From 51a59b7f7f9b134791d3b09673063e4c45ea9eee Mon Sep 17 00:00:00 2001 From: marha Date: Wed, 9 Feb 2011 07:47:31 +0000 Subject: libX11 mesa git update 9 Feb 2011 --- mesalib/src/glsl/ast_to_hir.cpp | 7 + mesalib/src/glsl/glsl_parser_extras.cpp | 2 +- mesalib/src/mesa/drivers/dri/common/dri_util.c | 2042 ++++----- mesalib/src/mesa/drivers/dri/common/dri_util.h | 1120 ++--- mesalib/src/mesa/drivers/dri/swrast/swrast.c | 2 +- mesalib/src/mesa/drivers/windows/gdi/wmesa.c | 3323 +++++++-------- .../src/mesa/drivers/windows/gldirect/dglcontext.c | 4424 ++++++++++---------- mesalib/src/mesa/main/blend.c | 1636 ++++---- mesalib/src/mesa/main/bufferobj.c | 4303 +++++++++---------- mesalib/src/mesa/main/context.c | 61 +- mesalib/src/mesa/main/context.h | 639 ++- mesalib/src/mesa/main/depth.c | 342 +- mesalib/src/mesa/main/hint.c | 293 +- mesalib/src/mesa/main/lines.c | 228 +- mesalib/src/mesa/main/mtypes.h | 17 +- mesalib/src/mesa/main/queryobj.c | 1208 +++--- mesalib/src/mesa/main/shaderapi.c | 11 + mesalib/src/mesa/main/stencil.c | 1204 +++--- mesalib/src/mesa/program/ir_to_mesa.cpp | 47 +- mesalib/src/mesa/state_tracker/st_context.c | 584 +-- mesalib/src/mesa/state_tracker/st_draw_feedback.c | 557 +-- mesalib/src/mesa/state_tracker/st_program.c | 2319 +++++----- 22 files changed, 12245 insertions(+), 12124 deletions(-) (limited to 'mesalib/src') diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp index 75f28cd2c..bef099cca 100644 --- a/mesalib/src/glsl/ast_to_hir.cpp +++ b/mesalib/src/glsl/ast_to_hir.cpp @@ -435,6 +435,13 @@ modulus_result_type(const struct glsl_type *type_a, const struct glsl_type *type_b, struct _mesa_glsl_parse_state *state, YYLTYPE *loc) { + if (state->language_version < 130) { + _mesa_glsl_error(loc, state, + "operator '%%' is reserved in %s", + state->version_string); + return glsl_type::error_type; + } + /* From GLSL 1.50 spec, page 56: * "The operator modulus (%) operates on signed or unsigned integers or * integer vectors. The operand types must both be signed or both be diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp index c2bb59b9c..d7a37aef4 100644 --- a/mesalib/src/glsl/glsl_parser_extras.cpp +++ b/mesalib/src/glsl/glsl_parser_extras.cpp @@ -764,7 +764,7 @@ do_common_optimization(exec_list *ir, bool linked, unsigned max_unroll_iteration progress = do_if_simplification(ir) || progress; progress = do_discard_simplification(ir) || progress; progress = do_copy_propagation(ir) || progress; - progress = do_copy_propagation_elements(ir) || progress; + /*progress = do_copy_propagation_elements(ir) || progress;*/ if (linked) progress = do_dead_code(ir) || progress; else diff --git a/mesalib/src/mesa/drivers/dri/common/dri_util.c b/mesalib/src/mesa/drivers/dri/common/dri_util.c index 8b3b55e5e..82638fa72 100644 --- a/mesalib/src/mesa/drivers/dri/common/dri_util.c +++ b/mesalib/src/mesa/drivers/dri/common/dri_util.c @@ -1,1012 +1,1030 @@ -/** - * \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 -#include -#include -#include -#include - -#ifndef MAP_FAILED -#define MAP_FAILED ((void *)-1) -#endif - -#include "main/imports.h" -#define None 0 - -#include "dri_util.h" -#include "drm_sarea.h" -#include "utils.h" -#include "xmlpool.h" -#include "../glsl/glsl_parser_extras.h" - -PUBLIC const char __dri2ConfigOptions[] = - DRI_CONF_BEGIN - DRI_CONF_SECTION_PERFORMANCE - DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_1) - DRI_CONF_SECTION_END - DRI_CONF_END; - -static const uint __dri2NConfigOptions = 1; - -#ifndef GLX_OML_sync_control -typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC) (__DRIdrawable *drawable, int32_t *numerator, int32_t *denominator); -#endif - -static void dri_get_drawable(__DRIdrawable *pdp); -static void dri_put_drawable(__DRIdrawable *pdp); - -/** - * This is just a token extension used to signal that the driver - * supports setting a read drawable. - */ -const __DRIextension driReadDrawableExtension = { - __DRI_READ_DRAWABLE, __DRI_READ_DRAWABLE_VERSION -}; - -GLint -driIntersectArea( drm_clip_rect_t rect1, drm_clip_rect_t rect2 ) -{ - if (rect2.x1 > rect1.x1) rect1.x1 = rect2.x1; - if (rect2.x2 < rect1.x2) rect1.x2 = rect2.x2; - if (rect2.y1 > rect1.y1) rect1.y1 = rect2.y1; - if (rect2.y2 < rect1.y2) rect1.y2 = rect2.y2; - - if (rect1.x1 > rect1.x2 || rect1.y1 > rect1.y2) return 0; - - return (rect1.x2 - rect1.x1) * (rect1.y2 - rect1.y1); -} - -/*****************************************************************/ -/** \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 - * __DRIdrawableRec::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. - */ -static int driUnbindContext(__DRIcontext *pcp) -{ - __DRIscreen *psp; - __DRIdrawable *pdp; - __DRIdrawable *prp; - - /* - ** Assume error checking is done properly in glXMakeCurrent before - ** calling driUnbindContext. - */ - - if (pcp == NULL) - return GL_FALSE; - - psp = pcp->driScreenPriv; - pdp = pcp->driDrawablePriv; - prp = pcp->driReadablePriv; - - /* already unbound */ - if (!pdp && !prp) - return GL_TRUE; - /* Let driver unbind drawable from context */ - (*psp->DriverAPI.UnbindContext)(pcp); - - assert(pdp); - if (pdp->refcount == 0) { - /* ERROR!!! */ - return GL_FALSE; - } - - dri_put_drawable(pdp); - - if (prp != pdp) { - if (prp->refcount == 0) { - /* ERROR!!! */ - return GL_FALSE; - } - - dri_put_drawable(prp); - } - - - /* 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) - */ - pcp->driDrawablePriv = pcp->driReadablePriv = NULL; - - 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. - */ -static int driBindContext(__DRIcontext *pcp, - __DRIdrawable *pdp, - __DRIdrawable *prp) -{ - __DRIscreen *psp = NULL; - - /* - ** Assume error checking is done properly in glXMakeCurrent before - ** calling driUnbindContext. - */ - - if (!pcp) - return GL_FALSE; - - /* Bind the drawable to the context */ - psp = pcp->driScreenPriv; - pcp->driDrawablePriv = pdp; - pcp->driReadablePriv = prp; - if (pdp) { - pdp->driContextPriv = pcp; - dri_get_drawable(pdp); - } - if (prp && pdp != prp) { - dri_get_drawable(prp); - } - - /* - ** Now that we have a context associated with this drawable, we can - ** initialize the drawable information if has not been done before. - */ - - if (!psp->dri2.enabled) { - if (pdp && !pdp->pStamp) { - DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); - __driUtilUpdateDrawableInfo(pdp); - DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); - } - if (prp && pdp != prp && !prp->pStamp) { - DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); - __driUtilUpdateDrawableInfo(prp); - DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); - } - } - - /* Call device-specific MakeCurrent */ - return (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp); -} - -/*@}*/ - - -/*****************************************************************/ -/** \name Drawable handling functions */ -/*****************************************************************/ -/*@{*/ - -/** - * Update private drawable information. - * - * \param pdp pointer to the private drawable information to update. - * - * This function basically updates the __DRIdrawable 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 -__driUtilUpdateDrawableInfo(__DRIdrawable *pdp) -{ - __DRIscreen *psp = pdp->driScreenPriv; - __DRIcontext *pcp = pdp->driContextPriv; - - if (!pcp - || ((pdp != pcp->driDrawablePriv) && (pdp != pcp->driReadablePriv))) { - /* ERROR!!! - * ...but we must ignore it. There can be many contexts bound to a - * drawable. - */ - } - - if (pdp->pClipRects) { - free(pdp->pClipRects); - pdp->pClipRects = NULL; - } - - if (pdp->pBackClipRects) { - free(pdp->pBackClipRects); - pdp->pBackClipRects = NULL; - } - - DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); - - if (! (*psp->getDrawableInfo->getDrawableInfo)(pdp, - &pdp->index, &pdp->lastStamp, - &pdp->x, &pdp->y, &pdp->w, &pdp->h, - &pdp->numClipRects, &pdp->pClipRects, - &pdp->backX, - &pdp->backY, - &pdp->numBackClipRects, - &pdp->pBackClipRects, - pdp->loaderPrivate)) { - /* Error -- eg the window may have been destroyed. Keep going - * with no cliprects. - */ - pdp->pStamp = &pdp->lastStamp; /* prevent endless loop */ - pdp->numClipRects = 0; - pdp->pClipRects = NULL; - pdp->numBackClipRects = 0; - pdp->pBackClipRects = NULL; - } - else - pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp); - - DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); -} - -/*@}*/ - -/*****************************************************************/ -/** \name GLX callbacks */ -/*****************************************************************/ -/*@{*/ - -static void driReportDamage(__DRIdrawable *pdp, - struct drm_clip_rect *pClipRects, int numClipRects) -{ - __DRIscreen *psp = pdp->driScreenPriv; - - /* Check that we actually have the new damage report method */ - if (psp->damage) { - /* 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). - */ - (*psp->damage->reportDamage)(pdp, - pdp->x, pdp->y, - pClipRects, numClipRects, - GL_TRUE, pdp->loaderPrivate); - } -} - - -/** - * Swap buffers. - * - * \param drawablePrivate opaque pointer to the per-drawable private info. - * - * \internal - * This function calls __DRIdrawable::swapBuffers. - * - * Is called directly from glXSwapBuffers(). - */ -static void driSwapBuffers(__DRIdrawable *dPriv) -{ - __DRIscreen *psp = dPriv->driScreenPriv; - drm_clip_rect_t *rects; - int i; - - psp->DriverAPI.SwapBuffers(dPriv); - - if (!dPriv->numClipRects) - return; - - rects = malloc(sizeof(*rects) * dPriv->numClipRects); - - if (!rects) - return; - - for (i = 0; i < dPriv->numClipRects; i++) { - rects[i].x1 = dPriv->pClipRects[i].x1 - dPriv->x; - rects[i].y1 = dPriv->pClipRects[i].y1 - dPriv->y; - rects[i].x2 = dPriv->pClipRects[i].x2 - dPriv->x; - rects[i].y2 = dPriv->pClipRects[i].y2 - dPriv->y; - } - - driReportDamage(dPriv, rects, dPriv->numClipRects); - free(rects); -} - -static int driDrawableGetMSC( __DRIscreen *sPriv, __DRIdrawable *dPriv, - int64_t *msc ) -{ - return sPriv->DriverAPI.GetDrawableMSC(sPriv, dPriv, msc); -} - - -static int driWaitForMSC(__DRIdrawable *dPriv, int64_t target_msc, - int64_t divisor, int64_t remainder, - int64_t * msc, int64_t * sbc) -{ - __DRIswapInfo sInfo; - int status; - - status = dPriv->driScreenPriv->DriverAPI.WaitForMSC( dPriv, target_msc, - divisor, remainder, - 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 - && dPriv->driScreenPriv->DriverAPI.GetSwapInfo ) { - status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo ); - *sbc = sInfo.swap_count; - } - - return status; -} - - -const __DRImediaStreamCounterExtension driMediaStreamCounterExtension = { - { __DRI_MEDIA_STREAM_COUNTER, __DRI_MEDIA_STREAM_COUNTER_VERSION }, - driWaitForMSC, - driDrawableGetMSC, -}; - - -static void driCopySubBuffer(__DRIdrawable *dPriv, - int x, int y, int w, int h) -{ - drm_clip_rect_t rect; - - rect.x1 = x; - rect.y1 = dPriv->h - y - h; - rect.x2 = x + w; - rect.y2 = rect.y1 + h; - driReportDamage(dPriv, &rect, 1); - - dPriv->driScreenPriv->DriverAPI.CopySubBuffer(dPriv, x, y, w, h); -} - -const __DRIcopySubBufferExtension driCopySubBufferExtension = { - { __DRI_COPY_SUB_BUFFER, __DRI_COPY_SUB_BUFFER_VERSION }, - driCopySubBuffer -}; - -static void driSetSwapInterval(__DRIdrawable *dPriv, unsigned int interval) -{ - dPriv->swap_interval = interval; -} - -static unsigned int driGetSwapInterval(__DRIdrawable *dPriv) -{ - return dPriv->swap_interval; -} - -const __DRIswapControlExtension driSwapControlExtension = { - { __DRI_SWAP_CONTROL, __DRI_SWAP_CONTROL_VERSION }, - driSetSwapInterval, - driGetSwapInterval -}; - - -/** - * This is called via __DRIscreenRec's createNewDrawable pointer. - */ -static __DRIdrawable * -driCreateNewDrawable(__DRIscreen *psp, const __DRIconfig *config, - drm_drawable_t hwDrawable, int renderType, - const int *attrs, void *data) -{ - __DRIdrawable *pdp; - - /* Since pbuffers are not yet supported, no drawable attributes are - * supported either. - */ - (void) attrs; - - pdp = malloc(sizeof *pdp); - if (!pdp) { - return NULL; - } - - pdp->driContextPriv = NULL; - pdp->loaderPrivate = data; - pdp->hHWDrawable = hwDrawable; - pdp->refcount = 1; - pdp->pStamp = NULL; - pdp->lastStamp = 0; - pdp->index = 0; - pdp->x = 0; - pdp->y = 0; - pdp->w = 0; - pdp->h = 0; - pdp->numClipRects = 0; - pdp->numBackClipRects = 0; - pdp->pClipRects = NULL; - pdp->pBackClipRects = NULL; - pdp->vblSeq = 0; - pdp->vblFlags = 0; - - pdp->driScreenPriv = psp; - - if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, &config->modes, 0)) { - free(pdp); - return NULL; - } - - pdp->msc_base = 0; - - /* This special default value is replaced with the configured - * default value when the drawable is first bound to a direct - * rendering context. - */ - pdp->swap_interval = (unsigned)-1; - - return pdp; -} - - -static __DRIdrawable * -dri2CreateNewDrawable(__DRIscreen *screen, - const __DRIconfig *config, - void *loaderPrivate) -{ - __DRIdrawable *pdraw; - - pdraw = driCreateNewDrawable(screen, config, 0, 0, NULL, loaderPrivate); - if (!pdraw) - return NULL; - - pdraw->pClipRects = &pdraw->dri2.clipRect; - pdraw->pBackClipRects = &pdraw->dri2.clipRect; - - pdraw->pStamp = &pdraw->dri2.stamp; - *pdraw->pStamp = pdraw->lastStamp + 1; - - return pdraw; -} - -static int -dri2ConfigQueryb(__DRIscreen *screen, const char *var, GLboolean *val) -{ - if (!driCheckOption(&screen->optionCache, var, DRI_BOOL)) - return -1; - - *val = driQueryOptionb(&screen->optionCache, var); - - return 0; -} - -static int -dri2ConfigQueryi(__DRIscreen *screen, const char *var, GLint *val) -{ - if (!driCheckOption(&screen->optionCache, var, DRI_INT) && - !driCheckOption(&screen->optionCache, var, DRI_ENUM)) - return -1; - - *val = driQueryOptioni(&screen->optionCache, var); - - return 0; -} - -static int -dri2ConfigQueryf(__DRIscreen *screen, const char *var, GLfloat *val) -{ - if (!driCheckOption(&screen->optionCache, var, DRI_FLOAT)) - return -1; - - *val = driQueryOptionf(&screen->optionCache, var); - - return 0; -} - - -static void dri_get_drawable(__DRIdrawable *pdp) -{ - pdp->refcount++; -} - -static void dri_put_drawable(__DRIdrawable *pdp) -{ - __DRIscreen *psp; - - if (pdp) { - pdp->refcount--; - if (pdp->refcount) - return; - - psp = pdp->driScreenPriv; - (*psp->DriverAPI.DestroyBuffer)(pdp); - if (pdp->pClipRects && pdp->pClipRects != &pdp->dri2.clipRect) { - free(pdp->pClipRects); - pdp->pClipRects = NULL; - } - if (pdp->pBackClipRects && pdp->pClipRects != &pdp->dri2.clipRect) { - free(pdp->pBackClipRects); - pdp->pBackClipRects = NULL; - } - free(pdp); - } -} - -static void -driDestroyDrawable(__DRIdrawable *pdp) -{ - dri_put_drawable(pdp); -} - -/*@}*/ - - -/*****************************************************************/ -/** \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 -driDestroyContext(__DRIcontext *pcp) -{ - if (pcp) { - (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp); - free(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 __DRIcontextRec structure. It - * performs some device independent initialization and passes all the - * relevent information to __DriverAPIRec::CreateContext to create the - * context. - * - */ -static __DRIcontext * -driCreateNewContext(__DRIscreen *psp, const __DRIconfig *config, - int render_type, __DRIcontext *shared, - drm_context_t hwContext, void *data) -{ - __DRIcontext *pcp; - void * const shareCtx = (shared != NULL) ? shared->driverPrivate : NULL; - - pcp = malloc(sizeof *pcp); - if (!pcp) - return NULL; - - pcp->driScreenPriv = psp; - pcp->driDrawablePriv = NULL; - pcp->loaderPrivate = data; - - pcp->dri2.draw_stamp = 0; - pcp->dri2.read_stamp = 0; - - pcp->hHWContext = hwContext; - - if ( !(*psp->DriverAPI.CreateContext)(API_OPENGL, - &config->modes, pcp, shareCtx) ) { - free(pcp); - return NULL; - } - - return pcp; -} - -static unsigned int -dri2GetAPIMask(__DRIscreen *screen) -{ - return screen->api_mask; -} - -static __DRIcontext * -dri2CreateNewContextForAPI(__DRIscreen *screen, int api, - const __DRIconfig *config, - __DRIcontext *shared, void *data) -{ - __DRIcontext *context; - const struct gl_config *modes = (config != NULL) ? &config->modes : NULL; - void *shareCtx = (shared != NULL) ? shared->driverPrivate : NULL; - gl_api mesa_api; - - if (!(screen->api_mask & (1 << api))) - return NULL; - - switch (api) { - case __DRI_API_OPENGL: - mesa_api = API_OPENGL; - break; - case __DRI_API_GLES: - mesa_api = API_OPENGLES; - break; - case __DRI_API_GLES2: - mesa_api = API_OPENGLES2; - break; - default: - return NULL; - } - - context = malloc(sizeof *context); - if (!context) - return NULL; - - context->driScreenPriv = screen; - context->driDrawablePriv = NULL; - context->loaderPrivate = data; - - if (!(*screen->DriverAPI.CreateContext)(mesa_api, modes, - context, shareCtx) ) { - free(context); - return NULL; - } - - return context; -} - - -static __DRIcontext * -dri2CreateNewContext(__DRIscreen *screen, const __DRIconfig *config, - __DRIcontext *shared, void *data) -{ - return dri2CreateNewContextForAPI(screen, __DRI_API_OPENGL, - config, shared, data); -} - -static int -driCopyContext(__DRIcontext *dest, __DRIcontext *src, unsigned long mask) -{ - 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. - */ -static void driDestroyScreen(__DRIscreen *psp) -{ - 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. - */ - - _mesa_destroy_shader_compiler(); - - if (psp->DriverAPI.DestroyScreen) - (*psp->DriverAPI.DestroyScreen)(psp); - - if (!psp->dri2.enabled) { - (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX); - (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize); - (void)drmCloseOnce(psp->fd); - } else { - driDestroyOptionCache(&psp->optionCache); - driDestroyOptionInfo(&psp->optionInfo); - } - - free(psp); - } -} - -static void -setupLoaderExtensions(__DRIscreen *psp, - const __DRIextension **extensions) -{ - int i; - - for (i = 0; extensions[i]; i++) { - if (strcmp(extensions[i]->name, __DRI_GET_DRAWABLE_INFO) == 0) - psp->getDrawableInfo = (__DRIgetDrawableInfoExtension *) extensions[i]; - if (strcmp(extensions[i]->name, __DRI_DAMAGE) == 0) - psp->damage = (__DRIdamageExtension *) extensions[i]; - if (strcmp(extensions[i]->name, __DRI_SYSTEM_TIME) == 0) - psp->systemTime = (__DRIsystemTimeExtension *) extensions[i]; - if (strcmp(extensions[i]->name, __DRI_DRI2_LOADER) == 0) - psp->dri2.loader = (__DRIdri2LoaderExtension *) extensions[i]; - if (strcmp(extensions[i]->name, __DRI_IMAGE_LOOKUP) == 0) - psp->dri2.image = (__DRIimageLookupExtension *) extensions[i]; - if (strcmp(extensions[i]->name, __DRI_USE_INVALIDATE) == 0) - psp->dri2.useInvalidate = (__DRIuseInvalidateExtension *) extensions[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 struct gl_config 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 to the SAREA. - * \param fd Device handle for the DRM. - * \param extensions ?? - * \param driver_modes Returns modes suppoted 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 * -driCreateNewScreen(int scrn, - const __DRIversion *ddx_version, - const __DRIversion *dri_version, - const __DRIversion *drm_version, - const __DRIframebuffer *frame_buffer, - drmAddress pSAREA, int fd, - const __DRIextension **extensions, - const __DRIconfig ***driver_modes, - void *loaderPrivate) -{ - static const __DRIextension *emptyExtensionList[] = { NULL }; - __DRIscreen *psp; - - if (driDriverAPI.InitScreen == NULL) - return NULL; - - psp = calloc(1, sizeof *psp); - if (!psp) - return NULL; - - setupLoaderExtensions(psp, extensions); - - /* - ** 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. - */ - psp->drawLockID = 1; - - psp->drm_version = *drm_version; - psp->ddx_version = *ddx_version; - psp->dri_version = *dri_version; - - psp->pSAREA = pSAREA; - psp->lock = (drmLock *) &psp->pSAREA->lock; - - psp->pFB = frame_buffer->base; - psp->fbSize = frame_buffer->size; - psp->fbStride = frame_buffer->stride; - psp->fbWidth = frame_buffer->width; - psp->fbHeight = frame_buffer->height; - psp->devPrivSize = frame_buffer->dev_priv_size; - psp->pDevPriv = frame_buffer->dev_priv; - psp->fbBPP = psp->fbStride * 8 / frame_buffer->width; - - psp->extensions = emptyExtensionList; - psp->fd = fd; - psp->myNum = scrn; - psp->dri2.enabled = GL_FALSE; - - psp->DriverAPI = driDriverAPI; - psp->api_mask = (1 << __DRI_API_OPENGL); - - *driver_modes = driDriverAPI.InitScreen(psp); - if (*driver_modes == NULL) { - free(psp); - return NULL; - } - - return psp; -} - -/** - * DRI2 - */ -static __DRIscreen * -dri2CreateNewScreen(int scrn, int fd, - const __DRIextension **extensions, - const __DRIconfig ***driver_configs, void *data) -{ - static const __DRIextension *emptyExtensionList[] = { NULL }; - __DRIscreen *psp; - drmVersionPtr version; - - if (driDriverAPI.InitScreen2 == NULL) - return NULL; - - psp = calloc(1, sizeof(*psp)); - if (!psp) - return NULL; - - setupLoaderExtensions(psp, extensions); - - version = drmGetVersion(fd); - if (version) { - psp->drm_version.major = version->version_major; - psp->drm_version.minor = version->version_minor; - psp->drm_version.patch = version->version_patchlevel; - drmFreeVersion(version); - } - - psp->extensions = emptyExtensionList; - psp->fd = fd; - psp->myNum = scrn; - psp->dri2.enabled = GL_TRUE; - - psp->DriverAPI = driDriverAPI; - psp->api_mask = (1 << __DRI_API_OPENGL); - *driver_configs = driDriverAPI.InitScreen2(psp); - if (*driver_configs == NULL) { - free(psp); - return NULL; - } - - psp->DriverAPI = driDriverAPI; - psp->loaderPrivate = data; - - driParseOptionInfo(&psp->optionInfo, __dri2ConfigOptions, - __dri2NConfigOptions); - driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum, - "dri2"); - - return psp; -} - -static const __DRIextension **driGetExtensions(__DRIscreen *psp) -{ - return psp->extensions; -} - -/** Core interface */ -const __DRIcoreExtension driCoreExtension = { - { __DRI_CORE, __DRI_CORE_VERSION }, - NULL, - driDestroyScreen, - driGetExtensions, - driGetConfigAttrib, - driIndexConfigAttrib, - NULL, - driDestroyDrawable, - driSwapBuffers, - NULL, - driCopyContext, - driDestroyContext, - driBindContext, - driUnbindContext -}; - -/** Legacy DRI interface */ -const __DRIlegacyExtension driLegacyExtension = { - { __DRI_LEGACY, __DRI_LEGACY_VERSION }, - driCreateNewScreen, - driCreateNewDrawable, - driCreateNewContext, -}; - -/** DRI2 interface */ -const __DRIdri2Extension driDRI2Extension = { - { __DRI_DRI2, __DRI_DRI2_VERSION }, - dri2CreateNewScreen, - dri2CreateNewDrawable, - dri2CreateNewContext, - dri2GetAPIMask, - dri2CreateNewContextForAPI -}; - -const __DRI2configQueryExtension dri2ConfigQueryExtension = { - { __DRI2_CONFIG_QUERY, __DRI2_CONFIG_QUERY_VERSION }, - dri2ConfigQueryb, - dri2ConfigQueryi, - dri2ConfigQueryf, -}; - -/** - * 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 -driCalculateSwapUsage( __DRIdrawable *dPriv, int64_t last_swap_ust, - int64_t current_ust ) -{ - int32_t n; - int32_t d; - int interval; - float usage = 1.0; - __DRIscreen *psp = dPriv->driScreenPriv; - - if ( (*psp->systemTime->getMSCRate)(dPriv, &n, &d, dPriv->loaderPrivate) ) { - interval = (dPriv->swap_interval != 0) ? dPriv->swap_interval : 1; - - - /* 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 = (current_ust - last_swap_ust); - usage *= n; - usage /= (interval * d); - usage /= 1000000.0; - } - - return usage; -} - -void -dri2InvalidateDrawable(__DRIdrawable *drawable) -{ - drawable->dri2.stamp++; -} - -/*@}*/ +/** + * \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 +#include +#include +#include +#include + +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + +#include "main/imports.h" +#define None 0 + +#include "dri_util.h" +#include "drm_sarea.h" +#include "utils.h" +#include "xmlpool.h" +#include "../glsl/glsl_parser_extras.h" + +PUBLIC const char __dri2ConfigOptions[] = + DRI_CONF_BEGIN + DRI_CONF_SECTION_PERFORMANCE + DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_1) + DRI_CONF_SECTION_END + DRI_CONF_END; + +static const uint __dri2NConfigOptions = 1; + +#ifndef GLX_OML_sync_control +typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC) (__DRIdrawable *drawable, int32_t *numerator, int32_t *denominator); +#endif + +static void dri_get_drawable(__DRIdrawable *pdp); +static void dri_put_drawable(__DRIdrawable *pdp); + +/** + * This is just a token extension used to signal that the driver + * supports setting a read drawable. + */ +const __DRIextension driReadDrawableExtension = { + __DRI_READ_DRAWABLE, __DRI_READ_DRAWABLE_VERSION +}; + +GLint +driIntersectArea( drm_clip_rect_t rect1, drm_clip_rect_t rect2 ) +{ + if (rect2.x1 > rect1.x1) rect1.x1 = rect2.x1; + if (rect2.x2 < rect1.x2) rect1.x2 = rect2.x2; + if (rect2.y1 > rect1.y1) rect1.y1 = rect2.y1; + if (rect2.y2 < rect1.y2) rect1.y2 = rect2.y2; + + if (rect1.x1 > rect1.x2 || rect1.y1 > rect1.y2) return 0; + + return (rect1.x2 - rect1.x1) * (rect1.y2 - rect1.y1); +} + +/*****************************************************************/ +/** \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 + * __DRIdrawableRec::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. + */ +static int driUnbindContext(__DRIcontext *pcp) +{ + __DRIscreen *psp; + __DRIdrawable *pdp; + __DRIdrawable *prp; + + /* + ** Assume error checking is done properly in glXMakeCurrent before + ** calling driUnbindContext. + */ + + if (pcp == NULL) + return GL_FALSE; + + psp = pcp->driScreenPriv; + pdp = pcp->driDrawablePriv; + prp = pcp->driReadablePriv; + + /* already unbound */ + if (!pdp && !prp) + return GL_TRUE; + /* Let driver unbind drawable from context */ + (*psp->DriverAPI.UnbindContext)(pcp); + + assert(pdp); + if (pdp->refcount == 0) { + /* ERROR!!! */ + return GL_FALSE; + } + + dri_put_drawable(pdp); + + if (prp != pdp) { + if (prp->refcount == 0) { + /* ERROR!!! */ + return GL_FALSE; + } + + dri_put_drawable(prp); + } + + + /* 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) + */ + pcp->driDrawablePriv = pcp->driReadablePriv = NULL; + + 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. + */ +static int driBindContext(__DRIcontext *pcp, + __DRIdrawable *pdp, + __DRIdrawable *prp) +{ + __DRIscreen *psp = NULL; + + /* + ** Assume error checking is done properly in glXMakeCurrent before + ** calling driUnbindContext. + */ + + if (!pcp) + return GL_FALSE; + + /* Bind the drawable to the context */ + psp = pcp->driScreenPriv; + pcp->driDrawablePriv = pdp; + pcp->driReadablePriv = prp; + if (pdp) { + pdp->driContextPriv = pcp; + dri_get_drawable(pdp); + } + if (prp && pdp != prp) { + dri_get_drawable(prp); + } + + /* + ** Now that we have a context associated with this drawable, we can + ** initialize the drawable information if has not been done before. + */ + + if (!psp->dri2.enabled) { + if (pdp && !pdp->pStamp) { + DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); + __driUtilUpdateDrawableInfo(pdp); + DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); + } + if (prp && pdp != prp && !prp->pStamp) { + DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); + __driUtilUpdateDrawableInfo(prp); + DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); + } + } + + /* Call device-specific MakeCurrent */ + return (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp); +} + +/*@}*/ + + +/*****************************************************************/ +/** \name Drawable handling functions */ +/*****************************************************************/ +/*@{*/ + +/** + * Update private drawable information. + * + * \param pdp pointer to the private drawable information to update. + * + * This function basically updates the __DRIdrawable 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 +__driUtilUpdateDrawableInfo(__DRIdrawable *pdp) +{ + __DRIscreen *psp = pdp->driScreenPriv; + __DRIcontext *pcp = pdp->driContextPriv; + + if (!pcp + || ((pdp != pcp->driDrawablePriv) && (pdp != pcp->driReadablePriv))) { + /* ERROR!!! + * ...but we must ignore it. There can be many contexts bound to a + * drawable. + */ + } + + if (pdp->pClipRects) { + free(pdp->pClipRects); + pdp->pClipRects = NULL; + } + + if (pdp->pBackClipRects) { + free(pdp->pBackClipRects); + pdp->pBackClipRects = NULL; + } + + DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); + + if (! (*psp->getDrawableInfo->getDrawableInfo)(pdp, + &pdp->index, &pdp->lastStamp, + &pdp->x, &pdp->y, &pdp->w, &pdp->h, + &pdp->numClipRects, &pdp->pClipRects, + &pdp->backX, + &pdp->backY, + &pdp->numBackClipRects, + &pdp->pBackClipRects, + pdp->loaderPrivate)) { + /* Error -- eg the window may have been destroyed. Keep going + * with no cliprects. + */ + pdp->pStamp = &pdp->lastStamp; /* prevent endless loop */ + pdp->numClipRects = 0; + pdp->pClipRects = NULL; + pdp->numBackClipRects = 0; + pdp->pBackClipRects = NULL; + } + else + pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp); + + DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); +} + +/*@}*/ + +/*****************************************************************/ +/** \name GLX callbacks */ +/*****************************************************************/ +/*@{*/ + +static void driReportDamage(__DRIdrawable *pdp, + struct drm_clip_rect *pClipRects, int numClipRects) +{ + __DRIscreen *psp = pdp->driScreenPriv; + + /* Check that we actually have the new damage report method */ + if (psp->damage) { + /* 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). + */ + (*psp->damage->reportDamage)(pdp, + pdp->x, pdp->y, + pClipRects, numClipRects, + GL_TRUE, pdp->loaderPrivate); + } +} + + +/** + * Swap buffers. + * + * \param drawablePrivate opaque pointer to the per-drawable private info. + * + * \internal + * This function calls __DRIdrawable::swapBuffers. + * + * Is called directly from glXSwapBuffers(). + */ +static void driSwapBuffers(__DRIdrawable *dPriv) +{ + __DRIscreen *psp = dPriv->driScreenPriv; + drm_clip_rect_t *rects; + int i; + + psp->DriverAPI.SwapBuffers(dPriv); + + if (!dPriv->numClipRects) + return; + + rects = malloc(sizeof(*rects) * dPriv->numClipRects); + + if (!rects) + return; + + for (i = 0; i < dPriv->numClipRects; i++) { + rects[i].x1 = dPriv->pClipRects[i].x1 - dPriv->x; + rects[i].y1 = dPriv->pClipRects[i].y1 - dPriv->y; + rects[i].x2 = dPriv->pClipRects[i].x2 - dPriv->x; + rects[i].y2 = dPriv->pClipRects[i].y2 - dPriv->y; + } + + driReportDamage(dPriv, rects, dPriv->numClipRects); + free(rects); +} + +static int driDrawableGetMSC( __DRIscreen *sPriv, __DRIdrawable *dPriv, + int64_t *msc ) +{ + return sPriv->DriverAPI.GetDrawableMSC(sPriv, dPriv, msc); +} + + +static int driWaitForMSC(__DRIdrawable *dPriv, int64_t target_msc, + int64_t divisor, int64_t remainder, + int64_t * msc, int64_t * sbc) +{ + __DRIswapInfo sInfo; + int status; + + status = dPriv->driScreenPriv->DriverAPI.WaitForMSC( dPriv, target_msc, + divisor, remainder, + 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 + && dPriv->driScreenPriv->DriverAPI.GetSwapInfo ) { + status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo ); + *sbc = sInfo.swap_count; + } + + return status; +} + + +const __DRImediaStreamCounterExtension driMediaStreamCounterExtension = { + { __DRI_MEDIA_STREAM_COUNTER, __DRI_MEDIA_STREAM_COUNTER_VERSION }, + driWaitForMSC, + driDrawableGetMSC, +}; + + +static void driCopySubBuffer(__DRIdrawable *dPriv, + int x, int y, int w, int h) +{ + drm_clip_rect_t rect; + + rect.x1 = x; + rect.y1 = dPriv->h - y - h; + rect.x2 = x + w; + rect.y2 = rect.y1 + h; + driReportDamage(dPriv, &rect, 1); + + dPriv->driScreenPriv->DriverAPI.CopySubBuffer(dPriv, x, y, w, h); +} + +const __DRIcopySubBufferExtension driCopySubBufferExtension = { + { __DRI_COPY_SUB_BUFFER, __DRI_COPY_SUB_BUFFER_VERSION }, + driCopySubBuffer +}; + +static void driSetSwapInterval(__DRIdrawable *dPriv, unsigned int interval) +{ + dPriv->swap_interval = interval; +} + +static unsigned int driGetSwapInterval(__DRIdrawable *dPriv) +{ + return dPriv->swap_interval; +} + +const __DRIswapControlExtension driSwapControlExtension = { + { __DRI_SWAP_CONTROL, __DRI_SWAP_CONTROL_VERSION }, + driSetSwapInterval, + driGetSwapInterval +}; + + +/** + * This is called via __DRIscreenRec's createNewDrawable pointer. + */ +static __DRIdrawable * +driCreateNewDrawable(__DRIscreen *psp, const __DRIconfig *config, + drm_drawable_t hwDrawable, int renderType, + const int *attrs, void *data) +{ + __DRIdrawable *pdp; + + /* Since pbuffers are not yet supported, no drawable attributes are + * supported either. + */ + (void) attrs; + + pdp = malloc(sizeof *pdp); + if (!pdp) { + return NULL; + } + + pdp->driContextPriv = NULL; + pdp->loaderPrivate = data; + pdp->hHWDrawable = hwDrawable; + pdp->refcount = 1; + pdp->pStamp = NULL; + pdp->lastStamp = 0; + pdp->index = 0; + pdp->x = 0; + pdp->y = 0; + pdp->w = 0; + pdp->h = 0; + pdp->numClipRects = 0; + pdp->numBackClipRects = 0; + pdp->pClipRects = NULL; + pdp->pBackClipRects = NULL; + pdp->vblSeq = 0; + pdp->vblFlags = 0; + + pdp->driScreenPriv = psp; + + if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, &config->modes, 0)) { + free(pdp); + return NULL; + } + + pdp->msc_base = 0; + + /* This special default value is replaced with the configured + * default value when the drawable is first bound to a direct + * rendering context. + */ + pdp->swap_interval = (unsigned)-1; + + return pdp; +} + + +static __DRIdrawable * +dri2CreateNewDrawable(__DRIscreen *screen, + const __DRIconfig *config, + void *loaderPrivate) +{ + __DRIdrawable *pdraw; + + pdraw = driCreateNewDrawable(screen, config, 0, 0, NULL, loaderPrivate); + if (!pdraw) + return NULL; + + pdraw->pClipRects = &pdraw->dri2.clipRect; + pdraw->pBackClipRects = &pdraw->dri2.clipRect; + + pdraw->pStamp = &pdraw->dri2.stamp; + *pdraw->pStamp = pdraw->lastStamp + 1; + + return pdraw; +} + +static __DRIbuffer * +dri2AllocateBuffer(__DRIscreen *screen, + unsigned int attachment, unsigned int format, + int width, int height) +{ + return (*screen->DriverAPI.AllocateBuffer)(screen, attachment, format, + width, height); +} + +static void +dri2ReleaseBuffer(__DRIscreen *screen, __DRIbuffer *buffer) +{ + (*screen->DriverAPI.ReleaseBuffer)(screen, buffer); +} + + +static int +dri2ConfigQueryb(__DRIscreen *screen, const char *var, GLboolean *val) +{ + if (!driCheckOption(&screen->optionCache, var, DRI_BOOL)) + return -1; + + *val = driQueryOptionb(&screen->optionCache, var); + + return 0; +} + +static int +dri2ConfigQueryi(__DRIscreen *screen, const char *var, GLint *val) +{ + if (!driCheckOption(&screen->optionCache, var, DRI_INT) && + !driCheckOption(&screen->optionCache, var, DRI_ENUM)) + return -1; + + *val = driQueryOptioni(&screen->optionCache, var); + + return 0; +} + +static int +dri2ConfigQueryf(__DRIscreen *screen, const char *var, GLfloat *val) +{ + if (!driCheckOption(&screen->optionCache, var, DRI_FLOAT)) + return -1; + + *val = driQueryOptionf(&screen->optionCache, var); + + return 0; +} + + +static void dri_get_drawable(__DRIdrawable *pdp) +{ + pdp->refcount++; +} + +static void dri_put_drawable(__DRIdrawable *pdp) +{ + __DRIscreen *psp; + + if (pdp) { + pdp->refcount--; + if (pdp->refcount) + return; + + psp = pdp->driScreenPriv; + (*psp->DriverAPI.DestroyBuffer)(pdp); + if (pdp->pClipRects && pdp->pClipRects != &pdp->dri2.clipRect) { + free(pdp->pClipRects); + pdp->pClipRects = NULL; + } + if (pdp->pBackClipRects && pdp->pClipRects != &pdp->dri2.clipRect) { + free(pdp->pBackClipRects); + pdp->pBackClipRects = NULL; + } + free(pdp); + } +} + +static void +driDestroyDrawable(__DRIdrawable *pdp) +{ + dri_put_drawable(pdp); +} + +/*@}*/ + + +/*****************************************************************/ +/** \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 +driDestroyContext(__DRIcontext *pcp) +{ + if (pcp) { + (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp); + free(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 __DRIcontextRec structure. It + * performs some device independent initialization and passes all the + * relevent information to __DriverAPIRec::CreateContext to create the + * context. + * + */ +static __DRIcontext * +driCreateNewContext(__DRIscreen *psp, const __DRIconfig *config, + int render_type, __DRIcontext *shared, + drm_context_t hwContext, void *data) +{ + __DRIcontext *pcp; + void * const shareCtx = (shared != NULL) ? shared->driverPrivate : NULL; + + pcp = malloc(sizeof *pcp); + if (!pcp) + return NULL; + + pcp->driScreenPriv = psp; + pcp->driDrawablePriv = NULL; + pcp->loaderPrivate = data; + + pcp->dri2.draw_stamp = 0; + pcp->dri2.read_stamp = 0; + + pcp->hHWContext = hwContext; + + if ( !(*psp->DriverAPI.CreateContext)(API_OPENGL, + &config->modes, pcp, shareCtx) ) { + free(pcp); + return NULL; + } + + return pcp; +} + +static unsigned int +dri2GetAPIMask(__DRIscreen *screen) +{ + return screen->api_mask; +} + +static __DRIcontext * +dri2CreateNewContextForAPI(__DRIscreen *screen, int api, + const __DRIconfig *config, + __DRIcontext *shared, void *data) +{ + __DRIcontext *context; + const struct gl_config *modes = (config != NULL) ? &config->modes : NULL; + void *shareCtx = (shared != NULL) ? shared->driverPrivate : NULL; + gl_api mesa_api; + + if (!(screen->api_mask & (1 << api))) + return NULL; + + switch (api) { + case __DRI_API_OPENGL: + mesa_api = API_OPENGL; + break; + case __DRI_API_GLES: + mesa_api = API_OPENGLES; + break; + case __DRI_API_GLES2: + mesa_api = API_OPENGLES2; + break; + default: + return NULL; + } + + context = malloc(sizeof *context); + if (!context) + return NULL; + + context->driScreenPriv = screen; + context->driDrawablePriv = NULL; + context->loaderPrivate = data; + + if (!(*screen->DriverAPI.CreateContext)(mesa_api, modes, + context, shareCtx) ) { + free(context); + return NULL; + } + + return context; +} + + +static __DRIcontext * +dri2CreateNewContext(__DRIscreen *screen, const __DRIconfig *config, + __DRIcontext *shared, void *data) +{ + return dri2CreateNewContextForAPI(screen, __DRI_API_OPENGL, + config, shared, data); +} + +static int +driCopyContext(__DRIcontext *dest, __DRIcontext *src, unsigned long mask) +{ + 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. + */ +static void driDestroyScreen(__DRIscreen *psp) +{ + 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. + */ + + _mesa_destroy_shader_compiler(); + + if (psp->DriverAPI.DestroyScreen) + (*psp->DriverAPI.DestroyScreen)(psp); + + if (!psp->dri2.enabled) { + (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX); + (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize); + (void)drmCloseOnce(psp->fd); + } else { + driDestroyOptionCache(&psp->optionCache); + driDestroyOptionInfo(&psp->optionInfo); + } + + free(psp); + } +} + +static void +setupLoaderExtensions(__DRIscreen *psp, + const __DRIextension **extensions) +{ + int i; + + for (i = 0; extensions[i]; i++) { + if (strcmp(extensions[i]->name, __DRI_GET_DRAWABLE_INFO) == 0) + psp->getDrawableInfo = (__DRIgetDrawableInfoExtension *) extensions[i]; + if (strcmp(extensions[i]->name, __DRI_DAMAGE) == 0) + psp->damage = (__DRIdamageExtension *) extensions[i]; + if (strcmp(extensions[i]->name, __DRI_SYSTEM_TIME) == 0) + psp->systemTime = (__DRIsystemTimeExtension *) extensions[i]; + if (strcmp(extensions[i]->name, __DRI_DRI2_LOADER) == 0) + psp->dri2.loader = (__DRIdri2LoaderExtension *) extensions[i]; + if (strcmp(extensions[i]->name, __DRI_IMAGE_LOOKUP) == 0) + psp->dri2.image = (__DRIimageLookupExtension *) extensions[i]; + if (strcmp(extensions[i]->name, __DRI_USE_INVALIDATE) == 0) + psp->dri2.useInvalidate = (__DRIuseInvalidateExtension *) extensions[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 struct gl_config 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 to the SAREA. + * \param fd Device handle for the DRM. + * \param extensions ?? + * \param driver_modes Returns modes suppoted 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 * +driCreateNewScreen(int scrn, + const __DRIversion *ddx_version, + const __DRIversion *dri_version, + const __DRIversion *drm_version, + const __DRIframebuffer *frame_buffer, + drmAddress pSAREA, int fd, + const __DRIextension **extensions, + const __DRIconfig ***driver_modes, + void *loaderPrivate) +{ + static const __DRIextension *emptyExtensionList[] = { NULL }; + __DRIscreen *psp; + + if (driDriverAPI.InitScreen == NULL) + return NULL; + + psp = calloc(1, sizeof *psp); + if (!psp) + return NULL; + + setupLoaderExtensions(psp, extensions); + + /* + ** 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. + */ + psp->drawLockID = 1; + + psp->drm_version = *drm_version; + psp->ddx_version = *ddx_version; + psp->dri_version = *dri_version; + + psp->pSAREA = pSAREA; + psp->lock = (drmLock *) &psp->pSAREA->lock; + + psp->pFB = frame_buffer->base; + psp->fbSize = frame_buffer->size; + psp->fbStride = frame_buffer->stride; + psp->fbWidth = frame_buffer->width; + psp->fbHeight = frame_buffer->height; + psp->devPrivSize = frame_buffer->dev_priv_size; + psp->pDevPriv = frame_buffer->dev_priv; + psp->fbBPP = psp->fbStride * 8 / frame_buffer->width; + + psp->extensions = emptyExtensionList; + psp->fd = fd; + psp->myNum = scrn; + psp->dri2.enabled = GL_FALSE; + + psp->DriverAPI = driDriverAPI; + psp->api_mask = (1 << __DRI_API_OPENGL); + + *driver_modes = driDriverAPI.InitScreen(psp); + if (*driver_modes == NULL) { + free(psp); + return NULL; + } + + return psp; +} + +/** + * DRI2 + */ +static __DRIscreen * +dri2CreateNewScreen(int scrn, int fd, + const __DRIextension **extensions, + const __DRIconfig ***driver_configs, void *data) +{ + static const __DRIextension *emptyExtensionList[] = { NULL }; + __DRIscreen *psp; + drmVersionPtr version; + + if (driDriverAPI.InitScreen2 == NULL) + return NULL; + + psp = calloc(1, sizeof(*psp)); + if (!psp) + return NULL; + + setupLoaderExtensions(psp, extensions); + + version = drmGetVersion(fd); + if (version) { + psp->drm_version.major = version->version_major; + psp->drm_version.minor = version->version_minor; + psp->drm_version.patch = version->version_patchlevel; + drmFreeVersion(version); + } + + psp->extensions = emptyExtensionList; + psp->fd = fd; + psp->myNum = scrn; + psp->dri2.enabled = GL_TRUE; + + psp->DriverAPI = driDriverAPI; + psp->api_mask = (1 << __DRI_API_OPENGL); + *driver_configs = driDriverAPI.InitScreen2(psp); + if (*driver_configs == NULL) { + free(psp); + return NULL; + } + + psp->DriverAPI = driDriverAPI; + psp->loaderPrivate = data; + + driParseOptionInfo(&psp->optionInfo, __dri2ConfigOptions, + __dri2NConfigOptions); + driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum, + "dri2"); + + return psp; +} + +static const __DRIextension **driGetExtensions(__DRIscreen *psp) +{ + return psp->extensions; +} + +/** Core interface */ +const __DRIcoreExtension driCoreExtension = { + { __DRI_CORE, __DRI_CORE_VERSION }, + NULL, + driDestroyScreen, + driGetExtensions, + driGetConfigAttrib, + driIndexConfigAttrib, + NULL, + driDestroyDrawable, + driSwapBuffers, + NULL, + driCopyContext, + driDestroyContext, + driBindContext, + driUnbindContext +}; + +/** Legacy DRI interface */ +const __DRIlegacyExtension driLegacyExtension = { + { __DRI_LEGACY, __DRI_LEGACY_VERSION }, + driCreateNewScreen, + driCreateNewDrawable, + driCreateNewContext, +}; + +/** DRI2 interface */ +const __DRIdri2Extension driDRI2Extension = { + { __DRI_DRI2, __DRI_DRI2_VERSION }, + dri2CreateNewScreen, + dri2CreateNewDrawable, + dri2CreateNewContext, + dri2GetAPIMask, + dri2CreateNewContextForAPI, + dri2AllocateBuffer, + dri2ReleaseBuffer +}; + +const __DRI2configQueryExtension dri2ConfigQueryExtension = { + { __DRI2_CONFIG_QUERY, __DRI2_CONFIG_QUERY_VERSION }, + dri2ConfigQueryb, + dri2ConfigQueryi, + dri2ConfigQueryf, +}; + +/** + * 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 +driCalculateSwapUsage( __DRIdrawable *dPriv, int64_t last_swap_ust, + int64_t current_ust ) +{ + int32_t n; + int32_t d; + int interval; + float usage = 1.0; + __DRIscreen *psp = dPriv->driScreenPriv; + + if ( (*psp->systemTime->getMSCRate)(dPriv, &n, &d, dPriv->loaderPrivate) ) { + interval = (dPriv->swap_interval != 0) ? dPriv->swap_interval : 1; + + + /* 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 = (current_ust - last_swap_ust); + usage *= n; + usage /= (interval * d); + usage /= 1000000.0; + } + + return usage; +} + +void +dri2InvalidateDrawable(__DRIdrawable *drawable) +{ + drawable->dri2.stamp++; +} + +/*@}*/ diff --git a/mesalib/src/mesa/drivers/dri/common/dri_util.h b/mesalib/src/mesa/drivers/dri/common/dri_util.h index b6f04993e..3d3d5c9cd 100644 --- a/mesalib/src/mesa/drivers/dri/common/dri_util.h +++ b/mesalib/src/mesa/drivers/dri/common/dri_util.h @@ -1,557 +1,563 @@ -/* - * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. - * 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, sub license, 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 NON-INFRINGEMENT. - * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. - */ - -/** - * \file dri_util.h - * DRI utility functions definitions. - * - * 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. - * - * \sa dri_util.c. - * - * \author Kevin E. Martin - * \author Brian Paul - */ - -#ifndef _DRI_UTIL_H_ -#define _DRI_UTIL_H_ - -#include -#include -#include -#include -#include "xmlconfig.h" -#include "main/glheader.h" -#include "main/mtypes.h" -#include "GL/internal/dri_interface.h" - -#define GLX_BAD_CONTEXT 5 - -typedef struct __DRIswapInfoRec __DRIswapInfo; - -/** - * Extensions. - */ -extern const __DRIlegacyExtension driLegacyExtension; -extern const __DRIcoreExtension driCoreExtension; -extern const __DRIdri2Extension driDRI2Extension; -extern const __DRIextension driReadDrawableExtension; -extern const __DRIcopySubBufferExtension driCopySubBufferExtension; -extern const __DRIswapControlExtension driSwapControlExtension; -extern const __DRImediaStreamCounterExtension driMediaStreamCounterExtension; -extern const __DRI2configQueryExtension dri2ConfigQueryExtension; - -/** - * Used by DRI_VALIDATE_DRAWABLE_INFO - */ -#define DRI_VALIDATE_DRAWABLE_INFO_ONCE(pDrawPriv) \ - do { \ - if (*(pDrawPriv->pStamp) != pDrawPriv->lastStamp) { \ - __driUtilUpdateDrawableInfo(pDrawPriv); \ - } \ - } while (0) - - -/** - * Utility macro to validate the drawable information. - * - * See __DRIdrawable::pStamp and __DRIdrawable::lastStamp. - */ -#define DRI_VALIDATE_DRAWABLE_INFO(psp, pdp) \ -do { \ - while (*(pdp->pStamp) != pdp->lastStamp) { \ - register unsigned int hwContext = psp->pSAREA->lock.lock & \ - ~(DRM_LOCK_HELD | DRM_LOCK_CONT); \ - DRM_UNLOCK(psp->fd, &psp->pSAREA->lock, hwContext); \ - \ - DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); \ - DRI_VALIDATE_DRAWABLE_INFO_ONCE(pdp); \ - DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); \ - \ - DRM_LIGHT_LOCK(psp->fd, &psp->pSAREA->lock, hwContext); \ - } \ -} while (0) - -/** - * Same as above, but for two drawables simultaneously. - * - */ - -#define DRI_VALIDATE_TWO_DRAWABLES_INFO(psp, pdp, prp) \ -do { \ - while (*((pdp)->pStamp) != (pdp)->lastStamp || \ - *((prp)->pStamp) != (prp)->lastStamp) { \ - register unsigned int hwContext = (psp)->pSAREA->lock.lock & \ - ~(DRM_LOCK_HELD | DRM_LOCK_CONT); \ - DRM_UNLOCK((psp)->fd, &(psp)->pSAREA->lock, hwContext); \ - \ - DRM_SPINLOCK(&(psp)->pSAREA->drawable_lock, (psp)->drawLockID); \ - DRI_VALIDATE_DRAWABLE_INFO_ONCE(pdp); \ - DRI_VALIDATE_DRAWABLE_INFO_ONCE(prp); \ - DRM_SPINUNLOCK(&(psp)->pSAREA->drawable_lock, (psp)->drawLockID); \ - \ - DRM_LIGHT_LOCK((psp)->fd, &(psp)->pSAREA->lock, hwContext); \ - } \ -} while (0) - - -/** - * Driver callback functions. - * - * Each DRI driver must have one of these structures with all the pointers set - * to appropriate functions within the driver. - * - * When glXCreateContext() is called, for example, it'll call a helper function - * dri_util.c which in turn will jump through the \a CreateContext pointer in - * this structure. - */ -struct __DriverAPIRec { - const __DRIconfig **(*InitScreen) (__DRIscreen * priv); - - /** - * Screen destruction callback - */ - void (*DestroyScreen)(__DRIscreen *driScrnPriv); - - /** - * Context creation callback - */ - GLboolean (*CreateContext)(gl_api api, - const struct gl_config *glVis, - __DRIcontext *driContextPriv, - void *sharedContextPrivate); - - /** - * Context destruction callback - */ - void (*DestroyContext)(__DRIcontext *driContextPriv); - - /** - * Buffer (drawable) creation callback - */ - GLboolean (*CreateBuffer)(__DRIscreen *driScrnPriv, - __DRIdrawable *driDrawPriv, - const struct gl_config *glVis, - GLboolean pixmapBuffer); - - /** - * Buffer (drawable) destruction callback - */ - void (*DestroyBuffer)(__DRIdrawable *driDrawPriv); - - /** - * Buffer swapping callback - */ - void (*SwapBuffers)(__DRIdrawable *driDrawPriv); - - /** - * Context activation callback - */ - GLboolean (*MakeCurrent)(__DRIcontext *driContextPriv, - __DRIdrawable *driDrawPriv, - __DRIdrawable *driReadPriv); - - /** - * Context unbinding callback - */ - GLboolean (*UnbindContext)(__DRIcontext *driContextPriv); - - /** - * Retrieves statistics about buffer swap operations. Required if - * GLX_OML_sync_control or GLX_MESA_swap_frame_usage is supported. - */ - int (*GetSwapInfo)( __DRIdrawable *dPriv, __DRIswapInfo * sInfo ); - - - /** - * These are required if GLX_OML_sync_control is supported. - */ - /*@{*/ - int (*WaitForMSC)( __DRIdrawable *priv, int64_t target_msc, - int64_t divisor, int64_t remainder, - int64_t * msc ); - int (*WaitForSBC)( __DRIdrawable *priv, int64_t target_sbc, - int64_t * msc, int64_t * sbc ); - - int64_t (*SwapBuffersMSC)( __DRIdrawable *priv, int64_t target_msc, - int64_t divisor, int64_t remainder ); - /*@}*/ - void (*CopySubBuffer)(__DRIdrawable *driDrawPriv, - int x, int y, int w, int h); - - /** - * New version of GetMSC so we can pass drawable data to the low - * level DRM driver (e.g. pipe info). Required if - * GLX_SGI_video_sync or GLX_OML_sync_control is supported. - */ - int (*GetDrawableMSC) ( __DRIscreen * priv, - __DRIdrawable *drawablePrivate, - int64_t *count); - - - - /* DRI2 Entry point */ - const __DRIconfig **(*InitScreen2) (__DRIscreen * priv); -}; - -extern const struct __DriverAPIRec driDriverAPI; - - -struct __DRIswapInfoRec { - /** - * Number of swapBuffers operations that have been *completed*. - */ - uint64_t swap_count; - - /** - * Unadjusted system time of the last buffer swap. This is the time - * when the swap completed, not the time when swapBuffers was called. - */ - int64_t swap_ust; - - /** - * Number of swap operations that occurred after the swap deadline. That - * is if a swap happens more than swap_interval frames after the previous - * swap, it has missed its deadline. If swap_interval is 0, then the - * swap deadline is 1 frame after the previous swap. - */ - uint64_t swap_missed_count; - - /** - * Amount of time used by the last swap that missed its deadline. This - * is calculated as (__glXGetUST() - swap_ust) / (swap_interval * - * time_for_single_vrefresh)). If the actual value of swap_interval is - * 0, then 1 is used instead. If swap_missed_count is non-zero, this - * should be greater-than 1.0. - */ - float swap_missed_usage; -}; - - -/** - * Per-drawable private DRI driver information. - */ -struct __DRIdrawableRec { - /** - * Kernel drawable handle - */ - drm_drawable_t hHWDrawable; - - /** - * Driver's private drawable information. - * - * This structure is opaque. - */ - void *driverPrivate; - - /** - * Private data from the loader. We just hold on to it and pass - * it back when calling into loader provided functions. - */ - void *loaderPrivate; - - /** - * Reference count for number of context's currently bound to this - * drawable. - * - * Once it reaches zero, the drawable can be destroyed. - * - * \note This behavior will change with GLX 1.3. - */ - int refcount; - - /** - * Index of this drawable information in the SAREA. - */ - unsigned int index; - - /** - * Pointer to the "drawable has changed ID" stamp in the SAREA (or - * to dri2.stamp if DRI2 is being used). - */ - unsigned int *pStamp; - - /** - * Last value of the stamp. - * - * If this differs from the value stored at __DRIdrawable::pStamp, - * then the drawable information has been modified by the X server, and the - * drawable information (below) should be retrieved from the X server. - */ - unsigned int lastStamp; - - /** - * \name Drawable - * - * Drawable information used in software fallbacks. - */ - /*@{*/ - int x; - int y; - int w; - int h; - int numClipRects; - drm_clip_rect_t *pClipRects; - /*@}*/ - - /** - * \name Back and depthbuffer - * - * Information about the back and depthbuffer where different from above. - */ - /*@{*/ - int backX; - int backY; - int backClipRectType; - int numBackClipRects; - drm_clip_rect_t *pBackClipRects; - /*@}*/ - - /** - * \name Vertical blank tracking information - * Used for waiting on vertical blank events. - */ - /*@{*/ - unsigned int vblSeq; - unsigned int vblFlags; - /*@}*/ - - /** - * \name Monotonic MSC tracking - * - * Low level driver is responsible for updating msc_base and - * vblSeq values so that higher level code can calculate - * a new msc value or msc target for a WaitMSC call. The new value - * will be: - * msc = msc_base + get_vblank_count() - vblank_base; - * - * And for waiting on a value, core code will use: - * actual_target = target_msc - msc_base + vblank_base; - */ - /*@{*/ - int64_t vblank_base; - int64_t msc_base; - /*@}*/ - - /** - * Pointer to context to which this drawable is currently bound. - */ - __DRIcontext *driContextPriv; - - /** - * Pointer to screen on which this drawable was created. - */ - __DRIscreen *driScreenPriv; - - /** - * Controls swap interval as used by GLX_SGI_swap_control and - * GLX_MESA_swap_control. - */ - unsigned int swap_interval; - - struct { - unsigned int stamp; - drm_clip_rect_t clipRect; - } dri2; -}; - -/** - * Per-context private driver information. - */ -struct __DRIcontextRec { - /** - * Kernel context handle used to access the device lock. - */ - drm_context_t hHWContext; - - /** - * Device driver's private context data. This structure is opaque. - */ - void *driverPrivate; - - /** - * Pointer to drawable currently bound to this context for drawing. - */ - __DRIdrawable *driDrawablePriv; - - /** - * Pointer to drawable currently bound to this context for reading. - */ - __DRIdrawable *driReadablePriv; - - /** - * Pointer to screen on which this context was created. - */ - __DRIscreen *driScreenPriv; - - /** - * The loaders's private context data. This structure is opaque. - */ - void *loaderPrivate; - - struct { - int draw_stamp; - int read_stamp; - } dri2; -}; - -/** - * Per-screen private driver information. - */ -struct __DRIscreenRec { - /** - * Current screen's number - */ - int myNum; - - /** - * Callback functions into the hardware-specific DRI driver code. - */ - struct __DriverAPIRec DriverAPI; - - const __DRIextension **extensions; - /** - * DDX / 2D driver version information. - */ - __DRIversion ddx_version; - - /** - * DRI X extension version information. - */ - __DRIversion dri_version; - - /** - * DRM (kernel module) version information. - */ - __DRIversion drm_version; - - /** - * ID used when the client sets the drawable lock. - * - * The X server uses this value to detect if the client has died while - * holding the drawable lock. - */ - int drawLockID; - - /** - * File descriptor returned when the kernel device driver is opened. - * - * Used to: - * - authenticate client to kernel - * - map the frame buffer, SAREA, etc. - * - close the kernel device driver - */ - int fd; - - /** - * SAREA pointer - * - * Used to access: - * - the device lock - * - the device-independent per-drawable and per-context(?) information - */ - drm_sarea_t *pSAREA; - - /** - * \name Direct frame buffer access information - * Used for software fallbacks. - */ - /*@{*/ - unsigned char *pFB; - int fbSize; - int fbOrigin; - int fbStride; - int fbWidth; - int fbHeight; - int fbBPP; - /*@}*/ - - /** - * \name Device-dependent private information (stored in the SAREA). - * - * This data is accessed by the client driver only. - */ - /*@{*/ - void *pDevPriv; - int devPrivSize; - /*@}*/ - - /** - * Device-dependent private information (not stored in the SAREA). - * - * This pointer is never touched by the DRI layer. - */ -#ifdef __cplusplus - void *priv; -#else - void *private; -#endif - - /* Extensions provided by the loader. */ - const __DRIgetDrawableInfoExtension *getDrawableInfo; - const __DRIsystemTimeExtension *systemTime; - const __DRIdamageExtension *damage; - - struct { - /* Flag to indicate that this is a DRI2 screen. Many of the above - * fields will not be valid or initializaed in that case. */ - int enabled; - __DRIdri2LoaderExtension *loader; - __DRIimageLookupExtension *image; - __DRIuseInvalidateExtension *useInvalidate; - } dri2; - - /* The lock actually in use, old sarea or DRI2 */ - drmLock *lock; - - driOptionCache optionInfo; - driOptionCache optionCache; - unsigned int api_mask; - void *loaderPrivate; -}; - -extern void -__driUtilUpdateDrawableInfo(__DRIdrawable *pdp); - -extern float -driCalculateSwapUsage( __DRIdrawable *dPriv, - int64_t last_swap_ust, int64_t current_ust ); - -extern GLint -driIntersectArea( drm_clip_rect_t rect1, drm_clip_rect_t rect2 ); - -extern void -dri2InvalidateDrawable(__DRIdrawable *drawable); - -#endif /* _DRI_UTIL_H_ */ +/* + * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. + * 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, sub license, 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + */ + +/** + * \file dri_util.h + * DRI utility functions definitions. + * + * 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. + * + * \sa dri_util.c. + * + * \author Kevin E. Martin + * \author Brian Paul + */ + +#ifndef _DRI_UTIL_H_ +#define _DRI_UTIL_H_ + +#include +#include +#include +#include +#include "xmlconfig.h" +#include "main/glheader.h" +#include "main/mtypes.h" +#include "GL/internal/dri_interface.h" + +#define GLX_BAD_CONTEXT 5 + +typedef struct __DRIswapInfoRec __DRIswapInfo; + +/** + * Extensions. + */ +extern const __DRIlegacyExtension driLegacyExtension; +extern const __DRIcoreExtension driCoreExtension; +extern const __DRIdri2Extension driDRI2Extension; +extern const __DRIextension driReadDrawableExtension; +extern const __DRIcopySubBufferExtension driCopySubBufferExtension; +extern const __DRIswapControlExtension driSwapControlExtension; +extern const __DRImediaStreamCounterExtension driMediaStreamCounterExtension; +extern const __DRI2configQueryExtension dri2ConfigQueryExtension; + +/** + * Used by DRI_VALIDATE_DRAWABLE_INFO + */ +#define DRI_VALIDATE_DRAWABLE_INFO_ONCE(pDrawPriv) \ + do { \ + if (*(pDrawPriv->pStamp) != pDrawPriv->lastStamp) { \ + __driUtilUpdateDrawableInfo(pDrawPriv); \ + } \ + } while (0) + + +/** + * Utility macro to validate the drawable information. + * + * See __DRIdrawable::pStamp and __DRIdrawable::lastStamp. + */ +#define DRI_VALIDATE_DRAWABLE_INFO(psp, pdp) \ +do { \ + while (*(pdp->pStamp) != pdp->lastStamp) { \ + register unsigned int hwContext = psp->pSAREA->lock.lock & \ + ~(DRM_LOCK_HELD | DRM_LOCK_CONT); \ + DRM_UNLOCK(psp->fd, &psp->pSAREA->lock, hwContext); \ + \ + DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); \ + DRI_VALIDATE_DRAWABLE_INFO_ONCE(pdp); \ + DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); \ + \ + DRM_LIGHT_LOCK(psp->fd, &psp->pSAREA->lock, hwContext); \ + } \ +} while (0) + +/** + * Same as above, but for two drawables simultaneously. + * + */ + +#define DRI_VALIDATE_TWO_DRAWABLES_INFO(psp, pdp, prp) \ +do { \ + while (*((pdp)->pStamp) != (pdp)->lastStamp || \ + *((prp)->pStamp) != (prp)->lastStamp) { \ + register unsigned int hwContext = (psp)->pSAREA->lock.lock & \ + ~(DRM_LOCK_HELD | DRM_LOCK_CONT); \ + DRM_UNLOCK((psp)->fd, &(psp)->pSAREA->lock, hwContext); \ + \ + DRM_SPINLOCK(&(psp)->pSAREA->drawable_lock, (psp)->drawLockID); \ + DRI_VALIDATE_DRAWABLE_INFO_ONCE(pdp); \ + DRI_VALIDATE_DRAWABLE_INFO_ONCE(prp); \ + DRM_SPINUNLOCK(&(psp)->pSAREA->drawable_lock, (psp)->drawLockID); \ + \ + DRM_LIGHT_LOCK((psp)->fd, &(psp)->pSAREA->lock, hwContext); \ + } \ +} while (0) + + +/** + * Driver callback functions. + * + * Each DRI driver must have one of these structures with all the pointers set + * to appropriate functions within the driver. + * + * When glXCreateContext() is called, for example, it'll call a helper function + * dri_util.c which in turn will jump through the \a CreateContext pointer in + * this structure. + */ +struct __DriverAPIRec { + const __DRIconfig **(*InitScreen) (__DRIscreen * priv); + + /** + * Screen destruction callback + */ + void (*DestroyScreen)(__DRIscreen *driScrnPriv); + + /** + * Context creation callback + */ + GLboolean (*CreateContext)(gl_api api, + const struct gl_config *glVis, + __DRIcontext *driContextPriv, + void *sharedContextPrivate); + + /** + * Context destruction callback + */ + void (*DestroyContext)(__DRIcontext *driContextPriv); + + /** + * Buffer (drawable) creation callback + */ + GLboolean (*CreateBuffer)(__DRIscreen *driScrnPriv, + __DRIdrawable *driDrawPriv, + const struct gl_config *glVis, + GLboolean pixmapBuffer); + + /** + * Buffer (drawable) destruction callback + */ + void (*DestroyBuffer)(__DRIdrawable *driDrawPriv); + + /** + * Buffer swapping callback + */ + void (*SwapBuffers)(__DRIdrawable *driDrawPriv); + + /** + * Context activation callback + */ + GLboolean (*MakeCurrent)(__DRIcontext *driContextPriv, + __DRIdrawable *driDrawPriv, + __DRIdrawable *driReadPriv); + + /** + * Context unbinding callback + */ + GLboolean (*UnbindContext)(__DRIcontext *driContextPriv); + + /** + * Retrieves statistics about buffer swap operations. Required if + * GLX_OML_sync_control or GLX_MESA_swap_frame_usage is supported. + */ + int (*GetSwapInfo)( __DRIdrawable *dPriv, __DRIswapInfo * sInfo ); + + + /** + * These are required if GLX_OML_sync_control is supported. + */ + /*@{*/ + int (*WaitForMSC)( __DRIdrawable *priv, int64_t target_msc, + int64_t divisor, int64_t remainder, + int64_t * msc ); + int (*WaitForSBC)( __DRIdrawable *priv, int64_t target_sbc, + int64_t * msc, int64_t * sbc ); + + int64_t (*SwapBuffersMSC)( __DRIdrawable *priv, int64_t target_msc, + int64_t divisor, int64_t remainder ); + /*@}*/ + void (*CopySubBuffer)(__DRIdrawable *driDrawPriv, + int x, int y, int w, int h); + + /** + * New version of GetMSC so we can pass drawable data to the low + * level DRM driver (e.g. pipe info). Required if + * GLX_SGI_video_sync or GLX_OML_sync_control is supported. + */ + int (*GetDrawableMSC) ( __DRIscreen * priv, + __DRIdrawable *drawablePrivate, + int64_t *count); + + + + /* DRI2 Entry point */ + const __DRIconfig **(*InitScreen2) (__DRIscreen * priv); + + __DRIbuffer *(*AllocateBuffer) (__DRIscreen *screenPrivate, + unsigned int attachment, + unsigned int format, + int width, int height); + void (*ReleaseBuffer) (__DRIscreen *screenPrivate, __DRIbuffer *buffer); +}; + +extern const struct __DriverAPIRec driDriverAPI; + + +struct __DRIswapInfoRec { + /** + * Number of swapBuffers operations that have been *completed*. + */ + uint64_t swap_count; + + /** + * Unadjusted system time of the last buffer swap. This is the time + * when the swap completed, not the time when swapBuffers was called. + */ + int64_t swap_ust; + + /** + * Number of swap operations that occurred after the swap deadline. That + * is if a swap happens more than swap_interval frames after the previous + * swap, it has missed its deadline. If swap_interval is 0, then the + * swap deadline is 1 frame after the previous swap. + */ + uint64_t swap_missed_count; + + /** + * Amount of time used by the last swap that missed its deadline. This + * is calculated as (__glXGetUST() - swap_ust) / (swap_interval * + * time_for_single_vrefresh)). If the actual value of swap_interval is + * 0, then 1 is used instead. If swap_missed_count is non-zero, this + * should be greater-than 1.0. + */ + float swap_missed_usage; +}; + + +/** + * Per-drawable private DRI driver information. + */ +struct __DRIdrawableRec { + /** + * Kernel drawable handle + */ + drm_drawable_t hHWDrawable; + + /** + * Driver's private drawable information. + * + * This structure is opaque. + */ + void *driverPrivate; + + /** + * Private data from the loader. We just hold on to it and pass + * it back when calling into loader provided functions. + */ + void *loaderPrivate; + + /** + * Reference count for number of context's currently bound to this + * drawable. + * + * Once it reaches zero, the drawable can be destroyed. + * + * \note This behavior will change with GLX 1.3. + */ + int refcount; + + /** + * Index of this drawable information in the SAREA. + */ + unsigned int index; + + /** + * Pointer to the "drawable has changed ID" stamp in the SAREA (or + * to dri2.stamp if DRI2 is being used). + */ + unsigned int *pStamp; + + /** + * Last value of the stamp. + * + * If this differs from the value stored at __DRIdrawable::pStamp, + * then the drawable information has been modified by the X server, and the + * drawable information (below) should be retrieved from the X server. + */ + unsigned int lastStamp; + + /** + * \name Drawable + * + * Drawable information used in software fallbacks. + */ + /*@{*/ + int x; + int y; + int w; + int h; + int numClipRects; + drm_clip_rect_t *pClipRects; + /*@}*/ + + /** + * \name Back and depthbuffer + * + * Information about the back and depthbuffer where different from above. + */ + /*@{*/ + int backX; + int backY; + int backClipRectType; + int numBackClipRects; + drm_clip_rect_t *pBackClipRects; + /*@}*/ + + /** + * \name Vertical blank tracking information + * Used for waiting on vertical blank events. + */ + /*@{*/ + unsigned int vblSeq; + unsigned int vblFlags; + /*@}*/ + + /** + * \name Monotonic MSC tracking + * + * Low level driver is responsible for updating msc_base and + * vblSeq values so that higher level code can calculate + * a new msc value or msc target for a WaitMSC call. The new value + * will be: + * msc = msc_base + get_vblank_count() - vblank_base; + * + * And for waiting on a value, core code will use: + * actual_target = target_msc - msc_base + vblank_base; + */ + /*@{*/ + int64_t vblank_base; + int64_t msc_base; + /*@}*/ + + /** + * Pointer to context to which this drawable is currently bound. + */ + __DRIcontext *driContextPriv; + + /** + * Pointer to screen on which this drawable was created. + */ + __DRIscreen *driScreenPriv; + + /** + * Controls swap interval as used by GLX_SGI_swap_control and + * GLX_MESA_swap_control. + */ + unsigned int swap_interval; + + struct { + unsigned int stamp; + drm_clip_rect_t clipRect; + } dri2; +}; + +/** + * Per-context private driver information. + */ +struct __DRIcontextRec { + /** + * Kernel context handle used to access the device lock. + */ + drm_context_t hHWContext; + + /** + * Device driver's private context data. This structure is opaque. + */ + void *driverPrivate; + + /** + * Pointer to drawable currently bound to this context for drawing. + */ + __DRIdrawable *driDrawablePriv; + + /** + * Pointer to drawable currently bound to this context for reading. + */ + __DRIdrawable *driReadablePriv; + + /** + * Pointer to screen on which this context was created. + */ + __DRIscreen *driScreenPriv; + + /** + * The loaders's private context data. This structure is opaque. + */ + void *loaderPrivate; + + struct { + int draw_stamp; + int read_stamp; + } dri2; +}; + +/** + * Per-screen private driver information. + */ +struct __DRIscreenRec { + /** + * Current screen's number + */ + int myNum; + + /** + * Callback functions into the hardware-specific DRI driver code. + */ + struct __DriverAPIRec DriverAPI; + + const __DRIextension **extensions; + /** + * DDX / 2D driver version information. + */ + __DRIversion ddx_version; + + /** + * DRI X extension version information. + */ + __DRIversion dri_version; + + /** + * DRM (kernel module) version information. + */ + __DRIversion drm_version; + + /** + * ID used when the client sets the drawable lock. + * + * The X server uses this value to detect if the client has died while + * holding the drawable lock. + */ + int drawLockID; + + /** + * File descriptor returned when the kernel device driver is opened. + * + * Used to: + * - authenticate client to kernel + * - map the frame buffer, SAREA, etc. + * - close the kernel device driver + */ + int fd; + + /** + * SAREA pointer + * + * Used to access: + * - the device lock + * - the device-independent per-drawable and per-context(?) information + */ + drm_sarea_t *pSAREA; + + /** + * \name Direct frame buffer access information + * Used for software fallbacks. + */ + /*@{*/ + unsigned char *pFB; + int fbSize; + int fbOrigin; + int fbStride; + int fbWidth; + int fbHeight; + int fbBPP; + /*@}*/ + + /** + * \name Device-dependent private information (stored in the SAREA). + * + * This data is accessed by the client driver only. + */ + /*@{*/ + void *pDevPriv; + int devPrivSize; + /*@}*/ + + /** + * Device-dependent private information (not stored in the SAREA). + * + * This pointer is never touched by the DRI layer. + */ +#ifdef __cplusplus + void *priv; +#else + void *private; +#endif + + /* Extensions provided by the loader. */ + const __DRIgetDrawableInfoExtension *getDrawableInfo; + const __DRIsystemTimeExtension *systemTime; + const __DRIdamageExtension *damage; + + struct { + /* Flag to indicate that this is a DRI2 screen. Many of the above + * fields will not be valid or initializaed in that case. */ + int enabled; + __DRIdri2LoaderExtension *loader; + __DRIimageLookupExtension *image; + __DRIuseInvalidateExtension *useInvalidate; + } dri2; + + /* The lock actually in use, old sarea or DRI2 */ + drmLock *lock; + + driOptionCache optionInfo; + driOptionCache optionCache; + unsigned int api_mask; + void *loaderPrivate; +}; + +extern void +__driUtilUpdateDrawableInfo(__DRIdrawable *pdp); + +extern float +driCalculateSwapUsage( __DRIdrawable *dPriv, + int64_t last_swap_ust, int64_t current_ust ); + +extern GLint +driIntersectArea( drm_clip_rect_t rect1, drm_clip_rect_t rect2 ); + +extern void +dri2InvalidateDrawable(__DRIdrawable *drawable); + +#endif /* _DRI_UTIL_H_ */ diff --git a/mesalib/src/mesa/drivers/dri/swrast/swrast.c b/mesalib/src/mesa/drivers/dri/swrast/swrast.c index 144b187c1..719b406ec 100644 --- a/mesalib/src/mesa/drivers/dri/swrast/swrast.c +++ b/mesalib/src/mesa/drivers/dri/swrast/swrast.c @@ -651,7 +651,7 @@ dri_create_context(gl_api api, mesaCtx = &ctx->Base; /* basic context setup */ - if (!_mesa_initialize_context_for_api(mesaCtx, api, visual, sharedCtx, &functions, (void *) cPriv)) { + if (!_mesa_initialize_context(mesaCtx, api, visual, sharedCtx, &functions, (void *) cPriv)) { goto context_fail; } diff --git a/mesalib/src/mesa/drivers/windows/gdi/wmesa.c b/mesalib/src/mesa/drivers/windows/gdi/wmesa.c index a30326c0c..4a8b1b283 100644 --- a/mesalib/src/mesa/drivers/windows/gdi/wmesa.c +++ b/mesalib/src/mesa/drivers/windows/gdi/wmesa.c @@ -1,1661 +1,1662 @@ -/* - * Windows (Win32/Win64) device driver for Mesa - * - */ - -#include "wmesadef.h" -#include "colors.h" -#include -#include -#include "context.h" -#include "extensions.h" -#include "framebuffer.h" -#include "renderbuffer.h" -#include "drivers/common/driverfuncs.h" -#include "drivers/common/meta.h" -#include "vbo/vbo.h" -#include "swrast/swrast.h" -#include "swrast_setup/swrast_setup.h" -#include "tnl/tnl.h" -#include "tnl/t_context.h" -#include "tnl/t_pipeline.h" - - -/* linked list of our Framebuffers (windows) */ -static WMesaFramebuffer FirstFramebuffer = NULL; - - -/** - * Create a new WMesaFramebuffer object which will correspond to the - * given HDC (Window handle). - */ -WMesaFramebuffer -wmesa_new_framebuffer(HDC hdc, struct gl_config *visual) -{ - WMesaFramebuffer pwfb - = (WMesaFramebuffer) malloc(sizeof(struct wmesa_framebuffer)); - if (pwfb) { - _mesa_initialize_window_framebuffer(&pwfb->Base, visual); - pwfb->hDC = hdc; - /* insert at head of list */ - pwfb->next = FirstFramebuffer; - FirstFramebuffer = pwfb; - } - return pwfb; -} - -/** - * Given an hdc, free the corresponding WMesaFramebuffer - */ -void -wmesa_free_framebuffer(HDC hdc) -{ - WMesaFramebuffer pwfb, prev; - for (pwfb = FirstFramebuffer; pwfb; pwfb = pwfb->next) { - if (pwfb->hDC == hdc) - break; - prev = pwfb; - } - if (pwfb) { - struct gl_framebuffer *fb; - if (pwfb == FirstFramebuffer) - FirstFramebuffer = pwfb->next; - else - prev->next = pwfb->next; - fb = &pwfb->Base; - _mesa_reference_framebuffer(&fb, NULL); - } -} - -/** - * Given an hdc, return the corresponding WMesaFramebuffer - */ -WMesaFramebuffer -wmesa_lookup_framebuffer(HDC hdc) -{ - WMesaFramebuffer pwfb; - for (pwfb = FirstFramebuffer; pwfb; pwfb = pwfb->next) { - if (pwfb->hDC == hdc) - return pwfb; - } - return NULL; -} - - -/** - * Given a struct gl_framebuffer, return the corresponding WMesaFramebuffer. - */ -static WMesaFramebuffer wmesa_framebuffer(struct gl_framebuffer *fb) -{ - return (WMesaFramebuffer) fb; -} - - -/** - * Given a struct gl_context, return the corresponding WMesaContext. - */ -static WMesaContext wmesa_context(const struct gl_context *ctx) -{ - return (WMesaContext) ctx; -} - - -/* - * Every driver should implement a GetString function in order to - * return a meaningful GL_RENDERER string. - */ -static const GLubyte *wmesa_get_string(struct gl_context *ctx, GLenum name) -{ - return (name == GL_RENDERER) ? - (GLubyte *) "Mesa Windows GDI Driver" : NULL; -} - - -/* - * Determine the pixel format based on the pixel size. - */ -static void wmSetPixelFormat(WMesaFramebuffer pwfb, HDC hDC) -{ - pwfb->cColorBits = GetDeviceCaps(hDC, BITSPIXEL); - - /* Only 16 and 32 bit targets are supported now */ - assert(pwfb->cColorBits == 0 || - pwfb->cColorBits == 16 || - pwfb->cColorBits == 24 || - pwfb->cColorBits == 32); - - switch(pwfb->cColorBits){ - case 8: - pwfb->pixelformat = PF_INDEX8; - break; - case 16: - pwfb->pixelformat = PF_5R6G5B; - break; - case 24: - case 32: - pwfb->pixelformat = PF_8R8G8B; - break; - default: - pwfb->pixelformat = PF_BADFORMAT; - } -} - - -/** - * Create DIB for back buffer. - * We write into this memory with the span routines and then blit it - * to the window on a buffer swap. - */ -BOOL wmCreateBackingStore(WMesaFramebuffer pwfb, long lxSize, long lySize) -{ - HDC hdc = pwfb->hDC; - LPBITMAPINFO pbmi = &(pwfb->bmi); - HDC hic; - - pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - pbmi->bmiHeader.biWidth = lxSize; - pbmi->bmiHeader.biHeight= -lySize; - pbmi->bmiHeader.biPlanes = 1; - pbmi->bmiHeader.biBitCount = GetDeviceCaps(pwfb->hDC, BITSPIXEL); - pbmi->bmiHeader.biCompression = BI_RGB; - pbmi->bmiHeader.biSizeImage = 0; - pbmi->bmiHeader.biXPelsPerMeter = 0; - pbmi->bmiHeader.biYPelsPerMeter = 0; - pbmi->bmiHeader.biClrUsed = 0; - pbmi->bmiHeader.biClrImportant = 0; - - pwfb->cColorBits = pbmi->bmiHeader.biBitCount; - pwfb->ScanWidth = (lxSize * (pwfb->cColorBits / 8) + 3) & ~3; - - hic = CreateIC("display", NULL, NULL, NULL); - pwfb->dib_hDC = CreateCompatibleDC(hic); - - pwfb->hbmDIB = CreateDIBSection(hic, - &pwfb->bmi, - DIB_RGB_COLORS, - (void **)&(pwfb->pbPixels), - 0, - 0); - pwfb->hOldBitmap = SelectObject(pwfb->dib_hDC, pwfb->hbmDIB); - - DeleteDC(hic); - - wmSetPixelFormat(pwfb, pwfb->hDC); - return TRUE; -} - - -static wmDeleteBackingStore(WMesaFramebuffer pwfb) -{ - if (pwfb->hbmDIB) { - SelectObject(pwfb->dib_hDC, pwfb->hOldBitmap); - DeleteDC(pwfb->dib_hDC); - DeleteObject(pwfb->hbmDIB); - } -} - - -/** - * Find the width and height of the window named by hdc. - */ -static void -get_window_size(HDC hdc, GLuint *width, GLuint *height) -{ - if (WindowFromDC(hdc)) { - RECT rect; - GetClientRect(WindowFromDC(hdc), &rect); - *width = rect.right - rect.left; - *height = rect.bottom - rect.top; - } - else { /* Memory context */ - /* From contributed code - use the size of the desktop - * for the size of a memory context (?) */ - *width = GetDeviceCaps(hdc, HORZRES); - *height = GetDeviceCaps(hdc, VERTRES); - } -} - - -static void -wmesa_get_buffer_size(struct gl_framebuffer *buffer, GLuint *width, GLuint *height) -{ - WMesaFramebuffer pwfb = wmesa_framebuffer(buffer); - get_window_size(pwfb->hDC, width, height); -} - - -static void wmesa_flush(struct gl_context *ctx) -{ - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->WinSysDrawBuffer); - - if (ctx->Visual.doubleBufferMode == 1) { - BitBlt(pwfb->hDC, 0, 0, pwfb->Base.Width, pwfb->Base.Height, - pwfb->dib_hDC, 0, 0, SRCCOPY); - } - else { - /* Do nothing for single buffer */ - } -} - - -/**********************************************************************/ -/***** CLEAR Functions *****/ -/**********************************************************************/ - -/* If we do not implement these, Mesa clears the buffers via the pixel - * span writing interface, which is very slow for a clear operation. - */ - -/* - * Set the color used to clear the color buffer. - */ -static void clear_color(struct gl_context *ctx, const GLfloat color[4]) -{ - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - GLubyte col[3]; - UINT bytesPerPixel = pwfb->cColorBits / 8; - - CLAMPED_FLOAT_TO_UBYTE(col[0], color[0]); - CLAMPED_FLOAT_TO_UBYTE(col[1], color[1]); - CLAMPED_FLOAT_TO_UBYTE(col[2], color[2]); - pwc->clearColorRef = RGB(col[0], col[1], col[2]); - DeleteObject(pwc->clearPen); - DeleteObject(pwc->clearBrush); - pwc->clearPen = CreatePen(PS_SOLID, 1, pwc->clearColorRef); - pwc->clearBrush = CreateSolidBrush(pwc->clearColorRef); -} - - -/* - * Clear the specified region of the color buffer using the clear color - * or index as specified by one of the two functions above. - * - * This procedure clears either the front and/or the back COLOR buffers. - * Only the "left" buffer is cleared since we are not stereo. - * Clearing of the other non-color buffers is left to the swrast. - */ - -static void clear(struct gl_context *ctx, GLbitfield mask) -{ -#define FLIP(Y) (ctx->DrawBuffer->Height - (Y) - 1) - const GLint x = ctx->DrawBuffer->_Xmin; - const GLint y = ctx->DrawBuffer->_Ymin; - const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; - const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; - - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - int done = 0; - - /* Let swrast do all the work if the masks are not set to - * clear all channels. */ - if (!ctx->Color.ColorMask[0][0] || - !ctx->Color.ColorMask[0][1] || - !ctx->Color.ColorMask[0][2] || - !ctx->Color.ColorMask[0][3]) { - _swrast_Clear(ctx, mask); - return; - } - - /* Back buffer */ - if (mask & BUFFER_BIT_BACK_LEFT) { - - int i, rowSize; - UINT bytesPerPixel = pwfb->cColorBits / 8; - LPBYTE lpb, clearRow; - LPWORD lpw; - BYTE bColor; - WORD wColor; - BYTE r, g, b; - DWORD dwColor; - LPDWORD lpdw; - - /* Try for a fast clear - clearing entire buffer with a single - * byte value. */ - if (width == ctx->DrawBuffer->Width && - height == ctx->DrawBuffer->Height) { /* entire buffer */ - /* Now check for an easy clear value */ - switch (bytesPerPixel) { - case 1: - bColor = BGR8(GetRValue(pwc->clearColorRef), - GetGValue(pwc->clearColorRef), - GetBValue(pwc->clearColorRef)); - memset(pwfb->pbPixels, bColor, - pwfb->ScanWidth * height); - done = 1; - break; - case 2: - wColor = BGR16(GetRValue(pwc->clearColorRef), - GetGValue(pwc->clearColorRef), - GetBValue(pwc->clearColorRef)); - if (((wColor >> 8) & 0xff) == (wColor & 0xff)) { - memset(pwfb->pbPixels, wColor & 0xff, - pwfb->ScanWidth * height); - done = 1; - } - break; - case 3: - /* fall through */ - case 4: - if (GetRValue(pwc->clearColorRef) == - GetGValue(pwc->clearColorRef) && - GetRValue(pwc->clearColorRef) == - GetBValue(pwc->clearColorRef)) { - memset(pwfb->pbPixels, - GetRValue(pwc->clearColorRef), - pwfb->ScanWidth * height); - done = 1; - } - break; - default: - break; - } - } /* all */ - - if (!done) { - /* Need to clear a row at a time. Begin by setting the first - * row in the area to be cleared to the clear color. */ - - clearRow = pwfb->pbPixels + - pwfb->ScanWidth * FLIP(y) + - bytesPerPixel * x; - switch (bytesPerPixel) { - case 1: - lpb = clearRow; - bColor = BGR8(GetRValue(pwc->clearColorRef), - GetGValue(pwc->clearColorRef), - GetBValue(pwc->clearColorRef)); - memset(lpb, bColor, width); - break; - case 2: - lpw = (LPWORD)clearRow; - wColor = BGR16(GetRValue(pwc->clearColorRef), - GetGValue(pwc->clearColorRef), - GetBValue(pwc->clearColorRef)); - for (i=0; iclearColorRef); - g = GetGValue(pwc->clearColorRef); - b = GetBValue(pwc->clearColorRef); - for (i=0; iclearColorRef), - GetGValue(pwc->clearColorRef), - GetBValue(pwc->clearColorRef)); - for (i=0; iScanWidth; - rowSize = width * bytesPerPixel; - for (i=1; iScanWidth; - } - } /* not done */ - mask &= ~BUFFER_BIT_BACK_LEFT; - } /* back buffer */ - - /* front buffer */ - if (mask & BUFFER_BIT_FRONT_LEFT) { - HDC DC = pwc->hDC; - HPEN Old_Pen = SelectObject(DC, pwc->clearPen); - HBRUSH Old_Brush = SelectObject(DC, pwc->clearBrush); - Rectangle(DC, - x, - FLIP(y) + 1, - x + width + 1, - FLIP(y) - height + 1); - SelectObject(DC, Old_Pen); - SelectObject(DC, Old_Brush); - mask &= ~BUFFER_BIT_FRONT_LEFT; - } /* front buffer */ - - /* Call swrast if there is anything left to clear (like DEPTH) */ - if (mask) - _swrast_Clear(ctx, mask); - -#undef FLIP -} - - -/**********************************************************************/ -/***** PIXEL Functions *****/ -/**********************************************************************/ - -#define FLIP(Y) (rb->Height - (Y) - 1) - - -/** - ** Front Buffer reading/writing - ** These are slow, but work with all non-indexed visual types. - **/ - -/* Write a horizontal span of RGBA color pixels with a boolean mask. */ -static void write_rgba_span_front(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLubyte rgba[][4], - const GLubyte mask[] ) -{ - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_lookup_framebuffer(pwc->hDC); - CONST BITMAPINFO bmi= - { - { - sizeof(BITMAPINFOHEADER), - n, 1, 1, 32, BI_RGB, 0, 1, 1, 0, 0 - } - }; - HBITMAP bmp=0; - HDC mdc=0; - typedef union - { - unsigned i; - struct { - unsigned b:8, g:8, r:8, a:8; - }; - } BGRA; - BGRA *bgra, c; - GLuint i; - - if (n < 16) { // the value 16 is just guessed - y=FLIP(y); - if (mask) { - for (i=0; ihDC, x+i, y, - RGB(rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP])); - } - else { - for (i=0; ihDC, x+i, y, - RGB(rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP])); - } - } - else { - if (!pwfb) { - _mesa_problem(NULL, "wmesa: write_rgba_span_front on unknown hdc"); - return; - } - bgra=malloc(n*sizeof(BGRA)); - if (!bgra) { - _mesa_problem(NULL, "wmesa: write_rgba_span_front: out of memory"); - return; - } - c.a=0; - if (mask) { - for (i=0; ihDC); - SelectObject(mdc, bmp); - y=FLIP(y); - BitBlt(pwfb->hDC, x, y, n, 1, mdc, 0, 0, SRCCOPY); - SelectObject(mdc, 0); - DeleteObject(bmp); - DeleteDC(mdc); - free(bgra); - } -} - -/* Write a horizontal span of RGB color pixels with a boolean mask. */ -static void write_rgb_span_front(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLubyte rgb[][3], - const GLubyte mask[] ) -{ - WMesaContext pwc = wmesa_context(ctx); - GLuint i; - - (void) ctx; - y=FLIP(y); - if (mask) { - for (i=0; ihDC, x+i, y, RGB(rgb[i][RCOMP], rgb[i][GCOMP], - rgb[i][BCOMP])); - } - else { - for (i=0; ihDC, x+i, y, RGB(rgb[i][RCOMP], rgb[i][GCOMP], - rgb[i][BCOMP])); - } - -} - -/* - * Write a horizontal span of pixels with a boolean mask. The current color - * is used for all pixels. - */ -static void write_mono_rgba_span_front(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLchan color[4], - const GLubyte mask[]) -{ - GLuint i; - WMesaContext pwc = wmesa_context(ctx); - COLORREF colorref; - - (void) ctx; - colorref = RGB(color[RCOMP], color[GCOMP], color[BCOMP]); - y=FLIP(y); - if (mask) { - for (i=0; ihDC, x+i, y, colorref); - } - else - for (i=0; ihDC, x+i, y, colorref); - -} - -/* Write an array of RGBA pixels with a boolean mask. */ -static void write_rgba_pixels_front(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, - const GLint x[], const GLint y[], - const GLubyte rgba[][4], - const GLubyte mask[] ) -{ - GLuint i; - WMesaContext pwc = wmesa_context(ctx); - (void) ctx; - for (i=0; ihDC, x[i], FLIP(y[i]), - RGB(rgba[i][RCOMP], rgba[i][GCOMP], - rgba[i][BCOMP])); -} - - - -/* - * Write an array of pixels with a boolean mask. The current color - * is used for all pixels. - */ -static void write_mono_rgba_pixels_front(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, - const GLint x[], const GLint y[], - const GLchan color[4], - const GLubyte mask[] ) -{ - GLuint i; - WMesaContext pwc = wmesa_context(ctx); - COLORREF colorref; - (void) ctx; - colorref = RGB(color[RCOMP], color[GCOMP], color[BCOMP]); - for (i=0; ihDC, x[i], FLIP(y[i]), colorref); -} - -/* Read a horizontal span of color pixels. */ -static void read_rgba_span_front(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - GLubyte rgba[][4] ) -{ - WMesaContext pwc = wmesa_context(ctx); - GLuint i; - COLORREF Color; - y = FLIP(y); - for (i=0; ihDC, x+i, y); - rgba[i][RCOMP] = GetRValue(Color); - rgba[i][GCOMP] = GetGValue(Color); - rgba[i][BCOMP] = GetBValue(Color); - rgba[i][ACOMP] = 255; - } -} - - -/* Read an array of color pixels. */ -static void read_rgba_pixels_front(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, const GLint x[], const GLint y[], - GLubyte rgba[][4]) -{ - WMesaContext pwc = wmesa_context(ctx); - GLuint i; - COLORREF Color; - for (i=0; ihDC, x[i], y2); - rgba[i][RCOMP] = GetRValue(Color); - rgba[i][GCOMP] = GetGValue(Color); - rgba[i][BCOMP] = GetBValue(Color); - rgba[i][ACOMP] = 255; - } -} - -/*********************************************************************/ - -/* DOUBLE BUFFER 32-bit */ - -#define WMSETPIXEL32(pwc, y, x, r, g, b) { \ -LPDWORD lpdw = ((LPDWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); \ -*lpdw = BGR32((r),(g),(b)); } - - - -/* Write a horizontal span of RGBA color pixels with a boolean mask. */ -static void write_rgba_span_32(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLubyte rgba[][4], - const GLubyte mask[] ) -{ - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - GLuint i; - LPDWORD lpdw; - - (void) ctx; - - y=FLIP(y); - lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; - if (mask) { - for (i=0; iDrawBuffer); - GLuint i; - LPDWORD lpdw; - - (void) ctx; - - y=FLIP(y); - lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; - if (mask) { - for (i=0; iDrawBuffer); - lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; - y=FLIP(y); - pixel = BGR32(color[RCOMP], color[GCOMP], color[BCOMP]); - if (mask) { - for (i=0; iDrawBuffer); - for (i=0; iDrawBuffer); - for (i=0; iDrawBuffer); - - y = FLIP(y); - lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; - for (i=0; i> 16); - rgba[i][GCOMP] = (GLubyte)((pixel & 0x0000ff00) >> 8); - rgba[i][BCOMP] = (GLubyte)(pixel & 0x000000ff); - rgba[i][ACOMP] = 255; - } -} - - -/* Read an array of color pixels. */ -static void read_rgba_pixels_32(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, const GLint x[], const GLint y[], - GLubyte rgba[][4]) -{ - GLuint i; - DWORD pixel; - LPDWORD lpdw; - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - - for (i=0; ipbPixels + pwfb->ScanWidth * y2)) + x[i]; - pixel = *lpdw; - rgba[i][RCOMP] = (GLubyte)((pixel & 0x00ff0000) >> 16); - rgba[i][GCOMP] = (GLubyte)((pixel & 0x0000ff00) >> 8); - rgba[i][BCOMP] = (GLubyte)(pixel & 0x000000ff); - rgba[i][ACOMP] = 255; - } -} - - -/*********************************************************************/ - -/* DOUBLE BUFFER 24-bit */ - -#define WMSETPIXEL24(pwc, y, x, r, g, b) { \ -LPBYTE lpb = ((LPBYTE)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (3 * x)); \ -lpb[0] = (b); \ -lpb[1] = (g); \ -lpb[2] = (r); } - -/* Write a horizontal span of RGBA color pixels with a boolean mask. */ -static void write_rgba_span_24(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLubyte rgba[][4], - const GLubyte mask[] ) -{ - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - GLuint i; - LPBYTE lpb; - - (void) ctx; - - y=FLIP(y); - lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x); - if (mask) { - for (i=0; iDrawBuffer); - GLuint i; - LPBYTE lpb; - - (void) ctx; - - y=FLIP(y); - lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x); - if (mask) { - for (i=0; iDrawBuffer); - lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x); - y=FLIP(y); - if (mask) { - for (i=0; iDrawBuffer); - for (i=0; iDrawBuffer); - for (i=0; iDrawBuffer); - - y = FLIP(y); - lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x); - for (i=0; iDrawBuffer); - - for (i=0; ipbPixels + pwfb->ScanWidth * y2)) + (3 * x[i]); - rgba[i][RCOMP] = lpb[3*i+2]; - rgba[i][GCOMP] = lpb[3*i+1]; - rgba[i][BCOMP] = lpb[3*i]; - rgba[i][ACOMP] = 255; - } -} - - -/*********************************************************************/ - -/* DOUBLE BUFFER 16-bit */ - -#define WMSETPIXEL16(pwc, y, x, r, g, b) { \ -LPWORD lpw = ((LPWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); \ -*lpw = BGR16((r),(g),(b)); } - - - -/* Write a horizontal span of RGBA color pixels with a boolean mask. */ -static void write_rgba_span_16(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLubyte rgba[][4], - const GLubyte mask[] ) -{ - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - GLuint i; - LPWORD lpw; - - (void) ctx; - - y=FLIP(y); - lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; - if (mask) { - for (i=0; iDrawBuffer); - GLuint i; - LPWORD lpw; - - (void) ctx; - - y=FLIP(y); - lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; - if (mask) { - for (i=0; iDrawBuffer); - (void) ctx; - lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; - y=FLIP(y); - pixel = BGR16(color[RCOMP], color[GCOMP], color[BCOMP]); - if (mask) { - for (i=0; iDrawBuffer); - (void) ctx; - for (i=0; iDrawBuffer); - (void) ctx; - for (i=0; iDrawBuffer); - - y = FLIP(y); - lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; - for (i=0; i> 7; - rgba[i][GCOMP] = (pixel & 0x03e0) >> 2; - rgba[i][BCOMP] = (pixel & 0x001f) << 3; - rgba[i][ACOMP] = 255; - } -} - - -/* Read an array of color pixels. */ -static void read_rgba_pixels_16(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, const GLint x[], const GLint y[], - GLubyte rgba[][4]) -{ - GLuint i, pixel; - LPWORD lpw; - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - - for (i=0; ipbPixels + pwfb->ScanWidth * y2)) + x[i]; - pixel = *lpw; - /* Windows uses 5,5,5 for 16-bit */ - rgba[i][RCOMP] = (pixel & 0x7c00) >> 7; - rgba[i][GCOMP] = (pixel & 0x03e0) >> 2; - rgba[i][BCOMP] = (pixel & 0x001f) << 3; - rgba[i][ACOMP] = 255; - } -} - - - - -/**********************************************************************/ -/***** BUFFER Functions *****/ -/**********************************************************************/ - - - - -static void -wmesa_delete_renderbuffer(struct gl_renderbuffer *rb) -{ - free(rb); -} - - -/** - * This is called by Mesa whenever it determines that the window size - * has changed. Do whatever's needed to cope with that. - */ -static GLboolean -wmesa_renderbuffer_storage(struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLenum internalFormat, - GLuint width, - GLuint height) -{ - rb->Width = width; - rb->Height = height; - return GL_TRUE; -} - - -/** - * Plug in the Get/PutRow/Values functions for a renderbuffer depending - * on if we're drawing to the front or back color buffer. - */ -void wmesa_set_renderbuffer_funcs(struct gl_renderbuffer *rb, int pixelformat, - int cColorBits, int double_buffer) -{ - if (double_buffer) { - /* back buffer */ - /* Picking the correct span functions is important because - * the DIB was allocated with the indicated depth. */ - switch(pixelformat) { - case PF_5R6G5B: - rb->PutRow = write_rgba_span_16; - rb->PutRowRGB = write_rgb_span_16; - rb->PutMonoRow = write_mono_rgba_span_16; - rb->PutValues = write_rgba_pixels_16; - rb->PutMonoValues = write_mono_rgba_pixels_16; - rb->GetRow = read_rgba_span_16; - rb->GetValues = read_rgba_pixels_16; - break; - case PF_8R8G8B: - if (cColorBits == 24) - { - rb->PutRow = write_rgba_span_24; - rb->PutRowRGB = write_rgb_span_24; - rb->PutMonoRow = write_mono_rgba_span_24; - rb->PutValues = write_rgba_pixels_24; - rb->PutMonoValues = write_mono_rgba_pixels_24; - rb->GetRow = read_rgba_span_24; - rb->GetValues = read_rgba_pixels_24; - } - else - { - rb->PutRow = write_rgba_span_32; - rb->PutRowRGB = write_rgb_span_32; - rb->PutMonoRow = write_mono_rgba_span_32; - rb->PutValues = write_rgba_pixels_32; - rb->PutMonoValues = write_mono_rgba_pixels_32; - rb->GetRow = read_rgba_span_32; - rb->GetValues = read_rgba_pixels_32; - } - break; - default: - break; - } - } - else { - /* front buffer (actual Windows window) */ - rb->PutRow = write_rgba_span_front; - rb->PutRowRGB = write_rgb_span_front; - rb->PutMonoRow = write_mono_rgba_span_front; - rb->PutValues = write_rgba_pixels_front; - rb->PutMonoValues = write_mono_rgba_pixels_front; - rb->GetRow = read_rgba_span_front; - rb->GetValues = read_rgba_pixels_front; - } -} - -/** - * Called by ctx->Driver.ResizeBuffers() - * Resize the front/back colorbuffers to match the latest window size. - */ -static void -wmesa_resize_buffers(struct gl_context *ctx, struct gl_framebuffer *buffer, - GLuint width, GLuint height) -{ - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(buffer); - - if (pwfb->Base.Width != width || pwfb->Base.Height != height) { - /* Realloc back buffer */ - if (ctx->Visual.doubleBufferMode == 1) { - wmDeleteBackingStore(pwfb); - wmCreateBackingStore(pwfb, width, height); - } - } - _mesa_resize_framebuffer(ctx, buffer, width, height); -} - - -/** - * Called by glViewport. - * This is a good time for us to poll the current window size and adjust - * our renderbuffers to match the current window size. - * Remember, we have no opportunity to respond to conventional - * resize events since the driver has no event loop. - * Thus, we poll. - * MakeCurrent also ends up making a call here, so that ensures - * we get the viewport set correctly, even if the app does not call - * glViewport and relies on the defaults. - */ -static void wmesa_viewport(struct gl_context *ctx, - GLint x, GLint y, - GLsizei width, GLsizei height) -{ - WMesaContext pwc = wmesa_context(ctx); - GLuint new_width, new_height; - - wmesa_get_buffer_size(ctx->WinSysDrawBuffer, &new_width, &new_height); - - /** - * Resize buffers if the window size changed. - */ - wmesa_resize_buffers(ctx, ctx->WinSysDrawBuffer, new_width, new_height); - ctx->NewState |= _NEW_BUFFERS; /* to update scissor / window bounds */ -} - - - - -/** - * Called when the driver should update it's state, based on the new_state - * flags. - */ -static void wmesa_update_state(struct gl_context *ctx, GLuint new_state) -{ - _swrast_InvalidateState(ctx, new_state); - _swsetup_InvalidateState(ctx, new_state); - _vbo_InvalidateState(ctx, new_state); - _tnl_InvalidateState(ctx, new_state); - - /* TODO - This code is not complete yet because I - * don't know what to do for all state updates. - */ - - if (new_state & _NEW_BUFFERS) { - } -} - - - - - -/**********************************************************************/ -/***** WMESA Functions *****/ -/**********************************************************************/ - -WMesaContext WMesaCreateContext(HDC hDC, - HPALETTE* Pal, - GLboolean rgb_flag, - GLboolean db_flag, - GLboolean alpha_flag) -{ - WMesaContext c; - struct dd_function_table functions; - GLint red_bits, green_bits, blue_bits, alpha_bits; - struct gl_context *ctx; - struct gl_config *visual; - - (void) Pal; - - /* Indexed mode not supported */ - if (!rgb_flag) - return NULL; - - /* Allocate wmesa context */ - c = CALLOC_STRUCT(wmesa_context); - if (!c) - return NULL; - -#if 0 - /* I do not understand this contributed code */ - /* Support memory and device contexts */ - if(WindowFromDC(hDC) != NULL) { - c->hDC = GetDC(WindowFromDC(hDC)); /* huh ???? */ - } - else { - c->hDC = hDC; - } -#else - c->hDC = hDC; -#endif - - /* Get data for visual */ - /* Dealing with this is actually a bit of overkill because Mesa will end - * up treating all color component size requests less than 8 by using - * a single byte per channel. In addition, the interface to the span - * routines passes colors as an entire byte per channel anyway, so there - * is nothing to be saved by telling the visual to be 16 bits if the device - * is 16 bits. That is, Mesa is going to compute colors down to 8 bits per - * channel anyway. - * But we go through the motions here anyway. - */ - switch (GetDeviceCaps(c->hDC, BITSPIXEL)) { - case 16: - red_bits = green_bits = blue_bits = 5; - alpha_bits = 0; - break; - default: - red_bits = green_bits = blue_bits = 8; - alpha_bits = 8; - break; - } - /* Create visual based on flags */ - visual = _mesa_create_visual(db_flag, /* db_flag */ - GL_FALSE, /* stereo */ - red_bits, green_bits, blue_bits, /* color RGB */ - alpha_flag ? alpha_bits : 0, /* color A */ - DEFAULT_SOFTWARE_DEPTH_BITS, /* depth_bits */ - 8, /* stencil_bits */ - 16,16,16, /* accum RGB */ - alpha_flag ? 16 : 0, /* accum A */ - 1); /* num samples */ - - if (!visual) { - free(c); - return NULL; - } - - /* Set up driver functions */ - _mesa_init_driver_functions(&functions); - functions.GetString = wmesa_get_string; - functions.UpdateState = wmesa_update_state; - functions.GetBufferSize = wmesa_get_buffer_size; - functions.Flush = wmesa_flush; - functions.Clear = clear; - functions.ClearColor = clear_color; - functions.ResizeBuffers = wmesa_resize_buffers; - functions.Viewport = wmesa_viewport; - - /* initialize the Mesa context data */ - ctx = &c->gl_ctx; - _mesa_initialize_context(ctx, visual, NULL, &functions, (void *)c); - - /* visual no longer needed - it was copied by _mesa_initialize_context() */ - _mesa_destroy_visual(visual); - - _mesa_enable_sw_extensions(ctx); - _mesa_enable_1_3_extensions(ctx); - _mesa_enable_1_4_extensions(ctx); - _mesa_enable_1_5_extensions(ctx); - _mesa_enable_2_0_extensions(ctx); - _mesa_enable_2_1_extensions(ctx); - - _mesa_meta_init(ctx); - - /* Initialize the software rasterizer and helper modules. */ - if (!_swrast_CreateContext(ctx) || - !_vbo_CreateContext(ctx) || - !_tnl_CreateContext(ctx) || - !_swsetup_CreateContext(ctx)) { - _mesa_free_context_data(ctx); - free(c); - return NULL; - } - _swsetup_Wakeup(ctx); - TNL_CONTEXT(ctx)->Driver.RunPipeline = _tnl_run_pipeline; - - return c; -} - - -void WMesaDestroyContext( WMesaContext pwc ) -{ - struct gl_context *ctx = &pwc->gl_ctx; - WMesaFramebuffer pwfb; - GET_CURRENT_CONTEXT(cur_ctx); - - if (cur_ctx == ctx) { - /* unbind current if deleting current context */ - WMesaMakeCurrent(NULL, NULL); - } - - /* clean up frame buffer resources */ - pwfb = wmesa_lookup_framebuffer(pwc->hDC); - if (pwfb) { - if (ctx->Visual.doubleBufferMode == 1) - wmDeleteBackingStore(pwfb); - wmesa_free_framebuffer(pwc->hDC); - } - - /* Release for device, not memory contexts */ - if (WindowFromDC(pwc->hDC) != NULL) - { - ReleaseDC(WindowFromDC(pwc->hDC), pwc->hDC); - } - DeleteObject(pwc->clearPen); - DeleteObject(pwc->clearBrush); - - _mesa_meta_free(ctx); - - _swsetup_DestroyContext(ctx); - _tnl_DestroyContext(ctx); - _vbo_DestroyContext(ctx); - _swrast_DestroyContext(ctx); - - _mesa_free_context_data(ctx); - free(pwc); -} - - -/** - * Create a new color renderbuffer. - */ -struct gl_renderbuffer * -wmesa_new_renderbuffer(void) -{ - struct gl_renderbuffer *rb = CALLOC_STRUCT(gl_renderbuffer); - if (!rb) - return NULL; - - _mesa_init_renderbuffer(rb, (GLuint)0); - - rb->_BaseFormat = GL_RGBA; - rb->InternalFormat = GL_RGBA; - rb->DataType = CHAN_TYPE; - rb->Delete = wmesa_delete_renderbuffer; - rb->AllocStorage = wmesa_renderbuffer_storage; - return rb; -} - - -void WMesaMakeCurrent(WMesaContext c, HDC hdc) -{ - WMesaFramebuffer pwfb; - - { - /* return if already current */ - GET_CURRENT_CONTEXT(ctx); - WMesaContext pwc = wmesa_context(ctx); - if (pwc && c == pwc && pwc->hDC == hdc) - return; - } - - pwfb = wmesa_lookup_framebuffer(hdc); - - /* Lazy creation of framebuffers */ - if (c && !pwfb && hdc) { - struct gl_renderbuffer *rb; - struct gl_config *visual = &c->gl_ctx.Visual; - GLuint width, height; - - get_window_size(hdc, &width, &height); - - c->clearPen = CreatePen(PS_SOLID, 1, 0); - c->clearBrush = CreateSolidBrush(0); - - pwfb = wmesa_new_framebuffer(hdc, visual); - - /* Create back buffer if double buffered */ - if (visual->doubleBufferMode == 1) { - wmCreateBackingStore(pwfb, width, height); - } - - /* make render buffers */ - if (visual->doubleBufferMode == 1) { - rb = wmesa_new_renderbuffer(); - _mesa_add_renderbuffer(&pwfb->Base, BUFFER_BACK_LEFT, rb); - wmesa_set_renderbuffer_funcs(rb, pwfb->pixelformat, pwfb->cColorBits, 1); - } - rb = wmesa_new_renderbuffer(); - _mesa_add_renderbuffer(&pwfb->Base, BUFFER_FRONT_LEFT, rb); - wmesa_set_renderbuffer_funcs(rb, pwfb->pixelformat, pwfb->cColorBits, 0); - - /* Let Mesa own the Depth, Stencil, and Accum buffers */ - _mesa_add_soft_renderbuffers(&pwfb->Base, - GL_FALSE, /* color */ - visual->depthBits > 0, - visual->stencilBits > 0, - visual->accumRedBits > 0, - visual->alphaBits >0, - GL_FALSE); - } - - if (c && pwfb) - _mesa_make_current(&c->gl_ctx, &pwfb->Base, &pwfb->Base); - else - _mesa_make_current(NULL, NULL, NULL); -} - - -void WMesaSwapBuffers( HDC hdc ) -{ - GET_CURRENT_CONTEXT(ctx); - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_lookup_framebuffer(hdc); - - if (!pwfb) { - _mesa_problem(NULL, "wmesa: swapbuffers on unknown hdc"); - return; - } - - /* If we're swapping the buffer associated with the current context - * we have to flush any pending rendering commands first. - */ - if (pwc->hDC == hdc) { - _mesa_notifySwapBuffers(ctx); - - BitBlt(pwfb->hDC, 0, 0, pwfb->Base.Width, pwfb->Base.Height, - pwfb->dib_hDC, 0, 0, SRCCOPY); - } - else { - /* XXX for now only allow swapping current window */ - _mesa_problem(NULL, "wmesa: can't swap non-current window"); - } -} - -void WMesaShareLists(WMesaContext ctx_to_share, WMesaContext ctx) -{ - _mesa_share_state(&ctx->gl_ctx, &ctx_to_share->gl_ctx); -} - +/* + * Windows (Win32/Win64) device driver for Mesa + * + */ + +#include "wmesadef.h" +#include "colors.h" +#include +#include +#include "context.h" +#include "extensions.h" +#include "framebuffer.h" +#include "renderbuffer.h" +#include "drivers/common/driverfuncs.h" +#include "drivers/common/meta.h" +#include "vbo/vbo.h" +#include "swrast/swrast.h" +#include "swrast_setup/swrast_setup.h" +#include "tnl/tnl.h" +#include "tnl/t_context.h" +#include "tnl/t_pipeline.h" + + +/* linked list of our Framebuffers (windows) */ +static WMesaFramebuffer FirstFramebuffer = NULL; + + +/** + * Create a new WMesaFramebuffer object which will correspond to the + * given HDC (Window handle). + */ +WMesaFramebuffer +wmesa_new_framebuffer(HDC hdc, struct gl_config *visual) +{ + WMesaFramebuffer pwfb + = (WMesaFramebuffer) malloc(sizeof(struct wmesa_framebuffer)); + if (pwfb) { + _mesa_initialize_window_framebuffer(&pwfb->Base, visual); + pwfb->hDC = hdc; + /* insert at head of list */ + pwfb->next = FirstFramebuffer; + FirstFramebuffer = pwfb; + } + return pwfb; +} + +/** + * Given an hdc, free the corresponding WMesaFramebuffer + */ +void +wmesa_free_framebuffer(HDC hdc) +{ + WMesaFramebuffer pwfb, prev; + for (pwfb = FirstFramebuffer; pwfb; pwfb = pwfb->next) { + if (pwfb->hDC == hdc) + break; + prev = pwfb; + } + if (pwfb) { + struct gl_framebuffer *fb; + if (pwfb == FirstFramebuffer) + FirstFramebuffer = pwfb->next; + else + prev->next = pwfb->next; + fb = &pwfb->Base; + _mesa_reference_framebuffer(&fb, NULL); + } +} + +/** + * Given an hdc, return the corresponding WMesaFramebuffer + */ +WMesaFramebuffer +wmesa_lookup_framebuffer(HDC hdc) +{ + WMesaFramebuffer pwfb; + for (pwfb = FirstFramebuffer; pwfb; pwfb = pwfb->next) { + if (pwfb->hDC == hdc) + return pwfb; + } + return NULL; +} + + +/** + * Given a struct gl_framebuffer, return the corresponding WMesaFramebuffer. + */ +static WMesaFramebuffer wmesa_framebuffer(struct gl_framebuffer *fb) +{ + return (WMesaFramebuffer) fb; +} + + +/** + * Given a struct gl_context, return the corresponding WMesaContext. + */ +static WMesaContext wmesa_context(const struct gl_context *ctx) +{ + return (WMesaContext) ctx; +} + + +/* + * Every driver should implement a GetString function in order to + * return a meaningful GL_RENDERER string. + */ +static const GLubyte *wmesa_get_string(struct gl_context *ctx, GLenum name) +{ + return (name == GL_RENDERER) ? + (GLubyte *) "Mesa Windows GDI Driver" : NULL; +} + + +/* + * Determine the pixel format based on the pixel size. + */ +static void wmSetPixelFormat(WMesaFramebuffer pwfb, HDC hDC) +{ + pwfb->cColorBits = GetDeviceCaps(hDC, BITSPIXEL); + + /* Only 16 and 32 bit targets are supported now */ + assert(pwfb->cColorBits == 0 || + pwfb->cColorBits == 16 || + pwfb->cColorBits == 24 || + pwfb->cColorBits == 32); + + switch(pwfb->cColorBits){ + case 8: + pwfb->pixelformat = PF_INDEX8; + break; + case 16: + pwfb->pixelformat = PF_5R6G5B; + break; + case 24: + case 32: + pwfb->pixelformat = PF_8R8G8B; + break; + default: + pwfb->pixelformat = PF_BADFORMAT; + } +} + + +/** + * Create DIB for back buffer. + * We write into this memory with the span routines and then blit it + * to the window on a buffer swap. + */ +BOOL wmCreateBackingStore(WMesaFramebuffer pwfb, long lxSize, long lySize) +{ + HDC hdc = pwfb->hDC; + LPBITMAPINFO pbmi = &(pwfb->bmi); + HDC hic; + + pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + pbmi->bmiHeader.biWidth = lxSize; + pbmi->bmiHeader.biHeight= -lySize; + pbmi->bmiHeader.biPlanes = 1; + pbmi->bmiHeader.biBitCount = GetDeviceCaps(pwfb->hDC, BITSPIXEL); + pbmi->bmiHeader.biCompression = BI_RGB; + pbmi->bmiHeader.biSizeImage = 0; + pbmi->bmiHeader.biXPelsPerMeter = 0; + pbmi->bmiHeader.biYPelsPerMeter = 0; + pbmi->bmiHeader.biClrUsed = 0; + pbmi->bmiHeader.biClrImportant = 0; + + pwfb->cColorBits = pbmi->bmiHeader.biBitCount; + pwfb->ScanWidth = (lxSize * (pwfb->cColorBits / 8) + 3) & ~3; + + hic = CreateIC("display", NULL, NULL, NULL); + pwfb->dib_hDC = CreateCompatibleDC(hic); + + pwfb->hbmDIB = CreateDIBSection(hic, + &pwfb->bmi, + DIB_RGB_COLORS, + (void **)&(pwfb->pbPixels), + 0, + 0); + pwfb->hOldBitmap = SelectObject(pwfb->dib_hDC, pwfb->hbmDIB); + + DeleteDC(hic); + + wmSetPixelFormat(pwfb, pwfb->hDC); + return TRUE; +} + + +static wmDeleteBackingStore(WMesaFramebuffer pwfb) +{ + if (pwfb->hbmDIB) { + SelectObject(pwfb->dib_hDC, pwfb->hOldBitmap); + DeleteDC(pwfb->dib_hDC); + DeleteObject(pwfb->hbmDIB); + } +} + + +/** + * Find the width and height of the window named by hdc. + */ +static void +get_window_size(HDC hdc, GLuint *width, GLuint *height) +{ + if (WindowFromDC(hdc)) { + RECT rect; + GetClientRect(WindowFromDC(hdc), &rect); + *width = rect.right - rect.left; + *height = rect.bottom - rect.top; + } + else { /* Memory context */ + /* From contributed code - use the size of the desktop + * for the size of a memory context (?) */ + *width = GetDeviceCaps(hdc, HORZRES); + *height = GetDeviceCaps(hdc, VERTRES); + } +} + + +static void +wmesa_get_buffer_size(struct gl_framebuffer *buffer, GLuint *width, GLuint *height) +{ + WMesaFramebuffer pwfb = wmesa_framebuffer(buffer); + get_window_size(pwfb->hDC, width, height); +} + + +static void wmesa_flush(struct gl_context *ctx) +{ + WMesaContext pwc = wmesa_context(ctx); + WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->WinSysDrawBuffer); + + if (ctx->Visual.doubleBufferMode == 1) { + BitBlt(pwfb->hDC, 0, 0, pwfb->Base.Width, pwfb->Base.Height, + pwfb->dib_hDC, 0, 0, SRCCOPY); + } + else { + /* Do nothing for single buffer */ + } +} + + +/**********************************************************************/ +/***** CLEAR Functions *****/ +/**********************************************************************/ + +/* If we do not implement these, Mesa clears the buffers via the pixel + * span writing interface, which is very slow for a clear operation. + */ + +/* + * Set the color used to clear the color buffer. + */ +static void clear_color(struct gl_context *ctx, const GLfloat color[4]) +{ + WMesaContext pwc = wmesa_context(ctx); + WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); + GLubyte col[3]; + UINT bytesPerPixel = pwfb->cColorBits / 8; + + CLAMPED_FLOAT_TO_UBYTE(col[0], color[0]); + CLAMPED_FLOAT_TO_UBYTE(col[1], color[1]); + CLAMPED_FLOAT_TO_UBYTE(col[2], color[2]); + pwc->clearColorRef = RGB(col[0], col[1], col[2]); + DeleteObject(pwc->clearPen); + DeleteObject(pwc->clearBrush); + pwc->clearPen = CreatePen(PS_SOLID, 1, pwc->clearColorRef); + pwc->clearBrush = CreateSolidBrush(pwc->clearColorRef); +} + + +/* + * Clear the specified region of the color buffer using the clear color + * or index as specified by one of the two functions above. + * + * This procedure clears either the front and/or the back COLOR buffers. + * Only the "left" buffer is cleared since we are not stereo. + * Clearing of the other non-color buffers is left to the swrast. + */ + +static void clear(struct gl_context *ctx, GLbitfield mask) +{ +#define FLIP(Y) (ctx->DrawBuffer->Height - (Y) - 1) + const GLint x = ctx->DrawBuffer->_Xmin; + const GLint y = ctx->DrawBuffer->_Ymin; + const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; + const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; + + WMesaContext pwc = wmesa_context(ctx); + WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); + int done = 0; + + /* Let swrast do all the work if the masks are not set to + * clear all channels. */ + if (!ctx->Color.ColorMask[0][0] || + !ctx->Color.ColorMask[0][1] || + !ctx->Color.ColorMask[0][2] || + !ctx->Color.ColorMask[0][3]) { + _swrast_Clear(ctx, mask); + return; + } + + /* Back buffer */ + if (mask & BUFFER_BIT_BACK_LEFT) { + + int i, rowSize; + UINT bytesPerPixel = pwfb->cColorBits / 8; + LPBYTE lpb, clearRow; + LPWORD lpw; + BYTE bColor; + WORD wColor; + BYTE r, g, b; + DWORD dwColor; + LPDWORD lpdw; + + /* Try for a fast clear - clearing entire buffer with a single + * byte value. */ + if (width == ctx->DrawBuffer->Width && + height == ctx->DrawBuffer->Height) { /* entire buffer */ + /* Now check for an easy clear value */ + switch (bytesPerPixel) { + case 1: + bColor = BGR8(GetRValue(pwc->clearColorRef), + GetGValue(pwc->clearColorRef), + GetBValue(pwc->clearColorRef)); + memset(pwfb->pbPixels, bColor, + pwfb->ScanWidth * height); + done = 1; + break; + case 2: + wColor = BGR16(GetRValue(pwc->clearColorRef), + GetGValue(pwc->clearColorRef), + GetBValue(pwc->clearColorRef)); + if (((wColor >> 8) & 0xff) == (wColor & 0xff)) { + memset(pwfb->pbPixels, wColor & 0xff, + pwfb->ScanWidth * height); + done = 1; + } + break; + case 3: + /* fall through */ + case 4: + if (GetRValue(pwc->clearColorRef) == + GetGValue(pwc->clearColorRef) && + GetRValue(pwc->clearColorRef) == + GetBValue(pwc->clearColorRef)) { + memset(pwfb->pbPixels, + GetRValue(pwc->clearColorRef), + pwfb->ScanWidth * height); + done = 1; + } + break; + default: + break; + } + } /* all */ + + if (!done) { + /* Need to clear a row at a time. Begin by setting the first + * row in the area to be cleared to the clear color. */ + + clearRow = pwfb->pbPixels + + pwfb->ScanWidth * FLIP(y) + + bytesPerPixel * x; + switch (bytesPerPixel) { + case 1: + lpb = clearRow; + bColor = BGR8(GetRValue(pwc->clearColorRef), + GetGValue(pwc->clearColorRef), + GetBValue(pwc->clearColorRef)); + memset(lpb, bColor, width); + break; + case 2: + lpw = (LPWORD)clearRow; + wColor = BGR16(GetRValue(pwc->clearColorRef), + GetGValue(pwc->clearColorRef), + GetBValue(pwc->clearColorRef)); + for (i=0; iclearColorRef); + g = GetGValue(pwc->clearColorRef); + b = GetBValue(pwc->clearColorRef); + for (i=0; iclearColorRef), + GetGValue(pwc->clearColorRef), + GetBValue(pwc->clearColorRef)); + for (i=0; iScanWidth; + rowSize = width * bytesPerPixel; + for (i=1; iScanWidth; + } + } /* not done */ + mask &= ~BUFFER_BIT_BACK_LEFT; + } /* back buffer */ + + /* front buffer */ + if (mask & BUFFER_BIT_FRONT_LEFT) { + HDC DC = pwc->hDC; + HPEN Old_Pen = SelectObject(DC, pwc->clearPen); + HBRUSH Old_Brush = SelectObject(DC, pwc->clearBrush); + Rectangle(DC, + x, + FLIP(y) + 1, + x + width + 1, + FLIP(y) - height + 1); + SelectObject(DC, Old_Pen); + SelectObject(DC, Old_Brush); + mask &= ~BUFFER_BIT_FRONT_LEFT; + } /* front buffer */ + + /* Call swrast if there is anything left to clear (like DEPTH) */ + if (mask) + _swrast_Clear(ctx, mask); + +#undef FLIP +} + + +/**********************************************************************/ +/***** PIXEL Functions *****/ +/**********************************************************************/ + +#define FLIP(Y) (rb->Height - (Y) - 1) + + +/** + ** Front Buffer reading/writing + ** These are slow, but work with all non-indexed visual types. + **/ + +/* Write a horizontal span of RGBA color pixels with a boolean mask. */ +static void write_rgba_span_front(const struct gl_context *ctx, + struct gl_renderbuffer *rb, + GLuint n, GLint x, GLint y, + const GLubyte rgba[][4], + const GLubyte mask[] ) +{ + WMesaContext pwc = wmesa_context(ctx); + WMesaFramebuffer pwfb = wmesa_lookup_framebuffer(pwc->hDC); + CONST BITMAPINFO bmi= + { + { + sizeof(BITMAPINFOHEADER), + n, 1, 1, 32, BI_RGB, 0, 1, 1, 0, 0 + } + }; + HBITMAP bmp=0; + HDC mdc=0; + typedef union + { + unsigned i; + struct { + unsigned b:8, g:8, r:8, a:8; + }; + } BGRA; + BGRA *bgra, c; + GLuint i; + + if (n < 16) { // the value 16 is just guessed + y=FLIP(y); + if (mask) { + for (i=0; ihDC, x+i, y, + RGB(rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP])); + } + else { + for (i=0; ihDC, x+i, y, + RGB(rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP])); + } + } + else { + if (!pwfb) { + _mesa_problem(NULL, "wmesa: write_rgba_span_front on unknown hdc"); + return; + } + bgra=malloc(n*sizeof(BGRA)); + if (!bgra) { + _mesa_problem(NULL, "wmesa: write_rgba_span_front: out of memory"); + return; + } + c.a=0; + if (mask) { + for (i=0; ihDC); + SelectObject(mdc, bmp); + y=FLIP(y); + BitBlt(pwfb->hDC, x, y, n, 1, mdc, 0, 0, SRCCOPY); + SelectObject(mdc, 0); + DeleteObject(bmp); + DeleteDC(mdc); + free(bgra); + } +} + +/* Write a horizontal span of RGB color pixels with a boolean mask. */ +static void write_rgb_span_front(const struct gl_context *ctx, + struct gl_renderbuffer *rb, + GLuint n, GLint x, GLint y, + const GLubyte rgb[][3], + const GLubyte mask[] ) +{ + WMesaContext pwc = wmesa_context(ctx); + GLuint i; + + (void) ctx; + y=FLIP(y); + if (mask) { + for (i=0; ihDC, x+i, y, RGB(rgb[i][RCOMP], rgb[i][GCOMP], + rgb[i][BCOMP])); + } + else { + for (i=0; ihDC, x+i, y, RGB(rgb[i][RCOMP], rgb[i][GCOMP], + rgb[i][BCOMP])); + } + +} + +/* + * Write a horizontal span of pixels with a boolean mask. The current color + * is used for all pixels. + */ +static void write_mono_rgba_span_front(const struct gl_context *ctx, + struct gl_renderbuffer *rb, + GLuint n, GLint x, GLint y, + const GLchan color[4], + const GLubyte mask[]) +{ + GLuint i; + WMesaContext pwc = wmesa_context(ctx); + COLORREF colorref; + + (void) ctx; + colorref = RGB(color[RCOMP], color[GCOMP], color[BCOMP]); + y=FLIP(y); + if (mask) { + for (i=0; ihDC, x+i, y, colorref); + } + else + for (i=0; ihDC, x+i, y, colorref); + +} + +/* Write an array of RGBA pixels with a boolean mask. */ +static void write_rgba_pixels_front(const struct gl_context *ctx, + struct gl_renderbuffer *rb, + GLuint n, + const GLint x[], const GLint y[], + const GLubyte rgba[][4], + const GLubyte mask[] ) +{ + GLuint i; + WMesaContext pwc = wmesa_context(ctx); + (void) ctx; + for (i=0; ihDC, x[i], FLIP(y[i]), + RGB(rgba[i][RCOMP], rgba[i][GCOMP], + rgba[i][BCOMP])); +} + + + +/* + * Write an array of pixels with a boolean mask. The current color + * is used for all pixels. + */ +static void write_mono_rgba_pixels_front(const struct gl_context *ctx, + struct gl_renderbuffer *rb, + GLuint n, + const GLint x[], const GLint y[], + const GLchan color[4], + const GLubyte mask[] ) +{ + GLuint i; + WMesaContext pwc = wmesa_context(ctx); + COLORREF colorref; + (void) ctx; + colorref = RGB(color[RCOMP], color[GCOMP], color[BCOMP]); + for (i=0; ihDC, x[i], FLIP(y[i]), colorref); +} + +/* Read a horizontal span of color pixels. */ +static void read_rgba_span_front(const struct gl_context *ctx, + struct gl_renderbuffer *rb, + GLuint n, GLint x, GLint y, + GLubyte rgba[][4] ) +{ + WMesaContext pwc = wmesa_context(ctx); + GLuint i; + COLORREF Color; + y = FLIP(y); + for (i=0; ihDC, x+i, y); + rgba[i][RCOMP] = GetRValue(Color); + rgba[i][GCOMP] = GetGValue(Color); + rgba[i][BCOMP] = GetBValue(Color); + rgba[i][ACOMP] = 255; + } +} + + +/* Read an array of color pixels. */ +static void read_rgba_pixels_front(const struct gl_context *ctx, + struct gl_renderbuffer *rb, + GLuint n, const GLint x[], const GLint y[], + GLubyte rgba[][4]) +{ + WMesaContext pwc = wmesa_context(ctx); + GLuint i; + COLORREF Color; + for (i=0; ihDC, x[i], y2); + rgba[i][RCOMP] = GetRValue(Color); + rgba[i][GCOMP] = GetGValue(Color); + rgba[i][BCOMP] = GetBValue(Color); + rgba[i][ACOMP] = 255; + } +} + +/*********************************************************************/ + +/* DOUBLE BUFFER 32-bit */ + +#define WMSETPIXEL32(pwc, y, x, r, g, b) { \ +LPDWORD lpdw = ((LPDWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); \ +*lpdw = BGR32((r),(g),(b)); } + + + +/* Write a horizontal span of RGBA color pixels with a boolean mask. */ +static void write_rgba_span_32(const struct gl_context *ctx, + struct gl_renderbuffer *rb, + GLuint n, GLint x, GLint y, + const GLubyte rgba[][4], + const GLubyte mask[] ) +{ + WMesaContext pwc = wmesa_context(ctx); + WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); + GLuint i; + LPDWORD lpdw; + + (void) ctx; + + y=FLIP(y); + lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; + if (mask) { + for (i=0; iDrawBuffer); + GLuint i; + LPDWORD lpdw; + + (void) ctx; + + y=FLIP(y); + lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; + if (mask) { + for (i=0; iDrawBuffer); + lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; + y=FLIP(y); + pixel = BGR32(color[RCOMP], color[GCOMP], color[BCOMP]); + if (mask) { + for (i=0; iDrawBuffer); + for (i=0; iDrawBuffer); + for (i=0; iDrawBuffer); + + y = FLIP(y); + lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; + for (i=0; i> 16); + rgba[i][GCOMP] = (GLubyte)((pixel & 0x0000ff00) >> 8); + rgba[i][BCOMP] = (GLubyte)(pixel & 0x000000ff); + rgba[i][ACOMP] = 255; + } +} + + +/* Read an array of color pixels. */ +static void read_rgba_pixels_32(const struct gl_context *ctx, + struct gl_renderbuffer *rb, + GLuint n, const GLint x[], const GLint y[], + GLubyte rgba[][4]) +{ + GLuint i; + DWORD pixel; + LPDWORD lpdw; + WMesaContext pwc = wmesa_context(ctx); + WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); + + for (i=0; ipbPixels + pwfb->ScanWidth * y2)) + x[i]; + pixel = *lpdw; + rgba[i][RCOMP] = (GLubyte)((pixel & 0x00ff0000) >> 16); + rgba[i][GCOMP] = (GLubyte)((pixel & 0x0000ff00) >> 8); + rgba[i][BCOMP] = (GLubyte)(pixel & 0x000000ff); + rgba[i][ACOMP] = 255; + } +} + + +/*********************************************************************/ + +/* DOUBLE BUFFER 24-bit */ + +#define WMSETPIXEL24(pwc, y, x, r, g, b) { \ +LPBYTE lpb = ((LPBYTE)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (3 * x)); \ +lpb[0] = (b); \ +lpb[1] = (g); \ +lpb[2] = (r); } + +/* Write a horizontal span of RGBA color pixels with a boolean mask. */ +static void write_rgba_span_24(const struct gl_context *ctx, + struct gl_renderbuffer *rb, + GLuint n, GLint x, GLint y, + const GLubyte rgba[][4], + const GLubyte mask[] ) +{ + WMesaContext pwc = wmesa_context(ctx); + WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); + GLuint i; + LPBYTE lpb; + + (void) ctx; + + y=FLIP(y); + lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x); + if (mask) { + for (i=0; iDrawBuffer); + GLuint i; + LPBYTE lpb; + + (void) ctx; + + y=FLIP(y); + lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x); + if (mask) { + for (i=0; iDrawBuffer); + lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x); + y=FLIP(y); + if (mask) { + for (i=0; iDrawBuffer); + for (i=0; iDrawBuffer); + for (i=0; iDrawBuffer); + + y = FLIP(y); + lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x); + for (i=0; iDrawBuffer); + + for (i=0; ipbPixels + pwfb->ScanWidth * y2)) + (3 * x[i]); + rgba[i][RCOMP] = lpb[3*i+2]; + rgba[i][GCOMP] = lpb[3*i+1]; + rgba[i][BCOMP] = lpb[3*i]; + rgba[i][ACOMP] = 255; + } +} + + +/*********************************************************************/ + +/* DOUBLE BUFFER 16-bit */ + +#define WMSETPIXEL16(pwc, y, x, r, g, b) { \ +LPWORD lpw = ((LPWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); \ +*lpw = BGR16((r),(g),(b)); } + + + +/* Write a horizontal span of RGBA color pixels with a boolean mask. */ +static void write_rgba_span_16(const struct gl_context *ctx, + struct gl_renderbuffer *rb, + GLuint n, GLint x, GLint y, + const GLubyte rgba[][4], + const GLubyte mask[] ) +{ + WMesaContext pwc = wmesa_context(ctx); + WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); + GLuint i; + LPWORD lpw; + + (void) ctx; + + y=FLIP(y); + lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; + if (mask) { + for (i=0; iDrawBuffer); + GLuint i; + LPWORD lpw; + + (void) ctx; + + y=FLIP(y); + lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; + if (mask) { + for (i=0; iDrawBuffer); + (void) ctx; + lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; + y=FLIP(y); + pixel = BGR16(color[RCOMP], color[GCOMP], color[BCOMP]); + if (mask) { + for (i=0; iDrawBuffer); + (void) ctx; + for (i=0; iDrawBuffer); + (void) ctx; + for (i=0; iDrawBuffer); + + y = FLIP(y); + lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; + for (i=0; i> 7; + rgba[i][GCOMP] = (pixel & 0x03e0) >> 2; + rgba[i][BCOMP] = (pixel & 0x001f) << 3; + rgba[i][ACOMP] = 255; + } +} + + +/* Read an array of color pixels. */ +static void read_rgba_pixels_16(const struct gl_context *ctx, + struct gl_renderbuffer *rb, + GLuint n, const GLint x[], const GLint y[], + GLubyte rgba[][4]) +{ + GLuint i, pixel; + LPWORD lpw; + WMesaContext pwc = wmesa_context(ctx); + WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); + + for (i=0; ipbPixels + pwfb->ScanWidth * y2)) + x[i]; + pixel = *lpw; + /* Windows uses 5,5,5 for 16-bit */ + rgba[i][RCOMP] = (pixel & 0x7c00) >> 7; + rgba[i][GCOMP] = (pixel & 0x03e0) >> 2; + rgba[i][BCOMP] = (pixel & 0x001f) << 3; + rgba[i][ACOMP] = 255; + } +} + + + + +/**********************************************************************/ +/***** BUFFER Functions *****/ +/**********************************************************************/ + + + + +static void +wmesa_delete_renderbuffer(struct gl_renderbuffer *rb) +{ + free(rb); +} + + +/** + * This is called by Mesa whenever it determines that the window size + * has changed. Do whatever's needed to cope with that. + */ +static GLboolean +wmesa_renderbuffer_storage(struct gl_context *ctx, + struct gl_renderbuffer *rb, + GLenum internalFormat, + GLuint width, + GLuint height) +{ + rb->Width = width; + rb->Height = height; + return GL_TRUE; +} + + +/** + * Plug in the Get/PutRow/Values functions for a renderbuffer depending + * on if we're drawing to the front or back color buffer. + */ +void wmesa_set_renderbuffer_funcs(struct gl_renderbuffer *rb, int pixelformat, + int cColorBits, int double_buffer) +{ + if (double_buffer) { + /* back buffer */ + /* Picking the correct span functions is important because + * the DIB was allocated with the indicated depth. */ + switch(pixelformat) { + case PF_5R6G5B: + rb->PutRow = write_rgba_span_16; + rb->PutRowRGB = write_rgb_span_16; + rb->PutMonoRow = write_mono_rgba_span_16; + rb->PutValues = write_rgba_pixels_16; + rb->PutMonoValues = write_mono_rgba_pixels_16; + rb->GetRow = read_rgba_span_16; + rb->GetValues = read_rgba_pixels_16; + break; + case PF_8R8G8B: + if (cColorBits == 24) + { + rb->PutRow = write_rgba_span_24; + rb->PutRowRGB = write_rgb_span_24; + rb->PutMonoRow = write_mono_rgba_span_24; + rb->PutValues = write_rgba_pixels_24; + rb->PutMonoValues = write_mono_rgba_pixels_24; + rb->GetRow = read_rgba_span_24; + rb->GetValues = read_rgba_pixels_24; + } + else + { + rb->PutRow = write_rgba_span_32; + rb->PutRowRGB = write_rgb_span_32; + rb->PutMonoRow = write_mono_rgba_span_32; + rb->PutValues = write_rgba_pixels_32; + rb->PutMonoValues = write_mono_rgba_pixels_32; + rb->GetRow = read_rgba_span_32; + rb->GetValues = read_rgba_pixels_32; + } + break; + default: + break; + } + } + else { + /* front buffer (actual Windows window) */ + rb->PutRow = write_rgba_span_front; + rb->PutRowRGB = write_rgb_span_front; + rb->PutMonoRow = write_mono_rgba_span_front; + rb->PutValues = write_rgba_pixels_front; + rb->PutMonoValues = write_mono_rgba_pixels_front; + rb->GetRow = read_rgba_span_front; + rb->GetValues = read_rgba_pixels_front; + } +} + +/** + * Called by ctx->Driver.ResizeBuffers() + * Resize the front/back colorbuffers to match the latest window size. + */ +static void +wmesa_resize_buffers(struct gl_context *ctx, struct gl_framebuffer *buffer, + GLuint width, GLuint height) +{ + WMesaContext pwc = wmesa_context(ctx); + WMesaFramebuffer pwfb = wmesa_framebuffer(buffer); + + if (pwfb->Base.Width != width || pwfb->Base.Height != height) { + /* Realloc back buffer */ + if (ctx->Visual.doubleBufferMode == 1) { + wmDeleteBackingStore(pwfb); + wmCreateBackingStore(pwfb, width, height); + } + } + _mesa_resize_framebuffer(ctx, buffer, width, height); +} + + +/** + * Called by glViewport. + * This is a good time for us to poll the current window size and adjust + * our renderbuffers to match the current window size. + * Remember, we have no opportunity to respond to conventional + * resize events since the driver has no event loop. + * Thus, we poll. + * MakeCurrent also ends up making a call here, so that ensures + * we get the viewport set correctly, even if the app does not call + * glViewport and relies on the defaults. + */ +static void wmesa_viewport(struct gl_context *ctx, + GLint x, GLint y, + GLsizei width, GLsizei height) +{ + WMesaContext pwc = wmesa_context(ctx); + GLuint new_width, new_height; + + wmesa_get_buffer_size(ctx->WinSysDrawBuffer, &new_width, &new_height); + + /** + * Resize buffers if the window size changed. + */ + wmesa_resize_buffers(ctx, ctx->WinSysDrawBuffer, new_width, new_height); + ctx->NewState |= _NEW_BUFFERS; /* to update scissor / window bounds */ +} + + + + +/** + * Called when the driver should update it's state, based on the new_state + * flags. + */ +static void wmesa_update_state(struct gl_context *ctx, GLuint new_state) +{ + _swrast_InvalidateState(ctx, new_state); + _swsetup_InvalidateState(ctx, new_state); + _vbo_InvalidateState(ctx, new_state); + _tnl_InvalidateState(ctx, new_state); + + /* TODO - This code is not complete yet because I + * don't know what to do for all state updates. + */ + + if (new_state & _NEW_BUFFERS) { + } +} + + + + + +/**********************************************************************/ +/***** WMESA Functions *****/ +/**********************************************************************/ + +WMesaContext WMesaCreateContext(HDC hDC, + HPALETTE* Pal, + GLboolean rgb_flag, + GLboolean db_flag, + GLboolean alpha_flag) +{ + WMesaContext c; + struct dd_function_table functions; + GLint red_bits, green_bits, blue_bits, alpha_bits; + struct gl_context *ctx; + struct gl_config *visual; + + (void) Pal; + + /* Indexed mode not supported */ + if (!rgb_flag) + return NULL; + + /* Allocate wmesa context */ + c = CALLOC_STRUCT(wmesa_context); + if (!c) + return NULL; + +#if 0 + /* I do not understand this contributed code */ + /* Support memory and device contexts */ + if(WindowFromDC(hDC) != NULL) { + c->hDC = GetDC(WindowFromDC(hDC)); /* huh ???? */ + } + else { + c->hDC = hDC; + } +#else + c->hDC = hDC; +#endif + + /* Get data for visual */ + /* Dealing with this is actually a bit of overkill because Mesa will end + * up treating all color component size requests less than 8 by using + * a single byte per channel. In addition, the interface to the span + * routines passes colors as an entire byte per channel anyway, so there + * is nothing to be saved by telling the visual to be 16 bits if the device + * is 16 bits. That is, Mesa is going to compute colors down to 8 bits per + * channel anyway. + * But we go through the motions here anyway. + */ + switch (GetDeviceCaps(c->hDC, BITSPIXEL)) { + case 16: + red_bits = green_bits = blue_bits = 5; + alpha_bits = 0; + break; + default: + red_bits = green_bits = blue_bits = 8; + alpha_bits = 8; + break; + } + /* Create visual based on flags */ + visual = _mesa_create_visual(db_flag, /* db_flag */ + GL_FALSE, /* stereo */ + red_bits, green_bits, blue_bits, /* color RGB */ + alpha_flag ? alpha_bits : 0, /* color A */ + DEFAULT_SOFTWARE_DEPTH_BITS, /* depth_bits */ + 8, /* stencil_bits */ + 16,16,16, /* accum RGB */ + alpha_flag ? 16 : 0, /* accum A */ + 1); /* num samples */ + + if (!visual) { + free(c); + return NULL; + } + + /* Set up driver functions */ + _mesa_init_driver_functions(&functions); + functions.GetString = wmesa_get_string; + functions.UpdateState = wmesa_update_state; + functions.GetBufferSize = wmesa_get_buffer_size; + functions.Flush = wmesa_flush; + functions.Clear = clear; + functions.ClearColor = clear_color; + functions.ResizeBuffers = wmesa_resize_buffers; + functions.Viewport = wmesa_viewport; + + /* initialize the Mesa context data */ + ctx = &c->gl_ctx; + _mesa_initialize_context(ctx, API_OPENGL, visual, + NULL, &functions, (void *)c); + + /* visual no longer needed - it was copied by _mesa_initialize_context() */ + _mesa_destroy_visual(visual); + + _mesa_enable_sw_extensions(ctx); + _mesa_enable_1_3_extensions(ctx); + _mesa_enable_1_4_extensions(ctx); + _mesa_enable_1_5_extensions(ctx); + _mesa_enable_2_0_extensions(ctx); + _mesa_enable_2_1_extensions(ctx); + + _mesa_meta_init(ctx); + + /* Initialize the software rasterizer and helper modules. */ + if (!_swrast_CreateContext(ctx) || + !_vbo_CreateContext(ctx) || + !_tnl_CreateContext(ctx) || + !_swsetup_CreateContext(ctx)) { + _mesa_free_context_data(ctx); + free(c); + return NULL; + } + _swsetup_Wakeup(ctx); + TNL_CONTEXT(ctx)->Driver.RunPipeline = _tnl_run_pipeline; + + return c; +} + + +void WMesaDestroyContext( WMesaContext pwc ) +{ + struct gl_context *ctx = &pwc->gl_ctx; + WMesaFramebuffer pwfb; + GET_CURRENT_CONTEXT(cur_ctx); + + if (cur_ctx == ctx) { + /* unbind current if deleting current context */ + WMesaMakeCurrent(NULL, NULL); + } + + /* clean up frame buffer resources */ + pwfb = wmesa_lookup_framebuffer(pwc->hDC); + if (pwfb) { + if (ctx->Visual.doubleBufferMode == 1) + wmDeleteBackingStore(pwfb); + wmesa_free_framebuffer(pwc->hDC); + } + + /* Release for device, not memory contexts */ + if (WindowFromDC(pwc->hDC) != NULL) + { + ReleaseDC(WindowFromDC(pwc->hDC), pwc->hDC); + } + DeleteObject(pwc->clearPen); + DeleteObject(pwc->clearBrush); + + _mesa_meta_free(ctx); + + _swsetup_DestroyContext(ctx); + _tnl_DestroyContext(ctx); + _vbo_DestroyContext(ctx); + _swrast_DestroyContext(ctx); + + _mesa_free_context_data(ctx); + free(pwc); +} + + +/** + * Create a new color renderbuffer. + */ +struct gl_renderbuffer * +wmesa_new_renderbuffer(void) +{ + struct gl_renderbuffer *rb = CALLOC_STRUCT(gl_renderbuffer); + if (!rb) + return NULL; + + _mesa_init_renderbuffer(rb, (GLuint)0); + + rb->_BaseFormat = GL_RGBA; + rb->InternalFormat = GL_RGBA; + rb->DataType = CHAN_TYPE; + rb->Delete = wmesa_delete_renderbuffer; + rb->AllocStorage = wmesa_renderbuffer_storage; + return rb; +} + + +void WMesaMakeCurrent(WMesaContext c, HDC hdc) +{ + WMesaFramebuffer pwfb; + + { + /* return if already current */ + GET_CURRENT_CONTEXT(ctx); + WMesaContext pwc = wmesa_context(ctx); + if (pwc && c == pwc && pwc->hDC == hdc) + return; + } + + pwfb = wmesa_lookup_framebuffer(hdc); + + /* Lazy creation of framebuffers */ + if (c && !pwfb && hdc) { + struct gl_renderbuffer *rb; + struct gl_config *visual = &c->gl_ctx.Visual; + GLuint width, height; + + get_window_size(hdc, &width, &height); + + c->clearPen = CreatePen(PS_SOLID, 1, 0); + c->clearBrush = CreateSolidBrush(0); + + pwfb = wmesa_new_framebuffer(hdc, visual); + + /* Create back buffer if double buffered */ + if (visual->doubleBufferMode == 1) { + wmCreateBackingStore(pwfb, width, height); + } + + /* make render buffers */ + if (visual->doubleBufferMode == 1) { + rb = wmesa_new_renderbuffer(); + _mesa_add_renderbuffer(&pwfb->Base, BUFFER_BACK_LEFT, rb); + wmesa_set_renderbuffer_funcs(rb, pwfb->pixelformat, pwfb->cColorBits, 1); + } + rb = wmesa_new_renderbuffer(); + _mesa_add_renderbuffer(&pwfb->Base, BUFFER_FRONT_LEFT, rb); + wmesa_set_renderbuffer_funcs(rb, pwfb->pixelformat, pwfb->cColorBits, 0); + + /* Let Mesa own the Depth, Stencil, and Accum buffers */ + _mesa_add_soft_renderbuffers(&pwfb->Base, + GL_FALSE, /* color */ + visual->depthBits > 0, + visual->stencilBits > 0, + visual->accumRedBits > 0, + visual->alphaBits >0, + GL_FALSE); + } + + if (c && pwfb) + _mesa_make_current(&c->gl_ctx, &pwfb->Base, &pwfb->Base); + else + _mesa_make_current(NULL, NULL, NULL); +} + + +void WMesaSwapBuffers( HDC hdc ) +{ + GET_CURRENT_CONTEXT(ctx); + WMesaContext pwc = wmesa_context(ctx); + WMesaFramebuffer pwfb = wmesa_lookup_framebuffer(hdc); + + if (!pwfb) { + _mesa_problem(NULL, "wmesa: swapbuffers on unknown hdc"); + return; + } + + /* If we're swapping the buffer associated with the current context + * we have to flush any pending rendering commands first. + */ + if (pwc->hDC == hdc) { + _mesa_notifySwapBuffers(ctx); + + BitBlt(pwfb->hDC, 0, 0, pwfb->Base.Width, pwfb->Base.Height, + pwfb->dib_hDC, 0, 0, SRCCOPY); + } + else { + /* XXX for now only allow swapping current window */ + _mesa_problem(NULL, "wmesa: can't swap non-current window"); + } +} + +void WMesaShareLists(WMesaContext ctx_to_share, WMesaContext ctx) +{ + _mesa_share_state(&ctx->gl_ctx, &ctx_to_share->gl_ctx); +} + diff --git a/mesalib/src/mesa/drivers/windows/gldirect/dglcontext.c b/mesalib/src/mesa/drivers/windows/gldirect/dglcontext.c index fabce4c0b..9aedd2e3c 100644 --- a/mesalib/src/mesa/drivers/windows/gldirect/dglcontext.c +++ b/mesalib/src/mesa/drivers/windows/gldirect/dglcontext.c @@ -1,2212 +1,2212 @@ -/**************************************************************************** -* -* Mesa 3-D graphics library -* Direct3D Driver Interface -* -* ======================================================================== -* -* Copyright (C) 1991-2004 SciTech Software, Inc. 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 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 -* SCITECH SOFTWARE INC 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. -* -* ====================================================================== -* -* Language: ANSI C -* Environment: Windows 9x (Win32) -* -* Description: Context handling. -* -****************************************************************************/ - -#include "dglcontext.h" - -// Get compile errors without this. KeithH -//#include "scitech.h" // ibool, etc. - -#ifdef _USE_GLD3_WGL -#include "gld_driver.h" - -extern void _gld_mesa_warning(struct gl_context *, char *); -extern void _gld_mesa_fatal(struct gl_context *, char *); -#endif // _USE_GLD3_WGL - -// TODO: Clean out old DX6-specific code from GLD 2.x CAD driver -// if it is no longer being built as part of GLDirect. (DaveM) - -// *********************************************************************** - -#define GLDERR_NONE 0 -#define GLDERR_MEM 1 -#define GLDERR_DDRAW 2 -#define GLDERR_D3D 3 -#define GLDERR_BPP 4 - -char szResourceWarning[] = -"GLDirect does not have enough video memory resources\n" -"to support the requested OpenGL rendering context.\n\n" -"You may have to reduce the current display resolution\n" -"to obtain satisfactory OpenGL performance.\n"; - -char szDDrawWarning[] = -"GLDirect is unable to initialize DirectDraw for the\n" -"requested OpenGL rendering context.\n\n" -"You will have to check the DirectX control panel\n" -"for further information.\n"; - -char szD3DWarning[] = -"GLDirect is unable to initialize Direct3D for the\n" -"requested OpenGL rendering context.\n\n" -"You may have to change the display mode resolution\n" -"color depth or check the DirectX control panel for\n" -"further information.\n"; - -char szBPPWarning[] = -"GLDirect is unable to use the selected color depth for\n" -"the requested OpenGL rendering context.\n\n" -"You will have to change the display mode resolution\n" -"color depth with the Display Settings control panel.\n"; - -int nContextError = GLDERR_NONE; - -// *********************************************************************** - -#define VENDORID_ATI 0x1002 - -static DWORD devATIRagePro[] = { - 0x4742, // 3D RAGE PRO BGA AGP 1X/2X - 0x4744, // 3D RAGE PRO BGA AGP 1X only - 0x4749, // 3D RAGE PRO BGA PCI 33 MHz - 0x4750, // 3D RAGE PRO PQFP PCI 33 MHz - 0x4751, // 3D RAGE PRO PQFP PCI 33 MHz limited 3D - 0x4C42, // 3D RAGE LT PRO BGA-312 AGP 133 MHz - 0x4C44, // 3D RAGE LT PRO BGA-312 AGP 66 MHz - 0x4C49, // 3D RAGE LT PRO BGA-312 PCI 33 MHz - 0x4C50, // 3D RAGE LT PRO BGA-256 PCI 33 MHz - 0x4C51, // 3D RAGE LT PRO BGA-256 PCI 33 MHz limited 3D -}; - -static DWORD devATIRageIIplus[] = { - 0x4755, // 3D RAGE II+ - 0x4756, // 3D RAGE IIC PQFP PCI - 0x4757, // 3D RAGE IIC BGA AGP - 0x475A, // 3D RAGE IIC PQFP AGP - 0x4C47, // 3D RAGE LT-G -}; - -// *********************************************************************** - -#ifndef _USE_GLD3_WGL -extern DGL_mesaFuncs mesaFuncs; -#endif - -extern DWORD dwLogging; - -#ifdef GLD_THREADS -#pragma message("compiling DGLCONTEXT.C vars for multi-threaded support") -CRITICAL_SECTION CriticalSection; // for serialized access -DWORD dwTLSCurrentContext = 0xFFFFFFFF; // TLS index for current context -DWORD dwTLSPixelFormat = 0xFFFFFFFF; // TLS index for current pixel format -#endif -HGLRC iCurrentContext = 0; // Index of current context (static) -BOOL bContextReady = FALSE; // Context state ready ? - -DGL_ctx ctxlist[DGL_MAX_CONTEXTS]; // Context list - -// *********************************************************************** - -static BOOL bHaveWin95 = FALSE; -static BOOL bHaveWinNT = FALSE; -static BOOL bHaveWin2K = FALSE; - -/**************************************************************************** -REMARKS: -Detect the installed OS type. -****************************************************************************/ -static void DetectOS(void) -{ - OSVERSIONINFO VersionInformation; - LPOSVERSIONINFO lpVersionInformation = &VersionInformation; - - VersionInformation.dwOSVersionInfoSize = sizeof(VersionInformation); - - GetVersionEx(lpVersionInformation); - - switch (VersionInformation.dwPlatformId) { - case VER_PLATFORM_WIN32_WINDOWS: - bHaveWin95 = TRUE; - bHaveWinNT = FALSE; - bHaveWin2K = FALSE; - break; - case VER_PLATFORM_WIN32_NT: - bHaveWin95 = FALSE; - if (VersionInformation.dwMajorVersion <= 4) { - bHaveWinNT = TRUE; - bHaveWin2K = FALSE; - } - else { - bHaveWinNT = FALSE; - bHaveWin2K = TRUE; - } - break; - case VER_PLATFORM_WIN32s: - bHaveWin95 = FALSE; - bHaveWinNT = FALSE; - bHaveWin2K = FALSE; - break; - } -} - -// *********************************************************************** - -HWND hWndEvent = NULL; // event monitor window -HWND hWndLastActive = NULL; // last active client window -LONG __stdcall GLD_EventWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); - -// *********************************************************************** - -// Checks if the HGLRC is valid in range of context list. -BOOL dglIsValidContext( - HGLRC a) -{ - return ((int)a > 0 && (int)a <= DGL_MAX_CONTEXTS); -} - -// *********************************************************************** - -// Convert a HGLRC to a pointer into the context list. -DGL_ctx* dglGetContextAddress( - const HGLRC a) -{ - if (dglIsValidContext(a)) - return &ctxlist[(int)a-1]; - return NULL; -} - -// *********************************************************************** - -// Return the current HGLRC (however it may be stored for multi-threading). -HGLRC dglGetCurrentContext(void) -{ -#ifdef GLD_THREADS - HGLRC hGLRC; - // load from thread-specific instance - if (glb.bMultiThreaded) { - // protect against calls from arbitrary threads - __try { - hGLRC = (HGLRC)TlsGetValue(dwTLSCurrentContext); - } - __except(EXCEPTION_EXECUTE_HANDLER) { - hGLRC = iCurrentContext; - } - } - // load from global static var - else { - hGLRC = iCurrentContext; - } - return hGLRC; -#else - return iCurrentContext; -#endif -} - -// *********************************************************************** - -// Set the current HGLRC (however it may be stored for multi-threading). -void dglSetCurrentContext(HGLRC hGLRC) -{ -#ifdef GLD_THREADS - // store in thread-specific instance - if (glb.bMultiThreaded) { - // protect against calls from arbitrary threads - __try { - TlsSetValue(dwTLSCurrentContext, (LPVOID)hGLRC); - } - __except(EXCEPTION_EXECUTE_HANDLER) { - iCurrentContext = hGLRC; - } - } - // store in global static var - else { - iCurrentContext = hGLRC; - } -#else - iCurrentContext = hGLRC; -#endif -} - -// *********************************************************************** - -// Return the current HDC only for a currently active HGLRC. -HDC dglGetCurrentDC(void) -{ - HGLRC hGLRC; - DGL_ctx* lpCtx; - - hGLRC = dglGetCurrentContext(); - if (hGLRC) { - lpCtx = dglGetContextAddress(hGLRC); - return lpCtx->hDC; - } - return 0; -} - -// *********************************************************************** - -void dglInitContextState() -{ - int i; - WNDCLASS wc; - -#ifdef GLD_THREADS - // Allocate thread local storage indexes for current context and pixel format - dwTLSCurrentContext = TlsAlloc(); - dwTLSPixelFormat = TlsAlloc(); -#endif - - dglSetCurrentContext(NULL); // No current rendering context - - // Clear all context data - ZeroMemory(ctxlist, sizeof(ctxlist[0]) * DGL_MAX_CONTEXTS); - - for (i=0; ilpfnWndProc; - break; - } - } - // Not one of ours... - if (!lpfnWndProc) - return DefWindowProc(hwnd, msg, wParam, lParam); - - // Intercept messages amd process *before* passing on to window - switch (msg) { -#ifdef _USE_GLD3_WGL - case WM_DISPLAYCHANGE: - glb.bPixelformatsDirty = TRUE; - break; -#endif - case WM_ACTIVATEAPP: - glb.bAppActive = (BOOL)wParam; - ddlogPrintf(DDLOG_INFO, "Calling app has been %s", glb.bAppActive ? "activated" : "de-activated"); - break; - case WM_ERASEBKGND: - // Eat the GDI erase event for the GL window - if (!lpCtx || !lpCtx->bHasBeenCurrent) - break; - lpCtx->bGDIEraseBkgnd = TRUE; - return TRUE; - case WM_PAINT: - // Eat the invalidated update region if render scene is in progress - if (!lpCtx || !lpCtx->bHasBeenCurrent) - break; - if (lpCtx->bFrameStarted) { - if (GetUpdateRect(hwnd, &rect, FALSE)) { - BeginPaint(hwnd, &ps); - EndPaint(hwnd, &ps); - ValidateRect(hwnd, &rect); - return TRUE; - } - } - break; - } - // Call the appropriate window message handler - rc = CallWindowProc((WNDPROC)lpfnWndProc, hwnd, msg, wParam, lParam); - - // Intercept messages and process *after* passing on to window - switch (msg) { - case WM_QUIT: - case WM_DESTROY: - bQuit = TRUE; - if (lpCtx && lpCtx->bAllocated) { - ddlogPrintf(DDLOG_WARN, "WM_DESTROY detected for HWND=%X, HDC=%X, HGLRC=%d", hwnd, lpCtx->hDC, i+1); - dglDeleteContext((HGLRC)(i+1)); - } - break; -#if 0 - case WM_SIZE: - // Resize surfaces to fit window but not viewport (in case app did not bother) - if (!lpCtx || !lpCtx->bHasBeenCurrent) - break; - w = LOWORD(lParam); - h = HIWORD(lParam); - if (lpCtx->dwWidth < w || lpCtx->dwHeight < h) { - if (!dglWglResizeBuffers(lpCtx->glCtx, TRUE)) - dglWglResizeBuffers(lpCtx->glCtx, FALSE); - } - break; -#endif - } - - // If the main window is quitting, then so should we... - if (bMain && bQuit) { - ddlogPrintf(DDLOG_SYSTEM, "shutting down after WM_DESTROY detected for main HWND=%X", hwnd); - dglDeleteContextState(); - dglExitDriver(); - } - - return rc; -} - -// *********************************************************************** - -// Driver Window message handler -static LONG __stdcall GLD_EventWndProc( - HWND hwnd, - UINT msg, - WPARAM wParam, - LPARAM lParam) -{ - switch (msg) { - // May be sent by splash screen dialog on exit - case WM_ACTIVATE: - if (LOWORD(wParam) == WA_ACTIVE && glb.hWndActive) { - SetForegroundWindow(glb.hWndActive); - return 0; - } - break; - } - return DefWindowProc(hwnd, msg, wParam, lParam); -} - -// *********************************************************************** - -// Intercepted Keyboard handler for detecting hot keys. -LRESULT CALLBACK dglKeyProc( - int code, - WPARAM wParam, - LPARAM lParam) -{ - HWND hWnd, hWndFrame; - HGLRC hGLRC = NULL; - DGL_ctx* lpCtx = NULL; - int cmd = 0, dx1 = 0, dx2 = 0, i; - static BOOL bAltPressed = FALSE; - static BOOL bCtrlPressed = FALSE; - static BOOL bShiftPressed = FALSE; - RECT r, rf, rc; - POINT pt; - BOOL bForceReshape = FALSE; - - return CallNextHookEx(hKeyHook, code, wParam, lParam); -} - -// *********************************************************************** - -HWND hWndMatch; - -// Window handle enumeration procedure. -BOOL CALLBACK dglEnumChildProc( - HWND hWnd, - LPARAM lParam) -{ - RECT rect; - - // Find window handle with matching client rect. - GetClientRect(hWnd, &rect); - if (EqualRect(&rect, (RECT*)lParam)) { - hWndMatch = hWnd; - return FALSE; - } - // Continue with next child window. - return TRUE; -} - -// *********************************************************************** - -// Find window handle with matching client rect. -HWND dglFindWindowRect( - RECT* pRect) -{ - hWndMatch = NULL; - EnumChildWindows(GetForegroundWindow(), dglEnumChildProc, (LPARAM)pRect); - return hWndMatch; -} - -// *********************************************************************** -#ifndef _USE_GLD3_WGL -void dglChooseDisplayMode( - DGL_ctx *lpCtx) -{ - // Note: Choose an exact match if possible. - - int i; - DWORD area; - DWORD bestarea; - DDSURFACEDESC2 *lpDDSD = NULL; // Mode list pointer - DDSURFACEDESC2 *lpBestDDSD = NULL; // Pointer to best - - lpDDSD = glb.lpDisplayModes; - for (i=0; idwWidth == lpCtx->dwWidth) && - (lpDDSD->dwHeight == lpCtx->dwHeight)) - goto matched; // Mode has been exactly matched - // Choose modes that are larger in both dimensions than - // the window, but smaller in area than the current best. - if ( (lpDDSD->dwWidth >= lpCtx->dwWidth) && - (lpDDSD->dwHeight >= lpCtx->dwHeight)) - { - if (lpBestDDSD == NULL) { - lpBestDDSD = lpDDSD; - bestarea = lpDDSD->dwWidth * lpDDSD->dwHeight; - continue; - } - area = lpDDSD->dwWidth * lpDDSD->dwHeight; - if (area < bestarea) { - lpBestDDSD = lpDDSD; - bestarea = area; - } - } - } - - // Safety check - if (lpBestDDSD == NULL) { - ddlogMessage(DDLOG_CRITICAL, "dglChooseDisplayMode"); - return; - } - - lpCtx->dwModeWidth = lpBestDDSD->dwWidth; - lpCtx->dwModeHeight = lpBestDDSD->dwHeight; -matched: - ddlogPrintf(DDLOG_INFO, "Matched (%ldx%ld) to (%ldx%ld)", - lpCtx->dwWidth, lpCtx->dwHeight, lpCtx->dwModeWidth, lpCtx->dwModeHeight); -} -#endif // _USE_GLD3_WGL -// *********************************************************************** - -static BOOL IsDevice( - DWORD *lpDeviceIdList, - DWORD dwDeviceId, - int count) -{ - int i; - - for (i=0; ilpDD4 == NULL) { - // Testing for broken cards is sensitive area, so we don't want - // anything saying "broken cards" in the error message. ;) - ddlogMessage(DDLOG_ERROR, "Null DD4 passed to TFBC\n"); - return; - } - - // Microsoft really fucked up with the GetDeviceIdentifier function - // on Windows 2000, since it locks up on stock driers on the CD. Updated - // drivers from vendors appear to work, but we can't identify the drivers - // without this function!!! For now we skip these tests on Windows 2000. - if ((GetVersion() & 0x80000000UL) == 0) - return; - - // Obtain device info - if (FAILED(IDirectDraw4_GetDeviceIdentifier(lpCtx->lpDD4, &dddi, 0))) - return; - - // Useful info. Log it. - ddlogPrintf(DDLOG_INFO, "DirectDraw: VendorId=0x%x, DeviceId=0x%x", dddi.dwVendorId, dddi.dwDeviceId); - - // Vendor 1: ATI - if (dddi.dwVendorId == VENDORID_ATI) { - // Test A: ATI Rage PRO - if (IsDevice(devATIRagePro, dddi.dwDeviceId, sizeof(devATIRagePro))) - glb.bUseMipmaps = FALSE; - // Test B: ATI Rage II+ - if (IsDevice(devATIRageIIplus, dddi.dwDeviceId, sizeof(devATIRageIIplus))) - glb.bEmulateAlphaTest = TRUE; - } - - // Vendor 2: Matrox - if (dddi.dwVendorId == 0x102B) { - // Test: Matrox G400 stencil buffer support does not work for AutoCAD - if (dddi.dwDeviceId == 0x0525) { - lpCtx->lpPF->pfd.cStencilBits = 0; - if (lpCtx->lpPF->iZBufferPF != -1) { - glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwStencilBitDepth = 0; - glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwStencilBitMask = 0; - glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwFlags &= ~DDPF_STENCILBUFFER; - } - } - } -#endif // _GLD3 -} - -// *********************************************************************** - -BOOL dglCreateContextBuffers( - HDC a, - DGL_ctx *lpCtx, - BOOL bFallback) -{ - HRESULT hResult; - - int i; -// HGLRC hGLRC; -// DGL_ctx* lpCtx; - -#ifndef _USE_GLD3_WGL - DWORD dwFlags; - DDSURFACEDESC2 ddsd2; - DDSCAPS2 ddscaps2; - LPDIRECTDRAWCLIPPER lpddClipper; - D3DDEVICEDESC D3DHWDevDesc; // Direct3D Hardware description - D3DDEVICEDESC D3DHELDevDesc; // Direct3D Hardware Emulation Layer -#endif // _USE_GLD3_WGL - - float inv_aspect; - - GLenum bDoubleBuffer; // TRUE if double buffer required - GLenum bDepthBuffer; // TRUE if depth buffer required - - const PIXELFORMATDESCRIPTOR *lpPFD = &lpCtx->lpPF->pfd; - - // Vars for Mesa visual - DWORD dwDepthBits = 0; - DWORD dwStencilBits = 0; - DWORD dwAlphaBits = 0; - DWORD bAlphaSW = GL_FALSE; - DWORD bDouble = GL_FALSE; - - DDSURFACEDESC2 ddsd2DisplayMode; - BOOL bFullScrnWin = FALSE; // fullscreen-size window ? - DDBLTFX ddbltfx; - DWORD dwMemoryType = (bFallback) ? DDSCAPS_SYSTEMMEMORY : glb.dwMemoryType; - BOOL bBogusWindow = FALSE; // non-drawable window ? - DWORD dwColorRef = 0; // GDI background color - RECT rcDst; // GDI window rect - POINT pt; // GDI window point - - // Palette used for creating default global palette - PALETTEENTRY ppe[256]; - -#ifndef _USE_GLD3_WGL - // Vertex buffer description. Used for creation of vertex buffers - D3DVERTEXBUFFERDESC vbufdesc; -#endif // _USE_GLD3_WGL - -#define DDLOG_CRITICAL_OR_WARN (bFallback ? DDLOG_CRITICAL : DDLOG_WARN) - - ddlogPrintf(DDLOG_SYSTEM, "dglCreateContextBuffers for HDC=%X", a); - nContextError = GLDERR_NONE; - -#ifdef GLD_THREADS - // Serialize access to DirectDraw object creation or DDS start - if (glb.bMultiThreaded) - EnterCriticalSection(&CriticalSection); -#endif - - // Check for back buffer - bDoubleBuffer = GL_TRUE; //(lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? GL_TRUE : GL_FALSE; - // Since we always do back buffering, check if we emulate front buffering - lpCtx->EmulateSingle = - (lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? FALSE : TRUE; -#if 0 // Don't have to mimic MS OpenGL behavior for front-buffering (DaveM) - lpCtx->EmulateSingle |= - (lpPFD->dwFlags & PFD_SUPPORT_GDI) ? TRUE : FALSE; -#endif - - // Check for depth buffer - bDepthBuffer = (lpPFD->cDepthBits) ? GL_TRUE : GL_FALSE; - - lpCtx->bDoubleBuffer = bDoubleBuffer; - lpCtx->bDepthBuffer = bDepthBuffer; - - // Set the Fullscreen flag for the context. -// lpCtx->bFullscreen = glb.bFullscreen; - - // Obtain the dimensions of the rendering window - lpCtx->hDC = a; // Cache DC - lpCtx->hWnd = WindowFromDC(lpCtx->hDC); - // Check for non-window DC = memory DC ? - if (lpCtx->hWnd == NULL) { - // bitmap memory contexts are always single-buffered - lpCtx->EmulateSingle = TRUE; - bBogusWindow = TRUE; - ddlogPrintf(DDLOG_INFO, "Non-Window Memory Device Context"); - if (GetClipBox(lpCtx->hDC, &lpCtx->rcScreenRect) == ERROR) { - ddlogMessage(DDLOG_WARN, "GetClipBox failed in dglCreateContext\n"); - SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0); - } - } - else if (!GetClientRect(lpCtx->hWnd, &lpCtx->rcScreenRect)) { - bBogusWindow = TRUE; - ddlogMessage(DDLOG_WARN, "GetClientRect failed in dglCreateContext\n"); - SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0); - } - lpCtx->dwWidth = lpCtx->rcScreenRect.right - lpCtx->rcScreenRect.left; - lpCtx->dwHeight = lpCtx->rcScreenRect.bottom - lpCtx->rcScreenRect.top; - - ddlogPrintf(DDLOG_INFO, "Input window %X: w=%i, h=%i", - lpCtx->hWnd, lpCtx->dwWidth, lpCtx->dwHeight); - - // What if app only zeroes one dimension instead of both? (DaveM) - if ( (lpCtx->dwWidth == 0) || (lpCtx->dwHeight == 0) ) { - // Make the buffer size something sensible - lpCtx->dwWidth = 8; - lpCtx->dwHeight = 8; - } - - // Set defaults - lpCtx->dwModeWidth = lpCtx->dwWidth; - lpCtx->dwModeHeight = lpCtx->dwHeight; -/* - // Find best display mode for fullscreen - if (glb.bFullscreen || !glb.bPrimary) { - dglChooseDisplayMode(lpCtx); - } -*/ - // Misc initialisation - lpCtx->bCanRender = FALSE; // No rendering allowed yet - lpCtx->bSceneStarted = FALSE; - lpCtx->bFrameStarted = FALSE; - - // Detect OS (specifically 'Windows 2000' or 'Windows XP') - DetectOS(); - - // NOTE: WinNT not supported - ddlogPrintf(DDLOG_INFO, "OS: %s", bHaveWin95 ? "Win9x" : (bHaveWin2K ? "Win2000/XP" : "Unsupported") ); - - // Test for Fullscreen - if (bHaveWin95) { // Problems with fullscreen on Win2K/XP - if ((GetSystemMetrics(SM_CXSCREEN) == lpCtx->dwWidth) && - (GetSystemMetrics(SM_CYSCREEN) == lpCtx->dwHeight)) - { - // Workaround for some apps that crash when going fullscreen. - //lpCtx->bFullscreen = TRUE; - } - - } - -#ifdef _USE_GLD3_WGL - _gldDriver.CreateDrawable(lpCtx, glb.bDirectDrawPersistant, glb.bPersistantBuffers); -#else - // Check if DirectDraw has already been created by original GLRC (DaveM) - if (glb.bDirectDrawPersistant && glb.bDirectDraw) { - lpCtx->lpDD4 = glb.lpDD4; - IDirectDraw4_AddRef(lpCtx->lpDD4); - goto SkipDirectDrawCreate; - } - - // Create DirectDraw object - if (glb.bPrimary) - hResult = DirectDrawCreate(NULL, &lpCtx->lpDD1, NULL); - else { - // A non-primary device is to be used. - // Force context to be Fullscreen, secondary adaptors can not - // be used in a window. - hResult = DirectDrawCreate(&glb.ddGuid, &lpCtx->lpDD1, NULL); - lpCtx->bFullscreen = TRUE; - } - if (FAILED(hResult)) { - MessageBox(NULL, "Unable to initialize DirectDraw", "GLDirect", MB_OK); - ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create DirectDraw interface", hResult); - nContextError = GLDERR_DDRAW; - goto return_with_error; - } - - // Query for DX6 IDirectDraw4. - hResult = IDirectDraw_QueryInterface(lpCtx->lpDD1, - &IID_IDirectDraw4, - (void**)&lpCtx->lpDD4); - if (FAILED(hResult)) { - MessageBox(NULL, "GLDirect requires DirectX 6.0 or above", "GLDirect", MB_OK); - ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create DirectDraw4 interface", hResult); - nContextError = GLDERR_DDRAW; - goto return_with_error; - } - - // Cache DirectDraw interface for subsequent GLRCs - if (glb.bDirectDrawPersistant && !glb.bDirectDraw) { - glb.lpDD4 = lpCtx->lpDD4; - IDirectDraw4_AddRef(glb.lpDD4); - glb.bDirectDraw = TRUE; - } -SkipDirectDrawCreate: - - // Now we have a DD4 interface we can check for broken cards - dglTestForBrokenCards(lpCtx); - - // Test if primary device can use flipping instead of blitting - ZeroMemory(&ddsd2DisplayMode, sizeof(ddsd2DisplayMode)); - ddsd2DisplayMode.dwSize = sizeof(ddsd2DisplayMode); - hResult = IDirectDraw4_GetDisplayMode( - lpCtx->lpDD4, - &ddsd2DisplayMode); - if (SUCCEEDED(hResult)) { - if ( (lpCtx->dwWidth == ddsd2DisplayMode.dwWidth) && - (lpCtx->dwHeight == ddsd2DisplayMode.dwHeight) ) { - // We have a fullscreen-size window - bFullScrnWin = TRUE; - // OK to use DirectDraw fullscreen mode ? - if (glb.bPrimary && !glb.bFullscreenBlit && !lpCtx->EmulateSingle && !glb.bDirectDrawPersistant) { - lpCtx->bFullscreen = TRUE; - ddlogMessage(DDLOG_INFO, "Primary upgraded to page flipping.\n"); - } - } - // Cache the display mode dimensions - lpCtx->dwModeWidth = ddsd2DisplayMode.dwWidth; - lpCtx->dwModeHeight = ddsd2DisplayMode.dwHeight; - } - - // Clamp the effective window dimensions to primary surface. - // We need to do this for D3D viewport dimensions even if wide - // surfaces are supported. This also is a good idea for handling - // whacked-out window dimensions passed for non-drawable windows - // like Solid Edge. (DaveM) - if (lpCtx->dwWidth > ddsd2DisplayMode.dwWidth) - lpCtx->dwWidth = ddsd2DisplayMode.dwWidth; - if (lpCtx->dwHeight > ddsd2DisplayMode.dwHeight) - lpCtx->dwHeight = ddsd2DisplayMode.dwHeight; - - // Check for non-RGB desktop resolution - if (!lpCtx->bFullscreen && ddsd2DisplayMode.ddpfPixelFormat.dwRGBBitCount <= 8) { - ddlogPrintf(DDLOG_CRITICAL_OR_WARN, "Desktop color depth %d bpp not supported", - ddsd2DisplayMode.ddpfPixelFormat.dwRGBBitCount); - nContextError = GLDERR_BPP; - goto return_with_error; - } -#endif // _USE_GLD3_WGL - - ddlogPrintf(DDLOG_INFO, "Window: w=%i, h=%i (%s)", - lpCtx->dwWidth, - lpCtx->dwHeight, - lpCtx->bFullscreen ? "fullscreen" : "windowed"); - -#ifndef _USE_GLD3_WGL - // Obtain ddraw caps - ZeroMemory(&lpCtx->ddCaps, sizeof(DDCAPS)); - lpCtx->ddCaps.dwSize = sizeof(DDCAPS); - if (glb.bHardware) { - // Get HAL caps - IDirectDraw4_GetCaps(lpCtx->lpDD4, &lpCtx->ddCaps, NULL); - } else { - // Get HEL caps - IDirectDraw4_GetCaps(lpCtx->lpDD4, NULL, &lpCtx->ddCaps); - } - - // If this flag is present then we can't default to Mesa - // SW rendering between BeginScene() and EndScene(). - if (lpCtx->ddCaps.dwCaps2 & DDCAPS2_NO2DDURING3DSCENE) { - ddlogMessage(DDLOG_INFO, - "Warning : No 2D allowed during 3D scene.\n"); - } - - // Query for DX6 Direct3D3 interface - hResult = IDirectDraw4_QueryInterface(lpCtx->lpDD4, - &IID_IDirect3D3, - (void**)&lpCtx->lpD3D3); - if (FAILED(hResult)) { - MessageBox(NULL, "Unable to initialize Direct3D", "GLDirect", MB_OK); - ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create Direct3D interface", hResult); - nContextError = GLDERR_D3D; - goto return_with_error; - } - - // Context creation - if (lpCtx->bFullscreen) { - // FULLSCREEN - - // Disable warning popups when in fullscreen mode - ddlogWarnOption(FALSE); - - // Have to release persistant primary surface if fullscreen mode - if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) { - RELEASE(glb.lpPrimary4); - glb.bDirectDrawPrimary = FALSE; - } - - dwFlags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT; - if (glb.bFastFPU) - dwFlags |= DDSCL_FPUSETUP; // fast FPU setup optional (DaveM) - hResult = IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, lpCtx->hWnd, dwFlags); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to set Exclusive Fullscreen mode", hResult); - goto return_with_error; - } - - hResult = IDirectDraw4_SetDisplayMode(lpCtx->lpDD4, - lpCtx->dwModeWidth, - lpCtx->dwModeHeight, - lpPFD->cColorBits, - 0, - 0); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "SetDisplayMode failed", hResult); - goto return_with_error; - } - - // ** The display mode has changed, so dont use MessageBox! ** - - ZeroMemory(&ddsd2, sizeof(ddsd2)); - ddsd2.dwSize = sizeof(ddsd2); - - if (bDoubleBuffer) { - // Double buffered - // Primary surface - ddsd2.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; - ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | - DDSCAPS_FLIP | - DDSCAPS_COMPLEX | - DDSCAPS_3DDEVICE | - dwMemoryType; - ddsd2.dwBackBufferCount = 1; - - hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult); - nContextError = GLDERR_MEM; - goto return_with_error; - } - - // Render target surface - ZeroMemory(&ddscaps2, sizeof(ddscaps2)); // Clear the entire struct. - ddscaps2.dwCaps = DDSCAPS_BACKBUFFER; - hResult = IDirectDrawSurface4_GetAttachedSurface(lpCtx->lpFront4, &ddscaps2, &lpCtx->lpBack4); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "GetAttachedSurface failed", hResult); - nContextError = GLDERR_MEM; - goto return_with_error; - } - } else { - // Single buffered - // Primary surface - ddsd2.dwFlags = DDSD_CAPS; - ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | - //DDSCAPS_3DDEVICE | - dwMemoryType; - - hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult); - nContextError = GLDERR_MEM; - goto return_with_error; - } - - lpCtx->lpBack4 = NULL; - } - } else { - // WINDOWED - - // OK to enable warning popups in windowed mode - ddlogWarnOption(glb.bMessageBoxWarnings); - - dwFlags = DDSCL_NORMAL; - if (glb.bMultiThreaded) - dwFlags |= DDSCL_MULTITHREADED; - if (glb.bFastFPU) - dwFlags |= DDSCL_FPUSETUP; // fast FPU setup optional (DaveM) - hResult = IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, - lpCtx->hWnd, - dwFlags); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to set Normal coop level", hResult); - goto return_with_error; - } - // Has Primary surface already been created for original GLRC ? - // Note this can only be applicable for windowed modes - if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) { - lpCtx->lpFront4 = glb.lpPrimary4; - IDirectDrawSurface4_AddRef(lpCtx->lpFront4); - // Update the window on the default clipper - IDirectDrawSurface4_GetClipper(lpCtx->lpFront4, &lpddClipper); - IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd); - IDirectDrawClipper_Release(lpddClipper); - goto SkipPrimaryCreate; - } - - // Primary surface - ZeroMemory(&ddsd2, sizeof(ddsd2)); - ddsd2.dwSize = sizeof(ddsd2); - ddsd2.dwFlags = DDSD_CAPS; - ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult); - nContextError = GLDERR_MEM; - goto return_with_error; - } - - // Cache Primary surface for subsequent GLRCs - // Note this can only be applicable to subsequent windowed modes - if (glb.bDirectDrawPersistant && !glb.bDirectDrawPrimary) { - glb.lpPrimary4 = lpCtx->lpFront4; - IDirectDrawSurface4_AddRef(glb.lpPrimary4); - glb.bDirectDrawPrimary = TRUE; - } - - // Clipper object - hResult = DirectDrawCreateClipper(0, &lpddClipper, NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateClipper failed", hResult); - goto return_with_error; - } - hResult = IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd); - if (FAILED(hResult)) { - RELEASE(lpddClipper); - ddlogError(DDLOG_CRITICAL_OR_WARN, "SetHWnd failed", hResult); - goto return_with_error; - } - hResult = IDirectDrawSurface4_SetClipper(lpCtx->lpFront4, lpddClipper); - RELEASE(lpddClipper); // We have finished with it. - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "SetClipper failed", hResult); - goto return_with_error; - } -SkipPrimaryCreate: - - if (bDoubleBuffer) { - // Render target surface - ZeroMemory(&ddsd2, sizeof(ddsd2)); - ddsd2.dwSize = sizeof(ddsd2); - ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; - ddsd2.dwWidth = lpCtx->dwWidth; - ddsd2.dwHeight = lpCtx->dwHeight; - ddsd2.ddsCaps.dwCaps = DDSCAPS_3DDEVICE | - DDSCAPS_OFFSCREENPLAIN | - dwMemoryType; - - // Reserve the entire desktop size for persistant buffers option - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers) { - ddsd2.dwWidth = ddsd2DisplayMode.dwWidth; - ddsd2.dwHeight = ddsd2DisplayMode.dwHeight; - } - // Re-use original back buffer if persistant buffers exist - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpBack4) - hResult = IDirectDrawSurface4_AddRef(lpCtx->lpBack4 = glb.lpBack4); - else - hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpBack4, NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "Create Backbuffer failed", hResult); - nContextError = GLDERR_MEM; - goto return_with_error; - } - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpBack4) - IDirectDrawSurface4_AddRef(glb.lpBack4 = lpCtx->lpBack4); - } else { - lpCtx->lpBack4 = NULL; - } - } - - // - // Now create the Z-buffer - // - lpCtx->bStencil = FALSE; // Default to no stencil buffer - if (bDepthBuffer && (lpCtx->lpPF->iZBufferPF != -1)) { - // Get z-buffer dimensions from the render target - // Setup the surface desc for the z-buffer. - ZeroMemory(&ddsd2, sizeof(ddsd2)); - ddsd2.dwSize = sizeof(ddsd2); - ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; - ddsd2.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | dwMemoryType; - ddsd2.dwWidth = lpCtx->dwWidth; - ddsd2.dwHeight = lpCtx->dwHeight; - memcpy(&ddsd2.ddpfPixelFormat, - &glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF], - sizeof(DDPIXELFORMAT) ); - - // Reserve the entire desktop size for persistant buffers option - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers) { - ddsd2.dwWidth = ddsd2DisplayMode.dwWidth; - ddsd2.dwHeight = ddsd2DisplayMode.dwHeight; - } - - // Create a z-buffer - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpDepth4) - hResult = IDirectDrawSurface4_AddRef(lpCtx->lpDepth4 = glb.lpDepth4); - else - hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpDepth4, NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (ZBuffer) failed", hResult); - nContextError = GLDERR_MEM; - goto return_with_error; - } - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpDepth4) - IDirectDrawSurface4_AddRef(glb.lpDepth4 = lpCtx->lpDepth4); - else if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpDepth4 && glb.lpBack4) - IDirectDrawSurface4_DeleteAttachedSurface(glb.lpBack4, 0, glb.lpDepth4); - - // Attach Zbuffer to render target - TRY(IDirectDrawSurface4_AddAttachedSurface( - bDoubleBuffer ? lpCtx->lpBack4 : lpCtx->lpFront4, - lpCtx->lpDepth4), - "dglCreateContext: Attach Zbuffer"); - if (glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwFlags & DDPF_STENCILBUFFER) { - lpCtx->bStencil = TRUE; - ddlogMessage(DDLOG_INFO, "Depth buffer has stencil\n"); - } - } - - // Clear all back buffers and Z-buffers in case of memory recycling. - ZeroMemory(&ddbltfx, sizeof(ddbltfx)); - ddbltfx.dwSize = sizeof(ddbltfx); - IDirectDrawSurface4_Blt(lpCtx->lpBack4, NULL, NULL, NULL, - DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); - if (lpCtx->lpDepth4) - IDirectDrawSurface4_Blt(lpCtx->lpDepth4, NULL, NULL, NULL, - DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); - - // Now that we have a Z-buffer we can create the 3D device - hResult = IDirect3D3_CreateDevice(lpCtx->lpD3D3, - &glb.d3dGuid, - bDoubleBuffer ? lpCtx->lpBack4 : lpCtx->lpFront4, - &lpCtx->lpDev3, - NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create Direct3D device", hResult); - nContextError = GLDERR_D3D; - goto return_with_error; - } - - // We must do this as soon as the device is created - dglInitStateCaches(lpCtx); - - // Obtain the D3D Device Description - D3DHWDevDesc.dwSize = D3DHELDevDesc.dwSize = sizeof(D3DDEVICEDESC); - TRY(IDirect3DDevice3_GetCaps(lpCtx->lpDev3, - &D3DHWDevDesc, - &D3DHELDevDesc), - "dglCreateContext: GetCaps failed"); - - // Choose the relevant description and cache it in the context. - // We will use this description later for caps checking - memcpy( &lpCtx->D3DDevDesc, - glb.bHardware ? &D3DHWDevDesc : &D3DHELDevDesc, - sizeof(D3DDEVICEDESC)); - - // Now we can examine the texture formats - if (!dglBuildTextureFormatList(lpCtx->lpDev3)) { - ddlogMessage(DDLOG_CRITICAL_OR_WARN, "dglBuildTextureFormatList failed\n"); - goto return_with_error; - } - - // Get the pixel format of the back buffer - lpCtx->ddpfRender.dwSize = sizeof(lpCtx->ddpfRender); - if (bDoubleBuffer) - hResult = IDirectDrawSurface4_GetPixelFormat( - lpCtx->lpBack4, - &lpCtx->ddpfRender); - else - hResult = IDirectDrawSurface4_GetPixelFormat( - lpCtx->lpFront4, - &lpCtx->ddpfRender); - - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "GetPixelFormat failed", hResult); - goto return_with_error; - } - // Find a pixel packing function suitable for this surface - pxClassifyPixelFormat(&lpCtx->ddpfRender, - &lpCtx->fnPackFunc, - &lpCtx->fnUnpackFunc, - &lpCtx->fnPackSpanFunc); - - // Viewport - hResult = IDirect3D3_CreateViewport(lpCtx->lpD3D3, &lpCtx->lpViewport3, NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateViewport failed", hResult); - goto return_with_error; - } - - hResult = IDirect3DDevice3_AddViewport(lpCtx->lpDev3, lpCtx->lpViewport3); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "AddViewport failed", hResult); - goto return_with_error; - } - - // Initialise the viewport - // Note screen coordinates are used for viewport clipping since D3D - // transform operations are not used in the GLD CAD driver. (DaveM) - inv_aspect = (float)lpCtx->dwHeight/(float)lpCtx->dwWidth; - - lpCtx->d3dViewport.dwSize = sizeof(lpCtx->d3dViewport); - lpCtx->d3dViewport.dwX = 0; - lpCtx->d3dViewport.dwY = 0; - lpCtx->d3dViewport.dwWidth = lpCtx->dwWidth; - lpCtx->d3dViewport.dwHeight = lpCtx->dwHeight; - lpCtx->d3dViewport.dvClipX = 0; // -1.0f; - lpCtx->d3dViewport.dvClipY = 0; // inv_aspect; - lpCtx->d3dViewport.dvClipWidth = lpCtx->dwWidth; // 2.0f; - lpCtx->d3dViewport.dvClipHeight = lpCtx->dwHeight; // 2.0f * inv_aspect; - lpCtx->d3dViewport.dvMinZ = 0.0f; - lpCtx->d3dViewport.dvMaxZ = 1.0f; - TRY(IDirect3DViewport3_SetViewport2(lpCtx->lpViewport3, &lpCtx->d3dViewport), "dglCreateContext: SetViewport2"); - - hResult = IDirect3DDevice3_SetCurrentViewport(lpCtx->lpDev3, lpCtx->lpViewport3); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "SetCurrentViewport failed", hResult); - goto return_with_error; - } - - lpCtx->dwBPP = lpPFD->cColorBits; - lpCtx->iZBufferPF = lpCtx->lpPF->iZBufferPF; - - // Set last texture to NULL - for (i=0; iColorOp[i] = D3DTOP_DISABLE; - lpCtx->AlphaOp[i] = D3DTOP_DISABLE; - lpCtx->tObj[i] = NULL; - } - - // Default to perspective correct texture mapping - dglSetRenderState(lpCtx, D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE, "TexturePersp"); - - // Set the default culling mode - lpCtx->cullmode = D3DCULL_NONE; - dglSetRenderState(lpCtx, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE, "CullMode"); - - // Disable specular - dglSetRenderState(lpCtx, D3DRENDERSTATE_SPECULARENABLE, FALSE, "SpecularEnable"); - // Disable subpixel correction -// dglSetRenderState(lpCtx, D3DRENDERSTATE_SUBPIXEL, FALSE, "SubpixelEnable"); - // Disable dithering - dglSetRenderState(lpCtx, D3DRENDERSTATE_DITHERENABLE, FALSE, "DitherEnable"); - - // Initialise the primitive caches -// lpCtx->dwNextLineVert = 0; -// lpCtx->dwNextTriVert = 0; - - // Init the global texture palette - lpCtx->lpGlobalPalette = NULL; - - // Init the HW/SW usage counters -// lpCtx->dwHWUsageCount = lpCtx->dwSWUsageCount = 0L; - - // - // Create two D3D vertex buffers. - // One will hold the pre-transformed data with the other one - // being used to hold the post-transformed & clipped verts. - // -#if 0 // never used (DaveM) - vbufdesc.dwSize = sizeof(D3DVERTEXBUFFERDESC); - vbufdesc.dwCaps = D3DVBCAPS_WRITEONLY; - if (glb.bHardware == FALSE) - vbufdesc.dwCaps = D3DVBCAPS_SYSTEMMEMORY; - vbufdesc.dwNumVertices = 32768; // For the time being - - // Source vertex buffer - vbufdesc.dwFVF = DGL_LVERTEX; - hResult = IDirect3D3_CreateVertexBuffer(lpCtx->lpD3D3, &vbufdesc, &lpCtx->m_vbuf, 0, NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateVertexBuffer(src) failed", hResult); - goto return_with_error; - } - - // Destination vertex buffer - vbufdesc.dwFVF = (glb.bMultitexture == FALSE) ? D3DFVF_TLVERTEX : (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX2); - hResult = IDirect3D3_CreateVertexBuffer(lpCtx->lpD3D3, &vbufdesc, &lpCtx->m_pvbuf, 0, NULL); - if(FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateVertexBuffer(dst) failed", hResult); - goto return_with_error; - } -#endif - -#endif _USE_GLD3_WGL - - // - // Now create the Mesa context - // - - // Create the Mesa visual - if (lpPFD->cDepthBits) - dwDepthBits = 16; - if (lpPFD->cStencilBits) - dwStencilBits = 8; - if (lpPFD->cAlphaBits) { - dwAlphaBits = 8; - bAlphaSW = GL_TRUE; - } - if (lpPFD->dwFlags & PFD_DOUBLEBUFFER) - bDouble = GL_TRUE; -// lpCtx->EmulateSingle = -// (lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? FALSE : TRUE; - -#ifdef _USE_GLD3_WGL - lpCtx->glVis = _mesa_create_visual( - bDouble, /* double buffer */ - GL_FALSE, // stereo - lpPFD->cRedBits, - lpPFD->cGreenBits, - lpPFD->cBlueBits, - dwAlphaBits, - dwDepthBits, - dwStencilBits, - lpPFD->cAccumRedBits, // accum bits - lpPFD->cAccumGreenBits, // accum bits - lpPFD->cAccumBlueBits, // accum bits - lpPFD->cAccumAlphaBits, // accum alpha bits - 1 // num samples - ); -#else // _USE_GLD3_WGL - lpCtx->glVis = (*mesaFuncs.gl_create_visual)( - GL_TRUE, // RGB mode - bAlphaSW, // Is an alpha buffer required? - bDouble, // Is an double-buffering required? - GL_FALSE, // stereo - dwDepthBits, // depth_size - dwStencilBits, // stencil_size - lpPFD->cAccumBits, // accum_size - 0, // colour-index bits - lpPFD->cRedBits, // Red bit count - lpPFD->cGreenBits, // Green bit count - lpPFD->cBlueBits, // Blue bit count - dwAlphaBits // Alpha bit count - ); -#endif // _USE_GLD3_WGL - - if (lpCtx->glVis == NULL) { - ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_visual failed\n"); - goto return_with_error; - } - -#ifdef _USE_GLD3_WGL - lpCtx->glCtx = _mesa_create_context(lpCtx->glVis, NULL, (void *)lpCtx, GL_TRUE); -#else - // Create the Mesa context - lpCtx->glCtx = (*mesaFuncs.gl_create_context)( - lpCtx->glVis, // Mesa visual - NULL, // share list context - (void *)lpCtx, // Pointer to our driver context - GL_TRUE // Direct context flag - ); -#endif // _USE_GLD3_WGL - - if (lpCtx->glCtx == NULL) { - ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_context failed\n"); - goto return_with_error; - } - - // Create the Mesa framebuffer -#ifdef _USE_GLD3_WGL - lpCtx->glBuffer = _mesa_create_framebuffer( - lpCtx->glVis, - lpCtx->glVis->depthBits > 0, - lpCtx->glVis->stencilBits > 0, - lpCtx->glVis->accumRedBits > 0, - GL_FALSE //swalpha - ); -#else - lpCtx->glBuffer = (*mesaFuncs.gl_create_framebuffer)(lpCtx->glVis); -#endif // _USE_GLD3_WGL - - if (lpCtx->glBuffer == NULL) { - ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_framebuffer failed\n"); - goto return_with_error; - } - -#ifdef _USE_GLD3_WGL - // Init Mesa internals - _swrast_CreateContext( lpCtx->glCtx ); - _vbo_CreateContext( lpCtx->glCtx ); - _tnl_CreateContext( lpCtx->glCtx ); - _swsetup_CreateContext( lpCtx->glCtx ); - - _gldDriver.InitialiseMesa(lpCtx); - - lpCtx->glCtx->imports.warning = _gld_mesa_warning; - lpCtx->glCtx->imports.fatal = _gld_mesa_fatal; - -#else - // Tell Mesa how many texture stages we have - glb.wMaxSimultaneousTextures = lpCtx->D3DDevDesc.wMaxSimultaneousTextures; - // Only use as many Units as the spec requires - if (glb.wMaxSimultaneousTextures > MAX_TEXTURE_UNITS) - glb.wMaxSimultaneousTextures = MAX_TEXTURE_UNITS; - lpCtx->glCtx->Const.MaxTextureUnits = glb.wMaxSimultaneousTextures; - ddlogPrintf(DDLOG_INFO, "Texture stages : %d", glb.wMaxSimultaneousTextures); - - // Set the max texture size. - // NOTE: clamped to a max of 1024 for extra performance! - lpCtx->dwMaxTextureSize = (lpCtx->D3DDevDesc.dwMaxTextureWidth <= 1024) ? lpCtx->D3DDevDesc.dwMaxTextureWidth : 1024; - -// Texture resize takes place elsewhere. KH -// NOTE: This was added to workaround an issue with the Intel app. -#if 0 - lpCtx->glCtx->Const.MaxTextureSize = lpCtx->dwMaxTextureSize; -#else - lpCtx->glCtx->Const.MaxTextureSize = 1024; -#endif - lpCtx->glCtx->Const.MaxDrawBuffers = 1; - - // Setup the Display Driver pointers - dglSetupDDPointers(lpCtx->glCtx); - - // Initialise all the Direct3D renderstates - dglInitStateD3D(lpCtx->glCtx); - -#if 0 - // Signal a reload of texture state on next glBegin - lpCtx->m_texHandleValid = FALSE; - lpCtx->m_mtex = FALSE; - lpCtx->m_texturing = FALSE; -#else - // Set default texture unit state -// dglSetTexture(lpCtx, 0, NULL); -// dglSetTexture(lpCtx, 1, NULL); -#endif - - // - // Set the global texture palette to default values. - // - - // Clear the entire palette - ZeroMemory(ppe, sizeof(PALETTEENTRY) * 256); - - // Fill the palette with a default colour. - // A garish colour is used to catch bugs. Here Magenta is used. - for (i=0; i < 256; i++) { - ppe[i].peRed = 255; - ppe[i].peGreen = 0; - ppe[i].peBlue = 255; - } - - RELEASE(lpCtx->lpGlobalPalette); - - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpGlobalPalette) - hResult = IDirectDrawPalette_AddRef(lpCtx->lpGlobalPalette = glb.lpGlobalPalette); - else - hResult = IDirectDraw4_CreatePalette( - lpCtx->lpDD4, - DDPCAPS_INITIALIZE | DDPCAPS_8BIT | DDPCAPS_ALLOW256, - ppe, - &(lpCtx->lpGlobalPalette), - NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_ERROR, "Default CreatePalette failed\n", hResult); - lpCtx->lpGlobalPalette = NULL; - goto return_with_error; - } - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpGlobalPalette) - IDirectDrawPalette_AddRef(glb.lpGlobalPalette = lpCtx->lpGlobalPalette); - -#endif // _USE_GLD3_WGL - - // ** If we have made it to here then we can enable rendering ** - lpCtx->bCanRender = TRUE; - -// ddlogMessage(DDLOG_SYSTEM, "dglCreateContextBuffers succeded\n"); - -#ifdef GLD_THREADS - // Release serialized access - if (glb.bMultiThreaded) - LeaveCriticalSection(&CriticalSection); -#endif - - return TRUE; - -return_with_error: - // Clean up before returning. - // This is critical for secondary devices. - - lpCtx->bCanRender = FALSE; - -#ifdef _USE_GLD3_WGL - // Destroy the Mesa context - if (lpCtx->glBuffer) - _mesa_destroy_framebuffer(lpCtx->glBuffer); - if (lpCtx->glCtx) - _mesa_destroy_context(lpCtx->glCtx); - if (lpCtx->glVis) - _mesa_destroy_visual(lpCtx->glVis); - - // Destroy driver data - _gldDriver.DestroyDrawable(lpCtx); -#else - // Destroy the Mesa context - if (lpCtx->glBuffer) - (*mesaFuncs.gl_destroy_framebuffer)(lpCtx->glBuffer); - if (lpCtx->glCtx) - (*mesaFuncs.gl_destroy_context)(lpCtx->glCtx); - if (lpCtx->glVis) - (*mesaFuncs.gl_destroy_visual)(lpCtx->glVis); - - RELEASE(lpCtx->m_pvbuf); // Release D3D vertex buffer - RELEASE(lpCtx->m_vbuf); // Release D3D vertex buffer - - if (lpCtx->lpViewport3) { - if (lpCtx->lpDev3) IDirect3DDevice3_DeleteViewport(lpCtx->lpDev3, lpCtx->lpViewport3); - RELEASE(lpCtx->lpViewport3); - lpCtx->lpViewport3 = NULL; - } - - RELEASE(lpCtx->lpDev3); - if (lpCtx->lpDepth4) { - if (lpCtx->lpBack4) - IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpBack4, 0L, lpCtx->lpDepth4); - else - IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpFront4, 0L, lpCtx->lpDepth4); - RELEASE(lpCtx->lpDepth4); - lpCtx->lpDepth4 = NULL; - } - RELEASE(lpCtx->lpBack4); - RELEASE(lpCtx->lpFront4); - else - if (lpCtx->bFullscreen) { - IDirectDraw4_RestoreDisplayMode(lpCtx->lpDD4); - IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, NULL, DDSCL_NORMAL); - } - RELEASE(lpCtx->lpD3D3); - RELEASE(lpCtx->lpDD4); - RELEASE(lpCtx->lpDD1); -#endif // _USE_GLD3_WGL - - lpCtx->bAllocated = FALSE; - -#ifdef GLD_THREADS - // Release serialized access - if (glb.bMultiThreaded) - LeaveCriticalSection(&CriticalSection); -#endif - - return FALSE; - -#undef DDLOG_CRITICAL_OR_WARN -} - -// *********************************************************************** - -HGLRC dglCreateContext( - HDC a, - const DGL_pixelFormat *lpPF) -{ - int i; - HGLRC hGLRC; - DGL_ctx* lpCtx; - static BOOL bWarnOnce = TRUE; - DWORD dwThreadId = GetCurrentThreadId(); - char szMsg[256]; - HWND hWnd; - LONG lpfnWndProc; - - // Validate license - if (!dglValidate()) - return NULL; - - // Is context state ready ? - if (!bContextReady) - return NULL; - - ddlogPrintf(DDLOG_SYSTEM, "dglCreateContext for HDC=%X, ThreadId=%X", a, dwThreadId); - - // Find next free context. - // Also ensure that only one Fullscreen context is created at any one time. - hGLRC = 0; // Default to Not Found - for (i=0; ibAllocated = TRUE; - // Flag that buffers need creating on next wglMakeCurrent call. - lpCtx->bHasBeenCurrent = FALSE; - lpCtx->lpPF = (DGL_pixelFormat *)lpPF; // cache pixel format - lpCtx->bCanRender = FALSE; - - // Create all the internal resources here, not in dglMakeCurrent(). - // We do a re-size check in dglMakeCurrent in case of re-allocations. (DaveM) - // We now try context allocations twice, first with video memory, - // then again with system memory. This is similar to technique - // used for dglWglResizeBuffers(). (DaveM) - if (lpCtx->bHasBeenCurrent == FALSE) { - if (!dglCreateContextBuffers(a, lpCtx, FALSE)) { - if (glb.bMessageBoxWarnings && bWarnOnce && dwLogging) { - bWarnOnce = FALSE; - switch (nContextError) { - case GLDERR_DDRAW: strcpy(szMsg, szDDrawWarning); break; - case GLDERR_D3D: strcpy(szMsg, szD3DWarning); break; - case GLDERR_MEM: strcpy(szMsg, szResourceWarning); break; - case GLDERR_BPP: strcpy(szMsg, szBPPWarning); break; - default: strcpy(szMsg, ""); - } - if (strlen(szMsg)) - MessageBox(NULL, szMsg, "GLDirect", MB_OK | MB_ICONWARNING); - } - // Only need to try again if memory error - if (nContextError == GLDERR_MEM) { - ddlogPrintf(DDLOG_WARN, "dglCreateContext failed 1st time with video memory"); - } - else { - ddlogPrintf(DDLOG_ERROR, "dglCreateContext failed"); - return NULL; - } - } - } - - // Now that we have a hWnd, we can intercept the WindowProc. - hWnd = lpCtx->hWnd; - if (hWnd) { - // Only hook individual window handler once if not hooked before. - lpfnWndProc = GetWindowLong(hWnd, GWL_WNDPROC); - if (lpfnWndProc != (LONG)dglWndProc) { - lpCtx->lpfnWndProc = lpfnWndProc; - SetWindowLong(hWnd, GWL_WNDPROC, (LONG)dglWndProc); - } - // Find the parent window of the app too. - if (glb.hWndActive == NULL) { - while (hWnd != NULL) { - glb.hWndActive = hWnd; - hWnd = GetParent(hWnd); - } - // Hook the parent window too. - lpfnWndProc = GetWindowLong(glb.hWndActive, GWL_WNDPROC); - if (glb.hWndActive == lpCtx->hWnd) - glb.lpfnWndProc = lpCtx->lpfnWndProc; - else if (lpfnWndProc != (LONG)dglWndProc) - glb.lpfnWndProc = lpfnWndProc; - if (glb.lpfnWndProc) - SetWindowLong(glb.hWndActive, GWL_WNDPROC, (LONG)dglWndProc); - } - } - - ddlogPrintf(DDLOG_SYSTEM, "dglCreateContext succeeded for HGLRC=%d", (int)hGLRC); - - return hGLRC; -} - -// *********************************************************************** -// Make a DirectGL context current -// Used by wgl functions and dgl functions -BOOL dglMakeCurrent( - HDC a, - HGLRC b) -{ - int context; - DGL_ctx* lpCtx; - HWND hWnd; - BOOL bNeedResize = FALSE; - BOOL bWindowChanged, bContextChanged; - LPDIRECTDRAWCLIPPER lpddClipper; - DWORD dwThreadId = GetCurrentThreadId(); - LONG lpfnWndProc; - - // Validate license - if (!dglValidate()) - return FALSE; - - // Is context state ready ? - if (!bContextReady) - return FALSE; - - context = (int)b; // This is as a result of STRICT! - ddlogPrintf(DDLOG_SYSTEM, "dglMakeCurrent: HDC=%X, HGLRC=%d, ThreadId=%X", a, context, dwThreadId); - - // If the HGLRC is NULL then make no context current; - // Ditto if the HDC is NULL either. (DaveM) - if (context == 0 || a == 0) { - // Corresponding Mesa operation -#ifdef _USE_GLD3_WGL - _mesa_make_current(NULL, NULL); -#else - (*mesaFuncs.gl_make_current)(NULL, NULL); -#endif - dglSetCurrentContext(0); - return TRUE; - } - - // Make sure the HGLRC is in range - if ((context > DGL_MAX_CONTEXTS) || (context < 0)) { - ddlogMessage(DDLOG_ERROR, "dglMakeCurrent: HGLRC out of range\n"); - return FALSE; - } - - // Find address of context and make sure that it has been allocated - lpCtx = dglGetContextAddress(b); - if (!lpCtx->bAllocated) { - ddlogMessage(DDLOG_ERROR, "dglMakeCurrent: Context not allocated\n"); -// return FALSE; - return TRUE; // HACK: Shuts up "WebLab Viewer Pro". KeithH - } - -#ifdef GLD_THREADS - // Serialize access to DirectDraw or DDS operations - if (glb.bMultiThreaded) - EnterCriticalSection(&CriticalSection); -#endif - - // Check if window has changed - hWnd = (a != lpCtx->hDC) ? WindowFromDC(a) : lpCtx->hWnd; - bWindowChanged = (hWnd != lpCtx->hWnd) ? TRUE : FALSE; - bContextChanged = (b != dglGetCurrentContext()) ? TRUE : FALSE; - - // If the window has changed, make sure the clipper is updated. (DaveM) - if (glb.bDirectDrawPersistant && !lpCtx->bFullscreen && (bWindowChanged || bContextChanged)) { - lpCtx->hWnd = hWnd; -#ifndef _USE_GLD3_WGL - IDirectDrawSurface4_GetClipper(lpCtx->lpFront4, &lpddClipper); - IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd); - IDirectDrawClipper_Release(lpddClipper); -#endif // _USE_GLD3_WGL - } - - // Make sure hDC and hWnd is current. (DaveM) - // Obtain the dimensions of the rendering window - lpCtx->hDC = a; // Cache DC - lpCtx->hWnd = hWnd; - hWndLastActive = hWnd; - - // Check for non-window DC = memory DC ? - if (hWnd == NULL) { - if (GetClipBox(a, &lpCtx->rcScreenRect) == ERROR) { - ddlogMessage(DDLOG_WARN, "GetClipBox failed in dglMakeCurrent\n"); - SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0); - } - } - else if (!GetClientRect(lpCtx->hWnd, &lpCtx->rcScreenRect)) { - ddlogMessage(DDLOG_WARN, "GetClientRect failed in dglMakeCurrent\n"); - SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0); - } - // Check if buffers need to be re-sized; - // If so, wait until Mesa GL stuff is setup before re-sizing; - if (lpCtx->dwWidth != lpCtx->rcScreenRect.right - lpCtx->rcScreenRect.left || - lpCtx->dwHeight != lpCtx->rcScreenRect.bottom - lpCtx->rcScreenRect.top) - bNeedResize = TRUE; - - // Now we can update our globals - dglSetCurrentContext(b); - - // Corresponding Mesa operation -#ifdef _USE_GLD3_WGL - _mesa_make_current(lpCtx->glCtx, lpCtx->glBuffer); - lpCtx->glCtx->Driver.UpdateState(lpCtx->glCtx, _NEW_ALL); - if (bNeedResize) { - // Resize buffers (Note Mesa GL needs to be setup beforehand); - // Resize Mesa internal buffer too via glViewport() command, - // which subsequently calls dglWglResizeBuffers() too. - lpCtx->glCtx->Driver.Viewport(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); - lpCtx->bHasBeenCurrent = TRUE; - } -#else - (*mesaFuncs.gl_make_current)(lpCtx->glCtx, lpCtx->glBuffer); - - dglSetupDDPointers(lpCtx->glCtx); - - // Insure DirectDraw surfaces fit current window DC - if (bNeedResize) { - // Resize buffers (Note Mesa GL needs to be setup beforehand); - // Resize Mesa internal buffer too via glViewport() command, - // which subsequently calls dglWglResizeBuffers() too. - (*mesaFuncs.gl_Viewport)(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); - lpCtx->bHasBeenCurrent = TRUE; - } -#endif // _USE_GLD3_WGL - ddlogPrintf(DDLOG_SYSTEM, "dglMakeCurrent: width = %d, height = %d", lpCtx->dwWidth, lpCtx->dwHeight); - - // We have to clear D3D back buffer and render state if emulated front buffering - // for different window (but not context) like in Solid Edge. - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers - && (bWindowChanged /* || bContextChanged */) && lpCtx->EmulateSingle) { -#ifdef _USE_GLD3_WGL -// IDirect3DDevice8_EndScene(lpCtx->pDev); -// lpCtx->bSceneStarted = FALSE; - lpCtx->glCtx->Driver.Clear(lpCtx->glCtx, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, - GL_TRUE, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); -#else - IDirect3DDevice3_EndScene(lpCtx->lpDev3); - lpCtx->bSceneStarted = FALSE; - dglClearD3D(lpCtx->glCtx, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, - GL_TRUE, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); -#endif // _USE_GLD3_WGL - } - - // The first time we call MakeCurrent we set the initial viewport size - if (lpCtx->bHasBeenCurrent == FALSE) -#ifdef _USE_GLD3_WGL - lpCtx->glCtx->Driver.Viewport(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); -#else - (*mesaFuncs.gl_Viewport)(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); -#endif // _USE_GLD3_WGL - lpCtx->bHasBeenCurrent = TRUE; - -#ifdef GLD_THREADS - // Release serialized access - if (glb.bMultiThreaded) - LeaveCriticalSection(&CriticalSection); -#endif - - return TRUE; -} - -// *********************************************************************** - -BOOL dglDeleteContext( - HGLRC a) -{ - DGL_ctx* lpCtx; - DWORD dwThreadId = GetCurrentThreadId(); - char argstr[256]; - -#if 0 // We have enough trouble throwing exceptions as it is... (DaveM) - // Validate license - if (!dglValidate()) - return FALSE; -#endif - - // Is context state ready ? - if (!bContextReady) - return FALSE; - - ddlogPrintf(DDLOG_SYSTEM, "dglDeleteContext: Deleting context HGLRC=%d, ThreadId=%X", (int)a, dwThreadId); - - // Make sure the HGLRC is in range - if (((int) a> DGL_MAX_CONTEXTS) || ((int)a < 0)) { - ddlogMessage(DDLOG_ERROR, "dglDeleteCurrent: HGLRC out of range\n"); - return FALSE; - } - - // Make sure context is valid - lpCtx = dglGetContextAddress(a); - if (!lpCtx->bAllocated) { - ddlogPrintf(DDLOG_WARN, "Tried to delete unallocated context HGLRC=%d", (int)a); -// return FALSE; - return TRUE; // HACK: Shuts up "WebLab Viewer Pro". KeithH - } - - // Make sure context is de-activated - if (a == dglGetCurrentContext()) { - ddlogPrintf(DDLOG_WARN, "dglDeleteContext: context HGLRC=%d still active", (int)a); - dglMakeCurrent(NULL, NULL); - } - -#ifdef GLD_THREADS - // Serialize access to DirectDraw or DDS operations - if (glb.bMultiThreaded) - EnterCriticalSection(&CriticalSection); -#endif - - // We are about to destroy all Direct3D objects. - // Therefore we must disable rendering - lpCtx->bCanRender = FALSE; - - // This exception handler was installed to catch some - // particularly nasty apps. Console apps that call exit() - // fall into this catagory (i.e. Win32 Glut). - - // VC cannot successfully implement multiple exception handlers - // if more than one exception occurs. Therefore reverting back to - // single exception handler as Keith originally had it. (DaveM) - -#define WARN_MESSAGE(p) strcpy(argstr, (#p)); -#define SAFE_RELEASE(p) WARN_MESSAGE(p); RELEASE(p); - -__try { -#ifdef _USE_GLD3_WGL - WARN_MESSAGE(gl_destroy_framebuffer); - if (lpCtx->glBuffer) - _mesa_destroy_framebuffer(lpCtx->glBuffer); - WARN_MESSAGE(gl_destroy_context); - if (lpCtx->glCtx) - _mesa_destroy_context(lpCtx->glCtx); - WARN_MESSAGE(gl_destroy_visual); - if (lpCtx->glVis) - _mesa_destroy_visual(lpCtx->glVis); - - _gldDriver.DestroyDrawable(lpCtx); -#else - // Destroy the Mesa context - WARN_MESSAGE(gl_destroy_framebuffer); - if (lpCtx->glBuffer) - (*mesaFuncs.gl_destroy_framebuffer)(lpCtx->glBuffer); - WARN_MESSAGE(gl_destroy_context); - if (lpCtx->glCtx) - (*mesaFuncs.gl_destroy_context)(lpCtx->glCtx); - WARN_MESSAGE(gl_destroy_visual); - if (lpCtx->glVis) - (*mesaFuncs.gl_destroy_visual)(lpCtx->glVis); - - SAFE_RELEASE(lpCtx->m_pvbuf); // release D3D vertex buffer - SAFE_RELEASE(lpCtx->m_vbuf); // release D3D vertex buffer - - // Delete the global palette - SAFE_RELEASE(lpCtx->lpGlobalPalette); - - // Clean up. - if (lpCtx->lpViewport3) { - if (lpCtx->lpDev3) IDirect3DDevice3_DeleteViewport(lpCtx->lpDev3, lpCtx->lpViewport3); - SAFE_RELEASE(lpCtx->lpViewport3); - lpCtx->lpViewport3 = NULL; - } - - SAFE_RELEASE(lpCtx->lpDev3); - if (lpCtx->lpDepth4) { - if (lpCtx->lpBack4) - IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpBack4, 0L, lpCtx->lpDepth4); - else - IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpFront4, 0L, lpCtx->lpDepth4); - SAFE_RELEASE(lpCtx->lpDepth4); - lpCtx->lpDepth4 = NULL; - } - SAFE_RELEASE(lpCtx->lpBack4); - SAFE_RELEASE(lpCtx->lpFront4); - if (lpCtx->bFullscreen) { - IDirectDraw4_RestoreDisplayMode(lpCtx->lpDD4); - IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, NULL, DDSCL_NORMAL); - } - SAFE_RELEASE(lpCtx->lpD3D3); - SAFE_RELEASE(lpCtx->lpDD4); - SAFE_RELEASE(lpCtx->lpDD1); -#endif // _ULSE_GLD3_WGL - -} -__except(EXCEPTION_EXECUTE_HANDLER) { - ddlogPrintf(DDLOG_WARN, "Exception raised in dglDeleteContext: %s", argstr); -} - - // Restore the window message handler because this context may be used - // again by another window with a *different* message handler. (DaveM) - if (lpCtx->lpfnWndProc) { - SetWindowLong(lpCtx->hWnd, GWL_WNDPROC, (LONG)lpCtx->lpfnWndProc); - lpCtx->lpfnWndProc = (LONG)NULL; - } - - lpCtx->bAllocated = FALSE; // This context is now free for use - -#ifdef GLD_THREADS - // Release serialized access - if (glb.bMultiThreaded) - LeaveCriticalSection(&CriticalSection); -#endif - - return TRUE; -} - -// *********************************************************************** - -BOOL dglSwapBuffers( - HDC hDC) -{ - RECT rSrcRect; // Source rectangle - RECT rDstRect; // Destination rectangle - POINT pt; - HRESULT hResult; - - DDBLTFX bltFX; - DWORD dwBlitFlags; - DDBLTFX *lpBltFX; - -// DWORD dwThreadId = GetCurrentThreadId(); - HGLRC hGLRC = dglGetCurrentContext(); - DGL_ctx *lpCtx = dglGetContextAddress(hGLRC); - HWND hWnd; - - HDC hDCAux; // for memory DC - int x,y,w,h; // for memory DC BitBlt - -#if 0 // Perhaps not a good idea. Called too often. KH - // Validate license - if (!dglValidate()) - return FALSE; -#endif - - if (!lpCtx) { - return TRUE; //FALSE; // No current context - } - - if (!lpCtx->bCanRender) { - // Don't return false else some apps will bail. - return TRUE; - } - - hWnd = lpCtx->hWnd; - if (hDC != lpCtx->hDC) { - ddlogPrintf(DDLOG_WARN, "dglSwapBuffers: HDC=%X does not match HDC=%X for HGLRC=%d", hDC, lpCtx->hDC, hGLRC); - hWnd = WindowFromDC(hDC); - } - -#ifndef _USE_GLD3_WGL - // Ensure that the surfaces exist before we tell - // the device to render to them. - IDirectDraw4_RestoreAllSurfaces(lpCtx->lpDD4); - - // Make sure that the vertex caches have been emptied -// dglStateChange(lpCtx); - - // Some OpenGL programs don't issue a glFinish - check for it here. - if (lpCtx->bSceneStarted) { - IDirect3DDevice3_EndScene(lpCtx->lpDev3); - lpCtx->bSceneStarted = FALSE; - } -#endif - -#if 0 - // If the calling app is not active then we don't need to Blit/Flip. - // We can therefore simply return TRUE. - if (!glb.bAppActive) - return TRUE; - // Addendum: This is WRONG! We should bail if the app is *minimized*, - // not merely if the app is just plain 'not active'. - // KeithH, 27/May/2000. -#endif - - // Check for non-window DC = memory DC ? - if (hWnd == NULL) { - if (GetClipBox(hDC, &rSrcRect) == ERROR) - return TRUE; - // Use GDI BitBlt instead from compatible DirectDraw DC - x = rSrcRect.left; - y = rSrcRect.top; - w = rSrcRect.right - rSrcRect.left; - h = rSrcRect.bottom - rSrcRect.top; - - // Ack. DX8 does not have a GetDC() function... - // TODO: Defer to DX7 or DX9 drivers... (DaveM) - return TRUE; - } - - // Bail if window client region is not drawable, like in Solid Edge - if (!IsWindow(hWnd) /* || !IsWindowVisible(hWnd) */ || !GetClientRect(hWnd, &rSrcRect)) - return TRUE; - -#ifdef GLD_THREADS - // Serialize access to DirectDraw or DDS operations - if (glb.bMultiThreaded) - EnterCriticalSection(&CriticalSection); -#endif - -#ifdef _USE_GLD3_WGL - // Notify Mesa of impending swap, so Mesa can flush internal buffers. - _mesa_notifySwapBuffers(lpCtx->glCtx); - // Now perform driver buffer swap - _gldDriver.SwapBuffers(lpCtx, hDC, hWnd); -#else - if (lpCtx->bFullscreen) { - // Sync with retrace if required - if (glb.bWaitForRetrace) { - IDirectDraw4_WaitForVerticalBlank( - lpCtx->lpDD4, - DDWAITVB_BLOCKBEGIN, - 0); - } - - // Perform the fullscreen flip - TRY(IDirectDrawSurface4_Flip( - lpCtx->lpFront4, - NULL, - DDFLIP_WAIT), - "dglSwapBuffers: Flip"); - } else { - // Calculate current window position and size - pt.x = pt.y = 0; - ClientToScreen(hWnd, &pt); - GetClientRect(hWnd, &rDstRect); - if (rDstRect.right > lpCtx->dwModeWidth) - rDstRect.right = lpCtx->dwModeWidth; - if (rDstRect.bottom > lpCtx->dwModeHeight) - rDstRect.bottom = lpCtx->dwModeHeight; - OffsetRect(&rDstRect, pt.x, pt.y); - rSrcRect.left = rSrcRect.top = 0; - rSrcRect.right = lpCtx->dwWidth; - rSrcRect.bottom = lpCtx->dwHeight; - if (rSrcRect.right > lpCtx->dwModeWidth) - rSrcRect.right = lpCtx->dwModeWidth; - if (rSrcRect.bottom > lpCtx->dwModeHeight) - rSrcRect.bottom = lpCtx->dwModeHeight; - - if (glb.bWaitForRetrace) { - // Sync the blit to the vertical retrace - ZeroMemory(&bltFX, sizeof(bltFX)); - bltFX.dwSize = sizeof(bltFX); - bltFX.dwDDFX = DDBLTFX_NOTEARING; - dwBlitFlags = DDBLT_WAIT | DDBLT_DDFX; - lpBltFX = &bltFX; - } else { - dwBlitFlags = DDBLT_WAIT; - lpBltFX = NULL; - } - - // Perform the actual blit - TRY(IDirectDrawSurface4_Blt( - lpCtx->lpFront4, - &rDstRect, - lpCtx->lpBack4, // Blit source - &rSrcRect, - dwBlitFlags, - lpBltFX), - "dglSwapBuffers: Blt"); - } -#endif // _USE_GLD3_WGL - -#ifdef GLD_THREADS - // Release serialized access - if (glb.bMultiThreaded) - LeaveCriticalSection(&CriticalSection); -#endif - - // TODO: Re-instate rendering bitmap snapshot feature??? (DaveM) - - // Render frame is completed - ValidateRect(hWnd, NULL); - lpCtx->bFrameStarted = FALSE; - - return TRUE; -} - -// *********************************************************************** +/**************************************************************************** +* +* Mesa 3-D graphics library +* Direct3D Driver Interface +* +* ======================================================================== +* +* Copyright (C) 1991-2004 SciTech Software, Inc. 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 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 +* SCITECH SOFTWARE INC 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. +* +* ====================================================================== +* +* Language: ANSI C +* Environment: Windows 9x (Win32) +* +* Description: Context handling. +* +****************************************************************************/ + +#include "dglcontext.h" + +// Get compile errors without this. KeithH +//#include "scitech.h" // ibool, etc. + +#ifdef _USE_GLD3_WGL +#include "gld_driver.h" + +extern void _gld_mesa_warning(struct gl_context *, char *); +extern void _gld_mesa_fatal(struct gl_context *, char *); +#endif // _USE_GLD3_WGL + +// TODO: Clean out old DX6-specific code from GLD 2.x CAD driver +// if it is no longer being built as part of GLDirect. (DaveM) + +// *********************************************************************** + +#define GLDERR_NONE 0 +#define GLDERR_MEM 1 +#define GLDERR_DDRAW 2 +#define GLDERR_D3D 3 +#define GLDERR_BPP 4 + +char szResourceWarning[] = +"GLDirect does not have enough video memory resources\n" +"to support the requested OpenGL rendering context.\n\n" +"You may have to reduce the current display resolution\n" +"to obtain satisfactory OpenGL performance.\n"; + +char szDDrawWarning[] = +"GLDirect is unable to initialize DirectDraw for the\n" +"requested OpenGL rendering context.\n\n" +"You will have to check the DirectX control panel\n" +"for further information.\n"; + +char szD3DWarning[] = +"GLDirect is unable to initialize Direct3D for the\n" +"requested OpenGL rendering context.\n\n" +"You may have to change the display mode resolution\n" +"color depth or check the DirectX control panel for\n" +"further information.\n"; + +char szBPPWarning[] = +"GLDirect is unable to use the selected color depth for\n" +"the requested OpenGL rendering context.\n\n" +"You will have to change the display mode resolution\n" +"color depth with the Display Settings control panel.\n"; + +int nContextError = GLDERR_NONE; + +// *********************************************************************** + +#define VENDORID_ATI 0x1002 + +static DWORD devATIRagePro[] = { + 0x4742, // 3D RAGE PRO BGA AGP 1X/2X + 0x4744, // 3D RAGE PRO BGA AGP 1X only + 0x4749, // 3D RAGE PRO BGA PCI 33 MHz + 0x4750, // 3D RAGE PRO PQFP PCI 33 MHz + 0x4751, // 3D RAGE PRO PQFP PCI 33 MHz limited 3D + 0x4C42, // 3D RAGE LT PRO BGA-312 AGP 133 MHz + 0x4C44, // 3D RAGE LT PRO BGA-312 AGP 66 MHz + 0x4C49, // 3D RAGE LT PRO BGA-312 PCI 33 MHz + 0x4C50, // 3D RAGE LT PRO BGA-256 PCI 33 MHz + 0x4C51, // 3D RAGE LT PRO BGA-256 PCI 33 MHz limited 3D +}; + +static DWORD devATIRageIIplus[] = { + 0x4755, // 3D RAGE II+ + 0x4756, // 3D RAGE IIC PQFP PCI + 0x4757, // 3D RAGE IIC BGA AGP + 0x475A, // 3D RAGE IIC PQFP AGP + 0x4C47, // 3D RAGE LT-G +}; + +// *********************************************************************** + +#ifndef _USE_GLD3_WGL +extern DGL_mesaFuncs mesaFuncs; +#endif + +extern DWORD dwLogging; + +#ifdef GLD_THREADS +#pragma message("compiling DGLCONTEXT.C vars for multi-threaded support") +CRITICAL_SECTION CriticalSection; // for serialized access +DWORD dwTLSCurrentContext = 0xFFFFFFFF; // TLS index for current context +DWORD dwTLSPixelFormat = 0xFFFFFFFF; // TLS index for current pixel format +#endif +HGLRC iCurrentContext = 0; // Index of current context (static) +BOOL bContextReady = FALSE; // Context state ready ? + +DGL_ctx ctxlist[DGL_MAX_CONTEXTS]; // Context list + +// *********************************************************************** + +static BOOL bHaveWin95 = FALSE; +static BOOL bHaveWinNT = FALSE; +static BOOL bHaveWin2K = FALSE; + +/**************************************************************************** +REMARKS: +Detect the installed OS type. +****************************************************************************/ +static void DetectOS(void) +{ + OSVERSIONINFO VersionInformation; + LPOSVERSIONINFO lpVersionInformation = &VersionInformation; + + VersionInformation.dwOSVersionInfoSize = sizeof(VersionInformation); + + GetVersionEx(lpVersionInformation); + + switch (VersionInformation.dwPlatformId) { + case VER_PLATFORM_WIN32_WINDOWS: + bHaveWin95 = TRUE; + bHaveWinNT = FALSE; + bHaveWin2K = FALSE; + break; + case VER_PLATFORM_WIN32_NT: + bHaveWin95 = FALSE; + if (VersionInformation.dwMajorVersion <= 4) { + bHaveWinNT = TRUE; + bHaveWin2K = FALSE; + } + else { + bHaveWinNT = FALSE; + bHaveWin2K = TRUE; + } + break; + case VER_PLATFORM_WIN32s: + bHaveWin95 = FALSE; + bHaveWinNT = FALSE; + bHaveWin2K = FALSE; + break; + } +} + +// *********************************************************************** + +HWND hWndEvent = NULL; // event monitor window +HWND hWndLastActive = NULL; // last active client window +LONG __stdcall GLD_EventWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); + +// *********************************************************************** + +// Checks if the HGLRC is valid in range of context list. +BOOL dglIsValidContext( + HGLRC a) +{ + return ((int)a > 0 && (int)a <= DGL_MAX_CONTEXTS); +} + +// *********************************************************************** + +// Convert a HGLRC to a pointer into the context list. +DGL_ctx* dglGetContextAddress( + const HGLRC a) +{ + if (dglIsValidContext(a)) + return &ctxlist[(int)a-1]; + return NULL; +} + +// *********************************************************************** + +// Return the current HGLRC (however it may be stored for multi-threading). +HGLRC dglGetCurrentContext(void) +{ +#ifdef GLD_THREADS + HGLRC hGLRC; + // load from thread-specific instance + if (glb.bMultiThreaded) { + // protect against calls from arbitrary threads + __try { + hGLRC = (HGLRC)TlsGetValue(dwTLSCurrentContext); + } + __except(EXCEPTION_EXECUTE_HANDLER) { + hGLRC = iCurrentContext; + } + } + // load from global static var + else { + hGLRC = iCurrentContext; + } + return hGLRC; +#else + return iCurrentContext; +#endif +} + +// *********************************************************************** + +// Set the current HGLRC (however it may be stored for multi-threading). +void dglSetCurrentContext(HGLRC hGLRC) +{ +#ifdef GLD_THREADS + // store in thread-specific instance + if (glb.bMultiThreaded) { + // protect against calls from arbitrary threads + __try { + TlsSetValue(dwTLSCurrentContext, (LPVOID)hGLRC); + } + __except(EXCEPTION_EXECUTE_HANDLER) { + iCurrentContext = hGLRC; + } + } + // store in global static var + else { + iCurrentContext = hGLRC; + } +#else + iCurrentContext = hGLRC; +#endif +} + +// *********************************************************************** + +// Return the current HDC only for a currently active HGLRC. +HDC dglGetCurrentDC(void) +{ + HGLRC hGLRC; + DGL_ctx* lpCtx; + + hGLRC = dglGetCurrentContext(); + if (hGLRC) { + lpCtx = dglGetContextAddress(hGLRC); + return lpCtx->hDC; + } + return 0; +} + +// *********************************************************************** + +void dglInitContextState() +{ + int i; + WNDCLASS wc; + +#ifdef GLD_THREADS + // Allocate thread local storage indexes for current context and pixel format + dwTLSCurrentContext = TlsAlloc(); + dwTLSPixelFormat = TlsAlloc(); +#endif + + dglSetCurrentContext(NULL); // No current rendering context + + // Clear all context data + ZeroMemory(ctxlist, sizeof(ctxlist[0]) * DGL_MAX_CONTEXTS); + + for (i=0; ilpfnWndProc; + break; + } + } + // Not one of ours... + if (!lpfnWndProc) + return DefWindowProc(hwnd, msg, wParam, lParam); + + // Intercept messages amd process *before* passing on to window + switch (msg) { +#ifdef _USE_GLD3_WGL + case WM_DISPLAYCHANGE: + glb.bPixelformatsDirty = TRUE; + break; +#endif + case WM_ACTIVATEAPP: + glb.bAppActive = (BOOL)wParam; + ddlogPrintf(DDLOG_INFO, "Calling app has been %s", glb.bAppActive ? "activated" : "de-activated"); + break; + case WM_ERASEBKGND: + // Eat the GDI erase event for the GL window + if (!lpCtx || !lpCtx->bHasBeenCurrent) + break; + lpCtx->bGDIEraseBkgnd = TRUE; + return TRUE; + case WM_PAINT: + // Eat the invalidated update region if render scene is in progress + if (!lpCtx || !lpCtx->bHasBeenCurrent) + break; + if (lpCtx->bFrameStarted) { + if (GetUpdateRect(hwnd, &rect, FALSE)) { + BeginPaint(hwnd, &ps); + EndPaint(hwnd, &ps); + ValidateRect(hwnd, &rect); + return TRUE; + } + } + break; + } + // Call the appropriate window message handler + rc = CallWindowProc((WNDPROC)lpfnWndProc, hwnd, msg, wParam, lParam); + + // Intercept messages and process *after* passing on to window + switch (msg) { + case WM_QUIT: + case WM_DESTROY: + bQuit = TRUE; + if (lpCtx && lpCtx->bAllocated) { + ddlogPrintf(DDLOG_WARN, "WM_DESTROY detected for HWND=%X, HDC=%X, HGLRC=%d", hwnd, lpCtx->hDC, i+1); + dglDeleteContext((HGLRC)(i+1)); + } + break; +#if 0 + case WM_SIZE: + // Resize surfaces to fit window but not viewport (in case app did not bother) + if (!lpCtx || !lpCtx->bHasBeenCurrent) + break; + w = LOWORD(lParam); + h = HIWORD(lParam); + if (lpCtx->dwWidth < w || lpCtx->dwHeight < h) { + if (!dglWglResizeBuffers(lpCtx->glCtx, TRUE)) + dglWglResizeBuffers(lpCtx->glCtx, FALSE); + } + break; +#endif + } + + // If the main window is quitting, then so should we... + if (bMain && bQuit) { + ddlogPrintf(DDLOG_SYSTEM, "shutting down after WM_DESTROY detected for main HWND=%X", hwnd); + dglDeleteContextState(); + dglExitDriver(); + } + + return rc; +} + +// *********************************************************************** + +// Driver Window message handler +static LONG __stdcall GLD_EventWndProc( + HWND hwnd, + UINT msg, + WPARAM wParam, + LPARAM lParam) +{ + switch (msg) { + // May be sent by splash screen dialog on exit + case WM_ACTIVATE: + if (LOWORD(wParam) == WA_ACTIVE && glb.hWndActive) { + SetForegroundWindow(glb.hWndActive); + return 0; + } + break; + } + return DefWindowProc(hwnd, msg, wParam, lParam); +} + +// *********************************************************************** + +// Intercepted Keyboard handler for detecting hot keys. +LRESULT CALLBACK dglKeyProc( + int code, + WPARAM wParam, + LPARAM lParam) +{ + HWND hWnd, hWndFrame; + HGLRC hGLRC = NULL; + DGL_ctx* lpCtx = NULL; + int cmd = 0, dx1 = 0, dx2 = 0, i; + static BOOL bAltPressed = FALSE; + static BOOL bCtrlPressed = FALSE; + static BOOL bShiftPressed = FALSE; + RECT r, rf, rc; + POINT pt; + BOOL bForceReshape = FALSE; + + return CallNextHookEx(hKeyHook, code, wParam, lParam); +} + +// *********************************************************************** + +HWND hWndMatch; + +// Window handle enumeration procedure. +BOOL CALLBACK dglEnumChildProc( + HWND hWnd, + LPARAM lParam) +{ + RECT rect; + + // Find window handle with matching client rect. + GetClientRect(hWnd, &rect); + if (EqualRect(&rect, (RECT*)lParam)) { + hWndMatch = hWnd; + return FALSE; + } + // Continue with next child window. + return TRUE; +} + +// *********************************************************************** + +// Find window handle with matching client rect. +HWND dglFindWindowRect( + RECT* pRect) +{ + hWndMatch = NULL; + EnumChildWindows(GetForegroundWindow(), dglEnumChildProc, (LPARAM)pRect); + return hWndMatch; +} + +// *********************************************************************** +#ifndef _USE_GLD3_WGL +void dglChooseDisplayMode( + DGL_ctx *lpCtx) +{ + // Note: Choose an exact match if possible. + + int i; + DWORD area; + DWORD bestarea; + DDSURFACEDESC2 *lpDDSD = NULL; // Mode list pointer + DDSURFACEDESC2 *lpBestDDSD = NULL; // Pointer to best + + lpDDSD = glb.lpDisplayModes; + for (i=0; idwWidth == lpCtx->dwWidth) && + (lpDDSD->dwHeight == lpCtx->dwHeight)) + goto matched; // Mode has been exactly matched + // Choose modes that are larger in both dimensions than + // the window, but smaller in area than the current best. + if ( (lpDDSD->dwWidth >= lpCtx->dwWidth) && + (lpDDSD->dwHeight >= lpCtx->dwHeight)) + { + if (lpBestDDSD == NULL) { + lpBestDDSD = lpDDSD; + bestarea = lpDDSD->dwWidth * lpDDSD->dwHeight; + continue; + } + area = lpDDSD->dwWidth * lpDDSD->dwHeight; + if (area < bestarea) { + lpBestDDSD = lpDDSD; + bestarea = area; + } + } + } + + // Safety check + if (lpBestDDSD == NULL) { + ddlogMessage(DDLOG_CRITICAL, "dglChooseDisplayMode"); + return; + } + + lpCtx->dwModeWidth = lpBestDDSD->dwWidth; + lpCtx->dwModeHeight = lpBestDDSD->dwHeight; +matched: + ddlogPrintf(DDLOG_INFO, "Matched (%ldx%ld) to (%ldx%ld)", + lpCtx->dwWidth, lpCtx->dwHeight, lpCtx->dwModeWidth, lpCtx->dwModeHeight); +} +#endif // _USE_GLD3_WGL +// *********************************************************************** + +static BOOL IsDevice( + DWORD *lpDeviceIdList, + DWORD dwDeviceId, + int count) +{ + int i; + + for (i=0; ilpDD4 == NULL) { + // Testing for broken cards is sensitive area, so we don't want + // anything saying "broken cards" in the error message. ;) + ddlogMessage(DDLOG_ERROR, "Null DD4 passed to TFBC\n"); + return; + } + + // Microsoft really fucked up with the GetDeviceIdentifier function + // on Windows 2000, since it locks up on stock driers on the CD. Updated + // drivers from vendors appear to work, but we can't identify the drivers + // without this function!!! For now we skip these tests on Windows 2000. + if ((GetVersion() & 0x80000000UL) == 0) + return; + + // Obtain device info + if (FAILED(IDirectDraw4_GetDeviceIdentifier(lpCtx->lpDD4, &dddi, 0))) + return; + + // Useful info. Log it. + ddlogPrintf(DDLOG_INFO, "DirectDraw: VendorId=0x%x, DeviceId=0x%x", dddi.dwVendorId, dddi.dwDeviceId); + + // Vendor 1: ATI + if (dddi.dwVendorId == VENDORID_ATI) { + // Test A: ATI Rage PRO + if (IsDevice(devATIRagePro, dddi.dwDeviceId, sizeof(devATIRagePro))) + glb.bUseMipmaps = FALSE; + // Test B: ATI Rage II+ + if (IsDevice(devATIRageIIplus, dddi.dwDeviceId, sizeof(devATIRageIIplus))) + glb.bEmulateAlphaTest = TRUE; + } + + // Vendor 2: Matrox + if (dddi.dwVendorId == 0x102B) { + // Test: Matrox G400 stencil buffer support does not work for AutoCAD + if (dddi.dwDeviceId == 0x0525) { + lpCtx->lpPF->pfd.cStencilBits = 0; + if (lpCtx->lpPF->iZBufferPF != -1) { + glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwStencilBitDepth = 0; + glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwStencilBitMask = 0; + glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwFlags &= ~DDPF_STENCILBUFFER; + } + } + } +#endif // _GLD3 +} + +// *********************************************************************** + +BOOL dglCreateContextBuffers( + HDC a, + DGL_ctx *lpCtx, + BOOL bFallback) +{ + HRESULT hResult; + + int i; +// HGLRC hGLRC; +// DGL_ctx* lpCtx; + +#ifndef _USE_GLD3_WGL + DWORD dwFlags; + DDSURFACEDESC2 ddsd2; + DDSCAPS2 ddscaps2; + LPDIRECTDRAWCLIPPER lpddClipper; + D3DDEVICEDESC D3DHWDevDesc; // Direct3D Hardware description + D3DDEVICEDESC D3DHELDevDesc; // Direct3D Hardware Emulation Layer +#endif // _USE_GLD3_WGL + + float inv_aspect; + + GLenum bDoubleBuffer; // TRUE if double buffer required + GLenum bDepthBuffer; // TRUE if depth buffer required + + const PIXELFORMATDESCRIPTOR *lpPFD = &lpCtx->lpPF->pfd; + + // Vars for Mesa visual + DWORD dwDepthBits = 0; + DWORD dwStencilBits = 0; + DWORD dwAlphaBits = 0; + DWORD bAlphaSW = GL_FALSE; + DWORD bDouble = GL_FALSE; + + DDSURFACEDESC2 ddsd2DisplayMode; + BOOL bFullScrnWin = FALSE; // fullscreen-size window ? + DDBLTFX ddbltfx; + DWORD dwMemoryType = (bFallback) ? DDSCAPS_SYSTEMMEMORY : glb.dwMemoryType; + BOOL bBogusWindow = FALSE; // non-drawable window ? + DWORD dwColorRef = 0; // GDI background color + RECT rcDst; // GDI window rect + POINT pt; // GDI window point + + // Palette used for creating default global palette + PALETTEENTRY ppe[256]; + +#ifndef _USE_GLD3_WGL + // Vertex buffer description. Used for creation of vertex buffers + D3DVERTEXBUFFERDESC vbufdesc; +#endif // _USE_GLD3_WGL + +#define DDLOG_CRITICAL_OR_WARN (bFallback ? DDLOG_CRITICAL : DDLOG_WARN) + + ddlogPrintf(DDLOG_SYSTEM, "dglCreateContextBuffers for HDC=%X", a); + nContextError = GLDERR_NONE; + +#ifdef GLD_THREADS + // Serialize access to DirectDraw object creation or DDS start + if (glb.bMultiThreaded) + EnterCriticalSection(&CriticalSection); +#endif + + // Check for back buffer + bDoubleBuffer = GL_TRUE; //(lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? GL_TRUE : GL_FALSE; + // Since we always do back buffering, check if we emulate front buffering + lpCtx->EmulateSingle = + (lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? FALSE : TRUE; +#if 0 // Don't have to mimic MS OpenGL behavior for front-buffering (DaveM) + lpCtx->EmulateSingle |= + (lpPFD->dwFlags & PFD_SUPPORT_GDI) ? TRUE : FALSE; +#endif + + // Check for depth buffer + bDepthBuffer = (lpPFD->cDepthBits) ? GL_TRUE : GL_FALSE; + + lpCtx->bDoubleBuffer = bDoubleBuffer; + lpCtx->bDepthBuffer = bDepthBuffer; + + // Set the Fullscreen flag for the context. +// lpCtx->bFullscreen = glb.bFullscreen; + + // Obtain the dimensions of the rendering window + lpCtx->hDC = a; // Cache DC + lpCtx->hWnd = WindowFromDC(lpCtx->hDC); + // Check for non-window DC = memory DC ? + if (lpCtx->hWnd == NULL) { + // bitmap memory contexts are always single-buffered + lpCtx->EmulateSingle = TRUE; + bBogusWindow = TRUE; + ddlogPrintf(DDLOG_INFO, "Non-Window Memory Device Context"); + if (GetClipBox(lpCtx->hDC, &lpCtx->rcScreenRect) == ERROR) { + ddlogMessage(DDLOG_WARN, "GetClipBox failed in dglCreateContext\n"); + SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0); + } + } + else if (!GetClientRect(lpCtx->hWnd, &lpCtx->rcScreenRect)) { + bBogusWindow = TRUE; + ddlogMessage(DDLOG_WARN, "GetClientRect failed in dglCreateContext\n"); + SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0); + } + lpCtx->dwWidth = lpCtx->rcScreenRect.right - lpCtx->rcScreenRect.left; + lpCtx->dwHeight = lpCtx->rcScreenRect.bottom - lpCtx->rcScreenRect.top; + + ddlogPrintf(DDLOG_INFO, "Input window %X: w=%i, h=%i", + lpCtx->hWnd, lpCtx->dwWidth, lpCtx->dwHeight); + + // What if app only zeroes one dimension instead of both? (DaveM) + if ( (lpCtx->dwWidth == 0) || (lpCtx->dwHeight == 0) ) { + // Make the buffer size something sensible + lpCtx->dwWidth = 8; + lpCtx->dwHeight = 8; + } + + // Set defaults + lpCtx->dwModeWidth = lpCtx->dwWidth; + lpCtx->dwModeHeight = lpCtx->dwHeight; +/* + // Find best display mode for fullscreen + if (glb.bFullscreen || !glb.bPrimary) { + dglChooseDisplayMode(lpCtx); + } +*/ + // Misc initialisation + lpCtx->bCanRender = FALSE; // No rendering allowed yet + lpCtx->bSceneStarted = FALSE; + lpCtx->bFrameStarted = FALSE; + + // Detect OS (specifically 'Windows 2000' or 'Windows XP') + DetectOS(); + + // NOTE: WinNT not supported + ddlogPrintf(DDLOG_INFO, "OS: %s", bHaveWin95 ? "Win9x" : (bHaveWin2K ? "Win2000/XP" : "Unsupported") ); + + // Test for Fullscreen + if (bHaveWin95) { // Problems with fullscreen on Win2K/XP + if ((GetSystemMetrics(SM_CXSCREEN) == lpCtx->dwWidth) && + (GetSystemMetrics(SM_CYSCREEN) == lpCtx->dwHeight)) + { + // Workaround for some apps that crash when going fullscreen. + //lpCtx->bFullscreen = TRUE; + } + + } + +#ifdef _USE_GLD3_WGL + _gldDriver.CreateDrawable(lpCtx, glb.bDirectDrawPersistant, glb.bPersistantBuffers); +#else + // Check if DirectDraw has already been created by original GLRC (DaveM) + if (glb.bDirectDrawPersistant && glb.bDirectDraw) { + lpCtx->lpDD4 = glb.lpDD4; + IDirectDraw4_AddRef(lpCtx->lpDD4); + goto SkipDirectDrawCreate; + } + + // Create DirectDraw object + if (glb.bPrimary) + hResult = DirectDrawCreate(NULL, &lpCtx->lpDD1, NULL); + else { + // A non-primary device is to be used. + // Force context to be Fullscreen, secondary adaptors can not + // be used in a window. + hResult = DirectDrawCreate(&glb.ddGuid, &lpCtx->lpDD1, NULL); + lpCtx->bFullscreen = TRUE; + } + if (FAILED(hResult)) { + MessageBox(NULL, "Unable to initialize DirectDraw", "GLDirect", MB_OK); + ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create DirectDraw interface", hResult); + nContextError = GLDERR_DDRAW; + goto return_with_error; + } + + // Query for DX6 IDirectDraw4. + hResult = IDirectDraw_QueryInterface(lpCtx->lpDD1, + &IID_IDirectDraw4, + (void**)&lpCtx->lpDD4); + if (FAILED(hResult)) { + MessageBox(NULL, "GLDirect requires DirectX 6.0 or above", "GLDirect", MB_OK); + ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create DirectDraw4 interface", hResult); + nContextError = GLDERR_DDRAW; + goto return_with_error; + } + + // Cache DirectDraw interface for subsequent GLRCs + if (glb.bDirectDrawPersistant && !glb.bDirectDraw) { + glb.lpDD4 = lpCtx->lpDD4; + IDirectDraw4_AddRef(glb.lpDD4); + glb.bDirectDraw = TRUE; + } +SkipDirectDrawCreate: + + // Now we have a DD4 interface we can check for broken cards + dglTestForBrokenCards(lpCtx); + + // Test if primary device can use flipping instead of blitting + ZeroMemory(&ddsd2DisplayMode, sizeof(ddsd2DisplayMode)); + ddsd2DisplayMode.dwSize = sizeof(ddsd2DisplayMode); + hResult = IDirectDraw4_GetDisplayMode( + lpCtx->lpDD4, + &ddsd2DisplayMode); + if (SUCCEEDED(hResult)) { + if ( (lpCtx->dwWidth == ddsd2DisplayMode.dwWidth) && + (lpCtx->dwHeight == ddsd2DisplayMode.dwHeight) ) { + // We have a fullscreen-size window + bFullScrnWin = TRUE; + // OK to use DirectDraw fullscreen mode ? + if (glb.bPrimary && !glb.bFullscreenBlit && !lpCtx->EmulateSingle && !glb.bDirectDrawPersistant) { + lpCtx->bFullscreen = TRUE; + ddlogMessage(DDLOG_INFO, "Primary upgraded to page flipping.\n"); + } + } + // Cache the display mode dimensions + lpCtx->dwModeWidth = ddsd2DisplayMode.dwWidth; + lpCtx->dwModeHeight = ddsd2DisplayMode.dwHeight; + } + + // Clamp the effective window dimensions to primary surface. + // We need to do this for D3D viewport dimensions even if wide + // surfaces are supported. This also is a good idea for handling + // whacked-out window dimensions passed for non-drawable windows + // like Solid Edge. (DaveM) + if (lpCtx->dwWidth > ddsd2DisplayMode.dwWidth) + lpCtx->dwWidth = ddsd2DisplayMode.dwWidth; + if (lpCtx->dwHeight > ddsd2DisplayMode.dwHeight) + lpCtx->dwHeight = ddsd2DisplayMode.dwHeight; + + // Check for non-RGB desktop resolution + if (!lpCtx->bFullscreen && ddsd2DisplayMode.ddpfPixelFormat.dwRGBBitCount <= 8) { + ddlogPrintf(DDLOG_CRITICAL_OR_WARN, "Desktop color depth %d bpp not supported", + ddsd2DisplayMode.ddpfPixelFormat.dwRGBBitCount); + nContextError = GLDERR_BPP; + goto return_with_error; + } +#endif // _USE_GLD3_WGL + + ddlogPrintf(DDLOG_INFO, "Window: w=%i, h=%i (%s)", + lpCtx->dwWidth, + lpCtx->dwHeight, + lpCtx->bFullscreen ? "fullscreen" : "windowed"); + +#ifndef _USE_GLD3_WGL + // Obtain ddraw caps + ZeroMemory(&lpCtx->ddCaps, sizeof(DDCAPS)); + lpCtx->ddCaps.dwSize = sizeof(DDCAPS); + if (glb.bHardware) { + // Get HAL caps + IDirectDraw4_GetCaps(lpCtx->lpDD4, &lpCtx->ddCaps, NULL); + } else { + // Get HEL caps + IDirectDraw4_GetCaps(lpCtx->lpDD4, NULL, &lpCtx->ddCaps); + } + + // If this flag is present then we can't default to Mesa + // SW rendering between BeginScene() and EndScene(). + if (lpCtx->ddCaps.dwCaps2 & DDCAPS2_NO2DDURING3DSCENE) { + ddlogMessage(DDLOG_INFO, + "Warning : No 2D allowed during 3D scene.\n"); + } + + // Query for DX6 Direct3D3 interface + hResult = IDirectDraw4_QueryInterface(lpCtx->lpDD4, + &IID_IDirect3D3, + (void**)&lpCtx->lpD3D3); + if (FAILED(hResult)) { + MessageBox(NULL, "Unable to initialize Direct3D", "GLDirect", MB_OK); + ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create Direct3D interface", hResult); + nContextError = GLDERR_D3D; + goto return_with_error; + } + + // Context creation + if (lpCtx->bFullscreen) { + // FULLSCREEN + + // Disable warning popups when in fullscreen mode + ddlogWarnOption(FALSE); + + // Have to release persistant primary surface if fullscreen mode + if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) { + RELEASE(glb.lpPrimary4); + glb.bDirectDrawPrimary = FALSE; + } + + dwFlags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT; + if (glb.bFastFPU) + dwFlags |= DDSCL_FPUSETUP; // fast FPU setup optional (DaveM) + hResult = IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, lpCtx->hWnd, dwFlags); + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to set Exclusive Fullscreen mode", hResult); + goto return_with_error; + } + + hResult = IDirectDraw4_SetDisplayMode(lpCtx->lpDD4, + lpCtx->dwModeWidth, + lpCtx->dwModeHeight, + lpPFD->cColorBits, + 0, + 0); + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "SetDisplayMode failed", hResult); + goto return_with_error; + } + + // ** The display mode has changed, so dont use MessageBox! ** + + ZeroMemory(&ddsd2, sizeof(ddsd2)); + ddsd2.dwSize = sizeof(ddsd2); + + if (bDoubleBuffer) { + // Double buffered + // Primary surface + ddsd2.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | + DDSCAPS_FLIP | + DDSCAPS_COMPLEX | + DDSCAPS_3DDEVICE | + dwMemoryType; + ddsd2.dwBackBufferCount = 1; + + hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL); + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult); + nContextError = GLDERR_MEM; + goto return_with_error; + } + + // Render target surface + ZeroMemory(&ddscaps2, sizeof(ddscaps2)); // Clear the entire struct. + ddscaps2.dwCaps = DDSCAPS_BACKBUFFER; + hResult = IDirectDrawSurface4_GetAttachedSurface(lpCtx->lpFront4, &ddscaps2, &lpCtx->lpBack4); + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "GetAttachedSurface failed", hResult); + nContextError = GLDERR_MEM; + goto return_with_error; + } + } else { + // Single buffered + // Primary surface + ddsd2.dwFlags = DDSD_CAPS; + ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | + //DDSCAPS_3DDEVICE | + dwMemoryType; + + hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL); + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult); + nContextError = GLDERR_MEM; + goto return_with_error; + } + + lpCtx->lpBack4 = NULL; + } + } else { + // WINDOWED + + // OK to enable warning popups in windowed mode + ddlogWarnOption(glb.bMessageBoxWarnings); + + dwFlags = DDSCL_NORMAL; + if (glb.bMultiThreaded) + dwFlags |= DDSCL_MULTITHREADED; + if (glb.bFastFPU) + dwFlags |= DDSCL_FPUSETUP; // fast FPU setup optional (DaveM) + hResult = IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, + lpCtx->hWnd, + dwFlags); + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to set Normal coop level", hResult); + goto return_with_error; + } + // Has Primary surface already been created for original GLRC ? + // Note this can only be applicable for windowed modes + if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) { + lpCtx->lpFront4 = glb.lpPrimary4; + IDirectDrawSurface4_AddRef(lpCtx->lpFront4); + // Update the window on the default clipper + IDirectDrawSurface4_GetClipper(lpCtx->lpFront4, &lpddClipper); + IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd); + IDirectDrawClipper_Release(lpddClipper); + goto SkipPrimaryCreate; + } + + // Primary surface + ZeroMemory(&ddsd2, sizeof(ddsd2)); + ddsd2.dwSize = sizeof(ddsd2); + ddsd2.dwFlags = DDSD_CAPS; + ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL); + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult); + nContextError = GLDERR_MEM; + goto return_with_error; + } + + // Cache Primary surface for subsequent GLRCs + // Note this can only be applicable to subsequent windowed modes + if (glb.bDirectDrawPersistant && !glb.bDirectDrawPrimary) { + glb.lpPrimary4 = lpCtx->lpFront4; + IDirectDrawSurface4_AddRef(glb.lpPrimary4); + glb.bDirectDrawPrimary = TRUE; + } + + // Clipper object + hResult = DirectDrawCreateClipper(0, &lpddClipper, NULL); + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateClipper failed", hResult); + goto return_with_error; + } + hResult = IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd); + if (FAILED(hResult)) { + RELEASE(lpddClipper); + ddlogError(DDLOG_CRITICAL_OR_WARN, "SetHWnd failed", hResult); + goto return_with_error; + } + hResult = IDirectDrawSurface4_SetClipper(lpCtx->lpFront4, lpddClipper); + RELEASE(lpddClipper); // We have finished with it. + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "SetClipper failed", hResult); + goto return_with_error; + } +SkipPrimaryCreate: + + if (bDoubleBuffer) { + // Render target surface + ZeroMemory(&ddsd2, sizeof(ddsd2)); + ddsd2.dwSize = sizeof(ddsd2); + ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd2.dwWidth = lpCtx->dwWidth; + ddsd2.dwHeight = lpCtx->dwHeight; + ddsd2.ddsCaps.dwCaps = DDSCAPS_3DDEVICE | + DDSCAPS_OFFSCREENPLAIN | + dwMemoryType; + + // Reserve the entire desktop size for persistant buffers option + if (glb.bDirectDrawPersistant && glb.bPersistantBuffers) { + ddsd2.dwWidth = ddsd2DisplayMode.dwWidth; + ddsd2.dwHeight = ddsd2DisplayMode.dwHeight; + } + // Re-use original back buffer if persistant buffers exist + if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpBack4) + hResult = IDirectDrawSurface4_AddRef(lpCtx->lpBack4 = glb.lpBack4); + else + hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpBack4, NULL); + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "Create Backbuffer failed", hResult); + nContextError = GLDERR_MEM; + goto return_with_error; + } + if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpBack4) + IDirectDrawSurface4_AddRef(glb.lpBack4 = lpCtx->lpBack4); + } else { + lpCtx->lpBack4 = NULL; + } + } + + // + // Now create the Z-buffer + // + lpCtx->bStencil = FALSE; // Default to no stencil buffer + if (bDepthBuffer && (lpCtx->lpPF->iZBufferPF != -1)) { + // Get z-buffer dimensions from the render target + // Setup the surface desc for the z-buffer. + ZeroMemory(&ddsd2, sizeof(ddsd2)); + ddsd2.dwSize = sizeof(ddsd2); + ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; + ddsd2.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | dwMemoryType; + ddsd2.dwWidth = lpCtx->dwWidth; + ddsd2.dwHeight = lpCtx->dwHeight; + memcpy(&ddsd2.ddpfPixelFormat, + &glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF], + sizeof(DDPIXELFORMAT) ); + + // Reserve the entire desktop size for persistant buffers option + if (glb.bDirectDrawPersistant && glb.bPersistantBuffers) { + ddsd2.dwWidth = ddsd2DisplayMode.dwWidth; + ddsd2.dwHeight = ddsd2DisplayMode.dwHeight; + } + + // Create a z-buffer + if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpDepth4) + hResult = IDirectDrawSurface4_AddRef(lpCtx->lpDepth4 = glb.lpDepth4); + else + hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpDepth4, NULL); + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (ZBuffer) failed", hResult); + nContextError = GLDERR_MEM; + goto return_with_error; + } + if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpDepth4) + IDirectDrawSurface4_AddRef(glb.lpDepth4 = lpCtx->lpDepth4); + else if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpDepth4 && glb.lpBack4) + IDirectDrawSurface4_DeleteAttachedSurface(glb.lpBack4, 0, glb.lpDepth4); + + // Attach Zbuffer to render target + TRY(IDirectDrawSurface4_AddAttachedSurface( + bDoubleBuffer ? lpCtx->lpBack4 : lpCtx->lpFront4, + lpCtx->lpDepth4), + "dglCreateContext: Attach Zbuffer"); + if (glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwFlags & DDPF_STENCILBUFFER) { + lpCtx->bStencil = TRUE; + ddlogMessage(DDLOG_INFO, "Depth buffer has stencil\n"); + } + } + + // Clear all back buffers and Z-buffers in case of memory recycling. + ZeroMemory(&ddbltfx, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(ddbltfx); + IDirectDrawSurface4_Blt(lpCtx->lpBack4, NULL, NULL, NULL, + DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); + if (lpCtx->lpDepth4) + IDirectDrawSurface4_Blt(lpCtx->lpDepth4, NULL, NULL, NULL, + DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); + + // Now that we have a Z-buffer we can create the 3D device + hResult = IDirect3D3_CreateDevice(lpCtx->lpD3D3, + &glb.d3dGuid, + bDoubleBuffer ? lpCtx->lpBack4 : lpCtx->lpFront4, + &lpCtx->lpDev3, + NULL); + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create Direct3D device", hResult); + nContextError = GLDERR_D3D; + goto return_with_error; + } + + // We must do this as soon as the device is created + dglInitStateCaches(lpCtx); + + // Obtain the D3D Device Description + D3DHWDevDesc.dwSize = D3DHELDevDesc.dwSize = sizeof(D3DDEVICEDESC); + TRY(IDirect3DDevice3_GetCaps(lpCtx->lpDev3, + &D3DHWDevDesc, + &D3DHELDevDesc), + "dglCreateContext: GetCaps failed"); + + // Choose the relevant description and cache it in the context. + // We will use this description later for caps checking + memcpy( &lpCtx->D3DDevDesc, + glb.bHardware ? &D3DHWDevDesc : &D3DHELDevDesc, + sizeof(D3DDEVICEDESC)); + + // Now we can examine the texture formats + if (!dglBuildTextureFormatList(lpCtx->lpDev3)) { + ddlogMessage(DDLOG_CRITICAL_OR_WARN, "dglBuildTextureFormatList failed\n"); + goto return_with_error; + } + + // Get the pixel format of the back buffer + lpCtx->ddpfRender.dwSize = sizeof(lpCtx->ddpfRender); + if (bDoubleBuffer) + hResult = IDirectDrawSurface4_GetPixelFormat( + lpCtx->lpBack4, + &lpCtx->ddpfRender); + else + hResult = IDirectDrawSurface4_GetPixelFormat( + lpCtx->lpFront4, + &lpCtx->ddpfRender); + + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "GetPixelFormat failed", hResult); + goto return_with_error; + } + // Find a pixel packing function suitable for this surface + pxClassifyPixelFormat(&lpCtx->ddpfRender, + &lpCtx->fnPackFunc, + &lpCtx->fnUnpackFunc, + &lpCtx->fnPackSpanFunc); + + // Viewport + hResult = IDirect3D3_CreateViewport(lpCtx->lpD3D3, &lpCtx->lpViewport3, NULL); + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateViewport failed", hResult); + goto return_with_error; + } + + hResult = IDirect3DDevice3_AddViewport(lpCtx->lpDev3, lpCtx->lpViewport3); + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "AddViewport failed", hResult); + goto return_with_error; + } + + // Initialise the viewport + // Note screen coordinates are used for viewport clipping since D3D + // transform operations are not used in the GLD CAD driver. (DaveM) + inv_aspect = (float)lpCtx->dwHeight/(float)lpCtx->dwWidth; + + lpCtx->d3dViewport.dwSize = sizeof(lpCtx->d3dViewport); + lpCtx->d3dViewport.dwX = 0; + lpCtx->d3dViewport.dwY = 0; + lpCtx->d3dViewport.dwWidth = lpCtx->dwWidth; + lpCtx->d3dViewport.dwHeight = lpCtx->dwHeight; + lpCtx->d3dViewport.dvClipX = 0; // -1.0f; + lpCtx->d3dViewport.dvClipY = 0; // inv_aspect; + lpCtx->d3dViewport.dvClipWidth = lpCtx->dwWidth; // 2.0f; + lpCtx->d3dViewport.dvClipHeight = lpCtx->dwHeight; // 2.0f * inv_aspect; + lpCtx->d3dViewport.dvMinZ = 0.0f; + lpCtx->d3dViewport.dvMaxZ = 1.0f; + TRY(IDirect3DViewport3_SetViewport2(lpCtx->lpViewport3, &lpCtx->d3dViewport), "dglCreateContext: SetViewport2"); + + hResult = IDirect3DDevice3_SetCurrentViewport(lpCtx->lpDev3, lpCtx->lpViewport3); + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "SetCurrentViewport failed", hResult); + goto return_with_error; + } + + lpCtx->dwBPP = lpPFD->cColorBits; + lpCtx->iZBufferPF = lpCtx->lpPF->iZBufferPF; + + // Set last texture to NULL + for (i=0; iColorOp[i] = D3DTOP_DISABLE; + lpCtx->AlphaOp[i] = D3DTOP_DISABLE; + lpCtx->tObj[i] = NULL; + } + + // Default to perspective correct texture mapping + dglSetRenderState(lpCtx, D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE, "TexturePersp"); + + // Set the default culling mode + lpCtx->cullmode = D3DCULL_NONE; + dglSetRenderState(lpCtx, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE, "CullMode"); + + // Disable specular + dglSetRenderState(lpCtx, D3DRENDERSTATE_SPECULARENABLE, FALSE, "SpecularEnable"); + // Disable subpixel correction +// dglSetRenderState(lpCtx, D3DRENDERSTATE_SUBPIXEL, FALSE, "SubpixelEnable"); + // Disable dithering + dglSetRenderState(lpCtx, D3DRENDERSTATE_DITHERENABLE, FALSE, "DitherEnable"); + + // Initialise the primitive caches +// lpCtx->dwNextLineVert = 0; +// lpCtx->dwNextTriVert = 0; + + // Init the global texture palette + lpCtx->lpGlobalPalette = NULL; + + // Init the HW/SW usage counters +// lpCtx->dwHWUsageCount = lpCtx->dwSWUsageCount = 0L; + + // + // Create two D3D vertex buffers. + // One will hold the pre-transformed data with the other one + // being used to hold the post-transformed & clipped verts. + // +#if 0 // never used (DaveM) + vbufdesc.dwSize = sizeof(D3DVERTEXBUFFERDESC); + vbufdesc.dwCaps = D3DVBCAPS_WRITEONLY; + if (glb.bHardware == FALSE) + vbufdesc.dwCaps = D3DVBCAPS_SYSTEMMEMORY; + vbufdesc.dwNumVertices = 32768; // For the time being + + // Source vertex buffer + vbufdesc.dwFVF = DGL_LVERTEX; + hResult = IDirect3D3_CreateVertexBuffer(lpCtx->lpD3D3, &vbufdesc, &lpCtx->m_vbuf, 0, NULL); + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateVertexBuffer(src) failed", hResult); + goto return_with_error; + } + + // Destination vertex buffer + vbufdesc.dwFVF = (glb.bMultitexture == FALSE) ? D3DFVF_TLVERTEX : (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX2); + hResult = IDirect3D3_CreateVertexBuffer(lpCtx->lpD3D3, &vbufdesc, &lpCtx->m_pvbuf, 0, NULL); + if(FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateVertexBuffer(dst) failed", hResult); + goto return_with_error; + } +#endif + +#endif _USE_GLD3_WGL + + // + // Now create the Mesa context + // + + // Create the Mesa visual + if (lpPFD->cDepthBits) + dwDepthBits = 16; + if (lpPFD->cStencilBits) + dwStencilBits = 8; + if (lpPFD->cAlphaBits) { + dwAlphaBits = 8; + bAlphaSW = GL_TRUE; + } + if (lpPFD->dwFlags & PFD_DOUBLEBUFFER) + bDouble = GL_TRUE; +// lpCtx->EmulateSingle = +// (lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? FALSE : TRUE; + +#ifdef _USE_GLD3_WGL + lpCtx->glVis = _mesa_create_visual( + bDouble, /* double buffer */ + GL_FALSE, // stereo + lpPFD->cRedBits, + lpPFD->cGreenBits, + lpPFD->cBlueBits, + dwAlphaBits, + dwDepthBits, + dwStencilBits, + lpPFD->cAccumRedBits, // accum bits + lpPFD->cAccumGreenBits, // accum bits + lpPFD->cAccumBlueBits, // accum bits + lpPFD->cAccumAlphaBits, // accum alpha bits + 1 // num samples + ); +#else // _USE_GLD3_WGL + lpCtx->glVis = (*mesaFuncs.gl_create_visual)( + GL_TRUE, // RGB mode + bAlphaSW, // Is an alpha buffer required? + bDouble, // Is an double-buffering required? + GL_FALSE, // stereo + dwDepthBits, // depth_size + dwStencilBits, // stencil_size + lpPFD->cAccumBits, // accum_size + 0, // colour-index bits + lpPFD->cRedBits, // Red bit count + lpPFD->cGreenBits, // Green bit count + lpPFD->cBlueBits, // Blue bit count + dwAlphaBits // Alpha bit count + ); +#endif // _USE_GLD3_WGL + + if (lpCtx->glVis == NULL) { + ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_visual failed\n"); + goto return_with_error; + } + +#ifdef _USE_GLD3_WGL + lpCtx->glCtx = _mesa_create_context(API_OPENGL, lpCtx->glVis, NULL, (void *)lpCtx, GL_TRUE); +#else + // Create the Mesa context + lpCtx->glCtx = (*mesaFuncs.gl_create_context)( + lpCtx->glVis, // Mesa visual + NULL, // share list context + (void *)lpCtx, // Pointer to our driver context + GL_TRUE // Direct context flag + ); +#endif // _USE_GLD3_WGL + + if (lpCtx->glCtx == NULL) { + ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_context failed\n"); + goto return_with_error; + } + + // Create the Mesa framebuffer +#ifdef _USE_GLD3_WGL + lpCtx->glBuffer = _mesa_create_framebuffer( + lpCtx->glVis, + lpCtx->glVis->depthBits > 0, + lpCtx->glVis->stencilBits > 0, + lpCtx->glVis->accumRedBits > 0, + GL_FALSE //swalpha + ); +#else + lpCtx->glBuffer = (*mesaFuncs.gl_create_framebuffer)(lpCtx->glVis); +#endif // _USE_GLD3_WGL + + if (lpCtx->glBuffer == NULL) { + ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_framebuffer failed\n"); + goto return_with_error; + } + +#ifdef _USE_GLD3_WGL + // Init Mesa internals + _swrast_CreateContext( lpCtx->glCtx ); + _vbo_CreateContext( lpCtx->glCtx ); + _tnl_CreateContext( lpCtx->glCtx ); + _swsetup_CreateContext( lpCtx->glCtx ); + + _gldDriver.InitialiseMesa(lpCtx); + + lpCtx->glCtx->imports.warning = _gld_mesa_warning; + lpCtx->glCtx->imports.fatal = _gld_mesa_fatal; + +#else + // Tell Mesa how many texture stages we have + glb.wMaxSimultaneousTextures = lpCtx->D3DDevDesc.wMaxSimultaneousTextures; + // Only use as many Units as the spec requires + if (glb.wMaxSimultaneousTextures > MAX_TEXTURE_UNITS) + glb.wMaxSimultaneousTextures = MAX_TEXTURE_UNITS; + lpCtx->glCtx->Const.MaxTextureUnits = glb.wMaxSimultaneousTextures; + ddlogPrintf(DDLOG_INFO, "Texture stages : %d", glb.wMaxSimultaneousTextures); + + // Set the max texture size. + // NOTE: clamped to a max of 1024 for extra performance! + lpCtx->dwMaxTextureSize = (lpCtx->D3DDevDesc.dwMaxTextureWidth <= 1024) ? lpCtx->D3DDevDesc.dwMaxTextureWidth : 1024; + +// Texture resize takes place elsewhere. KH +// NOTE: This was added to workaround an issue with the Intel app. +#if 0 + lpCtx->glCtx->Const.MaxTextureSize = lpCtx->dwMaxTextureSize; +#else + lpCtx->glCtx->Const.MaxTextureSize = 1024; +#endif + lpCtx->glCtx->Const.MaxDrawBuffers = 1; + + // Setup the Display Driver pointers + dglSetupDDPointers(lpCtx->glCtx); + + // Initialise all the Direct3D renderstates + dglInitStateD3D(lpCtx->glCtx); + +#if 0 + // Signal a reload of texture state on next glBegin + lpCtx->m_texHandleValid = FALSE; + lpCtx->m_mtex = FALSE; + lpCtx->m_texturing = FALSE; +#else + // Set default texture unit state +// dglSetTexture(lpCtx, 0, NULL); +// dglSetTexture(lpCtx, 1, NULL); +#endif + + // + // Set the global texture palette to default values. + // + + // Clear the entire palette + ZeroMemory(ppe, sizeof(PALETTEENTRY) * 256); + + // Fill the palette with a default colour. + // A garish colour is used to catch bugs. Here Magenta is used. + for (i=0; i < 256; i++) { + ppe[i].peRed = 255; + ppe[i].peGreen = 0; + ppe[i].peBlue = 255; + } + + RELEASE(lpCtx->lpGlobalPalette); + + if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpGlobalPalette) + hResult = IDirectDrawPalette_AddRef(lpCtx->lpGlobalPalette = glb.lpGlobalPalette); + else + hResult = IDirectDraw4_CreatePalette( + lpCtx->lpDD4, + DDPCAPS_INITIALIZE | DDPCAPS_8BIT | DDPCAPS_ALLOW256, + ppe, + &(lpCtx->lpGlobalPalette), + NULL); + if (FAILED(hResult)) { + ddlogError(DDLOG_ERROR, "Default CreatePalette failed\n", hResult); + lpCtx->lpGlobalPalette = NULL; + goto return_with_error; + } + if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpGlobalPalette) + IDirectDrawPalette_AddRef(glb.lpGlobalPalette = lpCtx->lpGlobalPalette); + +#endif // _USE_GLD3_WGL + + // ** If we have made it to here then we can enable rendering ** + lpCtx->bCanRender = TRUE; + +// ddlogMessage(DDLOG_SYSTEM, "dglCreateContextBuffers succeded\n"); + +#ifdef GLD_THREADS + // Release serialized access + if (glb.bMultiThreaded) + LeaveCriticalSection(&CriticalSection); +#endif + + return TRUE; + +return_with_error: + // Clean up before returning. + // This is critical for secondary devices. + + lpCtx->bCanRender = FALSE; + +#ifdef _USE_GLD3_WGL + // Destroy the Mesa context + if (lpCtx->glBuffer) + _mesa_destroy_framebuffer(lpCtx->glBuffer); + if (lpCtx->glCtx) + _mesa_destroy_context(lpCtx->glCtx); + if (lpCtx->glVis) + _mesa_destroy_visual(lpCtx->glVis); + + // Destroy driver data + _gldDriver.DestroyDrawable(lpCtx); +#else + // Destroy the Mesa context + if (lpCtx->glBuffer) + (*mesaFuncs.gl_destroy_framebuffer)(lpCtx->glBuffer); + if (lpCtx->glCtx) + (*mesaFuncs.gl_destroy_context)(lpCtx->glCtx); + if (lpCtx->glVis) + (*mesaFuncs.gl_destroy_visual)(lpCtx->glVis); + + RELEASE(lpCtx->m_pvbuf); // Release D3D vertex buffer + RELEASE(lpCtx->m_vbuf); // Release D3D vertex buffer + + if (lpCtx->lpViewport3) { + if (lpCtx->lpDev3) IDirect3DDevice3_DeleteViewport(lpCtx->lpDev3, lpCtx->lpViewport3); + RELEASE(lpCtx->lpViewport3); + lpCtx->lpViewport3 = NULL; + } + + RELEASE(lpCtx->lpDev3); + if (lpCtx->lpDepth4) { + if (lpCtx->lpBack4) + IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpBack4, 0L, lpCtx->lpDepth4); + else + IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpFront4, 0L, lpCtx->lpDepth4); + RELEASE(lpCtx->lpDepth4); + lpCtx->lpDepth4 = NULL; + } + RELEASE(lpCtx->lpBack4); + RELEASE(lpCtx->lpFront4); + else + if (lpCtx->bFullscreen) { + IDirectDraw4_RestoreDisplayMode(lpCtx->lpDD4); + IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, NULL, DDSCL_NORMAL); + } + RELEASE(lpCtx->lpD3D3); + RELEASE(lpCtx->lpDD4); + RELEASE(lpCtx->lpDD1); +#endif // _USE_GLD3_WGL + + lpCtx->bAllocated = FALSE; + +#ifdef GLD_THREADS + // Release serialized access + if (glb.bMultiThreaded) + LeaveCriticalSection(&CriticalSection); +#endif + + return FALSE; + +#undef DDLOG_CRITICAL_OR_WARN +} + +// *********************************************************************** + +HGLRC dglCreateContext( + HDC a, + const DGL_pixelFormat *lpPF) +{ + int i; + HGLRC hGLRC; + DGL_ctx* lpCtx; + static BOOL bWarnOnce = TRUE; + DWORD dwThreadId = GetCurrentThreadId(); + char szMsg[256]; + HWND hWnd; + LONG lpfnWndProc; + + // Validate license + if (!dglValidate()) + return NULL; + + // Is context state ready ? + if (!bContextReady) + return NULL; + + ddlogPrintf(DDLOG_SYSTEM, "dglCreateContext for HDC=%X, ThreadId=%X", a, dwThreadId); + + // Find next free context. + // Also ensure that only one Fullscreen context is created at any one time. + hGLRC = 0; // Default to Not Found + for (i=0; ibAllocated = TRUE; + // Flag that buffers need creating on next wglMakeCurrent call. + lpCtx->bHasBeenCurrent = FALSE; + lpCtx->lpPF = (DGL_pixelFormat *)lpPF; // cache pixel format + lpCtx->bCanRender = FALSE; + + // Create all the internal resources here, not in dglMakeCurrent(). + // We do a re-size check in dglMakeCurrent in case of re-allocations. (DaveM) + // We now try context allocations twice, first with video memory, + // then again with system memory. This is similar to technique + // used for dglWglResizeBuffers(). (DaveM) + if (lpCtx->bHasBeenCurrent == FALSE) { + if (!dglCreateContextBuffers(a, lpCtx, FALSE)) { + if (glb.bMessageBoxWarnings && bWarnOnce && dwLogging) { + bWarnOnce = FALSE; + switch (nContextError) { + case GLDERR_DDRAW: strcpy(szMsg, szDDrawWarning); break; + case GLDERR_D3D: strcpy(szMsg, szD3DWarning); break; + case GLDERR_MEM: strcpy(szMsg, szResourceWarning); break; + case GLDERR_BPP: strcpy(szMsg, szBPPWarning); break; + default: strcpy(szMsg, ""); + } + if (strlen(szMsg)) + MessageBox(NULL, szMsg, "GLDirect", MB_OK | MB_ICONWARNING); + } + // Only need to try again if memory error + if (nContextError == GLDERR_MEM) { + ddlogPrintf(DDLOG_WARN, "dglCreateContext failed 1st time with video memory"); + } + else { + ddlogPrintf(DDLOG_ERROR, "dglCreateContext failed"); + return NULL; + } + } + } + + // Now that we have a hWnd, we can intercept the WindowProc. + hWnd = lpCtx->hWnd; + if (hWnd) { + // Only hook individual window handler once if not hooked before. + lpfnWndProc = GetWindowLong(hWnd, GWL_WNDPROC); + if (lpfnWndProc != (LONG)dglWndProc) { + lpCtx->lpfnWndProc = lpfnWndProc; + SetWindowLong(hWnd, GWL_WNDPROC, (LONG)dglWndProc); + } + // Find the parent window of the app too. + if (glb.hWndActive == NULL) { + while (hWnd != NULL) { + glb.hWndActive = hWnd; + hWnd = GetParent(hWnd); + } + // Hook the parent window too. + lpfnWndProc = GetWindowLong(glb.hWndActive, GWL_WNDPROC); + if (glb.hWndActive == lpCtx->hWnd) + glb.lpfnWndProc = lpCtx->lpfnWndProc; + else if (lpfnWndProc != (LONG)dglWndProc) + glb.lpfnWndProc = lpfnWndProc; + if (glb.lpfnWndProc) + SetWindowLong(glb.hWndActive, GWL_WNDPROC, (LONG)dglWndProc); + } + } + + ddlogPrintf(DDLOG_SYSTEM, "dglCreateContext succeeded for HGLRC=%d", (int)hGLRC); + + return hGLRC; +} + +// *********************************************************************** +// Make a DirectGL context current +// Used by wgl functions and dgl functions +BOOL dglMakeCurrent( + HDC a, + HGLRC b) +{ + int context; + DGL_ctx* lpCtx; + HWND hWnd; + BOOL bNeedResize = FALSE; + BOOL bWindowChanged, bContextChanged; + LPDIRECTDRAWCLIPPER lpddClipper; + DWORD dwThreadId = GetCurrentThreadId(); + LONG lpfnWndProc; + + // Validate license + if (!dglValidate()) + return FALSE; + + // Is context state ready ? + if (!bContextReady) + return FALSE; + + context = (int)b; // This is as a result of STRICT! + ddlogPrintf(DDLOG_SYSTEM, "dglMakeCurrent: HDC=%X, HGLRC=%d, ThreadId=%X", a, context, dwThreadId); + + // If the HGLRC is NULL then make no context current; + // Ditto if the HDC is NULL either. (DaveM) + if (context == 0 || a == 0) { + // Corresponding Mesa operation +#ifdef _USE_GLD3_WGL + _mesa_make_current(NULL, NULL); +#else + (*mesaFuncs.gl_make_current)(NULL, NULL); +#endif + dglSetCurrentContext(0); + return TRUE; + } + + // Make sure the HGLRC is in range + if ((context > DGL_MAX_CONTEXTS) || (context < 0)) { + ddlogMessage(DDLOG_ERROR, "dglMakeCurrent: HGLRC out of range\n"); + return FALSE; + } + + // Find address of context and make sure that it has been allocated + lpCtx = dglGetContextAddress(b); + if (!lpCtx->bAllocated) { + ddlogMessage(DDLOG_ERROR, "dglMakeCurrent: Context not allocated\n"); +// return FALSE; + return TRUE; // HACK: Shuts up "WebLab Viewer Pro". KeithH + } + +#ifdef GLD_THREADS + // Serialize access to DirectDraw or DDS operations + if (glb.bMultiThreaded) + EnterCriticalSection(&CriticalSection); +#endif + + // Check if window has changed + hWnd = (a != lpCtx->hDC) ? WindowFromDC(a) : lpCtx->hWnd; + bWindowChanged = (hWnd != lpCtx->hWnd) ? TRUE : FALSE; + bContextChanged = (b != dglGetCurrentContext()) ? TRUE : FALSE; + + // If the window has changed, make sure the clipper is updated. (DaveM) + if (glb.bDirectDrawPersistant && !lpCtx->bFullscreen && (bWindowChanged || bContextChanged)) { + lpCtx->hWnd = hWnd; +#ifndef _USE_GLD3_WGL + IDirectDrawSurface4_GetClipper(lpCtx->lpFront4, &lpddClipper); + IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd); + IDirectDrawClipper_Release(lpddClipper); +#endif // _USE_GLD3_WGL + } + + // Make sure hDC and hWnd is current. (DaveM) + // Obtain the dimensions of the rendering window + lpCtx->hDC = a; // Cache DC + lpCtx->hWnd = hWnd; + hWndLastActive = hWnd; + + // Check for non-window DC = memory DC ? + if (hWnd == NULL) { + if (GetClipBox(a, &lpCtx->rcScreenRect) == ERROR) { + ddlogMessage(DDLOG_WARN, "GetClipBox failed in dglMakeCurrent\n"); + SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0); + } + } + else if (!GetClientRect(lpCtx->hWnd, &lpCtx->rcScreenRect)) { + ddlogMessage(DDLOG_WARN, "GetClientRect failed in dglMakeCurrent\n"); + SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0); + } + // Check if buffers need to be re-sized; + // If so, wait until Mesa GL stuff is setup before re-sizing; + if (lpCtx->dwWidth != lpCtx->rcScreenRect.right - lpCtx->rcScreenRect.left || + lpCtx->dwHeight != lpCtx->rcScreenRect.bottom - lpCtx->rcScreenRect.top) + bNeedResize = TRUE; + + // Now we can update our globals + dglSetCurrentContext(b); + + // Corresponding Mesa operation +#ifdef _USE_GLD3_WGL + _mesa_make_current(lpCtx->glCtx, lpCtx->glBuffer); + lpCtx->glCtx->Driver.UpdateState(lpCtx->glCtx, _NEW_ALL); + if (bNeedResize) { + // Resize buffers (Note Mesa GL needs to be setup beforehand); + // Resize Mesa internal buffer too via glViewport() command, + // which subsequently calls dglWglResizeBuffers() too. + lpCtx->glCtx->Driver.Viewport(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); + lpCtx->bHasBeenCurrent = TRUE; + } +#else + (*mesaFuncs.gl_make_current)(lpCtx->glCtx, lpCtx->glBuffer); + + dglSetupDDPointers(lpCtx->glCtx); + + // Insure DirectDraw surfaces fit current window DC + if (bNeedResize) { + // Resize buffers (Note Mesa GL needs to be setup beforehand); + // Resize Mesa internal buffer too via glViewport() command, + // which subsequently calls dglWglResizeBuffers() too. + (*mesaFuncs.gl_Viewport)(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); + lpCtx->bHasBeenCurrent = TRUE; + } +#endif // _USE_GLD3_WGL + ddlogPrintf(DDLOG_SYSTEM, "dglMakeCurrent: width = %d, height = %d", lpCtx->dwWidth, lpCtx->dwHeight); + + // We have to clear D3D back buffer and render state if emulated front buffering + // for different window (but not context) like in Solid Edge. + if (glb.bDirectDrawPersistant && glb.bPersistantBuffers + && (bWindowChanged /* || bContextChanged */) && lpCtx->EmulateSingle) { +#ifdef _USE_GLD3_WGL +// IDirect3DDevice8_EndScene(lpCtx->pDev); +// lpCtx->bSceneStarted = FALSE; + lpCtx->glCtx->Driver.Clear(lpCtx->glCtx, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, + GL_TRUE, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); +#else + IDirect3DDevice3_EndScene(lpCtx->lpDev3); + lpCtx->bSceneStarted = FALSE; + dglClearD3D(lpCtx->glCtx, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, + GL_TRUE, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); +#endif // _USE_GLD3_WGL + } + + // The first time we call MakeCurrent we set the initial viewport size + if (lpCtx->bHasBeenCurrent == FALSE) +#ifdef _USE_GLD3_WGL + lpCtx->glCtx->Driver.Viewport(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); +#else + (*mesaFuncs.gl_Viewport)(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); +#endif // _USE_GLD3_WGL + lpCtx->bHasBeenCurrent = TRUE; + +#ifdef GLD_THREADS + // Release serialized access + if (glb.bMultiThreaded) + LeaveCriticalSection(&CriticalSection); +#endif + + return TRUE; +} + +// *********************************************************************** + +BOOL dglDeleteContext( + HGLRC a) +{ + DGL_ctx* lpCtx; + DWORD dwThreadId = GetCurrentThreadId(); + char argstr[256]; + +#if 0 // We have enough trouble throwing exceptions as it is... (DaveM) + // Validate license + if (!dglValidate()) + return FALSE; +#endif + + // Is context state ready ? + if (!bContextReady) + return FALSE; + + ddlogPrintf(DDLOG_SYSTEM, "dglDeleteContext: Deleting context HGLRC=%d, ThreadId=%X", (int)a, dwThreadId); + + // Make sure the HGLRC is in range + if (((int) a> DGL_MAX_CONTEXTS) || ((int)a < 0)) { + ddlogMessage(DDLOG_ERROR, "dglDeleteCurrent: HGLRC out of range\n"); + return FALSE; + } + + // Make sure context is valid + lpCtx = dglGetContextAddress(a); + if (!lpCtx->bAllocated) { + ddlogPrintf(DDLOG_WARN, "Tried to delete unallocated context HGLRC=%d", (int)a); +// return FALSE; + return TRUE; // HACK: Shuts up "WebLab Viewer Pro". KeithH + } + + // Make sure context is de-activated + if (a == dglGetCurrentContext()) { + ddlogPrintf(DDLOG_WARN, "dglDeleteContext: context HGLRC=%d still active", (int)a); + dglMakeCurrent(NULL, NULL); + } + +#ifdef GLD_THREADS + // Serialize access to DirectDraw or DDS operations + if (glb.bMultiThreaded) + EnterCriticalSection(&CriticalSection); +#endif + + // We are about to destroy all Direct3D objects. + // Therefore we must disable rendering + lpCtx->bCanRender = FALSE; + + // This exception handler was installed to catch some + // particularly nasty apps. Console apps that call exit() + // fall into this catagory (i.e. Win32 Glut). + + // VC cannot successfully implement multiple exception handlers + // if more than one exception occurs. Therefore reverting back to + // single exception handler as Keith originally had it. (DaveM) + +#define WARN_MESSAGE(p) strcpy(argstr, (#p)); +#define SAFE_RELEASE(p) WARN_MESSAGE(p); RELEASE(p); + +__try { +#ifdef _USE_GLD3_WGL + WARN_MESSAGE(gl_destroy_framebuffer); + if (lpCtx->glBuffer) + _mesa_destroy_framebuffer(lpCtx->glBuffer); + WARN_MESSAGE(gl_destroy_context); + if (lpCtx->glCtx) + _mesa_destroy_context(lpCtx->glCtx); + WARN_MESSAGE(gl_destroy_visual); + if (lpCtx->glVis) + _mesa_destroy_visual(lpCtx->glVis); + + _gldDriver.DestroyDrawable(lpCtx); +#else + // Destroy the Mesa context + WARN_MESSAGE(gl_destroy_framebuffer); + if (lpCtx->glBuffer) + (*mesaFuncs.gl_destroy_framebuffer)(lpCtx->glBuffer); + WARN_MESSAGE(gl_destroy_context); + if (lpCtx->glCtx) + (*mesaFuncs.gl_destroy_context)(lpCtx->glCtx); + WARN_MESSAGE(gl_destroy_visual); + if (lpCtx->glVis) + (*mesaFuncs.gl_destroy_visual)(lpCtx->glVis); + + SAFE_RELEASE(lpCtx->m_pvbuf); // release D3D vertex buffer + SAFE_RELEASE(lpCtx->m_vbuf); // release D3D vertex buffer + + // Delete the global palette + SAFE_RELEASE(lpCtx->lpGlobalPalette); + + // Clean up. + if (lpCtx->lpViewport3) { + if (lpCtx->lpDev3) IDirect3DDevice3_DeleteViewport(lpCtx->lpDev3, lpCtx->lpViewport3); + SAFE_RELEASE(lpCtx->lpViewport3); + lpCtx->lpViewport3 = NULL; + } + + SAFE_RELEASE(lpCtx->lpDev3); + if (lpCtx->lpDepth4) { + if (lpCtx->lpBack4) + IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpBack4, 0L, lpCtx->lpDepth4); + else + IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpFront4, 0L, lpCtx->lpDepth4); + SAFE_RELEASE(lpCtx->lpDepth4); + lpCtx->lpDepth4 = NULL; + } + SAFE_RELEASE(lpCtx->lpBack4); + SAFE_RELEASE(lpCtx->lpFront4); + if (lpCtx->bFullscreen) { + IDirectDraw4_RestoreDisplayMode(lpCtx->lpDD4); + IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, NULL, DDSCL_NORMAL); + } + SAFE_RELEASE(lpCtx->lpD3D3); + SAFE_RELEASE(lpCtx->lpDD4); + SAFE_RELEASE(lpCtx->lpDD1); +#endif // _ULSE_GLD3_WGL + +} +__except(EXCEPTION_EXECUTE_HANDLER) { + ddlogPrintf(DDLOG_WARN, "Exception raised in dglDeleteContext: %s", argstr); +} + + // Restore the window message handler because this context may be used + // again by another window with a *different* message handler. (DaveM) + if (lpCtx->lpfnWndProc) { + SetWindowLong(lpCtx->hWnd, GWL_WNDPROC, (LONG)lpCtx->lpfnWndProc); + lpCtx->lpfnWndProc = (LONG)NULL; + } + + lpCtx->bAllocated = FALSE; // This context is now free for use + +#ifdef GLD_THREADS + // Release serialized access + if (glb.bMultiThreaded) + LeaveCriticalSection(&CriticalSection); +#endif + + return TRUE; +} + +// *********************************************************************** + +BOOL dglSwapBuffers( + HDC hDC) +{ + RECT rSrcRect; // Source rectangle + RECT rDstRect; // Destination rectangle + POINT pt; + HRESULT hResult; + + DDBLTFX bltFX; + DWORD dwBlitFlags; + DDBLTFX *lpBltFX; + +// DWORD dwThreadId = GetCurrentThreadId(); + HGLRC hGLRC = dglGetCurrentContext(); + DGL_ctx *lpCtx = dglGetContextAddress(hGLRC); + HWND hWnd; + + HDC hDCAux; // for memory DC + int x,y,w,h; // for memory DC BitBlt + +#if 0 // Perhaps not a good idea. Called too often. KH + // Validate license + if (!dglValidate()) + return FALSE; +#endif + + if (!lpCtx) { + return TRUE; //FALSE; // No current context + } + + if (!lpCtx->bCanRender) { + // Don't return false else some apps will bail. + return TRUE; + } + + hWnd = lpCtx->hWnd; + if (hDC != lpCtx->hDC) { + ddlogPrintf(DDLOG_WARN, "dglSwapBuffers: HDC=%X does not match HDC=%X for HGLRC=%d", hDC, lpCtx->hDC, hGLRC); + hWnd = WindowFromDC(hDC); + } + +#ifndef _USE_GLD3_WGL + // Ensure that the surfaces exist before we tell + // the device to render to them. + IDirectDraw4_RestoreAllSurfaces(lpCtx->lpDD4); + + // Make sure that the vertex caches have been emptied +// dglStateChange(lpCtx); + + // Some OpenGL programs don't issue a glFinish - check for it here. + if (lpCtx->bSceneStarted) { + IDirect3DDevice3_EndScene(lpCtx->lpDev3); + lpCtx->bSceneStarted = FALSE; + } +#endif + +#if 0 + // If the calling app is not active then we don't need to Blit/Flip. + // We can therefore simply return TRUE. + if (!glb.bAppActive) + return TRUE; + // Addendum: This is WRONG! We should bail if the app is *minimized*, + // not merely if the app is just plain 'not active'. + // KeithH, 27/May/2000. +#endif + + // Check for non-window DC = memory DC ? + if (hWnd == NULL) { + if (GetClipBox(hDC, &rSrcRect) == ERROR) + return TRUE; + // Use GDI BitBlt instead from compatible DirectDraw DC + x = rSrcRect.left; + y = rSrcRect.top; + w = rSrcRect.right - rSrcRect.left; + h = rSrcRect.bottom - rSrcRect.top; + + // Ack. DX8 does not have a GetDC() function... + // TODO: Defer to DX7 or DX9 drivers... (DaveM) + return TRUE; + } + + // Bail if window client region is not drawable, like in Solid Edge + if (!IsWindow(hWnd) /* || !IsWindowVisible(hWnd) */ || !GetClientRect(hWnd, &rSrcRect)) + return TRUE; + +#ifdef GLD_THREADS + // Serialize access to DirectDraw or DDS operations + if (glb.bMultiThreaded) + EnterCriticalSection(&CriticalSection); +#endif + +#ifdef _USE_GLD3_WGL + // Notify Mesa of impending swap, so Mesa can flush internal buffers. + _mesa_notifySwapBuffers(lpCtx->glCtx); + // Now perform driver buffer swap + _gldDriver.SwapBuffers(lpCtx, hDC, hWnd); +#else + if (lpCtx->bFullscreen) { + // Sync with retrace if required + if (glb.bWaitForRetrace) { + IDirectDraw4_WaitForVerticalBlank( + lpCtx->lpDD4, + DDWAITVB_BLOCKBEGIN, + 0); + } + + // Perform the fullscreen flip + TRY(IDirectDrawSurface4_Flip( + lpCtx->lpFront4, + NULL, + DDFLIP_WAIT), + "dglSwapBuffers: Flip"); + } else { + // Calculate current window position and size + pt.x = pt.y = 0; + ClientToScreen(hWnd, &pt); + GetClientRect(hWnd, &rDstRect); + if (rDstRect.right > lpCtx->dwModeWidth) + rDstRect.right = lpCtx->dwModeWidth; + if (rDstRect.bottom > lpCtx->dwModeHeight) + rDstRect.bottom = lpCtx->dwModeHeight; + OffsetRect(&rDstRect, pt.x, pt.y); + rSrcRect.left = rSrcRect.top = 0; + rSrcRect.right = lpCtx->dwWidth; + rSrcRect.bottom = lpCtx->dwHeight; + if (rSrcRect.right > lpCtx->dwModeWidth) + rSrcRect.right = lpCtx->dwModeWidth; + if (rSrcRect.bottom > lpCtx->dwModeHeight) + rSrcRect.bottom = lpCtx->dwModeHeight; + + if (glb.bWaitForRetrace) { + // Sync the blit to the vertical retrace + ZeroMemory(&bltFX, sizeof(bltFX)); + bltFX.dwSize = sizeof(bltFX); + bltFX.dwDDFX = DDBLTFX_NOTEARING; + dwBlitFlags = DDBLT_WAIT | DDBLT_DDFX; + lpBltFX = &bltFX; + } else { + dwBlitFlags = DDBLT_WAIT; + lpBltFX = NULL; + } + + // Perform the actual blit + TRY(IDirectDrawSurface4_Blt( + lpCtx->lpFront4, + &rDstRect, + lpCtx->lpBack4, // Blit source + &rSrcRect, + dwBlitFlags, + lpBltFX), + "dglSwapBuffers: Blt"); + } +#endif // _USE_GLD3_WGL + +#ifdef GLD_THREADS + // Release serialized access + if (glb.bMultiThreaded) + LeaveCriticalSection(&CriticalSection); +#endif + + // TODO: Re-instate rendering bitmap snapshot feature??? (DaveM) + + // Render frame is completed + ValidateRect(hWnd, NULL); + lpCtx->bFrameStarted = FALSE; + + return TRUE; +} + +// *********************************************************************** diff --git a/mesalib/src/mesa/main/blend.c b/mesalib/src/mesa/main/blend.c index 30466cca3..c74a16803 100644 --- a/mesalib/src/mesa/main/blend.c +++ b/mesalib/src/mesa/main/blend.c @@ -1,814 +1,822 @@ -/** - * \file blend.c - * Blending operations. - */ - -/* - * Mesa 3-D graphics library - * Version: 6.5.1 - * - * Copyright (C) 1999-2006 Brian Paul 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 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 - * BRIAN PAUL 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. - */ - - - -#include "glheader.h" -#include "blend.h" -#include "context.h" -#include "enums.h" -#include "macros.h" -#include "mtypes.h" - - - -/** - * Check if given blend source factor is legal. - * \return GL_TRUE if legal, GL_FALSE otherwise. - */ -static GLboolean -legal_src_factor(const struct gl_context *ctx, GLenum factor) -{ - switch (factor) { - case GL_SRC_COLOR: - case GL_ONE_MINUS_SRC_COLOR: - return ctx->Extensions.NV_blend_square; - case GL_ZERO: - case GL_ONE: - case GL_DST_COLOR: - case GL_ONE_MINUS_DST_COLOR: - case GL_SRC_ALPHA: - case GL_ONE_MINUS_SRC_ALPHA: - case GL_DST_ALPHA: - case GL_ONE_MINUS_DST_ALPHA: - case GL_SRC_ALPHA_SATURATE: - case GL_CONSTANT_COLOR: - case GL_ONE_MINUS_CONSTANT_COLOR: - case GL_CONSTANT_ALPHA: - case GL_ONE_MINUS_CONSTANT_ALPHA: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Check if given blend destination factor is legal. - * \return GL_TRUE if legal, GL_FALSE otherwise. - */ -static GLboolean -legal_dst_factor(const struct gl_context *ctx, GLenum factor) -{ - switch (factor) { - case GL_DST_COLOR: - case GL_ONE_MINUS_DST_COLOR: - return ctx->Extensions.NV_blend_square; - case GL_ZERO: - case GL_ONE: - case GL_SRC_COLOR: - case GL_ONE_MINUS_SRC_COLOR: - case GL_SRC_ALPHA: - case GL_ONE_MINUS_SRC_ALPHA: - case GL_DST_ALPHA: - case GL_ONE_MINUS_DST_ALPHA: - case GL_CONSTANT_COLOR: - case GL_ONE_MINUS_CONSTANT_COLOR: - case GL_CONSTANT_ALPHA: - case GL_ONE_MINUS_CONSTANT_ALPHA: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Check if src/dest RGB/A blend factors are legal. If not generate - * a GL error. - * \return GL_TRUE if factors are legal, GL_FALSE otherwise. - */ -static GLboolean -validate_blend_factors(struct gl_context *ctx, const char *func, - GLenum sfactorRGB, GLenum dfactorRGB, - GLenum sfactorA, GLenum dfactorA) -{ - if (!legal_src_factor(ctx, sfactorRGB)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "%s(sfactorRGB = %s)", func, - _mesa_lookup_enum_by_nr(sfactorRGB)); - return GL_FALSE; - } - - if (!legal_dst_factor(ctx, dfactorRGB)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "%s(dfactorRGB = %s)", func, - _mesa_lookup_enum_by_nr(dfactorRGB)); - return GL_FALSE; - } - - if (sfactorA != sfactorRGB && !legal_src_factor(ctx, sfactorA)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "%s(sfactorA = %s)", func, - _mesa_lookup_enum_by_nr(sfactorA)); - return GL_FALSE; - } - - if (dfactorA != dfactorRGB && !legal_dst_factor(ctx, dfactorA)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "%s(dfactorA = %s)", func, - _mesa_lookup_enum_by_nr(dfactorA)); - return GL_FALSE; - } - - return GL_TRUE; -} - - -/** - * Specify the blending operation. - * - * \param sfactor source factor operator. - * \param dfactor destination factor operator. - * - * \sa glBlendFunc, glBlendFuncSeparateEXT - */ -void GLAPIENTRY -_mesa_BlendFunc( GLenum sfactor, GLenum dfactor ) -{ - _mesa_BlendFuncSeparateEXT(sfactor, dfactor, sfactor, dfactor); -} - - -/** - * Set the separate blend source/dest factors for all draw buffers. - * - * \param sfactorRGB RGB source factor operator. - * \param dfactorRGB RGB destination factor operator. - * \param sfactorA alpha source factor operator. - * \param dfactorA alpha destination factor operator. - */ -void GLAPIENTRY -_mesa_BlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB, - GLenum sfactorA, GLenum dfactorA ) -{ - GLuint buf, numBuffers; - GLboolean changed; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glBlendFuncSeparate %s %s %s %s\n", - _mesa_lookup_enum_by_nr(sfactorRGB), - _mesa_lookup_enum_by_nr(dfactorRGB), - _mesa_lookup_enum_by_nr(sfactorA), - _mesa_lookup_enum_by_nr(dfactorA)); - - if (!validate_blend_factors(ctx, "glBlendFuncSeparate", - sfactorRGB, dfactorRGB, - sfactorA, dfactorA)) { - return; - } - - numBuffers = ctx->Extensions.ARB_draw_buffers_blend - ? ctx->Const.MaxDrawBuffers : 1; - - changed = GL_FALSE; - for (buf = 0; buf < numBuffers; buf++) { - if (ctx->Color.Blend[buf].SrcRGB != sfactorRGB || - ctx->Color.Blend[buf].DstRGB != dfactorRGB || - ctx->Color.Blend[buf].SrcA != sfactorA || - ctx->Color.Blend[buf].DstA != dfactorA) { - changed = GL_TRUE; - break; - } - } - if (!changed) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - - for (buf = 0; buf < numBuffers; buf++) { - ctx->Color.Blend[buf].SrcRGB = sfactorRGB; - ctx->Color.Blend[buf].DstRGB = dfactorRGB; - ctx->Color.Blend[buf].SrcA = sfactorA; - ctx->Color.Blend[buf].DstA = dfactorA; - } - ctx->Color._BlendFuncPerBuffer = GL_FALSE; - - if (ctx->Driver.BlendFuncSeparate) { - ctx->Driver.BlendFuncSeparate(ctx, sfactorRGB, dfactorRGB, - sfactorA, dfactorA); - } -} - - -#if _HAVE_FULL_GL - - -/** - * Set blend source/dest factors for one color buffer/target. - */ -void GLAPIENTRY -_mesa_BlendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) -{ - _mesa_BlendFuncSeparatei(buf, sfactor, dfactor, sfactor, dfactor); -} - - -/** - * Set separate blend source/dest factors for one color buffer/target. - */ -void GLAPIENTRY -_mesa_BlendFuncSeparatei(GLuint buf, GLenum sfactorRGB, GLenum dfactorRGB, - GLenum sfactorA, GLenum dfactorA) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!ctx->Extensions.ARB_draw_buffers_blend) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glBlendFunc[Separate]i()"); - return; - } - - if (buf >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)", - buf); - return; - } - - if (!validate_blend_factors(ctx, "glBlendFuncSeparatei", - sfactorRGB, dfactorRGB, - sfactorA, dfactorA)) { - return; - } - - if (ctx->Color.Blend[buf].SrcRGB == sfactorRGB && - ctx->Color.Blend[buf].DstRGB == dfactorRGB && - ctx->Color.Blend[buf].SrcA == sfactorA && - ctx->Color.Blend[buf].DstA == dfactorA) - return; /* no change */ - - FLUSH_VERTICES(ctx, _NEW_COLOR); - - ctx->Color.Blend[buf].SrcRGB = sfactorRGB; - ctx->Color.Blend[buf].DstRGB = dfactorRGB; - ctx->Color.Blend[buf].SrcA = sfactorA; - ctx->Color.Blend[buf].DstA = dfactorA; - ctx->Color._BlendFuncPerBuffer = GL_TRUE; - - if (ctx->Driver.BlendFuncSeparatei) { - ctx->Driver.BlendFuncSeparatei(ctx, buf, sfactorRGB, dfactorRGB, - sfactorA, dfactorA); - } -} - - -/** - * Check if given blend equation is legal. - * \return GL_TRUE if legal, GL_FALSE otherwise. - */ -static GLboolean -legal_blend_equation(const struct gl_context *ctx, - GLenum mode, GLboolean is_separate) -{ - switch (mode) { - case GL_FUNC_ADD: - return GL_TRUE; - case GL_MIN: - case GL_MAX: - return ctx->Extensions.EXT_blend_minmax; - case GL_LOGIC_OP: - /* glBlendEquationSeparate cannot take GL_LOGIC_OP as a parameter. - */ - return ctx->Extensions.EXT_blend_logic_op && !is_separate; - case GL_FUNC_SUBTRACT: - case GL_FUNC_REVERSE_SUBTRACT: - return ctx->Extensions.EXT_blend_subtract; - default: - return GL_FALSE; - } -} - - -/* This is really an extension function! */ -void GLAPIENTRY -_mesa_BlendEquation( GLenum mode ) -{ - GLuint buf, numBuffers; - GLboolean changed; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glBlendEquation %s\n", - _mesa_lookup_enum_by_nr(mode)); - - if (!legal_blend_equation(ctx, mode, GL_FALSE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation"); - return; - } - - numBuffers = ctx->Extensions.ARB_draw_buffers_blend - ? ctx->Const.MaxDrawBuffers : 1; - - changed = GL_FALSE; - for (buf = 0; buf < numBuffers; buf++) { - if (ctx->Color.Blend[buf].EquationRGB != mode || - ctx->Color.Blend[buf].EquationA != mode) { - changed = GL_TRUE; - break; - } - } - if (!changed) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - for (buf = 0; buf < numBuffers; buf++) { - ctx->Color.Blend[buf].EquationRGB = mode; - ctx->Color.Blend[buf].EquationA = mode; - } - ctx->Color._BlendEquationPerBuffer = GL_FALSE; - - if (ctx->Driver.BlendEquationSeparate) - (*ctx->Driver.BlendEquationSeparate)( ctx, mode, mode ); -} - - -/** - * Set blend equation for one color buffer/target. - */ -void GLAPIENTRY -_mesa_BlendEquationi(GLuint buf, GLenum mode) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glBlendEquationi(%u, %s)\n", - buf, _mesa_lookup_enum_by_nr(mode)); - - if (buf >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)", - buf); - return; - } - - if (!legal_blend_equation(ctx, mode, GL_FALSE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationi"); - return; - } - - if (ctx->Color.Blend[buf].EquationRGB == mode && - ctx->Color.Blend[buf].EquationA == mode) - return; /* no change */ - - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.Blend[buf].EquationRGB = mode; - ctx->Color.Blend[buf].EquationA = mode; - ctx->Color._BlendEquationPerBuffer = GL_TRUE; - - if (ctx->Driver.BlendEquationSeparatei) - ctx->Driver.BlendEquationSeparatei(ctx, buf, mode, mode); -} - - -void GLAPIENTRY -_mesa_BlendEquationSeparateEXT( GLenum modeRGB, GLenum modeA ) -{ - GLuint buf, numBuffers; - GLboolean changed; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glBlendEquationSeparateEXT %s %s\n", - _mesa_lookup_enum_by_nr(modeRGB), - _mesa_lookup_enum_by_nr(modeA)); - - if ( (modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate ) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlendEquationSeparateEXT not supported by driver"); - return; - } - - if (!legal_blend_equation(ctx, modeRGB, GL_TRUE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)"); - return; - } - - if (!legal_blend_equation(ctx, modeA, GL_TRUE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)"); - return; - } - - numBuffers = ctx->Extensions.ARB_draw_buffers_blend - ? ctx->Const.MaxDrawBuffers : 1; - - changed = GL_FALSE; - for (buf = 0; buf < numBuffers; buf++) { - if (ctx->Color.Blend[buf].EquationRGB != modeRGB || - ctx->Color.Blend[buf].EquationA != modeA) { - changed = GL_TRUE; - break; - } - } - if (!changed) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - for (buf = 0; buf < numBuffers; buf++) { - ctx->Color.Blend[buf].EquationRGB = modeRGB; - ctx->Color.Blend[buf].EquationA = modeA; - } - ctx->Color._BlendEquationPerBuffer = GL_FALSE; - - if (ctx->Driver.BlendEquationSeparate) - ctx->Driver.BlendEquationSeparate(ctx, modeRGB, modeA); -} - - -/** - * Set separate blend equations for one color buffer/target. - */ -void -_mesa_BlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeA) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glBlendEquationSeparatei %u, %s %s\n", buf, - _mesa_lookup_enum_by_nr(modeRGB), - _mesa_lookup_enum_by_nr(modeA)); - - if (buf >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationSeparatei(buffer=%u)", - buf); - return; - } - - if (!legal_blend_equation(ctx, modeRGB, GL_TRUE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeRGB)"); - return; - } - - if (!legal_blend_equation(ctx, modeA, GL_TRUE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeA)"); - return; - } - - if (ctx->Color.Blend[buf].EquationRGB == modeRGB && - ctx->Color.Blend[buf].EquationA == modeA) - return; /* no change */ - - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.Blend[buf].EquationRGB = modeRGB; - ctx->Color.Blend[buf].EquationA = modeA; - ctx->Color._BlendEquationPerBuffer = GL_TRUE; - - if (ctx->Driver.BlendEquationSeparatei) - ctx->Driver.BlendEquationSeparatei(ctx, buf, modeRGB, modeA); -} - - - -#endif /* _HAVE_FULL_GL */ - - -/** - * Set the blending color. - * - * \param red red color component. - * \param green green color component. - * \param blue blue color component. - * \param alpha alpha color component. - * - * \sa glBlendColor(). - * - * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor. On a - * change, flushes the vertices and notifies the driver via - * dd_function_table::BlendColor callback. - */ -void GLAPIENTRY -_mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) -{ - GLfloat tmp[4]; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - tmp[0] = CLAMP( red, 0.0F, 1.0F ); - tmp[1] = CLAMP( green, 0.0F, 1.0F ); - tmp[2] = CLAMP( blue, 0.0F, 1.0F ); - tmp[3] = CLAMP( alpha, 0.0F, 1.0F ); - - if (TEST_EQ_4V(tmp, ctx->Color.BlendColor)) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - COPY_4FV( ctx->Color.BlendColor, tmp ); - - if (ctx->Driver.BlendColor) - (*ctx->Driver.BlendColor)(ctx, tmp); -} - - -/** - * Specify the alpha test function. - * - * \param func alpha comparison function. - * \param ref reference value. - * - * Verifies the parameters and updates gl_colorbuffer_attrib. - * On a change, flushes the vertices and notifies the driver via - * dd_function_table::AlphaFunc callback. - */ -void GLAPIENTRY -_mesa_AlphaFunc( GLenum func, GLclampf ref ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - switch (func) { - case GL_NEVER: - case GL_LESS: - case GL_EQUAL: - case GL_LEQUAL: - case GL_GREATER: - case GL_NOTEQUAL: - case GL_GEQUAL: - case GL_ALWAYS: - ref = CLAMP(ref, 0.0F, 1.0F); - - if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRef == ref) - return; /* no change */ - - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.AlphaFunc = func; - ctx->Color.AlphaRef = ref; - - if (ctx->Driver.AlphaFunc) - ctx->Driver.AlphaFunc(ctx, func, ref); - return; - - default: - _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" ); - return; - } -} - - -/** - * Specify a logic pixel operation for color index rendering. - * - * \param opcode operation. - * - * Verifies that \p opcode is a valid enum and updates -gl_colorbuffer_attrib::LogicOp. - * On a change, flushes the vertices and notifies the driver via the - * dd_function_table::LogicOpcode callback. - */ -void GLAPIENTRY -_mesa_LogicOp( GLenum opcode ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - switch (opcode) { - case GL_CLEAR: - case GL_SET: - case GL_COPY: - case GL_COPY_INVERTED: - case GL_NOOP: - case GL_INVERT: - case GL_AND: - case GL_NAND: - case GL_OR: - case GL_NOR: - case GL_XOR: - case GL_EQUIV: - case GL_AND_REVERSE: - case GL_AND_INVERTED: - case GL_OR_REVERSE: - case GL_OR_INVERTED: - break; - default: - _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" ); - return; - } - - if (ctx->Color.LogicOp == opcode) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.LogicOp = opcode; - - if (ctx->Driver.LogicOpcode) - ctx->Driver.LogicOpcode( ctx, opcode ); -} - -#if _HAVE_FULL_GL -void GLAPIENTRY -_mesa_IndexMask( GLuint mask ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (ctx->Color.IndexMask == mask) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.IndexMask = mask; -} -#endif - - -/** - * Enable or disable writing of frame buffer color components. - * - * \param red whether to mask writing of the red color component. - * \param green whether to mask writing of the green color component. - * \param blue whether to mask writing of the blue color component. - * \param alpha whether to mask writing of the alpha color component. - * - * \sa glColorMask(). - * - * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a - * change, flushes the vertices and notifies the driver via the - * dd_function_table::ColorMask callback. - */ -void GLAPIENTRY -_mesa_ColorMask( GLboolean red, GLboolean green, - GLboolean blue, GLboolean alpha ) -{ - GET_CURRENT_CONTEXT(ctx); - GLubyte tmp[4]; - GLuint i; - GLboolean flushed; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glColorMask %d %d %d %d\n", red, green, blue, alpha); - - /* Shouldn't have any information about channel depth in core mesa - * -- should probably store these as the native booleans: - */ - tmp[RCOMP] = red ? 0xff : 0x0; - tmp[GCOMP] = green ? 0xff : 0x0; - tmp[BCOMP] = blue ? 0xff : 0x0; - tmp[ACOMP] = alpha ? 0xff : 0x0; - - flushed = GL_FALSE; - for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { - if (!TEST_EQ_4V(tmp, ctx->Color.ColorMask[i])) { - if (!flushed) { - FLUSH_VERTICES(ctx, _NEW_COLOR); - } - flushed = GL_TRUE; - COPY_4UBV(ctx->Color.ColorMask[i], tmp); - } - } - - if (ctx->Driver.ColorMask) - ctx->Driver.ColorMask( ctx, red, green, blue, alpha ); -} - - -/** - * For GL_EXT_draw_buffers2 and GL3 - */ -void GLAPIENTRY -_mesa_ColorMaskIndexed( GLuint buf, GLboolean red, GLboolean green, - GLboolean blue, GLboolean alpha ) -{ - GLubyte tmp[4]; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glColorMaskIndexed %u %d %d %d %d\n", - buf, red, green, blue, alpha); - - if (buf >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "glColorMaskIndexed(buf=%u)", buf); - return; - } - - /* Shouldn't have any information about channel depth in core mesa - * -- should probably store these as the native booleans: - */ - tmp[RCOMP] = red ? 0xff : 0x0; - tmp[GCOMP] = green ? 0xff : 0x0; - tmp[BCOMP] = blue ? 0xff : 0x0; - tmp[ACOMP] = alpha ? 0xff : 0x0; - - if (TEST_EQ_4V(tmp, ctx->Color.ColorMask[buf])) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - COPY_4UBV(ctx->Color.ColorMask[buf], tmp); - - if (ctx->Driver.ColorMaskIndexed) - ctx->Driver.ColorMaskIndexed(ctx, buf, red, green, blue, alpha); -} - - -extern void GLAPIENTRY -_mesa_ClampColorARB(GLenum target, GLenum clamp) -{ - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (clamp != GL_TRUE && clamp != GL_FALSE && clamp != GL_FIXED_ONLY_ARB) { - _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(clamp)"); - return; - } - - switch (target) { - case GL_CLAMP_VERTEX_COLOR_ARB: - ctx->Light.ClampVertexColor = clamp; - break; - case GL_CLAMP_FRAGMENT_COLOR_ARB: - ctx->Color.ClampFragmentColor = clamp; - break; - case GL_CLAMP_READ_COLOR_ARB: - ctx->Color.ClampReadColor = clamp; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(target)"); - return; - } -} - - - - -/**********************************************************************/ -/** \name Initialization */ -/*@{*/ - -/** - * Initialization of the context's Color attribute group. - * - * \param ctx GL context. - * - * Initializes the related fields in the context color attribute group, - * __struct gl_contextRec::Color. - */ -void _mesa_init_color( struct gl_context * ctx ) -{ - GLuint i; - - /* Color buffer group */ - ctx->Color.IndexMask = ~0u; - memset(ctx->Color.ColorMask, 0xff, sizeof(ctx->Color.ColorMask)); - ctx->Color.ClearIndex = 0; - ASSIGN_4V( ctx->Color.ClearColor, 0, 0, 0, 0 ); - ctx->Color.AlphaEnabled = GL_FALSE; - ctx->Color.AlphaFunc = GL_ALWAYS; - ctx->Color.AlphaRef = 0; - ctx->Color.BlendEnabled = 0x0; - for (i = 0; i < Elements(ctx->Color.Blend); i++) { - ctx->Color.Blend[i].SrcRGB = GL_ONE; - ctx->Color.Blend[i].DstRGB = GL_ZERO; - ctx->Color.Blend[i].SrcA = GL_ONE; - ctx->Color.Blend[i].DstA = GL_ZERO; - ctx->Color.Blend[i].EquationRGB = GL_FUNC_ADD; - ctx->Color.Blend[i].EquationA = GL_FUNC_ADD; - } - ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 ); - ctx->Color.IndexLogicOpEnabled = GL_FALSE; - ctx->Color.ColorLogicOpEnabled = GL_FALSE; - ctx->Color._LogicOpEnabled = GL_FALSE; - ctx->Color.LogicOp = GL_COPY; - ctx->Color.DitherFlag = GL_TRUE; - - if (ctx->Visual.doubleBufferMode) { - ctx->Color.DrawBuffer[0] = GL_BACK; - } - else { - ctx->Color.DrawBuffer[0] = GL_FRONT; - } - - ctx->Color.ClampFragmentColor = GL_FIXED_ONLY_ARB; - ctx->Color.ClampReadColor = GL_FIXED_ONLY_ARB; -} - -/*@}*/ +/** + * \file blend.c + * Blending operations. + */ + +/* + * Mesa 3-D graphics library + * Version: 6.5.1 + * + * Copyright (C) 1999-2006 Brian Paul 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 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 + * BRIAN PAUL 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. + */ + + + +#include "glheader.h" +#include "blend.h" +#include "context.h" +#include "enums.h" +#include "macros.h" +#include "mtypes.h" + + + +/** + * Check if given blend source factor is legal. + * \return GL_TRUE if legal, GL_FALSE otherwise. + */ +static GLboolean +legal_src_factor(const struct gl_context *ctx, GLenum factor) +{ + switch (factor) { + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + return ctx->Extensions.NV_blend_square; + case GL_ZERO: + case GL_ONE: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_SRC_ALPHA_SATURATE: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Check if given blend destination factor is legal. + * \return GL_TRUE if legal, GL_FALSE otherwise. + */ +static GLboolean +legal_dst_factor(const struct gl_context *ctx, GLenum factor) +{ + switch (factor) { + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + return ctx->Extensions.NV_blend_square; + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Check if src/dest RGB/A blend factors are legal. If not generate + * a GL error. + * \return GL_TRUE if factors are legal, GL_FALSE otherwise. + */ +static GLboolean +validate_blend_factors(struct gl_context *ctx, const char *func, + GLenum sfactorRGB, GLenum dfactorRGB, + GLenum sfactorA, GLenum dfactorA) +{ + if (!legal_src_factor(ctx, sfactorRGB)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "%s(sfactorRGB = %s)", func, + _mesa_lookup_enum_by_nr(sfactorRGB)); + return GL_FALSE; + } + + if (!legal_dst_factor(ctx, dfactorRGB)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "%s(dfactorRGB = %s)", func, + _mesa_lookup_enum_by_nr(dfactorRGB)); + return GL_FALSE; + } + + if (sfactorA != sfactorRGB && !legal_src_factor(ctx, sfactorA)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "%s(sfactorA = %s)", func, + _mesa_lookup_enum_by_nr(sfactorA)); + return GL_FALSE; + } + + if (dfactorA != dfactorRGB && !legal_dst_factor(ctx, dfactorA)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "%s(dfactorA = %s)", func, + _mesa_lookup_enum_by_nr(dfactorA)); + return GL_FALSE; + } + + return GL_TRUE; +} + + +/** + * Specify the blending operation. + * + * \param sfactor source factor operator. + * \param dfactor destination factor operator. + * + * \sa glBlendFunc, glBlendFuncSeparateEXT + */ +void GLAPIENTRY +_mesa_BlendFunc( GLenum sfactor, GLenum dfactor ) +{ + _mesa_BlendFuncSeparateEXT(sfactor, dfactor, sfactor, dfactor); +} + + +/** + * Set the separate blend source/dest factors for all draw buffers. + * + * \param sfactorRGB RGB source factor operator. + * \param dfactorRGB RGB destination factor operator. + * \param sfactorA alpha source factor operator. + * \param dfactorA alpha destination factor operator. + */ +void GLAPIENTRY +_mesa_BlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB, + GLenum sfactorA, GLenum dfactorA ) +{ + GLuint buf, numBuffers; + GLboolean changed; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glBlendFuncSeparate %s %s %s %s\n", + _mesa_lookup_enum_by_nr(sfactorRGB), + _mesa_lookup_enum_by_nr(dfactorRGB), + _mesa_lookup_enum_by_nr(sfactorA), + _mesa_lookup_enum_by_nr(dfactorA)); + + if (!validate_blend_factors(ctx, "glBlendFuncSeparate", + sfactorRGB, dfactorRGB, + sfactorA, dfactorA)) { + return; + } + + numBuffers = ctx->Extensions.ARB_draw_buffers_blend + ? ctx->Const.MaxDrawBuffers : 1; + + changed = GL_FALSE; + for (buf = 0; buf < numBuffers; buf++) { + if (ctx->Color.Blend[buf].SrcRGB != sfactorRGB || + ctx->Color.Blend[buf].DstRGB != dfactorRGB || + ctx->Color.Blend[buf].SrcA != sfactorA || + ctx->Color.Blend[buf].DstA != dfactorA) { + changed = GL_TRUE; + break; + } + } + if (!changed) + return; + + FLUSH_VERTICES(ctx, _NEW_COLOR); + + for (buf = 0; buf < numBuffers; buf++) { + ctx->Color.Blend[buf].SrcRGB = sfactorRGB; + ctx->Color.Blend[buf].DstRGB = dfactorRGB; + ctx->Color.Blend[buf].SrcA = sfactorA; + ctx->Color.Blend[buf].DstA = dfactorA; + } + ctx->Color._BlendFuncPerBuffer = GL_FALSE; + + if (ctx->Driver.BlendFuncSeparate) { + ctx->Driver.BlendFuncSeparate(ctx, sfactorRGB, dfactorRGB, + sfactorA, dfactorA); + } +} + + +#if _HAVE_FULL_GL + + +/** + * Set blend source/dest factors for one color buffer/target. + */ +void GLAPIENTRY +_mesa_BlendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) +{ + _mesa_BlendFuncSeparatei(buf, sfactor, dfactor, sfactor, dfactor); +} + + +/** + * Set separate blend source/dest factors for one color buffer/target. + */ +void GLAPIENTRY +_mesa_BlendFuncSeparatei(GLuint buf, GLenum sfactorRGB, GLenum dfactorRGB, + GLenum sfactorA, GLenum dfactorA) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (!ctx->Extensions.ARB_draw_buffers_blend) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glBlendFunc[Separate]i()"); + return; + } + + if (buf >= ctx->Const.MaxDrawBuffers) { + _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)", + buf); + return; + } + + if (!validate_blend_factors(ctx, "glBlendFuncSeparatei", + sfactorRGB, dfactorRGB, + sfactorA, dfactorA)) { + return; + } + + if (ctx->Color.Blend[buf].SrcRGB == sfactorRGB && + ctx->Color.Blend[buf].DstRGB == dfactorRGB && + ctx->Color.Blend[buf].SrcA == sfactorA && + ctx->Color.Blend[buf].DstA == dfactorA) + return; /* no change */ + + FLUSH_VERTICES(ctx, _NEW_COLOR); + + ctx->Color.Blend[buf].SrcRGB = sfactorRGB; + ctx->Color.Blend[buf].DstRGB = dfactorRGB; + ctx->Color.Blend[buf].SrcA = sfactorA; + ctx->Color.Blend[buf].DstA = dfactorA; + ctx->Color._BlendFuncPerBuffer = GL_TRUE; + + if (ctx->Driver.BlendFuncSeparatei) { + ctx->Driver.BlendFuncSeparatei(ctx, buf, sfactorRGB, dfactorRGB, + sfactorA, dfactorA); + } +} + + +/** + * Check if given blend equation is legal. + * \return GL_TRUE if legal, GL_FALSE otherwise. + */ +static GLboolean +legal_blend_equation(const struct gl_context *ctx, + GLenum mode, GLboolean is_separate) +{ + switch (mode) { + case GL_FUNC_ADD: + return GL_TRUE; + case GL_MIN: + case GL_MAX: + return ctx->Extensions.EXT_blend_minmax; + case GL_LOGIC_OP: + /* glBlendEquationSeparate cannot take GL_LOGIC_OP as a parameter. + */ + return ctx->Extensions.EXT_blend_logic_op && !is_separate; + case GL_FUNC_SUBTRACT: + case GL_FUNC_REVERSE_SUBTRACT: + return ctx->Extensions.EXT_blend_subtract; + default: + return GL_FALSE; + } +} + + +/* This is really an extension function! */ +void GLAPIENTRY +_mesa_BlendEquation( GLenum mode ) +{ + GLuint buf, numBuffers; + GLboolean changed; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glBlendEquation(%s)\n", + _mesa_lookup_enum_by_nr(mode)); + + if (!legal_blend_equation(ctx, mode, GL_FALSE)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation"); + return; + } + + numBuffers = ctx->Extensions.ARB_draw_buffers_blend + ? ctx->Const.MaxDrawBuffers : 1; + + changed = GL_FALSE; + for (buf = 0; buf < numBuffers; buf++) { + if (ctx->Color.Blend[buf].EquationRGB != mode || + ctx->Color.Blend[buf].EquationA != mode) { + changed = GL_TRUE; + break; + } + } + if (!changed) + return; + + FLUSH_VERTICES(ctx, _NEW_COLOR); + for (buf = 0; buf < numBuffers; buf++) { + ctx->Color.Blend[buf].EquationRGB = mode; + ctx->Color.Blend[buf].EquationA = mode; + } + ctx->Color._BlendEquationPerBuffer = GL_FALSE; + + if (ctx->Driver.BlendEquationSeparate) + (*ctx->Driver.BlendEquationSeparate)( ctx, mode, mode ); +} + + +/** + * Set blend equation for one color buffer/target. + */ +void GLAPIENTRY +_mesa_BlendEquationi(GLuint buf, GLenum mode) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glBlendEquationi(%u, %s)\n", + buf, _mesa_lookup_enum_by_nr(mode)); + + if (buf >= ctx->Const.MaxDrawBuffers) { + _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)", + buf); + return; + } + + if (!legal_blend_equation(ctx, mode, GL_FALSE)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationi"); + return; + } + + if (ctx->Color.Blend[buf].EquationRGB == mode && + ctx->Color.Blend[buf].EquationA == mode) + return; /* no change */ + + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.Blend[buf].EquationRGB = mode; + ctx->Color.Blend[buf].EquationA = mode; + ctx->Color._BlendEquationPerBuffer = GL_TRUE; + + if (ctx->Driver.BlendEquationSeparatei) + ctx->Driver.BlendEquationSeparatei(ctx, buf, mode, mode); +} + + +void GLAPIENTRY +_mesa_BlendEquationSeparateEXT( GLenum modeRGB, GLenum modeA ) +{ + GLuint buf, numBuffers; + GLboolean changed; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glBlendEquationSeparateEXT(%s %s)\n", + _mesa_lookup_enum_by_nr(modeRGB), + _mesa_lookup_enum_by_nr(modeA)); + + if ( (modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate ) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlendEquationSeparateEXT not supported by driver"); + return; + } + + if (!legal_blend_equation(ctx, modeRGB, GL_TRUE)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)"); + return; + } + + if (!legal_blend_equation(ctx, modeA, GL_TRUE)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)"); + return; + } + + numBuffers = ctx->Extensions.ARB_draw_buffers_blend + ? ctx->Const.MaxDrawBuffers : 1; + + changed = GL_FALSE; + for (buf = 0; buf < numBuffers; buf++) { + if (ctx->Color.Blend[buf].EquationRGB != modeRGB || + ctx->Color.Blend[buf].EquationA != modeA) { + changed = GL_TRUE; + break; + } + } + if (!changed) + return; + + FLUSH_VERTICES(ctx, _NEW_COLOR); + for (buf = 0; buf < numBuffers; buf++) { + ctx->Color.Blend[buf].EquationRGB = modeRGB; + ctx->Color.Blend[buf].EquationA = modeA; + } + ctx->Color._BlendEquationPerBuffer = GL_FALSE; + + if (ctx->Driver.BlendEquationSeparate) + ctx->Driver.BlendEquationSeparate(ctx, modeRGB, modeA); +} + + +/** + * Set separate blend equations for one color buffer/target. + */ +void +_mesa_BlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeA) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glBlendEquationSeparatei(%u, %s %s)\n", buf, + _mesa_lookup_enum_by_nr(modeRGB), + _mesa_lookup_enum_by_nr(modeA)); + + if (buf >= ctx->Const.MaxDrawBuffers) { + _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationSeparatei(buffer=%u)", + buf); + return; + } + + if (!legal_blend_equation(ctx, modeRGB, GL_TRUE)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeRGB)"); + return; + } + + if (!legal_blend_equation(ctx, modeA, GL_TRUE)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeA)"); + return; + } + + if (ctx->Color.Blend[buf].EquationRGB == modeRGB && + ctx->Color.Blend[buf].EquationA == modeA) + return; /* no change */ + + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.Blend[buf].EquationRGB = modeRGB; + ctx->Color.Blend[buf].EquationA = modeA; + ctx->Color._BlendEquationPerBuffer = GL_TRUE; + + if (ctx->Driver.BlendEquationSeparatei) + ctx->Driver.BlendEquationSeparatei(ctx, buf, modeRGB, modeA); +} + + + +#endif /* _HAVE_FULL_GL */ + + +/** + * Set the blending color. + * + * \param red red color component. + * \param green green color component. + * \param blue blue color component. + * \param alpha alpha color component. + * + * \sa glBlendColor(). + * + * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor. On a + * change, flushes the vertices and notifies the driver via + * dd_function_table::BlendColor callback. + */ +void GLAPIENTRY +_mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) +{ + GLfloat tmp[4]; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + tmp[0] = CLAMP( red, 0.0F, 1.0F ); + tmp[1] = CLAMP( green, 0.0F, 1.0F ); + tmp[2] = CLAMP( blue, 0.0F, 1.0F ); + tmp[3] = CLAMP( alpha, 0.0F, 1.0F ); + + if (TEST_EQ_4V(tmp, ctx->Color.BlendColor)) + return; + + FLUSH_VERTICES(ctx, _NEW_COLOR); + COPY_4FV( ctx->Color.BlendColor, tmp ); + + if (ctx->Driver.BlendColor) + (*ctx->Driver.BlendColor)(ctx, tmp); +} + + +/** + * Specify the alpha test function. + * + * \param func alpha comparison function. + * \param ref reference value. + * + * Verifies the parameters and updates gl_colorbuffer_attrib. + * On a change, flushes the vertices and notifies the driver via + * dd_function_table::AlphaFunc callback. + */ +void GLAPIENTRY +_mesa_AlphaFunc( GLenum func, GLclampf ref ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glAlphaFunc(%s, %f)\n", + _mesa_lookup_enum_by_nr(func), ref); + + switch (func) { + case GL_NEVER: + case GL_LESS: + case GL_EQUAL: + case GL_LEQUAL: + case GL_GREATER: + case GL_NOTEQUAL: + case GL_GEQUAL: + case GL_ALWAYS: + ref = CLAMP(ref, 0.0F, 1.0F); + + if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRef == ref) + return; /* no change */ + + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.AlphaFunc = func; + ctx->Color.AlphaRef = ref; + + if (ctx->Driver.AlphaFunc) + ctx->Driver.AlphaFunc(ctx, func, ref); + return; + + default: + _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" ); + return; + } +} + + +/** + * Specify a logic pixel operation for color index rendering. + * + * \param opcode operation. + * + * Verifies that \p opcode is a valid enum and updates +gl_colorbuffer_attrib::LogicOp. + * On a change, flushes the vertices and notifies the driver via the + * dd_function_table::LogicOpcode callback. + */ +void GLAPIENTRY +_mesa_LogicOp( GLenum opcode ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glLogicOp(%s)\n", _mesa_lookup_enum_by_nr(opcode)); + + switch (opcode) { + case GL_CLEAR: + case GL_SET: + case GL_COPY: + case GL_COPY_INVERTED: + case GL_NOOP: + case GL_INVERT: + case GL_AND: + case GL_NAND: + case GL_OR: + case GL_NOR: + case GL_XOR: + case GL_EQUIV: + case GL_AND_REVERSE: + case GL_AND_INVERTED: + case GL_OR_REVERSE: + case GL_OR_INVERTED: + break; + default: + _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" ); + return; + } + + if (ctx->Color.LogicOp == opcode) + return; + + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.LogicOp = opcode; + + if (ctx->Driver.LogicOpcode) + ctx->Driver.LogicOpcode( ctx, opcode ); +} + +#if _HAVE_FULL_GL +void GLAPIENTRY +_mesa_IndexMask( GLuint mask ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (ctx->Color.IndexMask == mask) + return; + + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.IndexMask = mask; +} +#endif + + +/** + * Enable or disable writing of frame buffer color components. + * + * \param red whether to mask writing of the red color component. + * \param green whether to mask writing of the green color component. + * \param blue whether to mask writing of the blue color component. + * \param alpha whether to mask writing of the alpha color component. + * + * \sa glColorMask(). + * + * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a + * change, flushes the vertices and notifies the driver via the + * dd_function_table::ColorMask callback. + */ +void GLAPIENTRY +_mesa_ColorMask( GLboolean red, GLboolean green, + GLboolean blue, GLboolean alpha ) +{ + GET_CURRENT_CONTEXT(ctx); + GLubyte tmp[4]; + GLuint i; + GLboolean flushed; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glColorMask(%d, %d, %d, %d)\n", + red, green, blue, alpha); + + /* Shouldn't have any information about channel depth in core mesa + * -- should probably store these as the native booleans: + */ + tmp[RCOMP] = red ? 0xff : 0x0; + tmp[GCOMP] = green ? 0xff : 0x0; + tmp[BCOMP] = blue ? 0xff : 0x0; + tmp[ACOMP] = alpha ? 0xff : 0x0; + + flushed = GL_FALSE; + for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { + if (!TEST_EQ_4V(tmp, ctx->Color.ColorMask[i])) { + if (!flushed) { + FLUSH_VERTICES(ctx, _NEW_COLOR); + } + flushed = GL_TRUE; + COPY_4UBV(ctx->Color.ColorMask[i], tmp); + } + } + + if (ctx->Driver.ColorMask) + ctx->Driver.ColorMask( ctx, red, green, blue, alpha ); +} + + +/** + * For GL_EXT_draw_buffers2 and GL3 + */ +void GLAPIENTRY +_mesa_ColorMaskIndexed( GLuint buf, GLboolean red, GLboolean green, + GLboolean blue, GLboolean alpha ) +{ + GLubyte tmp[4]; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glColorMaskIndexed %u %d %d %d %d\n", + buf, red, green, blue, alpha); + + if (buf >= ctx->Const.MaxDrawBuffers) { + _mesa_error(ctx, GL_INVALID_VALUE, "glColorMaskIndexed(buf=%u)", buf); + return; + } + + /* Shouldn't have any information about channel depth in core mesa + * -- should probably store these as the native booleans: + */ + tmp[RCOMP] = red ? 0xff : 0x0; + tmp[GCOMP] = green ? 0xff : 0x0; + tmp[BCOMP] = blue ? 0xff : 0x0; + tmp[ACOMP] = alpha ? 0xff : 0x0; + + if (TEST_EQ_4V(tmp, ctx->Color.ColorMask[buf])) + return; + + FLUSH_VERTICES(ctx, _NEW_COLOR); + COPY_4UBV(ctx->Color.ColorMask[buf], tmp); + + if (ctx->Driver.ColorMaskIndexed) + ctx->Driver.ColorMaskIndexed(ctx, buf, red, green, blue, alpha); +} + + +extern void GLAPIENTRY +_mesa_ClampColorARB(GLenum target, GLenum clamp) +{ + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (clamp != GL_TRUE && clamp != GL_FALSE && clamp != GL_FIXED_ONLY_ARB) { + _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(clamp)"); + return; + } + + switch (target) { + case GL_CLAMP_VERTEX_COLOR_ARB: + ctx->Light.ClampVertexColor = clamp; + break; + case GL_CLAMP_FRAGMENT_COLOR_ARB: + ctx->Color.ClampFragmentColor = clamp; + break; + case GL_CLAMP_READ_COLOR_ARB: + ctx->Color.ClampReadColor = clamp; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(target)"); + return; + } +} + + + + +/**********************************************************************/ +/** \name Initialization */ +/*@{*/ + +/** + * Initialization of the context's Color attribute group. + * + * \param ctx GL context. + * + * Initializes the related fields in the context color attribute group, + * __struct gl_contextRec::Color. + */ +void _mesa_init_color( struct gl_context * ctx ) +{ + GLuint i; + + /* Color buffer group */ + ctx->Color.IndexMask = ~0u; + memset(ctx->Color.ColorMask, 0xff, sizeof(ctx->Color.ColorMask)); + ctx->Color.ClearIndex = 0; + ASSIGN_4V( ctx->Color.ClearColor, 0, 0, 0, 0 ); + ctx->Color.AlphaEnabled = GL_FALSE; + ctx->Color.AlphaFunc = GL_ALWAYS; + ctx->Color.AlphaRef = 0; + ctx->Color.BlendEnabled = 0x0; + for (i = 0; i < Elements(ctx->Color.Blend); i++) { + ctx->Color.Blend[i].SrcRGB = GL_ONE; + ctx->Color.Blend[i].DstRGB = GL_ZERO; + ctx->Color.Blend[i].SrcA = GL_ONE; + ctx->Color.Blend[i].DstA = GL_ZERO; + ctx->Color.Blend[i].EquationRGB = GL_FUNC_ADD; + ctx->Color.Blend[i].EquationA = GL_FUNC_ADD; + } + ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 ); + ctx->Color.IndexLogicOpEnabled = GL_FALSE; + ctx->Color.ColorLogicOpEnabled = GL_FALSE; + ctx->Color._LogicOpEnabled = GL_FALSE; + ctx->Color.LogicOp = GL_COPY; + ctx->Color.DitherFlag = GL_TRUE; + + if (ctx->Visual.doubleBufferMode) { + ctx->Color.DrawBuffer[0] = GL_BACK; + } + else { + ctx->Color.DrawBuffer[0] = GL_FRONT; + } + + ctx->Color.ClampFragmentColor = GL_FIXED_ONLY_ARB; + ctx->Color.ClampReadColor = GL_FIXED_ONLY_ARB; +} + +/*@}*/ diff --git a/mesalib/src/mesa/main/bufferobj.c b/mesalib/src/mesa/main/bufferobj.c index 31475529e..75afae0ad 100644 --- a/mesalib/src/mesa/main/bufferobj.c +++ b/mesalib/src/mesa/main/bufferobj.c @@ -1,2145 +1,2158 @@ -/* - * Mesa 3-D graphics library - * Version: 7.6 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * Copyright (C) 2009 VMware, Inc. 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 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 - * BRIAN PAUL 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. - */ - - -/** - * \file bufferobj.c - * \brief Functions for the GL_ARB_vertex/pixel_buffer_object extensions. - * \author Brian Paul, Ian Romanick - */ - - -#include "glheader.h" -#include "enums.h" -#include "hash.h" -#include "imports.h" -#include "image.h" -#include "context.h" -#include "bufferobj.h" -#include "fbobject.h" -#include "mfeatures.h" -#include "mtypes.h" -#include "texobj.h" - - -/* Debug flags */ -/*#define VBO_DEBUG*/ -/*#define BOUNDS_CHECK*/ - - -#if FEATURE_OES_mapbuffer -#define DEFAULT_ACCESS GL_MAP_WRITE_BIT -#else -#define DEFAULT_ACCESS (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT) -#endif - - -/** - * Used as a placeholder for buffer objects between glGenBuffers() and - * glBindBuffer() so that glIsBuffer() can work correctly. - */ -static struct gl_buffer_object DummyBufferObject; - - -/** - * Return pointer to address of a buffer object target. - * \param ctx the GL context - * \param target the buffer object target to be retrieved. - * \return pointer to pointer to the buffer object bound to \c target in the - * specified context or \c NULL if \c target is invalid. - */ -static INLINE struct gl_buffer_object ** -get_buffer_target(struct gl_context *ctx, GLenum target) -{ - switch (target) { - case GL_ARRAY_BUFFER_ARB: - return &ctx->Array.ArrayBufferObj; - case GL_ELEMENT_ARRAY_BUFFER_ARB: - return &ctx->Array.ElementArrayBufferObj; - case GL_PIXEL_PACK_BUFFER_EXT: - return &ctx->Pack.BufferObj; - case GL_PIXEL_UNPACK_BUFFER_EXT: - return &ctx->Unpack.BufferObj; - case GL_COPY_READ_BUFFER: - return &ctx->CopyReadBuffer; - case GL_COPY_WRITE_BUFFER: - return &ctx->CopyWriteBuffer; -#if FEATURE_EXT_transform_feedback - case GL_TRANSFORM_FEEDBACK_BUFFER: - if (ctx->Extensions.EXT_transform_feedback) { - return &ctx->TransformFeedback.CurrentBuffer; - } - break; -#endif - default: - return NULL; - } - return NULL; -} - - -/** - * Get the buffer object bound to the specified target in a GL context. - * \param ctx the GL context - * \param target the buffer object target to be retrieved. - * \return pointer to the buffer object bound to \c target in the - * specified context or \c NULL if \c target is invalid. - */ -static INLINE struct gl_buffer_object * -get_buffer(struct gl_context *ctx, GLenum target) -{ - struct gl_buffer_object **bufObj = get_buffer_target(ctx, target); - if (bufObj) - return *bufObj; - return NULL; -} - - -/** - * Convert a GLbitfield describing the mapped buffer access flags - * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY. - */ -static GLenum -simplified_access_mode(GLbitfield access) -{ - const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; - if ((access & rwFlags) == rwFlags) - return GL_READ_WRITE; - if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT) - return GL_READ_ONLY; - if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT) - return GL_WRITE_ONLY; - return GL_READ_WRITE; /* this should never happen, but no big deal */ -} - - -/** - * Tests the subdata range parameters and sets the GL error code for - * \c glBufferSubDataARB and \c glGetBufferSubDataARB. - * - * \param ctx GL context. - * \param target Buffer object target on which to operate. - * \param offset Offset of the first byte of the subdata range. - * \param size Size, in bytes, of the subdata range. - * \param caller Name of calling function for recording errors. - * \return A pointer to the buffer object bound to \c target in the - * specified context or \c NULL if any of the parameter or state - * conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB - * are invalid. - * - * \sa glBufferSubDataARB, glGetBufferSubDataARB - */ -static struct gl_buffer_object * -buffer_object_subdata_range_good( struct gl_context * ctx, GLenum target, - GLintptrARB offset, GLsizeiptrARB size, - const char *caller ) -{ - struct gl_buffer_object *bufObj; - - if (size < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller); - return NULL; - } - - if (offset < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller); - return NULL; - } - - bufObj = get_buffer(ctx, target); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller); - return NULL; - } - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); - return NULL; - } - if (offset + size > bufObj->Size) { - _mesa_error(ctx, GL_INVALID_VALUE, - "%s(size + offset > buffer size)", caller); - return NULL; - } - if (_mesa_bufferobj_mapped(bufObj)) { - /* Buffer is currently mapped */ - _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); - return NULL; - } - - return bufObj; -} - - -/** - * Allocate and initialize a new buffer object. - * - * Default callback for the \c dd_function_table::NewBufferObject() hook. - */ -static struct gl_buffer_object * -_mesa_new_buffer_object( struct gl_context *ctx, GLuint name, GLenum target ) -{ - struct gl_buffer_object *obj; - - (void) ctx; - - obj = MALLOC_STRUCT(gl_buffer_object); - _mesa_initialize_buffer_object(obj, name, target); - return obj; -} - - -/** - * Delete a buffer object. - * - * Default callback for the \c dd_function_table::DeleteBuffer() hook. - */ -static void -_mesa_delete_buffer_object( struct gl_context *ctx, struct gl_buffer_object *bufObj ) -{ - (void) ctx; - - if (bufObj->Data) - free(bufObj->Data); - - /* assign strange values here to help w/ debugging */ - bufObj->RefCount = -1000; - bufObj->Name = ~0; - - _glthread_DESTROY_MUTEX(bufObj->Mutex); - free(bufObj); -} - - - -/** - * Set ptr to bufObj w/ reference counting. - */ -void -_mesa_reference_buffer_object(struct gl_context *ctx, - struct gl_buffer_object **ptr, - struct gl_buffer_object *bufObj) -{ - if (*ptr == bufObj) - return; - - if (*ptr) { - /* Unreference the old buffer */ - GLboolean deleteFlag = GL_FALSE; - struct gl_buffer_object *oldObj = *ptr; - - _glthread_LOCK_MUTEX(oldObj->Mutex); - ASSERT(oldObj->RefCount > 0); - oldObj->RefCount--; -#if 0 - printf("BufferObj %p %d DECR to %d\n", - (void *) oldObj, oldObj->Name, oldObj->RefCount); -#endif - deleteFlag = (oldObj->RefCount == 0); - _glthread_UNLOCK_MUTEX(oldObj->Mutex); - - if (deleteFlag) { - - /* some sanity checking: don't delete a buffer still in use */ -#if 0 - /* unfortunately, these tests are invalid during context tear-down */ - ASSERT(ctx->Array.ArrayBufferObj != bufObj); - ASSERT(ctx->Array.ElementArrayBufferObj != bufObj); - ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj); -#endif - - ASSERT(ctx->Driver.DeleteBuffer); - ctx->Driver.DeleteBuffer(ctx, oldObj); - } - - *ptr = NULL; - } - ASSERT(!*ptr); - - if (bufObj) { - /* reference new buffer */ - _glthread_LOCK_MUTEX(bufObj->Mutex); - if (bufObj->RefCount == 0) { - /* this buffer's being deleted (look just above) */ - /* Not sure this can every really happen. Warn if it does. */ - _mesa_problem(NULL, "referencing deleted buffer object"); - *ptr = NULL; - } - else { - bufObj->RefCount++; -#if 0 - printf("BufferObj %p %d INCR to %d\n", - (void *) bufObj, bufObj->Name, bufObj->RefCount); -#endif - *ptr = bufObj; - } - _glthread_UNLOCK_MUTEX(bufObj->Mutex); - } -} - - -/** - * Initialize a buffer object to default values. - */ -void -_mesa_initialize_buffer_object( struct gl_buffer_object *obj, - GLuint name, GLenum target ) -{ - (void) target; - - memset(obj, 0, sizeof(struct gl_buffer_object)); - _glthread_INIT_MUTEX(obj->Mutex); - obj->RefCount = 1; - obj->Name = name; - obj->Usage = GL_STATIC_DRAW_ARB; - obj->AccessFlags = DEFAULT_ACCESS; -} - - -/** - * Allocate space for and store data in a buffer object. Any data that was - * previously stored in the buffer object is lost. If \c data is \c NULL, - * memory will be allocated, but no copy will occur. - * - * This is the default callback for \c dd_function_table::BufferData() - * Note that all GL error checking will have been done already. - * - * \param ctx GL context. - * \param target Buffer object target on which to operate. - * \param size Size, in bytes, of the new data store. - * \param data Pointer to the data to store in the buffer object. This - * pointer may be \c NULL. - * \param usage Hints about how the data will be used. - * \param bufObj Object to be used. - * - * \return GL_TRUE for success, GL_FALSE for failure - * \sa glBufferDataARB, dd_function_table::BufferData. - */ -static GLboolean -_mesa_buffer_data( struct gl_context *ctx, GLenum target, GLsizeiptrARB size, - const GLvoid * data, GLenum usage, - struct gl_buffer_object * bufObj ) -{ - void * new_data; - - (void) ctx; (void) target; - - new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size ); - if (new_data) { - bufObj->Data = (GLubyte *) new_data; - bufObj->Size = size; - bufObj->Usage = usage; - - if (data) { - memcpy( bufObj->Data, data, size ); - } - - return GL_TRUE; - } - else { - return GL_FALSE; - } -} - - -/** - * Replace data in a subrange of buffer object. If the data range - * specified by \c size + \c offset extends beyond the end of the buffer or - * if \c data is \c NULL, no copy is performed. - * - * This is the default callback for \c dd_function_table::BufferSubData() - * Note that all GL error checking will have been done already. - * - * \param ctx GL context. - * \param target Buffer object target on which to operate. - * \param offset Offset of the first byte to be modified. - * \param size Size, in bytes, of the data range. - * \param data Pointer to the data to store in the buffer object. - * \param bufObj Object to be used. - * - * \sa glBufferSubDataARB, dd_function_table::BufferSubData. - */ -static void -_mesa_buffer_subdata( struct gl_context *ctx, GLenum target, GLintptrARB offset, - GLsizeiptrARB size, const GLvoid * data, - struct gl_buffer_object * bufObj ) -{ - (void) ctx; (void) target; - - /* this should have been caught in _mesa_BufferSubData() */ - ASSERT(size + offset <= bufObj->Size); - - if (bufObj->Data) { - memcpy( (GLubyte *) bufObj->Data + offset, data, size ); - } -} - - -/** - * Retrieve data from a subrange of buffer object. If the data range - * specified by \c size + \c offset extends beyond the end of the buffer or - * if \c data is \c NULL, no copy is performed. - * - * This is the default callback for \c dd_function_table::GetBufferSubData() - * Note that all GL error checking will have been done already. - * - * \param ctx GL context. - * \param target Buffer object target on which to operate. - * \param offset Offset of the first byte to be fetched. - * \param size Size, in bytes, of the data range. - * \param data Destination for data - * \param bufObj Object to be used. - * - * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData. - */ -static void -_mesa_buffer_get_subdata( struct gl_context *ctx, GLenum target, GLintptrARB offset, - GLsizeiptrARB size, GLvoid * data, - struct gl_buffer_object * bufObj ) -{ - (void) ctx; (void) target; - - if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) { - memcpy( data, (GLubyte *) bufObj->Data + offset, size ); - } -} - - -/** - * Default callback for \c dd_function_tabel::MapBuffer(). - * - * The function parameters will have been already tested for errors. - * - * \param ctx GL context. - * \param target Buffer object target on which to operate. - * \param access Information about how the buffer will be accessed. - * \param bufObj Object to be mapped. - * \return A pointer to the object's internal data store that can be accessed - * by the processor - * - * \sa glMapBufferARB, dd_function_table::MapBuffer - */ -static void * -_mesa_buffer_map( struct gl_context *ctx, GLenum target, GLenum access, - struct gl_buffer_object *bufObj ) -{ - (void) ctx; - (void) target; - (void) access; - /* Just return a direct pointer to the data */ - if (_mesa_bufferobj_mapped(bufObj)) { - /* already mapped! */ - return NULL; - } - bufObj->Pointer = bufObj->Data; - bufObj->Length = bufObj->Size; - bufObj->Offset = 0; - return bufObj->Pointer; -} - - -/** - * Default fallback for \c dd_function_table::MapBufferRange(). - * Called via glMapBufferRange(). - */ -static void * -_mesa_buffer_map_range( struct gl_context *ctx, GLenum target, GLintptr offset, - GLsizeiptr length, GLbitfield access, - struct gl_buffer_object *bufObj ) -{ - (void) ctx; - (void) target; - assert(!_mesa_bufferobj_mapped(bufObj)); - /* Just return a direct pointer to the data */ - bufObj->Pointer = bufObj->Data + offset; - bufObj->Length = length; - bufObj->Offset = offset; - bufObj->AccessFlags = access; - return bufObj->Pointer; -} - - -/** - * Default fallback for \c dd_function_table::FlushMappedBufferRange(). - * Called via glFlushMappedBufferRange(). - */ -static void -_mesa_buffer_flush_mapped_range( struct gl_context *ctx, GLenum target, - GLintptr offset, GLsizeiptr length, - struct gl_buffer_object *obj ) -{ - (void) ctx; - (void) target; - (void) offset; - (void) length; - (void) obj; - /* no-op */ -} - - -/** - * Default callback for \c dd_function_table::MapBuffer(). - * - * The input parameters will have been already tested for errors. - * - * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer - */ -static GLboolean -_mesa_buffer_unmap( struct gl_context *ctx, GLenum target, - struct gl_buffer_object *bufObj ) -{ - (void) ctx; - (void) target; - /* XXX we might assert here that bufObj->Pointer is non-null */ - bufObj->Pointer = NULL; - bufObj->Length = 0; - bufObj->Offset = 0; - bufObj->AccessFlags = 0x0; - return GL_TRUE; -} - - -/** - * Default fallback for \c dd_function_table::CopyBufferSubData(). - * Called via glCopyBuffserSubData(). - */ -static void -_mesa_copy_buffer_subdata(struct gl_context *ctx, - struct gl_buffer_object *src, - struct gl_buffer_object *dst, - GLintptr readOffset, GLintptr writeOffset, - GLsizeiptr size) -{ - GLubyte *srcPtr, *dstPtr; - - /* buffer should not already be mapped */ - assert(!_mesa_bufferobj_mapped(src)); - assert(!_mesa_bufferobj_mapped(dst)); - - srcPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_READ_BUFFER, - GL_READ_ONLY, src); - dstPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_WRITE_BUFFER, - GL_WRITE_ONLY, dst); - - if (srcPtr && dstPtr) - memcpy(dstPtr + writeOffset, srcPtr + readOffset, size); - - ctx->Driver.UnmapBuffer(ctx, GL_COPY_READ_BUFFER, src); - ctx->Driver.UnmapBuffer(ctx, GL_COPY_WRITE_BUFFER, dst); -} - - - -/** - * Initialize the state associated with buffer objects - */ -void -_mesa_init_buffer_objects( struct gl_context *ctx ) -{ - memset(&DummyBufferObject, 0, sizeof(DummyBufferObject)); - DummyBufferObject.RefCount = 1000*1000*1000; /* never delete */ - - _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, - ctx->Shared->NullBufferObj); - _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, - ctx->Shared->NullBufferObj); - - _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, - ctx->Shared->NullBufferObj); - _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, - ctx->Shared->NullBufferObj); -} - - -void -_mesa_free_buffer_objects( struct gl_context *ctx ) -{ - _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL); - _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL); - - _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL); - _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL); -} - - -/** - * Bind the specified target to buffer for the specified context. - * Called by glBindBuffer() and other functions. - */ -static void -bind_buffer_object(struct gl_context *ctx, GLenum target, GLuint buffer) -{ - struct gl_buffer_object *oldBufObj; - struct gl_buffer_object *newBufObj = NULL; - struct gl_buffer_object **bindTarget = NULL; - - bindTarget = get_buffer_target(ctx, target); - if (!bindTarget) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)", target); - return; - } - - /* Get pointer to old buffer object (to be unbound) */ - oldBufObj = *bindTarget; - if (oldBufObj && oldBufObj->Name == buffer) - return; /* rebinding the same buffer object- no change */ - - /* - * Get pointer to new buffer object (newBufObj) - */ - if (buffer == 0) { - /* The spec says there's not a buffer object named 0, but we use - * one internally because it simplifies things. - */ - newBufObj = ctx->Shared->NullBufferObj; - } - else { - /* non-default buffer object */ - newBufObj = _mesa_lookup_bufferobj(ctx, buffer); - if (!newBufObj || newBufObj == &DummyBufferObject) { - /* If this is a new buffer object id, or one which was generated but - * never used before, allocate a buffer object now. - */ - ASSERT(ctx->Driver.NewBufferObject); - newBufObj = ctx->Driver.NewBufferObject(ctx, buffer, target); - if (!newBufObj) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB"); - return; - } - _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, newBufObj); - } - } - - /* bind new buffer */ - _mesa_reference_buffer_object(ctx, bindTarget, newBufObj); - - /* Pass BindBuffer call to device driver */ - if (ctx->Driver.BindBuffer) - ctx->Driver.BindBuffer( ctx, target, newBufObj ); -} - - -/** - * Update the default buffer objects in the given context to reference those - * specified in the shared state and release those referencing the old - * shared state. - */ -void -_mesa_update_default_objects_buffer_objects(struct gl_context *ctx) -{ - /* Bind the NullBufferObj to remove references to those - * in the shared context hash table. - */ - bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0); - bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0); - bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0); -} - - -/** - * When we're about to read pixel data out of a PBO (via glDrawPixels, - * glTexImage, etc) or write data into a PBO (via glReadPixels, - * glGetTexImage, etc) we call this function to check that we're not - * going to read out of bounds. - * - * XXX This would also be a convenient time to check that the PBO isn't - * currently mapped. Whoever calls this function should check for that. - * Remember, we can't use a PBO when it's mapped! - * - * If we're not using a PBO, this is a no-op. - * - * \param width width of image to read/write - * \param height height of image to read/write - * \param depth depth of image to read/write - * \param format format of image to read/write - * \param type datatype of image to read/write - * \param ptr the user-provided pointer/offset - * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would - * go out of bounds. - */ -GLboolean -_mesa_validate_pbo_access(GLuint dimensions, - const struct gl_pixelstore_attrib *pack, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *ptr) -{ - GLvoid *start, *end; - const GLubyte *sizeAddr; /* buffer size, cast to a pointer */ - - if (!_mesa_is_bufferobj(pack->BufferObj)) - return GL_TRUE; /* no PBO, OK */ - - if (pack->BufferObj->Size == 0) - /* no buffer! */ - return GL_FALSE; - - /* get address of first pixel we'll read */ - start = _mesa_image_address(dimensions, pack, ptr, width, height, - format, type, 0, 0, 0); - - /* get address just past the last pixel we'll read */ - end = _mesa_image_address(dimensions, pack, ptr, width, height, - format, type, depth-1, height-1, width); - - - sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size; - - if ((const GLubyte *) start > sizeAddr) { - /* This will catch negative values / wrap-around */ - return GL_FALSE; - } - if ((const GLubyte *) end > sizeAddr) { - /* Image read goes beyond end of buffer */ - return GL_FALSE; - } - - /* OK! */ - return GL_TRUE; -} - - -/** - * For commands that read from a PBO (glDrawPixels, glTexImage, - * glPolygonStipple, etc), if we're reading from a PBO, map it read-only - * and return the pointer into the PBO. If we're not reading from a - * PBO, return \p src as-is. - * If non-null return, must call _mesa_unmap_pbo_source() when done. - * - * \return NULL if error, else pointer to start of data - */ -const GLvoid * -_mesa_map_pbo_source(struct gl_context *ctx, - const struct gl_pixelstore_attrib *unpack, - const GLvoid *src) -{ - const GLubyte *buf; - - if (_mesa_is_bufferobj(unpack->BufferObj)) { - /* unpack from PBO */ - buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, - GL_READ_ONLY_ARB, - unpack->BufferObj); - if (!buf) - return NULL; - - buf = ADD_POINTERS(buf, src); - } - else { - /* unpack from normal memory */ - buf = src; - } - - return buf; -} - - -/** - * Combine PBO-read validation and mapping. - * If any GL errors are detected, they'll be recorded and NULL returned. - * \sa _mesa_validate_pbo_access - * \sa _mesa_map_pbo_source - * A call to this function should have a matching call to - * _mesa_unmap_pbo_source(). - */ -const GLvoid * -_mesa_map_validate_pbo_source(struct gl_context *ctx, - GLuint dimensions, - const struct gl_pixelstore_attrib *unpack, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *ptr, - const char *where) -{ - ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); - - if (!_mesa_is_bufferobj(unpack->BufferObj)) { - /* non-PBO access: no validation to be done */ - return ptr; - } - - if (!_mesa_validate_pbo_access(dimensions, unpack, - width, height, depth, format, type, ptr)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(out of bounds PBO access)", where); - return NULL; - } - - if (_mesa_bufferobj_mapped(unpack->BufferObj)) { - /* buffer is already mapped - that's an error */ - _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); - return NULL; - } - - ptr = _mesa_map_pbo_source(ctx, unpack, ptr); - return ptr; -} - - -/** - * Counterpart to _mesa_map_pbo_source() - */ -void -_mesa_unmap_pbo_source(struct gl_context *ctx, - const struct gl_pixelstore_attrib *unpack) -{ - ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */ - if (_mesa_is_bufferobj(unpack->BufferObj)) { - ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, - unpack->BufferObj); - } -} - - -/** - * For commands that write to a PBO (glReadPixels, glGetColorTable, etc), - * if we're writing to a PBO, map it write-only and return the pointer - * into the PBO. If we're not writing to a PBO, return \p dst as-is. - * If non-null return, must call _mesa_unmap_pbo_dest() when done. - * - * \return NULL if error, else pointer to start of data - */ -void * -_mesa_map_pbo_dest(struct gl_context *ctx, - const struct gl_pixelstore_attrib *pack, - GLvoid *dest) -{ - void *buf; - - if (_mesa_is_bufferobj(pack->BufferObj)) { - /* pack into PBO */ - buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, - GL_WRITE_ONLY_ARB, - pack->BufferObj); - if (!buf) - return NULL; - - buf = ADD_POINTERS(buf, dest); - } - else { - /* pack to normal memory */ - buf = dest; - } - - return buf; -} - - -/** - * Combine PBO-write validation and mapping. - * If any GL errors are detected, they'll be recorded and NULL returned. - * \sa _mesa_validate_pbo_access - * \sa _mesa_map_pbo_dest - * A call to this function should have a matching call to - * _mesa_unmap_pbo_dest(). - */ -GLvoid * -_mesa_map_validate_pbo_dest(struct gl_context *ctx, - GLuint dimensions, - const struct gl_pixelstore_attrib *unpack, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, GLvoid *ptr, - const char *where) -{ - ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); - - if (!_mesa_is_bufferobj(unpack->BufferObj)) { - /* non-PBO access: no validation to be done */ - return ptr; - } - - if (!_mesa_validate_pbo_access(dimensions, unpack, - width, height, depth, format, type, ptr)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(out of bounds PBO access)", where); - return NULL; - } - - if (_mesa_bufferobj_mapped(unpack->BufferObj)) { - /* buffer is already mapped - that's an error */ - _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); - return NULL; - } - - ptr = _mesa_map_pbo_dest(ctx, unpack, ptr); - return ptr; -} - - -/** - * Counterpart to _mesa_map_pbo_dest() - */ -void -_mesa_unmap_pbo_dest(struct gl_context *ctx, - const struct gl_pixelstore_attrib *pack) -{ - ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */ - if (_mesa_is_bufferobj(pack->BufferObj)) { - ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj); - } -} - - - -/** - * Return the gl_buffer_object for the given ID. - * Always return NULL for ID 0. - */ -struct gl_buffer_object * -_mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer) -{ - if (buffer == 0) - return NULL; - else - return (struct gl_buffer_object *) - _mesa_HashLookup(ctx->Shared->BufferObjects, buffer); -} - - -/** - * If *ptr points to obj, set ptr = the Null/default buffer object. - * This is a helper for buffer object deletion. - * The GL spec says that deleting a buffer object causes it to get - * unbound from all arrays in the current context. - */ -static void -unbind(struct gl_context *ctx, - struct gl_buffer_object **ptr, - struct gl_buffer_object *obj) -{ - if (*ptr == obj) { - _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj); - } -} - - -/** - * Plug default/fallback buffer object functions into the device - * driver hooks. - */ -void -_mesa_init_buffer_object_functions(struct dd_function_table *driver) -{ - /* GL_ARB_vertex/pixel_buffer_object */ - driver->NewBufferObject = _mesa_new_buffer_object; - driver->DeleteBuffer = _mesa_delete_buffer_object; - driver->BindBuffer = NULL; - driver->BufferData = _mesa_buffer_data; - driver->BufferSubData = _mesa_buffer_subdata; - driver->GetBufferSubData = _mesa_buffer_get_subdata; - driver->MapBuffer = _mesa_buffer_map; - driver->UnmapBuffer = _mesa_buffer_unmap; - - /* GL_ARB_map_buffer_range */ - driver->MapBufferRange = _mesa_buffer_map_range; - driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range; - - /* GL_ARB_copy_buffer */ - driver->CopyBufferSubData = _mesa_copy_buffer_subdata; -} - - - -/**********************************************************************/ -/* API Functions */ -/**********************************************************************/ - -void GLAPIENTRY -_mesa_BindBufferARB(GLenum target, GLuint buffer) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - bind_buffer_object(ctx, target, buffer); -} - - -/** - * Delete a set of buffer objects. - * - * \param n Number of buffer objects to delete. - * \param ids Array of \c n buffer object IDs. - */ -void GLAPIENTRY -_mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids) -{ - GET_CURRENT_CONTEXT(ctx); - GLsizei i; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)"); - return; - } - - _glthread_LOCK_MUTEX(ctx->Shared->Mutex); - - for (i = 0; i < n; i++) { - struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]); - if (bufObj) { - struct gl_array_object *arrayObj = ctx->Array.ArrayObj; - GLuint j; - - ASSERT(bufObj->Name == ids[i] || bufObj == &DummyBufferObject); - - if (_mesa_bufferobj_mapped(bufObj)) { - /* if mapped, unmap it now */ - ctx->Driver.UnmapBuffer(ctx, 0, bufObj); - bufObj->AccessFlags = DEFAULT_ACCESS; - bufObj->Pointer = NULL; - } - - /* unbind any vertex pointers bound to this buffer */ - unbind(ctx, &arrayObj->Vertex.BufferObj, bufObj); - unbind(ctx, &arrayObj->Weight.BufferObj, bufObj); - unbind(ctx, &arrayObj->Normal.BufferObj, bufObj); - unbind(ctx, &arrayObj->Color.BufferObj, bufObj); - unbind(ctx, &arrayObj->SecondaryColor.BufferObj, bufObj); - unbind(ctx, &arrayObj->FogCoord.BufferObj, bufObj); - unbind(ctx, &arrayObj->Index.BufferObj, bufObj); - unbind(ctx, &arrayObj->EdgeFlag.BufferObj, bufObj); - for (j = 0; j < Elements(arrayObj->TexCoord); j++) { - unbind(ctx, &arrayObj->TexCoord[j].BufferObj, bufObj); - } - for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) { - unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj); - } - - if (ctx->Array.ArrayBufferObj == bufObj) { - _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 ); - } - if (ctx->Array.ElementArrayBufferObj == bufObj) { - _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 ); - } - - /* unbind any pixel pack/unpack pointers bound to this buffer */ - if (ctx->Pack.BufferObj == bufObj) { - _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 ); - } - if (ctx->Unpack.BufferObj == bufObj) { - _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 ); - } - - /* The ID is immediately freed for re-use */ - _mesa_HashRemove(ctx->Shared->BufferObjects, ids[i]); - _mesa_reference_buffer_object(ctx, &bufObj, NULL); - } - } - - _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); -} - - -/** - * Generate a set of unique buffer object IDs and store them in \c buffer. - * - * \param n Number of IDs to generate. - * \param buffer Array of \c n locations to store the IDs. - */ -void GLAPIENTRY -_mesa_GenBuffersARB(GLsizei n, GLuint *buffer) -{ - GET_CURRENT_CONTEXT(ctx); - GLuint first; - GLint i; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB"); - return; - } - - if (!buffer) { - return; - } - - /* - * This must be atomic (generation and allocation of buffer object IDs) - */ - _glthread_LOCK_MUTEX(ctx->Shared->Mutex); - - first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n); - - /* Insert the ID and pointer to dummy buffer object into hash table */ - for (i = 0; i < n; i++) { - _mesa_HashInsert(ctx->Shared->BufferObjects, first + i, - &DummyBufferObject); - buffer[i] = first + i; - } - - _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); -} - - -/** - * Determine if ID is the name of a buffer object. - * - * \param id ID of the potential buffer object. - * \return \c GL_TRUE if \c id is the name of a buffer object, - * \c GL_FALSE otherwise. - */ -GLboolean GLAPIENTRY -_mesa_IsBufferARB(GLuint id) -{ - struct gl_buffer_object *bufObj; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); - - _glthread_LOCK_MUTEX(ctx->Shared->Mutex); - bufObj = _mesa_lookup_bufferobj(ctx, id); - _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); - - return bufObj && bufObj != &DummyBufferObject; -} - - -void GLAPIENTRY -_mesa_BufferDataARB(GLenum target, GLsizeiptrARB size, - const GLvoid * data, GLenum usage) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (size < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)"); - return; - } - - switch (usage) { - case GL_STREAM_DRAW_ARB: - case GL_STREAM_READ_ARB: - case GL_STREAM_COPY_ARB: - case GL_STATIC_DRAW_ARB: - case GL_STATIC_READ_ARB: - case GL_STATIC_COPY_ARB: - case GL_DYNAMIC_DRAW_ARB: - case GL_DYNAMIC_READ_ARB: - case GL_DYNAMIC_COPY_ARB: - /* OK */ - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)"); - return; - } - - bufObj = get_buffer(ctx, target); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(target)" ); - return; - } - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer 0)" ); - return; - } - - if (_mesa_bufferobj_mapped(bufObj)) { - /* Unmap the existing buffer. We'll replace it now. Not an error. */ - ctx->Driver.UnmapBuffer(ctx, target, bufObj); - bufObj->AccessFlags = DEFAULT_ACCESS; - ASSERT(bufObj->Pointer == NULL); - } - - FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT); - - bufObj->Written = GL_TRUE; - -#ifdef VBO_DEBUG - printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n", - bufObj->Name, size, data, usage); -#endif - -#ifdef BOUNDS_CHECK - size += 100; -#endif - - ASSERT(ctx->Driver.BufferData); - if (!ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj )) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()"); - } -} - - -void GLAPIENTRY -_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset, - GLsizeiptrARB size, const GLvoid * data) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, - "glBufferSubDataARB" ); - if (!bufObj) { - /* error already recorded */ - return; - } - - if (size == 0) - return; - - bufObj->Written = GL_TRUE; - - ASSERT(ctx->Driver.BufferSubData); - ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj ); -} - - -void GLAPIENTRY -_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset, - GLsizeiptrARB size, void * data) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, - "glGetBufferSubDataARB" ); - if (!bufObj) { - /* error already recorded */ - return; - } - - ASSERT(ctx->Driver.GetBufferSubData); - ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj ); -} - - -void * GLAPIENTRY -_mesa_MapBufferARB(GLenum target, GLenum access) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object * bufObj; - GLbitfield accessFlags; - void *map; - - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); - - switch (access) { - case GL_READ_ONLY_ARB: - accessFlags = GL_MAP_READ_BIT; - break; - case GL_WRITE_ONLY_ARB: - accessFlags = GL_MAP_WRITE_BIT; - break; - case GL_READ_WRITE_ARB: - accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)"); - return NULL; - } - - bufObj = get_buffer(ctx, target); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" ); - return NULL; - } - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(buffer 0)" ); - return NULL; - } - if (_mesa_bufferobj_mapped(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)"); - return NULL; - } - - ASSERT(ctx->Driver.MapBuffer); - map = ctx->Driver.MapBuffer( ctx, target, access, bufObj ); - if (!map) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); - return NULL; - } - else { - /* The driver callback should have set these fields. - * This is important because other modules (like VBO) might call - * the driver function directly. - */ - ASSERT(bufObj->Pointer == map); - ASSERT(bufObj->Length == bufObj->Size); - ASSERT(bufObj->Offset == 0); - bufObj->AccessFlags = accessFlags; - } - - if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB) - bufObj->Written = GL_TRUE; - -#ifdef VBO_DEBUG - printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n", - bufObj->Name, bufObj->Size, access); - if (access == GL_WRITE_ONLY_ARB) { - GLuint i; - GLubyte *b = (GLubyte *) bufObj->Pointer; - for (i = 0; i < bufObj->Size; i++) - b[i] = i & 0xff; - } -#endif - -#ifdef BOUNDS_CHECK - { - GLubyte *buf = (GLubyte *) bufObj->Pointer; - GLuint i; - /* buffer is 100 bytes larger than requested, fill with magic value */ - for (i = 0; i < 100; i++) { - buf[bufObj->Size - i - 1] = 123; - } - } -#endif - - return bufObj->Pointer; -} - - -GLboolean GLAPIENTRY -_mesa_UnmapBufferARB(GLenum target) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; - GLboolean status = GL_TRUE; - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); - - bufObj = get_buffer(ctx, target); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" ); - return GL_FALSE; - } - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" ); - return GL_FALSE; - } - if (!_mesa_bufferobj_mapped(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB"); - return GL_FALSE; - } - -#ifdef BOUNDS_CHECK - if (bufObj->Access != GL_READ_ONLY_ARB) { - GLubyte *buf = (GLubyte *) bufObj->Pointer; - GLuint i; - /* check that last 100 bytes are still = magic value */ - for (i = 0; i < 100; i++) { - GLuint pos = bufObj->Size - i - 1; - if (buf[pos] != 123) { - _mesa_warning(ctx, "Out of bounds buffer object write detected" - " at position %d (value = %u)\n", - pos, buf[pos]); - } - } - } -#endif - -#ifdef VBO_DEBUG - if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) { - GLuint i, unchanged = 0; - GLubyte *b = (GLubyte *) bufObj->Pointer; - GLint pos = -1; - /* check which bytes changed */ - for (i = 0; i < bufObj->Size - 1; i++) { - if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) { - unchanged++; - if (pos == -1) - pos = i; - } - } - if (unchanged) { - printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n", - bufObj->Name, unchanged, bufObj->Size, pos); - } - } -#endif - - status = ctx->Driver.UnmapBuffer( ctx, target, bufObj ); - bufObj->AccessFlags = DEFAULT_ACCESS; - ASSERT(bufObj->Pointer == NULL); - ASSERT(bufObj->Offset == 0); - ASSERT(bufObj->Length == 0); - - return status; -} - - -void GLAPIENTRY -_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - bufObj = get_buffer(ctx, target); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(target)" ); - return; - } - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferParameterivARB" ); - return; - } - - switch (pname) { - case GL_BUFFER_SIZE_ARB: - *params = (GLint) bufObj->Size; - return; - case GL_BUFFER_USAGE_ARB: - *params = bufObj->Usage; - return; - case GL_BUFFER_ACCESS_ARB: - *params = simplified_access_mode(bufObj->AccessFlags); - return; - case GL_BUFFER_MAPPED_ARB: - *params = _mesa_bufferobj_mapped(bufObj); - return; - case GL_BUFFER_ACCESS_FLAGS: - if (ctx->VersionMajor < 3) - goto invalid_pname; - *params = bufObj->AccessFlags; - return; - case GL_BUFFER_MAP_OFFSET: - if (ctx->VersionMajor < 3) - goto invalid_pname; - *params = (GLint) bufObj->Offset; - return; - case GL_BUFFER_MAP_LENGTH: - if (ctx->VersionMajor < 3) - goto invalid_pname; - *params = (GLint) bufObj->Length; - return; - default: - ; /* fall-through */ - } - -invalid_pname: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname=%s)", - _mesa_lookup_enum_by_nr(pname)); -} - - -/** - * New in GL 3.2 - * This is pretty much a duplicate of GetBufferParameteriv() but the - * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system. - */ -void GLAPIENTRY -_mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - bufObj = get_buffer(ctx, target); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(target)" ); - return; - } - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferParameteri64v" ); - return; - } - - switch (pname) { - case GL_BUFFER_SIZE_ARB: - *params = bufObj->Size; - return; - case GL_BUFFER_USAGE_ARB: - *params = bufObj->Usage; - return; - case GL_BUFFER_ACCESS_ARB: - *params = simplified_access_mode(bufObj->AccessFlags); - return; - case GL_BUFFER_ACCESS_FLAGS: - if (ctx->VersionMajor < 3) - goto invalid_pname; - *params = bufObj->AccessFlags; - return; - case GL_BUFFER_MAPPED_ARB: - *params = _mesa_bufferobj_mapped(bufObj); - return; - case GL_BUFFER_MAP_OFFSET: - if (ctx->VersionMajor < 3) - goto invalid_pname; - *params = bufObj->Offset; - return; - case GL_BUFFER_MAP_LENGTH: - if (ctx->VersionMajor < 3) - goto invalid_pname; - *params = bufObj->Length; - return; - default: - ; /* fall-through */ - } - -invalid_pname: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname=%s)", - _mesa_lookup_enum_by_nr(pname)); -} - - -void GLAPIENTRY -_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object * bufObj; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (pname != GL_BUFFER_MAP_POINTER_ARB) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)"); - return; - } - - bufObj = get_buffer(ctx, target); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" ); - return; - } - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" ); - return; - } - - *params = bufObj->Pointer; -} - - -void GLAPIENTRY -_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, - GLintptr readOffset, GLintptr writeOffset, - GLsizeiptr size) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *src, *dst; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - src = get_buffer(ctx, readTarget); - if (!src || !_mesa_is_bufferobj(src)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glCopyBuffserSubData(readTarget = 0x%x)", readTarget); - return; - } - - dst = get_buffer(ctx, writeTarget); - if (!dst || !_mesa_is_bufferobj(dst)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glCopyBuffserSubData(writeTarget = 0x%x)", writeTarget); - return; - } - - if (_mesa_bufferobj_mapped(src)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyBuffserSubData(readBuffer is mapped)"); - return; - } - - if (_mesa_bufferobj_mapped(dst)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyBuffserSubData(writeBuffer is mapped)"); - return; - } - - if (readOffset < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBuffserSubData(readOffset = %d)", (int) readOffset); - return; - } - - if (writeOffset < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBuffserSubData(writeOffset = %d)", (int) writeOffset); - return; - } - - if (readOffset + size > src->Size) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBuffserSubData(readOffset + size = %d)", - (int) (readOffset + size)); - return; - } - - if (writeOffset + size > dst->Size) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBuffserSubData(writeOffset + size = %d)", - (int) (writeOffset + size)); - return; - } - - if (src == dst) { - if (readOffset + size <= writeOffset) { - /* OK */ - } - else if (writeOffset + size <= readOffset) { - /* OK */ - } - else { - /* overlapping src/dst is illegal */ - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBuffserSubData(overlapping src/dst)"); - return; - } - } - - ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size); -} - - -/** - * See GL_ARB_map_buffer_range spec - */ -void * GLAPIENTRY -_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, - GLbitfield access) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; - void *map; - - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); - - if (!ctx->Extensions.ARB_map_buffer_range) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(extension not supported)"); - return NULL; - } - - if (offset < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(offset = %ld)", (long)offset); - return NULL; - } - - if (length < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(length = %ld)", (long)length); - return NULL; - } - - if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(access indicates neither read or write)"); - return NULL; - } - - if (access & GL_MAP_READ_BIT) { - if ((access & GL_MAP_INVALIDATE_RANGE_BIT) || - (access & GL_MAP_INVALIDATE_BUFFER_BIT) || - (access & GL_MAP_UNSYNCHRONIZED_BIT)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(invalid access flags)"); - return NULL; - } - } - - if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) && - ((access & GL_MAP_WRITE_BIT) == 0)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(invalid access flags)"); - return NULL; - } - - bufObj = get_buffer(ctx, target); - if (!bufObj || !_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glMapBufferRange(target = 0x%x)", target); - return NULL; - } - - if (offset + length > bufObj->Size) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(offset + length > size)"); - return NULL; - } - - if (_mesa_bufferobj_mapped(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(buffer already mapped)"); - return NULL; - } - - ASSERT(ctx->Driver.MapBufferRange); - map = ctx->Driver.MapBufferRange(ctx, target, offset, length, - access, bufObj); - if (!map) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); - } - else { - /* The driver callback should have set all these fields. - * This is important because other modules (like VBO) might call - * the driver function directly. - */ - ASSERT(bufObj->Pointer == map); - ASSERT(bufObj->Length == length); - ASSERT(bufObj->Offset == offset); - ASSERT(bufObj->AccessFlags == access); - } - - return map; -} - - -/** - * See GL_ARB_map_buffer_range spec - */ -void GLAPIENTRY -_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!ctx->Extensions.ARB_map_buffer_range) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(extension not supported)"); - return; - } - - if (offset < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(offset = %ld)", (long)offset); - return; - } - - if (length < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(length = %ld)", (long)length); - return; - } - - bufObj = get_buffer(ctx, target); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glMapBufferRange(target = 0x%x)", target); - return; - } - - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(current buffer is 0)"); - return; - } - - if (!_mesa_bufferobj_mapped(bufObj)) { - /* buffer is not mapped */ - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(buffer is not mapped)"); - return; - } - - if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)"); - return; - } - - if (offset + length > bufObj->Length) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(offset %ld + length %ld > mapped length %ld)", - (long)offset, (long)length, (long)bufObj->Length); - return; - } - - ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT); - - if (ctx->Driver.FlushMappedBufferRange) - ctx->Driver.FlushMappedBufferRange(ctx, target, offset, length, bufObj); -} - - -#if FEATURE_APPLE_object_purgeable -static GLenum -_mesa_BufferObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option) -{ - struct gl_buffer_object *bufObj; - GLenum retval; - - bufObj = _mesa_lookup_bufferobj(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectPurgeable(name = 0x%x)", name); - return 0; - } - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glObjectPurgeable(buffer 0)" ); - return 0; - } - - if (bufObj->Purgeable) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glObjectPurgeable(name = 0x%x) is already purgeable", name); - return GL_VOLATILE_APPLE; - } - - bufObj->Purgeable = GL_TRUE; - - retval = GL_VOLATILE_APPLE; - if (ctx->Driver.BufferObjectPurgeable) - retval = ctx->Driver.BufferObjectPurgeable(ctx, bufObj, option); - - return retval; -} - - -static GLenum -_mesa_RenderObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option) -{ - struct gl_renderbuffer *bufObj; - GLenum retval; - - bufObj = _mesa_lookup_renderbuffer(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectUnpurgeable(name = 0x%x)", name); - return 0; - } - - if (bufObj->Purgeable) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glObjectPurgeable(name = 0x%x) is already purgeable", name); - return GL_VOLATILE_APPLE; - } - - bufObj->Purgeable = GL_TRUE; - - retval = GL_VOLATILE_APPLE; - if (ctx->Driver.RenderObjectPurgeable) - retval = ctx->Driver.RenderObjectPurgeable(ctx, bufObj, option); - - return retval; -} - - -static GLenum -_mesa_TextureObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option) -{ - struct gl_texture_object *bufObj; - GLenum retval; - - bufObj = _mesa_lookup_texture(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectPurgeable(name = 0x%x)", name); - return 0; - } - - if (bufObj->Purgeable) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glObjectPurgeable(name = 0x%x) is already purgeable", name); - return GL_VOLATILE_APPLE; - } - - bufObj->Purgeable = GL_TRUE; - - retval = GL_VOLATILE_APPLE; - if (ctx->Driver.TextureObjectPurgeable) - retval = ctx->Driver.TextureObjectPurgeable(ctx, bufObj, option); - - return retval; -} - - -GLenum GLAPIENTRY -_mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option) -{ - GLenum retval; - - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); - - if (name == 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectPurgeable(name = 0x%x)", name); - return 0; - } - - switch (option) { - case GL_VOLATILE_APPLE: - case GL_RELEASED_APPLE: - /* legal */ - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glObjectPurgeable(name = 0x%x) invalid option: %d", - name, option); - return 0; - } - - switch (objectType) { - case GL_TEXTURE: - retval = _mesa_TextureObjectPurgeable (ctx, name, option); - break; - case GL_RENDERBUFFER_EXT: - retval = _mesa_RenderObjectPurgeable (ctx, name, option); - break; - case GL_BUFFER_OBJECT_APPLE: - retval = _mesa_BufferObjectPurgeable (ctx, name, option); - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glObjectPurgeable(name = 0x%x) invalid type: %d", - name, objectType); - return 0; - } - - /* In strict conformance to the spec, we must only return VOLATILE when - * when passed the VOLATILE option. Madness. - * - * XXX First fix the spec, then fix me. - */ - return option == GL_VOLATILE_APPLE ? GL_VOLATILE_APPLE : retval; -} - - -static GLenum -_mesa_BufferObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option) -{ - struct gl_buffer_object *bufObj; - GLenum retval; - - bufObj = _mesa_lookup_bufferobj(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectUnpurgeable(name = 0x%x)", name); - return 0; - } - - if (! bufObj->Purgeable) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glObjectUnpurgeable(name = 0x%x) object is " - " already \"unpurged\"", name); - return 0; - } - - bufObj->Purgeable = GL_FALSE; - - retval = option; - if (ctx->Driver.BufferObjectUnpurgeable) - retval = ctx->Driver.BufferObjectUnpurgeable(ctx, bufObj, option); - - return retval; -} - - -static GLenum -_mesa_RenderObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option) -{ - struct gl_renderbuffer *bufObj; - GLenum retval; - - bufObj = _mesa_lookup_renderbuffer(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectUnpurgeable(name = 0x%x)", name); - return 0; - } - - if (! bufObj->Purgeable) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glObjectUnpurgeable(name = 0x%x) object is " - " already \"unpurged\"", name); - return 0; - } - - bufObj->Purgeable = GL_FALSE; - - retval = option; - if (ctx->Driver.RenderObjectUnpurgeable) - retval = ctx->Driver.RenderObjectUnpurgeable(ctx, bufObj, option); - - return retval; -} - - -static GLenum -_mesa_TextureObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option) -{ - struct gl_texture_object *bufObj; - GLenum retval; - - bufObj = _mesa_lookup_texture(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectUnpurgeable(name = 0x%x)", name); - return 0; - } - - if (! bufObj->Purgeable) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glObjectUnpurgeable(name = 0x%x) object is" - " already \"unpurged\"", name); - return 0; - } - - bufObj->Purgeable = GL_FALSE; - - retval = option; - if (ctx->Driver.TextureObjectUnpurgeable) - retval = ctx->Driver.TextureObjectUnpurgeable(ctx, bufObj, option); - - return retval; -} - - -GLenum GLAPIENTRY -_mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); - - if (name == 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectUnpurgeable(name = 0x%x)", name); - return 0; - } - - switch (option) { - case GL_RETAINED_APPLE: - case GL_UNDEFINED_APPLE: - /* legal */ - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glObjectUnpurgeable(name = 0x%x) invalid option: %d", - name, option); - return 0; - } - - switch (objectType) { - case GL_BUFFER_OBJECT_APPLE: - return _mesa_BufferObjectUnpurgeable(ctx, name, option); - case GL_TEXTURE: - return _mesa_TextureObjectUnpurgeable(ctx, name, option); - case GL_RENDERBUFFER_EXT: - return _mesa_RenderObjectUnpurgeable(ctx, name, option); - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glObjectUnpurgeable(name = 0x%x) invalid type: %d", - name, objectType); - return 0; - } -} - - -static void -_mesa_GetBufferObjectParameterivAPPLE(struct gl_context *ctx, GLuint name, - GLenum pname, GLint* params) -{ - struct gl_buffer_object *bufObj; - - bufObj = _mesa_lookup_bufferobj(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glGetObjectParameteriv(name = 0x%x) invalid object", name); - return; - } - - switch (pname) { - case GL_PURGEABLE_APPLE: - *params = bufObj->Purgeable; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", - name, pname); - break; - } -} - - -static void -_mesa_GetRenderObjectParameterivAPPLE(struct gl_context *ctx, GLuint name, - GLenum pname, GLint* params) -{ - struct gl_renderbuffer *bufObj; - - bufObj = _mesa_lookup_renderbuffer(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectUnpurgeable(name = 0x%x)", name); - return; - } - - switch (pname) { - case GL_PURGEABLE_APPLE: - *params = bufObj->Purgeable; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", - name, pname); - break; - } -} - - -static void -_mesa_GetTextureObjectParameterivAPPLE(struct gl_context *ctx, GLuint name, - GLenum pname, GLint* params) -{ - struct gl_texture_object *bufObj; - - bufObj = _mesa_lookup_texture(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectUnpurgeable(name = 0x%x)", name); - return; - } - - switch (pname) { - case GL_PURGEABLE_APPLE: - *params = bufObj->Purgeable; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", - name, pname); - break; - } -} - - -void GLAPIENTRY -_mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname, - GLint* params) -{ - GET_CURRENT_CONTEXT(ctx); - - if (name == 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glGetObjectParameteriv(name = 0x%x)", name); - return; - } - - switch (objectType) { - case GL_TEXTURE: - _mesa_GetTextureObjectParameterivAPPLE (ctx, name, pname, params); - break; - case GL_BUFFER_OBJECT_APPLE: - _mesa_GetBufferObjectParameterivAPPLE (ctx, name, pname, params); - break; - case GL_RENDERBUFFER_EXT: - _mesa_GetRenderObjectParameterivAPPLE (ctx, name, pname, params); - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetObjectParameteriv(name = 0x%x) invalid type: %d", - name, objectType); - } -} - -#endif /* FEATURE_APPLE_object_purgeable */ +/* + * Mesa 3-D graphics library + * Version: 7.6 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. 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 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 + * BRIAN PAUL 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. + */ + + +/** + * \file bufferobj.c + * \brief Functions for the GL_ARB_vertex/pixel_buffer_object extensions. + * \author Brian Paul, Ian Romanick + */ + + +#include "glheader.h" +#include "enums.h" +#include "hash.h" +#include "imports.h" +#include "image.h" +#include "context.h" +#include "bufferobj.h" +#include "fbobject.h" +#include "mfeatures.h" +#include "mtypes.h" +#include "texobj.h" + + +/* Debug flags */ +/*#define VBO_DEBUG*/ +/*#define BOUNDS_CHECK*/ + + +#if FEATURE_OES_mapbuffer +#define DEFAULT_ACCESS GL_MAP_WRITE_BIT +#else +#define DEFAULT_ACCESS (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT) +#endif + + +/** + * Used as a placeholder for buffer objects between glGenBuffers() and + * glBindBuffer() so that glIsBuffer() can work correctly. + */ +static struct gl_buffer_object DummyBufferObject; + + +/** + * Return pointer to address of a buffer object target. + * \param ctx the GL context + * \param target the buffer object target to be retrieved. + * \return pointer to pointer to the buffer object bound to \c target in the + * specified context or \c NULL if \c target is invalid. + */ +static INLINE struct gl_buffer_object ** +get_buffer_target(struct gl_context *ctx, GLenum target) +{ + switch (target) { + case GL_ARRAY_BUFFER_ARB: + return &ctx->Array.ArrayBufferObj; + case GL_ELEMENT_ARRAY_BUFFER_ARB: + return &ctx->Array.ElementArrayBufferObj; + case GL_PIXEL_PACK_BUFFER_EXT: + return &ctx->Pack.BufferObj; + case GL_PIXEL_UNPACK_BUFFER_EXT: + return &ctx->Unpack.BufferObj; + case GL_COPY_READ_BUFFER: + return &ctx->CopyReadBuffer; + case GL_COPY_WRITE_BUFFER: + return &ctx->CopyWriteBuffer; +#if FEATURE_EXT_transform_feedback + case GL_TRANSFORM_FEEDBACK_BUFFER: + if (ctx->Extensions.EXT_transform_feedback) { + return &ctx->TransformFeedback.CurrentBuffer; + } + break; +#endif + default: + return NULL; + } + return NULL; +} + + +/** + * Get the buffer object bound to the specified target in a GL context. + * \param ctx the GL context + * \param target the buffer object target to be retrieved. + * \return pointer to the buffer object bound to \c target in the + * specified context or \c NULL if \c target is invalid. + */ +static INLINE struct gl_buffer_object * +get_buffer(struct gl_context *ctx, GLenum target) +{ + struct gl_buffer_object **bufObj = get_buffer_target(ctx, target); + if (bufObj) + return *bufObj; + return NULL; +} + + +/** + * Convert a GLbitfield describing the mapped buffer access flags + * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY. + */ +static GLenum +simplified_access_mode(GLbitfield access) +{ + const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; + if ((access & rwFlags) == rwFlags) + return GL_READ_WRITE; + if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT) + return GL_READ_ONLY; + if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT) + return GL_WRITE_ONLY; + return GL_READ_WRITE; /* this should never happen, but no big deal */ +} + + +/** + * Tests the subdata range parameters and sets the GL error code for + * \c glBufferSubDataARB and \c glGetBufferSubDataARB. + * + * \param ctx GL context. + * \param target Buffer object target on which to operate. + * \param offset Offset of the first byte of the subdata range. + * \param size Size, in bytes, of the subdata range. + * \param caller Name of calling function for recording errors. + * \return A pointer to the buffer object bound to \c target in the + * specified context or \c NULL if any of the parameter or state + * conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB + * are invalid. + * + * \sa glBufferSubDataARB, glGetBufferSubDataARB + */ +static struct gl_buffer_object * +buffer_object_subdata_range_good( struct gl_context * ctx, GLenum target, + GLintptrARB offset, GLsizeiptrARB size, + const char *caller ) +{ + struct gl_buffer_object *bufObj; + + if (size < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller); + return NULL; + } + + if (offset < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller); + return NULL; + } + + bufObj = get_buffer(ctx, target); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller); + return NULL; + } + if (!_mesa_is_bufferobj(bufObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); + return NULL; + } + if (offset + size > bufObj->Size) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(size + offset > buffer size)", caller); + return NULL; + } + if (_mesa_bufferobj_mapped(bufObj)) { + /* Buffer is currently mapped */ + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); + return NULL; + } + + return bufObj; +} + + +/** + * Allocate and initialize a new buffer object. + * + * Default callback for the \c dd_function_table::NewBufferObject() hook. + */ +static struct gl_buffer_object * +_mesa_new_buffer_object( struct gl_context *ctx, GLuint name, GLenum target ) +{ + struct gl_buffer_object *obj; + + (void) ctx; + + obj = MALLOC_STRUCT(gl_buffer_object); + _mesa_initialize_buffer_object(obj, name, target); + return obj; +} + + +/** + * Delete a buffer object. + * + * Default callback for the \c dd_function_table::DeleteBuffer() hook. + */ +static void +_mesa_delete_buffer_object( struct gl_context *ctx, struct gl_buffer_object *bufObj ) +{ + (void) ctx; + + if (bufObj->Data) + free(bufObj->Data); + + /* assign strange values here to help w/ debugging */ + bufObj->RefCount = -1000; + bufObj->Name = ~0; + + _glthread_DESTROY_MUTEX(bufObj->Mutex); + free(bufObj); +} + + + +/** + * Set ptr to bufObj w/ reference counting. + */ +void +_mesa_reference_buffer_object(struct gl_context *ctx, + struct gl_buffer_object **ptr, + struct gl_buffer_object *bufObj) +{ + if (*ptr == bufObj) + return; + + if (*ptr) { + /* Unreference the old buffer */ + GLboolean deleteFlag = GL_FALSE; + struct gl_buffer_object *oldObj = *ptr; + + _glthread_LOCK_MUTEX(oldObj->Mutex); + ASSERT(oldObj->RefCount > 0); + oldObj->RefCount--; +#if 0 + printf("BufferObj %p %d DECR to %d\n", + (void *) oldObj, oldObj->Name, oldObj->RefCount); +#endif + deleteFlag = (oldObj->RefCount == 0); + _glthread_UNLOCK_MUTEX(oldObj->Mutex); + + if (deleteFlag) { + + /* some sanity checking: don't delete a buffer still in use */ +#if 0 + /* unfortunately, these tests are invalid during context tear-down */ + ASSERT(ctx->Array.ArrayBufferObj != bufObj); + ASSERT(ctx->Array.ElementArrayBufferObj != bufObj); + ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj); +#endif + + ASSERT(ctx->Driver.DeleteBuffer); + ctx->Driver.DeleteBuffer(ctx, oldObj); + } + + *ptr = NULL; + } + ASSERT(!*ptr); + + if (bufObj) { + /* reference new buffer */ + _glthread_LOCK_MUTEX(bufObj->Mutex); + if (bufObj->RefCount == 0) { + /* this buffer's being deleted (look just above) */ + /* Not sure this can every really happen. Warn if it does. */ + _mesa_problem(NULL, "referencing deleted buffer object"); + *ptr = NULL; + } + else { + bufObj->RefCount++; +#if 0 + printf("BufferObj %p %d INCR to %d\n", + (void *) bufObj, bufObj->Name, bufObj->RefCount); +#endif + *ptr = bufObj; + } + _glthread_UNLOCK_MUTEX(bufObj->Mutex); + } +} + + +/** + * Initialize a buffer object to default values. + */ +void +_mesa_initialize_buffer_object( struct gl_buffer_object *obj, + GLuint name, GLenum target ) +{ + (void) target; + + memset(obj, 0, sizeof(struct gl_buffer_object)); + _glthread_INIT_MUTEX(obj->Mutex); + obj->RefCount = 1; + obj->Name = name; + obj->Usage = GL_STATIC_DRAW_ARB; + obj->AccessFlags = DEFAULT_ACCESS; +} + + +/** + * Allocate space for and store data in a buffer object. Any data that was + * previously stored in the buffer object is lost. If \c data is \c NULL, + * memory will be allocated, but no copy will occur. + * + * This is the default callback for \c dd_function_table::BufferData() + * Note that all GL error checking will have been done already. + * + * \param ctx GL context. + * \param target Buffer object target on which to operate. + * \param size Size, in bytes, of the new data store. + * \param data Pointer to the data to store in the buffer object. This + * pointer may be \c NULL. + * \param usage Hints about how the data will be used. + * \param bufObj Object to be used. + * + * \return GL_TRUE for success, GL_FALSE for failure + * \sa glBufferDataARB, dd_function_table::BufferData. + */ +static GLboolean +_mesa_buffer_data( struct gl_context *ctx, GLenum target, GLsizeiptrARB size, + const GLvoid * data, GLenum usage, + struct gl_buffer_object * bufObj ) +{ + void * new_data; + + (void) ctx; (void) target; + + new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size ); + if (new_data) { + bufObj->Data = (GLubyte *) new_data; + bufObj->Size = size; + bufObj->Usage = usage; + + if (data) { + memcpy( bufObj->Data, data, size ); + } + + return GL_TRUE; + } + else { + return GL_FALSE; + } +} + + +/** + * Replace data in a subrange of buffer object. If the data range + * specified by \c size + \c offset extends beyond the end of the buffer or + * if \c data is \c NULL, no copy is performed. + * + * This is the default callback for \c dd_function_table::BufferSubData() + * Note that all GL error checking will have been done already. + * + * \param ctx GL context. + * \param target Buffer object target on which to operate. + * \param offset Offset of the first byte to be modified. + * \param size Size, in bytes, of the data range. + * \param data Pointer to the data to store in the buffer object. + * \param bufObj Object to be used. + * + * \sa glBufferSubDataARB, dd_function_table::BufferSubData. + */ +static void +_mesa_buffer_subdata( struct gl_context *ctx, GLenum target, GLintptrARB offset, + GLsizeiptrARB size, const GLvoid * data, + struct gl_buffer_object * bufObj ) +{ + (void) ctx; (void) target; + + /* this should have been caught in _mesa_BufferSubData() */ + ASSERT(size + offset <= bufObj->Size); + + if (bufObj->Data) { + memcpy( (GLubyte *) bufObj->Data + offset, data, size ); + } +} + + +/** + * Retrieve data from a subrange of buffer object. If the data range + * specified by \c size + \c offset extends beyond the end of the buffer or + * if \c data is \c NULL, no copy is performed. + * + * This is the default callback for \c dd_function_table::GetBufferSubData() + * Note that all GL error checking will have been done already. + * + * \param ctx GL context. + * \param target Buffer object target on which to operate. + * \param offset Offset of the first byte to be fetched. + * \param size Size, in bytes, of the data range. + * \param data Destination for data + * \param bufObj Object to be used. + * + * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData. + */ +static void +_mesa_buffer_get_subdata( struct gl_context *ctx, GLenum target, GLintptrARB offset, + GLsizeiptrARB size, GLvoid * data, + struct gl_buffer_object * bufObj ) +{ + (void) ctx; (void) target; + + if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) { + memcpy( data, (GLubyte *) bufObj->Data + offset, size ); + } +} + + +/** + * Default callback for \c dd_function_tabel::MapBuffer(). + * + * The function parameters will have been already tested for errors. + * + * \param ctx GL context. + * \param target Buffer object target on which to operate. + * \param access Information about how the buffer will be accessed. + * \param bufObj Object to be mapped. + * \return A pointer to the object's internal data store that can be accessed + * by the processor + * + * \sa glMapBufferARB, dd_function_table::MapBuffer + */ +static void * +_mesa_buffer_map( struct gl_context *ctx, GLenum target, GLenum access, + struct gl_buffer_object *bufObj ) +{ + (void) ctx; + (void) target; + (void) access; + /* Just return a direct pointer to the data */ + if (_mesa_bufferobj_mapped(bufObj)) { + /* already mapped! */ + return NULL; + } + bufObj->Pointer = bufObj->Data; + bufObj->Length = bufObj->Size; + bufObj->Offset = 0; + return bufObj->Pointer; +} + + +/** + * Default fallback for \c dd_function_table::MapBufferRange(). + * Called via glMapBufferRange(). + */ +static void * +_mesa_buffer_map_range( struct gl_context *ctx, GLenum target, GLintptr offset, + GLsizeiptr length, GLbitfield access, + struct gl_buffer_object *bufObj ) +{ + (void) ctx; + (void) target; + assert(!_mesa_bufferobj_mapped(bufObj)); + /* Just return a direct pointer to the data */ + bufObj->Pointer = bufObj->Data + offset; + bufObj->Length = length; + bufObj->Offset = offset; + bufObj->AccessFlags = access; + return bufObj->Pointer; +} + + +/** + * Default fallback for \c dd_function_table::FlushMappedBufferRange(). + * Called via glFlushMappedBufferRange(). + */ +static void +_mesa_buffer_flush_mapped_range( struct gl_context *ctx, GLenum target, + GLintptr offset, GLsizeiptr length, + struct gl_buffer_object *obj ) +{ + (void) ctx; + (void) target; + (void) offset; + (void) length; + (void) obj; + /* no-op */ +} + + +/** + * Default callback for \c dd_function_table::MapBuffer(). + * + * The input parameters will have been already tested for errors. + * + * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer + */ +static GLboolean +_mesa_buffer_unmap( struct gl_context *ctx, GLenum target, + struct gl_buffer_object *bufObj ) +{ + (void) ctx; + (void) target; + /* XXX we might assert here that bufObj->Pointer is non-null */ + bufObj->Pointer = NULL; + bufObj->Length = 0; + bufObj->Offset = 0; + bufObj->AccessFlags = 0x0; + return GL_TRUE; +} + + +/** + * Default fallback for \c dd_function_table::CopyBufferSubData(). + * Called via glCopyBuffserSubData(). + */ +static void +_mesa_copy_buffer_subdata(struct gl_context *ctx, + struct gl_buffer_object *src, + struct gl_buffer_object *dst, + GLintptr readOffset, GLintptr writeOffset, + GLsizeiptr size) +{ + GLubyte *srcPtr, *dstPtr; + + /* buffer should not already be mapped */ + assert(!_mesa_bufferobj_mapped(src)); + assert(!_mesa_bufferobj_mapped(dst)); + + srcPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_READ_BUFFER, + GL_READ_ONLY, src); + dstPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_WRITE_BUFFER, + GL_WRITE_ONLY, dst); + + if (srcPtr && dstPtr) + memcpy(dstPtr + writeOffset, srcPtr + readOffset, size); + + ctx->Driver.UnmapBuffer(ctx, GL_COPY_READ_BUFFER, src); + ctx->Driver.UnmapBuffer(ctx, GL_COPY_WRITE_BUFFER, dst); +} + + + +/** + * Initialize the state associated with buffer objects + */ +void +_mesa_init_buffer_objects( struct gl_context *ctx ) +{ + memset(&DummyBufferObject, 0, sizeof(DummyBufferObject)); + DummyBufferObject.RefCount = 1000*1000*1000; /* never delete */ + + _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, + ctx->Shared->NullBufferObj); + _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, + ctx->Shared->NullBufferObj); + + _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, + ctx->Shared->NullBufferObj); + _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, + ctx->Shared->NullBufferObj); +} + + +void +_mesa_free_buffer_objects( struct gl_context *ctx ) +{ + _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL); + _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL); + + _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL); + _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL); +} + + +/** + * Bind the specified target to buffer for the specified context. + * Called by glBindBuffer() and other functions. + */ +static void +bind_buffer_object(struct gl_context *ctx, GLenum target, GLuint buffer) +{ + struct gl_buffer_object *oldBufObj; + struct gl_buffer_object *newBufObj = NULL; + struct gl_buffer_object **bindTarget = NULL; + + bindTarget = get_buffer_target(ctx, target); + if (!bindTarget) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)", target); + return; + } + + /* Get pointer to old buffer object (to be unbound) */ + oldBufObj = *bindTarget; + if (oldBufObj && oldBufObj->Name == buffer) + return; /* rebinding the same buffer object- no change */ + + /* + * Get pointer to new buffer object (newBufObj) + */ + if (buffer == 0) { + /* The spec says there's not a buffer object named 0, but we use + * one internally because it simplifies things. + */ + newBufObj = ctx->Shared->NullBufferObj; + } + else { + /* non-default buffer object */ + newBufObj = _mesa_lookup_bufferobj(ctx, buffer); + if (!newBufObj || newBufObj == &DummyBufferObject) { + /* If this is a new buffer object id, or one which was generated but + * never used before, allocate a buffer object now. + */ + ASSERT(ctx->Driver.NewBufferObject); + newBufObj = ctx->Driver.NewBufferObject(ctx, buffer, target); + if (!newBufObj) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB"); + return; + } + _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, newBufObj); + } + } + + /* bind new buffer */ + _mesa_reference_buffer_object(ctx, bindTarget, newBufObj); + + /* Pass BindBuffer call to device driver */ + if (ctx->Driver.BindBuffer) + ctx->Driver.BindBuffer( ctx, target, newBufObj ); +} + + +/** + * Update the default buffer objects in the given context to reference those + * specified in the shared state and release those referencing the old + * shared state. + */ +void +_mesa_update_default_objects_buffer_objects(struct gl_context *ctx) +{ + /* Bind the NullBufferObj to remove references to those + * in the shared context hash table. + */ + bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0); + bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0); + bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0); +} + + +/** + * When we're about to read pixel data out of a PBO (via glDrawPixels, + * glTexImage, etc) or write data into a PBO (via glReadPixels, + * glGetTexImage, etc) we call this function to check that we're not + * going to read out of bounds. + * + * XXX This would also be a convenient time to check that the PBO isn't + * currently mapped. Whoever calls this function should check for that. + * Remember, we can't use a PBO when it's mapped! + * + * If we're not using a PBO, this is a no-op. + * + * \param width width of image to read/write + * \param height height of image to read/write + * \param depth depth of image to read/write + * \param format format of image to read/write + * \param type datatype of image to read/write + * \param ptr the user-provided pointer/offset + * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would + * go out of bounds. + */ +GLboolean +_mesa_validate_pbo_access(GLuint dimensions, + const struct gl_pixelstore_attrib *pack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *ptr) +{ + GLvoid *start, *end; + const GLubyte *sizeAddr; /* buffer size, cast to a pointer */ + + if (!_mesa_is_bufferobj(pack->BufferObj)) + return GL_TRUE; /* no PBO, OK */ + + if (pack->BufferObj->Size == 0) + /* no buffer! */ + return GL_FALSE; + + /* get address of first pixel we'll read */ + start = _mesa_image_address(dimensions, pack, ptr, width, height, + format, type, 0, 0, 0); + + /* get address just past the last pixel we'll read */ + end = _mesa_image_address(dimensions, pack, ptr, width, height, + format, type, depth-1, height-1, width); + + + sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size; + + if ((const GLubyte *) start > sizeAddr) { + /* This will catch negative values / wrap-around */ + return GL_FALSE; + } + if ((const GLubyte *) end > sizeAddr) { + /* Image read goes beyond end of buffer */ + return GL_FALSE; + } + + /* OK! */ + return GL_TRUE; +} + + +/** + * For commands that read from a PBO (glDrawPixels, glTexImage, + * glPolygonStipple, etc), if we're reading from a PBO, map it read-only + * and return the pointer into the PBO. If we're not reading from a + * PBO, return \p src as-is. + * If non-null return, must call _mesa_unmap_pbo_source() when done. + * + * \return NULL if error, else pointer to start of data + */ +const GLvoid * +_mesa_map_pbo_source(struct gl_context *ctx, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *src) +{ + const GLubyte *buf; + + if (_mesa_is_bufferobj(unpack->BufferObj)) { + /* unpack from PBO */ + buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, + GL_READ_ONLY_ARB, + unpack->BufferObj); + if (!buf) + return NULL; + + buf = ADD_POINTERS(buf, src); + } + else { + /* unpack from normal memory */ + buf = src; + } + + return buf; +} + + +/** + * Combine PBO-read validation and mapping. + * If any GL errors are detected, they'll be recorded and NULL returned. + * \sa _mesa_validate_pbo_access + * \sa _mesa_map_pbo_source + * A call to this function should have a matching call to + * _mesa_unmap_pbo_source(). + */ +const GLvoid * +_mesa_map_validate_pbo_source(struct gl_context *ctx, + GLuint dimensions, + const struct gl_pixelstore_attrib *unpack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *ptr, + const char *where) +{ + ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); + + if (!_mesa_is_bufferobj(unpack->BufferObj)) { + /* non-PBO access: no validation to be done */ + return ptr; + } + + if (!_mesa_validate_pbo_access(dimensions, unpack, + width, height, depth, format, type, ptr)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(out of bounds PBO access)", where); + return NULL; + } + + if (_mesa_bufferobj_mapped(unpack->BufferObj)) { + /* buffer is already mapped - that's an error */ + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); + return NULL; + } + + ptr = _mesa_map_pbo_source(ctx, unpack, ptr); + return ptr; +} + + +/** + * Counterpart to _mesa_map_pbo_source() + */ +void +_mesa_unmap_pbo_source(struct gl_context *ctx, + const struct gl_pixelstore_attrib *unpack) +{ + ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */ + if (_mesa_is_bufferobj(unpack->BufferObj)) { + ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, + unpack->BufferObj); + } +} + + +/** + * For commands that write to a PBO (glReadPixels, glGetColorTable, etc), + * if we're writing to a PBO, map it write-only and return the pointer + * into the PBO. If we're not writing to a PBO, return \p dst as-is. + * If non-null return, must call _mesa_unmap_pbo_dest() when done. + * + * \return NULL if error, else pointer to start of data + */ +void * +_mesa_map_pbo_dest(struct gl_context *ctx, + const struct gl_pixelstore_attrib *pack, + GLvoid *dest) +{ + void *buf; + + if (_mesa_is_bufferobj(pack->BufferObj)) { + /* pack into PBO */ + buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, + GL_WRITE_ONLY_ARB, + pack->BufferObj); + if (!buf) + return NULL; + + buf = ADD_POINTERS(buf, dest); + } + else { + /* pack to normal memory */ + buf = dest; + } + + return buf; +} + + +/** + * Combine PBO-write validation and mapping. + * If any GL errors are detected, they'll be recorded and NULL returned. + * \sa _mesa_validate_pbo_access + * \sa _mesa_map_pbo_dest + * A call to this function should have a matching call to + * _mesa_unmap_pbo_dest(). + */ +GLvoid * +_mesa_map_validate_pbo_dest(struct gl_context *ctx, + GLuint dimensions, + const struct gl_pixelstore_attrib *unpack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, GLvoid *ptr, + const char *where) +{ + ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); + + if (!_mesa_is_bufferobj(unpack->BufferObj)) { + /* non-PBO access: no validation to be done */ + return ptr; + } + + if (!_mesa_validate_pbo_access(dimensions, unpack, + width, height, depth, format, type, ptr)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(out of bounds PBO access)", where); + return NULL; + } + + if (_mesa_bufferobj_mapped(unpack->BufferObj)) { + /* buffer is already mapped - that's an error */ + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); + return NULL; + } + + ptr = _mesa_map_pbo_dest(ctx, unpack, ptr); + return ptr; +} + + +/** + * Counterpart to _mesa_map_pbo_dest() + */ +void +_mesa_unmap_pbo_dest(struct gl_context *ctx, + const struct gl_pixelstore_attrib *pack) +{ + ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */ + if (_mesa_is_bufferobj(pack->BufferObj)) { + ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj); + } +} + + + +/** + * Return the gl_buffer_object for the given ID. + * Always return NULL for ID 0. + */ +struct gl_buffer_object * +_mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer) +{ + if (buffer == 0) + return NULL; + else + return (struct gl_buffer_object *) + _mesa_HashLookup(ctx->Shared->BufferObjects, buffer); +} + + +/** + * If *ptr points to obj, set ptr = the Null/default buffer object. + * This is a helper for buffer object deletion. + * The GL spec says that deleting a buffer object causes it to get + * unbound from all arrays in the current context. + */ +static void +unbind(struct gl_context *ctx, + struct gl_buffer_object **ptr, + struct gl_buffer_object *obj) +{ + if (*ptr == obj) { + _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj); + } +} + + +/** + * Plug default/fallback buffer object functions into the device + * driver hooks. + */ +void +_mesa_init_buffer_object_functions(struct dd_function_table *driver) +{ + /* GL_ARB_vertex/pixel_buffer_object */ + driver->NewBufferObject = _mesa_new_buffer_object; + driver->DeleteBuffer = _mesa_delete_buffer_object; + driver->BindBuffer = NULL; + driver->BufferData = _mesa_buffer_data; + driver->BufferSubData = _mesa_buffer_subdata; + driver->GetBufferSubData = _mesa_buffer_get_subdata; + driver->MapBuffer = _mesa_buffer_map; + driver->UnmapBuffer = _mesa_buffer_unmap; + + /* GL_ARB_map_buffer_range */ + driver->MapBufferRange = _mesa_buffer_map_range; + driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range; + + /* GL_ARB_copy_buffer */ + driver->CopyBufferSubData = _mesa_copy_buffer_subdata; +} + + + +/**********************************************************************/ +/* API Functions */ +/**********************************************************************/ + +void GLAPIENTRY +_mesa_BindBufferARB(GLenum target, GLuint buffer) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glBindBuffer(%s, %u)\n", + _mesa_lookup_enum_by_nr(target), buffer); + + bind_buffer_object(ctx, target, buffer); +} + + +/** + * Delete a set of buffer objects. + * + * \param n Number of buffer objects to delete. + * \param ids Array of \c n buffer object IDs. + */ +void GLAPIENTRY +_mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids) +{ + GET_CURRENT_CONTEXT(ctx); + GLsizei i; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)"); + return; + } + + _glthread_LOCK_MUTEX(ctx->Shared->Mutex); + + for (i = 0; i < n; i++) { + struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]); + if (bufObj) { + struct gl_array_object *arrayObj = ctx->Array.ArrayObj; + GLuint j; + + ASSERT(bufObj->Name == ids[i] || bufObj == &DummyBufferObject); + + if (_mesa_bufferobj_mapped(bufObj)) { + /* if mapped, unmap it now */ + ctx->Driver.UnmapBuffer(ctx, 0, bufObj); + bufObj->AccessFlags = DEFAULT_ACCESS; + bufObj->Pointer = NULL; + } + + /* unbind any vertex pointers bound to this buffer */ + unbind(ctx, &arrayObj->Vertex.BufferObj, bufObj); + unbind(ctx, &arrayObj->Weight.BufferObj, bufObj); + unbind(ctx, &arrayObj->Normal.BufferObj, bufObj); + unbind(ctx, &arrayObj->Color.BufferObj, bufObj); + unbind(ctx, &arrayObj->SecondaryColor.BufferObj, bufObj); + unbind(ctx, &arrayObj->FogCoord.BufferObj, bufObj); + unbind(ctx, &arrayObj->Index.BufferObj, bufObj); + unbind(ctx, &arrayObj->EdgeFlag.BufferObj, bufObj); + for (j = 0; j < Elements(arrayObj->TexCoord); j++) { + unbind(ctx, &arrayObj->TexCoord[j].BufferObj, bufObj); + } + for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) { + unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj); + } + + if (ctx->Array.ArrayBufferObj == bufObj) { + _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 ); + } + if (ctx->Array.ElementArrayBufferObj == bufObj) { + _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 ); + } + + /* unbind any pixel pack/unpack pointers bound to this buffer */ + if (ctx->Pack.BufferObj == bufObj) { + _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 ); + } + if (ctx->Unpack.BufferObj == bufObj) { + _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 ); + } + + /* The ID is immediately freed for re-use */ + _mesa_HashRemove(ctx->Shared->BufferObjects, ids[i]); + _mesa_reference_buffer_object(ctx, &bufObj, NULL); + } + } + + _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); +} + + +/** + * Generate a set of unique buffer object IDs and store them in \c buffer. + * + * \param n Number of IDs to generate. + * \param buffer Array of \c n locations to store the IDs. + */ +void GLAPIENTRY +_mesa_GenBuffersARB(GLsizei n, GLuint *buffer) +{ + GET_CURRENT_CONTEXT(ctx); + GLuint first; + GLint i; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glGenBuffers(%d)\n", n); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB"); + return; + } + + if (!buffer) { + return; + } + + /* + * This must be atomic (generation and allocation of buffer object IDs) + */ + _glthread_LOCK_MUTEX(ctx->Shared->Mutex); + + first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n); + + /* Insert the ID and pointer to dummy buffer object into hash table */ + for (i = 0; i < n; i++) { + _mesa_HashInsert(ctx->Shared->BufferObjects, first + i, + &DummyBufferObject); + buffer[i] = first + i; + } + + _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); +} + + +/** + * Determine if ID is the name of a buffer object. + * + * \param id ID of the potential buffer object. + * \return \c GL_TRUE if \c id is the name of a buffer object, + * \c GL_FALSE otherwise. + */ +GLboolean GLAPIENTRY +_mesa_IsBufferARB(GLuint id) +{ + struct gl_buffer_object *bufObj; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + + _glthread_LOCK_MUTEX(ctx->Shared->Mutex); + bufObj = _mesa_lookup_bufferobj(ctx, id); + _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); + + return bufObj && bufObj != &DummyBufferObject; +} + + +void GLAPIENTRY +_mesa_BufferDataARB(GLenum target, GLsizeiptrARB size, + const GLvoid * data, GLenum usage) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glBufferData(%s, %ld, %p, %s)\n", + _mesa_lookup_enum_by_nr(target), + (long int) size, data, + _mesa_lookup_enum_by_nr(usage)); + + if (size < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)"); + return; + } + + switch (usage) { + case GL_STREAM_DRAW_ARB: + case GL_STREAM_READ_ARB: + case GL_STREAM_COPY_ARB: + case GL_STATIC_DRAW_ARB: + case GL_STATIC_READ_ARB: + case GL_STATIC_COPY_ARB: + case GL_DYNAMIC_DRAW_ARB: + case GL_DYNAMIC_READ_ARB: + case GL_DYNAMIC_COPY_ARB: + /* OK */ + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)"); + return; + } + + bufObj = get_buffer(ctx, target); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(target)" ); + return; + } + if (!_mesa_is_bufferobj(bufObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer 0)" ); + return; + } + + if (_mesa_bufferobj_mapped(bufObj)) { + /* Unmap the existing buffer. We'll replace it now. Not an error. */ + ctx->Driver.UnmapBuffer(ctx, target, bufObj); + bufObj->AccessFlags = DEFAULT_ACCESS; + ASSERT(bufObj->Pointer == NULL); + } + + FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT); + + bufObj->Written = GL_TRUE; + +#ifdef VBO_DEBUG + printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n", + bufObj->Name, size, data, usage); +#endif + +#ifdef BOUNDS_CHECK + size += 100; +#endif + + ASSERT(ctx->Driver.BufferData); + if (!ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj )) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()"); + } +} + + +void GLAPIENTRY +_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset, + GLsizeiptrARB size, const GLvoid * data) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, + "glBufferSubDataARB" ); + if (!bufObj) { + /* error already recorded */ + return; + } + + if (size == 0) + return; + + bufObj->Written = GL_TRUE; + + ASSERT(ctx->Driver.BufferSubData); + ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj ); +} + + +void GLAPIENTRY +_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset, + GLsizeiptrARB size, void * data) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, + "glGetBufferSubDataARB" ); + if (!bufObj) { + /* error already recorded */ + return; + } + + ASSERT(ctx->Driver.GetBufferSubData); + ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj ); +} + + +void * GLAPIENTRY +_mesa_MapBufferARB(GLenum target, GLenum access) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object * bufObj; + GLbitfield accessFlags; + void *map; + + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); + + switch (access) { + case GL_READ_ONLY_ARB: + accessFlags = GL_MAP_READ_BIT; + break; + case GL_WRITE_ONLY_ARB: + accessFlags = GL_MAP_WRITE_BIT; + break; + case GL_READ_WRITE_ARB: + accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)"); + return NULL; + } + + bufObj = get_buffer(ctx, target); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" ); + return NULL; + } + if (!_mesa_is_bufferobj(bufObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(buffer 0)" ); + return NULL; + } + if (_mesa_bufferobj_mapped(bufObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)"); + return NULL; + } + + ASSERT(ctx->Driver.MapBuffer); + map = ctx->Driver.MapBuffer( ctx, target, access, bufObj ); + if (!map) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); + return NULL; + } + else { + /* The driver callback should have set these fields. + * This is important because other modules (like VBO) might call + * the driver function directly. + */ + ASSERT(bufObj->Pointer == map); + ASSERT(bufObj->Length == bufObj->Size); + ASSERT(bufObj->Offset == 0); + bufObj->AccessFlags = accessFlags; + } + + if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB) + bufObj->Written = GL_TRUE; + +#ifdef VBO_DEBUG + printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n", + bufObj->Name, bufObj->Size, access); + if (access == GL_WRITE_ONLY_ARB) { + GLuint i; + GLubyte *b = (GLubyte *) bufObj->Pointer; + for (i = 0; i < bufObj->Size; i++) + b[i] = i & 0xff; + } +#endif + +#ifdef BOUNDS_CHECK + { + GLubyte *buf = (GLubyte *) bufObj->Pointer; + GLuint i; + /* buffer is 100 bytes larger than requested, fill with magic value */ + for (i = 0; i < 100; i++) { + buf[bufObj->Size - i - 1] = 123; + } + } +#endif + + return bufObj->Pointer; +} + + +GLboolean GLAPIENTRY +_mesa_UnmapBufferARB(GLenum target) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + GLboolean status = GL_TRUE; + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + + bufObj = get_buffer(ctx, target); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" ); + return GL_FALSE; + } + if (!_mesa_is_bufferobj(bufObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" ); + return GL_FALSE; + } + if (!_mesa_bufferobj_mapped(bufObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB"); + return GL_FALSE; + } + +#ifdef BOUNDS_CHECK + if (bufObj->Access != GL_READ_ONLY_ARB) { + GLubyte *buf = (GLubyte *) bufObj->Pointer; + GLuint i; + /* check that last 100 bytes are still = magic value */ + for (i = 0; i < 100; i++) { + GLuint pos = bufObj->Size - i - 1; + if (buf[pos] != 123) { + _mesa_warning(ctx, "Out of bounds buffer object write detected" + " at position %d (value = %u)\n", + pos, buf[pos]); + } + } + } +#endif + +#ifdef VBO_DEBUG + if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) { + GLuint i, unchanged = 0; + GLubyte *b = (GLubyte *) bufObj->Pointer; + GLint pos = -1; + /* check which bytes changed */ + for (i = 0; i < bufObj->Size - 1; i++) { + if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) { + unchanged++; + if (pos == -1) + pos = i; + } + } + if (unchanged) { + printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n", + bufObj->Name, unchanged, bufObj->Size, pos); + } + } +#endif + + status = ctx->Driver.UnmapBuffer( ctx, target, bufObj ); + bufObj->AccessFlags = DEFAULT_ACCESS; + ASSERT(bufObj->Pointer == NULL); + ASSERT(bufObj->Offset == 0); + ASSERT(bufObj->Length == 0); + + return status; +} + + +void GLAPIENTRY +_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + bufObj = get_buffer(ctx, target); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(target)" ); + return; + } + if (!_mesa_is_bufferobj(bufObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferParameterivARB" ); + return; + } + + switch (pname) { + case GL_BUFFER_SIZE_ARB: + *params = (GLint) bufObj->Size; + return; + case GL_BUFFER_USAGE_ARB: + *params = bufObj->Usage; + return; + case GL_BUFFER_ACCESS_ARB: + *params = simplified_access_mode(bufObj->AccessFlags); + return; + case GL_BUFFER_MAPPED_ARB: + *params = _mesa_bufferobj_mapped(bufObj); + return; + case GL_BUFFER_ACCESS_FLAGS: + if (ctx->VersionMajor < 3) + goto invalid_pname; + *params = bufObj->AccessFlags; + return; + case GL_BUFFER_MAP_OFFSET: + if (ctx->VersionMajor < 3) + goto invalid_pname; + *params = (GLint) bufObj->Offset; + return; + case GL_BUFFER_MAP_LENGTH: + if (ctx->VersionMajor < 3) + goto invalid_pname; + *params = (GLint) bufObj->Length; + return; + default: + ; /* fall-through */ + } + +invalid_pname: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname=%s)", + _mesa_lookup_enum_by_nr(pname)); +} + + +/** + * New in GL 3.2 + * This is pretty much a duplicate of GetBufferParameteriv() but the + * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system. + */ +void GLAPIENTRY +_mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + bufObj = get_buffer(ctx, target); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(target)" ); + return; + } + if (!_mesa_is_bufferobj(bufObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferParameteri64v" ); + return; + } + + switch (pname) { + case GL_BUFFER_SIZE_ARB: + *params = bufObj->Size; + return; + case GL_BUFFER_USAGE_ARB: + *params = bufObj->Usage; + return; + case GL_BUFFER_ACCESS_ARB: + *params = simplified_access_mode(bufObj->AccessFlags); + return; + case GL_BUFFER_ACCESS_FLAGS: + if (ctx->VersionMajor < 3) + goto invalid_pname; + *params = bufObj->AccessFlags; + return; + case GL_BUFFER_MAPPED_ARB: + *params = _mesa_bufferobj_mapped(bufObj); + return; + case GL_BUFFER_MAP_OFFSET: + if (ctx->VersionMajor < 3) + goto invalid_pname; + *params = bufObj->Offset; + return; + case GL_BUFFER_MAP_LENGTH: + if (ctx->VersionMajor < 3) + goto invalid_pname; + *params = bufObj->Length; + return; + default: + ; /* fall-through */ + } + +invalid_pname: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname=%s)", + _mesa_lookup_enum_by_nr(pname)); +} + + +void GLAPIENTRY +_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object * bufObj; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (pname != GL_BUFFER_MAP_POINTER_ARB) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)"); + return; + } + + bufObj = get_buffer(ctx, target); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" ); + return; + } + if (!_mesa_is_bufferobj(bufObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" ); + return; + } + + *params = bufObj->Pointer; +} + + +void GLAPIENTRY +_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, + GLintptr readOffset, GLintptr writeOffset, + GLsizeiptr size) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *src, *dst; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + src = get_buffer(ctx, readTarget); + if (!src || !_mesa_is_bufferobj(src)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glCopyBuffserSubData(readTarget = 0x%x)", readTarget); + return; + } + + dst = get_buffer(ctx, writeTarget); + if (!dst || !_mesa_is_bufferobj(dst)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glCopyBuffserSubData(writeTarget = 0x%x)", writeTarget); + return; + } + + if (_mesa_bufferobj_mapped(src)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyBuffserSubData(readBuffer is mapped)"); + return; + } + + if (_mesa_bufferobj_mapped(dst)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyBuffserSubData(writeBuffer is mapped)"); + return; + } + + if (readOffset < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyBuffserSubData(readOffset = %d)", (int) readOffset); + return; + } + + if (writeOffset < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyBuffserSubData(writeOffset = %d)", (int) writeOffset); + return; + } + + if (readOffset + size > src->Size) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyBuffserSubData(readOffset + size = %d)", + (int) (readOffset + size)); + return; + } + + if (writeOffset + size > dst->Size) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyBuffserSubData(writeOffset + size = %d)", + (int) (writeOffset + size)); + return; + } + + if (src == dst) { + if (readOffset + size <= writeOffset) { + /* OK */ + } + else if (writeOffset + size <= readOffset) { + /* OK */ + } + else { + /* overlapping src/dst is illegal */ + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyBuffserSubData(overlapping src/dst)"); + return; + } + } + + ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size); +} + + +/** + * See GL_ARB_map_buffer_range spec + */ +void * GLAPIENTRY +_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, + GLbitfield access) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + void *map; + + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); + + if (!ctx->Extensions.ARB_map_buffer_range) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(extension not supported)"); + return NULL; + } + + if (offset < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glMapBufferRange(offset = %ld)", (long)offset); + return NULL; + } + + if (length < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glMapBufferRange(length = %ld)", (long)length); + return NULL; + } + + if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(access indicates neither read or write)"); + return NULL; + } + + if (access & GL_MAP_READ_BIT) { + if ((access & GL_MAP_INVALIDATE_RANGE_BIT) || + (access & GL_MAP_INVALIDATE_BUFFER_BIT) || + (access & GL_MAP_UNSYNCHRONIZED_BIT)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(invalid access flags)"); + return NULL; + } + } + + if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) && + ((access & GL_MAP_WRITE_BIT) == 0)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(invalid access flags)"); + return NULL; + } + + bufObj = get_buffer(ctx, target); + if (!bufObj || !_mesa_is_bufferobj(bufObj)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glMapBufferRange(target = 0x%x)", target); + return NULL; + } + + if (offset + length > bufObj->Size) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glMapBufferRange(offset + length > size)"); + return NULL; + } + + if (_mesa_bufferobj_mapped(bufObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(buffer already mapped)"); + return NULL; + } + + ASSERT(ctx->Driver.MapBufferRange); + map = ctx->Driver.MapBufferRange(ctx, target, offset, length, + access, bufObj); + if (!map) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); + } + else { + /* The driver callback should have set all these fields. + * This is important because other modules (like VBO) might call + * the driver function directly. + */ + ASSERT(bufObj->Pointer == map); + ASSERT(bufObj->Length == length); + ASSERT(bufObj->Offset == offset); + ASSERT(bufObj->AccessFlags == access); + } + + return map; +} + + +/** + * See GL_ARB_map_buffer_range spec + */ +void GLAPIENTRY +_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (!ctx->Extensions.ARB_map_buffer_range) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(extension not supported)"); + return; + } + + if (offset < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glMapBufferRange(offset = %ld)", (long)offset); + return; + } + + if (length < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glMapBufferRange(length = %ld)", (long)length); + return; + } + + bufObj = get_buffer(ctx, target); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glMapBufferRange(target = 0x%x)", target); + return; + } + + if (!_mesa_is_bufferobj(bufObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(current buffer is 0)"); + return; + } + + if (!_mesa_bufferobj_mapped(bufObj)) { + /* buffer is not mapped */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(buffer is not mapped)"); + return; + } + + if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)"); + return; + } + + if (offset + length > bufObj->Length) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glMapBufferRange(offset %ld + length %ld > mapped length %ld)", + (long)offset, (long)length, (long)bufObj->Length); + return; + } + + ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT); + + if (ctx->Driver.FlushMappedBufferRange) + ctx->Driver.FlushMappedBufferRange(ctx, target, offset, length, bufObj); +} + + +#if FEATURE_APPLE_object_purgeable +static GLenum +_mesa_BufferObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option) +{ + struct gl_buffer_object *bufObj; + GLenum retval; + + bufObj = _mesa_lookup_bufferobj(ctx, name); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glObjectPurgeable(name = 0x%x)", name); + return 0; + } + if (!_mesa_is_bufferobj(bufObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glObjectPurgeable(buffer 0)" ); + return 0; + } + + if (bufObj->Purgeable) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glObjectPurgeable(name = 0x%x) is already purgeable", name); + return GL_VOLATILE_APPLE; + } + + bufObj->Purgeable = GL_TRUE; + + retval = GL_VOLATILE_APPLE; + if (ctx->Driver.BufferObjectPurgeable) + retval = ctx->Driver.BufferObjectPurgeable(ctx, bufObj, option); + + return retval; +} + + +static GLenum +_mesa_RenderObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option) +{ + struct gl_renderbuffer *bufObj; + GLenum retval; + + bufObj = _mesa_lookup_renderbuffer(ctx, name); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glObjectUnpurgeable(name = 0x%x)", name); + return 0; + } + + if (bufObj->Purgeable) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glObjectPurgeable(name = 0x%x) is already purgeable", name); + return GL_VOLATILE_APPLE; + } + + bufObj->Purgeable = GL_TRUE; + + retval = GL_VOLATILE_APPLE; + if (ctx->Driver.RenderObjectPurgeable) + retval = ctx->Driver.RenderObjectPurgeable(ctx, bufObj, option); + + return retval; +} + + +static GLenum +_mesa_TextureObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option) +{ + struct gl_texture_object *bufObj; + GLenum retval; + + bufObj = _mesa_lookup_texture(ctx, name); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glObjectPurgeable(name = 0x%x)", name); + return 0; + } + + if (bufObj->Purgeable) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glObjectPurgeable(name = 0x%x) is already purgeable", name); + return GL_VOLATILE_APPLE; + } + + bufObj->Purgeable = GL_TRUE; + + retval = GL_VOLATILE_APPLE; + if (ctx->Driver.TextureObjectPurgeable) + retval = ctx->Driver.TextureObjectPurgeable(ctx, bufObj, option); + + return retval; +} + + +GLenum GLAPIENTRY +_mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option) +{ + GLenum retval; + + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); + + if (name == 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glObjectPurgeable(name = 0x%x)", name); + return 0; + } + + switch (option) { + case GL_VOLATILE_APPLE: + case GL_RELEASED_APPLE: + /* legal */ + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "glObjectPurgeable(name = 0x%x) invalid option: %d", + name, option); + return 0; + } + + switch (objectType) { + case GL_TEXTURE: + retval = _mesa_TextureObjectPurgeable (ctx, name, option); + break; + case GL_RENDERBUFFER_EXT: + retval = _mesa_RenderObjectPurgeable (ctx, name, option); + break; + case GL_BUFFER_OBJECT_APPLE: + retval = _mesa_BufferObjectPurgeable (ctx, name, option); + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "glObjectPurgeable(name = 0x%x) invalid type: %d", + name, objectType); + return 0; + } + + /* In strict conformance to the spec, we must only return VOLATILE when + * when passed the VOLATILE option. Madness. + * + * XXX First fix the spec, then fix me. + */ + return option == GL_VOLATILE_APPLE ? GL_VOLATILE_APPLE : retval; +} + + +static GLenum +_mesa_BufferObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option) +{ + struct gl_buffer_object *bufObj; + GLenum retval; + + bufObj = _mesa_lookup_bufferobj(ctx, name); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glObjectUnpurgeable(name = 0x%x)", name); + return 0; + } + + if (! bufObj->Purgeable) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glObjectUnpurgeable(name = 0x%x) object is " + " already \"unpurged\"", name); + return 0; + } + + bufObj->Purgeable = GL_FALSE; + + retval = option; + if (ctx->Driver.BufferObjectUnpurgeable) + retval = ctx->Driver.BufferObjectUnpurgeable(ctx, bufObj, option); + + return retval; +} + + +static GLenum +_mesa_RenderObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option) +{ + struct gl_renderbuffer *bufObj; + GLenum retval; + + bufObj = _mesa_lookup_renderbuffer(ctx, name); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glObjectUnpurgeable(name = 0x%x)", name); + return 0; + } + + if (! bufObj->Purgeable) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glObjectUnpurgeable(name = 0x%x) object is " + " already \"unpurged\"", name); + return 0; + } + + bufObj->Purgeable = GL_FALSE; + + retval = option; + if (ctx->Driver.RenderObjectUnpurgeable) + retval = ctx->Driver.RenderObjectUnpurgeable(ctx, bufObj, option); + + return retval; +} + + +static GLenum +_mesa_TextureObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option) +{ + struct gl_texture_object *bufObj; + GLenum retval; + + bufObj = _mesa_lookup_texture(ctx, name); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glObjectUnpurgeable(name = 0x%x)", name); + return 0; + } + + if (! bufObj->Purgeable) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glObjectUnpurgeable(name = 0x%x) object is" + " already \"unpurged\"", name); + return 0; + } + + bufObj->Purgeable = GL_FALSE; + + retval = option; + if (ctx->Driver.TextureObjectUnpurgeable) + retval = ctx->Driver.TextureObjectUnpurgeable(ctx, bufObj, option); + + return retval; +} + + +GLenum GLAPIENTRY +_mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); + + if (name == 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glObjectUnpurgeable(name = 0x%x)", name); + return 0; + } + + switch (option) { + case GL_RETAINED_APPLE: + case GL_UNDEFINED_APPLE: + /* legal */ + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "glObjectUnpurgeable(name = 0x%x) invalid option: %d", + name, option); + return 0; + } + + switch (objectType) { + case GL_BUFFER_OBJECT_APPLE: + return _mesa_BufferObjectUnpurgeable(ctx, name, option); + case GL_TEXTURE: + return _mesa_TextureObjectUnpurgeable(ctx, name, option); + case GL_RENDERBUFFER_EXT: + return _mesa_RenderObjectUnpurgeable(ctx, name, option); + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "glObjectUnpurgeable(name = 0x%x) invalid type: %d", + name, objectType); + return 0; + } +} + + +static void +_mesa_GetBufferObjectParameterivAPPLE(struct gl_context *ctx, GLuint name, + GLenum pname, GLint* params) +{ + struct gl_buffer_object *bufObj; + + bufObj = _mesa_lookup_bufferobj(ctx, name); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetObjectParameteriv(name = 0x%x) invalid object", name); + return; + } + + switch (pname) { + case GL_PURGEABLE_APPLE: + *params = bufObj->Purgeable; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", + name, pname); + break; + } +} + + +static void +_mesa_GetRenderObjectParameterivAPPLE(struct gl_context *ctx, GLuint name, + GLenum pname, GLint* params) +{ + struct gl_renderbuffer *bufObj; + + bufObj = _mesa_lookup_renderbuffer(ctx, name); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glObjectUnpurgeable(name = 0x%x)", name); + return; + } + + switch (pname) { + case GL_PURGEABLE_APPLE: + *params = bufObj->Purgeable; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", + name, pname); + break; + } +} + + +static void +_mesa_GetTextureObjectParameterivAPPLE(struct gl_context *ctx, GLuint name, + GLenum pname, GLint* params) +{ + struct gl_texture_object *bufObj; + + bufObj = _mesa_lookup_texture(ctx, name); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glObjectUnpurgeable(name = 0x%x)", name); + return; + } + + switch (pname) { + case GL_PURGEABLE_APPLE: + *params = bufObj->Purgeable; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", + name, pname); + break; + } +} + + +void GLAPIENTRY +_mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname, + GLint* params) +{ + GET_CURRENT_CONTEXT(ctx); + + if (name == 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetObjectParameteriv(name = 0x%x)", name); + return; + } + + switch (objectType) { + case GL_TEXTURE: + _mesa_GetTextureObjectParameterivAPPLE (ctx, name, pname, params); + break; + case GL_BUFFER_OBJECT_APPLE: + _mesa_GetBufferObjectParameterivAPPLE (ctx, name, pname, params); + break; + case GL_RENDERBUFFER_EXT: + _mesa_GetRenderObjectParameterivAPPLE (ctx, name, pname, params); + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetObjectParameteriv(name = 0x%x) invalid type: %d", + name, objectType); + } +} + +#endif /* FEATURE_APPLE_object_purgeable */ diff --git a/mesalib/src/mesa/main/context.c b/mesalib/src/mesa/main/context.c index e017939a4..a94231455 100644 --- a/mesalib/src/mesa/main/context.c +++ b/mesalib/src/mesa/main/context.c @@ -886,12 +886,12 @@ _mesa_alloc_dispatch_table(int size) * \param driverContext pointer to driver-specific context data */ GLboolean -_mesa_initialize_context_for_api(struct gl_context *ctx, - gl_api api, - const struct gl_config *visual, - struct gl_context *share_list, - const struct dd_function_table *driverFunctions, - void *driverContext) +_mesa_initialize_context(struct gl_context *ctx, + gl_api api, + const struct gl_config *visual, + struct gl_context *share_list, + const struct dd_function_table *driverFunctions, + void *driverContext) { struct gl_shared_state *shared; int i; @@ -1028,25 +1028,6 @@ _mesa_initialize_context_for_api(struct gl_context *ctx, } -/** - * Initialize an OpenGL context. - */ -GLboolean -_mesa_initialize_context(struct gl_context *ctx, - const struct gl_config *visual, - struct gl_context *share_list, - const struct dd_function_table *driverFunctions, - void *driverContext) -{ - return _mesa_initialize_context_for_api(ctx, - API_OPENGL, - visual, - share_list, - driverFunctions, - driverContext); -} - - /** * Allocate and initialize a struct gl_context structure. * Note that the driver needs to pass in its dd_function_table here since @@ -1063,11 +1044,11 @@ _mesa_initialize_context(struct gl_context *ctx, * \return pointer to a new __struct gl_contextRec or NULL if error. */ struct gl_context * -_mesa_create_context_for_api(gl_api api, - const struct gl_config *visual, - struct gl_context *share_list, - const struct dd_function_table *driverFunctions, - void *driverContext) +_mesa_create_context(gl_api api, + const struct gl_config *visual, + struct gl_context *share_list, + const struct dd_function_table *driverFunctions, + void *driverContext) { struct gl_context *ctx; @@ -1078,8 +1059,8 @@ _mesa_create_context_for_api(gl_api api, if (!ctx) return NULL; - if (_mesa_initialize_context_for_api(ctx, api, visual, share_list, - driverFunctions, driverContext)) { + if (_mesa_initialize_context(ctx, api, visual, share_list, + driverFunctions, driverContext)) { return ctx; } else { @@ -1089,22 +1070,6 @@ _mesa_create_context_for_api(gl_api api, } -/** - * Create an OpenGL context. - */ -struct gl_context * -_mesa_create_context(const struct gl_config *visual, - struct gl_context *share_list, - const struct dd_function_table *driverFunctions, - void *driverContext) -{ - return _mesa_create_context_for_api(API_OPENGL, visual, - share_list, - driverFunctions, - driverContext); -} - - /** * Free the data associated with the given context. * diff --git a/mesalib/src/mesa/main/context.h b/mesalib/src/mesa/main/context.h index bcadaea4f..4e391dde4 100644 --- a/mesalib/src/mesa/main/context.h +++ b/mesalib/src/mesa/main/context.h @@ -1,326 +1,313 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.1 - * - * Copyright (C) 1999-2006 Brian Paul 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 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 - * BRIAN PAUL 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. - */ - - -/** - * \file context.h - * Mesa context and visual-related functions. - * - * There are three large Mesa data types/classes which are meant to be - * used by device drivers: - * - struct gl_context: this contains the Mesa rendering state - * - struct gl_config: this describes the color buffer (RGB vs. ci), whether or not - * there's a depth buffer, stencil buffer, etc. - * - struct gl_framebuffer: contains pointers to the depth buffer, stencil buffer, - * accum buffer and alpha buffers. - * - * These types should be encapsulated by corresponding device driver - * data types. See xmesa.h and xmesaP.h for an example. - * - * In OOP terms, struct gl_context, struct gl_config, and struct gl_framebuffer are base classes - * which the device driver must derive from. - * - * The following functions create and destroy these data types. - */ - - -#ifndef CONTEXT_H -#define CONTEXT_H - - -#include "imports.h" -#include "mtypes.h" - - -struct _glapi_table; - - -/** \name Visual-related functions */ -/*@{*/ - -extern struct gl_config * -_mesa_create_visual( GLboolean dbFlag, - GLboolean stereoFlag, - GLint redBits, - GLint greenBits, - GLint blueBits, - GLint alphaBits, - GLint depthBits, - GLint stencilBits, - GLint accumRedBits, - GLint accumGreenBits, - GLint accumBlueBits, - GLint accumAlphaBits, - GLint numSamples ); - -extern GLboolean -_mesa_initialize_visual( struct gl_config *v, - GLboolean dbFlag, - GLboolean stereoFlag, - GLint redBits, - GLint greenBits, - GLint blueBits, - GLint alphaBits, - GLint depthBits, - GLint stencilBits, - GLint accumRedBits, - GLint accumGreenBits, - GLint accumBlueBits, - GLint accumAlphaBits, - GLint numSamples ); - -extern void -_mesa_destroy_visual( struct gl_config *vis ); - -/*@}*/ - - -/** \name Context-related functions */ -/*@{*/ - -extern struct gl_context * -_mesa_create_context( const struct gl_config *visual, - struct gl_context *share_list, - const struct dd_function_table *driverFunctions, - void *driverContext ); - -extern GLboolean -_mesa_initialize_context( struct gl_context *ctx, - const struct gl_config *visual, - struct gl_context *share_list, - const struct dd_function_table *driverFunctions, - void *driverContext ); - -extern struct gl_context * -_mesa_create_context_for_api(gl_api api, - const struct gl_config *visual, - struct gl_context *share_list, - const struct dd_function_table *driverFunctions, - void *driverContext); - -extern GLboolean -_mesa_initialize_context_for_api(struct gl_context *ctx, - gl_api api, - const struct gl_config *visual, - struct gl_context *share_list, - const struct dd_function_table *driverFunctions, - void *driverContext); - -extern void -_mesa_free_context_data( struct gl_context *ctx ); - -extern void -_mesa_destroy_context( struct gl_context *ctx ); - - -extern void -_mesa_copy_context(const struct gl_context *src, struct gl_context *dst, GLuint mask); - - -extern void -_mesa_check_init_viewport(struct gl_context *ctx, GLuint width, GLuint height); - -extern GLboolean -_mesa_make_current( struct gl_context *ctx, struct gl_framebuffer *drawBuffer, - struct gl_framebuffer *readBuffer ); - -extern GLboolean -_mesa_share_state(struct gl_context *ctx, struct gl_context *ctxToShare); - -extern struct gl_context * -_mesa_get_current_context(void); - -/*@}*/ - -extern void -_mesa_init_get_hash(struct gl_context *ctx); - -extern void -_mesa_notifySwapBuffers(struct gl_context *gc); - - -extern struct _glapi_table * -_mesa_get_dispatch(struct gl_context *ctx); - - -void -_mesa_set_mvp_with_dp4( struct gl_context *ctx, - GLboolean flag ); - - -extern GLboolean -_mesa_valid_to_render(struct gl_context *ctx, const char *where); - - - -/** \name Miscellaneous */ -/*@{*/ - -extern void -_mesa_record_error( struct gl_context *ctx, GLenum error ); - - -extern void -_mesa_finish(struct gl_context *ctx); - -extern void -_mesa_flush(struct gl_context *ctx); - - -extern void GLAPIENTRY -_mesa_Finish( void ); - -extern void GLAPIENTRY -_mesa_Flush( void ); - -/*@}*/ - - -/** - * \name Macros for flushing buffered rendering commands before state changes, - * checking if inside glBegin/glEnd, etc. - */ -/*@{*/ - -/** - * Flush vertices. - * - * \param ctx GL context. - * \param newstate new state. - * - * Checks if dd_function_table::NeedFlush is marked to flush stored vertices, - * and calls dd_function_table::FlushVertices if so. Marks - * __struct gl_contextRec::NewState with \p newstate. - */ -#define FLUSH_VERTICES(ctx, newstate) \ -do { \ - if (MESA_VERBOSE & VERBOSE_STATE) \ - _mesa_debug(ctx, "FLUSH_VERTICES in %s\n", MESA_FUNCTION);\ - if (ctx->Driver.NeedFlush & FLUSH_STORED_VERTICES) \ - ctx->Driver.FlushVertices(ctx, FLUSH_STORED_VERTICES); \ - ctx->NewState |= newstate; \ -} while (0) - -/** - * Flush current state. - * - * \param ctx GL context. - * \param newstate new state. - * - * Checks if dd_function_table::NeedFlush is marked to flush current state, - * and calls dd_function_table::FlushVertices if so. Marks - * __struct gl_contextRec::NewState with \p newstate. - */ -#define FLUSH_CURRENT(ctx, newstate) \ -do { \ - if (MESA_VERBOSE & VERBOSE_STATE) \ - _mesa_debug(ctx, "FLUSH_CURRENT in %s\n", MESA_FUNCTION); \ - if (ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) \ - ctx->Driver.FlushVertices(ctx, FLUSH_UPDATE_CURRENT); \ - ctx->NewState |= newstate; \ -} while (0) - -/** - * Macro to assert that the API call was made outside the - * glBegin()/glEnd() pair, with return value. - * - * \param ctx GL context. - * \param retval value to return value in case the assertion fails. - */ -#define ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, retval) \ -do { \ - if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { \ - _mesa_error(ctx, GL_INVALID_OPERATION, "Inside glBegin/glEnd"); \ - return retval; \ - } \ -} while (0) - -/** - * Macro to assert that the API call was made outside the - * glBegin()/glEnd() pair. - * - * \param ctx GL context. - */ -#define ASSERT_OUTSIDE_BEGIN_END(ctx) \ -do { \ - if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { \ - _mesa_error(ctx, GL_INVALID_OPERATION, "Inside glBegin/glEnd"); \ - return; \ - } \ -} while (0) - -/** - * Macro to assert that the API call was made outside the - * glBegin()/glEnd() pair and flush the vertices. - * - * \param ctx GL context. - */ -#define ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx) \ -do { \ - ASSERT_OUTSIDE_BEGIN_END(ctx); \ - FLUSH_VERTICES(ctx, 0); \ -} while (0) - -/** - * Macro to assert that the API call was made outside the - * glBegin()/glEnd() pair and flush the vertices, with return value. - * - * \param ctx GL context. - * \param retval value to return value in case the assertion fails. - */ -#define ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, retval) \ -do { \ - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, retval); \ - FLUSH_VERTICES(ctx, 0); \ -} while (0) - -/*@}*/ - - - -/** - * Is the secondary color needed? - */ -#define NEED_SECONDARY_COLOR(CTX) \ - (((CTX)->Light.Enabled && \ - (CTX)->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) \ - || (CTX)->Fog.ColorSumEnabled \ - || ((CTX)->VertexProgram._Current && \ - ((CTX)->VertexProgram._Current != (CTX)->VertexProgram._TnlProgram) && \ - ((CTX)->VertexProgram._Current->Base.InputsRead & VERT_BIT_COLOR1)) \ - || ((CTX)->FragmentProgram._Current && \ - ((CTX)->FragmentProgram._Current != (CTX)->FragmentProgram._TexEnvProgram) && \ - ((CTX)->FragmentProgram._Current->Base.InputsRead & FRAG_BIT_COL1)) \ - ) - - -/** - * Is RGBA LogicOp enabled? - */ -#define RGBA_LOGICOP_ENABLED(CTX) \ - ((CTX)->Color.ColorLogicOpEnabled || \ - ((CTX)->Color.BlendEnabled && (CTX)->Color.Blend[0].EquationRGB == GL_LOGIC_OP)) - - -#endif /* CONTEXT_H */ +/* + * Mesa 3-D graphics library + * Version: 6.5.1 + * + * Copyright (C) 1999-2006 Brian Paul 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 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 + * BRIAN PAUL 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. + */ + + +/** + * \file context.h + * Mesa context and visual-related functions. + * + * There are three large Mesa data types/classes which are meant to be + * used by device drivers: + * - struct gl_context: this contains the Mesa rendering state + * - struct gl_config: this describes the color buffer (RGB vs. ci), whether or not + * there's a depth buffer, stencil buffer, etc. + * - struct gl_framebuffer: contains pointers to the depth buffer, stencil buffer, + * accum buffer and alpha buffers. + * + * These types should be encapsulated by corresponding device driver + * data types. See xmesa.h and xmesaP.h for an example. + * + * In OOP terms, struct gl_context, struct gl_config, and struct gl_framebuffer are base classes + * which the device driver must derive from. + * + * The following functions create and destroy these data types. + */ + + +#ifndef CONTEXT_H +#define CONTEXT_H + + +#include "imports.h" +#include "mtypes.h" + + +struct _glapi_table; + + +/** \name Visual-related functions */ +/*@{*/ + +extern struct gl_config * +_mesa_create_visual( GLboolean dbFlag, + GLboolean stereoFlag, + GLint redBits, + GLint greenBits, + GLint blueBits, + GLint alphaBits, + GLint depthBits, + GLint stencilBits, + GLint accumRedBits, + GLint accumGreenBits, + GLint accumBlueBits, + GLint accumAlphaBits, + GLint numSamples ); + +extern GLboolean +_mesa_initialize_visual( struct gl_config *v, + GLboolean dbFlag, + GLboolean stereoFlag, + GLint redBits, + GLint greenBits, + GLint blueBits, + GLint alphaBits, + GLint depthBits, + GLint stencilBits, + GLint accumRedBits, + GLint accumGreenBits, + GLint accumBlueBits, + GLint accumAlphaBits, + GLint numSamples ); + +extern void +_mesa_destroy_visual( struct gl_config *vis ); + +/*@}*/ + + +/** \name Context-related functions */ +/*@{*/ + +extern GLboolean +_mesa_initialize_context( struct gl_context *ctx, + gl_api api, + const struct gl_config *visual, + struct gl_context *share_list, + const struct dd_function_table *driverFunctions, + void *driverContext ); + +extern struct gl_context * +_mesa_create_context(gl_api api, + const struct gl_config *visual, + struct gl_context *share_list, + const struct dd_function_table *driverFunctions, + void *driverContext); + +extern void +_mesa_free_context_data( struct gl_context *ctx ); + +extern void +_mesa_destroy_context( struct gl_context *ctx ); + + +extern void +_mesa_copy_context(const struct gl_context *src, struct gl_context *dst, GLuint mask); + + +extern void +_mesa_check_init_viewport(struct gl_context *ctx, GLuint width, GLuint height); + +extern GLboolean +_mesa_make_current( struct gl_context *ctx, struct gl_framebuffer *drawBuffer, + struct gl_framebuffer *readBuffer ); + +extern GLboolean +_mesa_share_state(struct gl_context *ctx, struct gl_context *ctxToShare); + +extern struct gl_context * +_mesa_get_current_context(void); + +/*@}*/ + +extern void +_mesa_init_get_hash(struct gl_context *ctx); + +extern void +_mesa_notifySwapBuffers(struct gl_context *gc); + + +extern struct _glapi_table * +_mesa_get_dispatch(struct gl_context *ctx); + + +void +_mesa_set_mvp_with_dp4( struct gl_context *ctx, + GLboolean flag ); + + +extern GLboolean +_mesa_valid_to_render(struct gl_context *ctx, const char *where); + + + +/** \name Miscellaneous */ +/*@{*/ + +extern void +_mesa_record_error( struct gl_context *ctx, GLenum error ); + + +extern void +_mesa_finish(struct gl_context *ctx); + +extern void +_mesa_flush(struct gl_context *ctx); + + +extern void GLAPIENTRY +_mesa_Finish( void ); + +extern void GLAPIENTRY +_mesa_Flush( void ); + +/*@}*/ + + +/** + * \name Macros for flushing buffered rendering commands before state changes, + * checking if inside glBegin/glEnd, etc. + */ +/*@{*/ + +/** + * Flush vertices. + * + * \param ctx GL context. + * \param newstate new state. + * + * Checks if dd_function_table::NeedFlush is marked to flush stored vertices, + * and calls dd_function_table::FlushVertices if so. Marks + * __struct gl_contextRec::NewState with \p newstate. + */ +#define FLUSH_VERTICES(ctx, newstate) \ +do { \ + if (MESA_VERBOSE & VERBOSE_STATE) \ + _mesa_debug(ctx, "FLUSH_VERTICES in %s\n", MESA_FUNCTION);\ + if (ctx->Driver.NeedFlush & FLUSH_STORED_VERTICES) \ + ctx->Driver.FlushVertices(ctx, FLUSH_STORED_VERTICES); \ + ctx->NewState |= newstate; \ +} while (0) + +/** + * Flush current state. + * + * \param ctx GL context. + * \param newstate new state. + * + * Checks if dd_function_table::NeedFlush is marked to flush current state, + * and calls dd_function_table::FlushVertices if so. Marks + * __struct gl_contextRec::NewState with \p newstate. + */ +#define FLUSH_CURRENT(ctx, newstate) \ +do { \ + if (MESA_VERBOSE & VERBOSE_STATE) \ + _mesa_debug(ctx, "FLUSH_CURRENT in %s\n", MESA_FUNCTION); \ + if (ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) \ + ctx->Driver.FlushVertices(ctx, FLUSH_UPDATE_CURRENT); \ + ctx->NewState |= newstate; \ +} while (0) + +/** + * Macro to assert that the API call was made outside the + * glBegin()/glEnd() pair, with return value. + * + * \param ctx GL context. + * \param retval value to return value in case the assertion fails. + */ +#define ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, retval) \ +do { \ + if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { \ + _mesa_error(ctx, GL_INVALID_OPERATION, "Inside glBegin/glEnd"); \ + return retval; \ + } \ +} while (0) + +/** + * Macro to assert that the API call was made outside the + * glBegin()/glEnd() pair. + * + * \param ctx GL context. + */ +#define ASSERT_OUTSIDE_BEGIN_END(ctx) \ +do { \ + if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { \ + _mesa_error(ctx, GL_INVALID_OPERATION, "Inside glBegin/glEnd"); \ + return; \ + } \ +} while (0) + +/** + * Macro to assert that the API call was made outside the + * glBegin()/glEnd() pair and flush the vertices. + * + * \param ctx GL context. + */ +#define ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx) \ +do { \ + ASSERT_OUTSIDE_BEGIN_END(ctx); \ + FLUSH_VERTICES(ctx, 0); \ +} while (0) + +/** + * Macro to assert that the API call was made outside the + * glBegin()/glEnd() pair and flush the vertices, with return value. + * + * \param ctx GL context. + * \param retval value to return value in case the assertion fails. + */ +#define ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, retval) \ +do { \ + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, retval); \ + FLUSH_VERTICES(ctx, 0); \ +} while (0) + +/*@}*/ + + + +/** + * Is the secondary color needed? + */ +#define NEED_SECONDARY_COLOR(CTX) \ + (((CTX)->Light.Enabled && \ + (CTX)->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) \ + || (CTX)->Fog.ColorSumEnabled \ + || ((CTX)->VertexProgram._Current && \ + ((CTX)->VertexProgram._Current != (CTX)->VertexProgram._TnlProgram) && \ + ((CTX)->VertexProgram._Current->Base.InputsRead & VERT_BIT_COLOR1)) \ + || ((CTX)->FragmentProgram._Current && \ + ((CTX)->FragmentProgram._Current != (CTX)->FragmentProgram._TexEnvProgram) && \ + ((CTX)->FragmentProgram._Current->Base.InputsRead & FRAG_BIT_COL1)) \ + ) + + +/** + * Is RGBA LogicOp enabled? + */ +#define RGBA_LOGICOP_ENABLED(CTX) \ + ((CTX)->Color.ColorLogicOpEnabled || \ + ((CTX)->Color.BlendEnabled && (CTX)->Color.Blend[0].EquationRGB == GL_LOGIC_OP)) + + +#endif /* CONTEXT_H */ diff --git a/mesalib/src/mesa/main/depth.c b/mesalib/src/mesa/main/depth.c index fe1380e71..52c69a6bc 100644 --- a/mesalib/src/mesa/main/depth.c +++ b/mesalib/src/mesa/main/depth.c @@ -1,168 +1,174 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 1999-2007 Brian Paul 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 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 - * BRIAN PAUL 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. - */ - - -#include "glheader.h" -#include "imports.h" -#include "context.h" -#include "depth.h" -#include "enums.h" -#include "macros.h" -#include "mtypes.h" - - -/**********************************************************************/ -/***** API Functions *****/ -/**********************************************************************/ - - - -void GLAPIENTRY -_mesa_ClearDepth( GLclampd depth ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - depth = CLAMP( depth, 0.0, 1.0 ); - - if (ctx->Depth.Clear == depth) - return; - - FLUSH_VERTICES(ctx, _NEW_DEPTH); - ctx->Depth.Clear = depth; - if (ctx->Driver.ClearDepth) - (*ctx->Driver.ClearDepth)( ctx, ctx->Depth.Clear ); -} - - -void GLAPIENTRY -_mesa_ClearDepthf( GLclampf depth ) -{ - _mesa_ClearDepth(depth); -} - - -void GLAPIENTRY -_mesa_DepthFunc( GLenum func ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glDepthFunc %s\n", _mesa_lookup_enum_by_nr(func)); - - switch (func) { - case GL_LESS: /* (default) pass if incoming z < stored z */ - case GL_GEQUAL: - case GL_LEQUAL: - case GL_GREATER: - case GL_NOTEQUAL: - case GL_EQUAL: - case GL_ALWAYS: - case GL_NEVER: - break; - default: - _mesa_error( ctx, GL_INVALID_ENUM, "glDepth.Func" ); - return; - } - - if (ctx->Depth.Func == func) - return; - - FLUSH_VERTICES(ctx, _NEW_DEPTH); - ctx->Depth.Func = func; - - if (ctx->Driver.DepthFunc) - ctx->Driver.DepthFunc( ctx, func ); -} - - - -void GLAPIENTRY -_mesa_DepthMask( GLboolean flag ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glDepthMask %d\n", flag); - - /* - * GL_TRUE indicates depth buffer writing is enabled (default) - * GL_FALSE indicates depth buffer writing is disabled - */ - if (ctx->Depth.Mask == flag) - return; - - FLUSH_VERTICES(ctx, _NEW_DEPTH); - ctx->Depth.Mask = flag; - - if (ctx->Driver.DepthMask) - ctx->Driver.DepthMask( ctx, flag ); -} - - - -/** - * Specified by the GL_EXT_depth_bounds_test extension. - */ -void GLAPIENTRY -_mesa_DepthBoundsEXT( GLclampd zmin, GLclampd zmax ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (zmin > zmax) { - _mesa_error(ctx, GL_INVALID_VALUE, "glDepthBoundsEXT(zmin > zmax)"); - return; - } - - zmin = CLAMP(zmin, 0.0, 1.0); - zmax = CLAMP(zmax, 0.0, 1.0); - - if (ctx->Depth.BoundsMin == zmin && ctx->Depth.BoundsMax == zmax) - return; - - FLUSH_VERTICES(ctx, _NEW_DEPTH); - ctx->Depth.BoundsMin = (GLfloat) zmin; - ctx->Depth.BoundsMax = (GLfloat) zmax; -} - - -/**********************************************************************/ -/***** Initialization *****/ -/**********************************************************************/ - - -/** - * Initialize the depth buffer attribute group in the given context. - */ -void -_mesa_init_depth(struct gl_context *ctx) -{ - ctx->Depth.Test = GL_FALSE; - ctx->Depth.Clear = 1.0; - ctx->Depth.Func = GL_LESS; - ctx->Depth.Mask = GL_TRUE; -} +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2007 Brian Paul 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 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 + * BRIAN PAUL 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. + */ + + +#include "glheader.h" +#include "imports.h" +#include "context.h" +#include "depth.h" +#include "enums.h" +#include "macros.h" +#include "mtypes.h" + + +/**********************************************************************/ +/***** API Functions *****/ +/**********************************************************************/ + + + +void GLAPIENTRY +_mesa_ClearDepth( GLclampd depth ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glClearDepth(%f)\n", depth); + + depth = CLAMP( depth, 0.0, 1.0 ); + + if (ctx->Depth.Clear == depth) + return; + + FLUSH_VERTICES(ctx, _NEW_DEPTH); + ctx->Depth.Clear = depth; + if (ctx->Driver.ClearDepth) + (*ctx->Driver.ClearDepth)( ctx, ctx->Depth.Clear ); +} + + +void GLAPIENTRY +_mesa_ClearDepthf( GLclampf depth ) +{ + _mesa_ClearDepth(depth); +} + + +void GLAPIENTRY +_mesa_DepthFunc( GLenum func ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glDepthFunc %s\n", _mesa_lookup_enum_by_nr(func)); + + switch (func) { + case GL_LESS: /* (default) pass if incoming z < stored z */ + case GL_GEQUAL: + case GL_LEQUAL: + case GL_GREATER: + case GL_NOTEQUAL: + case GL_EQUAL: + case GL_ALWAYS: + case GL_NEVER: + break; + default: + _mesa_error( ctx, GL_INVALID_ENUM, "glDepth.Func" ); + return; + } + + if (ctx->Depth.Func == func) + return; + + FLUSH_VERTICES(ctx, _NEW_DEPTH); + ctx->Depth.Func = func; + + if (ctx->Driver.DepthFunc) + ctx->Driver.DepthFunc( ctx, func ); +} + + + +void GLAPIENTRY +_mesa_DepthMask( GLboolean flag ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glDepthMask %d\n", flag); + + /* + * GL_TRUE indicates depth buffer writing is enabled (default) + * GL_FALSE indicates depth buffer writing is disabled + */ + if (ctx->Depth.Mask == flag) + return; + + FLUSH_VERTICES(ctx, _NEW_DEPTH); + ctx->Depth.Mask = flag; + + if (ctx->Driver.DepthMask) + ctx->Driver.DepthMask( ctx, flag ); +} + + + +/** + * Specified by the GL_EXT_depth_bounds_test extension. + */ +void GLAPIENTRY +_mesa_DepthBoundsEXT( GLclampd zmin, GLclampd zmax ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glDepthBounds(%f, %f)\n", zmin, zmax); + + if (zmin > zmax) { + _mesa_error(ctx, GL_INVALID_VALUE, "glDepthBoundsEXT(zmin > zmax)"); + return; + } + + zmin = CLAMP(zmin, 0.0, 1.0); + zmax = CLAMP(zmax, 0.0, 1.0); + + if (ctx->Depth.BoundsMin == zmin && ctx->Depth.BoundsMax == zmax) + return; + + FLUSH_VERTICES(ctx, _NEW_DEPTH); + ctx->Depth.BoundsMin = (GLfloat) zmin; + ctx->Depth.BoundsMax = (GLfloat) zmax; +} + + +/**********************************************************************/ +/***** Initialization *****/ +/**********************************************************************/ + + +/** + * Initialize the depth buffer attribute group in the given context. + */ +void +_mesa_init_depth(struct gl_context *ctx) +{ + ctx->Depth.Test = GL_FALSE; + ctx->Depth.Clear = 1.0; + ctx->Depth.Func = GL_LESS; + ctx->Depth.Mask = GL_TRUE; +} diff --git a/mesalib/src/mesa/main/hint.c b/mesalib/src/mesa/main/hint.c index 96f5f4d6b..ff8d88fff 100644 --- a/mesalib/src/mesa/main/hint.c +++ b/mesalib/src/mesa/main/hint.c @@ -1,146 +1,147 @@ - -/* - * Mesa 3-D graphics library - * Version: 4.1 - * - * Copyright (C) 1999-2002 Brian Paul 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 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 - * BRIAN PAUL 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. - */ - - -#include "glheader.h" -#include "enums.h" -#include "context.h" -#include "hint.h" -#include "imports.h" -#include "mtypes.h" - - - -void GLAPIENTRY -_mesa_Hint( GLenum target, GLenum mode ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glHint %s %d\n", - _mesa_lookup_enum_by_nr(target), mode); - - if (mode != GL_NICEST && mode != GL_FASTEST && mode != GL_DONT_CARE) { - _mesa_error(ctx, GL_INVALID_ENUM, "glHint(mode)"); - return; - } - - switch (target) { - case GL_FOG_HINT: - if (ctx->Hint.Fog == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.Fog = mode; - break; - case GL_LINE_SMOOTH_HINT: - if (ctx->Hint.LineSmooth == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.LineSmooth = mode; - break; - case GL_PERSPECTIVE_CORRECTION_HINT: - if (ctx->Hint.PerspectiveCorrection == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.PerspectiveCorrection = mode; - break; - case GL_POINT_SMOOTH_HINT: - if (ctx->Hint.PointSmooth == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.PointSmooth = mode; - break; - case GL_POLYGON_SMOOTH_HINT: - if (ctx->Hint.PolygonSmooth == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.PolygonSmooth = mode; - break; - - /* GL_EXT_clip_volume_hint */ - case GL_CLIP_VOLUME_CLIPPING_HINT_EXT: - if (ctx->Hint.ClipVolumeClipping == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.ClipVolumeClipping = mode; - break; - - /* GL_ARB_texture_compression */ - case GL_TEXTURE_COMPRESSION_HINT_ARB: - if (ctx->Hint.TextureCompression == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.TextureCompression = mode; - break; - - /* GL_SGIS_generate_mipmap */ - case GL_GENERATE_MIPMAP_HINT_SGIS: - if (ctx->Hint.GenerateMipmap == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.GenerateMipmap = mode; - break; - - /* GL_ARB_fragment_shader */ - case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB: - if (!ctx->Extensions.ARB_fragment_shader) { - _mesa_error(ctx, GL_INVALID_ENUM, "glHint(target)"); - return; - } - if (ctx->Hint.FragmentShaderDerivative == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.FragmentShaderDerivative = mode; - break; - - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glHint(target)"); - return; - } - - if (ctx->Driver.Hint) { - (*ctx->Driver.Hint)( ctx, target, mode ); - } -} - - -/**********************************************************************/ -/***** Initialization *****/ -/**********************************************************************/ - -void _mesa_init_hint( struct gl_context * ctx ) -{ - /* Hint group */ - ctx->Hint.PerspectiveCorrection = GL_DONT_CARE; - ctx->Hint.PointSmooth = GL_DONT_CARE; - ctx->Hint.LineSmooth = GL_DONT_CARE; - ctx->Hint.PolygonSmooth = GL_DONT_CARE; - ctx->Hint.Fog = GL_DONT_CARE; - ctx->Hint.ClipVolumeClipping = GL_DONT_CARE; - ctx->Hint.TextureCompression = GL_DONT_CARE; - ctx->Hint.GenerateMipmap = GL_DONT_CARE; - ctx->Hint.FragmentShaderDerivative = GL_DONT_CARE; -} + +/* + * Mesa 3-D graphics library + * Version: 4.1 + * + * Copyright (C) 1999-2002 Brian Paul 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 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 + * BRIAN PAUL 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. + */ + + +#include "glheader.h" +#include "enums.h" +#include "context.h" +#include "hint.h" +#include "imports.h" +#include "mtypes.h" + + + +void GLAPIENTRY +_mesa_Hint( GLenum target, GLenum mode ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glHint %s %s\n", + _mesa_lookup_enum_by_nr(target), + _mesa_lookup_enum_by_nr(mode)); + + if (mode != GL_NICEST && mode != GL_FASTEST && mode != GL_DONT_CARE) { + _mesa_error(ctx, GL_INVALID_ENUM, "glHint(mode)"); + return; + } + + switch (target) { + case GL_FOG_HINT: + if (ctx->Hint.Fog == mode) + return; + FLUSH_VERTICES(ctx, _NEW_HINT); + ctx->Hint.Fog = mode; + break; + case GL_LINE_SMOOTH_HINT: + if (ctx->Hint.LineSmooth == mode) + return; + FLUSH_VERTICES(ctx, _NEW_HINT); + ctx->Hint.LineSmooth = mode; + break; + case GL_PERSPECTIVE_CORRECTION_HINT: + if (ctx->Hint.PerspectiveCorrection == mode) + return; + FLUSH_VERTICES(ctx, _NEW_HINT); + ctx->Hint.PerspectiveCorrection = mode; + break; + case GL_POINT_SMOOTH_HINT: + if (ctx->Hint.PointSmooth == mode) + return; + FLUSH_VERTICES(ctx, _NEW_HINT); + ctx->Hint.PointSmooth = mode; + break; + case GL_POLYGON_SMOOTH_HINT: + if (ctx->Hint.PolygonSmooth == mode) + return; + FLUSH_VERTICES(ctx, _NEW_HINT); + ctx->Hint.PolygonSmooth = mode; + break; + + /* GL_EXT_clip_volume_hint */ + case GL_CLIP_VOLUME_CLIPPING_HINT_EXT: + if (ctx->Hint.ClipVolumeClipping == mode) + return; + FLUSH_VERTICES(ctx, _NEW_HINT); + ctx->Hint.ClipVolumeClipping = mode; + break; + + /* GL_ARB_texture_compression */ + case GL_TEXTURE_COMPRESSION_HINT_ARB: + if (ctx->Hint.TextureCompression == mode) + return; + FLUSH_VERTICES(ctx, _NEW_HINT); + ctx->Hint.TextureCompression = mode; + break; + + /* GL_SGIS_generate_mipmap */ + case GL_GENERATE_MIPMAP_HINT_SGIS: + if (ctx->Hint.GenerateMipmap == mode) + return; + FLUSH_VERTICES(ctx, _NEW_HINT); + ctx->Hint.GenerateMipmap = mode; + break; + + /* GL_ARB_fragment_shader */ + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB: + if (!ctx->Extensions.ARB_fragment_shader) { + _mesa_error(ctx, GL_INVALID_ENUM, "glHint(target)"); + return; + } + if (ctx->Hint.FragmentShaderDerivative == mode) + return; + FLUSH_VERTICES(ctx, _NEW_HINT); + ctx->Hint.FragmentShaderDerivative = mode; + break; + + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glHint(target)"); + return; + } + + if (ctx->Driver.Hint) { + (*ctx->Driver.Hint)( ctx, target, mode ); + } +} + + +/**********************************************************************/ +/***** Initialization *****/ +/**********************************************************************/ + +void _mesa_init_hint( struct gl_context * ctx ) +{ + /* Hint group */ + ctx->Hint.PerspectiveCorrection = GL_DONT_CARE; + ctx->Hint.PointSmooth = GL_DONT_CARE; + ctx->Hint.LineSmooth = GL_DONT_CARE; + ctx->Hint.PolygonSmooth = GL_DONT_CARE; + ctx->Hint.Fog = GL_DONT_CARE; + ctx->Hint.ClipVolumeClipping = GL_DONT_CARE; + ctx->Hint.TextureCompression = GL_DONT_CARE; + ctx->Hint.GenerateMipmap = GL_DONT_CARE; + ctx->Hint.FragmentShaderDerivative = GL_DONT_CARE; +} diff --git a/mesalib/src/mesa/main/lines.c b/mesalib/src/mesa/main/lines.c index 79385cd75..79bf5679d 100644 --- a/mesalib/src/mesa/main/lines.c +++ b/mesalib/src/mesa/main/lines.c @@ -1,111 +1,117 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 1999-2006 Brian Paul 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 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 - * BRIAN PAUL 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. - */ - - -#include "glheader.h" -#include "context.h" -#include "lines.h" -#include "macros.h" -#include "mtypes.h" - - -/** - * Set the line width. - * - * \param width line width in pixels. - * - * \sa glLineWidth(). - */ -void GLAPIENTRY -_mesa_LineWidth( GLfloat width ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (width<=0.0) { - _mesa_error( ctx, GL_INVALID_VALUE, "glLineWidth" ); - return; - } - - if (ctx->Line.Width == width) - return; - - FLUSH_VERTICES(ctx, _NEW_LINE); - ctx->Line.Width = width; - - if (ctx->Driver.LineWidth) - ctx->Driver.LineWidth(ctx, width); -} - - -/** - * Set the line stipple pattern. - * - * \param factor pattern scale factor. - * \param pattern bit pattern. - * - * \sa glLineStipple(). - * - * Updates gl_line_attrib::StippleFactor and gl_line_attrib::StipplePattern. On - * change flushes the vertices and notifies the driver via - * the dd_function_table::LineStipple callback. - */ -void GLAPIENTRY -_mesa_LineStipple( GLint factor, GLushort pattern ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - factor = CLAMP( factor, 1, 256 ); - - if (ctx->Line.StippleFactor == factor && - ctx->Line.StipplePattern == pattern) - return; - - FLUSH_VERTICES(ctx, _NEW_LINE); - ctx->Line.StippleFactor = factor; - ctx->Line.StipplePattern = pattern; - - if (ctx->Driver.LineStipple) - ctx->Driver.LineStipple( ctx, factor, pattern ); -} - - -/** - * Initialize the context line state. - * - * \param ctx GL context. - * - * Initializes __struct gl_contextRec::Line and line related constants in - * __struct gl_contextRec::Const. - */ -void GLAPIENTRY -_mesa_init_line( struct gl_context * ctx ) -{ - ctx->Line.SmoothFlag = GL_FALSE; - ctx->Line.StippleFlag = GL_FALSE; - ctx->Line.Width = 1.0; - ctx->Line.StipplePattern = 0xffff; - ctx->Line.StippleFactor = 1; -} +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 1999-2006 Brian Paul 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 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 + * BRIAN PAUL 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. + */ + + +#include "glheader.h" +#include "context.h" +#include "lines.h" +#include "macros.h" +#include "mtypes.h" + + +/** + * Set the line width. + * + * \param width line width in pixels. + * + * \sa glLineWidth(). + */ +void GLAPIENTRY +_mesa_LineWidth( GLfloat width ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glLineWidth %f\n", width); + + if (width<=0.0) { + _mesa_error( ctx, GL_INVALID_VALUE, "glLineWidth" ); + return; + } + + if (ctx->Line.Width == width) + return; + + FLUSH_VERTICES(ctx, _NEW_LINE); + ctx->Line.Width = width; + + if (ctx->Driver.LineWidth) + ctx->Driver.LineWidth(ctx, width); +} + + +/** + * Set the line stipple pattern. + * + * \param factor pattern scale factor. + * \param pattern bit pattern. + * + * \sa glLineStipple(). + * + * Updates gl_line_attrib::StippleFactor and gl_line_attrib::StipplePattern. On + * change flushes the vertices and notifies the driver via + * the dd_function_table::LineStipple callback. + */ +void GLAPIENTRY +_mesa_LineStipple( GLint factor, GLushort pattern ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glLineStipple %d %u\n", factor, pattern); + + factor = CLAMP( factor, 1, 256 ); + + if (ctx->Line.StippleFactor == factor && + ctx->Line.StipplePattern == pattern) + return; + + FLUSH_VERTICES(ctx, _NEW_LINE); + ctx->Line.StippleFactor = factor; + ctx->Line.StipplePattern = pattern; + + if (ctx->Driver.LineStipple) + ctx->Driver.LineStipple( ctx, factor, pattern ); +} + + +/** + * Initialize the context line state. + * + * \param ctx GL context. + * + * Initializes __struct gl_contextRec::Line and line related constants in + * __struct gl_contextRec::Const. + */ +void GLAPIENTRY +_mesa_init_line( struct gl_context * ctx ) +{ + ctx->Line.SmoothFlag = GL_FALSE; + ctx->Line.StippleFlag = GL_FALSE; + ctx->Line.Width = 1.0; + ctx->Line.StipplePattern = 0xffff; + ctx->Line.StippleFactor = 1; +} diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h index 4e7621239..6f0aac6ee 100644 --- a/mesalib/src/mesa/main/mtypes.h +++ b/mesalib/src/mesa/main/mtypes.h @@ -84,23 +84,8 @@ /*@{*/ typedef GLuint64 GLbitfield64; -#define BITFIELD64_ONE 1ULL -#define BITFIELD64_ALLONES ~0ULL - /** Set a single bit */ -#define BITFIELD64_BIT(b) (BITFIELD64_ONE << (b)) - -/** Set a mask of the least significant \c b bits */ -#define BITFIELD64_MASK(b) (((b) >= 64) ? BITFIELD64_ALLONES : \ - (BITFIELD64_BIT(b) - 1)) - -/** - * Set all bits from l (low bit) to h (high bit), inclusive. - * - * \note \C BITFIELD_64_RANGE(0, 63) return 64 set bits. - */ -#define BITFIELD64_RANGE(l, h) (BITFIELD64_MASK((h) + 1) & ~BITFIELD64_MASK(l)) -/*@}*/ +#define BITFIELD64_BIT(b) (1ULL << (b)) /** diff --git a/mesalib/src/mesa/main/queryobj.c b/mesalib/src/mesa/main/queryobj.c index 1c45c38b9..fa35c6ce5 100644 --- a/mesalib/src/mesa/main/queryobj.c +++ b/mesalib/src/mesa/main/queryobj.c @@ -1,585 +1,623 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 1999-2007 Brian Paul 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 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 - * BRIAN PAUL 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. - */ - - -#include "glheader.h" -#include "context.h" -#include "hash.h" -#include "imports.h" -#include "queryobj.h" -#include "mfeatures.h" -#include "mtypes.h" -#include "main/dispatch.h" - - -#if FEATURE_queryobj - - -/** - * Allocate a new query object. This is a fallback routine called via - * ctx->Driver.NewQueryObject(). - * \param ctx - rendering context - * \param id - the new object's ID - * \return pointer to new query_object object or NULL if out of memory. - */ -static struct gl_query_object * -_mesa_new_query_object(struct gl_context *ctx, GLuint id) -{ - struct gl_query_object *q = MALLOC_STRUCT(gl_query_object); - (void) ctx; - if (q) { - q->Id = id; - q->Result = 0; - q->Active = GL_FALSE; - q->Ready = GL_TRUE; /* correct, see spec */ - } - return q; -} - - -/** - * Begin a query. Software driver fallback. - * Called via ctx->Driver.BeginQuery(). - */ -static void -_mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q) -{ - /* no-op */ -} - - -/** - * End a query. Software driver fallback. - * Called via ctx->Driver.EndQuery(). - */ -static void -_mesa_end_query(struct gl_context *ctx, struct gl_query_object *q) -{ - q->Ready = GL_TRUE; -} - - -/** - * Wait for query to complete. Software driver fallback. - * Called via ctx->Driver.WaitQuery(). - */ -static void -_mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q) -{ - /* For software drivers, _mesa_end_query() should have completed the query. - * For real hardware, implement a proper WaitQuery() driver function, - * which may require issuing a flush. - */ - assert(q->Ready); -} - - -/** - * Check if a query results are ready. Software driver fallback. - * Called via ctx->Driver.CheckQuery(). - */ -static void -_mesa_check_query(struct gl_context *ctx, struct gl_query_object *q) -{ - /* No-op for sw rendering. - * HW drivers may need to flush at this time. - */ -} - - -/** - * Delete a query object. Called via ctx->Driver.DeleteQuery(). - * Not removed from hash table here. - */ -static void -_mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q) -{ - free(q); -} - - -void -_mesa_init_query_object_functions(struct dd_function_table *driver) -{ - driver->NewQueryObject = _mesa_new_query_object; - driver->DeleteQuery = _mesa_delete_query; - driver->BeginQuery = _mesa_begin_query; - driver->EndQuery = _mesa_end_query; - driver->WaitQuery = _mesa_wait_query; - driver->CheckQuery = _mesa_check_query; -} - - -/** - * Return pointer to the query object binding point for the given target. - * \return NULL if invalid target, else the address of binding point - */ -static struct gl_query_object ** -get_query_binding_point(struct gl_context *ctx, GLenum target) -{ - switch (target) { - case GL_SAMPLES_PASSED_ARB: - if (ctx->Extensions.ARB_occlusion_query) - return &ctx->Query.CurrentOcclusionObject; - else - return NULL; - case GL_ANY_SAMPLES_PASSED: - if (ctx->Extensions.ARB_occlusion_query2) - return &ctx->Query.CurrentOcclusionObject; - else - return NULL; - case GL_TIME_ELAPSED_EXT: - if (ctx->Extensions.EXT_timer_query) - return &ctx->Query.CurrentTimerObject; - else - return NULL; -#if FEATURE_EXT_transform_feedback - case GL_PRIMITIVES_GENERATED: - if (ctx->Extensions.EXT_transform_feedback) - return &ctx->Query.PrimitivesGenerated; - else - return NULL; - case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: - if (ctx->Extensions.EXT_transform_feedback) - return &ctx->Query.PrimitivesWritten; - else - return NULL; -#endif - default: - return NULL; - } -} - - -void GLAPIENTRY -_mesa_GenQueriesARB(GLsizei n, GLuint *ids) -{ - GLuint first; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)"); - return; - } - - /* No query objects can be active at this time! */ - if (ctx->Query.CurrentOcclusionObject || - ctx->Query.CurrentTimerObject) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGenQueriesARB"); - return; - } - - first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n); - if (first) { - GLsizei i; - for (i = 0; i < n; i++) { - struct gl_query_object *q - = ctx->Driver.NewQueryObject(ctx, first + i); - if (!q) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB"); - return; - } - ids[i] = first + i; - _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q); - } - } -} - - -void GLAPIENTRY -_mesa_DeleteQueriesARB(GLsizei n, const GLuint *ids) -{ - GLint i; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)"); - return; - } - - /* No query objects can be active at this time! */ - if (ctx->Query.CurrentOcclusionObject || - ctx->Query.CurrentTimerObject) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteQueriesARB"); - return; - } - - for (i = 0; i < n; i++) { - if (ids[i] > 0) { - struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]); - if (q) { - ASSERT(!q->Active); /* should be caught earlier */ - _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]); - ctx->Driver.DeleteQuery(ctx, q); - } - } - } -} - - -GLboolean GLAPIENTRY -_mesa_IsQueryARB(GLuint id) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); - - if (id && _mesa_lookup_query_object(ctx, id)) - return GL_TRUE; - else - return GL_FALSE; -} - - -static void GLAPIENTRY -_mesa_BeginQueryARB(GLenum target, GLuint id) -{ - struct gl_query_object *q, **bindpt; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - FLUSH_VERTICES(ctx, _NEW_DEPTH); - - bindpt = get_query_binding_point(ctx, target); - if (!bindpt) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)"); - return; - } - - if (id == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB(id==0)"); - return; - } - - q = _mesa_lookup_query_object(ctx, id); - if (!q) { - /* create new object */ - q = ctx->Driver.NewQueryObject(ctx, id); - if (!q) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQueryARB"); - return; - } - _mesa_HashInsert(ctx->Query.QueryObjects, id, q); - } - else { - /* pre-existing object */ - if (q->Active) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBeginQueryARB(query already active)"); - return; - } - } - - q->Target = target; - q->Active = GL_TRUE; - q->Result = 0; - q->Ready = GL_FALSE; - - /* XXX should probably refcount query objects */ - *bindpt = q; - - ctx->Driver.BeginQuery(ctx, q); -} - - -static void GLAPIENTRY -_mesa_EndQueryARB(GLenum target) -{ - struct gl_query_object *q, **bindpt; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - FLUSH_VERTICES(ctx, _NEW_DEPTH); - - bindpt = get_query_binding_point(ctx, target); - if (!bindpt) { - _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)"); - return; - } - - /* XXX should probably refcount query objects */ - q = *bindpt; - *bindpt = NULL; - - if (!q || !q->Active) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glEndQueryARB(no matching glBeginQueryARB)"); - return; - } - - q->Active = GL_FALSE; - ctx->Driver.EndQuery(ctx, q); -} - - -void GLAPIENTRY -_mesa_GetQueryivARB(GLenum target, GLenum pname, GLint *params) -{ - struct gl_query_object *q, **bindpt; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - bindpt = get_query_binding_point(ctx, target); - if (!bindpt) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)"); - return; - } - - q = *bindpt; - - switch (pname) { - case GL_QUERY_COUNTER_BITS_ARB: - *params = 8 * sizeof(q->Result); - break; - case GL_CURRENT_QUERY_ARB: - *params = q ? q->Id : 0; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivARB(pname)"); - return; - } -} - - -void GLAPIENTRY -_mesa_GetQueryObjectivARB(GLuint id, GLenum pname, GLint *params) -{ - struct gl_query_object *q = NULL; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (id) - q = _mesa_lookup_query_object(ctx, id); - - if (!q || q->Active) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetQueryObjectivARB(id=%d is invalid or active)", id); - return; - } - - switch (pname) { - case GL_QUERY_RESULT_ARB: - if (!q->Ready) - ctx->Driver.WaitQuery(ctx, q); - /* if result is too large for returned type, clamp to max value */ - if (q->Target == GL_ANY_SAMPLES_PASSED) { - if (q->Result) - *params = GL_TRUE; - else - *params = GL_FALSE; - } else { - if (q->Result > 0x7fffffff) { - *params = 0x7fffffff; - } - else { - *params = (GLint)q->Result; - } - } - break; - case GL_QUERY_RESULT_AVAILABLE_ARB: - if (!q->Ready) - ctx->Driver.CheckQuery( ctx, q ); - *params = q->Ready; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)"); - return; - } -} - - -void GLAPIENTRY -_mesa_GetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params) -{ - struct gl_query_object *q = NULL; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (id) - q = _mesa_lookup_query_object(ctx, id); - - if (!q || q->Active) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetQueryObjectuivARB(id=%d is invalid or active)", id); - return; - } - - switch (pname) { - case GL_QUERY_RESULT_ARB: - if (!q->Ready) - ctx->Driver.WaitQuery(ctx, q); - /* if result is too large for returned type, clamp to max value */ - if (q->Target == GL_ANY_SAMPLES_PASSED) { - if (q->Result) - *params = GL_TRUE; - else - *params = GL_FALSE; - } else { - if (q->Result > 0xffffffff) { - *params = 0xffffffff; - } - else { - *params = (GLuint)q->Result; - } - } - break; - case GL_QUERY_RESULT_AVAILABLE_ARB: - if (!q->Ready) - ctx->Driver.CheckQuery( ctx, q ); - *params = q->Ready; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)"); - return; - } -} - - -/** - * New with GL_EXT_timer_query - */ -static void GLAPIENTRY -_mesa_GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64EXT *params) -{ - struct gl_query_object *q = NULL; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (id) - q = _mesa_lookup_query_object(ctx, id); - - if (!q || q->Active) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetQueryObjectui64vARB(id=%d is invalid or active)", id); - return; - } - - switch (pname) { - case GL_QUERY_RESULT_ARB: - if (!q->Ready) - ctx->Driver.WaitQuery(ctx, q); - *params = q->Result; - break; - case GL_QUERY_RESULT_AVAILABLE_ARB: - if (!q->Ready) - ctx->Driver.CheckQuery( ctx, q ); - *params = q->Ready; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)"); - return; - } -} - - -/** - * New with GL_EXT_timer_query - */ -static void GLAPIENTRY -_mesa_GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params) -{ - struct gl_query_object *q = NULL; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (id) - q = _mesa_lookup_query_object(ctx, id); - - if (!q || q->Active) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id); - return; - } - - switch (pname) { - case GL_QUERY_RESULT_ARB: - if (!q->Ready) - ctx->Driver.WaitQuery(ctx, q); - *params = q->Result; - break; - case GL_QUERY_RESULT_AVAILABLE_ARB: - if (!q->Ready) - ctx->Driver.CheckQuery( ctx, q ); - *params = q->Ready; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)"); - return; - } -} - - -void -_mesa_init_queryobj_dispatch(struct _glapi_table *disp) -{ - SET_GenQueriesARB(disp, _mesa_GenQueriesARB); - SET_DeleteQueriesARB(disp, _mesa_DeleteQueriesARB); - SET_IsQueryARB(disp, _mesa_IsQueryARB); - SET_BeginQueryARB(disp, _mesa_BeginQueryARB); - SET_EndQueryARB(disp, _mesa_EndQueryARB); - SET_GetQueryivARB(disp, _mesa_GetQueryivARB); - SET_GetQueryObjectivARB(disp, _mesa_GetQueryObjectivARB); - SET_GetQueryObjectuivARB(disp, _mesa_GetQueryObjectuivARB); - - SET_GetQueryObjecti64vEXT(disp, _mesa_GetQueryObjecti64vEXT); - SET_GetQueryObjectui64vEXT(disp, _mesa_GetQueryObjectui64vEXT); -} - - -#endif /* FEATURE_queryobj */ - - -/** - * Allocate/init the context state related to query objects. - */ -void -_mesa_init_queryobj(struct gl_context *ctx) -{ - ctx->Query.QueryObjects = _mesa_NewHashTable(); - ctx->Query.CurrentOcclusionObject = NULL; -} - - -/** - * Callback for deleting a query object. Called by _mesa_HashDeleteAll(). - */ -static void -delete_queryobj_cb(GLuint id, void *data, void *userData) -{ - struct gl_query_object *q= (struct gl_query_object *) data; - struct gl_context *ctx = (struct gl_context *)userData; - ctx->Driver.DeleteQuery(ctx, q); -} - - -/** - * Free the context state related to query objects. - */ -void -_mesa_free_queryobj_data(struct gl_context *ctx) -{ - _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx); - _mesa_DeleteHashTable(ctx->Query.QueryObjects); -} +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2007 Brian Paul 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 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 + * BRIAN PAUL 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. + */ + + +#include "glheader.h" +#include "context.h" +#include "enums.h" +#include "hash.h" +#include "imports.h" +#include "queryobj.h" +#include "mfeatures.h" +#include "mtypes.h" +#include "main/dispatch.h" + + +#if FEATURE_queryobj + + +/** + * Allocate a new query object. This is a fallback routine called via + * ctx->Driver.NewQueryObject(). + * \param ctx - rendering context + * \param id - the new object's ID + * \return pointer to new query_object object or NULL if out of memory. + */ +static struct gl_query_object * +_mesa_new_query_object(struct gl_context *ctx, GLuint id) +{ + struct gl_query_object *q = MALLOC_STRUCT(gl_query_object); + (void) ctx; + if (q) { + q->Id = id; + q->Result = 0; + q->Active = GL_FALSE; + q->Ready = GL_TRUE; /* correct, see spec */ + } + return q; +} + + +/** + * Begin a query. Software driver fallback. + * Called via ctx->Driver.BeginQuery(). + */ +static void +_mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q) +{ + /* no-op */ +} + + +/** + * End a query. Software driver fallback. + * Called via ctx->Driver.EndQuery(). + */ +static void +_mesa_end_query(struct gl_context *ctx, struct gl_query_object *q) +{ + q->Ready = GL_TRUE; +} + + +/** + * Wait for query to complete. Software driver fallback. + * Called via ctx->Driver.WaitQuery(). + */ +static void +_mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q) +{ + /* For software drivers, _mesa_end_query() should have completed the query. + * For real hardware, implement a proper WaitQuery() driver function, + * which may require issuing a flush. + */ + assert(q->Ready); +} + + +/** + * Check if a query results are ready. Software driver fallback. + * Called via ctx->Driver.CheckQuery(). + */ +static void +_mesa_check_query(struct gl_context *ctx, struct gl_query_object *q) +{ + /* No-op for sw rendering. + * HW drivers may need to flush at this time. + */ +} + + +/** + * Delete a query object. Called via ctx->Driver.DeleteQuery(). + * Not removed from hash table here. + */ +static void +_mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q) +{ + free(q); +} + + +void +_mesa_init_query_object_functions(struct dd_function_table *driver) +{ + driver->NewQueryObject = _mesa_new_query_object; + driver->DeleteQuery = _mesa_delete_query; + driver->BeginQuery = _mesa_begin_query; + driver->EndQuery = _mesa_end_query; + driver->WaitQuery = _mesa_wait_query; + driver->CheckQuery = _mesa_check_query; +} + + +/** + * Return pointer to the query object binding point for the given target. + * \return NULL if invalid target, else the address of binding point + */ +static struct gl_query_object ** +get_query_binding_point(struct gl_context *ctx, GLenum target) +{ + switch (target) { + case GL_SAMPLES_PASSED_ARB: + if (ctx->Extensions.ARB_occlusion_query) + return &ctx->Query.CurrentOcclusionObject; + else + return NULL; + case GL_ANY_SAMPLES_PASSED: + if (ctx->Extensions.ARB_occlusion_query2) + return &ctx->Query.CurrentOcclusionObject; + else + return NULL; + case GL_TIME_ELAPSED_EXT: + if (ctx->Extensions.EXT_timer_query) + return &ctx->Query.CurrentTimerObject; + else + return NULL; +#if FEATURE_EXT_transform_feedback + case GL_PRIMITIVES_GENERATED: + if (ctx->Extensions.EXT_transform_feedback) + return &ctx->Query.PrimitivesGenerated; + else + return NULL; + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: + if (ctx->Extensions.EXT_transform_feedback) + return &ctx->Query.PrimitivesWritten; + else + return NULL; +#endif + default: + return NULL; + } +} + + +void GLAPIENTRY +_mesa_GenQueriesARB(GLsizei n, GLuint *ids) +{ + GLuint first; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glGenQueries(%d)\n", n); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)"); + return; + } + + /* No query objects can be active at this time! */ + if (ctx->Query.CurrentOcclusionObject || + ctx->Query.CurrentTimerObject) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGenQueriesARB"); + return; + } + + first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n); + if (first) { + GLsizei i; + for (i = 0; i < n; i++) { + struct gl_query_object *q + = ctx->Driver.NewQueryObject(ctx, first + i); + if (!q) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB"); + return; + } + ids[i] = first + i; + _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q); + } + } +} + + +void GLAPIENTRY +_mesa_DeleteQueriesARB(GLsizei n, const GLuint *ids) +{ + GLint i; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glDeleeteQueries(%d)\n", n); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)"); + return; + } + + /* No query objects can be active at this time! */ + if (ctx->Query.CurrentOcclusionObject || + ctx->Query.CurrentTimerObject) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteQueriesARB"); + return; + } + + for (i = 0; i < n; i++) { + if (ids[i] > 0) { + struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]); + if (q) { + ASSERT(!q->Active); /* should be caught earlier */ + _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]); + ctx->Driver.DeleteQuery(ctx, q); + } + } + } +} + + +GLboolean GLAPIENTRY +_mesa_IsQueryARB(GLuint id) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glIsQuery(%u)\n", id); + + if (id && _mesa_lookup_query_object(ctx, id)) + return GL_TRUE; + else + return GL_FALSE; +} + + +static void GLAPIENTRY +_mesa_BeginQueryARB(GLenum target, GLuint id) +{ + struct gl_query_object *q, **bindpt; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glBeginQuery(%s, %u)\n", + _mesa_lookup_enum_by_nr(target), id); + + FLUSH_VERTICES(ctx, _NEW_DEPTH); + + bindpt = get_query_binding_point(ctx, target); + if (!bindpt) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)"); + return; + } + + if (id == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB(id==0)"); + return; + } + + q = _mesa_lookup_query_object(ctx, id); + if (!q) { + /* create new object */ + q = ctx->Driver.NewQueryObject(ctx, id); + if (!q) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQueryARB"); + return; + } + _mesa_HashInsert(ctx->Query.QueryObjects, id, q); + } + else { + /* pre-existing object */ + if (q->Active) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBeginQueryARB(query already active)"); + return; + } + } + + q->Target = target; + q->Active = GL_TRUE; + q->Result = 0; + q->Ready = GL_FALSE; + + /* XXX should probably refcount query objects */ + *bindpt = q; + + ctx->Driver.BeginQuery(ctx, q); +} + + +static void GLAPIENTRY +_mesa_EndQueryARB(GLenum target) +{ + struct gl_query_object *q, **bindpt; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glEndQuery(%s)\n", _mesa_lookup_enum_by_nr(target)); + + FLUSH_VERTICES(ctx, _NEW_DEPTH); + + bindpt = get_query_binding_point(ctx, target); + if (!bindpt) { + _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)"); + return; + } + + /* XXX should probably refcount query objects */ + q = *bindpt; + *bindpt = NULL; + + if (!q || !q->Active) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glEndQueryARB(no matching glBeginQueryARB)"); + return; + } + + q->Active = GL_FALSE; + ctx->Driver.EndQuery(ctx, q); +} + + +void GLAPIENTRY +_mesa_GetQueryivARB(GLenum target, GLenum pname, GLint *params) +{ + struct gl_query_object *q, **bindpt; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glGetQueryiv(%s, %s)\n", + _mesa_lookup_enum_by_nr(target), + _mesa_lookup_enum_by_nr(pname)); + + bindpt = get_query_binding_point(ctx, target); + if (!bindpt) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)"); + return; + } + + q = *bindpt; + + switch (pname) { + case GL_QUERY_COUNTER_BITS_ARB: + *params = 8 * sizeof(q->Result); + break; + case GL_CURRENT_QUERY_ARB: + *params = q ? q->Id : 0; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivARB(pname)"); + return; + } +} + + +void GLAPIENTRY +_mesa_GetQueryObjectivARB(GLuint id, GLenum pname, GLint *params) +{ + struct gl_query_object *q = NULL; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glGetQueryObjectiv(%u, %s)\n", id, + _mesa_lookup_enum_by_nr(pname)); + + if (id) + q = _mesa_lookup_query_object(ctx, id); + + if (!q || q->Active) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetQueryObjectivARB(id=%d is invalid or active)", id); + return; + } + + switch (pname) { + case GL_QUERY_RESULT_ARB: + if (!q->Ready) + ctx->Driver.WaitQuery(ctx, q); + /* if result is too large for returned type, clamp to max value */ + if (q->Target == GL_ANY_SAMPLES_PASSED) { + if (q->Result) + *params = GL_TRUE; + else + *params = GL_FALSE; + } else { + if (q->Result > 0x7fffffff) { + *params = 0x7fffffff; + } + else { + *params = (GLint)q->Result; + } + } + break; + case GL_QUERY_RESULT_AVAILABLE_ARB: + if (!q->Ready) + ctx->Driver.CheckQuery( ctx, q ); + *params = q->Ready; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)"); + return; + } +} + + +void GLAPIENTRY +_mesa_GetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params) +{ + struct gl_query_object *q = NULL; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glGetQueryObjectuiv(%u, %s)\n", id, + _mesa_lookup_enum_by_nr(pname)); + + if (id) + q = _mesa_lookup_query_object(ctx, id); + + if (!q || q->Active) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetQueryObjectuivARB(id=%d is invalid or active)", id); + return; + } + + switch (pname) { + case GL_QUERY_RESULT_ARB: + if (!q->Ready) + ctx->Driver.WaitQuery(ctx, q); + /* if result is too large for returned type, clamp to max value */ + if (q->Target == GL_ANY_SAMPLES_PASSED) { + if (q->Result) + *params = GL_TRUE; + else + *params = GL_FALSE; + } else { + if (q->Result > 0xffffffff) { + *params = 0xffffffff; + } + else { + *params = (GLuint)q->Result; + } + } + break; + case GL_QUERY_RESULT_AVAILABLE_ARB: + if (!q->Ready) + ctx->Driver.CheckQuery( ctx, q ); + *params = q->Ready; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)"); + return; + } +} + + +/** + * New with GL_EXT_timer_query + */ +static void GLAPIENTRY +_mesa_GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64EXT *params) +{ + struct gl_query_object *q = NULL; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glGetQueryObjecti64v(%u, %s)\n", id, + _mesa_lookup_enum_by_nr(pname)); + + if (id) + q = _mesa_lookup_query_object(ctx, id); + + if (!q || q->Active) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetQueryObjectui64vARB(id=%d is invalid or active)", id); + return; + } + + switch (pname) { + case GL_QUERY_RESULT_ARB: + if (!q->Ready) + ctx->Driver.WaitQuery(ctx, q); + *params = q->Result; + break; + case GL_QUERY_RESULT_AVAILABLE_ARB: + if (!q->Ready) + ctx->Driver.CheckQuery( ctx, q ); + *params = q->Ready; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)"); + return; + } +} + + +/** + * New with GL_EXT_timer_query + */ +static void GLAPIENTRY +_mesa_GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params) +{ + struct gl_query_object *q = NULL; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glGetQueryObjectui64v(%u, %s)\n", id, + _mesa_lookup_enum_by_nr(pname)); + + if (id) + q = _mesa_lookup_query_object(ctx, id); + + if (!q || q->Active) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id); + return; + } + + switch (pname) { + case GL_QUERY_RESULT_ARB: + if (!q->Ready) + ctx->Driver.WaitQuery(ctx, q); + *params = q->Result; + break; + case GL_QUERY_RESULT_AVAILABLE_ARB: + if (!q->Ready) + ctx->Driver.CheckQuery( ctx, q ); + *params = q->Ready; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)"); + return; + } +} + + +void +_mesa_init_queryobj_dispatch(struct _glapi_table *disp) +{ + SET_GenQueriesARB(disp, _mesa_GenQueriesARB); + SET_DeleteQueriesARB(disp, _mesa_DeleteQueriesARB); + SET_IsQueryARB(disp, _mesa_IsQueryARB); + SET_BeginQueryARB(disp, _mesa_BeginQueryARB); + SET_EndQueryARB(disp, _mesa_EndQueryARB); + SET_GetQueryivARB(disp, _mesa_GetQueryivARB); + SET_GetQueryObjectivARB(disp, _mesa_GetQueryObjectivARB); + SET_GetQueryObjectuivARB(disp, _mesa_GetQueryObjectuivARB); + + SET_GetQueryObjecti64vEXT(disp, _mesa_GetQueryObjecti64vEXT); + SET_GetQueryObjectui64vEXT(disp, _mesa_GetQueryObjectui64vEXT); +} + + +#endif /* FEATURE_queryobj */ + + +/** + * Allocate/init the context state related to query objects. + */ +void +_mesa_init_queryobj(struct gl_context *ctx) +{ + ctx->Query.QueryObjects = _mesa_NewHashTable(); + ctx->Query.CurrentOcclusionObject = NULL; +} + + +/** + * Callback for deleting a query object. Called by _mesa_HashDeleteAll(). + */ +static void +delete_queryobj_cb(GLuint id, void *data, void *userData) +{ + struct gl_query_object *q= (struct gl_query_object *) data; + struct gl_context *ctx = (struct gl_context *)userData; + ctx->Driver.DeleteQuery(ctx, q); +} + + +/** + * Free the context state related to query objects. + */ +void +_mesa_free_queryobj_data(struct gl_context *ctx) +{ + _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx); + _mesa_DeleteHashTable(ctx->Query.QueryObjects); +} diff --git a/mesalib/src/mesa/main/shaderapi.c b/mesalib/src/mesa/main/shaderapi.c index f2b8aa449..11b0f884f 100644 --- a/mesalib/src/mesa/main/shaderapi.c +++ b/mesalib/src/mesa/main/shaderapi.c @@ -1184,6 +1184,8 @@ void GLAPIENTRY _mesa_CompileShaderARB(GLhandleARB shaderObj) { GET_CURRENT_CONTEXT(ctx); + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glCompileShader %u\n", shaderObj); compile_shader(ctx, shaderObj); } @@ -1192,6 +1194,8 @@ GLuint GLAPIENTRY _mesa_CreateShader(GLenum type) { GET_CURRENT_CONTEXT(ctx); + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glCreateShader %s\n", _mesa_lookup_enum_by_nr(type)); return create_shader(ctx, type); } @@ -1208,6 +1212,8 @@ GLuint GLAPIENTRY _mesa_CreateProgram(void) { GET_CURRENT_CONTEXT(ctx); + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glCreateProgram\n"); return create_shader_program(ctx); } @@ -1223,6 +1229,11 @@ _mesa_CreateProgramObjectARB(void) void GLAPIENTRY _mesa_DeleteObjectARB(GLhandleARB obj) { + if (MESA_VERBOSE & VERBOSE_API) { + GET_CURRENT_CONTEXT(ctx); + _mesa_debug(ctx, "glDeleteObjectARB(%u)\n", obj); + } + if (obj) { GET_CURRENT_CONTEXT(ctx); if (is_program(ctx, obj)) { diff --git a/mesalib/src/mesa/main/stencil.c b/mesalib/src/mesa/main/stencil.c index c63b14d27..d898bf1d7 100644 --- a/mesalib/src/mesa/main/stencil.c +++ b/mesalib/src/mesa/main/stencil.c @@ -1,590 +1,614 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 1999-2007 Brian Paul 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 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 - * BRIAN PAUL 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. - */ - - -/** - * \file stencil.c - * Stencil operations. - * - * Note: There's some conflict between GL_EXT_stencil_two_side and - * OpenGL 2.0's two-sided stencil feature. - * - * With GL_EXT_stencil_two_side, calling glStencilOp/Func/Mask() only the - * front OR back face state (as set by glActiveStencilFaceEXT) is set. - * - * But with OpenGL 2.0, calling glStencilOp/Func/Mask() sets BOTH the - * front AND back state. - * - * Also, note that GL_ATI_separate_stencil is different as well: - * glStencilFuncSeparateATI(GLenum frontfunc, GLenum backfunc, ...) vs. - * glStencilFuncSeparate(GLenum face, GLenum func, ...). - * - * This problem is solved by keeping three sets of stencil state: - * state[0] = GL_FRONT state. - * state[1] = OpenGL 2.0 / GL_ATI_separate_stencil GL_BACK state. - * state[2] = GL_EXT_stencil_two_side GL_BACK state. - */ - - -#include "glheader.h" -#include "imports.h" -#include "context.h" -#include "macros.h" -#include "stencil.h" -#include "mtypes.h" - - -static GLboolean -validate_stencil_op(struct gl_context *ctx, GLenum op) -{ - switch (op) { - case GL_KEEP: - case GL_ZERO: - case GL_REPLACE: - case GL_INCR: - case GL_DECR: - case GL_INVERT: - return GL_TRUE; - case GL_INCR_WRAP_EXT: - case GL_DECR_WRAP_EXT: - if (ctx->Extensions.EXT_stencil_wrap) { - return GL_TRUE; - } - /* FALL-THROUGH */ - default: - return GL_FALSE; - } -} - - -static GLboolean -validate_stencil_func(struct gl_context *ctx, GLenum func) -{ - switch (func) { - case GL_NEVER: - case GL_LESS: - case GL_LEQUAL: - case GL_GREATER: - case GL_GEQUAL: - case GL_EQUAL: - case GL_NOTEQUAL: - case GL_ALWAYS: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Set the clear value for the stencil buffer. - * - * \param s clear value. - * - * \sa glClearStencil(). - * - * Updates gl_stencil_attrib::Clear. On change - * flushes the vertices and notifies the driver via - * the dd_function_table::ClearStencil callback. - */ -void GLAPIENTRY -_mesa_ClearStencil( GLint s ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (ctx->Stencil.Clear == (GLuint) s) - return; - - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.Clear = (GLuint) s; - - if (ctx->Driver.ClearStencil) { - ctx->Driver.ClearStencil( ctx, s ); - } -} - - -/** - * Set the function and reference value for stencil testing. - * - * \param frontfunc front test function. - * \param backfunc back test function. - * \param ref front and back reference value. - * \param mask front and back bitmask. - * - * \sa glStencilFunc(). - * - * Verifies the parameters and updates the respective values in - * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the - * driver via the dd_function_table::StencilFunc callback. - */ -void GLAPIENTRY -_mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask ) -{ - GET_CURRENT_CONTEXT(ctx); - const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!validate_stencil_func(ctx, frontfunc)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glStencilFuncSeparateATI(frontfunc)"); - return; - } - if (!validate_stencil_func(ctx, backfunc)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glStencilFuncSeparateATI(backfunc)"); - return; - } - - ref = CLAMP( ref, 0, stencilMax ); - - /* set both front and back state */ - if (ctx->Stencil.Function[0] == frontfunc && - ctx->Stencil.Function[1] == backfunc && - ctx->Stencil.ValueMask[0] == mask && - ctx->Stencil.ValueMask[1] == mask && - ctx->Stencil.Ref[0] == ref && - ctx->Stencil.Ref[1] == ref) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.Function[0] = frontfunc; - ctx->Stencil.Function[1] = backfunc; - ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; - ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; - if (ctx->Driver.StencilFuncSeparate) { - ctx->Driver.StencilFuncSeparate(ctx, GL_FRONT, - frontfunc, ref, mask); - ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, - backfunc, ref, mask); - } -} - - -/** - * Set the function and reference value for stencil testing. - * - * \param func test function. - * \param ref reference value. - * \param mask bitmask. - * - * \sa glStencilFunc(). - * - * Verifies the parameters and updates the respective values in - * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the - * driver via the dd_function_table::StencilFunc callback. - */ -void GLAPIENTRY -_mesa_StencilFunc( GLenum func, GLint ref, GLuint mask ) -{ - GET_CURRENT_CONTEXT(ctx); - const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; - const GLint face = ctx->Stencil.ActiveFace; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!validate_stencil_func(ctx, func)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFunc(func)"); - return; - } - - ref = CLAMP( ref, 0, stencilMax ); - - if (face != 0) { - if (ctx->Stencil.Function[face] == func && - ctx->Stencil.ValueMask[face] == mask && - ctx->Stencil.Ref[face] == ref) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.Function[face] = func; - ctx->Stencil.Ref[face] = ref; - ctx->Stencil.ValueMask[face] = mask; - - /* Only propagate the change to the driver if EXT_stencil_two_side - * is enabled. - */ - if (ctx->Driver.StencilFuncSeparate && ctx->Stencil.TestTwoSide) { - ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, func, ref, mask); - } - } - else { - /* set both front and back state */ - if (ctx->Stencil.Function[0] == func && - ctx->Stencil.Function[1] == func && - ctx->Stencil.ValueMask[0] == mask && - ctx->Stencil.ValueMask[1] == mask && - ctx->Stencil.Ref[0] == ref && - ctx->Stencil.Ref[1] == ref) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.Function[0] = ctx->Stencil.Function[1] = func; - ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; - ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; - if (ctx->Driver.StencilFuncSeparate) { - ctx->Driver.StencilFuncSeparate(ctx, - ((ctx->Stencil.TestTwoSide) - ? GL_FRONT : GL_FRONT_AND_BACK), - func, ref, mask); - } - } -} - - -/** - * Set the stencil writing mask. - * - * \param mask bit-mask to enable/disable writing of individual bits in the - * stencil planes. - * - * \sa glStencilMask(). - * - * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and - * notifies the driver via the dd_function_table::StencilMask callback. - */ -void GLAPIENTRY -_mesa_StencilMask( GLuint mask ) -{ - GET_CURRENT_CONTEXT(ctx); - const GLint face = ctx->Stencil.ActiveFace; - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (face != 0) { - /* Only modify the EXT_stencil_two_side back-face state. - */ - if (ctx->Stencil.WriteMask[face] == mask) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.WriteMask[face] = mask; - - /* Only propagate the change to the driver if EXT_stencil_two_side - * is enabled. - */ - if (ctx->Driver.StencilMaskSeparate && ctx->Stencil.TestTwoSide) { - ctx->Driver.StencilMaskSeparate(ctx, GL_BACK, mask); - } - } - else { - /* set both front and back state */ - if (ctx->Stencil.WriteMask[0] == mask && - ctx->Stencil.WriteMask[1] == mask) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.WriteMask[0] = ctx->Stencil.WriteMask[1] = mask; - if (ctx->Driver.StencilMaskSeparate) { - ctx->Driver.StencilMaskSeparate(ctx, - ((ctx->Stencil.TestTwoSide) - ? GL_FRONT : GL_FRONT_AND_BACK), - mask); - } - } -} - - -/** - * Set the stencil test actions. - * - * \param fail action to take when stencil test fails. - * \param zfail action to take when stencil test passes, but depth test fails. - * \param zpass action to take when stencil test passes and the depth test - * passes (or depth testing is not enabled). - * - * \sa glStencilOp(). - * - * Verifies the parameters and updates the respective fields in - * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the - * driver via the dd_function_table::StencilOp callback. - */ -void GLAPIENTRY -_mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass) -{ - GET_CURRENT_CONTEXT(ctx); - const GLint face = ctx->Stencil.ActiveFace; - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!validate_stencil_op(ctx, fail)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)"); - return; - } - if (!validate_stencil_op(ctx, zfail)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)"); - return; - } - if (!validate_stencil_op(ctx, zpass)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)"); - return; - } - - if (face != 0) { - /* only set active face state */ - if (ctx->Stencil.ZFailFunc[face] == zfail && - ctx->Stencil.ZPassFunc[face] == zpass && - ctx->Stencil.FailFunc[face] == fail) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.ZFailFunc[face] = zfail; - ctx->Stencil.ZPassFunc[face] = zpass; - ctx->Stencil.FailFunc[face] = fail; - - /* Only propagate the change to the driver if EXT_stencil_two_side - * is enabled. - */ - if (ctx->Driver.StencilOpSeparate && ctx->Stencil.TestTwoSide) { - ctx->Driver.StencilOpSeparate(ctx, GL_BACK, fail, zfail, zpass); - } - } - else { - /* set both front and back state */ - if (ctx->Stencil.ZFailFunc[0] == zfail && - ctx->Stencil.ZFailFunc[1] == zfail && - ctx->Stencil.ZPassFunc[0] == zpass && - ctx->Stencil.ZPassFunc[1] == zpass && - ctx->Stencil.FailFunc[0] == fail && - ctx->Stencil.FailFunc[1] == fail) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.ZFailFunc[0] = ctx->Stencil.ZFailFunc[1] = zfail; - ctx->Stencil.ZPassFunc[0] = ctx->Stencil.ZPassFunc[1] = zpass; - ctx->Stencil.FailFunc[0] = ctx->Stencil.FailFunc[1] = fail; - if (ctx->Driver.StencilOpSeparate) { - ctx->Driver.StencilOpSeparate(ctx, - ((ctx->Stencil.TestTwoSide) - ? GL_FRONT : GL_FRONT_AND_BACK), - fail, zfail, zpass); - } - } -} - - - -#if _HAVE_FULL_GL -/* GL_EXT_stencil_two_side */ -void GLAPIENTRY -_mesa_ActiveStencilFaceEXT(GLenum face) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!ctx->Extensions.EXT_stencil_two_side) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glActiveStencilFaceEXT"); - return; - } - - if (face == GL_FRONT || face == GL_BACK) { - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 2; - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glActiveStencilFaceEXT(face)"); - } -} -#endif - - - -/** - * OpenGL 2.0 function. - * \todo Make StencilOp() call this function. And eventually remove the - * ctx->Driver.StencilOp function and use ctx->Driver.StencilOpSeparate - * instead. - */ -void GLAPIENTRY -_mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass) -{ - GLboolean set = GL_FALSE; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!validate_stencil_op(ctx, sfail)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(sfail)"); - return; - } - if (!validate_stencil_op(ctx, zfail)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zfail)"); - return; - } - if (!validate_stencil_op(ctx, zpass)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zpass)"); - return; - } - if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(face)"); - return; - } - - if (face != GL_BACK) { - /* set front */ - if (ctx->Stencil.ZFailFunc[0] != zfail || - ctx->Stencil.ZPassFunc[0] != zpass || - ctx->Stencil.FailFunc[0] != sfail){ - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.ZFailFunc[0] = zfail; - ctx->Stencil.ZPassFunc[0] = zpass; - ctx->Stencil.FailFunc[0] = sfail; - set = GL_TRUE; - } - } - if (face != GL_FRONT) { - /* set back */ - if (ctx->Stencil.ZFailFunc[1] != zfail || - ctx->Stencil.ZPassFunc[1] != zpass || - ctx->Stencil.FailFunc[1] != sfail) { - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.ZFailFunc[1] = zfail; - ctx->Stencil.ZPassFunc[1] = zpass; - ctx->Stencil.FailFunc[1] = sfail; - set = GL_TRUE; - } - } - if (set && ctx->Driver.StencilOpSeparate) { - ctx->Driver.StencilOpSeparate(ctx, face, sfail, zfail, zpass); - } -} - - -/* OpenGL 2.0 */ -void GLAPIENTRY -_mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) -{ - GET_CURRENT_CONTEXT(ctx); - const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(face)"); - return; - } - if (!validate_stencil_func(ctx, func)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(func)"); - return; - } - - ref = CLAMP(ref, 0, stencilMax); - - FLUSH_VERTICES(ctx, _NEW_STENCIL); - - if (face != GL_BACK) { - /* set front */ - ctx->Stencil.Function[0] = func; - ctx->Stencil.Ref[0] = ref; - ctx->Stencil.ValueMask[0] = mask; - } - if (face != GL_FRONT) { - /* set back */ - ctx->Stencil.Function[1] = func; - ctx->Stencil.Ref[1] = ref; - ctx->Stencil.ValueMask[1] = mask; - } - if (ctx->Driver.StencilFuncSeparate) { - ctx->Driver.StencilFuncSeparate(ctx, face, func, ref, mask); - } -} - - -/* OpenGL 2.0 */ -void GLAPIENTRY -_mesa_StencilMaskSeparate(GLenum face, GLuint mask) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilaMaskSeparate(face)"); - return; - } - - FLUSH_VERTICES(ctx, _NEW_STENCIL); - - if (face != GL_BACK) { - ctx->Stencil.WriteMask[0] = mask; - } - if (face != GL_FRONT) { - ctx->Stencil.WriteMask[1] = mask; - } - if (ctx->Driver.StencilMaskSeparate) { - ctx->Driver.StencilMaskSeparate(ctx, face, mask); - } -} - - -/** - * Update derived stencil state. - */ -void -_mesa_update_stencil(struct gl_context *ctx) -{ - const GLint face = ctx->Stencil._BackFace; - - ctx->Stencil._Enabled = (ctx->Stencil.Enabled && - ctx->DrawBuffer->Visual.stencilBits > 0); - - ctx->Stencil._TestTwoSide = - ctx->Stencil._Enabled && - (ctx->Stencil.Function[0] != ctx->Stencil.Function[face] || - ctx->Stencil.FailFunc[0] != ctx->Stencil.FailFunc[face] || - ctx->Stencil.ZPassFunc[0] != ctx->Stencil.ZPassFunc[face] || - ctx->Stencil.ZFailFunc[0] != ctx->Stencil.ZFailFunc[face] || - ctx->Stencil.Ref[0] != ctx->Stencil.Ref[face] || - ctx->Stencil.ValueMask[0] != ctx->Stencil.ValueMask[face] || - ctx->Stencil.WriteMask[0] != ctx->Stencil.WriteMask[face]); -} - - -/** - * Initialize the context stipple state. - * - * \param ctx GL context. - * - * Initializes __struct gl_contextRec::Stencil attribute group. - */ -void -_mesa_init_stencil(struct gl_context *ctx) -{ - ctx->Stencil.Enabled = GL_FALSE; - ctx->Stencil.TestTwoSide = GL_FALSE; - ctx->Stencil.ActiveFace = 0; /* 0 = GL_FRONT, 2 = GL_BACK */ - ctx->Stencil.Function[0] = GL_ALWAYS; - ctx->Stencil.Function[1] = GL_ALWAYS; - ctx->Stencil.Function[2] = GL_ALWAYS; - ctx->Stencil.FailFunc[0] = GL_KEEP; - ctx->Stencil.FailFunc[1] = GL_KEEP; - ctx->Stencil.FailFunc[2] = GL_KEEP; - ctx->Stencil.ZPassFunc[0] = GL_KEEP; - ctx->Stencil.ZPassFunc[1] = GL_KEEP; - ctx->Stencil.ZPassFunc[2] = GL_KEEP; - ctx->Stencil.ZFailFunc[0] = GL_KEEP; - ctx->Stencil.ZFailFunc[1] = GL_KEEP; - ctx->Stencil.ZFailFunc[2] = GL_KEEP; - ctx->Stencil.Ref[0] = 0; - ctx->Stencil.Ref[1] = 0; - ctx->Stencil.Ref[2] = 0; - ctx->Stencil.ValueMask[0] = ~0U; - ctx->Stencil.ValueMask[1] = ~0U; - ctx->Stencil.ValueMask[2] = ~0U; - ctx->Stencil.WriteMask[0] = ~0U; - ctx->Stencil.WriteMask[1] = ~0U; - ctx->Stencil.WriteMask[2] = ~0U; - ctx->Stencil.Clear = 0; - ctx->Stencil._BackFace = 1; -} +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2007 Brian Paul 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 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 + * BRIAN PAUL 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. + */ + + +/** + * \file stencil.c + * Stencil operations. + * + * Note: There's some conflict between GL_EXT_stencil_two_side and + * OpenGL 2.0's two-sided stencil feature. + * + * With GL_EXT_stencil_two_side, calling glStencilOp/Func/Mask() only the + * front OR back face state (as set by glActiveStencilFaceEXT) is set. + * + * But with OpenGL 2.0, calling glStencilOp/Func/Mask() sets BOTH the + * front AND back state. + * + * Also, note that GL_ATI_separate_stencil is different as well: + * glStencilFuncSeparateATI(GLenum frontfunc, GLenum backfunc, ...) vs. + * glStencilFuncSeparate(GLenum face, GLenum func, ...). + * + * This problem is solved by keeping three sets of stencil state: + * state[0] = GL_FRONT state. + * state[1] = OpenGL 2.0 / GL_ATI_separate_stencil GL_BACK state. + * state[2] = GL_EXT_stencil_two_side GL_BACK state. + */ + + +#include "glheader.h" +#include "imports.h" +#include "context.h" +#include "macros.h" +#include "stencil.h" +#include "mtypes.h" + + +static GLboolean +validate_stencil_op(struct gl_context *ctx, GLenum op) +{ + switch (op) { + case GL_KEEP: + case GL_ZERO: + case GL_REPLACE: + case GL_INCR: + case GL_DECR: + case GL_INVERT: + return GL_TRUE; + case GL_INCR_WRAP_EXT: + case GL_DECR_WRAP_EXT: + if (ctx->Extensions.EXT_stencil_wrap) { + return GL_TRUE; + } + /* FALL-THROUGH */ + default: + return GL_FALSE; + } +} + + +static GLboolean +validate_stencil_func(struct gl_context *ctx, GLenum func) +{ + switch (func) { + case GL_NEVER: + case GL_LESS: + case GL_LEQUAL: + case GL_GREATER: + case GL_GEQUAL: + case GL_EQUAL: + case GL_NOTEQUAL: + case GL_ALWAYS: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Set the clear value for the stencil buffer. + * + * \param s clear value. + * + * \sa glClearStencil(). + * + * Updates gl_stencil_attrib::Clear. On change + * flushes the vertices and notifies the driver via + * the dd_function_table::ClearStencil callback. + */ +void GLAPIENTRY +_mesa_ClearStencil( GLint s ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (ctx->Stencil.Clear == (GLuint) s) + return; + + FLUSH_VERTICES(ctx, _NEW_STENCIL); + ctx->Stencil.Clear = (GLuint) s; + + if (ctx->Driver.ClearStencil) { + ctx->Driver.ClearStencil( ctx, s ); + } +} + + +/** + * Set the function and reference value for stencil testing. + * + * \param frontfunc front test function. + * \param backfunc back test function. + * \param ref front and back reference value. + * \param mask front and back bitmask. + * + * \sa glStencilFunc(). + * + * Verifies the parameters and updates the respective values in + * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the + * driver via the dd_function_table::StencilFunc callback. + */ +void GLAPIENTRY +_mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask ) +{ + GET_CURRENT_CONTEXT(ctx); + const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glStencilFuncSeparateATI()\n"); + + if (!validate_stencil_func(ctx, frontfunc)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glStencilFuncSeparateATI(frontfunc)"); + return; + } + if (!validate_stencil_func(ctx, backfunc)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glStencilFuncSeparateATI(backfunc)"); + return; + } + + ref = CLAMP( ref, 0, stencilMax ); + + /* set both front and back state */ + if (ctx->Stencil.Function[0] == frontfunc && + ctx->Stencil.Function[1] == backfunc && + ctx->Stencil.ValueMask[0] == mask && + ctx->Stencil.ValueMask[1] == mask && + ctx->Stencil.Ref[0] == ref && + ctx->Stencil.Ref[1] == ref) + return; + FLUSH_VERTICES(ctx, _NEW_STENCIL); + ctx->Stencil.Function[0] = frontfunc; + ctx->Stencil.Function[1] = backfunc; + ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; + ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; + if (ctx->Driver.StencilFuncSeparate) { + ctx->Driver.StencilFuncSeparate(ctx, GL_FRONT, + frontfunc, ref, mask); + ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, + backfunc, ref, mask); + } +} + + +/** + * Set the function and reference value for stencil testing. + * + * \param func test function. + * \param ref reference value. + * \param mask bitmask. + * + * \sa glStencilFunc(). + * + * Verifies the parameters and updates the respective values in + * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the + * driver via the dd_function_table::StencilFunc callback. + */ +void GLAPIENTRY +_mesa_StencilFunc( GLenum func, GLint ref, GLuint mask ) +{ + GET_CURRENT_CONTEXT(ctx); + const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; + const GLint face = ctx->Stencil.ActiveFace; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glStencilFunc()\n"); + + if (!validate_stencil_func(ctx, func)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFunc(func)"); + return; + } + + ref = CLAMP( ref, 0, stencilMax ); + + if (face != 0) { + if (ctx->Stencil.Function[face] == func && + ctx->Stencil.ValueMask[face] == mask && + ctx->Stencil.Ref[face] == ref) + return; + FLUSH_VERTICES(ctx, _NEW_STENCIL); + ctx->Stencil.Function[face] = func; + ctx->Stencil.Ref[face] = ref; + ctx->Stencil.ValueMask[face] = mask; + + /* Only propagate the change to the driver if EXT_stencil_two_side + * is enabled. + */ + if (ctx->Driver.StencilFuncSeparate && ctx->Stencil.TestTwoSide) { + ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, func, ref, mask); + } + } + else { + /* set both front and back state */ + if (ctx->Stencil.Function[0] == func && + ctx->Stencil.Function[1] == func && + ctx->Stencil.ValueMask[0] == mask && + ctx->Stencil.ValueMask[1] == mask && + ctx->Stencil.Ref[0] == ref && + ctx->Stencil.Ref[1] == ref) + return; + FLUSH_VERTICES(ctx, _NEW_STENCIL); + ctx->Stencil.Function[0] = ctx->Stencil.Function[1] = func; + ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; + ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; + if (ctx->Driver.StencilFuncSeparate) { + ctx->Driver.StencilFuncSeparate(ctx, + ((ctx->Stencil.TestTwoSide) + ? GL_FRONT : GL_FRONT_AND_BACK), + func, ref, mask); + } + } +} + + +/** + * Set the stencil writing mask. + * + * \param mask bit-mask to enable/disable writing of individual bits in the + * stencil planes. + * + * \sa glStencilMask(). + * + * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and + * notifies the driver via the dd_function_table::StencilMask callback. + */ +void GLAPIENTRY +_mesa_StencilMask( GLuint mask ) +{ + GET_CURRENT_CONTEXT(ctx); + const GLint face = ctx->Stencil.ActiveFace; + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glStencilMask()\n"); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (face != 0) { + /* Only modify the EXT_stencil_two_side back-face state. + */ + if (ctx->Stencil.WriteMask[face] == mask) + return; + FLUSH_VERTICES(ctx, _NEW_STENCIL); + ctx->Stencil.WriteMask[face] = mask; + + /* Only propagate the change to the driver if EXT_stencil_two_side + * is enabled. + */ + if (ctx->Driver.StencilMaskSeparate && ctx->Stencil.TestTwoSide) { + ctx->Driver.StencilMaskSeparate(ctx, GL_BACK, mask); + } + } + else { + /* set both front and back state */ + if (ctx->Stencil.WriteMask[0] == mask && + ctx->Stencil.WriteMask[1] == mask) + return; + FLUSH_VERTICES(ctx, _NEW_STENCIL); + ctx->Stencil.WriteMask[0] = ctx->Stencil.WriteMask[1] = mask; + if (ctx->Driver.StencilMaskSeparate) { + ctx->Driver.StencilMaskSeparate(ctx, + ((ctx->Stencil.TestTwoSide) + ? GL_FRONT : GL_FRONT_AND_BACK), + mask); + } + } +} + + +/** + * Set the stencil test actions. + * + * \param fail action to take when stencil test fails. + * \param zfail action to take when stencil test passes, but depth test fails. + * \param zpass action to take when stencil test passes and the depth test + * passes (or depth testing is not enabled). + * + * \sa glStencilOp(). + * + * Verifies the parameters and updates the respective fields in + * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the + * driver via the dd_function_table::StencilOp callback. + */ +void GLAPIENTRY +_mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass) +{ + GET_CURRENT_CONTEXT(ctx); + const GLint face = ctx->Stencil.ActiveFace; + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glStencilOp()\n"); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (!validate_stencil_op(ctx, fail)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)"); + return; + } + if (!validate_stencil_op(ctx, zfail)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)"); + return; + } + if (!validate_stencil_op(ctx, zpass)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)"); + return; + } + + if (face != 0) { + /* only set active face state */ + if (ctx->Stencil.ZFailFunc[face] == zfail && + ctx->Stencil.ZPassFunc[face] == zpass && + ctx->Stencil.FailFunc[face] == fail) + return; + FLUSH_VERTICES(ctx, _NEW_STENCIL); + ctx->Stencil.ZFailFunc[face] = zfail; + ctx->Stencil.ZPassFunc[face] = zpass; + ctx->Stencil.FailFunc[face] = fail; + + /* Only propagate the change to the driver if EXT_stencil_two_side + * is enabled. + */ + if (ctx->Driver.StencilOpSeparate && ctx->Stencil.TestTwoSide) { + ctx->Driver.StencilOpSeparate(ctx, GL_BACK, fail, zfail, zpass); + } + } + else { + /* set both front and back state */ + if (ctx->Stencil.ZFailFunc[0] == zfail && + ctx->Stencil.ZFailFunc[1] == zfail && + ctx->Stencil.ZPassFunc[0] == zpass && + ctx->Stencil.ZPassFunc[1] == zpass && + ctx->Stencil.FailFunc[0] == fail && + ctx->Stencil.FailFunc[1] == fail) + return; + FLUSH_VERTICES(ctx, _NEW_STENCIL); + ctx->Stencil.ZFailFunc[0] = ctx->Stencil.ZFailFunc[1] = zfail; + ctx->Stencil.ZPassFunc[0] = ctx->Stencil.ZPassFunc[1] = zpass; + ctx->Stencil.FailFunc[0] = ctx->Stencil.FailFunc[1] = fail; + if (ctx->Driver.StencilOpSeparate) { + ctx->Driver.StencilOpSeparate(ctx, + ((ctx->Stencil.TestTwoSide) + ? GL_FRONT : GL_FRONT_AND_BACK), + fail, zfail, zpass); + } + } +} + + + +#if _HAVE_FULL_GL +/* GL_EXT_stencil_two_side */ +void GLAPIENTRY +_mesa_ActiveStencilFaceEXT(GLenum face) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glActiveStencilFaceEXT()\n"); + + if (!ctx->Extensions.EXT_stencil_two_side) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glActiveStencilFaceEXT"); + return; + } + + if (face == GL_FRONT || face == GL_BACK) { + FLUSH_VERTICES(ctx, _NEW_STENCIL); + ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 2; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glActiveStencilFaceEXT(face)"); + } +} +#endif + + + +/** + * OpenGL 2.0 function. + * \todo Make StencilOp() call this function. And eventually remove the + * ctx->Driver.StencilOp function and use ctx->Driver.StencilOpSeparate + * instead. + */ +void GLAPIENTRY +_mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass) +{ + GLboolean set = GL_FALSE; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glStencilOpSeparate()\n"); + + if (!validate_stencil_op(ctx, sfail)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(sfail)"); + return; + } + if (!validate_stencil_op(ctx, zfail)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zfail)"); + return; + } + if (!validate_stencil_op(ctx, zpass)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zpass)"); + return; + } + if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { + _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(face)"); + return; + } + + if (face != GL_BACK) { + /* set front */ + if (ctx->Stencil.ZFailFunc[0] != zfail || + ctx->Stencil.ZPassFunc[0] != zpass || + ctx->Stencil.FailFunc[0] != sfail){ + FLUSH_VERTICES(ctx, _NEW_STENCIL); + ctx->Stencil.ZFailFunc[0] = zfail; + ctx->Stencil.ZPassFunc[0] = zpass; + ctx->Stencil.FailFunc[0] = sfail; + set = GL_TRUE; + } + } + if (face != GL_FRONT) { + /* set back */ + if (ctx->Stencil.ZFailFunc[1] != zfail || + ctx->Stencil.ZPassFunc[1] != zpass || + ctx->Stencil.FailFunc[1] != sfail) { + FLUSH_VERTICES(ctx, _NEW_STENCIL); + ctx->Stencil.ZFailFunc[1] = zfail; + ctx->Stencil.ZPassFunc[1] = zpass; + ctx->Stencil.FailFunc[1] = sfail; + set = GL_TRUE; + } + } + if (set && ctx->Driver.StencilOpSeparate) { + ctx->Driver.StencilOpSeparate(ctx, face, sfail, zfail, zpass); + } +} + + +/* OpenGL 2.0 */ +void GLAPIENTRY +_mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) +{ + GET_CURRENT_CONTEXT(ctx); + const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glStencilFuncSeparate()\n"); + + if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { + _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(face)"); + return; + } + if (!validate_stencil_func(ctx, func)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(func)"); + return; + } + + ref = CLAMP(ref, 0, stencilMax); + + FLUSH_VERTICES(ctx, _NEW_STENCIL); + + if (face != GL_BACK) { + /* set front */ + ctx->Stencil.Function[0] = func; + ctx->Stencil.Ref[0] = ref; + ctx->Stencil.ValueMask[0] = mask; + } + if (face != GL_FRONT) { + /* set back */ + ctx->Stencil.Function[1] = func; + ctx->Stencil.Ref[1] = ref; + ctx->Stencil.ValueMask[1] = mask; + } + if (ctx->Driver.StencilFuncSeparate) { + ctx->Driver.StencilFuncSeparate(ctx, face, func, ref, mask); + } +} + + +/* OpenGL 2.0 */ +void GLAPIENTRY +_mesa_StencilMaskSeparate(GLenum face, GLuint mask) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glStencilMaskSeparate()\n"); + + if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { + _mesa_error(ctx, GL_INVALID_ENUM, "glStencilaMaskSeparate(face)"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_STENCIL); + + if (face != GL_BACK) { + ctx->Stencil.WriteMask[0] = mask; + } + if (face != GL_FRONT) { + ctx->Stencil.WriteMask[1] = mask; + } + if (ctx->Driver.StencilMaskSeparate) { + ctx->Driver.StencilMaskSeparate(ctx, face, mask); + } +} + + +/** + * Update derived stencil state. + */ +void +_mesa_update_stencil(struct gl_context *ctx) +{ + const GLint face = ctx->Stencil._BackFace; + + ctx->Stencil._Enabled = (ctx->Stencil.Enabled && + ctx->DrawBuffer->Visual.stencilBits > 0); + + ctx->Stencil._TestTwoSide = + ctx->Stencil._Enabled && + (ctx->Stencil.Function[0] != ctx->Stencil.Function[face] || + ctx->Stencil.FailFunc[0] != ctx->Stencil.FailFunc[face] || + ctx->Stencil.ZPassFunc[0] != ctx->Stencil.ZPassFunc[face] || + ctx->Stencil.ZFailFunc[0] != ctx->Stencil.ZFailFunc[face] || + ctx->Stencil.Ref[0] != ctx->Stencil.Ref[face] || + ctx->Stencil.ValueMask[0] != ctx->Stencil.ValueMask[face] || + ctx->Stencil.WriteMask[0] != ctx->Stencil.WriteMask[face]); +} + + +/** + * Initialize the context stipple state. + * + * \param ctx GL context. + * + * Initializes __struct gl_contextRec::Stencil attribute group. + */ +void +_mesa_init_stencil(struct gl_context *ctx) +{ + ctx->Stencil.Enabled = GL_FALSE; + ctx->Stencil.TestTwoSide = GL_FALSE; + ctx->Stencil.ActiveFace = 0; /* 0 = GL_FRONT, 2 = GL_BACK */ + ctx->Stencil.Function[0] = GL_ALWAYS; + ctx->Stencil.Function[1] = GL_ALWAYS; + ctx->Stencil.Function[2] = GL_ALWAYS; + ctx->Stencil.FailFunc[0] = GL_KEEP; + ctx->Stencil.FailFunc[1] = GL_KEEP; + ctx->Stencil.FailFunc[2] = GL_KEEP; + ctx->Stencil.ZPassFunc[0] = GL_KEEP; + ctx->Stencil.ZPassFunc[1] = GL_KEEP; + ctx->Stencil.ZPassFunc[2] = GL_KEEP; + ctx->Stencil.ZFailFunc[0] = GL_KEEP; + ctx->Stencil.ZFailFunc[1] = GL_KEEP; + ctx->Stencil.ZFailFunc[2] = GL_KEEP; + ctx->Stencil.Ref[0] = 0; + ctx->Stencil.Ref[1] = 0; + ctx->Stencil.Ref[2] = 0; + ctx->Stencil.ValueMask[0] = ~0U; + ctx->Stencil.ValueMask[1] = ~0U; + ctx->Stencil.ValueMask[2] = ~0U; + ctx->Stencil.WriteMask[0] = ~0U; + ctx->Stencil.WriteMask[1] = ~0U; + ctx->Stencil.WriteMask[2] = ~0U; + ctx->Stencil.Clear = 0; + ctx->Stencil._BackFace = 1; +} diff --git a/mesalib/src/mesa/program/ir_to_mesa.cpp b/mesalib/src/mesa/program/ir_to_mesa.cpp index 3794c0de0..d0ec23fc8 100644 --- a/mesalib/src/mesa/program/ir_to_mesa.cpp +++ b/mesalib/src/mesa/program/ir_to_mesa.cpp @@ -2742,13 +2742,46 @@ ir_to_mesa_visitor::copy_propagate(void) /* Continuing the block, clear any written channels from * the ACP. */ - if (inst->dst_reg.file == PROGRAM_TEMPORARY) { - if (inst->dst_reg.reladdr) { - memset(acp, 0, sizeof(*acp) * this->next_temp * 4); - } else { - for (int i = 0; i < 4; i++) { - if (inst->dst_reg.writemask & (1 << i)) { - acp[4 * inst->dst_reg.index + i] = NULL; + if (inst->dst_reg.file == PROGRAM_TEMPORARY && inst->dst_reg.reladdr) { + /* Any temporary might be written, so no copy propagation + * across this instruction. + */ + memset(acp, 0, sizeof(*acp) * this->next_temp * 4); + } else if (inst->dst_reg.file == PROGRAM_OUTPUT && + inst->dst_reg.reladdr) { + /* Any output might be written, so no copy propagation + * from outputs across this instruction. + */ + for (int r = 0; r < this->next_temp; r++) { + for (int c = 0; c < 4; c++) { + if (acp[4 * r + c]->src_reg[0].file == PROGRAM_OUTPUT) + acp[4 * r + c] = NULL; + } + } + } else if (inst->dst_reg.file == PROGRAM_TEMPORARY || + inst->dst_reg.file == PROGRAM_OUTPUT) { + /* Clear where it's used as dst. */ + if (inst->dst_reg.file == PROGRAM_TEMPORARY) { + for (int c = 0; c < 4; c++) { + if (inst->dst_reg.writemask & (1 << c)) { + acp[4 * inst->dst_reg.index + c] = NULL; + } + } + } + + /* Clear where it's used as src. */ + for (int r = 0; r < this->next_temp; r++) { + for (int c = 0; c < 4; c++) { + if (!acp[4 * r + c]) + continue; + + int src_chan = GET_SWZ(acp[4 * r + c]->src_reg[0].swizzle, c); + + if (acp[4 * r + c]->src_reg[0].file == inst->dst_reg.file && + acp[4 * r + c]->src_reg[0].index == inst->dst_reg.index && + inst->dst_reg.writemask & (1 << src_chan)) + { + acp[4 * r + c] = NULL; } } } diff --git a/mesalib/src/mesa/state_tracker/st_context.c b/mesalib/src/mesa/state_tracker/st_context.c index 593da8fa6..dccbff3c1 100644 --- a/mesalib/src/mesa/state_tracker/st_context.c +++ b/mesalib/src/mesa/state_tracker/st_context.c @@ -1,292 +1,292 @@ -/************************************************************************** - * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. - * 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, sub license, 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 NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. - * - **************************************************************************/ - -#include "main/imports.h" -#include "main/context.h" -#include "main/shaderobj.h" -#include "program/prog_cache.h" -#include "vbo/vbo.h" -#include "glapi/glapi.h" -#include "st_context.h" -#include "st_debug.h" -#include "st_cb_accum.h" -#include "st_cb_bitmap.h" -#include "st_cb_blit.h" -#include "st_cb_bufferobjects.h" -#include "st_cb_clear.h" -#include "st_cb_condrender.h" -#include "st_cb_drawpixels.h" -#include "st_cb_rasterpos.h" -#include "st_cb_drawtex.h" -#include "st_cb_eglimage.h" -#include "st_cb_fbo.h" -#include "st_cb_feedback.h" -#include "st_cb_program.h" -#include "st_cb_queryobj.h" -#include "st_cb_readpixels.h" -#include "st_cb_texture.h" -#include "st_cb_xformfb.h" -#include "st_cb_flush.h" -#include "st_cb_strings.h" -#include "st_cb_viewport.h" -#include "st_atom.h" -#include "st_draw.h" -#include "st_extensions.h" -#include "st_gen_mipmap.h" -#include "st_program.h" -#include "pipe/p_context.h" -#include "util/u_inlines.h" -#include "cso_cache/cso_context.h" - - -DEBUG_GET_ONCE_BOOL_OPTION(mesa_mvp_dp4, "MESA_MVP_DP4", FALSE) - - -/** - * Called via ctx->Driver.UpdateState() - */ -void st_invalidate_state(struct gl_context * ctx, GLuint new_state) -{ - struct st_context *st = st_context(ctx); - - st->dirty.mesa |= new_state; - st->dirty.st |= ST_NEW_MESA; - - /* This is the only core Mesa module we depend upon. - * No longer use swrast, swsetup, tnl. - */ - _vbo_InvalidateState(ctx, new_state); -} - - -/** - * Check for multisample env var override. - */ -int -st_get_msaa(void) -{ - const char *msaa = _mesa_getenv("__GL_FSAA_MODE"); - if (msaa) - return atoi(msaa); - return 0; -} - - -static struct st_context * -st_create_context_priv( struct gl_context *ctx, struct pipe_context *pipe ) -{ - uint i; - struct st_context *st = ST_CALLOC_STRUCT( st_context ); - - ctx->st = st; - - st->ctx = ctx; - st->pipe = pipe; - - /* XXX: this is one-off, per-screen init: */ - st_debug_init(); - - /* state tracker needs the VBO module */ - _vbo_CreateContext(ctx); - - st->dirty.mesa = ~0; - st->dirty.st = ~0; - - st->cso_context = cso_create_context(pipe); - - st_init_atoms( st ); - st_init_bitmap(st); - st_init_clear(st); - st_init_draw( st ); - st_init_generate_mipmap(st); - st_init_blit(st); - - if(pipe->screen->get_param(pipe->screen, PIPE_CAP_NPOT_TEXTURES)) - st->internal_target = PIPE_TEXTURE_2D; - else - st->internal_target = PIPE_TEXTURE_RECT; - - for (i = 0; i < PIPE_MAX_SAMPLERS; i++) - st->state.sampler_list[i] = &st->state.samplers[i]; - - for (i = 0; i < 3; i++) { - memset(&st->velems_util_draw[i], 0, sizeof(struct pipe_vertex_element)); - st->velems_util_draw[i].src_offset = i * 4 * sizeof(float); - st->velems_util_draw[i].instance_divisor = 0; - st->velems_util_draw[i].vertex_buffer_index = 0; - st->velems_util_draw[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; - } - - /* we want all vertex data to be placed in buffer objects */ - vbo_use_buffer_objects(ctx); - - /* Need these flags: - */ - st->ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE; - - st->ctx->VertexProgram._MaintainTnlProgram = GL_TRUE; - - st->pixel_xfer.cache = _mesa_new_program_cache(); - - st->force_msaa = st_get_msaa(); - - /* GL limits and extensions */ - st_init_limits(st); - st_init_extensions(st); - - return st; -} - - -struct st_context *st_create_context(gl_api api, struct pipe_context *pipe, - const struct gl_config *visual, - struct st_context *share) -{ - struct gl_context *ctx; - struct gl_context *shareCtx = share ? share->ctx : NULL; - struct dd_function_table funcs; - - /* Sanity checks */ - assert(MESA_SHADER_VERTEX == PIPE_SHADER_VERTEX); - assert(MESA_SHADER_FRAGMENT == PIPE_SHADER_FRAGMENT); - assert(MESA_SHADER_GEOMETRY == PIPE_SHADER_GEOMETRY); - - memset(&funcs, 0, sizeof(funcs)); - st_init_driver_functions(&funcs); - - ctx = _mesa_create_context_for_api(api, visual, shareCtx, &funcs, NULL); - - /* XXX: need a capability bit in gallium to query if the pipe - * driver prefers DP4 or MUL/MAD for vertex transformation. - */ - if (debug_get_option_mesa_mvp_dp4()) - _mesa_set_mvp_with_dp4( ctx, GL_TRUE ); - - return st_create_context_priv(ctx, pipe); -} - - -static void st_destroy_context_priv( struct st_context *st ) -{ - uint i; - - st_destroy_atoms( st ); - st_destroy_draw( st ); - st_destroy_generate_mipmap(st); - st_destroy_blit(st); - st_destroy_clear(st); - st_destroy_bitmap(st); - st_destroy_drawpix(st); - st_destroy_drawtex(st); - - for (i = 0; i < Elements(st->state.sampler_views); i++) { - pipe_sampler_view_reference(&st->state.sampler_views[i], NULL); - } - - if (st->default_texture) { - st->ctx->Driver.DeleteTexture(st->ctx, st->default_texture); - st->default_texture = NULL; - } - - free( st ); -} - - -void st_destroy_context( struct st_context *st ) -{ - struct pipe_context *pipe = st->pipe; - struct cso_context *cso = st->cso_context; - struct gl_context *ctx = st->ctx; - GLuint i; - - /* need to unbind and destroy CSO objects before anything else */ - cso_release_all(st->cso_context); - - st_reference_fragprog(st, &st->fp, NULL); - st_reference_vertprog(st, &st->vp, NULL); - - /* release framebuffer surfaces */ - for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) { - pipe_surface_reference(&st->state.framebuffer.cbufs[i], NULL); - } - pipe_surface_reference(&st->state.framebuffer.zsbuf, NULL); - - pipe->set_index_buffer(pipe, NULL); - - for (i = 0; i < PIPE_SHADER_TYPES; i++) { - pipe->set_constant_buffer(pipe, i, 0, NULL); - } - - _mesa_delete_program_cache(st->ctx, st->pixel_xfer.cache); - - _vbo_DestroyContext(st->ctx); - - st_destroy_program_variants(st); - - _mesa_free_context_data(ctx); - - st_destroy_context_priv(st); - - cso_destroy_context(cso); - - pipe->destroy( pipe ); - - free(ctx); -} - - -void st_init_driver_functions(struct dd_function_table *functions) -{ - _mesa_init_shader_object_functions(functions); - - st_init_accum_functions(functions); - st_init_blit_functions(functions); - st_init_bufferobject_functions(functions); - st_init_clear_functions(functions); - st_init_bitmap_functions(functions); - st_init_drawpixels_functions(functions); - st_init_rasterpos_functions(functions); - - st_init_drawtex_functions(functions); - - st_init_eglimage_functions(functions); - - st_init_fbo_functions(functions); - st_init_feedback_functions(functions); - st_init_program_functions(functions); - st_init_query_functions(functions); - st_init_cond_render_functions(functions); - st_init_readpixels_functions(functions); - st_init_texture_functions(functions); - st_init_flush_functions(functions); - st_init_string_functions(functions); - st_init_viewport_functions(functions); - - st_init_xformfb_functions(functions); - - functions->UpdateState = st_invalidate_state; -} +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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, sub license, 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include "main/imports.h" +#include "main/context.h" +#include "main/shaderobj.h" +#include "program/prog_cache.h" +#include "vbo/vbo.h" +#include "glapi/glapi.h" +#include "st_context.h" +#include "st_debug.h" +#include "st_cb_accum.h" +#include "st_cb_bitmap.h" +#include "st_cb_blit.h" +#include "st_cb_bufferobjects.h" +#include "st_cb_clear.h" +#include "st_cb_condrender.h" +#include "st_cb_drawpixels.h" +#include "st_cb_rasterpos.h" +#include "st_cb_drawtex.h" +#include "st_cb_eglimage.h" +#include "st_cb_fbo.h" +#include "st_cb_feedback.h" +#include "st_cb_program.h" +#include "st_cb_queryobj.h" +#include "st_cb_readpixels.h" +#include "st_cb_texture.h" +#include "st_cb_xformfb.h" +#include "st_cb_flush.h" +#include "st_cb_strings.h" +#include "st_cb_viewport.h" +#include "st_atom.h" +#include "st_draw.h" +#include "st_extensions.h" +#include "st_gen_mipmap.h" +#include "st_program.h" +#include "pipe/p_context.h" +#include "util/u_inlines.h" +#include "cso_cache/cso_context.h" + + +DEBUG_GET_ONCE_BOOL_OPTION(mesa_mvp_dp4, "MESA_MVP_DP4", FALSE) + + +/** + * Called via ctx->Driver.UpdateState() + */ +void st_invalidate_state(struct gl_context * ctx, GLuint new_state) +{ + struct st_context *st = st_context(ctx); + + st->dirty.mesa |= new_state; + st->dirty.st |= ST_NEW_MESA; + + /* This is the only core Mesa module we depend upon. + * No longer use swrast, swsetup, tnl. + */ + _vbo_InvalidateState(ctx, new_state); +} + + +/** + * Check for multisample env var override. + */ +int +st_get_msaa(void) +{ + const char *msaa = _mesa_getenv("__GL_FSAA_MODE"); + if (msaa) + return atoi(msaa); + return 0; +} + + +static struct st_context * +st_create_context_priv( struct gl_context *ctx, struct pipe_context *pipe ) +{ + uint i; + struct st_context *st = ST_CALLOC_STRUCT( st_context ); + + ctx->st = st; + + st->ctx = ctx; + st->pipe = pipe; + + /* XXX: this is one-off, per-screen init: */ + st_debug_init(); + + /* state tracker needs the VBO module */ + _vbo_CreateContext(ctx); + + st->dirty.mesa = ~0; + st->dirty.st = ~0; + + st->cso_context = cso_create_context(pipe); + + st_init_atoms( st ); + st_init_bitmap(st); + st_init_clear(st); + st_init_draw( st ); + st_init_generate_mipmap(st); + st_init_blit(st); + + if(pipe->screen->get_param(pipe->screen, PIPE_CAP_NPOT_TEXTURES)) + st->internal_target = PIPE_TEXTURE_2D; + else + st->internal_target = PIPE_TEXTURE_RECT; + + for (i = 0; i < PIPE_MAX_SAMPLERS; i++) + st->state.sampler_list[i] = &st->state.samplers[i]; + + for (i = 0; i < 3; i++) { + memset(&st->velems_util_draw[i], 0, sizeof(struct pipe_vertex_element)); + st->velems_util_draw[i].src_offset = i * 4 * sizeof(float); + st->velems_util_draw[i].instance_divisor = 0; + st->velems_util_draw[i].vertex_buffer_index = 0; + st->velems_util_draw[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; + } + + /* we want all vertex data to be placed in buffer objects */ + vbo_use_buffer_objects(ctx); + + /* Need these flags: + */ + st->ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE; + + st->ctx->VertexProgram._MaintainTnlProgram = GL_TRUE; + + st->pixel_xfer.cache = _mesa_new_program_cache(); + + st->force_msaa = st_get_msaa(); + + /* GL limits and extensions */ + st_init_limits(st); + st_init_extensions(st); + + return st; +} + + +struct st_context *st_create_context(gl_api api, struct pipe_context *pipe, + const struct gl_config *visual, + struct st_context *share) +{ + struct gl_context *ctx; + struct gl_context *shareCtx = share ? share->ctx : NULL; + struct dd_function_table funcs; + + /* Sanity checks */ + assert(MESA_SHADER_VERTEX == PIPE_SHADER_VERTEX); + assert(MESA_SHADER_FRAGMENT == PIPE_SHADER_FRAGMENT); + assert(MESA_SHADER_GEOMETRY == PIPE_SHADER_GEOMETRY); + + memset(&funcs, 0, sizeof(funcs)); + st_init_driver_functions(&funcs); + + ctx = _mesa_create_context(api, visual, shareCtx, &funcs, NULL); + + /* XXX: need a capability bit in gallium to query if the pipe + * driver prefers DP4 or MUL/MAD for vertex transformation. + */ + if (debug_get_option_mesa_mvp_dp4()) + _mesa_set_mvp_with_dp4( ctx, GL_TRUE ); + + return st_create_context_priv(ctx, pipe); +} + + +static void st_destroy_context_priv( struct st_context *st ) +{ + uint i; + + st_destroy_atoms( st ); + st_destroy_draw( st ); + st_destroy_generate_mipmap(st); + st_destroy_blit(st); + st_destroy_clear(st); + st_destroy_bitmap(st); + st_destroy_drawpix(st); + st_destroy_drawtex(st); + + for (i = 0; i < Elements(st->state.sampler_views); i++) { + pipe_sampler_view_reference(&st->state.sampler_views[i], NULL); + } + + if (st->default_texture) { + st->ctx->Driver.DeleteTexture(st->ctx, st->default_texture); + st->default_texture = NULL; + } + + free( st ); +} + + +void st_destroy_context( struct st_context *st ) +{ + struct pipe_context *pipe = st->pipe; + struct cso_context *cso = st->cso_context; + struct gl_context *ctx = st->ctx; + GLuint i; + + /* need to unbind and destroy CSO objects before anything else */ + cso_release_all(st->cso_context); + + st_reference_fragprog(st, &st->fp, NULL); + st_reference_vertprog(st, &st->vp, NULL); + + /* release framebuffer surfaces */ + for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) { + pipe_surface_reference(&st->state.framebuffer.cbufs[i], NULL); + } + pipe_surface_reference(&st->state.framebuffer.zsbuf, NULL); + + pipe->set_index_buffer(pipe, NULL); + + for (i = 0; i < PIPE_SHADER_TYPES; i++) { + pipe->set_constant_buffer(pipe, i, 0, NULL); + } + + _mesa_delete_program_cache(st->ctx, st->pixel_xfer.cache); + + _vbo_DestroyContext(st->ctx); + + st_destroy_program_variants(st); + + _mesa_free_context_data(ctx); + + st_destroy_context_priv(st); + + cso_destroy_context(cso); + + pipe->destroy( pipe ); + + free(ctx); +} + + +void st_init_driver_functions(struct dd_function_table *functions) +{ + _mesa_init_shader_object_functions(functions); + + st_init_accum_functions(functions); + st_init_blit_functions(functions); + st_init_bufferobject_functions(functions); + st_init_clear_functions(functions); + st_init_bitmap_functions(functions); + st_init_drawpixels_functions(functions); + st_init_rasterpos_functions(functions); + + st_init_drawtex_functions(functions); + + st_init_eglimage_functions(functions); + + st_init_fbo_functions(functions); + st_init_feedback_functions(functions); + st_init_program_functions(functions); + st_init_query_functions(functions); + st_init_cond_render_functions(functions); + st_init_readpixels_functions(functions); + st_init_texture_functions(functions); + st_init_flush_functions(functions); + st_init_string_functions(functions); + st_init_viewport_functions(functions); + + st_init_xformfb_functions(functions); + + functions->UpdateState = st_invalidate_state; +} diff --git a/mesalib/src/mesa/state_tracker/st_draw_feedback.c b/mesalib/src/mesa/state_tracker/st_draw_feedback.c index 72ed75e73..c11c7696e 100644 --- a/mesalib/src/mesa/state_tracker/st_draw_feedback.c +++ b/mesalib/src/mesa/state_tracker/st_draw_feedback.c @@ -1,278 +1,279 @@ -/************************************************************************** - * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. - * 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, sub license, 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 NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. - * - **************************************************************************/ - -#include "main/imports.h" -#include "main/image.h" -#include "main/macros.h" -#include "main/mfeatures.h" - -#include "vbo/vbo.h" - -#include "st_context.h" -#include "st_atom.h" -#include "st_cb_bufferobjects.h" -#include "st_draw.h" -#include "st_program.h" - -#include "pipe/p_context.h" -#include "pipe/p_defines.h" -#include "util/u_inlines.h" - -#include "draw/draw_private.h" -#include "draw/draw_context.h" - - -#if FEATURE_feedback || FEATURE_rastpos - -/** - * Set the (private) draw module's post-transformed vertex format when in - * GL_SELECT or GL_FEEDBACK mode or for glRasterPos. - */ -static void -set_feedback_vertex_format(struct gl_context *ctx) -{ -#if 0 - struct st_context *st = st_context(ctx); - struct vertex_info vinfo; - GLuint i; - - memset(&vinfo, 0, sizeof(vinfo)); - - if (ctx->RenderMode == GL_SELECT) { - assert(ctx->RenderMode == GL_SELECT); - vinfo.num_attribs = 1; - vinfo.format[0] = FORMAT_4F; - vinfo.interp_mode[0] = INTERP_LINEAR; - } - else { - /* GL_FEEDBACK, or glRasterPos */ - /* emit all attribs (pos, color, texcoord) as GLfloat[4] */ - vinfo.num_attribs = st->state.vs->cso->state.num_outputs; - for (i = 0; i < vinfo.num_attribs; i++) { - vinfo.format[i] = FORMAT_4F; - vinfo.interp_mode[i] = INTERP_LINEAR; - } - } - - draw_set_vertex_info(st->draw, &vinfo); -#endif -} - - -/** - * Called by VBO to draw arrays when in selection or feedback mode and - * to implement glRasterPos. - * This is very much like the normal draw_vbo() function above. - * Look at code refactoring some day. - * Might move this into the failover module some day. - */ -void -st_feedback_draw_vbo(struct gl_context *ctx, - const struct gl_client_array **arrays, - const struct _mesa_prim *prims, - GLuint nr_prims, - const struct _mesa_index_buffer *ib, - GLboolean index_bounds_valid, - GLuint min_index, - GLuint max_index) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - struct draw_context *draw = st->draw; - const struct st_vertex_program *vp; - const struct pipe_shader_state *vs; - struct pipe_vertex_buffer vbuffers[PIPE_MAX_SHADER_INPUTS]; - struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS]; - struct pipe_index_buffer ibuffer; - struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS]; - struct pipe_transfer *ib_transfer = NULL; - GLuint attr, i; - const void *mapped_indices = NULL; - - assert(draw); - - st_validate_state(st); - - if (!index_bounds_valid) - vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index); - - /* must get these after state validation! */ - vp = st->vp; - vs = &st->vp_variant->tgsi; - - if (!st->vp_variant->draw_shader) { - st->vp_variant->draw_shader = draw_create_vertex_shader(draw, vs); - } - - /* - * Set up the draw module's state. - * - * We'd like to do this less frequently, but the normal state-update - * code sends state updates to the pipe, not to our private draw module. - */ - assert(draw); - draw_set_viewport_state(draw, &st->state.viewport); - draw_set_clip_state(draw, &st->state.clip); - draw_set_rasterizer_state(draw, &st->state.rasterizer, NULL); - draw_bind_vertex_shader(draw, st->vp_variant->draw_shader); - set_feedback_vertex_format(ctx); - - /* loop over TGSI shader inputs to determine vertex buffer - * and attribute info - */ - for (attr = 0; attr < vp->num_inputs; attr++) { - const GLuint mesaAttr = vp->index_to_input[attr]; - struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; - void *map; - - if (bufobj && bufobj->Name) { - /* Attribute data is in a VBO. - * Recall that for VBOs, the gl_client_array->Ptr field is - * really an offset from the start of the VBO, not a pointer. - */ - struct st_buffer_object *stobj = st_buffer_object(bufobj); - assert(stobj->buffer); - - vbuffers[attr].buffer = NULL; - pipe_resource_reference(&vbuffers[attr].buffer, stobj->buffer); - vbuffers[attr].buffer_offset = pointer_to_offset(arrays[0]->Ptr); - velements[attr].src_offset = arrays[mesaAttr]->Ptr - arrays[0]->Ptr; - } - else { - /* attribute data is in user-space memory, not a VBO */ - uint bytes = (arrays[mesaAttr]->Size - * _mesa_sizeof_type(arrays[mesaAttr]->Type) - * (max_index + 1)); - - /* wrap user data */ - vbuffers[attr].buffer - = pipe_user_buffer_create(pipe->screen, (void *) arrays[mesaAttr]->Ptr, - bytes, - PIPE_BIND_VERTEX_BUFFER); - vbuffers[attr].buffer_offset = 0; - velements[attr].src_offset = 0; - } - - /* common-case setup */ - vbuffers[attr].stride = arrays[mesaAttr]->StrideB; /* in bytes */ - vbuffers[attr].max_index = max_index; - velements[attr].instance_divisor = 0; - velements[attr].vertex_buffer_index = attr; - velements[attr].src_format = - st_pipe_vertex_format(arrays[mesaAttr]->Type, - arrays[mesaAttr]->Size, - arrays[mesaAttr]->Format, - arrays[mesaAttr]->Normalized); - assert(velements[attr].src_format); - - /* tell draw about this attribute */ -#if 0 - draw_set_vertex_buffer(draw, attr, &vbuffer[attr]); -#endif - - /* map the attrib buffer */ - map = pipe_buffer_map(pipe, vbuffers[attr].buffer, - PIPE_TRANSFER_READ, - &vb_transfer[attr]); - draw_set_mapped_vertex_buffer(draw, attr, map); - } - - draw_set_vertex_buffers(draw, vp->num_inputs, vbuffers); - draw_set_vertex_elements(draw, vp->num_inputs, velements); - - memset(&ibuffer, 0, sizeof(ibuffer)); - if (ib) { - struct gl_buffer_object *bufobj = ib->obj; - - switch (ib->type) { - case GL_UNSIGNED_INT: - ibuffer.index_size = 4; - break; - case GL_UNSIGNED_SHORT: - ibuffer.index_size = 2; - break; - case GL_UNSIGNED_BYTE: - ibuffer.index_size = 1; - break; - default: - assert(0); - return; - } - - if (bufobj && bufobj->Name) { - struct st_buffer_object *stobj = st_buffer_object(bufobj); - - pipe_resource_reference(&ibuffer.buffer, stobj->buffer); - ibuffer.offset = pointer_to_offset(ib->ptr); - - mapped_indices = pipe_buffer_map(pipe, stobj->buffer, - PIPE_TRANSFER_READ, &ib_transfer); - } - else { - /* skip setting ibuffer.buffer as the draw module does not use it */ - mapped_indices = ib->ptr; - } - - draw_set_index_buffer(draw, &ibuffer); - draw_set_mapped_index_buffer(draw, mapped_indices); - } - - /* set the constant buffer */ - draw_set_mapped_constant_buffer(st->draw, PIPE_SHADER_VERTEX, 0, - st->state.constants[PIPE_SHADER_VERTEX].ptr, - st->state.constants[PIPE_SHADER_VERTEX].size); - - - /* draw here */ - for (i = 0; i < nr_prims; i++) { - draw_arrays(draw, prims[i].mode, prims[i].start, prims[i].count); - } - - - /* - * unmap vertex/index buffers - */ - for (i = 0; i < PIPE_MAX_ATTRIBS; i++) { - if (draw->pt.vertex_buffer[i].buffer) { - pipe_buffer_unmap(pipe, vb_transfer[i]); - pipe_resource_reference(&draw->pt.vertex_buffer[i].buffer, NULL); - draw_set_mapped_vertex_buffer(draw, i, NULL); - } - } - - if (ib) { - draw_set_mapped_index_buffer(draw, NULL); - draw_set_index_buffer(draw, NULL); - - if (ib_transfer) - pipe_buffer_unmap(pipe, ib_transfer); - pipe_resource_reference(&ibuffer.buffer, NULL); - } -} - -#endif /* FEATURE_feedback || FEATURE_rastpos */ - +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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, sub license, 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include "main/imports.h" +#include "main/image.h" +#include "main/macros.h" +#include "main/mfeatures.h" + +#include "vbo/vbo.h" + +#include "st_context.h" +#include "st_atom.h" +#include "st_cb_bufferobjects.h" +#include "st_draw.h" +#include "st_program.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "util/u_inlines.h" + +#include "draw/draw_private.h" +#include "draw/draw_context.h" + + +#if FEATURE_feedback || FEATURE_rastpos + +/** + * Set the (private) draw module's post-transformed vertex format when in + * GL_SELECT or GL_FEEDBACK mode or for glRasterPos. + */ +static void +set_feedback_vertex_format(struct gl_context *ctx) +{ +#if 0 + struct st_context *st = st_context(ctx); + struct vertex_info vinfo; + GLuint i; + + memset(&vinfo, 0, sizeof(vinfo)); + + if (ctx->RenderMode == GL_SELECT) { + assert(ctx->RenderMode == GL_SELECT); + vinfo.num_attribs = 1; + vinfo.format[0] = FORMAT_4F; + vinfo.interp_mode[0] = INTERP_LINEAR; + } + else { + /* GL_FEEDBACK, or glRasterPos */ + /* emit all attribs (pos, color, texcoord) as GLfloat[4] */ + vinfo.num_attribs = st->state.vs->cso->state.num_outputs; + for (i = 0; i < vinfo.num_attribs; i++) { + vinfo.format[i] = FORMAT_4F; + vinfo.interp_mode[i] = INTERP_LINEAR; + } + } + + draw_set_vertex_info(st->draw, &vinfo); +#endif +} + + +/** + * Called by VBO to draw arrays when in selection or feedback mode and + * to implement glRasterPos. + * This is very much like the normal draw_vbo() function above. + * Look at code refactoring some day. + * Might move this into the failover module some day. + */ +void +st_feedback_draw_vbo(struct gl_context *ctx, + const struct gl_client_array **arrays, + const struct _mesa_prim *prims, + GLuint nr_prims, + const struct _mesa_index_buffer *ib, + GLboolean index_bounds_valid, + GLuint min_index, + GLuint max_index) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct draw_context *draw = st->draw; + const struct st_vertex_program *vp; + const struct pipe_shader_state *vs; + struct pipe_vertex_buffer vbuffers[PIPE_MAX_SHADER_INPUTS]; + struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS]; + struct pipe_index_buffer ibuffer; + struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS]; + struct pipe_transfer *ib_transfer = NULL; + GLuint attr, i; + const void *mapped_indices = NULL; + + assert(draw); + + st_validate_state(st); + + if (!index_bounds_valid) + vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index); + + /* must get these after state validation! */ + vp = st->vp; + vs = &st->vp_variant->tgsi; + + if (!st->vp_variant->draw_shader) { + st->vp_variant->draw_shader = draw_create_vertex_shader(draw, vs); + } + + /* + * Set up the draw module's state. + * + * We'd like to do this less frequently, but the normal state-update + * code sends state updates to the pipe, not to our private draw module. + */ + assert(draw); + draw_set_viewport_state(draw, &st->state.viewport); + draw_set_clip_state(draw, &st->state.clip); + draw_set_rasterizer_state(draw, &st->state.rasterizer, NULL); + draw_bind_vertex_shader(draw, st->vp_variant->draw_shader); + set_feedback_vertex_format(ctx); + + /* loop over TGSI shader inputs to determine vertex buffer + * and attribute info + */ + for (attr = 0; attr < vp->num_inputs; attr++) { + const GLuint mesaAttr = vp->index_to_input[attr]; + struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; + void *map; + + if (bufobj && bufobj->Name) { + /* Attribute data is in a VBO. + * Recall that for VBOs, the gl_client_array->Ptr field is + * really an offset from the start of the VBO, not a pointer. + */ + struct st_buffer_object *stobj = st_buffer_object(bufobj); + assert(stobj->buffer); + + vbuffers[attr].buffer = NULL; + pipe_resource_reference(&vbuffers[attr].buffer, stobj->buffer); + vbuffers[attr].buffer_offset = pointer_to_offset(arrays[0]->Ptr); + velements[attr].src_offset = arrays[mesaAttr]->Ptr - arrays[0]->Ptr; + } + else { + /* attribute data is in user-space memory, not a VBO */ + uint bytes = (arrays[mesaAttr]->Size + * _mesa_sizeof_type(arrays[mesaAttr]->Type) + * (max_index + 1)); + + /* wrap user data */ + vbuffers[attr].buffer + = pipe_user_buffer_create(pipe->screen, (void *) arrays[mesaAttr]->Ptr, + bytes, + PIPE_BIND_VERTEX_BUFFER); + vbuffers[attr].buffer_offset = 0; + velements[attr].src_offset = 0; + } + + /* common-case setup */ + vbuffers[attr].stride = arrays[mesaAttr]->StrideB; /* in bytes */ + vbuffers[attr].max_index = max_index; + velements[attr].instance_divisor = 0; + velements[attr].vertex_buffer_index = attr; + velements[attr].src_format = + st_pipe_vertex_format(arrays[mesaAttr]->Type, + arrays[mesaAttr]->Size, + arrays[mesaAttr]->Format, + arrays[mesaAttr]->Normalized); + assert(velements[attr].src_format); + + /* tell draw about this attribute */ +#if 0 + draw_set_vertex_buffer(draw, attr, &vbuffer[attr]); +#endif + + /* map the attrib buffer */ + map = pipe_buffer_map(pipe, vbuffers[attr].buffer, + PIPE_TRANSFER_READ, + &vb_transfer[attr]); + draw_set_mapped_vertex_buffer(draw, attr, map); + } + + draw_set_vertex_buffers(draw, vp->num_inputs, vbuffers); + draw_set_vertex_elements(draw, vp->num_inputs, velements); + + memset(&ibuffer, 0, sizeof(ibuffer)); + if (ib) { + struct gl_buffer_object *bufobj = ib->obj; + + switch (ib->type) { + case GL_UNSIGNED_INT: + ibuffer.index_size = 4; + break; + case GL_UNSIGNED_SHORT: + ibuffer.index_size = 2; + break; + case GL_UNSIGNED_BYTE: + ibuffer.index_size = 1; + break; + default: + assert(0); + return; + } + + if (bufobj && bufobj->Name) { + struct st_buffer_object *stobj = st_buffer_object(bufobj); + + pipe_resource_reference(&ibuffer.buffer, stobj->buffer); + ibuffer.offset = pointer_to_offset(ib->ptr); + + mapped_indices = pipe_buffer_map(pipe, stobj->buffer, + PIPE_TRANSFER_READ, &ib_transfer); + } + else { + /* skip setting ibuffer.buffer as the draw module does not use it */ + mapped_indices = ib->ptr; + } + + draw_set_index_buffer(draw, &ibuffer); + draw_set_mapped_index_buffer(draw, mapped_indices); + } + + /* set the constant buffer */ + draw_set_mapped_constant_buffer(st->draw, PIPE_SHADER_VERTEX, 0, + st->state.constants[PIPE_SHADER_VERTEX].ptr, + st->state.constants[PIPE_SHADER_VERTEX].size); + + + /* draw here */ + for (i = 0; i < nr_prims; i++) { + draw_arrays(draw, prims[i].mode, prims[i].start, prims[i].count); + } + + + /* + * unmap vertex/index buffers + */ + for (i = 0; i < PIPE_MAX_ATTRIBS; i++) { + if (draw->pt.vertex_buffer[i].buffer) { + pipe_buffer_unmap(pipe, vb_transfer[i]); + pipe_resource_reference(&draw->pt.vertex_buffer[i].buffer, NULL); + draw_set_mapped_vertex_buffer(draw, i, NULL); + pipe_resource_reference(&vbuffers[i].buffer, NULL); + } + } + + if (ib) { + draw_set_mapped_index_buffer(draw, NULL); + draw_set_index_buffer(draw, NULL); + + if (ib_transfer) + pipe_buffer_unmap(pipe, ib_transfer); + pipe_resource_reference(&ibuffer.buffer, NULL); + } +} + +#endif /* FEATURE_feedback || FEATURE_rastpos */ + diff --git a/mesalib/src/mesa/state_tracker/st_program.c b/mesalib/src/mesa/state_tracker/st_program.c index f70e5005f..fc1dfb3ef 100644 --- a/mesalib/src/mesa/state_tracker/st_program.c +++ b/mesalib/src/mesa/state_tracker/st_program.c @@ -1,1154 +1,1165 @@ -/************************************************************************** - * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. - * 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, sub license, 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 NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. - * - **************************************************************************/ - /* - * Authors: - * Keith Whitwell - * Brian Paul - */ - - -#include "main/imports.h" -#include "main/hash.h" -#include "main/mfeatures.h" -#include "main/mtypes.h" -#include "program/prog_parameter.h" -#include "program/prog_print.h" -#include "program/programopt.h" - -#include "pipe/p_context.h" -#include "pipe/p_defines.h" -#include "pipe/p_shader_tokens.h" -#include "draw/draw_context.h" -#include "tgsi/tgsi_dump.h" -#include "tgsi/tgsi_ureg.h" - -#include "st_debug.h" -#include "st_cb_bitmap.h" -#include "st_cb_drawpixels.h" -#include "st_context.h" -#include "st_program.h" -#include "st_mesa_to_tgsi.h" -#include "cso_cache/cso_context.h" - - - -/** - * Delete a vertex program variant. Note the caller must unlink - * the variant from the linked list. - */ -static void -delete_vp_variant(struct st_context *st, struct st_vp_variant *vpv) -{ - if (vpv->driver_shader) - cso_delete_vertex_shader(st->cso_context, vpv->driver_shader); - -#if FEATURE_feedback || FEATURE_rastpos - if (vpv->draw_shader) - draw_delete_vertex_shader( st->draw, vpv->draw_shader ); -#endif - - if (vpv->tgsi.tokens) - st_free_tokens(vpv->tgsi.tokens); - - FREE( vpv ); -} - - - -/** - * Clean out any old compilations: - */ -void -st_release_vp_variants( struct st_context *st, - struct st_vertex_program *stvp ) -{ - struct st_vp_variant *vpv; - - for (vpv = stvp->variants; vpv; ) { - struct st_vp_variant *next = vpv->next; - delete_vp_variant(st, vpv); - vpv = next; - } - - stvp->variants = NULL; -} - - - -/** - * Delete a fragment program variant. Note the caller must unlink - * the variant from the linked list. - */ -static void -delete_fp_variant(struct st_context *st, struct st_fp_variant *fpv) -{ - if (fpv->driver_shader) - cso_delete_fragment_shader(st->cso_context, fpv->driver_shader); - - FREE(fpv); -} - - -/** - * Free all variants of a fragment program. - */ -void -st_release_fp_variants(struct st_context *st, struct st_fragment_program *stfp) -{ - struct st_fp_variant *fpv; - - for (fpv = stfp->variants; fpv; ) { - struct st_fp_variant *next = fpv->next; - delete_fp_variant(st, fpv); - fpv = next; - } - - stfp->variants = NULL; -} - - -/** - * Delete a geometry program variant. Note the caller must unlink - * the variant from the linked list. - */ -static void -delete_gp_variant(struct st_context *st, struct st_gp_variant *gpv) -{ - if (gpv->driver_shader) - cso_delete_geometry_shader(st->cso_context, gpv->driver_shader); - - FREE(gpv); -} - - -/** - * Free all variants of a geometry program. - */ -void -st_release_gp_variants(struct st_context *st, struct st_geometry_program *stgp) -{ - struct st_gp_variant *gpv; - - for (gpv = stgp->variants; gpv; ) { - struct st_gp_variant *next = gpv->next; - delete_gp_variant(st, gpv); - gpv = next; - } - - stgp->variants = NULL; -} - - - - -/** - * Translate a Mesa vertex shader into a TGSI shader. - * \param outputMapping to map vertex program output registers (VERT_RESULT_x) - * to TGSI output slots - * \param tokensOut destination for TGSI tokens - * \return pointer to cached pipe_shader object. - */ -static void -st_prepare_vertex_program(struct st_context *st, - struct st_vertex_program *stvp) -{ - GLuint attr; - - stvp->num_inputs = 0; - stvp->num_outputs = 0; - - if (stvp->Base.IsPositionInvariant) - _mesa_insert_mvp_code(st->ctx, &stvp->Base); - - assert(stvp->Base.Base.NumInstructions > 1); - - /* - * Determine number of inputs, the mappings between VERT_ATTRIB_x - * and TGSI generic input indexes, plus input attrib semantic info. - */ - for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) { - if (stvp->Base.Base.InputsRead & (1 << attr)) { - stvp->input_to_index[attr] = stvp->num_inputs; - stvp->index_to_input[stvp->num_inputs] = attr; - stvp->num_inputs++; - } - } - /* bit of a hack, presetup potentially unused edgeflag input */ - stvp->input_to_index[VERT_ATTRIB_EDGEFLAG] = stvp->num_inputs; - stvp->index_to_input[stvp->num_inputs] = VERT_ATTRIB_EDGEFLAG; - - /* Compute mapping of vertex program outputs to slots. - */ - for (attr = 0; attr < VERT_RESULT_MAX; attr++) { - if ((stvp->Base.Base.OutputsWritten & BITFIELD64_BIT(attr)) == 0) { - stvp->result_to_output[attr] = ~0; - } - else { - unsigned slot = stvp->num_outputs++; - - stvp->result_to_output[attr] = slot; - - switch (attr) { - case VERT_RESULT_HPOS: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; - stvp->output_semantic_index[slot] = 0; - break; - case VERT_RESULT_COL0: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - stvp->output_semantic_index[slot] = 0; - break; - case VERT_RESULT_COL1: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - stvp->output_semantic_index[slot] = 1; - break; - case VERT_RESULT_BFC0: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; - stvp->output_semantic_index[slot] = 0; - break; - case VERT_RESULT_BFC1: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; - stvp->output_semantic_index[slot] = 1; - break; - case VERT_RESULT_FOGC: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_FOG; - stvp->output_semantic_index[slot] = 0; - break; - case VERT_RESULT_PSIZ: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; - stvp->output_semantic_index[slot] = 0; - break; - case VERT_RESULT_EDGE: - assert(0); - break; - - case VERT_RESULT_TEX0: - case VERT_RESULT_TEX1: - case VERT_RESULT_TEX2: - case VERT_RESULT_TEX3: - case VERT_RESULT_TEX4: - case VERT_RESULT_TEX5: - case VERT_RESULT_TEX6: - case VERT_RESULT_TEX7: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - stvp->output_semantic_index[slot] = attr - VERT_RESULT_TEX0; - break; - - case VERT_RESULT_VAR0: - default: - assert(attr < VERT_RESULT_MAX); - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - stvp->output_semantic_index[slot] = (FRAG_ATTRIB_VAR0 - - FRAG_ATTRIB_TEX0 + - attr - - VERT_RESULT_VAR0); - break; - } - } - } - /* similar hack to above, presetup potentially unused edgeflag output */ - stvp->result_to_output[VERT_RESULT_EDGE] = stvp->num_outputs; - stvp->output_semantic_name[stvp->num_outputs] = TGSI_SEMANTIC_EDGEFLAG; - stvp->output_semantic_index[stvp->num_outputs] = 0; -} - - -/** - * Translate a vertex program to create a new variant. - */ -static struct st_vp_variant * -st_translate_vertex_program(struct st_context *st, - struct st_vertex_program *stvp, - const struct st_vp_variant_key *key) -{ - struct st_vp_variant *vpv = CALLOC_STRUCT(st_vp_variant); - struct pipe_context *pipe = st->pipe; - struct ureg_program *ureg; - enum pipe_error error; - unsigned num_outputs; - - st_prepare_vertex_program( st, stvp ); - - _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_OUTPUT); - _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_VARYING); - - ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); - if (ureg == NULL) { - FREE(vpv); - return NULL; - } - - vpv->key = *key; - - vpv->num_inputs = stvp->num_inputs; - num_outputs = stvp->num_outputs; - if (key->passthrough_edgeflags) { - vpv->num_inputs++; - num_outputs++; - } - - if (ST_DEBUG & DEBUG_MESA) { - _mesa_print_program(&stvp->Base.Base); - _mesa_print_program_parameters(st->ctx, &stvp->Base.Base); - debug_printf("\n"); - } - - error = st_translate_mesa_program(st->ctx, - TGSI_PROCESSOR_VERTEX, - ureg, - &stvp->Base.Base, - /* inputs */ - vpv->num_inputs, - stvp->input_to_index, - NULL, /* input semantic name */ - NULL, /* input semantic index */ - NULL, - /* outputs */ - num_outputs, - stvp->result_to_output, - stvp->output_semantic_name, - stvp->output_semantic_index, - key->passthrough_edgeflags ); - - if (error) - goto fail; - - vpv->tgsi.tokens = ureg_get_tokens( ureg, NULL ); - if (!vpv->tgsi.tokens) - goto fail; - - ureg_destroy( ureg ); - - vpv->driver_shader = pipe->create_vs_state(pipe, &vpv->tgsi); - - if (ST_DEBUG & DEBUG_TGSI) { - tgsi_dump( vpv->tgsi.tokens, 0 ); - debug_printf("\n"); - } - - return vpv; - -fail: - debug_printf("%s: failed to translate Mesa program:\n", __FUNCTION__); - _mesa_print_program(&stvp->Base.Base); - debug_assert(0); - - ureg_destroy( ureg ); - return NULL; -} - - -/** - * Find/create a vertex program variant. - */ -struct st_vp_variant * -st_get_vp_variant(struct st_context *st, - struct st_vertex_program *stvp, - const struct st_vp_variant_key *key) -{ - struct st_vp_variant *vpv; - - /* Search for existing variant */ - for (vpv = stvp->variants; vpv; vpv = vpv->next) { - if (memcmp(&vpv->key, key, sizeof(*key)) == 0) { - break; - } - } - - if (!vpv) { - /* create now */ - vpv = st_translate_vertex_program(st, stvp, key); - if (vpv) { - /* insert into list */ - vpv->next = stvp->variants; - stvp->variants = vpv; - } - } - - return vpv; -} - - -/** - * Translate a Mesa fragment shader into a TGSI shader using extra info in - * the key. - * \return new fragment program variant - */ -static struct st_fp_variant * -st_translate_fragment_program(struct st_context *st, - struct st_fragment_program *stfp, - const struct st_fp_variant_key *key) -{ - struct pipe_context *pipe = st->pipe; - struct st_fp_variant *variant = CALLOC_STRUCT(st_fp_variant); - - if (!variant) - return NULL; - - assert(!(key->bitmap && key->drawpixels)); - -#if FEATURE_drawpix - if (key->bitmap) { - /* glBitmap drawing */ - struct gl_fragment_program *fp; - - st_make_bitmap_fragment_program(st, &stfp->Base, - &fp, &variant->bitmap_sampler); - - variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters); - stfp = st_fragment_program(fp); - } - else if (key->drawpixels) { - /* glDrawPixels drawing */ - struct gl_fragment_program *fp; - - if (key->drawpixels_z || key->drawpixels_stencil) { - fp = st_make_drawpix_z_stencil_program(st, key->drawpixels_z, - key->drawpixels_stencil); - } - else { - /* RGBA */ - st_make_drawpix_fragment_program(st, &stfp->Base, &fp); - variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters); - } - stfp = st_fragment_program(fp); - } -#endif - - if (!stfp->tgsi.tokens) { - /* need to translate Mesa instructions to TGSI now */ - GLuint outputMapping[FRAG_RESULT_MAX]; - GLuint inputMapping[FRAG_ATTRIB_MAX]; - GLuint interpMode[PIPE_MAX_SHADER_INPUTS]; /* XXX size? */ - GLuint attr; - enum pipe_error error; - const GLbitfield inputsRead = stfp->Base.Base.InputsRead; - struct ureg_program *ureg; - GLboolean write_all = GL_FALSE; - - ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS]; - ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS]; - uint fs_num_inputs = 0; - - ubyte fs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; - ubyte fs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; - uint fs_num_outputs = 0; - - - _mesa_remove_output_reads(&stfp->Base.Base, PROGRAM_OUTPUT); - - /* - * Convert Mesa program inputs to TGSI input register semantics. - */ - for (attr = 0; attr < FRAG_ATTRIB_MAX; attr++) { - if (inputsRead & (1 << attr)) { - const GLuint slot = fs_num_inputs++; - - inputMapping[attr] = slot; - - switch (attr) { - case FRAG_ATTRIB_WPOS: - input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; - input_semantic_index[slot] = 0; - interpMode[slot] = TGSI_INTERPOLATE_LINEAR; - break; - case FRAG_ATTRIB_COL0: - input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - input_semantic_index[slot] = 0; - interpMode[slot] = TGSI_INTERPOLATE_LINEAR; - break; - case FRAG_ATTRIB_COL1: - input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - input_semantic_index[slot] = 1; - interpMode[slot] = TGSI_INTERPOLATE_LINEAR; - break; - case FRAG_ATTRIB_FOGC: - input_semantic_name[slot] = TGSI_SEMANTIC_FOG; - input_semantic_index[slot] = 0; - interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; - break; - case FRAG_ATTRIB_FACE: - input_semantic_name[slot] = TGSI_SEMANTIC_FACE; - input_semantic_index[slot] = 0; - interpMode[slot] = TGSI_INTERPOLATE_CONSTANT; - break; - /* In most cases, there is nothing special about these - * inputs, so adopt a convention to use the generic - * semantic name and the mesa FRAG_ATTRIB_ number as the - * index. - * - * All that is required is that the vertex shader labels - * its own outputs similarly, and that the vertex shader - * generates at least every output required by the - * fragment shader plus fixed-function hardware (such as - * BFC). - * - * There is no requirement that semantic indexes start at - * zero or be restricted to a particular range -- nobody - * should be building tables based on semantic index. - */ - case FRAG_ATTRIB_PNTC: - case FRAG_ATTRIB_TEX0: - case FRAG_ATTRIB_TEX1: - case FRAG_ATTRIB_TEX2: - case FRAG_ATTRIB_TEX3: - case FRAG_ATTRIB_TEX4: - case FRAG_ATTRIB_TEX5: - case FRAG_ATTRIB_TEX6: - case FRAG_ATTRIB_TEX7: - case FRAG_ATTRIB_VAR0: - default: - /* Actually, let's try and zero-base this just for - * readability of the generated TGSI. - */ - assert(attr >= FRAG_ATTRIB_TEX0); - input_semantic_index[slot] = (attr - FRAG_ATTRIB_TEX0); - input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - if (attr == FRAG_ATTRIB_PNTC) - interpMode[slot] = TGSI_INTERPOLATE_LINEAR; - else - interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; - break; - } - } - else { - inputMapping[attr] = -1; - } - } - - /* - * Semantics and mapping for outputs - */ - { - uint numColors = 0; - GLbitfield64 outputsWritten = stfp->Base.Base.OutputsWritten; - - /* if z is written, emit that first */ - if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) { - fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_POSITION; - fs_output_semantic_index[fs_num_outputs] = 0; - outputMapping[FRAG_RESULT_DEPTH] = fs_num_outputs; - fs_num_outputs++; - outputsWritten &= ~(1 << FRAG_RESULT_DEPTH); - } - - if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_STENCIL)) { - fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_STENCIL; - fs_output_semantic_index[fs_num_outputs] = 0; - outputMapping[FRAG_RESULT_STENCIL] = fs_num_outputs; - fs_num_outputs++; - outputsWritten &= ~(1 << FRAG_RESULT_STENCIL); - } - - /* handle remaning outputs (color) */ - for (attr = 0; attr < FRAG_RESULT_MAX; attr++) { - if (outputsWritten & BITFIELD64_BIT(attr)) { - switch (attr) { - case FRAG_RESULT_DEPTH: - case FRAG_RESULT_STENCIL: - /* handled above */ - assert(0); - break; - case FRAG_RESULT_COLOR: - write_all = GL_TRUE; /* fallthrough */ - default: - assert(attr == FRAG_RESULT_COLOR || - (FRAG_RESULT_DATA0 <= attr && attr < FRAG_RESULT_MAX)); - fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_COLOR; - fs_output_semantic_index[fs_num_outputs] = numColors; - outputMapping[attr] = fs_num_outputs; - numColors++; - break; - } - - fs_num_outputs++; - } - } - } - - ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); - if (ureg == NULL) - return NULL; - - if (ST_DEBUG & DEBUG_MESA) { - _mesa_print_program(&stfp->Base.Base); - _mesa_print_program_parameters(st->ctx, &stfp->Base.Base); - debug_printf("\n"); - } - if (write_all == GL_TRUE) - ureg_property_fs_color0_writes_all_cbufs(ureg, 1); - - error = st_translate_mesa_program(st->ctx, - TGSI_PROCESSOR_FRAGMENT, - ureg, - &stfp->Base.Base, - /* inputs */ - fs_num_inputs, - inputMapping, - input_semantic_name, - input_semantic_index, - interpMode, - /* outputs */ - fs_num_outputs, - outputMapping, - fs_output_semantic_name, - fs_output_semantic_index, FALSE ); - - stfp->tgsi.tokens = ureg_get_tokens( ureg, NULL ); - ureg_destroy( ureg ); - } - - /* fill in variant */ - variant->driver_shader = pipe->create_fs_state(pipe, &stfp->tgsi); - variant->key = *key; - - if (ST_DEBUG & DEBUG_TGSI) { - tgsi_dump( stfp->tgsi.tokens, 0/*TGSI_DUMP_VERBOSE*/ ); - debug_printf("\n"); - } - - return variant; -} - - -/** - * Translate fragment program if needed. - */ -struct st_fp_variant * -st_get_fp_variant(struct st_context *st, - struct st_fragment_program *stfp, - const struct st_fp_variant_key *key) -{ - struct st_fp_variant *fpv; - - /* Search for existing variant */ - for (fpv = stfp->variants; fpv; fpv = fpv->next) { - if (memcmp(&fpv->key, key, sizeof(*key)) == 0) { - break; - } - } - - if (!fpv) { - /* create new */ - fpv = st_translate_fragment_program(st, stfp, key); - if (fpv) { - /* insert into list */ - fpv->next = stfp->variants; - stfp->variants = fpv; - } - } - - return fpv; -} - - -/** - * Translate a geometry program to create a new variant. - */ -static struct st_gp_variant * -st_translate_geometry_program(struct st_context *st, - struct st_geometry_program *stgp, - const struct st_gp_variant_key *key) -{ - GLuint inputMapping[GEOM_ATTRIB_MAX]; - GLuint outputMapping[GEOM_RESULT_MAX]; - struct pipe_context *pipe = st->pipe; - enum pipe_error error; - GLuint attr; - const GLbitfield inputsRead = stgp->Base.Base.InputsRead; - GLuint vslot = 0; - GLuint num_generic = 0; - - uint gs_num_inputs = 0; - uint gs_builtin_inputs = 0; - uint gs_array_offset = 0; - - ubyte gs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; - ubyte gs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; - uint gs_num_outputs = 0; - - GLint i; - GLuint maxSlot = 0; - struct ureg_program *ureg; - - struct st_gp_variant *gpv; - - gpv = CALLOC_STRUCT(st_gp_variant); - if (!gpv) - return NULL; - - _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_OUTPUT); - _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_VARYING); - - ureg = ureg_create( TGSI_PROCESSOR_GEOMETRY ); - if (ureg == NULL) { - FREE(gpv); - return NULL; - } - - /* which vertex output goes to the first geometry input */ - vslot = 0; - - memset(inputMapping, 0, sizeof(inputMapping)); - memset(outputMapping, 0, sizeof(outputMapping)); - - /* - * Convert Mesa program inputs to TGSI input register semantics. - */ - for (attr = 0; attr < GEOM_ATTRIB_MAX; attr++) { - if (inputsRead & (1 << attr)) { - const GLuint slot = gs_num_inputs; - - gs_num_inputs++; - - inputMapping[attr] = slot; - - stgp->input_map[slot + gs_array_offset] = vslot - gs_builtin_inputs; - stgp->input_to_index[attr] = vslot; - stgp->index_to_input[vslot] = attr; - ++vslot; - - if (attr != GEOM_ATTRIB_PRIMITIVE_ID) { - gs_array_offset += 2; - } else - ++gs_builtin_inputs; - -#if 0 - debug_printf("input map at %d = %d\n", - slot + gs_array_offset, stgp->input_map[slot + gs_array_offset]); -#endif - - switch (attr) { - case GEOM_ATTRIB_PRIMITIVE_ID: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_PRIMID; - stgp->input_semantic_index[slot] = 0; - break; - case GEOM_ATTRIB_POSITION: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; - stgp->input_semantic_index[slot] = 0; - break; - case GEOM_ATTRIB_COLOR0: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - stgp->input_semantic_index[slot] = 0; - break; - case GEOM_ATTRIB_COLOR1: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - stgp->input_semantic_index[slot] = 1; - break; - case GEOM_ATTRIB_FOG_FRAG_COORD: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_FOG; - stgp->input_semantic_index[slot] = 0; - break; - case GEOM_ATTRIB_TEX_COORD: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - stgp->input_semantic_index[slot] = num_generic++; - break; - case GEOM_ATTRIB_VAR0: - /* fall-through */ - default: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - stgp->input_semantic_index[slot] = num_generic++; - } - } - } - - /* initialize output semantics to defaults */ - for (i = 0; i < PIPE_MAX_SHADER_OUTPUTS; i++) { - gs_output_semantic_name[i] = TGSI_SEMANTIC_GENERIC; - gs_output_semantic_index[i] = 0; - } - - num_generic = 0; - /* - * Determine number of outputs, the (default) output register - * mapping and the semantic information for each output. - */ - for (attr = 0; attr < GEOM_RESULT_MAX; attr++) { - if (stgp->Base.Base.OutputsWritten & (1 << attr)) { - GLuint slot; - - slot = gs_num_outputs; - gs_num_outputs++; - outputMapping[attr] = slot; - - switch (attr) { - case GEOM_RESULT_POS: - assert(slot == 0); - gs_output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; - gs_output_semantic_index[slot] = 0; - break; - case GEOM_RESULT_COL0: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - gs_output_semantic_index[slot] = 0; - break; - case GEOM_RESULT_COL1: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - gs_output_semantic_index[slot] = 1; - break; - case GEOM_RESULT_SCOL0: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; - gs_output_semantic_index[slot] = 0; - break; - case GEOM_RESULT_SCOL1: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; - gs_output_semantic_index[slot] = 1; - break; - case GEOM_RESULT_FOGC: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_FOG; - gs_output_semantic_index[slot] = 0; - break; - case GEOM_RESULT_PSIZ: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; - gs_output_semantic_index[slot] = 0; - break; - case GEOM_RESULT_TEX0: - case GEOM_RESULT_TEX1: - case GEOM_RESULT_TEX2: - case GEOM_RESULT_TEX3: - case GEOM_RESULT_TEX4: - case GEOM_RESULT_TEX5: - case GEOM_RESULT_TEX6: - case GEOM_RESULT_TEX7: - /* fall-through */ - case GEOM_RESULT_VAR0: - /* fall-through */ - default: - assert(slot < Elements(gs_output_semantic_name)); - /* use default semantic info */ - gs_output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - gs_output_semantic_index[slot] = num_generic++; - } - } - } - - assert(gs_output_semantic_name[0] == TGSI_SEMANTIC_POSITION); - - /* find max output slot referenced to compute gs_num_outputs */ - for (attr = 0; attr < GEOM_RESULT_MAX; attr++) { - if (outputMapping[attr] != ~0 && outputMapping[attr] > maxSlot) - maxSlot = outputMapping[attr]; - } - gs_num_outputs = maxSlot + 1; - -#if 0 /* debug */ - { - GLuint i; - printf("outputMapping? %d\n", outputMapping ? 1 : 0); - if (outputMapping) { - printf("attr -> slot\n"); - for (i = 0; i < 16; i++) { - printf(" %2d %3d\n", i, outputMapping[i]); - } - } - printf("slot sem_name sem_index\n"); - for (i = 0; i < gs_num_outputs; i++) { - printf(" %2d %d %d\n", - i, - gs_output_semantic_name[i], - gs_output_semantic_index[i]); - } - } -#endif - - /* free old shader state, if any */ - if (stgp->tgsi.tokens) { - st_free_tokens(stgp->tgsi.tokens); - stgp->tgsi.tokens = NULL; - } - - ureg_property_gs_input_prim(ureg, stgp->Base.InputType); - ureg_property_gs_output_prim(ureg, stgp->Base.OutputType); - ureg_property_gs_max_vertices(ureg, stgp->Base.VerticesOut); - - error = st_translate_mesa_program(st->ctx, - TGSI_PROCESSOR_GEOMETRY, - ureg, - &stgp->Base.Base, - /* inputs */ - gs_num_inputs, - inputMapping, - stgp->input_semantic_name, - stgp->input_semantic_index, - NULL, - /* outputs */ - gs_num_outputs, - outputMapping, - gs_output_semantic_name, - gs_output_semantic_index, - FALSE); - - stgp->num_inputs = gs_num_inputs; - stgp->tgsi.tokens = ureg_get_tokens( ureg, NULL ); - ureg_destroy( ureg ); - - /* fill in new variant */ - gpv->driver_shader = pipe->create_gs_state(pipe, &stgp->tgsi); - gpv->key = *key; - - if ((ST_DEBUG & DEBUG_TGSI) && (ST_DEBUG & DEBUG_MESA)) { - _mesa_print_program(&stgp->Base.Base); - debug_printf("\n"); - } - - if (ST_DEBUG & DEBUG_TGSI) { - tgsi_dump(stgp->tgsi.tokens, 0); - debug_printf("\n"); - } - - return gpv; -} - - -/** - * Get/create geometry program variant. - */ -struct st_gp_variant * -st_get_gp_variant(struct st_context *st, - struct st_geometry_program *stgp, - const struct st_gp_variant_key *key) -{ - struct st_gp_variant *gpv; - - /* Search for existing variant */ - for (gpv = stgp->variants; gpv; gpv = gpv->next) { - if (memcmp(&gpv->key, key, sizeof(*key)) == 0) { - break; - } - } - - if (!gpv) { - /* create new */ - gpv = st_translate_geometry_program(st, stgp, key); - if (gpv) { - /* insert into list */ - gpv->next = stgp->variants; - stgp->variants = gpv; - } - } - - return gpv; -} - - - - -/** - * Debug- print current shader text - */ -void -st_print_shaders(struct gl_context *ctx) -{ - struct gl_shader_program *shProg[3] = { - ctx->Shader.CurrentVertexProgram, - ctx->Shader.CurrentGeometryProgram, - ctx->Shader.CurrentFragmentProgram, - }; - unsigned j; - - for (j = 0; j < 3; j++) { - unsigned i; - - if (shProg[j] == NULL) - continue; - - for (i = 0; i < shProg[j]->NumShaders; i++) { - struct gl_shader *sh; - - switch (shProg[j]->Shaders[i]->Type) { - case GL_VERTEX_SHADER: - sh = (i != 0) ? NULL : shProg[j]->Shaders[i]; - break; - case GL_GEOMETRY_SHADER_ARB: - sh = (i != 1) ? NULL : shProg[j]->Shaders[i]; - break; - case GL_FRAGMENT_SHADER: - sh = (i != 2) ? NULL : shProg[j]->Shaders[i]; - break; - default: - assert(0); - sh = NULL; - break; - } - - if (sh != NULL) { - printf("GLSL shader %u of %u:\n", i, shProg[j]->NumShaders); - printf("%s\n", sh->Source); - } - } - } -} - - -/** - * Vert/Geom/Frag programs have per-context variants. Free all the - * variants attached to the given program which match the given context. - */ -static void -destroy_program_variants(struct st_context *st, struct gl_program *program) -{ - if (!program) - return; - - switch (program->Target) { - case GL_VERTEX_PROGRAM_ARB: - { - struct st_vertex_program *stvp = (struct st_vertex_program *) program; - struct st_vp_variant *vpv, **prevPtr = &stvp->variants; - - for (vpv = stvp->variants; vpv; ) { - struct st_vp_variant *next = vpv->next; - if (vpv->key.st == st) { - /* unlink from list */ - *prevPtr = next; - /* destroy this variant */ - delete_vp_variant(st, vpv); - } - else { - prevPtr = &vpv->next; - } - vpv = next; - } - } - break; - case GL_FRAGMENT_PROGRAM_ARB: - { - struct st_fragment_program *stfp = - (struct st_fragment_program *) program; - struct st_fp_variant *fpv, **prevPtr = &stfp->variants; - - for (fpv = stfp->variants; fpv; ) { - struct st_fp_variant *next = fpv->next; - if (fpv->key.st == st) { - /* unlink from list */ - *prevPtr = next; - /* destroy this variant */ - delete_fp_variant(st, fpv); - } - else { - prevPtr = &fpv->next; - } - fpv = next; - } - } - break; - case MESA_GEOMETRY_PROGRAM: - { - struct st_geometry_program *stgp = - (struct st_geometry_program *) program; - struct st_gp_variant *gpv, **prevPtr = &stgp->variants; - - for (gpv = stgp->variants; gpv; ) { - struct st_gp_variant *next = gpv->next; - if (gpv->key.st == st) { - /* unlink from list */ - *prevPtr = next; - /* destroy this variant */ - delete_gp_variant(st, gpv); - } - else { - prevPtr = &gpv->next; - } - gpv = next; - } - } - break; - default: - _mesa_problem(NULL, "Unexpected program target in " - "destroy_program_variants_cb()"); - } -} - - -/** - * Callback for _mesa_HashWalk. Free all the shader's program variants - * which match the given context. - */ -static void -destroy_shader_program_variants_cb(GLuint key, void *data, void *userData) -{ - struct st_context *st = (struct st_context *) userData; - struct gl_shader *shader = (struct gl_shader *) data; - - switch (shader->Type) { - case GL_SHADER_PROGRAM_MESA: - { - struct gl_shader_program *shProg = (struct gl_shader_program *) data; - GLuint i; - - for (i = 0; i < shProg->NumShaders; i++) { - destroy_program_variants(st, shProg->Shaders[i]->Program); - } - - destroy_program_variants(st, (struct gl_program *) - shProg->VertexProgram); - destroy_program_variants(st, (struct gl_program *) - shProg->FragmentProgram); - destroy_program_variants(st, (struct gl_program *) - shProg->GeometryProgram); - } - break; - case GL_VERTEX_SHADER: - case GL_FRAGMENT_SHADER: - case GL_GEOMETRY_SHADER: - { - destroy_program_variants(st, shader->Program); - } - break; - default: - assert(0); - } -} - - -/** - * Callback for _mesa_HashWalk. Free all the program variants which match - * the given context. - */ -static void -destroy_program_variants_cb(GLuint key, void *data, void *userData) -{ - struct st_context *st = (struct st_context *) userData; - struct gl_program *program = (struct gl_program *) data; - destroy_program_variants(st, program); -} - - -/** - * Walk over all shaders and programs to delete any variants which - * belong to the given context. - * This is called during context tear-down. - */ -void -st_destroy_program_variants(struct st_context *st) -{ - /* ARB vert/frag program */ - _mesa_HashWalk(st->ctx->Shared->Programs, - destroy_program_variants_cb, st); - - /* GLSL vert/frag/geom shaders */ - _mesa_HashWalk(st->ctx->Shared->ShaderObjects, - destroy_shader_program_variants_cb, st); -} +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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, sub license, 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + /* + * Authors: + * Keith Whitwell + * Brian Paul + */ + + +#include "main/imports.h" +#include "main/hash.h" +#include "main/mfeatures.h" +#include "main/mtypes.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" +#include "program/programopt.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_shader_tokens.h" +#include "draw/draw_context.h" +#include "tgsi/tgsi_dump.h" +#include "tgsi/tgsi_ureg.h" + +#include "st_debug.h" +#include "st_cb_bitmap.h" +#include "st_cb_drawpixels.h" +#include "st_context.h" +#include "st_program.h" +#include "st_mesa_to_tgsi.h" +#include "cso_cache/cso_context.h" + + + +/** + * Delete a vertex program variant. Note the caller must unlink + * the variant from the linked list. + */ +static void +delete_vp_variant(struct st_context *st, struct st_vp_variant *vpv) +{ + if (vpv->driver_shader) + cso_delete_vertex_shader(st->cso_context, vpv->driver_shader); + +#if FEATURE_feedback || FEATURE_rastpos + if (vpv->draw_shader) + draw_delete_vertex_shader( st->draw, vpv->draw_shader ); +#endif + + if (vpv->tgsi.tokens) + st_free_tokens(vpv->tgsi.tokens); + + FREE( vpv ); +} + + + +/** + * Clean out any old compilations: + */ +void +st_release_vp_variants( struct st_context *st, + struct st_vertex_program *stvp ) +{ + struct st_vp_variant *vpv; + + for (vpv = stvp->variants; vpv; ) { + struct st_vp_variant *next = vpv->next; + delete_vp_variant(st, vpv); + vpv = next; + } + + stvp->variants = NULL; +} + + + +/** + * Delete a fragment program variant. Note the caller must unlink + * the variant from the linked list. + */ +static void +delete_fp_variant(struct st_context *st, struct st_fp_variant *fpv) +{ + if (fpv->driver_shader) + cso_delete_fragment_shader(st->cso_context, fpv->driver_shader); + if (fpv->parameters) + _mesa_free_parameter_list(fpv->parameters); + + FREE(fpv); +} + + +/** + * Free all variants of a fragment program. + */ +void +st_release_fp_variants(struct st_context *st, struct st_fragment_program *stfp) +{ + struct st_fp_variant *fpv; + + for (fpv = stfp->variants; fpv; ) { + struct st_fp_variant *next = fpv->next; + delete_fp_variant(st, fpv); + fpv = next; + } + + stfp->variants = NULL; +} + + +/** + * Delete a geometry program variant. Note the caller must unlink + * the variant from the linked list. + */ +static void +delete_gp_variant(struct st_context *st, struct st_gp_variant *gpv) +{ + if (gpv->driver_shader) + cso_delete_geometry_shader(st->cso_context, gpv->driver_shader); + + FREE(gpv); +} + + +/** + * Free all variants of a geometry program. + */ +void +st_release_gp_variants(struct st_context *st, struct st_geometry_program *stgp) +{ + struct st_gp_variant *gpv; + + for (gpv = stgp->variants; gpv; ) { + struct st_gp_variant *next = gpv->next; + delete_gp_variant(st, gpv); + gpv = next; + } + + stgp->variants = NULL; +} + + + + +/** + * Translate a Mesa vertex shader into a TGSI shader. + * \param outputMapping to map vertex program output registers (VERT_RESULT_x) + * to TGSI output slots + * \param tokensOut destination for TGSI tokens + * \return pointer to cached pipe_shader object. + */ +static void +st_prepare_vertex_program(struct st_context *st, + struct st_vertex_program *stvp) +{ + GLuint attr; + + stvp->num_inputs = 0; + stvp->num_outputs = 0; + + if (stvp->Base.IsPositionInvariant) + _mesa_insert_mvp_code(st->ctx, &stvp->Base); + + assert(stvp->Base.Base.NumInstructions > 1); + + /* + * Determine number of inputs, the mappings between VERT_ATTRIB_x + * and TGSI generic input indexes, plus input attrib semantic info. + */ + for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) { + if (stvp->Base.Base.InputsRead & (1 << attr)) { + stvp->input_to_index[attr] = stvp->num_inputs; + stvp->index_to_input[stvp->num_inputs] = attr; + stvp->num_inputs++; + } + } + /* bit of a hack, presetup potentially unused edgeflag input */ + stvp->input_to_index[VERT_ATTRIB_EDGEFLAG] = stvp->num_inputs; + stvp->index_to_input[stvp->num_inputs] = VERT_ATTRIB_EDGEFLAG; + + /* Compute mapping of vertex program outputs to slots. + */ + for (attr = 0; attr < VERT_RESULT_MAX; attr++) { + if ((stvp->Base.Base.OutputsWritten & BITFIELD64_BIT(attr)) == 0) { + stvp->result_to_output[attr] = ~0; + } + else { + unsigned slot = stvp->num_outputs++; + + stvp->result_to_output[attr] = slot; + + switch (attr) { + case VERT_RESULT_HPOS: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + stvp->output_semantic_index[slot] = 0; + break; + case VERT_RESULT_COL0: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + stvp->output_semantic_index[slot] = 0; + break; + case VERT_RESULT_COL1: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + stvp->output_semantic_index[slot] = 1; + break; + case VERT_RESULT_BFC0: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + stvp->output_semantic_index[slot] = 0; + break; + case VERT_RESULT_BFC1: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + stvp->output_semantic_index[slot] = 1; + break; + case VERT_RESULT_FOGC: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_FOG; + stvp->output_semantic_index[slot] = 0; + break; + case VERT_RESULT_PSIZ: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; + stvp->output_semantic_index[slot] = 0; + break; + case VERT_RESULT_EDGE: + assert(0); + break; + + case VERT_RESULT_TEX0: + case VERT_RESULT_TEX1: + case VERT_RESULT_TEX2: + case VERT_RESULT_TEX3: + case VERT_RESULT_TEX4: + case VERT_RESULT_TEX5: + case VERT_RESULT_TEX6: + case VERT_RESULT_TEX7: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + stvp->output_semantic_index[slot] = attr - VERT_RESULT_TEX0; + break; + + case VERT_RESULT_VAR0: + default: + assert(attr < VERT_RESULT_MAX); + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + stvp->output_semantic_index[slot] = (FRAG_ATTRIB_VAR0 - + FRAG_ATTRIB_TEX0 + + attr - + VERT_RESULT_VAR0); + break; + } + } + } + /* similar hack to above, presetup potentially unused edgeflag output */ + stvp->result_to_output[VERT_RESULT_EDGE] = stvp->num_outputs; + stvp->output_semantic_name[stvp->num_outputs] = TGSI_SEMANTIC_EDGEFLAG; + stvp->output_semantic_index[stvp->num_outputs] = 0; +} + + +/** + * Translate a vertex program to create a new variant. + */ +static struct st_vp_variant * +st_translate_vertex_program(struct st_context *st, + struct st_vertex_program *stvp, + const struct st_vp_variant_key *key) +{ + struct st_vp_variant *vpv = CALLOC_STRUCT(st_vp_variant); + struct pipe_context *pipe = st->pipe; + struct ureg_program *ureg; + enum pipe_error error; + unsigned num_outputs; + + st_prepare_vertex_program( st, stvp ); + + _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_OUTPUT); + _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_VARYING); + + ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); + if (ureg == NULL) { + FREE(vpv); + return NULL; + } + + vpv->key = *key; + + vpv->num_inputs = stvp->num_inputs; + num_outputs = stvp->num_outputs; + if (key->passthrough_edgeflags) { + vpv->num_inputs++; + num_outputs++; + } + + if (ST_DEBUG & DEBUG_MESA) { + _mesa_print_program(&stvp->Base.Base); + _mesa_print_program_parameters(st->ctx, &stvp->Base.Base); + debug_printf("\n"); + } + + error = st_translate_mesa_program(st->ctx, + TGSI_PROCESSOR_VERTEX, + ureg, + &stvp->Base.Base, + /* inputs */ + vpv->num_inputs, + stvp->input_to_index, + NULL, /* input semantic name */ + NULL, /* input semantic index */ + NULL, + /* outputs */ + num_outputs, + stvp->result_to_output, + stvp->output_semantic_name, + stvp->output_semantic_index, + key->passthrough_edgeflags ); + + if (error) + goto fail; + + vpv->tgsi.tokens = ureg_get_tokens( ureg, NULL ); + if (!vpv->tgsi.tokens) + goto fail; + + ureg_destroy( ureg ); + + vpv->driver_shader = pipe->create_vs_state(pipe, &vpv->tgsi); + + if (ST_DEBUG & DEBUG_TGSI) { + tgsi_dump( vpv->tgsi.tokens, 0 ); + debug_printf("\n"); + } + + return vpv; + +fail: + debug_printf("%s: failed to translate Mesa program:\n", __FUNCTION__); + _mesa_print_program(&stvp->Base.Base); + debug_assert(0); + + ureg_destroy( ureg ); + return NULL; +} + + +/** + * Find/create a vertex program variant. + */ +struct st_vp_variant * +st_get_vp_variant(struct st_context *st, + struct st_vertex_program *stvp, + const struct st_vp_variant_key *key) +{ + struct st_vp_variant *vpv; + + /* Search for existing variant */ + for (vpv = stvp->variants; vpv; vpv = vpv->next) { + if (memcmp(&vpv->key, key, sizeof(*key)) == 0) { + break; + } + } + + if (!vpv) { + /* create now */ + vpv = st_translate_vertex_program(st, stvp, key); + if (vpv) { + /* insert into list */ + vpv->next = stvp->variants; + stvp->variants = vpv; + } + } + + return vpv; +} + + +/** + * Translate a Mesa fragment shader into a TGSI shader using extra info in + * the key. + * \return new fragment program variant + */ +static struct st_fp_variant * +st_translate_fragment_program(struct st_context *st, + struct st_fragment_program *stfp, + const struct st_fp_variant_key *key) +{ + struct pipe_context *pipe = st->pipe; + struct st_fp_variant *variant = CALLOC_STRUCT(st_fp_variant); + GLboolean deleteFP = GL_FALSE; + + if (!variant) + return NULL; + + assert(!(key->bitmap && key->drawpixels)); + +#if FEATURE_drawpix + if (key->bitmap) { + /* glBitmap drawing */ + struct gl_fragment_program *fp; /* we free this temp program below */ + + st_make_bitmap_fragment_program(st, &stfp->Base, + &fp, &variant->bitmap_sampler); + + variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters); + stfp = st_fragment_program(fp); + deleteFP = GL_TRUE; + } + else if (key->drawpixels) { + /* glDrawPixels drawing */ + struct gl_fragment_program *fp; /* we free this temp program below */ + + if (key->drawpixels_z || key->drawpixels_stencil) { + fp = st_make_drawpix_z_stencil_program(st, key->drawpixels_z, + key->drawpixels_stencil); + } + else { + /* RGBA */ + st_make_drawpix_fragment_program(st, &stfp->Base, &fp); + variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters); + deleteFP = GL_TRUE; + } + stfp = st_fragment_program(fp); + } +#endif + + if (!stfp->tgsi.tokens) { + /* need to translate Mesa instructions to TGSI now */ + GLuint outputMapping[FRAG_RESULT_MAX]; + GLuint inputMapping[FRAG_ATTRIB_MAX]; + GLuint interpMode[PIPE_MAX_SHADER_INPUTS]; /* XXX size? */ + GLuint attr; + enum pipe_error error; + const GLbitfield inputsRead = stfp->Base.Base.InputsRead; + struct ureg_program *ureg; + GLboolean write_all = GL_FALSE; + + ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS]; + ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS]; + uint fs_num_inputs = 0; + + ubyte fs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; + ubyte fs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; + uint fs_num_outputs = 0; + + + _mesa_remove_output_reads(&stfp->Base.Base, PROGRAM_OUTPUT); + + /* + * Convert Mesa program inputs to TGSI input register semantics. + */ + for (attr = 0; attr < FRAG_ATTRIB_MAX; attr++) { + if (inputsRead & (1 << attr)) { + const GLuint slot = fs_num_inputs++; + + inputMapping[attr] = slot; + + switch (attr) { + case FRAG_ATTRIB_WPOS: + input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + break; + case FRAG_ATTRIB_COL0: + input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + break; + case FRAG_ATTRIB_COL1: + input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + input_semantic_index[slot] = 1; + interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + break; + case FRAG_ATTRIB_FOGC: + input_semantic_name[slot] = TGSI_SEMANTIC_FOG; + input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; + break; + case FRAG_ATTRIB_FACE: + input_semantic_name[slot] = TGSI_SEMANTIC_FACE; + input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_CONSTANT; + break; + /* In most cases, there is nothing special about these + * inputs, so adopt a convention to use the generic + * semantic name and the mesa FRAG_ATTRIB_ number as the + * index. + * + * All that is required is that the vertex shader labels + * its own outputs similarly, and that the vertex shader + * generates at least every output required by the + * fragment shader plus fixed-function hardware (such as + * BFC). + * + * There is no requirement that semantic indexes start at + * zero or be restricted to a particular range -- nobody + * should be building tables based on semantic index. + */ + case FRAG_ATTRIB_PNTC: + case FRAG_ATTRIB_TEX0: + case FRAG_ATTRIB_TEX1: + case FRAG_ATTRIB_TEX2: + case FRAG_ATTRIB_TEX3: + case FRAG_ATTRIB_TEX4: + case FRAG_ATTRIB_TEX5: + case FRAG_ATTRIB_TEX6: + case FRAG_ATTRIB_TEX7: + case FRAG_ATTRIB_VAR0: + default: + /* Actually, let's try and zero-base this just for + * readability of the generated TGSI. + */ + assert(attr >= FRAG_ATTRIB_TEX0); + input_semantic_index[slot] = (attr - FRAG_ATTRIB_TEX0); + input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + if (attr == FRAG_ATTRIB_PNTC) + interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + else + interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; + break; + } + } + else { + inputMapping[attr] = -1; + } + } + + /* + * Semantics and mapping for outputs + */ + { + uint numColors = 0; + GLbitfield64 outputsWritten = stfp->Base.Base.OutputsWritten; + + /* if z is written, emit that first */ + if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) { + fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_POSITION; + fs_output_semantic_index[fs_num_outputs] = 0; + outputMapping[FRAG_RESULT_DEPTH] = fs_num_outputs; + fs_num_outputs++; + outputsWritten &= ~(1 << FRAG_RESULT_DEPTH); + } + + if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_STENCIL)) { + fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_STENCIL; + fs_output_semantic_index[fs_num_outputs] = 0; + outputMapping[FRAG_RESULT_STENCIL] = fs_num_outputs; + fs_num_outputs++; + outputsWritten &= ~(1 << FRAG_RESULT_STENCIL); + } + + /* handle remaning outputs (color) */ + for (attr = 0; attr < FRAG_RESULT_MAX; attr++) { + if (outputsWritten & BITFIELD64_BIT(attr)) { + switch (attr) { + case FRAG_RESULT_DEPTH: + case FRAG_RESULT_STENCIL: + /* handled above */ + assert(0); + break; + case FRAG_RESULT_COLOR: + write_all = GL_TRUE; /* fallthrough */ + default: + assert(attr == FRAG_RESULT_COLOR || + (FRAG_RESULT_DATA0 <= attr && attr < FRAG_RESULT_MAX)); + fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_COLOR; + fs_output_semantic_index[fs_num_outputs] = numColors; + outputMapping[attr] = fs_num_outputs; + numColors++; + break; + } + + fs_num_outputs++; + } + } + } + + ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); + if (ureg == NULL) + return NULL; + + if (ST_DEBUG & DEBUG_MESA) { + _mesa_print_program(&stfp->Base.Base); + _mesa_print_program_parameters(st->ctx, &stfp->Base.Base); + debug_printf("\n"); + } + if (write_all == GL_TRUE) + ureg_property_fs_color0_writes_all_cbufs(ureg, 1); + + error = st_translate_mesa_program(st->ctx, + TGSI_PROCESSOR_FRAGMENT, + ureg, + &stfp->Base.Base, + /* inputs */ + fs_num_inputs, + inputMapping, + input_semantic_name, + input_semantic_index, + interpMode, + /* outputs */ + fs_num_outputs, + outputMapping, + fs_output_semantic_name, + fs_output_semantic_index, FALSE ); + + stfp->tgsi.tokens = ureg_get_tokens( ureg, NULL ); + ureg_destroy( ureg ); + } + + /* fill in variant */ + variant->driver_shader = pipe->create_fs_state(pipe, &stfp->tgsi); + variant->key = *key; + + if (ST_DEBUG & DEBUG_TGSI) { + tgsi_dump( stfp->tgsi.tokens, 0/*TGSI_DUMP_VERBOSE*/ ); + debug_printf("\n"); + } + + if (deleteFP) { + /* Free the temporary program made above */ + struct gl_fragment_program *fp = &stfp->Base; + _mesa_reference_fragprog(st->ctx, &fp, NULL); + } + + return variant; +} + + +/** + * Translate fragment program if needed. + */ +struct st_fp_variant * +st_get_fp_variant(struct st_context *st, + struct st_fragment_program *stfp, + const struct st_fp_variant_key *key) +{ + struct st_fp_variant *fpv; + + /* Search for existing variant */ + for (fpv = stfp->variants; fpv; fpv = fpv->next) { + if (memcmp(&fpv->key, key, sizeof(*key)) == 0) { + break; + } + } + + if (!fpv) { + /* create new */ + fpv = st_translate_fragment_program(st, stfp, key); + if (fpv) { + /* insert into list */ + fpv->next = stfp->variants; + stfp->variants = fpv; + } + } + + return fpv; +} + + +/** + * Translate a geometry program to create a new variant. + */ +static struct st_gp_variant * +st_translate_geometry_program(struct st_context *st, + struct st_geometry_program *stgp, + const struct st_gp_variant_key *key) +{ + GLuint inputMapping[GEOM_ATTRIB_MAX]; + GLuint outputMapping[GEOM_RESULT_MAX]; + struct pipe_context *pipe = st->pipe; + enum pipe_error error; + GLuint attr; + const GLbitfield inputsRead = stgp->Base.Base.InputsRead; + GLuint vslot = 0; + GLuint num_generic = 0; + + uint gs_num_inputs = 0; + uint gs_builtin_inputs = 0; + uint gs_array_offset = 0; + + ubyte gs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; + ubyte gs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; + uint gs_num_outputs = 0; + + GLint i; + GLuint maxSlot = 0; + struct ureg_program *ureg; + + struct st_gp_variant *gpv; + + gpv = CALLOC_STRUCT(st_gp_variant); + if (!gpv) + return NULL; + + _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_OUTPUT); + _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_VARYING); + + ureg = ureg_create( TGSI_PROCESSOR_GEOMETRY ); + if (ureg == NULL) { + FREE(gpv); + return NULL; + } + + /* which vertex output goes to the first geometry input */ + vslot = 0; + + memset(inputMapping, 0, sizeof(inputMapping)); + memset(outputMapping, 0, sizeof(outputMapping)); + + /* + * Convert Mesa program inputs to TGSI input register semantics. + */ + for (attr = 0; attr < GEOM_ATTRIB_MAX; attr++) { + if (inputsRead & (1 << attr)) { + const GLuint slot = gs_num_inputs; + + gs_num_inputs++; + + inputMapping[attr] = slot; + + stgp->input_map[slot + gs_array_offset] = vslot - gs_builtin_inputs; + stgp->input_to_index[attr] = vslot; + stgp->index_to_input[vslot] = attr; + ++vslot; + + if (attr != GEOM_ATTRIB_PRIMITIVE_ID) { + gs_array_offset += 2; + } else + ++gs_builtin_inputs; + +#if 0 + debug_printf("input map at %d = %d\n", + slot + gs_array_offset, stgp->input_map[slot + gs_array_offset]); +#endif + + switch (attr) { + case GEOM_ATTRIB_PRIMITIVE_ID: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_PRIMID; + stgp->input_semantic_index[slot] = 0; + break; + case GEOM_ATTRIB_POSITION: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + stgp->input_semantic_index[slot] = 0; + break; + case GEOM_ATTRIB_COLOR0: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + stgp->input_semantic_index[slot] = 0; + break; + case GEOM_ATTRIB_COLOR1: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + stgp->input_semantic_index[slot] = 1; + break; + case GEOM_ATTRIB_FOG_FRAG_COORD: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_FOG; + stgp->input_semantic_index[slot] = 0; + break; + case GEOM_ATTRIB_TEX_COORD: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + stgp->input_semantic_index[slot] = num_generic++; + break; + case GEOM_ATTRIB_VAR0: + /* fall-through */ + default: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + stgp->input_semantic_index[slot] = num_generic++; + } + } + } + + /* initialize output semantics to defaults */ + for (i = 0; i < PIPE_MAX_SHADER_OUTPUTS; i++) { + gs_output_semantic_name[i] = TGSI_SEMANTIC_GENERIC; + gs_output_semantic_index[i] = 0; + } + + num_generic = 0; + /* + * Determine number of outputs, the (default) output register + * mapping and the semantic information for each output. + */ + for (attr = 0; attr < GEOM_RESULT_MAX; attr++) { + if (stgp->Base.Base.OutputsWritten & (1 << attr)) { + GLuint slot; + + slot = gs_num_outputs; + gs_num_outputs++; + outputMapping[attr] = slot; + + switch (attr) { + case GEOM_RESULT_POS: + assert(slot == 0); + gs_output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + gs_output_semantic_index[slot] = 0; + break; + case GEOM_RESULT_COL0: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + gs_output_semantic_index[slot] = 0; + break; + case GEOM_RESULT_COL1: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + gs_output_semantic_index[slot] = 1; + break; + case GEOM_RESULT_SCOL0: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + gs_output_semantic_index[slot] = 0; + break; + case GEOM_RESULT_SCOL1: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + gs_output_semantic_index[slot] = 1; + break; + case GEOM_RESULT_FOGC: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_FOG; + gs_output_semantic_index[slot] = 0; + break; + case GEOM_RESULT_PSIZ: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; + gs_output_semantic_index[slot] = 0; + break; + case GEOM_RESULT_TEX0: + case GEOM_RESULT_TEX1: + case GEOM_RESULT_TEX2: + case GEOM_RESULT_TEX3: + case GEOM_RESULT_TEX4: + case GEOM_RESULT_TEX5: + case GEOM_RESULT_TEX6: + case GEOM_RESULT_TEX7: + /* fall-through */ + case GEOM_RESULT_VAR0: + /* fall-through */ + default: + assert(slot < Elements(gs_output_semantic_name)); + /* use default semantic info */ + gs_output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + gs_output_semantic_index[slot] = num_generic++; + } + } + } + + assert(gs_output_semantic_name[0] == TGSI_SEMANTIC_POSITION); + + /* find max output slot referenced to compute gs_num_outputs */ + for (attr = 0; attr < GEOM_RESULT_MAX; attr++) { + if (outputMapping[attr] != ~0 && outputMapping[attr] > maxSlot) + maxSlot = outputMapping[attr]; + } + gs_num_outputs = maxSlot + 1; + +#if 0 /* debug */ + { + GLuint i; + printf("outputMapping? %d\n", outputMapping ? 1 : 0); + if (outputMapping) { + printf("attr -> slot\n"); + for (i = 0; i < 16; i++) { + printf(" %2d %3d\n", i, outputMapping[i]); + } + } + printf("slot sem_name sem_index\n"); + for (i = 0; i < gs_num_outputs; i++) { + printf(" %2d %d %d\n", + i, + gs_output_semantic_name[i], + gs_output_semantic_index[i]); + } + } +#endif + + /* free old shader state, if any */ + if (stgp->tgsi.tokens) { + st_free_tokens(stgp->tgsi.tokens); + stgp->tgsi.tokens = NULL; + } + + ureg_property_gs_input_prim(ureg, stgp->Base.InputType); + ureg_property_gs_output_prim(ureg, stgp->Base.OutputType); + ureg_property_gs_max_vertices(ureg, stgp->Base.VerticesOut); + + error = st_translate_mesa_program(st->ctx, + TGSI_PROCESSOR_GEOMETRY, + ureg, + &stgp->Base.Base, + /* inputs */ + gs_num_inputs, + inputMapping, + stgp->input_semantic_name, + stgp->input_semantic_index, + NULL, + /* outputs */ + gs_num_outputs, + outputMapping, + gs_output_semantic_name, + gs_output_semantic_index, + FALSE); + + stgp->num_inputs = gs_num_inputs; + stgp->tgsi.tokens = ureg_get_tokens( ureg, NULL ); + ureg_destroy( ureg ); + + /* fill in new variant */ + gpv->driver_shader = pipe->create_gs_state(pipe, &stgp->tgsi); + gpv->key = *key; + + if ((ST_DEBUG & DEBUG_TGSI) && (ST_DEBUG & DEBUG_MESA)) { + _mesa_print_program(&stgp->Base.Base); + debug_printf("\n"); + } + + if (ST_DEBUG & DEBUG_TGSI) { + tgsi_dump(stgp->tgsi.tokens, 0); + debug_printf("\n"); + } + + return gpv; +} + + +/** + * Get/create geometry program variant. + */ +struct st_gp_variant * +st_get_gp_variant(struct st_context *st, + struct st_geometry_program *stgp, + const struct st_gp_variant_key *key) +{ + struct st_gp_variant *gpv; + + /* Search for existing variant */ + for (gpv = stgp->variants; gpv; gpv = gpv->next) { + if (memcmp(&gpv->key, key, sizeof(*key)) == 0) { + break; + } + } + + if (!gpv) { + /* create new */ + gpv = st_translate_geometry_program(st, stgp, key); + if (gpv) { + /* insert into list */ + gpv->next = stgp->variants; + stgp->variants = gpv; + } + } + + return gpv; +} + + + + +/** + * Debug- print current shader text + */ +void +st_print_shaders(struct gl_context *ctx) +{ + struct gl_shader_program *shProg[3] = { + ctx->Shader.CurrentVertexProgram, + ctx->Shader.CurrentGeometryProgram, + ctx->Shader.CurrentFragmentProgram, + }; + unsigned j; + + for (j = 0; j < 3; j++) { + unsigned i; + + if (shProg[j] == NULL) + continue; + + for (i = 0; i < shProg[j]->NumShaders; i++) { + struct gl_shader *sh; + + switch (shProg[j]->Shaders[i]->Type) { + case GL_VERTEX_SHADER: + sh = (i != 0) ? NULL : shProg[j]->Shaders[i]; + break; + case GL_GEOMETRY_SHADER_ARB: + sh = (i != 1) ? NULL : shProg[j]->Shaders[i]; + break; + case GL_FRAGMENT_SHADER: + sh = (i != 2) ? NULL : shProg[j]->Shaders[i]; + break; + default: + assert(0); + sh = NULL; + break; + } + + if (sh != NULL) { + printf("GLSL shader %u of %u:\n", i, shProg[j]->NumShaders); + printf("%s\n", sh->Source); + } + } + } +} + + +/** + * Vert/Geom/Frag programs have per-context variants. Free all the + * variants attached to the given program which match the given context. + */ +static void +destroy_program_variants(struct st_context *st, struct gl_program *program) +{ + if (!program) + return; + + switch (program->Target) { + case GL_VERTEX_PROGRAM_ARB: + { + struct st_vertex_program *stvp = (struct st_vertex_program *) program; + struct st_vp_variant *vpv, **prevPtr = &stvp->variants; + + for (vpv = stvp->variants; vpv; ) { + struct st_vp_variant *next = vpv->next; + if (vpv->key.st == st) { + /* unlink from list */ + *prevPtr = next; + /* destroy this variant */ + delete_vp_variant(st, vpv); + } + else { + prevPtr = &vpv->next; + } + vpv = next; + } + } + break; + case GL_FRAGMENT_PROGRAM_ARB: + { + struct st_fragment_program *stfp = + (struct st_fragment_program *) program; + struct st_fp_variant *fpv, **prevPtr = &stfp->variants; + + for (fpv = stfp->variants; fpv; ) { + struct st_fp_variant *next = fpv->next; + if (fpv->key.st == st) { + /* unlink from list */ + *prevPtr = next; + /* destroy this variant */ + delete_fp_variant(st, fpv); + } + else { + prevPtr = &fpv->next; + } + fpv = next; + } + } + break; + case MESA_GEOMETRY_PROGRAM: + { + struct st_geometry_program *stgp = + (struct st_geometry_program *) program; + struct st_gp_variant *gpv, **prevPtr = &stgp->variants; + + for (gpv = stgp->variants; gpv; ) { + struct st_gp_variant *next = gpv->next; + if (gpv->key.st == st) { + /* unlink from list */ + *prevPtr = next; + /* destroy this variant */ + delete_gp_variant(st, gpv); + } + else { + prevPtr = &gpv->next; + } + gpv = next; + } + } + break; + default: + _mesa_problem(NULL, "Unexpected program target in " + "destroy_program_variants_cb()"); + } +} + + +/** + * Callback for _mesa_HashWalk. Free all the shader's program variants + * which match the given context. + */ +static void +destroy_shader_program_variants_cb(GLuint key, void *data, void *userData) +{ + struct st_context *st = (struct st_context *) userData; + struct gl_shader *shader = (struct gl_shader *) data; + + switch (shader->Type) { + case GL_SHADER_PROGRAM_MESA: + { + struct gl_shader_program *shProg = (struct gl_shader_program *) data; + GLuint i; + + for (i = 0; i < shProg->NumShaders; i++) { + destroy_program_variants(st, shProg->Shaders[i]->Program); + } + + destroy_program_variants(st, (struct gl_program *) + shProg->VertexProgram); + destroy_program_variants(st, (struct gl_program *) + shProg->FragmentProgram); + destroy_program_variants(st, (struct gl_program *) + shProg->GeometryProgram); + } + break; + case GL_VERTEX_SHADER: + case GL_FRAGMENT_SHADER: + case GL_GEOMETRY_SHADER: + { + destroy_program_variants(st, shader->Program); + } + break; + default: + assert(0); + } +} + + +/** + * Callback for _mesa_HashWalk. Free all the program variants which match + * the given context. + */ +static void +destroy_program_variants_cb(GLuint key, void *data, void *userData) +{ + struct st_context *st = (struct st_context *) userData; + struct gl_program *program = (struct gl_program *) data; + destroy_program_variants(st, program); +} + + +/** + * Walk over all shaders and programs to delete any variants which + * belong to the given context. + * This is called during context tear-down. + */ +void +st_destroy_program_variants(struct st_context *st) +{ + /* ARB vert/frag program */ + _mesa_HashWalk(st->ctx->Shared->Programs, + destroy_program_variants_cb, st); + + /* GLSL vert/frag/geom shaders */ + _mesa_HashWalk(st->ctx->Shared->ShaderObjects, + destroy_shader_program_variants_cb, st); +} -- cgit v1.2.3