aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/mesa
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/mesa')
-rw-r--r--mesalib/src/mesa/drivers/dri/Makefile.template222
-rw-r--r--mesalib/src/mesa/drivers/dri/common/dri_util.c2060
-rw-r--r--mesalib/src/mesa/drivers/dri/common/dri_util.h1126
-rw-r--r--mesalib/src/mesa/drivers/dri/common/utils.c2
-rw-r--r--mesalib/src/mesa/drivers/dri/swrast/swrast.c1617
-rw-r--r--mesalib/src/mesa/drivers/dri/swrast/swrast_priv.h7
-rw-r--r--mesalib/src/mesa/drivers/windows/gdi/wmesa.c3324
-rw-r--r--mesalib/src/mesa/drivers/windows/gldirect/dglcontext.c4424
-rw-r--r--mesalib/src/mesa/main/api_arrayelt.c2
-rw-r--r--mesalib/src/mesa/main/api_exec.c1
-rw-r--r--mesalib/src/mesa/main/blend.c1644
-rw-r--r--mesalib/src/mesa/main/bufferobj.c4316
-rw-r--r--mesalib/src/mesa/main/compiler.h24
-rw-r--r--mesalib/src/mesa/main/context.c3764
-rw-r--r--mesalib/src/mesa/main/context.h626
-rw-r--r--mesalib/src/mesa/main/depth.c348
-rw-r--r--mesalib/src/mesa/main/dlopen.c6
-rw-r--r--mesalib/src/mesa/main/hint.c294
-rw-r--r--mesalib/src/mesa/main/imports.c2056
-rw-r--r--mesalib/src/mesa/main/imports.h1230
-rw-r--r--mesalib/src/mesa/main/lines.c234
-rw-r--r--mesalib/src/mesa/main/queryobj.c1246
-rw-r--r--mesalib/src/mesa/main/shaderapi.c3884
-rw-r--r--mesalib/src/mesa/main/state.c1468
-rw-r--r--mesalib/src/mesa/main/stencil.c1228
-rw-r--r--mesalib/src/mesa/main/syncobj.c12
-rw-r--r--mesalib/src/mesa/main/syncobj.h12
-rw-r--r--mesalib/src/mesa/main/texcompress_s3tc.c4
-rw-r--r--mesalib/src/mesa/program/sampler.cpp274
-rw-r--r--mesalib/src/mesa/state_tracker/st_atom_blend.c604
-rw-r--r--mesalib/src/mesa/state_tracker/st_atom_framebuffer.c364
-rw-r--r--mesalib/src/mesa/state_tracker/st_atom_sampler.c456
-rw-r--r--mesalib/src/mesa/state_tracker/st_cb_bitmap.c1786
-rw-r--r--mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c936
-rw-r--r--mesalib/src/mesa/state_tracker/st_cb_clear.c1158
-rw-r--r--mesalib/src/mesa/state_tracker/st_cb_drawtex.c614
-rw-r--r--mesalib/src/mesa/state_tracker/st_cb_texture.c3836
-rw-r--r--mesalib/src/mesa/state_tracker/st_context.c594
-rw-r--r--mesalib/src/mesa/state_tracker/st_context.h540
-rw-r--r--mesalib/src/mesa/state_tracker/st_draw.c1518
-rw-r--r--mesalib/src/mesa/state_tracker/st_draw_feedback.c554
-rw-r--r--mesalib/src/mesa/state_tracker/st_format.c2298
-rw-r--r--mesalib/src/mesa/state_tracker/st_format.h172
-rw-r--r--mesalib/src/mesa/state_tracker/st_gen_mipmap.c844
-rw-r--r--mesalib/src/mesa/state_tracker/st_program.c2330
-rw-r--r--mesalib/src/mesa/tnl/t_draw.c1068
-rw-r--r--mesalib/src/mesa/vbo/vbo_exec.h396
-rw-r--r--mesalib/src/mesa/vbo/vbo_exec_api.c2214
-rw-r--r--mesalib/src/mesa/vbo/vbo_exec_draw.c852
-rw-r--r--mesalib/src/mesa/vbo/vbo_save_draw.c610
50 files changed, 29597 insertions, 29602 deletions
diff --git a/mesalib/src/mesa/drivers/dri/Makefile.template b/mesalib/src/mesa/drivers/dri/Makefile.template
index d1a119379..195d60a9c 100644
--- a/mesalib/src/mesa/drivers/dri/Makefile.template
+++ b/mesalib/src/mesa/drivers/dri/Makefile.template
@@ -1,111 +1,111 @@
-# -*-makefile-*-
-
-COMMON_GALLIUM_SOURCES = \
- ../common/utils.c \
- ../common/vblank.c \
- ../common/dri_util.c \
- ../common/xmlconfig.c
-
-COMMON_SOURCES = $(COMMON_GALLIUM_SOURCES) \
- ../../common/driverfuncs.c \
- ../common/texmem.c \
- ../common/drirenderbuffer.c
-
-INCLUDES = $(SHARED_INCLUDES) $(EXPAT_INCLUDES)
-
-OBJECTS = $(C_SOURCES:.c=.o) \
- $(CXX_SOURCES:.cpp=.o) \
- $(ASM_SOURCES:.S=.o)
-
-
-### Include directories
-SHARED_INCLUDES = \
- -I. \
- -I$(TOP)/src/mesa/drivers/dri/common \
- -Iserver \
- -I$(TOP)/include \
- -I$(TOP)/src/mapi \
- -I$(TOP)/src/mesa \
- -I$(TOP)/src/egl/main \
- -I$(TOP)/src/egl/drivers/dri \
- $(LIBDRM_CFLAGS)
-
-CFLAGS += $(API_DEFINES)
-CXXFLAGS += $(API_DEFINES)
-
-##### RULES #####
-
-.c.o:
- $(CC) -c $(INCLUDES) $(DRI_CFLAGS) $(DRIVER_DEFINES) $< -o $@
-
-.cpp.o:
- $(CC) -c $(INCLUDES) $(DRI_CXXFLAGS) $(DRIVER_DEFINES) $< -o $@
-
-.S.o:
- $(CC) -c $(INCLUDES) $(DRI_CFLAGS) $(DRIVER_DEFINES) $< -o $@
-
-
-##### TARGETS #####
-
-default: subdirs lib
-
-
-.PHONY: lib
-lib: symlinks subdirs depend
- @$(MAKE) $(LIBNAME) $(TOP)/$(LIB_DIR)/$(LIBNAME)
-
-$(LIBNAME): $(OBJECTS) $(EXTRA_MODULES) $(MESA_MODULES) Makefile \
- $(TOP)/src/mesa/drivers/dri/Makefile.template $(TOP)/src/mesa/drivers/dri/common/dri_test.o
- $(MKLIB) -o $@.tmp -noprefix -linker '$(CXX)' -ldflags '$(LDFLAGS)' \
- $(OBJECTS) $(EXTRA_MODULES) $(DRI_LIB_DEPS)
- $(CXX) $(CFLAGS) -o $@.test $(TOP)/src/mesa/drivers/dri/common/dri_test.o $@.tmp $(DRI_LIB_DEPS)
- @rm -f $@.test
- mv -f $@.tmp $@
-
-
-$(TOP)/$(LIB_DIR)/$(LIBNAME): $(LIBNAME)
- $(INSTALL) $(LIBNAME) $(TOP)/$(LIB_DIR)
-
-
-# If the Makefile defined SUBDIRS, run make in each
-.PHONY: subdirs
-subdirs:
- @if test -n "$(SUBDIRS)" ; then \
- for dir in $(SUBDIRS) ; do \
- if [ -d $$dir ] ; then \
- (cd $$dir && $(MAKE)) || exit 1; \
- fi \
- done \
- fi
-
-
-.PHONY: symlinks
-symlinks:
-
-
-depend: $(C_SOURCES) $(CXX_SOURCES) $(ASM_SOURCES) $(SYMLINKS)
- @ echo "running $(MKDEP)"
- @ rm -f depend
- @ touch depend
- @ $(MKDEP) $(MKDEP_OPTIONS) $(DRIVER_DEFINES) $(INCLUDES) \
- $(C_SOURCES) $(CXX_SOURCES) \
- $(ASM_SOURCES) > /dev/null 2>/dev/null
-
-
-# Emacs tags
-tags:
- etags `find . -name \*.[ch]` `find ../include`
-
-
-# Remove .o and backup files
-clean:
- -rm -f *.o */*.o *~ *.so *~ server/*.o $(SYMLINKS)
- -rm -f depend depend.bak
-
-
-install: $(LIBNAME)
- $(INSTALL) -d $(DESTDIR)$(DRI_DRIVER_INSTALL_DIR)
- $(MINSTALL) -m 755 $(LIBNAME) $(DESTDIR)$(DRI_DRIVER_INSTALL_DIR)
-
-
--include depend
+# -*-makefile-*-
+
+COMMON_GALLIUM_SOURCES = \
+ ../common/utils.c \
+ ../common/vblank.c \
+ ../common/dri_util.c \
+ ../common/xmlconfig.c
+
+COMMON_SOURCES = $(COMMON_GALLIUM_SOURCES) \
+ ../../common/driverfuncs.c \
+ ../common/texmem.c \
+ ../common/drirenderbuffer.c
+
+INCLUDES = $(SHARED_INCLUDES) $(EXPAT_INCLUDES)
+
+OBJECTS = $(C_SOURCES:.c=.o) \
+ $(CXX_SOURCES:.cpp=.o) \
+ $(ASM_SOURCES:.S=.o)
+
+
+### Include directories
+SHARED_INCLUDES = \
+ -I. \
+ -I$(TOP)/src/mesa/drivers/dri/common \
+ -Iserver \
+ -I$(TOP)/include \
+ -I$(TOP)/src/mapi \
+ -I$(TOP)/src/mesa \
+ -I$(TOP)/src/egl/main \
+ -I$(TOP)/src/egl/drivers/dri \
+ $(LIBDRM_CFLAGS)
+
+CFLAGS += $(API_DEFINES)
+CXXFLAGS += $(API_DEFINES)
+
+##### RULES #####
+
+.c.o:
+ $(CC) -c $(INCLUDES) $(DRI_CFLAGS) $(DRIVER_DEFINES) $< -o $@
+
+.cpp.o:
+ $(CC) -c $(INCLUDES) $(DRI_CXXFLAGS) $(DRIVER_DEFINES) $< -o $@
+
+.S.o:
+ $(CC) -c $(INCLUDES) $(DRI_CFLAGS) $(DRIVER_DEFINES) $< -o $@
+
+
+##### TARGETS #####
+
+default: subdirs lib
+
+
+.PHONY: lib
+lib: symlinks subdirs depend
+ @$(MAKE) $(LIBNAME) $(TOP)/$(LIB_DIR)/$(LIBNAME)
+
+$(LIBNAME): $(OBJECTS) $(EXTRA_MODULES) $(MESA_MODULES) Makefile \
+ $(TOP)/src/mesa/drivers/dri/Makefile.template $(TOP)/src/mesa/drivers/dri/common/dri_test.o
+ $(MKLIB) -o $@.tmp -noprefix -linker '$(CXX)' -ldflags '$(LDFLAGS)' \
+ $(OBJECTS) $(EXTRA_MODULES) $(DRI_LIB_DEPS)
+ $(CXX) $(CFLAGS) -o $@.test $(TOP)/src/mesa/drivers/dri/common/dri_test.o $@.tmp $(DRI_LIB_DEPS)
+ @rm -f $@.test
+ mv -f $@.tmp $@
+
+
+$(TOP)/$(LIB_DIR)/$(LIBNAME): $(LIBNAME)
+ $(INSTALL) $(LIBNAME) $(TOP)/$(LIB_DIR)
+
+
+# If the Makefile defined SUBDIRS, run make in each
+.PHONY: subdirs
+subdirs:
+ @if test -n "$(SUBDIRS)" ; then \
+ for dir in $(SUBDIRS) ; do \
+ if [ -d $$dir ] ; then \
+ (cd $$dir && $(MAKE)) || exit 1; \
+ fi \
+ done \
+ fi
+
+
+.PHONY: symlinks
+symlinks:
+
+
+depend: $(C_SOURCES) $(CXX_SOURCES) $(ASM_SOURCES) $(SYMLINKS)
+ @ echo "running $(MKDEP)"
+ @ rm -f depend
+ @ touch depend
+ @ $(MKDEP) $(MKDEP_OPTIONS) $(DRIVER_DEFINES) $(INCLUDES) \
+ $(C_SOURCES) $(CXX_SOURCES) \
+ $(ASM_SOURCES) > /dev/null 2>/dev/null
+
+
+# Emacs tags
+tags:
+ etags `find . -name \*.[ch]` `find ../include`
+
+
+# Remove .o and backup files
+clean:
+ -rm -f *.o */*.o *~ *.so *~ server/*.o $(SYMLINKS)
+ -rm -f depend depend.bak
+
+
+install: $(LIBNAME)
+ $(INSTALL) -d $(DESTDIR)$(DRI_DRIVER_INSTALL_DIR)
+ $(MINSTALL) -m 755 $(LIBNAME) $(DESTDIR)$(DRI_DRIVER_INSTALL_DIR)
+
+
+-include depend
diff --git a/mesalib/src/mesa/drivers/dri/common/dri_util.c b/mesalib/src/mesa/drivers/dri/common/dri_util.c
index 82638fa72..6d3dd0a2c 100644
--- a/mesalib/src/mesa/drivers/dri/common/dri_util.c
+++ b/mesalib/src/mesa/drivers/dri/common/dri_util.c
@@ -1,1030 +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 <assert.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <stdio.h>
-
-#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++;
-}
-
-/*@}*/
+/**
+ * \file dri_util.c
+ * DRI utility functions.
+ *
+ * This module acts as glue between GLX and the actual hardware driver. A DRI
+ * driver doesn't really \e have to use any of this - it's optional. But, some
+ * useful stuff is done here that otherwise would have to be duplicated in most
+ * drivers.
+ *
+ * Basically, these utility functions take care of some of the dirty details of
+ * screen initialization, context creation, context binding, DRM setup, etc.
+ *
+ * These functions are compiled into each DRI driver so libGL.so knows nothing
+ * about them.
+ */
+
+
+#include <assert.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <stdio.h>
+
+#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 3d3d5c9cd..8d2a38524 100644
--- a/mesalib/src/mesa/drivers/dri/common/dri_util.h
+++ b/mesalib/src/mesa/drivers/dri/common/dri_util.h
@@ -1,563 +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 <kevin@precisioninsight.com>
- * \author Brian Paul <brian@precisioninsight.com>
- */
-
-#ifndef _DRI_UTIL_H_
-#define _DRI_UTIL_H_
-
-#include <GL/gl.h>
-#include <drm.h>
-#include <drm_sarea.h>
-#include <xf86drm.h>
-#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_ */
+/*
+ * 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 <kevin@precisioninsight.com>
+ * \author Brian Paul <brian@precisioninsight.com>
+ */
+
+#ifndef _DRI_UTIL_H_
+#define _DRI_UTIL_H_
+
+#include <GL/gl.h>
+#include <drm.h>
+#include <drm_sarea.h>
+#include <xf86drm.h>
+#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/common/utils.c b/mesalib/src/mesa/drivers/dri/common/utils.c
index a2b0b4e94..02c8cc6f5 100644
--- a/mesalib/src/mesa/drivers/dri/common/utils.c
+++ b/mesalib/src/mesa/drivers/dri/common/utils.c
@@ -219,7 +219,9 @@ void driInitExtensions( struct gl_context * ctx,
/* Map the static functions. Together with those mapped by remap
* table, this should cover everything mesa core knows.
*/
+#ifdef _GLAPI_USE_REMAP_TABLE
_mesa_map_static_functions();
+#endif
return;
}
diff --git a/mesalib/src/mesa/drivers/dri/swrast/swrast.c b/mesalib/src/mesa/drivers/dri/swrast/swrast.c
index 719b406ec..e6d1ab741 100644
--- a/mesalib/src/mesa/drivers/dri/swrast/swrast.c
+++ b/mesalib/src/mesa/drivers/dri/swrast/swrast.c
@@ -1,806 +1,811 @@
-/*
- * Copyright 2008, 2010 George Sapountzis <gsapountzis@gmail.com>
- *
- * 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.
- */
-
-/*
- * DRI software rasterizer
- *
- * This is the mesa swrast module packaged into a DRI driver structure.
- *
- * The front-buffer is allocated by the loader. The loader provides read/write
- * callbacks for access to the front-buffer. The driver uses a scratch row for
- * front-buffer rendering to avoid repeated calls to the loader.
- *
- * The back-buffer is allocated by the driver and is private.
- */
-
-#include "main/context.h"
-#include "main/extensions.h"
-#include "main/formats.h"
-#include "main/framebuffer.h"
-#include "main/imports.h"
-#include "main/renderbuffer.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"
-#include "vbo/vbo.h"
-#include "drivers/common/driverfuncs.h"
-#include "drivers/common/meta.h"
-#include "utils.h"
-
-#include "main/teximage.h"
-#include "main/texformat.h"
-#include "main/texstate.h"
-
-#include "swrast_priv.h"
-
-
-/**
- * Screen and config-related functions
- */
-
-static void swrastSetTexBuffer2(__DRIcontext *pDRICtx, GLint target,
- GLint texture_format, __DRIdrawable *dPriv)
-{
- struct dri_context *dri_ctx;
- int x, y, w, h;
- __DRIscreen *sPriv = dPriv->driScreenPriv;
- struct gl_texture_unit *texUnit;
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
- uint32_t internalFormat;
- gl_format texFormat;
-
- dri_ctx = pDRICtx->driverPrivate;
-
- internalFormat = (texture_format == __DRI_TEXTURE_FORMAT_RGB ? 3 : 4);
-
- texUnit = _mesa_get_current_tex_unit(&dri_ctx->Base);
- texObj = _mesa_select_tex_object(&dri_ctx->Base, texUnit, target);
- texImage = _mesa_get_tex_image(&dri_ctx->Base, texObj, target, 0);
-
- _mesa_lock_texture(&dri_ctx->Base, texObj);
-
- sPriv->swrast_loader->getDrawableInfo(dPriv, &x, &y, &w, &h, dPriv->loaderPrivate);
-
- if (texture_format == __DRI_TEXTURE_FORMAT_RGB)
- texFormat = MESA_FORMAT_XRGB8888;
- else
- texFormat = MESA_FORMAT_ARGB8888;
-
- _mesa_init_teximage_fields(&dri_ctx->Base, target, texImage,
- w, h, 1, 0, internalFormat, texFormat);
-
- sPriv->swrast_loader->getImage(dPriv, x, y, w, h, (char *)texImage->Data,
- dPriv->loaderPrivate);
-
- _mesa_unlock_texture(&dri_ctx->Base, texObj);
-}
-
-static void swrastSetTexBuffer(__DRIcontext *pDRICtx, GLint target,
- __DRIdrawable *dPriv)
-{
- swrastSetTexBuffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);
-}
-
-static const __DRItexBufferExtension swrastTexBufferExtension = {
- { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION },
- swrastSetTexBuffer,
- swrastSetTexBuffer2,
-};
-
-static const __DRIextension *dri_screen_extensions[] = {
- &swrastTexBufferExtension.base,
- NULL
-};
-
-static __DRIconfig **
-swrastFillInModes(__DRIscreen *psp,
- unsigned pixel_bits, unsigned depth_bits,
- unsigned stencil_bits, GLboolean have_back_buffer)
-{
- __DRIconfig **configs;
- unsigned depth_buffer_factor;
- unsigned back_buffer_factor;
- GLenum fb_format;
- GLenum fb_type;
-
- /* GLX_SWAP_COPY_OML is only supported because the Intel driver doesn't
- * support pageflipping at all.
- */
- static const GLenum back_buffer_modes[] = {
- GLX_NONE, GLX_SWAP_UNDEFINED_OML
- };
-
- uint8_t depth_bits_array[4];
- uint8_t stencil_bits_array[4];
- uint8_t msaa_samples_array[1];
-
- depth_bits_array[0] = 0;
- depth_bits_array[1] = 0;
- depth_bits_array[2] = depth_bits;
- depth_bits_array[3] = depth_bits;
-
- /* Just like with the accumulation buffer, always provide some modes
- * with a stencil buffer.
- */
- stencil_bits_array[0] = 0;
- stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
- stencil_bits_array[2] = 0;
- stencil_bits_array[3] = (stencil_bits == 0) ? 8 : stencil_bits;
-
- msaa_samples_array[0] = 0;
-
- depth_buffer_factor = 4;
- back_buffer_factor = 2;
-
- switch (pixel_bits) {
- case 8:
- fb_format = GL_RGB;
- fb_type = GL_UNSIGNED_BYTE_2_3_3_REV;
- break;
- case 16:
- fb_format = GL_RGB;
- fb_type = GL_UNSIGNED_SHORT_5_6_5;
- break;
- case 24:
- fb_format = GL_BGR;
- fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
- break;
- case 32:
- fb_format = GL_BGRA;
- fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
- break;
- default:
- fprintf(stderr, "[%s:%u] bad depth %d\n", __func__, __LINE__,
- pixel_bits);
- return NULL;
- }
-
- configs = driCreateConfigs(fb_format, fb_type,
- depth_bits_array, stencil_bits_array,
- depth_buffer_factor, back_buffer_modes,
- back_buffer_factor, msaa_samples_array, 1,
- GL_TRUE);
- if (configs == NULL) {
- fprintf(stderr, "[%s:%u] Error creating FBConfig!\n", __func__,
- __LINE__);
- return NULL;
- }
-
- return configs;
-}
-
-static const __DRIconfig **
-dri_init_screen(__DRIscreen * psp)
-{
- __DRIconfig **configs8, **configs16, **configs24, **configs32;
-
- TRACE;
-
- psp->extensions = dri_screen_extensions;
-
- configs8 = swrastFillInModes(psp, 8, 8, 0, 1);
- configs16 = swrastFillInModes(psp, 16, 16, 0, 1);
- configs24 = swrastFillInModes(psp, 24, 24, 8, 1);
- configs32 = swrastFillInModes(psp, 32, 24, 8, 1);
-
- configs16 = driConcatConfigs(configs8, configs16);
- configs24 = driConcatConfigs(configs16, configs24);
- configs32 = driConcatConfigs(configs24, configs32);
-
- return (const __DRIconfig **)configs32;
-}
-
-static void
-dri_destroy_screen(__DRIscreen * sPriv)
-{
- TRACE;
-}
-
-
-/**
- * Framebuffer and renderbuffer-related functions.
- */
-
-static GLuint
-choose_pixel_format(const struct gl_config *v)
-{
- int depth = v->rgbBits;
-
- if (depth == 32
- && v->redMask == 0xff0000
- && v->greenMask == 0x00ff00
- && v->blueMask == 0x0000ff)
- return PF_A8R8G8B8;
- else if (depth == 24
- && v->redMask == 0xff0000
- && v->greenMask == 0x00ff00
- && v->blueMask == 0x0000ff)
- return PF_X8R8G8B8;
- else if (depth == 16
- && v->redMask == 0xf800
- && v->greenMask == 0x07e0
- && v->blueMask == 0x001f)
- return PF_R5G6B5;
- else if (depth == 8
- && v->redMask == 0x07
- && v->greenMask == 0x38
- && v->blueMask == 0xc0)
- return PF_R3G3B2;
-
- _mesa_problem( NULL, "unexpected format in %s", __FUNCTION__ );
- return 0;
-}
-
-static void
-swrast_delete_renderbuffer(struct gl_renderbuffer *rb)
-{
- TRACE;
-
- free(rb->Data);
- free(rb);
-}
-
-/* see bytes_per_line in libGL */
-static INLINE int
-bytes_per_line(unsigned pitch_bits, unsigned mul)
-{
- unsigned mask = mul - 1;
-
- return ((pitch_bits + mask) & ~mask) / 8;
-}
-
-static GLboolean
-swrast_alloc_front_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
- GLenum internalFormat, GLuint width, GLuint height)
-{
- struct swrast_renderbuffer *xrb = swrast_renderbuffer(rb);
-
- TRACE;
-
- rb->Data = NULL;
- rb->Width = width;
- rb->Height = height;
-
- xrb->pitch = bytes_per_line(width * xrb->bpp, 32);
-
- return GL_TRUE;
-}
-
-static GLboolean
-swrast_alloc_back_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
- GLenum internalFormat, GLuint width, GLuint height)
-{
- struct swrast_renderbuffer *xrb = swrast_renderbuffer(rb);
-
- TRACE;
-
- free(rb->Data);
-
- swrast_alloc_front_storage(ctx, rb, internalFormat, width, height);
-
- rb->Data = malloc(height * xrb->pitch);
-
- return GL_TRUE;
-}
-
-static struct swrast_renderbuffer *
-swrast_new_renderbuffer(const struct gl_config *visual, GLboolean front)
-{
- struct swrast_renderbuffer *xrb = calloc(1, sizeof *xrb);
- GLuint pixel_format;
-
- TRACE;
-
- if (!xrb)
- return NULL;
-
- _mesa_init_renderbuffer(&xrb->Base, 0);
-
- pixel_format = choose_pixel_format(visual);
-
- xrb->Base.Delete = swrast_delete_renderbuffer;
- if (front) {
- xrb->Base.AllocStorage = swrast_alloc_front_storage;
- swrast_set_span_funcs_front(xrb, pixel_format);
- }
- else {
- xrb->Base.AllocStorage = swrast_alloc_back_storage;
- swrast_set_span_funcs_back(xrb, pixel_format);
- }
-
- switch (pixel_format) {
- case PF_A8R8G8B8:
- xrb->Base.Format = MESA_FORMAT_ARGB8888;
- xrb->Base.InternalFormat = GL_RGBA;
- xrb->Base._BaseFormat = GL_RGBA;
- xrb->Base.DataType = GL_UNSIGNED_BYTE;
- xrb->bpp = 32;
- break;
- case PF_X8R8G8B8:
- xrb->Base.Format = MESA_FORMAT_ARGB8888; /* XXX */
- xrb->Base.InternalFormat = GL_RGB;
- xrb->Base._BaseFormat = GL_RGB;
- xrb->Base.DataType = GL_UNSIGNED_BYTE;
- xrb->bpp = 32;
- break;
- case PF_R5G6B5:
- xrb->Base.Format = MESA_FORMAT_RGB565;
- xrb->Base.InternalFormat = GL_RGB;
- xrb->Base._BaseFormat = GL_RGB;
- xrb->Base.DataType = GL_UNSIGNED_BYTE;
- xrb->bpp = 16;
- break;
- case PF_R3G3B2:
- xrb->Base.Format = MESA_FORMAT_RGB332;
- xrb->Base.InternalFormat = GL_RGB;
- xrb->Base._BaseFormat = GL_RGB;
- xrb->Base.DataType = GL_UNSIGNED_BYTE;
- xrb->bpp = 8;
- break;
- default:
- return NULL;
- }
-
- return xrb;
-}
-
-static GLboolean
-dri_create_buffer(__DRIscreen * sPriv,
- __DRIdrawable * dPriv,
- const struct gl_config * visual, GLboolean isPixmap)
-{
- struct dri_drawable *drawable = NULL;
- struct gl_framebuffer *fb;
- struct swrast_renderbuffer *frontrb, *backrb;
-
- TRACE;
-
- drawable = CALLOC_STRUCT(dri_drawable);
- if (drawable == NULL)
- goto drawable_fail;
-
- dPriv->driverPrivate = drawable;
- drawable->dPriv = dPriv;
-
- drawable->row = malloc(MAX_WIDTH * 4);
- if (drawable->row == NULL)
- goto drawable_fail;
-
- fb = &drawable->Base;
-
- /* basic framebuffer setup */
- _mesa_initialize_window_framebuffer(fb, visual);
-
- /* add front renderbuffer */
- frontrb = swrast_new_renderbuffer(visual, GL_TRUE);
- _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &frontrb->Base);
-
- /* add back renderbuffer */
- if (visual->doubleBufferMode) {
- backrb = swrast_new_renderbuffer(visual, GL_FALSE);
- _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &backrb->Base);
- }
-
- /* add software renderbuffers */
- _mesa_add_soft_renderbuffers(fb,
- GL_FALSE, /* color */
- visual->haveDepthBuffer,
- visual->haveStencilBuffer,
- visual->haveAccumBuffer,
- GL_FALSE, /* alpha */
- GL_FALSE /* aux bufs */);
-
- return GL_TRUE;
-
-drawable_fail:
-
- if (drawable)
- free(drawable->row);
-
- FREE(drawable);
-
- return GL_FALSE;
-}
-
-static void
-dri_destroy_buffer(__DRIdrawable * dPriv)
-{
- TRACE;
-
- if (dPriv) {
- struct dri_drawable *drawable = dri_drawable(dPriv);
- struct gl_framebuffer *fb;
-
- free(drawable->row);
-
- fb = &drawable->Base;
-
- fb->DeletePending = GL_TRUE;
- _mesa_reference_framebuffer(&fb, NULL);
- }
-}
-
-static void
-dri_swap_buffers(__DRIdrawable * dPriv)
-{
- __DRIscreen *sPriv = dPriv->driScreenPriv;
-
- GET_CURRENT_CONTEXT(ctx);
-
- struct dri_drawable *drawable = dri_drawable(dPriv);
- struct gl_framebuffer *fb;
- struct swrast_renderbuffer *frontrb, *backrb;
-
- TRACE;
-
- fb = &drawable->Base;
-
- frontrb =
- swrast_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
- backrb =
- swrast_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer);
-
- /* check for signle-buffered */
- if (backrb == NULL)
- return;
-
- /* check if swapping currently bound buffer */
- if (ctx && ctx->DrawBuffer == fb) {
- /* flush pending rendering */
- _mesa_notifySwapBuffers(ctx);
- }
-
- sPriv->swrast_loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,
- 0, 0,
- frontrb->Base.Width,
- frontrb->Base.Height,
- backrb->Base.Data,
- dPriv->loaderPrivate);
-}
-
-
-/**
- * General device driver functions.
- */
-
-static void
-get_window_size( struct gl_framebuffer *fb, GLsizei *w, GLsizei *h )
-{
- __DRIdrawable *dPriv = swrast_drawable(fb)->dPriv;
- __DRIscreen *sPriv = dPriv->driScreenPriv;
- int x, y;
-
- sPriv->swrast_loader->getDrawableInfo(dPriv,
- &x, &y, w, h,
- dPriv->loaderPrivate);
-}
-
-static void
-swrast_check_and_update_window_size( struct gl_context *ctx, struct gl_framebuffer *fb )
-{
- GLsizei width, height;
-
- get_window_size(fb, &width, &height);
- if (fb->Width != width || fb->Height != height) {
- _mesa_resize_framebuffer(ctx, fb, width, height);
- }
-}
-
-static const GLubyte *
-get_string(struct gl_context *ctx, GLenum pname)
-{
- (void) ctx;
- switch (pname) {
- case GL_VENDOR:
- return (const GLubyte *) "Mesa Project";
- case GL_RENDERER:
- return (const GLubyte *) "Software Rasterizer";
- default:
- return NULL;
- }
-}
-
-static void
-update_state( struct gl_context *ctx, GLuint new_state )
-{
- /* not much to do here - pass it on */
- _swrast_InvalidateState( ctx, new_state );
- _swsetup_InvalidateState( ctx, new_state );
- _vbo_InvalidateState( ctx, new_state );
- _tnl_InvalidateState( ctx, new_state );
-}
-
-static void
-viewport(struct gl_context *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
-{
- struct gl_framebuffer *draw = ctx->WinSysDrawBuffer;
- struct gl_framebuffer *read = ctx->WinSysReadBuffer;
-
- swrast_check_and_update_window_size(ctx, draw);
- swrast_check_and_update_window_size(ctx, read);
-}
-
-static gl_format swrastChooseTextureFormat(struct gl_context * ctx,
- GLint internalFormat,
- GLenum format,
- GLenum type)
-{
- if (internalFormat == GL_RGB)
- return MESA_FORMAT_XRGB8888;
- return _mesa_choose_tex_format(ctx, internalFormat, format, type);
-}
-
-static void
-swrast_init_driver_functions(struct dd_function_table *driver)
-{
- driver->GetString = get_string;
- driver->UpdateState = update_state;
- driver->GetBufferSize = NULL;
- driver->Viewport = viewport;
- driver->ChooseTextureFormat = swrastChooseTextureFormat;
-}
-
-static const char *es2_extensions[] = {
- /* Used by mesa internally (cf all_mesa_extensions in ../common/utils.c) */
- "GL_ARB_draw_buffers",
- "GL_ARB_multisample",
- "GL_ARB_texture_compression",
- "GL_ARB_transpose_matrix",
- "GL_ARB_vertex_buffer_object",
- "GL_ARB_window_pos",
- "GL_EXT_blend_func_separate",
- "GL_EXT_compiled_vertex_array",
- "GL_EXT_framebuffer_blit",
- "GL_EXT_multi_draw_arrays",
- "GL_EXT_polygon_offset",
- "GL_EXT_texture_object",
- "GL_EXT_vertex_array",
- "GL_IBM_multimode_draw_arrays",
- "GL_MESA_window_pos",
- "GL_NV_vertex_program",
-
- /* Required by GLES2 */
- "GL_ARB_fragment_program",
- "GL_ARB_fragment_shader",
- "GL_ARB_multitexture",
- "GL_ARB_shader_objects",
- "GL_ARB_texture_cube_map",
- "GL_ARB_texture_mirrored_repeat",
- "GL_ARB_texture_non_power_of_two",
- "GL_ARB_vertex_shader",
- "GL_EXT_blend_color",
- "GL_EXT_blend_equation_separate",
- "GL_EXT_blend_minmax",
- "GL_EXT_blend_subtract",
- "GL_EXT_stencil_wrap",
-
- /* Optional GLES2 */
- "GL_ARB_framebuffer_object",
- "GL_EXT_texture_filter_anisotropic",
- "GL_ARB_depth_texture",
- "GL_EXT_packed_depth_stencil",
- "GL_EXT_framebuffer_object",
- NULL,
-};
-
-static void
-InitExtensionsES2(struct gl_context *ctx)
-{
- int i;
-
- /* Can't use driInitExtensions() since it uses extensions from
- * main/remap_helper.h when called the first time. */
-
- for (i = 0; es2_extensions[i]; i++)
- _mesa_enable_extension(ctx, es2_extensions[i]);
-}
-
-/**
- * Context-related functions.
- */
-
-static GLboolean
-dri_create_context(gl_api api,
- const struct gl_config * visual,
- __DRIcontext * cPriv, void *sharedContextPrivate)
-{
- struct dri_context *ctx = NULL;
- struct dri_context *share = (struct dri_context *)sharedContextPrivate;
- struct gl_context *mesaCtx = NULL;
- struct gl_context *sharedCtx = NULL;
- struct dd_function_table functions;
-
- TRACE;
-
- ctx = CALLOC_STRUCT(dri_context);
- if (ctx == NULL)
- goto context_fail;
-
- cPriv->driverPrivate = ctx;
- ctx->cPriv = cPriv;
-
- /* build table of device driver functions */
- _mesa_init_driver_functions(&functions);
- swrast_init_driver_functions(&functions);
-
- if (share) {
- sharedCtx = &share->Base;
- }
-
- mesaCtx = &ctx->Base;
-
- /* basic context setup */
- if (!_mesa_initialize_context(mesaCtx, api, visual, sharedCtx, &functions, (void *) cPriv)) {
- goto context_fail;
- }
-
- /* do bounds checking to prevent segfaults and server crashes! */
- mesaCtx->Const.CheckArrayBounds = GL_TRUE;
-
- /* create module contexts */
- _swrast_CreateContext( mesaCtx );
- _vbo_CreateContext( mesaCtx );
- _tnl_CreateContext( mesaCtx );
- _swsetup_CreateContext( mesaCtx );
- _swsetup_Wakeup( mesaCtx );
-
- /* use default TCL pipeline */
- {
- TNLcontext *tnl = TNL_CONTEXT(mesaCtx);
- tnl->Driver.RunPipeline = _tnl_run_pipeline;
- }
-
- _mesa_meta_init(mesaCtx);
- _mesa_enable_sw_extensions(mesaCtx);
-
- switch (api) {
- case API_OPENGL:
- _mesa_enable_1_3_extensions(mesaCtx);
- _mesa_enable_1_4_extensions(mesaCtx);
- _mesa_enable_1_5_extensions(mesaCtx);
- _mesa_enable_2_0_extensions(mesaCtx);
- _mesa_enable_2_1_extensions(mesaCtx);
-
- driInitExtensions( mesaCtx, NULL, GL_FALSE );
- break;
- case API_OPENGLES:
- _mesa_enable_1_3_extensions(mesaCtx);
- _mesa_enable_1_4_extensions(mesaCtx);
- _mesa_enable_1_5_extensions(mesaCtx);
-
- break;
- case API_OPENGLES2:
- InitExtensionsES2( mesaCtx);
- break;
- }
-
- return GL_TRUE;
-
-context_fail:
-
- FREE(ctx);
-
- return GL_FALSE;
-}
-
-static void
-dri_destroy_context(__DRIcontext * cPriv)
-{
- TRACE;
-
- if (cPriv) {
- struct dri_context *ctx = dri_context(cPriv);
- struct gl_context *mesaCtx;
-
- mesaCtx = &ctx->Base;
-
- _mesa_meta_free(mesaCtx);
- _swsetup_DestroyContext( mesaCtx );
- _swrast_DestroyContext( mesaCtx );
- _tnl_DestroyContext( mesaCtx );
- _vbo_DestroyContext( mesaCtx );
- _mesa_destroy_context( mesaCtx );
- }
-}
-
-static GLboolean
-dri_make_current(__DRIcontext * cPriv,
- __DRIdrawable * driDrawPriv,
- __DRIdrawable * driReadPriv)
-{
- struct gl_context *mesaCtx;
- struct gl_framebuffer *mesaDraw;
- struct gl_framebuffer *mesaRead;
- TRACE;
-
- if (cPriv) {
- struct dri_context *ctx = dri_context(cPriv);
- struct dri_drawable *draw;
- struct dri_drawable *read;
-
- if (!driDrawPriv || !driReadPriv)
- return GL_FALSE;
-
- draw = dri_drawable(driDrawPriv);
- read = dri_drawable(driReadPriv);
- mesaCtx = &ctx->Base;
- mesaDraw = &draw->Base;
- mesaRead = &read->Base;
-
- /* check for same context and buffer */
- if (mesaCtx == _mesa_get_current_context()
- && mesaCtx->DrawBuffer == mesaDraw
- && mesaCtx->ReadBuffer == mesaRead) {
- return GL_TRUE;
- }
-
- _glapi_check_multithread();
-
- swrast_check_and_update_window_size(mesaCtx, mesaDraw);
- if (mesaRead != mesaDraw)
- swrast_check_and_update_window_size(mesaCtx, mesaRead);
-
- _mesa_make_current( mesaCtx,
- mesaDraw,
- mesaRead );
- }
- else {
- /* unbind */
- _mesa_make_current( NULL, NULL, NULL );
- }
-
- return GL_TRUE;
-}
-
-static GLboolean
-dri_unbind_context(__DRIcontext * cPriv)
-{
- TRACE;
- (void) cPriv;
-
- /* Unset current context and dispath table */
- _mesa_make_current(NULL, NULL, NULL);
-
- return GL_TRUE;
-}
-
-
-const struct __DriverAPIRec driDriverAPI = {
- .InitScreen = dri_init_screen,
- .DestroyScreen = dri_destroy_screen,
- .CreateContext = dri_create_context,
- .DestroyContext = dri_destroy_context,
- .CreateBuffer = dri_create_buffer,
- .DestroyBuffer = dri_destroy_buffer,
- .SwapBuffers = dri_swap_buffers,
- .MakeCurrent = dri_make_current,
- .UnbindContext = dri_unbind_context,
-};
-
-/* This is the table of extensions that the loader will dlsym() for. */
-PUBLIC const __DRIextension *__driDriverExtensions[] = {
- &driCoreExtension.base,
- &driSWRastExtension.base,
- NULL
-};
+/*
+ * Copyright 2008, 2010 George Sapountzis <gsapountzis@gmail.com>
+ *
+ * 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.
+ */
+
+/*
+ * DRI software rasterizer
+ *
+ * This is the mesa swrast module packaged into a DRI driver structure.
+ *
+ * The front-buffer is allocated by the loader. The loader provides read/write
+ * callbacks for access to the front-buffer. The driver uses a scratch row for
+ * front-buffer rendering to avoid repeated calls to the loader.
+ *
+ * The back-buffer is allocated by the driver and is private.
+ */
+
+#ifdef _MSC_VER
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+#endif
+
+#include "main/context.h"
+#include "main/extensions.h"
+#include "main/formats.h"
+#include "main/framebuffer.h"
+#include "main/imports.h"
+#include "main/renderbuffer.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"
+#include "vbo/vbo.h"
+#include "drivers/common/driverfuncs.h"
+#include "drivers/common/meta.h"
+#include "utils.h"
+
+#include "main/teximage.h"
+#include "main/texformat.h"
+#include "main/texstate.h"
+
+#include "swrast_priv.h"
+
+
+/**
+ * Screen and config-related functions
+ */
+
+static void swrastSetTexBuffer2(__DRIcontext *pDRICtx, GLint target,
+ GLint texture_format, __DRIdrawable *dPriv)
+{
+ struct dri_context *dri_ctx;
+ int x, y, w, h;
+ __DRIscreen *sPriv = dPriv->driScreenPriv;
+ struct gl_texture_unit *texUnit;
+ struct gl_texture_object *texObj;
+ struct gl_texture_image *texImage;
+ uint32_t internalFormat;
+ gl_format texFormat;
+
+ dri_ctx = pDRICtx->driverPrivate;
+
+ internalFormat = (texture_format == __DRI_TEXTURE_FORMAT_RGB ? 3 : 4);
+
+ texUnit = _mesa_get_current_tex_unit(&dri_ctx->Base);
+ texObj = _mesa_select_tex_object(&dri_ctx->Base, texUnit, target);
+ texImage = _mesa_get_tex_image(&dri_ctx->Base, texObj, target, 0);
+
+ _mesa_lock_texture(&dri_ctx->Base, texObj);
+
+ sPriv->swrast_loader->getDrawableInfo(dPriv, &x, &y, &w, &h, dPriv->loaderPrivate);
+
+ if (texture_format == __DRI_TEXTURE_FORMAT_RGB)
+ texFormat = MESA_FORMAT_XRGB8888;
+ else
+ texFormat = MESA_FORMAT_ARGB8888;
+
+ _mesa_init_teximage_fields(&dri_ctx->Base, target, texImage,
+ w, h, 1, 0, internalFormat, texFormat);
+
+ sPriv->swrast_loader->getImage(dPriv, x, y, w, h, (char *)texImage->Data,
+ dPriv->loaderPrivate);
+
+ _mesa_unlock_texture(&dri_ctx->Base, texObj);
+}
+
+static void swrastSetTexBuffer(__DRIcontext *pDRICtx, GLint target,
+ __DRIdrawable *dPriv)
+{
+ swrastSetTexBuffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);
+}
+
+static const __DRItexBufferExtension swrastTexBufferExtension = {
+ { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION },
+ swrastSetTexBuffer,
+ swrastSetTexBuffer2,
+};
+
+static const __DRIextension *dri_screen_extensions[] = {
+ &swrastTexBufferExtension.base,
+ NULL
+};
+
+static __DRIconfig **
+swrastFillInModes(__DRIscreen *psp,
+ unsigned pixel_bits, unsigned depth_bits,
+ unsigned stencil_bits, GLboolean have_back_buffer)
+{
+ __DRIconfig **configs;
+ unsigned depth_buffer_factor;
+ unsigned back_buffer_factor;
+ GLenum fb_format;
+ GLenum fb_type;
+
+ /* GLX_SWAP_COPY_OML is only supported because the Intel driver doesn't
+ * support pageflipping at all.
+ */
+ static const GLenum back_buffer_modes[] = {
+ GLX_NONE, GLX_SWAP_UNDEFINED_OML
+ };
+
+ uint8_t depth_bits_array[4];
+ uint8_t stencil_bits_array[4];
+ uint8_t msaa_samples_array[1];
+
+ depth_bits_array[0] = 0;
+ depth_bits_array[1] = 0;
+ depth_bits_array[2] = depth_bits;
+ depth_bits_array[3] = depth_bits;
+
+ /* Just like with the accumulation buffer, always provide some modes
+ * with a stencil buffer.
+ */
+ stencil_bits_array[0] = 0;
+ stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
+ stencil_bits_array[2] = 0;
+ stencil_bits_array[3] = (stencil_bits == 0) ? 8 : stencil_bits;
+
+ msaa_samples_array[0] = 0;
+
+ depth_buffer_factor = 4;
+ back_buffer_factor = 2;
+
+ switch (pixel_bits) {
+ case 8:
+ fb_format = GL_RGB;
+ fb_type = GL_UNSIGNED_BYTE_2_3_3_REV;
+ break;
+ case 16:
+ fb_format = GL_RGB;
+ fb_type = GL_UNSIGNED_SHORT_5_6_5;
+ break;
+ case 24:
+ fb_format = GL_BGR;
+ fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ break;
+ case 32:
+ fb_format = GL_BGRA;
+ fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ break;
+ default:
+ fprintf(stderr, "[%s:%u] bad depth %d\n", __FUNCTION__, __LINE__,
+ pixel_bits);
+ return NULL;
+ }
+
+ configs = driCreateConfigs(fb_format, fb_type,
+ depth_bits_array, stencil_bits_array,
+ depth_buffer_factor, back_buffer_modes,
+ back_buffer_factor, msaa_samples_array, 1,
+ GL_TRUE);
+ if (configs == NULL) {
+ fprintf(stderr, "[%s:%u] Error creating FBConfig!\n", __FUNCTION__,
+ __LINE__);
+ return NULL;
+ }
+
+ return configs;
+}
+
+static const __DRIconfig **
+dri_init_screen(__DRIscreen * psp)
+{
+ __DRIconfig **configs8, **configs16, **configs24, **configs32;
+
+ TRACE;
+
+ psp->extensions = dri_screen_extensions;
+
+ configs8 = swrastFillInModes(psp, 8, 8, 0, 1);
+ configs16 = swrastFillInModes(psp, 16, 16, 0, 1);
+ configs24 = swrastFillInModes(psp, 24, 24, 8, 1);
+ configs32 = swrastFillInModes(psp, 32, 24, 8, 1);
+
+ configs16 = driConcatConfigs(configs8, configs16);
+ configs24 = driConcatConfigs(configs16, configs24);
+ configs32 = driConcatConfigs(configs24, configs32);
+
+ return (const __DRIconfig **)configs32;
+}
+
+static void
+dri_destroy_screen(__DRIscreen * sPriv)
+{
+ TRACE;
+}
+
+
+/**
+ * Framebuffer and renderbuffer-related functions.
+ */
+
+static GLuint
+choose_pixel_format(const struct gl_config *v)
+{
+ int depth = v->rgbBits;
+
+ if (depth == 32
+ && v->redMask == 0xff0000
+ && v->greenMask == 0x00ff00
+ && v->blueMask == 0x0000ff)
+ return PF_A8R8G8B8;
+ else if (depth == 24
+ && v->redMask == 0xff0000
+ && v->greenMask == 0x00ff00
+ && v->blueMask == 0x0000ff)
+ return PF_X8R8G8B8;
+ else if (depth == 16
+ && v->redMask == 0xf800
+ && v->greenMask == 0x07e0
+ && v->blueMask == 0x001f)
+ return PF_R5G6B5;
+ else if (depth == 8
+ && v->redMask == 0x07
+ && v->greenMask == 0x38
+ && v->blueMask == 0xc0)
+ return PF_R3G3B2;
+
+ _mesa_problem( NULL, "unexpected format in %s", __FUNCTION__ );
+ return 0;
+}
+
+static void
+swrast_delete_renderbuffer(struct gl_renderbuffer *rb)
+{
+ TRACE;
+
+ free(rb->Data);
+ free(rb);
+}
+
+/* see bytes_per_line in libGL */
+static INLINE int
+bytes_per_line(unsigned pitch_bits, unsigned mul)
+{
+ unsigned mask = mul - 1;
+
+ return ((pitch_bits + mask) & ~mask) / 8;
+}
+
+static GLboolean
+swrast_alloc_front_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
+ GLenum internalFormat, GLuint width, GLuint height)
+{
+ struct swrast_renderbuffer *xrb = swrast_renderbuffer(rb);
+
+ TRACE;
+
+ rb->Data = NULL;
+ rb->Width = width;
+ rb->Height = height;
+
+ xrb->pitch = bytes_per_line(width * xrb->bpp, 32);
+
+ return GL_TRUE;
+}
+
+static GLboolean
+swrast_alloc_back_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
+ GLenum internalFormat, GLuint width, GLuint height)
+{
+ struct swrast_renderbuffer *xrb = swrast_renderbuffer(rb);
+
+ TRACE;
+
+ free(rb->Data);
+
+ swrast_alloc_front_storage(ctx, rb, internalFormat, width, height);
+
+ rb->Data = malloc(height * xrb->pitch);
+
+ return GL_TRUE;
+}
+
+static struct swrast_renderbuffer *
+swrast_new_renderbuffer(const struct gl_config *visual, GLboolean front)
+{
+ struct swrast_renderbuffer *xrb = calloc(1, sizeof *xrb);
+ GLuint pixel_format;
+
+ TRACE;
+
+ if (!xrb)
+ return NULL;
+
+ _mesa_init_renderbuffer(&xrb->Base, 0);
+
+ pixel_format = choose_pixel_format(visual);
+
+ xrb->Base.Delete = swrast_delete_renderbuffer;
+ if (front) {
+ xrb->Base.AllocStorage = swrast_alloc_front_storage;
+ swrast_set_span_funcs_front(xrb, pixel_format);
+ }
+ else {
+ xrb->Base.AllocStorage = swrast_alloc_back_storage;
+ swrast_set_span_funcs_back(xrb, pixel_format);
+ }
+
+ switch (pixel_format) {
+ case PF_A8R8G8B8:
+ xrb->Base.Format = MESA_FORMAT_ARGB8888;
+ xrb->Base.InternalFormat = GL_RGBA;
+ xrb->Base._BaseFormat = GL_RGBA;
+ xrb->Base.DataType = GL_UNSIGNED_BYTE;
+ xrb->bpp = 32;
+ break;
+ case PF_X8R8G8B8:
+ xrb->Base.Format = MESA_FORMAT_ARGB8888; /* XXX */
+ xrb->Base.InternalFormat = GL_RGB;
+ xrb->Base._BaseFormat = GL_RGB;
+ xrb->Base.DataType = GL_UNSIGNED_BYTE;
+ xrb->bpp = 32;
+ break;
+ case PF_R5G6B5:
+ xrb->Base.Format = MESA_FORMAT_RGB565;
+ xrb->Base.InternalFormat = GL_RGB;
+ xrb->Base._BaseFormat = GL_RGB;
+ xrb->Base.DataType = GL_UNSIGNED_BYTE;
+ xrb->bpp = 16;
+ break;
+ case PF_R3G3B2:
+ xrb->Base.Format = MESA_FORMAT_RGB332;
+ xrb->Base.InternalFormat = GL_RGB;
+ xrb->Base._BaseFormat = GL_RGB;
+ xrb->Base.DataType = GL_UNSIGNED_BYTE;
+ xrb->bpp = 8;
+ break;
+ default:
+ return NULL;
+ }
+
+ return xrb;
+}
+
+static GLboolean
+dri_create_buffer(__DRIscreen * sPriv,
+ __DRIdrawable * dPriv,
+ const struct gl_config * visual, GLboolean isPixmap)
+{
+ struct dri_drawable *drawable = NULL;
+ struct gl_framebuffer *fb;
+ struct swrast_renderbuffer *frontrb, *backrb;
+
+ TRACE;
+
+ drawable = CALLOC_STRUCT(dri_drawable);
+ if (drawable == NULL)
+ goto drawable_fail;
+
+ dPriv->driverPrivate = drawable;
+ drawable->dPriv = dPriv;
+
+ drawable->row = malloc(MAX_WIDTH * 4);
+ if (drawable->row == NULL)
+ goto drawable_fail;
+
+ fb = &drawable->Base;
+
+ /* basic framebuffer setup */
+ _mesa_initialize_window_framebuffer(fb, visual);
+
+ /* add front renderbuffer */
+ frontrb = swrast_new_renderbuffer(visual, GL_TRUE);
+ _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &frontrb->Base);
+
+ /* add back renderbuffer */
+ if (visual->doubleBufferMode) {
+ backrb = swrast_new_renderbuffer(visual, GL_FALSE);
+ _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &backrb->Base);
+ }
+
+ /* add software renderbuffers */
+ _mesa_add_soft_renderbuffers(fb,
+ GL_FALSE, /* color */
+ visual->haveDepthBuffer,
+ visual->haveStencilBuffer,
+ visual->haveAccumBuffer,
+ GL_FALSE, /* alpha */
+ GL_FALSE /* aux bufs */);
+
+ return GL_TRUE;
+
+drawable_fail:
+
+ if (drawable)
+ free(drawable->row);
+
+ FREE(drawable);
+
+ return GL_FALSE;
+}
+
+static void
+dri_destroy_buffer(__DRIdrawable * dPriv)
+{
+ TRACE;
+
+ if (dPriv) {
+ struct dri_drawable *drawable = dri_drawable(dPriv);
+ struct gl_framebuffer *fb;
+
+ free(drawable->row);
+
+ fb = &drawable->Base;
+
+ fb->DeletePending = GL_TRUE;
+ _mesa_reference_framebuffer(&fb, NULL);
+ }
+}
+
+static void
+dri_swap_buffers(__DRIdrawable * dPriv)
+{
+ __DRIscreen *sPriv = dPriv->driScreenPriv;
+
+ GET_CURRENT_CONTEXT(ctx);
+
+ struct dri_drawable *drawable = dri_drawable(dPriv);
+ struct gl_framebuffer *fb;
+ struct swrast_renderbuffer *frontrb, *backrb;
+
+ TRACE;
+
+ fb = &drawable->Base;
+
+ frontrb =
+ swrast_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
+ backrb =
+ swrast_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer);
+
+ /* check for signle-buffered */
+ if (backrb == NULL)
+ return;
+
+ /* check if swapping currently bound buffer */
+ if (ctx && ctx->DrawBuffer == fb) {
+ /* flush pending rendering */
+ _mesa_notifySwapBuffers(ctx);
+ }
+
+ sPriv->swrast_loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,
+ 0, 0,
+ frontrb->Base.Width,
+ frontrb->Base.Height,
+ backrb->Base.Data,
+ dPriv->loaderPrivate);
+}
+
+
+/**
+ * General device driver functions.
+ */
+
+static void
+get_window_size( struct gl_framebuffer *fb, GLsizei *w, GLsizei *h )
+{
+ __DRIdrawable *dPriv = swrast_drawable(fb)->dPriv;
+ __DRIscreen *sPriv = dPriv->driScreenPriv;
+ int x, y;
+
+ sPriv->swrast_loader->getDrawableInfo(dPriv,
+ &x, &y, w, h,
+ dPriv->loaderPrivate);
+}
+
+static void
+swrast_check_and_update_window_size( struct gl_context *ctx, struct gl_framebuffer *fb )
+{
+ GLsizei width, height;
+
+ get_window_size(fb, &width, &height);
+ if (fb->Width != width || fb->Height != height) {
+ _mesa_resize_framebuffer(ctx, fb, width, height);
+ }
+}
+
+static const GLubyte *
+get_string(struct gl_context *ctx, GLenum pname)
+{
+ (void) ctx;
+ switch (pname) {
+ case GL_VENDOR:
+ return (const GLubyte *) "Mesa Project";
+ case GL_RENDERER:
+ return (const GLubyte *) "Software Rasterizer";
+ default:
+ return NULL;
+ }
+}
+
+static void
+update_state( struct gl_context *ctx, GLuint new_state )
+{
+ /* not much to do here - pass it on */
+ _swrast_InvalidateState( ctx, new_state );
+ _swsetup_InvalidateState( ctx, new_state );
+ _vbo_InvalidateState( ctx, new_state );
+ _tnl_InvalidateState( ctx, new_state );
+}
+
+static void
+viewport(struct gl_context *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
+{
+ struct gl_framebuffer *draw = ctx->WinSysDrawBuffer;
+ struct gl_framebuffer *read = ctx->WinSysReadBuffer;
+
+ swrast_check_and_update_window_size(ctx, draw);
+ swrast_check_and_update_window_size(ctx, read);
+}
+
+static gl_format swrastChooseTextureFormat(struct gl_context * ctx,
+ GLint internalFormat,
+ GLenum format,
+ GLenum type)
+{
+ if (internalFormat == GL_RGB)
+ return MESA_FORMAT_XRGB8888;
+ return _mesa_choose_tex_format(ctx, internalFormat, format, type);
+}
+
+static void
+swrast_init_driver_functions(struct dd_function_table *driver)
+{
+ driver->GetString = get_string;
+ driver->UpdateState = update_state;
+ driver->GetBufferSize = NULL;
+ driver->Viewport = viewport;
+ driver->ChooseTextureFormat = swrastChooseTextureFormat;
+}
+
+static const char *es2_extensions[] = {
+ /* Used by mesa internally (cf all_mesa_extensions in ../common/utils.c) */
+ "GL_ARB_draw_buffers",
+ "GL_ARB_multisample",
+ "GL_ARB_texture_compression",
+ "GL_ARB_transpose_matrix",
+ "GL_ARB_vertex_buffer_object",
+ "GL_ARB_window_pos",
+ "GL_EXT_blend_func_separate",
+ "GL_EXT_compiled_vertex_array",
+ "GL_EXT_framebuffer_blit",
+ "GL_EXT_multi_draw_arrays",
+ "GL_EXT_polygon_offset",
+ "GL_EXT_texture_object",
+ "GL_EXT_vertex_array",
+ "GL_IBM_multimode_draw_arrays",
+ "GL_MESA_window_pos",
+ "GL_NV_vertex_program",
+
+ /* Required by GLES2 */
+ "GL_ARB_fragment_program",
+ "GL_ARB_fragment_shader",
+ "GL_ARB_multitexture",
+ "GL_ARB_shader_objects",
+ "GL_ARB_texture_cube_map",
+ "GL_ARB_texture_mirrored_repeat",
+ "GL_ARB_texture_non_power_of_two",
+ "GL_ARB_vertex_shader",
+ "GL_EXT_blend_color",
+ "GL_EXT_blend_equation_separate",
+ "GL_EXT_blend_minmax",
+ "GL_EXT_blend_subtract",
+ "GL_EXT_stencil_wrap",
+
+ /* Optional GLES2 */
+ "GL_ARB_framebuffer_object",
+ "GL_EXT_texture_filter_anisotropic",
+ "GL_ARB_depth_texture",
+ "GL_EXT_packed_depth_stencil",
+ "GL_EXT_framebuffer_object",
+ NULL,
+};
+
+static void
+InitExtensionsES2(struct gl_context *ctx)
+{
+ int i;
+
+ /* Can't use driInitExtensions() since it uses extensions from
+ * main/remap_helper.h when called the first time. */
+
+ for (i = 0; es2_extensions[i]; i++)
+ _mesa_enable_extension(ctx, es2_extensions[i]);
+}
+
+/**
+ * Context-related functions.
+ */
+
+static GLboolean
+dri_create_context(gl_api api,
+ const struct gl_config * visual,
+ __DRIcontext * cPriv, void *sharedContextPrivate)
+{
+ struct dri_context *ctx = NULL;
+ struct dri_context *share = (struct dri_context *)sharedContextPrivate;
+ struct gl_context *mesaCtx = NULL;
+ struct gl_context *sharedCtx = NULL;
+ struct dd_function_table functions;
+
+ TRACE;
+
+ ctx = CALLOC_STRUCT(dri_context);
+ if (ctx == NULL)
+ goto context_fail;
+
+ cPriv->driverPrivate = ctx;
+ ctx->cPriv = cPriv;
+
+ /* build table of device driver functions */
+ _mesa_init_driver_functions(&functions);
+ swrast_init_driver_functions(&functions);
+
+ if (share) {
+ sharedCtx = &share->Base;
+ }
+
+ mesaCtx = &ctx->Base;
+
+ /* basic context setup */
+ if (!_mesa_initialize_context(mesaCtx, api, visual, sharedCtx, &functions, (void *) cPriv)) {
+ goto context_fail;
+ }
+
+ /* do bounds checking to prevent segfaults and server crashes! */
+ mesaCtx->Const.CheckArrayBounds = GL_TRUE;
+
+ /* create module contexts */
+ _swrast_CreateContext( mesaCtx );
+ _vbo_CreateContext( mesaCtx );
+ _tnl_CreateContext( mesaCtx );
+ _swsetup_CreateContext( mesaCtx );
+ _swsetup_Wakeup( mesaCtx );
+
+ /* use default TCL pipeline */
+ {
+ TNLcontext *tnl = TNL_CONTEXT(mesaCtx);
+ tnl->Driver.RunPipeline = _tnl_run_pipeline;
+ }
+
+ _mesa_meta_init(mesaCtx);
+ _mesa_enable_sw_extensions(mesaCtx);
+
+ switch (api) {
+ case API_OPENGL:
+ _mesa_enable_1_3_extensions(mesaCtx);
+ _mesa_enable_1_4_extensions(mesaCtx);
+ _mesa_enable_1_5_extensions(mesaCtx);
+ _mesa_enable_2_0_extensions(mesaCtx);
+ _mesa_enable_2_1_extensions(mesaCtx);
+
+ driInitExtensions( mesaCtx, NULL, GL_FALSE );
+ break;
+ case API_OPENGLES:
+ _mesa_enable_1_3_extensions(mesaCtx);
+ _mesa_enable_1_4_extensions(mesaCtx);
+ _mesa_enable_1_5_extensions(mesaCtx);
+
+ break;
+ case API_OPENGLES2:
+ InitExtensionsES2( mesaCtx);
+ break;
+ }
+
+ return GL_TRUE;
+
+context_fail:
+
+ FREE(ctx);
+
+ return GL_FALSE;
+}
+
+static void
+dri_destroy_context(__DRIcontext * cPriv)
+{
+ TRACE;
+
+ if (cPriv) {
+ struct dri_context *ctx = dri_context(cPriv);
+ struct gl_context *mesaCtx;
+
+ mesaCtx = &ctx->Base;
+
+ _mesa_meta_free(mesaCtx);
+ _swsetup_DestroyContext( mesaCtx );
+ _swrast_DestroyContext( mesaCtx );
+ _tnl_DestroyContext( mesaCtx );
+ _vbo_DestroyContext( mesaCtx );
+ _mesa_destroy_context( mesaCtx );
+ }
+}
+
+static GLboolean
+dri_make_current(__DRIcontext * cPriv,
+ __DRIdrawable * driDrawPriv,
+ __DRIdrawable * driReadPriv)
+{
+ struct gl_context *mesaCtx;
+ struct gl_framebuffer *mesaDraw;
+ struct gl_framebuffer *mesaRead;
+ TRACE;
+
+ if (cPriv) {
+ struct dri_context *ctx = dri_context(cPriv);
+ struct dri_drawable *draw;
+ struct dri_drawable *read;
+
+ if (!driDrawPriv || !driReadPriv)
+ return GL_FALSE;
+
+ draw = dri_drawable(driDrawPriv);
+ read = dri_drawable(driReadPriv);
+ mesaCtx = &ctx->Base;
+ mesaDraw = &draw->Base;
+ mesaRead = &read->Base;
+
+ /* check for same context and buffer */
+ if (mesaCtx == _mesa_get_current_context()
+ && mesaCtx->DrawBuffer == mesaDraw
+ && mesaCtx->ReadBuffer == mesaRead) {
+ return GL_TRUE;
+ }
+
+ _glapi_check_multithread();
+
+ swrast_check_and_update_window_size(mesaCtx, mesaDraw);
+ if (mesaRead != mesaDraw)
+ swrast_check_and_update_window_size(mesaCtx, mesaRead);
+
+ _mesa_make_current( mesaCtx,
+ mesaDraw,
+ mesaRead );
+ }
+ else {
+ /* unbind */
+ _mesa_make_current( NULL, NULL, NULL );
+ }
+
+ return GL_TRUE;
+}
+
+static GLboolean
+dri_unbind_context(__DRIcontext * cPriv)
+{
+ TRACE;
+ (void) cPriv;
+
+ /* Unset current context and dispath table */
+ _mesa_make_current(NULL, NULL, NULL);
+
+ return GL_TRUE;
+}
+
+
+const struct __DriverAPIRec driDriverAPI = {
+ /*.InitScreen = */dri_init_screen,
+ /*.DestroyScreen = */dri_destroy_screen,
+ /*.CreateContext = */dri_create_context,
+ /*.DestroyContext = */dri_destroy_context,
+ /*.CreateBuffer = */dri_create_buffer,
+ /*.DestroyBuffer = */dri_destroy_buffer,
+ /*.SwapBuffers = */dri_swap_buffers,
+ /*.MakeCurrent = */dri_make_current,
+ /*.UnbindContext = */dri_unbind_context,
+};
+
+/* This is the table of extensions that the loader will dlsym() for. */
+PUBLIC const __DRIextension *__driDriverExtensions[] = {
+ &driCoreExtension.base,
+ &driSWRastExtension.base,
+ NULL
+};
diff --git a/mesalib/src/mesa/drivers/dri/swrast/swrast_priv.h b/mesalib/src/mesa/drivers/dri/swrast/swrast_priv.h
index 4c3c9830f..e61965147 100644
--- a/mesalib/src/mesa/drivers/dri/swrast/swrast_priv.h
+++ b/mesalib/src/mesa/drivers/dri/swrast/swrast_priv.h
@@ -32,6 +32,13 @@
#include "main/mtypes.h"
#include "drisw_util.h"
+#ifdef _MSC_VER
+#ifdef PUBLIC
+#undef PUBLIC
+#endif
+#define PUBLIC __declspec(dllexport)
+#endif
+
/**
* Debugging
diff --git a/mesalib/src/mesa/drivers/windows/gdi/wmesa.c b/mesalib/src/mesa/drivers/windows/gdi/wmesa.c
index 4a8b1b283..1a13e9f5c 100644
--- a/mesalib/src/mesa/drivers/windows/gdi/wmesa.c
+++ b/mesalib/src/mesa/drivers/windows/gdi/wmesa.c
@@ -1,1662 +1,1662 @@
-/*
- * Windows (Win32/Win64) device driver for Mesa
- *
- */
-
-#include "wmesadef.h"
-#include "colors.h"
-#include <GL/wmesa.h>
-#include <winuser.h>
-#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; i<width; i++)
- *lpw++ = wColor;
- break;
- case 3:
- lpb = clearRow;
- r = GetRValue(pwc->clearColorRef);
- g = GetGValue(pwc->clearColorRef);
- b = GetBValue(pwc->clearColorRef);
- for (i=0; i<width; i++) {
- *lpb++ = b;
- *lpb++ = g;
- *lpb++ = r;
- }
- break;
- case 4:
- lpdw = (LPDWORD)clearRow;
- dwColor = BGR32(GetRValue(pwc->clearColorRef),
- GetGValue(pwc->clearColorRef),
- GetBValue(pwc->clearColorRef));
- for (i=0; i<width; i++)
- *lpdw++ = dwColor;
- break;
- default:
- break;
- } /* switch */
-
- /* copy cleared row to other rows in buffer */
- lpb = clearRow - pwfb->ScanWidth;
- rowSize = width * bytesPerPixel;
- for (i=1; i<height; i++) {
- memcpy(lpb, clearRow, rowSize);
- lpb -= pwfb->ScanWidth;
- }
- } /* 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; i<n; i++)
- if (mask[i])
- SetPixel(pwc->hDC, x+i, y,
- RGB(rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]));
- }
- else {
- for (i=0; i<n; i++)
- SetPixel(pwc->hDC, 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; i<n; i++) {
- if (mask[i]) {
- c.r=rgba[i][RCOMP];
- c.g=rgba[i][GCOMP];
- c.b=rgba[i][BCOMP];
- c.a=rgba[i][ACOMP];
- bgra[i]=c;
- }
- else
- bgra[i].i=0;
- }
- }
- else {
- for (i=0; i<n; i++) {
- c.r=rgba[i][RCOMP];
- c.g=rgba[i][GCOMP];
- c.b=rgba[i][BCOMP];
- c.a=rgba[i][ACOMP];
- bgra[i]=c;
- }
- }
- bmp=CreateBitmap(n, 1, 1, 32, bgra);
- mdc=CreateCompatibleDC(pwfb->hDC);
- 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; i<n; i++)
- if (mask[i])
- SetPixel(pwc->hDC, x+i, y, RGB(rgb[i][RCOMP], rgb[i][GCOMP],
- rgb[i][BCOMP]));
- }
- else {
- for (i=0; i<n; i++)
- SetPixel(pwc->hDC, 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; i<n; i++)
- if (mask[i])
- SetPixel(pwc->hDC, x+i, y, colorref);
- }
- else
- for (i=0; i<n; i++)
- SetPixel(pwc->hDC, 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; i<n; i++)
- if (mask[i])
- SetPixel(pwc->hDC, 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; i<n; i++)
- if (mask[i])
- SetPixel(pwc->hDC, 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; i<n; i++) {
- Color = GetPixel(pwc->hDC, 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; i<n; i++) {
- GLint y2 = FLIP(y[i]);
- Color = GetPixel(pwc->hDC, 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; i<n; i++)
- if (mask[i])
- lpdw[i] = BGR32(rgba[i][RCOMP], rgba[i][GCOMP],
- rgba[i][BCOMP]);
- }
- else {
- for (i=0; i<n; i++)
- *lpdw++ = BGR32(rgba[i][RCOMP], rgba[i][GCOMP],
- rgba[i][BCOMP]);
- }
-}
-
-
-/* Write a horizontal span of RGB color pixels with a boolean mask. */
-static void write_rgb_span_32(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);
- 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; i<n; i++)
- if (mask[i])
- lpdw[i] = BGR32(rgb[i][RCOMP], rgb[i][GCOMP],
- rgb[i][BCOMP]);
- }
- else {
- for (i=0; i<n; i++)
- *lpdw++ = BGR32(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_32(const struct gl_context *ctx,
- struct gl_renderbuffer *rb,
- GLuint n, GLint x, GLint y,
- const GLchan color[4],
- const GLubyte mask[])
-{
- LPDWORD lpdw;
- DWORD pixel;
- GLuint i;
- WMesaContext pwc = wmesa_context(ctx);
- WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
- lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
- y=FLIP(y);
- pixel = BGR32(color[RCOMP], color[GCOMP], color[BCOMP]);
- if (mask) {
- for (i=0; i<n; i++)
- if (mask[i])
- lpdw[i] = pixel;
- }
- else
- for (i=0; i<n; i++)
- *lpdw++ = pixel;
-
-}
-
-/* Write an array of RGBA pixels with a boolean mask. */
-static void write_rgba_pixels_32(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);
- WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
- for (i=0; i<n; i++)
- if (mask[i])
- WMSETPIXEL32(pwfb, FLIP(y[i]), x[i],
- 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_32(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);
- WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
- for (i=0; i<n; i++)
- if (mask[i])
- WMSETPIXEL32(pwfb, FLIP(y[i]),x[i],color[RCOMP],
- color[GCOMP], color[BCOMP]);
-}
-
-/* Read a horizontal span of color pixels. */
-static void read_rgba_span_32(const struct gl_context *ctx,
- struct gl_renderbuffer *rb,
- GLuint n, GLint x, GLint y,
- GLubyte rgba[][4] )
-{
- GLuint i;
- DWORD pixel;
- LPDWORD lpdw;
- WMesaContext pwc = wmesa_context(ctx);
- WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
-
- y = FLIP(y);
- lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
- for (i=0; i<n; i++) {
- pixel = lpdw[i];
- rgba[i][RCOMP] = (GLubyte)((pixel & 0x00ff0000) >> 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; i<n; i++) {
- GLint y2 = FLIP(y[i]);
- lpdw = ((LPDWORD)(pwfb->pbPixels + 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; i<n; i++)
- if (mask[i]) {
- lpb[3*i] = rgba[i][BCOMP];
- lpb[3*i+1] = rgba[i][GCOMP];
- lpb[3*i+2] = rgba[i][RCOMP];
- }
- }
- else {
- for (i=0; i<n; i++) {
- *lpb++ = rgba[i][BCOMP];
- *lpb++ = rgba[i][GCOMP];
- *lpb++ = rgba[i][RCOMP];
- }
- }
-}
-
-
-/* Write a horizontal span of RGB color pixels with a boolean mask. */
-static void write_rgb_span_24(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);
- 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; i<n; i++)
- if (mask[i]) {
- lpb[3*i] = rgb[i][BCOMP];
- lpb[3*i+1] = rgb[i][GCOMP];
- lpb[3*i+2] = rgb[i][RCOMP];
- }
- }
- else {
- for (i=0; i<n; i++) {
- *lpb++ = rgb[i][BCOMP];
- *lpb++ = rgb[i][GCOMP];
- *lpb++ = rgb[i][RCOMP];
- }
- }
-}
-
-/*
- * Write a horizontal span of pixels with a boolean mask. The current color
- * is used for all pixels.
- */
-static void write_mono_rgba_span_24(const struct gl_context *ctx,
- struct gl_renderbuffer *rb,
- GLuint n, GLint x, GLint y,
- const GLchan color[4],
- const GLubyte mask[])
-{
- LPBYTE lpb;
- GLuint i;
- WMesaContext pwc = wmesa_context(ctx);
- WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
- lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x);
- y=FLIP(y);
- if (mask) {
- for (i=0; i<n; i++)
- if (mask[i]) {
- lpb[3*i] = color[BCOMP];
- lpb[3*i+1] = color[GCOMP];
- lpb[3*i+2] = color[RCOMP];
- }
- }
- else
- for (i=0; i<n; i++) {
- *lpb++ = color[BCOMP];
- *lpb++ = color[GCOMP];
- *lpb++ = color[RCOMP];
- }
-}
-
-/* Write an array of RGBA pixels with a boolean mask. */
-static void write_rgba_pixels_24(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);
- WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
- for (i=0; i<n; i++)
- if (mask[i])
- WMSETPIXEL24(pwfb, FLIP(y[i]), x[i],
- 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_24(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);
- WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
- for (i=0; i<n; i++)
- if (mask[i])
- WMSETPIXEL24(pwfb, FLIP(y[i]),x[i],color[RCOMP],
- color[GCOMP], color[BCOMP]);
-}
-
-/* Read a horizontal span of color pixels. */
-static void read_rgba_span_24(const struct gl_context *ctx,
- struct gl_renderbuffer *rb,
- GLuint n, GLint x, GLint y,
- GLubyte rgba[][4] )
-{
- GLuint i;
- LPBYTE lpb;
- WMesaContext pwc = wmesa_context(ctx);
- WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
-
- y = FLIP(y);
- lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x);
- for (i=0; i<n; 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;
- }
-}
-
-
-/* Read an array of color pixels. */
-static void read_rgba_pixels_24(const struct gl_context *ctx,
- struct gl_renderbuffer *rb,
- GLuint n, const GLint x[], const GLint y[],
- GLubyte rgba[][4])
-{
- GLuint i;
- LPBYTE lpb;
- WMesaContext pwc = wmesa_context(ctx);
- WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
-
- for (i=0; i<n; i++) {
- GLint y2 = FLIP(y[i]);
- lpb = ((LPBYTE)(pwfb->pbPixels + 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; i<n; i++)
- if (mask[i])
- lpw[i] = BGR16(rgba[i][RCOMP], rgba[i][GCOMP],
- rgba[i][BCOMP]);
- }
- else {
- for (i=0; i<n; i++)
- *lpw++ = BGR16(rgba[i][RCOMP], rgba[i][GCOMP],
- rgba[i][BCOMP]);
- }
-}
-
-
-/* Write a horizontal span of RGB color pixels with a boolean mask. */
-static void write_rgb_span_16(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);
- 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; i<n; i++)
- if (mask[i])
- lpw[i] = BGR16(rgb[i][RCOMP], rgb[i][GCOMP],
- rgb[i][BCOMP]);
- }
- else {
- for (i=0; i<n; i++)
- *lpw++ = BGR16(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_16(const struct gl_context *ctx,
- struct gl_renderbuffer *rb,
- GLuint n, GLint x, GLint y,
- const GLchan color[4],
- const GLubyte mask[])
-{
- LPWORD lpw;
- WORD pixel;
- GLuint i;
- WMesaContext pwc = wmesa_context(ctx);
- WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
- (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; i<n; i++)
- if (mask[i])
- lpw[i] = pixel;
- }
- else
- for (i=0; i<n; i++)
- *lpw++ = pixel;
-
-}
-
-/* Write an array of RGBA pixels with a boolean mask. */
-static void write_rgba_pixels_16(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);
- WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
- (void) ctx;
- for (i=0; i<n; i++)
- if (mask[i])
- WMSETPIXEL16(pwfb, FLIP(y[i]), x[i],
- 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_16(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);
- WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
- (void) ctx;
- for (i=0; i<n; i++)
- if (mask[i])
- WMSETPIXEL16(pwfb, FLIP(y[i]),x[i],color[RCOMP],
- color[GCOMP], color[BCOMP]);
-}
-
-/* Read a horizontal span of color pixels. */
-static void read_rgba_span_16(const struct gl_context *ctx,
- struct gl_renderbuffer *rb,
- GLuint n, GLint x, GLint y,
- GLubyte rgba[][4] )
-{
- GLuint i, pixel;
- LPWORD lpw;
- WMesaContext pwc = wmesa_context(ctx);
- WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
-
- y = FLIP(y);
- lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
- for (i=0; i<n; i++) {
- pixel = lpw[i];
- /* 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;
- }
-}
-
-
-/* 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; i<n; i++) {
- GLint y2 = FLIP(y[i]);
- lpw = ((LPWORD)(pwfb->pbPixels + 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);
-}
-
+/*
+ * Windows (Win32/Win64) device driver for Mesa
+ *
+ */
+
+#include "wmesadef.h"
+#include "colors.h"
+#include <GL/wmesa.h>
+#include <winuser.h>
+#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; i<width; i++)
+ *lpw++ = wColor;
+ break;
+ case 3:
+ lpb = clearRow;
+ r = GetRValue(pwc->clearColorRef);
+ g = GetGValue(pwc->clearColorRef);
+ b = GetBValue(pwc->clearColorRef);
+ for (i=0; i<width; i++) {
+ *lpb++ = b;
+ *lpb++ = g;
+ *lpb++ = r;
+ }
+ break;
+ case 4:
+ lpdw = (LPDWORD)clearRow;
+ dwColor = BGR32(GetRValue(pwc->clearColorRef),
+ GetGValue(pwc->clearColorRef),
+ GetBValue(pwc->clearColorRef));
+ for (i=0; i<width; i++)
+ *lpdw++ = dwColor;
+ break;
+ default:
+ break;
+ } /* switch */
+
+ /* copy cleared row to other rows in buffer */
+ lpb = clearRow - pwfb->ScanWidth;
+ rowSize = width * bytesPerPixel;
+ for (i=1; i<height; i++) {
+ memcpy(lpb, clearRow, rowSize);
+ lpb -= pwfb->ScanWidth;
+ }
+ } /* 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; i<n; i++)
+ if (mask[i])
+ SetPixel(pwc->hDC, x+i, y,
+ RGB(rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]));
+ }
+ else {
+ for (i=0; i<n; i++)
+ SetPixel(pwc->hDC, 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; i<n; i++) {
+ if (mask[i]) {
+ c.r=rgba[i][RCOMP];
+ c.g=rgba[i][GCOMP];
+ c.b=rgba[i][BCOMP];
+ c.a=rgba[i][ACOMP];
+ bgra[i]=c;
+ }
+ else
+ bgra[i].i=0;
+ }
+ }
+ else {
+ for (i=0; i<n; i++) {
+ c.r=rgba[i][RCOMP];
+ c.g=rgba[i][GCOMP];
+ c.b=rgba[i][BCOMP];
+ c.a=rgba[i][ACOMP];
+ bgra[i]=c;
+ }
+ }
+ bmp=CreateBitmap(n, 1, 1, 32, bgra);
+ mdc=CreateCompatibleDC(pwfb->hDC);
+ 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; i<n; i++)
+ if (mask[i])
+ SetPixel(pwc->hDC, x+i, y, RGB(rgb[i][RCOMP], rgb[i][GCOMP],
+ rgb[i][BCOMP]));
+ }
+ else {
+ for (i=0; i<n; i++)
+ SetPixel(pwc->hDC, 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; i<n; i++)
+ if (mask[i])
+ SetPixel(pwc->hDC, x+i, y, colorref);
+ }
+ else
+ for (i=0; i<n; i++)
+ SetPixel(pwc->hDC, 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; i<n; i++)
+ if (mask[i])
+ SetPixel(pwc->hDC, 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; i<n; i++)
+ if (mask[i])
+ SetPixel(pwc->hDC, 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; i<n; i++) {
+ Color = GetPixel(pwc->hDC, 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; i<n; i++) {
+ GLint y2 = FLIP(y[i]);
+ Color = GetPixel(pwc->hDC, 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; i<n; i++)
+ if (mask[i])
+ lpdw[i] = BGR32(rgba[i][RCOMP], rgba[i][GCOMP],
+ rgba[i][BCOMP]);
+ }
+ else {
+ for (i=0; i<n; i++)
+ *lpdw++ = BGR32(rgba[i][RCOMP], rgba[i][GCOMP],
+ rgba[i][BCOMP]);
+ }
+}
+
+
+/* Write a horizontal span of RGB color pixels with a boolean mask. */
+static void write_rgb_span_32(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);
+ 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; i<n; i++)
+ if (mask[i])
+ lpdw[i] = BGR32(rgb[i][RCOMP], rgb[i][GCOMP],
+ rgb[i][BCOMP]);
+ }
+ else {
+ for (i=0; i<n; i++)
+ *lpdw++ = BGR32(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_32(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const GLchan color[4],
+ const GLubyte mask[])
+{
+ LPDWORD lpdw;
+ DWORD pixel;
+ GLuint i;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
+ y=FLIP(y);
+ pixel = BGR32(color[RCOMP], color[GCOMP], color[BCOMP]);
+ if (mask) {
+ for (i=0; i<n; i++)
+ if (mask[i])
+ lpdw[i] = pixel;
+ }
+ else
+ for (i=0; i<n; i++)
+ *lpdw++ = pixel;
+
+}
+
+/* Write an array of RGBA pixels with a boolean mask. */
+static void write_rgba_pixels_32(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);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ for (i=0; i<n; i++)
+ if (mask[i])
+ WMSETPIXEL32(pwfb, FLIP(y[i]), x[i],
+ 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_32(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);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ for (i=0; i<n; i++)
+ if (mask[i])
+ WMSETPIXEL32(pwfb, FLIP(y[i]),x[i],color[RCOMP],
+ color[GCOMP], color[BCOMP]);
+}
+
+/* Read a horizontal span of color pixels. */
+static void read_rgba_span_32(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ GLubyte rgba[][4] )
+{
+ GLuint i;
+ DWORD pixel;
+ LPDWORD lpdw;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+
+ y = FLIP(y);
+ lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
+ for (i=0; i<n; i++) {
+ pixel = lpdw[i];
+ rgba[i][RCOMP] = (GLubyte)((pixel & 0x00ff0000) >> 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; i<n; i++) {
+ GLint y2 = FLIP(y[i]);
+ lpdw = ((LPDWORD)(pwfb->pbPixels + 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; i<n; i++)
+ if (mask[i]) {
+ lpb[3*i] = rgba[i][BCOMP];
+ lpb[3*i+1] = rgba[i][GCOMP];
+ lpb[3*i+2] = rgba[i][RCOMP];
+ }
+ }
+ else {
+ for (i=0; i<n; i++) {
+ *lpb++ = rgba[i][BCOMP];
+ *lpb++ = rgba[i][GCOMP];
+ *lpb++ = rgba[i][RCOMP];
+ }
+ }
+}
+
+
+/* Write a horizontal span of RGB color pixels with a boolean mask. */
+static void write_rgb_span_24(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);
+ 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; i<n; i++)
+ if (mask[i]) {
+ lpb[3*i] = rgb[i][BCOMP];
+ lpb[3*i+1] = rgb[i][GCOMP];
+ lpb[3*i+2] = rgb[i][RCOMP];
+ }
+ }
+ else {
+ for (i=0; i<n; i++) {
+ *lpb++ = rgb[i][BCOMP];
+ *lpb++ = rgb[i][GCOMP];
+ *lpb++ = rgb[i][RCOMP];
+ }
+ }
+}
+
+/*
+ * Write a horizontal span of pixels with a boolean mask. The current color
+ * is used for all pixels.
+ */
+static void write_mono_rgba_span_24(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const GLchan color[4],
+ const GLubyte mask[])
+{
+ LPBYTE lpb;
+ GLuint i;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x);
+ y=FLIP(y);
+ if (mask) {
+ for (i=0; i<n; i++)
+ if (mask[i]) {
+ lpb[3*i] = color[BCOMP];
+ lpb[3*i+1] = color[GCOMP];
+ lpb[3*i+2] = color[RCOMP];
+ }
+ }
+ else
+ for (i=0; i<n; i++) {
+ *lpb++ = color[BCOMP];
+ *lpb++ = color[GCOMP];
+ *lpb++ = color[RCOMP];
+ }
+}
+
+/* Write an array of RGBA pixels with a boolean mask. */
+static void write_rgba_pixels_24(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);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ for (i=0; i<n; i++)
+ if (mask[i])
+ WMSETPIXEL24(pwfb, FLIP(y[i]), x[i],
+ 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_24(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);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ for (i=0; i<n; i++)
+ if (mask[i])
+ WMSETPIXEL24(pwfb, FLIP(y[i]),x[i],color[RCOMP],
+ color[GCOMP], color[BCOMP]);
+}
+
+/* Read a horizontal span of color pixels. */
+static void read_rgba_span_24(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ GLubyte rgba[][4] )
+{
+ GLuint i;
+ LPBYTE lpb;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+
+ y = FLIP(y);
+ lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x);
+ for (i=0; i<n; 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;
+ }
+}
+
+
+/* Read an array of color pixels. */
+static void read_rgba_pixels_24(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, const GLint x[], const GLint y[],
+ GLubyte rgba[][4])
+{
+ GLuint i;
+ LPBYTE lpb;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+
+ for (i=0; i<n; i++) {
+ GLint y2 = FLIP(y[i]);
+ lpb = ((LPBYTE)(pwfb->pbPixels + 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; i<n; i++)
+ if (mask[i])
+ lpw[i] = BGR16(rgba[i][RCOMP], rgba[i][GCOMP],
+ rgba[i][BCOMP]);
+ }
+ else {
+ for (i=0; i<n; i++)
+ *lpw++ = BGR16(rgba[i][RCOMP], rgba[i][GCOMP],
+ rgba[i][BCOMP]);
+ }
+}
+
+
+/* Write a horizontal span of RGB color pixels with a boolean mask. */
+static void write_rgb_span_16(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);
+ 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; i<n; i++)
+ if (mask[i])
+ lpw[i] = BGR16(rgb[i][RCOMP], rgb[i][GCOMP],
+ rgb[i][BCOMP]);
+ }
+ else {
+ for (i=0; i<n; i++)
+ *lpw++ = BGR16(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_16(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const GLchan color[4],
+ const GLubyte mask[])
+{
+ LPWORD lpw;
+ WORD pixel;
+ GLuint i;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ (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; i<n; i++)
+ if (mask[i])
+ lpw[i] = pixel;
+ }
+ else
+ for (i=0; i<n; i++)
+ *lpw++ = pixel;
+
+}
+
+/* Write an array of RGBA pixels with a boolean mask. */
+static void write_rgba_pixels_16(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);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ (void) ctx;
+ for (i=0; i<n; i++)
+ if (mask[i])
+ WMSETPIXEL16(pwfb, FLIP(y[i]), x[i],
+ 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_16(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);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ (void) ctx;
+ for (i=0; i<n; i++)
+ if (mask[i])
+ WMSETPIXEL16(pwfb, FLIP(y[i]),x[i],color[RCOMP],
+ color[GCOMP], color[BCOMP]);
+}
+
+/* Read a horizontal span of color pixels. */
+static void read_rgba_span_16(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ GLubyte rgba[][4] )
+{
+ GLuint i, pixel;
+ LPWORD lpw;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+
+ y = FLIP(y);
+ lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
+ for (i=0; i<n; i++) {
+ pixel = lpw[i];
+ /* 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;
+ }
+}
+
+
+/* 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; i<n; i++) {
+ GLint y2 = FLIP(y[i]);
+ lpw = ((LPWORD)(pwfb->pbPixels + 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 9aedd2e3c..bc4839cfe 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; i<DGL_MAX_CONTEXTS; i++)
- ctxlist[i].bAllocated = FALSE; // Flag context as unused
-
- // This section of code crashes the dll in circumstances where the app
- // creates and destroys contexts.
-/*
- // Register the class for our event monitor window
- wc.style = 0;
- wc.lpfnWndProc = GLD_EventWndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = GetModuleHandle(NULL);
- wc.hIcon = LoadIcon(GetModuleHandle(NULL), IDI_APPLICATION);
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
- wc.lpszMenuName = NULL;
- wc.lpszClassName = "GLDIRECT";
- RegisterClass(&wc);
-
- // Create the non-visible window to monitor all broadcast messages
- hWndEvent = CreateWindowEx(
- WS_EX_TOOLWINDOW,"GLDIRECT","GLDIRECT",WS_POPUP,
- 0,0,0,0,
- NULL,NULL,GetModuleHandle(NULL),NULL);
-*/
-
-#ifdef GLD_THREADS
- // Create a critical section object for serializing access to
- // DirectDraw and DDStereo create/destroy functions in multiple threads
- if (glb.bMultiThreaded)
- InitializeCriticalSection(&CriticalSection);
-#endif
-
- // Context state is now initialized and ready
- bContextReady = TRUE;
-}
-
-// ***********************************************************************
-
-void dglDeleteContextState()
-{
- int i;
- static BOOL bOnceIsEnough = FALSE;
-
- // Only call once, from either DGL_exitDriver(), or DLL_PROCESS_DETACH
- if (bOnceIsEnough)
- return;
- bOnceIsEnough = TRUE;
-
- for (i=0; i<DGL_MAX_CONTEXTS; i++) {
- if (ctxlist[i].bAllocated == TRUE) {
- ddlogPrintf(DDLOG_WARN, "** Context %i not deleted - cleaning up.", (i+1));
- dglDeleteContext((HGLRC)(i+1));
- }
- }
-
- // Context state is no longer ready
- bContextReady = FALSE;
-
- // If executed when DLL unloads, DDraw objects may be invalid.
- // So catch any page faults with this exception handler.
-__try {
-
- // Release final DirectDraw interfaces
- if (glb.bDirectDrawPersistant) {
-// RELEASE(glb.lpGlobalPalette);
-// RELEASE(glb.lpDepth4);
-// RELEASE(glb.lpBack4);
-// RELEASE(glb.lpPrimary4);
-// RELEASE(glb.lpDD4);
- }
-}
-__except(EXCEPTION_EXECUTE_HANDLER) {
- ddlogPrintf(DDLOG_WARN, "Exception raised in dglDeleteContextState.");
-}
-
- // Destroy our event monitor window
- if (hWndEvent) {
- DestroyWindow(hWndEvent);
- hWndEvent = hWndLastActive = NULL;
- }
-
-#ifdef GLD_THREADS
- // Destroy the critical section object
- if (glb.bMultiThreaded)
- DeleteCriticalSection(&CriticalSection);
-
- // Release thread local storage indexes for current HGLRC and pixel format
- TlsFree(dwTLSPixelFormat);
- TlsFree(dwTLSCurrentContext);
-#endif
-}
-
-// ***********************************************************************
-
-// Application Window message handler interception
-static LONG __stdcall dglWndProc(
- HWND hwnd,
- UINT msg,
- WPARAM wParam,
- LPARAM lParam)
-{
- DGL_ctx* lpCtx = NULL;
- LONG lpfnWndProc = 0L;
- int i;
- HGLRC hGLRC;
- RECT rect;
- PAINTSTRUCT ps;
- BOOL bQuit = FALSE;
- BOOL bMain = FALSE;
- LONG rc;
-
- // Get the window's message handler *before* it is unhooked in WM_DESTROY
-
- // Is this the main window?
- if (hwnd == glb.hWndActive) {
- bMain = TRUE;
- lpfnWndProc = glb.lpfnWndProc;
- }
- // Search for DGL context matching window handle
- for (i=0; i<DGL_MAX_CONTEXTS; i++) {
- if (ctxlist[i].hWnd == hwnd) {
- lpCtx = &ctxlist[i];
- lpfnWndProc = lpCtx->lpfnWndProc;
- 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; i<glb.nDisplayModeCount; i++, lpDDSD++) {
- if ((lpDDSD->dwWidth == 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; i<count; i++)
- if (dwDeviceId == lpDeviceIdList[i])
- return TRUE;
-
- return FALSE;
-}
-
-// ***********************************************************************
-
-void dglTestForBrokenCards(
- DGL_ctx *lpCtx)
-{
-#ifndef _GLD3
- DDDEVICEIDENTIFIER dddi; // DX6 device identifier
-
- // Sanity check.
- if (lpCtx == 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 context passed to TFBC\n");
- return;
- }
-
- if (lpCtx->lpDD4 == 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; i<MAX_TEXTURE_UNITS; i++) {
- lpCtx->ColorOp[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; i<DGL_MAX_CONTEXTS; i++) {
- if (ctxlist[i].bAllocated) {
- if (/*glb.bFullscreen && */ctxlist[i].bFullscreen)
- break;
- } else {
- hGLRC = (HGLRC)(i+1);
- break;
- }
- }
-
- // Bail if no GLRC was found
- if (!hGLRC)
- return NULL;
-
- // Set the context pointer
- lpCtx = dglGetContextAddress(hGLRC);
- // Make sure that context is zeroed before we do anything.
- // MFC and C++ apps call wglCreateContext() and wglDeleteContext() multiple times,
- // even though only one context is ever used by the app, so keep it clean. (DaveM)
- ZeroMemory(lpCtx, sizeof(DGL_ctx));
- lpCtx->bAllocated = 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; i<DGL_MAX_CONTEXTS; i++)
+ ctxlist[i].bAllocated = FALSE; // Flag context as unused
+
+ // This section of code crashes the dll in circumstances where the app
+ // creates and destroys contexts.
+/*
+ // Register the class for our event monitor window
+ wc.style = 0;
+ wc.lpfnWndProc = GLD_EventWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hIcon = LoadIcon(GetModuleHandle(NULL), IDI_APPLICATION);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "GLDIRECT";
+ RegisterClass(&wc);
+
+ // Create the non-visible window to monitor all broadcast messages
+ hWndEvent = CreateWindowEx(
+ WS_EX_TOOLWINDOW,"GLDIRECT","GLDIRECT",WS_POPUP,
+ 0,0,0,0,
+ NULL,NULL,GetModuleHandle(NULL),NULL);
+*/
+
+#ifdef GLD_THREADS
+ // Create a critical section object for serializing access to
+ // DirectDraw and DDStereo create/destroy functions in multiple threads
+ if (glb.bMultiThreaded)
+ InitializeCriticalSection(&CriticalSection);
+#endif
+
+ // Context state is now initialized and ready
+ bContextReady = TRUE;
+}
+
+// ***********************************************************************
+
+void dglDeleteContextState()
+{
+ int i;
+ static BOOL bOnceIsEnough = FALSE;
+
+ // Only call once, from either DGL_exitDriver(), or DLL_PROCESS_DETACH
+ if (bOnceIsEnough)
+ return;
+ bOnceIsEnough = TRUE;
+
+ for (i=0; i<DGL_MAX_CONTEXTS; i++) {
+ if (ctxlist[i].bAllocated == TRUE) {
+ ddlogPrintf(DDLOG_WARN, "** Context %i not deleted - cleaning up.", (i+1));
+ dglDeleteContext((HGLRC)(i+1));
+ }
+ }
+
+ // Context state is no longer ready
+ bContextReady = FALSE;
+
+ // If executed when DLL unloads, DDraw objects may be invalid.
+ // So catch any page faults with this exception handler.
+__try {
+
+ // Release final DirectDraw interfaces
+ if (glb.bDirectDrawPersistant) {
+// RELEASE(glb.lpGlobalPalette);
+// RELEASE(glb.lpDepth4);
+// RELEASE(glb.lpBack4);
+// RELEASE(glb.lpPrimary4);
+// RELEASE(glb.lpDD4);
+ }
+}
+__except(EXCEPTION_EXECUTE_HANDLER) {
+ ddlogPrintf(DDLOG_WARN, "Exception raised in dglDeleteContextState.");
+}
+
+ // Destroy our event monitor window
+ if (hWndEvent) {
+ DestroyWindow(hWndEvent);
+ hWndEvent = hWndLastActive = NULL;
+ }
+
+#ifdef GLD_THREADS
+ // Destroy the critical section object
+ if (glb.bMultiThreaded)
+ DeleteCriticalSection(&CriticalSection);
+
+ // Release thread local storage indexes for current HGLRC and pixel format
+ TlsFree(dwTLSPixelFormat);
+ TlsFree(dwTLSCurrentContext);
+#endif
+}
+
+// ***********************************************************************
+
+// Application Window message handler interception
+static LONG __stdcall dglWndProc(
+ HWND hwnd,
+ UINT msg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ DGL_ctx* lpCtx = NULL;
+ LONG lpfnWndProc = 0L;
+ int i;
+ HGLRC hGLRC;
+ RECT rect;
+ PAINTSTRUCT ps;
+ BOOL bQuit = FALSE;
+ BOOL bMain = FALSE;
+ LONG rc;
+
+ // Get the window's message handler *before* it is unhooked in WM_DESTROY
+
+ // Is this the main window?
+ if (hwnd == glb.hWndActive) {
+ bMain = TRUE;
+ lpfnWndProc = glb.lpfnWndProc;
+ }
+ // Search for DGL context matching window handle
+ for (i=0; i<DGL_MAX_CONTEXTS; i++) {
+ if (ctxlist[i].hWnd == hwnd) {
+ lpCtx = &ctxlist[i];
+ lpfnWndProc = lpCtx->lpfnWndProc;
+ 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; i<glb.nDisplayModeCount; i++, lpDDSD++) {
+ if ((lpDDSD->dwWidth == 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; i<count; i++)
+ if (dwDeviceId == lpDeviceIdList[i])
+ return TRUE;
+
+ return FALSE;
+}
+
+// ***********************************************************************
+
+void dglTestForBrokenCards(
+ DGL_ctx *lpCtx)
+{
+#ifndef _GLD3
+ DDDEVICEIDENTIFIER dddi; // DX6 device identifier
+
+ // Sanity check.
+ if (lpCtx == 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 context passed to TFBC\n");
+ return;
+ }
+
+ if (lpCtx->lpDD4 == 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; i<MAX_TEXTURE_UNITS; i++) {
+ lpCtx->ColorOp[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; i<DGL_MAX_CONTEXTS; i++) {
+ if (ctxlist[i].bAllocated) {
+ if (/*glb.bFullscreen && */ctxlist[i].bFullscreen)
+ break;
+ } else {
+ hGLRC = (HGLRC)(i+1);
+ break;
+ }
+ }
+
+ // Bail if no GLRC was found
+ if (!hGLRC)
+ return NULL;
+
+ // Set the context pointer
+ lpCtx = dglGetContextAddress(hGLRC);
+ // Make sure that context is zeroed before we do anything.
+ // MFC and C++ apps call wglCreateContext() and wglDeleteContext() multiple times,
+ // even though only one context is ever used by the app, so keep it clean. (DaveM)
+ ZeroMemory(lpCtx, sizeof(DGL_ctx));
+ lpCtx->bAllocated = 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/api_arrayelt.c b/mesalib/src/mesa/main/api_arrayelt.c
index 080c20606..3c59e9be3 100644
--- a/mesalib/src/mesa/main/api_arrayelt.c
+++ b/mesalib/src/mesa/main/api_arrayelt.c
@@ -51,7 +51,7 @@ typedef struct {
int offset;
} AEarray;
-typedef void (GLAPIENTRY *attrib_func)( GLuint indx, const void *data );
+typedef void (*attrib_func)( GLuint indx, const void *data );
typedef struct {
const struct gl_client_array *array;
diff --git a/mesalib/src/mesa/main/api_exec.c b/mesalib/src/mesa/main/api_exec.c
index d7a4c90d7..02e39c189 100644
--- a/mesalib/src/mesa/main/api_exec.c
+++ b/mesalib/src/mesa/main/api_exec.c
@@ -104,7 +104,6 @@
#if FEATURE_GL
-
/**
* Initialize a dispatch table with pointers to Mesa's immediate-mode
* commands.
diff --git a/mesalib/src/mesa/main/blend.c b/mesalib/src/mesa/main/blend.c
index c74a16803..22031fd2a 100644
--- a/mesalib/src/mesa/main/blend.c
+++ b/mesalib/src/mesa/main/blend.c
@@ -1,822 +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);
-
- 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;
-}
-
-/*@}*/
+/**
+ * \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 75afae0ad..2de4602b8 100644
--- a/mesalib/src/mesa/main/bufferobj.c
+++ b/mesalib/src/mesa/main/bufferobj.c
@@ -1,2158 +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);
-
- 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 */
+/*
+ * 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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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
+ */
+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
+ */
+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/compiler.h b/mesalib/src/mesa/main/compiler.h
index 41cd48bc6..c1d773b18 100644
--- a/mesalib/src/mesa/main/compiler.h
+++ b/mesalib/src/mesa/main/compiler.h
@@ -60,29 +60,7 @@ extern "C" {
/**
* Get standard integer types
*/
-#if defined(_MSC_VER)
- typedef __int8 int8_t;
- typedef unsigned __int8 uint8_t;
- typedef __int16 int16_t;
- typedef unsigned __int16 uint16_t;
- typedef __int32 int32_t;
- typedef unsigned __int32 uint32_t;
- typedef __int64 int64_t;
- typedef unsigned __int64 uint64_t;
-
-# if defined(_WIN64)
- typedef __int64 intptr_t;
- typedef unsigned __int64 uintptr_t;
-# else
- typedef __int32 intptr_t;
- typedef unsigned __int32 uintptr_t;
-# endif
-
-# define INT64_C(__val) __val##i64
-# define UINT64_C(__val) __val##ui64
-#else
-# include <stdint.h>
-#endif
+#include <stdint.h>
/**
diff --git a/mesalib/src/mesa/main/context.c b/mesalib/src/mesa/main/context.c
index a94231455..cfb6b348b 100644
--- a/mesalib/src/mesa/main/context.c
+++ b/mesalib/src/mesa/main/context.c
@@ -1,1882 +1,1882 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.3
- *
- * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
- * Copyright (C) 2008 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 context.c
- * Mesa context/visual/framebuffer management functions.
- * \author Brian Paul
- */
-
-/**
- * \mainpage Mesa Main Module
- *
- * \section MainIntroduction Introduction
- *
- * The Mesa Main module consists of all the files in the main/ directory.
- * Among the features of this module are:
- * <UL>
- * <LI> Structures to represent most GL state </LI>
- * <LI> State set/get functions </LI>
- * <LI> Display lists </LI>
- * <LI> Texture unit, object and image handling </LI>
- * <LI> Matrix and attribute stacks </LI>
- * </UL>
- *
- * Other modules are responsible for API dispatch, vertex transformation,
- * point/line/triangle setup, rasterization, vertex array caching,
- * vertex/fragment programs/shaders, etc.
- *
- *
- * \section AboutDoxygen About Doxygen
- *
- * If you're viewing this information as Doxygen-generated HTML you'll
- * see the documentation index at the top of this page.
- *
- * The first line lists the Mesa source code modules.
- * The second line lists the indexes available for viewing the documentation
- * for each module.
- *
- * Selecting the <b>Main page</b> link will display a summary of the module
- * (this page).
- *
- * Selecting <b>Data Structures</b> will list all C structures.
- *
- * Selecting the <b>File List</b> link will list all the source files in
- * the module.
- * Selecting a filename will show a list of all functions defined in that file.
- *
- * Selecting the <b>Data Fields</b> link will display a list of all
- * documented structure members.
- *
- * Selecting the <b>Globals</b> link will display a list
- * of all functions, structures, global variables and macros in the module.
- *
- */
-
-
-#include "glheader.h"
-#include "mfeatures.h"
-#include "imports.h"
-#include "accum.h"
-#include "api_exec.h"
-#include "arrayobj.h"
-#include "attrib.h"
-#include "blend.h"
-#include "buffers.h"
-#include "bufferobj.h"
-#include "context.h"
-#include "cpuinfo.h"
-#include "debug.h"
-#include "depth.h"
-#include "dlist.h"
-#include "eval.h"
-#include "extensions.h"
-#include "fbobject.h"
-#include "feedback.h"
-#include "fog.h"
-#include "formats.h"
-#include "framebuffer.h"
-#include "hint.h"
-#include "hash.h"
-#include "light.h"
-#include "lines.h"
-#include "macros.h"
-#include "matrix.h"
-#include "multisample.h"
-#include "pixel.h"
-#include "pixelstore.h"
-#include "points.h"
-#include "polygon.h"
-#include "queryobj.h"
-#include "syncobj.h"
-#include "rastpos.h"
-#include "remap.h"
-#include "scissor.h"
-#include "shared.h"
-#include "shaderobj.h"
-#include "simple_list.h"
-#include "state.h"
-#include "stencil.h"
-#include "texcompress_s3tc.h"
-#include "texstate.h"
-#include "transformfeedback.h"
-#include "mtypes.h"
-#include "varray.h"
-#include "version.h"
-#include "viewport.h"
-#include "vtxfmt.h"
-#include "program/program.h"
-#include "program/prog_print.h"
-#if _HAVE_FULL_GL
-#include "math/m_matrix.h"
-#endif
-#include "main/dispatch.h" /* for _gloffset_COUNT */
-
-#ifdef USE_SPARC_ASM
-#include "sparc/sparc.h"
-#endif
-
-#include "glsl_parser_extras.h"
-#include <stdbool.h>
-
-
-#ifndef MESA_VERBOSE
-int MESA_VERBOSE = 0;
-#endif
-
-#ifndef MESA_DEBUG_FLAGS
-int MESA_DEBUG_FLAGS = 0;
-#endif
-
-
-/* ubyte -> float conversion */
-GLfloat _mesa_ubyte_to_float_color_tab[256];
-
-
-
-/**
- * Swap buffers notification callback.
- *
- * \param ctx GL context.
- *
- * Called by window system just before swapping buffers.
- * We have to finish any pending rendering.
- */
-void
-_mesa_notifySwapBuffers(struct gl_context *ctx)
-{
- if (MESA_VERBOSE & VERBOSE_SWAPBUFFERS)
- _mesa_debug(ctx, "SwapBuffers\n");
- FLUSH_CURRENT( ctx, 0 );
- if (ctx->Driver.Flush) {
- ctx->Driver.Flush(ctx);
- }
-}
-
-
-/**********************************************************************/
-/** \name GL Visual allocation/destruction */
-/**********************************************************************/
-/*@{*/
-
-/**
- * Allocates a struct gl_config structure and initializes it via
- * _mesa_initialize_visual().
- *
- * \param dbFlag double buffering
- * \param stereoFlag stereo buffer
- * \param depthBits requested bits per depth buffer value. Any value in [0, 32]
- * is acceptable but the actual depth type will be GLushort or GLuint as
- * needed.
- * \param stencilBits requested minimum bits per stencil buffer value
- * \param accumRedBits, accumGreenBits, accumBlueBits, accumAlphaBits number of bits per color component in accum buffer.
- * \param indexBits number of bits per pixel if \p rgbFlag is GL_FALSE
- * \param redBits number of bits per color component in frame buffer for RGB(A)
- * mode. We always use 8 in core Mesa though.
- * \param greenBits same as above.
- * \param blueBits same as above.
- * \param alphaBits same as above.
- * \param numSamples not really used.
- *
- * \return pointer to new struct gl_config or NULL if requested parameters can't be
- * met.
- *
- * \note Need to add params for level and numAuxBuffers (at least)
- */
-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 )
-{
- struct gl_config *vis = CALLOC_STRUCT(gl_config);
- if (vis) {
- if (!_mesa_initialize_visual(vis, dbFlag, stereoFlag,
- redBits, greenBits, blueBits, alphaBits,
- depthBits, stencilBits,
- accumRedBits, accumGreenBits,
- accumBlueBits, accumAlphaBits,
- numSamples)) {
- free(vis);
- return NULL;
- }
- }
- return vis;
-}
-
-
-/**
- * Makes some sanity checks and fills in the fields of the struct
- * gl_config object with the given parameters. If the caller needs to
- * set additional fields, he should just probably init the whole
- * gl_config object himself.
- *
- * \return GL_TRUE on success, or GL_FALSE on failure.
- *
- * \sa _mesa_create_visual() above for the parameter description.
- */
-GLboolean
-_mesa_initialize_visual( struct gl_config *vis,
- 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 )
-{
- assert(vis);
-
- if (depthBits < 0 || depthBits > 32) {
- return GL_FALSE;
- }
- if (stencilBits < 0 || stencilBits > STENCIL_BITS) {
- return GL_FALSE;
- }
- assert(accumRedBits >= 0);
- assert(accumGreenBits >= 0);
- assert(accumBlueBits >= 0);
- assert(accumAlphaBits >= 0);
-
- vis->rgbMode = GL_TRUE;
- vis->doubleBufferMode = dbFlag;
- vis->stereoMode = stereoFlag;
-
- vis->redBits = redBits;
- vis->greenBits = greenBits;
- vis->blueBits = blueBits;
- vis->alphaBits = alphaBits;
- vis->rgbBits = redBits + greenBits + blueBits;
-
- vis->indexBits = 0;
- vis->depthBits = depthBits;
- vis->stencilBits = stencilBits;
-
- vis->accumRedBits = accumRedBits;
- vis->accumGreenBits = accumGreenBits;
- vis->accumBlueBits = accumBlueBits;
- vis->accumAlphaBits = accumAlphaBits;
-
- vis->haveAccumBuffer = accumRedBits > 0;
- vis->haveDepthBuffer = depthBits > 0;
- vis->haveStencilBuffer = stencilBits > 0;
-
- vis->numAuxBuffers = 0;
- vis->level = 0;
- vis->sampleBuffers = numSamples > 0 ? 1 : 0;
- vis->samples = numSamples;
-
- return GL_TRUE;
-}
-
-
-/**
- * Destroy a visual and free its memory.
- *
- * \param vis visual.
- *
- * Frees the visual structure.
- */
-void
-_mesa_destroy_visual( struct gl_config *vis )
-{
- free(vis);
-}
-
-/*@}*/
-
-
-/**********************************************************************/
-/** \name Context allocation, initialization, destroying
- *
- * The purpose of the most initialization functions here is to provide the
- * default state values according to the OpenGL specification.
- */
-/**********************************************************************/
-/*@{*/
-
-
-/**
- * This is lame. gdb only seems to recognize enum types that are
- * actually used somewhere. We want to be able to print/use enum
- * values such as TEXTURE_2D_INDEX in gdb. But we don't actually use
- * the gl_texture_index type anywhere. Thus, this lame function.
- */
-static void
-dummy_enum_func(void)
-{
- gl_buffer_index bi = BUFFER_FRONT_LEFT;
- gl_face_index fi = FACE_POS_X;
- gl_frag_attrib fa = FRAG_ATTRIB_WPOS;
- gl_frag_result fr = FRAG_RESULT_DEPTH;
- gl_texture_index ti = TEXTURE_2D_ARRAY_INDEX;
- gl_vert_attrib va = VERT_ATTRIB_POS;
- gl_vert_result vr = VERT_RESULT_HPOS;
- gl_geom_attrib ga = GEOM_ATTRIB_POSITION;
- gl_geom_result gr = GEOM_RESULT_POS;
-
- (void) bi;
- (void) fi;
- (void) fa;
- (void) fr;
- (void) ti;
- (void) va;
- (void) vr;
- (void) ga;
- (void) gr;
-}
-
-
-/**
- * One-time initialization mutex lock.
- *
- * \sa Used by one_time_init().
- */
-_glthread_DECLARE_STATIC_MUTEX(OneTimeLock);
-
-
-
-/**
- * Calls all the various one-time-init functions in Mesa.
- *
- * While holding a global mutex lock, calls several initialization functions,
- * and sets the glapi callbacks if the \c MESA_DEBUG environment variable is
- * defined.
- *
- * \sa _math_init().
- */
-static void
-one_time_init( struct gl_context *ctx )
-{
- static GLbitfield api_init_mask = 0x0;
-
- _glthread_LOCK_MUTEX(OneTimeLock);
-
- /* truly one-time init */
- if (!api_init_mask) {
- GLuint i;
-
- /* do some implementation tests */
- assert( sizeof(GLbyte) == 1 );
- assert( sizeof(GLubyte) == 1 );
- assert( sizeof(GLshort) == 2 );
- assert( sizeof(GLushort) == 2 );
- assert( sizeof(GLint) == 4 );
- assert( sizeof(GLuint) == 4 );
-
- _mesa_get_cpu_features();
-
- _mesa_init_sqrt_table();
-
- /* context dependence is never a one-time thing... */
- _mesa_init_get_hash(ctx);
-
- for (i = 0; i < 256; i++) {
- _mesa_ubyte_to_float_color_tab[i] = (float) i / 255.0F;
- }
-
-#if defined(DEBUG) && defined(__DATE__) && defined(__TIME__)
- if (MESA_VERBOSE != 0) {
- _mesa_debug(ctx, "Mesa %s DEBUG build %s %s\n",
- MESA_VERSION_STRING, __DATE__, __TIME__);
- }
-#endif
-
-#ifdef DEBUG
- _mesa_test_formats();
-#endif
- }
-
- /* per-API one-time init */
- if (!(api_init_mask & (1 << ctx->API))) {
- /*
- * This is fine as ES does not use the remap table, but it may not be
- * future-proof. We cannot always initialize the remap table because
- * when an app is linked to libGLES*, there are not enough dynamic
- * entries.
- */
- if (ctx->API == API_OPENGL)
- _mesa_init_remap_table();
- }
-
- api_init_mask |= 1 << ctx->API;
-
- _glthread_UNLOCK_MUTEX(OneTimeLock);
-
- /* Hopefully atexit() is widely available. If not, we may need some
- * #ifdef tests here.
- */
- atexit(_mesa_destroy_shader_compiler);
-
- dummy_enum_func();
-}
-
-
-/**
- * Initialize fields of gl_current_attrib (aka ctx->Current.*)
- */
-static void
-_mesa_init_current(struct gl_context *ctx)
-{
- GLuint i;
-
- /* Init all to (0,0,0,1) */
- for (i = 0; i < Elements(ctx->Current.Attrib); i++) {
- ASSIGN_4V( ctx->Current.Attrib[i], 0.0, 0.0, 0.0, 1.0 );
- }
-
- /* redo special cases: */
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_WEIGHT], 1.0, 0.0, 0.0, 0.0 );
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_NORMAL], 0.0, 0.0, 1.0, 1.0 );
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR0], 1.0, 1.0, 1.0, 1.0 );
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR1], 0.0, 0.0, 0.0, 1.0 );
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR_INDEX], 1.0, 0.0, 0.0, 1.0 );
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_EDGEFLAG], 1.0, 0.0, 0.0, 1.0 );
-}
-
-
-/**
- * Init vertex/fragment/geometry program limits.
- * Important: drivers should override these with actual limits.
- */
-static void
-init_program_limits(GLenum type, struct gl_program_constants *prog)
-{
- prog->MaxInstructions = MAX_PROGRAM_INSTRUCTIONS;
- prog->MaxAluInstructions = MAX_PROGRAM_INSTRUCTIONS;
- prog->MaxTexInstructions = MAX_PROGRAM_INSTRUCTIONS;
- prog->MaxTexIndirections = MAX_PROGRAM_INSTRUCTIONS;
- prog->MaxTemps = MAX_PROGRAM_TEMPS;
- prog->MaxEnvParams = MAX_PROGRAM_ENV_PARAMS;
- prog->MaxLocalParams = MAX_PROGRAM_LOCAL_PARAMS;
- prog->MaxUniformComponents = 4 * MAX_UNIFORMS;
-
- switch (type) {
- case GL_VERTEX_PROGRAM_ARB:
- prog->MaxParameters = MAX_VERTEX_PROGRAM_PARAMS;
- prog->MaxAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS;
- prog->MaxAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS;
- break;
- case GL_FRAGMENT_PROGRAM_ARB:
- prog->MaxParameters = MAX_NV_FRAGMENT_PROGRAM_PARAMS;
- prog->MaxAttribs = MAX_NV_FRAGMENT_PROGRAM_INPUTS;
- prog->MaxAddressRegs = MAX_FRAGMENT_PROGRAM_ADDRESS_REGS;
- break;
- case MESA_GEOMETRY_PROGRAM:
- prog->MaxParameters = MAX_NV_VERTEX_PROGRAM_PARAMS;
- prog->MaxAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS;
- prog->MaxAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS;
-
- prog->MaxGeometryTextureImageUnits = MAX_GEOMETRY_TEXTURE_IMAGE_UNITS;
- prog->MaxGeometryVaryingComponents = MAX_GEOMETRY_VARYING_COMPONENTS;
- prog->MaxVertexVaryingComponents = MAX_VERTEX_VARYING_COMPONENTS;
- prog->MaxGeometryUniformComponents = MAX_GEOMETRY_UNIFORM_COMPONENTS;
- prog->MaxGeometryOutputVertices = MAX_GEOMETRY_OUTPUT_VERTICES;
- prog->MaxGeometryTotalOutputComponents = MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS;
- break;
- default:
- assert(0 && "Bad program type in init_program_limits()");
- }
-
- /* Set the native limits to zero. This implies that there is no native
- * support for shaders. Let the drivers fill in the actual values.
- */
- prog->MaxNativeInstructions = 0;
- prog->MaxNativeAluInstructions = 0;
- prog->MaxNativeTexInstructions = 0;
- prog->MaxNativeTexIndirections = 0;
- prog->MaxNativeAttribs = 0;
- prog->MaxNativeTemps = 0;
- prog->MaxNativeAddressRegs = 0;
- prog->MaxNativeParameters = 0;
-
- /* Set GLSL datatype range/precision info assuming IEEE float values.
- * Drivers should override these defaults as needed.
- */
- prog->MediumFloat.RangeMin = 127;
- prog->MediumFloat.RangeMax = 127;
- prog->MediumFloat.Precision = 23;
- prog->LowFloat = prog->HighFloat = prog->MediumFloat;
-
- /* Assume ints are stored as floats for now, since this is the least-common
- * denominator. The OpenGL ES spec implies (page 132) that the precision
- * of integer types should be 0. Practically speaking, IEEE
- * single-precision floating point values can only store integers in the
- * range [-0x01000000, 0x01000000] without loss of precision.
- */
- prog->MediumInt.RangeMin = 24;
- prog->MediumInt.RangeMax = 24;
- prog->MediumInt.Precision = 0;
- prog->LowInt = prog->HighInt = prog->MediumInt;
-}
-
-
-/**
- * Initialize fields of gl_constants (aka ctx->Const.*).
- * Use defaults from config.h. The device drivers will often override
- * some of these values (such as number of texture units).
- */
-static void
-_mesa_init_constants(struct gl_context *ctx)
-{
- assert(ctx);
-
- /* Constants, may be overriden (usually only reduced) by device drivers */
- ctx->Const.MaxTextureMbytes = MAX_TEXTURE_MBYTES;
- ctx->Const.MaxTextureLevels = MAX_TEXTURE_LEVELS;
- ctx->Const.Max3DTextureLevels = MAX_3D_TEXTURE_LEVELS;
- ctx->Const.MaxCubeTextureLevels = MAX_CUBE_TEXTURE_LEVELS;
- ctx->Const.MaxTextureRectSize = MAX_TEXTURE_RECT_SIZE;
- ctx->Const.MaxArrayTextureLayers = MAX_ARRAY_TEXTURE_LAYERS;
- ctx->Const.MaxTextureCoordUnits = MAX_TEXTURE_COORD_UNITS;
- ctx->Const.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
- ctx->Const.MaxTextureUnits = MIN2(ctx->Const.MaxTextureCoordUnits,
- ctx->Const.MaxTextureImageUnits);
- ctx->Const.MaxTextureMaxAnisotropy = MAX_TEXTURE_MAX_ANISOTROPY;
- ctx->Const.MaxTextureLodBias = MAX_TEXTURE_LOD_BIAS;
- ctx->Const.MaxArrayLockSize = MAX_ARRAY_LOCK_SIZE;
- ctx->Const.SubPixelBits = SUB_PIXEL_BITS;
- ctx->Const.MinPointSize = MIN_POINT_SIZE;
- ctx->Const.MaxPointSize = MAX_POINT_SIZE;
- ctx->Const.MinPointSizeAA = MIN_POINT_SIZE;
- ctx->Const.MaxPointSizeAA = MAX_POINT_SIZE;
- ctx->Const.PointSizeGranularity = (GLfloat) POINT_SIZE_GRANULARITY;
- ctx->Const.MinLineWidth = MIN_LINE_WIDTH;
- ctx->Const.MaxLineWidth = MAX_LINE_WIDTH;
- ctx->Const.MinLineWidthAA = MIN_LINE_WIDTH;
- ctx->Const.MaxLineWidthAA = MAX_LINE_WIDTH;
- ctx->Const.LineWidthGranularity = (GLfloat) LINE_WIDTH_GRANULARITY;
- ctx->Const.MaxColorTableSize = MAX_COLOR_TABLE_SIZE;
- ctx->Const.MaxClipPlanes = MAX_CLIP_PLANES;
- ctx->Const.MaxLights = MAX_LIGHTS;
- ctx->Const.MaxShininess = 128.0;
- ctx->Const.MaxSpotExponent = 128.0;
- ctx->Const.MaxViewportWidth = MAX_WIDTH;
- ctx->Const.MaxViewportHeight = MAX_HEIGHT;
-#if FEATURE_ARB_vertex_program
- init_program_limits(GL_VERTEX_PROGRAM_ARB, &ctx->Const.VertexProgram);
-#endif
-#if FEATURE_ARB_fragment_program
- init_program_limits(GL_FRAGMENT_PROGRAM_ARB, &ctx->Const.FragmentProgram);
-#endif
-#if FEATURE_ARB_geometry_shader4
- init_program_limits(MESA_GEOMETRY_PROGRAM, &ctx->Const.GeometryProgram);
-#endif
- ctx->Const.MaxProgramMatrices = MAX_PROGRAM_MATRICES;
- ctx->Const.MaxProgramMatrixStackDepth = MAX_PROGRAM_MATRIX_STACK_DEPTH;
-
- /* CheckArrayBounds is overriden by drivers/x11 for X server */
- ctx->Const.CheckArrayBounds = GL_FALSE;
-
- /* GL_ARB_draw_buffers */
- ctx->Const.MaxDrawBuffers = MAX_DRAW_BUFFERS;
-
-#if FEATURE_EXT_framebuffer_object
- ctx->Const.MaxColorAttachments = MAX_COLOR_ATTACHMENTS;
- ctx->Const.MaxRenderbufferSize = MAX_WIDTH;
-#endif
-
-#if FEATURE_ARB_vertex_shader
- ctx->Const.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
- ctx->Const.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
- ctx->Const.MaxVarying = MAX_VARYING;
-#endif
-
- /* Shading language version */
- if (ctx->API == API_OPENGL) {
- ctx->Const.GLSLVersion = 120;
- }
- else if (ctx->API == API_OPENGLES2) {
- ctx->Const.GLSLVersion = 100;
- }
- else if (ctx->API == API_OPENGLES) {
- ctx->Const.GLSLVersion = 0; /* GLSL not supported */
- }
-
- /* GL_ARB_framebuffer_object */
- ctx->Const.MaxSamples = 0;
-
- /* GL_ARB_sync */
- ctx->Const.MaxServerWaitTimeout = (GLuint64) ~0;
-
- /* GL_ATI_envmap_bumpmap */
- ctx->Const.SupportedBumpUnits = SUPPORTED_ATI_BUMP_UNITS;
-
- /* GL_EXT_provoking_vertex */
- ctx->Const.QuadsFollowProvokingVertexConvention = GL_TRUE;
-
- /* GL_EXT_transform_feedback */
- ctx->Const.MaxTransformFeedbackSeparateAttribs = MAX_FEEDBACK_ATTRIBS;
- ctx->Const.MaxTransformFeedbackSeparateComponents = 4 * MAX_FEEDBACK_ATTRIBS;
- ctx->Const.MaxTransformFeedbackInterleavedComponents = 4 * MAX_FEEDBACK_ATTRIBS;
-
- /* GL 3.2: hard-coded for now: */
- ctx->Const.ProfileMask = GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
-
- /** GL_EXT_gpu_shader4 */
- ctx->Const.MinProgramTexelOffset = -8;
- ctx->Const.MaxProgramTexelOffset = 7;
-}
-
-
-/**
- * Do some sanity checks on the limits/constants for the given context.
- * Only called the first time a context is bound.
- */
-static void
-check_context_limits(struct gl_context *ctx)
-{
- /* check that we don't exceed the size of various bitfields */
- assert(VERT_RESULT_MAX <=
- (8 * sizeof(ctx->VertexProgram._Current->Base.OutputsWritten)));
- assert(FRAG_ATTRIB_MAX <=
- (8 * sizeof(ctx->FragmentProgram._Current->Base.InputsRead)));
-
- assert(MAX_COMBINED_TEXTURE_IMAGE_UNITS <= 8 * sizeof(GLbitfield));
-
- /* shader-related checks */
- assert(ctx->Const.FragmentProgram.MaxLocalParams <= MAX_PROGRAM_LOCAL_PARAMS);
- assert(ctx->Const.VertexProgram.MaxLocalParams <= MAX_PROGRAM_LOCAL_PARAMS);
-
- assert(MAX_NV_FRAGMENT_PROGRAM_TEMPS <= MAX_PROGRAM_TEMPS);
- assert(MAX_NV_VERTEX_PROGRAM_TEMPS <= MAX_PROGRAM_TEMPS);
- assert(MAX_NV_VERTEX_PROGRAM_INPUTS <= VERT_ATTRIB_MAX);
- assert(MAX_NV_VERTEX_PROGRAM_OUTPUTS <= VERT_RESULT_MAX);
-
- /* Texture unit checks */
- assert(ctx->Const.MaxTextureImageUnits > 0);
- assert(ctx->Const.MaxTextureImageUnits <= MAX_TEXTURE_IMAGE_UNITS);
- assert(ctx->Const.MaxTextureCoordUnits > 0);
- assert(ctx->Const.MaxTextureCoordUnits <= MAX_TEXTURE_COORD_UNITS);
- assert(ctx->Const.MaxTextureUnits > 0);
- assert(ctx->Const.MaxTextureUnits <= MAX_TEXTURE_IMAGE_UNITS);
- assert(ctx->Const.MaxTextureUnits <= MAX_TEXTURE_COORD_UNITS);
- assert(ctx->Const.MaxTextureUnits == MIN2(ctx->Const.MaxTextureImageUnits,
- ctx->Const.MaxTextureCoordUnits));
- assert(ctx->Const.MaxCombinedTextureImageUnits > 0);
- assert(ctx->Const.MaxCombinedTextureImageUnits <= MAX_COMBINED_TEXTURE_IMAGE_UNITS);
- assert(ctx->Const.MaxTextureCoordUnits <= MAX_COMBINED_TEXTURE_IMAGE_UNITS);
- /* number of coord units cannot be greater than number of image units */
- assert(ctx->Const.MaxTextureCoordUnits <= ctx->Const.MaxTextureImageUnits);
-
-
- /* Texture size checks */
- assert(ctx->Const.MaxTextureLevels <= MAX_TEXTURE_LEVELS);
- assert(ctx->Const.Max3DTextureLevels <= MAX_3D_TEXTURE_LEVELS);
- assert(ctx->Const.MaxCubeTextureLevels <= MAX_CUBE_TEXTURE_LEVELS);
- assert(ctx->Const.MaxTextureRectSize <= MAX_TEXTURE_RECT_SIZE);
-
- /* make sure largest texture image is <= MAX_WIDTH in size */
- assert((1 << (ctx->Const.MaxTextureLevels - 1)) <= MAX_WIDTH);
- assert((1 << (ctx->Const.MaxCubeTextureLevels - 1)) <= MAX_WIDTH);
- assert((1 << (ctx->Const.Max3DTextureLevels - 1)) <= MAX_WIDTH);
-
- /* Texture level checks */
- assert(MAX_TEXTURE_LEVELS >= MAX_3D_TEXTURE_LEVELS);
- assert(MAX_TEXTURE_LEVELS >= MAX_CUBE_TEXTURE_LEVELS);
-
- /* Max texture size should be <= max viewport size (render to texture) */
- assert((1 << (MAX_TEXTURE_LEVELS - 1)) <= MAX_WIDTH);
-
- assert(ctx->Const.MaxViewportWidth <= MAX_WIDTH);
- assert(ctx->Const.MaxViewportHeight <= MAX_WIDTH);
-
- assert(ctx->Const.MaxDrawBuffers <= MAX_DRAW_BUFFERS);
-
- /* if this fails, add more enum values to gl_buffer_index */
- assert(BUFFER_COLOR0 + MAX_DRAW_BUFFERS <= BUFFER_COUNT);
-
- /* XXX probably add more tests */
-}
-
-
-/**
- * Initialize the attribute groups in a GL context.
- *
- * \param ctx GL context.
- *
- * Initializes all the attributes, calling the respective <tt>init*</tt>
- * functions for the more complex data structures.
- */
-static GLboolean
-init_attrib_groups(struct gl_context *ctx)
-{
- assert(ctx);
-
- /* Constants */
- _mesa_init_constants( ctx );
-
- /* Extensions */
- _mesa_init_extensions( ctx );
-
- /* Attribute Groups */
- _mesa_init_accum( ctx );
- _mesa_init_attrib( ctx );
- _mesa_init_buffer_objects( ctx );
- _mesa_init_color( ctx );
- _mesa_init_current( ctx );
- _mesa_init_depth( ctx );
- _mesa_init_debug( ctx );
- _mesa_init_display_list( ctx );
- _mesa_init_eval( ctx );
- _mesa_init_fbobjects( ctx );
- _mesa_init_feedback( ctx );
- _mesa_init_fog( ctx );
- _mesa_init_hint( ctx );
- _mesa_init_line( ctx );
- _mesa_init_lighting( ctx );
- _mesa_init_matrix( ctx );
- _mesa_init_multisample( ctx );
- _mesa_init_pixel( ctx );
- _mesa_init_pixelstore( ctx );
- _mesa_init_point( ctx );
- _mesa_init_polygon( ctx );
- _mesa_init_program( ctx );
- _mesa_init_queryobj( ctx );
- _mesa_init_sync( ctx );
- _mesa_init_rastpos( ctx );
- _mesa_init_scissor( ctx );
- _mesa_init_shader_state( ctx );
- _mesa_init_stencil( ctx );
- _mesa_init_transform( ctx );
- _mesa_init_transform_feedback( ctx );
- _mesa_init_varray( ctx );
- _mesa_init_viewport( ctx );
-
- if (!_mesa_init_texture( ctx ))
- return GL_FALSE;
-
- _mesa_init_texture_s3tc( ctx );
-
- /* Miscellaneous */
- ctx->NewState = _NEW_ALL;
- ctx->ErrorValue = (GLenum) GL_NO_ERROR;
- ctx->varying_vp_inputs = ~0;
-
- return GL_TRUE;
-}
-
-
-/**
- * Update default objects in a GL context with respect to shared state.
- *
- * \param ctx GL context.
- *
- * Removes references to old default objects, (texture objects, program
- * objects, etc.) and changes to reference those from the current shared
- * state.
- */
-static GLboolean
-update_default_objects(struct gl_context *ctx)
-{
- assert(ctx);
-
- _mesa_update_default_objects_program(ctx);
- _mesa_update_default_objects_texture(ctx);
- _mesa_update_default_objects_buffer_objects(ctx);
-
- return GL_TRUE;
-}
-
-
-/**
- * This is the default function we plug into all dispatch table slots
- * This helps prevents a segfault when someone calls a GL function without
- * first checking if the extension's supported.
- */
-static int
-generic_nop(void)
-{
- _mesa_warning(NULL, "User called no-op dispatch function (an unsupported extension function?)");
- return 0;
-}
-
-
-/**
- * Allocate and initialize a new dispatch table.
- */
-struct _glapi_table *
-_mesa_alloc_dispatch_table(int size)
-{
- /* Find the larger of Mesa's dispatch table and libGL's dispatch table.
- * In practice, this'll be the same for stand-alone Mesa. But for DRI
- * Mesa we do this to accomodate different versions of libGL and various
- * DRI drivers.
- */
- GLint numEntries = MAX2(_glapi_get_dispatch_table_size(), _gloffset_COUNT);
- struct _glapi_table *table;
-
- /* should never happen, but just in case */
- numEntries = MAX2(numEntries, size);
-
- table = (struct _glapi_table *) malloc(numEntries * sizeof(_glapi_proc));
- if (table) {
- _glapi_proc *entry = (_glapi_proc *) table;
- GLint i;
- for (i = 0; i < numEntries; i++) {
- entry[i] = (_glapi_proc) generic_nop;
- }
- }
- return table;
-}
-
-
-/**
- * Initialize a struct gl_context struct (rendering context).
- *
- * This includes allocating all the other structs and arrays which hang off of
- * the context by pointers.
- * Note that the driver needs to pass in its dd_function_table here since
- * we need to at least call driverFunctions->NewTextureObject to create the
- * default texture objects.
- *
- * Called by _mesa_create_context().
- *
- * Performs the imports and exports callback tables initialization, and
- * miscellaneous one-time initializations. If no shared context is supplied one
- * is allocated, and increase its reference count. Setups the GL API dispatch
- * tables. Initialize the TNL module. Sets the maximum Z buffer depth.
- * Finally queries the \c MESA_DEBUG and \c MESA_VERBOSE environment variables
- * for debug flags.
- *
- * \param ctx the context to initialize
- * \param api the GL API type to create the context for
- * \param visual describes the visual attributes for this context
- * \param share_list points to context to share textures, display lists,
- * etc with, or NULL
- * \param driverFunctions table of device driver functions for this context
- * to use
- * \param driverContext pointer to driver-specific context data
- */
-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)
-{
- struct gl_shared_state *shared;
- int i;
-
- /*ASSERT(driverContext);*/
- assert(driverFunctions->NewTextureObject);
- assert(driverFunctions->FreeTexImageData);
-
- ctx->API = api;
- ctx->Visual = *visual;
- ctx->DrawBuffer = NULL;
- ctx->ReadBuffer = NULL;
- ctx->WinSysDrawBuffer = NULL;
- ctx->WinSysReadBuffer = NULL;
-
- /* misc one-time initializations */
- one_time_init(ctx);
-
- /* Plug in driver functions and context pointer here.
- * This is important because when we call alloc_shared_state() below
- * we'll call ctx->Driver.NewTextureObject() to create the default
- * textures.
- */
- ctx->Driver = *driverFunctions;
- ctx->DriverCtx = driverContext;
-
- if (share_list) {
- /* share state with another context */
- shared = share_list->Shared;
- }
- else {
- /* allocate new, unshared state */
- shared = _mesa_alloc_shared_state(ctx);
- if (!shared)
- return GL_FALSE;
- }
-
- _glthread_LOCK_MUTEX(shared->Mutex);
- ctx->Shared = shared;
- shared->RefCount++;
- _glthread_UNLOCK_MUTEX(shared->Mutex);
-
- if (!init_attrib_groups( ctx )) {
- _mesa_release_shared_state(ctx, ctx->Shared);
- return GL_FALSE;
- }
-
-#if FEATURE_dispatch
- /* setup the API dispatch tables */
- switch (ctx->API) {
-#if FEATURE_GL
- case API_OPENGL:
- ctx->Exec = _mesa_create_exec_table();
- break;
-#endif
-#if FEATURE_ES1
- case API_OPENGLES:
- ctx->Exec = _mesa_create_exec_table_es1();
- break;
-#endif
-#if FEATURE_ES2
- case API_OPENGLES2:
- ctx->Exec = _mesa_create_exec_table_es2();
- break;
-#endif
- default:
- _mesa_problem(ctx, "unknown or unsupported API");
- break;
- }
-
- if (!ctx->Exec) {
- _mesa_release_shared_state(ctx, ctx->Shared);
- return GL_FALSE;
- }
-#endif
- ctx->CurrentDispatch = ctx->Exec;
-
- ctx->FragmentProgram._MaintainTexEnvProgram
- = (_mesa_getenv("MESA_TEX_PROG") != NULL);
-
- ctx->VertexProgram._MaintainTnlProgram
- = (_mesa_getenv("MESA_TNL_PROG") != NULL);
- if (ctx->VertexProgram._MaintainTnlProgram) {
- /* this is required... */
- ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;
- }
-
- /* Mesa core handles all the formats that mesa core knows about.
- * Drivers will want to override this list with just the formats
- * they can handle, and confirm that appropriate fallbacks exist in
- * _mesa_choose_tex_format().
- */
- memset(&ctx->TextureFormatSupported, GL_TRUE,
- sizeof(ctx->TextureFormatSupported));
-
- switch (ctx->API) {
- case API_OPENGL:
-#if FEATURE_dlist
- ctx->Save = _mesa_create_save_table();
- if (!ctx->Save) {
- _mesa_release_shared_state(ctx, ctx->Shared);
- free(ctx->Exec);
- return GL_FALSE;
- }
-
- _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
-#endif
- break;
- case API_OPENGLES:
- /**
- * GL_OES_texture_cube_map says
- * "Initially all texture generation modes are set to REFLECTION_MAP_OES"
- */
- for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
- struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
- texUnit->GenS.Mode = GL_REFLECTION_MAP_NV;
- texUnit->GenT.Mode = GL_REFLECTION_MAP_NV;
- texUnit->GenR.Mode = GL_REFLECTION_MAP_NV;
- texUnit->GenS._ModeBit = TEXGEN_REFLECTION_MAP_NV;
- texUnit->GenT._ModeBit = TEXGEN_REFLECTION_MAP_NV;
- texUnit->GenR._ModeBit = TEXGEN_REFLECTION_MAP_NV;
- }
- break;
- case API_OPENGLES2:
- ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;
- ctx->VertexProgram._MaintainTnlProgram = GL_TRUE;
- ctx->Point.PointSprite = GL_TRUE; /* always on for ES 2.x */
- break;
- }
-
- ctx->FirstTimeCurrent = GL_TRUE;
-
- return GL_TRUE;
-}
-
-
-/**
- * Allocate and initialize a struct gl_context structure.
- * Note that the driver needs to pass in its dd_function_table here since
- * we need to at least call driverFunctions->NewTextureObject to initialize
- * the rendering context.
- *
- * \param api the GL API type to create the context for
- * \param visual a struct gl_config pointer (we copy the struct contents)
- * \param share_list another context to share display lists with or NULL
- * \param driverFunctions points to the dd_function_table into which the
- * driver has plugged in all its special functions.
- * \param driverContext points to the device driver's private context state
- *
- * \return pointer to a new __struct gl_contextRec or NULL if error.
- */
-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)
-{
- struct gl_context *ctx;
-
- ASSERT(visual);
- /*ASSERT(driverContext);*/
-
- ctx = (struct gl_context *) calloc(1, sizeof(struct gl_context));
- if (!ctx)
- return NULL;
-
- if (_mesa_initialize_context(ctx, api, visual, share_list,
- driverFunctions, driverContext)) {
- return ctx;
- }
- else {
- free(ctx);
- return NULL;
- }
-}
-
-
-/**
- * Free the data associated with the given context.
- *
- * But doesn't free the struct gl_context struct itself.
- *
- * \sa _mesa_initialize_context() and init_attrib_groups().
- */
-void
-_mesa_free_context_data( struct gl_context *ctx )
-{
- if (!_mesa_get_current_context()){
- /* No current context, but we may need one in order to delete
- * texture objs, etc. So temporarily bind the context now.
- */
- _mesa_make_current(ctx, NULL, NULL);
- }
-
- /* unreference WinSysDraw/Read buffers */
- _mesa_reference_framebuffer(&ctx->WinSysDrawBuffer, NULL);
- _mesa_reference_framebuffer(&ctx->WinSysReadBuffer, NULL);
- _mesa_reference_framebuffer(&ctx->DrawBuffer, NULL);
- _mesa_reference_framebuffer(&ctx->ReadBuffer, NULL);
-
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL);
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current, NULL);
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram._TnlProgram, NULL);
-
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL);
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, NULL);
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram, NULL);
-
- _mesa_free_attrib_data(ctx);
- _mesa_free_buffer_objects(ctx);
- _mesa_free_lighting_data( ctx );
- _mesa_free_eval_data( ctx );
- _mesa_free_texture_data( ctx );
- _mesa_free_matrix_data( ctx );
- _mesa_free_viewport_data( ctx );
- _mesa_free_program_data(ctx);
- _mesa_free_shader_state(ctx);
- _mesa_free_queryobj_data(ctx);
- _mesa_free_sync_data(ctx);
- _mesa_free_varray_data(ctx);
- _mesa_free_transform_feedback(ctx);
-
- _mesa_delete_array_object(ctx, ctx->Array.DefaultArrayObj);
-
-#if FEATURE_ARB_pixel_buffer_object
- _mesa_reference_buffer_object(ctx, &ctx->Pack.BufferObj, NULL);
- _mesa_reference_buffer_object(ctx, &ctx->Unpack.BufferObj, NULL);
- _mesa_reference_buffer_object(ctx, &ctx->DefaultPacking.BufferObj, NULL);
-#endif
-
-#if FEATURE_ARB_vertex_buffer_object
- _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL);
- _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL);
-#endif
-
- /* free dispatch tables */
- free(ctx->Exec);
- free(ctx->Save);
-
- /* Shared context state (display lists, textures, etc) */
- _mesa_release_shared_state( ctx, ctx->Shared );
-
- /* needs to be after freeing shared state */
- _mesa_free_display_list_data(ctx);
-
- if (ctx->Extensions.String)
- free((void *) ctx->Extensions.String);
-
- if (ctx->VersionString)
- free(ctx->VersionString);
-
- /* unbind the context if it's currently bound */
- if (ctx == _mesa_get_current_context()) {
- _mesa_make_current(NULL, NULL, NULL);
- }
-}
-
-
-/**
- * Destroy a struct gl_context structure.
- *
- * \param ctx GL context.
- *
- * Calls _mesa_free_context_data() and frees the gl_context object itself.
- */
-void
-_mesa_destroy_context( struct gl_context *ctx )
-{
- if (ctx) {
- _mesa_free_context_data(ctx);
- free( (void *) ctx );
- }
-}
-
-
-#if _HAVE_FULL_GL
-/**
- * Copy attribute groups from one context to another.
- *
- * \param src source context
- * \param dst destination context
- * \param mask bitwise OR of GL_*_BIT flags
- *
- * According to the bits specified in \p mask, copies the corresponding
- * attributes from \p src into \p dst. For many of the attributes a simple \c
- * memcpy is not enough due to the existence of internal pointers in their data
- * structures.
- */
-void
-_mesa_copy_context( const struct gl_context *src, struct gl_context *dst, GLuint mask )
-{
- if (mask & GL_ACCUM_BUFFER_BIT) {
- /* OK to memcpy */
- dst->Accum = src->Accum;
- }
- if (mask & GL_COLOR_BUFFER_BIT) {
- /* OK to memcpy */
- dst->Color = src->Color;
- }
- if (mask & GL_CURRENT_BIT) {
- /* OK to memcpy */
- dst->Current = src->Current;
- }
- if (mask & GL_DEPTH_BUFFER_BIT) {
- /* OK to memcpy */
- dst->Depth = src->Depth;
- }
- if (mask & GL_ENABLE_BIT) {
- /* no op */
- }
- if (mask & GL_EVAL_BIT) {
- /* OK to memcpy */
- dst->Eval = src->Eval;
- }
- if (mask & GL_FOG_BIT) {
- /* OK to memcpy */
- dst->Fog = src->Fog;
- }
- if (mask & GL_HINT_BIT) {
- /* OK to memcpy */
- dst->Hint = src->Hint;
- }
- if (mask & GL_LIGHTING_BIT) {
- GLuint i;
- /* begin with memcpy */
- dst->Light = src->Light;
- /* fixup linked lists to prevent pointer insanity */
- make_empty_list( &(dst->Light.EnabledList) );
- for (i = 0; i < MAX_LIGHTS; i++) {
- if (dst->Light.Light[i].Enabled) {
- insert_at_tail(&(dst->Light.EnabledList), &(dst->Light.Light[i]));
- }
- }
- }
- if (mask & GL_LINE_BIT) {
- /* OK to memcpy */
- dst->Line = src->Line;
- }
- if (mask & GL_LIST_BIT) {
- /* OK to memcpy */
- dst->List = src->List;
- }
- if (mask & GL_PIXEL_MODE_BIT) {
- /* OK to memcpy */
- dst->Pixel = src->Pixel;
- }
- if (mask & GL_POINT_BIT) {
- /* OK to memcpy */
- dst->Point = src->Point;
- }
- if (mask & GL_POLYGON_BIT) {
- /* OK to memcpy */
- dst->Polygon = src->Polygon;
- }
- if (mask & GL_POLYGON_STIPPLE_BIT) {
- /* Use loop instead of memcpy due to problem with Portland Group's
- * C compiler. Reported by John Stone.
- */
- GLuint i;
- for (i = 0; i < 32; i++) {
- dst->PolygonStipple[i] = src->PolygonStipple[i];
- }
- }
- if (mask & GL_SCISSOR_BIT) {
- /* OK to memcpy */
- dst->Scissor = src->Scissor;
- }
- if (mask & GL_STENCIL_BUFFER_BIT) {
- /* OK to memcpy */
- dst->Stencil = src->Stencil;
- }
- if (mask & GL_TEXTURE_BIT) {
- /* Cannot memcpy because of pointers */
- _mesa_copy_texture_state(src, dst);
- }
- if (mask & GL_TRANSFORM_BIT) {
- /* OK to memcpy */
- dst->Transform = src->Transform;
- }
- if (mask & GL_VIEWPORT_BIT) {
- /* Cannot use memcpy, because of pointers in GLmatrix _WindowMap */
- dst->Viewport.X = src->Viewport.X;
- dst->Viewport.Y = src->Viewport.Y;
- dst->Viewport.Width = src->Viewport.Width;
- dst->Viewport.Height = src->Viewport.Height;
- dst->Viewport.Near = src->Viewport.Near;
- dst->Viewport.Far = src->Viewport.Far;
- _math_matrix_copy(&dst->Viewport._WindowMap, &src->Viewport._WindowMap);
- }
-
- /* XXX FIXME: Call callbacks?
- */
- dst->NewState = _NEW_ALL;
-}
-#endif
-
-
-/**
- * Check if the given context can render into the given framebuffer
- * by checking visual attributes.
- *
- * Most of these tests could go away because Mesa is now pretty flexible
- * in terms of mixing rendering contexts with framebuffers. As long
- * as RGB vs. CI mode agree, we're probably good.
- *
- * \return GL_TRUE if compatible, GL_FALSE otherwise.
- */
-static GLboolean
-check_compatible(const struct gl_context *ctx,
- const struct gl_framebuffer *buffer)
-{
- const struct gl_config *ctxvis = &ctx->Visual;
- const struct gl_config *bufvis = &buffer->Visual;
-
- if (buffer == _mesa_get_incomplete_framebuffer())
- return GL_TRUE;
-
-#if 0
- /* disabling this fixes the fgl_glxgears pbuffer demo */
- if (ctxvis->doubleBufferMode && !bufvis->doubleBufferMode)
- return GL_FALSE;
-#endif
- if (ctxvis->stereoMode && !bufvis->stereoMode)
- return GL_FALSE;
- if (ctxvis->haveAccumBuffer && !bufvis->haveAccumBuffer)
- return GL_FALSE;
- if (ctxvis->haveDepthBuffer && !bufvis->haveDepthBuffer)
- return GL_FALSE;
- if (ctxvis->haveStencilBuffer && !bufvis->haveStencilBuffer)
- return GL_FALSE;
- if (ctxvis->redMask && ctxvis->redMask != bufvis->redMask)
- return GL_FALSE;
- if (ctxvis->greenMask && ctxvis->greenMask != bufvis->greenMask)
- return GL_FALSE;
- if (ctxvis->blueMask && ctxvis->blueMask != bufvis->blueMask)
- return GL_FALSE;
-#if 0
- /* disabled (see bug 11161) */
- if (ctxvis->depthBits && ctxvis->depthBits != bufvis->depthBits)
- return GL_FALSE;
-#endif
- if (ctxvis->stencilBits && ctxvis->stencilBits != bufvis->stencilBits)
- return GL_FALSE;
-
- return GL_TRUE;
-}
-
-
-/**
- * Do one-time initialization for the given framebuffer. Specifically,
- * ask the driver for the window's current size and update the framebuffer
- * object to match.
- * Really, the device driver should totally take care of this.
- */
-static void
-initialize_framebuffer_size(struct gl_context *ctx, struct gl_framebuffer *fb)
-{
- GLuint width, height;
- if (ctx->Driver.GetBufferSize) {
- ctx->Driver.GetBufferSize(fb, &width, &height);
- if (ctx->Driver.ResizeBuffers)
- ctx->Driver.ResizeBuffers(ctx, fb, width, height);
- fb->Initialized = GL_TRUE;
- }
-}
-
-
-/**
- * Check if the viewport/scissor size has not yet been initialized.
- * Initialize the size if the given width and height are non-zero.
- */
-void
-_mesa_check_init_viewport(struct gl_context *ctx, GLuint width, GLuint height)
-{
- if (!ctx->ViewportInitialized && width > 0 && height > 0) {
- /* Note: set flag here, before calling _mesa_set_viewport(), to prevent
- * potential infinite recursion.
- */
- ctx->ViewportInitialized = GL_TRUE;
- _mesa_set_viewport(ctx, 0, 0, width, height);
- _mesa_set_scissor(ctx, 0, 0, width, height);
- }
-}
-
-
-/**
- * Bind the given context to the given drawBuffer and readBuffer and
- * make it the current context for the calling thread.
- * We'll render into the drawBuffer and read pixels from the
- * readBuffer (i.e. glRead/CopyPixels, glCopyTexImage, etc).
- *
- * We check that the context's and framebuffer's visuals are compatible
- * and return immediately if they're not.
- *
- * \param newCtx the new GL context. If NULL then there will be no current GL
- * context.
- * \param drawBuffer the drawing framebuffer
- * \param readBuffer the reading framebuffer
- */
-GLboolean
-_mesa_make_current( struct gl_context *newCtx,
- struct gl_framebuffer *drawBuffer,
- struct gl_framebuffer *readBuffer )
-{
- GET_CURRENT_CONTEXT(curCtx);
-
- if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(newCtx, "_mesa_make_current()\n");
-
- /* Check that the context's and framebuffer's visuals are compatible.
- */
- if (newCtx && drawBuffer && newCtx->WinSysDrawBuffer != drawBuffer) {
- if (!check_compatible(newCtx, drawBuffer)) {
- _mesa_warning(newCtx,
- "MakeCurrent: incompatible visuals for context and drawbuffer");
- return GL_FALSE;
- }
- }
- if (newCtx && readBuffer && newCtx->WinSysReadBuffer != readBuffer) {
- if (!check_compatible(newCtx, readBuffer)) {
- _mesa_warning(newCtx,
- "MakeCurrent: incompatible visuals for context and readbuffer");
- return GL_FALSE;
- }
- }
-
- if (curCtx &&
- (curCtx->WinSysDrawBuffer || curCtx->WinSysReadBuffer) && /* make sure this context is valid for flushing */
- curCtx != newCtx)
- _mesa_flush(curCtx);
-
- /* We used to call _glapi_check_multithread() here. Now do it in drivers */
- _glapi_set_context((void *) newCtx);
- ASSERT(_mesa_get_current_context() == newCtx);
-
- if (!newCtx) {
- _glapi_set_dispatch(NULL); /* none current */
- }
- else {
- _glapi_set_dispatch(newCtx->CurrentDispatch);
-
- if (drawBuffer && readBuffer) {
- /* TODO: check if newCtx and buffer's visual match??? */
-
- ASSERT(drawBuffer->Name == 0);
- ASSERT(readBuffer->Name == 0);
- _mesa_reference_framebuffer(&newCtx->WinSysDrawBuffer, drawBuffer);
- _mesa_reference_framebuffer(&newCtx->WinSysReadBuffer, readBuffer);
-
- /*
- * Only set the context's Draw/ReadBuffer fields if they're NULL
- * or not bound to a user-created FBO.
- */
- if (!newCtx->DrawBuffer || newCtx->DrawBuffer->Name == 0) {
- /* KW: merge conflict here, revisit.
- */
- /* fix up the fb fields - these will end up wrong otherwise
- * if the DRIdrawable changes, and everything relies on them.
- * This is a bit messy (same as needed in _mesa_BindFramebufferEXT)
- */
- unsigned int i;
- GLenum buffers[MAX_DRAW_BUFFERS];
-
- _mesa_reference_framebuffer(&newCtx->DrawBuffer, drawBuffer);
-
- for(i = 0; i < newCtx->Const.MaxDrawBuffers; i++) {
- buffers[i] = newCtx->Color.DrawBuffer[i];
- }
-
- _mesa_drawbuffers(newCtx, newCtx->Const.MaxDrawBuffers,
- buffers, NULL);
- }
- if (!newCtx->ReadBuffer || newCtx->ReadBuffer->Name == 0) {
- _mesa_reference_framebuffer(&newCtx->ReadBuffer, readBuffer);
- }
-
- /* XXX only set this flag if we're really changing the draw/read
- * framebuffer bindings.
- */
- newCtx->NewState |= _NEW_BUFFERS;
-
-#if 1
- /* We want to get rid of these lines: */
-
-#if _HAVE_FULL_GL
- if (!drawBuffer->Initialized) {
- initialize_framebuffer_size(newCtx, drawBuffer);
- }
- if (readBuffer != drawBuffer && !readBuffer->Initialized) {
- initialize_framebuffer_size(newCtx, readBuffer);
- }
-
- _mesa_resizebuffers(newCtx);
-#endif
-
-#else
- /* We want the drawBuffer and readBuffer to be initialized by
- * the driver.
- * This generally means the Width and Height match the actual
- * window size and the renderbuffers (both hardware and software
- * based) are allocated to match. The later can generally be
- * done with a call to _mesa_resize_framebuffer().
- *
- * It's theoretically possible for a buffer to have zero width
- * or height, but for now, assert check that the driver did what's
- * expected of it.
- */
- ASSERT(drawBuffer->Width > 0);
- ASSERT(drawBuffer->Height > 0);
-#endif
-
- if (drawBuffer) {
- _mesa_check_init_viewport(newCtx,
- drawBuffer->Width, drawBuffer->Height);
- }
- }
-
- if (newCtx->FirstTimeCurrent) {
- _mesa_compute_version(newCtx);
-
- newCtx->Extensions.String = _mesa_make_extension_string(newCtx);
-
- check_context_limits(newCtx);
-
- /* We can use this to help debug user's problems. Tell them to set
- * the MESA_INFO env variable before running their app. Then the
- * first time each context is made current we'll print some useful
- * information.
- */
- if (_mesa_getenv("MESA_INFO")) {
- _mesa_print_info();
- }
-
- newCtx->FirstTimeCurrent = GL_FALSE;
- }
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Make context 'ctx' share the display lists, textures and programs
- * that are associated with 'ctxToShare'.
- * Any display lists, textures or programs associated with 'ctx' will
- * be deleted if nobody else is sharing them.
- */
-GLboolean
-_mesa_share_state(struct gl_context *ctx, struct gl_context *ctxToShare)
-{
- if (ctx && ctxToShare && ctx->Shared && ctxToShare->Shared) {
- struct gl_shared_state *oldSharedState = ctx->Shared;
-
- ctx->Shared = ctxToShare->Shared;
-
- _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
- ctx->Shared->RefCount++;
- _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
-
- update_default_objects(ctx);
-
- _mesa_release_shared_state(ctx, oldSharedState);
-
- return GL_TRUE;
- }
- else {
- return GL_FALSE;
- }
-}
-
-
-
-/**
- * \return pointer to the current GL context for this thread.
- *
- * Calls _glapi_get_context(). This isn't the fastest way to get the current
- * context. If you need speed, see the #GET_CURRENT_CONTEXT macro in
- * context.h.
- */
-struct gl_context *
-_mesa_get_current_context( void )
-{
- return (struct gl_context *) _glapi_get_context();
-}
-
-
-/**
- * Get context's current API dispatch table.
- *
- * It'll either be the immediate-mode execute dispatcher or the display list
- * compile dispatcher.
- *
- * \param ctx GL context.
- *
- * \return pointer to dispatch_table.
- *
- * Simply returns __struct gl_contextRec::CurrentDispatch.
- */
-struct _glapi_table *
-_mesa_get_dispatch(struct gl_context *ctx)
-{
- return ctx->CurrentDispatch;
-}
-
-/*@}*/
-
-
-/**********************************************************************/
-/** \name Miscellaneous functions */
-/**********************************************************************/
-/*@{*/
-
-/**
- * Record an error.
- *
- * \param ctx GL context.
- * \param error error code.
- *
- * Records the given error code and call the driver's dd_function_table::Error
- * function if defined.
- *
- * \sa
- * This is called via _mesa_error().
- */
-void
-_mesa_record_error(struct gl_context *ctx, GLenum error)
-{
- if (!ctx)
- return;
-
- if (ctx->ErrorValue == GL_NO_ERROR) {
- ctx->ErrorValue = error;
- }
-
- /* Call device driver's error handler, if any. This is used on the Mac. */
- if (ctx->Driver.Error) {
- ctx->Driver.Error(ctx);
- }
-}
-
-
-/**
- * Flush commands and wait for completion.
- */
-void
-_mesa_finish(struct gl_context *ctx)
-{
- FLUSH_CURRENT( ctx, 0 );
- if (ctx->Driver.Finish) {
- ctx->Driver.Finish(ctx);
- }
-}
-
-
-/**
- * Flush commands.
- */
-void
-_mesa_flush(struct gl_context *ctx)
-{
- FLUSH_CURRENT( ctx, 0 );
- if (ctx->Driver.Flush) {
- ctx->Driver.Flush(ctx);
- }
-}
-
-
-
-/**
- * Execute glFinish().
- *
- * Calls the #ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH macro and the
- * dd_function_table::Finish driver callback, if not NULL.
- */
-void GLAPIENTRY
-_mesa_Finish(void)
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
- _mesa_finish(ctx);
-}
-
-
-/**
- * Execute glFlush().
- *
- * Calls the #ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH macro and the
- * dd_function_table::Flush driver callback, if not NULL.
- */
-void GLAPIENTRY
-_mesa_Flush(void)
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
- _mesa_flush(ctx);
-}
-
-
-/**
- * Set mvp_with_dp4 flag. If a driver has a preference for DP4 over
- * MUL/MAD, or vice versa, call this function to register that.
- * Otherwise we default to MUL/MAD.
- */
-void
-_mesa_set_mvp_with_dp4( struct gl_context *ctx,
- GLboolean flag )
-{
- ctx->mvp_with_dp4 = flag;
-}
-
-
-
-/**
- * Prior to drawing anything with glBegin, glDrawArrays, etc. this function
- * is called to see if it's valid to render. This involves checking that
- * the current shader is valid and the framebuffer is complete.
- * If an error is detected it'll be recorded here.
- * \return GL_TRUE if OK to render, GL_FALSE if not
- */
-GLboolean
-_mesa_valid_to_render(struct gl_context *ctx, const char *where)
-{
- bool vert_from_glsl_shader = false;
- bool geom_from_glsl_shader = false;
- bool frag_from_glsl_shader = false;
-
- /* This depends on having up to date derived state (shaders) */
- if (ctx->NewState)
- _mesa_update_state(ctx);
-
- if (ctx->Shader.CurrentVertexProgram) {
- vert_from_glsl_shader = true;
-
- if (!ctx->Shader.CurrentVertexProgram->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(shader not linked)", where);
- return GL_FALSE;
- }
-#if 0 /* not normally enabled */
- {
- char errMsg[100];
- if (!_mesa_validate_shader_program(ctx,
- ctx->Shader.CurrentVertexProgram,
- errMsg)) {
- _mesa_warning(ctx, "Shader program %u is invalid: %s",
- ctx->Shader.CurrentVertexProgram->Name, errMsg);
- }
- }
-#endif
- }
-
- if (ctx->Shader.CurrentGeometryProgram) {
- geom_from_glsl_shader = true;
-
- if (!ctx->Shader.CurrentGeometryProgram->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(shader not linked)", where);
- return GL_FALSE;
- }
-#if 0 /* not normally enabled */
- {
- char errMsg[100];
- if (!_mesa_validate_shader_program(ctx,
- ctx->Shader.CurrentGeometryProgram,
- errMsg)) {
- _mesa_warning(ctx, "Shader program %u is invalid: %s",
- ctx->Shader.CurrentGeometryProgram->Name, errMsg);
- }
- }
-#endif
- }
-
- if (ctx->Shader.CurrentFragmentProgram) {
- frag_from_glsl_shader = true;
-
- if (!ctx->Shader.CurrentFragmentProgram->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(shader not linked)", where);
- return GL_FALSE;
- }
-#if 0 /* not normally enabled */
- {
- char errMsg[100];
- if (!_mesa_validate_shader_program(ctx,
- ctx->Shader.CurrentFragmentProgram,
- errMsg)) {
- _mesa_warning(ctx, "Shader program %u is invalid: %s",
- ctx->Shader.CurrentFragmentProgram->Name, errMsg);
- }
- }
-#endif
- }
-
- /* Any shader stages that are not supplied by the GLSL shader and have
- * assembly shaders enabled must now be validated.
- */
- if (!vert_from_glsl_shader
- && ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(vertex program not valid)", where);
- return GL_FALSE;
- }
-
- /* FINISHME: If GL_NV_geometry_program4 is ever supported, the current
- * FINISHME: geometry program should validated here.
- */
- (void) geom_from_glsl_shader;
-
- if (!frag_from_glsl_shader) {
- if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(fragment program not valid)", where);
- return GL_FALSE;
- }
-
- /* If drawing to integer-valued color buffers, there must be an
- * active fragment shader (GL_EXT_texture_integer).
- */
- if (ctx->DrawBuffer && ctx->DrawBuffer->_IntegerColor) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(integer format but no fragment shader)", where);
- return GL_FALSE;
- }
- }
-
- if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
- "%s(incomplete framebuffer)", where);
- return GL_FALSE;
- }
-
-#ifdef DEBUG
- if (ctx->Shader.Flags & GLSL_LOG) {
- struct gl_shader_program *shProg[MESA_SHADER_TYPES];
- gl_shader_type i;
-
- shProg[MESA_SHADER_VERTEX] = ctx->Shader.CurrentVertexProgram;
- shProg[MESA_SHADER_GEOMETRY] = ctx->Shader.CurrentGeometryProgram;
- shProg[MESA_SHADER_FRAGMENT] = ctx->Shader.CurrentFragmentProgram;
-
- for (i = 0; i < MESA_SHADER_TYPES; i++) {
- struct gl_shader *sh;
-
- if (shProg[i] == NULL || shProg[i]->_Used
- || shProg[i]->_LinkedShaders[i] == NULL)
- continue;
-
- /* This is the first time this shader is being used.
- * Append shader's constants/uniforms to log file.
- *
- * The logic is a little odd here. We only want to log data for each
- * shader target that will actually be used, and we only want to log
- * it once. It's possible to have a program bound to the vertex
- * shader target that also supplied a fragment shader. If that
- * program isn't also bound to the fragment shader target we don't
- * want to log its fragment data.
- */
- sh = shProg[i]->_LinkedShaders[i];
- switch (sh->Type) {
- case GL_VERTEX_SHADER:
- _mesa_append_uniforms_to_file(sh, &shProg[i]->VertexProgram->Base);
- break;
-
- case GL_GEOMETRY_SHADER_ARB:
- _mesa_append_uniforms_to_file(sh,
- &shProg[i]->GeometryProgram->Base);
- break;
-
- case GL_FRAGMENT_SHADER:
- _mesa_append_uniforms_to_file(sh,
- &shProg[i]->FragmentProgram->Base);
- break;
- }
- }
-
- for (i = 0; i < MESA_SHADER_TYPES; i++) {
- if (shProg[i] != NULL)
- shProg[i]->_Used = GL_TRUE;
- }
- }
-#endif
-
- return GL_TRUE;
-}
-
-
-/*@}*/
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.3
+ *
+ * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
+ * Copyright (C) 2008 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 context.c
+ * Mesa context/visual/framebuffer management functions.
+ * \author Brian Paul
+ */
+
+/**
+ * \mainpage Mesa Main Module
+ *
+ * \section MainIntroduction Introduction
+ *
+ * The Mesa Main module consists of all the files in the main/ directory.
+ * Among the features of this module are:
+ * <UL>
+ * <LI> Structures to represent most GL state </LI>
+ * <LI> State set/get functions </LI>
+ * <LI> Display lists </LI>
+ * <LI> Texture unit, object and image handling </LI>
+ * <LI> Matrix and attribute stacks </LI>
+ * </UL>
+ *
+ * Other modules are responsible for API dispatch, vertex transformation,
+ * point/line/triangle setup, rasterization, vertex array caching,
+ * vertex/fragment programs/shaders, etc.
+ *
+ *
+ * \section AboutDoxygen About Doxygen
+ *
+ * If you're viewing this information as Doxygen-generated HTML you'll
+ * see the documentation index at the top of this page.
+ *
+ * The first line lists the Mesa source code modules.
+ * The second line lists the indexes available for viewing the documentation
+ * for each module.
+ *
+ * Selecting the <b>Main page</b> link will display a summary of the module
+ * (this page).
+ *
+ * Selecting <b>Data Structures</b> will list all C structures.
+ *
+ * Selecting the <b>File List</b> link will list all the source files in
+ * the module.
+ * Selecting a filename will show a list of all functions defined in that file.
+ *
+ * Selecting the <b>Data Fields</b> link will display a list of all
+ * documented structure members.
+ *
+ * Selecting the <b>Globals</b> link will display a list
+ * of all functions, structures, global variables and macros in the module.
+ *
+ */
+
+
+#include "glheader.h"
+#include "mfeatures.h"
+#include "imports.h"
+#include "accum.h"
+#include "api_exec.h"
+#include "arrayobj.h"
+#include "attrib.h"
+#include "blend.h"
+#include "buffers.h"
+#include "bufferobj.h"
+#include "context.h"
+#include "cpuinfo.h"
+#include "debug.h"
+#include "depth.h"
+#include "dlist.h"
+#include "eval.h"
+#include "extensions.h"
+#include "fbobject.h"
+#include "feedback.h"
+#include "fog.h"
+#include "formats.h"
+#include "framebuffer.h"
+#include "hint.h"
+#include "hash.h"
+#include "light.h"
+#include "lines.h"
+#include "macros.h"
+#include "matrix.h"
+#include "multisample.h"
+#include "pixel.h"
+#include "pixelstore.h"
+#include "points.h"
+#include "polygon.h"
+#include "queryobj.h"
+#include "syncobj.h"
+#include "rastpos.h"
+#include "remap.h"
+#include "scissor.h"
+#include "shared.h"
+#include "shaderobj.h"
+#include "simple_list.h"
+#include "state.h"
+#include "stencil.h"
+#include "texcompress_s3tc.h"
+#include "texstate.h"
+#include "transformfeedback.h"
+#include "mtypes.h"
+#include "varray.h"
+#include "version.h"
+#include "viewport.h"
+#include "vtxfmt.h"
+#include "program/program.h"
+#include "program/prog_print.h"
+#if _HAVE_FULL_GL
+#include "math/m_matrix.h"
+#endif
+#include "main/dispatch.h" /* for _gloffset_COUNT */
+
+#ifdef USE_SPARC_ASM
+#include "sparc/sparc.h"
+#endif
+
+#include "glsl_parser_extras.h"
+#include <stdbool.h>
+
+
+#ifndef MESA_VERBOSE
+int MESA_VERBOSE = 0;
+#endif
+
+#ifndef MESA_DEBUG_FLAGS
+int MESA_DEBUG_FLAGS = 0;
+#endif
+
+
+/* ubyte -> float conversion */
+GLfloat _mesa_ubyte_to_float_color_tab[256];
+
+
+
+/**
+ * Swap buffers notification callback.
+ *
+ * \param ctx GL context.
+ *
+ * Called by window system just before swapping buffers.
+ * We have to finish any pending rendering.
+ */
+void
+_mesa_notifySwapBuffers(struct gl_context *ctx)
+{
+ if (MESA_VERBOSE & VERBOSE_SWAPBUFFERS)
+ _mesa_debug(ctx, "SwapBuffers\n");
+ FLUSH_CURRENT( ctx, 0 );
+ if (ctx->Driver.Flush) {
+ ctx->Driver.Flush(ctx);
+ }
+}
+
+
+/**********************************************************************/
+/** \name GL Visual allocation/destruction */
+/**********************************************************************/
+/*@{*/
+
+/**
+ * Allocates a struct gl_config structure and initializes it via
+ * _mesa_initialize_visual().
+ *
+ * \param dbFlag double buffering
+ * \param stereoFlag stereo buffer
+ * \param depthBits requested bits per depth buffer value. Any value in [0, 32]
+ * is acceptable but the actual depth type will be GLushort or GLuint as
+ * needed.
+ * \param stencilBits requested minimum bits per stencil buffer value
+ * \param accumRedBits, accumGreenBits, accumBlueBits, accumAlphaBits number of bits per color component in accum buffer.
+ * \param indexBits number of bits per pixel if \p rgbFlag is GL_FALSE
+ * \param redBits number of bits per color component in frame buffer for RGB(A)
+ * mode. We always use 8 in core Mesa though.
+ * \param greenBits same as above.
+ * \param blueBits same as above.
+ * \param alphaBits same as above.
+ * \param numSamples not really used.
+ *
+ * \return pointer to new struct gl_config or NULL if requested parameters can't be
+ * met.
+ *
+ * \note Need to add params for level and numAuxBuffers (at least)
+ */
+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 )
+{
+ struct gl_config *vis = CALLOC_STRUCT(gl_config);
+ if (vis) {
+ if (!_mesa_initialize_visual(vis, dbFlag, stereoFlag,
+ redBits, greenBits, blueBits, alphaBits,
+ depthBits, stencilBits,
+ accumRedBits, accumGreenBits,
+ accumBlueBits, accumAlphaBits,
+ numSamples)) {
+ free(vis);
+ return NULL;
+ }
+ }
+ return vis;
+}
+
+
+/**
+ * Makes some sanity checks and fills in the fields of the struct
+ * gl_config object with the given parameters. If the caller needs to
+ * set additional fields, he should just probably init the whole
+ * gl_config object himself.
+ *
+ * \return GL_TRUE on success, or GL_FALSE on failure.
+ *
+ * \sa _mesa_create_visual() above for the parameter description.
+ */
+GLboolean
+_mesa_initialize_visual( struct gl_config *vis,
+ 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 )
+{
+ assert(vis);
+
+ if (depthBits < 0 || depthBits > 32) {
+ return GL_FALSE;
+ }
+ if (stencilBits < 0 || stencilBits > STENCIL_BITS) {
+ return GL_FALSE;
+ }
+ assert(accumRedBits >= 0);
+ assert(accumGreenBits >= 0);
+ assert(accumBlueBits >= 0);
+ assert(accumAlphaBits >= 0);
+
+ vis->rgbMode = GL_TRUE;
+ vis->doubleBufferMode = dbFlag;
+ vis->stereoMode = stereoFlag;
+
+ vis->redBits = redBits;
+ vis->greenBits = greenBits;
+ vis->blueBits = blueBits;
+ vis->alphaBits = alphaBits;
+ vis->rgbBits = redBits + greenBits + blueBits;
+
+ vis->indexBits = 0;
+ vis->depthBits = depthBits;
+ vis->stencilBits = stencilBits;
+
+ vis->accumRedBits = accumRedBits;
+ vis->accumGreenBits = accumGreenBits;
+ vis->accumBlueBits = accumBlueBits;
+ vis->accumAlphaBits = accumAlphaBits;
+
+ vis->haveAccumBuffer = accumRedBits > 0;
+ vis->haveDepthBuffer = depthBits > 0;
+ vis->haveStencilBuffer = stencilBits > 0;
+
+ vis->numAuxBuffers = 0;
+ vis->level = 0;
+ vis->sampleBuffers = numSamples > 0 ? 1 : 0;
+ vis->samples = numSamples;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Destroy a visual and free its memory.
+ *
+ * \param vis visual.
+ *
+ * Frees the visual structure.
+ */
+void
+_mesa_destroy_visual( struct gl_config *vis )
+{
+ free(vis);
+}
+
+/*@}*/
+
+
+/**********************************************************************/
+/** \name Context allocation, initialization, destroying
+ *
+ * The purpose of the most initialization functions here is to provide the
+ * default state values according to the OpenGL specification.
+ */
+/**********************************************************************/
+/*@{*/
+
+
+/**
+ * This is lame. gdb only seems to recognize enum types that are
+ * actually used somewhere. We want to be able to print/use enum
+ * values such as TEXTURE_2D_INDEX in gdb. But we don't actually use
+ * the gl_texture_index type anywhere. Thus, this lame function.
+ */
+static void
+dummy_enum_func(void)
+{
+ gl_buffer_index bi = BUFFER_FRONT_LEFT;
+ gl_face_index fi = FACE_POS_X;
+ gl_frag_attrib fa = FRAG_ATTRIB_WPOS;
+ gl_frag_result fr = FRAG_RESULT_DEPTH;
+ gl_texture_index ti = TEXTURE_2D_ARRAY_INDEX;
+ gl_vert_attrib va = VERT_ATTRIB_POS;
+ gl_vert_result vr = VERT_RESULT_HPOS;
+ gl_geom_attrib ga = GEOM_ATTRIB_POSITION;
+ gl_geom_result gr = GEOM_RESULT_POS;
+
+ (void) bi;
+ (void) fi;
+ (void) fa;
+ (void) fr;
+ (void) ti;
+ (void) va;
+ (void) vr;
+ (void) ga;
+ (void) gr;
+}
+
+
+/**
+ * One-time initialization mutex lock.
+ *
+ * \sa Used by one_time_init().
+ */
+_glthread_DECLARE_STATIC_MUTEX(OneTimeLock);
+
+
+
+/**
+ * Calls all the various one-time-init functions in Mesa.
+ *
+ * While holding a global mutex lock, calls several initialization functions,
+ * and sets the glapi callbacks if the \c MESA_DEBUG environment variable is
+ * defined.
+ *
+ * \sa _math_init().
+ */
+static void
+one_time_init( struct gl_context *ctx )
+{
+ static GLbitfield api_init_mask = 0x0;
+
+ _glthread_LOCK_MUTEX(OneTimeLock);
+
+ /* truly one-time init */
+ if (!api_init_mask) {
+ GLuint i;
+
+ /* do some implementation tests */
+ assert( sizeof(GLbyte) == 1 );
+ assert( sizeof(GLubyte) == 1 );
+ assert( sizeof(GLshort) == 2 );
+ assert( sizeof(GLushort) == 2 );
+ assert( sizeof(GLint) == 4 );
+ assert( sizeof(GLuint) == 4 );
+
+ _mesa_get_cpu_features();
+
+ _mesa_init_sqrt_table();
+
+ /* context dependence is never a one-time thing... */
+ _mesa_init_get_hash(ctx);
+
+ for (i = 0; i < 256; i++) {
+ _mesa_ubyte_to_float_color_tab[i] = (float) i / 255.0F;
+ }
+
+#if defined(DEBUG) && defined(__DATE__) && defined(__TIME__)
+ if (MESA_VERBOSE != 0) {
+ _mesa_debug(ctx, "Mesa %s DEBUG build %s %s\n",
+ MESA_VERSION_STRING, __DATE__, __TIME__);
+ }
+#endif
+
+#ifdef DEBUG
+ _mesa_test_formats();
+#endif
+ }
+
+ /* per-API one-time init */
+ if (!(api_init_mask & (1 << ctx->API))) {
+ /*
+ * This is fine as ES does not use the remap table, but it may not be
+ * future-proof. We cannot always initialize the remap table because
+ * when an app is linked to libGLES*, there are not enough dynamic
+ * entries.
+ */
+ if (ctx->API == API_OPENGL)
+ _mesa_init_remap_table();
+ }
+
+ api_init_mask |= 1 << ctx->API;
+
+ _glthread_UNLOCK_MUTEX(OneTimeLock);
+
+ /* Hopefully atexit() is widely available. If not, we may need some
+ * #ifdef tests here.
+ */
+ atexit(_mesa_destroy_shader_compiler);
+
+ dummy_enum_func();
+}
+
+
+/**
+ * Initialize fields of gl_current_attrib (aka ctx->Current.*)
+ */
+static void
+_mesa_init_current(struct gl_context *ctx)
+{
+ GLuint i;
+
+ /* Init all to (0,0,0,1) */
+ for (i = 0; i < Elements(ctx->Current.Attrib); i++) {
+ ASSIGN_4V( ctx->Current.Attrib[i], 0.0, 0.0, 0.0, 1.0 );
+ }
+
+ /* redo special cases: */
+ ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_WEIGHT], 1.0, 0.0, 0.0, 0.0 );
+ ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_NORMAL], 0.0, 0.0, 1.0, 1.0 );
+ ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR0], 1.0, 1.0, 1.0, 1.0 );
+ ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR1], 0.0, 0.0, 0.0, 1.0 );
+ ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR_INDEX], 1.0, 0.0, 0.0, 1.0 );
+ ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_EDGEFLAG], 1.0, 0.0, 0.0, 1.0 );
+}
+
+
+/**
+ * Init vertex/fragment/geometry program limits.
+ * Important: drivers should override these with actual limits.
+ */
+static void
+init_program_limits(GLenum type, struct gl_program_constants *prog)
+{
+ prog->MaxInstructions = MAX_PROGRAM_INSTRUCTIONS;
+ prog->MaxAluInstructions = MAX_PROGRAM_INSTRUCTIONS;
+ prog->MaxTexInstructions = MAX_PROGRAM_INSTRUCTIONS;
+ prog->MaxTexIndirections = MAX_PROGRAM_INSTRUCTIONS;
+ prog->MaxTemps = MAX_PROGRAM_TEMPS;
+ prog->MaxEnvParams = MAX_PROGRAM_ENV_PARAMS;
+ prog->MaxLocalParams = MAX_PROGRAM_LOCAL_PARAMS;
+ prog->MaxUniformComponents = 4 * MAX_UNIFORMS;
+
+ switch (type) {
+ case GL_VERTEX_PROGRAM_ARB:
+ prog->MaxParameters = MAX_VERTEX_PROGRAM_PARAMS;
+ prog->MaxAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS;
+ prog->MaxAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS;
+ break;
+ case GL_FRAGMENT_PROGRAM_ARB:
+ prog->MaxParameters = MAX_NV_FRAGMENT_PROGRAM_PARAMS;
+ prog->MaxAttribs = MAX_NV_FRAGMENT_PROGRAM_INPUTS;
+ prog->MaxAddressRegs = MAX_FRAGMENT_PROGRAM_ADDRESS_REGS;
+ break;
+ case MESA_GEOMETRY_PROGRAM:
+ prog->MaxParameters = MAX_NV_VERTEX_PROGRAM_PARAMS;
+ prog->MaxAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS;
+ prog->MaxAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS;
+
+ prog->MaxGeometryTextureImageUnits = MAX_GEOMETRY_TEXTURE_IMAGE_UNITS;
+ prog->MaxGeometryVaryingComponents = MAX_GEOMETRY_VARYING_COMPONENTS;
+ prog->MaxVertexVaryingComponents = MAX_VERTEX_VARYING_COMPONENTS;
+ prog->MaxGeometryUniformComponents = MAX_GEOMETRY_UNIFORM_COMPONENTS;
+ prog->MaxGeometryOutputVertices = MAX_GEOMETRY_OUTPUT_VERTICES;
+ prog->MaxGeometryTotalOutputComponents = MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS;
+ break;
+ default:
+ assert(0 && "Bad program type in init_program_limits()");
+ }
+
+ /* Set the native limits to zero. This implies that there is no native
+ * support for shaders. Let the drivers fill in the actual values.
+ */
+ prog->MaxNativeInstructions = 0;
+ prog->MaxNativeAluInstructions = 0;
+ prog->MaxNativeTexInstructions = 0;
+ prog->MaxNativeTexIndirections = 0;
+ prog->MaxNativeAttribs = 0;
+ prog->MaxNativeTemps = 0;
+ prog->MaxNativeAddressRegs = 0;
+ prog->MaxNativeParameters = 0;
+
+ /* Set GLSL datatype range/precision info assuming IEEE float values.
+ * Drivers should override these defaults as needed.
+ */
+ prog->MediumFloat.RangeMin = 127;
+ prog->MediumFloat.RangeMax = 127;
+ prog->MediumFloat.Precision = 23;
+ prog->LowFloat = prog->HighFloat = prog->MediumFloat;
+
+ /* Assume ints are stored as floats for now, since this is the least-common
+ * denominator. The OpenGL ES spec implies (page 132) that the precision
+ * of integer types should be 0. Practically speaking, IEEE
+ * single-precision floating point values can only store integers in the
+ * range [-0x01000000, 0x01000000] without loss of precision.
+ */
+ prog->MediumInt.RangeMin = 24;
+ prog->MediumInt.RangeMax = 24;
+ prog->MediumInt.Precision = 0;
+ prog->LowInt = prog->HighInt = prog->MediumInt;
+}
+
+
+/**
+ * Initialize fields of gl_constants (aka ctx->Const.*).
+ * Use defaults from config.h. The device drivers will often override
+ * some of these values (such as number of texture units).
+ */
+static void
+_mesa_init_constants(struct gl_context *ctx)
+{
+ assert(ctx);
+
+ /* Constants, may be overriden (usually only reduced) by device drivers */
+ ctx->Const.MaxTextureMbytes = MAX_TEXTURE_MBYTES;
+ ctx->Const.MaxTextureLevels = MAX_TEXTURE_LEVELS;
+ ctx->Const.Max3DTextureLevels = MAX_3D_TEXTURE_LEVELS;
+ ctx->Const.MaxCubeTextureLevels = MAX_CUBE_TEXTURE_LEVELS;
+ ctx->Const.MaxTextureRectSize = MAX_TEXTURE_RECT_SIZE;
+ ctx->Const.MaxArrayTextureLayers = MAX_ARRAY_TEXTURE_LAYERS;
+ ctx->Const.MaxTextureCoordUnits = MAX_TEXTURE_COORD_UNITS;
+ ctx->Const.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
+ ctx->Const.MaxTextureUnits = MIN2(ctx->Const.MaxTextureCoordUnits,
+ ctx->Const.MaxTextureImageUnits);
+ ctx->Const.MaxTextureMaxAnisotropy = MAX_TEXTURE_MAX_ANISOTROPY;
+ ctx->Const.MaxTextureLodBias = MAX_TEXTURE_LOD_BIAS;
+ ctx->Const.MaxArrayLockSize = MAX_ARRAY_LOCK_SIZE;
+ ctx->Const.SubPixelBits = SUB_PIXEL_BITS;
+ ctx->Const.MinPointSize = MIN_POINT_SIZE;
+ ctx->Const.MaxPointSize = MAX_POINT_SIZE;
+ ctx->Const.MinPointSizeAA = MIN_POINT_SIZE;
+ ctx->Const.MaxPointSizeAA = MAX_POINT_SIZE;
+ ctx->Const.PointSizeGranularity = (GLfloat) POINT_SIZE_GRANULARITY;
+ ctx->Const.MinLineWidth = MIN_LINE_WIDTH;
+ ctx->Const.MaxLineWidth = MAX_LINE_WIDTH;
+ ctx->Const.MinLineWidthAA = MIN_LINE_WIDTH;
+ ctx->Const.MaxLineWidthAA = MAX_LINE_WIDTH;
+ ctx->Const.LineWidthGranularity = (GLfloat) LINE_WIDTH_GRANULARITY;
+ ctx->Const.MaxColorTableSize = MAX_COLOR_TABLE_SIZE;
+ ctx->Const.MaxClipPlanes = MAX_CLIP_PLANES;
+ ctx->Const.MaxLights = MAX_LIGHTS;
+ ctx->Const.MaxShininess = 128.0;
+ ctx->Const.MaxSpotExponent = 128.0;
+ ctx->Const.MaxViewportWidth = MAX_WIDTH;
+ ctx->Const.MaxViewportHeight = MAX_HEIGHT;
+#if FEATURE_ARB_vertex_program
+ init_program_limits(GL_VERTEX_PROGRAM_ARB, &ctx->Const.VertexProgram);
+#endif
+#if FEATURE_ARB_fragment_program
+ init_program_limits(GL_FRAGMENT_PROGRAM_ARB, &ctx->Const.FragmentProgram);
+#endif
+#if FEATURE_ARB_geometry_shader4
+ init_program_limits(MESA_GEOMETRY_PROGRAM, &ctx->Const.GeometryProgram);
+#endif
+ ctx->Const.MaxProgramMatrices = MAX_PROGRAM_MATRICES;
+ ctx->Const.MaxProgramMatrixStackDepth = MAX_PROGRAM_MATRIX_STACK_DEPTH;
+
+ /* CheckArrayBounds is overriden by drivers/x11 for X server */
+ ctx->Const.CheckArrayBounds = GL_FALSE;
+
+ /* GL_ARB_draw_buffers */
+ ctx->Const.MaxDrawBuffers = MAX_DRAW_BUFFERS;
+
+#if FEATURE_EXT_framebuffer_object
+ ctx->Const.MaxColorAttachments = MAX_COLOR_ATTACHMENTS;
+ ctx->Const.MaxRenderbufferSize = MAX_WIDTH;
+#endif
+
+#if FEATURE_ARB_vertex_shader
+ ctx->Const.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
+ ctx->Const.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
+ ctx->Const.MaxVarying = MAX_VARYING;
+#endif
+
+ /* Shading language version */
+ if (ctx->API == API_OPENGL) {
+ ctx->Const.GLSLVersion = 120;
+ }
+ else if (ctx->API == API_OPENGLES2) {
+ ctx->Const.GLSLVersion = 100;
+ }
+ else if (ctx->API == API_OPENGLES) {
+ ctx->Const.GLSLVersion = 0; /* GLSL not supported */
+ }
+
+ /* GL_ARB_framebuffer_object */
+ ctx->Const.MaxSamples = 0;
+
+ /* GL_ARB_sync */
+ ctx->Const.MaxServerWaitTimeout = (GLuint64) ~0;
+
+ /* GL_ATI_envmap_bumpmap */
+ ctx->Const.SupportedBumpUnits = SUPPORTED_ATI_BUMP_UNITS;
+
+ /* GL_EXT_provoking_vertex */
+ ctx->Const.QuadsFollowProvokingVertexConvention = GL_TRUE;
+
+ /* GL_EXT_transform_feedback */
+ ctx->Const.MaxTransformFeedbackSeparateAttribs = MAX_FEEDBACK_ATTRIBS;
+ ctx->Const.MaxTransformFeedbackSeparateComponents = 4 * MAX_FEEDBACK_ATTRIBS;
+ ctx->Const.MaxTransformFeedbackInterleavedComponents = 4 * MAX_FEEDBACK_ATTRIBS;
+
+ /* GL 3.2: hard-coded for now: */
+ ctx->Const.ProfileMask = GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
+
+ /** GL_EXT_gpu_shader4 */
+ ctx->Const.MinProgramTexelOffset = -8;
+ ctx->Const.MaxProgramTexelOffset = 7;
+}
+
+
+/**
+ * Do some sanity checks on the limits/constants for the given context.
+ * Only called the first time a context is bound.
+ */
+static void
+check_context_limits(struct gl_context *ctx)
+{
+ /* check that we don't exceed the size of various bitfields */
+ assert(VERT_RESULT_MAX <=
+ (8 * sizeof(ctx->VertexProgram._Current->Base.OutputsWritten)));
+ assert(FRAG_ATTRIB_MAX <=
+ (8 * sizeof(ctx->FragmentProgram._Current->Base.InputsRead)));
+
+ assert(MAX_COMBINED_TEXTURE_IMAGE_UNITS <= 8 * sizeof(GLbitfield));
+
+ /* shader-related checks */
+ assert(ctx->Const.FragmentProgram.MaxLocalParams <= MAX_PROGRAM_LOCAL_PARAMS);
+ assert(ctx->Const.VertexProgram.MaxLocalParams <= MAX_PROGRAM_LOCAL_PARAMS);
+
+ assert(MAX_NV_FRAGMENT_PROGRAM_TEMPS <= MAX_PROGRAM_TEMPS);
+ assert(MAX_NV_VERTEX_PROGRAM_TEMPS <= MAX_PROGRAM_TEMPS);
+ assert(MAX_NV_VERTEX_PROGRAM_INPUTS <= VERT_ATTRIB_MAX);
+ assert(MAX_NV_VERTEX_PROGRAM_OUTPUTS <= VERT_RESULT_MAX);
+
+ /* Texture unit checks */
+ assert(ctx->Const.MaxTextureImageUnits > 0);
+ assert(ctx->Const.MaxTextureImageUnits <= MAX_TEXTURE_IMAGE_UNITS);
+ assert(ctx->Const.MaxTextureCoordUnits > 0);
+ assert(ctx->Const.MaxTextureCoordUnits <= MAX_TEXTURE_COORD_UNITS);
+ assert(ctx->Const.MaxTextureUnits > 0);
+ assert(ctx->Const.MaxTextureUnits <= MAX_TEXTURE_IMAGE_UNITS);
+ assert(ctx->Const.MaxTextureUnits <= MAX_TEXTURE_COORD_UNITS);
+ assert(ctx->Const.MaxTextureUnits == MIN2(ctx->Const.MaxTextureImageUnits,
+ ctx->Const.MaxTextureCoordUnits));
+ assert(ctx->Const.MaxCombinedTextureImageUnits > 0);
+ assert(ctx->Const.MaxCombinedTextureImageUnits <= MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+ assert(ctx->Const.MaxTextureCoordUnits <= MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+ /* number of coord units cannot be greater than number of image units */
+ assert(ctx->Const.MaxTextureCoordUnits <= ctx->Const.MaxTextureImageUnits);
+
+
+ /* Texture size checks */
+ assert(ctx->Const.MaxTextureLevels <= MAX_TEXTURE_LEVELS);
+ assert(ctx->Const.Max3DTextureLevels <= MAX_3D_TEXTURE_LEVELS);
+ assert(ctx->Const.MaxCubeTextureLevels <= MAX_CUBE_TEXTURE_LEVELS);
+ assert(ctx->Const.MaxTextureRectSize <= MAX_TEXTURE_RECT_SIZE);
+
+ /* make sure largest texture image is <= MAX_WIDTH in size */
+ assert((1 << (ctx->Const.MaxTextureLevels - 1)) <= MAX_WIDTH);
+ assert((1 << (ctx->Const.MaxCubeTextureLevels - 1)) <= MAX_WIDTH);
+ assert((1 << (ctx->Const.Max3DTextureLevels - 1)) <= MAX_WIDTH);
+
+ /* Texture level checks */
+ assert(MAX_TEXTURE_LEVELS >= MAX_3D_TEXTURE_LEVELS);
+ assert(MAX_TEXTURE_LEVELS >= MAX_CUBE_TEXTURE_LEVELS);
+
+ /* Max texture size should be <= max viewport size (render to texture) */
+ assert((1 << (MAX_TEXTURE_LEVELS - 1)) <= MAX_WIDTH);
+
+ assert(ctx->Const.MaxViewportWidth <= MAX_WIDTH);
+ assert(ctx->Const.MaxViewportHeight <= MAX_WIDTH);
+
+ assert(ctx->Const.MaxDrawBuffers <= MAX_DRAW_BUFFERS);
+
+ /* if this fails, add more enum values to gl_buffer_index */
+ assert(BUFFER_COLOR0 + MAX_DRAW_BUFFERS <= BUFFER_COUNT);
+
+ /* XXX probably add more tests */
+}
+
+
+/**
+ * Initialize the attribute groups in a GL context.
+ *
+ * \param ctx GL context.
+ *
+ * Initializes all the attributes, calling the respective <tt>init*</tt>
+ * functions for the more complex data structures.
+ */
+static GLboolean
+init_attrib_groups(struct gl_context *ctx)
+{
+ assert(ctx);
+
+ /* Constants */
+ _mesa_init_constants( ctx );
+
+ /* Extensions */
+ _mesa_init_extensions( ctx );
+
+ /* Attribute Groups */
+ _mesa_init_accum( ctx );
+ _mesa_init_attrib( ctx );
+ _mesa_init_buffer_objects( ctx );
+ _mesa_init_color( ctx );
+ _mesa_init_current( ctx );
+ _mesa_init_depth( ctx );
+ _mesa_init_debug( ctx );
+ _mesa_init_display_list( ctx );
+ _mesa_init_eval( ctx );
+ _mesa_init_fbobjects( ctx );
+ _mesa_init_feedback( ctx );
+ _mesa_init_fog( ctx );
+ _mesa_init_hint( ctx );
+ _mesa_init_line( ctx );
+ _mesa_init_lighting( ctx );
+ _mesa_init_matrix( ctx );
+ _mesa_init_multisample( ctx );
+ _mesa_init_pixel( ctx );
+ _mesa_init_pixelstore( ctx );
+ _mesa_init_point( ctx );
+ _mesa_init_polygon( ctx );
+ _mesa_init_program( ctx );
+ _mesa_init_queryobj( ctx );
+ _mesa_init_sync( ctx );
+ _mesa_init_rastpos( ctx );
+ _mesa_init_scissor( ctx );
+ _mesa_init_shader_state( ctx );
+ _mesa_init_stencil( ctx );
+ _mesa_init_transform( ctx );
+ _mesa_init_transform_feedback( ctx );
+ _mesa_init_varray( ctx );
+ _mesa_init_viewport( ctx );
+
+ if (!_mesa_init_texture( ctx ))
+ return GL_FALSE;
+
+ _mesa_init_texture_s3tc( ctx );
+
+ /* Miscellaneous */
+ ctx->NewState = _NEW_ALL;
+ ctx->ErrorValue = (GLenum) GL_NO_ERROR;
+ ctx->varying_vp_inputs = ~0;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Update default objects in a GL context with respect to shared state.
+ *
+ * \param ctx GL context.
+ *
+ * Removes references to old default objects, (texture objects, program
+ * objects, etc.) and changes to reference those from the current shared
+ * state.
+ */
+static GLboolean
+update_default_objects(struct gl_context *ctx)
+{
+ assert(ctx);
+
+ _mesa_update_default_objects_program(ctx);
+ _mesa_update_default_objects_texture(ctx);
+ _mesa_update_default_objects_buffer_objects(ctx);
+
+ return GL_TRUE;
+}
+
+
+/**
+ * This is the default function we plug into all dispatch table slots
+ * This helps prevents a segfault when someone calls a GL function without
+ * first checking if the extension's supported.
+ */
+static int
+generic_nop(void)
+{
+ _mesa_warning(NULL, "User called no-op dispatch function (an unsupported extension function?)");
+ return 0;
+}
+
+
+/**
+ * Allocate and initialize a new dispatch table.
+ */
+struct _glapi_table *
+_mesa_alloc_dispatch_table(int size)
+{
+ /* Find the larger of Mesa's dispatch table and libGL's dispatch table.
+ * In practice, this'll be the same for stand-alone Mesa. But for DRI
+ * Mesa we do this to accomodate different versions of libGL and various
+ * DRI drivers.
+ */
+ GLint numEntries = MAX2(_glapi_get_dispatch_table_size(), _gloffset_COUNT);
+ struct _glapi_table *table;
+
+ /* should never happen, but just in case */
+ numEntries = MAX2(numEntries, size);
+
+ table = (struct _glapi_table *) malloc(numEntries * sizeof(_glapi_proc));
+ if (table) {
+ _glapi_proc *entry = (_glapi_proc *) table;
+ GLint i;
+ for (i = 0; i < numEntries; i++) {
+ entry[i] = (_glapi_proc) generic_nop;
+ }
+ }
+ return table;
+}
+
+
+/**
+ * Initialize a struct gl_context struct (rendering context).
+ *
+ * This includes allocating all the other structs and arrays which hang off of
+ * the context by pointers.
+ * Note that the driver needs to pass in its dd_function_table here since
+ * we need to at least call driverFunctions->NewTextureObject to create the
+ * default texture objects.
+ *
+ * Called by _mesa_create_context().
+ *
+ * Performs the imports and exports callback tables initialization, and
+ * miscellaneous one-time initializations. If no shared context is supplied one
+ * is allocated, and increase its reference count. Setups the GL API dispatch
+ * tables. Initialize the TNL module. Sets the maximum Z buffer depth.
+ * Finally queries the \c MESA_DEBUG and \c MESA_VERBOSE environment variables
+ * for debug flags.
+ *
+ * \param ctx the context to initialize
+ * \param api the GL API type to create the context for
+ * \param visual describes the visual attributes for this context
+ * \param share_list points to context to share textures, display lists,
+ * etc with, or NULL
+ * \param driverFunctions table of device driver functions for this context
+ * to use
+ * \param driverContext pointer to driver-specific context data
+ */
+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)
+{
+ struct gl_shared_state *shared;
+ int i;
+
+ /*ASSERT(driverContext);*/
+ assert(driverFunctions->NewTextureObject);
+ assert(driverFunctions->FreeTexImageData);
+
+ ctx->API = api;
+ ctx->Visual = *visual;
+ ctx->DrawBuffer = NULL;
+ ctx->ReadBuffer = NULL;
+ ctx->WinSysDrawBuffer = NULL;
+ ctx->WinSysReadBuffer = NULL;
+
+ /* misc one-time initializations */
+ one_time_init(ctx);
+
+ /* Plug in driver functions and context pointer here.
+ * This is important because when we call alloc_shared_state() below
+ * we'll call ctx->Driver.NewTextureObject() to create the default
+ * textures.
+ */
+ ctx->Driver = *driverFunctions;
+ ctx->DriverCtx = driverContext;
+
+ if (share_list) {
+ /* share state with another context */
+ shared = share_list->Shared;
+ }
+ else {
+ /* allocate new, unshared state */
+ shared = _mesa_alloc_shared_state(ctx);
+ if (!shared)
+ return GL_FALSE;
+ }
+
+ _glthread_LOCK_MUTEX(shared->Mutex);
+ ctx->Shared = shared;
+ shared->RefCount++;
+ _glthread_UNLOCK_MUTEX(shared->Mutex);
+
+ if (!init_attrib_groups( ctx )) {
+ _mesa_release_shared_state(ctx, ctx->Shared);
+ return GL_FALSE;
+ }
+
+#if FEATURE_dispatch
+ /* setup the API dispatch tables */
+ switch (ctx->API) {
+#if FEATURE_GL
+ case API_OPENGL:
+ ctx->Exec = _mesa_create_exec_table();
+ break;
+#endif
+#if FEATURE_ES1
+ case API_OPENGLES:
+ ctx->Exec = _mesa_create_exec_table_es1();
+ break;
+#endif
+#if FEATURE_ES2
+ case API_OPENGLES2:
+ ctx->Exec = _mesa_create_exec_table_es2();
+ break;
+#endif
+ default:
+ _mesa_problem(ctx, "unknown or unsupported API");
+ break;
+ }
+
+ if (!ctx->Exec) {
+ _mesa_release_shared_state(ctx, ctx->Shared);
+ return GL_FALSE;
+ }
+#endif
+ ctx->CurrentDispatch = ctx->Exec;
+
+ ctx->FragmentProgram._MaintainTexEnvProgram
+ = (_mesa_getenv("MESA_TEX_PROG") != NULL);
+
+ ctx->VertexProgram._MaintainTnlProgram
+ = (_mesa_getenv("MESA_TNL_PROG") != NULL);
+ if (ctx->VertexProgram._MaintainTnlProgram) {
+ /* this is required... */
+ ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;
+ }
+
+ /* Mesa core handles all the formats that mesa core knows about.
+ * Drivers will want to override this list with just the formats
+ * they can handle, and confirm that appropriate fallbacks exist in
+ * _mesa_choose_tex_format().
+ */
+ memset(&ctx->TextureFormatSupported, GL_TRUE,
+ sizeof(ctx->TextureFormatSupported));
+
+ switch (ctx->API) {
+ case API_OPENGL:
+#if FEATURE_dlist
+ ctx->Save = _mesa_create_save_table();
+ if (!ctx->Save) {
+ _mesa_release_shared_state(ctx, ctx->Shared);
+ free(ctx->Exec);
+ return GL_FALSE;
+ }
+
+ _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
+#endif
+ break;
+ case API_OPENGLES:
+ /**
+ * GL_OES_texture_cube_map says
+ * "Initially all texture generation modes are set to REFLECTION_MAP_OES"
+ */
+ for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
+ texUnit->GenS.Mode = GL_REFLECTION_MAP_NV;
+ texUnit->GenT.Mode = GL_REFLECTION_MAP_NV;
+ texUnit->GenR.Mode = GL_REFLECTION_MAP_NV;
+ texUnit->GenS._ModeBit = TEXGEN_REFLECTION_MAP_NV;
+ texUnit->GenT._ModeBit = TEXGEN_REFLECTION_MAP_NV;
+ texUnit->GenR._ModeBit = TEXGEN_REFLECTION_MAP_NV;
+ }
+ break;
+ case API_OPENGLES2:
+ ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;
+ ctx->VertexProgram._MaintainTnlProgram = GL_TRUE;
+ ctx->Point.PointSprite = GL_TRUE; /* always on for ES 2.x */
+ break;
+ }
+
+ ctx->FirstTimeCurrent = GL_TRUE;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Allocate and initialize a struct gl_context structure.
+ * Note that the driver needs to pass in its dd_function_table here since
+ * we need to at least call driverFunctions->NewTextureObject to initialize
+ * the rendering context.
+ *
+ * \param api the GL API type to create the context for
+ * \param visual a struct gl_config pointer (we copy the struct contents)
+ * \param share_list another context to share display lists with or NULL
+ * \param driverFunctions points to the dd_function_table into which the
+ * driver has plugged in all its special functions.
+ * \param driverContext points to the device driver's private context state
+ *
+ * \return pointer to a new __struct gl_contextRec or NULL if error.
+ */
+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)
+{
+ struct gl_context *ctx;
+
+ ASSERT(visual);
+ /*ASSERT(driverContext);*/
+
+ ctx = (struct gl_context *) calloc(1, sizeof(struct gl_context));
+ if (!ctx)
+ return NULL;
+
+ if (_mesa_initialize_context(ctx, api, visual, share_list,
+ driverFunctions, driverContext)) {
+ return ctx;
+ }
+ else {
+ free(ctx);
+ return NULL;
+ }
+}
+
+
+/**
+ * Free the data associated with the given context.
+ *
+ * But doesn't free the struct gl_context struct itself.
+ *
+ * \sa _mesa_initialize_context() and init_attrib_groups().
+ */
+void
+_mesa_free_context_data( struct gl_context *ctx )
+{
+ if (!_mesa_get_current_context()){
+ /* No current context, but we may need one in order to delete
+ * texture objs, etc. So temporarily bind the context now.
+ */
+ _mesa_make_current(ctx, NULL, NULL);
+ }
+
+ /* unreference WinSysDraw/Read buffers */
+ _mesa_reference_framebuffer(&ctx->WinSysDrawBuffer, NULL);
+ _mesa_reference_framebuffer(&ctx->WinSysReadBuffer, NULL);
+ _mesa_reference_framebuffer(&ctx->DrawBuffer, NULL);
+ _mesa_reference_framebuffer(&ctx->ReadBuffer, NULL);
+
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL);
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current, NULL);
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram._TnlProgram, NULL);
+
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL);
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, NULL);
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram, NULL);
+
+ _mesa_free_attrib_data(ctx);
+ _mesa_free_buffer_objects(ctx);
+ _mesa_free_lighting_data( ctx );
+ _mesa_free_eval_data( ctx );
+ _mesa_free_texture_data( ctx );
+ _mesa_free_matrix_data( ctx );
+ _mesa_free_viewport_data( ctx );
+ _mesa_free_program_data(ctx);
+ _mesa_free_shader_state(ctx);
+ _mesa_free_queryobj_data(ctx);
+ _mesa_free_sync_data(ctx);
+ _mesa_free_varray_data(ctx);
+ _mesa_free_transform_feedback(ctx);
+
+ _mesa_delete_array_object(ctx, ctx->Array.DefaultArrayObj);
+
+#if FEATURE_ARB_pixel_buffer_object
+ _mesa_reference_buffer_object(ctx, &ctx->Pack.BufferObj, NULL);
+ _mesa_reference_buffer_object(ctx, &ctx->Unpack.BufferObj, NULL);
+ _mesa_reference_buffer_object(ctx, &ctx->DefaultPacking.BufferObj, NULL);
+#endif
+
+#if FEATURE_ARB_vertex_buffer_object
+ _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL);
+ _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL);
+#endif
+
+ /* free dispatch tables */
+ free(ctx->Exec);
+ free(ctx->Save);
+
+ /* Shared context state (display lists, textures, etc) */
+ _mesa_release_shared_state( ctx, ctx->Shared );
+
+ /* needs to be after freeing shared state */
+ _mesa_free_display_list_data(ctx);
+
+ if (ctx->Extensions.String)
+ free((void *) ctx->Extensions.String);
+
+ if (ctx->VersionString)
+ free(ctx->VersionString);
+
+ /* unbind the context if it's currently bound */
+ if (ctx == _mesa_get_current_context()) {
+ _mesa_make_current(NULL, NULL, NULL);
+ }
+}
+
+
+/**
+ * Destroy a struct gl_context structure.
+ *
+ * \param ctx GL context.
+ *
+ * Calls _mesa_free_context_data() and frees the gl_context object itself.
+ */
+void
+_mesa_destroy_context( struct gl_context *ctx )
+{
+ if (ctx) {
+ _mesa_free_context_data(ctx);
+ free( (void *) ctx );
+ }
+}
+
+
+#if _HAVE_FULL_GL
+/**
+ * Copy attribute groups from one context to another.
+ *
+ * \param src source context
+ * \param dst destination context
+ * \param mask bitwise OR of GL_*_BIT flags
+ *
+ * According to the bits specified in \p mask, copies the corresponding
+ * attributes from \p src into \p dst. For many of the attributes a simple \c
+ * memcpy is not enough due to the existence of internal pointers in their data
+ * structures.
+ */
+void
+_mesa_copy_context( const struct gl_context *src, struct gl_context *dst, GLuint mask )
+{
+ if (mask & GL_ACCUM_BUFFER_BIT) {
+ /* OK to memcpy */
+ dst->Accum = src->Accum;
+ }
+ if (mask & GL_COLOR_BUFFER_BIT) {
+ /* OK to memcpy */
+ dst->Color = src->Color;
+ }
+ if (mask & GL_CURRENT_BIT) {
+ /* OK to memcpy */
+ dst->Current = src->Current;
+ }
+ if (mask & GL_DEPTH_BUFFER_BIT) {
+ /* OK to memcpy */
+ dst->Depth = src->Depth;
+ }
+ if (mask & GL_ENABLE_BIT) {
+ /* no op */
+ }
+ if (mask & GL_EVAL_BIT) {
+ /* OK to memcpy */
+ dst->Eval = src->Eval;
+ }
+ if (mask & GL_FOG_BIT) {
+ /* OK to memcpy */
+ dst->Fog = src->Fog;
+ }
+ if (mask & GL_HINT_BIT) {
+ /* OK to memcpy */
+ dst->Hint = src->Hint;
+ }
+ if (mask & GL_LIGHTING_BIT) {
+ GLuint i;
+ /* begin with memcpy */
+ dst->Light = src->Light;
+ /* fixup linked lists to prevent pointer insanity */
+ make_empty_list( &(dst->Light.EnabledList) );
+ for (i = 0; i < MAX_LIGHTS; i++) {
+ if (dst->Light.Light[i].Enabled) {
+ insert_at_tail(&(dst->Light.EnabledList), &(dst->Light.Light[i]));
+ }
+ }
+ }
+ if (mask & GL_LINE_BIT) {
+ /* OK to memcpy */
+ dst->Line = src->Line;
+ }
+ if (mask & GL_LIST_BIT) {
+ /* OK to memcpy */
+ dst->List = src->List;
+ }
+ if (mask & GL_PIXEL_MODE_BIT) {
+ /* OK to memcpy */
+ dst->Pixel = src->Pixel;
+ }
+ if (mask & GL_POINT_BIT) {
+ /* OK to memcpy */
+ dst->Point = src->Point;
+ }
+ if (mask & GL_POLYGON_BIT) {
+ /* OK to memcpy */
+ dst->Polygon = src->Polygon;
+ }
+ if (mask & GL_POLYGON_STIPPLE_BIT) {
+ /* Use loop instead of memcpy due to problem with Portland Group's
+ * C compiler. Reported by John Stone.
+ */
+ GLuint i;
+ for (i = 0; i < 32; i++) {
+ dst->PolygonStipple[i] = src->PolygonStipple[i];
+ }
+ }
+ if (mask & GL_SCISSOR_BIT) {
+ /* OK to memcpy */
+ dst->Scissor = src->Scissor;
+ }
+ if (mask & GL_STENCIL_BUFFER_BIT) {
+ /* OK to memcpy */
+ dst->Stencil = src->Stencil;
+ }
+ if (mask & GL_TEXTURE_BIT) {
+ /* Cannot memcpy because of pointers */
+ _mesa_copy_texture_state(src, dst);
+ }
+ if (mask & GL_TRANSFORM_BIT) {
+ /* OK to memcpy */
+ dst->Transform = src->Transform;
+ }
+ if (mask & GL_VIEWPORT_BIT) {
+ /* Cannot use memcpy, because of pointers in GLmatrix _WindowMap */
+ dst->Viewport.X = src->Viewport.X;
+ dst->Viewport.Y = src->Viewport.Y;
+ dst->Viewport.Width = src->Viewport.Width;
+ dst->Viewport.Height = src->Viewport.Height;
+ dst->Viewport.Near = src->Viewport.Near;
+ dst->Viewport.Far = src->Viewport.Far;
+ _math_matrix_copy(&dst->Viewport._WindowMap, &src->Viewport._WindowMap);
+ }
+
+ /* XXX FIXME: Call callbacks?
+ */
+ dst->NewState = _NEW_ALL;
+}
+#endif
+
+
+/**
+ * Check if the given context can render into the given framebuffer
+ * by checking visual attributes.
+ *
+ * Most of these tests could go away because Mesa is now pretty flexible
+ * in terms of mixing rendering contexts with framebuffers. As long
+ * as RGB vs. CI mode agree, we're probably good.
+ *
+ * \return GL_TRUE if compatible, GL_FALSE otherwise.
+ */
+static GLboolean
+check_compatible(const struct gl_context *ctx,
+ const struct gl_framebuffer *buffer)
+{
+ const struct gl_config *ctxvis = &ctx->Visual;
+ const struct gl_config *bufvis = &buffer->Visual;
+
+ if (buffer == _mesa_get_incomplete_framebuffer())
+ return GL_TRUE;
+
+#if 0
+ /* disabling this fixes the fgl_glxgears pbuffer demo */
+ if (ctxvis->doubleBufferMode && !bufvis->doubleBufferMode)
+ return GL_FALSE;
+#endif
+ if (ctxvis->stereoMode && !bufvis->stereoMode)
+ return GL_FALSE;
+ if (ctxvis->haveAccumBuffer && !bufvis->haveAccumBuffer)
+ return GL_FALSE;
+ if (ctxvis->haveDepthBuffer && !bufvis->haveDepthBuffer)
+ return GL_FALSE;
+ if (ctxvis->haveStencilBuffer && !bufvis->haveStencilBuffer)
+ return GL_FALSE;
+ if (ctxvis->redMask && ctxvis->redMask != bufvis->redMask)
+ return GL_FALSE;
+ if (ctxvis->greenMask && ctxvis->greenMask != bufvis->greenMask)
+ return GL_FALSE;
+ if (ctxvis->blueMask && ctxvis->blueMask != bufvis->blueMask)
+ return GL_FALSE;
+#if 0
+ /* disabled (see bug 11161) */
+ if (ctxvis->depthBits && ctxvis->depthBits != bufvis->depthBits)
+ return GL_FALSE;
+#endif
+ if (ctxvis->stencilBits && ctxvis->stencilBits != bufvis->stencilBits)
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Do one-time initialization for the given framebuffer. Specifically,
+ * ask the driver for the window's current size and update the framebuffer
+ * object to match.
+ * Really, the device driver should totally take care of this.
+ */
+static void
+initialize_framebuffer_size(struct gl_context *ctx, struct gl_framebuffer *fb)
+{
+ GLuint width, height;
+ if (ctx->Driver.GetBufferSize) {
+ ctx->Driver.GetBufferSize(fb, &width, &height);
+ if (ctx->Driver.ResizeBuffers)
+ ctx->Driver.ResizeBuffers(ctx, fb, width, height);
+ fb->Initialized = GL_TRUE;
+ }
+}
+
+
+/**
+ * Check if the viewport/scissor size has not yet been initialized.
+ * Initialize the size if the given width and height are non-zero.
+ */
+void
+_mesa_check_init_viewport(struct gl_context *ctx, GLuint width, GLuint height)
+{
+ if (!ctx->ViewportInitialized && width > 0 && height > 0) {
+ /* Note: set flag here, before calling _mesa_set_viewport(), to prevent
+ * potential infinite recursion.
+ */
+ ctx->ViewportInitialized = GL_TRUE;
+ _mesa_set_viewport(ctx, 0, 0, width, height);
+ _mesa_set_scissor(ctx, 0, 0, width, height);
+ }
+}
+
+
+/**
+ * Bind the given context to the given drawBuffer and readBuffer and
+ * make it the current context for the calling thread.
+ * We'll render into the drawBuffer and read pixels from the
+ * readBuffer (i.e. glRead/CopyPixels, glCopyTexImage, etc).
+ *
+ * We check that the context's and framebuffer's visuals are compatible
+ * and return immediately if they're not.
+ *
+ * \param newCtx the new GL context. If NULL then there will be no current GL
+ * context.
+ * \param drawBuffer the drawing framebuffer
+ * \param readBuffer the reading framebuffer
+ */
+GLboolean
+_mesa_make_current( struct gl_context *newCtx,
+ struct gl_framebuffer *drawBuffer,
+ struct gl_framebuffer *readBuffer )
+{
+ GET_CURRENT_CONTEXT(curCtx);
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(newCtx, "_mesa_make_current()\n");
+
+ /* Check that the context's and framebuffer's visuals are compatible.
+ */
+ if (newCtx && drawBuffer && newCtx->WinSysDrawBuffer != drawBuffer) {
+ if (!check_compatible(newCtx, drawBuffer)) {
+ _mesa_warning(newCtx,
+ "MakeCurrent: incompatible visuals for context and drawbuffer");
+ return GL_FALSE;
+ }
+ }
+ if (newCtx && readBuffer && newCtx->WinSysReadBuffer != readBuffer) {
+ if (!check_compatible(newCtx, readBuffer)) {
+ _mesa_warning(newCtx,
+ "MakeCurrent: incompatible visuals for context and readbuffer");
+ return GL_FALSE;
+ }
+ }
+
+ if (curCtx &&
+ (curCtx->WinSysDrawBuffer || curCtx->WinSysReadBuffer) && /* make sure this context is valid for flushing */
+ curCtx != newCtx)
+ _mesa_flush(curCtx);
+
+ /* We used to call _glapi_check_multithread() here. Now do it in drivers */
+ _glapi_set_context((void *) newCtx);
+ ASSERT(_mesa_get_current_context() == newCtx);
+
+ if (!newCtx) {
+ _glapi_set_dispatch(NULL); /* none current */
+ }
+ else {
+ _glapi_set_dispatch(newCtx->CurrentDispatch);
+
+ if (drawBuffer && readBuffer) {
+ /* TODO: check if newCtx and buffer's visual match??? */
+
+ ASSERT(drawBuffer->Name == 0);
+ ASSERT(readBuffer->Name == 0);
+ _mesa_reference_framebuffer(&newCtx->WinSysDrawBuffer, drawBuffer);
+ _mesa_reference_framebuffer(&newCtx->WinSysReadBuffer, readBuffer);
+
+ /*
+ * Only set the context's Draw/ReadBuffer fields if they're NULL
+ * or not bound to a user-created FBO.
+ */
+ if (!newCtx->DrawBuffer || newCtx->DrawBuffer->Name == 0) {
+ /* KW: merge conflict here, revisit.
+ */
+ /* fix up the fb fields - these will end up wrong otherwise
+ * if the DRIdrawable changes, and everything relies on them.
+ * This is a bit messy (same as needed in _mesa_BindFramebufferEXT)
+ */
+ unsigned int i;
+ GLenum buffers[MAX_DRAW_BUFFERS];
+
+ _mesa_reference_framebuffer(&newCtx->DrawBuffer, drawBuffer);
+
+ for(i = 0; i < newCtx->Const.MaxDrawBuffers; i++) {
+ buffers[i] = newCtx->Color.DrawBuffer[i];
+ }
+
+ _mesa_drawbuffers(newCtx, newCtx->Const.MaxDrawBuffers,
+ buffers, NULL);
+ }
+ if (!newCtx->ReadBuffer || newCtx->ReadBuffer->Name == 0) {
+ _mesa_reference_framebuffer(&newCtx->ReadBuffer, readBuffer);
+ }
+
+ /* XXX only set this flag if we're really changing the draw/read
+ * framebuffer bindings.
+ */
+ newCtx->NewState |= _NEW_BUFFERS;
+
+#if 1
+ /* We want to get rid of these lines: */
+
+#if _HAVE_FULL_GL
+ if (!drawBuffer->Initialized) {
+ initialize_framebuffer_size(newCtx, drawBuffer);
+ }
+ if (readBuffer != drawBuffer && !readBuffer->Initialized) {
+ initialize_framebuffer_size(newCtx, readBuffer);
+ }
+
+ _mesa_resizebuffers(newCtx);
+#endif
+
+#else
+ /* We want the drawBuffer and readBuffer to be initialized by
+ * the driver.
+ * This generally means the Width and Height match the actual
+ * window size and the renderbuffers (both hardware and software
+ * based) are allocated to match. The later can generally be
+ * done with a call to _mesa_resize_framebuffer().
+ *
+ * It's theoretically possible for a buffer to have zero width
+ * or height, but for now, assert check that the driver did what's
+ * expected of it.
+ */
+ ASSERT(drawBuffer->Width > 0);
+ ASSERT(drawBuffer->Height > 0);
+#endif
+
+ if (drawBuffer) {
+ _mesa_check_init_viewport(newCtx,
+ drawBuffer->Width, drawBuffer->Height);
+ }
+ }
+
+ if (newCtx->FirstTimeCurrent) {
+ _mesa_compute_version(newCtx);
+
+ newCtx->Extensions.String = _mesa_make_extension_string(newCtx);
+
+ check_context_limits(newCtx);
+
+ /* We can use this to help debug user's problems. Tell them to set
+ * the MESA_INFO env variable before running their app. Then the
+ * first time each context is made current we'll print some useful
+ * information.
+ */
+ if (_mesa_getenv("MESA_INFO")) {
+ _mesa_print_info();
+ }
+
+ newCtx->FirstTimeCurrent = GL_FALSE;
+ }
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Make context 'ctx' share the display lists, textures and programs
+ * that are associated with 'ctxToShare'.
+ * Any display lists, textures or programs associated with 'ctx' will
+ * be deleted if nobody else is sharing them.
+ */
+GLboolean
+_mesa_share_state(struct gl_context *ctx, struct gl_context *ctxToShare)
+{
+ if (ctx && ctxToShare && ctx->Shared && ctxToShare->Shared) {
+ struct gl_shared_state *oldSharedState = ctx->Shared;
+
+ ctx->Shared = ctxToShare->Shared;
+
+ _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+ ctx->Shared->RefCount++;
+ _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+
+ update_default_objects(ctx);
+
+ _mesa_release_shared_state(ctx, oldSharedState);
+
+ return GL_TRUE;
+ }
+ else {
+ return GL_FALSE;
+ }
+}
+
+
+
+/**
+ * \return pointer to the current GL context for this thread.
+ *
+ * Calls _glapi_get_context(). This isn't the fastest way to get the current
+ * context. If you need speed, see the #GET_CURRENT_CONTEXT macro in
+ * context.h.
+ */
+struct gl_context *
+_mesa_get_current_context( void )
+{
+ return (struct gl_context *) _glapi_get_context();
+}
+
+
+/**
+ * Get context's current API dispatch table.
+ *
+ * It'll either be the immediate-mode execute dispatcher or the display list
+ * compile dispatcher.
+ *
+ * \param ctx GL context.
+ *
+ * \return pointer to dispatch_table.
+ *
+ * Simply returns __struct gl_contextRec::CurrentDispatch.
+ */
+struct _glapi_table *
+_mesa_get_dispatch(struct gl_context *ctx)
+{
+ return ctx->CurrentDispatch;
+}
+
+/*@}*/
+
+
+/**********************************************************************/
+/** \name Miscellaneous functions */
+/**********************************************************************/
+/*@{*/
+
+/**
+ * Record an error.
+ *
+ * \param ctx GL context.
+ * \param error error code.
+ *
+ * Records the given error code and call the driver's dd_function_table::Error
+ * function if defined.
+ *
+ * \sa
+ * This is called via _mesa_error().
+ */
+void
+_mesa_record_error(struct gl_context *ctx, GLenum error)
+{
+ if (!ctx)
+ return;
+
+ if (ctx->ErrorValue == GL_NO_ERROR) {
+ ctx->ErrorValue = error;
+ }
+
+ /* Call device driver's error handler, if any. This is used on the Mac. */
+ if (ctx->Driver.Error) {
+ ctx->Driver.Error(ctx);
+ }
+}
+
+
+/**
+ * Flush commands and wait for completion.
+ */
+void
+_mesa_finish(struct gl_context *ctx)
+{
+ FLUSH_CURRENT( ctx, 0 );
+ if (ctx->Driver.Finish) {
+ ctx->Driver.Finish(ctx);
+ }
+}
+
+
+/**
+ * Flush commands.
+ */
+void
+_mesa_flush(struct gl_context *ctx)
+{
+ FLUSH_CURRENT( ctx, 0 );
+ if (ctx->Driver.Flush) {
+ ctx->Driver.Flush(ctx);
+ }
+}
+
+
+
+/**
+ * Execute glFinish().
+ *
+ * Calls the #ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH macro and the
+ * dd_function_table::Finish driver callback, if not NULL.
+ */
+void GLAPIENTRY
+_mesa_Finish(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+ _mesa_finish(ctx);
+}
+
+
+/**
+ * Execute glFlush().
+ *
+ * Calls the #ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH macro and the
+ * dd_function_table::Flush driver callback, if not NULL.
+ */
+void GLAPIENTRY
+_mesa_Flush(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+ _mesa_flush(ctx);
+}
+
+
+/**
+ * Set mvp_with_dp4 flag. If a driver has a preference for DP4 over
+ * MUL/MAD, or vice versa, call this function to register that.
+ * Otherwise we default to MUL/MAD.
+ */
+void
+_mesa_set_mvp_with_dp4( struct gl_context *ctx,
+ GLboolean flag )
+{
+ ctx->mvp_with_dp4 = flag;
+}
+
+
+
+/**
+ * Prior to drawing anything with glBegin, glDrawArrays, etc. this function
+ * is called to see if it's valid to render. This involves checking that
+ * the current shader is valid and the framebuffer is complete.
+ * If an error is detected it'll be recorded here.
+ * \return GL_TRUE if OK to render, GL_FALSE if not
+ */
+GLboolean
+_mesa_valid_to_render(struct gl_context *ctx, const char *where)
+{
+ bool vert_from_glsl_shader = false;
+ bool geom_from_glsl_shader = false;
+ bool frag_from_glsl_shader = false;
+
+ /* This depends on having up to date derived state (shaders) */
+ if (ctx->NewState)
+ _mesa_update_state(ctx);
+
+ if (ctx->Shader.CurrentVertexProgram) {
+ vert_from_glsl_shader = true;
+
+ if (!ctx->Shader.CurrentVertexProgram->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(shader not linked)", where);
+ return GL_FALSE;
+ }
+#if 0 /* not normally enabled */
+ {
+ char errMsg[100];
+ if (!_mesa_validate_shader_program(ctx,
+ ctx->Shader.CurrentVertexProgram,
+ errMsg)) {
+ _mesa_warning(ctx, "Shader program %u is invalid: %s",
+ ctx->Shader.CurrentVertexProgram->Name, errMsg);
+ }
+ }
+#endif
+ }
+
+ if (ctx->Shader.CurrentGeometryProgram) {
+ geom_from_glsl_shader = true;
+
+ if (!ctx->Shader.CurrentGeometryProgram->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(shader not linked)", where);
+ return GL_FALSE;
+ }
+#if 0 /* not normally enabled */
+ {
+ char errMsg[100];
+ if (!_mesa_validate_shader_program(ctx,
+ ctx->Shader.CurrentGeometryProgram,
+ errMsg)) {
+ _mesa_warning(ctx, "Shader program %u is invalid: %s",
+ ctx->Shader.CurrentGeometryProgram->Name, errMsg);
+ }
+ }
+#endif
+ }
+
+ if (ctx->Shader.CurrentFragmentProgram) {
+ frag_from_glsl_shader = true;
+
+ if (!ctx->Shader.CurrentFragmentProgram->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(shader not linked)", where);
+ return GL_FALSE;
+ }
+#if 0 /* not normally enabled */
+ {
+ char errMsg[100];
+ if (!_mesa_validate_shader_program(ctx,
+ ctx->Shader.CurrentFragmentProgram,
+ errMsg)) {
+ _mesa_warning(ctx, "Shader program %u is invalid: %s",
+ ctx->Shader.CurrentFragmentProgram->Name, errMsg);
+ }
+ }
+#endif
+ }
+
+ /* Any shader stages that are not supplied by the GLSL shader and have
+ * assembly shaders enabled must now be validated.
+ */
+ if (!vert_from_glsl_shader
+ && ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(vertex program not valid)", where);
+ return GL_FALSE;
+ }
+
+ /* FINISHME: If GL_NV_geometry_program4 is ever supported, the current
+ * FINISHME: geometry program should validated here.
+ */
+ (void) geom_from_glsl_shader;
+
+ if (!frag_from_glsl_shader) {
+ if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(fragment program not valid)", where);
+ return GL_FALSE;
+ }
+
+ /* If drawing to integer-valued color buffers, there must be an
+ * active fragment shader (GL_EXT_texture_integer).
+ */
+ if (ctx->DrawBuffer && ctx->DrawBuffer->_IntegerColor) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(integer format but no fragment shader)", where);
+ return GL_FALSE;
+ }
+ }
+
+ if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
+ "%s(incomplete framebuffer)", where);
+ return GL_FALSE;
+ }
+
+#ifdef DEBUG
+ if (ctx->Shader.Flags & GLSL_LOG) {
+ struct gl_shader_program *shProg[MESA_SHADER_TYPES];
+ gl_shader_type i;
+
+ shProg[MESA_SHADER_VERTEX] = ctx->Shader.CurrentVertexProgram;
+ shProg[MESA_SHADER_GEOMETRY] = ctx->Shader.CurrentGeometryProgram;
+ shProg[MESA_SHADER_FRAGMENT] = ctx->Shader.CurrentFragmentProgram;
+
+ for (i = 0; i < MESA_SHADER_TYPES; i++) {
+ struct gl_shader *sh;
+
+ if (shProg[i] == NULL || shProg[i]->_Used
+ || shProg[i]->_LinkedShaders[i] == NULL)
+ continue;
+
+ /* This is the first time this shader is being used.
+ * Append shader's constants/uniforms to log file.
+ *
+ * The logic is a little odd here. We only want to log data for each
+ * shader target that will actually be used, and we only want to log
+ * it once. It's possible to have a program bound to the vertex
+ * shader target that also supplied a fragment shader. If that
+ * program isn't also bound to the fragment shader target we don't
+ * want to log its fragment data.
+ */
+ sh = shProg[i]->_LinkedShaders[i];
+ switch (sh->Type) {
+ case GL_VERTEX_SHADER:
+ _mesa_append_uniforms_to_file(sh, &shProg[i]->VertexProgram->Base);
+ break;
+
+ case GL_GEOMETRY_SHADER_ARB:
+ _mesa_append_uniforms_to_file(sh,
+ &shProg[i]->GeometryProgram->Base);
+ break;
+
+ case GL_FRAGMENT_SHADER:
+ _mesa_append_uniforms_to_file(sh,
+ &shProg[i]->FragmentProgram->Base);
+ break;
+ }
+ }
+
+ for (i = 0; i < MESA_SHADER_TYPES; i++) {
+ if (shProg[i] != NULL)
+ shProg[i]->_Used = GL_TRUE;
+ }
+ }
+#endif
+
+ return GL_TRUE;
+}
+
+
+/*@}*/
diff --git a/mesalib/src/mesa/main/context.h b/mesalib/src/mesa/main/context.h
index 4e391dde4..160e795f7 100644
--- a/mesalib/src/mesa/main/context.h
+++ b/mesalib/src/mesa/main/context.h
@@ -1,313 +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 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 */
+/*
+ * 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 52c69a6bc..d666ed5fe 100644
--- a/mesalib/src/mesa/main/depth.c
+++ b/mesalib/src/mesa/main/depth.c
@@ -1,174 +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);
-
- 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;
-}
+/*
+ * 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/dlopen.c b/mesalib/src/mesa/main/dlopen.c
index 57a33292e..62d9023a9 100644
--- a/mesalib/src/mesa/main/dlopen.c
+++ b/mesalib/src/mesa/main/dlopen.c
@@ -51,7 +51,7 @@ _mesa_dlopen(const char *libname, int flags)
#elif defined(_GNU_SOURCE)
flags = RTLD_LAZY | RTLD_GLOBAL; /* Overriding flags at this time */
return dlopen(libname, flags);
-#elif defined(__MINGW32__)
+#elif defined(__MINGW32__) | defined(_MSC_VER)
return LoadLibraryA(libname);
#else
return NULL;
@@ -82,7 +82,7 @@ _mesa_dlsym(void *handle, const char *fname)
u.v = dlsym(handle, fname2);
#elif defined(_GNU_SOURCE)
u.v = dlsym(handle, fname);
-#elif defined(__MINGW32__)
+#elif defined(__MINGW32__) | defined(_MSC_VER)
u.v = (void *) GetProcAddress(handle, fname);
#else
u.v = NULL;
@@ -101,7 +101,7 @@ _mesa_dlclose(void *handle)
(void) handle;
#elif defined(_GNU_SOURCE)
dlclose(handle);
-#elif defined(__MINGW32__)
+#elif defined(__MINGW32__) | defined(_MSC_VER)
FreeLibrary(handle);
#else
(void) handle;
diff --git a/mesalib/src/mesa/main/hint.c b/mesalib/src/mesa/main/hint.c
index ff8d88fff..aea0d7022 100644
--- a/mesalib/src/mesa/main/hint.c
+++ b/mesalib/src/mesa/main/hint.c
@@ -1,147 +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 %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;
-}
+
+/*
+ * 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/imports.c b/mesalib/src/mesa/main/imports.c
index bf89815f2..3f856402f 100644
--- a/mesalib/src/mesa/main/imports.c
+++ b/mesalib/src/mesa/main/imports.c
@@ -1,1028 +1,1028 @@
-/**
- * \file imports.c
- * Standard C library function wrappers.
- *
- * Imports are services which the device driver or window system or
- * operating system provides to the core renderer. The core renderer (Mesa)
- * will call these functions in order to do memory allocation, simple I/O,
- * etc.
- *
- * Some drivers will want to override/replace this file with something
- * specialized, but that'll be rare.
- *
- * Eventually, I want to move roll the glheader.h file into this.
- *
- * \todo Functions still needed:
- * - scanf
- * - qsort
- * - rand and RAND_MAX
- */
-
-/*
- * 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 "imports.h"
-#include "context.h"
-#include "mtypes.h"
-#include "version.h"
-
-#ifdef _GNU_SOURCE
-#include <locale.h>
-#ifdef __APPLE__
-#include <xlocale.h>
-#endif
-#endif
-
-
-#define MAXSTRING 4000 /* for vsnprintf() */
-
-#ifdef WIN32
-#define vsnprintf _vsnprintf
-#elif defined(__IBMC__) || defined(__IBMCPP__) || ( defined(__VMS) && __CRTL_VER < 70312000 )
-extern int vsnprintf(char *str, size_t count, const char *fmt, va_list arg);
-#ifdef __VMS
-#include "vsnprintf.c"
-#endif
-#endif
-
-/**********************************************************************/
-/** \name Memory */
-/*@{*/
-
-/**
- * Allocate aligned memory.
- *
- * \param bytes number of bytes to allocate.
- * \param alignment alignment (must be greater than zero).
- *
- * Allocates extra memory to accommodate rounding up the address for
- * alignment and to record the real malloc address.
- *
- * \sa _mesa_align_free().
- */
-void *
-_mesa_align_malloc(size_t bytes, unsigned long alignment)
-{
-#if defined(HAVE_POSIX_MEMALIGN)
- void *mem;
- int err = posix_memalign(& mem, alignment, bytes);
- if (err)
- return NULL;
- return mem;
-#elif defined(_WIN32) && defined(_MSC_VER)
- return _aligned_malloc(bytes, alignment);
-#else
- uintptr_t ptr, buf;
-
- ASSERT( alignment > 0 );
-
- ptr = (uintptr_t) malloc(bytes + alignment + sizeof(void *));
- if (!ptr)
- return NULL;
-
- buf = (ptr + alignment + sizeof(void *)) & ~(uintptr_t)(alignment - 1);
- *(uintptr_t *)(buf - sizeof(void *)) = ptr;
-
-#ifdef DEBUG
- /* mark the non-aligned area */
- while ( ptr < buf - sizeof(void *) ) {
- *(unsigned long *)ptr = 0xcdcdcdcd;
- ptr += sizeof(unsigned long);
- }
-#endif
-
- return (void *) buf;
-#endif /* defined(HAVE_POSIX_MEMALIGN) */
-}
-
-/**
- * Same as _mesa_align_malloc(), but using calloc(1, ) instead of
- * malloc()
- */
-void *
-_mesa_align_calloc(size_t bytes, unsigned long alignment)
-{
-#if defined(HAVE_POSIX_MEMALIGN)
- void *mem;
-
- mem = _mesa_align_malloc(bytes, alignment);
- if (mem != NULL) {
- (void) memset(mem, 0, bytes);
- }
-
- return mem;
-#elif defined(_WIN32) && defined(_MSC_VER)
- void *mem;
-
- mem = _aligned_malloc(bytes, alignment);
- if (mem != NULL) {
- (void) memset(mem, 0, bytes);
- }
-
- return mem;
-#else
- uintptr_t ptr, buf;
-
- ASSERT( alignment > 0 );
-
- ptr = (uintptr_t) calloc(1, bytes + alignment + sizeof(void *));
- if (!ptr)
- return NULL;
-
- buf = (ptr + alignment + sizeof(void *)) & ~(uintptr_t)(alignment - 1);
- *(uintptr_t *)(buf - sizeof(void *)) = ptr;
-
-#ifdef DEBUG
- /* mark the non-aligned area */
- while ( ptr < buf - sizeof(void *) ) {
- *(unsigned long *)ptr = 0xcdcdcdcd;
- ptr += sizeof(unsigned long);
- }
-#endif
-
- return (void *)buf;
-#endif /* defined(HAVE_POSIX_MEMALIGN) */
-}
-
-/**
- * Free memory which was allocated with either _mesa_align_malloc()
- * or _mesa_align_calloc().
- * \param ptr pointer to the memory to be freed.
- * The actual address to free is stored in the word immediately before the
- * address the client sees.
- */
-void
-_mesa_align_free(void *ptr)
-{
-#if defined(HAVE_POSIX_MEMALIGN)
- free(ptr);
-#elif defined(_WIN32) && defined(_MSC_VER)
- _aligned_free(ptr);
-#else
- void **cubbyHole = (void **) ((char *) ptr - sizeof(void *));
- void *realAddr = *cubbyHole;
- free(realAddr);
-#endif /* defined(HAVE_POSIX_MEMALIGN) */
-}
-
-/**
- * Reallocate memory, with alignment.
- */
-void *
-_mesa_align_realloc(void *oldBuffer, size_t oldSize, size_t newSize,
- unsigned long alignment)
-{
-#if defined(_WIN32) && defined(_MSC_VER)
- (void) oldSize;
- return _aligned_realloc(oldBuffer, newSize, alignment);
-#else
- const size_t copySize = (oldSize < newSize) ? oldSize : newSize;
- void *newBuf = _mesa_align_malloc(newSize, alignment);
- if (newBuf && oldBuffer && copySize > 0) {
- memcpy(newBuf, oldBuffer, copySize);
- }
- if (oldBuffer)
- _mesa_align_free(oldBuffer);
- return newBuf;
-#endif
-}
-
-
-
-/** Reallocate memory */
-void *
-_mesa_realloc(void *oldBuffer, size_t oldSize, size_t newSize)
-{
- const size_t copySize = (oldSize < newSize) ? oldSize : newSize;
- void *newBuffer = malloc(newSize);
- if (newBuffer && oldBuffer && copySize > 0)
- memcpy(newBuffer, oldBuffer, copySize);
- if (oldBuffer)
- free(oldBuffer);
- return newBuffer;
-}
-
-/**
- * Fill memory with a constant 16bit word.
- * \param dst destination pointer.
- * \param val value.
- * \param n number of words.
- */
-void
-_mesa_memset16( unsigned short *dst, unsigned short val, size_t n )
-{
- while (n-- > 0)
- *dst++ = val;
-}
-
-/*@}*/
-
-
-/**********************************************************************/
-/** \name Math */
-/*@{*/
-
-/** Wrapper around sqrt() */
-double
-_mesa_sqrtd(double x)
-{
- return sqrt(x);
-}
-
-
-/*
- * A High Speed, Low Precision Square Root
- * by Paul Lalonde and Robert Dawson
- * from "Graphics Gems", Academic Press, 1990
- *
- * SPARC implementation of a fast square root by table
- * lookup.
- * SPARC floating point format is as follows:
- *
- * BIT 31 30 23 22 0
- * sign exponent mantissa
- */
-static short sqrttab[0x100]; /* declare table of square roots */
-
-void
-_mesa_init_sqrt_table(void)
-{
-#if defined(USE_IEEE) && !defined(DEBUG)
- unsigned short i;
- fi_type fi; /* to access the bits of a float in C quickly */
- /* we use a union defined in glheader.h */
-
- for(i=0; i<= 0x7f; i++) {
- fi.i = 0;
-
- /*
- * Build a float with the bit pattern i as mantissa
- * and an exponent of 0, stored as 127
- */
-
- fi.i = (i << 16) | (127 << 23);
- fi.f = _mesa_sqrtd(fi.f);
-
- /*
- * Take the square root then strip the first 7 bits of
- * the mantissa into the table
- */
-
- sqrttab[i] = (fi.i & 0x7fffff) >> 16;
-
- /*
- * Repeat the process, this time with an exponent of
- * 1, stored as 128
- */
-
- fi.i = 0;
- fi.i = (i << 16) | (128 << 23);
- fi.f = sqrt(fi.f);
- sqrttab[i+0x80] = (fi.i & 0x7fffff) >> 16;
- }
-#else
- (void) sqrttab; /* silence compiler warnings */
-#endif /*HAVE_FAST_MATH*/
-}
-
-
-/**
- * Single precision square root.
- */
-float
-_mesa_sqrtf( float x )
-{
-#if defined(USE_IEEE) && !defined(DEBUG)
- fi_type num;
- /* to access the bits of a float in C
- * we use a union from glheader.h */
-
- short e; /* the exponent */
- if (x == 0.0F) return 0.0F; /* check for square root of 0 */
- num.f = x;
- e = (num.i >> 23) - 127; /* get the exponent - on a SPARC the */
- /* exponent is stored with 127 added */
- num.i &= 0x7fffff; /* leave only the mantissa */
- if (e & 0x01) num.i |= 0x800000;
- /* the exponent is odd so we have to */
- /* look it up in the second half of */
- /* the lookup table, so we set the */
- /* high bit */
- e >>= 1; /* divide the exponent by two */
- /* note that in C the shift */
- /* operators are sign preserving */
- /* for signed operands */
- /* Do the table lookup, based on the quaternary mantissa,
- * then reconstruct the result back into a float
- */
- num.i = ((sqrttab[num.i >> 16]) << 16) | ((e + 127) << 23);
-
- return num.f;
-#else
- return (float) _mesa_sqrtd((double) x);
-#endif
-}
-
-
-/**
- inv_sqrt - A single precision 1/sqrt routine for IEEE format floats.
- written by Josh Vanderhoof, based on newsgroup posts by James Van Buskirk
- and Vesa Karvonen.
-*/
-float
-_mesa_inv_sqrtf(float n)
-{
-#if defined(USE_IEEE) && !defined(DEBUG)
- float r0, x0, y0;
- float r1, x1, y1;
- float r2, x2, y2;
-#if 0 /* not used, see below -BP */
- float r3, x3, y3;
-#endif
- fi_type u;
- unsigned int magic;
-
- /*
- Exponent part of the magic number -
-
- We want to:
- 1. subtract the bias from the exponent,
- 2. negate it
- 3. divide by two (rounding towards -inf)
- 4. add the bias back
-
- Which is the same as subtracting the exponent from 381 and dividing
- by 2.
-
- floor(-(x - 127) / 2) + 127 = floor((381 - x) / 2)
- */
-
- magic = 381 << 23;
-
- /*
- Significand part of magic number -
-
- With the current magic number, "(magic - u.i) >> 1" will give you:
-
- for 1 <= u.f <= 2: 1.25 - u.f / 4
- for 2 <= u.f <= 4: 1.00 - u.f / 8
-
- This isn't a bad approximation of 1/sqrt. The maximum difference from
- 1/sqrt will be around .06. After three Newton-Raphson iterations, the
- maximum difference is less than 4.5e-8. (Which is actually close
- enough to make the following bias academic...)
-
- To get a better approximation you can add a bias to the magic
- number. For example, if you subtract 1/2 of the maximum difference in
- the first approximation (.03), you will get the following function:
-
- for 1 <= u.f <= 2: 1.22 - u.f / 4
- for 2 <= u.f <= 3.76: 0.97 - u.f / 8
- for 3.76 <= u.f <= 4: 0.72 - u.f / 16
- (The 3.76 to 4 range is where the result is < .5.)
-
- This is the closest possible initial approximation, but with a maximum
- error of 8e-11 after three NR iterations, it is still not perfect. If
- you subtract 0.0332281 instead of .03, the maximum error will be
- 2.5e-11 after three NR iterations, which should be about as close as
- is possible.
-
- for 1 <= u.f <= 2: 1.2167719 - u.f / 4
- for 2 <= u.f <= 3.73: 0.9667719 - u.f / 8
- for 3.73 <= u.f <= 4: 0.7167719 - u.f / 16
-
- */
-
- magic -= (int)(0.0332281 * (1 << 25));
-
- u.f = n;
- u.i = (magic - u.i) >> 1;
-
- /*
- Instead of Newton-Raphson, we use Goldschmidt's algorithm, which
- allows more parallelism. From what I understand, the parallelism
- comes at the cost of less precision, because it lets error
- accumulate across iterations.
- */
- x0 = 1.0f;
- y0 = 0.5f * n;
- r0 = u.f;
-
- x1 = x0 * r0;
- y1 = y0 * r0 * r0;
- r1 = 1.5f - y1;
-
- x2 = x1 * r1;
- y2 = y1 * r1 * r1;
- r2 = 1.5f - y2;
-
-#if 1
- return x2 * r2; /* we can stop here, and be conformant -BP */
-#else
- x3 = x2 * r2;
- y3 = y2 * r2 * r2;
- r3 = 1.5f - y3;
-
- return x3 * r3;
-#endif
-#else
- return (float) (1.0 / sqrt(n));
-#endif
-}
-
-#ifndef __GNUC__
-/**
- * Find the first bit set in a word.
- */
-int
-_mesa_ffs(int32_t i)
-{
-#if (defined(_WIN32) ) || defined(__IBMC__) || defined(__IBMCPP__)
- register int bit = 0;
- if (i != 0) {
- if ((i & 0xffff) == 0) {
- bit += 16;
- i >>= 16;
- }
- if ((i & 0xff) == 0) {
- bit += 8;
- i >>= 8;
- }
- if ((i & 0xf) == 0) {
- bit += 4;
- i >>= 4;
- }
- while ((i & 1) == 0) {
- bit++;
- i >>= 1;
- }
- bit++;
- }
- return bit;
-#else
- return ffs(i);
-#endif
-}
-
-
-/**
- * Find position of first bit set in given value.
- * XXX Warning: this function can only be used on 64-bit systems!
- * \return position of least-significant bit set, starting at 1, return zero
- * if no bits set.
- */
-int
-_mesa_ffsll(int64_t val)
-{
- int bit;
-
- assert(sizeof(val) == 8);
-
- bit = _mesa_ffs((int32_t)val);
- if (bit != 0)
- return bit;
-
- bit = _mesa_ffs((int32_t)(val >> 32));
- if (bit != 0)
- return 32 + bit;
-
- return 0;
-}
-
-
-#if ((_GNUC__ == 3 && __GNUC_MINOR__ < 4) || __GNUC__ < 4)
-/**
- * Return number of bits set in given GLuint.
- */
-unsigned int
-_mesa_bitcount(unsigned int n)
-{
- unsigned int bits;
- for (bits = 0; n > 0; n = n >> 1) {
- bits += (n & 1);
- }
- return bits;
-}
-#endif
-#endif
-
-
-/**
- * Convert a 4-byte float to a 2-byte half float.
- * Based on code from:
- * http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/008786.html
- */
-GLhalfARB
-_mesa_float_to_half(float val)
-{
- const fi_type fi = {val};
- const int flt_m = fi.i & 0x7fffff;
- const int flt_e = (fi.i >> 23) & 0xff;
- const int flt_s = (fi.i >> 31) & 0x1;
- int s, e, m = 0;
- GLhalfARB result;
-
- /* sign bit */
- s = flt_s;
-
- /* handle special cases */
- if ((flt_e == 0) && (flt_m == 0)) {
- /* zero */
- /* m = 0; - already set */
- e = 0;
- }
- else if ((flt_e == 0) && (flt_m != 0)) {
- /* denorm -- denorm float maps to 0 half */
- /* m = 0; - already set */
- e = 0;
- }
- else if ((flt_e == 0xff) && (flt_m == 0)) {
- /* infinity */
- /* m = 0; - already set */
- e = 31;
- }
- else if ((flt_e == 0xff) && (flt_m != 0)) {
- /* NaN */
- m = 1;
- e = 31;
- }
- else {
- /* regular number */
- const int new_exp = flt_e - 127;
- if (new_exp < -24) {
- /* this maps to 0 */
- /* m = 0; - already set */
- e = 0;
- }
- else if (new_exp < -14) {
- /* this maps to a denorm */
- unsigned int exp_val = (unsigned int) (-14 - new_exp); /* 2^-exp_val*/
- e = 0;
- switch (exp_val) {
- case 0:
- _mesa_warning(NULL,
- "float_to_half: logical error in denorm creation!\n");
- /* m = 0; - already set */
- break;
- case 1: m = 512 + (flt_m >> 14); break;
- case 2: m = 256 + (flt_m >> 15); break;
- case 3: m = 128 + (flt_m >> 16); break;
- case 4: m = 64 + (flt_m >> 17); break;
- case 5: m = 32 + (flt_m >> 18); break;
- case 6: m = 16 + (flt_m >> 19); break;
- case 7: m = 8 + (flt_m >> 20); break;
- case 8: m = 4 + (flt_m >> 21); break;
- case 9: m = 2 + (flt_m >> 22); break;
- case 10: m = 1; break;
- }
- }
- else if (new_exp > 15) {
- /* map this value to infinity */
- /* m = 0; - already set */
- e = 31;
- }
- else {
- /* regular */
- e = new_exp + 15;
- m = flt_m >> 13;
- }
- }
-
- result = (s << 15) | (e << 10) | m;
- return result;
-}
-
-
-/**
- * Convert a 2-byte half float to a 4-byte float.
- * Based on code from:
- * http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/008786.html
- */
-float
-_mesa_half_to_float(GLhalfARB val)
-{
- /* XXX could also use a 64K-entry lookup table */
- const int m = val & 0x3ff;
- const int e = (val >> 10) & 0x1f;
- const int s = (val >> 15) & 0x1;
- int flt_m, flt_e, flt_s;
- fi_type fi;
- float result;
-
- /* sign bit */
- flt_s = s;
-
- /* handle special cases */
- if ((e == 0) && (m == 0)) {
- /* zero */
- flt_m = 0;
- flt_e = 0;
- }
- else if ((e == 0) && (m != 0)) {
- /* denorm -- denorm half will fit in non-denorm single */
- const float half_denorm = 1.0f / 16384.0f; /* 2^-14 */
- float mantissa = ((float) (m)) / 1024.0f;
- float sign = s ? -1.0f : 1.0f;
- return sign * mantissa * half_denorm;
- }
- else if ((e == 31) && (m == 0)) {
- /* infinity */
- flt_e = 0xff;
- flt_m = 0;
- }
- else if ((e == 31) && (m != 0)) {
- /* NaN */
- flt_e = 0xff;
- flt_m = 1;
- }
- else {
- /* regular */
- flt_e = e + 112;
- flt_m = m << 13;
- }
-
- fi.i = (flt_s << 31) | (flt_e << 23) | flt_m;
- result = fi.f;
- return result;
-}
-
-/*@}*/
-
-
-/**********************************************************************/
-/** \name Sort & Search */
-/*@{*/
-
-/**
- * Wrapper for bsearch().
- */
-void *
-_mesa_bsearch( const void *key, const void *base, size_t nmemb, size_t size,
- int (*compar)(const void *, const void *) )
-{
-#if defined(_WIN32_WCE)
- void *mid;
- int cmp;
- while (nmemb) {
- nmemb >>= 1;
- mid = (char *)base + nmemb * size;
- cmp = (*compar)(key, mid);
- if (cmp == 0)
- return mid;
- if (cmp > 0) {
- base = (char *)mid + size;
- --nmemb;
- }
- }
- return NULL;
-#else
- return bsearch(key, base, nmemb, size, compar);
-#endif
-}
-
-/*@}*/
-
-
-/**********************************************************************/
-/** \name Environment vars */
-/*@{*/
-
-/**
- * Wrapper for getenv().
- */
-char *
-_mesa_getenv( const char *var )
-{
-#if defined(_XBOX) || defined(_WIN32_WCE)
- return NULL;
-#else
- return getenv(var);
-#endif
-}
-
-/*@}*/
-
-
-/**********************************************************************/
-/** \name String */
-/*@{*/
-
-/**
- * Implemented using malloc() and strcpy.
- * Note that NULL is handled accordingly.
- */
-char *
-_mesa_strdup( const char *s )
-{
- if (s) {
- size_t l = strlen(s);
- char *s2 = (char *) malloc(l + 1);
- if (s2)
- strcpy(s2, s);
- return s2;
- }
- else {
- return NULL;
- }
-}
-
-/** Wrapper around strtof() */
-float
-_mesa_strtof( const char *s, char **end )
-{
-#if defined(_GNU_SOURCE) && !defined(__CYGWIN__) && !defined(__FreeBSD__)
- static locale_t loc = NULL;
- if (!loc) {
- loc = newlocale(LC_CTYPE_MASK, "C", NULL);
- }
- return strtof_l(s, end, loc);
-#elif defined(_ISOC99_SOURCE) || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600)
- return strtof(s, end);
-#else
- return (float)strtod(s, end);
-#endif
-}
-
-/** Compute simple checksum/hash for a string */
-unsigned int
-_mesa_str_checksum(const char *str)
-{
- /* This could probably be much better */
- unsigned int sum, i;
- const char *c;
- sum = i = 1;
- for (c = str; *c; c++, i++)
- sum += *c * (i % 100);
- return sum + i;
-}
-
-
-/*@}*/
-
-
-/** Wrapper around vsnprintf() */
-int
-_mesa_snprintf( char *str, size_t size, const char *fmt, ... )
-{
- int r;
- va_list args;
- va_start( args, fmt );
- r = vsnprintf( str, size, fmt, args );
- va_end( args );
- return r;
-}
-
-
-/**********************************************************************/
-/** \name Diagnostics */
-/*@{*/
-
-static void
-output_if_debug(const char *prefixString, const char *outputString,
- GLboolean newline)
-{
- static int debug = -1;
-
- /* Check the MESA_DEBUG environment variable if it hasn't
- * been checked yet. We only have to check it once...
- */
- if (debug == -1) {
- char *env = _mesa_getenv("MESA_DEBUG");
-
- /* In a debug build, we print warning messages *unless*
- * MESA_DEBUG is 0. In a non-debug build, we don't
- * print warning messages *unless* MESA_DEBUG is
- * set *to any value*.
- */
-#ifdef DEBUG
- debug = (env != NULL && atoi(env) == 0) ? 0 : 1;
-#else
- debug = (env != NULL) ? 1 : 0;
-#endif
- }
-
- /* Now only print the string if we're required to do so. */
- if (debug) {
- fprintf(stderr, "%s: %s", prefixString, outputString);
- if (newline)
- fprintf(stderr, "\n");
-
-#if defined(_WIN32) && !defined(_WIN32_WCE)
- /* stderr from windows applications without console is not usually
- * visible, so communicate with the debugger instead */
- {
- char buf[4096];
- _mesa_snprintf(buf, sizeof(buf), "%s: %s%s", prefixString, outputString, newline ? "\n" : "");
- OutputDebugStringA(buf);
- }
-#endif
- }
-}
-
-
-/**
- * Return string version of GL error code.
- */
-static const char *
-error_string( GLenum error )
-{
- switch (error) {
- case GL_NO_ERROR:
- return "GL_NO_ERROR";
- case GL_INVALID_VALUE:
- return "GL_INVALID_VALUE";
- case GL_INVALID_ENUM:
- return "GL_INVALID_ENUM";
- case GL_INVALID_OPERATION:
- return "GL_INVALID_OPERATION";
- case GL_STACK_OVERFLOW:
- return "GL_STACK_OVERFLOW";
- case GL_STACK_UNDERFLOW:
- return "GL_STACK_UNDERFLOW";
- case GL_OUT_OF_MEMORY:
- return "GL_OUT_OF_MEMORY";
- case GL_TABLE_TOO_LARGE:
- return "GL_TABLE_TOO_LARGE";
- case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
- return "GL_INVALID_FRAMEBUFFER_OPERATION";
- default:
- return "unknown";
- }
-}
-
-
-/**
- * When a new type of error is recorded, print a message describing
- * previous errors which were accumulated.
- */
-static void
-flush_delayed_errors( struct gl_context *ctx )
-{
- char s[MAXSTRING];
-
- if (ctx->ErrorDebugCount) {
- _mesa_snprintf(s, MAXSTRING, "%d similar %s errors",
- ctx->ErrorDebugCount,
- error_string(ctx->ErrorValue));
-
- output_if_debug("Mesa", s, GL_TRUE);
-
- ctx->ErrorDebugCount = 0;
- }
-}
-
-
-/**
- * Report a warning (a recoverable error condition) to stderr if
- * either DEBUG is defined or the MESA_DEBUG env var is set.
- *
- * \param ctx GL context.
- * \param fmtString printf()-like format string.
- */
-void
-_mesa_warning( struct gl_context *ctx, const char *fmtString, ... )
-{
- char str[MAXSTRING];
- va_list args;
- va_start( args, fmtString );
- (void) vsnprintf( str, MAXSTRING, fmtString, args );
- va_end( args );
-
- if (ctx)
- flush_delayed_errors( ctx );
-
- output_if_debug("Mesa warning", str, GL_TRUE);
-}
-
-
-/**
- * Report an internal implementation problem.
- * Prints the message to stderr via fprintf().
- *
- * \param ctx GL context.
- * \param fmtString problem description string.
- */
-void
-_mesa_problem( const struct gl_context *ctx, const char *fmtString, ... )
-{
- va_list args;
- char str[MAXSTRING];
- (void) ctx;
-
- va_start( args, fmtString );
- vsnprintf( str, MAXSTRING, fmtString, args );
- va_end( args );
-
- fprintf(stderr, "Mesa %s implementation error: %s\n", MESA_VERSION_STRING, str);
- fprintf(stderr, "Please report at bugs.freedesktop.org\n");
-}
-
-
-/**
- * Record an OpenGL state error. These usually occur when the user
- * passes invalid parameters to a GL function.
- *
- * If debugging is enabled (either at compile-time via the DEBUG macro, or
- * run-time via the MESA_DEBUG environment variable), report the error with
- * _mesa_debug().
- *
- * \param ctx the GL context.
- * \param error the error value.
- * \param fmtString printf() style format string, followed by optional args
- */
-void
-_mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... )
-{
- static GLint debug = -1;
-
- /* Check debug environment variable only once:
- */
- if (debug == -1) {
- const char *debugEnv = _mesa_getenv("MESA_DEBUG");
-
-#ifdef DEBUG
- if (debugEnv && strstr(debugEnv, "silent"))
- debug = GL_FALSE;
- else
- debug = GL_TRUE;
-#else
- if (debugEnv)
- debug = GL_TRUE;
- else
- debug = GL_FALSE;
-#endif
- }
-
- if (debug) {
- if (ctx->ErrorValue == error &&
- ctx->ErrorDebugFmtString == fmtString) {
- ctx->ErrorDebugCount++;
- }
- else {
- char s[MAXSTRING], s2[MAXSTRING];
- va_list args;
-
- flush_delayed_errors( ctx );
-
- va_start(args, fmtString);
- vsnprintf(s, MAXSTRING, fmtString, args);
- va_end(args);
-
- _mesa_snprintf(s2, MAXSTRING, "%s in %s", error_string(error), s);
- output_if_debug("Mesa: User error", s2, GL_TRUE);
-
- ctx->ErrorDebugFmtString = fmtString;
- ctx->ErrorDebugCount = 0;
- }
- }
-
- _mesa_record_error(ctx, error);
-}
-
-
-/**
- * Report debug information. Print error message to stderr via fprintf().
- * No-op if DEBUG mode not enabled.
- *
- * \param ctx GL context.
- * \param fmtString printf()-style format string, followed by optional args.
- */
-void
-_mesa_debug( const struct gl_context *ctx, const char *fmtString, ... )
-{
-#ifdef DEBUG
- char s[MAXSTRING];
- va_list args;
- va_start(args, fmtString);
- vsnprintf(s, MAXSTRING, fmtString, args);
- va_end(args);
- output_if_debug("Mesa", s, GL_FALSE);
-#endif /* DEBUG */
- (void) ctx;
- (void) fmtString;
-}
-
-/*@}*/
+/**
+ * \file imports.c
+ * Standard C library function wrappers.
+ *
+ * Imports are services which the device driver or window system or
+ * operating system provides to the core renderer. The core renderer (Mesa)
+ * will call these functions in order to do memory allocation, simple I/O,
+ * etc.
+ *
+ * Some drivers will want to override/replace this file with something
+ * specialized, but that'll be rare.
+ *
+ * Eventually, I want to move roll the glheader.h file into this.
+ *
+ * \todo Functions still needed:
+ * - scanf
+ * - qsort
+ * - rand and RAND_MAX
+ */
+
+/*
+ * 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 "imports.h"
+#include "context.h"
+#include "mtypes.h"
+#include "version.h"
+
+#ifdef _GNU_SOURCE
+#include <locale.h>
+#ifdef __APPLE__
+#include <xlocale.h>
+#endif
+#endif
+
+
+#define MAXSTRING 4000 /* for vsnprintf() */
+
+#ifdef WIN32
+#define vsnprintf _vsnprintf
+#elif defined(__IBMC__) || defined(__IBMCPP__) || ( defined(__VMS) && __CRTL_VER < 70312000 )
+extern int vsnprintf(char *str, size_t count, const char *fmt, va_list arg);
+#ifdef __VMS
+#include "vsnprintf.c"
+#endif
+#endif
+
+/**********************************************************************/
+/** \name Memory */
+/*@{*/
+
+/**
+ * Allocate aligned memory.
+ *
+ * \param bytes number of bytes to allocate.
+ * \param alignment alignment (must be greater than zero).
+ *
+ * Allocates extra memory to accommodate rounding up the address for
+ * alignment and to record the real malloc address.
+ *
+ * \sa _mesa_align_free().
+ */
+void *
+_mesa_align_malloc(size_t bytes, unsigned long alignment)
+{
+#if defined(HAVE_POSIX_MEMALIGN)
+ void *mem;
+ int err = posix_memalign(& mem, alignment, bytes);
+ if (err)
+ return NULL;
+ return mem;
+#elif defined(_WIN32) && defined(_MSC_VER)
+ return _aligned_malloc(bytes, alignment);
+#else
+ uintptr_t ptr, buf;
+
+ ASSERT( alignment > 0 );
+
+ ptr = (uintptr_t) malloc(bytes + alignment + sizeof(void *));
+ if (!ptr)
+ return NULL;
+
+ buf = (ptr + alignment + sizeof(void *)) & ~(uintptr_t)(alignment - 1);
+ *(uintptr_t *)(buf - sizeof(void *)) = ptr;
+
+#ifdef DEBUG
+ /* mark the non-aligned area */
+ while ( ptr < buf - sizeof(void *) ) {
+ *(unsigned long *)ptr = 0xcdcdcdcd;
+ ptr += sizeof(unsigned long);
+ }
+#endif
+
+ return (void *) buf;
+#endif /* defined(HAVE_POSIX_MEMALIGN) */
+}
+
+/**
+ * Same as _mesa_align_malloc(), but using calloc(1, ) instead of
+ * malloc()
+ */
+void *
+_mesa_align_calloc(size_t bytes, unsigned long alignment)
+{
+#if defined(HAVE_POSIX_MEMALIGN)
+ void *mem;
+
+ mem = _mesa_align_malloc(bytes, alignment);
+ if (mem != NULL) {
+ (void) memset(mem, 0, bytes);
+ }
+
+ return mem;
+#elif defined(_WIN32) && defined(_MSC_VER)
+ void *mem;
+
+ mem = _aligned_malloc(bytes, alignment);
+ if (mem != NULL) {
+ (void) memset(mem, 0, bytes);
+ }
+
+ return mem;
+#else
+ uintptr_t ptr, buf;
+
+ ASSERT( alignment > 0 );
+
+ ptr = (uintptr_t) calloc(1, bytes + alignment + sizeof(void *));
+ if (!ptr)
+ return NULL;
+
+ buf = (ptr + alignment + sizeof(void *)) & ~(uintptr_t)(alignment - 1);
+ *(uintptr_t *)(buf - sizeof(void *)) = ptr;
+
+#ifdef DEBUG
+ /* mark the non-aligned area */
+ while ( ptr < buf - sizeof(void *) ) {
+ *(unsigned long *)ptr = 0xcdcdcdcd;
+ ptr += sizeof(unsigned long);
+ }
+#endif
+
+ return (void *)buf;
+#endif /* defined(HAVE_POSIX_MEMALIGN) */
+}
+
+/**
+ * Free memory which was allocated with either _mesa_align_malloc()
+ * or _mesa_align_calloc().
+ * \param ptr pointer to the memory to be freed.
+ * The actual address to free is stored in the word immediately before the
+ * address the client sees.
+ */
+void
+_mesa_align_free(void *ptr)
+{
+#if defined(HAVE_POSIX_MEMALIGN)
+ free(ptr);
+#elif defined(_WIN32) && defined(_MSC_VER)
+ _aligned_free(ptr);
+#else
+ void **cubbyHole = (void **) ((char *) ptr - sizeof(void *));
+ void *realAddr = *cubbyHole;
+ free(realAddr);
+#endif /* defined(HAVE_POSIX_MEMALIGN) */
+}
+
+/**
+ * Reallocate memory, with alignment.
+ */
+void *
+_mesa_align_realloc(void *oldBuffer, size_t oldSize, size_t newSize,
+ unsigned long alignment)
+{
+#if defined(_WIN32) && defined(_MSC_VER)
+ (void) oldSize;
+ return _aligned_realloc(oldBuffer, newSize, alignment);
+#else
+ const size_t copySize = (oldSize < newSize) ? oldSize : newSize;
+ void *newBuf = _mesa_align_malloc(newSize, alignment);
+ if (newBuf && oldBuffer && copySize > 0) {
+ memcpy(newBuf, oldBuffer, copySize);
+ }
+ if (oldBuffer)
+ _mesa_align_free(oldBuffer);
+ return newBuf;
+#endif
+}
+
+
+
+/** Reallocate memory */
+void *
+_mesa_realloc(void *oldBuffer, size_t oldSize, size_t newSize)
+{
+ const size_t copySize = (oldSize < newSize) ? oldSize : newSize;
+ void *newBuffer = malloc(newSize);
+ if (newBuffer && oldBuffer && copySize > 0)
+ memcpy(newBuffer, oldBuffer, copySize);
+ if (oldBuffer)
+ free(oldBuffer);
+ return newBuffer;
+}
+
+/**
+ * Fill memory with a constant 16bit word.
+ * \param dst destination pointer.
+ * \param val value.
+ * \param n number of words.
+ */
+void
+_mesa_memset16( unsigned short *dst, unsigned short val, size_t n )
+{
+ while (n-- > 0)
+ *dst++ = val;
+}
+
+/*@}*/
+
+
+/**********************************************************************/
+/** \name Math */
+/*@{*/
+
+/** Wrapper around sqrt() */
+double
+_mesa_sqrtd(double x)
+{
+ return sqrt(x);
+}
+
+
+/*
+ * A High Speed, Low Precision Square Root
+ * by Paul Lalonde and Robert Dawson
+ * from "Graphics Gems", Academic Press, 1990
+ *
+ * SPARC implementation of a fast square root by table
+ * lookup.
+ * SPARC floating point format is as follows:
+ *
+ * BIT 31 30 23 22 0
+ * sign exponent mantissa
+ */
+static short sqrttab[0x100]; /* declare table of square roots */
+
+void
+_mesa_init_sqrt_table(void)
+{
+#if defined(USE_IEEE) && !defined(DEBUG)
+ unsigned short i;
+ fi_type fi; /* to access the bits of a float in C quickly */
+ /* we use a union defined in glheader.h */
+
+ for(i=0; i<= 0x7f; i++) {
+ fi.i = 0;
+
+ /*
+ * Build a float with the bit pattern i as mantissa
+ * and an exponent of 0, stored as 127
+ */
+
+ fi.i = (i << 16) | (127 << 23);
+ fi.f = _mesa_sqrtd(fi.f);
+
+ /*
+ * Take the square root then strip the first 7 bits of
+ * the mantissa into the table
+ */
+
+ sqrttab[i] = (fi.i & 0x7fffff) >> 16;
+
+ /*
+ * Repeat the process, this time with an exponent of
+ * 1, stored as 128
+ */
+
+ fi.i = 0;
+ fi.i = (i << 16) | (128 << 23);
+ fi.f = sqrt(fi.f);
+ sqrttab[i+0x80] = (fi.i & 0x7fffff) >> 16;
+ }
+#else
+ (void) sqrttab; /* silence compiler warnings */
+#endif /*HAVE_FAST_MATH*/
+}
+
+
+/**
+ * Single precision square root.
+ */
+float
+_mesa_sqrtf( float x )
+{
+#if defined(USE_IEEE) && !defined(DEBUG)
+ fi_type num;
+ /* to access the bits of a float in C
+ * we use a union from glheader.h */
+
+ short e; /* the exponent */
+ if (x == 0.0F) return 0.0F; /* check for square root of 0 */
+ num.f = x;
+ e = (num.i >> 23) - 127; /* get the exponent - on a SPARC the */
+ /* exponent is stored with 127 added */
+ num.i &= 0x7fffff; /* leave only the mantissa */
+ if (e & 0x01) num.i |= 0x800000;
+ /* the exponent is odd so we have to */
+ /* look it up in the second half of */
+ /* the lookup table, so we set the */
+ /* high bit */
+ e >>= 1; /* divide the exponent by two */
+ /* note that in C the shift */
+ /* operators are sign preserving */
+ /* for signed operands */
+ /* Do the table lookup, based on the quaternary mantissa,
+ * then reconstruct the result back into a float
+ */
+ num.i = ((sqrttab[num.i >> 16]) << 16) | ((e + 127) << 23);
+
+ return num.f;
+#else
+ return (float) _mesa_sqrtd((double) x);
+#endif
+}
+
+
+/**
+ inv_sqrt - A single precision 1/sqrt routine for IEEE format floats.
+ written by Josh Vanderhoof, based on newsgroup posts by James Van Buskirk
+ and Vesa Karvonen.
+*/
+float
+_mesa_inv_sqrtf(float n)
+{
+#if defined(USE_IEEE) && !defined(DEBUG)
+ float r0, x0, y0;
+ float r1, x1, y1;
+ float r2, x2, y2;
+#if 0 /* not used, see below -BP */
+ float r3, x3, y3;
+#endif
+ fi_type u;
+ unsigned int magic;
+
+ /*
+ Exponent part of the magic number -
+
+ We want to:
+ 1. subtract the bias from the exponent,
+ 2. negate it
+ 3. divide by two (rounding towards -inf)
+ 4. add the bias back
+
+ Which is the same as subtracting the exponent from 381 and dividing
+ by 2.
+
+ floor(-(x - 127) / 2) + 127 = floor((381 - x) / 2)
+ */
+
+ magic = 381 << 23;
+
+ /*
+ Significand part of magic number -
+
+ With the current magic number, "(magic - u.i) >> 1" will give you:
+
+ for 1 <= u.f <= 2: 1.25 - u.f / 4
+ for 2 <= u.f <= 4: 1.00 - u.f / 8
+
+ This isn't a bad approximation of 1/sqrt. The maximum difference from
+ 1/sqrt will be around .06. After three Newton-Raphson iterations, the
+ maximum difference is less than 4.5e-8. (Which is actually close
+ enough to make the following bias academic...)
+
+ To get a better approximation you can add a bias to the magic
+ number. For example, if you subtract 1/2 of the maximum difference in
+ the first approximation (.03), you will get the following function:
+
+ for 1 <= u.f <= 2: 1.22 - u.f / 4
+ for 2 <= u.f <= 3.76: 0.97 - u.f / 8
+ for 3.76 <= u.f <= 4: 0.72 - u.f / 16
+ (The 3.76 to 4 range is where the result is < .5.)
+
+ This is the closest possible initial approximation, but with a maximum
+ error of 8e-11 after three NR iterations, it is still not perfect. If
+ you subtract 0.0332281 instead of .03, the maximum error will be
+ 2.5e-11 after three NR iterations, which should be about as close as
+ is possible.
+
+ for 1 <= u.f <= 2: 1.2167719 - u.f / 4
+ for 2 <= u.f <= 3.73: 0.9667719 - u.f / 8
+ for 3.73 <= u.f <= 4: 0.7167719 - u.f / 16
+
+ */
+
+ magic -= (int)(0.0332281 * (1 << 25));
+
+ u.f = n;
+ u.i = (magic - u.i) >> 1;
+
+ /*
+ Instead of Newton-Raphson, we use Goldschmidt's algorithm, which
+ allows more parallelism. From what I understand, the parallelism
+ comes at the cost of less precision, because it lets error
+ accumulate across iterations.
+ */
+ x0 = 1.0f;
+ y0 = 0.5f * n;
+ r0 = u.f;
+
+ x1 = x0 * r0;
+ y1 = y0 * r0 * r0;
+ r1 = 1.5f - y1;
+
+ x2 = x1 * r1;
+ y2 = y1 * r1 * r1;
+ r2 = 1.5f - y2;
+
+#if 1
+ return x2 * r2; /* we can stop here, and be conformant -BP */
+#else
+ x3 = x2 * r2;
+ y3 = y2 * r2 * r2;
+ r3 = 1.5f - y3;
+
+ return x3 * r3;
+#endif
+#else
+ return (float) (1.0 / sqrt(n));
+#endif
+}
+
+#ifndef __GNUC__
+/**
+ * Find the first bit set in a word.
+ */
+int
+_mesa_ffs(int32_t i)
+{
+#if (defined(_WIN32) ) || defined(__IBMC__) || defined(__IBMCPP__)
+ register int bit = 0;
+ if (i != 0) {
+ if ((i & 0xffff) == 0) {
+ bit += 16;
+ i >>= 16;
+ }
+ if ((i & 0xff) == 0) {
+ bit += 8;
+ i >>= 8;
+ }
+ if ((i & 0xf) == 0) {
+ bit += 4;
+ i >>= 4;
+ }
+ while ((i & 1) == 0) {
+ bit++;
+ i >>= 1;
+ }
+ bit++;
+ }
+ return bit;
+#else
+ return ffs(i);
+#endif
+}
+
+
+/**
+ * Find position of first bit set in given value.
+ * XXX Warning: this function can only be used on 64-bit systems!
+ * \return position of least-significant bit set, starting at 1, return zero
+ * if no bits set.
+ */
+int
+_mesa_ffsll(int64_t val)
+{
+ int bit;
+
+ assert(sizeof(val) == 8);
+
+ bit = _mesa_ffs((int32_t)val);
+ if (bit != 0)
+ return bit;
+
+ bit = _mesa_ffs((int32_t)(val >> 32));
+ if (bit != 0)
+ return 32 + bit;
+
+ return 0;
+}
+
+
+#if ((_GNUC__ == 3 && __GNUC_MINOR__ < 4) || __GNUC__ < 4)
+/**
+ * Return number of bits set in given GLuint.
+ */
+unsigned int
+_mesa_bitcount(unsigned int n)
+{
+ unsigned int bits;
+ for (bits = 0; n > 0; n = n >> 1) {
+ bits += (n & 1);
+ }
+ return bits;
+}
+#endif
+#endif
+
+
+/**
+ * Convert a 4-byte float to a 2-byte half float.
+ * Based on code from:
+ * http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/008786.html
+ */
+GLhalfARB
+_mesa_float_to_half(float val)
+{
+ const fi_type fi = {val};
+ const int flt_m = fi.i & 0x7fffff;
+ const int flt_e = (fi.i >> 23) & 0xff;
+ const int flt_s = (fi.i >> 31) & 0x1;
+ int s, e, m = 0;
+ GLhalfARB result;
+
+ /* sign bit */
+ s = flt_s;
+
+ /* handle special cases */
+ if ((flt_e == 0) && (flt_m == 0)) {
+ /* zero */
+ /* m = 0; - already set */
+ e = 0;
+ }
+ else if ((flt_e == 0) && (flt_m != 0)) {
+ /* denorm -- denorm float maps to 0 half */
+ /* m = 0; - already set */
+ e = 0;
+ }
+ else if ((flt_e == 0xff) && (flt_m == 0)) {
+ /* infinity */
+ /* m = 0; - already set */
+ e = 31;
+ }
+ else if ((flt_e == 0xff) && (flt_m != 0)) {
+ /* NaN */
+ m = 1;
+ e = 31;
+ }
+ else {
+ /* regular number */
+ const int new_exp = flt_e - 127;
+ if (new_exp < -24) {
+ /* this maps to 0 */
+ /* m = 0; - already set */
+ e = 0;
+ }
+ else if (new_exp < -14) {
+ /* this maps to a denorm */
+ unsigned int exp_val = (unsigned int) (-14 - new_exp); /* 2^-exp_val*/
+ e = 0;
+ switch (exp_val) {
+ case 0:
+ _mesa_warning(NULL,
+ "float_to_half: logical error in denorm creation!\n");
+ /* m = 0; - already set */
+ break;
+ case 1: m = 512 + (flt_m >> 14); break;
+ case 2: m = 256 + (flt_m >> 15); break;
+ case 3: m = 128 + (flt_m >> 16); break;
+ case 4: m = 64 + (flt_m >> 17); break;
+ case 5: m = 32 + (flt_m >> 18); break;
+ case 6: m = 16 + (flt_m >> 19); break;
+ case 7: m = 8 + (flt_m >> 20); break;
+ case 8: m = 4 + (flt_m >> 21); break;
+ case 9: m = 2 + (flt_m >> 22); break;
+ case 10: m = 1; break;
+ }
+ }
+ else if (new_exp > 15) {
+ /* map this value to infinity */
+ /* m = 0; - already set */
+ e = 31;
+ }
+ else {
+ /* regular */
+ e = new_exp + 15;
+ m = flt_m >> 13;
+ }
+ }
+
+ result = (s << 15) | (e << 10) | m;
+ return result;
+}
+
+
+/**
+ * Convert a 2-byte half float to a 4-byte float.
+ * Based on code from:
+ * http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/008786.html
+ */
+float
+_mesa_half_to_float(GLhalfARB val)
+{
+ /* XXX could also use a 64K-entry lookup table */
+ const int m = val & 0x3ff;
+ const int e = (val >> 10) & 0x1f;
+ const int s = (val >> 15) & 0x1;
+ int flt_m, flt_e, flt_s;
+ fi_type fi;
+ float result;
+
+ /* sign bit */
+ flt_s = s;
+
+ /* handle special cases */
+ if ((e == 0) && (m == 0)) {
+ /* zero */
+ flt_m = 0;
+ flt_e = 0;
+ }
+ else if ((e == 0) && (m != 0)) {
+ /* denorm -- denorm half will fit in non-denorm single */
+ const float half_denorm = 1.0f / 16384.0f; /* 2^-14 */
+ float mantissa = ((float) (m)) / 1024.0f;
+ float sign = s ? -1.0f : 1.0f;
+ return sign * mantissa * half_denorm;
+ }
+ else if ((e == 31) && (m == 0)) {
+ /* infinity */
+ flt_e = 0xff;
+ flt_m = 0;
+ }
+ else if ((e == 31) && (m != 0)) {
+ /* NaN */
+ flt_e = 0xff;
+ flt_m = 1;
+ }
+ else {
+ /* regular */
+ flt_e = e + 112;
+ flt_m = m << 13;
+ }
+
+ fi.i = (flt_s << 31) | (flt_e << 23) | flt_m;
+ result = fi.f;
+ return result;
+}
+
+/*@}*/
+
+
+/**********************************************************************/
+/** \name Sort & Search */
+/*@{*/
+
+/**
+ * Wrapper for bsearch().
+ */
+void *
+_mesa_bsearch( const void *key, const void *base, size_t nmemb, size_t size,
+ int (*compar)(const void *, const void *) )
+{
+#if defined(_WIN32_WCE)
+ void *mid;
+ int cmp;
+ while (nmemb) {
+ nmemb >>= 1;
+ mid = (char *)base + nmemb * size;
+ cmp = (*compar)(key, mid);
+ if (cmp == 0)
+ return mid;
+ if (cmp > 0) {
+ base = (char *)mid + size;
+ --nmemb;
+ }
+ }
+ return NULL;
+#else
+ return bsearch(key, base, nmemb, size, compar);
+#endif
+}
+
+/*@}*/
+
+
+/**********************************************************************/
+/** \name Environment vars */
+/*@{*/
+
+/**
+ * Wrapper for getenv().
+ */
+char *
+_mesa_getenv( const char *var )
+{
+#if defined(_XBOX) || defined(_WIN32_WCE)
+ return NULL;
+#else
+ return getenv(var);
+#endif
+}
+
+/*@}*/
+
+
+/**********************************************************************/
+/** \name String */
+/*@{*/
+
+/**
+ * Implemented using malloc() and strcpy.
+ * Note that NULL is handled accordingly.
+ */
+char *
+_mesa_strdup( const char *s )
+{
+ if (s) {
+ size_t l = strlen(s);
+ char *s2 = (char *) malloc(l + 1);
+ if (s2)
+ strcpy(s2, s);
+ return s2;
+ }
+ else {
+ return NULL;
+ }
+}
+
+/** Wrapper around strtof() */
+float
+_mesa_strtof( const char *s, char **end )
+{
+#if defined(_GNU_SOURCE) && !defined(__CYGWIN__) && !defined(__FreeBSD__)
+ static locale_t loc = NULL;
+ if (!loc) {
+ loc = newlocale(LC_CTYPE_MASK, "C", NULL);
+ }
+ return strtof_l(s, end, loc);
+#elif defined(_ISOC99_SOURCE) || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600)
+ return strtof(s, end);
+#else
+ return (float)strtod(s, end);
+#endif
+}
+
+/** Compute simple checksum/hash for a string */
+unsigned int
+_mesa_str_checksum(const char *str)
+{
+ /* This could probably be much better */
+ unsigned int sum, i;
+ const char *c;
+ sum = i = 1;
+ for (c = str; *c; c++, i++)
+ sum += *c * (i % 100);
+ return sum + i;
+}
+
+
+/*@}*/
+
+
+/** Wrapper around vsnprintf() */
+int
+_mesa_snprintf( char *str, size_t size, const char *fmt, ... )
+{
+ int r;
+ va_list args;
+ va_start( args, fmt );
+ r = vsnprintf( str, size, fmt, args );
+ va_end( args );
+ return r;
+}
+
+
+/**********************************************************************/
+/** \name Diagnostics */
+/*@{*/
+
+static void
+output_if_debug(const char *prefixString, const char *outputString,
+ GLboolean newline)
+{
+ static int debug = -1;
+
+ /* Check the MESA_DEBUG environment variable if it hasn't
+ * been checked yet. We only have to check it once...
+ */
+ if (debug == -1) {
+ char *env = _mesa_getenv("MESA_DEBUG");
+
+ /* In a debug build, we print warning messages *unless*
+ * MESA_DEBUG is 0. In a non-debug build, we don't
+ * print warning messages *unless* MESA_DEBUG is
+ * set *to any value*.
+ */
+#ifdef DEBUG
+ debug = (env != NULL && atoi(env) == 0) ? 0 : 1;
+#else
+ debug = (env != NULL) ? 1 : 0;
+#endif
+ }
+
+ /* Now only print the string if we're required to do so. */
+ if (debug) {
+ fprintf(stderr, "%s: %s", prefixString, outputString);
+ if (newline)
+ fprintf(stderr, "\n");
+
+#if defined(_WIN32) && !defined(_WIN32_WCE)
+ /* stderr from windows applications without console is not usually
+ * visible, so communicate with the debugger instead */
+ {
+ char buf[4096];
+ _mesa_snprintf(buf, sizeof(buf), "%s: %s%s", prefixString, outputString, newline ? "\n" : "");
+ OutputDebugStringA(buf);
+ }
+#endif
+ }
+}
+
+
+/**
+ * Return string version of GL error code.
+ */
+static const char *
+error_string( GLenum error )
+{
+ switch (error) {
+ case GL_NO_ERROR:
+ return "GL_NO_ERROR";
+ case GL_INVALID_VALUE:
+ return "GL_INVALID_VALUE";
+ case GL_INVALID_ENUM:
+ return "GL_INVALID_ENUM";
+ case GL_INVALID_OPERATION:
+ return "GL_INVALID_OPERATION";
+ case GL_STACK_OVERFLOW:
+ return "GL_STACK_OVERFLOW";
+ case GL_STACK_UNDERFLOW:
+ return "GL_STACK_UNDERFLOW";
+ case GL_OUT_OF_MEMORY:
+ return "GL_OUT_OF_MEMORY";
+ case GL_TABLE_TOO_LARGE:
+ return "GL_TABLE_TOO_LARGE";
+ case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
+ return "GL_INVALID_FRAMEBUFFER_OPERATION";
+ default:
+ return "unknown";
+ }
+}
+
+
+/**
+ * When a new type of error is recorded, print a message describing
+ * previous errors which were accumulated.
+ */
+static void
+flush_delayed_errors( struct gl_context *ctx )
+{
+ char s[MAXSTRING];
+
+ if (ctx->ErrorDebugCount) {
+ _mesa_snprintf(s, MAXSTRING, "%d similar %s errors",
+ ctx->ErrorDebugCount,
+ error_string(ctx->ErrorValue));
+
+ output_if_debug("Mesa", s, GL_TRUE);
+
+ ctx->ErrorDebugCount = 0;
+ }
+}
+
+
+/**
+ * Report a warning (a recoverable error condition) to stderr if
+ * either DEBUG is defined or the MESA_DEBUG env var is set.
+ *
+ * \param ctx GL context.
+ * \param fmtString printf()-like format string.
+ */
+void
+_mesa_warning( struct gl_context *ctx, const char *fmtString, ... )
+{
+ char str[MAXSTRING];
+ va_list args;
+ va_start( args, fmtString );
+ (void) vsnprintf( str, MAXSTRING, fmtString, args );
+ va_end( args );
+
+ if (ctx)
+ flush_delayed_errors( ctx );
+
+ output_if_debug("Mesa warning", str, GL_TRUE);
+}
+
+
+/**
+ * Report an internal implementation problem.
+ * Prints the message to stderr via fprintf().
+ *
+ * \param ctx GL context.
+ * \param fmtString problem description string.
+ */
+void
+_mesa_problem( const struct gl_context *ctx, const char *fmtString, ... )
+{
+ va_list args;
+ char str[MAXSTRING];
+ (void) ctx;
+
+ va_start( args, fmtString );
+ vsnprintf( str, MAXSTRING, fmtString, args );
+ va_end( args );
+
+ fprintf(stderr, "Mesa %s implementation error: %s\n", MESA_VERSION_STRING, str);
+ fprintf(stderr, "Please report at bugs.freedesktop.org\n");
+}
+
+
+/**
+ * Record an OpenGL state error. These usually occur when the user
+ * passes invalid parameters to a GL function.
+ *
+ * If debugging is enabled (either at compile-time via the DEBUG macro, or
+ * run-time via the MESA_DEBUG environment variable), report the error with
+ * _mesa_debug().
+ *
+ * \param ctx the GL context.
+ * \param error the error value.
+ * \param fmtString printf() style format string, followed by optional args
+ */
+void
+_mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... )
+{
+ static GLint debug = -1;
+
+ /* Check debug environment variable only once:
+ */
+ if (debug == -1) {
+ const char *debugEnv = _mesa_getenv("MESA_DEBUG");
+
+#ifdef DEBUG
+ if (debugEnv && strstr(debugEnv, "silent"))
+ debug = GL_FALSE;
+ else
+ debug = GL_TRUE;
+#else
+ if (debugEnv)
+ debug = GL_TRUE;
+ else
+ debug = GL_FALSE;
+#endif
+ }
+
+ if (debug) {
+ if (ctx->ErrorValue == error &&
+ ctx->ErrorDebugFmtString == fmtString) {
+ ctx->ErrorDebugCount++;
+ }
+ else {
+ char s[MAXSTRING], s2[MAXSTRING];
+ va_list args;
+
+ flush_delayed_errors( ctx );
+
+ va_start(args, fmtString);
+ vsnprintf(s, MAXSTRING, fmtString, args);
+ va_end(args);
+
+ _mesa_snprintf(s2, MAXSTRING, "%s in %s", error_string(error), s);
+ output_if_debug("Mesa: User error", s2, GL_TRUE);
+
+ ctx->ErrorDebugFmtString = fmtString;
+ ctx->ErrorDebugCount = 0;
+ }
+ }
+
+ _mesa_record_error(ctx, error);
+}
+
+
+/**
+ * Report debug information. Print error message to stderr via fprintf().
+ * No-op if DEBUG mode not enabled.
+ *
+ * \param ctx GL context.
+ * \param fmtString printf()-style format string, followed by optional args.
+ */
+void
+_mesa_debug( const struct gl_context *ctx, const char *fmtString, ... )
+{
+#ifdef DEBUG
+ char s[MAXSTRING];
+ va_list args;
+ va_start(args, fmtString);
+ vsnprintf(s, MAXSTRING, fmtString, args);
+ va_end(args);
+ output_if_debug("Mesa", s, GL_FALSE);
+#endif /* DEBUG */
+ (void) ctx;
+ (void) fmtString;
+}
+
+/*@}*/
diff --git a/mesalib/src/mesa/main/imports.h b/mesalib/src/mesa/main/imports.h
index a994dbcae..9922f43e3 100644
--- a/mesalib/src/mesa/main/imports.h
+++ b/mesalib/src/mesa/main/imports.h
@@ -1,615 +1,615 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.5
- *
- * Copyright (C) 1999-2008 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 imports.h
- * Standard C library function wrappers.
- *
- * This file provides wrappers for all the standard C library functions
- * like malloc(), free(), printf(), getenv(), etc.
- */
-
-
-#ifndef IMPORTS_H
-#define IMPORTS_H
-
-
-#include "compiler.h"
-#include "glheader.h"
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/**********************************************************************/
-/** Memory macros */
-/*@{*/
-
-/** Allocate \p BYTES bytes */
-#define MALLOC(BYTES) malloc(BYTES)
-/** Allocate and zero \p BYTES bytes */
-#define CALLOC(BYTES) calloc(1, BYTES)
-/** Allocate a structure of type \p T */
-#define MALLOC_STRUCT(T) (struct T *) malloc(sizeof(struct T))
-/** Allocate and zero a structure of type \p T */
-#define CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T))
-/** Free memory */
-#define FREE(PTR) free(PTR)
-
-/*@}*/
-
-
-/*
- * For GL_ARB_vertex_buffer_object we need to treat vertex array pointers
- * as offsets into buffer stores. Since the vertex array pointer and
- * buffer store pointer are both pointers and we need to add them, we use
- * this macro.
- * Both pointers/offsets are expressed in bytes.
- */
-#define ADD_POINTERS(A, B) ( (GLubyte *) (A) + (uintptr_t) (B) )
-
-
-/**
- * Sometimes we treat GLfloats as GLints. On x86 systems, moving a float
- * as a int (thereby using integer registers instead of FP registers) is
- * a performance win. Typically, this can be done with ordinary casts.
- * But with gcc's -fstrict-aliasing flag (which defaults to on in gcc 3.0)
- * these casts generate warnings.
- * The following union typedef is used to solve that.
- */
-typedef union { GLfloat f; GLint i; } fi_type;
-
-
-
-/**********************************************************************
- * Math macros
- */
-
-#define MAX_GLUSHORT 0xffff
-#define MAX_GLUINT 0xffffffff
-
-/* Degrees to radians conversion: */
-#define DEG2RAD (M_PI/180.0)
-
-
-/***
- *** SQRTF: single-precision square root
- ***/
-#if 0 /* _mesa_sqrtf() not accurate enough - temporarily disabled */
-# define SQRTF(X) _mesa_sqrtf(X)
-#else
-# define SQRTF(X) (float) sqrt((float) (X))
-#endif
-
-
-/***
- *** INV_SQRTF: single-precision inverse square root
- ***/
-#if 0
-#define INV_SQRTF(X) _mesa_inv_sqrt(X)
-#else
-#define INV_SQRTF(X) (1.0F / SQRTF(X)) /* this is faster on a P4 */
-#endif
-
-
-/**
- * \name Work-arounds for platforms that lack C99 math functions
- */
-/*@{*/
-#if (!defined(_XOPEN_SOURCE) || (_XOPEN_SOURCE < 600)) && !defined(_ISOC99_SOURCE) \
- && (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)) \
- && (!defined(_MSC_VER) || (_MSC_VER < 1400))
-#define acosf(f) ((float) acos(f))
-#define asinf(f) ((float) asin(f))
-#define atan2f(x,y) ((float) atan2(x,y))
-#define atanf(f) ((float) atan(f))
-#define cielf(f) ((float) ciel(f))
-#define cosf(f) ((float) cos(f))
-#define coshf(f) ((float) cosh(f))
-#define expf(f) ((float) exp(f))
-#define exp2f(f) ((float) exp2(f))
-#define floorf(f) ((float) floor(f))
-#define logf(f) ((float) log(f))
-#define log2f(f) ((float) log2(f))
-#define powf(x,y) ((float) pow(x,y))
-#define sinf(f) ((float) sin(f))
-#define sinhf(f) ((float) sinh(f))
-#define sqrtf(f) ((float) sqrt(f))
-#define tanf(f) ((float) tan(f))
-#define tanhf(f) ((float) tanh(f))
-#define acoshf(f) ((float) acosh(f))
-#define asinhf(f) ((float) asinh(f))
-#define atanhf(f) ((float) atanh(f))
-#endif
-
-#if defined(_MSC_VER)
-static INLINE float truncf(float x) { return x < 0.0f ? ceilf(x) : floorf(x); }
-static INLINE float exp2f(float x) { return powf(2.0f, x); }
-static INLINE float log2f(float x) { return logf(x) * 1.442695041f; }
-static INLINE float asinhf(float x) { return logf(x + sqrtf(x * x + 1.0f)); }
-static INLINE float acoshf(float x) { return logf(x + sqrtf(x * x - 1.0f)); }
-static INLINE float atanhf(float x) { return (logf(1.0f + x) - logf(1.0f - x)) / 2.0f; }
-static INLINE int isblank(int ch) { return ch == ' ' || ch == '\t'; }
-#define strtoll(p, e, b) _strtoi64(p, e, b)
-#endif
-/*@}*/
-
-/***
- *** LOG2: Log base 2 of float
- ***/
-#ifdef USE_IEEE
-#if 0
-/* This is pretty fast, but not accurate enough (only 2 fractional bits).
- * Based on code from http://www.stereopsis.com/log2.html
- */
-static INLINE GLfloat LOG2(GLfloat x)
-{
- const GLfloat y = x * x * x * x;
- const GLuint ix = *((GLuint *) &y);
- const GLuint exp = (ix >> 23) & 0xFF;
- const GLint log2 = ((GLint) exp) - 127;
- return (GLfloat) log2 * (1.0 / 4.0); /* 4, because of x^4 above */
-}
-#endif
-/* Pretty fast, and accurate.
- * Based on code from http://www.flipcode.com/totd/
- */
-static INLINE GLfloat LOG2(GLfloat val)
-{
- fi_type num;
- GLint log_2;
- num.f = val;
- log_2 = ((num.i >> 23) & 255) - 128;
- num.i &= ~(255 << 23);
- num.i += 127 << 23;
- num.f = ((-1.0f/3) * num.f + 2) * num.f - 2.0f/3;
- return num.f + log_2;
-}
-#else
-/*
- * NOTE: log_base_2(x) = log(x) / log(2)
- * NOTE: 1.442695 = 1/log(2).
- */
-#define LOG2(x) ((GLfloat) (log(x) * 1.442695F))
-#endif
-
-
-/***
- *** IS_INF_OR_NAN: test if float is infinite or NaN
- ***/
-#ifdef USE_IEEE
-static INLINE int IS_INF_OR_NAN( float x )
-{
- fi_type tmp;
- tmp.f = x;
- return !(int)((unsigned int)((tmp.i & 0x7fffffff)-0x7f800000) >> 31);
-}
-#elif defined(isfinite)
-#define IS_INF_OR_NAN(x) (!isfinite(x))
-#elif defined(finite)
-#define IS_INF_OR_NAN(x) (!finite(x))
-#elif defined(__VMS)
-#define IS_INF_OR_NAN(x) (!finite(x))
-#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-#define IS_INF_OR_NAN(x) (!isfinite(x))
-#else
-#define IS_INF_OR_NAN(x) (!finite(x))
-#endif
-
-
-/***
- *** IS_NEGATIVE: test if float is negative
- ***/
-#if defined(USE_IEEE)
-static INLINE int GET_FLOAT_BITS( float x )
-{
- fi_type fi;
- fi.f = x;
- return fi.i;
-}
-#define IS_NEGATIVE(x) (GET_FLOAT_BITS(x) < 0)
-#else
-#define IS_NEGATIVE(x) (x < 0.0F)
-#endif
-
-
-/***
- *** DIFFERENT_SIGNS: test if two floats have opposite signs
- ***/
-#if defined(USE_IEEE)
-#define DIFFERENT_SIGNS(x,y) ((GET_FLOAT_BITS(x) ^ GET_FLOAT_BITS(y)) & (1<<31))
-#else
-/* Could just use (x*y<0) except for the flatshading requirements.
- * Maybe there's a better way?
- */
-#define DIFFERENT_SIGNS(x,y) ((x) * (y) <= 0.0F && (x) - (y) != 0.0F)
-#endif
-
-
-/***
- *** CEILF: ceiling of float
- *** FLOORF: floor of float
- *** FABSF: absolute value of float
- *** LOGF: the natural logarithm (base e) of the value
- *** EXPF: raise e to the value
- *** LDEXPF: multiply value by an integral power of two
- *** FREXPF: extract mantissa and exponent from value
- ***/
-#if defined(__gnu_linux__)
-/* C99 functions */
-#define CEILF(x) ceilf(x)
-#define FLOORF(x) floorf(x)
-#define FABSF(x) fabsf(x)
-#define LOGF(x) logf(x)
-#define EXPF(x) expf(x)
-#define LDEXPF(x,y) ldexpf(x,y)
-#define FREXPF(x,y) frexpf(x,y)
-#else
-#define CEILF(x) ((GLfloat) ceil(x))
-#define FLOORF(x) ((GLfloat) floor(x))
-#define FABSF(x) ((GLfloat) fabs(x))
-#define LOGF(x) ((GLfloat) log(x))
-#define EXPF(x) ((GLfloat) exp(x))
-#define LDEXPF(x,y) ((GLfloat) ldexp(x,y))
-#define FREXPF(x,y) ((GLfloat) frexp(x,y))
-#endif
-
-
-/***
- *** IROUND: return (as an integer) float rounded to nearest integer
- ***/
-#if defined(USE_X86_ASM) && defined(__GNUC__) && defined(__i386__)
-static INLINE int iround(float f)
-{
- int r;
- __asm__ ("fistpl %0" : "=m" (r) : "t" (f) : "st");
- return r;
-}
-#define IROUND(x) iround(x)
-#elif defined(USE_X86_ASM) && defined(_MSC_VER)
-static INLINE int iround(float f)
-{
- int r;
- _asm {
- fld f
- fistp r
- }
- return r;
-}
-#define IROUND(x) iround(x)
-#elif defined(__WATCOMC__) && defined(__386__)
-long iround(float f);
-#pragma aux iround = \
- "push eax" \
- "fistp dword ptr [esp]" \
- "pop eax" \
- parm [8087] \
- value [eax] \
- modify exact [eax];
-#define IROUND(x) iround(x)
-#else
-#define IROUND(f) ((int) (((f) >= 0.0F) ? ((f) + 0.5F) : ((f) - 0.5F)))
-#endif
-
-#define IROUND64(f) ((GLint64) (((f) >= 0.0F) ? ((f) + 0.5F) : ((f) - 0.5F)))
-
-/***
- *** IROUND_POS: return (as an integer) positive float rounded to nearest int
- ***/
-#ifdef DEBUG
-#define IROUND_POS(f) (assert((f) >= 0.0F), IROUND(f))
-#else
-#define IROUND_POS(f) (IROUND(f))
-#endif
-
-
-/***
- *** IFLOOR: return (as an integer) floor of float
- ***/
-#if defined(USE_X86_ASM) && defined(__GNUC__) && defined(__i386__)
-/*
- * IEEE floor for computers that round to nearest or even.
- * 'f' must be between -4194304 and 4194303.
- * This floor operation is done by "(iround(f + .5) + iround(f - .5)) >> 1",
- * but uses some IEEE specific tricks for better speed.
- * Contributed by Josh Vanderhoof
- */
-static INLINE int ifloor(float f)
-{
- int ai, bi;
- double af, bf;
- af = (3 << 22) + 0.5 + (double)f;
- bf = (3 << 22) + 0.5 - (double)f;
- /* GCC generates an extra fstp/fld without this. */
- __asm__ ("fstps %0" : "=m" (ai) : "t" (af) : "st");
- __asm__ ("fstps %0" : "=m" (bi) : "t" (bf) : "st");
- return (ai - bi) >> 1;
-}
-#define IFLOOR(x) ifloor(x)
-#elif defined(USE_IEEE)
-static INLINE int ifloor(float f)
-{
- int ai, bi;
- double af, bf;
- fi_type u;
-
- af = (3 << 22) + 0.5 + (double)f;
- bf = (3 << 22) + 0.5 - (double)f;
- u.f = (float) af; ai = u.i;
- u.f = (float) bf; bi = u.i;
- return (ai - bi) >> 1;
-}
-#define IFLOOR(x) ifloor(x)
-#else
-static INLINE int ifloor(float f)
-{
- int i = IROUND(f);
- return (i > f) ? i - 1 : i;
-}
-#define IFLOOR(x) ifloor(x)
-#endif
-
-
-/***
- *** ICEIL: return (as an integer) ceiling of float
- ***/
-#if defined(USE_X86_ASM) && defined(__GNUC__) && defined(__i386__)
-/*
- * IEEE ceil for computers that round to nearest or even.
- * 'f' must be between -4194304 and 4194303.
- * This ceil operation is done by "(iround(f + .5) + iround(f - .5) + 1) >> 1",
- * but uses some IEEE specific tricks for better speed.
- * Contributed by Josh Vanderhoof
- */
-static INLINE int iceil(float f)
-{
- int ai, bi;
- double af, bf;
- af = (3 << 22) + 0.5 + (double)f;
- bf = (3 << 22) + 0.5 - (double)f;
- /* GCC generates an extra fstp/fld without this. */
- __asm__ ("fstps %0" : "=m" (ai) : "t" (af) : "st");
- __asm__ ("fstps %0" : "=m" (bi) : "t" (bf) : "st");
- return (ai - bi + 1) >> 1;
-}
-#define ICEIL(x) iceil(x)
-#elif defined(USE_IEEE)
-static INLINE int iceil(float f)
-{
- int ai, bi;
- double af, bf;
- fi_type u;
- af = (3 << 22) + 0.5 + (double)f;
- bf = (3 << 22) + 0.5 - (double)f;
- u.f = (float) af; ai = u.i;
- u.f = (float) bf; bi = u.i;
- return (ai - bi + 1) >> 1;
-}
-#define ICEIL(x) iceil(x)
-#else
-static INLINE int iceil(float f)
-{
- int i = IROUND(f);
- return (i < f) ? i + 1 : i;
-}
-#define ICEIL(x) iceil(x)
-#endif
-
-
-/**
- * Is x a power of two?
- */
-static INLINE int
-_mesa_is_pow_two(int x)
-{
- return !(x & (x - 1));
-}
-
-/**
- * Round given integer to next higer power of two
- * If X is zero result is undefined.
- *
- * Source for the fallback implementation is
- * Sean Eron Anderson's webpage "Bit Twiddling Hacks"
- * http://graphics.stanford.edu/~seander/bithacks.html
- *
- * When using builtin function have to do some work
- * for case when passed values 1 to prevent hiting
- * undefined result from __builtin_clz. Undefined
- * results would be different depending on optimization
- * level used for build.
- */
-static INLINE int32_t
-_mesa_next_pow_two_32(uint32_t x)
-{
-#if defined(__GNUC__) && \
- ((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4)
- uint32_t y = (x != 1);
- return (1 + y) << ((__builtin_clz(x - y) ^ 31) );
-#else
- x--;
- x |= x >> 1;
- x |= x >> 2;
- x |= x >> 4;
- x |= x >> 8;
- x |= x >> 16;
- x++;
- return x;
-#endif
-}
-
-static INLINE int64_t
-_mesa_next_pow_two_64(uint64_t x)
-{
-#if defined(__GNUC__) && \
- ((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4)
- uint64_t y = (x != 1);
- if (sizeof(x) == sizeof(long))
- return (1 + y) << ((__builtin_clzl(x - y) ^ 63));
- else
- return (1 + y) << ((__builtin_clzll(x - y) ^ 63));
-#else
- x--;
- x |= x >> 1;
- x |= x >> 2;
- x |= x >> 4;
- x |= x >> 8;
- x |= x >> 16;
- x |= x >> 32;
- x++;
- return x;
-#endif
-}
-
-
-/**
- * Return 1 if this is a little endian machine, 0 if big endian.
- */
-static INLINE GLboolean
-_mesa_little_endian(void)
-{
- const GLuint ui = 1; /* intentionally not static */
- return *((const GLubyte *) &ui);
-}
-
-
-
-/**********************************************************************
- * Functions
- */
-
-extern void *
-_mesa_align_malloc( size_t bytes, unsigned long alignment );
-
-extern void *
-_mesa_align_calloc( size_t bytes, unsigned long alignment );
-
-extern void
-_mesa_align_free( void *ptr );
-
-extern void *
-_mesa_align_realloc(void *oldBuffer, size_t oldSize, size_t newSize,
- unsigned long alignment);
-
-extern void *
-_mesa_exec_malloc( GLuint size );
-
-extern void
-_mesa_exec_free( void *addr );
-
-extern void *
-_mesa_realloc( void *oldBuffer, size_t oldSize, size_t newSize );
-
-extern void
-_mesa_memset16( unsigned short *dst, unsigned short val, size_t n );
-
-extern double
-_mesa_sqrtd(double x);
-
-extern float
-_mesa_sqrtf(float x);
-
-extern float
-_mesa_inv_sqrtf(float x);
-
-extern void
-_mesa_init_sqrt_table(void);
-
-#ifdef __GNUC__
-#define _mesa_ffs(i) ffs(i)
-#define _mesa_ffsll(i) ffsll(i)
-
-#if ((_GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4)
-#define _mesa_bitcount(i) __builtin_popcount(i)
-#else
-extern unsigned int
-_mesa_bitcount(unsigned int n);
-#endif
-
-#else
-extern int
-_mesa_ffs(int32_t i);
-
-extern int
-_mesa_ffsll(int64_t i);
-
-extern unsigned int
-_mesa_bitcount(unsigned int n);
-#endif
-
-extern GLhalfARB
-_mesa_float_to_half(float f);
-
-extern float
-_mesa_half_to_float(GLhalfARB h);
-
-
-extern void *
-_mesa_bsearch( const void *key, const void *base, size_t nmemb, size_t size,
- int (*compar)(const void *, const void *) );
-
-extern char *
-_mesa_getenv( const char *var );
-
-extern char *
-_mesa_strdup( const char *s );
-
-extern float
-_mesa_strtof( const char *s, char **end );
-
-extern unsigned int
-_mesa_str_checksum(const char *str);
-
-extern int
-_mesa_snprintf( char *str, size_t size, const char *fmt, ... ) PRINTFLIKE(3, 4);
-
-struct gl_context;
-
-extern void
-_mesa_warning( struct gl_context *gc, const char *fmtString, ... ) PRINTFLIKE(2, 3);
-
-extern void
-_mesa_problem( const struct gl_context *ctx, const char *fmtString, ... ) PRINTFLIKE(2, 3);
-
-extern void
-_mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... ) PRINTFLIKE(3, 4);
-
-extern void
-_mesa_debug( const struct gl_context *ctx, const char *fmtString, ... ) PRINTFLIKE(2, 3);
-
-
-#if defined(_MSC_VER) && !defined(snprintf)
-#define snprintf _snprintf
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* IMPORTS_H */
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.5
+ *
+ * Copyright (C) 1999-2008 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 imports.h
+ * Standard C library function wrappers.
+ *
+ * This file provides wrappers for all the standard C library functions
+ * like malloc(), free(), printf(), getenv(), etc.
+ */
+
+
+#ifndef IMPORTS_H
+#define IMPORTS_H
+
+
+#include "compiler.h"
+#include "glheader.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**********************************************************************/
+/** Memory macros */
+/*@{*/
+
+/** Allocate \p BYTES bytes */
+#define MALLOC(BYTES) malloc(BYTES)
+/** Allocate and zero \p BYTES bytes */
+#define CALLOC(BYTES) calloc(1, BYTES)
+/** Allocate a structure of type \p T */
+#define MALLOC_STRUCT(T) (struct T *) malloc(sizeof(struct T))
+/** Allocate and zero a structure of type \p T */
+#define CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T))
+/** Free memory */
+#define FREE(PTR) free(PTR)
+
+/*@}*/
+
+
+/*
+ * For GL_ARB_vertex_buffer_object we need to treat vertex array pointers
+ * as offsets into buffer stores. Since the vertex array pointer and
+ * buffer store pointer are both pointers and we need to add them, we use
+ * this macro.
+ * Both pointers/offsets are expressed in bytes.
+ */
+#define ADD_POINTERS(A, B) ( (GLubyte *) (A) + (uintptr_t) (B) )
+
+
+/**
+ * Sometimes we treat GLfloats as GLints. On x86 systems, moving a float
+ * as a int (thereby using integer registers instead of FP registers) is
+ * a performance win. Typically, this can be done with ordinary casts.
+ * But with gcc's -fstrict-aliasing flag (which defaults to on in gcc 3.0)
+ * these casts generate warnings.
+ * The following union typedef is used to solve that.
+ */
+typedef union { GLfloat f; GLint i; } fi_type;
+
+
+
+/**********************************************************************
+ * Math macros
+ */
+
+#define MAX_GLUSHORT 0xffff
+#define MAX_GLUINT 0xffffffff
+
+/* Degrees to radians conversion: */
+#define DEG2RAD (M_PI/180.0)
+
+
+/***
+ *** SQRTF: single-precision square root
+ ***/
+#if 0 /* _mesa_sqrtf() not accurate enough - temporarily disabled */
+# define SQRTF(X) _mesa_sqrtf(X)
+#else
+# define SQRTF(X) (float) sqrt((float) (X))
+#endif
+
+
+/***
+ *** INV_SQRTF: single-precision inverse square root
+ ***/
+#if 0
+#define INV_SQRTF(X) _mesa_inv_sqrt(X)
+#else
+#define INV_SQRTF(X) (1.0F / SQRTF(X)) /* this is faster on a P4 */
+#endif
+
+
+/**
+ * \name Work-arounds for platforms that lack C99 math functions
+ */
+/*@{*/
+#if (!defined(_XOPEN_SOURCE) || (_XOPEN_SOURCE < 600)) && !defined(_ISOC99_SOURCE) \
+ && (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)) \
+ && (!defined(_MSC_VER) || (_MSC_VER < 1400))
+#define acosf(f) ((float) acos(f))
+#define asinf(f) ((float) asin(f))
+#define atan2f(x,y) ((float) atan2(x,y))
+#define atanf(f) ((float) atan(f))
+#define cielf(f) ((float) ciel(f))
+#define cosf(f) ((float) cos(f))
+#define coshf(f) ((float) cosh(f))
+#define expf(f) ((float) exp(f))
+#define exp2f(f) ((float) exp2(f))
+#define floorf(f) ((float) floor(f))
+#define logf(f) ((float) log(f))
+#define log2f(f) ((float) log2(f))
+#define powf(x,y) ((float) pow(x,y))
+#define sinf(f) ((float) sin(f))
+#define sinhf(f) ((float) sinh(f))
+#define sqrtf(f) ((float) sqrt(f))
+#define tanf(f) ((float) tan(f))
+#define tanhf(f) ((float) tanh(f))
+#define acoshf(f) ((float) acosh(f))
+#define asinhf(f) ((float) asinh(f))
+#define atanhf(f) ((float) atanh(f))
+#endif
+
+#if defined(_MSC_VER)
+static INLINE float truncf(float x) { return x < 0.0f ? ceilf(x) : floorf(x); }
+static INLINE float exp2f(float x) { return powf(2.0f, x); }
+static INLINE float log2f(float x) { return logf(x) * 1.442695041f; }
+static INLINE float asinhf(float x) { return logf(x + sqrtf(x * x + 1.0f)); }
+static INLINE float acoshf(float x) { return logf(x + sqrtf(x * x - 1.0f)); }
+static INLINE float atanhf(float x) { return (logf(1.0f + x) - logf(1.0f - x)) / 2.0f; }
+static INLINE int isblank(int ch) { return ch == ' ' || ch == '\t'; }
+#define strtoll(p, e, b) _strtoi64(p, e, b)
+#endif
+/*@}*/
+
+/***
+ *** LOG2: Log base 2 of float
+ ***/
+#ifdef USE_IEEE
+#if 0
+/* This is pretty fast, but not accurate enough (only 2 fractional bits).
+ * Based on code from http://www.stereopsis.com/log2.html
+ */
+static INLINE GLfloat LOG2(GLfloat x)
+{
+ const GLfloat y = x * x * x * x;
+ const GLuint ix = *((GLuint *) &y);
+ const GLuint exp = (ix >> 23) & 0xFF;
+ const GLint log2 = ((GLint) exp) - 127;
+ return (GLfloat) log2 * (1.0 / 4.0); /* 4, because of x^4 above */
+}
+#endif
+/* Pretty fast, and accurate.
+ * Based on code from http://www.flipcode.com/totd/
+ */
+static INLINE GLfloat LOG2(GLfloat val)
+{
+ fi_type num;
+ GLint log_2;
+ num.f = val;
+ log_2 = ((num.i >> 23) & 255) - 128;
+ num.i &= ~(255 << 23);
+ num.i += 127 << 23;
+ num.f = ((-1.0f/3) * num.f + 2) * num.f - 2.0f/3;
+ return num.f + log_2;
+}
+#else
+/*
+ * NOTE: log_base_2(x) = log(x) / log(2)
+ * NOTE: 1.442695 = 1/log(2).
+ */
+#define LOG2(x) ((GLfloat) (log(x) * 1.442695F))
+#endif
+
+
+/***
+ *** IS_INF_OR_NAN: test if float is infinite or NaN
+ ***/
+#ifdef USE_IEEE
+static INLINE int IS_INF_OR_NAN( float x )
+{
+ fi_type tmp;
+ tmp.f = x;
+ return !(int)((unsigned int)((tmp.i & 0x7fffffff)-0x7f800000) >> 31);
+}
+#elif defined(isfinite)
+#define IS_INF_OR_NAN(x) (!isfinite(x))
+#elif defined(finite)
+#define IS_INF_OR_NAN(x) (!finite(x))
+#elif defined(__VMS)
+#define IS_INF_OR_NAN(x) (!finite(x))
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define IS_INF_OR_NAN(x) (!isfinite(x))
+#else
+#define IS_INF_OR_NAN(x) (!finite(x))
+#endif
+
+
+/***
+ *** IS_NEGATIVE: test if float is negative
+ ***/
+#if defined(USE_IEEE)
+static INLINE int GET_FLOAT_BITS( float x )
+{
+ fi_type fi;
+ fi.f = x;
+ return fi.i;
+}
+#define IS_NEGATIVE(x) (GET_FLOAT_BITS(x) < 0)
+#else
+#define IS_NEGATIVE(x) (x < 0.0F)
+#endif
+
+
+/***
+ *** DIFFERENT_SIGNS: test if two floats have opposite signs
+ ***/
+#if defined(USE_IEEE)
+#define DIFFERENT_SIGNS(x,y) ((GET_FLOAT_BITS(x) ^ GET_FLOAT_BITS(y)) & (1<<31))
+#else
+/* Could just use (x*y<0) except for the flatshading requirements.
+ * Maybe there's a better way?
+ */
+#define DIFFERENT_SIGNS(x,y) ((x) * (y) <= 0.0F && (x) - (y) != 0.0F)
+#endif
+
+
+/***
+ *** CEILF: ceiling of float
+ *** FLOORF: floor of float
+ *** FABSF: absolute value of float
+ *** LOGF: the natural logarithm (base e) of the value
+ *** EXPF: raise e to the value
+ *** LDEXPF: multiply value by an integral power of two
+ *** FREXPF: extract mantissa and exponent from value
+ ***/
+#if defined(__gnu_linux__)
+/* C99 functions */
+#define CEILF(x) ceilf(x)
+#define FLOORF(x) floorf(x)
+#define FABSF(x) fabsf(x)
+#define LOGF(x) logf(x)
+#define EXPF(x) expf(x)
+#define LDEXPF(x,y) ldexpf(x,y)
+#define FREXPF(x,y) frexpf(x,y)
+#else
+#define CEILF(x) ((GLfloat) ceil(x))
+#define FLOORF(x) ((GLfloat) floor(x))
+#define FABSF(x) ((GLfloat) fabs(x))
+#define LOGF(x) ((GLfloat) log(x))
+#define EXPF(x) ((GLfloat) exp(x))
+#define LDEXPF(x,y) ((GLfloat) ldexp(x,y))
+#define FREXPF(x,y) ((GLfloat) frexp(x,y))
+#endif
+
+
+/***
+ *** IROUND: return (as an integer) float rounded to nearest integer
+ ***/
+#if defined(USE_X86_ASM) && defined(__GNUC__) && defined(__i386__)
+static INLINE int iround(float f)
+{
+ int r;
+ __asm__ ("fistpl %0" : "=m" (r) : "t" (f) : "st");
+ return r;
+}
+#define IROUND(x) iround(x)
+#elif defined(USE_X86_ASM) && defined(_MSC_VER)
+static INLINE int iround(float f)
+{
+ int r;
+ _asm {
+ fld f
+ fistp r
+ }
+ return r;
+}
+#define IROUND(x) iround(x)
+#elif defined(__WATCOMC__) && defined(__386__)
+long iround(float f);
+#pragma aux iround = \
+ "push eax" \
+ "fistp dword ptr [esp]" \
+ "pop eax" \
+ parm [8087] \
+ value [eax] \
+ modify exact [eax];
+#define IROUND(x) iround(x)
+#else
+#define IROUND(f) ((int) (((f) >= 0.0F) ? ((f) + 0.5F) : ((f) - 0.5F)))
+#endif
+
+#define IROUND64(f) ((GLint64) (((f) >= 0.0F) ? ((f) + 0.5F) : ((f) - 0.5F)))
+
+/***
+ *** IROUND_POS: return (as an integer) positive float rounded to nearest int
+ ***/
+#ifdef DEBUG
+#define IROUND_POS(f) (assert((f) >= 0.0F), IROUND(f))
+#else
+#define IROUND_POS(f) (IROUND(f))
+#endif
+
+
+/***
+ *** IFLOOR: return (as an integer) floor of float
+ ***/
+#if defined(USE_X86_ASM) && defined(__GNUC__) && defined(__i386__)
+/*
+ * IEEE floor for computers that round to nearest or even.
+ * 'f' must be between -4194304 and 4194303.
+ * This floor operation is done by "(iround(f + .5) + iround(f - .5)) >> 1",
+ * but uses some IEEE specific tricks for better speed.
+ * Contributed by Josh Vanderhoof
+ */
+static INLINE int ifloor(float f)
+{
+ int ai, bi;
+ double af, bf;
+ af = (3 << 22) + 0.5 + (double)f;
+ bf = (3 << 22) + 0.5 - (double)f;
+ /* GCC generates an extra fstp/fld without this. */
+ __asm__ ("fstps %0" : "=m" (ai) : "t" (af) : "st");
+ __asm__ ("fstps %0" : "=m" (bi) : "t" (bf) : "st");
+ return (ai - bi) >> 1;
+}
+#define IFLOOR(x) ifloor(x)
+#elif defined(USE_IEEE)
+static INLINE int ifloor(float f)
+{
+ int ai, bi;
+ double af, bf;
+ fi_type u;
+
+ af = (3 << 22) + 0.5 + (double)f;
+ bf = (3 << 22) + 0.5 - (double)f;
+ u.f = (float) af; ai = u.i;
+ u.f = (float) bf; bi = u.i;
+ return (ai - bi) >> 1;
+}
+#define IFLOOR(x) ifloor(x)
+#else
+static INLINE int ifloor(float f)
+{
+ int i = IROUND(f);
+ return (i > f) ? i - 1 : i;
+}
+#define IFLOOR(x) ifloor(x)
+#endif
+
+
+/***
+ *** ICEIL: return (as an integer) ceiling of float
+ ***/
+#if defined(USE_X86_ASM) && defined(__GNUC__) && defined(__i386__)
+/*
+ * IEEE ceil for computers that round to nearest or even.
+ * 'f' must be between -4194304 and 4194303.
+ * This ceil operation is done by "(iround(f + .5) + iround(f - .5) + 1) >> 1",
+ * but uses some IEEE specific tricks for better speed.
+ * Contributed by Josh Vanderhoof
+ */
+static INLINE int iceil(float f)
+{
+ int ai, bi;
+ double af, bf;
+ af = (3 << 22) + 0.5 + (double)f;
+ bf = (3 << 22) + 0.5 - (double)f;
+ /* GCC generates an extra fstp/fld without this. */
+ __asm__ ("fstps %0" : "=m" (ai) : "t" (af) : "st");
+ __asm__ ("fstps %0" : "=m" (bi) : "t" (bf) : "st");
+ return (ai - bi + 1) >> 1;
+}
+#define ICEIL(x) iceil(x)
+#elif defined(USE_IEEE)
+static INLINE int iceil(float f)
+{
+ int ai, bi;
+ double af, bf;
+ fi_type u;
+ af = (3 << 22) + 0.5 + (double)f;
+ bf = (3 << 22) + 0.5 - (double)f;
+ u.f = (float) af; ai = u.i;
+ u.f = (float) bf; bi = u.i;
+ return (ai - bi + 1) >> 1;
+}
+#define ICEIL(x) iceil(x)
+#else
+static INLINE int iceil(float f)
+{
+ int i = IROUND(f);
+ return (i < f) ? i + 1 : i;
+}
+#define ICEIL(x) iceil(x)
+#endif
+
+
+/**
+ * Is x a power of two?
+ */
+static INLINE int
+_mesa_is_pow_two(int x)
+{
+ return !(x & (x - 1));
+}
+
+/**
+ * Round given integer to next higer power of two
+ * If X is zero result is undefined.
+ *
+ * Source for the fallback implementation is
+ * Sean Eron Anderson's webpage "Bit Twiddling Hacks"
+ * http://graphics.stanford.edu/~seander/bithacks.html
+ *
+ * When using builtin function have to do some work
+ * for case when passed values 1 to prevent hiting
+ * undefined result from __builtin_clz. Undefined
+ * results would be different depending on optimization
+ * level used for build.
+ */
+static INLINE int32_t
+_mesa_next_pow_two_32(uint32_t x)
+{
+#if defined(__GNUC__) && \
+ ((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4)
+ uint32_t y = (x != 1);
+ return (1 + y) << ((__builtin_clz(x - y) ^ 31) );
+#else
+ x--;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ x++;
+ return x;
+#endif
+}
+
+static INLINE int64_t
+_mesa_next_pow_two_64(uint64_t x)
+{
+#if defined(__GNUC__) && \
+ ((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4)
+ uint64_t y = (x != 1);
+ if (sizeof(x) == sizeof(long))
+ return (1 + y) << ((__builtin_clzl(x - y) ^ 63));
+ else
+ return (1 + y) << ((__builtin_clzll(x - y) ^ 63));
+#else
+ x--;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ x |= x >> 32;
+ x++;
+ return x;
+#endif
+}
+
+
+/**
+ * Return 1 if this is a little endian machine, 0 if big endian.
+ */
+static INLINE GLboolean
+_mesa_little_endian(void)
+{
+ const GLuint ui = 1; /* intentionally not static */
+ return *((const GLubyte *) &ui);
+}
+
+
+
+/**********************************************************************
+ * Functions
+ */
+
+extern void *
+_mesa_align_malloc( size_t bytes, unsigned long alignment );
+
+extern void *
+_mesa_align_calloc( size_t bytes, unsigned long alignment );
+
+extern void
+_mesa_align_free( void *ptr );
+
+extern void *
+_mesa_align_realloc(void *oldBuffer, size_t oldSize, size_t newSize,
+ unsigned long alignment);
+
+extern void *
+_mesa_exec_malloc( GLuint size );
+
+extern void
+_mesa_exec_free( void *addr );
+
+extern void *
+_mesa_realloc( void *oldBuffer, size_t oldSize, size_t newSize );
+
+extern void
+_mesa_memset16( unsigned short *dst, unsigned short val, size_t n );
+
+extern double
+_mesa_sqrtd(double x);
+
+extern float
+_mesa_sqrtf(float x);
+
+extern float
+_mesa_inv_sqrtf(float x);
+
+extern void
+_mesa_init_sqrt_table(void);
+
+#ifdef __GNUC__
+#define _mesa_ffs(i) ffs(i)
+#define _mesa_ffsll(i) ffsll(i)
+
+#if ((_GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4)
+#define _mesa_bitcount(i) __builtin_popcount(i)
+#else
+extern unsigned int
+_mesa_bitcount(unsigned int n);
+#endif
+
+#else
+extern int
+_mesa_ffs(int32_t i);
+
+extern int
+_mesa_ffsll(int64_t i);
+
+extern unsigned int
+_mesa_bitcount(unsigned int n);
+#endif
+
+extern GLhalfARB
+_mesa_float_to_half(float f);
+
+extern float
+_mesa_half_to_float(GLhalfARB h);
+
+
+extern void *
+_mesa_bsearch( const void *key, const void *base, size_t nmemb, size_t size,
+ int (*compar)(const void *, const void *) );
+
+extern char *
+_mesa_getenv( const char *var );
+
+extern char *
+_mesa_strdup( const char *s );
+
+extern float
+_mesa_strtof( const char *s, char **end );
+
+extern unsigned int
+_mesa_str_checksum(const char *str);
+
+extern int
+_mesa_snprintf( char *str, size_t size, const char *fmt, ... ) PRINTFLIKE(3, 4);
+
+struct gl_context;
+
+extern void
+_mesa_warning( struct gl_context *gc, const char *fmtString, ... ) PRINTFLIKE(2, 3);
+
+extern void
+_mesa_problem( const struct gl_context *ctx, const char *fmtString, ... ) PRINTFLIKE(2, 3);
+
+extern void
+_mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... ) PRINTFLIKE(3, 4);
+
+extern void
+_mesa_debug( const struct gl_context *ctx, const char *fmtString, ... ) PRINTFLIKE(2, 3);
+
+
+#if defined(_MSC_VER) && !defined(snprintf)
+#define snprintf _snprintf
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* IMPORTS_H */
diff --git a/mesalib/src/mesa/main/lines.c b/mesalib/src/mesa/main/lines.c
index 79bf5679d..1df409f45 100644
--- a/mesalib/src/mesa/main/lines.c
+++ b/mesalib/src/mesa/main/lines.c
@@ -1,117 +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 (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;
-}
+/*
+ * 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/queryobj.c b/mesalib/src/mesa/main/queryobj.c
index fa35c6ce5..dc9f18a65 100644
--- a/mesalib/src/mesa/main/queryobj.c
+++ b/mesalib/src/mesa/main/queryobj.c
@@ -1,623 +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 "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);
-}
+/*
+ * 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.
+ */
+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().
+ */
+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().
+ */
+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().
+ */
+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.
+ */
+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 11b0f884f..252cda845 100644
--- a/mesalib/src/mesa/main/shaderapi.c
+++ b/mesalib/src/mesa/main/shaderapi.c
@@ -1,1942 +1,1942 @@
-/*
- * Mesa 3-D graphics library
- *
- * Copyright (C) 2004-2008 Brian Paul All Rights Reserved.
- * Copyright (C) 2009-2010 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 shaderapi.c
- * \author Brian Paul
- *
- * Implementation of GLSL-related API functions.
- * The glUniform* functions are in uniforms.c
- *
- *
- * XXX things to do:
- * 1. Check that the right error code is generated for all _mesa_error() calls.
- * 2. Insert FLUSH_VERTICES calls in various places
- */
-
-
-#include "main/glheader.h"
-#include "main/context.h"
-#include "main/dispatch.h"
-#include "main/enums.h"
-#include "main/hash.h"
-#include "main/mfeatures.h"
-#include "main/mtypes.h"
-#include "main/shaderapi.h"
-#include "main/shaderobj.h"
-#include "program/program.h"
-#include "program/prog_parameter.h"
-#include "program/prog_uniform.h"
-#include "ralloc.h"
-#include <stdbool.h>
-#include "../glsl/glsl_parser_extras.h"
-
-/** Define this to enable shader substitution (see below) */
-#define SHADER_SUBST 0
-
-
-/**
- * Return mask of GLSL_x flags by examining the MESA_GLSL env var.
- */
-static GLbitfield
-get_shader_flags(void)
-{
- GLbitfield flags = 0x0;
- const char *env = _mesa_getenv("MESA_GLSL");
-
- if (env) {
- if (strstr(env, "dump"))
- flags |= GLSL_DUMP;
- if (strstr(env, "log"))
- flags |= GLSL_LOG;
- if (strstr(env, "nopvert"))
- flags |= GLSL_NOP_VERT;
- if (strstr(env, "nopfrag"))
- flags |= GLSL_NOP_FRAG;
- if (strstr(env, "nopt"))
- flags |= GLSL_NO_OPT;
- else if (strstr(env, "opt"))
- flags |= GLSL_OPT;
- if (strstr(env, "uniform"))
- flags |= GLSL_UNIFORMS;
- if (strstr(env, "useprog"))
- flags |= GLSL_USE_PROG;
- }
-
- return flags;
-}
-
-
-/**
- * Initialize context's shader state.
- */
-void
-_mesa_init_shader_state(struct gl_context *ctx)
-{
- /* Device drivers may override these to control what kind of instructions
- * are generated by the GLSL compiler.
- */
- struct gl_shader_compiler_options options;
- gl_shader_type sh;
-
- memset(&options, 0, sizeof(options));
- options.MaxUnrollIterations = 32;
-
- /* Default pragma settings */
- options.DefaultPragmas.Optimize = GL_TRUE;
-
- for (sh = 0; sh < MESA_SHADER_TYPES; ++sh)
- memcpy(&ctx->ShaderCompilerOptions[sh], &options, sizeof(options));
-
- ctx->Shader.Flags = get_shader_flags();
-}
-
-
-/**
- * Free the per-context shader-related state.
- */
-void
-_mesa_free_shader_state(struct gl_context *ctx)
-{
- _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentVertexProgram, NULL);
- _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentGeometryProgram,
- NULL);
- _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentFragmentProgram,
- NULL);
- _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL);
-}
-
-
-/**
- * Return the size of the given GLSL datatype, in floats (components).
- */
-GLint
-_mesa_sizeof_glsl_type(GLenum type)
-{
- switch (type) {
- case GL_FLOAT:
- case GL_INT:
- case GL_BOOL:
- case GL_SAMPLER_1D:
- case GL_SAMPLER_2D:
- case GL_SAMPLER_3D:
- case GL_SAMPLER_CUBE:
- case GL_SAMPLER_1D_SHADOW:
- case GL_SAMPLER_2D_SHADOW:
- case GL_SAMPLER_2D_RECT_ARB:
- case GL_SAMPLER_2D_RECT_SHADOW_ARB:
- case GL_SAMPLER_1D_ARRAY_EXT:
- case GL_SAMPLER_2D_ARRAY_EXT:
- case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
- case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
- case GL_SAMPLER_CUBE_SHADOW_EXT:
- return 1;
- case GL_FLOAT_VEC2:
- case GL_INT_VEC2:
- case GL_UNSIGNED_INT_VEC2:
- case GL_BOOL_VEC2:
- return 2;
- case GL_FLOAT_VEC3:
- case GL_INT_VEC3:
- case GL_UNSIGNED_INT_VEC3:
- case GL_BOOL_VEC3:
- return 3;
- case GL_FLOAT_VEC4:
- case GL_INT_VEC4:
- case GL_UNSIGNED_INT_VEC4:
- case GL_BOOL_VEC4:
- return 4;
- case GL_FLOAT_MAT2:
- case GL_FLOAT_MAT2x3:
- case GL_FLOAT_MAT2x4:
- return 8; /* two float[4] vectors */
- case GL_FLOAT_MAT3:
- case GL_FLOAT_MAT3x2:
- case GL_FLOAT_MAT3x4:
- return 12; /* three float[4] vectors */
- case GL_FLOAT_MAT4:
- case GL_FLOAT_MAT4x2:
- case GL_FLOAT_MAT4x3:
- return 16; /* four float[4] vectors */
- default:
- _mesa_problem(NULL, "Invalid type in _mesa_sizeof_glsl_type()");
- return 1;
- }
-}
-
-
-/**
- * Copy string from <src> to <dst>, up to maxLength characters, returning
- * length of <dst> in <length>.
- * \param src the strings source
- * \param maxLength max chars to copy
- * \param length returns number of chars copied
- * \param dst the string destination
- */
-void
-_mesa_copy_string(GLchar *dst, GLsizei maxLength,
- GLsizei *length, const GLchar *src)
-{
- GLsizei len;
- for (len = 0; len < maxLength - 1 && src && src[len]; len++)
- dst[len] = src[len];
- if (maxLength > 0)
- dst[len] = 0;
- if (length)
- *length = len;
-}
-
-
-
-/**
- * Confirm that the a shader type is valid and supported by the implementation
- *
- * \param ctx Current GL context
- * \param type Shader target
- *
- */
-static bool
-validate_shader_target(const struct gl_context *ctx, GLenum type)
-{
- switch (type) {
-#if FEATURE_ARB_fragment_shader
- case GL_FRAGMENT_SHADER:
- return ctx->Extensions.ARB_fragment_shader;
-#endif
-#if FEATURE_ARB_vertex_shader
- case GL_VERTEX_SHADER:
- return ctx->Extensions.ARB_vertex_shader;
-#endif
-#if FEATURE_ARB_geometry_shader4
- case GL_GEOMETRY_SHADER_ARB:
- return ctx->Extensions.ARB_geometry_shader4;
-#endif
- default:
- return false;
- }
-}
-
-
-/**
- * Find the length of the longest transform feedback varying name
- * which was specified with glTransformFeedbackVaryings().
- */
-static GLint
-longest_feedback_varying_name(const struct gl_shader_program *shProg)
-{
- GLuint i;
- GLint max = 0;
- for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
- GLint len = strlen(shProg->TransformFeedback.VaryingNames[i]);
- if (len > max)
- max = len;
- }
- return max;
-}
-
-
-
-static GLboolean
-is_program(struct gl_context *ctx, GLuint name)
-{
- struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
- return shProg ? GL_TRUE : GL_FALSE;
-}
-
-
-static GLboolean
-is_shader(struct gl_context *ctx, GLuint name)
-{
- struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
- return shader ? GL_TRUE : GL_FALSE;
-}
-
-
-/**
- * Attach shader to a shader program.
- */
-static void
-attach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
-{
- struct gl_shader_program *shProg;
- struct gl_shader *sh;
- GLuint i, n;
-
- shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader");
- if (!shProg)
- return;
-
- sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
- if (!sh) {
- return;
- }
-
- n = shProg->NumShaders;
- for (i = 0; i < n; i++) {
- if (shProg->Shaders[i] == sh) {
- /* The shader is already attched to this program. The
- * GL_ARB_shader_objects spec says:
- *
- * "The error INVALID_OPERATION is generated by AttachObjectARB
- * if <obj> is already attached to <containerObj>."
- */
- _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader");
- return;
- }
- }
-
- /* grow list */
- shProg->Shaders = (struct gl_shader **)
- _mesa_realloc(shProg->Shaders,
- n * sizeof(struct gl_shader *),
- (n + 1) * sizeof(struct gl_shader *));
- if (!shProg->Shaders) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
- return;
- }
-
- /* append */
- shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
- _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
- shProg->NumShaders++;
-}
-
-
-static GLint
-get_attrib_location(struct gl_context *ctx, GLuint program, const GLchar *name)
-{
- struct gl_shader_program *shProg
- = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
-
- if (!shProg) {
- return -1;
- }
-
- if (!shProg->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetAttribLocation(program not linked)");
- return -1;
- }
-
- if (!name)
- return -1;
-
- if (shProg->VertexProgram) {
- const struct gl_program_parameter_list *attribs =
- shProg->VertexProgram->Base.Attributes;
- if (attribs) {
- GLint i = _mesa_lookup_parameter_index(attribs, -1, name);
- if (i >= 0) {
- return attribs->Parameters[i].StateIndexes[0];
- }
- }
- }
- return -1;
-}
-
-
-static void
-bind_attrib_location(struct gl_context *ctx, GLuint program, GLuint index,
- const GLchar *name)
-{
- struct gl_shader_program *shProg;
- const GLint size = -1; /* unknown size */
- GLint i, oldIndex;
- GLenum datatype = GL_FLOAT_VEC4;
-
- shProg = _mesa_lookup_shader_program_err(ctx, program,
- "glBindAttribLocation");
- if (!shProg) {
- return;
- }
-
- if (!name)
- return;
-
- if (strncmp(name, "gl_", 3) == 0) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBindAttribLocation(illegal name)");
- return;
- }
-
- if (index >= ctx->Const.VertexProgram.MaxAttribs) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
- return;
- }
-
- if (shProg->LinkStatus) {
- /* get current index/location for the attribute */
- oldIndex = get_attrib_location(ctx, program, name);
- }
- else {
- oldIndex = -1;
- }
-
- /* this will replace the current value if it's already in the list */
- i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index);
- if (i < 0) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
- return;
- }
-
- /*
- * Note that this attribute binding won't go into effect until
- * glLinkProgram is called again.
- */
-}
-
-
-static void
-bind_frag_data_location(struct gl_context *ctx, GLuint program,
- GLuint colorNumber, const GLchar *name)
-{
- _mesa_problem(ctx, "bind_frag_data_location() not implemented yet");
-}
-
-
-static GLuint
-create_shader(struct gl_context *ctx, GLenum type)
-{
- struct gl_shader *sh;
- GLuint name;
-
- if (!validate_shader_target(ctx, type)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
- return 0;
- }
-
- name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
- sh = ctx->Driver.NewShader(ctx, name, type);
- _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
-
- return name;
-}
-
-
-static GLuint
-create_shader_program(struct gl_context *ctx)
-{
- GLuint name;
- struct gl_shader_program *shProg;
-
- name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
-
- shProg = ctx->Driver.NewShaderProgram(ctx, name);
-
- _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
-
- assert(shProg->RefCount == 1);
-
- return name;
-}
-
-
-/**
- * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
- * DeleteProgramARB.
- */
-static void
-delete_shader_program(struct gl_context *ctx, GLuint name)
-{
- /*
- * NOTE: deleting shaders/programs works a bit differently than
- * texture objects (and buffer objects, etc). Shader/program
- * handles/IDs exist in the hash table until the object is really
- * deleted (refcount==0). With texture objects, the handle/ID is
- * removed from the hash table in glDeleteTextures() while the tex
- * object itself might linger until its refcount goes to zero.
- */
- struct gl_shader_program *shProg;
-
- shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
- if (!shProg)
- return;
-
- shProg->DeletePending = GL_TRUE;
-
- /* effectively, decr shProg's refcount */
- _mesa_reference_shader_program(ctx, &shProg, NULL);
-}
-
-
-static void
-delete_shader(struct gl_context *ctx, GLuint shader)
-{
- struct gl_shader *sh;
-
- sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
- if (!sh)
- return;
-
- sh->DeletePending = GL_TRUE;
-
- /* effectively, decr sh's refcount */
- _mesa_reference_shader(ctx, &sh, NULL);
-}
-
-
-static void
-detach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
-{
- struct gl_shader_program *shProg;
- GLuint n;
- GLuint i, j;
-
- shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
- if (!shProg)
- return;
-
- n = shProg->NumShaders;
-
- for (i = 0; i < n; i++) {
- if (shProg->Shaders[i]->Name == shader) {
- /* found it */
- struct gl_shader **newList;
-
- /* release */
- _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
-
- /* alloc new, smaller array */
- newList = (struct gl_shader **)
- malloc((n - 1) * sizeof(struct gl_shader *));
- if (!newList) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
- return;
- }
- for (j = 0; j < i; j++) {
- newList[j] = shProg->Shaders[j];
- }
- while (++i < n)
- newList[j++] = shProg->Shaders[i];
- free(shProg->Shaders);
-
- shProg->Shaders = newList;
- shProg->NumShaders = n - 1;
-
-#ifdef DEBUG
- /* sanity check */
- {
- for (j = 0; j < shProg->NumShaders; j++) {
- assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
- shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
- assert(shProg->Shaders[j]->RefCount > 0);
- }
- }
-#endif
-
- return;
- }
- }
-
- /* not found */
- {
- GLenum err;
- if (is_shader(ctx, shader))
- err = GL_INVALID_OPERATION;
- else if (is_program(ctx, shader))
- err = GL_INVALID_OPERATION;
- else
- err = GL_INVALID_VALUE;
- _mesa_error(ctx, err, "glDetachProgram(shader)");
- return;
- }
-}
-
-
-static void
-get_active_attrib(struct gl_context *ctx, GLuint program, GLuint index,
- GLsizei maxLength, GLsizei *length, GLint *size,
- GLenum *type, GLchar *nameOut)
-{
- const struct gl_program_parameter_list *attribs = NULL;
- struct gl_shader_program *shProg;
-
- shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
- if (!shProg)
- return;
-
- if (shProg->VertexProgram)
- attribs = shProg->VertexProgram->Base.Attributes;
-
- if (!attribs || index >= attribs->NumParameters) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
- return;
- }
-
- _mesa_copy_string(nameOut, maxLength, length,
- attribs->Parameters[index].Name);
-
- if (size)
- *size = attribs->Parameters[index].Size
- / _mesa_sizeof_glsl_type(attribs->Parameters[index].DataType);
-
- if (type)
- *type = attribs->Parameters[index].DataType;
-}
-
-
-/**
- * Return list of shaders attached to shader program.
- */
-static void
-get_attached_shaders(struct gl_context *ctx, GLuint program, GLsizei maxCount,
- GLsizei *count, GLuint *obj)
-{
- struct gl_shader_program *shProg =
- _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
- if (shProg) {
- GLuint i;
- for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
- obj[i] = shProg->Shaders[i]->Name;
- }
- if (count)
- *count = i;
- }
-}
-
-
-static GLint
-get_frag_data_location(struct gl_context *ctx, GLuint program,
- const GLchar *name)
-{
- _mesa_problem(ctx, "get_frag_data_location() not implemented yet");
- return -1;
-}
-
-
-
-/**
- * glGetHandleARB() - return ID/name of currently bound shader program.
- */
-static GLuint
-get_handle(struct gl_context *ctx, GLenum pname)
-{
- if (pname == GL_PROGRAM_OBJECT_ARB) {
- if (ctx->Shader.ActiveProgram)
- return ctx->Shader.ActiveProgram->Name;
- else
- return 0;
- }
- else {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
- return 0;
- }
-}
-
-
-/**
- * glGetProgramiv() - get shader program state.
- * Note that this is for GLSL shader programs, not ARB vertex/fragment
- * programs (see glGetProgramivARB).
- */
-static void
-get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *params)
-{
- const struct gl_program_parameter_list *attribs;
- struct gl_shader_program *shProg
- = _mesa_lookup_shader_program(ctx, program);
-
- if (!shProg) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
- return;
- }
-
- if (shProg->VertexProgram)
- attribs = shProg->VertexProgram->Base.Attributes;
- else
- attribs = NULL;
-
- switch (pname) {
- case GL_DELETE_STATUS:
- *params = shProg->DeletePending;
- break;
- case GL_LINK_STATUS:
- *params = shProg->LinkStatus;
- break;
- case GL_VALIDATE_STATUS:
- *params = shProg->Validated;
- break;
- case GL_INFO_LOG_LENGTH:
- *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
- break;
- case GL_ATTACHED_SHADERS:
- *params = shProg->NumShaders;
- break;
- case GL_ACTIVE_ATTRIBUTES:
- *params = attribs ? attribs->NumParameters : 0;
- break;
- case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
- *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1;
- break;
- case GL_ACTIVE_UNIFORMS:
- *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
- break;
- case GL_ACTIVE_UNIFORM_MAX_LENGTH:
- *params = _mesa_longest_uniform_name(shProg->Uniforms);
- if (*params > 0)
- (*params)++; /* add one for terminating zero */
- break;
- case GL_PROGRAM_BINARY_LENGTH_OES:
- *params = 0;
- break;
-#if FEATURE_EXT_transform_feedback
- case GL_TRANSFORM_FEEDBACK_VARYINGS:
- *params = shProg->TransformFeedback.NumVarying;
- break;
- case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
- *params = longest_feedback_varying_name(shProg) + 1;
- break;
- case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
- *params = shProg->TransformFeedback.BufferMode;
- break;
-#endif
-#if FEATURE_ARB_geometry_shader4
- case GL_GEOMETRY_VERTICES_OUT_ARB:
- *params = shProg->Geom.VerticesOut;
- break;
- case GL_GEOMETRY_INPUT_TYPE_ARB:
- *params = shProg->Geom.InputType;
- break;
- case GL_GEOMETRY_OUTPUT_TYPE_ARB:
- *params = shProg->Geom.OutputType;
- break;
-#endif
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
- return;
- }
-}
-
-
-/**
- * glGetShaderiv() - get GLSL shader state
- */
-static void
-get_shaderiv(struct gl_context *ctx, GLuint name, GLenum pname, GLint *params)
-{
- struct gl_shader *shader =
- _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
-
- if (!shader) {
- return;
- }
-
- switch (pname) {
- case GL_SHADER_TYPE:
- *params = shader->Type;
- break;
- case GL_DELETE_STATUS:
- *params = shader->DeletePending;
- break;
- case GL_COMPILE_STATUS:
- *params = shader->CompileStatus;
- break;
- case GL_INFO_LOG_LENGTH:
- *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
- break;
- case GL_SHADER_SOURCE_LENGTH:
- *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
- return;
- }
-}
-
-
-static void
-get_program_info_log(struct gl_context *ctx, GLuint program, GLsizei bufSize,
- GLsizei *length, GLchar *infoLog)
-{
- struct gl_shader_program *shProg
- = _mesa_lookup_shader_program(ctx, program);
- if (!shProg) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
- return;
- }
- _mesa_copy_string(infoLog, bufSize, length, shProg->InfoLog);
-}
-
-
-static void
-get_shader_info_log(struct gl_context *ctx, GLuint shader, GLsizei bufSize,
- GLsizei *length, GLchar *infoLog)
-{
- struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
- if (!sh) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
- return;
- }
- _mesa_copy_string(infoLog, bufSize, length, sh->InfoLog);
-}
-
-
-/**
- * Return shader source code.
- */
-static void
-get_shader_source(struct gl_context *ctx, GLuint shader, GLsizei maxLength,
- GLsizei *length, GLchar *sourceOut)
-{
- struct gl_shader *sh;
- sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
- if (!sh) {
- return;
- }
- _mesa_copy_string(sourceOut, maxLength, length, sh->Source);
-}
-
-
-/**
- * Set/replace shader source code.
- */
-static void
-shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source)
-{
- struct gl_shader *sh;
-
- sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
- if (!sh)
- return;
-
- /* free old shader source string and install new one */
- if (sh->Source) {
- free((void *) sh->Source);
- }
- sh->Source = source;
- sh->CompileStatus = GL_FALSE;
-#ifdef DEBUG
- sh->SourceChecksum = _mesa_str_checksum(sh->Source);
-#endif
-}
-
-
-/**
- * Compile a shader.
- */
-static void
-compile_shader(struct gl_context *ctx, GLuint shaderObj)
-{
- struct gl_shader *sh;
- struct gl_shader_compiler_options *options;
-
- sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
- if (!sh)
- return;
-
- options = &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(sh->Type)];
-
- /* set default pragma state for shader */
- sh->Pragmas = options->DefaultPragmas;
-
- /* this call will set the sh->CompileStatus field to indicate if
- * compilation was successful.
- */
- _mesa_glsl_compile_shader(ctx, sh);
-}
-
-
-/**
- * Link a program's shaders.
- */
-static void
-link_program(struct gl_context *ctx, GLuint program)
-{
- struct gl_shader_program *shProg;
- struct gl_transform_feedback_object *obj =
- ctx->TransformFeedback.CurrentObject;
-
- shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
- if (!shProg)
- return;
-
- if (obj->Active
- && (shProg == ctx->Shader.CurrentVertexProgram
- || shProg == ctx->Shader.CurrentGeometryProgram
- || shProg == ctx->Shader.CurrentFragmentProgram)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glLinkProgram(transform feedback active");
- return;
- }
-
- FLUSH_VERTICES(ctx, _NEW_PROGRAM);
-
- _mesa_glsl_link_shader(ctx, shProg);
-
- /* debug code */
- if (0) {
- GLuint i;
-
- printf("Link %u shaders in program %u: %s\n",
- shProg->NumShaders, shProg->Name,
- shProg->LinkStatus ? "Success" : "Failed");
-
- for (i = 0; i < shProg->NumShaders; i++) {
- printf(" shader %u, type 0x%x\n",
- shProg->Shaders[i]->Name,
- shProg->Shaders[i]->Type);
- }
- }
-}
-
-
-/**
- * Print basic shader info (for debug).
- */
-static void
-print_shader_info(const struct gl_shader_program *shProg)
-{
- GLuint i;
-
- printf("Mesa: glUseProgram(%u)\n", shProg->Name);
- for (i = 0; i < shProg->NumShaders; i++) {
- const char *s;
- switch (shProg->Shaders[i]->Type) {
- case GL_VERTEX_SHADER:
- s = "vertex";
- break;
- case GL_FRAGMENT_SHADER:
- s = "fragment";
- break;
- case GL_GEOMETRY_SHADER:
- s = "geometry";
- break;
- default:
- s = "";
- }
- printf(" %s shader %u, checksum %u\n", s,
- shProg->Shaders[i]->Name,
- shProg->Shaders[i]->SourceChecksum);
- }
- if (shProg->VertexProgram)
- printf(" vert prog %u\n", shProg->VertexProgram->Base.Id);
- if (shProg->FragmentProgram)
- printf(" frag prog %u\n", shProg->FragmentProgram->Base.Id);
-}
-
-
-/**
- * Use the named shader program for subsequent glUniform calls
- */
-void
-_mesa_active_program(struct gl_context *ctx, struct gl_shader_program *shProg,
- const char *caller)
-{
- if ((shProg != NULL) && !shProg->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(program %u not linked)", caller, shProg->Name);
- return;
- }
-
- if (ctx->Shader.ActiveProgram != shProg) {
- _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, shProg);
- }
-}
-
-/**
- */
-static bool
-use_shader_program(struct gl_context *ctx, GLenum type,
- struct gl_shader_program *shProg)
-{
- struct gl_shader_program **target;
-
- switch (type) {
-#if FEATURE_ARB_vertex_shader
- case GL_VERTEX_SHADER:
- target = &ctx->Shader.CurrentVertexProgram;
- if ((shProg == NULL)
- || (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)) {
- shProg = NULL;
- }
- break;
-#endif
-#if FEATURE_ARB_geometry_shader4
- case GL_GEOMETRY_SHADER_ARB:
- target = &ctx->Shader.CurrentGeometryProgram;
- if ((shProg == NULL)
- || (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] == NULL)) {
- shProg = NULL;
- }
- break;
-#endif
-#if FEATURE_ARB_fragment_shader
- case GL_FRAGMENT_SHADER:
- target = &ctx->Shader.CurrentFragmentProgram;
- if ((shProg == NULL)
- || (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)) {
- shProg = NULL;
- }
- break;
-#endif
- default:
- return false;
- }
-
- if (*target != shProg) {
- FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
- _mesa_reference_shader_program(ctx, target, shProg);
- return true;
- }
-
- return false;
-}
-
-/**
- * Use the named shader program for subsequent rendering.
- */
-void
-_mesa_use_program(struct gl_context *ctx, struct gl_shader_program *shProg)
-{
- use_shader_program(ctx, GL_VERTEX_SHADER, shProg);
- use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, shProg);
- use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg);
- _mesa_active_program(ctx, shProg, "glUseProgram");
-
- if (ctx->Driver.UseProgram)
- ctx->Driver.UseProgram(ctx, shProg);
-}
-
-
-/**
- * Validate a program's samplers.
- * Specifically, check that there aren't two samplers of different types
- * pointing to the same texture unit.
- * \return GL_TRUE if valid, GL_FALSE if invalid
- */
-static GLboolean
-validate_samplers(const struct gl_program *prog, char *errMsg)
-{
- static const char *targetName[] = {
- "TEXTURE_2D_ARRAY",
- "TEXTURE_1D_ARRAY",
- "TEXTURE_CUBE",
- "TEXTURE_3D",
- "TEXTURE_RECT",
- "TEXTURE_2D",
- "TEXTURE_1D",
- };
- GLint targetUsed[MAX_TEXTURE_IMAGE_UNITS];
- GLbitfield samplersUsed = prog->SamplersUsed;
- GLuint i;
-
- assert(Elements(targetName) == NUM_TEXTURE_TARGETS);
-
- if (samplersUsed == 0x0)
- return GL_TRUE;
-
- for (i = 0; i < Elements(targetUsed); i++)
- targetUsed[i] = -1;
-
- /* walk over bits which are set in 'samplers' */
- while (samplersUsed) {
- GLuint unit;
- gl_texture_index target;
- GLint sampler = _mesa_ffs(samplersUsed) - 1;
- assert(sampler >= 0);
- assert(sampler < MAX_TEXTURE_IMAGE_UNITS);
- unit = prog->SamplerUnits[sampler];
- target = prog->SamplerTargets[sampler];
- if (targetUsed[unit] != -1 && targetUsed[unit] != (int) target) {
- _mesa_snprintf(errMsg, 100,
- "Texture unit %d is accessed both as %s and %s",
- unit, targetName[targetUsed[unit]], targetName[target]);
- return GL_FALSE;
- }
- targetUsed[unit] = target;
- samplersUsed ^= (1 << sampler);
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Do validation of the given shader program.
- * \param errMsg returns error message if validation fails.
- * \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg)
- */
-static GLboolean
-validate_shader_program(const struct gl_shader_program *shProg,
- char *errMsg)
-{
- const struct gl_vertex_program *vp = shProg->VertexProgram;
- const struct gl_fragment_program *fp = shProg->FragmentProgram;
-
- if (!shProg->LinkStatus) {
- return GL_FALSE;
- }
-
- /* From the GL spec, a program is invalid if any of these are true:
-
- any two active samplers in the current program object are of
- different types, but refer to the same texture image unit,
-
- any active sampler in the current program object refers to a texture
- image unit where fixed-function fragment processing accesses a
- texture target that does not match the sampler type, or
-
- the sum of the number of active samplers in the program and the
- number of texture image units enabled for fixed-function fragment
- processing exceeds the combined limit on the total number of texture
- image units allowed.
- */
-
-
- /*
- * Check: any two active samplers in the current program object are of
- * different types, but refer to the same texture image unit,
- */
- if (vp && !validate_samplers(&vp->Base, errMsg)) {
- return GL_FALSE;
- }
- if (fp && !validate_samplers(&fp->Base, errMsg)) {
- return GL_FALSE;
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Called via glValidateProgram()
- */
-static void
-validate_program(struct gl_context *ctx, GLuint program)
-{
- struct gl_shader_program *shProg;
- char errMsg[100];
-
- shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
- if (!shProg) {
- return;
- }
-
- shProg->Validated = validate_shader_program(shProg, errMsg);
- if (!shProg->Validated) {
- /* update info log */
- if (shProg->InfoLog) {
- ralloc_free(shProg->InfoLog);
- }
- shProg->InfoLog = ralloc_strdup(shProg, errMsg);
- }
-}
-
-
-
-void GLAPIENTRY
-_mesa_AttachObjectARB(GLhandleARB program, GLhandleARB shader)
-{
- GET_CURRENT_CONTEXT(ctx);
- attach_shader(ctx, program, shader);
-}
-
-
-void GLAPIENTRY
-_mesa_AttachShader(GLuint program, GLuint shader)
-{
- GET_CURRENT_CONTEXT(ctx);
- attach_shader(ctx, program, shader);
-}
-
-
-void GLAPIENTRY
-_mesa_BindAttribLocationARB(GLhandleARB program, GLuint index,
- const GLcharARB *name)
-{
- GET_CURRENT_CONTEXT(ctx);
- bind_attrib_location(ctx, program, index, name);
-}
-
-
-/* GL_EXT_gpu_shader4, GL3 */
-void GLAPIENTRY
-_mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
- const GLchar *name)
-{
- GET_CURRENT_CONTEXT(ctx);
- bind_frag_data_location(ctx, program, colorNumber, name);
-}
-
-
-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);
-}
-
-
-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);
-}
-
-
-GLhandleARB GLAPIENTRY
-_mesa_CreateShaderObjectARB(GLenum type)
-{
- GET_CURRENT_CONTEXT(ctx);
- return create_shader(ctx, type);
-}
-
-
-GLuint GLAPIENTRY
-_mesa_CreateProgram(void)
-{
- GET_CURRENT_CONTEXT(ctx);
- if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(ctx, "glCreateProgram\n");
- return create_shader_program(ctx);
-}
-
-
-GLhandleARB GLAPIENTRY
-_mesa_CreateProgramObjectARB(void)
-{
- GET_CURRENT_CONTEXT(ctx);
- return create_shader_program(ctx);
-}
-
-
-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)) {
- delete_shader_program(ctx, obj);
- }
- else if (is_shader(ctx, obj)) {
- delete_shader(ctx, obj);
- }
- else {
- /* error? */
- }
- }
-}
-
-
-void GLAPIENTRY
-_mesa_DeleteProgram(GLuint name)
-{
- if (name) {
- GET_CURRENT_CONTEXT(ctx);
- delete_shader_program(ctx, name);
- }
-}
-
-
-void GLAPIENTRY
-_mesa_DeleteShader(GLuint name)
-{
- if (name) {
- GET_CURRENT_CONTEXT(ctx);
- delete_shader(ctx, name);
- }
-}
-
-
-void GLAPIENTRY
-_mesa_DetachObjectARB(GLhandleARB program, GLhandleARB shader)
-{
- GET_CURRENT_CONTEXT(ctx);
- detach_shader(ctx, program, shader);
-}
-
-
-void GLAPIENTRY
-_mesa_DetachShader(GLuint program, GLuint shader)
-{
- GET_CURRENT_CONTEXT(ctx);
- detach_shader(ctx, program, shader);
-}
-
-
-void GLAPIENTRY
-_mesa_GetActiveAttribARB(GLhandleARB program, GLuint index,
- GLsizei maxLength, GLsizei * length, GLint * size,
- GLenum * type, GLcharARB * name)
-{
- GET_CURRENT_CONTEXT(ctx);
- get_active_attrib(ctx, program, index, maxLength, length, size, type, name);
-}
-
-
-void GLAPIENTRY
-_mesa_GetAttachedObjectsARB(GLhandleARB container, GLsizei maxCount,
- GLsizei * count, GLhandleARB * obj)
-{
- GET_CURRENT_CONTEXT(ctx);
- get_attached_shaders(ctx, container, maxCount, count, obj);
-}
-
-
-void GLAPIENTRY
-_mesa_GetAttachedShaders(GLuint program, GLsizei maxCount,
- GLsizei *count, GLuint *obj)
-{
- GET_CURRENT_CONTEXT(ctx);
- get_attached_shaders(ctx, program, maxCount, count, obj);
-}
-
-
-GLint GLAPIENTRY
-_mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name)
-{
- GET_CURRENT_CONTEXT(ctx);
- return get_attrib_location(ctx, program, name);
-}
-
-
-/* GL_EXT_gpu_shader4, GL3 */
-GLint GLAPIENTRY
-_mesa_GetFragDataLocation(GLuint program, const GLchar *name)
-{
- GET_CURRENT_CONTEXT(ctx);
- return get_frag_data_location(ctx, program, name);
-}
-
-
-
-void GLAPIENTRY
-_mesa_GetInfoLogARB(GLhandleARB object, GLsizei maxLength, GLsizei * length,
- GLcharARB * infoLog)
-{
- GET_CURRENT_CONTEXT(ctx);
- if (is_program(ctx, object)) {
- get_program_info_log(ctx, object, maxLength, length, infoLog);
- }
- else if (is_shader(ctx, object)) {
- get_shader_info_log(ctx, object, maxLength, length, infoLog);
- }
- else {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetInfoLogARB");
- }
-}
-
-
-void GLAPIENTRY
-_mesa_GetObjectParameterivARB(GLhandleARB object, GLenum pname, GLint *params)
-{
- GET_CURRENT_CONTEXT(ctx);
- /* Implement in terms of GetProgramiv, GetShaderiv */
- if (is_program(ctx, object)) {
- if (pname == GL_OBJECT_TYPE_ARB) {
- *params = GL_PROGRAM_OBJECT_ARB;
- }
- else {
- get_programiv(ctx, object, pname, params);
- }
- }
- else if (is_shader(ctx, object)) {
- if (pname == GL_OBJECT_TYPE_ARB) {
- *params = GL_SHADER_OBJECT_ARB;
- }
- else {
- get_shaderiv(ctx, object, pname, params);
- }
- }
- else {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetObjectParameterivARB");
- }
-}
-
-
-void GLAPIENTRY
-_mesa_GetObjectParameterfvARB(GLhandleARB object, GLenum pname,
- GLfloat *params)
-{
- GLint iparams[1]; /* XXX is one element enough? */
- _mesa_GetObjectParameterivARB(object, pname, iparams);
- params[0] = (GLfloat) iparams[0];
-}
-
-
-void GLAPIENTRY
-_mesa_GetProgramiv(GLuint program, GLenum pname, GLint *params)
-{
- GET_CURRENT_CONTEXT(ctx);
- get_programiv(ctx, program, pname, params);
-}
-
-
-void GLAPIENTRY
-_mesa_GetShaderiv(GLuint shader, GLenum pname, GLint *params)
-{
- GET_CURRENT_CONTEXT(ctx);
- get_shaderiv(ctx, shader, pname, params);
-}
-
-
-void GLAPIENTRY
-_mesa_GetProgramInfoLog(GLuint program, GLsizei bufSize,
- GLsizei *length, GLchar *infoLog)
-{
- GET_CURRENT_CONTEXT(ctx);
- get_program_info_log(ctx, program, bufSize, length, infoLog);
-}
-
-
-void GLAPIENTRY
-_mesa_GetShaderInfoLog(GLuint shader, GLsizei bufSize,
- GLsizei *length, GLchar *infoLog)
-{
- GET_CURRENT_CONTEXT(ctx);
- get_shader_info_log(ctx, shader, bufSize, length, infoLog);
-}
-
-
-void GLAPIENTRY
-_mesa_GetShaderSourceARB(GLhandleARB shader, GLsizei maxLength,
- GLsizei *length, GLcharARB *sourceOut)
-{
- GET_CURRENT_CONTEXT(ctx);
- get_shader_source(ctx, shader, maxLength, length, sourceOut);
-}
-
-
-GLhandleARB GLAPIENTRY
-_mesa_GetHandleARB(GLenum pname)
-{
- GET_CURRENT_CONTEXT(ctx);
- return get_handle(ctx, pname);
-}
-
-
-GLboolean GLAPIENTRY
-_mesa_IsProgram(GLuint name)
-{
- GET_CURRENT_CONTEXT(ctx);
- return is_program(ctx, name);
-}
-
-
-GLboolean GLAPIENTRY
-_mesa_IsShader(GLuint name)
-{
- GET_CURRENT_CONTEXT(ctx);
- return is_shader(ctx, name);
-}
-
-
-void GLAPIENTRY
-_mesa_LinkProgramARB(GLhandleARB programObj)
-{
- GET_CURRENT_CONTEXT(ctx);
- link_program(ctx, programObj);
-}
-
-
-
-/**
- * Read shader source code from a file.
- * Useful for debugging to override an app's shader.
- */
-static GLcharARB *
-read_shader(const char *fname)
-{
- const int max = 50*1000;
- FILE *f = fopen(fname, "r");
- GLcharARB *buffer, *shader;
- int len;
-
- if (!f) {
- return NULL;
- }
-
- buffer = (char *) malloc(max);
- len = fread(buffer, 1, max, f);
- buffer[len] = 0;
-
- fclose(f);
-
- shader = _mesa_strdup(buffer);
- free(buffer);
-
- return shader;
-}
-
-
-/**
- * Called via glShaderSource() and glShaderSourceARB() API functions.
- * Basically, concatenate the source code strings into one long string
- * and pass it to _mesa_shader_source().
- */
-void GLAPIENTRY
-_mesa_ShaderSourceARB(GLhandleARB shaderObj, GLsizei count,
- const GLcharARB ** string, const GLint * length)
-{
- GET_CURRENT_CONTEXT(ctx);
- GLint *offsets;
- GLsizei i, totalLength;
- GLcharARB *source;
- GLuint checksum;
-
- if (!shaderObj || string == NULL) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB");
- return;
- }
-
- /*
- * This array holds offsets of where the appropriate string ends, thus the
- * last element will be set to the total length of the source code.
- */
- offsets = (GLint *) malloc(count * sizeof(GLint));
- if (offsets == NULL) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB");
- return;
- }
-
- for (i = 0; i < count; i++) {
- if (string[i] == NULL) {
- free((GLvoid *) offsets);
- _mesa_error(ctx, GL_INVALID_OPERATION, "glShaderSourceARB(null string)");
- return;
- }
- if (length == NULL || length[i] < 0)
- offsets[i] = strlen(string[i]);
- else
- offsets[i] = length[i];
- /* accumulate string lengths */
- if (i > 0)
- offsets[i] += offsets[i - 1];
- }
-
- /* Total length of source string is sum off all strings plus two.
- * One extra byte for terminating zero, another extra byte to silence
- * valgrind warnings in the parser/grammer code.
- */
- totalLength = offsets[count - 1] + 2;
- source = (GLcharARB *) malloc(totalLength * sizeof(GLcharARB));
- if (source == NULL) {
- free((GLvoid *) offsets);
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB");
- return;
- }
-
- for (i = 0; i < count; i++) {
- GLint start = (i > 0) ? offsets[i - 1] : 0;
- memcpy(source + start, string[i],
- (offsets[i] - start) * sizeof(GLcharARB));
- }
- source[totalLength - 1] = '\0';
- source[totalLength - 2] = '\0';
-
- if (SHADER_SUBST) {
- /* Compute the shader's source code checksum then try to open a file
- * named newshader_<CHECKSUM>. If it exists, use it in place of the
- * original shader source code. For debugging.
- */
- char filename[100];
- GLcharARB *newSource;
-
- checksum = _mesa_str_checksum(source);
-
- _mesa_snprintf(filename, sizeof(filename), "newshader_%d", checksum);
-
- newSource = read_shader(filename);
- if (newSource) {
- fprintf(stderr, "Mesa: Replacing shader %u chksum=%d with %s\n",
- shaderObj, checksum, filename);
- free(source);
- source = newSource;
- }
- }
-
- shader_source(ctx, shaderObj, source);
-
- if (SHADER_SUBST) {
- struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
- if (sh)
- sh->SourceChecksum = checksum; /* save original checksum */
- }
-
- free(offsets);
-}
-
-
-void GLAPIENTRY
-_mesa_UseProgramObjectARB(GLhandleARB program)
-{
- GET_CURRENT_CONTEXT(ctx);
- struct gl_shader_program *shProg;
- struct gl_transform_feedback_object *obj =
- ctx->TransformFeedback.CurrentObject;
-
- if (obj->Active) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUseProgram(transform feedback active)");
- return;
- }
-
- if (program) {
- shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
- if (!shProg) {
- return;
- }
- if (!shProg->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUseProgram(program %u not linked)", program);
- return;
- }
-
- /* debug code */
- if (ctx->Shader.Flags & GLSL_USE_PROG) {
- print_shader_info(shProg);
- }
- }
- else {
- shProg = NULL;
- }
-
- _mesa_use_program(ctx, shProg);
-}
-
-
-void GLAPIENTRY
-_mesa_ValidateProgramARB(GLhandleARB program)
-{
- GET_CURRENT_CONTEXT(ctx);
- validate_program(ctx, program);
-}
-
-#ifdef FEATURE_ES2
-
-void GLAPIENTRY
-_mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype,
- GLint* range, GLint* precision)
-{
- const struct gl_program_constants *limits;
- const struct gl_precision *p;
- GET_CURRENT_CONTEXT(ctx);
-
- switch (shadertype) {
- case GL_VERTEX_SHADER:
- limits = &ctx->Const.VertexProgram;
- break;
- case GL_FRAGMENT_SHADER:
- limits = &ctx->Const.FragmentProgram;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetShaderPrecisionFormat(shadertype)");
- return;
- }
-
- switch (precisiontype) {
- case GL_LOW_FLOAT:
- p = &limits->LowFloat;
- break;
- case GL_MEDIUM_FLOAT:
- p = &limits->MediumFloat;
- break;
- case GL_HIGH_FLOAT:
- p = &limits->HighFloat;
- break;
- case GL_LOW_INT:
- p = &limits->LowInt;
- break;
- case GL_MEDIUM_INT:
- p = &limits->MediumInt;
- break;
- case GL_HIGH_INT:
- p = &limits->HighInt;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetShaderPrecisionFormat(precisiontype)");
- return;
- }
-
- range[0] = p->RangeMin;
- range[1] = p->RangeMax;
- precision[0] = p->Precision;
-}
-
-
-void GLAPIENTRY
-_mesa_ReleaseShaderCompiler(void)
-{
- _mesa_destroy_shader_compiler_caches();
-}
-
-
-void GLAPIENTRY
-_mesa_ShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat,
- const void* binary, GLint length)
-{
- GET_CURRENT_CONTEXT(ctx);
- (void) n;
- (void) shaders;
- (void) binaryformat;
- (void) binary;
- (void) length;
- _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__);
-}
-
-#endif /* FEATURE_ES2 */
-
-
-#if FEATURE_ARB_geometry_shader4
-
-void GLAPIENTRY
-_mesa_ProgramParameteriARB(GLuint program, GLenum pname,
- GLint value)
-{
- struct gl_shader_program *shProg;
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- shProg = _mesa_lookup_shader_program_err(ctx, program,
- "glProgramParameteri");
- if (!shProg)
- return;
-
- switch (pname) {
- case GL_GEOMETRY_VERTICES_OUT_ARB:
- if (value < 1 ||
- (unsigned) value > ctx->Const.GeometryProgram.MaxGeometryOutputVertices) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glProgramParameteri(GL_GEOMETRY_VERTICES_OUT_ARB=%d",
- value);
- return;
- }
- shProg->Geom.VerticesOut = value;
- break;
- case GL_GEOMETRY_INPUT_TYPE_ARB:
- switch (value) {
- case GL_POINTS:
- case GL_LINES:
- case GL_LINES_ADJACENCY_ARB:
- case GL_TRIANGLES:
- case GL_TRIANGLES_ADJACENCY_ARB:
- shProg->Geom.InputType = value;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glProgramParameteri(geometry input type = %s",
- _mesa_lookup_enum_by_nr(value));
- return;
- }
- break;
- case GL_GEOMETRY_OUTPUT_TYPE_ARB:
- switch (value) {
- case GL_POINTS:
- case GL_LINE_STRIP:
- case GL_TRIANGLE_STRIP:
- shProg->Geom.OutputType = value;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glProgramParameteri(geometry output type = %s",
- _mesa_lookup_enum_by_nr(value));
- return;
- }
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameteriARB(pname=%s)",
- _mesa_lookup_enum_by_nr(pname));
- break;
- }
-}
-
-#endif
-
-void
-_mesa_use_shader_program(struct gl_context *ctx, GLenum type,
- struct gl_shader_program *shProg)
-{
- use_shader_program(ctx, type, shProg);
-
- if (ctx->Driver.UseProgram)
- ctx->Driver.UseProgram(ctx, shProg);
-}
-
-void GLAPIENTRY
-_mesa_UseShaderProgramEXT(GLenum type, GLuint program)
-{
- GET_CURRENT_CONTEXT(ctx);
- struct gl_shader_program *shProg = NULL;
-
- if (!validate_shader_target(ctx, type)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)");
- return;
- }
-
- if (ctx->TransformFeedback.CurrentObject->Active) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUseShaderProgramEXT(transform feedback is active)");
- return;
- }
-
- if (program) {
- shProg = _mesa_lookup_shader_program_err(ctx, program,
- "glUseShaderProgramEXT");
- if (shProg == NULL)
- return;
-
- if (!shProg->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUseShaderProgramEXT(program not linked)");
- return;
- }
- }
-
- _mesa_use_shader_program(ctx, type, shProg);
-}
-
-void GLAPIENTRY
-_mesa_ActiveProgramEXT(GLuint program)
-{
- GET_CURRENT_CONTEXT(ctx);
- struct gl_shader_program *shProg = (program != 0)
- ? _mesa_lookup_shader_program_err(ctx, program, "glActiveProgramEXT")
- : NULL;
-
- _mesa_active_program(ctx, shProg, "glActiveProgramEXT");
- return;
-}
-
-GLuint GLAPIENTRY
-_mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string)
-{
- GET_CURRENT_CONTEXT(ctx);
- const GLuint shader = create_shader(ctx, type);
- GLuint program = 0;
-
- if (shader) {
- shader_source(ctx, shader, _mesa_strdup(string));
- compile_shader(ctx, shader);
-
- program = create_shader_program(ctx);
- if (program) {
- struct gl_shader_program *shProg;
- struct gl_shader *sh;
- GLint compiled = GL_FALSE;
-
- shProg = _mesa_lookup_shader_program(ctx, program);
- sh = _mesa_lookup_shader(ctx, shader);
-
- get_shaderiv(ctx, shader, GL_COMPILE_STATUS, &compiled);
- if (compiled) {
- attach_shader(ctx, program, shader);
- link_program(ctx, program);
- detach_shader(ctx, program, shader);
-
-#if 0
- /* Possibly... */
- if (active-user-defined-varyings-in-linked-program) {
- append-error-to-info-log;
- shProg->LinkStatus = GL_FALSE;
- }
-#endif
- }
-
- ralloc_strcat(&shProg->InfoLog, sh->InfoLog);
- }
-
- delete_shader(ctx, shader);
- }
-
- return program;
-}
-
-/**
- * Plug in shader-related functions into API dispatch table.
- */
-void
-_mesa_init_shader_dispatch(struct _glapi_table *exec)
-{
-#if FEATURE_GL
- /* GL_ARB_vertex/fragment_shader */
- SET_DeleteObjectARB(exec, _mesa_DeleteObjectARB);
- SET_GetHandleARB(exec, _mesa_GetHandleARB);
- SET_DetachObjectARB(exec, _mesa_DetachObjectARB);
- SET_CreateShaderObjectARB(exec, _mesa_CreateShaderObjectARB);
- SET_ShaderSourceARB(exec, _mesa_ShaderSourceARB);
- SET_CompileShaderARB(exec, _mesa_CompileShaderARB);
- SET_CreateProgramObjectARB(exec, _mesa_CreateProgramObjectARB);
- SET_AttachObjectARB(exec, _mesa_AttachObjectARB);
- SET_LinkProgramARB(exec, _mesa_LinkProgramARB);
- SET_UseProgramObjectARB(exec, _mesa_UseProgramObjectARB);
- SET_ValidateProgramARB(exec, _mesa_ValidateProgramARB);
- SET_GetObjectParameterfvARB(exec, _mesa_GetObjectParameterfvARB);
- SET_GetObjectParameterivARB(exec, _mesa_GetObjectParameterivARB);
- SET_GetInfoLogARB(exec, _mesa_GetInfoLogARB);
- SET_GetAttachedObjectsARB(exec, _mesa_GetAttachedObjectsARB);
- SET_GetShaderSourceARB(exec, _mesa_GetShaderSourceARB);
-
- /* OpenGL 2.0 */
- SET_AttachShader(exec, _mesa_AttachShader);
- SET_CreateProgram(exec, _mesa_CreateProgram);
- SET_CreateShader(exec, _mesa_CreateShader);
- SET_DeleteProgram(exec, _mesa_DeleteProgram);
- SET_DeleteShader(exec, _mesa_DeleteShader);
- SET_DetachShader(exec, _mesa_DetachShader);
- SET_GetAttachedShaders(exec, _mesa_GetAttachedShaders);
- SET_GetProgramiv(exec, _mesa_GetProgramiv);
- SET_GetProgramInfoLog(exec, _mesa_GetProgramInfoLog);
- SET_GetShaderiv(exec, _mesa_GetShaderiv);
- SET_GetShaderInfoLog(exec, _mesa_GetShaderInfoLog);
- SET_IsProgram(exec, _mesa_IsProgram);
- SET_IsShader(exec, _mesa_IsShader);
-
-#if FEATURE_ARB_vertex_shader
- SET_BindAttribLocationARB(exec, _mesa_BindAttribLocationARB);
- SET_GetActiveAttribARB(exec, _mesa_GetActiveAttribARB);
- SET_GetAttribLocationARB(exec, _mesa_GetAttribLocationARB);
-#endif
-
-#if FEATURE_ARB_geometry_shader4
- SET_ProgramParameteriARB(exec, _mesa_ProgramParameteriARB);
-#endif
-
- SET_UseShaderProgramEXT(exec, _mesa_UseShaderProgramEXT);
- SET_ActiveProgramEXT(exec, _mesa_ActiveProgramEXT);
- SET_CreateShaderProgramEXT(exec, _mesa_CreateShaderProgramEXT);
-
- /* GL_EXT_gpu_shader4 / GL 3.0 */
- SET_BindFragDataLocationEXT(exec, _mesa_BindFragDataLocation);
- SET_GetFragDataLocationEXT(exec, _mesa_GetFragDataLocation);
-
- /* GL_ARB_ES2_compatibility */
- SET_ReleaseShaderCompiler(exec, _mesa_ReleaseShaderCompiler);
- SET_GetShaderPrecisionFormat(exec, _mesa_GetShaderPrecisionFormat);
-
-#endif /* FEATURE_GL */
-}
-
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2004-2008 Brian Paul All Rights Reserved.
+ * Copyright (C) 2009-2010 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 shaderapi.c
+ * \author Brian Paul
+ *
+ * Implementation of GLSL-related API functions.
+ * The glUniform* functions are in uniforms.c
+ *
+ *
+ * XXX things to do:
+ * 1. Check that the right error code is generated for all _mesa_error() calls.
+ * 2. Insert FLUSH_VERTICES calls in various places
+ */
+
+
+#include "main/glheader.h"
+#include "main/context.h"
+#include "main/dispatch.h"
+#include "main/enums.h"
+#include "main/hash.h"
+#include "main/mfeatures.h"
+#include "main/mtypes.h"
+#include "main/shaderapi.h"
+#include "main/shaderobj.h"
+#include "program/program.h"
+#include "program/prog_parameter.h"
+#include "program/prog_uniform.h"
+#include "ralloc.h"
+#include <stdbool.h>
+#include "../glsl/glsl_parser_extras.h"
+
+/** Define this to enable shader substitution (see below) */
+#define SHADER_SUBST 0
+
+
+/**
+ * Return mask of GLSL_x flags by examining the MESA_GLSL env var.
+ */
+static GLbitfield
+get_shader_flags(void)
+{
+ GLbitfield flags = 0x0;
+ const char *env = _mesa_getenv("MESA_GLSL");
+
+ if (env) {
+ if (strstr(env, "dump"))
+ flags |= GLSL_DUMP;
+ if (strstr(env, "log"))
+ flags |= GLSL_LOG;
+ if (strstr(env, "nopvert"))
+ flags |= GLSL_NOP_VERT;
+ if (strstr(env, "nopfrag"))
+ flags |= GLSL_NOP_FRAG;
+ if (strstr(env, "nopt"))
+ flags |= GLSL_NO_OPT;
+ else if (strstr(env, "opt"))
+ flags |= GLSL_OPT;
+ if (strstr(env, "uniform"))
+ flags |= GLSL_UNIFORMS;
+ if (strstr(env, "useprog"))
+ flags |= GLSL_USE_PROG;
+ }
+
+ return flags;
+}
+
+
+/**
+ * Initialize context's shader state.
+ */
+void
+_mesa_init_shader_state(struct gl_context *ctx)
+{
+ /* Device drivers may override these to control what kind of instructions
+ * are generated by the GLSL compiler.
+ */
+ struct gl_shader_compiler_options options;
+ gl_shader_type sh;
+
+ memset(&options, 0, sizeof(options));
+ options.MaxUnrollIterations = 32;
+
+ /* Default pragma settings */
+ options.DefaultPragmas.Optimize = GL_TRUE;
+
+ for (sh = 0; sh < MESA_SHADER_TYPES; ++sh)
+ memcpy(&ctx->ShaderCompilerOptions[sh], &options, sizeof(options));
+
+ ctx->Shader.Flags = get_shader_flags();
+}
+
+
+/**
+ * Free the per-context shader-related state.
+ */
+void
+_mesa_free_shader_state(struct gl_context *ctx)
+{
+ _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentVertexProgram, NULL);
+ _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentGeometryProgram,
+ NULL);
+ _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentFragmentProgram,
+ NULL);
+ _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL);
+}
+
+
+/**
+ * Return the size of the given GLSL datatype, in floats (components).
+ */
+GLint
+_mesa_sizeof_glsl_type(GLenum type)
+{
+ switch (type) {
+ case GL_FLOAT:
+ case GL_INT:
+ case GL_BOOL:
+ case GL_SAMPLER_1D:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_1D_SHADOW:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_2D_RECT_ARB:
+ case GL_SAMPLER_2D_RECT_SHADOW_ARB:
+ case GL_SAMPLER_1D_ARRAY_EXT:
+ case GL_SAMPLER_2D_ARRAY_EXT:
+ case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
+ case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
+ case GL_SAMPLER_CUBE_SHADOW_EXT:
+ return 1;
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC2:
+ case GL_BOOL_VEC2:
+ return 2;
+ case GL_FLOAT_VEC3:
+ case GL_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC3:
+ case GL_BOOL_VEC3:
+ return 3;
+ case GL_FLOAT_VEC4:
+ case GL_INT_VEC4:
+ case GL_UNSIGNED_INT_VEC4:
+ case GL_BOOL_VEC4:
+ return 4;
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT2x3:
+ case GL_FLOAT_MAT2x4:
+ return 8; /* two float[4] vectors */
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT3x2:
+ case GL_FLOAT_MAT3x4:
+ return 12; /* three float[4] vectors */
+ case GL_FLOAT_MAT4:
+ case GL_FLOAT_MAT4x2:
+ case GL_FLOAT_MAT4x3:
+ return 16; /* four float[4] vectors */
+ default:
+ _mesa_problem(NULL, "Invalid type in _mesa_sizeof_glsl_type()");
+ return 1;
+ }
+}
+
+
+/**
+ * Copy string from <src> to <dst>, up to maxLength characters, returning
+ * length of <dst> in <length>.
+ * \param src the strings source
+ * \param maxLength max chars to copy
+ * \param length returns number of chars copied
+ * \param dst the string destination
+ */
+void
+_mesa_copy_string(GLchar *dst, GLsizei maxLength,
+ GLsizei *length, const GLchar *src)
+{
+ GLsizei len;
+ for (len = 0; len < maxLength - 1 && src && src[len]; len++)
+ dst[len] = src[len];
+ if (maxLength > 0)
+ dst[len] = 0;
+ if (length)
+ *length = len;
+}
+
+
+
+/**
+ * Confirm that the a shader type is valid and supported by the implementation
+ *
+ * \param ctx Current GL context
+ * \param type Shader target
+ *
+ */
+static bool
+validate_shader_target(const struct gl_context *ctx, GLenum type)
+{
+ switch (type) {
+#if FEATURE_ARB_fragment_shader
+ case GL_FRAGMENT_SHADER:
+ return ctx->Extensions.ARB_fragment_shader;
+#endif
+#if FEATURE_ARB_vertex_shader
+ case GL_VERTEX_SHADER:
+ return ctx->Extensions.ARB_vertex_shader;
+#endif
+#if FEATURE_ARB_geometry_shader4
+ case GL_GEOMETRY_SHADER_ARB:
+ return ctx->Extensions.ARB_geometry_shader4;
+#endif
+ default:
+ return false;
+ }
+}
+
+
+/**
+ * Find the length of the longest transform feedback varying name
+ * which was specified with glTransformFeedbackVaryings().
+ */
+static GLint
+longest_feedback_varying_name(const struct gl_shader_program *shProg)
+{
+ GLuint i;
+ GLint max = 0;
+ for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
+ GLint len = strlen(shProg->TransformFeedback.VaryingNames[i]);
+ if (len > max)
+ max = len;
+ }
+ return max;
+}
+
+
+
+static GLboolean
+is_program(struct gl_context *ctx, GLuint name)
+{
+ struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
+ return shProg ? GL_TRUE : GL_FALSE;
+}
+
+
+static GLboolean
+is_shader(struct gl_context *ctx, GLuint name)
+{
+ struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
+ return shader ? GL_TRUE : GL_FALSE;
+}
+
+
+/**
+ * Attach shader to a shader program.
+ */
+static void
+attach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
+{
+ struct gl_shader_program *shProg;
+ struct gl_shader *sh;
+ GLuint i, n;
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader");
+ if (!shProg)
+ return;
+
+ sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
+ if (!sh) {
+ return;
+ }
+
+ n = shProg->NumShaders;
+ for (i = 0; i < n; i++) {
+ if (shProg->Shaders[i] == sh) {
+ /* The shader is already attched to this program. The
+ * GL_ARB_shader_objects spec says:
+ *
+ * "The error INVALID_OPERATION is generated by AttachObjectARB
+ * if <obj> is already attached to <containerObj>."
+ */
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader");
+ return;
+ }
+ }
+
+ /* grow list */
+ shProg->Shaders = (struct gl_shader **)
+ _mesa_realloc(shProg->Shaders,
+ n * sizeof(struct gl_shader *),
+ (n + 1) * sizeof(struct gl_shader *));
+ if (!shProg->Shaders) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
+ return;
+ }
+
+ /* append */
+ shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
+ _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
+ shProg->NumShaders++;
+}
+
+
+static GLint
+get_attrib_location(struct gl_context *ctx, GLuint program, const GLchar *name)
+{
+ struct gl_shader_program *shProg
+ = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
+
+ if (!shProg) {
+ return -1;
+ }
+
+ if (!shProg->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetAttribLocation(program not linked)");
+ return -1;
+ }
+
+ if (!name)
+ return -1;
+
+ if (shProg->VertexProgram) {
+ const struct gl_program_parameter_list *attribs =
+ shProg->VertexProgram->Base.Attributes;
+ if (attribs) {
+ GLint i = _mesa_lookup_parameter_index(attribs, -1, name);
+ if (i >= 0) {
+ return attribs->Parameters[i].StateIndexes[0];
+ }
+ }
+ }
+ return -1;
+}
+
+
+static void
+bind_attrib_location(struct gl_context *ctx, GLuint program, GLuint index,
+ const GLchar *name)
+{
+ struct gl_shader_program *shProg;
+ const GLint size = -1; /* unknown size */
+ GLint i, oldIndex;
+ GLenum datatype = GL_FLOAT_VEC4;
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program,
+ "glBindAttribLocation");
+ if (!shProg) {
+ return;
+ }
+
+ if (!name)
+ return;
+
+ if (strncmp(name, "gl_", 3) == 0) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindAttribLocation(illegal name)");
+ return;
+ }
+
+ if (index >= ctx->Const.VertexProgram.MaxAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
+ return;
+ }
+
+ if (shProg->LinkStatus) {
+ /* get current index/location for the attribute */
+ oldIndex = get_attrib_location(ctx, program, name);
+ }
+ else {
+ oldIndex = -1;
+ }
+
+ /* this will replace the current value if it's already in the list */
+ i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index);
+ if (i < 0) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
+ return;
+ }
+
+ /*
+ * Note that this attribute binding won't go into effect until
+ * glLinkProgram is called again.
+ */
+}
+
+
+static void
+bind_frag_data_location(struct gl_context *ctx, GLuint program,
+ GLuint colorNumber, const GLchar *name)
+{
+ _mesa_problem(ctx, "bind_frag_data_location() not implemented yet");
+}
+
+
+static GLuint
+create_shader(struct gl_context *ctx, GLenum type)
+{
+ struct gl_shader *sh;
+ GLuint name;
+
+ if (!validate_shader_target(ctx, type)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
+ return 0;
+ }
+
+ name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
+ sh = ctx->Driver.NewShader(ctx, name, type);
+ _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
+
+ return name;
+}
+
+
+static GLuint
+create_shader_program(struct gl_context *ctx)
+{
+ GLuint name;
+ struct gl_shader_program *shProg;
+
+ name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
+
+ shProg = ctx->Driver.NewShaderProgram(ctx, name);
+
+ _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
+
+ assert(shProg->RefCount == 1);
+
+ return name;
+}
+
+
+/**
+ * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
+ * DeleteProgramARB.
+ */
+static void
+delete_shader_program(struct gl_context *ctx, GLuint name)
+{
+ /*
+ * NOTE: deleting shaders/programs works a bit differently than
+ * texture objects (and buffer objects, etc). Shader/program
+ * handles/IDs exist in the hash table until the object is really
+ * deleted (refcount==0). With texture objects, the handle/ID is
+ * removed from the hash table in glDeleteTextures() while the tex
+ * object itself might linger until its refcount goes to zero.
+ */
+ struct gl_shader_program *shProg;
+
+ shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
+ if (!shProg)
+ return;
+
+ shProg->DeletePending = GL_TRUE;
+
+ /* effectively, decr shProg's refcount */
+ _mesa_reference_shader_program(ctx, &shProg, NULL);
+}
+
+
+static void
+delete_shader(struct gl_context *ctx, GLuint shader)
+{
+ struct gl_shader *sh;
+
+ sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
+ if (!sh)
+ return;
+
+ sh->DeletePending = GL_TRUE;
+
+ /* effectively, decr sh's refcount */
+ _mesa_reference_shader(ctx, &sh, NULL);
+}
+
+
+static void
+detach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
+{
+ struct gl_shader_program *shProg;
+ GLuint n;
+ GLuint i, j;
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
+ if (!shProg)
+ return;
+
+ n = shProg->NumShaders;
+
+ for (i = 0; i < n; i++) {
+ if (shProg->Shaders[i]->Name == shader) {
+ /* found it */
+ struct gl_shader **newList;
+
+ /* release */
+ _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
+
+ /* alloc new, smaller array */
+ newList = (struct gl_shader **)
+ malloc((n - 1) * sizeof(struct gl_shader *));
+ if (!newList) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
+ return;
+ }
+ for (j = 0; j < i; j++) {
+ newList[j] = shProg->Shaders[j];
+ }
+ while (++i < n)
+ newList[j++] = shProg->Shaders[i];
+ free(shProg->Shaders);
+
+ shProg->Shaders = newList;
+ shProg->NumShaders = n - 1;
+
+#ifdef DEBUG
+ /* sanity check */
+ {
+ for (j = 0; j < shProg->NumShaders; j++) {
+ assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
+ shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
+ assert(shProg->Shaders[j]->RefCount > 0);
+ }
+ }
+#endif
+
+ return;
+ }
+ }
+
+ /* not found */
+ {
+ GLenum err;
+ if (is_shader(ctx, shader))
+ err = GL_INVALID_OPERATION;
+ else if (is_program(ctx, shader))
+ err = GL_INVALID_OPERATION;
+ else
+ err = GL_INVALID_VALUE;
+ _mesa_error(ctx, err, "glDetachProgram(shader)");
+ return;
+ }
+}
+
+
+static void
+get_active_attrib(struct gl_context *ctx, GLuint program, GLuint index,
+ GLsizei maxLength, GLsizei *length, GLint *size,
+ GLenum *type, GLchar *nameOut)
+{
+ const struct gl_program_parameter_list *attribs = NULL;
+ struct gl_shader_program *shProg;
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
+ if (!shProg)
+ return;
+
+ if (shProg->VertexProgram)
+ attribs = shProg->VertexProgram->Base.Attributes;
+
+ if (!attribs || index >= attribs->NumParameters) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
+ return;
+ }
+
+ _mesa_copy_string(nameOut, maxLength, length,
+ attribs->Parameters[index].Name);
+
+ if (size)
+ *size = attribs->Parameters[index].Size
+ / _mesa_sizeof_glsl_type(attribs->Parameters[index].DataType);
+
+ if (type)
+ *type = attribs->Parameters[index].DataType;
+}
+
+
+/**
+ * Return list of shaders attached to shader program.
+ */
+static void
+get_attached_shaders(struct gl_context *ctx, GLuint program, GLsizei maxCount,
+ GLsizei *count, GLuint *obj)
+{
+ struct gl_shader_program *shProg =
+ _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
+ if (shProg) {
+ GLuint i;
+ for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
+ obj[i] = shProg->Shaders[i]->Name;
+ }
+ if (count)
+ *count = i;
+ }
+}
+
+
+static GLint
+get_frag_data_location(struct gl_context *ctx, GLuint program,
+ const GLchar *name)
+{
+ _mesa_problem(ctx, "get_frag_data_location() not implemented yet");
+ return -1;
+}
+
+
+
+/**
+ * glGetHandleARB() - return ID/name of currently bound shader program.
+ */
+static GLuint
+get_handle(struct gl_context *ctx, GLenum pname)
+{
+ if (pname == GL_PROGRAM_OBJECT_ARB) {
+ if (ctx->Shader.ActiveProgram)
+ return ctx->Shader.ActiveProgram->Name;
+ else
+ return 0;
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
+ return 0;
+ }
+}
+
+
+/**
+ * glGetProgramiv() - get shader program state.
+ * Note that this is for GLSL shader programs, not ARB vertex/fragment
+ * programs (see glGetProgramivARB).
+ */
+static void
+get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *params)
+{
+ const struct gl_program_parameter_list *attribs;
+ struct gl_shader_program *shProg
+ = _mesa_lookup_shader_program(ctx, program);
+
+ if (!shProg) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
+ return;
+ }
+
+ if (shProg->VertexProgram)
+ attribs = shProg->VertexProgram->Base.Attributes;
+ else
+ attribs = NULL;
+
+ switch (pname) {
+ case GL_DELETE_STATUS:
+ *params = shProg->DeletePending;
+ break;
+ case GL_LINK_STATUS:
+ *params = shProg->LinkStatus;
+ break;
+ case GL_VALIDATE_STATUS:
+ *params = shProg->Validated;
+ break;
+ case GL_INFO_LOG_LENGTH:
+ *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
+ break;
+ case GL_ATTACHED_SHADERS:
+ *params = shProg->NumShaders;
+ break;
+ case GL_ACTIVE_ATTRIBUTES:
+ *params = attribs ? attribs->NumParameters : 0;
+ break;
+ case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
+ *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1;
+ break;
+ case GL_ACTIVE_UNIFORMS:
+ *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
+ break;
+ case GL_ACTIVE_UNIFORM_MAX_LENGTH:
+ *params = _mesa_longest_uniform_name(shProg->Uniforms);
+ if (*params > 0)
+ (*params)++; /* add one for terminating zero */
+ break;
+ case GL_PROGRAM_BINARY_LENGTH_OES:
+ *params = 0;
+ break;
+#if FEATURE_EXT_transform_feedback
+ case GL_TRANSFORM_FEEDBACK_VARYINGS:
+ *params = shProg->TransformFeedback.NumVarying;
+ break;
+ case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
+ *params = longest_feedback_varying_name(shProg) + 1;
+ break;
+ case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
+ *params = shProg->TransformFeedback.BufferMode;
+ break;
+#endif
+#if FEATURE_ARB_geometry_shader4
+ case GL_GEOMETRY_VERTICES_OUT_ARB:
+ *params = shProg->Geom.VerticesOut;
+ break;
+ case GL_GEOMETRY_INPUT_TYPE_ARB:
+ *params = shProg->Geom.InputType;
+ break;
+ case GL_GEOMETRY_OUTPUT_TYPE_ARB:
+ *params = shProg->Geom.OutputType;
+ break;
+#endif
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
+ return;
+ }
+}
+
+
+/**
+ * glGetShaderiv() - get GLSL shader state
+ */
+static void
+get_shaderiv(struct gl_context *ctx, GLuint name, GLenum pname, GLint *params)
+{
+ struct gl_shader *shader =
+ _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
+
+ if (!shader) {
+ return;
+ }
+
+ switch (pname) {
+ case GL_SHADER_TYPE:
+ *params = shader->Type;
+ break;
+ case GL_DELETE_STATUS:
+ *params = shader->DeletePending;
+ break;
+ case GL_COMPILE_STATUS:
+ *params = shader->CompileStatus;
+ break;
+ case GL_INFO_LOG_LENGTH:
+ *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
+ break;
+ case GL_SHADER_SOURCE_LENGTH:
+ *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
+ return;
+ }
+}
+
+
+static void
+get_program_info_log(struct gl_context *ctx, GLuint program, GLsizei bufSize,
+ GLsizei *length, GLchar *infoLog)
+{
+ struct gl_shader_program *shProg
+ = _mesa_lookup_shader_program(ctx, program);
+ if (!shProg) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
+ return;
+ }
+ _mesa_copy_string(infoLog, bufSize, length, shProg->InfoLog);
+}
+
+
+static void
+get_shader_info_log(struct gl_context *ctx, GLuint shader, GLsizei bufSize,
+ GLsizei *length, GLchar *infoLog)
+{
+ struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
+ if (!sh) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
+ return;
+ }
+ _mesa_copy_string(infoLog, bufSize, length, sh->InfoLog);
+}
+
+
+/**
+ * Return shader source code.
+ */
+static void
+get_shader_source(struct gl_context *ctx, GLuint shader, GLsizei maxLength,
+ GLsizei *length, GLchar *sourceOut)
+{
+ struct gl_shader *sh;
+ sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
+ if (!sh) {
+ return;
+ }
+ _mesa_copy_string(sourceOut, maxLength, length, sh->Source);
+}
+
+
+/**
+ * Set/replace shader source code.
+ */
+static void
+shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source)
+{
+ struct gl_shader *sh;
+
+ sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
+ if (!sh)
+ return;
+
+ /* free old shader source string and install new one */
+ if (sh->Source) {
+ free((void *) sh->Source);
+ }
+ sh->Source = source;
+ sh->CompileStatus = GL_FALSE;
+#ifdef DEBUG
+ sh->SourceChecksum = _mesa_str_checksum(sh->Source);
+#endif
+}
+
+
+/**
+ * Compile a shader.
+ */
+static void
+compile_shader(struct gl_context *ctx, GLuint shaderObj)
+{
+ struct gl_shader *sh;
+ struct gl_shader_compiler_options *options;
+
+ sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
+ if (!sh)
+ return;
+
+ options = &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(sh->Type)];
+
+ /* set default pragma state for shader */
+ sh->Pragmas = options->DefaultPragmas;
+
+ /* this call will set the sh->CompileStatus field to indicate if
+ * compilation was successful.
+ */
+ _mesa_glsl_compile_shader(ctx, sh);
+}
+
+
+/**
+ * Link a program's shaders.
+ */
+static void
+link_program(struct gl_context *ctx, GLuint program)
+{
+ struct gl_shader_program *shProg;
+ struct gl_transform_feedback_object *obj =
+ ctx->TransformFeedback.CurrentObject;
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
+ if (!shProg)
+ return;
+
+ if (obj->Active
+ && (shProg == ctx->Shader.CurrentVertexProgram
+ || shProg == ctx->Shader.CurrentGeometryProgram
+ || shProg == ctx->Shader.CurrentFragmentProgram)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glLinkProgram(transform feedback active");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ _mesa_glsl_link_shader(ctx, shProg);
+
+ /* debug code */
+ if (0) {
+ GLuint i;
+
+ printf("Link %u shaders in program %u: %s\n",
+ shProg->NumShaders, shProg->Name,
+ shProg->LinkStatus ? "Success" : "Failed");
+
+ for (i = 0; i < shProg->NumShaders; i++) {
+ printf(" shader %u, type 0x%x\n",
+ shProg->Shaders[i]->Name,
+ shProg->Shaders[i]->Type);
+ }
+ }
+}
+
+
+/**
+ * Print basic shader info (for debug).
+ */
+static void
+print_shader_info(const struct gl_shader_program *shProg)
+{
+ GLuint i;
+
+ printf("Mesa: glUseProgram(%u)\n", shProg->Name);
+ for (i = 0; i < shProg->NumShaders; i++) {
+ const char *s;
+ switch (shProg->Shaders[i]->Type) {
+ case GL_VERTEX_SHADER:
+ s = "vertex";
+ break;
+ case GL_FRAGMENT_SHADER:
+ s = "fragment";
+ break;
+ case GL_GEOMETRY_SHADER:
+ s = "geometry";
+ break;
+ default:
+ s = "";
+ }
+ printf(" %s shader %u, checksum %u\n", s,
+ shProg->Shaders[i]->Name,
+ shProg->Shaders[i]->SourceChecksum);
+ }
+ if (shProg->VertexProgram)
+ printf(" vert prog %u\n", shProg->VertexProgram->Base.Id);
+ if (shProg->FragmentProgram)
+ printf(" frag prog %u\n", shProg->FragmentProgram->Base.Id);
+}
+
+
+/**
+ * Use the named shader program for subsequent glUniform calls
+ */
+void
+_mesa_active_program(struct gl_context *ctx, struct gl_shader_program *shProg,
+ const char *caller)
+{
+ if ((shProg != NULL) && !shProg->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(program %u not linked)", caller, shProg->Name);
+ return;
+ }
+
+ if (ctx->Shader.ActiveProgram != shProg) {
+ _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, shProg);
+ }
+}
+
+/**
+ */
+static bool
+use_shader_program(struct gl_context *ctx, GLenum type,
+ struct gl_shader_program *shProg)
+{
+ struct gl_shader_program **target;
+
+ switch (type) {
+#if FEATURE_ARB_vertex_shader
+ case GL_VERTEX_SHADER:
+ target = &ctx->Shader.CurrentVertexProgram;
+ if ((shProg == NULL)
+ || (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)) {
+ shProg = NULL;
+ }
+ break;
+#endif
+#if FEATURE_ARB_geometry_shader4
+ case GL_GEOMETRY_SHADER_ARB:
+ target = &ctx->Shader.CurrentGeometryProgram;
+ if ((shProg == NULL)
+ || (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] == NULL)) {
+ shProg = NULL;
+ }
+ break;
+#endif
+#if FEATURE_ARB_fragment_shader
+ case GL_FRAGMENT_SHADER:
+ target = &ctx->Shader.CurrentFragmentProgram;
+ if ((shProg == NULL)
+ || (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)) {
+ shProg = NULL;
+ }
+ break;
+#endif
+ default:
+ return false;
+ }
+
+ if (*target != shProg) {
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
+ _mesa_reference_shader_program(ctx, target, shProg);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Use the named shader program for subsequent rendering.
+ */
+void
+_mesa_use_program(struct gl_context *ctx, struct gl_shader_program *shProg)
+{
+ use_shader_program(ctx, GL_VERTEX_SHADER, shProg);
+ use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, shProg);
+ use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg);
+ _mesa_active_program(ctx, shProg, "glUseProgram");
+
+ if (ctx->Driver.UseProgram)
+ ctx->Driver.UseProgram(ctx, shProg);
+}
+
+
+/**
+ * Validate a program's samplers.
+ * Specifically, check that there aren't two samplers of different types
+ * pointing to the same texture unit.
+ * \return GL_TRUE if valid, GL_FALSE if invalid
+ */
+static GLboolean
+validate_samplers(const struct gl_program *prog, char *errMsg)
+{
+ static const char *targetName[] = {
+ "TEXTURE_2D_ARRAY",
+ "TEXTURE_1D_ARRAY",
+ "TEXTURE_CUBE",
+ "TEXTURE_3D",
+ "TEXTURE_RECT",
+ "TEXTURE_2D",
+ "TEXTURE_1D",
+ };
+ GLint targetUsed[MAX_TEXTURE_IMAGE_UNITS];
+ GLbitfield samplersUsed = prog->SamplersUsed;
+ GLuint i;
+
+ assert(Elements(targetName) == NUM_TEXTURE_TARGETS);
+
+ if (samplersUsed == 0x0)
+ return GL_TRUE;
+
+ for (i = 0; i < Elements(targetUsed); i++)
+ targetUsed[i] = -1;
+
+ /* walk over bits which are set in 'samplers' */
+ while (samplersUsed) {
+ GLuint unit;
+ gl_texture_index target;
+ GLint sampler = _mesa_ffs(samplersUsed) - 1;
+ assert(sampler >= 0);
+ assert(sampler < MAX_TEXTURE_IMAGE_UNITS);
+ unit = prog->SamplerUnits[sampler];
+ target = prog->SamplerTargets[sampler];
+ if (targetUsed[unit] != -1 && targetUsed[unit] != (int) target) {
+ _mesa_snprintf(errMsg, 100,
+ "Texture unit %d is accessed both as %s and %s",
+ unit, targetName[targetUsed[unit]], targetName[target]);
+ return GL_FALSE;
+ }
+ targetUsed[unit] = target;
+ samplersUsed ^= (1 << sampler);
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Do validation of the given shader program.
+ * \param errMsg returns error message if validation fails.
+ * \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg)
+ */
+static GLboolean
+validate_shader_program(const struct gl_shader_program *shProg,
+ char *errMsg)
+{
+ const struct gl_vertex_program *vp = shProg->VertexProgram;
+ const struct gl_fragment_program *fp = shProg->FragmentProgram;
+
+ if (!shProg->LinkStatus) {
+ return GL_FALSE;
+ }
+
+ /* From the GL spec, a program is invalid if any of these are true:
+
+ any two active samplers in the current program object are of
+ different types, but refer to the same texture image unit,
+
+ any active sampler in the current program object refers to a texture
+ image unit where fixed-function fragment processing accesses a
+ texture target that does not match the sampler type, or
+
+ the sum of the number of active samplers in the program and the
+ number of texture image units enabled for fixed-function fragment
+ processing exceeds the combined limit on the total number of texture
+ image units allowed.
+ */
+
+
+ /*
+ * Check: any two active samplers in the current program object are of
+ * different types, but refer to the same texture image unit,
+ */
+ if (vp && !validate_samplers(&vp->Base, errMsg)) {
+ return GL_FALSE;
+ }
+ if (fp && !validate_samplers(&fp->Base, errMsg)) {
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Called via glValidateProgram()
+ */
+static void
+validate_program(struct gl_context *ctx, GLuint program)
+{
+ struct gl_shader_program *shProg;
+ char errMsg[100];
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
+ if (!shProg) {
+ return;
+ }
+
+ shProg->Validated = validate_shader_program(shProg, errMsg);
+ if (!shProg->Validated) {
+ /* update info log */
+ if (shProg->InfoLog) {
+ ralloc_free(shProg->InfoLog);
+ }
+ shProg->InfoLog = ralloc_strdup(shProg, errMsg);
+ }
+}
+
+
+
+void GLAPIENTRY
+_mesa_AttachObjectARB(GLhandleARB program, GLhandleARB shader)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ attach_shader(ctx, program, shader);
+}
+
+
+void GLAPIENTRY
+_mesa_AttachShader(GLuint program, GLuint shader)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ attach_shader(ctx, program, shader);
+}
+
+
+void GLAPIENTRY
+_mesa_BindAttribLocationARB(GLhandleARB program, GLuint index,
+ const GLcharARB *name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ bind_attrib_location(ctx, program, index, name);
+}
+
+
+/* GL_EXT_gpu_shader4, GL3 */
+void GLAPIENTRY
+_mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
+ const GLchar *name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ bind_frag_data_location(ctx, program, colorNumber, name);
+}
+
+
+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);
+}
+
+
+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);
+}
+
+
+GLhandleARB GLAPIENTRY
+_mesa_CreateShaderObjectARB(GLenum type)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ return create_shader(ctx, type);
+}
+
+
+GLuint GLAPIENTRY
+_mesa_CreateProgram(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glCreateProgram\n");
+ return create_shader_program(ctx);
+}
+
+
+GLhandleARB GLAPIENTRY
+_mesa_CreateProgramObjectARB(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ return create_shader_program(ctx);
+}
+
+
+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)) {
+ delete_shader_program(ctx, obj);
+ }
+ else if (is_shader(ctx, obj)) {
+ delete_shader(ctx, obj);
+ }
+ else {
+ /* error? */
+ }
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_DeleteProgram(GLuint name)
+{
+ if (name) {
+ GET_CURRENT_CONTEXT(ctx);
+ delete_shader_program(ctx, name);
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_DeleteShader(GLuint name)
+{
+ if (name) {
+ GET_CURRENT_CONTEXT(ctx);
+ delete_shader(ctx, name);
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_DetachObjectARB(GLhandleARB program, GLhandleARB shader)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ detach_shader(ctx, program, shader);
+}
+
+
+void GLAPIENTRY
+_mesa_DetachShader(GLuint program, GLuint shader)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ detach_shader(ctx, program, shader);
+}
+
+
+void GLAPIENTRY
+_mesa_GetActiveAttribARB(GLhandleARB program, GLuint index,
+ GLsizei maxLength, GLsizei * length, GLint * size,
+ GLenum * type, GLcharARB * name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ get_active_attrib(ctx, program, index, maxLength, length, size, type, name);
+}
+
+
+void GLAPIENTRY
+_mesa_GetAttachedObjectsARB(GLhandleARB container, GLsizei maxCount,
+ GLsizei * count, GLhandleARB * obj)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ get_attached_shaders(ctx, container, maxCount, count, obj);
+}
+
+
+void GLAPIENTRY
+_mesa_GetAttachedShaders(GLuint program, GLsizei maxCount,
+ GLsizei *count, GLuint *obj)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ get_attached_shaders(ctx, program, maxCount, count, obj);
+}
+
+
+GLint GLAPIENTRY
+_mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ return get_attrib_location(ctx, program, name);
+}
+
+
+/* GL_EXT_gpu_shader4, GL3 */
+GLint GLAPIENTRY
+_mesa_GetFragDataLocation(GLuint program, const GLchar *name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ return get_frag_data_location(ctx, program, name);
+}
+
+
+
+void GLAPIENTRY
+_mesa_GetInfoLogARB(GLhandleARB object, GLsizei maxLength, GLsizei * length,
+ GLcharARB * infoLog)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (is_program(ctx, object)) {
+ get_program_info_log(ctx, object, maxLength, length, infoLog);
+ }
+ else if (is_shader(ctx, object)) {
+ get_shader_info_log(ctx, object, maxLength, length, infoLog);
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glGetInfoLogARB");
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GetObjectParameterivARB(GLhandleARB object, GLenum pname, GLint *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ /* Implement in terms of GetProgramiv, GetShaderiv */
+ if (is_program(ctx, object)) {
+ if (pname == GL_OBJECT_TYPE_ARB) {
+ *params = GL_PROGRAM_OBJECT_ARB;
+ }
+ else {
+ get_programiv(ctx, object, pname, params);
+ }
+ }
+ else if (is_shader(ctx, object)) {
+ if (pname == GL_OBJECT_TYPE_ARB) {
+ *params = GL_SHADER_OBJECT_ARB;
+ }
+ else {
+ get_shaderiv(ctx, object, pname, params);
+ }
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetObjectParameterivARB");
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GetObjectParameterfvARB(GLhandleARB object, GLenum pname,
+ GLfloat *params)
+{
+ GLint iparams[1]; /* XXX is one element enough? */
+ _mesa_GetObjectParameterivARB(object, pname, iparams);
+ params[0] = (GLfloat) iparams[0];
+}
+
+
+void GLAPIENTRY
+_mesa_GetProgramiv(GLuint program, GLenum pname, GLint *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ get_programiv(ctx, program, pname, params);
+}
+
+
+void GLAPIENTRY
+_mesa_GetShaderiv(GLuint shader, GLenum pname, GLint *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ get_shaderiv(ctx, shader, pname, params);
+}
+
+
+void GLAPIENTRY
+_mesa_GetProgramInfoLog(GLuint program, GLsizei bufSize,
+ GLsizei *length, GLchar *infoLog)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ get_program_info_log(ctx, program, bufSize, length, infoLog);
+}
+
+
+void GLAPIENTRY
+_mesa_GetShaderInfoLog(GLuint shader, GLsizei bufSize,
+ GLsizei *length, GLchar *infoLog)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ get_shader_info_log(ctx, shader, bufSize, length, infoLog);
+}
+
+
+void GLAPIENTRY
+_mesa_GetShaderSourceARB(GLhandleARB shader, GLsizei maxLength,
+ GLsizei *length, GLcharARB *sourceOut)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ get_shader_source(ctx, shader, maxLength, length, sourceOut);
+}
+
+
+GLhandleARB GLAPIENTRY
+_mesa_GetHandleARB(GLenum pname)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ return get_handle(ctx, pname);
+}
+
+
+GLboolean GLAPIENTRY
+_mesa_IsProgram(GLuint name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ return is_program(ctx, name);
+}
+
+
+GLboolean GLAPIENTRY
+_mesa_IsShader(GLuint name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ return is_shader(ctx, name);
+}
+
+
+void GLAPIENTRY
+_mesa_LinkProgramARB(GLhandleARB programObj)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ link_program(ctx, programObj);
+}
+
+
+
+/**
+ * Read shader source code from a file.
+ * Useful for debugging to override an app's shader.
+ */
+static GLcharARB *
+read_shader(const char *fname)
+{
+ const int max = 50*1000;
+ FILE *f = fopen(fname, "r");
+ GLcharARB *buffer, *shader;
+ int len;
+
+ if (!f) {
+ return NULL;
+ }
+
+ buffer = (char *) malloc(max);
+ len = fread(buffer, 1, max, f);
+ buffer[len] = 0;
+
+ fclose(f);
+
+ shader = _mesa_strdup(buffer);
+ free(buffer);
+
+ return shader;
+}
+
+
+/**
+ * Called via glShaderSource() and glShaderSourceARB() API functions.
+ * Basically, concatenate the source code strings into one long string
+ * and pass it to _mesa_shader_source().
+ */
+void GLAPIENTRY
+_mesa_ShaderSourceARB(GLhandleARB shaderObj, GLsizei count,
+ const GLcharARB ** string, const GLint * length)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint *offsets;
+ GLsizei i, totalLength;
+ GLcharARB *source;
+ GLuint checksum;
+
+ if (!shaderObj || string == NULL) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB");
+ return;
+ }
+
+ /*
+ * This array holds offsets of where the appropriate string ends, thus the
+ * last element will be set to the total length of the source code.
+ */
+ offsets = (GLint *) malloc(count * sizeof(GLint));
+ if (offsets == NULL) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB");
+ return;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (string[i] == NULL) {
+ free((GLvoid *) offsets);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glShaderSourceARB(null string)");
+ return;
+ }
+ if (length == NULL || length[i] < 0)
+ offsets[i] = strlen(string[i]);
+ else
+ offsets[i] = length[i];
+ /* accumulate string lengths */
+ if (i > 0)
+ offsets[i] += offsets[i - 1];
+ }
+
+ /* Total length of source string is sum off all strings plus two.
+ * One extra byte for terminating zero, another extra byte to silence
+ * valgrind warnings in the parser/grammer code.
+ */
+ totalLength = offsets[count - 1] + 2;
+ source = (GLcharARB *) malloc(totalLength * sizeof(GLcharARB));
+ if (source == NULL) {
+ free((GLvoid *) offsets);
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB");
+ return;
+ }
+
+ for (i = 0; i < count; i++) {
+ GLint start = (i > 0) ? offsets[i - 1] : 0;
+ memcpy(source + start, string[i],
+ (offsets[i] - start) * sizeof(GLcharARB));
+ }
+ source[totalLength - 1] = '\0';
+ source[totalLength - 2] = '\0';
+
+ if (SHADER_SUBST) {
+ /* Compute the shader's source code checksum then try to open a file
+ * named newshader_<CHECKSUM>. If it exists, use it in place of the
+ * original shader source code. For debugging.
+ */
+ char filename[100];
+ GLcharARB *newSource;
+
+ checksum = _mesa_str_checksum(source);
+
+ _mesa_snprintf(filename, sizeof(filename), "newshader_%d", checksum);
+
+ newSource = read_shader(filename);
+ if (newSource) {
+ fprintf(stderr, "Mesa: Replacing shader %u chksum=%d with %s\n",
+ shaderObj, checksum, filename);
+ free(source);
+ source = newSource;
+ }
+ }
+
+ shader_source(ctx, shaderObj, source);
+
+ if (SHADER_SUBST) {
+ struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
+ if (sh)
+ sh->SourceChecksum = checksum; /* save original checksum */
+ }
+
+ free(offsets);
+}
+
+
+void GLAPIENTRY
+_mesa_UseProgramObjectARB(GLhandleARB program)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_shader_program *shProg;
+ struct gl_transform_feedback_object *obj =
+ ctx->TransformFeedback.CurrentObject;
+
+ if (obj->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUseProgram(transform feedback active)");
+ return;
+ }
+
+ if (program) {
+ shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
+ if (!shProg) {
+ return;
+ }
+ if (!shProg->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUseProgram(program %u not linked)", program);
+ return;
+ }
+
+ /* debug code */
+ if (ctx->Shader.Flags & GLSL_USE_PROG) {
+ print_shader_info(shProg);
+ }
+ }
+ else {
+ shProg = NULL;
+ }
+
+ _mesa_use_program(ctx, shProg);
+}
+
+
+void GLAPIENTRY
+_mesa_ValidateProgramARB(GLhandleARB program)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ validate_program(ctx, program);
+}
+
+#ifdef FEATURE_ES2
+
+void GLAPIENTRY
+_mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype,
+ GLint* range, GLint* precision)
+{
+ const struct gl_program_constants *limits;
+ const struct gl_precision *p;
+ GET_CURRENT_CONTEXT(ctx);
+
+ switch (shadertype) {
+ case GL_VERTEX_SHADER:
+ limits = &ctx->Const.VertexProgram;
+ break;
+ case GL_FRAGMENT_SHADER:
+ limits = &ctx->Const.FragmentProgram;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetShaderPrecisionFormat(shadertype)");
+ return;
+ }
+
+ switch (precisiontype) {
+ case GL_LOW_FLOAT:
+ p = &limits->LowFloat;
+ break;
+ case GL_MEDIUM_FLOAT:
+ p = &limits->MediumFloat;
+ break;
+ case GL_HIGH_FLOAT:
+ p = &limits->HighFloat;
+ break;
+ case GL_LOW_INT:
+ p = &limits->LowInt;
+ break;
+ case GL_MEDIUM_INT:
+ p = &limits->MediumInt;
+ break;
+ case GL_HIGH_INT:
+ p = &limits->HighInt;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetShaderPrecisionFormat(precisiontype)");
+ return;
+ }
+
+ range[0] = p->RangeMin;
+ range[1] = p->RangeMax;
+ precision[0] = p->Precision;
+}
+
+
+void GLAPIENTRY
+_mesa_ReleaseShaderCompiler(void)
+{
+ _mesa_destroy_shader_compiler_caches();
+}
+
+
+void GLAPIENTRY
+_mesa_ShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat,
+ const void* binary, GLint length)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) n;
+ (void) shaders;
+ (void) binaryformat;
+ (void) binary;
+ (void) length;
+ _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__);
+}
+
+#endif /* FEATURE_ES2 */
+
+
+#if FEATURE_ARB_geometry_shader4
+
+void GLAPIENTRY
+_mesa_ProgramParameteriARB(GLuint program, GLenum pname,
+ GLint value)
+{
+ struct gl_shader_program *shProg;
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program,
+ "glProgramParameteri");
+ if (!shProg)
+ return;
+
+ switch (pname) {
+ case GL_GEOMETRY_VERTICES_OUT_ARB:
+ if (value < 1 ||
+ (unsigned) value > ctx->Const.GeometryProgram.MaxGeometryOutputVertices) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glProgramParameteri(GL_GEOMETRY_VERTICES_OUT_ARB=%d",
+ value);
+ return;
+ }
+ shProg->Geom.VerticesOut = value;
+ break;
+ case GL_GEOMETRY_INPUT_TYPE_ARB:
+ switch (value) {
+ case GL_POINTS:
+ case GL_LINES:
+ case GL_LINES_ADJACENCY_ARB:
+ case GL_TRIANGLES:
+ case GL_TRIANGLES_ADJACENCY_ARB:
+ shProg->Geom.InputType = value;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glProgramParameteri(geometry input type = %s",
+ _mesa_lookup_enum_by_nr(value));
+ return;
+ }
+ break;
+ case GL_GEOMETRY_OUTPUT_TYPE_ARB:
+ switch (value) {
+ case GL_POINTS:
+ case GL_LINE_STRIP:
+ case GL_TRIANGLE_STRIP:
+ shProg->Geom.OutputType = value;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glProgramParameteri(geometry output type = %s",
+ _mesa_lookup_enum_by_nr(value));
+ return;
+ }
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameteriARB(pname=%s)",
+ _mesa_lookup_enum_by_nr(pname));
+ break;
+ }
+}
+
+#endif
+
+void
+_mesa_use_shader_program(struct gl_context *ctx, GLenum type,
+ struct gl_shader_program *shProg)
+{
+ use_shader_program(ctx, type, shProg);
+
+ if (ctx->Driver.UseProgram)
+ ctx->Driver.UseProgram(ctx, shProg);
+}
+
+void GLAPIENTRY
+_mesa_UseShaderProgramEXT(GLenum type, GLuint program)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_shader_program *shProg = NULL;
+
+ if (!validate_shader_target(ctx, type)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)");
+ return;
+ }
+
+ if (ctx->TransformFeedback.CurrentObject->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUseShaderProgramEXT(transform feedback is active)");
+ return;
+ }
+
+ if (program) {
+ shProg = _mesa_lookup_shader_program_err(ctx, program,
+ "glUseShaderProgramEXT");
+ if (shProg == NULL)
+ return;
+
+ if (!shProg->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUseShaderProgramEXT(program not linked)");
+ return;
+ }
+ }
+
+ _mesa_use_shader_program(ctx, type, shProg);
+}
+
+void GLAPIENTRY
+_mesa_ActiveProgramEXT(GLuint program)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_shader_program *shProg = (program != 0)
+ ? _mesa_lookup_shader_program_err(ctx, program, "glActiveProgramEXT")
+ : NULL;
+
+ _mesa_active_program(ctx, shProg, "glActiveProgramEXT");
+ return;
+}
+
+GLuint GLAPIENTRY
+_mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ const GLuint shader = create_shader(ctx, type);
+ GLuint program = 0;
+
+ if (shader) {
+ shader_source(ctx, shader, _mesa_strdup(string));
+ compile_shader(ctx, shader);
+
+ program = create_shader_program(ctx);
+ if (program) {
+ struct gl_shader_program *shProg;
+ struct gl_shader *sh;
+ GLint compiled = GL_FALSE;
+
+ shProg = _mesa_lookup_shader_program(ctx, program);
+ sh = _mesa_lookup_shader(ctx, shader);
+
+ get_shaderiv(ctx, shader, GL_COMPILE_STATUS, &compiled);
+ if (compiled) {
+ attach_shader(ctx, program, shader);
+ link_program(ctx, program);
+ detach_shader(ctx, program, shader);
+
+#if 0
+ /* Possibly... */
+ if (active-user-defined-varyings-in-linked-program) {
+ append-error-to-info-log;
+ shProg->LinkStatus = GL_FALSE;
+ }
+#endif
+ }
+
+ ralloc_strcat(&shProg->InfoLog, sh->InfoLog);
+ }
+
+ delete_shader(ctx, shader);
+ }
+
+ return program;
+}
+
+/**
+ * Plug in shader-related functions into API dispatch table.
+ */
+void
+_mesa_init_shader_dispatch(struct _glapi_table *exec)
+{
+#if FEATURE_GL
+ /* GL_ARB_vertex/fragment_shader */
+ SET_DeleteObjectARB(exec, _mesa_DeleteObjectARB);
+ SET_GetHandleARB(exec, _mesa_GetHandleARB);
+ SET_DetachObjectARB(exec, _mesa_DetachObjectARB);
+ SET_CreateShaderObjectARB(exec, _mesa_CreateShaderObjectARB);
+ SET_ShaderSourceARB(exec, _mesa_ShaderSourceARB);
+ SET_CompileShaderARB(exec, _mesa_CompileShaderARB);
+ SET_CreateProgramObjectARB(exec, _mesa_CreateProgramObjectARB);
+ SET_AttachObjectARB(exec, _mesa_AttachObjectARB);
+ SET_LinkProgramARB(exec, _mesa_LinkProgramARB);
+ SET_UseProgramObjectARB(exec, _mesa_UseProgramObjectARB);
+ SET_ValidateProgramARB(exec, _mesa_ValidateProgramARB);
+ SET_GetObjectParameterfvARB(exec, _mesa_GetObjectParameterfvARB);
+ SET_GetObjectParameterivARB(exec, _mesa_GetObjectParameterivARB);
+ SET_GetInfoLogARB(exec, _mesa_GetInfoLogARB);
+ SET_GetAttachedObjectsARB(exec, _mesa_GetAttachedObjectsARB);
+ SET_GetShaderSourceARB(exec, _mesa_GetShaderSourceARB);
+
+ /* OpenGL 2.0 */
+ SET_AttachShader(exec, _mesa_AttachShader);
+ SET_CreateProgram(exec, _mesa_CreateProgram);
+ SET_CreateShader(exec, _mesa_CreateShader);
+ SET_DeleteProgram(exec, _mesa_DeleteProgram);
+ SET_DeleteShader(exec, _mesa_DeleteShader);
+ SET_DetachShader(exec, _mesa_DetachShader);
+ SET_GetAttachedShaders(exec, _mesa_GetAttachedShaders);
+ SET_GetProgramiv(exec, _mesa_GetProgramiv);
+ SET_GetProgramInfoLog(exec, _mesa_GetProgramInfoLog);
+ SET_GetShaderiv(exec, _mesa_GetShaderiv);
+ SET_GetShaderInfoLog(exec, _mesa_GetShaderInfoLog);
+ SET_IsProgram(exec, _mesa_IsProgram);
+ SET_IsShader(exec, _mesa_IsShader);
+
+#if FEATURE_ARB_vertex_shader
+ SET_BindAttribLocationARB(exec, _mesa_BindAttribLocationARB);
+ SET_GetActiveAttribARB(exec, _mesa_GetActiveAttribARB);
+ SET_GetAttribLocationARB(exec, _mesa_GetAttribLocationARB);
+#endif
+
+#if FEATURE_ARB_geometry_shader4
+ SET_ProgramParameteriARB(exec, _mesa_ProgramParameteriARB);
+#endif
+
+ SET_UseShaderProgramEXT(exec, _mesa_UseShaderProgramEXT);
+ SET_ActiveProgramEXT(exec, _mesa_ActiveProgramEXT);
+ SET_CreateShaderProgramEXT(exec, _mesa_CreateShaderProgramEXT);
+
+ /* GL_EXT_gpu_shader4 / GL 3.0 */
+ SET_BindFragDataLocationEXT(exec, _mesa_BindFragDataLocation);
+ SET_GetFragDataLocationEXT(exec, _mesa_GetFragDataLocation);
+
+ /* GL_ARB_ES2_compatibility */
+ SET_ReleaseShaderCompiler(exec, _mesa_ReleaseShaderCompiler);
+ SET_GetShaderPrecisionFormat(exec, _mesa_GetShaderPrecisionFormat);
+
+#endif /* FEATURE_GL */
+}
+
diff --git a/mesalib/src/mesa/main/state.c b/mesalib/src/mesa/main/state.c
index 502c42929..f11578faf 100644
--- a/mesalib/src/mesa/main/state.c
+++ b/mesalib/src/mesa/main/state.c
@@ -1,734 +1,734 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.3
- *
- * Copyright (C) 1999-2008 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 state.c
- * State management.
- *
- * This file manages recalculation of derived values in struct gl_context.
- */
-
-
-#include "glheader.h"
-#include "mtypes.h"
-#include "context.h"
-#include "debug.h"
-#include "macros.h"
-#include "ffvertex_prog.h"
-#include "framebuffer.h"
-#include "light.h"
-#include "matrix.h"
-#include "pixel.h"
-#include "program/program.h"
-#include "program/prog_parameter.h"
-#include "state.h"
-#include "stencil.h"
-#include "texenvprogram.h"
-#include "texobj.h"
-#include "texstate.h"
-
-
-static void
-update_separate_specular(struct gl_context *ctx)
-{
- if (NEED_SECONDARY_COLOR(ctx))
- ctx->_TriangleCaps |= DD_SEPARATE_SPECULAR;
- else
- ctx->_TriangleCaps &= ~DD_SEPARATE_SPECULAR;
-}
-
-
-/**
- * Compute the index of the last array element that can be safely accessed
- * in a vertex array. We can really only do this when the array lives in
- * a VBO.
- * The array->_MaxElement field will be updated.
- * Later in glDrawArrays/Elements/etc we can do some bounds checking.
- */
-static void
-compute_max_element(struct gl_client_array *array)
-{
- assert(array->Enabled);
- if (array->BufferObj->Name) {
- GLsizeiptrARB offset = (GLsizeiptrARB) array->Ptr;
- GLsizeiptrARB obj_size = (GLsizeiptrARB) array->BufferObj->Size;
-
- if (offset < obj_size) {
- array->_MaxElement = (obj_size - offset +
- array->StrideB -
- array->_ElementSize) / array->StrideB;
- } else {
- array->_MaxElement = 0;
- }
- }
- else {
- /* user-space array, no idea how big it is */
- array->_MaxElement = 2 * 1000 * 1000 * 1000; /* just a big number */
- }
-}
-
-
-/**
- * Helper for update_arrays().
- * \return min(current min, array->_MaxElement).
- */
-static GLuint
-update_min(GLuint min, struct gl_client_array *array)
-{
- compute_max_element(array);
- return MIN2(min, array->_MaxElement);
-}
-
-
-/**
- * Update ctx->Array._MaxElement (the max legal index into all enabled arrays).
- * Need to do this upon new array state or new buffer object state.
- */
-static void
-update_arrays( struct gl_context *ctx )
-{
- struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
- GLuint i, min = ~0;
-
- /* find min of _MaxElement values for all enabled arrays */
-
- /* 0 */
- if (ctx->VertexProgram._Current
- && arrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled) {
- min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_POS]);
- }
- else if (arrayObj->Vertex.Enabled) {
- min = update_min(min, &arrayObj->Vertex);
- }
-
- /* 1 */
- if (ctx->VertexProgram._Enabled
- && arrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT].Enabled) {
- min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT]);
- }
- /* no conventional vertex weight array */
-
- /* 2 */
- if (ctx->VertexProgram._Enabled
- && arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL].Enabled) {
- min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL]);
- }
- else if (arrayObj->Normal.Enabled) {
- min = update_min(min, &arrayObj->Normal);
- }
-
- /* 3 */
- if (ctx->VertexProgram._Enabled
- && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0].Enabled) {
- min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0]);
- }
- else if (arrayObj->Color.Enabled) {
- min = update_min(min, &arrayObj->Color);
- }
-
- /* 4 */
- if (ctx->VertexProgram._Enabled
- && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1].Enabled) {
- min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1]);
- }
- else if (arrayObj->SecondaryColor.Enabled) {
- min = update_min(min, &arrayObj->SecondaryColor);
- }
-
- /* 5 */
- if (ctx->VertexProgram._Enabled
- && arrayObj->VertexAttrib[VERT_ATTRIB_FOG].Enabled) {
- min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_FOG]);
- }
- else if (arrayObj->FogCoord.Enabled) {
- min = update_min(min, &arrayObj->FogCoord);
- }
-
- /* 6 */
- if (ctx->VertexProgram._Enabled
- && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled) {
- min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX]);
- }
- else if (arrayObj->Index.Enabled) {
- min = update_min(min, &arrayObj->Index);
- }
-
- /* 7 */
- if (ctx->VertexProgram._Enabled
- && arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled) {
- min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG]);
- }
-
- /* 8..15 */
- for (i = VERT_ATTRIB_TEX0; i <= VERT_ATTRIB_TEX7; i++) {
- if (ctx->VertexProgram._Enabled
- && arrayObj->VertexAttrib[i].Enabled) {
- min = update_min(min, &arrayObj->VertexAttrib[i]);
- }
- else if (i - VERT_ATTRIB_TEX0 < ctx->Const.MaxTextureCoordUnits
- && arrayObj->TexCoord[i - VERT_ATTRIB_TEX0].Enabled) {
- min = update_min(min, &arrayObj->TexCoord[i - VERT_ATTRIB_TEX0]);
- }
- }
-
- /* 16..31 */
- if (ctx->VertexProgram._Current) {
- for (i = 0; i < Elements(arrayObj->VertexAttrib); i++) {
- if (arrayObj->VertexAttrib[i].Enabled) {
- min = update_min(min, &arrayObj->VertexAttrib[i]);
- }
- }
- }
-
- if (arrayObj->EdgeFlag.Enabled) {
- min = update_min(min, &arrayObj->EdgeFlag);
- }
-
- /* _MaxElement is one past the last legal array element */
- arrayObj->_MaxElement = min;
-}
-
-
-/**
- * Update the following fields:
- * ctx->VertexProgram._Enabled
- * ctx->FragmentProgram._Enabled
- * ctx->ATIFragmentShader._Enabled
- * This needs to be done before texture state validation.
- */
-static void
-update_program_enables(struct gl_context *ctx)
-{
- /* These _Enabled flags indicate if the program is enabled AND valid. */
- ctx->VertexProgram._Enabled = ctx->VertexProgram.Enabled
- && ctx->VertexProgram.Current->Base.Instructions;
- ctx->FragmentProgram._Enabled = ctx->FragmentProgram.Enabled
- && ctx->FragmentProgram.Current->Base.Instructions;
- ctx->ATIFragmentShader._Enabled = ctx->ATIFragmentShader.Enabled
- && ctx->ATIFragmentShader.Current->Instructions[0];
-}
-
-
-/**
- * Update vertex/fragment program state. In particular, update these fields:
- * ctx->VertexProgram._Current
- * ctx->VertexProgram._TnlProgram,
- * These point to the highest priority enabled vertex/fragment program or are
- * NULL if fixed-function processing is to be done.
- *
- * This function needs to be called after texture state validation in case
- * we're generating a fragment program from fixed-function texture state.
- *
- * \return bitfield which will indicate _NEW_PROGRAM state if a new vertex
- * or fragment program is being used.
- */
-static GLbitfield
-update_program(struct gl_context *ctx)
-{
- const struct gl_shader_program *vsProg = ctx->Shader.CurrentVertexProgram;
- const struct gl_shader_program *gsProg = ctx->Shader.CurrentGeometryProgram;
- const struct gl_shader_program *fsProg = ctx->Shader.CurrentFragmentProgram;
- const struct gl_vertex_program *prevVP = ctx->VertexProgram._Current;
- const struct gl_fragment_program *prevFP = ctx->FragmentProgram._Current;
- const struct gl_geometry_program *prevGP = ctx->GeometryProgram._Current;
- GLbitfield new_state = 0x0;
-
- /*
- * Set the ctx->VertexProgram._Current and ctx->FragmentProgram._Current
- * pointers to the programs that should be used for rendering. If either
- * is NULL, use fixed-function code paths.
- *
- * These programs may come from several sources. The priority is as
- * follows:
- * 1. OpenGL 2.0/ARB vertex/fragment shaders
- * 2. ARB/NV vertex/fragment programs
- * 3. Programs derived from fixed-function state.
- *
- * Note: it's possible for a vertex shader to get used with a fragment
- * program (and vice versa) here, but in practice that shouldn't ever
- * come up, or matter.
- */
-
- if (fsProg && fsProg->LinkStatus && fsProg->FragmentProgram) {
- /* Use shader programs */
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current,
- fsProg->FragmentProgram);
- }
- else if (ctx->FragmentProgram._Enabled) {
- /* use user-defined vertex program */
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current,
- ctx->FragmentProgram.Current);
- }
- else if (ctx->FragmentProgram._MaintainTexEnvProgram) {
- /* Use fragment program generated from fixed-function state.
- */
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current,
- _mesa_get_fixed_func_fragment_program(ctx));
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram,
- ctx->FragmentProgram._Current);
- }
- else {
- /* no fragment program */
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, NULL);
- }
-
- if (gsProg && gsProg->LinkStatus && gsProg->GeometryProgram) {
- /* Use shader programs */
- _mesa_reference_geomprog(ctx, &ctx->GeometryProgram._Current,
- gsProg->GeometryProgram);
- } else {
- /* no fragment program */
- _mesa_reference_geomprog(ctx, &ctx->GeometryProgram._Current, NULL);
- }
-
- /* Examine vertex program after fragment program as
- * _mesa_get_fixed_func_vertex_program() needs to know active
- * fragprog inputs.
- */
- if (vsProg && vsProg->LinkStatus && vsProg->VertexProgram) {
- /* Use shader programs */
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current,
- vsProg->VertexProgram);
- }
- else if (ctx->VertexProgram._Enabled) {
- /* use user-defined vertex program */
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current,
- ctx->VertexProgram.Current);
- }
- else if (ctx->VertexProgram._MaintainTnlProgram) {
- /* Use vertex program generated from fixed-function state.
- */
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current,
- _mesa_get_fixed_func_vertex_program(ctx));
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram._TnlProgram,
- ctx->VertexProgram._Current);
- }
- else {
- /* no vertex program */
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current, NULL);
- }
-
- /* Let the driver know what's happening:
- */
- if (ctx->FragmentProgram._Current != prevFP) {
- new_state |= _NEW_PROGRAM;
- if (ctx->Driver.BindProgram) {
- ctx->Driver.BindProgram(ctx, GL_FRAGMENT_PROGRAM_ARB,
- (struct gl_program *) ctx->FragmentProgram._Current);
- }
- }
-
- if (ctx->GeometryProgram._Current != prevGP) {
- new_state |= _NEW_PROGRAM;
- if (ctx->Driver.BindProgram) {
- ctx->Driver.BindProgram(ctx, MESA_GEOMETRY_PROGRAM,
- (struct gl_program *) ctx->GeometryProgram._Current);
- }
- }
-
- if (ctx->VertexProgram._Current != prevVP) {
- new_state |= _NEW_PROGRAM;
- if (ctx->Driver.BindProgram) {
- ctx->Driver.BindProgram(ctx, GL_VERTEX_PROGRAM_ARB,
- (struct gl_program *) ctx->VertexProgram._Current);
- }
- }
-
- return new_state;
-}
-
-
-/**
- * Examine shader constants and return either _NEW_PROGRAM_CONSTANTS or 0.
- */
-static GLbitfield
-update_program_constants(struct gl_context *ctx)
-{
- GLbitfield new_state = 0x0;
-
- if (ctx->FragmentProgram._Current) {
- const struct gl_program_parameter_list *params =
- ctx->FragmentProgram._Current->Base.Parameters;
- if (params && params->StateFlags & ctx->NewState) {
- new_state |= _NEW_PROGRAM_CONSTANTS;
- }
- }
-
- if (ctx->GeometryProgram._Current) {
- const struct gl_program_parameter_list *params =
- ctx->GeometryProgram._Current->Base.Parameters;
- /*FIXME: StateFlags is always 0 because we have unnamed constant
- * not state changes */
- if (params /*&& params->StateFlags & ctx->NewState*/) {
- new_state |= _NEW_PROGRAM_CONSTANTS;
- }
- }
-
- if (ctx->VertexProgram._Current) {
- const struct gl_program_parameter_list *params =
- ctx->VertexProgram._Current->Base.Parameters;
- if (params && params->StateFlags & ctx->NewState) {
- new_state |= _NEW_PROGRAM_CONSTANTS;
- }
- }
-
- return new_state;
-}
-
-
-
-
-static void
-update_viewport_matrix(struct gl_context *ctx)
-{
- const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
-
- ASSERT(depthMax > 0);
-
- /* Compute scale and bias values. This is really driver-specific
- * and should be maintained elsewhere if at all.
- * NOTE: RasterPos uses this.
- */
- _math_matrix_viewport(&ctx->Viewport._WindowMap,
- ctx->Viewport.X, ctx->Viewport.Y,
- ctx->Viewport.Width, ctx->Viewport.Height,
- ctx->Viewport.Near, ctx->Viewport.Far,
- depthMax);
-}
-
-
-/**
- * Update derived multisample state.
- */
-static void
-update_multisample(struct gl_context *ctx)
-{
- ctx->Multisample._Enabled = GL_FALSE;
- if (ctx->Multisample.Enabled &&
- ctx->DrawBuffer &&
- ctx->DrawBuffer->Visual.sampleBuffers)
- ctx->Multisample._Enabled = GL_TRUE;
-}
-
-
-/**
- * Update derived color/blend/logicop state.
- */
-static void
-update_color(struct gl_context *ctx)
-{
- /* This is needed to support 1.1's RGB logic ops AND
- * 1.0's blending logicops.
- */
- ctx->Color._LogicOpEnabled = RGBA_LOGICOP_ENABLED(ctx);
-}
-
-
-/*
- * Check polygon state and set DD_TRI_CULL_FRONT_BACK and/or DD_TRI_OFFSET
- * in ctx->_TriangleCaps if needed.
- */
-static void
-update_polygon(struct gl_context *ctx)
-{
- ctx->_TriangleCaps &= ~(DD_TRI_CULL_FRONT_BACK | DD_TRI_OFFSET);
-
- if (ctx->Polygon.CullFlag && ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK)
- ctx->_TriangleCaps |= DD_TRI_CULL_FRONT_BACK;
-
- if ( ctx->Polygon.OffsetPoint
- || ctx->Polygon.OffsetLine
- || ctx->Polygon.OffsetFill)
- ctx->_TriangleCaps |= DD_TRI_OFFSET;
-}
-
-
-/**
- * Update the ctx->_TriangleCaps bitfield.
- * XXX that bitfield should really go away someday!
- * This function must be called after other update_*() functions since
- * there are dependencies on some other derived values.
- */
-#if 0
-static void
-update_tricaps(struct gl_context *ctx, GLbitfield new_state)
-{
- ctx->_TriangleCaps = 0;
-
- /*
- * Points
- */
- if (1/*new_state & _NEW_POINT*/) {
- if (ctx->Point.SmoothFlag)
- ctx->_TriangleCaps |= DD_POINT_SMOOTH;
- if (ctx->Point._Attenuated)
- ctx->_TriangleCaps |= DD_POINT_ATTEN;
- }
-
- /*
- * Lines
- */
- if (1/*new_state & _NEW_LINE*/) {
- if (ctx->Line.SmoothFlag)
- ctx->_TriangleCaps |= DD_LINE_SMOOTH;
- if (ctx->Line.StippleFlag)
- ctx->_TriangleCaps |= DD_LINE_STIPPLE;
- }
-
- /*
- * Polygons
- */
- if (1/*new_state & _NEW_POLYGON*/) {
- if (ctx->Polygon.SmoothFlag)
- ctx->_TriangleCaps |= DD_TRI_SMOOTH;
- if (ctx->Polygon.StippleFlag)
- ctx->_TriangleCaps |= DD_TRI_STIPPLE;
- if (ctx->Polygon.FrontMode != GL_FILL
- || ctx->Polygon.BackMode != GL_FILL)
- ctx->_TriangleCaps |= DD_TRI_UNFILLED;
- if (ctx->Polygon.CullFlag
- && ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK)
- ctx->_TriangleCaps |= DD_TRI_CULL_FRONT_BACK;
- if (ctx->Polygon.OffsetPoint ||
- ctx->Polygon.OffsetLine ||
- ctx->Polygon.OffsetFill)
- ctx->_TriangleCaps |= DD_TRI_OFFSET;
- }
-
- /*
- * Lighting and shading
- */
- if (ctx->Light.Enabled && ctx->Light.Model.TwoSide)
- ctx->_TriangleCaps |= DD_TRI_LIGHT_TWOSIDE;
- if (ctx->Light.ShadeModel == GL_FLAT)
- ctx->_TriangleCaps |= DD_FLATSHADE;
- if (NEED_SECONDARY_COLOR(ctx))
- ctx->_TriangleCaps |= DD_SEPARATE_SPECULAR;
-
- /*
- * Stencil
- */
- if (ctx->Stencil._TestTwoSide)
- ctx->_TriangleCaps |= DD_TRI_TWOSTENCIL;
-}
-#endif
-
-
-/**
- * Compute derived GL state.
- * If __struct gl_contextRec::NewState is non-zero then this function \b must
- * be called before rendering anything.
- *
- * Calls dd_function_table::UpdateState to perform any internal state
- * management necessary.
- *
- * \sa _mesa_update_modelview_project(), _mesa_update_texture(),
- * _mesa_update_buffer_bounds(),
- * _mesa_update_lighting() and _mesa_update_tnl_spaces().
- */
-void
-_mesa_update_state_locked( struct gl_context *ctx )
-{
- GLbitfield new_state = ctx->NewState;
- GLbitfield prog_flags = _NEW_PROGRAM;
- GLbitfield new_prog_state = 0x0;
-
- if (new_state == _NEW_CURRENT_ATTRIB)
- goto out;
-
- if (MESA_VERBOSE & VERBOSE_STATE)
- _mesa_print_state("_mesa_update_state", new_state);
-
- /* Determine which state flags effect vertex/fragment program state */
- if (ctx->FragmentProgram._MaintainTexEnvProgram) {
- prog_flags |= (_NEW_BUFFERS | _NEW_TEXTURE | _NEW_FOG |
- _NEW_ARRAY | _NEW_LIGHT | _NEW_POINT | _NEW_RENDERMODE |
- _NEW_PROGRAM);
- }
- if (ctx->VertexProgram._MaintainTnlProgram) {
- prog_flags |= (_NEW_ARRAY | _NEW_TEXTURE | _NEW_TEXTURE_MATRIX |
- _NEW_TRANSFORM | _NEW_POINT |
- _NEW_FOG | _NEW_LIGHT |
- _MESA_NEW_NEED_EYE_COORDS);
- }
-
- /*
- * Now update derived state info
- */
-
- if (new_state & prog_flags)
- update_program_enables( ctx );
-
- if (new_state & (_NEW_MODELVIEW|_NEW_PROJECTION))
- _mesa_update_modelview_project( ctx, new_state );
-
- if (new_state & (_NEW_PROGRAM|_NEW_TEXTURE|_NEW_TEXTURE_MATRIX))
- _mesa_update_texture( ctx, new_state );
-
- if (new_state & _NEW_BUFFERS)
- _mesa_update_framebuffer(ctx);
-
- if (new_state & (_NEW_SCISSOR | _NEW_BUFFERS | _NEW_VIEWPORT))
- _mesa_update_draw_buffer_bounds( ctx );
-
- if (new_state & _NEW_POLYGON)
- update_polygon( ctx );
-
- if (new_state & _NEW_LIGHT)
- _mesa_update_lighting( ctx );
-
- if (new_state & (_NEW_STENCIL | _NEW_BUFFERS))
- _mesa_update_stencil( ctx );
-
- if (new_state & _MESA_NEW_TRANSFER_STATE)
- _mesa_update_pixel( ctx, new_state );
-
- if (new_state & _DD_NEW_SEPARATE_SPECULAR)
- update_separate_specular( ctx );
-
- if (new_state & (_NEW_BUFFERS | _NEW_VIEWPORT))
- update_viewport_matrix(ctx);
-
- if (new_state & _NEW_MULTISAMPLE)
- update_multisample( ctx );
-
- if (new_state & _NEW_COLOR)
- update_color( ctx );
-
-#if 0
- if (new_state & (_NEW_POINT | _NEW_LINE | _NEW_POLYGON | _NEW_LIGHT
- | _NEW_STENCIL | _DD_NEW_SEPARATE_SPECULAR))
- update_tricaps( ctx, new_state );
-#endif
-
- /* ctx->_NeedEyeCoords is now up to date.
- *
- * If the truth value of this variable has changed, update for the
- * new lighting space and recompute the positions of lights and the
- * normal transform.
- *
- * If the lighting space hasn't changed, may still need to recompute
- * light positions & normal transforms for other reasons.
- */
- if (new_state & _MESA_NEW_NEED_EYE_COORDS)
- _mesa_update_tnl_spaces( ctx, new_state );
-
- if (new_state & prog_flags) {
- /* When we generate programs from fixed-function vertex/fragment state
- * this call may generate/bind a new program. If so, we need to
- * propogate the _NEW_PROGRAM flag to the driver.
- */
- new_prog_state |= update_program( ctx );
- }
-
- if (new_state & (_NEW_ARRAY | _NEW_PROGRAM | _NEW_BUFFER_OBJECT))
- update_arrays( ctx );
-
- out:
- new_prog_state |= update_program_constants(ctx);
-
- /*
- * Give the driver a chance to act upon the new_state flags.
- * The driver might plug in different span functions, for example.
- * Also, this is where the driver can invalidate the state of any
- * active modules (such as swrast_setup, swrast, tnl, etc).
- *
- * Set ctx->NewState to zero to avoid recursion if
- * Driver.UpdateState() has to call FLUSH_VERTICES(). (fixed?)
- */
- new_state = ctx->NewState | new_prog_state;
- ctx->NewState = 0;
- ctx->Driver.UpdateState(ctx, new_state);
- ctx->Array.NewState = 0;
- if (!ctx->Array.RebindArrays)
- ctx->Array.RebindArrays = (new_state & (_NEW_ARRAY | _NEW_PROGRAM)) != 0;
-}
-
-
-/* This is the usual entrypoint for state updates:
- */
-void
-_mesa_update_state( struct gl_context *ctx )
-{
- _mesa_lock_context_textures(ctx);
- _mesa_update_state_locked(ctx);
- _mesa_unlock_context_textures(ctx);
-}
-
-
-
-
-/**
- * Want to figure out which fragment program inputs are actually
- * constant/current values from ctx->Current. These should be
- * referenced as a tracked state variable rather than a fragment
- * program input, to save the overhead of putting a constant value in
- * every submitted vertex, transferring it to hardware, interpolating
- * it across the triangle, etc...
- *
- * When there is a VP bound, just use vp->outputs. But when we're
- * generating vp from fixed function state, basically want to
- * calculate:
- *
- * vp_out_2_fp_in( vp_in_2_vp_out( varying_inputs ) |
- * potential_vp_outputs )
- *
- * Where potential_vp_outputs is calculated by looking at enabled
- * texgen, etc.
- *
- * The generated fragment program should then only declare inputs that
- * may vary or otherwise differ from the ctx->Current values.
- * Otherwise, the fp should track them as state values instead.
- */
-void
-_mesa_set_varying_vp_inputs( struct gl_context *ctx,
- GLbitfield varying_inputs )
-{
- if (ctx->varying_vp_inputs != varying_inputs) {
- ctx->varying_vp_inputs = varying_inputs;
- ctx->NewState |= _NEW_ARRAY;
- /*printf("%s %x\n", __FUNCTION__, varying_inputs);*/
- }
-}
-
-
-/**
- * Used by drivers to tell core Mesa that the driver is going to
- * install/ use its own vertex program. In particular, this will
- * prevent generated fragment programs from using state vars instead
- * of ordinary varyings/inputs.
- */
-void
-_mesa_set_vp_override(struct gl_context *ctx, GLboolean flag)
-{
- if (ctx->VertexProgram._Overriden != flag) {
- ctx->VertexProgram._Overriden = flag;
-
- /* Set one of the bits which will trigger fragment program
- * regeneration:
- */
- ctx->NewState |= _NEW_PROGRAM;
- }
-}
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.3
+ *
+ * Copyright (C) 1999-2008 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 state.c
+ * State management.
+ *
+ * This file manages recalculation of derived values in struct gl_context.
+ */
+
+
+#include "glheader.h"
+#include "mtypes.h"
+#include "context.h"
+#include "debug.h"
+#include "macros.h"
+#include "ffvertex_prog.h"
+#include "framebuffer.h"
+#include "light.h"
+#include "matrix.h"
+#include "pixel.h"
+#include "program/program.h"
+#include "program/prog_parameter.h"
+#include "state.h"
+#include "stencil.h"
+#include "texenvprogram.h"
+#include "texobj.h"
+#include "texstate.h"
+
+
+static void
+update_separate_specular(struct gl_context *ctx)
+{
+ if (NEED_SECONDARY_COLOR(ctx))
+ ctx->_TriangleCaps |= DD_SEPARATE_SPECULAR;
+ else
+ ctx->_TriangleCaps &= ~DD_SEPARATE_SPECULAR;
+}
+
+
+/**
+ * Compute the index of the last array element that can be safely accessed
+ * in a vertex array. We can really only do this when the array lives in
+ * a VBO.
+ * The array->_MaxElement field will be updated.
+ * Later in glDrawArrays/Elements/etc we can do some bounds checking.
+ */
+static void
+compute_max_element(struct gl_client_array *array)
+{
+ assert(array->Enabled);
+ if (array->BufferObj->Name) {
+ GLsizeiptrARB offset = (GLsizeiptrARB) array->Ptr;
+ GLsizeiptrARB obj_size = (GLsizeiptrARB) array->BufferObj->Size;
+
+ if (offset < obj_size) {
+ array->_MaxElement = (obj_size - offset +
+ array->StrideB -
+ array->_ElementSize) / array->StrideB;
+ } else {
+ array->_MaxElement = 0;
+ }
+ }
+ else {
+ /* user-space array, no idea how big it is */
+ array->_MaxElement = 2 * 1000 * 1000 * 1000; /* just a big number */
+ }
+}
+
+
+/**
+ * Helper for update_arrays().
+ * \return min(current min, array->_MaxElement).
+ */
+static GLuint
+update_min(GLuint min, struct gl_client_array *array)
+{
+ compute_max_element(array);
+ return MIN2(min, array->_MaxElement);
+}
+
+
+/**
+ * Update ctx->Array._MaxElement (the max legal index into all enabled arrays).
+ * Need to do this upon new array state or new buffer object state.
+ */
+static void
+update_arrays( struct gl_context *ctx )
+{
+ struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
+ GLuint i, min = ~0;
+
+ /* find min of _MaxElement values for all enabled arrays */
+
+ /* 0 */
+ if (ctx->VertexProgram._Current
+ && arrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_POS]);
+ }
+ else if (arrayObj->Vertex.Enabled) {
+ min = update_min(min, &arrayObj->Vertex);
+ }
+
+ /* 1 */
+ if (ctx->VertexProgram._Enabled
+ && arrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT]);
+ }
+ /* no conventional vertex weight array */
+
+ /* 2 */
+ if (ctx->VertexProgram._Enabled
+ && arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL]);
+ }
+ else if (arrayObj->Normal.Enabled) {
+ min = update_min(min, &arrayObj->Normal);
+ }
+
+ /* 3 */
+ if (ctx->VertexProgram._Enabled
+ && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0]);
+ }
+ else if (arrayObj->Color.Enabled) {
+ min = update_min(min, &arrayObj->Color);
+ }
+
+ /* 4 */
+ if (ctx->VertexProgram._Enabled
+ && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1]);
+ }
+ else if (arrayObj->SecondaryColor.Enabled) {
+ min = update_min(min, &arrayObj->SecondaryColor);
+ }
+
+ /* 5 */
+ if (ctx->VertexProgram._Enabled
+ && arrayObj->VertexAttrib[VERT_ATTRIB_FOG].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_FOG]);
+ }
+ else if (arrayObj->FogCoord.Enabled) {
+ min = update_min(min, &arrayObj->FogCoord);
+ }
+
+ /* 6 */
+ if (ctx->VertexProgram._Enabled
+ && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX]);
+ }
+ else if (arrayObj->Index.Enabled) {
+ min = update_min(min, &arrayObj->Index);
+ }
+
+ /* 7 */
+ if (ctx->VertexProgram._Enabled
+ && arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG]);
+ }
+
+ /* 8..15 */
+ for (i = VERT_ATTRIB_TEX0; i <= VERT_ATTRIB_TEX7; i++) {
+ if (ctx->VertexProgram._Enabled
+ && arrayObj->VertexAttrib[i].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[i]);
+ }
+ else if (i - VERT_ATTRIB_TEX0 < ctx->Const.MaxTextureCoordUnits
+ && arrayObj->TexCoord[i - VERT_ATTRIB_TEX0].Enabled) {
+ min = update_min(min, &arrayObj->TexCoord[i - VERT_ATTRIB_TEX0]);
+ }
+ }
+
+ /* 16..31 */
+ if (ctx->VertexProgram._Current) {
+ for (i = 0; i < Elements(arrayObj->VertexAttrib); i++) {
+ if (arrayObj->VertexAttrib[i].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[i]);
+ }
+ }
+ }
+
+ if (arrayObj->EdgeFlag.Enabled) {
+ min = update_min(min, &arrayObj->EdgeFlag);
+ }
+
+ /* _MaxElement is one past the last legal array element */
+ arrayObj->_MaxElement = min;
+}
+
+
+/**
+ * Update the following fields:
+ * ctx->VertexProgram._Enabled
+ * ctx->FragmentProgram._Enabled
+ * ctx->ATIFragmentShader._Enabled
+ * This needs to be done before texture state validation.
+ */
+static void
+update_program_enables(struct gl_context *ctx)
+{
+ /* These _Enabled flags indicate if the program is enabled AND valid. */
+ ctx->VertexProgram._Enabled = ctx->VertexProgram.Enabled
+ && ctx->VertexProgram.Current->Base.Instructions;
+ ctx->FragmentProgram._Enabled = ctx->FragmentProgram.Enabled
+ && ctx->FragmentProgram.Current->Base.Instructions;
+ ctx->ATIFragmentShader._Enabled = ctx->ATIFragmentShader.Enabled
+ && ctx->ATIFragmentShader.Current->Instructions[0];
+}
+
+
+/**
+ * Update vertex/fragment program state. In particular, update these fields:
+ * ctx->VertexProgram._Current
+ * ctx->VertexProgram._TnlProgram,
+ * These point to the highest priority enabled vertex/fragment program or are
+ * NULL if fixed-function processing is to be done.
+ *
+ * This function needs to be called after texture state validation in case
+ * we're generating a fragment program from fixed-function texture state.
+ *
+ * \return bitfield which will indicate _NEW_PROGRAM state if a new vertex
+ * or fragment program is being used.
+ */
+static GLbitfield
+update_program(struct gl_context *ctx)
+{
+ const struct gl_shader_program *vsProg = ctx->Shader.CurrentVertexProgram;
+ const struct gl_shader_program *gsProg = ctx->Shader.CurrentGeometryProgram;
+ const struct gl_shader_program *fsProg = ctx->Shader.CurrentFragmentProgram;
+ const struct gl_vertex_program *prevVP = ctx->VertexProgram._Current;
+ const struct gl_fragment_program *prevFP = ctx->FragmentProgram._Current;
+ const struct gl_geometry_program *prevGP = ctx->GeometryProgram._Current;
+ GLbitfield new_state = 0x0;
+
+ /*
+ * Set the ctx->VertexProgram._Current and ctx->FragmentProgram._Current
+ * pointers to the programs that should be used for rendering. If either
+ * is NULL, use fixed-function code paths.
+ *
+ * These programs may come from several sources. The priority is as
+ * follows:
+ * 1. OpenGL 2.0/ARB vertex/fragment shaders
+ * 2. ARB/NV vertex/fragment programs
+ * 3. Programs derived from fixed-function state.
+ *
+ * Note: it's possible for a vertex shader to get used with a fragment
+ * program (and vice versa) here, but in practice that shouldn't ever
+ * come up, or matter.
+ */
+
+ if (fsProg && fsProg->LinkStatus && fsProg->FragmentProgram) {
+ /* Use shader programs */
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current,
+ fsProg->FragmentProgram);
+ }
+ else if (ctx->FragmentProgram._Enabled) {
+ /* use user-defined vertex program */
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current,
+ ctx->FragmentProgram.Current);
+ }
+ else if (ctx->FragmentProgram._MaintainTexEnvProgram) {
+ /* Use fragment program generated from fixed-function state.
+ */
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current,
+ _mesa_get_fixed_func_fragment_program(ctx));
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram,
+ ctx->FragmentProgram._Current);
+ }
+ else {
+ /* no fragment program */
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, NULL);
+ }
+
+ if (gsProg && gsProg->LinkStatus && gsProg->GeometryProgram) {
+ /* Use shader programs */
+ _mesa_reference_geomprog(ctx, &ctx->GeometryProgram._Current,
+ gsProg->GeometryProgram);
+ } else {
+ /* no fragment program */
+ _mesa_reference_geomprog(ctx, &ctx->GeometryProgram._Current, NULL);
+ }
+
+ /* Examine vertex program after fragment program as
+ * _mesa_get_fixed_func_vertex_program() needs to know active
+ * fragprog inputs.
+ */
+ if (vsProg && vsProg->LinkStatus && vsProg->VertexProgram) {
+ /* Use shader programs */
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current,
+ vsProg->VertexProgram);
+ }
+ else if (ctx->VertexProgram._Enabled) {
+ /* use user-defined vertex program */
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current,
+ ctx->VertexProgram.Current);
+ }
+ else if (ctx->VertexProgram._MaintainTnlProgram) {
+ /* Use vertex program generated from fixed-function state.
+ */
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current,
+ _mesa_get_fixed_func_vertex_program(ctx));
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram._TnlProgram,
+ ctx->VertexProgram._Current);
+ }
+ else {
+ /* no vertex program */
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current, NULL);
+ }
+
+ /* Let the driver know what's happening:
+ */
+ if (ctx->FragmentProgram._Current != prevFP) {
+ new_state |= _NEW_PROGRAM;
+ if (ctx->Driver.BindProgram) {
+ ctx->Driver.BindProgram(ctx, GL_FRAGMENT_PROGRAM_ARB,
+ (struct gl_program *) ctx->FragmentProgram._Current);
+ }
+ }
+
+ if (ctx->GeometryProgram._Current != prevGP) {
+ new_state |= _NEW_PROGRAM;
+ if (ctx->Driver.BindProgram) {
+ ctx->Driver.BindProgram(ctx, MESA_GEOMETRY_PROGRAM,
+ (struct gl_program *) ctx->GeometryProgram._Current);
+ }
+ }
+
+ if (ctx->VertexProgram._Current != prevVP) {
+ new_state |= _NEW_PROGRAM;
+ if (ctx->Driver.BindProgram) {
+ ctx->Driver.BindProgram(ctx, GL_VERTEX_PROGRAM_ARB,
+ (struct gl_program *) ctx->VertexProgram._Current);
+ }
+ }
+
+ return new_state;
+}
+
+
+/**
+ * Examine shader constants and return either _NEW_PROGRAM_CONSTANTS or 0.
+ */
+static GLbitfield
+update_program_constants(struct gl_context *ctx)
+{
+ GLbitfield new_state = 0x0;
+
+ if (ctx->FragmentProgram._Current) {
+ const struct gl_program_parameter_list *params =
+ ctx->FragmentProgram._Current->Base.Parameters;
+ if (params && params->StateFlags & ctx->NewState) {
+ new_state |= _NEW_PROGRAM_CONSTANTS;
+ }
+ }
+
+ if (ctx->GeometryProgram._Current) {
+ const struct gl_program_parameter_list *params =
+ ctx->GeometryProgram._Current->Base.Parameters;
+ /*FIXME: StateFlags is always 0 because we have unnamed constant
+ * not state changes */
+ if (params /*&& params->StateFlags & ctx->NewState*/) {
+ new_state |= _NEW_PROGRAM_CONSTANTS;
+ }
+ }
+
+ if (ctx->VertexProgram._Current) {
+ const struct gl_program_parameter_list *params =
+ ctx->VertexProgram._Current->Base.Parameters;
+ if (params && params->StateFlags & ctx->NewState) {
+ new_state |= _NEW_PROGRAM_CONSTANTS;
+ }
+ }
+
+ return new_state;
+}
+
+
+
+
+static void
+update_viewport_matrix(struct gl_context *ctx)
+{
+ const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
+
+ ASSERT(depthMax > 0);
+
+ /* Compute scale and bias values. This is really driver-specific
+ * and should be maintained elsewhere if at all.
+ * NOTE: RasterPos uses this.
+ */
+ _math_matrix_viewport(&ctx->Viewport._WindowMap,
+ ctx->Viewport.X, ctx->Viewport.Y,
+ ctx->Viewport.Width, ctx->Viewport.Height,
+ ctx->Viewport.Near, ctx->Viewport.Far,
+ depthMax);
+}
+
+
+/**
+ * Update derived multisample state.
+ */
+static void
+update_multisample(struct gl_context *ctx)
+{
+ ctx->Multisample._Enabled = GL_FALSE;
+ if (ctx->Multisample.Enabled &&
+ ctx->DrawBuffer &&
+ ctx->DrawBuffer->Visual.sampleBuffers)
+ ctx->Multisample._Enabled = GL_TRUE;
+}
+
+
+/**
+ * Update derived color/blend/logicop state.
+ */
+static void
+update_color(struct gl_context *ctx)
+{
+ /* This is needed to support 1.1's RGB logic ops AND
+ * 1.0's blending logicops.
+ */
+ ctx->Color._LogicOpEnabled = RGBA_LOGICOP_ENABLED(ctx);
+}
+
+
+/*
+ * Check polygon state and set DD_TRI_CULL_FRONT_BACK and/or DD_TRI_OFFSET
+ * in ctx->_TriangleCaps if needed.
+ */
+static void
+update_polygon(struct gl_context *ctx)
+{
+ ctx->_TriangleCaps &= ~(DD_TRI_CULL_FRONT_BACK | DD_TRI_OFFSET);
+
+ if (ctx->Polygon.CullFlag && ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK)
+ ctx->_TriangleCaps |= DD_TRI_CULL_FRONT_BACK;
+
+ if ( ctx->Polygon.OffsetPoint
+ || ctx->Polygon.OffsetLine
+ || ctx->Polygon.OffsetFill)
+ ctx->_TriangleCaps |= DD_TRI_OFFSET;
+}
+
+
+/**
+ * Update the ctx->_TriangleCaps bitfield.
+ * XXX that bitfield should really go away someday!
+ * This function must be called after other update_*() functions since
+ * there are dependencies on some other derived values.
+ */
+#if 0
+static void
+update_tricaps(struct gl_context *ctx, GLbitfield new_state)
+{
+ ctx->_TriangleCaps = 0;
+
+ /*
+ * Points
+ */
+ if (1/*new_state & _NEW_POINT*/) {
+ if (ctx->Point.SmoothFlag)
+ ctx->_TriangleCaps |= DD_POINT_SMOOTH;
+ if (ctx->Point._Attenuated)
+ ctx->_TriangleCaps |= DD_POINT_ATTEN;
+ }
+
+ /*
+ * Lines
+ */
+ if (1/*new_state & _NEW_LINE*/) {
+ if (ctx->Line.SmoothFlag)
+ ctx->_TriangleCaps |= DD_LINE_SMOOTH;
+ if (ctx->Line.StippleFlag)
+ ctx->_TriangleCaps |= DD_LINE_STIPPLE;
+ }
+
+ /*
+ * Polygons
+ */
+ if (1/*new_state & _NEW_POLYGON*/) {
+ if (ctx->Polygon.SmoothFlag)
+ ctx->_TriangleCaps |= DD_TRI_SMOOTH;
+ if (ctx->Polygon.StippleFlag)
+ ctx->_TriangleCaps |= DD_TRI_STIPPLE;
+ if (ctx->Polygon.FrontMode != GL_FILL
+ || ctx->Polygon.BackMode != GL_FILL)
+ ctx->_TriangleCaps |= DD_TRI_UNFILLED;
+ if (ctx->Polygon.CullFlag
+ && ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK)
+ ctx->_TriangleCaps |= DD_TRI_CULL_FRONT_BACK;
+ if (ctx->Polygon.OffsetPoint ||
+ ctx->Polygon.OffsetLine ||
+ ctx->Polygon.OffsetFill)
+ ctx->_TriangleCaps |= DD_TRI_OFFSET;
+ }
+
+ /*
+ * Lighting and shading
+ */
+ if (ctx->Light.Enabled && ctx->Light.Model.TwoSide)
+ ctx->_TriangleCaps |= DD_TRI_LIGHT_TWOSIDE;
+ if (ctx->Light.ShadeModel == GL_FLAT)
+ ctx->_TriangleCaps |= DD_FLATSHADE;
+ if (NEED_SECONDARY_COLOR(ctx))
+ ctx->_TriangleCaps |= DD_SEPARATE_SPECULAR;
+
+ /*
+ * Stencil
+ */
+ if (ctx->Stencil._TestTwoSide)
+ ctx->_TriangleCaps |= DD_TRI_TWOSTENCIL;
+}
+#endif
+
+
+/**
+ * Compute derived GL state.
+ * If __struct gl_contextRec::NewState is non-zero then this function \b must
+ * be called before rendering anything.
+ *
+ * Calls dd_function_table::UpdateState to perform any internal state
+ * management necessary.
+ *
+ * \sa _mesa_update_modelview_project(), _mesa_update_texture(),
+ * _mesa_update_buffer_bounds(),
+ * _mesa_update_lighting() and _mesa_update_tnl_spaces().
+ */
+void
+_mesa_update_state_locked( struct gl_context *ctx )
+{
+ GLbitfield new_state = ctx->NewState;
+ GLbitfield prog_flags = _NEW_PROGRAM;
+ GLbitfield new_prog_state = 0x0;
+
+ if (new_state == _NEW_CURRENT_ATTRIB)
+ goto out;
+
+ if (MESA_VERBOSE & VERBOSE_STATE)
+ _mesa_print_state("_mesa_update_state", new_state);
+
+ /* Determine which state flags effect vertex/fragment program state */
+ if (ctx->FragmentProgram._MaintainTexEnvProgram) {
+ prog_flags |= (_NEW_BUFFERS | _NEW_TEXTURE | _NEW_FOG |
+ _NEW_ARRAY | _NEW_LIGHT | _NEW_POINT | _NEW_RENDERMODE |
+ _NEW_PROGRAM);
+ }
+ if (ctx->VertexProgram._MaintainTnlProgram) {
+ prog_flags |= (_NEW_ARRAY | _NEW_TEXTURE | _NEW_TEXTURE_MATRIX |
+ _NEW_TRANSFORM | _NEW_POINT |
+ _NEW_FOG | _NEW_LIGHT |
+ _MESA_NEW_NEED_EYE_COORDS);
+ }
+
+ /*
+ * Now update derived state info
+ */
+
+ if (new_state & prog_flags)
+ update_program_enables( ctx );
+
+ if (new_state & (_NEW_MODELVIEW|_NEW_PROJECTION))
+ _mesa_update_modelview_project( ctx, new_state );
+
+ if (new_state & (_NEW_PROGRAM|_NEW_TEXTURE|_NEW_TEXTURE_MATRIX))
+ _mesa_update_texture( ctx, new_state );
+
+ if (new_state & _NEW_BUFFERS)
+ _mesa_update_framebuffer(ctx);
+
+ if (new_state & (_NEW_SCISSOR | _NEW_BUFFERS | _NEW_VIEWPORT))
+ _mesa_update_draw_buffer_bounds( ctx );
+
+ if (new_state & _NEW_POLYGON)
+ update_polygon( ctx );
+
+ if (new_state & _NEW_LIGHT)
+ _mesa_update_lighting( ctx );
+
+ if (new_state & (_NEW_STENCIL | _NEW_BUFFERS))
+ _mesa_update_stencil( ctx );
+
+ if (new_state & _MESA_NEW_TRANSFER_STATE)
+ _mesa_update_pixel( ctx, new_state );
+
+ if (new_state & _DD_NEW_SEPARATE_SPECULAR)
+ update_separate_specular( ctx );
+
+ if (new_state & (_NEW_BUFFERS | _NEW_VIEWPORT))
+ update_viewport_matrix(ctx);
+
+ if (new_state & _NEW_MULTISAMPLE)
+ update_multisample( ctx );
+
+ if (new_state & _NEW_COLOR)
+ update_color( ctx );
+
+#if 0
+ if (new_state & (_NEW_POINT | _NEW_LINE | _NEW_POLYGON | _NEW_LIGHT
+ | _NEW_STENCIL | _DD_NEW_SEPARATE_SPECULAR))
+ update_tricaps( ctx, new_state );
+#endif
+
+ /* ctx->_NeedEyeCoords is now up to date.
+ *
+ * If the truth value of this variable has changed, update for the
+ * new lighting space and recompute the positions of lights and the
+ * normal transform.
+ *
+ * If the lighting space hasn't changed, may still need to recompute
+ * light positions & normal transforms for other reasons.
+ */
+ if (new_state & _MESA_NEW_NEED_EYE_COORDS)
+ _mesa_update_tnl_spaces( ctx, new_state );
+
+ if (new_state & prog_flags) {
+ /* When we generate programs from fixed-function vertex/fragment state
+ * this call may generate/bind a new program. If so, we need to
+ * propogate the _NEW_PROGRAM flag to the driver.
+ */
+ new_prog_state |= update_program( ctx );
+ }
+
+ if (new_state & (_NEW_ARRAY | _NEW_PROGRAM | _NEW_BUFFER_OBJECT))
+ update_arrays( ctx );
+
+ out:
+ new_prog_state |= update_program_constants(ctx);
+
+ /*
+ * Give the driver a chance to act upon the new_state flags.
+ * The driver might plug in different span functions, for example.
+ * Also, this is where the driver can invalidate the state of any
+ * active modules (such as swrast_setup, swrast, tnl, etc).
+ *
+ * Set ctx->NewState to zero to avoid recursion if
+ * Driver.UpdateState() has to call FLUSH_VERTICES(). (fixed?)
+ */
+ new_state = ctx->NewState | new_prog_state;
+ ctx->NewState = 0;
+ ctx->Driver.UpdateState(ctx, new_state);
+ ctx->Array.NewState = 0;
+ if (!ctx->Array.RebindArrays)
+ ctx->Array.RebindArrays = (new_state & (_NEW_ARRAY | _NEW_PROGRAM)) != 0;
+}
+
+
+/* This is the usual entrypoint for state updates:
+ */
+void
+_mesa_update_state( struct gl_context *ctx )
+{
+ _mesa_lock_context_textures(ctx);
+ _mesa_update_state_locked(ctx);
+ _mesa_unlock_context_textures(ctx);
+}
+
+
+
+
+/**
+ * Want to figure out which fragment program inputs are actually
+ * constant/current values from ctx->Current. These should be
+ * referenced as a tracked state variable rather than a fragment
+ * program input, to save the overhead of putting a constant value in
+ * every submitted vertex, transferring it to hardware, interpolating
+ * it across the triangle, etc...
+ *
+ * When there is a VP bound, just use vp->outputs. But when we're
+ * generating vp from fixed function state, basically want to
+ * calculate:
+ *
+ * vp_out_2_fp_in( vp_in_2_vp_out( varying_inputs ) |
+ * potential_vp_outputs )
+ *
+ * Where potential_vp_outputs is calculated by looking at enabled
+ * texgen, etc.
+ *
+ * The generated fragment program should then only declare inputs that
+ * may vary or otherwise differ from the ctx->Current values.
+ * Otherwise, the fp should track them as state values instead.
+ */
+void
+_mesa_set_varying_vp_inputs( struct gl_context *ctx,
+ GLbitfield varying_inputs )
+{
+ if (ctx->varying_vp_inputs != varying_inputs) {
+ ctx->varying_vp_inputs = varying_inputs;
+ ctx->NewState |= _NEW_ARRAY;
+ /*printf("%s %x\n", __FUNCTION__, varying_inputs);*/
+ }
+}
+
+
+/**
+ * Used by drivers to tell core Mesa that the driver is going to
+ * install/ use its own vertex program. In particular, this will
+ * prevent generated fragment programs from using state vars instead
+ * of ordinary varyings/inputs.
+ */
+void
+_mesa_set_vp_override(struct gl_context *ctx, GLboolean flag)
+{
+ if (ctx->VertexProgram._Overriden != flag) {
+ ctx->VertexProgram._Overriden = flag;
+
+ /* Set one of the bits which will trigger fragment program
+ * regeneration:
+ */
+ ctx->NewState |= _NEW_PROGRAM;
+ }
+}
diff --git a/mesalib/src/mesa/main/stencil.c b/mesalib/src/mesa/main/stencil.c
index d898bf1d7..b49ddbdbb 100644
--- a/mesalib/src/mesa/main/stencil.c
+++ b/mesalib/src/mesa/main/stencil.c
@@ -1,614 +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 (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;
-}
+/*
+ * 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/main/syncobj.c b/mesalib/src/mesa/main/syncobj.c
index 676038430..25307a17c 100644
--- a/mesalib/src/mesa/main/syncobj.c
+++ b/mesalib/src/mesa/main/syncobj.c
@@ -125,7 +125,7 @@ _mesa_wait_sync(struct gl_context *ctx, struct gl_sync_object *syncObj,
}
-void
+void GLAPIENTRY
_mesa_init_sync_object_functions(struct dd_function_table *driver)
{
driver->NewSyncObject = _mesa_new_sync_object;
@@ -140,7 +140,7 @@ _mesa_init_sync_object_functions(struct dd_function_table *driver)
}
-void
+void GLAPIENTRY
_mesa_init_sync_dispatch(struct _glapi_table *disp)
{
SET_IsSync(disp, _mesa_IsSync);
@@ -156,7 +156,7 @@ _mesa_init_sync_dispatch(struct _glapi_table *disp)
/**
* Allocate/init the context state related to sync objects.
*/
-void
+void GLAPIENTRY
_mesa_init_sync(struct gl_context *ctx)
{
(void) ctx;
@@ -166,7 +166,7 @@ _mesa_init_sync(struct gl_context *ctx)
/**
* Free the context state related to sync objects.
*/
-void
+void GLAPIENTRY
_mesa_free_sync_data(struct gl_context *ctx)
{
(void) ctx;
@@ -182,7 +182,7 @@ _mesa_validate_sync(struct gl_sync_object *syncObj)
}
-void
+void GLAPIENTRY
_mesa_ref_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj)
{
_glthread_LOCK_MUTEX(ctx->Shared->Mutex);
@@ -191,7 +191,7 @@ _mesa_ref_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj)
}
-void
+void GLAPIENTRY
_mesa_unref_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj)
{
_glthread_LOCK_MUTEX(ctx->Shared->Mutex);
diff --git a/mesalib/src/mesa/main/syncobj.h b/mesalib/src/mesa/main/syncobj.h
index ac1384f61..e83ac8b0e 100644
--- a/mesalib/src/mesa/main/syncobj.h
+++ b/mesalib/src/mesa/main/syncobj.h
@@ -41,22 +41,22 @@ struct gl_sync_object;
#if FEATURE_ARB_sync
-extern void
+extern void GLAPIENTRY
_mesa_init_sync_object_functions(struct dd_function_table *driver);
-extern void
+extern void GLAPIENTRY
_mesa_init_sync_dispatch(struct _glapi_table *disp);
-extern void
+extern void GLAPIENTRY
_mesa_init_sync(struct gl_context *);
-extern void
+extern void GLAPIENTRY
_mesa_free_sync_data(struct gl_context *);
-extern void
+extern void GLAPIENTRY
_mesa_ref_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj);
-extern void
+extern void GLAPIENTRY
_mesa_unref_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj);
extern GLboolean GLAPIENTRY
diff --git a/mesalib/src/mesa/main/texcompress_s3tc.c b/mesalib/src/mesa/main/texcompress_s3tc.c
index 90be6c0a8..479806eca 100644
--- a/mesalib/src/mesa/main/texcompress_s3tc.c
+++ b/mesalib/src/mesa/main/texcompress_s3tc.c
@@ -50,7 +50,11 @@
#if defined(_WIN32) || defined(WIN32)
+#ifdef _DEBUG
+#define DXTN_LIBNAME "dxtn_dbg.dll"
+#else
#define DXTN_LIBNAME "dxtn.dll"
+#endif
#define RTLD_LAZY 0
#define RTLD_GLOBAL 0
#elif defined(__DJGPP__)
diff --git a/mesalib/src/mesa/program/sampler.cpp b/mesalib/src/mesa/program/sampler.cpp
index 1457d1199..b219d7016 100644
--- a/mesalib/src/mesa/program/sampler.cpp
+++ b/mesalib/src/mesa/program/sampler.cpp
@@ -1,137 +1,137 @@
-/*
- * Copyright (C) 2005-2007 Brian Paul All Rights Reserved.
- * Copyright (C) 2008 VMware, Inc. All Rights Reserved.
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include "ir.h"
-#include "glsl_types.h"
-#include "ir_visitor.h"
-
-extern "C" {
-#include "main/compiler.h"
-#include "main/mtypes.h"
-#include "program/prog_parameter.h"
-}
-
-static void fail_link(struct gl_shader_program *prog, const char *fmt, ...) PRINTFLIKE(2, 3);
-
-static void fail_link(struct gl_shader_program *prog, const char *fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- ralloc_vasprintf_append(&prog->InfoLog, fmt, args);
- va_end(args);
-
- prog->LinkStatus = GL_FALSE;
-}
-
-class get_sampler_name : public ir_hierarchical_visitor
-{
-public:
- get_sampler_name(ir_dereference *last,
- struct gl_shader_program *shader_program)
- {
- this->mem_ctx = ralloc_context(NULL);
- this->shader_program = shader_program;
- this->name = NULL;
- this->offset = 0;
- this->last = last;
- }
-
- ~get_sampler_name()
- {
- ralloc_free(this->mem_ctx);
- }
-
- virtual ir_visitor_status visit(ir_dereference_variable *ir)
- {
- this->name = ir->var->name;
- return visit_continue;
- }
-
- virtual ir_visitor_status visit_leave(ir_dereference_record *ir)
- {
- this->name = ralloc_asprintf(mem_ctx, "%s.%s", name, ir->field);
- return visit_continue;
- }
-
- virtual ir_visitor_status visit_leave(ir_dereference_array *ir)
- {
- ir_constant *index = ir->array_index->as_constant();
- int i;
-
- if (index) {
- i = index->value.i[0];
- } else {
- /* GLSL 1.10 and 1.20 allowed variable sampler array indices,
- * while GLSL 1.30 requires that the array indices be
- * constant integer expressions. We don't expect any driver
- * to actually work with a really variable array index, so
- * all that would work would be an unrolled loop counter that ends
- * up being constant above.
- */
- ralloc_strcat(&shader_program->InfoLog,
- "warning: Variable sampler array index unsupported.\n"
- "This feature of the language was removed in GLSL 1.20 "
- "and is unlikely to be supported for 1.10 in Mesa.\n");
- i = 0;
- }
- if (ir != last) {
- this->name = ralloc_asprintf(mem_ctx, "%s[%d]", name, i);
- } else {
- offset = i;
- }
- return visit_continue;
- }
-
- struct gl_shader_program *shader_program;
- const char *name;
- void *mem_ctx;
- int offset;
- ir_dereference *last;
-};
-
-extern "C" {
-int
-_mesa_get_sampler_uniform_value(class ir_dereference *sampler,
- struct gl_shader_program *shader_program,
- const struct gl_program *prog)
-{
- get_sampler_name getname(sampler, shader_program);
-
- sampler->accept(&getname);
-
- GLint index = _mesa_lookup_parameter_index(prog->Parameters, -1,
- getname.name);
-
- if (index < 0) {
- fail_link(shader_program,
- "failed to find sampler named %s.\n", getname.name);
- return 0;
- }
-
- index += getname.offset;
-
- return prog->Parameters->ParameterValues[index][0];
-}
-}
+/*
+ * Copyright (C) 2005-2007 Brian Paul All Rights Reserved.
+ * Copyright (C) 2008 VMware, Inc. All Rights Reserved.
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "ir.h"
+#include "glsl_types.h"
+#include "ir_visitor.h"
+
+extern "C" {
+#include "main/compiler.h"
+#include "main/mtypes.h"
+#include "program/prog_parameter.h"
+}
+
+static void fail_link(struct gl_shader_program *prog, const char *fmt, ...) PRINTFLIKE(2, 3);
+
+static void fail_link(struct gl_shader_program *prog, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ ralloc_vasprintf_append(&prog->InfoLog, fmt, args);
+ va_end(args);
+
+ prog->LinkStatus = GL_FALSE;
+}
+
+class get_sampler_name : public ir_hierarchical_visitor
+{
+public:
+ get_sampler_name(ir_dereference *last,
+ struct gl_shader_program *shader_program)
+ {
+ this->mem_ctx = ralloc_context(NULL);
+ this->shader_program = shader_program;
+ this->name = NULL;
+ this->offset = 0;
+ this->last = last;
+ }
+
+ ~get_sampler_name()
+ {
+ ralloc_free(this->mem_ctx);
+ }
+
+ virtual ir_visitor_status visit(ir_dereference_variable *ir)
+ {
+ this->name = ir->var->name;
+ return visit_continue;
+ }
+
+ virtual ir_visitor_status visit_leave(ir_dereference_record *ir)
+ {
+ this->name = ralloc_asprintf(mem_ctx, "%s.%s", name, ir->field);
+ return visit_continue;
+ }
+
+ virtual ir_visitor_status visit_leave(ir_dereference_array *ir)
+ {
+ ir_constant *index = ir->array_index->as_constant();
+ int i;
+
+ if (index) {
+ i = index->value.i[0];
+ } else {
+ /* GLSL 1.10 and 1.20 allowed variable sampler array indices,
+ * while GLSL 1.30 requires that the array indices be
+ * constant integer expressions. We don't expect any driver
+ * to actually work with a really variable array index, so
+ * all that would work would be an unrolled loop counter that ends
+ * up being constant above.
+ */
+ ralloc_strcat(&shader_program->InfoLog,
+ "warning: Variable sampler array index unsupported.\n"
+ "This feature of the language was removed in GLSL 1.20 "
+ "and is unlikely to be supported for 1.10 in Mesa.\n");
+ i = 0;
+ }
+ if (ir != last) {
+ this->name = ralloc_asprintf(mem_ctx, "%s[%d]", name, i);
+ } else {
+ offset = i;
+ }
+ return visit_continue;
+ }
+
+ struct gl_shader_program *shader_program;
+ const char *name;
+ void *mem_ctx;
+ int offset;
+ ir_dereference *last;
+};
+
+extern "C" {
+int
+_mesa_get_sampler_uniform_value(class ir_dereference *sampler,
+ struct gl_shader_program *shader_program,
+ const struct gl_program *prog)
+{
+ get_sampler_name getname(sampler, shader_program);
+
+ sampler->accept(&getname);
+
+ GLint index = _mesa_lookup_parameter_index(prog->Parameters, -1,
+ getname.name);
+
+ if (index < 0) {
+ fail_link(shader_program,
+ "failed to find sampler named %s.\n", getname.name);
+ return 0;
+ }
+
+ index += getname.offset;
+
+ return prog->Parameters->ParameterValues[index][0];
+}
+}
diff --git a/mesalib/src/mesa/state_tracker/st_atom_blend.c b/mesalib/src/mesa/state_tracker/st_atom_blend.c
index fb1c7a4ef..e3b3b9936 100644
--- a/mesalib/src/mesa/state_tracker/st_atom_blend.c
+++ b/mesalib/src/mesa/state_tracker/st_atom_blend.c
@@ -1,302 +1,302 @@
-/**************************************************************************
- *
- * 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 <keith@tungstengraphics.com>
- * Brian Paul
- */
-
-
-#include "st_context.h"
-#include "st_atom.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "cso_cache/cso_context.h"
-
-#include "main/macros.h"
-
-/**
- * Convert GLenum blend tokens to pipe tokens.
- * Both blend factors and blend funcs are accepted.
- */
-static GLuint
-translate_blend(GLenum blend)
-{
- switch (blend) {
- /* blend functions */
- case GL_FUNC_ADD:
- return PIPE_BLEND_ADD;
- case GL_FUNC_SUBTRACT:
- return PIPE_BLEND_SUBTRACT;
- case GL_FUNC_REVERSE_SUBTRACT:
- return PIPE_BLEND_REVERSE_SUBTRACT;
- case GL_MIN:
- return PIPE_BLEND_MIN;
- case GL_MAX:
- return PIPE_BLEND_MAX;
-
- /* blend factors */
- case GL_ONE:
- return PIPE_BLENDFACTOR_ONE;
- case GL_SRC_COLOR:
- return PIPE_BLENDFACTOR_SRC_COLOR;
- case GL_SRC_ALPHA:
- return PIPE_BLENDFACTOR_SRC_ALPHA;
- case GL_DST_ALPHA:
- return PIPE_BLENDFACTOR_DST_ALPHA;
- case GL_DST_COLOR:
- return PIPE_BLENDFACTOR_DST_COLOR;
- case GL_SRC_ALPHA_SATURATE:
- return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE;
- case GL_CONSTANT_COLOR:
- return PIPE_BLENDFACTOR_CONST_COLOR;
- case GL_CONSTANT_ALPHA:
- return PIPE_BLENDFACTOR_CONST_ALPHA;
- /*
- return PIPE_BLENDFACTOR_SRC1_COLOR;
- return PIPE_BLENDFACTOR_SRC1_ALPHA;
- */
- case GL_ZERO:
- return PIPE_BLENDFACTOR_ZERO;
- case GL_ONE_MINUS_SRC_COLOR:
- return PIPE_BLENDFACTOR_INV_SRC_COLOR;
- case GL_ONE_MINUS_SRC_ALPHA:
- return PIPE_BLENDFACTOR_INV_SRC_ALPHA;
- case GL_ONE_MINUS_DST_COLOR:
- return PIPE_BLENDFACTOR_INV_DST_COLOR;
- case GL_ONE_MINUS_DST_ALPHA:
- return PIPE_BLENDFACTOR_INV_DST_ALPHA;
- case GL_ONE_MINUS_CONSTANT_COLOR:
- return PIPE_BLENDFACTOR_INV_CONST_COLOR;
- case GL_ONE_MINUS_CONSTANT_ALPHA:
- return PIPE_BLENDFACTOR_INV_CONST_ALPHA;
- /*
- return PIPE_BLENDFACTOR_INV_SRC1_COLOR;
- return PIPE_BLENDFACTOR_INV_SRC1_ALPHA;
- */
- default:
- assert("invalid GL token in translate_blend()" == NULL);
- return 0;
- }
-}
-
-
-/**
- * Convert GLenum logicop tokens to pipe tokens.
- */
-static GLuint
-translate_logicop(GLenum logicop)
-{
- switch (logicop) {
- case GL_CLEAR:
- return PIPE_LOGICOP_CLEAR;
- case GL_NOR:
- return PIPE_LOGICOP_NOR;
- case GL_AND_INVERTED:
- return PIPE_LOGICOP_AND_INVERTED;
- case GL_COPY_INVERTED:
- return PIPE_LOGICOP_COPY_INVERTED;
- case GL_AND_REVERSE:
- return PIPE_LOGICOP_AND_REVERSE;
- case GL_INVERT:
- return PIPE_LOGICOP_INVERT;
- case GL_XOR:
- return PIPE_LOGICOP_XOR;
- case GL_NAND:
- return PIPE_LOGICOP_NAND;
- case GL_AND:
- return PIPE_LOGICOP_AND;
- case GL_EQUIV:
- return PIPE_LOGICOP_EQUIV;
- case GL_NOOP:
- return PIPE_LOGICOP_NOOP;
- case GL_OR_INVERTED:
- return PIPE_LOGICOP_OR_INVERTED;
- case GL_COPY:
- return PIPE_LOGICOP_COPY;
- case GL_OR_REVERSE:
- return PIPE_LOGICOP_OR_REVERSE;
- case GL_OR:
- return PIPE_LOGICOP_OR;
- case GL_SET:
- return PIPE_LOGICOP_SET;
- default:
- assert("invalid GL token in translate_logicop()" == NULL);
- return 0;
- }
-}
-
-/**
- * Figure out if colormasks are different per rt.
- */
-static GLboolean
-colormask_per_rt(struct gl_context *ctx)
-{
- /* a bit suboptimal have to compare lots of values */
- unsigned i;
- for (i = 1; i < ctx->Const.MaxDrawBuffers; i++) {
- if (memcmp(ctx->Color.ColorMask[0], ctx->Color.ColorMask[i], 4)) {
- return GL_TRUE;
- }
- }
- return GL_FALSE;
-}
-
-/**
- * Figure out if blend enables/state are different per rt.
- */
-static GLboolean
-blend_per_rt(struct gl_context *ctx)
-{
- if (ctx->Color.BlendEnabled &&
- (ctx->Color.BlendEnabled != ((1 << ctx->Const.MaxDrawBuffers) - 1))) {
- /* This can only happen if GL_EXT_draw_buffers2 is enabled */
- return GL_TRUE;
- }
- if (ctx->Color._BlendFuncPerBuffer || ctx->Color._BlendEquationPerBuffer) {
- /* this can only happen if GL_ARB_draw_buffers_blend is enabled */
- return GL_TRUE;
- }
- return GL_FALSE;
-}
-
-static void
-update_blend( struct st_context *st )
-{
- struct pipe_blend_state *blend = &st->state.blend;
- unsigned num_state = 1;
- unsigned i, j;
-
- memset(blend, 0, sizeof(*blend));
-
- if (blend_per_rt(st->ctx) || colormask_per_rt(st->ctx)) {
- num_state = st->ctx->Const.MaxDrawBuffers;
- blend->independent_blend_enable = 1;
- }
- /* Note it is impossible to correctly deal with EXT_blend_logic_op and
- EXT_draw_buffers2/EXT_blend_equation_separate at the same time.
- These combinations would require support for per-rt logicop enables
- and separate alpha/rgb logicop/blend support respectively. Neither
- possible in gallium nor most hardware. Assume these combinations
- don't happen. */
- if (st->ctx->Color.ColorLogicOpEnabled ||
- (st->ctx->Color.BlendEnabled &&
- st->ctx->Color.Blend[0].EquationRGB == GL_LOGIC_OP)) {
- /* logicop enabled */
- blend->logicop_enable = 1;
- blend->logicop_func = translate_logicop(st->ctx->Color.LogicOp);
- }
- else if (st->ctx->Color.BlendEnabled) {
- /* blending enabled */
- for (i = 0, j = 0; i < num_state; i++) {
-
- blend->rt[i].blend_enable = (st->ctx->Color.BlendEnabled >> i) & 0x1;
-
- if (st->ctx->Extensions.ARB_draw_buffers_blend)
- j = i;
-
- blend->rt[i].rgb_func =
- translate_blend(st->ctx->Color.Blend[j].EquationRGB);
-
- if (st->ctx->Color.Blend[i].EquationRGB == GL_MIN ||
- st->ctx->Color.Blend[i].EquationRGB == GL_MAX) {
- /* Min/max are special */
- blend->rt[i].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
- blend->rt[i].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
- }
- else {
- blend->rt[i].rgb_src_factor =
- translate_blend(st->ctx->Color.Blend[j].SrcRGB);
- blend->rt[i].rgb_dst_factor =
- translate_blend(st->ctx->Color.Blend[j].DstRGB);
- }
-
- blend->rt[i].alpha_func =
- translate_blend(st->ctx->Color.Blend[j].EquationA);
-
- if (st->ctx->Color.Blend[i].EquationA == GL_MIN ||
- st->ctx->Color.Blend[i].EquationA == GL_MAX) {
- /* Min/max are special */
- blend->rt[i].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
- blend->rt[i].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
- }
- else {
- blend->rt[i].alpha_src_factor =
- translate_blend(st->ctx->Color.Blend[j].SrcA);
- blend->rt[i].alpha_dst_factor =
- translate_blend(st->ctx->Color.Blend[j].DstA);
- }
- }
- }
- else {
- /* no blending / logicop */
- }
-
- /* Colormask - maybe reverse these bits? */
- for (i = 0; i < num_state; i++) {
- if (st->ctx->Color.ColorMask[i][0])
- blend->rt[i].colormask |= PIPE_MASK_R;
- if (st->ctx->Color.ColorMask[i][1])
- blend->rt[i].colormask |= PIPE_MASK_G;
- if (st->ctx->Color.ColorMask[i][2])
- blend->rt[i].colormask |= PIPE_MASK_B;
- if (st->ctx->Color.ColorMask[i][3])
- blend->rt[i].colormask |= PIPE_MASK_A;
- }
-
- if (st->ctx->Color.DitherFlag)
- blend->dither = 1;
-
- if (st->ctx->Multisample.Enabled) {
- /* unlike in gallium/d3d10 these operations are only performed
- if msaa is enabled */
- if (st->ctx->Multisample.SampleAlphaToCoverage)
- blend->alpha_to_coverage = 1;
- if (st->ctx->Multisample.SampleAlphaToOne)
- blend->alpha_to_one = 1;
- }
-
- cso_set_blend(st->cso_context, blend);
-
- {
- struct pipe_blend_color bc;
- COPY_4FV(bc.color, st->ctx->Color.BlendColor);
- cso_set_blend_color(st->cso_context, &bc);
- }
-}
-
-
-const struct st_tracked_state st_update_blend = {
- "st_update_blend", /* name */
- { /* dirty */
- (_NEW_COLOR | _NEW_MULTISAMPLE), /* XXX _NEW_BLEND someday? */ /* mesa */
- 0, /* st */
- },
- update_blend, /* update */
-};
+/**************************************************************************
+ *
+ * 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 <keith@tungstengraphics.com>
+ * Brian Paul
+ */
+
+
+#include "st_context.h"
+#include "st_atom.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_defines.h"
+#include "cso_cache/cso_context.h"
+
+#include "main/macros.h"
+
+/**
+ * Convert GLenum blend tokens to pipe tokens.
+ * Both blend factors and blend funcs are accepted.
+ */
+static GLuint
+translate_blend(GLenum blend)
+{
+ switch (blend) {
+ /* blend functions */
+ case GL_FUNC_ADD:
+ return PIPE_BLEND_ADD;
+ case GL_FUNC_SUBTRACT:
+ return PIPE_BLEND_SUBTRACT;
+ case GL_FUNC_REVERSE_SUBTRACT:
+ return PIPE_BLEND_REVERSE_SUBTRACT;
+ case GL_MIN:
+ return PIPE_BLEND_MIN;
+ case GL_MAX:
+ return PIPE_BLEND_MAX;
+
+ /* blend factors */
+ case GL_ONE:
+ return PIPE_BLENDFACTOR_ONE;
+ case GL_SRC_COLOR:
+ return PIPE_BLENDFACTOR_SRC_COLOR;
+ case GL_SRC_ALPHA:
+ return PIPE_BLENDFACTOR_SRC_ALPHA;
+ case GL_DST_ALPHA:
+ return PIPE_BLENDFACTOR_DST_ALPHA;
+ case GL_DST_COLOR:
+ return PIPE_BLENDFACTOR_DST_COLOR;
+ case GL_SRC_ALPHA_SATURATE:
+ return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE;
+ case GL_CONSTANT_COLOR:
+ return PIPE_BLENDFACTOR_CONST_COLOR;
+ case GL_CONSTANT_ALPHA:
+ return PIPE_BLENDFACTOR_CONST_ALPHA;
+ /*
+ return PIPE_BLENDFACTOR_SRC1_COLOR;
+ return PIPE_BLENDFACTOR_SRC1_ALPHA;
+ */
+ case GL_ZERO:
+ return PIPE_BLENDFACTOR_ZERO;
+ case GL_ONE_MINUS_SRC_COLOR:
+ return PIPE_BLENDFACTOR_INV_SRC_COLOR;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ return PIPE_BLENDFACTOR_INV_SRC_ALPHA;
+ case GL_ONE_MINUS_DST_COLOR:
+ return PIPE_BLENDFACTOR_INV_DST_COLOR;
+ case GL_ONE_MINUS_DST_ALPHA:
+ return PIPE_BLENDFACTOR_INV_DST_ALPHA;
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ return PIPE_BLENDFACTOR_INV_CONST_COLOR;
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ return PIPE_BLENDFACTOR_INV_CONST_ALPHA;
+ /*
+ return PIPE_BLENDFACTOR_INV_SRC1_COLOR;
+ return PIPE_BLENDFACTOR_INV_SRC1_ALPHA;
+ */
+ default:
+ assert("invalid GL token in translate_blend()" == NULL);
+ return 0;
+ }
+}
+
+
+/**
+ * Convert GLenum logicop tokens to pipe tokens.
+ */
+static GLuint
+translate_logicop(GLenum logicop)
+{
+ switch (logicop) {
+ case GL_CLEAR:
+ return PIPE_LOGICOP_CLEAR;
+ case GL_NOR:
+ return PIPE_LOGICOP_NOR;
+ case GL_AND_INVERTED:
+ return PIPE_LOGICOP_AND_INVERTED;
+ case GL_COPY_INVERTED:
+ return PIPE_LOGICOP_COPY_INVERTED;
+ case GL_AND_REVERSE:
+ return PIPE_LOGICOP_AND_REVERSE;
+ case GL_INVERT:
+ return PIPE_LOGICOP_INVERT;
+ case GL_XOR:
+ return PIPE_LOGICOP_XOR;
+ case GL_NAND:
+ return PIPE_LOGICOP_NAND;
+ case GL_AND:
+ return PIPE_LOGICOP_AND;
+ case GL_EQUIV:
+ return PIPE_LOGICOP_EQUIV;
+ case GL_NOOP:
+ return PIPE_LOGICOP_NOOP;
+ case GL_OR_INVERTED:
+ return PIPE_LOGICOP_OR_INVERTED;
+ case GL_COPY:
+ return PIPE_LOGICOP_COPY;
+ case GL_OR_REVERSE:
+ return PIPE_LOGICOP_OR_REVERSE;
+ case GL_OR:
+ return PIPE_LOGICOP_OR;
+ case GL_SET:
+ return PIPE_LOGICOP_SET;
+ default:
+ assert("invalid GL token in translate_logicop()" == NULL);
+ return 0;
+ }
+}
+
+/**
+ * Figure out if colormasks are different per rt.
+ */
+static GLboolean
+colormask_per_rt(struct gl_context *ctx)
+{
+ /* a bit suboptimal have to compare lots of values */
+ unsigned i;
+ for (i = 1; i < ctx->Const.MaxDrawBuffers; i++) {
+ if (memcmp(ctx->Color.ColorMask[0], ctx->Color.ColorMask[i], 4)) {
+ return GL_TRUE;
+ }
+ }
+ return GL_FALSE;
+}
+
+/**
+ * Figure out if blend enables/state are different per rt.
+ */
+static GLboolean
+blend_per_rt(struct gl_context *ctx)
+{
+ if (ctx->Color.BlendEnabled &&
+ (ctx->Color.BlendEnabled != ((1 << ctx->Const.MaxDrawBuffers) - 1))) {
+ /* This can only happen if GL_EXT_draw_buffers2 is enabled */
+ return GL_TRUE;
+ }
+ if (ctx->Color._BlendFuncPerBuffer || ctx->Color._BlendEquationPerBuffer) {
+ /* this can only happen if GL_ARB_draw_buffers_blend is enabled */
+ return GL_TRUE;
+ }
+ return GL_FALSE;
+}
+
+static void
+update_blend( struct st_context *st )
+{
+ struct pipe_blend_state *blend = &st->state.blend;
+ unsigned num_state = 1;
+ unsigned i, j;
+
+ memset(blend, 0, sizeof(*blend));
+
+ if (blend_per_rt(st->ctx) || colormask_per_rt(st->ctx)) {
+ num_state = st->ctx->Const.MaxDrawBuffers;
+ blend->independent_blend_enable = 1;
+ }
+ /* Note it is impossible to correctly deal with EXT_blend_logic_op and
+ EXT_draw_buffers2/EXT_blend_equation_separate at the same time.
+ These combinations would require support for per-rt logicop enables
+ and separate alpha/rgb logicop/blend support respectively. Neither
+ possible in gallium nor most hardware. Assume these combinations
+ don't happen. */
+ if (st->ctx->Color.ColorLogicOpEnabled ||
+ (st->ctx->Color.BlendEnabled &&
+ st->ctx->Color.Blend[0].EquationRGB == GL_LOGIC_OP)) {
+ /* logicop enabled */
+ blend->logicop_enable = 1;
+ blend->logicop_func = translate_logicop(st->ctx->Color.LogicOp);
+ }
+ else if (st->ctx->Color.BlendEnabled) {
+ /* blending enabled */
+ for (i = 0, j = 0; i < num_state; i++) {
+
+ blend->rt[i].blend_enable = (st->ctx->Color.BlendEnabled >> i) & 0x1;
+
+ if (st->ctx->Extensions.ARB_draw_buffers_blend)
+ j = i;
+
+ blend->rt[i].rgb_func =
+ translate_blend(st->ctx->Color.Blend[j].EquationRGB);
+
+ if (st->ctx->Color.Blend[i].EquationRGB == GL_MIN ||
+ st->ctx->Color.Blend[i].EquationRGB == GL_MAX) {
+ /* Min/max are special */
+ blend->rt[i].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend->rt[i].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
+ }
+ else {
+ blend->rt[i].rgb_src_factor =
+ translate_blend(st->ctx->Color.Blend[j].SrcRGB);
+ blend->rt[i].rgb_dst_factor =
+ translate_blend(st->ctx->Color.Blend[j].DstRGB);
+ }
+
+ blend->rt[i].alpha_func =
+ translate_blend(st->ctx->Color.Blend[j].EquationA);
+
+ if (st->ctx->Color.Blend[i].EquationA == GL_MIN ||
+ st->ctx->Color.Blend[i].EquationA == GL_MAX) {
+ /* Min/max are special */
+ blend->rt[i].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend->rt[i].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
+ }
+ else {
+ blend->rt[i].alpha_src_factor =
+ translate_blend(st->ctx->Color.Blend[j].SrcA);
+ blend->rt[i].alpha_dst_factor =
+ translate_blend(st->ctx->Color.Blend[j].DstA);
+ }
+ }
+ }
+ else {
+ /* no blending / logicop */
+ }
+
+ /* Colormask - maybe reverse these bits? */
+ for (i = 0; i < num_state; i++) {
+ if (st->ctx->Color.ColorMask[i][0])
+ blend->rt[i].colormask |= PIPE_MASK_R;
+ if (st->ctx->Color.ColorMask[i][1])
+ blend->rt[i].colormask |= PIPE_MASK_G;
+ if (st->ctx->Color.ColorMask[i][2])
+ blend->rt[i].colormask |= PIPE_MASK_B;
+ if (st->ctx->Color.ColorMask[i][3])
+ blend->rt[i].colormask |= PIPE_MASK_A;
+ }
+
+ if (st->ctx->Color.DitherFlag)
+ blend->dither = 1;
+
+ if (st->ctx->Multisample.Enabled) {
+ /* unlike in gallium/d3d10 these operations are only performed
+ if msaa is enabled */
+ if (st->ctx->Multisample.SampleAlphaToCoverage)
+ blend->alpha_to_coverage = 1;
+ if (st->ctx->Multisample.SampleAlphaToOne)
+ blend->alpha_to_one = 1;
+ }
+
+ cso_set_blend(st->cso_context, blend);
+
+ {
+ struct pipe_blend_color bc;
+ COPY_4FV(bc.color, st->ctx->Color.BlendColor);
+ cso_set_blend_color(st->cso_context, &bc);
+ }
+}
+
+
+const struct st_tracked_state st_update_blend = {
+ "st_update_blend", /* name */
+ { /* dirty */
+ (_NEW_COLOR | _NEW_MULTISAMPLE), /* XXX _NEW_BLEND someday? */ /* mesa */
+ 0, /* st */
+ },
+ update_blend, /* update */
+};
diff --git a/mesalib/src/mesa/state_tracker/st_atom_framebuffer.c b/mesalib/src/mesa/state_tracker/st_atom_framebuffer.c
index 76386fe01..678a270c7 100644
--- a/mesalib/src/mesa/state_tracker/st_atom_framebuffer.c
+++ b/mesalib/src/mesa/state_tracker/st_atom_framebuffer.c
@@ -1,182 +1,182 @@
-/**************************************************************************
- *
- * 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 <keith@tungstengraphics.com>
- * Brian Paul
- */
-
-#include "st_context.h"
-#include "st_atom.h"
-#include "st_cb_fbo.h"
-#include "st_texture.h"
-#include "pipe/p_context.h"
-#include "cso_cache/cso_context.h"
-#include "util/u_math.h"
-#include "util/u_inlines.h"
-#include "util/u_format.h"
-
-
-/**
- * When doing GL render to texture, we have to be sure that finalize_texture()
- * didn't yank out the pipe_resource that we earlier created a surface for.
- * Check for that here and create a new surface if needed.
- */
-static void
-update_renderbuffer_surface(struct st_context *st,
- struct st_renderbuffer *strb)
-{
- struct pipe_context *pipe = st->pipe;
- struct pipe_resource *resource = strb->rtt->pt;
- int rtt_width = strb->Base.Width;
- int rtt_height = strb->Base.Height;
- enum pipe_format format = st->ctx->Color.sRGBEnabled ? resource->format : util_format_linear(resource->format);
-
- if (!strb->surface ||
- strb->surface->format != format ||
- strb->surface->texture != resource ||
- strb->surface->width != rtt_width ||
- strb->surface->height != rtt_height) {
- GLuint level;
- /* find matching mipmap level size */
- for (level = 0; level <= resource->last_level; level++) {
- if (u_minify(resource->width0, level) == rtt_width &&
- u_minify(resource->height0, level) == rtt_height) {
- struct pipe_surface surf_tmpl;
- memset(&surf_tmpl, 0, sizeof(surf_tmpl));
- surf_tmpl.format = format;
- surf_tmpl.usage = PIPE_BIND_RENDER_TARGET;
- surf_tmpl.u.tex.level = level;
- surf_tmpl.u.tex.first_layer = strb->rtt_face + strb->rtt_slice;
- surf_tmpl.u.tex.last_layer = strb->rtt_face + strb->rtt_slice;
-
- pipe_surface_reference(&strb->surface, NULL);
-
- strb->surface = pipe->create_surface(pipe,
- resource,
- &surf_tmpl);
-#if 0
- printf("-- alloc new surface %d x %d into tex %p\n",
- strb->surface->width, strb->surface->height,
- texture);
-#endif
- break;
- }
- }
- }
-}
-
-
-/**
- * Update framebuffer state (color, depth, stencil, etc. buffers)
- */
-static void
-update_framebuffer_state( struct st_context *st )
-{
- struct pipe_framebuffer_state *framebuffer = &st->state.framebuffer;
- struct gl_framebuffer *fb = st->ctx->DrawBuffer;
- struct st_renderbuffer *strb;
- GLuint i;
-
- framebuffer->width = fb->Width;
- framebuffer->height = fb->Height;
-
- /*printf("------ fb size %d x %d\n", fb->Width, fb->Height);*/
-
- /* Examine Mesa's ctx->DrawBuffer->_ColorDrawBuffers state
- * to determine which surfaces to draw to
- */
- framebuffer->nr_cbufs = 0;
- for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
- strb = st_renderbuffer(fb->_ColorDrawBuffers[i]);
-
- if (strb) {
- /*printf("--------- framebuffer surface rtt %p\n", strb->rtt);*/
- if (strb->rtt) {
- /* rendering to a GL texture, may have to update surface */
- update_renderbuffer_surface(st, strb);
- }
-
- if (strb->surface) {
- pipe_surface_reference(&framebuffer->cbufs[framebuffer->nr_cbufs],
- strb->surface);
- framebuffer->nr_cbufs++;
- }
- strb->defined = GL_TRUE; /* we'll be drawing something */
- }
- }
- for (i = framebuffer->nr_cbufs; i < PIPE_MAX_COLOR_BUFS; i++) {
- pipe_surface_reference(&framebuffer->cbufs[i], NULL);
- }
-
- /*
- * Depth/Stencil renderbuffer/surface.
- */
- strb = st_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer);
- if (strb) {
- strb = st_renderbuffer(strb->Base.Wrapped);
- if (strb->rtt) {
- /* rendering to a GL texture, may have to update surface */
- update_renderbuffer_surface(st, strb);
- }
- pipe_surface_reference(&framebuffer->zsbuf, strb->surface);
- }
- else {
- strb = st_renderbuffer(fb->Attachment[BUFFER_STENCIL].Renderbuffer);
- if (strb) {
- strb = st_renderbuffer(strb->Base.Wrapped);
- assert(strb->surface);
- pipe_surface_reference(&framebuffer->zsbuf, strb->surface);
- }
- else
- pipe_surface_reference(&framebuffer->zsbuf, NULL);
- }
-
-#ifdef DEBUG
- /* Make sure the resource binding flags were set properly */
- for (i = 0; i < framebuffer->nr_cbufs; i++) {
- assert(framebuffer->cbufs[i]->texture->bind & PIPE_BIND_RENDER_TARGET);
- }
- if (framebuffer->zsbuf) {
- assert(framebuffer->zsbuf->texture->bind & PIPE_BIND_DEPTH_STENCIL);
- }
-#endif
-
- cso_set_framebuffer(st->cso_context, framebuffer);
-}
-
-
-const struct st_tracked_state st_update_framebuffer = {
- "st_update_framebuffer", /* name */
- { /* dirty */
- _NEW_BUFFERS, /* mesa */
- ST_NEW_FRAMEBUFFER, /* st */
- },
- update_framebuffer_state /* update */
-};
-
+/**************************************************************************
+ *
+ * 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 <keith@tungstengraphics.com>
+ * Brian Paul
+ */
+
+#include "st_context.h"
+#include "st_atom.h"
+#include "st_cb_fbo.h"
+#include "st_texture.h"
+#include "pipe/p_context.h"
+#include "cso_cache/cso_context.h"
+#include "util/u_math.h"
+#include "util/u_inlines.h"
+#include "util/u_format.h"
+
+
+/**
+ * When doing GL render to texture, we have to be sure that finalize_texture()
+ * didn't yank out the pipe_resource that we earlier created a surface for.
+ * Check for that here and create a new surface if needed.
+ */
+static void
+update_renderbuffer_surface(struct st_context *st,
+ struct st_renderbuffer *strb)
+{
+ struct pipe_context *pipe = st->pipe;
+ struct pipe_resource *resource = strb->rtt->pt;
+ int rtt_width = strb->Base.Width;
+ int rtt_height = strb->Base.Height;
+ enum pipe_format format = st->ctx->Color.sRGBEnabled ? resource->format : util_format_linear(resource->format);
+
+ if (!strb->surface ||
+ strb->surface->format != format ||
+ strb->surface->texture != resource ||
+ strb->surface->width != rtt_width ||
+ strb->surface->height != rtt_height) {
+ GLuint level;
+ /* find matching mipmap level size */
+ for (level = 0; level <= resource->last_level; level++) {
+ if (u_minify(resource->width0, level) == rtt_width &&
+ u_minify(resource->height0, level) == rtt_height) {
+ struct pipe_surface surf_tmpl;
+ memset(&surf_tmpl, 0, sizeof(surf_tmpl));
+ surf_tmpl.format = format;
+ surf_tmpl.usage = PIPE_BIND_RENDER_TARGET;
+ surf_tmpl.u.tex.level = level;
+ surf_tmpl.u.tex.first_layer = strb->rtt_face + strb->rtt_slice;
+ surf_tmpl.u.tex.last_layer = strb->rtt_face + strb->rtt_slice;
+
+ pipe_surface_reference(&strb->surface, NULL);
+
+ strb->surface = pipe->create_surface(pipe,
+ resource,
+ &surf_tmpl);
+#if 0
+ printf("-- alloc new surface %d x %d into tex %p\n",
+ strb->surface->width, strb->surface->height,
+ texture);
+#endif
+ break;
+ }
+ }
+ }
+}
+
+
+/**
+ * Update framebuffer state (color, depth, stencil, etc. buffers)
+ */
+static void
+update_framebuffer_state( struct st_context *st )
+{
+ struct pipe_framebuffer_state *framebuffer = &st->state.framebuffer;
+ struct gl_framebuffer *fb = st->ctx->DrawBuffer;
+ struct st_renderbuffer *strb;
+ GLuint i;
+
+ framebuffer->width = fb->Width;
+ framebuffer->height = fb->Height;
+
+ /*printf("------ fb size %d x %d\n", fb->Width, fb->Height);*/
+
+ /* Examine Mesa's ctx->DrawBuffer->_ColorDrawBuffers state
+ * to determine which surfaces to draw to
+ */
+ framebuffer->nr_cbufs = 0;
+ for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
+ strb = st_renderbuffer(fb->_ColorDrawBuffers[i]);
+
+ if (strb) {
+ /*printf("--------- framebuffer surface rtt %p\n", strb->rtt);*/
+ if (strb->rtt) {
+ /* rendering to a GL texture, may have to update surface */
+ update_renderbuffer_surface(st, strb);
+ }
+
+ if (strb->surface) {
+ pipe_surface_reference(&framebuffer->cbufs[framebuffer->nr_cbufs],
+ strb->surface);
+ framebuffer->nr_cbufs++;
+ }
+ strb->defined = GL_TRUE; /* we'll be drawing something */
+ }
+ }
+ for (i = framebuffer->nr_cbufs; i < PIPE_MAX_COLOR_BUFS; i++) {
+ pipe_surface_reference(&framebuffer->cbufs[i], NULL);
+ }
+
+ /*
+ * Depth/Stencil renderbuffer/surface.
+ */
+ strb = st_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer);
+ if (strb) {
+ strb = st_renderbuffer(strb->Base.Wrapped);
+ if (strb->rtt) {
+ /* rendering to a GL texture, may have to update surface */
+ update_renderbuffer_surface(st, strb);
+ }
+ pipe_surface_reference(&framebuffer->zsbuf, strb->surface);
+ }
+ else {
+ strb = st_renderbuffer(fb->Attachment[BUFFER_STENCIL].Renderbuffer);
+ if (strb) {
+ strb = st_renderbuffer(strb->Base.Wrapped);
+ assert(strb->surface);
+ pipe_surface_reference(&framebuffer->zsbuf, strb->surface);
+ }
+ else
+ pipe_surface_reference(&framebuffer->zsbuf, NULL);
+ }
+
+#ifdef DEBUG
+ /* Make sure the resource binding flags were set properly */
+ for (i = 0; i < framebuffer->nr_cbufs; i++) {
+ assert(framebuffer->cbufs[i]->texture->bind & PIPE_BIND_RENDER_TARGET);
+ }
+ if (framebuffer->zsbuf) {
+ assert(framebuffer->zsbuf->texture->bind & PIPE_BIND_DEPTH_STENCIL);
+ }
+#endif
+
+ cso_set_framebuffer(st->cso_context, framebuffer);
+}
+
+
+const struct st_tracked_state st_update_framebuffer = {
+ "st_update_framebuffer", /* name */
+ { /* dirty */
+ _NEW_BUFFERS, /* mesa */
+ ST_NEW_FRAMEBUFFER, /* st */
+ },
+ update_framebuffer_state /* update */
+};
+
diff --git a/mesalib/src/mesa/state_tracker/st_atom_sampler.c b/mesalib/src/mesa/state_tracker/st_atom_sampler.c
index 474cbd589..17596d4c8 100644
--- a/mesalib/src/mesa/state_tracker/st_atom_sampler.c
+++ b/mesalib/src/mesa/state_tracker/st_atom_sampler.c
@@ -1,228 +1,228 @@
-/**************************************************************************
- *
- * 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 <keith@tungstengraphics.com>
- * Brian Paul
- */
-
-
-#include "main/macros.h"
-
-#include "st_context.h"
-#include "st_cb_texture.h"
-#include "st_format.h"
-#include "st_atom.h"
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-
-#include "cso_cache/cso_context.h"
-
-
-/**
- * Convert GLenum texcoord wrap tokens to pipe tokens.
- */
-static GLuint
-gl_wrap_xlate(GLenum wrap)
-{
- switch (wrap) {
- case GL_REPEAT:
- return PIPE_TEX_WRAP_REPEAT;
- case GL_CLAMP:
- return PIPE_TEX_WRAP_CLAMP;
- case GL_CLAMP_TO_EDGE:
- return PIPE_TEX_WRAP_CLAMP_TO_EDGE;
- case GL_CLAMP_TO_BORDER:
- return PIPE_TEX_WRAP_CLAMP_TO_BORDER;
- case GL_MIRRORED_REPEAT:
- return PIPE_TEX_WRAP_MIRROR_REPEAT;
- case GL_MIRROR_CLAMP_EXT:
- return PIPE_TEX_WRAP_MIRROR_CLAMP;
- case GL_MIRROR_CLAMP_TO_EDGE_EXT:
- return PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE;
- case GL_MIRROR_CLAMP_TO_BORDER_EXT:
- return PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER;
- default:
- assert(0);
- return 0;
- }
-}
-
-
-static GLuint
-gl_filter_to_mip_filter(GLenum filter)
-{
- switch (filter) {
- case GL_NEAREST:
- case GL_LINEAR:
- return PIPE_TEX_MIPFILTER_NONE;
-
- case GL_NEAREST_MIPMAP_NEAREST:
- case GL_LINEAR_MIPMAP_NEAREST:
- return PIPE_TEX_MIPFILTER_NEAREST;
-
- case GL_NEAREST_MIPMAP_LINEAR:
- case GL_LINEAR_MIPMAP_LINEAR:
- return PIPE_TEX_MIPFILTER_LINEAR;
-
- default:
- assert(0);
- return PIPE_TEX_MIPFILTER_NONE;
- }
-}
-
-
-static GLuint
-gl_filter_to_img_filter(GLenum filter)
-{
- switch (filter) {
- case GL_NEAREST:
- case GL_NEAREST_MIPMAP_NEAREST:
- case GL_NEAREST_MIPMAP_LINEAR:
- return PIPE_TEX_FILTER_NEAREST;
-
- case GL_LINEAR:
- case GL_LINEAR_MIPMAP_NEAREST:
- case GL_LINEAR_MIPMAP_LINEAR:
- return PIPE_TEX_FILTER_LINEAR;
-
- default:
- assert(0);
- return PIPE_TEX_FILTER_NEAREST;
- }
-}
-
-
-static void
-update_samplers(struct st_context *st)
-{
- struct gl_vertex_program *vprog = st->ctx->VertexProgram._Current;
- struct gl_fragment_program *fprog = st->ctx->FragmentProgram._Current;
- const GLbitfield samplersUsed = (vprog->Base.SamplersUsed |
- fprog->Base.SamplersUsed);
- GLuint su;
-
- st->state.num_samplers = 0;
-
- /* loop over sampler units (aka tex image units) */
- for (su = 0; su < st->ctx->Const.MaxTextureImageUnits; su++) {
- struct pipe_sampler_state *sampler = st->state.samplers + su;
-
- memset(sampler, 0, sizeof(*sampler));
-
- if (samplersUsed & (1 << su)) {
- struct gl_texture_object *texobj;
- struct gl_texture_image *teximg;
- GLuint texUnit;
-
- if (fprog->Base.SamplersUsed & (1 << su))
- texUnit = fprog->Base.SamplerUnits[su];
- else
- texUnit = vprog->Base.SamplerUnits[su];
-
- texobj = st->ctx->Texture.Unit[texUnit]._Current;
- if (!texobj) {
- texobj = st_get_default_texture(st);
- }
-
- teximg = texobj->Image[0][texobj->BaseLevel];
-
- sampler->wrap_s = gl_wrap_xlate(texobj->WrapS);
- sampler->wrap_t = gl_wrap_xlate(texobj->WrapT);
- sampler->wrap_r = gl_wrap_xlate(texobj->WrapR);
-
- sampler->min_img_filter = gl_filter_to_img_filter(texobj->MinFilter);
- sampler->min_mip_filter = gl_filter_to_mip_filter(texobj->MinFilter);
- sampler->mag_img_filter = gl_filter_to_img_filter(texobj->MagFilter);
-
- if (texobj->Target != GL_TEXTURE_RECTANGLE_ARB)
- sampler->normalized_coords = 1;
-
- sampler->lod_bias = st->ctx->Texture.Unit[su].LodBias;
-
- sampler->min_lod = texobj->BaseLevel + texobj->MinLod;
- if (sampler->min_lod < texobj->BaseLevel)
- sampler->min_lod = texobj->BaseLevel;
-
- sampler->max_lod = MIN2((GLfloat) texobj->MaxLevel,
- (texobj->MaxLod + texobj->BaseLevel));
- if (sampler->max_lod < sampler->min_lod) {
- /* The GL spec doesn't seem to specify what to do in this case.
- * Swap the values.
- */
- float tmp = sampler->max_lod;
- sampler->max_lod = sampler->min_lod;
- sampler->min_lod = tmp;
- assert(sampler->min_lod <= sampler->max_lod);
- }
-
- st_translate_color(texobj->BorderColor.f,
- teximg ? teximg->_BaseFormat : GL_RGBA,
- sampler->border_color);
-
- sampler->max_anisotropy = (texobj->MaxAnisotropy == 1.0 ? 0 : (GLuint)texobj->MaxAnisotropy);
-
- /* only care about ARB_shadow, not SGI shadow */
- if (texobj->CompareMode == GL_COMPARE_R_TO_TEXTURE) {
- sampler->compare_mode = PIPE_TEX_COMPARE_R_TO_TEXTURE;
- sampler->compare_func
- = st_compare_func_to_pipe(texobj->CompareFunc);
- }
-
- st->state.num_samplers = su + 1;
-
- /*printf("%s su=%u non-null\n", __FUNCTION__, su);*/
- cso_single_sampler(st->cso_context, su, sampler);
- if (su < st->ctx->Const.MaxVertexTextureImageUnits) {
- cso_single_vertex_sampler(st->cso_context, su, sampler);
- }
- }
- else {
- /*printf("%s su=%u null\n", __FUNCTION__, su);*/
- cso_single_sampler(st->cso_context, su, NULL);
- if (su < st->ctx->Const.MaxVertexTextureImageUnits) {
- cso_single_vertex_sampler(st->cso_context, su, NULL);
- }
- }
- }
-
- cso_single_sampler_done(st->cso_context);
- if (st->ctx->Const.MaxVertexTextureImageUnits > 0) {
- cso_single_vertex_sampler_done(st->cso_context);
- }
-}
-
-
-const struct st_tracked_state st_update_sampler = {
- "st_update_sampler", /* name */
- { /* dirty */
- _NEW_TEXTURE, /* mesa */
- 0, /* st */
- },
- update_samplers /* update */
-};
+/**************************************************************************
+ *
+ * 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 <keith@tungstengraphics.com>
+ * Brian Paul
+ */
+
+
+#include "main/macros.h"
+
+#include "st_context.h"
+#include "st_cb_texture.h"
+#include "st_format.h"
+#include "st_atom.h"
+#include "pipe/p_context.h"
+#include "pipe/p_defines.h"
+
+#include "cso_cache/cso_context.h"
+
+
+/**
+ * Convert GLenum texcoord wrap tokens to pipe tokens.
+ */
+static GLuint
+gl_wrap_xlate(GLenum wrap)
+{
+ switch (wrap) {
+ case GL_REPEAT:
+ return PIPE_TEX_WRAP_REPEAT;
+ case GL_CLAMP:
+ return PIPE_TEX_WRAP_CLAMP;
+ case GL_CLAMP_TO_EDGE:
+ return PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+ case GL_CLAMP_TO_BORDER:
+ return PIPE_TEX_WRAP_CLAMP_TO_BORDER;
+ case GL_MIRRORED_REPEAT:
+ return PIPE_TEX_WRAP_MIRROR_REPEAT;
+ case GL_MIRROR_CLAMP_EXT:
+ return PIPE_TEX_WRAP_MIRROR_CLAMP;
+ case GL_MIRROR_CLAMP_TO_EDGE_EXT:
+ return PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE;
+ case GL_MIRROR_CLAMP_TO_BORDER_EXT:
+ return PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+
+static GLuint
+gl_filter_to_mip_filter(GLenum filter)
+{
+ switch (filter) {
+ case GL_NEAREST:
+ case GL_LINEAR:
+ return PIPE_TEX_MIPFILTER_NONE;
+
+ case GL_NEAREST_MIPMAP_NEAREST:
+ case GL_LINEAR_MIPMAP_NEAREST:
+ return PIPE_TEX_MIPFILTER_NEAREST;
+
+ case GL_NEAREST_MIPMAP_LINEAR:
+ case GL_LINEAR_MIPMAP_LINEAR:
+ return PIPE_TEX_MIPFILTER_LINEAR;
+
+ default:
+ assert(0);
+ return PIPE_TEX_MIPFILTER_NONE;
+ }
+}
+
+
+static GLuint
+gl_filter_to_img_filter(GLenum filter)
+{
+ switch (filter) {
+ case GL_NEAREST:
+ case GL_NEAREST_MIPMAP_NEAREST:
+ case GL_NEAREST_MIPMAP_LINEAR:
+ return PIPE_TEX_FILTER_NEAREST;
+
+ case GL_LINEAR:
+ case GL_LINEAR_MIPMAP_NEAREST:
+ case GL_LINEAR_MIPMAP_LINEAR:
+ return PIPE_TEX_FILTER_LINEAR;
+
+ default:
+ assert(0);
+ return PIPE_TEX_FILTER_NEAREST;
+ }
+}
+
+
+static void
+update_samplers(struct st_context *st)
+{
+ struct gl_vertex_program *vprog = st->ctx->VertexProgram._Current;
+ struct gl_fragment_program *fprog = st->ctx->FragmentProgram._Current;
+ const GLbitfield samplersUsed = (vprog->Base.SamplersUsed |
+ fprog->Base.SamplersUsed);
+ GLuint su;
+
+ st->state.num_samplers = 0;
+
+ /* loop over sampler units (aka tex image units) */
+ for (su = 0; su < st->ctx->Const.MaxTextureImageUnits; su++) {
+ struct pipe_sampler_state *sampler = st->state.samplers + su;
+
+ memset(sampler, 0, sizeof(*sampler));
+
+ if (samplersUsed & (1 << su)) {
+ struct gl_texture_object *texobj;
+ struct gl_texture_image *teximg;
+ GLuint texUnit;
+
+ if (fprog->Base.SamplersUsed & (1 << su))
+ texUnit = fprog->Base.SamplerUnits[su];
+ else
+ texUnit = vprog->Base.SamplerUnits[su];
+
+ texobj = st->ctx->Texture.Unit[texUnit]._Current;
+ if (!texobj) {
+ texobj = st_get_default_texture(st);
+ }
+
+ teximg = texobj->Image[0][texobj->BaseLevel];
+
+ sampler->wrap_s = gl_wrap_xlate(texobj->WrapS);
+ sampler->wrap_t = gl_wrap_xlate(texobj->WrapT);
+ sampler->wrap_r = gl_wrap_xlate(texobj->WrapR);
+
+ sampler->min_img_filter = gl_filter_to_img_filter(texobj->MinFilter);
+ sampler->min_mip_filter = gl_filter_to_mip_filter(texobj->MinFilter);
+ sampler->mag_img_filter = gl_filter_to_img_filter(texobj->MagFilter);
+
+ if (texobj->Target != GL_TEXTURE_RECTANGLE_ARB)
+ sampler->normalized_coords = 1;
+
+ sampler->lod_bias = st->ctx->Texture.Unit[su].LodBias;
+
+ sampler->min_lod = texobj->BaseLevel + texobj->MinLod;
+ if (sampler->min_lod < texobj->BaseLevel)
+ sampler->min_lod = texobj->BaseLevel;
+
+ sampler->max_lod = MIN2((GLfloat) texobj->MaxLevel,
+ (texobj->MaxLod + texobj->BaseLevel));
+ if (sampler->max_lod < sampler->min_lod) {
+ /* The GL spec doesn't seem to specify what to do in this case.
+ * Swap the values.
+ */
+ float tmp = sampler->max_lod;
+ sampler->max_lod = sampler->min_lod;
+ sampler->min_lod = tmp;
+ assert(sampler->min_lod <= sampler->max_lod);
+ }
+
+ st_translate_color(texobj->BorderColor.f,
+ teximg ? teximg->_BaseFormat : GL_RGBA,
+ sampler->border_color);
+
+ sampler->max_anisotropy = (texobj->MaxAnisotropy == 1.0 ? 0 : (GLuint)texobj->MaxAnisotropy);
+
+ /* only care about ARB_shadow, not SGI shadow */
+ if (texobj->CompareMode == GL_COMPARE_R_TO_TEXTURE) {
+ sampler->compare_mode = PIPE_TEX_COMPARE_R_TO_TEXTURE;
+ sampler->compare_func
+ = st_compare_func_to_pipe(texobj->CompareFunc);
+ }
+
+ st->state.num_samplers = su + 1;
+
+ /*printf("%s su=%u non-null\n", __FUNCTION__, su);*/
+ cso_single_sampler(st->cso_context, su, sampler);
+ if (su < st->ctx->Const.MaxVertexTextureImageUnits) {
+ cso_single_vertex_sampler(st->cso_context, su, sampler);
+ }
+ }
+ else {
+ /*printf("%s su=%u null\n", __FUNCTION__, su);*/
+ cso_single_sampler(st->cso_context, su, NULL);
+ if (su < st->ctx->Const.MaxVertexTextureImageUnits) {
+ cso_single_vertex_sampler(st->cso_context, su, NULL);
+ }
+ }
+ }
+
+ cso_single_sampler_done(st->cso_context);
+ if (st->ctx->Const.MaxVertexTextureImageUnits > 0) {
+ cso_single_vertex_sampler_done(st->cso_context);
+ }
+}
+
+
+const struct st_tracked_state st_update_sampler = {
+ "st_update_sampler", /* name */
+ { /* dirty */
+ _NEW_TEXTURE, /* mesa */
+ 0, /* st */
+ },
+ update_samplers /* update */
+};
diff --git a/mesalib/src/mesa/state_tracker/st_cb_bitmap.c b/mesalib/src/mesa/state_tracker/st_cb_bitmap.c
index 0ea567155..51623c179 100644
--- a/mesalib/src/mesa/state_tracker/st_cb_bitmap.c
+++ b/mesalib/src/mesa/state_tracker/st_cb_bitmap.c
@@ -1,893 +1,893 @@
-/**************************************************************************
- *
- * 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:
- * Brian Paul
- */
-
-#include "main/imports.h"
-#include "main/image.h"
-#include "main/bufferobj.h"
-#include "main/macros.h"
-#include "main/mfeatures.h"
-#include "program/program.h"
-#include "program/prog_print.h"
-
-#include "st_context.h"
-#include "st_atom.h"
-#include "st_atom_constbuf.h"
-#include "st_program.h"
-#include "st_cb_bitmap.h"
-#include "st_texture.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "pipe/p_shader_tokens.h"
-#include "util/u_inlines.h"
-#include "util/u_draw_quad.h"
-#include "util/u_simple_shaders.h"
-#include "program/prog_instruction.h"
-#include "cso_cache/cso_context.h"
-
-
-#if FEATURE_drawpix
-
-/**
- * glBitmaps are drawn as textured quads. The user's bitmap pattern
- * is stored in a texture image. An alpha8 texture format is used.
- * The fragment shader samples a bit (texel) from the texture, then
- * discards the fragment if the bit is off.
- *
- * Note that we actually store the inverse image of the bitmap to
- * simplify the fragment program. An "on" bit gets stored as texel=0x0
- * and an "off" bit is stored as texel=0xff. Then we kill the
- * fragment if the negated texel value is less than zero.
- */
-
-
-/**
- * The bitmap cache attempts to accumulate multiple glBitmap calls in a
- * buffer which is then rendered en mass upon a flush, state change, etc.
- * A wide, short buffer is used to target the common case of a series
- * of glBitmap calls being used to draw text.
- */
-static GLboolean UseBitmapCache = GL_TRUE;
-
-
-#define BITMAP_CACHE_WIDTH 512
-#define BITMAP_CACHE_HEIGHT 32
-
-struct bitmap_cache
-{
- /** Window pos to render the cached image */
- GLint xpos, ypos;
- /** Bounds of region used in window coords */
- GLint xmin, ymin, xmax, ymax;
-
- GLfloat color[4];
-
- /** Bitmap's Z position */
- GLfloat zpos;
-
- struct pipe_resource *texture;
- struct pipe_transfer *trans;
-
- GLboolean empty;
-
- /** An I8 texture image: */
- ubyte *buffer;
-};
-
-
-/** Epsilon for Z comparisons */
-#define Z_EPSILON 1e-06
-
-
-/**
- * Make fragment program for glBitmap:
- * Sample the texture and kill the fragment if the bit is 0.
- * This program will be combined with the user's fragment program.
- */
-static struct st_fragment_program *
-make_bitmap_fragment_program(struct gl_context *ctx, GLuint samplerIndex)
-{
- struct st_context *st = st_context(ctx);
- struct st_fragment_program *stfp;
- struct gl_program *p;
- GLuint ic = 0;
-
- p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
- if (!p)
- return NULL;
-
- p->NumInstructions = 3;
-
- p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
- if (!p->Instructions) {
- ctx->Driver.DeleteProgram(ctx, p);
- return NULL;
- }
- _mesa_init_instructions(p->Instructions, p->NumInstructions);
-
- /* TEX tmp0, fragment.texcoord[0], texture[0], 2D; */
- p->Instructions[ic].Opcode = OPCODE_TEX;
- p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY;
- p->Instructions[ic].DstReg.Index = 0;
- p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
- p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
- p->Instructions[ic].TexSrcUnit = samplerIndex;
- p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
- ic++;
-
- /* KIL if -tmp0 < 0 # texel=0 -> keep / texel=0 -> discard */
- p->Instructions[ic].Opcode = OPCODE_KIL;
- p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
-
- if (st->bitmap.tex_format == PIPE_FORMAT_L8_UNORM)
- p->Instructions[ic].SrcReg[0].Swizzle = SWIZZLE_XXXX;
-
- p->Instructions[ic].SrcReg[0].Index = 0;
- p->Instructions[ic].SrcReg[0].Negate = NEGATE_XYZW;
- ic++;
-
- /* END; */
- p->Instructions[ic++].Opcode = OPCODE_END;
-
- assert(ic == p->NumInstructions);
-
- p->InputsRead = FRAG_BIT_TEX0;
- p->OutputsWritten = 0x0;
- p->SamplersUsed = (1 << samplerIndex);
-
- stfp = (struct st_fragment_program *) p;
- stfp->Base.UsesKill = GL_TRUE;
-
- return stfp;
-}
-
-
-static int
-find_free_bit(uint bitfield)
-{
- int i;
- for (i = 0; i < 32; i++) {
- if ((bitfield & (1 << i)) == 0) {
- return i;
- }
- }
- return -1;
-}
-
-
-/**
- * Combine basic bitmap fragment program with the user-defined program.
- * \param st current context
- * \param fpIn the incoming fragment program
- * \param fpOut the new fragment program which does fragment culling
- * \param bitmap_sampler sampler number for the bitmap texture
- */
-void
-st_make_bitmap_fragment_program(struct st_context *st,
- struct gl_fragment_program *fpIn,
- struct gl_fragment_program **fpOut,
- GLuint *bitmap_sampler)
-{
- struct st_fragment_program *bitmap_prog;
- struct gl_program *newProg;
- uint sampler;
-
- /*
- * Generate new program which is the user-defined program prefixed
- * with the bitmap sampler/kill instructions.
- */
- sampler = find_free_bit(fpIn->Base.SamplersUsed);
- bitmap_prog = make_bitmap_fragment_program(st->ctx, sampler);
-
- newProg = _mesa_combine_programs(st->ctx,
- &bitmap_prog->Base.Base,
- &fpIn->Base);
- /* done with this after combining */
- st_reference_fragprog(st, &bitmap_prog, NULL);
-
-#if 0
- {
- printf("Combined bitmap program:\n");
- _mesa_print_program(newProg);
- printf("InputsRead: 0x%x\n", newProg->InputsRead);
- printf("OutputsWritten: 0x%x\n", newProg->OutputsWritten);
- _mesa_print_parameter_list(newProg->Parameters);
- }
-#endif
-
- /* return results */
- *fpOut = (struct gl_fragment_program *) newProg;
- *bitmap_sampler = sampler;
-}
-
-
-/**
- * Copy user-provide bitmap bits into texture buffer, expanding
- * bits into texels.
- * "On" bits will set texels to 0x0.
- * "Off" bits will not modify texels.
- * Note that the image is actually going to be upside down in
- * the texture. We deal with that with texcoords.
- */
-static void
-unpack_bitmap(struct st_context *st,
- GLint px, GLint py, GLsizei width, GLsizei height,
- const struct gl_pixelstore_attrib *unpack,
- const GLubyte *bitmap,
- ubyte *destBuffer, uint destStride)
-{
- destBuffer += py * destStride + px;
-
- _mesa_expand_bitmap(width, height, unpack, bitmap,
- destBuffer, destStride, 0x0);
-}
-
-
-/**
- * Create a texture which represents a bitmap image.
- */
-static struct pipe_resource *
-make_bitmap_texture(struct gl_context *ctx, GLsizei width, GLsizei height,
- const struct gl_pixelstore_attrib *unpack,
- const GLubyte *bitmap)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct pipe_transfer *transfer;
- ubyte *dest;
- struct pipe_resource *pt;
-
- /* PBO source... */
- bitmap = _mesa_map_pbo_source(ctx, unpack, bitmap);
- if (!bitmap) {
- return NULL;
- }
-
- /**
- * Create texture to hold bitmap pattern.
- */
- pt = st_texture_create(st, st->internal_target, st->bitmap.tex_format,
- 0, width, height, 1, 1,
- PIPE_BIND_SAMPLER_VIEW);
- if (!pt) {
- _mesa_unmap_pbo_source(ctx, unpack);
- return NULL;
- }
-
- transfer = pipe_get_transfer(st->pipe, pt, 0, 0,
- PIPE_TRANSFER_WRITE,
- 0, 0, width, height);
-
- dest = pipe_transfer_map(pipe, transfer);
-
- /* Put image into texture transfer */
- memset(dest, 0xff, height * transfer->stride);
- unpack_bitmap(st, 0, 0, width, height, unpack, bitmap,
- dest, transfer->stride);
-
- _mesa_unmap_pbo_source(ctx, unpack);
-
- /* Release transfer */
- pipe_transfer_unmap(pipe, transfer);
- pipe->transfer_destroy(pipe, transfer);
-
- return pt;
-}
-
-static GLuint
-setup_bitmap_vertex_data(struct st_context *st, bool normalized,
- int x, int y, int width, int height,
- float z, const float color[4])
-{
- struct pipe_context *pipe = st->pipe;
- const struct gl_framebuffer *fb = st->ctx->DrawBuffer;
- const GLfloat fb_width = (GLfloat)fb->Width;
- const GLfloat fb_height = (GLfloat)fb->Height;
- const GLfloat x0 = (GLfloat)x;
- const GLfloat x1 = (GLfloat)(x + width);
- const GLfloat y0 = (GLfloat)y;
- const GLfloat y1 = (GLfloat)(y + height);
- GLfloat sLeft = (GLfloat)0.0, sRight = (GLfloat)1.0;
- GLfloat tTop = (GLfloat)0.0, tBot = (GLfloat)1.0 - tTop;
- const GLfloat clip_x0 = (GLfloat)(x0 / fb_width * 2.0 - 1.0);
- const GLfloat clip_y0 = (GLfloat)(y0 / fb_height * 2.0 - 1.0);
- const GLfloat clip_x1 = (GLfloat)(x1 / fb_width * 2.0 - 1.0);
- const GLfloat clip_y1 = (GLfloat)(y1 / fb_height * 2.0 - 1.0);
- const GLuint max_slots = 1; /* 4096 / sizeof(st->bitmap.vertices); */
- GLuint i;
-
- if(!normalized)
- {
- sRight = width;
- tBot = height;
- }
-
- /* XXX: Need to improve buffer_write to allow NO_WAIT (as well as
- * no_flush) updates to buffers where we know there is no conflict
- * with previous data. Currently using max_slots > 1 will cause
- * synchronous rendering if the driver flushes its command buffers
- * between one bitmap and the next. Our flush hook below isn't
- * sufficient to catch this as the driver doesn't tell us when it
- * flushes its own command buffers. Until this gets fixed, pay the
- * price of allocating a new buffer for each bitmap cache-flush to
- * avoid synchronous rendering.
- */
- if (st->bitmap.vbuf_slot >= max_slots) {
- pipe_resource_reference(&st->bitmap.vbuf, NULL);
- st->bitmap.vbuf_slot = 0;
- }
-
- if (!st->bitmap.vbuf) {
- st->bitmap.vbuf = pipe_buffer_create(pipe->screen,
- PIPE_BIND_VERTEX_BUFFER,
- PIPE_USAGE_STREAM,
- max_slots *
- sizeof(st->bitmap.vertices));
- }
-
- /* Positions are in clip coords since we need to do clipping in case
- * the bitmap quad goes beyond the window bounds.
- */
- st->bitmap.vertices[0][0][0] = clip_x0;
- st->bitmap.vertices[0][0][1] = clip_y0;
- st->bitmap.vertices[0][2][0] = sLeft;
- st->bitmap.vertices[0][2][1] = tTop;
-
- st->bitmap.vertices[1][0][0] = clip_x1;
- st->bitmap.vertices[1][0][1] = clip_y0;
- st->bitmap.vertices[1][2][0] = sRight;
- st->bitmap.vertices[1][2][1] = tTop;
-
- st->bitmap.vertices[2][0][0] = clip_x1;
- st->bitmap.vertices[2][0][1] = clip_y1;
- st->bitmap.vertices[2][2][0] = sRight;
- st->bitmap.vertices[2][2][1] = tBot;
-
- st->bitmap.vertices[3][0][0] = clip_x0;
- st->bitmap.vertices[3][0][1] = clip_y1;
- st->bitmap.vertices[3][2][0] = sLeft;
- st->bitmap.vertices[3][2][1] = tBot;
-
- /* same for all verts: */
- for (i = 0; i < 4; i++) {
- st->bitmap.vertices[i][0][2] = z;
- st->bitmap.vertices[i][0][3] = 1.0;
- st->bitmap.vertices[i][1][0] = color[0];
- st->bitmap.vertices[i][1][1] = color[1];
- st->bitmap.vertices[i][1][2] = color[2];
- st->bitmap.vertices[i][1][3] = color[3];
- st->bitmap.vertices[i][2][2] = 0.0; /*R*/
- st->bitmap.vertices[i][2][3] = 1.0; /*Q*/
- }
-
- /* put vertex data into vbuf */
- pipe_buffer_write_nooverlap(st->pipe,
- st->bitmap.vbuf,
- st->bitmap.vbuf_slot
- * sizeof(st->bitmap.vertices),
- sizeof st->bitmap.vertices,
- st->bitmap.vertices);
-
- return st->bitmap.vbuf_slot++ * sizeof st->bitmap.vertices;
-}
-
-
-
-/**
- * Render a glBitmap by drawing a textured quad
- */
-static void
-draw_bitmap_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z,
- GLsizei width, GLsizei height,
- struct pipe_sampler_view *sv,
- const GLfloat *color)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct cso_context *cso = st->cso_context;
- struct st_fp_variant *fpv;
- struct st_fp_variant_key key;
- GLuint maxSize;
- GLuint offset;
-
- memset(&key, 0, sizeof(key));
- key.st = st;
- key.bitmap = GL_TRUE;
-
- fpv = st_get_fp_variant(st, st->fp, &key);
-
- /* As an optimization, Mesa's fragment programs will sometimes get the
- * primary color from a statevar/constant rather than a varying variable.
- * when that's the case, we need to ensure that we use the 'color'
- * parameter and not the current attribute color (which may have changed
- * through glRasterPos and state validation.
- * So, we force the proper color here. Not elegant, but it works.
- */
- {
- GLfloat colorSave[4];
- COPY_4V(colorSave, ctx->Current.Attrib[VERT_ATTRIB_COLOR0]);
- COPY_4V(ctx->Current.Attrib[VERT_ATTRIB_COLOR0], color);
- st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT);
- COPY_4V(ctx->Current.Attrib[VERT_ATTRIB_COLOR0], colorSave);
- }
-
-
- /* limit checks */
- /* XXX if the bitmap is larger than the max texture size, break
- * it up into chunks.
- */
- maxSize = 1 << (pipe->screen->get_param(pipe->screen,
- PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1);
- assert(width <= (GLsizei)maxSize);
- assert(height <= (GLsizei)maxSize);
-
- cso_save_rasterizer(cso);
- cso_save_samplers(cso);
- cso_save_fragment_sampler_views(cso);
- cso_save_viewport(cso);
- cso_save_fragment_shader(cso);
- cso_save_vertex_shader(cso);
- cso_save_vertex_elements(cso);
- cso_save_vertex_buffers(cso);
-
- /* rasterizer state: just scissor */
- st->bitmap.rasterizer.scissor = ctx->Scissor.Enabled;
- cso_set_rasterizer(cso, &st->bitmap.rasterizer);
-
- /* fragment shader state: TEX lookup program */
- cso_set_fragment_shader_handle(cso, fpv->driver_shader);
-
- /* vertex shader state: position + texcoord pass-through */
- cso_set_vertex_shader_handle(cso, st->bitmap.vs);
-
- /* user samplers, plus our bitmap sampler */
- {
- struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
- uint num = MAX2(fpv->bitmap_sampler + 1, st->state.num_samplers);
- uint i;
- for (i = 0; i < st->state.num_samplers; i++) {
- samplers[i] = &st->state.samplers[i];
- }
- samplers[fpv->bitmap_sampler] =
- &st->bitmap.samplers[sv->texture->target != PIPE_TEXTURE_RECT];
- cso_set_samplers(cso, num, (const struct pipe_sampler_state **) samplers);
- }
-
- /* user textures, plus the bitmap texture */
- {
- struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS];
- uint num = MAX2(fpv->bitmap_sampler + 1, st->state.num_textures);
- memcpy(sampler_views, st->state.sampler_views, sizeof(sampler_views));
- sampler_views[fpv->bitmap_sampler] = sv;
- cso_set_fragment_sampler_views(cso, num, sampler_views);
- }
-
- /* viewport state: viewport matching window dims */
- {
- const struct gl_framebuffer *fb = st->ctx->DrawBuffer;
- const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP);
- const GLfloat width = (GLfloat)fb->Width;
- const GLfloat height = (GLfloat)fb->Height;
- struct pipe_viewport_state vp;
- vp.scale[0] = 0.5f * width;
- vp.scale[1] = height * (invert ? -0.5f : 0.5f);
- vp.scale[2] = 0.5f;
- vp.scale[3] = 1.0f;
- vp.translate[0] = 0.5f * width;
- vp.translate[1] = 0.5f * height;
- vp.translate[2] = 0.5f;
- vp.translate[3] = 0.0f;
- cso_set_viewport(cso, &vp);
- }
-
- cso_set_vertex_elements(cso, 3, st->velems_util_draw);
-
- /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */
- z = z * 2.0 - 1.0;
-
- /* draw textured quad */
- offset = setup_bitmap_vertex_data(st,
- sv->texture->target != PIPE_TEXTURE_RECT,
- x, y, width, height, z, color);
-
- util_draw_vertex_buffer(pipe, st->cso_context, st->bitmap.vbuf, offset,
- PIPE_PRIM_TRIANGLE_FAN,
- 4, /* verts */
- 3); /* attribs/vert */
-
-
- /* restore state */
- cso_restore_rasterizer(cso);
- cso_restore_samplers(cso);
- cso_restore_fragment_sampler_views(cso);
- cso_restore_viewport(cso);
- cso_restore_fragment_shader(cso);
- cso_restore_vertex_shader(cso);
- cso_restore_vertex_elements(cso);
- cso_restore_vertex_buffers(cso);
-}
-
-
-static void
-reset_cache(struct st_context *st)
-{
- struct pipe_context *pipe = st->pipe;
- struct bitmap_cache *cache = st->bitmap.cache;
-
- /*memset(cache->buffer, 0xff, sizeof(cache->buffer));*/
- cache->empty = GL_TRUE;
-
- cache->xmin = 1000000;
- cache->xmax = -1000000;
- cache->ymin = 1000000;
- cache->ymax = -1000000;
-
- if (cache->trans) {
- pipe->transfer_destroy(pipe, cache->trans);
- cache->trans = NULL;
- }
-
- assert(!cache->texture);
-
- /* allocate a new texture */
- cache->texture = st_texture_create(st, PIPE_TEXTURE_2D,
- st->bitmap.tex_format, 0,
- BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT,
- 1, 1,
- PIPE_BIND_SAMPLER_VIEW);
-}
-
-
-/** Print bitmap image to stdout (debug) */
-static void
-print_cache(const struct bitmap_cache *cache)
-{
- int i, j, k;
-
- for (i = 0; i < BITMAP_CACHE_HEIGHT; i++) {
- k = BITMAP_CACHE_WIDTH * (BITMAP_CACHE_HEIGHT - i - 1);
- for (j = 0; j < BITMAP_CACHE_WIDTH; j++) {
- if (cache->buffer[k])
- printf("X");
- else
- printf(" ");
- k++;
- }
- printf("\n");
- }
-}
-
-
-/**
- * Create gallium pipe_transfer object for the bitmap cache.
- */
-static void
-create_cache_trans(struct st_context *st)
-{
- struct pipe_context *pipe = st->pipe;
- struct bitmap_cache *cache = st->bitmap.cache;
-
- if (cache->trans)
- return;
-
- /* Map the texture transfer.
- * Subsequent glBitmap calls will write into the texture image.
- */
- cache->trans = pipe_get_transfer(st->pipe, cache->texture, 0, 0,
- PIPE_TRANSFER_WRITE, 0, 0,
- BITMAP_CACHE_WIDTH,
- BITMAP_CACHE_HEIGHT);
- cache->buffer = pipe_transfer_map(pipe, cache->trans);
-
- /* init image to all 0xff */
- memset(cache->buffer, 0xff, cache->trans->stride * BITMAP_CACHE_HEIGHT);
-}
-
-
-/**
- * If there's anything in the bitmap cache, draw/flush it now.
- */
-void
-st_flush_bitmap_cache(struct st_context *st)
-{
- if (!st->bitmap.cache->empty) {
- struct bitmap_cache *cache = st->bitmap.cache;
-
- if (st->ctx->DrawBuffer) {
- struct pipe_context *pipe = st->pipe;
- struct pipe_sampler_view *sv;
-
- assert(cache->xmin <= cache->xmax);
-
-/* printf("flush size %d x %d at %d, %d\n",
- cache->xmax - cache->xmin,
- cache->ymax - cache->ymin,
- cache->xpos, cache->ypos);
-*/
-
- /* The texture transfer has been mapped until now.
- * So unmap and release the texture transfer before drawing.
- */
- if (cache->trans) {
- if (0)
- print_cache(cache);
- pipe_transfer_unmap(pipe, cache->trans);
- cache->buffer = NULL;
-
- pipe->transfer_destroy(pipe, cache->trans);
- cache->trans = NULL;
- }
-
- sv = st_create_texture_sampler_view(st->pipe, cache->texture);
- if (sv) {
- draw_bitmap_quad(st->ctx,
- cache->xpos,
- cache->ypos,
- cache->zpos,
- BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT,
- sv,
- cache->color);
-
- pipe_sampler_view_reference(&sv, NULL);
- }
- }
-
- /* release/free the texture */
- pipe_resource_reference(&cache->texture, NULL);
-
- reset_cache(st);
- }
-}
-
-
-/**
- * Flush bitmap cache and release vertex buffer.
- */
-void
-st_flush_bitmap( struct st_context *st )
-{
- st_flush_bitmap_cache(st);
-
- /* Release vertex buffer to avoid synchronous rendering if we were
- * to map it in the next frame.
- */
- pipe_resource_reference(&st->bitmap.vbuf, NULL);
- st->bitmap.vbuf_slot = 0;
-}
-
-
-/**
- * Try to accumulate this glBitmap call in the bitmap cache.
- * \return GL_TRUE for success, GL_FALSE if bitmap is too large, etc.
- */
-static GLboolean
-accum_bitmap(struct st_context *st,
- GLint x, GLint y, GLsizei width, GLsizei height,
- const struct gl_pixelstore_attrib *unpack,
- const GLubyte *bitmap )
-{
- struct bitmap_cache *cache = st->bitmap.cache;
- int px = -999, py = -999;
- const GLfloat z = st->ctx->Current.RasterPos[2];
-
- if (width > BITMAP_CACHE_WIDTH ||
- height > BITMAP_CACHE_HEIGHT)
- return GL_FALSE; /* too big to cache */
-
- if (!cache->empty) {
- px = x - cache->xpos; /* pos in buffer */
- py = y - cache->ypos;
- if (px < 0 || px + width > BITMAP_CACHE_WIDTH ||
- py < 0 || py + height > BITMAP_CACHE_HEIGHT ||
- !TEST_EQ_4V(st->ctx->Current.RasterColor, cache->color) ||
- ((fabs(z - cache->zpos) > Z_EPSILON))) {
- /* This bitmap would extend beyond cache bounds, or the bitmap
- * color is changing
- * so flush and continue.
- */
- st_flush_bitmap_cache(st);
- }
- }
-
- if (cache->empty) {
- /* Initialize. Center bitmap vertically in the buffer. */
- px = 0;
- py = (BITMAP_CACHE_HEIGHT - height) / 2;
- cache->xpos = x;
- cache->ypos = y - py;
- cache->zpos = z;
- cache->empty = GL_FALSE;
- COPY_4FV(cache->color, st->ctx->Current.RasterColor);
- }
-
- assert(px != -999);
- assert(py != -999);
-
- if (x < cache->xmin)
- cache->xmin = x;
- if (y < cache->ymin)
- cache->ymin = y;
- if (x + width > cache->xmax)
- cache->xmax = x + width;
- if (y + height > cache->ymax)
- cache->ymax = y + height;
-
- /* create the transfer if needed */
- create_cache_trans(st);
-
- unpack_bitmap(st, px, py, width, height, unpack, bitmap,
- cache->buffer, BITMAP_CACHE_WIDTH);
-
- return GL_TRUE; /* accumulated */
-}
-
-
-
-/**
- * Called via ctx->Driver.Bitmap()
- */
-static void
-st_Bitmap(struct gl_context *ctx, GLint x, GLint y,
- GLsizei width, GLsizei height,
- const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap )
-{
- struct st_context *st = st_context(ctx);
- struct pipe_resource *pt;
-
- if (width == 0 || height == 0)
- return;
-
- st_validate_state(st);
-
- if (!st->bitmap.vs) {
- /* create pass-through vertex shader now */
- const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
- TGSI_SEMANTIC_COLOR,
- TGSI_SEMANTIC_GENERIC };
- const uint semantic_indexes[] = { 0, 0, 0 };
- st->bitmap.vs = util_make_vertex_passthrough_shader(st->pipe, 3,
- semantic_names,
- semantic_indexes);
- }
-
- if (UseBitmapCache && accum_bitmap(st, x, y, width, height, unpack, bitmap))
- return;
-
- pt = make_bitmap_texture(ctx, width, height, unpack, bitmap);
- if (pt) {
- struct pipe_sampler_view *sv =
- st_create_texture_sampler_view(st->pipe, pt);
-
- assert(pt->target == PIPE_TEXTURE_2D || pt->target == PIPE_TEXTURE_RECT);
-
- if (sv) {
- draw_bitmap_quad(ctx, x, y, ctx->Current.RasterPos[2],
- width, height, sv,
- st->ctx->Current.RasterColor);
-
- pipe_sampler_view_reference(&sv, NULL);
- }
-
- /* release/free the texture */
- pipe_resource_reference(&pt, NULL);
- }
-}
-
-
-/** Per-context init */
-void
-st_init_bitmap_functions(struct dd_function_table *functions)
-{
- functions->Bitmap = st_Bitmap;
-}
-
-
-/** Per-context init */
-void
-st_init_bitmap(struct st_context *st)
-{
- struct pipe_sampler_state *sampler = &st->bitmap.samplers[0];
- struct pipe_context *pipe = st->pipe;
- struct pipe_screen *screen = pipe->screen;
-
- /* init sampler state once */
- memset(sampler, 0, sizeof(*sampler));
- sampler->wrap_s = PIPE_TEX_WRAP_CLAMP;
- sampler->wrap_t = PIPE_TEX_WRAP_CLAMP;
- sampler->wrap_r = PIPE_TEX_WRAP_CLAMP;
- sampler->min_img_filter = PIPE_TEX_FILTER_NEAREST;
- sampler->min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
- sampler->mag_img_filter = PIPE_TEX_FILTER_NEAREST;
- st->bitmap.samplers[1] = *sampler;
- st->bitmap.samplers[1].normalized_coords = 1;
-
- /* init baseline rasterizer state once */
- memset(&st->bitmap.rasterizer, 0, sizeof(st->bitmap.rasterizer));
- st->bitmap.rasterizer.gl_rasterization_rules = 1;
-
- /* find a usable texture format */
- if (screen->is_format_supported(screen, PIPE_FORMAT_I8_UNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW, 0)) {
- st->bitmap.tex_format = PIPE_FORMAT_I8_UNORM;
- }
- else if (screen->is_format_supported(screen, PIPE_FORMAT_A8_UNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW, 0)) {
- st->bitmap.tex_format = PIPE_FORMAT_A8_UNORM;
- }
- else if (screen->is_format_supported(screen, PIPE_FORMAT_L8_UNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW, 0)) {
- st->bitmap.tex_format = PIPE_FORMAT_L8_UNORM;
- }
- else {
- /* XXX support more formats */
- assert(0);
- }
-
- /* alloc bitmap cache object */
- st->bitmap.cache = ST_CALLOC_STRUCT(bitmap_cache);
-
- reset_cache(st);
-}
-
-
-/** Per-context tear-down */
-void
-st_destroy_bitmap(struct st_context *st)
-{
- struct pipe_context *pipe = st->pipe;
- struct bitmap_cache *cache = st->bitmap.cache;
-
- if (st->bitmap.vs) {
- cso_delete_vertex_shader(st->cso_context, st->bitmap.vs);
- st->bitmap.vs = NULL;
- }
-
- if (st->bitmap.vbuf) {
- pipe_resource_reference(&st->bitmap.vbuf, NULL);
- st->bitmap.vbuf = NULL;
- }
-
- if (cache) {
- if (cache->trans) {
- pipe_transfer_unmap(pipe, cache->trans);
- pipe->transfer_destroy(pipe, cache->trans);
- }
- pipe_resource_reference(&st->bitmap.cache->texture, NULL);
- free(st->bitmap.cache);
- st->bitmap.cache = NULL;
- }
-}
-
-#endif /* FEATURE_drawpix */
+/**************************************************************************
+ *
+ * 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:
+ * Brian Paul
+ */
+
+#include "main/imports.h"
+#include "main/image.h"
+#include "main/bufferobj.h"
+#include "main/macros.h"
+#include "main/mfeatures.h"
+#include "program/program.h"
+#include "program/prog_print.h"
+
+#include "st_context.h"
+#include "st_atom.h"
+#include "st_atom_constbuf.h"
+#include "st_program.h"
+#include "st_cb_bitmap.h"
+#include "st_texture.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_shader_tokens.h"
+#include "util/u_inlines.h"
+#include "util/u_draw_quad.h"
+#include "util/u_simple_shaders.h"
+#include "program/prog_instruction.h"
+#include "cso_cache/cso_context.h"
+
+
+#if FEATURE_drawpix
+
+/**
+ * glBitmaps are drawn as textured quads. The user's bitmap pattern
+ * is stored in a texture image. An alpha8 texture format is used.
+ * The fragment shader samples a bit (texel) from the texture, then
+ * discards the fragment if the bit is off.
+ *
+ * Note that we actually store the inverse image of the bitmap to
+ * simplify the fragment program. An "on" bit gets stored as texel=0x0
+ * and an "off" bit is stored as texel=0xff. Then we kill the
+ * fragment if the negated texel value is less than zero.
+ */
+
+
+/**
+ * The bitmap cache attempts to accumulate multiple glBitmap calls in a
+ * buffer which is then rendered en mass upon a flush, state change, etc.
+ * A wide, short buffer is used to target the common case of a series
+ * of glBitmap calls being used to draw text.
+ */
+static GLboolean UseBitmapCache = GL_TRUE;
+
+
+#define BITMAP_CACHE_WIDTH 512
+#define BITMAP_CACHE_HEIGHT 32
+
+struct bitmap_cache
+{
+ /** Window pos to render the cached image */
+ GLint xpos, ypos;
+ /** Bounds of region used in window coords */
+ GLint xmin, ymin, xmax, ymax;
+
+ GLfloat color[4];
+
+ /** Bitmap's Z position */
+ GLfloat zpos;
+
+ struct pipe_resource *texture;
+ struct pipe_transfer *trans;
+
+ GLboolean empty;
+
+ /** An I8 texture image: */
+ ubyte *buffer;
+};
+
+
+/** Epsilon for Z comparisons */
+#define Z_EPSILON 1e-06
+
+
+/**
+ * Make fragment program for glBitmap:
+ * Sample the texture and kill the fragment if the bit is 0.
+ * This program will be combined with the user's fragment program.
+ */
+static struct st_fragment_program *
+make_bitmap_fragment_program(struct gl_context *ctx, GLuint samplerIndex)
+{
+ struct st_context *st = st_context(ctx);
+ struct st_fragment_program *stfp;
+ struct gl_program *p;
+ GLuint ic = 0;
+
+ p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
+ if (!p)
+ return NULL;
+
+ p->NumInstructions = 3;
+
+ p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
+ if (!p->Instructions) {
+ ctx->Driver.DeleteProgram(ctx, p);
+ return NULL;
+ }
+ _mesa_init_instructions(p->Instructions, p->NumInstructions);
+
+ /* TEX tmp0, fragment.texcoord[0], texture[0], 2D; */
+ p->Instructions[ic].Opcode = OPCODE_TEX;
+ p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY;
+ p->Instructions[ic].DstReg.Index = 0;
+ p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
+ p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
+ p->Instructions[ic].TexSrcUnit = samplerIndex;
+ p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
+ ic++;
+
+ /* KIL if -tmp0 < 0 # texel=0 -> keep / texel=0 -> discard */
+ p->Instructions[ic].Opcode = OPCODE_KIL;
+ p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
+
+ if (st->bitmap.tex_format == PIPE_FORMAT_L8_UNORM)
+ p->Instructions[ic].SrcReg[0].Swizzle = SWIZZLE_XXXX;
+
+ p->Instructions[ic].SrcReg[0].Index = 0;
+ p->Instructions[ic].SrcReg[0].Negate = NEGATE_XYZW;
+ ic++;
+
+ /* END; */
+ p->Instructions[ic++].Opcode = OPCODE_END;
+
+ assert(ic == p->NumInstructions);
+
+ p->InputsRead = FRAG_BIT_TEX0;
+ p->OutputsWritten = 0x0;
+ p->SamplersUsed = (1 << samplerIndex);
+
+ stfp = (struct st_fragment_program *) p;
+ stfp->Base.UsesKill = GL_TRUE;
+
+ return stfp;
+}
+
+
+static int
+find_free_bit(uint bitfield)
+{
+ int i;
+ for (i = 0; i < 32; i++) {
+ if ((bitfield & (1 << i)) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+/**
+ * Combine basic bitmap fragment program with the user-defined program.
+ * \param st current context
+ * \param fpIn the incoming fragment program
+ * \param fpOut the new fragment program which does fragment culling
+ * \param bitmap_sampler sampler number for the bitmap texture
+ */
+void
+st_make_bitmap_fragment_program(struct st_context *st,
+ struct gl_fragment_program *fpIn,
+ struct gl_fragment_program **fpOut,
+ GLuint *bitmap_sampler)
+{
+ struct st_fragment_program *bitmap_prog;
+ struct gl_program *newProg;
+ uint sampler;
+
+ /*
+ * Generate new program which is the user-defined program prefixed
+ * with the bitmap sampler/kill instructions.
+ */
+ sampler = find_free_bit(fpIn->Base.SamplersUsed);
+ bitmap_prog = make_bitmap_fragment_program(st->ctx, sampler);
+
+ newProg = _mesa_combine_programs(st->ctx,
+ &bitmap_prog->Base.Base,
+ &fpIn->Base);
+ /* done with this after combining */
+ st_reference_fragprog(st, &bitmap_prog, NULL);
+
+#if 0
+ {
+ printf("Combined bitmap program:\n");
+ _mesa_print_program(newProg);
+ printf("InputsRead: 0x%x\n", newProg->InputsRead);
+ printf("OutputsWritten: 0x%x\n", newProg->OutputsWritten);
+ _mesa_print_parameter_list(newProg->Parameters);
+ }
+#endif
+
+ /* return results */
+ *fpOut = (struct gl_fragment_program *) newProg;
+ *bitmap_sampler = sampler;
+}
+
+
+/**
+ * Copy user-provide bitmap bits into texture buffer, expanding
+ * bits into texels.
+ * "On" bits will set texels to 0x0.
+ * "Off" bits will not modify texels.
+ * Note that the image is actually going to be upside down in
+ * the texture. We deal with that with texcoords.
+ */
+static void
+unpack_bitmap(struct st_context *st,
+ GLint px, GLint py, GLsizei width, GLsizei height,
+ const struct gl_pixelstore_attrib *unpack,
+ const GLubyte *bitmap,
+ ubyte *destBuffer, uint destStride)
+{
+ destBuffer += py * destStride + px;
+
+ _mesa_expand_bitmap(width, height, unpack, bitmap,
+ destBuffer, destStride, 0x0);
+}
+
+
+/**
+ * Create a texture which represents a bitmap image.
+ */
+static struct pipe_resource *
+make_bitmap_texture(struct gl_context *ctx, GLsizei width, GLsizei height,
+ const struct gl_pixelstore_attrib *unpack,
+ const GLubyte *bitmap)
+{
+ struct st_context *st = st_context(ctx);
+ struct pipe_context *pipe = st->pipe;
+ struct pipe_transfer *transfer;
+ ubyte *dest;
+ struct pipe_resource *pt;
+
+ /* PBO source... */
+ bitmap = _mesa_map_pbo_source(ctx, unpack, bitmap);
+ if (!bitmap) {
+ return NULL;
+ }
+
+ /**
+ * Create texture to hold bitmap pattern.
+ */
+ pt = st_texture_create(st, st->internal_target, st->bitmap.tex_format,
+ 0, width, height, 1, 1,
+ PIPE_BIND_SAMPLER_VIEW);
+ if (!pt) {
+ _mesa_unmap_pbo_source(ctx, unpack);
+ return NULL;
+ }
+
+ transfer = pipe_get_transfer(st->pipe, pt, 0, 0,
+ PIPE_TRANSFER_WRITE,
+ 0, 0, width, height);
+
+ dest = pipe_transfer_map(pipe, transfer);
+
+ /* Put image into texture transfer */
+ memset(dest, 0xff, height * transfer->stride);
+ unpack_bitmap(st, 0, 0, width, height, unpack, bitmap,
+ dest, transfer->stride);
+
+ _mesa_unmap_pbo_source(ctx, unpack);
+
+ /* Release transfer */
+ pipe_transfer_unmap(pipe, transfer);
+ pipe->transfer_destroy(pipe, transfer);
+
+ return pt;
+}
+
+static GLuint
+setup_bitmap_vertex_data(struct st_context *st, bool normalized,
+ int x, int y, int width, int height,
+ float z, const float color[4])
+{
+ struct pipe_context *pipe = st->pipe;
+ const struct gl_framebuffer *fb = st->ctx->DrawBuffer;
+ const GLfloat fb_width = (GLfloat)fb->Width;
+ const GLfloat fb_height = (GLfloat)fb->Height;
+ const GLfloat x0 = (GLfloat)x;
+ const GLfloat x1 = (GLfloat)(x + width);
+ const GLfloat y0 = (GLfloat)y;
+ const GLfloat y1 = (GLfloat)(y + height);
+ GLfloat sLeft = (GLfloat)0.0, sRight = (GLfloat)1.0;
+ GLfloat tTop = (GLfloat)0.0, tBot = (GLfloat)1.0 - tTop;
+ const GLfloat clip_x0 = (GLfloat)(x0 / fb_width * 2.0 - 1.0);
+ const GLfloat clip_y0 = (GLfloat)(y0 / fb_height * 2.0 - 1.0);
+ const GLfloat clip_x1 = (GLfloat)(x1 / fb_width * 2.0 - 1.0);
+ const GLfloat clip_y1 = (GLfloat)(y1 / fb_height * 2.0 - 1.0);
+ const GLuint max_slots = 1; /* 4096 / sizeof(st->bitmap.vertices); */
+ GLuint i;
+
+ if(!normalized)
+ {
+ sRight = width;
+ tBot = height;
+ }
+
+ /* XXX: Need to improve buffer_write to allow NO_WAIT (as well as
+ * no_flush) updates to buffers where we know there is no conflict
+ * with previous data. Currently using max_slots > 1 will cause
+ * synchronous rendering if the driver flushes its command buffers
+ * between one bitmap and the next. Our flush hook below isn't
+ * sufficient to catch this as the driver doesn't tell us when it
+ * flushes its own command buffers. Until this gets fixed, pay the
+ * price of allocating a new buffer for each bitmap cache-flush to
+ * avoid synchronous rendering.
+ */
+ if (st->bitmap.vbuf_slot >= max_slots) {
+ pipe_resource_reference(&st->bitmap.vbuf, NULL);
+ st->bitmap.vbuf_slot = 0;
+ }
+
+ if (!st->bitmap.vbuf) {
+ st->bitmap.vbuf = pipe_buffer_create(pipe->screen,
+ PIPE_BIND_VERTEX_BUFFER,
+ PIPE_USAGE_STREAM,
+ max_slots *
+ sizeof(st->bitmap.vertices));
+ }
+
+ /* Positions are in clip coords since we need to do clipping in case
+ * the bitmap quad goes beyond the window bounds.
+ */
+ st->bitmap.vertices[0][0][0] = clip_x0;
+ st->bitmap.vertices[0][0][1] = clip_y0;
+ st->bitmap.vertices[0][2][0] = sLeft;
+ st->bitmap.vertices[0][2][1] = tTop;
+
+ st->bitmap.vertices[1][0][0] = clip_x1;
+ st->bitmap.vertices[1][0][1] = clip_y0;
+ st->bitmap.vertices[1][2][0] = sRight;
+ st->bitmap.vertices[1][2][1] = tTop;
+
+ st->bitmap.vertices[2][0][0] = clip_x1;
+ st->bitmap.vertices[2][0][1] = clip_y1;
+ st->bitmap.vertices[2][2][0] = sRight;
+ st->bitmap.vertices[2][2][1] = tBot;
+
+ st->bitmap.vertices[3][0][0] = clip_x0;
+ st->bitmap.vertices[3][0][1] = clip_y1;
+ st->bitmap.vertices[3][2][0] = sLeft;
+ st->bitmap.vertices[3][2][1] = tBot;
+
+ /* same for all verts: */
+ for (i = 0; i < 4; i++) {
+ st->bitmap.vertices[i][0][2] = z;
+ st->bitmap.vertices[i][0][3] = 1.0;
+ st->bitmap.vertices[i][1][0] = color[0];
+ st->bitmap.vertices[i][1][1] = color[1];
+ st->bitmap.vertices[i][1][2] = color[2];
+ st->bitmap.vertices[i][1][3] = color[3];
+ st->bitmap.vertices[i][2][2] = 0.0; /*R*/
+ st->bitmap.vertices[i][2][3] = 1.0; /*Q*/
+ }
+
+ /* put vertex data into vbuf */
+ pipe_buffer_write_nooverlap(st->pipe,
+ st->bitmap.vbuf,
+ st->bitmap.vbuf_slot
+ * sizeof(st->bitmap.vertices),
+ sizeof st->bitmap.vertices,
+ st->bitmap.vertices);
+
+ return st->bitmap.vbuf_slot++ * sizeof st->bitmap.vertices;
+}
+
+
+
+/**
+ * Render a glBitmap by drawing a textured quad
+ */
+static void
+draw_bitmap_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z,
+ GLsizei width, GLsizei height,
+ struct pipe_sampler_view *sv,
+ const GLfloat *color)
+{
+ struct st_context *st = st_context(ctx);
+ struct pipe_context *pipe = st->pipe;
+ struct cso_context *cso = st->cso_context;
+ struct st_fp_variant *fpv;
+ struct st_fp_variant_key key;
+ GLuint maxSize;
+ GLuint offset;
+
+ memset(&key, 0, sizeof(key));
+ key.st = st;
+ key.bitmap = GL_TRUE;
+
+ fpv = st_get_fp_variant(st, st->fp, &key);
+
+ /* As an optimization, Mesa's fragment programs will sometimes get the
+ * primary color from a statevar/constant rather than a varying variable.
+ * when that's the case, we need to ensure that we use the 'color'
+ * parameter and not the current attribute color (which may have changed
+ * through glRasterPos and state validation.
+ * So, we force the proper color here. Not elegant, but it works.
+ */
+ {
+ GLfloat colorSave[4];
+ COPY_4V(colorSave, ctx->Current.Attrib[VERT_ATTRIB_COLOR0]);
+ COPY_4V(ctx->Current.Attrib[VERT_ATTRIB_COLOR0], color);
+ st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT);
+ COPY_4V(ctx->Current.Attrib[VERT_ATTRIB_COLOR0], colorSave);
+ }
+
+
+ /* limit checks */
+ /* XXX if the bitmap is larger than the max texture size, break
+ * it up into chunks.
+ */
+ maxSize = 1 << (pipe->screen->get_param(pipe->screen,
+ PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1);
+ assert(width <= (GLsizei)maxSize);
+ assert(height <= (GLsizei)maxSize);
+
+ cso_save_rasterizer(cso);
+ cso_save_samplers(cso);
+ cso_save_fragment_sampler_views(cso);
+ cso_save_viewport(cso);
+ cso_save_fragment_shader(cso);
+ cso_save_vertex_shader(cso);
+ cso_save_vertex_elements(cso);
+ cso_save_vertex_buffers(cso);
+
+ /* rasterizer state: just scissor */
+ st->bitmap.rasterizer.scissor = ctx->Scissor.Enabled;
+ cso_set_rasterizer(cso, &st->bitmap.rasterizer);
+
+ /* fragment shader state: TEX lookup program */
+ cso_set_fragment_shader_handle(cso, fpv->driver_shader);
+
+ /* vertex shader state: position + texcoord pass-through */
+ cso_set_vertex_shader_handle(cso, st->bitmap.vs);
+
+ /* user samplers, plus our bitmap sampler */
+ {
+ struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
+ uint num = MAX2(fpv->bitmap_sampler + 1, st->state.num_samplers);
+ uint i;
+ for (i = 0; i < st->state.num_samplers; i++) {
+ samplers[i] = &st->state.samplers[i];
+ }
+ samplers[fpv->bitmap_sampler] =
+ &st->bitmap.samplers[sv->texture->target != PIPE_TEXTURE_RECT];
+ cso_set_samplers(cso, num, (const struct pipe_sampler_state **) samplers);
+ }
+
+ /* user textures, plus the bitmap texture */
+ {
+ struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS];
+ uint num = MAX2(fpv->bitmap_sampler + 1, st->state.num_textures);
+ memcpy(sampler_views, st->state.sampler_views, sizeof(sampler_views));
+ sampler_views[fpv->bitmap_sampler] = sv;
+ cso_set_fragment_sampler_views(cso, num, sampler_views);
+ }
+
+ /* viewport state: viewport matching window dims */
+ {
+ const struct gl_framebuffer *fb = st->ctx->DrawBuffer;
+ const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP);
+ const GLfloat width = (GLfloat)fb->Width;
+ const GLfloat height = (GLfloat)fb->Height;
+ struct pipe_viewport_state vp;
+ vp.scale[0] = 0.5f * width;
+ vp.scale[1] = height * (invert ? -0.5f : 0.5f);
+ vp.scale[2] = 0.5f;
+ vp.scale[3] = 1.0f;
+ vp.translate[0] = 0.5f * width;
+ vp.translate[1] = 0.5f * height;
+ vp.translate[2] = 0.5f;
+ vp.translate[3] = 0.0f;
+ cso_set_viewport(cso, &vp);
+ }
+
+ cso_set_vertex_elements(cso, 3, st->velems_util_draw);
+
+ /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */
+ z = z * 2.0 - 1.0;
+
+ /* draw textured quad */
+ offset = setup_bitmap_vertex_data(st,
+ sv->texture->target != PIPE_TEXTURE_RECT,
+ x, y, width, height, z, color);
+
+ util_draw_vertex_buffer(pipe, st->cso_context, st->bitmap.vbuf, offset,
+ PIPE_PRIM_TRIANGLE_FAN,
+ 4, /* verts */
+ 3); /* attribs/vert */
+
+
+ /* restore state */
+ cso_restore_rasterizer(cso);
+ cso_restore_samplers(cso);
+ cso_restore_fragment_sampler_views(cso);
+ cso_restore_viewport(cso);
+ cso_restore_fragment_shader(cso);
+ cso_restore_vertex_shader(cso);
+ cso_restore_vertex_elements(cso);
+ cso_restore_vertex_buffers(cso);
+}
+
+
+static void
+reset_cache(struct st_context *st)
+{
+ struct pipe_context *pipe = st->pipe;
+ struct bitmap_cache *cache = st->bitmap.cache;
+
+ /*memset(cache->buffer, 0xff, sizeof(cache->buffer));*/
+ cache->empty = GL_TRUE;
+
+ cache->xmin = 1000000;
+ cache->xmax = -1000000;
+ cache->ymin = 1000000;
+ cache->ymax = -1000000;
+
+ if (cache->trans) {
+ pipe->transfer_destroy(pipe, cache->trans);
+ cache->trans = NULL;
+ }
+
+ assert(!cache->texture);
+
+ /* allocate a new texture */
+ cache->texture = st_texture_create(st, PIPE_TEXTURE_2D,
+ st->bitmap.tex_format, 0,
+ BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT,
+ 1, 1,
+ PIPE_BIND_SAMPLER_VIEW);
+}
+
+
+/** Print bitmap image to stdout (debug) */
+static void
+print_cache(const struct bitmap_cache *cache)
+{
+ int i, j, k;
+
+ for (i = 0; i < BITMAP_CACHE_HEIGHT; i++) {
+ k = BITMAP_CACHE_WIDTH * (BITMAP_CACHE_HEIGHT - i - 1);
+ for (j = 0; j < BITMAP_CACHE_WIDTH; j++) {
+ if (cache->buffer[k])
+ printf("X");
+ else
+ printf(" ");
+ k++;
+ }
+ printf("\n");
+ }
+}
+
+
+/**
+ * Create gallium pipe_transfer object for the bitmap cache.
+ */
+static void
+create_cache_trans(struct st_context *st)
+{
+ struct pipe_context *pipe = st->pipe;
+ struct bitmap_cache *cache = st->bitmap.cache;
+
+ if (cache->trans)
+ return;
+
+ /* Map the texture transfer.
+ * Subsequent glBitmap calls will write into the texture image.
+ */
+ cache->trans = pipe_get_transfer(st->pipe, cache->texture, 0, 0,
+ PIPE_TRANSFER_WRITE, 0, 0,
+ BITMAP_CACHE_WIDTH,
+ BITMAP_CACHE_HEIGHT);
+ cache->buffer = pipe_transfer_map(pipe, cache->trans);
+
+ /* init image to all 0xff */
+ memset(cache->buffer, 0xff, cache->trans->stride * BITMAP_CACHE_HEIGHT);
+}
+
+
+/**
+ * If there's anything in the bitmap cache, draw/flush it now.
+ */
+void
+st_flush_bitmap_cache(struct st_context *st)
+{
+ if (!st->bitmap.cache->empty) {
+ struct bitmap_cache *cache = st->bitmap.cache;
+
+ if (st->ctx->DrawBuffer) {
+ struct pipe_context *pipe = st->pipe;
+ struct pipe_sampler_view *sv;
+
+ assert(cache->xmin <= cache->xmax);
+
+/* printf("flush size %d x %d at %d, %d\n",
+ cache->xmax - cache->xmin,
+ cache->ymax - cache->ymin,
+ cache->xpos, cache->ypos);
+*/
+
+ /* The texture transfer has been mapped until now.
+ * So unmap and release the texture transfer before drawing.
+ */
+ if (cache->trans) {
+ if (0)
+ print_cache(cache);
+ pipe_transfer_unmap(pipe, cache->trans);
+ cache->buffer = NULL;
+
+ pipe->transfer_destroy(pipe, cache->trans);
+ cache->trans = NULL;
+ }
+
+ sv = st_create_texture_sampler_view(st->pipe, cache->texture);
+ if (sv) {
+ draw_bitmap_quad(st->ctx,
+ cache->xpos,
+ cache->ypos,
+ cache->zpos,
+ BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT,
+ sv,
+ cache->color);
+
+ pipe_sampler_view_reference(&sv, NULL);
+ }
+ }
+
+ /* release/free the texture */
+ pipe_resource_reference(&cache->texture, NULL);
+
+ reset_cache(st);
+ }
+}
+
+
+/**
+ * Flush bitmap cache and release vertex buffer.
+ */
+void
+st_flush_bitmap( struct st_context *st )
+{
+ st_flush_bitmap_cache(st);
+
+ /* Release vertex buffer to avoid synchronous rendering if we were
+ * to map it in the next frame.
+ */
+ pipe_resource_reference(&st->bitmap.vbuf, NULL);
+ st->bitmap.vbuf_slot = 0;
+}
+
+
+/**
+ * Try to accumulate this glBitmap call in the bitmap cache.
+ * \return GL_TRUE for success, GL_FALSE if bitmap is too large, etc.
+ */
+static GLboolean
+accum_bitmap(struct st_context *st,
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ const struct gl_pixelstore_attrib *unpack,
+ const GLubyte *bitmap )
+{
+ struct bitmap_cache *cache = st->bitmap.cache;
+ int px = -999, py = -999;
+ const GLfloat z = st->ctx->Current.RasterPos[2];
+
+ if (width > BITMAP_CACHE_WIDTH ||
+ height > BITMAP_CACHE_HEIGHT)
+ return GL_FALSE; /* too big to cache */
+
+ if (!cache->empty) {
+ px = x - cache->xpos; /* pos in buffer */
+ py = y - cache->ypos;
+ if (px < 0 || px + width > BITMAP_CACHE_WIDTH ||
+ py < 0 || py + height > BITMAP_CACHE_HEIGHT ||
+ !TEST_EQ_4V(st->ctx->Current.RasterColor, cache->color) ||
+ ((fabs(z - cache->zpos) > Z_EPSILON))) {
+ /* This bitmap would extend beyond cache bounds, or the bitmap
+ * color is changing
+ * so flush and continue.
+ */
+ st_flush_bitmap_cache(st);
+ }
+ }
+
+ if (cache->empty) {
+ /* Initialize. Center bitmap vertically in the buffer. */
+ px = 0;
+ py = (BITMAP_CACHE_HEIGHT - height) / 2;
+ cache->xpos = x;
+ cache->ypos = y - py;
+ cache->zpos = z;
+ cache->empty = GL_FALSE;
+ COPY_4FV(cache->color, st->ctx->Current.RasterColor);
+ }
+
+ assert(px != -999);
+ assert(py != -999);
+
+ if (x < cache->xmin)
+ cache->xmin = x;
+ if (y < cache->ymin)
+ cache->ymin = y;
+ if (x + width > cache->xmax)
+ cache->xmax = x + width;
+ if (y + height > cache->ymax)
+ cache->ymax = y + height;
+
+ /* create the transfer if needed */
+ create_cache_trans(st);
+
+ unpack_bitmap(st, px, py, width, height, unpack, bitmap,
+ cache->buffer, BITMAP_CACHE_WIDTH);
+
+ return GL_TRUE; /* accumulated */
+}
+
+
+
+/**
+ * Called via ctx->Driver.Bitmap()
+ */
+static void
+st_Bitmap(struct gl_context *ctx, GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap )
+{
+ struct st_context *st = st_context(ctx);
+ struct pipe_resource *pt;
+
+ if (width == 0 || height == 0)
+ return;
+
+ st_validate_state(st);
+
+ if (!st->bitmap.vs) {
+ /* create pass-through vertex shader now */
+ const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
+ TGSI_SEMANTIC_COLOR,
+ TGSI_SEMANTIC_GENERIC };
+ const uint semantic_indexes[] = { 0, 0, 0 };
+ st->bitmap.vs = util_make_vertex_passthrough_shader(st->pipe, 3,
+ semantic_names,
+ semantic_indexes);
+ }
+
+ if (UseBitmapCache && accum_bitmap(st, x, y, width, height, unpack, bitmap))
+ return;
+
+ pt = make_bitmap_texture(ctx, width, height, unpack, bitmap);
+ if (pt) {
+ struct pipe_sampler_view *sv =
+ st_create_texture_sampler_view(st->pipe, pt);
+
+ assert(pt->target == PIPE_TEXTURE_2D || pt->target == PIPE_TEXTURE_RECT);
+
+ if (sv) {
+ draw_bitmap_quad(ctx, x, y, ctx->Current.RasterPos[2],
+ width, height, sv,
+ st->ctx->Current.RasterColor);
+
+ pipe_sampler_view_reference(&sv, NULL);
+ }
+
+ /* release/free the texture */
+ pipe_resource_reference(&pt, NULL);
+ }
+}
+
+
+/** Per-context init */
+void
+st_init_bitmap_functions(struct dd_function_table *functions)
+{
+ functions->Bitmap = st_Bitmap;
+}
+
+
+/** Per-context init */
+void
+st_init_bitmap(struct st_context *st)
+{
+ struct pipe_sampler_state *sampler = &st->bitmap.samplers[0];
+ struct pipe_context *pipe = st->pipe;
+ struct pipe_screen *screen = pipe->screen;
+
+ /* init sampler state once */
+ memset(sampler, 0, sizeof(*sampler));
+ sampler->wrap_s = PIPE_TEX_WRAP_CLAMP;
+ sampler->wrap_t = PIPE_TEX_WRAP_CLAMP;
+ sampler->wrap_r = PIPE_TEX_WRAP_CLAMP;
+ sampler->min_img_filter = PIPE_TEX_FILTER_NEAREST;
+ sampler->min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
+ sampler->mag_img_filter = PIPE_TEX_FILTER_NEAREST;
+ st->bitmap.samplers[1] = *sampler;
+ st->bitmap.samplers[1].normalized_coords = 1;
+
+ /* init baseline rasterizer state once */
+ memset(&st->bitmap.rasterizer, 0, sizeof(st->bitmap.rasterizer));
+ st->bitmap.rasterizer.gl_rasterization_rules = 1;
+
+ /* find a usable texture format */
+ if (screen->is_format_supported(screen, PIPE_FORMAT_I8_UNORM,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_SAMPLER_VIEW, 0)) {
+ st->bitmap.tex_format = PIPE_FORMAT_I8_UNORM;
+ }
+ else if (screen->is_format_supported(screen, PIPE_FORMAT_A8_UNORM,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_SAMPLER_VIEW, 0)) {
+ st->bitmap.tex_format = PIPE_FORMAT_A8_UNORM;
+ }
+ else if (screen->is_format_supported(screen, PIPE_FORMAT_L8_UNORM,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_SAMPLER_VIEW, 0)) {
+ st->bitmap.tex_format = PIPE_FORMAT_L8_UNORM;
+ }
+ else {
+ /* XXX support more formats */
+ assert(0);
+ }
+
+ /* alloc bitmap cache object */
+ st->bitmap.cache = ST_CALLOC_STRUCT(bitmap_cache);
+
+ reset_cache(st);
+}
+
+
+/** Per-context tear-down */
+void
+st_destroy_bitmap(struct st_context *st)
+{
+ struct pipe_context *pipe = st->pipe;
+ struct bitmap_cache *cache = st->bitmap.cache;
+
+ if (st->bitmap.vs) {
+ cso_delete_vertex_shader(st->cso_context, st->bitmap.vs);
+ st->bitmap.vs = NULL;
+ }
+
+ if (st->bitmap.vbuf) {
+ pipe_resource_reference(&st->bitmap.vbuf, NULL);
+ st->bitmap.vbuf = NULL;
+ }
+
+ if (cache) {
+ if (cache->trans) {
+ pipe_transfer_unmap(pipe, cache->trans);
+ pipe->transfer_destroy(pipe, cache->trans);
+ }
+ pipe_resource_reference(&st->bitmap.cache->texture, NULL);
+ free(st->bitmap.cache);
+ st->bitmap.cache = NULL;
+ }
+}
+
+#endif /* FEATURE_drawpix */
diff --git a/mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c b/mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c
index 12528f49f..9dd1f8a3e 100644
--- a/mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c
+++ b/mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c
@@ -1,468 +1,468 @@
-/**************************************************************************
- *
- * 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.
- *
- **************************************************************************/
-
-
-/**
- * Functions for pixel buffer objects and vertex/element buffer objects.
- */
-
-
-#include "main/imports.h"
-#include "main/mtypes.h"
-#include "main/arrayobj.h"
-#include "main/bufferobj.h"
-
-#include "st_context.h"
-#include "st_cb_bufferobjects.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "util/u_inlines.h"
-
-
-/**
- * There is some duplication between mesa's bufferobjects and our
- * bufmgr buffers. Both have an integer handle and a hashtable to
- * lookup an opaque structure. It would be nice if the handles and
- * internal structure where somehow shared.
- */
-static struct gl_buffer_object *
-st_bufferobj_alloc(struct gl_context *ctx, GLuint name, GLenum target)
-{
- struct st_buffer_object *st_obj = ST_CALLOC_STRUCT(st_buffer_object);
-
- if (!st_obj)
- return NULL;
-
- _mesa_initialize_buffer_object(&st_obj->Base, name, target);
-
- return &st_obj->Base;
-}
-
-
-
-/**
- * Deallocate/free a vertex/pixel buffer object.
- * Called via glDeleteBuffersARB().
- */
-static void
-st_bufferobj_free(struct gl_context *ctx, struct gl_buffer_object *obj)
-{
- struct st_buffer_object *st_obj = st_buffer_object(obj);
-
- assert(obj->RefCount == 0);
- assert(st_obj->transfer == NULL);
-
- if (st_obj->buffer)
- pipe_resource_reference(&st_obj->buffer, NULL);
-
- free(st_obj);
-}
-
-
-
-/**
- * Replace data in a subrange of buffer object. If the data range
- * specified by size + offset extends beyond the end of the buffer or
- * if data is NULL, no copy is performed.
- * Called via glBufferSubDataARB().
- */
-static void
-st_bufferobj_subdata(struct gl_context *ctx,
- GLenum target,
- GLintptrARB offset,
- GLsizeiptrARB size,
- const GLvoid * data, struct gl_buffer_object *obj)
-{
- struct st_buffer_object *st_obj = st_buffer_object(obj);
-
- /* we may be called from VBO code, so double-check params here */
- ASSERT(offset >= 0);
- ASSERT(size >= 0);
- ASSERT(offset + size <= obj->Size);
-
- if (!size)
- return;
-
- /*
- * According to ARB_vertex_buffer_object specification, if data is null,
- * then the contents of the buffer object's data store is undefined. We just
- * ignore, and leave it unchanged.
- */
- if (!data)
- return;
-
- /* Now that transfers are per-context, we don't have to figure out
- * flushing here. Usually drivers won't need to flush in this case
- * even if the buffer is currently referenced by hardware - they
- * just queue the upload as dma rather than mapping the underlying
- * buffer directly.
- */
- pipe_buffer_write(st_context(ctx)->pipe,
- st_obj->buffer,
- offset, size, data);
-}
-
-
-/**
- * Called via glGetBufferSubDataARB().
- */
-static void
-st_bufferobj_get_subdata(struct gl_context *ctx,
- GLenum target,
- GLintptrARB offset,
- GLsizeiptrARB size,
- GLvoid * data, struct gl_buffer_object *obj)
-{
- struct st_buffer_object *st_obj = st_buffer_object(obj);
-
- /* we may be called from VBO code, so double-check params here */
- ASSERT(offset >= 0);
- ASSERT(size >= 0);
- ASSERT(offset + size <= obj->Size);
-
- if (!size)
- return;
-
- pipe_buffer_read(st_context(ctx)->pipe, st_obj->buffer,
- offset, size, data);
-}
-
-
-/**
- * Allocate space for and store data in a buffer object. Any data that was
- * previously stored in the buffer object is lost. If data is NULL,
- * memory will be allocated, but no copy will occur.
- * Called via ctx->Driver.BufferData().
- * \return GL_TRUE for success, GL_FALSE if out of memory
- */
-static GLboolean
-st_bufferobj_data(struct gl_context *ctx,
- GLenum target,
- GLsizeiptrARB size,
- const GLvoid * data,
- GLenum usage,
- struct gl_buffer_object *obj)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct st_buffer_object *st_obj = st_buffer_object(obj);
- unsigned bind, pipe_usage;
-
- st_obj->Base.Size = size;
- st_obj->Base.Usage = usage;
-
- switch(target) {
- case GL_PIXEL_PACK_BUFFER_ARB:
- case GL_PIXEL_UNPACK_BUFFER_ARB:
- bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
- break;
- case GL_ARRAY_BUFFER_ARB:
- bind = PIPE_BIND_VERTEX_BUFFER;
- break;
- case GL_ELEMENT_ARRAY_BUFFER_ARB:
- bind = PIPE_BIND_INDEX_BUFFER;
- break;
- default:
- bind = 0;
- }
-
- switch (usage) {
- case GL_STATIC_DRAW:
- case GL_STATIC_READ:
- case GL_STATIC_COPY:
- pipe_usage = PIPE_USAGE_STATIC;
- break;
- case GL_DYNAMIC_DRAW:
- case GL_DYNAMIC_READ:
- case GL_DYNAMIC_COPY:
- pipe_usage = PIPE_USAGE_DYNAMIC;
- break;
- case GL_STREAM_DRAW:
- case GL_STREAM_READ:
- case GL_STREAM_COPY:
- pipe_usage = PIPE_USAGE_STREAM;
- break;
- default:
- pipe_usage = PIPE_USAGE_DEFAULT;
- }
-
- pipe_resource_reference( &st_obj->buffer, NULL );
-
- if (size != 0) {
- st_obj->buffer = pipe_buffer_create(pipe->screen, bind,
- pipe_usage, size);
-
- if (!st_obj->buffer) {
- return GL_FALSE;
- }
-
- if (data)
- pipe_buffer_write(st_context(ctx)->pipe, st_obj->buffer, 0,
- size, data);
- return GL_TRUE;
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Dummy data whose's pointer is used for zero size buffers or ranges.
- */
-static long st_bufferobj_zero_length = 0;
-
-
-
-/**
- * Called via glMapBufferARB().
- */
-static void *
-st_bufferobj_map(struct gl_context *ctx, GLenum target, GLenum access,
- struct gl_buffer_object *obj)
-{
- struct st_buffer_object *st_obj = st_buffer_object(obj);
- uint flags;
-
- switch (access) {
- case GL_WRITE_ONLY:
- flags = PIPE_TRANSFER_WRITE;
- break;
- case GL_READ_ONLY:
- flags = PIPE_TRANSFER_READ;
- break;
- case GL_READ_WRITE:
- default:
- flags = PIPE_TRANSFER_READ_WRITE;
- break;
- }
-
- /* Handle zero-size buffers here rather than in drivers */
- if (obj->Size == 0) {
- obj->Pointer = &st_bufferobj_zero_length;
- }
- else {
- obj->Pointer = pipe_buffer_map(st_context(ctx)->pipe,
- st_obj->buffer,
- flags,
- &st_obj->transfer);
- }
-
- if (obj->Pointer) {
- obj->Offset = 0;
- obj->Length = obj->Size;
- }
- return obj->Pointer;
-}
-
-
-/**
- * Called via glMapBufferRange().
- */
-static void *
-st_bufferobj_map_range(struct gl_context *ctx, GLenum target,
- GLintptr offset, GLsizeiptr length, GLbitfield access,
- struct gl_buffer_object *obj)
-{
- struct pipe_context *pipe = st_context(ctx)->pipe;
- struct st_buffer_object *st_obj = st_buffer_object(obj);
- enum pipe_transfer_usage flags = 0x0;
-
- if (access & GL_MAP_WRITE_BIT)
- flags |= PIPE_TRANSFER_WRITE;
-
- if (access & GL_MAP_READ_BIT)
- flags |= PIPE_TRANSFER_READ;
-
- if (access & GL_MAP_FLUSH_EXPLICIT_BIT)
- flags |= PIPE_TRANSFER_FLUSH_EXPLICIT;
-
- if (access & GL_MAP_INVALIDATE_RANGE_BIT)
- flags |= PIPE_TRANSFER_DISCARD;
-
- if (access & GL_MAP_INVALIDATE_BUFFER_BIT)
- flags |= PIPE_TRANSFER_DISCARD;
-
- if (access & GL_MAP_UNSYNCHRONIZED_BIT)
- flags |= PIPE_TRANSFER_UNSYNCHRONIZED;
-
- /* ... other flags ...
- */
-
- if (access & MESA_MAP_NOWAIT_BIT)
- flags |= PIPE_TRANSFER_DONTBLOCK;
-
- assert(offset >= 0);
- assert(length >= 0);
- assert(offset < obj->Size);
- assert(offset + length <= obj->Size);
-
- /*
- * We go out of way here to hide the degenerate yet valid case of zero
- * length range from the pipe driver.
- */
- if (!length) {
- obj->Pointer = &st_bufferobj_zero_length;
- }
- else {
- obj->Pointer = pipe_buffer_map_range(pipe,
- st_obj->buffer,
- offset, length,
- flags,
- &st_obj->transfer);
- if (obj->Pointer) {
- obj->Pointer = (ubyte *) obj->Pointer + offset;
- }
- }
-
- if (obj->Pointer) {
- obj->Offset = offset;
- obj->Length = length;
- obj->AccessFlags = access;
- }
-
- return obj->Pointer;
-}
-
-
-static void
-st_bufferobj_flush_mapped_range(struct gl_context *ctx, GLenum target,
- GLintptr offset, GLsizeiptr length,
- struct gl_buffer_object *obj)
-{
- struct pipe_context *pipe = st_context(ctx)->pipe;
- struct st_buffer_object *st_obj = st_buffer_object(obj);
-
- /* Subrange is relative to mapped range */
- assert(offset >= 0);
- assert(length >= 0);
- assert(offset + length <= obj->Length);
- assert(obj->Pointer);
-
- if (!length)
- return;
-
- pipe_buffer_flush_mapped_range(pipe, st_obj->transfer,
- obj->Offset + offset, length);
-}
-
-
-/**
- * Called via glUnmapBufferARB().
- */
-static GLboolean
-st_bufferobj_unmap(struct gl_context *ctx, GLenum target, struct gl_buffer_object *obj)
-{
- struct pipe_context *pipe = st_context(ctx)->pipe;
- struct st_buffer_object *st_obj = st_buffer_object(obj);
-
- if (obj->Length)
- pipe_buffer_unmap(pipe, st_obj->transfer);
-
- st_obj->transfer = NULL;
- obj->Pointer = NULL;
- obj->Offset = 0;
- obj->Length = 0;
- return GL_TRUE;
-}
-
-
-/**
- * Called via glCopyBufferSubData().
- */
-static void
-st_copy_buffer_subdata(struct gl_context *ctx,
- struct gl_buffer_object *src,
- struct gl_buffer_object *dst,
- GLintptr readOffset, GLintptr writeOffset,
- GLsizeiptr size)
-{
- struct pipe_context *pipe = st_context(ctx)->pipe;
- struct st_buffer_object *srcObj = st_buffer_object(src);
- struct st_buffer_object *dstObj = st_buffer_object(dst);
- struct pipe_transfer *src_transfer;
- struct pipe_transfer *dst_transfer;
- ubyte *srcPtr, *dstPtr;
-
- if(!size)
- return;
-
- /* buffer should not already be mapped */
- assert(!src->Pointer);
- assert(!dst->Pointer);
-
- srcPtr = (ubyte *) pipe_buffer_map_range(pipe,
- srcObj->buffer,
- readOffset, size,
- PIPE_TRANSFER_READ,
- &src_transfer);
-
- dstPtr = (ubyte *) pipe_buffer_map_range(pipe,
- dstObj->buffer,
- writeOffset, size,
- PIPE_TRANSFER_WRITE,
- &dst_transfer);
-
- if (srcPtr && dstPtr)
- memcpy(dstPtr + writeOffset, srcPtr + readOffset, size);
-
- pipe_buffer_unmap(pipe, src_transfer);
- pipe_buffer_unmap(pipe, dst_transfer);
-}
-
-
-/* TODO: if buffer wasn't created with appropriate usage flags, need
- * to recreate it now and copy contents -- or possibly create a
- * gallium entrypoint to extend the usage flags and let the driver
- * decide if a copy is necessary.
- */
-void
-st_bufferobj_validate_usage(struct st_context *st,
- struct st_buffer_object *obj,
- unsigned usage)
-{
-}
-
-
-void
-st_init_bufferobject_functions(struct dd_function_table *functions)
-{
- functions->NewBufferObject = st_bufferobj_alloc;
- functions->DeleteBuffer = st_bufferobj_free;
- functions->BufferData = st_bufferobj_data;
- functions->BufferSubData = st_bufferobj_subdata;
- functions->GetBufferSubData = st_bufferobj_get_subdata;
- functions->MapBuffer = st_bufferobj_map;
- functions->MapBufferRange = st_bufferobj_map_range;
- functions->FlushMappedBufferRange = st_bufferobj_flush_mapped_range;
- functions->UnmapBuffer = st_bufferobj_unmap;
- functions->CopyBufferSubData = st_copy_buffer_subdata;
-
- /* For GL_APPLE_vertex_array_object */
- functions->NewArrayObject = _mesa_new_array_object;
- functions->DeleteArrayObject = _mesa_delete_array_object;
-}
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+
+/**
+ * Functions for pixel buffer objects and vertex/element buffer objects.
+ */
+
+
+#include "main/imports.h"
+#include "main/mtypes.h"
+#include "main/arrayobj.h"
+#include "main/bufferobj.h"
+
+#include "st_context.h"
+#include "st_cb_bufferobjects.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_defines.h"
+#include "util/u_inlines.h"
+
+
+/**
+ * There is some duplication between mesa's bufferobjects and our
+ * bufmgr buffers. Both have an integer handle and a hashtable to
+ * lookup an opaque structure. It would be nice if the handles and
+ * internal structure where somehow shared.
+ */
+static struct gl_buffer_object *
+st_bufferobj_alloc(struct gl_context *ctx, GLuint name, GLenum target)
+{
+ struct st_buffer_object *st_obj = ST_CALLOC_STRUCT(st_buffer_object);
+
+ if (!st_obj)
+ return NULL;
+
+ _mesa_initialize_buffer_object(&st_obj->Base, name, target);
+
+ return &st_obj->Base;
+}
+
+
+
+/**
+ * Deallocate/free a vertex/pixel buffer object.
+ * Called via glDeleteBuffersARB().
+ */
+static void
+st_bufferobj_free(struct gl_context *ctx, struct gl_buffer_object *obj)
+{
+ struct st_buffer_object *st_obj = st_buffer_object(obj);
+
+ assert(obj->RefCount == 0);
+ assert(st_obj->transfer == NULL);
+
+ if (st_obj->buffer)
+ pipe_resource_reference(&st_obj->buffer, NULL);
+
+ free(st_obj);
+}
+
+
+
+/**
+ * Replace data in a subrange of buffer object. If the data range
+ * specified by size + offset extends beyond the end of the buffer or
+ * if data is NULL, no copy is performed.
+ * Called via glBufferSubDataARB().
+ */
+static void
+st_bufferobj_subdata(struct gl_context *ctx,
+ GLenum target,
+ GLintptrARB offset,
+ GLsizeiptrARB size,
+ const GLvoid * data, struct gl_buffer_object *obj)
+{
+ struct st_buffer_object *st_obj = st_buffer_object(obj);
+
+ /* we may be called from VBO code, so double-check params here */
+ ASSERT(offset >= 0);
+ ASSERT(size >= 0);
+ ASSERT(offset + size <= obj->Size);
+
+ if (!size)
+ return;
+
+ /*
+ * According to ARB_vertex_buffer_object specification, if data is null,
+ * then the contents of the buffer object's data store is undefined. We just
+ * ignore, and leave it unchanged.
+ */
+ if (!data)
+ return;
+
+ /* Now that transfers are per-context, we don't have to figure out
+ * flushing here. Usually drivers won't need to flush in this case
+ * even if the buffer is currently referenced by hardware - they
+ * just queue the upload as dma rather than mapping the underlying
+ * buffer directly.
+ */
+ pipe_buffer_write(st_context(ctx)->pipe,
+ st_obj->buffer,
+ offset, size, data);
+}
+
+
+/**
+ * Called via glGetBufferSubDataARB().
+ */
+static void
+st_bufferobj_get_subdata(struct gl_context *ctx,
+ GLenum target,
+ GLintptrARB offset,
+ GLsizeiptrARB size,
+ GLvoid * data, struct gl_buffer_object *obj)
+{
+ struct st_buffer_object *st_obj = st_buffer_object(obj);
+
+ /* we may be called from VBO code, so double-check params here */
+ ASSERT(offset >= 0);
+ ASSERT(size >= 0);
+ ASSERT(offset + size <= obj->Size);
+
+ if (!size)
+ return;
+
+ pipe_buffer_read(st_context(ctx)->pipe, st_obj->buffer,
+ offset, size, data);
+}
+
+
+/**
+ * Allocate space for and store data in a buffer object. Any data that was
+ * previously stored in the buffer object is lost. If data is NULL,
+ * memory will be allocated, but no copy will occur.
+ * Called via ctx->Driver.BufferData().
+ * \return GL_TRUE for success, GL_FALSE if out of memory
+ */
+static GLboolean
+st_bufferobj_data(struct gl_context *ctx,
+ GLenum target,
+ GLsizeiptrARB size,
+ const GLvoid * data,
+ GLenum usage,
+ struct gl_buffer_object *obj)
+{
+ struct st_context *st = st_context(ctx);
+ struct pipe_context *pipe = st->pipe;
+ struct st_buffer_object *st_obj = st_buffer_object(obj);
+ unsigned bind, pipe_usage;
+
+ st_obj->Base.Size = size;
+ st_obj->Base.Usage = usage;
+
+ switch(target) {
+ case GL_PIXEL_PACK_BUFFER_ARB:
+ case GL_PIXEL_UNPACK_BUFFER_ARB:
+ bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
+ break;
+ case GL_ARRAY_BUFFER_ARB:
+ bind = PIPE_BIND_VERTEX_BUFFER;
+ break;
+ case GL_ELEMENT_ARRAY_BUFFER_ARB:
+ bind = PIPE_BIND_INDEX_BUFFER;
+ break;
+ default:
+ bind = 0;
+ }
+
+ switch (usage) {
+ case GL_STATIC_DRAW:
+ case GL_STATIC_READ:
+ case GL_STATIC_COPY:
+ pipe_usage = PIPE_USAGE_STATIC;
+ break;
+ case GL_DYNAMIC_DRAW:
+ case GL_DYNAMIC_READ:
+ case GL_DYNAMIC_COPY:
+ pipe_usage = PIPE_USAGE_DYNAMIC;
+ break;
+ case GL_STREAM_DRAW:
+ case GL_STREAM_READ:
+ case GL_STREAM_COPY:
+ pipe_usage = PIPE_USAGE_STREAM;
+ break;
+ default:
+ pipe_usage = PIPE_USAGE_DEFAULT;
+ }
+
+ pipe_resource_reference( &st_obj->buffer, NULL );
+
+ if (size != 0) {
+ st_obj->buffer = pipe_buffer_create(pipe->screen, bind,
+ pipe_usage, size);
+
+ if (!st_obj->buffer) {
+ return GL_FALSE;
+ }
+
+ if (data)
+ pipe_buffer_write(st_context(ctx)->pipe, st_obj->buffer, 0,
+ size, data);
+ return GL_TRUE;
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Dummy data whose's pointer is used for zero size buffers or ranges.
+ */
+static long st_bufferobj_zero_length = 0;
+
+
+
+/**
+ * Called via glMapBufferARB().
+ */
+static void *
+st_bufferobj_map(struct gl_context *ctx, GLenum target, GLenum access,
+ struct gl_buffer_object *obj)
+{
+ struct st_buffer_object *st_obj = st_buffer_object(obj);
+ uint flags;
+
+ switch (access) {
+ case GL_WRITE_ONLY:
+ flags = PIPE_TRANSFER_WRITE;
+ break;
+ case GL_READ_ONLY:
+ flags = PIPE_TRANSFER_READ;
+ break;
+ case GL_READ_WRITE:
+ default:
+ flags = PIPE_TRANSFER_READ_WRITE;
+ break;
+ }
+
+ /* Handle zero-size buffers here rather than in drivers */
+ if (obj->Size == 0) {
+ obj->Pointer = &st_bufferobj_zero_length;
+ }
+ else {
+ obj->Pointer = pipe_buffer_map(st_context(ctx)->pipe,
+ st_obj->buffer,
+ flags,
+ &st_obj->transfer);
+ }
+
+ if (obj->Pointer) {
+ obj->Offset = 0;
+ obj->Length = obj->Size;
+ }
+ return obj->Pointer;
+}
+
+
+/**
+ * Called via glMapBufferRange().
+ */
+static void *
+st_bufferobj_map_range(struct gl_context *ctx, GLenum target,
+ GLintptr offset, GLsizeiptr length, GLbitfield access,
+ struct gl_buffer_object *obj)
+{
+ struct pipe_context *pipe = st_context(ctx)->pipe;
+ struct st_buffer_object *st_obj = st_buffer_object(obj);
+ enum pipe_transfer_usage flags = 0x0;
+
+ if (access & GL_MAP_WRITE_BIT)
+ flags |= PIPE_TRANSFER_WRITE;
+
+ if (access & GL_MAP_READ_BIT)
+ flags |= PIPE_TRANSFER_READ;
+
+ if (access & GL_MAP_FLUSH_EXPLICIT_BIT)
+ flags |= PIPE_TRANSFER_FLUSH_EXPLICIT;
+
+ if (access & GL_MAP_INVALIDATE_RANGE_BIT)
+ flags |= PIPE_TRANSFER_DISCARD;
+
+ if (access & GL_MAP_INVALIDATE_BUFFER_BIT)
+ flags |= PIPE_TRANSFER_DISCARD;
+
+ if (access & GL_MAP_UNSYNCHRONIZED_BIT)
+ flags |= PIPE_TRANSFER_UNSYNCHRONIZED;
+
+ /* ... other flags ...
+ */
+
+ if (access & MESA_MAP_NOWAIT_BIT)
+ flags |= PIPE_TRANSFER_DONTBLOCK;
+
+ assert(offset >= 0);
+ assert(length >= 0);
+ assert(offset < obj->Size);
+ assert(offset + length <= obj->Size);
+
+ /*
+ * We go out of way here to hide the degenerate yet valid case of zero
+ * length range from the pipe driver.
+ */
+ if (!length) {
+ obj->Pointer = &st_bufferobj_zero_length;
+ }
+ else {
+ obj->Pointer = pipe_buffer_map_range(pipe,
+ st_obj->buffer,
+ offset, length,
+ flags,
+ &st_obj->transfer);
+ if (obj->Pointer) {
+ obj->Pointer = (ubyte *) obj->Pointer + offset;
+ }
+ }
+
+ if (obj->Pointer) {
+ obj->Offset = offset;
+ obj->Length = length;
+ obj->AccessFlags = access;
+ }
+
+ return obj->Pointer;
+}
+
+
+static void
+st_bufferobj_flush_mapped_range(struct gl_context *ctx, GLenum target,
+ GLintptr offset, GLsizeiptr length,
+ struct gl_buffer_object *obj)
+{
+ struct pipe_context *pipe = st_context(ctx)->pipe;
+ struct st_buffer_object *st_obj = st_buffer_object(obj);
+
+ /* Subrange is relative to mapped range */
+ assert(offset >= 0);
+ assert(length >= 0);
+ assert(offset + length <= obj->Length);
+ assert(obj->Pointer);
+
+ if (!length)
+ return;
+
+ pipe_buffer_flush_mapped_range(pipe, st_obj->transfer,
+ obj->Offset + offset, length);
+}
+
+
+/**
+ * Called via glUnmapBufferARB().
+ */
+static GLboolean
+st_bufferobj_unmap(struct gl_context *ctx, GLenum target, struct gl_buffer_object *obj)
+{
+ struct pipe_context *pipe = st_context(ctx)->pipe;
+ struct st_buffer_object *st_obj = st_buffer_object(obj);
+
+ if (obj->Length)
+ pipe_buffer_unmap(pipe, st_obj->transfer);
+
+ st_obj->transfer = NULL;
+ obj->Pointer = NULL;
+ obj->Offset = 0;
+ obj->Length = 0;
+ return GL_TRUE;
+}
+
+
+/**
+ * Called via glCopyBufferSubData().
+ */
+static void
+st_copy_buffer_subdata(struct gl_context *ctx,
+ struct gl_buffer_object *src,
+ struct gl_buffer_object *dst,
+ GLintptr readOffset, GLintptr writeOffset,
+ GLsizeiptr size)
+{
+ struct pipe_context *pipe = st_context(ctx)->pipe;
+ struct st_buffer_object *srcObj = st_buffer_object(src);
+ struct st_buffer_object *dstObj = st_buffer_object(dst);
+ struct pipe_transfer *src_transfer;
+ struct pipe_transfer *dst_transfer;
+ ubyte *srcPtr, *dstPtr;
+
+ if(!size)
+ return;
+
+ /* buffer should not already be mapped */
+ assert(!src->Pointer);
+ assert(!dst->Pointer);
+
+ srcPtr = (ubyte *) pipe_buffer_map_range(pipe,
+ srcObj->buffer,
+ readOffset, size,
+ PIPE_TRANSFER_READ,
+ &src_transfer);
+
+ dstPtr = (ubyte *) pipe_buffer_map_range(pipe,
+ dstObj->buffer,
+ writeOffset, size,
+ PIPE_TRANSFER_WRITE,
+ &dst_transfer);
+
+ if (srcPtr && dstPtr)
+ memcpy(dstPtr + writeOffset, srcPtr + readOffset, size);
+
+ pipe_buffer_unmap(pipe, src_transfer);
+ pipe_buffer_unmap(pipe, dst_transfer);
+}
+
+
+/* TODO: if buffer wasn't created with appropriate usage flags, need
+ * to recreate it now and copy contents -- or possibly create a
+ * gallium entrypoint to extend the usage flags and let the driver
+ * decide if a copy is necessary.
+ */
+void
+st_bufferobj_validate_usage(struct st_context *st,
+ struct st_buffer_object *obj,
+ unsigned usage)
+{
+}
+
+
+void
+st_init_bufferobject_functions(struct dd_function_table *functions)
+{
+ functions->NewBufferObject = st_bufferobj_alloc;
+ functions->DeleteBuffer = st_bufferobj_free;
+ functions->BufferData = st_bufferobj_data;
+ functions->BufferSubData = st_bufferobj_subdata;
+ functions->GetBufferSubData = st_bufferobj_get_subdata;
+ functions->MapBuffer = st_bufferobj_map;
+ functions->MapBufferRange = st_bufferobj_map_range;
+ functions->FlushMappedBufferRange = st_bufferobj_flush_mapped_range;
+ functions->UnmapBuffer = st_bufferobj_unmap;
+ functions->CopyBufferSubData = st_copy_buffer_subdata;
+
+ /* For GL_APPLE_vertex_array_object */
+ functions->NewArrayObject = _mesa_new_array_object;
+ functions->DeleteArrayObject = _mesa_delete_array_object;
+}
diff --git a/mesalib/src/mesa/state_tracker/st_cb_clear.c b/mesalib/src/mesa/state_tracker/st_cb_clear.c
index 0e0c4326e..79e58182f 100644
--- a/mesalib/src/mesa/state_tracker/st_cb_clear.c
+++ b/mesalib/src/mesa/state_tracker/st_cb_clear.c
@@ -1,579 +1,579 @@
-/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * All Rights Reserved.
- * Copyright 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, 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 <keith@tungstengraphics.com>
- * Brian Paul
- * Michel Dänzer
- */
-
-#include "main/glheader.h"
-#include "main/formats.h"
-#include "main/macros.h"
-#include "program/prog_instruction.h"
-#include "st_context.h"
-#include "st_atom.h"
-#include "st_cb_accum.h"
-#include "st_cb_clear.h"
-#include "st_cb_fbo.h"
-#include "st_format.h"
-#include "st_program.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_shader_tokens.h"
-#include "pipe/p_state.h"
-#include "pipe/p_defines.h"
-#include "util/u_format.h"
-#include "util/u_inlines.h"
-#include "util/u_simple_shaders.h"
-#include "util/u_draw_quad.h"
-
-#include "cso_cache/cso_context.h"
-
-
-/**
- * Do per-context initialization for glClear.
- */
-void
-st_init_clear(struct st_context *st)
-{
- struct pipe_context *pipe = st->pipe;
- struct pipe_screen *pscreen = st->pipe->screen;
-
- memset(&st->clear, 0, sizeof(st->clear));
-
- st->clear.raster.gl_rasterization_rules = 1;
- st->clear.enable_ds_separate = pscreen->get_param(pscreen, PIPE_CAP_DEPTHSTENCIL_CLEAR_SEPARATE);
-
- /* fragment shader state: color pass-through program */
- st->clear.fs = util_make_fragment_passthrough_shader(pipe);
-
- /* vertex shader state: color/position pass-through */
- {
- const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
- TGSI_SEMANTIC_COLOR };
- const uint semantic_indexes[] = { 0, 0 };
- st->clear.vs = util_make_vertex_passthrough_shader(pipe, 2,
- semantic_names,
- semantic_indexes);
- }
-}
-
-
-/**
- * Free per-context state for glClear.
- */
-void
-st_destroy_clear(struct st_context *st)
-{
- if (st->clear.fs) {
- cso_delete_fragment_shader(st->cso_context, st->clear.fs);
- st->clear.fs = NULL;
- }
- if (st->clear.vs) {
- cso_delete_vertex_shader(st->cso_context, st->clear.vs);
- st->clear.vs = NULL;
- }
- if (st->clear.vbuf) {
- pipe_resource_reference(&st->clear.vbuf, NULL);
- st->clear.vbuf = NULL;
- }
-}
-
-
-/**
- * Draw a screen-aligned quadrilateral.
- * Coords are clip coords with y=0=bottom.
- */
-static void
-draw_quad(struct st_context *st,
- float x0, float y0, float x1, float y1, GLfloat z,
- const GLfloat color[4])
-{
- struct pipe_context *pipe = st->pipe;
-
- /* XXX: Need to improve buffer_write to allow NO_WAIT (as well as
- * no_flush) updates to buffers where we know there is no conflict
- * with previous data. Currently using max_slots > 1 will cause
- * synchronous rendering if the driver flushes its command buffers
- * between one bitmap and the next. Our flush hook below isn't
- * sufficient to catch this as the driver doesn't tell us when it
- * flushes its own command buffers. Until this gets fixed, pay the
- * price of allocating a new buffer for each bitmap cache-flush to
- * avoid synchronous rendering.
- */
- const GLuint max_slots = 1; /* 1024 / sizeof(st->clear.vertices); */
- GLuint i;
-
- if (st->clear.vbuf_slot >= max_slots) {
- pipe_resource_reference(&st->clear.vbuf, NULL);
- st->clear.vbuf_slot = 0;
- }
-
- if (!st->clear.vbuf) {
- st->clear.vbuf = pipe_buffer_create(pipe->screen,
- PIPE_BIND_VERTEX_BUFFER,
- PIPE_USAGE_STREAM,
- max_slots * sizeof(st->clear.vertices));
- }
-
- /* positions */
- st->clear.vertices[0][0][0] = x0;
- st->clear.vertices[0][0][1] = y0;
-
- st->clear.vertices[1][0][0] = x1;
- st->clear.vertices[1][0][1] = y0;
-
- st->clear.vertices[2][0][0] = x1;
- st->clear.vertices[2][0][1] = y1;
-
- st->clear.vertices[3][0][0] = x0;
- st->clear.vertices[3][0][1] = y1;
-
- /* same for all verts: */
- for (i = 0; i < 4; i++) {
- st->clear.vertices[i][0][2] = z;
- st->clear.vertices[i][0][3] = 1.0;
- st->clear.vertices[i][1][0] = color[0];
- st->clear.vertices[i][1][1] = color[1];
- st->clear.vertices[i][1][2] = color[2];
- st->clear.vertices[i][1][3] = color[3];
- }
-
- /* put vertex data into vbuf */
- pipe_buffer_write_nooverlap(st->pipe, st->clear.vbuf,
- st->clear.vbuf_slot
- * sizeof(st->clear.vertices),
- sizeof(st->clear.vertices),
- st->clear.vertices);
-
- /* draw */
- util_draw_vertex_buffer(pipe,
- st->cso_context,
- st->clear.vbuf,
- st->clear.vbuf_slot * sizeof(st->clear.vertices),
- PIPE_PRIM_TRIANGLE_FAN,
- 4, /* verts */
- 2); /* attribs/vert */
-
- /* Increment slot */
- st->clear.vbuf_slot++;
-}
-
-
-
-/**
- * Do glClear by drawing a quadrilateral.
- * The vertices of the quad will be computed from the
- * ctx->DrawBuffer->_X/Ymin/max fields.
- */
-static void
-clear_with_quad(struct gl_context *ctx,
- GLboolean color, GLboolean depth, GLboolean stencil)
-{
- struct st_context *st = st_context(ctx);
- const struct gl_framebuffer *fb = ctx->DrawBuffer;
- const GLfloat fb_width = (GLfloat) fb->Width;
- const GLfloat fb_height = (GLfloat) fb->Height;
- const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin / fb_width * 2.0f - 1.0f;
- const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax / fb_width * 2.0f - 1.0f;
- const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin / fb_height * 2.0f - 1.0f;
- const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax / fb_height * 2.0f - 1.0f;
- float clearColor[4];
-
- /*
- printf("%s %s%s%s %f,%f %f,%f\n", __FUNCTION__,
- color ? "color, " : "",
- depth ? "depth, " : "",
- stencil ? "stencil" : "",
- x0, y0,
- x1, y1);
- */
-
- cso_save_blend(st->cso_context);
- cso_save_stencil_ref(st->cso_context);
- cso_save_depth_stencil_alpha(st->cso_context);
- cso_save_rasterizer(st->cso_context);
- cso_save_viewport(st->cso_context);
- cso_save_clip(st->cso_context);
- cso_save_fragment_shader(st->cso_context);
- cso_save_vertex_shader(st->cso_context);
- cso_save_vertex_elements(st->cso_context);
- cso_save_vertex_buffers(st->cso_context);
-
- /* blend state: RGBA masking */
- {
- struct pipe_blend_state blend;
- memset(&blend, 0, sizeof(blend));
- blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
- blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
- blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
- blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
- if (color) {
- if (ctx->Color.ColorMask[0][0])
- blend.rt[0].colormask |= PIPE_MASK_R;
- if (ctx->Color.ColorMask[0][1])
- blend.rt[0].colormask |= PIPE_MASK_G;
- if (ctx->Color.ColorMask[0][2])
- blend.rt[0].colormask |= PIPE_MASK_B;
- if (ctx->Color.ColorMask[0][3])
- blend.rt[0].colormask |= PIPE_MASK_A;
- if (st->ctx->Color.DitherFlag)
- blend.dither = 1;
- }
- cso_set_blend(st->cso_context, &blend);
- }
-
- /* depth_stencil state: always pass/set to ref value */
- {
- struct pipe_depth_stencil_alpha_state depth_stencil;
- memset(&depth_stencil, 0, sizeof(depth_stencil));
- if (depth) {
- depth_stencil.depth.enabled = 1;
- depth_stencil.depth.writemask = 1;
- depth_stencil.depth.func = PIPE_FUNC_ALWAYS;
- }
-
- if (stencil) {
- struct pipe_stencil_ref stencil_ref;
- memset(&stencil_ref, 0, sizeof(stencil_ref));
- depth_stencil.stencil[0].enabled = 1;
- depth_stencil.stencil[0].func = PIPE_FUNC_ALWAYS;
- depth_stencil.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE;
- depth_stencil.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
- depth_stencil.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE;
- depth_stencil.stencil[0].valuemask = 0xff;
- depth_stencil.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff;
- stencil_ref.ref_value[0] = ctx->Stencil.Clear;
- cso_set_stencil_ref(st->cso_context, &stencil_ref);
- }
-
- cso_set_depth_stencil_alpha(st->cso_context, &depth_stencil);
- }
-
- cso_set_vertex_elements(st->cso_context, 2, st->velems_util_draw);
-
- cso_set_rasterizer(st->cso_context, &st->clear.raster);
-
- /* viewport state: viewport matching window dims */
- {
- const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP);
- struct pipe_viewport_state vp;
- vp.scale[0] = 0.5f * fb_width;
- vp.scale[1] = fb_height * (invert ? -0.5f : 0.5f);
- vp.scale[2] = 1.0f;
- vp.scale[3] = 1.0f;
- vp.translate[0] = 0.5f * fb_width;
- vp.translate[1] = 0.5f * fb_height;
- vp.translate[2] = 0.0f;
- vp.translate[3] = 0.0f;
- cso_set_viewport(st->cso_context, &vp);
- }
-
- cso_set_clip(st->cso_context, &st->clear.clip);
- cso_set_fragment_shader_handle(st->cso_context, st->clear.fs);
- cso_set_vertex_shader_handle(st->cso_context, st->clear.vs);
-
- if (ctx->DrawBuffer->_ColorDrawBuffers[0]) {
- st_translate_color(ctx->Color.ClearColor,
- ctx->DrawBuffer->_ColorDrawBuffers[0]->_BaseFormat,
- clearColor);
- }
-
- /* draw quad matching scissor rect */
- draw_quad(st, x0, y0, x1, y1, (GLfloat) ctx->Depth.Clear, clearColor);
-
- /* Restore pipe state */
- cso_restore_blend(st->cso_context);
- cso_restore_stencil_ref(st->cso_context);
- cso_restore_depth_stencil_alpha(st->cso_context);
- cso_restore_rasterizer(st->cso_context);
- cso_restore_viewport(st->cso_context);
- cso_restore_clip(st->cso_context);
- cso_restore_fragment_shader(st->cso_context);
- cso_restore_vertex_shader(st->cso_context);
- cso_restore_vertex_elements(st->cso_context);
- cso_restore_vertex_buffers(st->cso_context);
-}
-
-
-/**
- * Determine if we need to clear the depth buffer by drawing a quad.
- */
-static INLINE GLboolean
-check_clear_color_with_quad(struct gl_context *ctx, struct gl_renderbuffer *rb)
-{
- if (ctx->Scissor.Enabled &&
- (ctx->Scissor.X != 0 ||
- ctx->Scissor.Y != 0 ||
- ctx->Scissor.Width < rb->Width ||
- ctx->Scissor.Height < rb->Height))
- return GL_TRUE;
-
- if (!ctx->Color.ColorMask[0][0] ||
- !ctx->Color.ColorMask[0][1] ||
- !ctx->Color.ColorMask[0][2] ||
- !ctx->Color.ColorMask[0][3])
- return GL_TRUE;
-
- return GL_FALSE;
-}
-
-
-/**
- * Determine if we need to clear the combiend depth/stencil buffer by
- * drawing a quad.
- */
-static INLINE GLboolean
-check_clear_depth_stencil_with_quad(struct gl_context *ctx, struct gl_renderbuffer *rb)
-{
- const GLuint stencilMax = 0xff;
- GLboolean maskStencil
- = (ctx->Stencil.WriteMask[0] & stencilMax) != stencilMax;
-
- assert(rb->Format == MESA_FORMAT_S8 ||
- rb->Format == MESA_FORMAT_Z24_S8 ||
- rb->Format == MESA_FORMAT_S8_Z24);
-
- if (ctx->Scissor.Enabled &&
- (ctx->Scissor.X != 0 ||
- ctx->Scissor.Y != 0 ||
- ctx->Scissor.Width < rb->Width ||
- ctx->Scissor.Height < rb->Height))
- return GL_TRUE;
-
- if (maskStencil)
- return GL_TRUE;
-
- return GL_FALSE;
-}
-
-
-/**
- * Determine if we need to clear the depth buffer by drawing a quad.
- */
-static INLINE GLboolean
-check_clear_depth_with_quad(struct gl_context *ctx, struct gl_renderbuffer *rb,
- boolean ds_separate)
-{
- const struct st_renderbuffer *strb = st_renderbuffer(rb);
- const GLboolean isDS = util_format_is_depth_and_stencil(strb->surface->format);
-
- if (ctx->Scissor.Enabled &&
- (ctx->Scissor.X != 0 ||
- ctx->Scissor.Y != 0 ||
- ctx->Scissor.Width < rb->Width ||
- ctx->Scissor.Height < rb->Height))
- return GL_TRUE;
-
- if (!ds_separate && isDS && ctx->DrawBuffer->Visual.stencilBits > 0)
- return GL_TRUE;
-
- return GL_FALSE;
-}
-
-
-/**
- * Determine if we need to clear the stencil buffer by drawing a quad.
- */
-static INLINE GLboolean
-check_clear_stencil_with_quad(struct gl_context *ctx, struct gl_renderbuffer *rb,
- boolean ds_separate)
-{
- const struct st_renderbuffer *strb = st_renderbuffer(rb);
- const GLboolean isDS = util_format_is_depth_and_stencil(strb->surface->format);
- const GLuint stencilMax = 0xff;
- const GLboolean maskStencil
- = (ctx->Stencil.WriteMask[0] & stencilMax) != stencilMax;
-
- assert(rb->Format == MESA_FORMAT_S8 ||
- rb->Format == MESA_FORMAT_Z24_S8 ||
- rb->Format == MESA_FORMAT_S8_Z24);
-
- if (maskStencil)
- return GL_TRUE;
-
- if (ctx->Scissor.Enabled &&
- (ctx->Scissor.X != 0 ||
- ctx->Scissor.Y != 0 ||
- ctx->Scissor.Width < rb->Width ||
- ctx->Scissor.Height < rb->Height))
- return GL_TRUE;
-
- /* This is correct, but it is necessary to look at the depth clear
- * value held in the surface when it comes time to issue the clear,
- * rather than taking depth and stencil clear values from the
- * current state.
- */
- if (!ds_separate && isDS && ctx->DrawBuffer->Visual.depthBits > 0)
- return GL_TRUE;
-
- return GL_FALSE;
-}
-
-
-
-/**
- * Called when we need to flush.
- */
-void
-st_flush_clear(struct st_context *st)
-{
- /* Release vertex buffer to avoid synchronous rendering if we were
- * to map it in the next frame.
- */
- pipe_resource_reference(&st->clear.vbuf, NULL);
- st->clear.vbuf_slot = 0;
-}
-
-
-
-/**
- * Called via ctx->Driver.Clear()
- */
-static void
-st_Clear(struct gl_context *ctx, GLbitfield mask)
-{
- static const GLbitfield BUFFER_BITS_DS
- = (BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL);
- struct st_context *st = st_context(ctx);
- struct gl_renderbuffer *depthRb
- = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
- struct gl_renderbuffer *stencilRb
- = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
- GLbitfield quad_buffers = 0x0;
- GLbitfield clear_buffers = 0x0;
- GLuint i;
-
- /* This makes sure the pipe has the latest scissor, etc values */
- st_validate_state( st );
-
- if (mask & BUFFER_BITS_COLOR) {
- for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
- GLuint b = ctx->DrawBuffer->_ColorDrawBufferIndexes[i];
-
- if (mask & (1 << b)) {
- struct gl_renderbuffer *rb
- = ctx->DrawBuffer->Attachment[b].Renderbuffer;
- struct st_renderbuffer *strb = st_renderbuffer(rb);
-
- if (!strb || !strb->surface)
- continue;
-
- if (check_clear_color_with_quad( ctx, rb ))
- quad_buffers |= PIPE_CLEAR_COLOR;
- else
- clear_buffers |= PIPE_CLEAR_COLOR;
- }
- }
- }
-
- if ((mask & BUFFER_BITS_DS) == BUFFER_BITS_DS && depthRb == stencilRb) {
- /* clearing combined depth + stencil */
- struct st_renderbuffer *strb = st_renderbuffer(depthRb);
-
- if (strb->surface) {
- if (check_clear_depth_stencil_with_quad(ctx, depthRb))
- quad_buffers |= PIPE_CLEAR_DEPTHSTENCIL;
- else
- clear_buffers |= PIPE_CLEAR_DEPTHSTENCIL;
- }
- }
- else {
- /* separate depth/stencil clears */
- /* I don't think truly separate buffers are actually possible in gallium or hw? */
- if (mask & BUFFER_BIT_DEPTH) {
- struct st_renderbuffer *strb = st_renderbuffer(depthRb);
-
- if (strb->surface) {
- if (check_clear_depth_with_quad(ctx, depthRb,
- st->clear.enable_ds_separate))
- quad_buffers |= PIPE_CLEAR_DEPTH;
- else
- clear_buffers |= PIPE_CLEAR_DEPTH;
- }
- }
- if (mask & BUFFER_BIT_STENCIL) {
- struct st_renderbuffer *strb = st_renderbuffer(stencilRb);
-
- if (strb->surface) {
- if (check_clear_stencil_with_quad(ctx, stencilRb,
- st->clear.enable_ds_separate))
- quad_buffers |= PIPE_CLEAR_STENCIL;
- else
- clear_buffers |= PIPE_CLEAR_STENCIL;
- }
- }
- }
-
- /*
- * If we're going to use clear_with_quad() for any reason, use it for
- * everything possible.
- */
- if (quad_buffers) {
- quad_buffers |= clear_buffers;
- clear_with_quad(ctx,
- quad_buffers & PIPE_CLEAR_COLOR,
- quad_buffers & PIPE_CLEAR_DEPTH,
- quad_buffers & PIPE_CLEAR_STENCIL);
- } else if (clear_buffers) {
- /* driver cannot know it can clear everything if the buffer
- * is a combined depth/stencil buffer but this wasn't actually
- * required from the visual. Hence fix this up to avoid potential
- * read-modify-write in the driver.
- */
- float clearColor[4];
-
- if ((clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) &&
- ((clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) != PIPE_CLEAR_DEPTHSTENCIL) &&
- (depthRb == stencilRb) &&
- (ctx->DrawBuffer->Visual.depthBits == 0 ||
- ctx->DrawBuffer->Visual.stencilBits == 0))
- clear_buffers |= PIPE_CLEAR_DEPTHSTENCIL;
-
- if (ctx->DrawBuffer->_ColorDrawBuffers[0]) {
- st_translate_color(ctx->Color.ClearColor,
- ctx->DrawBuffer->_ColorDrawBuffers[0]->_BaseFormat,
- clearColor);
- }
-
- st->pipe->clear(st->pipe, clear_buffers, ctx->Color.ClearColor,
- ctx->Depth.Clear, ctx->Stencil.Clear);
- }
- if (mask & BUFFER_BIT_ACCUM)
- st_clear_accum_buffer(ctx,
- ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer);
-}
-
-
-void
-st_init_clear_functions(struct dd_function_table *functions)
-{
- functions->Clear = st_Clear;
-}
+/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * Copyright 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, 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 <keith@tungstengraphics.com>
+ * Brian Paul
+ * Michel Dänzer
+ */
+
+#include "main/glheader.h"
+#include "main/formats.h"
+#include "main/macros.h"
+#include "program/prog_instruction.h"
+#include "st_context.h"
+#include "st_atom.h"
+#include "st_cb_accum.h"
+#include "st_cb_clear.h"
+#include "st_cb_fbo.h"
+#include "st_format.h"
+#include "st_program.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_shader_tokens.h"
+#include "pipe/p_state.h"
+#include "pipe/p_defines.h"
+#include "util/u_format.h"
+#include "util/u_inlines.h"
+#include "util/u_simple_shaders.h"
+#include "util/u_draw_quad.h"
+
+#include "cso_cache/cso_context.h"
+
+
+/**
+ * Do per-context initialization for glClear.
+ */
+void
+st_init_clear(struct st_context *st)
+{
+ struct pipe_context *pipe = st->pipe;
+ struct pipe_screen *pscreen = st->pipe->screen;
+
+ memset(&st->clear, 0, sizeof(st->clear));
+
+ st->clear.raster.gl_rasterization_rules = 1;
+ st->clear.enable_ds_separate = pscreen->get_param(pscreen, PIPE_CAP_DEPTHSTENCIL_CLEAR_SEPARATE);
+
+ /* fragment shader state: color pass-through program */
+ st->clear.fs = util_make_fragment_passthrough_shader(pipe);
+
+ /* vertex shader state: color/position pass-through */
+ {
+ const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
+ TGSI_SEMANTIC_COLOR };
+ const uint semantic_indexes[] = { 0, 0 };
+ st->clear.vs = util_make_vertex_passthrough_shader(pipe, 2,
+ semantic_names,
+ semantic_indexes);
+ }
+}
+
+
+/**
+ * Free per-context state for glClear.
+ */
+void
+st_destroy_clear(struct st_context *st)
+{
+ if (st->clear.fs) {
+ cso_delete_fragment_shader(st->cso_context, st->clear.fs);
+ st->clear.fs = NULL;
+ }
+ if (st->clear.vs) {
+ cso_delete_vertex_shader(st->cso_context, st->clear.vs);
+ st->clear.vs = NULL;
+ }
+ if (st->clear.vbuf) {
+ pipe_resource_reference(&st->clear.vbuf, NULL);
+ st->clear.vbuf = NULL;
+ }
+}
+
+
+/**
+ * Draw a screen-aligned quadrilateral.
+ * Coords are clip coords with y=0=bottom.
+ */
+static void
+draw_quad(struct st_context *st,
+ float x0, float y0, float x1, float y1, GLfloat z,
+ const GLfloat color[4])
+{
+ struct pipe_context *pipe = st->pipe;
+
+ /* XXX: Need to improve buffer_write to allow NO_WAIT (as well as
+ * no_flush) updates to buffers where we know there is no conflict
+ * with previous data. Currently using max_slots > 1 will cause
+ * synchronous rendering if the driver flushes its command buffers
+ * between one bitmap and the next. Our flush hook below isn't
+ * sufficient to catch this as the driver doesn't tell us when it
+ * flushes its own command buffers. Until this gets fixed, pay the
+ * price of allocating a new buffer for each bitmap cache-flush to
+ * avoid synchronous rendering.
+ */
+ const GLuint max_slots = 1; /* 1024 / sizeof(st->clear.vertices); */
+ GLuint i;
+
+ if (st->clear.vbuf_slot >= max_slots) {
+ pipe_resource_reference(&st->clear.vbuf, NULL);
+ st->clear.vbuf_slot = 0;
+ }
+
+ if (!st->clear.vbuf) {
+ st->clear.vbuf = pipe_buffer_create(pipe->screen,
+ PIPE_BIND_VERTEX_BUFFER,
+ PIPE_USAGE_STREAM,
+ max_slots * sizeof(st->clear.vertices));
+ }
+
+ /* positions */
+ st->clear.vertices[0][0][0] = x0;
+ st->clear.vertices[0][0][1] = y0;
+
+ st->clear.vertices[1][0][0] = x1;
+ st->clear.vertices[1][0][1] = y0;
+
+ st->clear.vertices[2][0][0] = x1;
+ st->clear.vertices[2][0][1] = y1;
+
+ st->clear.vertices[3][0][0] = x0;
+ st->clear.vertices[3][0][1] = y1;
+
+ /* same for all verts: */
+ for (i = 0; i < 4; i++) {
+ st->clear.vertices[i][0][2] = z;
+ st->clear.vertices[i][0][3] = 1.0;
+ st->clear.vertices[i][1][0] = color[0];
+ st->clear.vertices[i][1][1] = color[1];
+ st->clear.vertices[i][1][2] = color[2];
+ st->clear.vertices[i][1][3] = color[3];
+ }
+
+ /* put vertex data into vbuf */
+ pipe_buffer_write_nooverlap(st->pipe, st->clear.vbuf,
+ st->clear.vbuf_slot
+ * sizeof(st->clear.vertices),
+ sizeof(st->clear.vertices),
+ st->clear.vertices);
+
+ /* draw */
+ util_draw_vertex_buffer(pipe,
+ st->cso_context,
+ st->clear.vbuf,
+ st->clear.vbuf_slot * sizeof(st->clear.vertices),
+ PIPE_PRIM_TRIANGLE_FAN,
+ 4, /* verts */
+ 2); /* attribs/vert */
+
+ /* Increment slot */
+ st->clear.vbuf_slot++;
+}
+
+
+
+/**
+ * Do glClear by drawing a quadrilateral.
+ * The vertices of the quad will be computed from the
+ * ctx->DrawBuffer->_X/Ymin/max fields.
+ */
+static void
+clear_with_quad(struct gl_context *ctx,
+ GLboolean color, GLboolean depth, GLboolean stencil)
+{
+ struct st_context *st = st_context(ctx);
+ const struct gl_framebuffer *fb = ctx->DrawBuffer;
+ const GLfloat fb_width = (GLfloat) fb->Width;
+ const GLfloat fb_height = (GLfloat) fb->Height;
+ const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin / fb_width * 2.0f - 1.0f;
+ const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax / fb_width * 2.0f - 1.0f;
+ const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin / fb_height * 2.0f - 1.0f;
+ const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax / fb_height * 2.0f - 1.0f;
+ float clearColor[4];
+
+ /*
+ printf("%s %s%s%s %f,%f %f,%f\n", __FUNCTION__,
+ color ? "color, " : "",
+ depth ? "depth, " : "",
+ stencil ? "stencil" : "",
+ x0, y0,
+ x1, y1);
+ */
+
+ cso_save_blend(st->cso_context);
+ cso_save_stencil_ref(st->cso_context);
+ cso_save_depth_stencil_alpha(st->cso_context);
+ cso_save_rasterizer(st->cso_context);
+ cso_save_viewport(st->cso_context);
+ cso_save_clip(st->cso_context);
+ cso_save_fragment_shader(st->cso_context);
+ cso_save_vertex_shader(st->cso_context);
+ cso_save_vertex_elements(st->cso_context);
+ cso_save_vertex_buffers(st->cso_context);
+
+ /* blend state: RGBA masking */
+ {
+ struct pipe_blend_state blend;
+ memset(&blend, 0, sizeof(blend));
+ blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ if (color) {
+ if (ctx->Color.ColorMask[0][0])
+ blend.rt[0].colormask |= PIPE_MASK_R;
+ if (ctx->Color.ColorMask[0][1])
+ blend.rt[0].colormask |= PIPE_MASK_G;
+ if (ctx->Color.ColorMask[0][2])
+ blend.rt[0].colormask |= PIPE_MASK_B;
+ if (ctx->Color.ColorMask[0][3])
+ blend.rt[0].colormask |= PIPE_MASK_A;
+ if (st->ctx->Color.DitherFlag)
+ blend.dither = 1;
+ }
+ cso_set_blend(st->cso_context, &blend);
+ }
+
+ /* depth_stencil state: always pass/set to ref value */
+ {
+ struct pipe_depth_stencil_alpha_state depth_stencil;
+ memset(&depth_stencil, 0, sizeof(depth_stencil));
+ if (depth) {
+ depth_stencil.depth.enabled = 1;
+ depth_stencil.depth.writemask = 1;
+ depth_stencil.depth.func = PIPE_FUNC_ALWAYS;
+ }
+
+ if (stencil) {
+ struct pipe_stencil_ref stencil_ref;
+ memset(&stencil_ref, 0, sizeof(stencil_ref));
+ depth_stencil.stencil[0].enabled = 1;
+ depth_stencil.stencil[0].func = PIPE_FUNC_ALWAYS;
+ depth_stencil.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE;
+ depth_stencil.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
+ depth_stencil.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE;
+ depth_stencil.stencil[0].valuemask = 0xff;
+ depth_stencil.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff;
+ stencil_ref.ref_value[0] = ctx->Stencil.Clear;
+ cso_set_stencil_ref(st->cso_context, &stencil_ref);
+ }
+
+ cso_set_depth_stencil_alpha(st->cso_context, &depth_stencil);
+ }
+
+ cso_set_vertex_elements(st->cso_context, 2, st->velems_util_draw);
+
+ cso_set_rasterizer(st->cso_context, &st->clear.raster);
+
+ /* viewport state: viewport matching window dims */
+ {
+ const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP);
+ struct pipe_viewport_state vp;
+ vp.scale[0] = 0.5f * fb_width;
+ vp.scale[1] = fb_height * (invert ? -0.5f : 0.5f);
+ vp.scale[2] = 1.0f;
+ vp.scale[3] = 1.0f;
+ vp.translate[0] = 0.5f * fb_width;
+ vp.translate[1] = 0.5f * fb_height;
+ vp.translate[2] = 0.0f;
+ vp.translate[3] = 0.0f;
+ cso_set_viewport(st->cso_context, &vp);
+ }
+
+ cso_set_clip(st->cso_context, &st->clear.clip);
+ cso_set_fragment_shader_handle(st->cso_context, st->clear.fs);
+ cso_set_vertex_shader_handle(st->cso_context, st->clear.vs);
+
+ if (ctx->DrawBuffer->_ColorDrawBuffers[0]) {
+ st_translate_color(ctx->Color.ClearColor,
+ ctx->DrawBuffer->_ColorDrawBuffers[0]->_BaseFormat,
+ clearColor);
+ }
+
+ /* draw quad matching scissor rect */
+ draw_quad(st, x0, y0, x1, y1, (GLfloat) ctx->Depth.Clear, clearColor);
+
+ /* Restore pipe state */
+ cso_restore_blend(st->cso_context);
+ cso_restore_stencil_ref(st->cso_context);
+ cso_restore_depth_stencil_alpha(st->cso_context);
+ cso_restore_rasterizer(st->cso_context);
+ cso_restore_viewport(st->cso_context);
+ cso_restore_clip(st->cso_context);
+ cso_restore_fragment_shader(st->cso_context);
+ cso_restore_vertex_shader(st->cso_context);
+ cso_restore_vertex_elements(st->cso_context);
+ cso_restore_vertex_buffers(st->cso_context);
+}
+
+
+/**
+ * Determine if we need to clear the depth buffer by drawing a quad.
+ */
+static INLINE GLboolean
+check_clear_color_with_quad(struct gl_context *ctx, struct gl_renderbuffer *rb)
+{
+ if (ctx->Scissor.Enabled &&
+ (ctx->Scissor.X != 0 ||
+ ctx->Scissor.Y != 0 ||
+ ctx->Scissor.Width < rb->Width ||
+ ctx->Scissor.Height < rb->Height))
+ return GL_TRUE;
+
+ if (!ctx->Color.ColorMask[0][0] ||
+ !ctx->Color.ColorMask[0][1] ||
+ !ctx->Color.ColorMask[0][2] ||
+ !ctx->Color.ColorMask[0][3])
+ return GL_TRUE;
+
+ return GL_FALSE;
+}
+
+
+/**
+ * Determine if we need to clear the combiend depth/stencil buffer by
+ * drawing a quad.
+ */
+static INLINE GLboolean
+check_clear_depth_stencil_with_quad(struct gl_context *ctx, struct gl_renderbuffer *rb)
+{
+ const GLuint stencilMax = 0xff;
+ GLboolean maskStencil
+ = (ctx->Stencil.WriteMask[0] & stencilMax) != stencilMax;
+
+ assert(rb->Format == MESA_FORMAT_S8 ||
+ rb->Format == MESA_FORMAT_Z24_S8 ||
+ rb->Format == MESA_FORMAT_S8_Z24);
+
+ if (ctx->Scissor.Enabled &&
+ (ctx->Scissor.X != 0 ||
+ ctx->Scissor.Y != 0 ||
+ ctx->Scissor.Width < rb->Width ||
+ ctx->Scissor.Height < rb->Height))
+ return GL_TRUE;
+
+ if (maskStencil)
+ return GL_TRUE;
+
+ return GL_FALSE;
+}
+
+
+/**
+ * Determine if we need to clear the depth buffer by drawing a quad.
+ */
+static INLINE GLboolean
+check_clear_depth_with_quad(struct gl_context *ctx, struct gl_renderbuffer *rb,
+ boolean ds_separate)
+{
+ const struct st_renderbuffer *strb = st_renderbuffer(rb);
+ const GLboolean isDS = util_format_is_depth_and_stencil(strb->surface->format);
+
+ if (ctx->Scissor.Enabled &&
+ (ctx->Scissor.X != 0 ||
+ ctx->Scissor.Y != 0 ||
+ ctx->Scissor.Width < rb->Width ||
+ ctx->Scissor.Height < rb->Height))
+ return GL_TRUE;
+
+ if (!ds_separate && isDS && ctx->DrawBuffer->Visual.stencilBits > 0)
+ return GL_TRUE;
+
+ return GL_FALSE;
+}
+
+
+/**
+ * Determine if we need to clear the stencil buffer by drawing a quad.
+ */
+static INLINE GLboolean
+check_clear_stencil_with_quad(struct gl_context *ctx, struct gl_renderbuffer *rb,
+ boolean ds_separate)
+{
+ const struct st_renderbuffer *strb = st_renderbuffer(rb);
+ const GLboolean isDS = util_format_is_depth_and_stencil(strb->surface->format);
+ const GLuint stencilMax = 0xff;
+ const GLboolean maskStencil
+ = (ctx->Stencil.WriteMask[0] & stencilMax) != stencilMax;
+
+ assert(rb->Format == MESA_FORMAT_S8 ||
+ rb->Format == MESA_FORMAT_Z24_S8 ||
+ rb->Format == MESA_FORMAT_S8_Z24);
+
+ if (maskStencil)
+ return GL_TRUE;
+
+ if (ctx->Scissor.Enabled &&
+ (ctx->Scissor.X != 0 ||
+ ctx->Scissor.Y != 0 ||
+ ctx->Scissor.Width < rb->Width ||
+ ctx->Scissor.Height < rb->Height))
+ return GL_TRUE;
+
+ /* This is correct, but it is necessary to look at the depth clear
+ * value held in the surface when it comes time to issue the clear,
+ * rather than taking depth and stencil clear values from the
+ * current state.
+ */
+ if (!ds_separate && isDS && ctx->DrawBuffer->Visual.depthBits > 0)
+ return GL_TRUE;
+
+ return GL_FALSE;
+}
+
+
+
+/**
+ * Called when we need to flush.
+ */
+void
+st_flush_clear(struct st_context *st)
+{
+ /* Release vertex buffer to avoid synchronous rendering if we were
+ * to map it in the next frame.
+ */
+ pipe_resource_reference(&st->clear.vbuf, NULL);
+ st->clear.vbuf_slot = 0;
+}
+
+
+
+/**
+ * Called via ctx->Driver.Clear()
+ */
+static void
+st_Clear(struct gl_context *ctx, GLbitfield mask)
+{
+ static const GLbitfield BUFFER_BITS_DS
+ = (BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL);
+ struct st_context *st = st_context(ctx);
+ struct gl_renderbuffer *depthRb
+ = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
+ struct gl_renderbuffer *stencilRb
+ = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
+ GLbitfield quad_buffers = 0x0;
+ GLbitfield clear_buffers = 0x0;
+ GLuint i;
+
+ /* This makes sure the pipe has the latest scissor, etc values */
+ st_validate_state( st );
+
+ if (mask & BUFFER_BITS_COLOR) {
+ for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
+ GLuint b = ctx->DrawBuffer->_ColorDrawBufferIndexes[i];
+
+ if (mask & (1 << b)) {
+ struct gl_renderbuffer *rb
+ = ctx->DrawBuffer->Attachment[b].Renderbuffer;
+ struct st_renderbuffer *strb = st_renderbuffer(rb);
+
+ if (!strb || !strb->surface)
+ continue;
+
+ if (check_clear_color_with_quad( ctx, rb ))
+ quad_buffers |= PIPE_CLEAR_COLOR;
+ else
+ clear_buffers |= PIPE_CLEAR_COLOR;
+ }
+ }
+ }
+
+ if ((mask & BUFFER_BITS_DS) == BUFFER_BITS_DS && depthRb == stencilRb) {
+ /* clearing combined depth + stencil */
+ struct st_renderbuffer *strb = st_renderbuffer(depthRb);
+
+ if (strb->surface) {
+ if (check_clear_depth_stencil_with_quad(ctx, depthRb))
+ quad_buffers |= PIPE_CLEAR_DEPTHSTENCIL;
+ else
+ clear_buffers |= PIPE_CLEAR_DEPTHSTENCIL;
+ }
+ }
+ else {
+ /* separate depth/stencil clears */
+ /* I don't think truly separate buffers are actually possible in gallium or hw? */
+ if (mask & BUFFER_BIT_DEPTH) {
+ struct st_renderbuffer *strb = st_renderbuffer(depthRb);
+
+ if (strb->surface) {
+ if (check_clear_depth_with_quad(ctx, depthRb,
+ st->clear.enable_ds_separate))
+ quad_buffers |= PIPE_CLEAR_DEPTH;
+ else
+ clear_buffers |= PIPE_CLEAR_DEPTH;
+ }
+ }
+ if (mask & BUFFER_BIT_STENCIL) {
+ struct st_renderbuffer *strb = st_renderbuffer(stencilRb);
+
+ if (strb->surface) {
+ if (check_clear_stencil_with_quad(ctx, stencilRb,
+ st->clear.enable_ds_separate))
+ quad_buffers |= PIPE_CLEAR_STENCIL;
+ else
+ clear_buffers |= PIPE_CLEAR_STENCIL;
+ }
+ }
+ }
+
+ /*
+ * If we're going to use clear_with_quad() for any reason, use it for
+ * everything possible.
+ */
+ if (quad_buffers) {
+ quad_buffers |= clear_buffers;
+ clear_with_quad(ctx,
+ quad_buffers & PIPE_CLEAR_COLOR,
+ quad_buffers & PIPE_CLEAR_DEPTH,
+ quad_buffers & PIPE_CLEAR_STENCIL);
+ } else if (clear_buffers) {
+ /* driver cannot know it can clear everything if the buffer
+ * is a combined depth/stencil buffer but this wasn't actually
+ * required from the visual. Hence fix this up to avoid potential
+ * read-modify-write in the driver.
+ */
+ float clearColor[4];
+
+ if ((clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) &&
+ ((clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) != PIPE_CLEAR_DEPTHSTENCIL) &&
+ (depthRb == stencilRb) &&
+ (ctx->DrawBuffer->Visual.depthBits == 0 ||
+ ctx->DrawBuffer->Visual.stencilBits == 0))
+ clear_buffers |= PIPE_CLEAR_DEPTHSTENCIL;
+
+ if (ctx->DrawBuffer->_ColorDrawBuffers[0]) {
+ st_translate_color(ctx->Color.ClearColor,
+ ctx->DrawBuffer->_ColorDrawBuffers[0]->_BaseFormat,
+ clearColor);
+ }
+
+ st->pipe->clear(st->pipe, clear_buffers, ctx->Color.ClearColor,
+ ctx->Depth.Clear, ctx->Stencil.Clear);
+ }
+ if (mask & BUFFER_BIT_ACCUM)
+ st_clear_accum_buffer(ctx,
+ ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer);
+}
+
+
+void
+st_init_clear_functions(struct dd_function_table *functions)
+{
+ functions->Clear = st_Clear;
+}
diff --git a/mesalib/src/mesa/state_tracker/st_cb_drawtex.c b/mesalib/src/mesa/state_tracker/st_cb_drawtex.c
index 86ceb9d78..db299eb8d 100644
--- a/mesalib/src/mesa/state_tracker/st_cb_drawtex.c
+++ b/mesalib/src/mesa/state_tracker/st_cb_drawtex.c
@@ -1,307 +1,307 @@
-/**************************************************************************
- *
- * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
- * All Rights Reserved.
- *
- **************************************************************************/
-
-
-/**
- * Implementation of glDrawTex() for GL_OES_draw_tex
- */
-
-
-
-#include "main/imports.h"
-#include "main/image.h"
-#include "main/macros.h"
-#include "main/mfeatures.h"
-#include "program/program.h"
-#include "program/prog_print.h"
-
-#include "st_context.h"
-#include "st_atom.h"
-#include "st_cb_drawtex.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "util/u_inlines.h"
-#include "pipe/p_shader_tokens.h"
-#include "util/u_draw_quad.h"
-#include "util/u_simple_shaders.h"
-
-#include "cso_cache/cso_context.h"
-
-
-#if FEATURE_OES_draw_texture
-
-
-struct cached_shader
-{
- void *handle;
-
- uint num_attribs;
- uint semantic_names[2 + MAX_TEXTURE_UNITS];
- uint semantic_indexes[2 + MAX_TEXTURE_UNITS];
-};
-
-#define MAX_SHADERS (2 * MAX_TEXTURE_UNITS)
-
-/**
- * Simple linear list cache.
- * Most of the time there'll only be one cached shader.
- */
-static struct cached_shader CachedShaders[MAX_SHADERS];
-static GLuint NumCachedShaders = 0;
-
-
-static void *
-lookup_shader(struct pipe_context *pipe,
- uint num_attribs,
- const uint *semantic_names,
- const uint *semantic_indexes)
-{
- GLuint i, j;
-
- /* look for existing shader with same attributes */
- for (i = 0; i < NumCachedShaders; i++) {
- if (CachedShaders[i].num_attribs == num_attribs) {
- GLboolean match = GL_TRUE;
- for (j = 0; j < num_attribs; j++) {
- if (semantic_names[j] != CachedShaders[i].semantic_names[j] ||
- semantic_indexes[j] != CachedShaders[i].semantic_indexes[j]) {
- match = GL_FALSE;
- break;
- }
- }
- if (match)
- return CachedShaders[i].handle;
- }
- }
-
- /* not found - create new one now */
- if (NumCachedShaders >= MAX_SHADERS) {
- return NULL;
- }
-
- CachedShaders[i].num_attribs = num_attribs;
- for (j = 0; j < num_attribs; j++) {
- CachedShaders[i].semantic_names[j] = semantic_names[j];
- CachedShaders[i].semantic_indexes[j] = semantic_indexes[j];
- }
-
- CachedShaders[i].handle =
- util_make_vertex_passthrough_shader(pipe,
- num_attribs,
- semantic_names,
- semantic_indexes);
- NumCachedShaders++;
-
- return CachedShaders[i].handle;
-}
-
-static void
-st_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z,
- GLfloat width, GLfloat height)
-{
- struct st_context *st = ctx->st;
- struct pipe_context *pipe = st->pipe;
- struct cso_context *cso = ctx->st->cso_context;
- struct pipe_resource *vbuffer;
- struct pipe_transfer *vbuffer_transfer;
- GLuint i, numTexCoords, numAttribs;
- GLboolean emitColor;
- uint semantic_names[2 + MAX_TEXTURE_UNITS];
- uint semantic_indexes[2 + MAX_TEXTURE_UNITS];
- struct pipe_vertex_element velements[2 + MAX_TEXTURE_UNITS];
- GLbitfield inputs = VERT_BIT_POS;
-
- st_validate_state(st);
-
- /* determine if we need vertex color */
- if (ctx->FragmentProgram._Current->Base.InputsRead & FRAG_BIT_COL0)
- emitColor = GL_TRUE;
- else
- emitColor = GL_FALSE;
-
- /* determine how many enabled sets of texcoords */
- numTexCoords = 0;
- for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
- if (ctx->Texture.Unit[i]._ReallyEnabled & TEXTURE_2D_BIT) {
- inputs |= VERT_BIT_TEX(i);
- numTexCoords++;
- }
- }
-
- /* total number of attributes per vertex */
- numAttribs = 1 + emitColor + numTexCoords;
-
-
- /* create the vertex buffer */
- vbuffer = pipe_buffer_create(pipe->screen, PIPE_BIND_VERTEX_BUFFER,
- PIPE_USAGE_STREAM,
- numAttribs * 4 * 4 * sizeof(GLfloat));
-
- /* load vertex buffer */
- {
-#define SET_ATTRIB(VERT, ATTR, X, Y, Z, W) \
- do { \
- GLuint k = (((VERT) * numAttribs + (ATTR)) * 4); \
- assert(k < 4 * 4 * numAttribs); \
- vbuf[k + 0] = X; \
- vbuf[k + 1] = Y; \
- vbuf[k + 2] = Z; \
- vbuf[k + 3] = W; \
- } while (0)
-
- const GLfloat x0 = x, y0 = y, x1 = x + width, y1 = y + height;
- GLfloat *vbuf = (GLfloat *) pipe_buffer_map(pipe, vbuffer,
- PIPE_TRANSFER_WRITE,
- &vbuffer_transfer);
- GLuint attr;
-
- z = CLAMP(z, 0.0f, 1.0f);
-
- /* positions (in clip coords) */
- {
- const struct gl_framebuffer *fb = st->ctx->DrawBuffer;
- const GLfloat fb_width = (GLfloat)fb->Width;
- const GLfloat fb_height = (GLfloat)fb->Height;
-
- const GLfloat clip_x0 = (GLfloat)(x0 / fb_width * 2.0 - 1.0);
- const GLfloat clip_y0 = (GLfloat)(y0 / fb_height * 2.0 - 1.0);
- const GLfloat clip_x1 = (GLfloat)(x1 / fb_width * 2.0 - 1.0);
- const GLfloat clip_y1 = (GLfloat)(y1 / fb_height * 2.0 - 1.0);
-
- SET_ATTRIB(0, 0, clip_x0, clip_y0, z, 1.0f); /* lower left */
- SET_ATTRIB(1, 0, clip_x1, clip_y0, z, 1.0f); /* lower right */
- SET_ATTRIB(2, 0, clip_x1, clip_y1, z, 1.0f); /* upper right */
- SET_ATTRIB(3, 0, clip_x0, clip_y1, z, 1.0f); /* upper left */
-
- semantic_names[0] = TGSI_SEMANTIC_POSITION;
- semantic_indexes[0] = 0;
- }
-
- /* colors */
- if (emitColor) {
- const GLfloat *c = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
- SET_ATTRIB(0, 1, c[0], c[1], c[2], c[3]);
- SET_ATTRIB(1, 1, c[0], c[1], c[2], c[3]);
- SET_ATTRIB(2, 1, c[0], c[1], c[2], c[3]);
- SET_ATTRIB(3, 1, c[0], c[1], c[2], c[3]);
- semantic_names[1] = TGSI_SEMANTIC_COLOR;
- semantic_indexes[1] = 0;
- attr = 2;
- }
- else {
- attr = 1;
- }
-
- /* texcoords */
- for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
- if (ctx->Texture.Unit[i]._ReallyEnabled & TEXTURE_2D_BIT) {
- struct gl_texture_object *obj = ctx->Texture.Unit[i]._Current;
- struct gl_texture_image *img = obj->Image[0][obj->BaseLevel];
- const GLfloat wt = (GLfloat) img->Width;
- const GLfloat ht = (GLfloat) img->Height;
- const GLfloat s0 = obj->CropRect[0] / wt;
- const GLfloat t0 = obj->CropRect[1] / ht;
- const GLfloat s1 = (obj->CropRect[0] + obj->CropRect[2]) / wt;
- const GLfloat t1 = (obj->CropRect[1] + obj->CropRect[3]) / ht;
-
- /*printf("crop texcoords: %g, %g .. %g, %g\n", s0, t0, s1, t1);*/
- SET_ATTRIB(0, attr, s0, t0, 0.0f, 1.0f); /* lower left */
- SET_ATTRIB(1, attr, s1, t0, 0.0f, 1.0f); /* lower right */
- SET_ATTRIB(2, attr, s1, t1, 0.0f, 1.0f); /* upper right */
- SET_ATTRIB(3, attr, s0, t1, 0.0f, 1.0f); /* upper left */
-
- semantic_names[attr] = TGSI_SEMANTIC_GENERIC;
- semantic_indexes[attr] = 0;
-
- attr++;
- }
- }
-
- pipe_buffer_unmap(pipe, vbuffer_transfer);
-
-#undef SET_ATTRIB
- }
-
-
- cso_save_viewport(cso);
- cso_save_vertex_shader(cso);
- cso_save_vertex_elements(cso);
- cso_save_vertex_buffers(cso);
-
- {
- void *vs = lookup_shader(pipe, numAttribs,
- semantic_names, semantic_indexes);
- cso_set_vertex_shader_handle(cso, vs);
- }
-
- for (i = 0; i < numAttribs; i++) {
- velements[i].src_offset = i * 4 * sizeof(float);
- velements[i].instance_divisor = 0;
- velements[i].vertex_buffer_index = 0;
- velements[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
- }
- cso_set_vertex_elements(cso, numAttribs, velements);
-
- /* viewport state: viewport matching window dims */
- {
- const struct gl_framebuffer *fb = st->ctx->DrawBuffer;
- const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP);
- const GLfloat width = (GLfloat)fb->Width;
- const GLfloat height = (GLfloat)fb->Height;
- struct pipe_viewport_state vp;
- vp.scale[0] = 0.5f * width;
- vp.scale[1] = height * (invert ? -0.5f : 0.5f);
- vp.scale[2] = 1.0f;
- vp.scale[3] = 1.0f;
- vp.translate[0] = 0.5f * width;
- vp.translate[1] = 0.5f * height;
- vp.translate[2] = 0.0f;
- vp.translate[3] = 0.0f;
- cso_set_viewport(cso, &vp);
- }
-
-
- util_draw_vertex_buffer(pipe, cso, vbuffer,
- 0, /* offset */
- PIPE_PRIM_TRIANGLE_FAN,
- 4, /* verts */
- numAttribs); /* attribs/vert */
-
-
- pipe_resource_reference(&vbuffer, NULL);
-
- /* restore state */
- cso_restore_viewport(cso);
- cso_restore_vertex_shader(cso);
- cso_restore_vertex_elements(cso);
- cso_restore_vertex_buffers(cso);
-}
-
-
-void
-st_init_drawtex_functions(struct dd_function_table *functions)
-{
- functions->DrawTex = st_DrawTex;
-}
-
-
-/**
- * Free any cached shaders
- */
-void
-st_destroy_drawtex(struct st_context *st)
-{
- GLuint i;
- for (i = 0; i < NumCachedShaders; i++) {
- cso_delete_vertex_shader(st->cso_context, CachedShaders[i].handle);
- }
- NumCachedShaders = 0;
-}
-
-
-#endif /* FEATURE_OES_draw_texture */
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ **************************************************************************/
+
+
+/**
+ * Implementation of glDrawTex() for GL_OES_draw_tex
+ */
+
+
+
+#include "main/imports.h"
+#include "main/image.h"
+#include "main/macros.h"
+#include "main/mfeatures.h"
+#include "program/program.h"
+#include "program/prog_print.h"
+
+#include "st_context.h"
+#include "st_atom.h"
+#include "st_cb_drawtex.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_defines.h"
+#include "util/u_inlines.h"
+#include "pipe/p_shader_tokens.h"
+#include "util/u_draw_quad.h"
+#include "util/u_simple_shaders.h"
+
+#include "cso_cache/cso_context.h"
+
+
+#if FEATURE_OES_draw_texture
+
+
+struct cached_shader
+{
+ void *handle;
+
+ uint num_attribs;
+ uint semantic_names[2 + MAX_TEXTURE_UNITS];
+ uint semantic_indexes[2 + MAX_TEXTURE_UNITS];
+};
+
+#define MAX_SHADERS (2 * MAX_TEXTURE_UNITS)
+
+/**
+ * Simple linear list cache.
+ * Most of the time there'll only be one cached shader.
+ */
+static struct cached_shader CachedShaders[MAX_SHADERS];
+static GLuint NumCachedShaders = 0;
+
+
+static void *
+lookup_shader(struct pipe_context *pipe,
+ uint num_attribs,
+ const uint *semantic_names,
+ const uint *semantic_indexes)
+{
+ GLuint i, j;
+
+ /* look for existing shader with same attributes */
+ for (i = 0; i < NumCachedShaders; i++) {
+ if (CachedShaders[i].num_attribs == num_attribs) {
+ GLboolean match = GL_TRUE;
+ for (j = 0; j < num_attribs; j++) {
+ if (semantic_names[j] != CachedShaders[i].semantic_names[j] ||
+ semantic_indexes[j] != CachedShaders[i].semantic_indexes[j]) {
+ match = GL_FALSE;
+ break;
+ }
+ }
+ if (match)
+ return CachedShaders[i].handle;
+ }
+ }
+
+ /* not found - create new one now */
+ if (NumCachedShaders >= MAX_SHADERS) {
+ return NULL;
+ }
+
+ CachedShaders[i].num_attribs = num_attribs;
+ for (j = 0; j < num_attribs; j++) {
+ CachedShaders[i].semantic_names[j] = semantic_names[j];
+ CachedShaders[i].semantic_indexes[j] = semantic_indexes[j];
+ }
+
+ CachedShaders[i].handle =
+ util_make_vertex_passthrough_shader(pipe,
+ num_attribs,
+ semantic_names,
+ semantic_indexes);
+ NumCachedShaders++;
+
+ return CachedShaders[i].handle;
+}
+
+static void
+st_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z,
+ GLfloat width, GLfloat height)
+{
+ struct st_context *st = ctx->st;
+ struct pipe_context *pipe = st->pipe;
+ struct cso_context *cso = ctx->st->cso_context;
+ struct pipe_resource *vbuffer;
+ struct pipe_transfer *vbuffer_transfer;
+ GLuint i, numTexCoords, numAttribs;
+ GLboolean emitColor;
+ uint semantic_names[2 + MAX_TEXTURE_UNITS];
+ uint semantic_indexes[2 + MAX_TEXTURE_UNITS];
+ struct pipe_vertex_element velements[2 + MAX_TEXTURE_UNITS];
+ GLbitfield inputs = VERT_BIT_POS;
+
+ st_validate_state(st);
+
+ /* determine if we need vertex color */
+ if (ctx->FragmentProgram._Current->Base.InputsRead & FRAG_BIT_COL0)
+ emitColor = GL_TRUE;
+ else
+ emitColor = GL_FALSE;
+
+ /* determine how many enabled sets of texcoords */
+ numTexCoords = 0;
+ for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
+ if (ctx->Texture.Unit[i]._ReallyEnabled & TEXTURE_2D_BIT) {
+ inputs |= VERT_BIT_TEX(i);
+ numTexCoords++;
+ }
+ }
+
+ /* total number of attributes per vertex */
+ numAttribs = 1 + emitColor + numTexCoords;
+
+
+ /* create the vertex buffer */
+ vbuffer = pipe_buffer_create(pipe->screen, PIPE_BIND_VERTEX_BUFFER,
+ PIPE_USAGE_STREAM,
+ numAttribs * 4 * 4 * sizeof(GLfloat));
+
+ /* load vertex buffer */
+ {
+#define SET_ATTRIB(VERT, ATTR, X, Y, Z, W) \
+ do { \
+ GLuint k = (((VERT) * numAttribs + (ATTR)) * 4); \
+ assert(k < 4 * 4 * numAttribs); \
+ vbuf[k + 0] = X; \
+ vbuf[k + 1] = Y; \
+ vbuf[k + 2] = Z; \
+ vbuf[k + 3] = W; \
+ } while (0)
+
+ const GLfloat x0 = x, y0 = y, x1 = x + width, y1 = y + height;
+ GLfloat *vbuf = (GLfloat *) pipe_buffer_map(pipe, vbuffer,
+ PIPE_TRANSFER_WRITE,
+ &vbuffer_transfer);
+ GLuint attr;
+
+ z = CLAMP(z, 0.0f, 1.0f);
+
+ /* positions (in clip coords) */
+ {
+ const struct gl_framebuffer *fb = st->ctx->DrawBuffer;
+ const GLfloat fb_width = (GLfloat)fb->Width;
+ const GLfloat fb_height = (GLfloat)fb->Height;
+
+ const GLfloat clip_x0 = (GLfloat)(x0 / fb_width * 2.0 - 1.0);
+ const GLfloat clip_y0 = (GLfloat)(y0 / fb_height * 2.0 - 1.0);
+ const GLfloat clip_x1 = (GLfloat)(x1 / fb_width * 2.0 - 1.0);
+ const GLfloat clip_y1 = (GLfloat)(y1 / fb_height * 2.0 - 1.0);
+
+ SET_ATTRIB(0, 0, clip_x0, clip_y0, z, 1.0f); /* lower left */
+ SET_ATTRIB(1, 0, clip_x1, clip_y0, z, 1.0f); /* lower right */
+ SET_ATTRIB(2, 0, clip_x1, clip_y1, z, 1.0f); /* upper right */
+ SET_ATTRIB(3, 0, clip_x0, clip_y1, z, 1.0f); /* upper left */
+
+ semantic_names[0] = TGSI_SEMANTIC_POSITION;
+ semantic_indexes[0] = 0;
+ }
+
+ /* colors */
+ if (emitColor) {
+ const GLfloat *c = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
+ SET_ATTRIB(0, 1, c[0], c[1], c[2], c[3]);
+ SET_ATTRIB(1, 1, c[0], c[1], c[2], c[3]);
+ SET_ATTRIB(2, 1, c[0], c[1], c[2], c[3]);
+ SET_ATTRIB(3, 1, c[0], c[1], c[2], c[3]);
+ semantic_names[1] = TGSI_SEMANTIC_COLOR;
+ semantic_indexes[1] = 0;
+ attr = 2;
+ }
+ else {
+ attr = 1;
+ }
+
+ /* texcoords */
+ for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
+ if (ctx->Texture.Unit[i]._ReallyEnabled & TEXTURE_2D_BIT) {
+ struct gl_texture_object *obj = ctx->Texture.Unit[i]._Current;
+ struct gl_texture_image *img = obj->Image[0][obj->BaseLevel];
+ const GLfloat wt = (GLfloat) img->Width;
+ const GLfloat ht = (GLfloat) img->Height;
+ const GLfloat s0 = obj->CropRect[0] / wt;
+ const GLfloat t0 = obj->CropRect[1] / ht;
+ const GLfloat s1 = (obj->CropRect[0] + obj->CropRect[2]) / wt;
+ const GLfloat t1 = (obj->CropRect[1] + obj->CropRect[3]) / ht;
+
+ /*printf("crop texcoords: %g, %g .. %g, %g\n", s0, t0, s1, t1);*/
+ SET_ATTRIB(0, attr, s0, t0, 0.0f, 1.0f); /* lower left */
+ SET_ATTRIB(1, attr, s1, t0, 0.0f, 1.0f); /* lower right */
+ SET_ATTRIB(2, attr, s1, t1, 0.0f, 1.0f); /* upper right */
+ SET_ATTRIB(3, attr, s0, t1, 0.0f, 1.0f); /* upper left */
+
+ semantic_names[attr] = TGSI_SEMANTIC_GENERIC;
+ semantic_indexes[attr] = 0;
+
+ attr++;
+ }
+ }
+
+ pipe_buffer_unmap(pipe, vbuffer_transfer);
+
+#undef SET_ATTRIB
+ }
+
+
+ cso_save_viewport(cso);
+ cso_save_vertex_shader(cso);
+ cso_save_vertex_elements(cso);
+ cso_save_vertex_buffers(cso);
+
+ {
+ void *vs = lookup_shader(pipe, numAttribs,
+ semantic_names, semantic_indexes);
+ cso_set_vertex_shader_handle(cso, vs);
+ }
+
+ for (i = 0; i < numAttribs; i++) {
+ velements[i].src_offset = i * 4 * sizeof(float);
+ velements[i].instance_divisor = 0;
+ velements[i].vertex_buffer_index = 0;
+ velements[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+ }
+ cso_set_vertex_elements(cso, numAttribs, velements);
+
+ /* viewport state: viewport matching window dims */
+ {
+ const struct gl_framebuffer *fb = st->ctx->DrawBuffer;
+ const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP);
+ const GLfloat width = (GLfloat)fb->Width;
+ const GLfloat height = (GLfloat)fb->Height;
+ struct pipe_viewport_state vp;
+ vp.scale[0] = 0.5f * width;
+ vp.scale[1] = height * (invert ? -0.5f : 0.5f);
+ vp.scale[2] = 1.0f;
+ vp.scale[3] = 1.0f;
+ vp.translate[0] = 0.5f * width;
+ vp.translate[1] = 0.5f * height;
+ vp.translate[2] = 0.0f;
+ vp.translate[3] = 0.0f;
+ cso_set_viewport(cso, &vp);
+ }
+
+
+ util_draw_vertex_buffer(pipe, cso, vbuffer,
+ 0, /* offset */
+ PIPE_PRIM_TRIANGLE_FAN,
+ 4, /* verts */
+ numAttribs); /* attribs/vert */
+
+
+ pipe_resource_reference(&vbuffer, NULL);
+
+ /* restore state */
+ cso_restore_viewport(cso);
+ cso_restore_vertex_shader(cso);
+ cso_restore_vertex_elements(cso);
+ cso_restore_vertex_buffers(cso);
+}
+
+
+void
+st_init_drawtex_functions(struct dd_function_table *functions)
+{
+ functions->DrawTex = st_DrawTex;
+}
+
+
+/**
+ * Free any cached shaders
+ */
+void
+st_destroy_drawtex(struct st_context *st)
+{
+ GLuint i;
+ for (i = 0; i < NumCachedShaders; i++) {
+ cso_delete_vertex_shader(st->cso_context, CachedShaders[i].handle);
+ }
+ NumCachedShaders = 0;
+}
+
+
+#endif /* FEATURE_OES_draw_texture */
diff --git a/mesalib/src/mesa/state_tracker/st_cb_texture.c b/mesalib/src/mesa/state_tracker/st_cb_texture.c
index a40a79bb8..708aa1290 100644
--- a/mesalib/src/mesa/state_tracker/st_cb_texture.c
+++ b/mesalib/src/mesa/state_tracker/st_cb_texture.c
@@ -1,1918 +1,1918 @@
-/**************************************************************************
- *
- * 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/mfeatures.h"
-#include "main/bufferobj.h"
-#include "main/enums.h"
-#include "main/fbobject.h"
-#include "main/formats.h"
-#include "main/image.h"
-#include "main/imports.h"
-#include "main/macros.h"
-#include "main/mipmap.h"
-#include "main/pack.h"
-#include "main/pixeltransfer.h"
-#include "main/texcompress.h"
-#include "main/texfetch.h"
-#include "main/texgetimage.h"
-#include "main/teximage.h"
-#include "main/texobj.h"
-#include "main/texstore.h"
-
-#include "state_tracker/st_debug.h"
-#include "state_tracker/st_context.h"
-#include "state_tracker/st_cb_fbo.h"
-#include "state_tracker/st_cb_flush.h"
-#include "state_tracker/st_cb_texture.h"
-#include "state_tracker/st_format.h"
-#include "state_tracker/st_texture.h"
-#include "state_tracker/st_gen_mipmap.h"
-#include "state_tracker/st_atom.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "util/u_inlines.h"
-#include "pipe/p_shader_tokens.h"
-#include "util/u_tile.h"
-#include "util/u_blit.h"
-#include "util/u_format.h"
-#include "util/u_surface.h"
-#include "util/u_sampler.h"
-#include "util/u_math.h"
-#include "util/u_box.h"
-
-#define DBG if (0) printf
-
-
-static enum pipe_texture_target
-gl_target_to_pipe(GLenum target)
-{
- switch (target) {
- case GL_TEXTURE_1D:
- return PIPE_TEXTURE_1D;
- case GL_TEXTURE_2D:
- return PIPE_TEXTURE_2D;
- case GL_TEXTURE_RECTANGLE_NV:
- return PIPE_TEXTURE_RECT;
- case GL_TEXTURE_3D:
- return PIPE_TEXTURE_3D;
- case GL_TEXTURE_CUBE_MAP_ARB:
- return PIPE_TEXTURE_CUBE;
- case GL_TEXTURE_1D_ARRAY_EXT:
- return PIPE_TEXTURE_1D_ARRAY;
- case GL_TEXTURE_2D_ARRAY_EXT:
- return PIPE_TEXTURE_2D_ARRAY;
- default:
- assert(0);
- return 0;
- }
-}
-
-
-/** called via ctx->Driver.NewTextureImage() */
-static struct gl_texture_image *
-st_NewTextureImage(struct gl_context * ctx)
-{
- DBG("%s\n", __FUNCTION__);
- (void) ctx;
- return (struct gl_texture_image *) ST_CALLOC_STRUCT(st_texture_image);
-}
-
-
-/** called via ctx->Driver.NewTextureObject() */
-static struct gl_texture_object *
-st_NewTextureObject(struct gl_context * ctx, GLuint name, GLenum target)
-{
- struct st_texture_object *obj = ST_CALLOC_STRUCT(st_texture_object);
-
- DBG("%s\n", __FUNCTION__);
- _mesa_initialize_texture_object(&obj->base, name, target);
-
- return &obj->base;
-}
-
-/** called via ctx->Driver.DeleteTextureObject() */
-static void
-st_DeleteTextureObject(struct gl_context *ctx,
- struct gl_texture_object *texObj)
-{
- struct st_context *st = st_context(ctx);
- struct st_texture_object *stObj = st_texture_object(texObj);
- if (stObj->pt)
- pipe_resource_reference(&stObj->pt, NULL);
- if (stObj->sampler_view) {
- if (stObj->sampler_view->context != st->pipe) {
- /* Take "ownership" of this texture sampler view by setting
- * its context pointer to this context. This avoids potential
- * crashes when the texture object is shared among contexts
- * and the original/owner context has already been destroyed.
- */
- stObj->sampler_view->context = st->pipe;
- }
- pipe_sampler_view_reference(&stObj->sampler_view, NULL);
- }
- _mesa_delete_texture_object(ctx, texObj);
-}
-
-
-/** called via ctx->Driver.FreeTexImageData() */
-static void
-st_FreeTextureImageData(struct gl_context * ctx, struct gl_texture_image *texImage)
-{
- struct st_texture_image *stImage = st_texture_image(texImage);
-
- DBG("%s\n", __FUNCTION__);
-
- if (stImage->pt) {
- pipe_resource_reference(&stImage->pt, NULL);
- }
-
- if (texImage->Data) {
- _mesa_align_free(texImage->Data);
- texImage->Data = NULL;
- }
-}
-
-
-/**
- * From linux kernel i386 header files, copes with odd sizes better
- * than COPY_DWORDS would:
- * XXX Put this in src/mesa/main/imports.h ???
- */
-#if defined(PIPE_CC_GCC) && defined(PIPE_ARCH_X86)
-static INLINE void *
-__memcpy(void *to, const void *from, size_t n)
-{
- int d0, d1, d2;
- __asm__ __volatile__("rep ; movsl\n\t"
- "testb $2,%b4\n\t"
- "je 1f\n\t"
- "movsw\n"
- "1:\ttestb $1,%b4\n\t"
- "je 2f\n\t"
- "movsb\n" "2:":"=&c"(d0), "=&D"(d1), "=&S"(d2)
- :"0"(n / 4), "q"(n), "1"((long) to), "2"((long) from)
- :"memory");
- return (to);
-}
-#else
-#define __memcpy(a,b,c) memcpy(a,b,c)
-#endif
-
-
-/**
- * The system memcpy (at least on ubuntu 5.10) has problems copying
- * to agp (writecombined) memory from a source which isn't 64-byte
- * aligned - there is a 4x performance falloff.
- *
- * The x86 __memcpy is immune to this but is slightly slower
- * (10%-ish) than the system memcpy.
- *
- * The sse_memcpy seems to have a slight cliff at 64/32 bytes, but
- * isn't much faster than x86_memcpy for agp copies.
- *
- * TODO: switch dynamically.
- */
-static void *
-do_memcpy(void *dest, const void *src, size_t n)
-{
- if ((((unsigned long) src) & 63) || (((unsigned long) dest) & 63)) {
- return __memcpy(dest, src, n);
- }
- else
- return memcpy(dest, src, n);
-}
-
-
-/**
- * Return default texture resource binding bitmask for the given format.
- */
-static GLuint
-default_bindings(struct st_context *st, enum pipe_format format)
-{
- struct pipe_screen *screen = st->pipe->screen;
- const unsigned target = PIPE_TEXTURE_2D;
- const unsigned geom = 0x0;
- unsigned bindings;
-
- if (util_format_is_depth_or_stencil(format))
- bindings = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_DEPTH_STENCIL;
- else
- bindings = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
-
- if (screen->is_format_supported(screen, format, target, 0, bindings, geom))
- return bindings;
- else
- return PIPE_BIND_SAMPLER_VIEW;
-}
-
-
-/** Return number of image dimensions (1, 2 or 3) for a texture target. */
-static GLuint
-get_texture_dims(GLenum target)
-{
- switch (target) {
- case GL_TEXTURE_1D:
- case GL_TEXTURE_1D_ARRAY_EXT:
- return 1;
- case GL_TEXTURE_2D:
- case GL_TEXTURE_CUBE_MAP_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
- case GL_TEXTURE_RECTANGLE_NV:
- case GL_TEXTURE_2D_ARRAY_EXT:
- return 2;
- case GL_TEXTURE_3D:
- return 3;
- default:
- assert(0 && "invalid texture target in get_texture_dims()");
- return 1;
- }
-}
-
-
-/**
- * Given the size of a mipmap image, try to compute the size of the level=0
- * mipmap image.
- *
- * Note that this isn't always accurate for odd-sized, non-POW textures.
- * For example, if level=1 and width=40 then the level=0 width may be 80 or 81.
- *
- * \return GL_TRUE for success, GL_FALSE for failure
- */
-static GLboolean
-guess_base_level_size(GLenum target,
- GLuint width, GLuint height, GLuint depth, GLuint level,
- GLuint *width0, GLuint *height0, GLuint *depth0)
-{
- const GLuint dims = get_texture_dims(target);
-
- assert(width >= 1);
- assert(height >= 1);
- assert(depth >= 1);
-
- if (level > 0) {
- /* Depending on the image's size, we can't always make a guess here */
- if ((dims >= 1 && width == 1) ||
- (dims >= 2 && height == 1) ||
- (dims >= 3 && depth == 1)) {
- /* we can't determine the image size at level=0 */
- return GL_FALSE;
- }
-
- /* grow the image size until we hit level = 0 */
- while (level > 0) {
- if (width > 1)
- width <<= 1;
- if (height > 1)
- height <<= 1;
- if (depth > 1)
- depth <<= 1;
- level--;
- }
- }
-
- *width0 = width;
- *height0 = height;
- *depth0 = depth;
-
- return GL_TRUE;
-}
-
-
-/**
- * Try to allocate a pipe_resource object for the given st_texture_object.
- *
- * We use the given st_texture_image as a clue to determine the size of the
- * mipmap image at level=0.
- *
- * \return GL_TRUE for success, GL_FALSE if out of memory.
- */
-static GLboolean
-guess_and_alloc_texture(struct st_context *st,
- struct st_texture_object *stObj,
- const struct st_texture_image *stImage)
-{
- GLuint lastLevel, width, height, depth;
- GLuint bindings;
- GLuint ptWidth, ptHeight, ptDepth, ptLayers;
- enum pipe_format fmt;
-
- DBG("%s\n", __FUNCTION__);
-
- assert(!stObj->pt);
-
- if (!guess_base_level_size(stObj->base.Target,
- stImage->base.Width2,
- stImage->base.Height2,
- stImage->base.Depth2,
- stImage->level,
- &width, &height, &depth)) {
- /* we can't determine the image size at level=0 */
- stObj->width0 = stObj->height0 = stObj->depth0 = 0;
- /* this is not an out of memory error */
- return GL_TRUE;
- }
-
- /* At this point, (width x height x depth) is the expected size of
- * the level=0 mipmap image.
- */
-
- /* Guess a reasonable value for lastLevel. With OpenGL we have no
- * idea how many mipmap levels will be in a texture until we start
- * to render with it. Make an educated guess here but be prepared
- * to re-allocating a texture buffer with space for more (or fewer)
- * mipmap levels later.
- */
- if ((stObj->base.MinFilter == GL_NEAREST ||
- stObj->base.MinFilter == GL_LINEAR ||
- stImage->base._BaseFormat == GL_DEPTH_COMPONENT ||
- stImage->base._BaseFormat == GL_DEPTH_STENCIL_EXT) &&
- !stObj->base.GenerateMipmap &&
- stImage->level == 0) {
- /* only alloc space for a single mipmap level */
- lastLevel = 0;
- }
- else {
- /* alloc space for a full mipmap */
- GLuint l2width = util_logbase2(width);
- GLuint l2height = util_logbase2(height);
- GLuint l2depth = util_logbase2(depth);
- lastLevel = MAX2(MAX2(l2width, l2height), l2depth);
- }
-
- /* Save the level=0 dimensions */
- stObj->width0 = width;
- stObj->height0 = height;
- stObj->depth0 = depth;
-
- fmt = st_mesa_format_to_pipe_format(stImage->base.TexFormat);
-
- bindings = default_bindings(st, fmt);
-
- st_gl_texture_dims_to_pipe_dims(stObj->base.Target,
- width, height, depth,
- &ptWidth, &ptHeight, &ptDepth, &ptLayers);
-
- stObj->pt = st_texture_create(st,
- gl_target_to_pipe(stObj->base.Target),
- fmt,
- lastLevel,
- ptWidth,
- ptHeight,
- ptDepth,
- ptLayers,
- bindings);
-
- DBG("%s returning %d\n", __FUNCTION__, (stObj->pt != NULL));
-
- return stObj->pt != NULL;
-}
-
-
-/**
- * Adjust pixel unpack params and image dimensions to strip off the
- * texture border.
- * Gallium doesn't support texture borders. They've seldem been used
- * and seldom been implemented correctly anyway.
- * \param unpackNew returns the new pixel unpack parameters
- */
-static void
-strip_texture_border(GLint border,
- GLint *width, GLint *height, GLint *depth,
- const struct gl_pixelstore_attrib *unpack,
- struct gl_pixelstore_attrib *unpackNew)
-{
- assert(border > 0); /* sanity check */
-
- *unpackNew = *unpack;
-
- if (unpackNew->RowLength == 0)
- unpackNew->RowLength = *width;
-
- if (depth && unpackNew->ImageHeight == 0)
- unpackNew->ImageHeight = *height;
-
- unpackNew->SkipPixels += border;
- if (height)
- unpackNew->SkipRows += border;
- if (depth)
- unpackNew->SkipImages += border;
-
- assert(*width >= 3);
- *width = *width - 2 * border;
- if (height && *height >= 3)
- *height = *height - 2 * border;
- if (depth && *depth >= 3)
- *depth = *depth - 2 * border;
-}
-
-
-/**
- * Do glTexImage1/2/3D().
- */
-static void
-st_TexImage(struct gl_context * ctx,
- GLint dims,
- GLenum target, GLint level,
- GLint internalFormat,
- GLint width, GLint height, GLint depth,
- GLint border,
- GLenum format, GLenum type, const void *pixels,
- const struct gl_pixelstore_attrib *unpack,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage,
- GLsizei imageSize, GLboolean compressed_src)
-{
- struct st_context *st = st_context(ctx);
- struct st_texture_object *stObj = st_texture_object(texObj);
- struct st_texture_image *stImage = st_texture_image(texImage);
- GLuint dstRowStride = 0;
- struct gl_pixelstore_attrib unpackNB;
- enum pipe_transfer_usage transfer_usage = 0;
-
- DBG("%s target %s level %d %dx%dx%d border %d\n", __FUNCTION__,
- _mesa_lookup_enum_by_nr(target), level, width, height, depth, border);
-
- /* switch to "normal" */
- if (stObj->surface_based) {
- gl_format texFormat;
-
- _mesa_clear_texture_object(ctx, texObj);
- pipe_resource_reference(&stObj->pt, NULL);
-
- /* oops, need to init this image again */
- texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
- internalFormat, format, type);
-
- _mesa_init_teximage_fields(ctx, target, texImage,
- width, height, depth, border,
- internalFormat, texFormat);
-
- stObj->surface_based = GL_FALSE;
- }
-
- /* gallium does not support texture borders, strip it off */
- if (border) {
- strip_texture_border(border, &width, &height, &depth, unpack, &unpackNB);
- unpack = &unpackNB;
- texImage->Width = width;
- texImage->Height = height;
- texImage->Depth = depth;
- texImage->Border = 0;
- border = 0;
- }
- else {
- assert(texImage->Width == width);
- assert(texImage->Height == height);
- assert(texImage->Depth == depth);
- }
-
- stImage->face = _mesa_tex_target_to_face(target);
- stImage->level = level;
-
- _mesa_set_fetch_functions(texImage, dims);
-
- /* Release the reference to a potentially orphaned buffer.
- * Release any old malloced memory.
- */
- if (stImage->pt) {
- pipe_resource_reference(&stImage->pt, NULL);
- assert(!texImage->Data);
- }
- else if (texImage->Data) {
- _mesa_align_free(texImage->Data);
- }
-
- /*
- * See if the new image is somehow incompatible with the existing
- * mipmap. If so, free the old mipmap.
- */
- if (stObj->pt) {
- if (level > (GLint) stObj->pt->last_level ||
- !st_texture_match_image(stObj->pt, &stImage->base,
- stImage->face, stImage->level)) {
- DBG("release it\n");
- pipe_resource_reference(&stObj->pt, NULL);
- assert(!stObj->pt);
- pipe_sampler_view_reference(&stObj->sampler_view, NULL);
- }
- }
-
- if (width == 0 || height == 0 || depth == 0) {
- /* stop after freeing old image */
- return;
- }
-
- if (!stObj->pt) {
- if (!guess_and_alloc_texture(st, stObj, stImage)) {
- /* Probably out of memory.
- * Try flushing any pending rendering, then retry.
- */
- st_finish(st);
- if (!guess_and_alloc_texture(st, stObj, stImage)) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
- return;
- }
- }
- }
-
- assert(!stImage->pt);
-
- /* Check if this texture image can live inside the texture object's buffer.
- * If so, store the image there. Otherwise the image will temporarily live
- * in its own buffer.
- */
- if (stObj->pt &&
- st_texture_match_image(stObj->pt, &stImage->base,
- stImage->face, stImage->level)) {
-
- pipe_resource_reference(&stImage->pt, stObj->pt);
- assert(stImage->pt);
- }
-
- if (!stImage->pt)
- DBG("XXX: Image did not fit into texture - storing in local memory!\n");
-
- /* Pixel data may come from regular user memory or a PBO. For the later,
- * do bounds checking and map the PBO to read pixels data from it.
- *
- * XXX we should try to use a GPU-accelerated path to copy the image data
- * from the PBO to the texture.
- */
- if (compressed_src) {
- pixels = _mesa_validate_pbo_compressed_teximage(ctx, imageSize, pixels,
- unpack,
- "glCompressedTexImage");
- }
- else {
- pixels = _mesa_validate_pbo_teximage(ctx, dims, width, height, 1,
- format, type,
- pixels, unpack, "glTexImage");
- }
-
- /*
- * Prepare to store the texture data. Either map the gallium texture buffer
- * memory or malloc space for it.
- */
- if (stImage->pt) {
- /* Store the image in the gallium texture memory buffer */
- if (format == GL_DEPTH_COMPONENT &&
- util_format_is_depth_and_stencil(stImage->pt->format))
- transfer_usage = PIPE_TRANSFER_READ_WRITE;
- else
- transfer_usage = PIPE_TRANSFER_WRITE;
-
- texImage->Data = st_texture_image_map(st, stImage, 0,
- transfer_usage, 0, 0, width, height);
- if(stImage->transfer)
- dstRowStride = stImage->transfer->stride;
- }
- else {
- /* Allocate regular memory and store the image there temporarily. */
- GLuint imageSize = _mesa_format_image_size(texImage->TexFormat,
- width, height, depth);
- dstRowStride = _mesa_format_row_stride(texImage->TexFormat, width);
-
- texImage->Data = _mesa_align_malloc(imageSize, 16);
- }
-
- if (!texImage->Data) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
- return;
- }
-
- if (!pixels) {
- /* We've allocated texture memory, but have no pixel data - all done. */
- goto done;
- }
-
- DBG("Upload image %dx%dx%d row_len %x pitch %x\n",
- width, height, depth, width, dstRowStride);
-
- /* Copy user texture image into the texture buffer.
- */
- if (compressed_src) {
- const GLuint srcRowStride =
- _mesa_format_row_stride(texImage->TexFormat, width);
- if (dstRowStride == srcRowStride) {
- memcpy(texImage->Data, pixels, imageSize);
- }
- else {
- char *dst = texImage->Data;
- const char *src = pixels;
- GLuint i, bw, bh, lines;
- _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
- lines = (height + bh - 1) / bh;
-
- for (i = 0; i < lines; ++i) {
- memcpy(dst, src, srcRowStride);
- dst += dstRowStride;
- src += srcRowStride;
- }
- }
- }
- else {
- const GLuint srcImageStride =
- _mesa_image_image_stride(unpack, width, height, format, type);
- GLint i;
- const GLubyte *src = (const GLubyte *) pixels;
-
- for (i = 0; i < depth; i++) {
- if (!_mesa_texstore(ctx, dims,
- texImage->_BaseFormat,
- texImage->TexFormat,
- texImage->Data,
- 0, 0, 0, /* dstX/Y/Zoffset */
- dstRowStride,
- texImage->ImageOffsets,
- width, height, 1,
- format, type, src, unpack)) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
- }
-
- if (stImage->pt && i + 1 < depth) {
- /* unmap this slice */
- st_texture_image_unmap(st, stImage);
- /* map next slice of 3D texture */
- texImage->Data = st_texture_image_map(st, stImage, i + 1,
- transfer_usage, 0, 0,
- width, height);
- src += srcImageStride;
- }
- }
- }
-
-done:
- _mesa_unmap_teximage_pbo(ctx, unpack);
-
- if (stImage->pt && texImage->Data) {
- st_texture_image_unmap(st, stImage);
- texImage->Data = NULL;
- }
-}
-
-
-static void
-st_TexImage3D(struct gl_context * ctx,
- GLenum target, GLint level,
- GLint internalFormat,
- GLint width, GLint height, GLint depth,
- GLint border,
- GLenum format, GLenum type, const void *pixels,
- const struct gl_pixelstore_attrib *unpack,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_TexImage(ctx, 3, target, level, internalFormat, width, height, depth,
- border, format, type, pixels, unpack, texObj, texImage,
- 0, GL_FALSE);
-}
-
-
-static void
-st_TexImage2D(struct gl_context * ctx,
- GLenum target, GLint level,
- GLint internalFormat,
- GLint width, GLint height, GLint border,
- GLenum format, GLenum type, const void *pixels,
- const struct gl_pixelstore_attrib *unpack,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_TexImage(ctx, 2, target, level, internalFormat, width, height, 1, border,
- format, type, pixels, unpack, texObj, texImage, 0, GL_FALSE);
-}
-
-
-static void
-st_TexImage1D(struct gl_context * ctx,
- GLenum target, GLint level,
- GLint internalFormat,
- GLint width, GLint border,
- GLenum format, GLenum type, const void *pixels,
- const struct gl_pixelstore_attrib *unpack,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_TexImage(ctx, 1, target, level, internalFormat, width, 1, 1, border,
- format, type, pixels, unpack, texObj, texImage, 0, GL_FALSE);
-}
-
-
-static void
-st_CompressedTexImage2D(struct gl_context *ctx, GLenum target, GLint level,
- GLint internalFormat,
- GLint width, GLint height, GLint border,
- GLsizei imageSize, const GLvoid *data,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_TexImage(ctx, 2, target, level, internalFormat, width, height, 1, border,
- 0, 0, data, &ctx->Unpack, texObj, texImage, imageSize, GL_TRUE);
-}
-
-
-
-/**
- * glGetTexImage() helper: decompress a compressed texture by rendering
- * a textured quad. Store the results in the user's buffer.
- */
-static void
-decompress_with_blit(struct gl_context * ctx, GLenum target, GLint level,
- GLenum format, GLenum type, GLvoid *pixels,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct st_texture_image *stImage = st_texture_image(texImage);
- struct st_texture_object *stObj = st_texture_object(texObj);
- struct pipe_sampler_view *src_view =
- st_get_texture_sampler_view(stObj, pipe);
- const GLuint width = texImage->Width;
- const GLuint height = texImage->Height;
- struct pipe_surface *dst_surface;
- struct pipe_resource *dst_texture;
- struct pipe_transfer *tex_xfer;
- unsigned bind = (PIPE_BIND_RENDER_TARGET | /* util_blit may choose to render */
- PIPE_BIND_TRANSFER_READ);
-
- /* create temp / dest surface */
- if (!util_create_rgba_surface(pipe, width, height, bind,
- &dst_texture, &dst_surface)) {
- _mesa_problem(ctx, "util_create_rgba_surface() failed "
- "in decompress_with_blit()");
- return;
- }
-
- /* blit/render/decompress */
- util_blit_pixels_tex(st->blit,
- src_view, /* pipe_resource (src) */
- 0, 0, /* src x0, y0 */
- width, height, /* src x1, y1 */
- dst_surface, /* pipe_surface (dst) */
- 0, 0, /* dst x0, y0 */
- width, height, /* dst x1, y1 */
- 0.0, /* z */
- PIPE_TEX_MIPFILTER_NEAREST);
-
- /* map the dst_surface so we can read from it */
- tex_xfer = pipe_get_transfer(st_context(ctx)->pipe,
- dst_texture, 0, 0,
- PIPE_TRANSFER_READ,
- 0, 0, width, height);
-
- pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels);
-
- /* copy/pack data into user buffer */
- if (st_equal_formats(stImage->pt->format, format, type)) {
- /* memcpy */
- const uint bytesPerRow = width * util_format_get_blocksize(stImage->pt->format);
- ubyte *map = pipe_transfer_map(pipe, tex_xfer);
- GLuint row;
- for (row = 0; row < height; row++) {
- GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width,
- height, format, type, row, 0);
- memcpy(dest, map, bytesPerRow);
- map += tex_xfer->stride;
- }
- pipe_transfer_unmap(pipe, tex_xfer);
- }
- else {
- /* format translation via floats */
- GLuint row;
- enum pipe_format format = util_format_linear(dst_texture->format);
- for (row = 0; row < height; row++) {
- const GLbitfield transferOps = 0x0; /* bypassed for glGetTexImage() */
- GLfloat rgba[4 * MAX_WIDTH];
- GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width,
- height, format, type, row, 0);
-
- if (ST_DEBUG & DEBUG_FALLBACK)
- debug_printf("%s: fallback format translation\n", __FUNCTION__);
-
- /* get float[4] rgba row from surface */
- pipe_get_tile_rgba_format(pipe, tex_xfer, 0, row, width, 1,
- format, rgba);
-
- _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format,
- type, dest, &ctx->Pack, transferOps);
- }
- }
-
- _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
-
- pipe->transfer_destroy(pipe, tex_xfer);
-
- /* destroy the temp / dest surface */
- util_destroy_rgba_surface(dst_texture, dst_surface);
-}
-
-
-
-/**
- * Need to map texture image into memory before copying image data,
- * then unmap it.
- */
-static void
-st_get_tex_image(struct gl_context * ctx, GLenum target, GLint level,
- GLenum format, GLenum type, GLvoid * pixels,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage, GLboolean compressed_dst)
-{
- struct st_context *st = st_context(ctx);
- struct st_texture_image *stImage = st_texture_image(texImage);
- const GLuint dstImageStride =
- _mesa_image_image_stride(&ctx->Pack, texImage->Width, texImage->Height,
- format, type);
- GLuint depth, i;
- GLubyte *dest;
-
- if (stImage->pt &&
- util_format_is_s3tc(stImage->pt->format) &&
- !compressed_dst) {
- /* Need to decompress the texture.
- * We'll do this by rendering a textured quad.
- * Note that we only expect RGBA formats (no Z/depth formats).
- */
- decompress_with_blit(ctx, target, level, format, type, pixels,
- texObj, texImage);
- return;
- }
-
- /* Map */
- if (stImage->pt) {
- /* Image is stored in hardware format in a buffer managed by the
- * kernel. Need to explicitly map and unmap it.
- */
- texImage->Data = st_texture_image_map(st, stImage, 0,
- PIPE_TRANSFER_READ, 0, 0,
- stImage->base.Width,
- stImage->base.Height);
- /* compute stride in texels from stride in bytes */
- texImage->RowStride = stImage->transfer->stride
- * util_format_get_blockwidth(stImage->pt->format)
- / util_format_get_blocksize(stImage->pt->format);
- }
- else {
- /* Otherwise, the image should actually be stored in
- * texImage->Data. This is pretty confusing for
- * everybody, I'd much prefer to separate the two functions of
- * texImage->Data - storage for texture images in main memory
- * and access (ie mappings) of images. In other words, we'd
- * create a new texImage->Map field and leave Data simply for
- * storage.
- */
- assert(texImage->Data);
- }
-
- depth = texImage->Depth;
- texImage->Depth = 1;
-
- dest = (GLubyte *) pixels;
-
- _mesa_set_fetch_functions(texImage, get_texture_dims(target));
-
- for (i = 0; i < depth; i++) {
- if (compressed_dst) {
- _mesa_get_compressed_teximage(ctx, target, level, dest,
- texObj, texImage);
- }
- else {
- _mesa_get_teximage(ctx, target, level, format, type, dest,
- texObj, texImage);
- }
-
- if (stImage->pt && i + 1 < depth) {
- /* unmap this slice */
- st_texture_image_unmap(st, stImage);
- /* map next slice of 3D texture */
- texImage->Data = st_texture_image_map(st, stImage, i + 1,
- PIPE_TRANSFER_READ, 0, 0,
- stImage->base.Width,
- stImage->base.Height);
- dest += dstImageStride;
- }
- }
-
- texImage->Depth = depth;
-
- /* Unmap */
- if (stImage->pt) {
- st_texture_image_unmap(st, stImage);
- texImage->Data = NULL;
- }
-}
-
-
-static void
-st_GetTexImage(struct gl_context * ctx, GLenum target, GLint level,
- GLenum format, GLenum type, GLvoid * pixels,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_get_tex_image(ctx, target, level, format, type, pixels, texObj, texImage,
- GL_FALSE);
-}
-
-
-static void
-st_GetCompressedTexImage(struct gl_context *ctx, GLenum target, GLint level,
- GLvoid *pixels,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_get_tex_image(ctx, target, level, 0, 0, pixels, texObj, texImage,
- GL_TRUE);
-}
-
-
-
-static void
-st_TexSubimage(struct gl_context *ctx, GLint dims, GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLint width, GLint height, GLint depth,
- GLenum format, GLenum type, const void *pixels,
- const struct gl_pixelstore_attrib *packing,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- struct st_context *st = st_context(ctx);
- struct st_texture_image *stImage = st_texture_image(texImage);
- GLuint dstRowStride;
- const GLuint srcImageStride =
- _mesa_image_image_stride(packing, width, height, format, type);
- GLint i;
- const GLubyte *src;
- /* init to silence warning only: */
- enum pipe_transfer_usage transfer_usage = PIPE_TRANSFER_WRITE;
-
- DBG("%s target %s level %d offset %d,%d %dx%d\n", __FUNCTION__,
- _mesa_lookup_enum_by_nr(target),
- level, xoffset, yoffset, width, height);
-
- pixels =
- _mesa_validate_pbo_teximage(ctx, dims, width, height, depth, format,
- type, pixels, packing, "glTexSubImage2D");
- if (!pixels)
- return;
-
- /* Map buffer if necessary. Need to lock to prevent other contexts
- * from uploading the buffer under us.
- */
- if (stImage->pt) {
- if (format == GL_DEPTH_COMPONENT &&
- util_format_is_depth_and_stencil(stImage->pt->format))
- transfer_usage = PIPE_TRANSFER_READ_WRITE;
- else
- transfer_usage = PIPE_TRANSFER_WRITE;
-
- texImage->Data = st_texture_image_map(st, stImage, zoffset,
- transfer_usage,
- xoffset, yoffset,
- width, height);
- }
-
- if (!texImage->Data) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage");
- goto done;
- }
-
- src = (const GLubyte *) pixels;
- dstRowStride = stImage->transfer->stride;
-
- for (i = 0; i < depth; i++) {
- if (!_mesa_texstore(ctx, dims, texImage->_BaseFormat,
- texImage->TexFormat,
- texImage->Data,
- 0, 0, 0,
- dstRowStride,
- texImage->ImageOffsets,
- width, height, 1,
- format, type, src, packing)) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage");
- }
-
- if (stImage->pt && i + 1 < depth) {
- /* unmap this slice */
- st_texture_image_unmap(st, stImage);
- /* map next slice of 3D texture */
- texImage->Data = st_texture_image_map(st, stImage,
- zoffset + i + 1,
- transfer_usage,
- xoffset, yoffset,
- width, height);
- src += srcImageStride;
- }
- }
-
-done:
- _mesa_unmap_teximage_pbo(ctx, packing);
-
- if (stImage->pt && texImage->Data) {
- st_texture_image_unmap(st, stImage);
- texImage->Data = NULL;
- }
-}
-
-
-
-static void
-st_TexSubImage3D(struct gl_context *ctx, GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum format, GLenum type, const GLvoid *pixels,
- const struct gl_pixelstore_attrib *packing,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_TexSubimage(ctx, 3, target, level, xoffset, yoffset, zoffset,
- width, height, depth, format, type,
- pixels, packing, texObj, texImage);
-}
-
-
-static void
-st_TexSubImage2D(struct gl_context *ctx, GLenum target, GLint level,
- GLint xoffset, GLint yoffset,
- GLsizei width, GLsizei height,
- GLenum format, GLenum type, const GLvoid * pixels,
- const struct gl_pixelstore_attrib *packing,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_TexSubimage(ctx, 2, target, level, xoffset, yoffset, 0,
- width, height, 1, format, type,
- pixels, packing, texObj, texImage);
-}
-
-
-static void
-st_TexSubImage1D(struct gl_context *ctx, GLenum target, GLint level,
- GLint xoffset, GLsizei width, GLenum format, GLenum type,
- const GLvoid * pixels,
- const struct gl_pixelstore_attrib *packing,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_TexSubimage(ctx, 1, target, level, xoffset, 0, 0, width, 1, 1,
- format, type, pixels, packing, texObj, texImage);
-}
-
-
-static void
-st_CompressedTexSubImage1D(struct gl_context *ctx, GLenum target, GLint level,
- GLint xoffset, GLsizei width,
- GLenum format,
- GLsizei imageSize, const GLvoid *data,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- assert(0);
-}
-
-
-static void
-st_CompressedTexSubImage2D(struct gl_context *ctx, GLenum target, GLint level,
- GLint xoffset, GLint yoffset,
- GLsizei width, GLint height,
- GLenum format,
- GLsizei imageSize, const GLvoid *data,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- struct st_context *st = st_context(ctx);
- struct st_texture_image *stImage = st_texture_image(texImage);
- int srcBlockStride;
- int dstBlockStride;
- int y;
- enum pipe_format pformat;
-
- if (stImage->pt) {
- pformat = stImage->pt->format;
-
- texImage->Data = st_texture_image_map(st, stImage, 0,
- PIPE_TRANSFER_WRITE,
- xoffset, yoffset,
- width, height);
-
- srcBlockStride = util_format_get_stride(pformat, width);
- dstBlockStride = stImage->transfer->stride;
- } else {
- assert(stImage->pt);
- /* TODO find good values for block and strides */
- /* TODO also adjust texImage->data for yoffset/xoffset */
- return;
- }
-
- if (!texImage->Data) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexSubImage");
- return;
- }
-
- assert(xoffset % util_format_get_blockwidth(pformat) == 0);
- assert(yoffset % util_format_get_blockheight(pformat) == 0);
-
- for (y = 0; y < height; y += util_format_get_blockheight(pformat)) {
- /* don't need to adjust for xoffset and yoffset as st_texture_image_map does that */
- const char *src = (const char*)data + srcBlockStride * util_format_get_nblocksy(pformat, y);
- char *dst = (char*)texImage->Data + dstBlockStride * util_format_get_nblocksy(pformat, y);
- memcpy(dst, src, util_format_get_stride(pformat, width));
- }
-
- if (stImage->pt) {
- st_texture_image_unmap(st, stImage);
- texImage->Data = NULL;
- }
-}
-
-
-static void
-st_CompressedTexSubImage3D(struct gl_context *ctx, GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLsizei width, GLint height, GLint depth,
- GLenum format,
- GLsizei imageSize, const GLvoid *data,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- assert(0);
-}
-
-
-
-/**
- * Do a CopyTexSubImage operation using a read transfer from the source,
- * a write transfer to the destination and get_tile()/put_tile() to access
- * the pixels/texels.
- *
- * Note: srcY=0=TOP of renderbuffer
- */
-static void
-fallback_copy_texsubimage(struct gl_context *ctx, GLenum target, GLint level,
- struct st_renderbuffer *strb,
- struct st_texture_image *stImage,
- GLenum baseFormat,
- GLint destX, GLint destY, GLint destZ,
- GLint srcX, GLint srcY,
- GLsizei width, GLsizei height)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct pipe_transfer *src_trans;
- GLvoid *texDest;
- enum pipe_transfer_usage transfer_usage;
-
- if (ST_DEBUG & DEBUG_FALLBACK)
- debug_printf("%s: fallback processing\n", __FUNCTION__);
-
- assert(width <= MAX_WIDTH);
-
- if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
- srcY = strb->Base.Height - srcY - height;
- }
-
- src_trans = pipe_get_transfer(st_context(ctx)->pipe,
- strb->texture,
- 0, 0,
- PIPE_TRANSFER_READ,
- srcX, srcY,
- width, height);
-
- if ((baseFormat == GL_DEPTH_COMPONENT ||
- baseFormat == GL_DEPTH_STENCIL) &&
- util_format_is_depth_and_stencil(stImage->pt->format))
- transfer_usage = PIPE_TRANSFER_READ_WRITE;
- else
- transfer_usage = PIPE_TRANSFER_WRITE;
-
- /* XXX this used to ignore destZ param */
- texDest = st_texture_image_map(st, stImage, destZ, transfer_usage,
- destX, destY, width, height);
-
- if (baseFormat == GL_DEPTH_COMPONENT ||
- baseFormat == GL_DEPTH_STENCIL) {
- const GLboolean scaleOrBias = (ctx->Pixel.DepthScale != 1.0F ||
- ctx->Pixel.DepthBias != 0.0F);
- GLint row, yStep;
-
- /* determine bottom-to-top vs. top-to-bottom order for src buffer */
- if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
- srcY = height - 1;
- yStep = -1;
- }
- else {
- srcY = 0;
- yStep = 1;
- }
-
- /* To avoid a large temp memory allocation, do copy row by row */
- for (row = 0; row < height; row++, srcY += yStep) {
- uint data[MAX_WIDTH];
- pipe_get_tile_z(pipe, src_trans, 0, srcY, width, 1, data);
- if (scaleOrBias) {
- _mesa_scale_and_bias_depth_uint(ctx, width, data);
- }
- pipe_put_tile_z(pipe, stImage->transfer, 0, row, width, 1, data);
- }
- }
- else {
- /* RGBA format */
- GLfloat *tempSrc =
- (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
-
- if (tempSrc && texDest) {
- const GLint dims = 2;
- const GLint dstRowStride = stImage->transfer->stride;
- struct gl_texture_image *texImage = &stImage->base;
- struct gl_pixelstore_attrib unpack = ctx->DefaultPacking;
-
- if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
- unpack.Invert = GL_TRUE;
- }
-
- /* get float/RGBA image from framebuffer */
- /* XXX this usually involves a lot of int/float conversion.
- * try to avoid that someday.
- */
- pipe_get_tile_rgba_format(pipe, src_trans, 0, 0, width, height,
- util_format_linear(strb->texture->format),
- tempSrc);
-
- /* Store into texture memory.
- * Note that this does some special things such as pixel transfer
- * ops and format conversion. In particular, if the dest tex format
- * is actually RGBA but the user created the texture as GL_RGB we
- * need to fill-in/override the alpha channel with 1.0.
- */
- _mesa_texstore(ctx, dims,
- texImage->_BaseFormat,
- texImage->TexFormat,
- texDest,
- 0, 0, 0,
- dstRowStride,
- texImage->ImageOffsets,
- width, height, 1,
- GL_RGBA, GL_FLOAT, tempSrc, /* src */
- &unpack);
- }
- else {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage");
- }
-
- if (tempSrc)
- free(tempSrc);
- }
-
- st_texture_image_unmap(st, stImage);
- pipe->transfer_destroy(pipe, src_trans);
-}
-
-
-
-/**
- * If the format of the src renderbuffer and the format of the dest
- * texture are compatible (in terms of blitting), return a TGSI writemask
- * to be used during the blit.
- * If the src/dest are incompatible, return 0.
- */
-static unsigned
-compatible_src_dst_formats(struct gl_context *ctx,
- const struct gl_renderbuffer *src,
- const struct gl_texture_image *dst)
-{
- /* Get logical base formats for the src and dest.
- * That is, use the user-requested formats and not the actual, device-
- * chosen formats.
- * For example, the user may have requested an A8 texture but the
- * driver may actually be using an RGBA texture format. When we
- * copy/blit to that texture, we only want to copy the Alpha channel
- * and not the RGB channels.
- *
- * Similarly, when the src FBO was created an RGB format may have been
- * requested but the driver actually chose an RGBA format. In that case,
- * we don't want to copy the undefined Alpha channel to the dest texture
- * (it should be 1.0).
- */
- const GLenum srcFormat = _mesa_base_fbo_format(ctx, src->InternalFormat);
- const GLenum dstFormat = _mesa_base_tex_format(ctx, dst->InternalFormat);
-
- /**
- * XXX when we have red-only and red/green renderbuffers we'll need
- * to add more cases here (or implement a general-purpose routine that
- * queries the existance of the R,G,B,A channels in the src and dest).
- */
- if (srcFormat == dstFormat) {
- /* This is the same as matching_base_formats, which should
- * always pass, as it did previously.
- */
- return TGSI_WRITEMASK_XYZW;
- }
- else if (srcFormat == GL_RGB && dstFormat == GL_RGBA) {
- /* Make sure that A in the dest is 1. The actual src format
- * may be RGBA and have undefined A values.
- */
- return TGSI_WRITEMASK_XYZ;
- }
- else if (srcFormat == GL_RGBA && dstFormat == GL_RGB) {
- /* Make sure that A in the dest is 1. The actual dst format
- * may be RGBA and will need A=1 to provide proper alpha values
- * when sampled later.
- */
- return TGSI_WRITEMASK_XYZ;
- }
- else {
- if (ST_DEBUG & DEBUG_FALLBACK)
- debug_printf("%s failed for src %s, dst %s\n",
- __FUNCTION__,
- _mesa_lookup_enum_by_nr(srcFormat),
- _mesa_lookup_enum_by_nr(dstFormat));
-
- /* Otherwise fail.
- */
- return 0;
- }
-}
-
-
-
-/**
- * Do a CopyTex[Sub]Image1/2/3D() using a hardware (blit) path if possible.
- * Note that the region to copy has already been clipped so we know we
- * won't read from outside the source renderbuffer's bounds.
- *
- * Note: srcY=0=Bottom of renderbuffer (GL convention)
- */
-static void
-st_copy_texsubimage(struct gl_context *ctx,
- GLenum target, GLint level,
- GLint destX, GLint destY, GLint destZ,
- GLint srcX, GLint srcY,
- GLsizei width, GLsizei height)
-{
- struct gl_texture_unit *texUnit =
- &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
- struct gl_texture_object *texObj =
- _mesa_select_tex_object(ctx, texUnit, target);
- struct gl_texture_image *texImage =
- _mesa_select_tex_image(ctx, texObj, target, level);
- struct st_texture_image *stImage = st_texture_image(texImage);
- const GLenum texBaseFormat = texImage->_BaseFormat;
- struct gl_framebuffer *fb = ctx->ReadBuffer;
- struct st_renderbuffer *strb;
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct pipe_screen *screen = pipe->screen;
- enum pipe_format dest_format, src_format;
- GLboolean use_fallback = GL_TRUE;
- GLboolean matching_base_formats;
- GLuint format_writemask, sample_count;
- struct pipe_surface *dest_surface = NULL;
- GLboolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP);
-
- /* make sure finalize_textures has been called?
- */
- if (0) st_validate_state(st);
-
- /* determine if copying depth or color data */
- if (texBaseFormat == GL_DEPTH_COMPONENT ||
- texBaseFormat == GL_DEPTH_STENCIL) {
- strb = st_renderbuffer(fb->_DepthBuffer);
- if (strb->Base.Wrapped) {
- strb = st_renderbuffer(strb->Base.Wrapped);
- }
- }
- else {
- /* texBaseFormat == GL_RGB, GL_RGBA, GL_ALPHA, etc */
- strb = st_renderbuffer(fb->_ColorReadBuffer);
- }
-
- if (!strb || !strb->surface || !stImage->pt) {
- debug_printf("%s: null strb or stImage\n", __FUNCTION__);
- return;
- }
-
- sample_count = strb->surface->texture->nr_samples;
- /* I believe this would be legal, presumably would need to do a resolve
- for color, and for depth/stencil spec says to just use one of the
- depth/stencil samples per pixel? Need some transfer clarifications. */
- assert(sample_count < 2);
-
- if (srcX < 0) {
- width -= -srcX;
- destX += -srcX;
- srcX = 0;
- }
-
- if (srcY < 0) {
- height -= -srcY;
- destY += -srcY;
- srcY = 0;
- }
-
- if (destX < 0) {
- width -= -destX;
- srcX += -destX;
- destX = 0;
- }
-
- if (destY < 0) {
- height -= -destY;
- srcY += -destY;
- destY = 0;
- }
-
- if (width < 0 || height < 0)
- return;
-
-
- assert(strb);
- assert(strb->surface);
- assert(stImage->pt);
-
- src_format = strb->surface->format;
- dest_format = stImage->pt->format;
-
- /*
- * Determine if the src framebuffer and dest texture have the same
- * base format. We need this to detect a case such as the framebuffer
- * being GL_RGBA but the texture being GL_RGB. If the actual hardware
- * texture format stores RGBA we need to set A=1 (overriding the
- * framebuffer's alpha values). We can't do that with the blit or
- * textured-quad paths.
- */
- matching_base_formats =
- (_mesa_get_format_base_format(strb->Base.Format) ==
- _mesa_get_format_base_format(texImage->TexFormat));
- format_writemask = compatible_src_dst_formats(ctx, &strb->Base, texImage);
-
- if (ctx->_ImageTransferState == 0x0) {
-
- if (matching_base_formats &&
- src_format == dest_format &&
- !do_flip)
- {
- /* use surface_copy() / blit */
- struct pipe_box src_box;
- u_box_2d_zslice(srcX, srcY, strb->surface->u.tex.first_layer,
- width, height, &src_box);
-
- /* for resource_copy_region(), y=0=top, always */
- pipe->resource_copy_region(pipe,
- /* dest */
- stImage->pt,
- stImage->level,
- destX, destY, destZ + stImage->face,
- /* src */
- strb->texture,
- strb->surface->u.tex.level,
- &src_box);
- use_fallback = GL_FALSE;
- }
- else if (format_writemask &&
- texBaseFormat != GL_DEPTH_COMPONENT &&
- texBaseFormat != GL_DEPTH_STENCIL &&
- screen->is_format_supported(screen, src_format,
- PIPE_TEXTURE_2D, sample_count,
- PIPE_BIND_SAMPLER_VIEW,
- 0) &&
- screen->is_format_supported(screen, dest_format,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_RENDER_TARGET,
- 0)) {
- /* draw textured quad to do the copy */
- GLint srcY0, srcY1;
- struct pipe_surface surf_tmpl;
- memset(&surf_tmpl, 0, sizeof(surf_tmpl));
- surf_tmpl.format = stImage->pt->format;
- surf_tmpl.usage = PIPE_BIND_RENDER_TARGET;
- surf_tmpl.u.tex.level = stImage->level;
- surf_tmpl.u.tex.first_layer = stImage->face + destZ;
- surf_tmpl.u.tex.last_layer = stImage->face + destZ;
-
- dest_surface = pipe->create_surface(pipe, stImage->pt,
- &surf_tmpl);
-
- if (do_flip) {
- srcY1 = strb->Base.Height - srcY - height;
- srcY0 = srcY1 + height;
- }
- else {
- srcY0 = srcY;
- srcY1 = srcY0 + height;
- }
-
- util_blit_pixels_writemask(st->blit,
- strb->texture,
- strb->surface->u.tex.level,
- srcX, srcY0,
- srcX + width, srcY1,
- strb->surface->u.tex.first_layer,
- dest_surface,
- destX, destY,
- destX + width, destY + height,
- 0.0, PIPE_TEX_MIPFILTER_NEAREST,
- format_writemask);
- use_fallback = GL_FALSE;
- }
-
- if (dest_surface)
- pipe_surface_reference(&dest_surface, NULL);
- }
-
- if (use_fallback) {
- /* software fallback */
- fallback_copy_texsubimage(ctx, target, level,
- strb, stImage, texBaseFormat,
- destX, destY, destZ,
- srcX, srcY, width, height);
- }
-}
-
-
-
-static void
-st_CopyTexImage1D(struct gl_context * ctx, GLenum target, GLint level,
- GLenum internalFormat,
- GLint x, GLint y, GLsizei width, GLint border)
-{
- struct gl_texture_unit *texUnit =
- &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
- struct gl_texture_object *texObj =
- _mesa_select_tex_object(ctx, texUnit, target);
- struct gl_texture_image *texImage =
- _mesa_select_tex_image(ctx, texObj, target, level);
-
- /* Setup or redefine the texture object, texture and texture
- * image. Don't populate yet.
- */
- ctx->Driver.TexImage1D(ctx, target, level, internalFormat,
- width, border,
- GL_RGBA, CHAN_TYPE, NULL,
- &ctx->DefaultPacking, texObj, texImage);
-
- st_copy_texsubimage(ctx, target, level,
- 0, 0, 0, /* destX,Y,Z */
- x, y, width, 1); /* src X, Y, size */
-}
-
-
-static void
-st_CopyTexImage2D(struct gl_context * ctx, GLenum target, GLint level,
- GLenum internalFormat,
- GLint x, GLint y, GLsizei width, GLsizei height,
- GLint border)
-{
- struct gl_texture_unit *texUnit =
- &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
- struct gl_texture_object *texObj =
- _mesa_select_tex_object(ctx, texUnit, target);
- struct gl_texture_image *texImage =
- _mesa_select_tex_image(ctx, texObj, target, level);
-
- /* Setup or redefine the texture object, texture and texture
- * image. Don't populate yet.
- */
- ctx->Driver.TexImage2D(ctx, target, level, internalFormat,
- width, height, border,
- GL_RGBA, CHAN_TYPE, NULL,
- &ctx->DefaultPacking, texObj, texImage);
-
- st_copy_texsubimage(ctx, target, level,
- 0, 0, 0, /* destX,Y,Z */
- x, y, width, height); /* src X, Y, size */
-}
-
-
-static void
-st_CopyTexSubImage1D(struct gl_context * ctx, GLenum target, GLint level,
- GLint xoffset, GLint x, GLint y, GLsizei width)
-{
- const GLint yoffset = 0, zoffset = 0;
- const GLsizei height = 1;
- st_copy_texsubimage(ctx, target, level,
- xoffset, yoffset, zoffset, /* destX,Y,Z */
- x, y, width, height); /* src X, Y, size */
-}
-
-
-static void
-st_CopyTexSubImage2D(struct gl_context * ctx, GLenum target, GLint level,
- GLint xoffset, GLint yoffset,
- GLint x, GLint y, GLsizei width, GLsizei height)
-{
- const GLint zoffset = 0;
- st_copy_texsubimage(ctx, target, level,
- xoffset, yoffset, zoffset, /* destX,Y,Z */
- x, y, width, height); /* src X, Y, size */
-}
-
-
-static void
-st_CopyTexSubImage3D(struct gl_context * ctx, GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLint x, GLint y, GLsizei width, GLsizei height)
-{
- st_copy_texsubimage(ctx, target, level,
- xoffset, yoffset, zoffset, /* destX,Y,Z */
- x, y, width, height); /* src X, Y, size */
-}
-
-
-/**
- * Copy image data from stImage into the texture object 'stObj' at level
- * 'dstLevel'.
- */
-static void
-copy_image_data_to_texture(struct st_context *st,
- struct st_texture_object *stObj,
- GLuint dstLevel,
- struct st_texture_image *stImage)
-{
- /* debug checks */
- {
- const struct gl_texture_image *dstImage =
- stObj->base.Image[stImage->face][stImage->level];
- assert(dstImage);
- assert(dstImage->Width == stImage->base.Width);
- assert(dstImage->Height == stImage->base.Height);
- assert(dstImage->Depth == stImage->base.Depth);
- }
-
- if (stImage->pt) {
- /* Copy potentially with the blitter:
- */
- st_texture_image_copy(st->pipe,
- stObj->pt, dstLevel, /* dest texture, level */
- stImage->pt, stImage->level, /* src texture, level */
- stImage->face);
-
- pipe_resource_reference(&stImage->pt, NULL);
- }
- else if (stImage->base.Data) {
- st_texture_image_data(st,
- stObj->pt,
- stImage->face,
- dstLevel,
- stImage->base.Data,
- stImage->base.RowStride *
- util_format_get_blocksize(stObj->pt->format),
- stImage->base.RowStride *
- stImage->base.Height *
- util_format_get_blocksize(stObj->pt->format));
- _mesa_align_free(stImage->base.Data);
- stImage->base.Data = NULL;
- }
-
- pipe_resource_reference(&stImage->pt, stObj->pt);
-}
-
-
-/**
- * Called during state validation. When this function is finished,
- * the texture object should be ready for rendering.
- * \return GL_TRUE for success, GL_FALSE for failure (out of mem)
- */
-GLboolean
-st_finalize_texture(struct gl_context *ctx,
- struct pipe_context *pipe,
- struct gl_texture_object *tObj)
-{
- struct st_context *st = st_context(ctx);
- struct st_texture_object *stObj = st_texture_object(tObj);
- const GLuint nr_faces = (stObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
- GLuint face;
- struct st_texture_image *firstImage;
- enum pipe_format firstImageFormat;
- GLuint ptWidth, ptHeight, ptDepth, ptLayers;
-
- if (stObj->base._Complete) {
- /* The texture is complete and we know exactly how many mipmap levels
- * are present/needed. This is conditional because we may be called
- * from the st_generate_mipmap() function when the texture object is
- * incomplete. In that case, we'll have set stObj->lastLevel before
- * we get here.
- */
- if (stObj->base.MinFilter == GL_LINEAR ||
- stObj->base.MinFilter == GL_NEAREST)
- stObj->lastLevel = stObj->base.BaseLevel;
- else
- stObj->lastLevel = stObj->base._MaxLevel;
- }
-
- firstImage = st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]);
- assert(firstImage);
-
- /* If both firstImage and stObj point to a texture which can contain
- * all active images, favour firstImage. Note that because of the
- * completeness requirement, we know that the image dimensions
- * will match.
- */
- if (firstImage->pt &&
- firstImage->pt != stObj->pt &&
- (!stObj->pt || firstImage->pt->last_level >= stObj->pt->last_level)) {
- pipe_resource_reference(&stObj->pt, firstImage->pt);
- pipe_sampler_view_reference(&stObj->sampler_view, NULL);
- }
-
- /* Find gallium format for the Mesa texture */
- firstImageFormat = st_mesa_format_to_pipe_format(firstImage->base.TexFormat);
-
- /* Find size of level=0 Gallium mipmap image, plus number of texture layers */
- {
- GLuint width, height, depth;
- if (!guess_base_level_size(stObj->base.Target,
- firstImage->base.Width2,
- firstImage->base.Height2,
- firstImage->base.Depth2,
- stObj->base.BaseLevel,
- &width, &height, &depth)) {
- width = stObj->width0;
- height = stObj->height0;
- depth = stObj->depth0;
- }
- /* convert GL dims to Gallium dims */
- st_gl_texture_dims_to_pipe_dims(stObj->base.Target, width, height, depth,
- &ptWidth, &ptHeight, &ptDepth, &ptLayers);
- }
-
- /* If we already have a gallium texture, check that it matches the texture
- * object's format, target, size, num_levels, etc.
- */
- if (stObj->pt) {
- if (stObj->pt->target != gl_target_to_pipe(stObj->base.Target) ||
- !st_sampler_compat_formats(stObj->pt->format, firstImageFormat) ||
- stObj->pt->last_level < stObj->lastLevel ||
- stObj->pt->width0 != ptWidth ||
- stObj->pt->height0 != ptHeight ||
- stObj->pt->depth0 != ptDepth ||
- stObj->pt->array_size != ptLayers)
- {
- /* The gallium texture does not match the Mesa texture so delete the
- * gallium texture now. We'll make a new one below.
- */
- pipe_resource_reference(&stObj->pt, NULL);
- pipe_sampler_view_reference(&stObj->sampler_view, NULL);
- st->dirty.st |= ST_NEW_FRAMEBUFFER;
- }
- }
-
- /* May need to create a new gallium texture:
- */
- if (!stObj->pt) {
- GLuint bindings = default_bindings(st, firstImageFormat);
-
- stObj->pt = st_texture_create(st,
- gl_target_to_pipe(stObj->base.Target),
- firstImageFormat,
- stObj->lastLevel,
- ptWidth,
- ptHeight,
- ptDepth,
- ptLayers,
- bindings);
-
- if (!stObj->pt) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
- return GL_FALSE;
- }
- }
-
- /* Pull in any images not in the object's texture:
- */
- for (face = 0; face < nr_faces; face++) {
- GLuint level;
- for (level = stObj->base.BaseLevel; level <= stObj->lastLevel; level++) {
- struct st_texture_image *stImage =
- st_texture_image(stObj->base.Image[face][level]);
-
- /* Need to import images in main memory or held in other textures.
- */
- if (stImage && stObj->pt != stImage->pt) {
- copy_image_data_to_texture(st, stObj, level, stImage);
- }
- }
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Returns pointer to a default/dummy texture.
- * This is typically used when the current shader has tex/sample instructions
- * but the user has not provided a (any) texture(s).
- */
-struct gl_texture_object *
-st_get_default_texture(struct st_context *st)
-{
- if (!st->default_texture) {
- static const GLenum target = GL_TEXTURE_2D;
- GLubyte pixels[16][16][4];
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImg;
- GLuint i, j;
-
- /* The ARB_fragment_program spec says (0,0,0,1) should be returned
- * when attempting to sample incomplete textures.
- */
- for (i = 0; i < 16; i++) {
- for (j = 0; j < 16; j++) {
- pixels[i][j][0] = 0;
- pixels[i][j][1] = 0;
- pixels[i][j][2] = 0;
- pixels[i][j][3] = 255;
- }
- }
-
- texObj = st->ctx->Driver.NewTextureObject(st->ctx, 0, target);
-
- texImg = _mesa_get_tex_image(st->ctx, texObj, target, 0);
-
- _mesa_init_teximage_fields(st->ctx, target, texImg,
- 16, 16, 1, 0, /* w, h, d, border */
- GL_RGBA, MESA_FORMAT_RGBA8888);
-
- st_TexImage(st->ctx, 2, target,
- 0, GL_RGBA, /* level, intformat */
- 16, 16, 1, 0, /* w, h, d, border */
- GL_RGBA, GL_UNSIGNED_BYTE, pixels,
- &st->ctx->DefaultPacking,
- texObj, texImg,
- 0, 0);
-
- texObj->MinFilter = GL_NEAREST;
- texObj->MagFilter = GL_NEAREST;
- texObj->_Complete = GL_TRUE;
-
- st->default_texture = texObj;
- }
- return st->default_texture;
-}
-
-
-void
-st_init_texture_functions(struct dd_function_table *functions)
-{
- functions->ChooseTextureFormat = st_ChooseTextureFormat;
- functions->TexImage1D = st_TexImage1D;
- functions->TexImage2D = st_TexImage2D;
- functions->TexImage3D = st_TexImage3D;
- functions->TexSubImage1D = st_TexSubImage1D;
- functions->TexSubImage2D = st_TexSubImage2D;
- functions->TexSubImage3D = st_TexSubImage3D;
- functions->CompressedTexSubImage1D = st_CompressedTexSubImage1D;
- functions->CompressedTexSubImage2D = st_CompressedTexSubImage2D;
- functions->CompressedTexSubImage3D = st_CompressedTexSubImage3D;
- functions->CopyTexImage1D = st_CopyTexImage1D;
- functions->CopyTexImage2D = st_CopyTexImage2D;
- functions->CopyTexSubImage1D = st_CopyTexSubImage1D;
- functions->CopyTexSubImage2D = st_CopyTexSubImage2D;
- functions->CopyTexSubImage3D = st_CopyTexSubImage3D;
- functions->GenerateMipmap = st_generate_mipmap;
-
- functions->GetTexImage = st_GetTexImage;
-
- /* compressed texture functions */
- functions->CompressedTexImage2D = st_CompressedTexImage2D;
- functions->GetCompressedTexImage = st_GetCompressedTexImage;
-
- functions->NewTextureObject = st_NewTextureObject;
- functions->NewTextureImage = st_NewTextureImage;
- functions->DeleteTexture = st_DeleteTextureObject;
- functions->FreeTexImageData = st_FreeTextureImageData;
-
- functions->TextureMemCpy = do_memcpy;
-
- /* XXX Temporary until we can query pipe's texture sizes */
- functions->TestProxyTexImage = _mesa_test_proxy_teximage;
-}
+/**************************************************************************
+ *
+ * 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/mfeatures.h"
+#include "main/bufferobj.h"
+#include "main/enums.h"
+#include "main/fbobject.h"
+#include "main/formats.h"
+#include "main/image.h"
+#include "main/imports.h"
+#include "main/macros.h"
+#include "main/mipmap.h"
+#include "main/pack.h"
+#include "main/pixeltransfer.h"
+#include "main/texcompress.h"
+#include "main/texfetch.h"
+#include "main/texgetimage.h"
+#include "main/teximage.h"
+#include "main/texobj.h"
+#include "main/texstore.h"
+
+#include "state_tracker/st_debug.h"
+#include "state_tracker/st_context.h"
+#include "state_tracker/st_cb_fbo.h"
+#include "state_tracker/st_cb_flush.h"
+#include "state_tracker/st_cb_texture.h"
+#include "state_tracker/st_format.h"
+#include "state_tracker/st_texture.h"
+#include "state_tracker/st_gen_mipmap.h"
+#include "state_tracker/st_atom.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_defines.h"
+#include "util/u_inlines.h"
+#include "pipe/p_shader_tokens.h"
+#include "util/u_tile.h"
+#include "util/u_blit.h"
+#include "util/u_format.h"
+#include "util/u_surface.h"
+#include "util/u_sampler.h"
+#include "util/u_math.h"
+#include "util/u_box.h"
+
+#define DBG if (0) printf
+
+
+static enum pipe_texture_target
+gl_target_to_pipe(GLenum target)
+{
+ switch (target) {
+ case GL_TEXTURE_1D:
+ return PIPE_TEXTURE_1D;
+ case GL_TEXTURE_2D:
+ return PIPE_TEXTURE_2D;
+ case GL_TEXTURE_RECTANGLE_NV:
+ return PIPE_TEXTURE_RECT;
+ case GL_TEXTURE_3D:
+ return PIPE_TEXTURE_3D;
+ case GL_TEXTURE_CUBE_MAP_ARB:
+ return PIPE_TEXTURE_CUBE;
+ case GL_TEXTURE_1D_ARRAY_EXT:
+ return PIPE_TEXTURE_1D_ARRAY;
+ case GL_TEXTURE_2D_ARRAY_EXT:
+ return PIPE_TEXTURE_2D_ARRAY;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+
+/** called via ctx->Driver.NewTextureImage() */
+static struct gl_texture_image *
+st_NewTextureImage(struct gl_context * ctx)
+{
+ DBG("%s\n", __FUNCTION__);
+ (void) ctx;
+ return (struct gl_texture_image *) ST_CALLOC_STRUCT(st_texture_image);
+}
+
+
+/** called via ctx->Driver.NewTextureObject() */
+static struct gl_texture_object *
+st_NewTextureObject(struct gl_context * ctx, GLuint name, GLenum target)
+{
+ struct st_texture_object *obj = ST_CALLOC_STRUCT(st_texture_object);
+
+ DBG("%s\n", __FUNCTION__);
+ _mesa_initialize_texture_object(&obj->base, name, target);
+
+ return &obj->base;
+}
+
+/** called via ctx->Driver.DeleteTextureObject() */
+static void
+st_DeleteTextureObject(struct gl_context *ctx,
+ struct gl_texture_object *texObj)
+{
+ struct st_context *st = st_context(ctx);
+ struct st_texture_object *stObj = st_texture_object(texObj);
+ if (stObj->pt)
+ pipe_resource_reference(&stObj->pt, NULL);
+ if (stObj->sampler_view) {
+ if (stObj->sampler_view->context != st->pipe) {
+ /* Take "ownership" of this texture sampler view by setting
+ * its context pointer to this context. This avoids potential
+ * crashes when the texture object is shared among contexts
+ * and the original/owner context has already been destroyed.
+ */
+ stObj->sampler_view->context = st->pipe;
+ }
+ pipe_sampler_view_reference(&stObj->sampler_view, NULL);
+ }
+ _mesa_delete_texture_object(ctx, texObj);
+}
+
+
+/** called via ctx->Driver.FreeTexImageData() */
+static void
+st_FreeTextureImageData(struct gl_context * ctx, struct gl_texture_image *texImage)
+{
+ struct st_texture_image *stImage = st_texture_image(texImage);
+
+ DBG("%s\n", __FUNCTION__);
+
+ if (stImage->pt) {
+ pipe_resource_reference(&stImage->pt, NULL);
+ }
+
+ if (texImage->Data) {
+ _mesa_align_free(texImage->Data);
+ texImage->Data = NULL;
+ }
+}
+
+
+/**
+ * From linux kernel i386 header files, copes with odd sizes better
+ * than COPY_DWORDS would:
+ * XXX Put this in src/mesa/main/imports.h ???
+ */
+#if defined(PIPE_CC_GCC) && defined(PIPE_ARCH_X86)
+static INLINE void *
+__memcpy(void *to, const void *from, size_t n)
+{
+ int d0, d1, d2;
+ __asm__ __volatile__("rep ; movsl\n\t"
+ "testb $2,%b4\n\t"
+ "je 1f\n\t"
+ "movsw\n"
+ "1:\ttestb $1,%b4\n\t"
+ "je 2f\n\t"
+ "movsb\n" "2:":"=&c"(d0), "=&D"(d1), "=&S"(d2)
+ :"0"(n / 4), "q"(n), "1"((long) to), "2"((long) from)
+ :"memory");
+ return (to);
+}
+#else
+#define __memcpy(a,b,c) memcpy(a,b,c)
+#endif
+
+
+/**
+ * The system memcpy (at least on ubuntu 5.10) has problems copying
+ * to agp (writecombined) memory from a source which isn't 64-byte
+ * aligned - there is a 4x performance falloff.
+ *
+ * The x86 __memcpy is immune to this but is slightly slower
+ * (10%-ish) than the system memcpy.
+ *
+ * The sse_memcpy seems to have a slight cliff at 64/32 bytes, but
+ * isn't much faster than x86_memcpy for agp copies.
+ *
+ * TODO: switch dynamically.
+ */
+static void *
+do_memcpy(void *dest, const void *src, size_t n)
+{
+ if ((((unsigned long) src) & 63) || (((unsigned long) dest) & 63)) {
+ return __memcpy(dest, src, n);
+ }
+ else
+ return memcpy(dest, src, n);
+}
+
+
+/**
+ * Return default texture resource binding bitmask for the given format.
+ */
+static GLuint
+default_bindings(struct st_context *st, enum pipe_format format)
+{
+ struct pipe_screen *screen = st->pipe->screen;
+ const unsigned target = PIPE_TEXTURE_2D;
+ const unsigned geom = 0x0;
+ unsigned bindings;
+
+ if (util_format_is_depth_or_stencil(format))
+ bindings = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_DEPTH_STENCIL;
+ else
+ bindings = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
+
+ if (screen->is_format_supported(screen, format, target, 0, bindings, geom))
+ return bindings;
+ else
+ return PIPE_BIND_SAMPLER_VIEW;
+}
+
+
+/** Return number of image dimensions (1, 2 or 3) for a texture target. */
+static GLuint
+get_texture_dims(GLenum target)
+{
+ switch (target) {
+ case GL_TEXTURE_1D:
+ case GL_TEXTURE_1D_ARRAY_EXT:
+ return 1;
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_CUBE_MAP_ARB:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
+ case GL_TEXTURE_RECTANGLE_NV:
+ case GL_TEXTURE_2D_ARRAY_EXT:
+ return 2;
+ case GL_TEXTURE_3D:
+ return 3;
+ default:
+ assert(0 && "invalid texture target in get_texture_dims()");
+ return 1;
+ }
+}
+
+
+/**
+ * Given the size of a mipmap image, try to compute the size of the level=0
+ * mipmap image.
+ *
+ * Note that this isn't always accurate for odd-sized, non-POW textures.
+ * For example, if level=1 and width=40 then the level=0 width may be 80 or 81.
+ *
+ * \return GL_TRUE for success, GL_FALSE for failure
+ */
+static GLboolean
+guess_base_level_size(GLenum target,
+ GLuint width, GLuint height, GLuint depth, GLuint level,
+ GLuint *width0, GLuint *height0, GLuint *depth0)
+{
+ const GLuint dims = get_texture_dims(target);
+
+ assert(width >= 1);
+ assert(height >= 1);
+ assert(depth >= 1);
+
+ if (level > 0) {
+ /* Depending on the image's size, we can't always make a guess here */
+ if ((dims >= 1 && width == 1) ||
+ (dims >= 2 && height == 1) ||
+ (dims >= 3 && depth == 1)) {
+ /* we can't determine the image size at level=0 */
+ return GL_FALSE;
+ }
+
+ /* grow the image size until we hit level = 0 */
+ while (level > 0) {
+ if (width > 1)
+ width <<= 1;
+ if (height > 1)
+ height <<= 1;
+ if (depth > 1)
+ depth <<= 1;
+ level--;
+ }
+ }
+
+ *width0 = width;
+ *height0 = height;
+ *depth0 = depth;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Try to allocate a pipe_resource object for the given st_texture_object.
+ *
+ * We use the given st_texture_image as a clue to determine the size of the
+ * mipmap image at level=0.
+ *
+ * \return GL_TRUE for success, GL_FALSE if out of memory.
+ */
+static GLboolean
+guess_and_alloc_texture(struct st_context *st,
+ struct st_texture_object *stObj,
+ const struct st_texture_image *stImage)
+{
+ GLuint lastLevel, width, height, depth;
+ GLuint bindings;
+ GLuint ptWidth, ptHeight, ptDepth, ptLayers;
+ enum pipe_format fmt;
+
+ DBG("%s\n", __FUNCTION__);
+
+ assert(!stObj->pt);
+
+ if (!guess_base_level_size(stObj->base.Target,
+ stImage->base.Width2,
+ stImage->base.Height2,
+ stImage->base.Depth2,
+ stImage->level,
+ &width, &height, &depth)) {
+ /* we can't determine the image size at level=0 */
+ stObj->width0 = stObj->height0 = stObj->depth0 = 0;
+ /* this is not an out of memory error */
+ return GL_TRUE;
+ }
+
+ /* At this point, (width x height x depth) is the expected size of
+ * the level=0 mipmap image.
+ */
+
+ /* Guess a reasonable value for lastLevel. With OpenGL we have no
+ * idea how many mipmap levels will be in a texture until we start
+ * to render with it. Make an educated guess here but be prepared
+ * to re-allocating a texture buffer with space for more (or fewer)
+ * mipmap levels later.
+ */
+ if ((stObj->base.MinFilter == GL_NEAREST ||
+ stObj->base.MinFilter == GL_LINEAR ||
+ stImage->base._BaseFormat == GL_DEPTH_COMPONENT ||
+ stImage->base._BaseFormat == GL_DEPTH_STENCIL_EXT) &&
+ !stObj->base.GenerateMipmap &&
+ stImage->level == 0) {
+ /* only alloc space for a single mipmap level */
+ lastLevel = 0;
+ }
+ else {
+ /* alloc space for a full mipmap */
+ GLuint l2width = util_logbase2(width);
+ GLuint l2height = util_logbase2(height);
+ GLuint l2depth = util_logbase2(depth);
+ lastLevel = MAX2(MAX2(l2width, l2height), l2depth);
+ }
+
+ /* Save the level=0 dimensions */
+ stObj->width0 = width;
+ stObj->height0 = height;
+ stObj->depth0 = depth;
+
+ fmt = st_mesa_format_to_pipe_format(stImage->base.TexFormat);
+
+ bindings = default_bindings(st, fmt);
+
+ st_gl_texture_dims_to_pipe_dims(stObj->base.Target,
+ width, height, depth,
+ &ptWidth, &ptHeight, &ptDepth, &ptLayers);
+
+ stObj->pt = st_texture_create(st,
+ gl_target_to_pipe(stObj->base.Target),
+ fmt,
+ lastLevel,
+ ptWidth,
+ ptHeight,
+ ptDepth,
+ ptLayers,
+ bindings);
+
+ DBG("%s returning %d\n", __FUNCTION__, (stObj->pt != NULL));
+
+ return stObj->pt != NULL;
+}
+
+
+/**
+ * Adjust pixel unpack params and image dimensions to strip off the
+ * texture border.
+ * Gallium doesn't support texture borders. They've seldem been used
+ * and seldom been implemented correctly anyway.
+ * \param unpackNew returns the new pixel unpack parameters
+ */
+static void
+strip_texture_border(GLint border,
+ GLint *width, GLint *height, GLint *depth,
+ const struct gl_pixelstore_attrib *unpack,
+ struct gl_pixelstore_attrib *unpackNew)
+{
+ assert(border > 0); /* sanity check */
+
+ *unpackNew = *unpack;
+
+ if (unpackNew->RowLength == 0)
+ unpackNew->RowLength = *width;
+
+ if (depth && unpackNew->ImageHeight == 0)
+ unpackNew->ImageHeight = *height;
+
+ unpackNew->SkipPixels += border;
+ if (height)
+ unpackNew->SkipRows += border;
+ if (depth)
+ unpackNew->SkipImages += border;
+
+ assert(*width >= 3);
+ *width = *width - 2 * border;
+ if (height && *height >= 3)
+ *height = *height - 2 * border;
+ if (depth && *depth >= 3)
+ *depth = *depth - 2 * border;
+}
+
+
+/**
+ * Do glTexImage1/2/3D().
+ */
+static void
+st_TexImage(struct gl_context * ctx,
+ GLint dims,
+ GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, GLint height, GLint depth,
+ GLint border,
+ GLenum format, GLenum type, const void *pixels,
+ const struct gl_pixelstore_attrib *unpack,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage,
+ GLsizei imageSize, GLboolean compressed_src)
+{
+ struct st_context *st = st_context(ctx);
+ struct st_texture_object *stObj = st_texture_object(texObj);
+ struct st_texture_image *stImage = st_texture_image(texImage);
+ GLuint dstRowStride = 0;
+ struct gl_pixelstore_attrib unpackNB;
+ enum pipe_transfer_usage transfer_usage = 0;
+
+ DBG("%s target %s level %d %dx%dx%d border %d\n", __FUNCTION__,
+ _mesa_lookup_enum_by_nr(target), level, width, height, depth, border);
+
+ /* switch to "normal" */
+ if (stObj->surface_based) {
+ gl_format texFormat;
+
+ _mesa_clear_texture_object(ctx, texObj);
+ pipe_resource_reference(&stObj->pt, NULL);
+
+ /* oops, need to init this image again */
+ texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
+ internalFormat, format, type);
+
+ _mesa_init_teximage_fields(ctx, target, texImage,
+ width, height, depth, border,
+ internalFormat, texFormat);
+
+ stObj->surface_based = GL_FALSE;
+ }
+
+ /* gallium does not support texture borders, strip it off */
+ if (border) {
+ strip_texture_border(border, &width, &height, &depth, unpack, &unpackNB);
+ unpack = &unpackNB;
+ texImage->Width = width;
+ texImage->Height = height;
+ texImage->Depth = depth;
+ texImage->Border = 0;
+ border = 0;
+ }
+ else {
+ assert(texImage->Width == width);
+ assert(texImage->Height == height);
+ assert(texImage->Depth == depth);
+ }
+
+ stImage->face = _mesa_tex_target_to_face(target);
+ stImage->level = level;
+
+ _mesa_set_fetch_functions(texImage, dims);
+
+ /* Release the reference to a potentially orphaned buffer.
+ * Release any old malloced memory.
+ */
+ if (stImage->pt) {
+ pipe_resource_reference(&stImage->pt, NULL);
+ assert(!texImage->Data);
+ }
+ else if (texImage->Data) {
+ _mesa_align_free(texImage->Data);
+ }
+
+ /*
+ * See if the new image is somehow incompatible with the existing
+ * mipmap. If so, free the old mipmap.
+ */
+ if (stObj->pt) {
+ if (level > (GLint) stObj->pt->last_level ||
+ !st_texture_match_image(stObj->pt, &stImage->base,
+ stImage->face, stImage->level)) {
+ DBG("release it\n");
+ pipe_resource_reference(&stObj->pt, NULL);
+ assert(!stObj->pt);
+ pipe_sampler_view_reference(&stObj->sampler_view, NULL);
+ }
+ }
+
+ if (width == 0 || height == 0 || depth == 0) {
+ /* stop after freeing old image */
+ return;
+ }
+
+ if (!stObj->pt) {
+ if (!guess_and_alloc_texture(st, stObj, stImage)) {
+ /* Probably out of memory.
+ * Try flushing any pending rendering, then retry.
+ */
+ st_finish(st);
+ if (!guess_and_alloc_texture(st, stObj, stImage)) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
+ return;
+ }
+ }
+ }
+
+ assert(!stImage->pt);
+
+ /* Check if this texture image can live inside the texture object's buffer.
+ * If so, store the image there. Otherwise the image will temporarily live
+ * in its own buffer.
+ */
+ if (stObj->pt &&
+ st_texture_match_image(stObj->pt, &stImage->base,
+ stImage->face, stImage->level)) {
+
+ pipe_resource_reference(&stImage->pt, stObj->pt);
+ assert(stImage->pt);
+ }
+
+ if (!stImage->pt)
+ DBG("XXX: Image did not fit into texture - storing in local memory!\n");
+
+ /* Pixel data may come from regular user memory or a PBO. For the later,
+ * do bounds checking and map the PBO to read pixels data from it.
+ *
+ * XXX we should try to use a GPU-accelerated path to copy the image data
+ * from the PBO to the texture.
+ */
+ if (compressed_src) {
+ pixels = _mesa_validate_pbo_compressed_teximage(ctx, imageSize, pixels,
+ unpack,
+ "glCompressedTexImage");
+ }
+ else {
+ pixels = _mesa_validate_pbo_teximage(ctx, dims, width, height, 1,
+ format, type,
+ pixels, unpack, "glTexImage");
+ }
+
+ /*
+ * Prepare to store the texture data. Either map the gallium texture buffer
+ * memory or malloc space for it.
+ */
+ if (stImage->pt) {
+ /* Store the image in the gallium texture memory buffer */
+ if (format == GL_DEPTH_COMPONENT &&
+ util_format_is_depth_and_stencil(stImage->pt->format))
+ transfer_usage = PIPE_TRANSFER_READ_WRITE;
+ else
+ transfer_usage = PIPE_TRANSFER_WRITE;
+
+ texImage->Data = st_texture_image_map(st, stImage, 0,
+ transfer_usage, 0, 0, width, height);
+ if(stImage->transfer)
+ dstRowStride = stImage->transfer->stride;
+ }
+ else {
+ /* Allocate regular memory and store the image there temporarily. */
+ GLuint imageSize = _mesa_format_image_size(texImage->TexFormat,
+ width, height, depth);
+ dstRowStride = _mesa_format_row_stride(texImage->TexFormat, width);
+
+ texImage->Data = _mesa_align_malloc(imageSize, 16);
+ }
+
+ if (!texImage->Data) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
+ return;
+ }
+
+ if (!pixels) {
+ /* We've allocated texture memory, but have no pixel data - all done. */
+ goto done;
+ }
+
+ DBG("Upload image %dx%dx%d row_len %x pitch %x\n",
+ width, height, depth, width, dstRowStride);
+
+ /* Copy user texture image into the texture buffer.
+ */
+ if (compressed_src) {
+ const GLuint srcRowStride =
+ _mesa_format_row_stride(texImage->TexFormat, width);
+ if (dstRowStride == srcRowStride) {
+ memcpy(texImage->Data, pixels, imageSize);
+ }
+ else {
+ char *dst = texImage->Data;
+ const char *src = pixels;
+ GLuint i, bw, bh, lines;
+ _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
+ lines = (height + bh - 1) / bh;
+
+ for (i = 0; i < lines; ++i) {
+ memcpy(dst, src, srcRowStride);
+ dst += dstRowStride;
+ src += srcRowStride;
+ }
+ }
+ }
+ else {
+ const GLuint srcImageStride =
+ _mesa_image_image_stride(unpack, width, height, format, type);
+ GLint i;
+ const GLubyte *src = (const GLubyte *) pixels;
+
+ for (i = 0; i < depth; i++) {
+ if (!_mesa_texstore(ctx, dims,
+ texImage->_BaseFormat,
+ texImage->TexFormat,
+ texImage->Data,
+ 0, 0, 0, /* dstX/Y/Zoffset */
+ dstRowStride,
+ texImage->ImageOffsets,
+ width, height, 1,
+ format, type, src, unpack)) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
+ }
+
+ if (stImage->pt && i + 1 < depth) {
+ /* unmap this slice */
+ st_texture_image_unmap(st, stImage);
+ /* map next slice of 3D texture */
+ texImage->Data = st_texture_image_map(st, stImage, i + 1,
+ transfer_usage, 0, 0,
+ width, height);
+ src += srcImageStride;
+ }
+ }
+ }
+
+done:
+ _mesa_unmap_teximage_pbo(ctx, unpack);
+
+ if (stImage->pt && texImage->Data) {
+ st_texture_image_unmap(st, stImage);
+ texImage->Data = NULL;
+ }
+}
+
+
+static void
+st_TexImage3D(struct gl_context * ctx,
+ GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, GLint height, GLint depth,
+ GLint border,
+ GLenum format, GLenum type, const void *pixels,
+ const struct gl_pixelstore_attrib *unpack,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ st_TexImage(ctx, 3, target, level, internalFormat, width, height, depth,
+ border, format, type, pixels, unpack, texObj, texImage,
+ 0, GL_FALSE);
+}
+
+
+static void
+st_TexImage2D(struct gl_context * ctx,
+ GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, GLint height, GLint border,
+ GLenum format, GLenum type, const void *pixels,
+ const struct gl_pixelstore_attrib *unpack,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ st_TexImage(ctx, 2, target, level, internalFormat, width, height, 1, border,
+ format, type, pixels, unpack, texObj, texImage, 0, GL_FALSE);
+}
+
+
+static void
+st_TexImage1D(struct gl_context * ctx,
+ GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, GLint border,
+ GLenum format, GLenum type, const void *pixels,
+ const struct gl_pixelstore_attrib *unpack,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ st_TexImage(ctx, 1, target, level, internalFormat, width, 1, 1, border,
+ format, type, pixels, unpack, texObj, texImage, 0, GL_FALSE);
+}
+
+
+static void
+st_CompressedTexImage2D(struct gl_context *ctx, GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, GLint height, GLint border,
+ GLsizei imageSize, const GLvoid *data,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ st_TexImage(ctx, 2, target, level, internalFormat, width, height, 1, border,
+ 0, 0, data, &ctx->Unpack, texObj, texImage, imageSize, GL_TRUE);
+}
+
+
+
+/**
+ * glGetTexImage() helper: decompress a compressed texture by rendering
+ * a textured quad. Store the results in the user's buffer.
+ */
+static void
+decompress_with_blit(struct gl_context * ctx, GLenum target, GLint level,
+ GLenum format, GLenum type, GLvoid *pixels,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ struct st_context *st = st_context(ctx);
+ struct pipe_context *pipe = st->pipe;
+ struct st_texture_image *stImage = st_texture_image(texImage);
+ struct st_texture_object *stObj = st_texture_object(texObj);
+ struct pipe_sampler_view *src_view =
+ st_get_texture_sampler_view(stObj, pipe);
+ const GLuint width = texImage->Width;
+ const GLuint height = texImage->Height;
+ struct pipe_surface *dst_surface;
+ struct pipe_resource *dst_texture;
+ struct pipe_transfer *tex_xfer;
+ unsigned bind = (PIPE_BIND_RENDER_TARGET | /* util_blit may choose to render */
+ PIPE_BIND_TRANSFER_READ);
+
+ /* create temp / dest surface */
+ if (!util_create_rgba_surface(pipe, width, height, bind,
+ &dst_texture, &dst_surface)) {
+ _mesa_problem(ctx, "util_create_rgba_surface() failed "
+ "in decompress_with_blit()");
+ return;
+ }
+
+ /* blit/render/decompress */
+ util_blit_pixels_tex(st->blit,
+ src_view, /* pipe_resource (src) */
+ 0, 0, /* src x0, y0 */
+ width, height, /* src x1, y1 */
+ dst_surface, /* pipe_surface (dst) */
+ 0, 0, /* dst x0, y0 */
+ width, height, /* dst x1, y1 */
+ 0.0, /* z */
+ PIPE_TEX_MIPFILTER_NEAREST);
+
+ /* map the dst_surface so we can read from it */
+ tex_xfer = pipe_get_transfer(st_context(ctx)->pipe,
+ dst_texture, 0, 0,
+ PIPE_TRANSFER_READ,
+ 0, 0, width, height);
+
+ pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels);
+
+ /* copy/pack data into user buffer */
+ if (st_equal_formats(stImage->pt->format, format, type)) {
+ /* memcpy */
+ const uint bytesPerRow = width * util_format_get_blocksize(stImage->pt->format);
+ ubyte *map = pipe_transfer_map(pipe, tex_xfer);
+ GLuint row;
+ for (row = 0; row < height; row++) {
+ GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width,
+ height, format, type, row, 0);
+ memcpy(dest, map, bytesPerRow);
+ map += tex_xfer->stride;
+ }
+ pipe_transfer_unmap(pipe, tex_xfer);
+ }
+ else {
+ /* format translation via floats */
+ GLuint row;
+ enum pipe_format format = util_format_linear(dst_texture->format);
+ for (row = 0; row < height; row++) {
+ const GLbitfield transferOps = 0x0; /* bypassed for glGetTexImage() */
+ GLfloat rgba[4 * MAX_WIDTH];
+ GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width,
+ height, format, type, row, 0);
+
+ if (ST_DEBUG & DEBUG_FALLBACK)
+ debug_printf("%s: fallback format translation\n", __FUNCTION__);
+
+ /* get float[4] rgba row from surface */
+ pipe_get_tile_rgba_format(pipe, tex_xfer, 0, row, width, 1,
+ format, rgba);
+
+ _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format,
+ type, dest, &ctx->Pack, transferOps);
+ }
+ }
+
+ _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
+
+ pipe->transfer_destroy(pipe, tex_xfer);
+
+ /* destroy the temp / dest surface */
+ util_destroy_rgba_surface(dst_texture, dst_surface);
+}
+
+
+
+/**
+ * Need to map texture image into memory before copying image data,
+ * then unmap it.
+ */
+static void
+st_get_tex_image(struct gl_context * ctx, GLenum target, GLint level,
+ GLenum format, GLenum type, GLvoid * pixels,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage, GLboolean compressed_dst)
+{
+ struct st_context *st = st_context(ctx);
+ struct st_texture_image *stImage = st_texture_image(texImage);
+ const GLuint dstImageStride =
+ _mesa_image_image_stride(&ctx->Pack, texImage->Width, texImage->Height,
+ format, type);
+ GLuint depth, i;
+ GLubyte *dest;
+
+ if (stImage->pt &&
+ util_format_is_s3tc(stImage->pt->format) &&
+ !compressed_dst) {
+ /* Need to decompress the texture.
+ * We'll do this by rendering a textured quad.
+ * Note that we only expect RGBA formats (no Z/depth formats).
+ */
+ decompress_with_blit(ctx, target, level, format, type, pixels,
+ texObj, texImage);
+ return;
+ }
+
+ /* Map */
+ if (stImage->pt) {
+ /* Image is stored in hardware format in a buffer managed by the
+ * kernel. Need to explicitly map and unmap it.
+ */
+ texImage->Data = st_texture_image_map(st, stImage, 0,
+ PIPE_TRANSFER_READ, 0, 0,
+ stImage->base.Width,
+ stImage->base.Height);
+ /* compute stride in texels from stride in bytes */
+ texImage->RowStride = stImage->transfer->stride
+ * util_format_get_blockwidth(stImage->pt->format)
+ / util_format_get_blocksize(stImage->pt->format);
+ }
+ else {
+ /* Otherwise, the image should actually be stored in
+ * texImage->Data. This is pretty confusing for
+ * everybody, I'd much prefer to separate the two functions of
+ * texImage->Data - storage for texture images in main memory
+ * and access (ie mappings) of images. In other words, we'd
+ * create a new texImage->Map field and leave Data simply for
+ * storage.
+ */
+ assert(texImage->Data);
+ }
+
+ depth = texImage->Depth;
+ texImage->Depth = 1;
+
+ dest = (GLubyte *) pixels;
+
+ _mesa_set_fetch_functions(texImage, get_texture_dims(target));
+
+ for (i = 0; i < depth; i++) {
+ if (compressed_dst) {
+ _mesa_get_compressed_teximage(ctx, target, level, dest,
+ texObj, texImage);
+ }
+ else {
+ _mesa_get_teximage(ctx, target, level, format, type, dest,
+ texObj, texImage);
+ }
+
+ if (stImage->pt && i + 1 < depth) {
+ /* unmap this slice */
+ st_texture_image_unmap(st, stImage);
+ /* map next slice of 3D texture */
+ texImage->Data = st_texture_image_map(st, stImage, i + 1,
+ PIPE_TRANSFER_READ, 0, 0,
+ stImage->base.Width,
+ stImage->base.Height);
+ dest += dstImageStride;
+ }
+ }
+
+ texImage->Depth = depth;
+
+ /* Unmap */
+ if (stImage->pt) {
+ st_texture_image_unmap(st, stImage);
+ texImage->Data = NULL;
+ }
+}
+
+
+static void
+st_GetTexImage(struct gl_context * ctx, GLenum target, GLint level,
+ GLenum format, GLenum type, GLvoid * pixels,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ st_get_tex_image(ctx, target, level, format, type, pixels, texObj, texImage,
+ GL_FALSE);
+}
+
+
+static void
+st_GetCompressedTexImage(struct gl_context *ctx, GLenum target, GLint level,
+ GLvoid *pixels,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ st_get_tex_image(ctx, target, level, 0, 0, pixels, texObj, texImage,
+ GL_TRUE);
+}
+
+
+
+static void
+st_TexSubimage(struct gl_context *ctx, GLint dims, GLenum target, GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLint width, GLint height, GLint depth,
+ GLenum format, GLenum type, const void *pixels,
+ const struct gl_pixelstore_attrib *packing,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ struct st_context *st = st_context(ctx);
+ struct st_texture_image *stImage = st_texture_image(texImage);
+ GLuint dstRowStride;
+ const GLuint srcImageStride =
+ _mesa_image_image_stride(packing, width, height, format, type);
+ GLint i;
+ const GLubyte *src;
+ /* init to silence warning only: */
+ enum pipe_transfer_usage transfer_usage = PIPE_TRANSFER_WRITE;
+
+ DBG("%s target %s level %d offset %d,%d %dx%d\n", __FUNCTION__,
+ _mesa_lookup_enum_by_nr(target),
+ level, xoffset, yoffset, width, height);
+
+ pixels =
+ _mesa_validate_pbo_teximage(ctx, dims, width, height, depth, format,
+ type, pixels, packing, "glTexSubImage2D");
+ if (!pixels)
+ return;
+
+ /* Map buffer if necessary. Need to lock to prevent other contexts
+ * from uploading the buffer under us.
+ */
+ if (stImage->pt) {
+ if (format == GL_DEPTH_COMPONENT &&
+ util_format_is_depth_and_stencil(stImage->pt->format))
+ transfer_usage = PIPE_TRANSFER_READ_WRITE;
+ else
+ transfer_usage = PIPE_TRANSFER_WRITE;
+
+ texImage->Data = st_texture_image_map(st, stImage, zoffset,
+ transfer_usage,
+ xoffset, yoffset,
+ width, height);
+ }
+
+ if (!texImage->Data) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage");
+ goto done;
+ }
+
+ src = (const GLubyte *) pixels;
+ dstRowStride = stImage->transfer->stride;
+
+ for (i = 0; i < depth; i++) {
+ if (!_mesa_texstore(ctx, dims, texImage->_BaseFormat,
+ texImage->TexFormat,
+ texImage->Data,
+ 0, 0, 0,
+ dstRowStride,
+ texImage->ImageOffsets,
+ width, height, 1,
+ format, type, src, packing)) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage");
+ }
+
+ if (stImage->pt && i + 1 < depth) {
+ /* unmap this slice */
+ st_texture_image_unmap(st, stImage);
+ /* map next slice of 3D texture */
+ texImage->Data = st_texture_image_map(st, stImage,
+ zoffset + i + 1,
+ transfer_usage,
+ xoffset, yoffset,
+ width, height);
+ src += srcImageStride;
+ }
+ }
+
+done:
+ _mesa_unmap_teximage_pbo(ctx, packing);
+
+ if (stImage->pt && texImage->Data) {
+ st_texture_image_unmap(st, stImage);
+ texImage->Data = NULL;
+ }
+}
+
+
+
+static void
+st_TexSubImage3D(struct gl_context *ctx, GLenum target, GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format, GLenum type, const GLvoid *pixels,
+ const struct gl_pixelstore_attrib *packing,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ st_TexSubimage(ctx, 3, target, level, xoffset, yoffset, zoffset,
+ width, height, depth, format, type,
+ pixels, packing, texObj, texImage);
+}
+
+
+static void
+st_TexSubImage2D(struct gl_context *ctx, GLenum target, GLint level,
+ GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type, const GLvoid * pixels,
+ const struct gl_pixelstore_attrib *packing,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ st_TexSubimage(ctx, 2, target, level, xoffset, yoffset, 0,
+ width, height, 1, format, type,
+ pixels, packing, texObj, texImage);
+}
+
+
+static void
+st_TexSubImage1D(struct gl_context *ctx, GLenum target, GLint level,
+ GLint xoffset, GLsizei width, GLenum format, GLenum type,
+ const GLvoid * pixels,
+ const struct gl_pixelstore_attrib *packing,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ st_TexSubimage(ctx, 1, target, level, xoffset, 0, 0, width, 1, 1,
+ format, type, pixels, packing, texObj, texImage);
+}
+
+
+static void
+st_CompressedTexSubImage1D(struct gl_context *ctx, GLenum target, GLint level,
+ GLint xoffset, GLsizei width,
+ GLenum format,
+ GLsizei imageSize, const GLvoid *data,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ assert(0);
+}
+
+
+static void
+st_CompressedTexSubImage2D(struct gl_context *ctx, GLenum target, GLint level,
+ GLint xoffset, GLint yoffset,
+ GLsizei width, GLint height,
+ GLenum format,
+ GLsizei imageSize, const GLvoid *data,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ struct st_context *st = st_context(ctx);
+ struct st_texture_image *stImage = st_texture_image(texImage);
+ int srcBlockStride;
+ int dstBlockStride;
+ int y;
+ enum pipe_format pformat;
+
+ if (stImage->pt) {
+ pformat = stImage->pt->format;
+
+ texImage->Data = st_texture_image_map(st, stImage, 0,
+ PIPE_TRANSFER_WRITE,
+ xoffset, yoffset,
+ width, height);
+
+ srcBlockStride = util_format_get_stride(pformat, width);
+ dstBlockStride = stImage->transfer->stride;
+ } else {
+ assert(stImage->pt);
+ /* TODO find good values for block and strides */
+ /* TODO also adjust texImage->data for yoffset/xoffset */
+ return;
+ }
+
+ if (!texImage->Data) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexSubImage");
+ return;
+ }
+
+ assert(xoffset % util_format_get_blockwidth(pformat) == 0);
+ assert(yoffset % util_format_get_blockheight(pformat) == 0);
+
+ for (y = 0; y < height; y += util_format_get_blockheight(pformat)) {
+ /* don't need to adjust for xoffset and yoffset as st_texture_image_map does that */
+ const char *src = (const char*)data + srcBlockStride * util_format_get_nblocksy(pformat, y);
+ char *dst = (char*)texImage->Data + dstBlockStride * util_format_get_nblocksy(pformat, y);
+ memcpy(dst, src, util_format_get_stride(pformat, width));
+ }
+
+ if (stImage->pt) {
+ st_texture_image_unmap(st, stImage);
+ texImage->Data = NULL;
+ }
+}
+
+
+static void
+st_CompressedTexSubImage3D(struct gl_context *ctx, GLenum target, GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLint height, GLint depth,
+ GLenum format,
+ GLsizei imageSize, const GLvoid *data,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ assert(0);
+}
+
+
+
+/**
+ * Do a CopyTexSubImage operation using a read transfer from the source,
+ * a write transfer to the destination and get_tile()/put_tile() to access
+ * the pixels/texels.
+ *
+ * Note: srcY=0=TOP of renderbuffer
+ */
+static void
+fallback_copy_texsubimage(struct gl_context *ctx, GLenum target, GLint level,
+ struct st_renderbuffer *strb,
+ struct st_texture_image *stImage,
+ GLenum baseFormat,
+ GLint destX, GLint destY, GLint destZ,
+ GLint srcX, GLint srcY,
+ GLsizei width, GLsizei height)
+{
+ struct st_context *st = st_context(ctx);
+ struct pipe_context *pipe = st->pipe;
+ struct pipe_transfer *src_trans;
+ GLvoid *texDest;
+ enum pipe_transfer_usage transfer_usage;
+
+ if (ST_DEBUG & DEBUG_FALLBACK)
+ debug_printf("%s: fallback processing\n", __FUNCTION__);
+
+ assert(width <= MAX_WIDTH);
+
+ if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
+ srcY = strb->Base.Height - srcY - height;
+ }
+
+ src_trans = pipe_get_transfer(st_context(ctx)->pipe,
+ strb->texture,
+ 0, 0,
+ PIPE_TRANSFER_READ,
+ srcX, srcY,
+ width, height);
+
+ if ((baseFormat == GL_DEPTH_COMPONENT ||
+ baseFormat == GL_DEPTH_STENCIL) &&
+ util_format_is_depth_and_stencil(stImage->pt->format))
+ transfer_usage = PIPE_TRANSFER_READ_WRITE;
+ else
+ transfer_usage = PIPE_TRANSFER_WRITE;
+
+ /* XXX this used to ignore destZ param */
+ texDest = st_texture_image_map(st, stImage, destZ, transfer_usage,
+ destX, destY, width, height);
+
+ if (baseFormat == GL_DEPTH_COMPONENT ||
+ baseFormat == GL_DEPTH_STENCIL) {
+ const GLboolean scaleOrBias = (ctx->Pixel.DepthScale != 1.0F ||
+ ctx->Pixel.DepthBias != 0.0F);
+ GLint row, yStep;
+
+ /* determine bottom-to-top vs. top-to-bottom order for src buffer */
+ if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
+ srcY = height - 1;
+ yStep = -1;
+ }
+ else {
+ srcY = 0;
+ yStep = 1;
+ }
+
+ /* To avoid a large temp memory allocation, do copy row by row */
+ for (row = 0; row < height; row++, srcY += yStep) {
+ uint data[MAX_WIDTH];
+ pipe_get_tile_z(pipe, src_trans, 0, srcY, width, 1, data);
+ if (scaleOrBias) {
+ _mesa_scale_and_bias_depth_uint(ctx, width, data);
+ }
+ pipe_put_tile_z(pipe, stImage->transfer, 0, row, width, 1, data);
+ }
+ }
+ else {
+ /* RGBA format */
+ GLfloat *tempSrc =
+ (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
+
+ if (tempSrc && texDest) {
+ const GLint dims = 2;
+ const GLint dstRowStride = stImage->transfer->stride;
+ struct gl_texture_image *texImage = &stImage->base;
+ struct gl_pixelstore_attrib unpack = ctx->DefaultPacking;
+
+ if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
+ unpack.Invert = GL_TRUE;
+ }
+
+ /* get float/RGBA image from framebuffer */
+ /* XXX this usually involves a lot of int/float conversion.
+ * try to avoid that someday.
+ */
+ pipe_get_tile_rgba_format(pipe, src_trans, 0, 0, width, height,
+ util_format_linear(strb->texture->format),
+ tempSrc);
+
+ /* Store into texture memory.
+ * Note that this does some special things such as pixel transfer
+ * ops and format conversion. In particular, if the dest tex format
+ * is actually RGBA but the user created the texture as GL_RGB we
+ * need to fill-in/override the alpha channel with 1.0.
+ */
+ _mesa_texstore(ctx, dims,
+ texImage->_BaseFormat,
+ texImage->TexFormat,
+ texDest,
+ 0, 0, 0,
+ dstRowStride,
+ texImage->ImageOffsets,
+ width, height, 1,
+ GL_RGBA, GL_FLOAT, tempSrc, /* src */
+ &unpack);
+ }
+ else {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage");
+ }
+
+ if (tempSrc)
+ free(tempSrc);
+ }
+
+ st_texture_image_unmap(st, stImage);
+ pipe->transfer_destroy(pipe, src_trans);
+}
+
+
+
+/**
+ * If the format of the src renderbuffer and the format of the dest
+ * texture are compatible (in terms of blitting), return a TGSI writemask
+ * to be used during the blit.
+ * If the src/dest are incompatible, return 0.
+ */
+static unsigned
+compatible_src_dst_formats(struct gl_context *ctx,
+ const struct gl_renderbuffer *src,
+ const struct gl_texture_image *dst)
+{
+ /* Get logical base formats for the src and dest.
+ * That is, use the user-requested formats and not the actual, device-
+ * chosen formats.
+ * For example, the user may have requested an A8 texture but the
+ * driver may actually be using an RGBA texture format. When we
+ * copy/blit to that texture, we only want to copy the Alpha channel
+ * and not the RGB channels.
+ *
+ * Similarly, when the src FBO was created an RGB format may have been
+ * requested but the driver actually chose an RGBA format. In that case,
+ * we don't want to copy the undefined Alpha channel to the dest texture
+ * (it should be 1.0).
+ */
+ const GLenum srcFormat = _mesa_base_fbo_format(ctx, src->InternalFormat);
+ const GLenum dstFormat = _mesa_base_tex_format(ctx, dst->InternalFormat);
+
+ /**
+ * XXX when we have red-only and red/green renderbuffers we'll need
+ * to add more cases here (or implement a general-purpose routine that
+ * queries the existance of the R,G,B,A channels in the src and dest).
+ */
+ if (srcFormat == dstFormat) {
+ /* This is the same as matching_base_formats, which should
+ * always pass, as it did previously.
+ */
+ return TGSI_WRITEMASK_XYZW;
+ }
+ else if (srcFormat == GL_RGB && dstFormat == GL_RGBA) {
+ /* Make sure that A in the dest is 1. The actual src format
+ * may be RGBA and have undefined A values.
+ */
+ return TGSI_WRITEMASK_XYZ;
+ }
+ else if (srcFormat == GL_RGBA && dstFormat == GL_RGB) {
+ /* Make sure that A in the dest is 1. The actual dst format
+ * may be RGBA and will need A=1 to provide proper alpha values
+ * when sampled later.
+ */
+ return TGSI_WRITEMASK_XYZ;
+ }
+ else {
+ if (ST_DEBUG & DEBUG_FALLBACK)
+ debug_printf("%s failed for src %s, dst %s\n",
+ __FUNCTION__,
+ _mesa_lookup_enum_by_nr(srcFormat),
+ _mesa_lookup_enum_by_nr(dstFormat));
+
+ /* Otherwise fail.
+ */
+ return 0;
+ }
+}
+
+
+
+/**
+ * Do a CopyTex[Sub]Image1/2/3D() using a hardware (blit) path if possible.
+ * Note that the region to copy has already been clipped so we know we
+ * won't read from outside the source renderbuffer's bounds.
+ *
+ * Note: srcY=0=Bottom of renderbuffer (GL convention)
+ */
+static void
+st_copy_texsubimage(struct gl_context *ctx,
+ GLenum target, GLint level,
+ GLint destX, GLint destY, GLint destZ,
+ GLint srcX, GLint srcY,
+ GLsizei width, GLsizei height)
+{
+ struct gl_texture_unit *texUnit =
+ &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+ struct gl_texture_object *texObj =
+ _mesa_select_tex_object(ctx, texUnit, target);
+ struct gl_texture_image *texImage =
+ _mesa_select_tex_image(ctx, texObj, target, level);
+ struct st_texture_image *stImage = st_texture_image(texImage);
+ const GLenum texBaseFormat = texImage->_BaseFormat;
+ struct gl_framebuffer *fb = ctx->ReadBuffer;
+ struct st_renderbuffer *strb;
+ struct st_context *st = st_context(ctx);
+ struct pipe_context *pipe = st->pipe;
+ struct pipe_screen *screen = pipe->screen;
+ enum pipe_format dest_format, src_format;
+ GLboolean use_fallback = GL_TRUE;
+ GLboolean matching_base_formats;
+ GLuint format_writemask, sample_count;
+ struct pipe_surface *dest_surface = NULL;
+ GLboolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP);
+
+ /* make sure finalize_textures has been called?
+ */
+ if (0) st_validate_state(st);
+
+ /* determine if copying depth or color data */
+ if (texBaseFormat == GL_DEPTH_COMPONENT ||
+ texBaseFormat == GL_DEPTH_STENCIL) {
+ strb = st_renderbuffer(fb->_DepthBuffer);
+ if (strb->Base.Wrapped) {
+ strb = st_renderbuffer(strb->Base.Wrapped);
+ }
+ }
+ else {
+ /* texBaseFormat == GL_RGB, GL_RGBA, GL_ALPHA, etc */
+ strb = st_renderbuffer(fb->_ColorReadBuffer);
+ }
+
+ if (!strb || !strb->surface || !stImage->pt) {
+ debug_printf("%s: null strb or stImage\n", __FUNCTION__);
+ return;
+ }
+
+ sample_count = strb->surface->texture->nr_samples;
+ /* I believe this would be legal, presumably would need to do a resolve
+ for color, and for depth/stencil spec says to just use one of the
+ depth/stencil samples per pixel? Need some transfer clarifications. */
+ assert(sample_count < 2);
+
+ if (srcX < 0) {
+ width -= -srcX;
+ destX += -srcX;
+ srcX = 0;
+ }
+
+ if (srcY < 0) {
+ height -= -srcY;
+ destY += -srcY;
+ srcY = 0;
+ }
+
+ if (destX < 0) {
+ width -= -destX;
+ srcX += -destX;
+ destX = 0;
+ }
+
+ if (destY < 0) {
+ height -= -destY;
+ srcY += -destY;
+ destY = 0;
+ }
+
+ if (width < 0 || height < 0)
+ return;
+
+
+ assert(strb);
+ assert(strb->surface);
+ assert(stImage->pt);
+
+ src_format = strb->surface->format;
+ dest_format = stImage->pt->format;
+
+ /*
+ * Determine if the src framebuffer and dest texture have the same
+ * base format. We need this to detect a case such as the framebuffer
+ * being GL_RGBA but the texture being GL_RGB. If the actual hardware
+ * texture format stores RGBA we need to set A=1 (overriding the
+ * framebuffer's alpha values). We can't do that with the blit or
+ * textured-quad paths.
+ */
+ matching_base_formats =
+ (_mesa_get_format_base_format(strb->Base.Format) ==
+ _mesa_get_format_base_format(texImage->TexFormat));
+ format_writemask = compatible_src_dst_formats(ctx, &strb->Base, texImage);
+
+ if (ctx->_ImageTransferState == 0x0) {
+
+ if (matching_base_formats &&
+ src_format == dest_format &&
+ !do_flip)
+ {
+ /* use surface_copy() / blit */
+ struct pipe_box src_box;
+ u_box_2d_zslice(srcX, srcY, strb->surface->u.tex.first_layer,
+ width, height, &src_box);
+
+ /* for resource_copy_region(), y=0=top, always */
+ pipe->resource_copy_region(pipe,
+ /* dest */
+ stImage->pt,
+ stImage->level,
+ destX, destY, destZ + stImage->face,
+ /* src */
+ strb->texture,
+ strb->surface->u.tex.level,
+ &src_box);
+ use_fallback = GL_FALSE;
+ }
+ else if (format_writemask &&
+ texBaseFormat != GL_DEPTH_COMPONENT &&
+ texBaseFormat != GL_DEPTH_STENCIL &&
+ screen->is_format_supported(screen, src_format,
+ PIPE_TEXTURE_2D, sample_count,
+ PIPE_BIND_SAMPLER_VIEW,
+ 0) &&
+ screen->is_format_supported(screen, dest_format,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_RENDER_TARGET,
+ 0)) {
+ /* draw textured quad to do the copy */
+ GLint srcY0, srcY1;
+ struct pipe_surface surf_tmpl;
+ memset(&surf_tmpl, 0, sizeof(surf_tmpl));
+ surf_tmpl.format = stImage->pt->format;
+ surf_tmpl.usage = PIPE_BIND_RENDER_TARGET;
+ surf_tmpl.u.tex.level = stImage->level;
+ surf_tmpl.u.tex.first_layer = stImage->face + destZ;
+ surf_tmpl.u.tex.last_layer = stImage->face + destZ;
+
+ dest_surface = pipe->create_surface(pipe, stImage->pt,
+ &surf_tmpl);
+
+ if (do_flip) {
+ srcY1 = strb->Base.Height - srcY - height;
+ srcY0 = srcY1 + height;
+ }
+ else {
+ srcY0 = srcY;
+ srcY1 = srcY0 + height;
+ }
+
+ util_blit_pixels_writemask(st->blit,
+ strb->texture,
+ strb->surface->u.tex.level,
+ srcX, srcY0,
+ srcX + width, srcY1,
+ strb->surface->u.tex.first_layer,
+ dest_surface,
+ destX, destY,
+ destX + width, destY + height,
+ 0.0, PIPE_TEX_MIPFILTER_NEAREST,
+ format_writemask);
+ use_fallback = GL_FALSE;
+ }
+
+ if (dest_surface)
+ pipe_surface_reference(&dest_surface, NULL);
+ }
+
+ if (use_fallback) {
+ /* software fallback */
+ fallback_copy_texsubimage(ctx, target, level,
+ strb, stImage, texBaseFormat,
+ destX, destY, destZ,
+ srcX, srcY, width, height);
+ }
+}
+
+
+
+static void
+st_CopyTexImage1D(struct gl_context * ctx, GLenum target, GLint level,
+ GLenum internalFormat,
+ GLint x, GLint y, GLsizei width, GLint border)
+{
+ struct gl_texture_unit *texUnit =
+ &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+ struct gl_texture_object *texObj =
+ _mesa_select_tex_object(ctx, texUnit, target);
+ struct gl_texture_image *texImage =
+ _mesa_select_tex_image(ctx, texObj, target, level);
+
+ /* Setup or redefine the texture object, texture and texture
+ * image. Don't populate yet.
+ */
+ ctx->Driver.TexImage1D(ctx, target, level, internalFormat,
+ width, border,
+ GL_RGBA, CHAN_TYPE, NULL,
+ &ctx->DefaultPacking, texObj, texImage);
+
+ st_copy_texsubimage(ctx, target, level,
+ 0, 0, 0, /* destX,Y,Z */
+ x, y, width, 1); /* src X, Y, size */
+}
+
+
+static void
+st_CopyTexImage2D(struct gl_context * ctx, GLenum target, GLint level,
+ GLenum internalFormat,
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ GLint border)
+{
+ struct gl_texture_unit *texUnit =
+ &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+ struct gl_texture_object *texObj =
+ _mesa_select_tex_object(ctx, texUnit, target);
+ struct gl_texture_image *texImage =
+ _mesa_select_tex_image(ctx, texObj, target, level);
+
+ /* Setup or redefine the texture object, texture and texture
+ * image. Don't populate yet.
+ */
+ ctx->Driver.TexImage2D(ctx, target, level, internalFormat,
+ width, height, border,
+ GL_RGBA, CHAN_TYPE, NULL,
+ &ctx->DefaultPacking, texObj, texImage);
+
+ st_copy_texsubimage(ctx, target, level,
+ 0, 0, 0, /* destX,Y,Z */
+ x, y, width, height); /* src X, Y, size */
+}
+
+
+static void
+st_CopyTexSubImage1D(struct gl_context * ctx, GLenum target, GLint level,
+ GLint xoffset, GLint x, GLint y, GLsizei width)
+{
+ const GLint yoffset = 0, zoffset = 0;
+ const GLsizei height = 1;
+ st_copy_texsubimage(ctx, target, level,
+ xoffset, yoffset, zoffset, /* destX,Y,Z */
+ x, y, width, height); /* src X, Y, size */
+}
+
+
+static void
+st_CopyTexSubImage2D(struct gl_context * ctx, GLenum target, GLint level,
+ GLint xoffset, GLint yoffset,
+ GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ const GLint zoffset = 0;
+ st_copy_texsubimage(ctx, target, level,
+ xoffset, yoffset, zoffset, /* destX,Y,Z */
+ x, y, width, height); /* src X, Y, size */
+}
+
+
+static void
+st_CopyTexSubImage3D(struct gl_context * ctx, GLenum target, GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ st_copy_texsubimage(ctx, target, level,
+ xoffset, yoffset, zoffset, /* destX,Y,Z */
+ x, y, width, height); /* src X, Y, size */
+}
+
+
+/**
+ * Copy image data from stImage into the texture object 'stObj' at level
+ * 'dstLevel'.
+ */
+static void
+copy_image_data_to_texture(struct st_context *st,
+ struct st_texture_object *stObj,
+ GLuint dstLevel,
+ struct st_texture_image *stImage)
+{
+ /* debug checks */
+ {
+ const struct gl_texture_image *dstImage =
+ stObj->base.Image[stImage->face][stImage->level];
+ assert(dstImage);
+ assert(dstImage->Width == stImage->base.Width);
+ assert(dstImage->Height == stImage->base.Height);
+ assert(dstImage->Depth == stImage->base.Depth);
+ }
+
+ if (stImage->pt) {
+ /* Copy potentially with the blitter:
+ */
+ st_texture_image_copy(st->pipe,
+ stObj->pt, dstLevel, /* dest texture, level */
+ stImage->pt, stImage->level, /* src texture, level */
+ stImage->face);
+
+ pipe_resource_reference(&stImage->pt, NULL);
+ }
+ else if (stImage->base.Data) {
+ st_texture_image_data(st,
+ stObj->pt,
+ stImage->face,
+ dstLevel,
+ stImage->base.Data,
+ stImage->base.RowStride *
+ util_format_get_blocksize(stObj->pt->format),
+ stImage->base.RowStride *
+ stImage->base.Height *
+ util_format_get_blocksize(stObj->pt->format));
+ _mesa_align_free(stImage->base.Data);
+ stImage->base.Data = NULL;
+ }
+
+ pipe_resource_reference(&stImage->pt, stObj->pt);
+}
+
+
+/**
+ * Called during state validation. When this function is finished,
+ * the texture object should be ready for rendering.
+ * \return GL_TRUE for success, GL_FALSE for failure (out of mem)
+ */
+GLboolean
+st_finalize_texture(struct gl_context *ctx,
+ struct pipe_context *pipe,
+ struct gl_texture_object *tObj)
+{
+ struct st_context *st = st_context(ctx);
+ struct st_texture_object *stObj = st_texture_object(tObj);
+ const GLuint nr_faces = (stObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
+ GLuint face;
+ struct st_texture_image *firstImage;
+ enum pipe_format firstImageFormat;
+ GLuint ptWidth, ptHeight, ptDepth, ptLayers;
+
+ if (stObj->base._Complete) {
+ /* The texture is complete and we know exactly how many mipmap levels
+ * are present/needed. This is conditional because we may be called
+ * from the st_generate_mipmap() function when the texture object is
+ * incomplete. In that case, we'll have set stObj->lastLevel before
+ * we get here.
+ */
+ if (stObj->base.MinFilter == GL_LINEAR ||
+ stObj->base.MinFilter == GL_NEAREST)
+ stObj->lastLevel = stObj->base.BaseLevel;
+ else
+ stObj->lastLevel = stObj->base._MaxLevel;
+ }
+
+ firstImage = st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]);
+ assert(firstImage);
+
+ /* If both firstImage and stObj point to a texture which can contain
+ * all active images, favour firstImage. Note that because of the
+ * completeness requirement, we know that the image dimensions
+ * will match.
+ */
+ if (firstImage->pt &&
+ firstImage->pt != stObj->pt &&
+ (!stObj->pt || firstImage->pt->last_level >= stObj->pt->last_level)) {
+ pipe_resource_reference(&stObj->pt, firstImage->pt);
+ pipe_sampler_view_reference(&stObj->sampler_view, NULL);
+ }
+
+ /* Find gallium format for the Mesa texture */
+ firstImageFormat = st_mesa_format_to_pipe_format(firstImage->base.TexFormat);
+
+ /* Find size of level=0 Gallium mipmap image, plus number of texture layers */
+ {
+ GLuint width, height, depth;
+ if (!guess_base_level_size(stObj->base.Target,
+ firstImage->base.Width2,
+ firstImage->base.Height2,
+ firstImage->base.Depth2,
+ stObj->base.BaseLevel,
+ &width, &height, &depth)) {
+ width = stObj->width0;
+ height = stObj->height0;
+ depth = stObj->depth0;
+ }
+ /* convert GL dims to Gallium dims */
+ st_gl_texture_dims_to_pipe_dims(stObj->base.Target, width, height, depth,
+ &ptWidth, &ptHeight, &ptDepth, &ptLayers);
+ }
+
+ /* If we already have a gallium texture, check that it matches the texture
+ * object's format, target, size, num_levels, etc.
+ */
+ if (stObj->pt) {
+ if (stObj->pt->target != gl_target_to_pipe(stObj->base.Target) ||
+ !st_sampler_compat_formats(stObj->pt->format, firstImageFormat) ||
+ stObj->pt->last_level < stObj->lastLevel ||
+ stObj->pt->width0 != ptWidth ||
+ stObj->pt->height0 != ptHeight ||
+ stObj->pt->depth0 != ptDepth ||
+ stObj->pt->array_size != ptLayers)
+ {
+ /* The gallium texture does not match the Mesa texture so delete the
+ * gallium texture now. We'll make a new one below.
+ */
+ pipe_resource_reference(&stObj->pt, NULL);
+ pipe_sampler_view_reference(&stObj->sampler_view, NULL);
+ st->dirty.st |= ST_NEW_FRAMEBUFFER;
+ }
+ }
+
+ /* May need to create a new gallium texture:
+ */
+ if (!stObj->pt) {
+ GLuint bindings = default_bindings(st, firstImageFormat);
+
+ stObj->pt = st_texture_create(st,
+ gl_target_to_pipe(stObj->base.Target),
+ firstImageFormat,
+ stObj->lastLevel,
+ ptWidth,
+ ptHeight,
+ ptDepth,
+ ptLayers,
+ bindings);
+
+ if (!stObj->pt) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
+ return GL_FALSE;
+ }
+ }
+
+ /* Pull in any images not in the object's texture:
+ */
+ for (face = 0; face < nr_faces; face++) {
+ GLuint level;
+ for (level = stObj->base.BaseLevel; level <= stObj->lastLevel; level++) {
+ struct st_texture_image *stImage =
+ st_texture_image(stObj->base.Image[face][level]);
+
+ /* Need to import images in main memory or held in other textures.
+ */
+ if (stImage && stObj->pt != stImage->pt) {
+ copy_image_data_to_texture(st, stObj, level, stImage);
+ }
+ }
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Returns pointer to a default/dummy texture.
+ * This is typically used when the current shader has tex/sample instructions
+ * but the user has not provided a (any) texture(s).
+ */
+struct gl_texture_object *
+st_get_default_texture(struct st_context *st)
+{
+ if (!st->default_texture) {
+ static const GLenum target = GL_TEXTURE_2D;
+ GLubyte pixels[16][16][4];
+ struct gl_texture_object *texObj;
+ struct gl_texture_image *texImg;
+ GLuint i, j;
+
+ /* The ARB_fragment_program spec says (0,0,0,1) should be returned
+ * when attempting to sample incomplete textures.
+ */
+ for (i = 0; i < 16; i++) {
+ for (j = 0; j < 16; j++) {
+ pixels[i][j][0] = 0;
+ pixels[i][j][1] = 0;
+ pixels[i][j][2] = 0;
+ pixels[i][j][3] = 255;
+ }
+ }
+
+ texObj = st->ctx->Driver.NewTextureObject(st->ctx, 0, target);
+
+ texImg = _mesa_get_tex_image(st->ctx, texObj, target, 0);
+
+ _mesa_init_teximage_fields(st->ctx, target, texImg,
+ 16, 16, 1, 0, /* w, h, d, border */
+ GL_RGBA, MESA_FORMAT_RGBA8888);
+
+ st_TexImage(st->ctx, 2, target,
+ 0, GL_RGBA, /* level, intformat */
+ 16, 16, 1, 0, /* w, h, d, border */
+ GL_RGBA, GL_UNSIGNED_BYTE, pixels,
+ &st->ctx->DefaultPacking,
+ texObj, texImg,
+ 0, 0);
+
+ texObj->MinFilter = GL_NEAREST;
+ texObj->MagFilter = GL_NEAREST;
+ texObj->_Complete = GL_TRUE;
+
+ st->default_texture = texObj;
+ }
+ return st->default_texture;
+}
+
+
+void
+st_init_texture_functions(struct dd_function_table *functions)
+{
+ functions->ChooseTextureFormat = st_ChooseTextureFormat;
+ functions->TexImage1D = st_TexImage1D;
+ functions->TexImage2D = st_TexImage2D;
+ functions->TexImage3D = st_TexImage3D;
+ functions->TexSubImage1D = st_TexSubImage1D;
+ functions->TexSubImage2D = st_TexSubImage2D;
+ functions->TexSubImage3D = st_TexSubImage3D;
+ functions->CompressedTexSubImage1D = st_CompressedTexSubImage1D;
+ functions->CompressedTexSubImage2D = st_CompressedTexSubImage2D;
+ functions->CompressedTexSubImage3D = st_CompressedTexSubImage3D;
+ functions->CopyTexImage1D = st_CopyTexImage1D;
+ functions->CopyTexImage2D = st_CopyTexImage2D;
+ functions->CopyTexSubImage1D = st_CopyTexSubImage1D;
+ functions->CopyTexSubImage2D = st_CopyTexSubImage2D;
+ functions->CopyTexSubImage3D = st_CopyTexSubImage3D;
+ functions->GenerateMipmap = st_generate_mipmap;
+
+ functions->GetTexImage = st_GetTexImage;
+
+ /* compressed texture functions */
+ functions->CompressedTexImage2D = st_CompressedTexImage2D;
+ functions->GetCompressedTexImage = st_GetCompressedTexImage;
+
+ functions->NewTextureObject = st_NewTextureObject;
+ functions->NewTextureImage = st_NewTextureImage;
+ functions->DeleteTexture = st_DeleteTextureObject;
+ functions->FreeTexImageData = st_FreeTextureImageData;
+
+ functions->TextureMemCpy = do_memcpy;
+
+ /* XXX Temporary until we can query pipe's texture sizes */
+ functions->TestProxyTexImage = _mesa_test_proxy_teximage;
+}
diff --git a/mesalib/src/mesa/state_tracker/st_context.c b/mesalib/src/mesa/state_tracker/st_context.c
index 7a19f35bb..8f3a7415d 100644
--- a/mesalib/src/mesa/state_tracker/st_context.c
+++ b/mesalib/src/mesa/state_tracker/st_context.c
@@ -1,297 +1,297 @@
-/**************************************************************************
- *
- * 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);
-
- /* Unreference any user vertex buffers. */
- for (i = 0; i < st->num_user_vbs; i++) {
- pipe_resource_reference(&st->user_vb[i], NULL);
- }
-
- 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);
+
+ /* Unreference any user vertex buffers. */
+ for (i = 0; i < st->num_user_vbs; i++) {
+ pipe_resource_reference(&st->user_vb[i], NULL);
+ }
+
+ 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_context.h b/mesalib/src/mesa/state_tracker/st_context.h
index 77765f023..ef54fd7cd 100644
--- a/mesalib/src/mesa/state_tracker/st_context.h
+++ b/mesalib/src/mesa/state_tracker/st_context.h
@@ -1,270 +1,270 @@
-/**************************************************************************
- *
- * Copyright 2003 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.
- *
- **************************************************************************/
-
-#ifndef ST_CONTEXT_H
-#define ST_CONTEXT_H
-
-#include "main/mtypes.h"
-#include "pipe/p_state.h"
-#include "state_tracker/st_api.h"
-
-struct bitmap_cache;
-struct blit_state;
-struct dd_function_table;
-struct draw_context;
-struct draw_stage;
-struct gen_mipmap_state;
-struct st_context;
-struct st_fragment_program;
-
-
-#define ST_NEW_MESA 0x1 /* Mesa state has changed */
-#define ST_NEW_FRAGMENT_PROGRAM 0x2
-#define ST_NEW_VERTEX_PROGRAM 0x4
-#define ST_NEW_FRAMEBUFFER 0x8
-#define ST_NEW_EDGEFLAGS_DATA 0x10
-#define ST_NEW_GEOMETRY_PROGRAM 0x20
-
-
-struct st_state_flags {
- GLuint mesa;
- GLuint st;
-};
-
-struct st_tracked_state {
- const char *name;
- struct st_state_flags dirty;
- void (*update)( struct st_context *st );
-};
-
-
-
-struct st_context
-{
- struct st_context_iface iface;
-
- struct gl_context *ctx;
-
- struct pipe_context *pipe;
-
- struct draw_context *draw; /**< For selection/feedback/rastpos only */
- struct draw_stage *feedback_stage; /**< For GL_FEEDBACK rendermode */
- struct draw_stage *selection_stage; /**< For GL_SELECT rendermode */
- struct draw_stage *rastpos_stage; /**< For glRasterPos */
-
-
- /* On old libGL's for linux we need to invalidate the drawables
- * on glViewpport calls, this is set via a option.
- */
- boolean invalidate_on_gl_viewport;
-
- /* Some state is contained in constant objects.
- * Other state is just parameter values.
- */
- struct {
- struct pipe_blend_state blend;
- struct pipe_depth_stencil_alpha_state depth_stencil;
- struct pipe_rasterizer_state rasterizer;
- struct pipe_sampler_state samplers[PIPE_MAX_SAMPLERS];
- struct pipe_sampler_state *sampler_list[PIPE_MAX_SAMPLERS];
- struct pipe_clip_state clip;
- struct {
- void *ptr;
- unsigned size;
- } constants[PIPE_SHADER_TYPES];
- struct pipe_framebuffer_state framebuffer;
- struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS];
- struct pipe_scissor_state scissor;
- struct pipe_viewport_state viewport;
- unsigned sample_mask;
-
- GLuint num_samplers;
- GLuint num_textures;
-
- GLuint poly_stipple[32]; /**< In OpenGL's bottom-to-top order */
- } state;
-
- char vendor[100];
- char renderer[100];
-
- struct st_state_flags dirty;
-
- GLboolean missing_textures;
- GLboolean vertdata_edgeflags;
-
- /** Mapping from VERT_RESULT_x to post-transformed vertex slot */
- const GLuint *vertex_result_to_slot;
-
- struct st_vertex_program *vp; /**< Currently bound vertex program */
- struct st_fragment_program *fp; /**< Currently bound fragment program */
- struct st_geometry_program *gp; /**< Currently bound geometry program */
-
- struct st_vp_variant *vp_variant;
- struct st_fp_variant *fp_variant;
- struct st_gp_variant *gp_variant;
-
- struct gl_texture_object *default_texture;
-
- struct {
- struct gl_program_cache *cache;
- struct st_fragment_program *program; /**< cur pixel transfer prog */
- GLuint xfer_prog_sn; /**< pixel xfer program serial no. */
- GLuint user_prog_sn; /**< user fragment program serial no. */
- struct st_fragment_program *combined_prog;
- GLuint combined_prog_sn;
- struct pipe_resource *pixelmap_texture;
- struct pipe_sampler_view *pixelmap_sampler_view;
- boolean pixelmap_enabled; /**< use the pixelmap texture? */
- } pixel_xfer;
-
- /** for glBitmap */
- struct {
- struct pipe_rasterizer_state rasterizer;
- struct pipe_sampler_state samplers[2];
- enum pipe_format tex_format;
- void *vs;
- float vertices[4][3][4]; /**< vertex pos + color + texcoord */
- struct pipe_resource *vbuf;
- unsigned vbuf_slot; /* next free slot in vbuf */
- struct bitmap_cache *cache;
- } bitmap;
-
- /** for glDraw/CopyPixels */
- struct {
- struct gl_fragment_program *shaders[4];
- void *vert_shaders[2]; /**< ureg shaders */
- } drawpix;
-
- /** for glClear */
- struct {
- struct pipe_rasterizer_state raster;
- struct pipe_viewport_state viewport;
- struct pipe_clip_state clip;
- void *vs;
- void *fs;
- float vertices[4][2][4]; /**< vertex pos + color */
- struct pipe_resource *vbuf;
- unsigned vbuf_slot;
- boolean enable_ds_separate;
- } clear;
-
- /** used for anything using util_draw_vertex_buffer */
- struct pipe_vertex_element velems_util_draw[3];
-
- void *passthrough_fs; /**< simple pass-through frag shader */
-
- enum pipe_texture_target internal_target;
- struct gen_mipmap_state *gen_mipmap;
- struct blit_state *blit;
-
- struct cso_context *cso_context;
-
- int force_msaa;
- void *winsys_drawable_handle;
-
- /* User vertex buffers. */
- struct pipe_resource *user_vb[PIPE_MAX_ATTRIBS];
- unsigned user_vb_stride[PIPE_MAX_ATTRIBS];
- unsigned num_user_vbs;
-};
-
-
-/* Need this so that we can implement Mesa callbacks in this module.
- */
-static INLINE struct st_context *st_context(struct gl_context *ctx)
-{
- return ctx->st;
-}
-
-
-/**
- * Wrapper for struct gl_framebuffer.
- * This is an opaque type to the outside world.
- */
-struct st_framebuffer
-{
- struct gl_framebuffer Base;
- void *Private;
-
- struct st_framebuffer_iface *iface;
- enum st_attachment_type statts[ST_ATTACHMENT_COUNT];
- unsigned num_statts;
- int32_t revalidate;
-};
-
-
-extern void st_init_driver_functions(struct dd_function_table *functions);
-
-void st_invalidate_state(struct gl_context * ctx, GLuint new_state);
-
-
-
-#define Y_0_TOP 1
-#define Y_0_BOTTOM 2
-
-static INLINE GLuint
-st_fb_orientation(const struct gl_framebuffer *fb)
-{
- if (fb && fb->Name == 0) {
- /* Drawing into a window (on-screen buffer).
- *
- * Negate Y scale to flip image vertically.
- * The NDC Y coords prior to viewport transformation are in the range
- * [y=-1=bottom, y=1=top]
- * Hardware window coords are in the range [y=0=top, y=H-1=bottom] where
- * H is the window height.
- * Use the viewport transformation to invert Y.
- */
- return Y_0_TOP;
- }
- else {
- /* Drawing into user-created FBO (very likely a texture).
- *
- * For textures, T=0=Bottom, so by extension Y=0=Bottom for rendering.
- */
- return Y_0_BOTTOM;
- }
-}
-
-
-/** clear-alloc a struct-sized object, with casting */
-#define ST_CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T))
-
-
-extern int
-st_get_msaa(void);
-
-extern struct st_context *
-st_create_context(gl_api api, struct pipe_context *pipe,
- const struct gl_config *visual,
- struct st_context *share);
-
-extern void
-st_destroy_context(struct st_context *st);
-
-
-#endif
+/**************************************************************************
+ *
+ * Copyright 2003 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.
+ *
+ **************************************************************************/
+
+#ifndef ST_CONTEXT_H
+#define ST_CONTEXT_H
+
+#include "main/mtypes.h"
+#include "pipe/p_state.h"
+#include "state_tracker/st_api.h"
+
+struct bitmap_cache;
+struct blit_state;
+struct dd_function_table;
+struct draw_context;
+struct draw_stage;
+struct gen_mipmap_state;
+struct st_context;
+struct st_fragment_program;
+
+
+#define ST_NEW_MESA 0x1 /* Mesa state has changed */
+#define ST_NEW_FRAGMENT_PROGRAM 0x2
+#define ST_NEW_VERTEX_PROGRAM 0x4
+#define ST_NEW_FRAMEBUFFER 0x8
+#define ST_NEW_EDGEFLAGS_DATA 0x10
+#define ST_NEW_GEOMETRY_PROGRAM 0x20
+
+
+struct st_state_flags {
+ GLuint mesa;
+ GLuint st;
+};
+
+struct st_tracked_state {
+ const char *name;
+ struct st_state_flags dirty;
+ void (*update)( struct st_context *st );
+};
+
+
+
+struct st_context
+{
+ struct st_context_iface iface;
+
+ struct gl_context *ctx;
+
+ struct pipe_context *pipe;
+
+ struct draw_context *draw; /**< For selection/feedback/rastpos only */
+ struct draw_stage *feedback_stage; /**< For GL_FEEDBACK rendermode */
+ struct draw_stage *selection_stage; /**< For GL_SELECT rendermode */
+ struct draw_stage *rastpos_stage; /**< For glRasterPos */
+
+
+ /* On old libGL's for linux we need to invalidate the drawables
+ * on glViewpport calls, this is set via a option.
+ */
+ boolean invalidate_on_gl_viewport;
+
+ /* Some state is contained in constant objects.
+ * Other state is just parameter values.
+ */
+ struct {
+ struct pipe_blend_state blend;
+ struct pipe_depth_stencil_alpha_state depth_stencil;
+ struct pipe_rasterizer_state rasterizer;
+ struct pipe_sampler_state samplers[PIPE_MAX_SAMPLERS];
+ struct pipe_sampler_state *sampler_list[PIPE_MAX_SAMPLERS];
+ struct pipe_clip_state clip;
+ struct {
+ void *ptr;
+ unsigned size;
+ } constants[PIPE_SHADER_TYPES];
+ struct pipe_framebuffer_state framebuffer;
+ struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS];
+ struct pipe_scissor_state scissor;
+ struct pipe_viewport_state viewport;
+ unsigned sample_mask;
+
+ GLuint num_samplers;
+ GLuint num_textures;
+
+ GLuint poly_stipple[32]; /**< In OpenGL's bottom-to-top order */
+ } state;
+
+ char vendor[100];
+ char renderer[100];
+
+ struct st_state_flags dirty;
+
+ GLboolean missing_textures;
+ GLboolean vertdata_edgeflags;
+
+ /** Mapping from VERT_RESULT_x to post-transformed vertex slot */
+ const GLuint *vertex_result_to_slot;
+
+ struct st_vertex_program *vp; /**< Currently bound vertex program */
+ struct st_fragment_program *fp; /**< Currently bound fragment program */
+ struct st_geometry_program *gp; /**< Currently bound geometry program */
+
+ struct st_vp_variant *vp_variant;
+ struct st_fp_variant *fp_variant;
+ struct st_gp_variant *gp_variant;
+
+ struct gl_texture_object *default_texture;
+
+ struct {
+ struct gl_program_cache *cache;
+ struct st_fragment_program *program; /**< cur pixel transfer prog */
+ GLuint xfer_prog_sn; /**< pixel xfer program serial no. */
+ GLuint user_prog_sn; /**< user fragment program serial no. */
+ struct st_fragment_program *combined_prog;
+ GLuint combined_prog_sn;
+ struct pipe_resource *pixelmap_texture;
+ struct pipe_sampler_view *pixelmap_sampler_view;
+ boolean pixelmap_enabled; /**< use the pixelmap texture? */
+ } pixel_xfer;
+
+ /** for glBitmap */
+ struct {
+ struct pipe_rasterizer_state rasterizer;
+ struct pipe_sampler_state samplers[2];
+ enum pipe_format tex_format;
+ void *vs;
+ float vertices[4][3][4]; /**< vertex pos + color + texcoord */
+ struct pipe_resource *vbuf;
+ unsigned vbuf_slot; /* next free slot in vbuf */
+ struct bitmap_cache *cache;
+ } bitmap;
+
+ /** for glDraw/CopyPixels */
+ struct {
+ struct gl_fragment_program *shaders[4];
+ void *vert_shaders[2]; /**< ureg shaders */
+ } drawpix;
+
+ /** for glClear */
+ struct {
+ struct pipe_rasterizer_state raster;
+ struct pipe_viewport_state viewport;
+ struct pipe_clip_state clip;
+ void *vs;
+ void *fs;
+ float vertices[4][2][4]; /**< vertex pos + color */
+ struct pipe_resource *vbuf;
+ unsigned vbuf_slot;
+ boolean enable_ds_separate;
+ } clear;
+
+ /** used for anything using util_draw_vertex_buffer */
+ struct pipe_vertex_element velems_util_draw[3];
+
+ void *passthrough_fs; /**< simple pass-through frag shader */
+
+ enum pipe_texture_target internal_target;
+ struct gen_mipmap_state *gen_mipmap;
+ struct blit_state *blit;
+
+ struct cso_context *cso_context;
+
+ int force_msaa;
+ void *winsys_drawable_handle;
+
+ /* User vertex buffers. */
+ struct pipe_resource *user_vb[PIPE_MAX_ATTRIBS];
+ unsigned user_vb_stride[PIPE_MAX_ATTRIBS];
+ unsigned num_user_vbs;
+};
+
+
+/* Need this so that we can implement Mesa callbacks in this module.
+ */
+static INLINE struct st_context *st_context(struct gl_context *ctx)
+{
+ return ctx->st;
+}
+
+
+/**
+ * Wrapper for struct gl_framebuffer.
+ * This is an opaque type to the outside world.
+ */
+struct st_framebuffer
+{
+ struct gl_framebuffer Base;
+ void *Private;
+
+ struct st_framebuffer_iface *iface;
+ enum st_attachment_type statts[ST_ATTACHMENT_COUNT];
+ unsigned num_statts;
+ int32_t revalidate;
+};
+
+
+extern void st_init_driver_functions(struct dd_function_table *functions);
+
+void st_invalidate_state(struct gl_context * ctx, GLuint new_state);
+
+
+
+#define Y_0_TOP 1
+#define Y_0_BOTTOM 2
+
+static INLINE GLuint
+st_fb_orientation(const struct gl_framebuffer *fb)
+{
+ if (fb && fb->Name == 0) {
+ /* Drawing into a window (on-screen buffer).
+ *
+ * Negate Y scale to flip image vertically.
+ * The NDC Y coords prior to viewport transformation are in the range
+ * [y=-1=bottom, y=1=top]
+ * Hardware window coords are in the range [y=0=top, y=H-1=bottom] where
+ * H is the window height.
+ * Use the viewport transformation to invert Y.
+ */
+ return Y_0_TOP;
+ }
+ else {
+ /* Drawing into user-created FBO (very likely a texture).
+ *
+ * For textures, T=0=Bottom, so by extension Y=0=Bottom for rendering.
+ */
+ return Y_0_BOTTOM;
+ }
+}
+
+
+/** clear-alloc a struct-sized object, with casting */
+#define ST_CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T))
+
+
+extern int
+st_get_msaa(void);
+
+extern struct st_context *
+st_create_context(gl_api api, struct pipe_context *pipe,
+ const struct gl_config *visual,
+ struct st_context *share);
+
+extern void
+st_destroy_context(struct st_context *st);
+
+
+#endif
diff --git a/mesalib/src/mesa/state_tracker/st_draw.c b/mesalib/src/mesa/state_tracker/st_draw.c
index 11ebd067e..7f661d529 100644
--- a/mesalib/src/mesa/state_tracker/st_draw.c
+++ b/mesalib/src/mesa/state_tracker/st_draw.c
@@ -1,759 +1,759 @@
-/**************************************************************************
- *
- * 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.
- *
- **************************************************************************/
-
-/*
- * This file implements the st_draw_vbo() function which is called from
- * Mesa's VBO module. All point/line/triangle rendering is done through
- * this function whether the user called glBegin/End, glDrawArrays,
- * glDrawElements, glEvalMesh, or glCalList, etc.
- *
- * We basically convert the VBO's vertex attribute/array information into
- * Gallium vertex state, bind the vertex buffer objects and call
- * pipe->draw_elements(), pipe->draw_range_elements() or pipe->draw_arrays().
- *
- * Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
- */
-
-
-#include "main/imports.h"
-#include "main/image.h"
-#include "main/macros.h"
-#include "main/mfeatures.h"
-#include "program/prog_uniform.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 "util/u_format.h"
-#include "util/u_prim.h"
-#include "util/u_draw_quad.h"
-#include "draw/draw_context.h"
-#include "cso_cache/cso_context.h"
-
-
-static GLuint double_types[4] = {
- PIPE_FORMAT_R64_FLOAT,
- PIPE_FORMAT_R64G64_FLOAT,
- PIPE_FORMAT_R64G64B64_FLOAT,
- PIPE_FORMAT_R64G64B64A64_FLOAT
-};
-
-static GLuint float_types[4] = {
- PIPE_FORMAT_R32_FLOAT,
- PIPE_FORMAT_R32G32_FLOAT,
- PIPE_FORMAT_R32G32B32_FLOAT,
- PIPE_FORMAT_R32G32B32A32_FLOAT
-};
-
-static GLuint half_float_types[4] = {
- PIPE_FORMAT_R16_FLOAT,
- PIPE_FORMAT_R16G16_FLOAT,
- PIPE_FORMAT_R16G16B16_FLOAT,
- PIPE_FORMAT_R16G16B16A16_FLOAT
-};
-
-static GLuint uint_types_norm[4] = {
- PIPE_FORMAT_R32_UNORM,
- PIPE_FORMAT_R32G32_UNORM,
- PIPE_FORMAT_R32G32B32_UNORM,
- PIPE_FORMAT_R32G32B32A32_UNORM
-};
-
-static GLuint uint_types_scale[4] = {
- PIPE_FORMAT_R32_USCALED,
- PIPE_FORMAT_R32G32_USCALED,
- PIPE_FORMAT_R32G32B32_USCALED,
- PIPE_FORMAT_R32G32B32A32_USCALED
-};
-
-static GLuint int_types_norm[4] = {
- PIPE_FORMAT_R32_SNORM,
- PIPE_FORMAT_R32G32_SNORM,
- PIPE_FORMAT_R32G32B32_SNORM,
- PIPE_FORMAT_R32G32B32A32_SNORM
-};
-
-static GLuint int_types_scale[4] = {
- PIPE_FORMAT_R32_SSCALED,
- PIPE_FORMAT_R32G32_SSCALED,
- PIPE_FORMAT_R32G32B32_SSCALED,
- PIPE_FORMAT_R32G32B32A32_SSCALED
-};
-
-static GLuint ushort_types_norm[4] = {
- PIPE_FORMAT_R16_UNORM,
- PIPE_FORMAT_R16G16_UNORM,
- PIPE_FORMAT_R16G16B16_UNORM,
- PIPE_FORMAT_R16G16B16A16_UNORM
-};
-
-static GLuint ushort_types_scale[4] = {
- PIPE_FORMAT_R16_USCALED,
- PIPE_FORMAT_R16G16_USCALED,
- PIPE_FORMAT_R16G16B16_USCALED,
- PIPE_FORMAT_R16G16B16A16_USCALED
-};
-
-static GLuint short_types_norm[4] = {
- PIPE_FORMAT_R16_SNORM,
- PIPE_FORMAT_R16G16_SNORM,
- PIPE_FORMAT_R16G16B16_SNORM,
- PIPE_FORMAT_R16G16B16A16_SNORM
-};
-
-static GLuint short_types_scale[4] = {
- PIPE_FORMAT_R16_SSCALED,
- PIPE_FORMAT_R16G16_SSCALED,
- PIPE_FORMAT_R16G16B16_SSCALED,
- PIPE_FORMAT_R16G16B16A16_SSCALED
-};
-
-static GLuint ubyte_types_norm[4] = {
- PIPE_FORMAT_R8_UNORM,
- PIPE_FORMAT_R8G8_UNORM,
- PIPE_FORMAT_R8G8B8_UNORM,
- PIPE_FORMAT_R8G8B8A8_UNORM
-};
-
-static GLuint ubyte_types_scale[4] = {
- PIPE_FORMAT_R8_USCALED,
- PIPE_FORMAT_R8G8_USCALED,
- PIPE_FORMAT_R8G8B8_USCALED,
- PIPE_FORMAT_R8G8B8A8_USCALED
-};
-
-static GLuint byte_types_norm[4] = {
- PIPE_FORMAT_R8_SNORM,
- PIPE_FORMAT_R8G8_SNORM,
- PIPE_FORMAT_R8G8B8_SNORM,
- PIPE_FORMAT_R8G8B8A8_SNORM
-};
-
-static GLuint byte_types_scale[4] = {
- PIPE_FORMAT_R8_SSCALED,
- PIPE_FORMAT_R8G8_SSCALED,
- PIPE_FORMAT_R8G8B8_SSCALED,
- PIPE_FORMAT_R8G8B8A8_SSCALED
-};
-
-static GLuint fixed_types[4] = {
- PIPE_FORMAT_R32_FIXED,
- PIPE_FORMAT_R32G32_FIXED,
- PIPE_FORMAT_R32G32B32_FIXED,
- PIPE_FORMAT_R32G32B32A32_FIXED
-};
-
-
-
-/**
- * Return a PIPE_FORMAT_x for the given GL datatype and size.
- */
-GLuint
-st_pipe_vertex_format(GLenum type, GLuint size, GLenum format,
- GLboolean normalized)
-{
- assert((type >= GL_BYTE && type <= GL_DOUBLE) ||
- type == GL_FIXED || type == GL_HALF_FLOAT);
- assert(size >= 1);
- assert(size <= 4);
- assert(format == GL_RGBA || format == GL_BGRA);
-
- if (format == GL_BGRA) {
- /* this is an odd-ball case */
- assert(type == GL_UNSIGNED_BYTE);
- assert(normalized);
- return PIPE_FORMAT_B8G8R8A8_UNORM;
- }
-
- if (normalized) {
- switch (type) {
- case GL_DOUBLE: return double_types[size-1];
- case GL_FLOAT: return float_types[size-1];
- case GL_HALF_FLOAT: return half_float_types[size-1];
- case GL_INT: return int_types_norm[size-1];
- case GL_SHORT: return short_types_norm[size-1];
- case GL_BYTE: return byte_types_norm[size-1];
- case GL_UNSIGNED_INT: return uint_types_norm[size-1];
- case GL_UNSIGNED_SHORT: return ushort_types_norm[size-1];
- case GL_UNSIGNED_BYTE: return ubyte_types_norm[size-1];
- case GL_FIXED: return fixed_types[size-1];
- default: assert(0); return 0;
- }
- }
- else {
- switch (type) {
- case GL_DOUBLE: return double_types[size-1];
- case GL_FLOAT: return float_types[size-1];
- case GL_HALF_FLOAT: return half_float_types[size-1];
- case GL_INT: return int_types_scale[size-1];
- case GL_SHORT: return short_types_scale[size-1];
- case GL_BYTE: return byte_types_scale[size-1];
- case GL_UNSIGNED_INT: return uint_types_scale[size-1];
- case GL_UNSIGNED_SHORT: return ushort_types_scale[size-1];
- case GL_UNSIGNED_BYTE: return ubyte_types_scale[size-1];
- case GL_FIXED: return fixed_types[size-1];
- default: assert(0); return 0;
- }
- }
- return 0; /* silence compiler warning */
-}
-
-
-
-
-
-/**
- * Examine the active arrays to determine if we have interleaved
- * vertex arrays all living in one VBO, or all living in user space.
- * \param userSpace returns whether the arrays are in user space.
- */
-static GLboolean
-is_interleaved_arrays(const struct st_vertex_program *vp,
- const struct st_vp_variant *vpv,
- const struct gl_client_array **arrays)
-{
- GLuint attr;
- const struct gl_buffer_object *firstBufObj = NULL;
- GLint firstStride = -1;
- const GLubyte *client_addr = NULL;
- GLboolean user_memory;
-
- for (attr = 0; attr < vpv->num_inputs; attr++) {
- const GLuint mesaAttr = vp->index_to_input[attr];
- const struct gl_buffer_object *bufObj = arrays[mesaAttr]->BufferObj;
- const GLsizei stride = arrays[mesaAttr]->StrideB; /* in bytes */
-
- if (firstStride < 0) {
- firstStride = stride;
- user_memory = !bufObj || !bufObj->Name;
- }
- else if (firstStride != stride) {
- return GL_FALSE;
- }
-
- if (!bufObj || !bufObj->Name) {
- /* Try to detect if the client-space arrays are
- * "close" to each other.
- */
- if (!user_memory) {
- return GL_FALSE;
- }
- if (!client_addr) {
- client_addr = arrays[mesaAttr]->Ptr;
- }
- else if (abs(arrays[mesaAttr]->Ptr - client_addr) > firstStride) {
- /* arrays start too far apart */
- return GL_FALSE;
- }
- }
- else if (!firstBufObj) {
- if (user_memory) {
- return GL_FALSE;
- }
- firstBufObj = bufObj;
- }
- else if (bufObj != firstBufObj) {
- return GL_FALSE;
- }
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Set up for drawing interleaved arrays that all live in one VBO
- * or all live in user space.
- * \param vbuffer returns vertex buffer info
- * \param velements returns vertex element info
- */
-static void
-setup_interleaved_attribs(struct gl_context *ctx,
- const struct st_vertex_program *vp,
- const struct st_vp_variant *vpv,
- const struct gl_client_array **arrays,
- struct pipe_vertex_buffer *vbuffer,
- struct pipe_vertex_element velements[],
- unsigned max_index)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- GLuint attr;
- const GLubyte *low_addr = NULL;
-
- /* Find the lowest address. */
- for (attr = 0; attr < vpv->num_inputs; attr++) {
- const GLubyte *start = arrays[vp->index_to_input[attr]]->Ptr;
-
- low_addr = !low_addr ? start : MIN2(low_addr, start);
- }
-
- for (attr = 0; attr < vpv->num_inputs; attr++) {
- const GLuint mesaAttr = vp->index_to_input[attr];
- struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj;
- struct st_buffer_object *stobj = st_buffer_object(bufobj);
- GLsizei stride = arrays[mesaAttr]->StrideB;
-
- if (attr == 0) {
- if (bufobj && bufobj->Name) {
- vbuffer->buffer = NULL;
- pipe_resource_reference(&vbuffer->buffer, stobj->buffer);
- vbuffer->buffer_offset = pointer_to_offset(low_addr);
- } else {
- vbuffer->buffer =
- pipe_user_buffer_create(pipe->screen, (void*)low_addr,
- stride * (max_index + 1),
- PIPE_BIND_VERTEX_BUFFER);
- vbuffer->buffer_offset = 0;
-
- /* Track user vertex buffers. */
- pipe_resource_reference(&st->user_vb[0], vbuffer->buffer);
- st->user_vb_stride[0] = stride;
- st->num_user_vbs = 1;
- }
- vbuffer->stride = stride; /* in bytes */
- }
-
- velements[attr].src_offset =
- (unsigned) (arrays[mesaAttr]->Ptr - low_addr);
- velements[attr].instance_divisor = arrays[mesaAttr]->InstanceDivisor;
- velements[attr].vertex_buffer_index = 0;
- 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);
- }
-}
-
-
-/**
- * Set up a separate pipe_vertex_buffer and pipe_vertex_element for each
- * vertex attribute.
- * \param vbuffer returns vertex buffer info
- * \param velements returns vertex element info
- */
-static void
-setup_non_interleaved_attribs(struct gl_context *ctx,
- const struct st_vertex_program *vp,
- const struct st_vp_variant *vpv,
- const struct gl_client_array **arrays,
- struct pipe_vertex_buffer vbuffer[],
- struct pipe_vertex_element velements[],
- unsigned max_index)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- GLuint attr;
-
- for (attr = 0; attr < vpv->num_inputs; attr++) {
- const GLuint mesaAttr = vp->index_to_input[attr];
- struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj;
- GLsizei stride = arrays[mesaAttr]->StrideB;
-
- 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);
-
- vbuffer[attr].buffer = NULL;
- pipe_resource_reference(&vbuffer[attr].buffer, stobj->buffer);
- vbuffer[attr].buffer_offset = pointer_to_offset(arrays[mesaAttr]->Ptr);
- }
- else {
- /* wrap user data */
- if (arrays[mesaAttr]->Ptr) {
- vbuffer[attr].buffer =
- pipe_user_buffer_create(pipe->screen,
- (void *) arrays[mesaAttr]->Ptr,
- stride * (max_index + 1),
- PIPE_BIND_VERTEX_BUFFER);
- }
- else {
- /* no array, use ctx->Current.Attrib[] value */
- uint bytes = sizeof(ctx->Current.Attrib[0]);
- vbuffer[attr].buffer =
- pipe_user_buffer_create(pipe->screen,
- (void *) ctx->Current.Attrib[mesaAttr],
- bytes,
- PIPE_BIND_VERTEX_BUFFER);
- stride = 0;
- }
-
- vbuffer[attr].buffer_offset = 0;
-
- /* Track user vertex buffers. */
- pipe_resource_reference(&st->user_vb[attr], vbuffer->buffer);
- st->user_vb_stride[attr] = stride;
- st->num_user_vbs = MAX2(st->num_user_vbs, attr+1);
- }
-
- /* common-case setup */
- vbuffer[attr].stride = stride; /* in bytes */
-
- velements[attr].src_offset = 0;
- velements[attr].instance_divisor = arrays[mesaAttr]->InstanceDivisor;
- 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);
- }
-}
-
-
-static void
-setup_index_buffer(struct gl_context *ctx,
- const struct _mesa_index_buffer *ib,
- struct pipe_index_buffer *ibuffer)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
-
- 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;
- }
-
- /* get/create the index buffer object */
- if (bufobj && bufobj->Name) {
- /* elements/indexes are in a real VBO */
- struct st_buffer_object *stobj = st_buffer_object(bufobj);
- pipe_resource_reference(&ibuffer->buffer, stobj->buffer);
- ibuffer->offset = pointer_to_offset(ib->ptr);
- }
- else {
- /* element/indicies are in user space memory */
- ibuffer->buffer =
- pipe_user_buffer_create(pipe->screen, (void *) ib->ptr,
- ib->count * ibuffer->index_size,
- PIPE_BIND_INDEX_BUFFER);
- }
- }
-}
-
-/**
- * Prior to drawing, check that any uniforms referenced by the
- * current shader have been set. If a uniform has not been set,
- * issue a warning.
- */
-static void
-check_uniforms(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 || !shProg[j]->LinkStatus)
- continue;
-
- for (i = 0; i < shProg[j]->Uniforms->NumUniforms; i++) {
- const struct gl_uniform *u = &shProg[j]->Uniforms->Uniforms[i];
- if (!u->Initialized) {
- _mesa_warning(ctx,
- "Using shader with uninitialized uniform: %s",
- u->Name);
- }
- }
- }
-}
-
-
-/**
- * Translate OpenGL primtive type (GL_POINTS, GL_TRIANGLE_STRIP, etc) to
- * the corresponding Gallium type.
- */
-static unsigned
-translate_prim(const struct gl_context *ctx, unsigned prim)
-{
- /* GL prims should match Gallium prims, spot-check a few */
- assert(GL_POINTS == PIPE_PRIM_POINTS);
- assert(GL_QUADS == PIPE_PRIM_QUADS);
- assert(GL_TRIANGLE_STRIP_ADJACENCY == PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY);
-
- /* Avoid quadstrips if it's easy to do so:
- * Note: it's imporant to do the correct trimming if we change the prim type!
- * We do that wherever this function is called.
- */
- if (prim == GL_QUAD_STRIP &&
- ctx->Light.ShadeModel != GL_FLAT &&
- ctx->Polygon.FrontMode == GL_FILL &&
- ctx->Polygon.BackMode == GL_FILL)
- prim = GL_TRIANGLE_STRIP;
-
- return prim;
-}
-
-
-static void
-st_validate_varrays(struct gl_context *ctx,
- const struct gl_client_array **arrays,
- unsigned max_index)
-{
- struct st_context *st = st_context(ctx);
- const struct st_vertex_program *vp;
- const struct st_vp_variant *vpv;
- struct pipe_vertex_buffer vbuffer[PIPE_MAX_SHADER_INPUTS];
- struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS];
- unsigned num_vbuffers, num_velements;
- GLuint attr;
- unsigned i;
-
- /* must get these after state validation! */
- vp = st->vp;
- vpv = st->vp_variant;
-
- memset(velements, 0, sizeof(struct pipe_vertex_element) * vpv->num_inputs);
-
- /* Unreference any user vertex buffers. */
- for (i = 0; i < st->num_user_vbs; i++) {
- pipe_resource_reference(&st->user_vb[i], NULL);
- }
- st->num_user_vbs = 0;
-
- /*
- * Setup the vbuffer[] and velements[] arrays.
- */
- if (is_interleaved_arrays(vp, vpv, arrays)) {
- setup_interleaved_attribs(ctx, vp, vpv, arrays, vbuffer, velements,
- max_index);
- num_vbuffers = 1;
- num_velements = vpv->num_inputs;
- if (num_velements == 0)
- num_vbuffers = 0;
- }
- else {
- setup_non_interleaved_attribs(ctx, vp, vpv, arrays,
- vbuffer, velements, max_index);
- num_vbuffers = vpv->num_inputs;
- num_velements = vpv->num_inputs;
- }
-
- cso_set_vertex_buffers(st->cso_context, num_vbuffers, vbuffer);
- cso_set_vertex_elements(st->cso_context, num_velements, velements);
-
- /* unreference buffers (frees wrapped user-space buffer objects)
- * This is OK, because the pipe driver should reference buffers by itself
- * in set_vertex_buffers. */
- for (attr = 0; attr < num_vbuffers; attr++) {
- pipe_resource_reference(&vbuffer[attr].buffer, NULL);
- assert(!vbuffer[attr].buffer);
- }
-}
-
-
-/**
- * This function gets plugged into the VBO module and is called when
- * we have something to render.
- * Basically, translate the information into the format expected by gallium.
- */
-void
-st_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 pipe_index_buffer ibuffer;
- struct pipe_draw_info info;
- unsigned i;
- GLboolean new_array = GL_TRUE;
- /* Fix this (Bug 34378):
- GLboolean new_array =
- st->dirty.st && (st->dirty.mesa & (_NEW_ARRAY | _NEW_PROGRAM)) != 0;*/
-
- /* Mesa core state should have been validated already */
- assert(ctx->NewState == 0x0);
-
- if (ib) {
- /* Gallium probably doesn't want this in some cases. */
- if (!index_bounds_valid)
- if (!vbo_all_varyings_in_vbos(arrays))
- vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index);
- } else {
- /* Get min/max index for non-indexed drawing. */
- min_index = ~0;
- max_index = 0;
-
- for (i = 0; i < nr_prims; i++) {
- min_index = MIN2(min_index, prims[i].start);
- max_index = MAX2(max_index, prims[i].start + prims[i].count - 1);
- }
- }
-
- /* Validate state. */
- if (st->dirty.st) {
- GLboolean vertDataEdgeFlags;
-
- /* sanity check for pointer arithmetic below */
- assert(sizeof(arrays[0]->Ptr[0]) == 1);
-
- vertDataEdgeFlags = arrays[VERT_ATTRIB_EDGEFLAG]->BufferObj &&
- arrays[VERT_ATTRIB_EDGEFLAG]->BufferObj->Name;
- if (vertDataEdgeFlags != st->vertdata_edgeflags) {
- st->vertdata_edgeflags = vertDataEdgeFlags;
- st->dirty.st |= ST_NEW_EDGEFLAGS_DATA;
- }
-
- st_validate_state(st);
-
- if (new_array) {
- st_validate_varrays(ctx, arrays, max_index);
- }
-
-#if 0
- if (MESA_VERBOSE & VERBOSE_GLSL) {
- check_uniforms(ctx);
- }
-#else
- (void) check_uniforms;
-#endif
- }
-
- /* Notify the driver that the content of user buffers may have been
- * changed. */
- if (!new_array && st->num_user_vbs) {
- for (i = 0; i < st->num_user_vbs; i++) {
- if (st->user_vb[i]) {
- unsigned stride = st->user_vb_stride[i];
-
- if (stride) {
- pipe->redefine_user_buffer(pipe, st->user_vb[i],
- min_index * stride,
- (max_index + 1 - min_index) * stride);
- } else {
- /* stride == 0 */
- pipe->redefine_user_buffer(pipe, st->user_vb[i],
- 0, st->user_vb[i]->width0);
- }
- }
- }
- }
-
- setup_index_buffer(ctx, ib, &ibuffer);
- pipe->set_index_buffer(pipe, &ibuffer);
-
- util_draw_init_info(&info);
- if (ib) {
- info.indexed = TRUE;
- if (min_index != ~0 && max_index != ~0) {
- info.min_index = min_index;
- info.max_index = max_index;
- }
- }
-
- info.primitive_restart = st->ctx->Array.PrimitiveRestart;
- info.restart_index = st->ctx->Array.RestartIndex;
-
- /* do actual drawing */
- for (i = 0; i < nr_prims; i++) {
- info.mode = translate_prim( ctx, prims[i].mode );
- info.start = prims[i].start;
- info.count = prims[i].count;
- info.instance_count = prims[i].num_instances;
- info.index_bias = prims[i].basevertex;
- if (!ib) {
- info.min_index = info.start;
- info.max_index = info.start + info.count - 1;
- }
-
- if (u_trim_pipe_prim(info.mode, &info.count))
- pipe->draw_vbo(pipe, &info);
- }
-
- pipe_resource_reference(&ibuffer.buffer, NULL);
-}
-
-
-void st_init_draw( struct st_context *st )
-{
- struct gl_context *ctx = st->ctx;
-
- vbo_set_draw_func(ctx, st_draw_vbo);
-
-#if FEATURE_feedback || FEATURE_rastpos
- st->draw = draw_create(st->pipe); /* for selection/feedback */
-
- /* Disable draw options that might convert points/lines to tris, etc.
- * as that would foul-up feedback/selection mode.
- */
- draw_wide_line_threshold(st->draw, 1000.0f);
- draw_wide_point_threshold(st->draw, 1000.0f);
- draw_enable_line_stipple(st->draw, FALSE);
- draw_enable_point_sprites(st->draw, FALSE);
-#endif
-}
-
-
-void st_destroy_draw( struct st_context *st )
-{
-#if FEATURE_feedback || FEATURE_rastpos
- draw_destroy(st->draw);
-#endif
-}
-
-
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * This file implements the st_draw_vbo() function which is called from
+ * Mesa's VBO module. All point/line/triangle rendering is done through
+ * this function whether the user called glBegin/End, glDrawArrays,
+ * glDrawElements, glEvalMesh, or glCalList, etc.
+ *
+ * We basically convert the VBO's vertex attribute/array information into
+ * Gallium vertex state, bind the vertex buffer objects and call
+ * pipe->draw_elements(), pipe->draw_range_elements() or pipe->draw_arrays().
+ *
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+
+#include "main/imports.h"
+#include "main/image.h"
+#include "main/macros.h"
+#include "main/mfeatures.h"
+#include "program/prog_uniform.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 "util/u_format.h"
+#include "util/u_prim.h"
+#include "util/u_draw_quad.h"
+#include "draw/draw_context.h"
+#include "cso_cache/cso_context.h"
+
+
+static GLuint double_types[4] = {
+ PIPE_FORMAT_R64_FLOAT,
+ PIPE_FORMAT_R64G64_FLOAT,
+ PIPE_FORMAT_R64G64B64_FLOAT,
+ PIPE_FORMAT_R64G64B64A64_FLOAT
+};
+
+static GLuint float_types[4] = {
+ PIPE_FORMAT_R32_FLOAT,
+ PIPE_FORMAT_R32G32_FLOAT,
+ PIPE_FORMAT_R32G32B32_FLOAT,
+ PIPE_FORMAT_R32G32B32A32_FLOAT
+};
+
+static GLuint half_float_types[4] = {
+ PIPE_FORMAT_R16_FLOAT,
+ PIPE_FORMAT_R16G16_FLOAT,
+ PIPE_FORMAT_R16G16B16_FLOAT,
+ PIPE_FORMAT_R16G16B16A16_FLOAT
+};
+
+static GLuint uint_types_norm[4] = {
+ PIPE_FORMAT_R32_UNORM,
+ PIPE_FORMAT_R32G32_UNORM,
+ PIPE_FORMAT_R32G32B32_UNORM,
+ PIPE_FORMAT_R32G32B32A32_UNORM
+};
+
+static GLuint uint_types_scale[4] = {
+ PIPE_FORMAT_R32_USCALED,
+ PIPE_FORMAT_R32G32_USCALED,
+ PIPE_FORMAT_R32G32B32_USCALED,
+ PIPE_FORMAT_R32G32B32A32_USCALED
+};
+
+static GLuint int_types_norm[4] = {
+ PIPE_FORMAT_R32_SNORM,
+ PIPE_FORMAT_R32G32_SNORM,
+ PIPE_FORMAT_R32G32B32_SNORM,
+ PIPE_FORMAT_R32G32B32A32_SNORM
+};
+
+static GLuint int_types_scale[4] = {
+ PIPE_FORMAT_R32_SSCALED,
+ PIPE_FORMAT_R32G32_SSCALED,
+ PIPE_FORMAT_R32G32B32_SSCALED,
+ PIPE_FORMAT_R32G32B32A32_SSCALED
+};
+
+static GLuint ushort_types_norm[4] = {
+ PIPE_FORMAT_R16_UNORM,
+ PIPE_FORMAT_R16G16_UNORM,
+ PIPE_FORMAT_R16G16B16_UNORM,
+ PIPE_FORMAT_R16G16B16A16_UNORM
+};
+
+static GLuint ushort_types_scale[4] = {
+ PIPE_FORMAT_R16_USCALED,
+ PIPE_FORMAT_R16G16_USCALED,
+ PIPE_FORMAT_R16G16B16_USCALED,
+ PIPE_FORMAT_R16G16B16A16_USCALED
+};
+
+static GLuint short_types_norm[4] = {
+ PIPE_FORMAT_R16_SNORM,
+ PIPE_FORMAT_R16G16_SNORM,
+ PIPE_FORMAT_R16G16B16_SNORM,
+ PIPE_FORMAT_R16G16B16A16_SNORM
+};
+
+static GLuint short_types_scale[4] = {
+ PIPE_FORMAT_R16_SSCALED,
+ PIPE_FORMAT_R16G16_SSCALED,
+ PIPE_FORMAT_R16G16B16_SSCALED,
+ PIPE_FORMAT_R16G16B16A16_SSCALED
+};
+
+static GLuint ubyte_types_norm[4] = {
+ PIPE_FORMAT_R8_UNORM,
+ PIPE_FORMAT_R8G8_UNORM,
+ PIPE_FORMAT_R8G8B8_UNORM,
+ PIPE_FORMAT_R8G8B8A8_UNORM
+};
+
+static GLuint ubyte_types_scale[4] = {
+ PIPE_FORMAT_R8_USCALED,
+ PIPE_FORMAT_R8G8_USCALED,
+ PIPE_FORMAT_R8G8B8_USCALED,
+ PIPE_FORMAT_R8G8B8A8_USCALED
+};
+
+static GLuint byte_types_norm[4] = {
+ PIPE_FORMAT_R8_SNORM,
+ PIPE_FORMAT_R8G8_SNORM,
+ PIPE_FORMAT_R8G8B8_SNORM,
+ PIPE_FORMAT_R8G8B8A8_SNORM
+};
+
+static GLuint byte_types_scale[4] = {
+ PIPE_FORMAT_R8_SSCALED,
+ PIPE_FORMAT_R8G8_SSCALED,
+ PIPE_FORMAT_R8G8B8_SSCALED,
+ PIPE_FORMAT_R8G8B8A8_SSCALED
+};
+
+static GLuint fixed_types[4] = {
+ PIPE_FORMAT_R32_FIXED,
+ PIPE_FORMAT_R32G32_FIXED,
+ PIPE_FORMAT_R32G32B32_FIXED,
+ PIPE_FORMAT_R32G32B32A32_FIXED
+};
+
+
+
+/**
+ * Return a PIPE_FORMAT_x for the given GL datatype and size.
+ */
+GLuint
+st_pipe_vertex_format(GLenum type, GLuint size, GLenum format,
+ GLboolean normalized)
+{
+ assert((type >= GL_BYTE && type <= GL_DOUBLE) ||
+ type == GL_FIXED || type == GL_HALF_FLOAT);
+ assert(size >= 1);
+ assert(size <= 4);
+ assert(format == GL_RGBA || format == GL_BGRA);
+
+ if (format == GL_BGRA) {
+ /* this is an odd-ball case */
+ assert(type == GL_UNSIGNED_BYTE);
+ assert(normalized);
+ return PIPE_FORMAT_B8G8R8A8_UNORM;
+ }
+
+ if (normalized) {
+ switch (type) {
+ case GL_DOUBLE: return double_types[size-1];
+ case GL_FLOAT: return float_types[size-1];
+ case GL_HALF_FLOAT: return half_float_types[size-1];
+ case GL_INT: return int_types_norm[size-1];
+ case GL_SHORT: return short_types_norm[size-1];
+ case GL_BYTE: return byte_types_norm[size-1];
+ case GL_UNSIGNED_INT: return uint_types_norm[size-1];
+ case GL_UNSIGNED_SHORT: return ushort_types_norm[size-1];
+ case GL_UNSIGNED_BYTE: return ubyte_types_norm[size-1];
+ case GL_FIXED: return fixed_types[size-1];
+ default: assert(0); return 0;
+ }
+ }
+ else {
+ switch (type) {
+ case GL_DOUBLE: return double_types[size-1];
+ case GL_FLOAT: return float_types[size-1];
+ case GL_HALF_FLOAT: return half_float_types[size-1];
+ case GL_INT: return int_types_scale[size-1];
+ case GL_SHORT: return short_types_scale[size-1];
+ case GL_BYTE: return byte_types_scale[size-1];
+ case GL_UNSIGNED_INT: return uint_types_scale[size-1];
+ case GL_UNSIGNED_SHORT: return ushort_types_scale[size-1];
+ case GL_UNSIGNED_BYTE: return ubyte_types_scale[size-1];
+ case GL_FIXED: return fixed_types[size-1];
+ default: assert(0); return 0;
+ }
+ }
+ return 0; /* silence compiler warning */
+}
+
+
+
+
+
+/**
+ * Examine the active arrays to determine if we have interleaved
+ * vertex arrays all living in one VBO, or all living in user space.
+ * \param userSpace returns whether the arrays are in user space.
+ */
+static GLboolean
+is_interleaved_arrays(const struct st_vertex_program *vp,
+ const struct st_vp_variant *vpv,
+ const struct gl_client_array **arrays)
+{
+ GLuint attr;
+ const struct gl_buffer_object *firstBufObj = NULL;
+ GLint firstStride = -1;
+ const GLubyte *client_addr = NULL;
+ GLboolean user_memory;
+
+ for (attr = 0; attr < vpv->num_inputs; attr++) {
+ const GLuint mesaAttr = vp->index_to_input[attr];
+ const struct gl_buffer_object *bufObj = arrays[mesaAttr]->BufferObj;
+ const GLsizei stride = arrays[mesaAttr]->StrideB; /* in bytes */
+
+ if (firstStride < 0) {
+ firstStride = stride;
+ user_memory = !bufObj || !bufObj->Name;
+ }
+ else if (firstStride != stride) {
+ return GL_FALSE;
+ }
+
+ if (!bufObj || !bufObj->Name) {
+ /* Try to detect if the client-space arrays are
+ * "close" to each other.
+ */
+ if (!user_memory) {
+ return GL_FALSE;
+ }
+ if (!client_addr) {
+ client_addr = arrays[mesaAttr]->Ptr;
+ }
+ else if (abs(arrays[mesaAttr]->Ptr - client_addr) > firstStride) {
+ /* arrays start too far apart */
+ return GL_FALSE;
+ }
+ }
+ else if (!firstBufObj) {
+ if (user_memory) {
+ return GL_FALSE;
+ }
+ firstBufObj = bufObj;
+ }
+ else if (bufObj != firstBufObj) {
+ return GL_FALSE;
+ }
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Set up for drawing interleaved arrays that all live in one VBO
+ * or all live in user space.
+ * \param vbuffer returns vertex buffer info
+ * \param velements returns vertex element info
+ */
+static void
+setup_interleaved_attribs(struct gl_context *ctx,
+ const struct st_vertex_program *vp,
+ const struct st_vp_variant *vpv,
+ const struct gl_client_array **arrays,
+ struct pipe_vertex_buffer *vbuffer,
+ struct pipe_vertex_element velements[],
+ unsigned max_index)
+{
+ struct st_context *st = st_context(ctx);
+ struct pipe_context *pipe = st->pipe;
+ GLuint attr;
+ const GLubyte *low_addr = NULL;
+
+ /* Find the lowest address. */
+ for (attr = 0; attr < vpv->num_inputs; attr++) {
+ const GLubyte *start = arrays[vp->index_to_input[attr]]->Ptr;
+
+ low_addr = !low_addr ? start : MIN2(low_addr, start);
+ }
+
+ for (attr = 0; attr < vpv->num_inputs; attr++) {
+ const GLuint mesaAttr = vp->index_to_input[attr];
+ struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj;
+ struct st_buffer_object *stobj = st_buffer_object(bufobj);
+ GLsizei stride = arrays[mesaAttr]->StrideB;
+
+ if (attr == 0) {
+ if (bufobj && bufobj->Name) {
+ vbuffer->buffer = NULL;
+ pipe_resource_reference(&vbuffer->buffer, stobj->buffer);
+ vbuffer->buffer_offset = pointer_to_offset(low_addr);
+ } else {
+ vbuffer->buffer =
+ pipe_user_buffer_create(pipe->screen, (void*)low_addr,
+ stride * (max_index + 1),
+ PIPE_BIND_VERTEX_BUFFER);
+ vbuffer->buffer_offset = 0;
+
+ /* Track user vertex buffers. */
+ pipe_resource_reference(&st->user_vb[0], vbuffer->buffer);
+ st->user_vb_stride[0] = stride;
+ st->num_user_vbs = 1;
+ }
+ vbuffer->stride = stride; /* in bytes */
+ }
+
+ velements[attr].src_offset =
+ (unsigned) (arrays[mesaAttr]->Ptr - low_addr);
+ velements[attr].instance_divisor = arrays[mesaAttr]->InstanceDivisor;
+ velements[attr].vertex_buffer_index = 0;
+ 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);
+ }
+}
+
+
+/**
+ * Set up a separate pipe_vertex_buffer and pipe_vertex_element for each
+ * vertex attribute.
+ * \param vbuffer returns vertex buffer info
+ * \param velements returns vertex element info
+ */
+static void
+setup_non_interleaved_attribs(struct gl_context *ctx,
+ const struct st_vertex_program *vp,
+ const struct st_vp_variant *vpv,
+ const struct gl_client_array **arrays,
+ struct pipe_vertex_buffer vbuffer[],
+ struct pipe_vertex_element velements[],
+ unsigned max_index)
+{
+ struct st_context *st = st_context(ctx);
+ struct pipe_context *pipe = st->pipe;
+ GLuint attr;
+
+ for (attr = 0; attr < vpv->num_inputs; attr++) {
+ const GLuint mesaAttr = vp->index_to_input[attr];
+ struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj;
+ GLsizei stride = arrays[mesaAttr]->StrideB;
+
+ 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);
+
+ vbuffer[attr].buffer = NULL;
+ pipe_resource_reference(&vbuffer[attr].buffer, stobj->buffer);
+ vbuffer[attr].buffer_offset = pointer_to_offset(arrays[mesaAttr]->Ptr);
+ }
+ else {
+ /* wrap user data */
+ if (arrays[mesaAttr]->Ptr) {
+ vbuffer[attr].buffer =
+ pipe_user_buffer_create(pipe->screen,
+ (void *) arrays[mesaAttr]->Ptr,
+ stride * (max_index + 1),
+ PIPE_BIND_VERTEX_BUFFER);
+ }
+ else {
+ /* no array, use ctx->Current.Attrib[] value */
+ uint bytes = sizeof(ctx->Current.Attrib[0]);
+ vbuffer[attr].buffer =
+ pipe_user_buffer_create(pipe->screen,
+ (void *) ctx->Current.Attrib[mesaAttr],
+ bytes,
+ PIPE_BIND_VERTEX_BUFFER);
+ stride = 0;
+ }
+
+ vbuffer[attr].buffer_offset = 0;
+
+ /* Track user vertex buffers. */
+ pipe_resource_reference(&st->user_vb[attr], vbuffer->buffer);
+ st->user_vb_stride[attr] = stride;
+ st->num_user_vbs = MAX2(st->num_user_vbs, attr+1);
+ }
+
+ /* common-case setup */
+ vbuffer[attr].stride = stride; /* in bytes */
+
+ velements[attr].src_offset = 0;
+ velements[attr].instance_divisor = arrays[mesaAttr]->InstanceDivisor;
+ 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);
+ }
+}
+
+
+static void
+setup_index_buffer(struct gl_context *ctx,
+ const struct _mesa_index_buffer *ib,
+ struct pipe_index_buffer *ibuffer)
+{
+ struct st_context *st = st_context(ctx);
+ struct pipe_context *pipe = st->pipe;
+
+ 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;
+ }
+
+ /* get/create the index buffer object */
+ if (bufobj && bufobj->Name) {
+ /* elements/indexes are in a real VBO */
+ struct st_buffer_object *stobj = st_buffer_object(bufobj);
+ pipe_resource_reference(&ibuffer->buffer, stobj->buffer);
+ ibuffer->offset = pointer_to_offset(ib->ptr);
+ }
+ else {
+ /* element/indicies are in user space memory */
+ ibuffer->buffer =
+ pipe_user_buffer_create(pipe->screen, (void *) ib->ptr,
+ ib->count * ibuffer->index_size,
+ PIPE_BIND_INDEX_BUFFER);
+ }
+ }
+}
+
+/**
+ * Prior to drawing, check that any uniforms referenced by the
+ * current shader have been set. If a uniform has not been set,
+ * issue a warning.
+ */
+static void
+check_uniforms(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 || !shProg[j]->LinkStatus)
+ continue;
+
+ for (i = 0; i < shProg[j]->Uniforms->NumUniforms; i++) {
+ const struct gl_uniform *u = &shProg[j]->Uniforms->Uniforms[i];
+ if (!u->Initialized) {
+ _mesa_warning(ctx,
+ "Using shader with uninitialized uniform: %s",
+ u->Name);
+ }
+ }
+ }
+}
+
+
+/**
+ * Translate OpenGL primtive type (GL_POINTS, GL_TRIANGLE_STRIP, etc) to
+ * the corresponding Gallium type.
+ */
+static unsigned
+translate_prim(const struct gl_context *ctx, unsigned prim)
+{
+ /* GL prims should match Gallium prims, spot-check a few */
+ assert(GL_POINTS == PIPE_PRIM_POINTS);
+ assert(GL_QUADS == PIPE_PRIM_QUADS);
+ assert(GL_TRIANGLE_STRIP_ADJACENCY == PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY);
+
+ /* Avoid quadstrips if it's easy to do so:
+ * Note: it's imporant to do the correct trimming if we change the prim type!
+ * We do that wherever this function is called.
+ */
+ if (prim == GL_QUAD_STRIP &&
+ ctx->Light.ShadeModel != GL_FLAT &&
+ ctx->Polygon.FrontMode == GL_FILL &&
+ ctx->Polygon.BackMode == GL_FILL)
+ prim = GL_TRIANGLE_STRIP;
+
+ return prim;
+}
+
+
+static void
+st_validate_varrays(struct gl_context *ctx,
+ const struct gl_client_array **arrays,
+ unsigned max_index)
+{
+ struct st_context *st = st_context(ctx);
+ const struct st_vertex_program *vp;
+ const struct st_vp_variant *vpv;
+ struct pipe_vertex_buffer vbuffer[PIPE_MAX_SHADER_INPUTS];
+ struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS];
+ unsigned num_vbuffers, num_velements;
+ GLuint attr;
+ unsigned i;
+
+ /* must get these after state validation! */
+ vp = st->vp;
+ vpv = st->vp_variant;
+
+ memset(velements, 0, sizeof(struct pipe_vertex_element) * vpv->num_inputs);
+
+ /* Unreference any user vertex buffers. */
+ for (i = 0; i < st->num_user_vbs; i++) {
+ pipe_resource_reference(&st->user_vb[i], NULL);
+ }
+ st->num_user_vbs = 0;
+
+ /*
+ * Setup the vbuffer[] and velements[] arrays.
+ */
+ if (is_interleaved_arrays(vp, vpv, arrays)) {
+ setup_interleaved_attribs(ctx, vp, vpv, arrays, vbuffer, velements,
+ max_index);
+ num_vbuffers = 1;
+ num_velements = vpv->num_inputs;
+ if (num_velements == 0)
+ num_vbuffers = 0;
+ }
+ else {
+ setup_non_interleaved_attribs(ctx, vp, vpv, arrays,
+ vbuffer, velements, max_index);
+ num_vbuffers = vpv->num_inputs;
+ num_velements = vpv->num_inputs;
+ }
+
+ cso_set_vertex_buffers(st->cso_context, num_vbuffers, vbuffer);
+ cso_set_vertex_elements(st->cso_context, num_velements, velements);
+
+ /* unreference buffers (frees wrapped user-space buffer objects)
+ * This is OK, because the pipe driver should reference buffers by itself
+ * in set_vertex_buffers. */
+ for (attr = 0; attr < num_vbuffers; attr++) {
+ pipe_resource_reference(&vbuffer[attr].buffer, NULL);
+ assert(!vbuffer[attr].buffer);
+ }
+}
+
+
+/**
+ * This function gets plugged into the VBO module and is called when
+ * we have something to render.
+ * Basically, translate the information into the format expected by gallium.
+ */
+void
+st_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 pipe_index_buffer ibuffer;
+ struct pipe_draw_info info;
+ unsigned i;
+ GLboolean new_array = GL_TRUE;
+ /* Fix this (Bug 34378):
+ GLboolean new_array =
+ st->dirty.st && (st->dirty.mesa & (_NEW_ARRAY | _NEW_PROGRAM)) != 0;*/
+
+ /* Mesa core state should have been validated already */
+ assert(ctx->NewState == 0x0);
+
+ if (ib) {
+ /* Gallium probably doesn't want this in some cases. */
+ if (!index_bounds_valid)
+ if (!vbo_all_varyings_in_vbos(arrays))
+ vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index);
+ } else {
+ /* Get min/max index for non-indexed drawing. */
+ min_index = ~0;
+ max_index = 0;
+
+ for (i = 0; i < nr_prims; i++) {
+ min_index = MIN2(min_index, prims[i].start);
+ max_index = MAX2(max_index, prims[i].start + prims[i].count - 1);
+ }
+ }
+
+ /* Validate state. */
+ if (st->dirty.st) {
+ GLboolean vertDataEdgeFlags;
+
+ /* sanity check for pointer arithmetic below */
+ assert(sizeof(arrays[0]->Ptr[0]) == 1);
+
+ vertDataEdgeFlags = arrays[VERT_ATTRIB_EDGEFLAG]->BufferObj &&
+ arrays[VERT_ATTRIB_EDGEFLAG]->BufferObj->Name;
+ if (vertDataEdgeFlags != st->vertdata_edgeflags) {
+ st->vertdata_edgeflags = vertDataEdgeFlags;
+ st->dirty.st |= ST_NEW_EDGEFLAGS_DATA;
+ }
+
+ st_validate_state(st);
+
+ if (new_array) {
+ st_validate_varrays(ctx, arrays, max_index);
+ }
+
+#if 0
+ if (MESA_VERBOSE & VERBOSE_GLSL) {
+ check_uniforms(ctx);
+ }
+#else
+ (void) check_uniforms;
+#endif
+ }
+
+ /* Notify the driver that the content of user buffers may have been
+ * changed. */
+ if (!new_array && st->num_user_vbs) {
+ for (i = 0; i < st->num_user_vbs; i++) {
+ if (st->user_vb[i]) {
+ unsigned stride = st->user_vb_stride[i];
+
+ if (stride) {
+ pipe->redefine_user_buffer(pipe, st->user_vb[i],
+ min_index * stride,
+ (max_index + 1 - min_index) * stride);
+ } else {
+ /* stride == 0 */
+ pipe->redefine_user_buffer(pipe, st->user_vb[i],
+ 0, st->user_vb[i]->width0);
+ }
+ }
+ }
+ }
+
+ setup_index_buffer(ctx, ib, &ibuffer);
+ pipe->set_index_buffer(pipe, &ibuffer);
+
+ util_draw_init_info(&info);
+ if (ib) {
+ info.indexed = TRUE;
+ if (min_index != ~0 && max_index != ~0) {
+ info.min_index = min_index;
+ info.max_index = max_index;
+ }
+ }
+
+ info.primitive_restart = st->ctx->Array.PrimitiveRestart;
+ info.restart_index = st->ctx->Array.RestartIndex;
+
+ /* do actual drawing */
+ for (i = 0; i < nr_prims; i++) {
+ info.mode = translate_prim( ctx, prims[i].mode );
+ info.start = prims[i].start;
+ info.count = prims[i].count;
+ info.instance_count = prims[i].num_instances;
+ info.index_bias = prims[i].basevertex;
+ if (!ib) {
+ info.min_index = info.start;
+ info.max_index = info.start + info.count - 1;
+ }
+
+ if (u_trim_pipe_prim(info.mode, &info.count))
+ pipe->draw_vbo(pipe, &info);
+ }
+
+ pipe_resource_reference(&ibuffer.buffer, NULL);
+}
+
+
+void st_init_draw( struct st_context *st )
+{
+ struct gl_context *ctx = st->ctx;
+
+ vbo_set_draw_func(ctx, st_draw_vbo);
+
+#if FEATURE_feedback || FEATURE_rastpos
+ st->draw = draw_create(st->pipe); /* for selection/feedback */
+
+ /* Disable draw options that might convert points/lines to tris, etc.
+ * as that would foul-up feedback/selection mode.
+ */
+ draw_wide_line_threshold(st->draw, 1000.0f);
+ draw_wide_point_threshold(st->draw, 1000.0f);
+ draw_enable_line_stipple(st->draw, FALSE);
+ draw_enable_point_sprites(st->draw, FALSE);
+#endif
+}
+
+
+void st_destroy_draw( struct st_context *st )
+{
+#if FEATURE_feedback || FEATURE_rastpos
+ draw_destroy(st->draw);
+#endif
+}
+
+
diff --git a/mesalib/src/mesa/state_tracker/st_draw_feedback.c b/mesalib/src/mesa/state_tracker/st_draw_feedback.c
index 1e1220bfe..f0734eae0 100644
--- a/mesalib/src/mesa/state_tracker/st_draw_feedback.c
+++ b/mesalib/src/mesa/state_tracker/st_draw_feedback.c
@@ -1,277 +1,277 @@
-/**************************************************************************
- *
- * 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 */
- 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);
- goto out_unref_vertex;
- }
-
- 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
- */
- 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);
- }
-
- out_unref_vertex:
- for (attr = 0; attr < vp->num_inputs; attr++) {
- pipe_buffer_unmap(pipe, vb_transfer[attr]);
- draw_set_mapped_vertex_buffer(draw, attr, NULL);
- pipe_resource_reference(&vbuffers[attr].buffer, NULL);
- }
- draw_set_vertex_buffers(draw, 0, 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 */
+ 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);
+ goto out_unref_vertex;
+ }
+
+ 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
+ */
+ 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);
+ }
+
+ out_unref_vertex:
+ for (attr = 0; attr < vp->num_inputs; attr++) {
+ pipe_buffer_unmap(pipe, vb_transfer[attr]);
+ draw_set_mapped_vertex_buffer(draw, attr, NULL);
+ pipe_resource_reference(&vbuffers[attr].buffer, NULL);
+ }
+ draw_set_vertex_buffers(draw, 0, NULL);
+}
+
+#endif /* FEATURE_feedback || FEATURE_rastpos */
+
diff --git a/mesalib/src/mesa/state_tracker/st_format.c b/mesalib/src/mesa/state_tracker/st_format.c
index 577ee6189..3620d0cb6 100644
--- a/mesalib/src/mesa/state_tracker/st_format.c
+++ b/mesalib/src/mesa/state_tracker/st_format.c
@@ -1,1149 +1,1149 @@
-/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * Copyright (c) 2008-2010 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, 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.
- *
- **************************************************************************/
-
-
-/**
- * Mesa / Gallium format conversion and format selection code.
- * \author Brian Paul
- */
-
-#include "main/imports.h"
-#include "main/context.h"
-#include "main/texstore.h"
-#include "main/image.h"
-#include "main/macros.h"
-#include "main/mfeatures.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "pipe/p_screen.h"
-#include "util/u_format.h"
-#include "st_context.h"
-#include "st_format.h"
-
-
-static GLuint
-format_max_bits(enum pipe_format format)
-{
- GLuint size = util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 0);
-
- size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 1));
- size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 2));
- size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 3));
- size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 0));
- size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1));
- return size;
-}
-
-
-/**
- * Return basic GL datatype for the given gallium format.
- */
-GLenum
-st_format_datatype(enum pipe_format format)
-{
- const struct util_format_description *desc;
-
- desc = util_format_description(format);
- assert(desc);
-
- if (desc->layout == UTIL_FORMAT_LAYOUT_PLAIN) {
- if (format == PIPE_FORMAT_B5G5R5A1_UNORM ||
- format == PIPE_FORMAT_B5G6R5_UNORM) {
- return GL_UNSIGNED_SHORT;
- }
- else if (format == PIPE_FORMAT_Z24_UNORM_S8_USCALED ||
- format == PIPE_FORMAT_S8_USCALED_Z24_UNORM ||
- format == PIPE_FORMAT_Z24X8_UNORM ||
- format == PIPE_FORMAT_X8Z24_UNORM) {
- return GL_UNSIGNED_INT_24_8;
- }
- else {
- const GLuint size = format_max_bits(format);
- if (size == 8) {
- if (desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED)
- return GL_UNSIGNED_BYTE;
- else
- return GL_BYTE;
- }
- else if (size == 16) {
- if (desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED)
- return GL_UNSIGNED_SHORT;
- else
- return GL_SHORT;
- }
- else {
- assert( size <= 32 );
- if (desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED)
- return GL_UNSIGNED_INT;
- else
- return GL_INT;
- }
- }
- }
- else if (format == PIPE_FORMAT_UYVY) {
- return GL_UNSIGNED_SHORT;
- }
- else if (format == PIPE_FORMAT_YUYV) {
- return GL_UNSIGNED_SHORT;
- }
- else {
- /* probably a compressed format, unsupported anyway */
- return GL_NONE;
- }
-}
-
-
-/**
- * Translate Mesa format to Gallium format.
- */
-enum pipe_format
-st_mesa_format_to_pipe_format(gl_format mesaFormat)
-{
- switch (mesaFormat) {
- case MESA_FORMAT_RGBA8888:
- return PIPE_FORMAT_A8B8G8R8_UNORM;
- case MESA_FORMAT_RGBA8888_REV:
- return PIPE_FORMAT_R8G8B8A8_UNORM;
- case MESA_FORMAT_ARGB8888:
- return PIPE_FORMAT_B8G8R8A8_UNORM;
- case MESA_FORMAT_ARGB8888_REV:
- return PIPE_FORMAT_A8R8G8B8_UNORM;
- case MESA_FORMAT_XRGB8888:
- return PIPE_FORMAT_B8G8R8X8_UNORM;
- case MESA_FORMAT_XRGB8888_REV:
- return PIPE_FORMAT_X8R8G8B8_UNORM;
- case MESA_FORMAT_ARGB1555:
- return PIPE_FORMAT_B5G5R5A1_UNORM;
- case MESA_FORMAT_ARGB4444:
- return PIPE_FORMAT_B4G4R4A4_UNORM;
- case MESA_FORMAT_RGB565:
- return PIPE_FORMAT_B5G6R5_UNORM;
- case MESA_FORMAT_RGB332:
- return PIPE_FORMAT_B2G3R3_UNORM;
- case MESA_FORMAT_ARGB2101010:
- return PIPE_FORMAT_B10G10R10A2_UNORM;
- case MESA_FORMAT_AL44:
- return PIPE_FORMAT_L4A4_UNORM;
- case MESA_FORMAT_AL88:
- return PIPE_FORMAT_L8A8_UNORM;
- case MESA_FORMAT_AL1616:
- return PIPE_FORMAT_L16A16_UNORM;
- case MESA_FORMAT_A8:
- return PIPE_FORMAT_A8_UNORM;
- case MESA_FORMAT_A16:
- return PIPE_FORMAT_A16_UNORM;
- case MESA_FORMAT_L8:
- return PIPE_FORMAT_L8_UNORM;
- case MESA_FORMAT_L16:
- return PIPE_FORMAT_L16_UNORM;
- case MESA_FORMAT_I8:
- return PIPE_FORMAT_I8_UNORM;
- case MESA_FORMAT_I16:
- return PIPE_FORMAT_I16_UNORM;
- case MESA_FORMAT_Z16:
- return PIPE_FORMAT_Z16_UNORM;
- case MESA_FORMAT_Z32:
- return PIPE_FORMAT_Z32_UNORM;
- case MESA_FORMAT_Z24_S8:
- return PIPE_FORMAT_S8_USCALED_Z24_UNORM;
- case MESA_FORMAT_S8_Z24:
- return PIPE_FORMAT_Z24_UNORM_S8_USCALED;
- case MESA_FORMAT_Z24_X8:
- return PIPE_FORMAT_X8Z24_UNORM;
- case MESA_FORMAT_X8_Z24:
- return PIPE_FORMAT_Z24X8_UNORM;
- case MESA_FORMAT_S8:
- return PIPE_FORMAT_S8_USCALED;
- case MESA_FORMAT_YCBCR:
- return PIPE_FORMAT_UYVY;
-#if FEATURE_texture_s3tc
- case MESA_FORMAT_RGB_DXT1:
- return PIPE_FORMAT_DXT1_RGB;
- case MESA_FORMAT_RGBA_DXT1:
- return PIPE_FORMAT_DXT1_RGBA;
- case MESA_FORMAT_RGBA_DXT3:
- return PIPE_FORMAT_DXT3_RGBA;
- case MESA_FORMAT_RGBA_DXT5:
- return PIPE_FORMAT_DXT5_RGBA;
-#if FEATURE_EXT_texture_sRGB
- case MESA_FORMAT_SRGB_DXT1:
- return PIPE_FORMAT_DXT1_SRGB;
- case MESA_FORMAT_SRGBA_DXT1:
- return PIPE_FORMAT_DXT1_SRGBA;
- case MESA_FORMAT_SRGBA_DXT3:
- return PIPE_FORMAT_DXT3_SRGBA;
- case MESA_FORMAT_SRGBA_DXT5:
- return PIPE_FORMAT_DXT5_SRGBA;
-#endif
-#endif
-#if FEATURE_EXT_texture_sRGB
- case MESA_FORMAT_SLA8:
- return PIPE_FORMAT_L8A8_SRGB;
- case MESA_FORMAT_SL8:
- return PIPE_FORMAT_L8_SRGB;
- case MESA_FORMAT_SRGB8:
- return PIPE_FORMAT_R8G8B8_SRGB;
- case MESA_FORMAT_SRGBA8:
- return PIPE_FORMAT_A8B8G8R8_SRGB;
- case MESA_FORMAT_SARGB8:
- return PIPE_FORMAT_B8G8R8A8_SRGB;
-#endif
- case MESA_FORMAT_R8:
- return PIPE_FORMAT_R8_UNORM;
- case MESA_FORMAT_R16:
- return PIPE_FORMAT_R16_UNORM;
- case MESA_FORMAT_RG88:
- return PIPE_FORMAT_R8G8_UNORM;
- case MESA_FORMAT_RG1616:
- return PIPE_FORMAT_R16G16_UNORM;
- case MESA_FORMAT_RGBA_16:
- return PIPE_FORMAT_R16G16B16A16_UNORM;
-
- /* signed int formats */
- case MESA_FORMAT_RGBA_INT8:
- return PIPE_FORMAT_R8G8B8A8_SSCALED;
- case MESA_FORMAT_RGBA_INT16:
- return PIPE_FORMAT_R16G16B16A16_SSCALED;
- case MESA_FORMAT_RGBA_INT32:
- return PIPE_FORMAT_R32G32B32A32_SSCALED;
-
- /* unsigned int formats */
- case MESA_FORMAT_RGBA_UINT8:
- return PIPE_FORMAT_R8G8B8A8_USCALED;
- case MESA_FORMAT_RGBA_UINT16:
- return PIPE_FORMAT_R16G16B16A16_USCALED;
- case MESA_FORMAT_RGBA_UINT32:
- return PIPE_FORMAT_R32G32B32A32_USCALED;
-
- default:
- assert(0);
- return PIPE_FORMAT_NONE;
- }
-}
-
-
-/**
- * Translate Gallium format to Mesa format.
- */
-gl_format
-st_pipe_format_to_mesa_format(enum pipe_format format)
-{
- switch (format) {
- case PIPE_FORMAT_A8B8G8R8_UNORM:
- return MESA_FORMAT_RGBA8888;
- case PIPE_FORMAT_R8G8B8A8_UNORM:
- return MESA_FORMAT_RGBA8888_REV;
- case PIPE_FORMAT_B8G8R8A8_UNORM:
- return MESA_FORMAT_ARGB8888;
- case PIPE_FORMAT_A8R8G8B8_UNORM:
- return MESA_FORMAT_ARGB8888_REV;
- case PIPE_FORMAT_B8G8R8X8_UNORM:
- return MESA_FORMAT_XRGB8888;
- case PIPE_FORMAT_X8R8G8B8_UNORM:
- return MESA_FORMAT_XRGB8888_REV;
- case PIPE_FORMAT_B5G5R5A1_UNORM:
- return MESA_FORMAT_ARGB1555;
- case PIPE_FORMAT_B4G4R4A4_UNORM:
- return MESA_FORMAT_ARGB4444;
- case PIPE_FORMAT_B5G6R5_UNORM:
- return MESA_FORMAT_RGB565;
- case PIPE_FORMAT_B2G3R3_UNORM:
- return MESA_FORMAT_RGB332;
- case PIPE_FORMAT_B10G10R10A2_UNORM:
- return MESA_FORMAT_ARGB2101010;
- case PIPE_FORMAT_L4A4_UNORM:
- return MESA_FORMAT_AL44;
- case PIPE_FORMAT_L8A8_UNORM:
- return MESA_FORMAT_AL88;
- case PIPE_FORMAT_L16A16_UNORM:
- return MESA_FORMAT_AL1616;
- case PIPE_FORMAT_A8_UNORM:
- return MESA_FORMAT_A8;
- case PIPE_FORMAT_A16_UNORM:
- return MESA_FORMAT_A16;
- case PIPE_FORMAT_L8_UNORM:
- return MESA_FORMAT_L8;
- case PIPE_FORMAT_L16_UNORM:
- return MESA_FORMAT_L16;
- case PIPE_FORMAT_I8_UNORM:
- return MESA_FORMAT_I8;
- case PIPE_FORMAT_I16_UNORM:
- return MESA_FORMAT_I16;
- case PIPE_FORMAT_S8_USCALED:
- return MESA_FORMAT_S8;
-
- case PIPE_FORMAT_R16G16B16A16_UNORM:
- return MESA_FORMAT_RGBA_16;
- case PIPE_FORMAT_R16G16B16A16_SNORM:
- return MESA_FORMAT_SIGNED_RGBA_16;
-
- case PIPE_FORMAT_Z16_UNORM:
- return MESA_FORMAT_Z16;
- case PIPE_FORMAT_Z32_UNORM:
- return MESA_FORMAT_Z32;
- case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
- return MESA_FORMAT_Z24_S8;
- case PIPE_FORMAT_X8Z24_UNORM:
- return MESA_FORMAT_Z24_X8;
- case PIPE_FORMAT_Z24X8_UNORM:
- return MESA_FORMAT_X8_Z24;
- case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
- return MESA_FORMAT_S8_Z24;
-
- case PIPE_FORMAT_UYVY:
- return MESA_FORMAT_YCBCR;
- case PIPE_FORMAT_YUYV:
- return MESA_FORMAT_YCBCR_REV;
-
-#if FEATURE_texture_s3tc
- case PIPE_FORMAT_DXT1_RGB:
- return MESA_FORMAT_RGB_DXT1;
- case PIPE_FORMAT_DXT1_RGBA:
- return MESA_FORMAT_RGBA_DXT1;
- case PIPE_FORMAT_DXT3_RGBA:
- return MESA_FORMAT_RGBA_DXT3;
- case PIPE_FORMAT_DXT5_RGBA:
- return MESA_FORMAT_RGBA_DXT5;
-#if FEATURE_EXT_texture_sRGB
- case PIPE_FORMAT_DXT1_SRGB:
- return MESA_FORMAT_SRGB_DXT1;
- case PIPE_FORMAT_DXT1_SRGBA:
- return MESA_FORMAT_SRGBA_DXT1;
- case PIPE_FORMAT_DXT3_SRGBA:
- return MESA_FORMAT_SRGBA_DXT3;
- case PIPE_FORMAT_DXT5_SRGBA:
- return MESA_FORMAT_SRGBA_DXT5;
-#endif
-#endif
-
-#if FEATURE_EXT_texture_sRGB
- case PIPE_FORMAT_L8A8_SRGB:
- return MESA_FORMAT_SLA8;
- case PIPE_FORMAT_L8_SRGB:
- return MESA_FORMAT_SL8;
- case PIPE_FORMAT_R8G8B8_SRGB:
- return MESA_FORMAT_SRGB8;
- case PIPE_FORMAT_A8B8G8R8_SRGB:
- return MESA_FORMAT_SRGBA8;
- case PIPE_FORMAT_B8G8R8A8_SRGB:
- return MESA_FORMAT_SARGB8;
-#endif
-
- case PIPE_FORMAT_R8_UNORM:
- return MESA_FORMAT_R8;
- case PIPE_FORMAT_R16_UNORM:
- return MESA_FORMAT_R16;
- case PIPE_FORMAT_R8G8_UNORM:
- return MESA_FORMAT_RG88;
- case PIPE_FORMAT_R16G16_UNORM:
- return MESA_FORMAT_RG1616;
-
- /* signed int formats */
- case PIPE_FORMAT_R8G8B8A8_SSCALED:
- return MESA_FORMAT_RGBA_INT8;
- case PIPE_FORMAT_R16G16B16A16_SSCALED:
- return MESA_FORMAT_RGBA_INT16;
- case PIPE_FORMAT_R32G32B32A32_SSCALED:
- return MESA_FORMAT_RGBA_INT32;
-
- /* unsigned int formats */
- case PIPE_FORMAT_R8G8B8A8_USCALED:
- return MESA_FORMAT_RGBA_UINT8;
- case PIPE_FORMAT_R16G16B16A16_USCALED:
- return MESA_FORMAT_RGBA_UINT16;
- case PIPE_FORMAT_R32G32B32A32_USCALED:
- return MESA_FORMAT_RGBA_UINT32;
-
- default:
- assert(0);
- return MESA_FORMAT_NONE;
- }
-}
-
-
-/**
- * Return first supported format from the given list.
- */
-static enum pipe_format
-find_supported_format(struct pipe_screen *screen,
- const enum pipe_format formats[],
- uint num_formats,
- enum pipe_texture_target target,
- unsigned sample_count,
- unsigned tex_usage,
- unsigned geom_flags)
-{
- uint i;
- for (i = 0; i < num_formats; i++) {
- if (screen->is_format_supported(screen, formats[i], target,
- sample_count, tex_usage, geom_flags)) {
- return formats[i];
- }
- }
- return PIPE_FORMAT_NONE;
-}
-
-
-/**
- * Find an RGBA format supported by the context/winsys.
- */
-static enum pipe_format
-default_rgba_format(struct pipe_screen *screen,
- enum pipe_texture_target target,
- unsigned sample_count,
- unsigned tex_usage,
- unsigned geom_flags)
-{
- static const enum pipe_format colorFormats[] = {
- PIPE_FORMAT_B8G8R8A8_UNORM,
- PIPE_FORMAT_A8R8G8B8_UNORM,
- PIPE_FORMAT_A8B8G8R8_UNORM,
- PIPE_FORMAT_B5G6R5_UNORM
- };
- return find_supported_format(screen, colorFormats, Elements(colorFormats),
- target, sample_count, tex_usage, geom_flags);
-}
-
-
-/**
- * Find an RGB format supported by the context/winsys.
- */
-static enum pipe_format
-default_rgb_format(struct pipe_screen *screen,
- enum pipe_texture_target target,
- unsigned sample_count,
- unsigned tex_usage,
- unsigned geom_flags)
-{
- static const enum pipe_format colorFormats[] = {
- PIPE_FORMAT_B8G8R8X8_UNORM,
- PIPE_FORMAT_X8R8G8B8_UNORM,
- PIPE_FORMAT_X8B8G8R8_UNORM,
- PIPE_FORMAT_B8G8R8A8_UNORM,
- PIPE_FORMAT_A8R8G8B8_UNORM,
- PIPE_FORMAT_A8B8G8R8_UNORM,
- PIPE_FORMAT_B5G6R5_UNORM
- };
- return find_supported_format(screen, colorFormats, Elements(colorFormats),
- target, sample_count, tex_usage, geom_flags);
-}
-
-/**
- * Find an sRGBA format supported by the context/winsys.
- */
-static enum pipe_format
-default_srgba_format(struct pipe_screen *screen,
- enum pipe_texture_target target,
- unsigned sample_count,
- unsigned tex_usage,
- unsigned geom_flags)
-{
- static const enum pipe_format colorFormats[] = {
- PIPE_FORMAT_B8G8R8A8_SRGB,
- PIPE_FORMAT_A8R8G8B8_SRGB,
- PIPE_FORMAT_A8B8G8R8_SRGB,
- };
- return find_supported_format(screen, colorFormats, Elements(colorFormats),
- target, sample_count, tex_usage, geom_flags);
-}
-
-
-/**
- * Given an OpenGL internalFormat value for a texture or surface, return
- * the best matching PIPE_FORMAT_x, or PIPE_FORMAT_NONE if there's no match.
- * This is called during glTexImage2D, for example.
- *
- * The bindings parameter typically has PIPE_BIND_SAMPLER_VIEW set, plus
- * either PIPE_BINDING_RENDER_TARGET or PIPE_BINDING_DEPTH_STENCIL if
- * we want render-to-texture ability.
- *
- * \param internalFormat the user value passed to glTexImage2D
- * \param target one of PIPE_TEXTURE_x
- * \param bindings bitmask of PIPE_BIND_x flags.
- */
-enum pipe_format
-st_choose_format(struct pipe_screen *screen, GLenum internalFormat,
- enum pipe_texture_target target, unsigned sample_count,
- unsigned bindings)
-{
- unsigned geom_flags = 0; /* we don't care about POT vs. NPOT here, yet */
-
- switch (internalFormat) {
- case GL_RGB10:
- case GL_RGB10_A2:
- if (screen->is_format_supported( screen, PIPE_FORMAT_B10G10R10A2_UNORM,
- target, sample_count, bindings,
- geom_flags ))
- return PIPE_FORMAT_B10G10R10A2_UNORM;
- /* Pass through. */
- case 4:
- case GL_RGBA:
- case GL_RGBA8:
- return default_rgba_format( screen, target, sample_count, bindings,
- geom_flags );
-
- case GL_BGRA:
- if (screen->is_format_supported( screen, PIPE_FORMAT_B8G8R8A8_UNORM,
- target, sample_count, bindings,
- geom_flags ))
- return PIPE_FORMAT_B8G8R8A8_UNORM;
- return default_rgba_format( screen, target, sample_count, bindings,
- geom_flags );
-
- case 3:
- case GL_RGB:
- case GL_RGB8:
- return default_rgb_format( screen, target, sample_count, bindings,
- geom_flags );
-
- case GL_RGB12:
- case GL_RGB16:
- case GL_RGBA12:
- case GL_RGBA16:
- if (screen->is_format_supported( screen, PIPE_FORMAT_R16G16B16A16_UNORM,
- target, sample_count, bindings,
- geom_flags ))
- return PIPE_FORMAT_R16G16B16A16_UNORM;
- return default_rgba_format( screen, target, sample_count, bindings,
- geom_flags );
-
- case GL_RGBA4:
- case GL_RGBA2:
- if (screen->is_format_supported( screen, PIPE_FORMAT_B4G4R4A4_UNORM,
- target, sample_count, bindings,
- geom_flags ))
- return PIPE_FORMAT_B4G4R4A4_UNORM;
- return default_rgba_format( screen, target, sample_count, bindings,
- geom_flags );
-
- case GL_RGB5_A1:
- if (screen->is_format_supported( screen, PIPE_FORMAT_B5G5R5A1_UNORM,
- target, sample_count, bindings,
- geom_flags ))
- return PIPE_FORMAT_B5G5R5A1_UNORM;
- return default_rgba_format( screen, target, sample_count, bindings,
- geom_flags );
-
- case GL_R3_G3_B2:
- if (screen->is_format_supported( screen, PIPE_FORMAT_B2G3R3_UNORM,
- target, sample_count, bindings,
- geom_flags ))
- return PIPE_FORMAT_B2G3R3_UNORM;
- /* Pass through. */
- case GL_RGB5:
- case GL_RGB4:
- if (screen->is_format_supported( screen, PIPE_FORMAT_B5G6R5_UNORM,
- target, sample_count, bindings,
- geom_flags ))
- return PIPE_FORMAT_B5G6R5_UNORM;
- if (screen->is_format_supported( screen, PIPE_FORMAT_B5G5R5A1_UNORM,
- target, sample_count, bindings,
- geom_flags ))
- return PIPE_FORMAT_B5G5R5A1_UNORM;
- return default_rgba_format( screen, target, sample_count, bindings,
- geom_flags );
-
- case GL_ALPHA12:
- case GL_ALPHA16:
- if (screen->is_format_supported( screen, PIPE_FORMAT_A16_UNORM, target,
- sample_count, bindings, geom_flags ))
- return PIPE_FORMAT_A16_UNORM;
- /* Pass through. */
- case GL_ALPHA:
- case GL_ALPHA4:
- case GL_ALPHA8:
- case GL_COMPRESSED_ALPHA:
- if (screen->is_format_supported( screen, PIPE_FORMAT_A8_UNORM, target,
- sample_count, bindings, geom_flags ))
- return PIPE_FORMAT_A8_UNORM;
- return default_rgba_format( screen, target, sample_count, bindings,
- geom_flags );
-
- case GL_LUMINANCE12:
- case GL_LUMINANCE16:
- if (screen->is_format_supported( screen, PIPE_FORMAT_L16_UNORM, target,
- sample_count, bindings, geom_flags ))
- return PIPE_FORMAT_L16_UNORM;
- /* Pass through. */
- case 1:
- case GL_LUMINANCE:
- case GL_LUMINANCE4:
- case GL_LUMINANCE8:
- case GL_COMPRESSED_LUMINANCE:
- if (screen->is_format_supported( screen, PIPE_FORMAT_L8_UNORM, target,
- sample_count, bindings, geom_flags ))
- return PIPE_FORMAT_L8_UNORM;
- return default_rgba_format( screen, target, sample_count, bindings,
- geom_flags );
-
- case GL_LUMINANCE12_ALPHA4:
- case GL_LUMINANCE12_ALPHA12:
- case GL_LUMINANCE16_ALPHA16:
- if (screen->is_format_supported( screen, PIPE_FORMAT_L16A16_UNORM, target,
- sample_count, bindings, geom_flags ))
- return PIPE_FORMAT_L16A16_UNORM;
- /* Pass through. */
- case 2:
- case GL_LUMINANCE_ALPHA:
- case GL_LUMINANCE6_ALPHA2:
- case GL_LUMINANCE8_ALPHA8:
- case GL_COMPRESSED_LUMINANCE_ALPHA:
- if (screen->is_format_supported( screen, PIPE_FORMAT_L8A8_UNORM, target,
- sample_count, bindings, geom_flags ))
- return PIPE_FORMAT_L8A8_UNORM;
- return default_rgba_format( screen, target, sample_count, bindings,
- geom_flags );
-
- case GL_LUMINANCE4_ALPHA4:
- if (screen->is_format_supported( screen, PIPE_FORMAT_L4A4_UNORM, target,
- sample_count, bindings, geom_flags ))
- return PIPE_FORMAT_L4A4_UNORM;
- if (screen->is_format_supported( screen, PIPE_FORMAT_L8A8_UNORM, target,
- sample_count, bindings, geom_flags ))
- return PIPE_FORMAT_L8A8_UNORM;
- return default_rgba_format( screen, target, sample_count, bindings,
- geom_flags );
-
- case GL_INTENSITY12:
- case GL_INTENSITY16:
- if (screen->is_format_supported( screen, PIPE_FORMAT_I16_UNORM, target,
- sample_count, bindings, geom_flags ))
- return PIPE_FORMAT_I16_UNORM;
- /* Pass through. */
- case GL_INTENSITY:
- case GL_INTENSITY4:
- case GL_INTENSITY8:
- case GL_COMPRESSED_INTENSITY:
- if (screen->is_format_supported( screen, PIPE_FORMAT_I8_UNORM, target,
- sample_count, bindings, geom_flags ))
- return PIPE_FORMAT_I8_UNORM;
- return default_rgba_format( screen, target, sample_count, bindings,
- geom_flags );
-
- case GL_YCBCR_MESA:
- if (screen->is_format_supported(screen, PIPE_FORMAT_UYVY, target,
- sample_count, bindings, geom_flags)) {
- return PIPE_FORMAT_UYVY;
- }
- if (screen->is_format_supported(screen, PIPE_FORMAT_YUYV, target,
- sample_count, bindings, geom_flags)) {
- return PIPE_FORMAT_YUYV;
- }
- return PIPE_FORMAT_NONE;
-
- case GL_COMPRESSED_RED:
- case GL_COMPRESSED_RG:
- case GL_COMPRESSED_RGB:
- /* can only sample from compressed formats */
- if (bindings & ~PIPE_BIND_SAMPLER_VIEW)
- return PIPE_FORMAT_NONE;
- else if (screen->is_format_supported(screen, PIPE_FORMAT_DXT1_RGB,
- target, sample_count, bindings,
- geom_flags))
- return PIPE_FORMAT_DXT1_RGB;
- else
- return default_rgb_format(screen, target, sample_count, bindings,
- geom_flags);
-
- case GL_COMPRESSED_RGBA:
- /* can only sample from compressed formats */
- if (bindings & ~PIPE_BIND_SAMPLER_VIEW)
- return PIPE_FORMAT_NONE;
- else if (screen->is_format_supported(screen, PIPE_FORMAT_DXT3_RGBA,
- target, sample_count, bindings,
- geom_flags))
- return PIPE_FORMAT_DXT3_RGBA;
- else
- return default_rgba_format(screen, target, sample_count, bindings,
- geom_flags);
-
- case GL_RGB_S3TC:
- case GL_RGB4_S3TC:
- case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
- if (screen->is_format_supported(screen, PIPE_FORMAT_DXT1_RGB,
- target, sample_count, bindings,
- geom_flags))
- return PIPE_FORMAT_DXT1_RGB;
- else
- return PIPE_FORMAT_NONE;
-
- case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
- if (screen->is_format_supported(screen, PIPE_FORMAT_DXT1_RGBA,
- target, sample_count, bindings,
- geom_flags))
- return PIPE_FORMAT_DXT1_RGBA;
- else
- return PIPE_FORMAT_NONE;
-
- case GL_RGBA_S3TC:
- case GL_RGBA4_S3TC:
- case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
- if (screen->is_format_supported(screen, PIPE_FORMAT_DXT3_RGBA,
- target, sample_count, bindings,
- geom_flags))
- return PIPE_FORMAT_DXT3_RGBA;
- else
- return PIPE_FORMAT_NONE;
-
- case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
- if (screen->is_format_supported(screen, PIPE_FORMAT_DXT5_RGBA,
- target, sample_count, bindings,
- geom_flags))
- return PIPE_FORMAT_DXT5_RGBA;
- else
- return PIPE_FORMAT_NONE;
-
-#if 0
- case GL_COMPRESSED_RGB_FXT1_3DFX:
- return PIPE_FORMAT_RGB_FXT1;
- case GL_COMPRESSED_RGBA_FXT1_3DFX:
- return PIPE_FORMAT_RGB_FXT1;
-#endif
-
- case GL_DEPTH_COMPONENT16:
- if (screen->is_format_supported(screen, PIPE_FORMAT_Z16_UNORM, target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_Z16_UNORM;
- /* fall-through */
- case GL_DEPTH_COMPONENT24:
- if (screen->is_format_supported(screen, PIPE_FORMAT_Z24_UNORM_S8_USCALED,
- target, sample_count, bindings, geom_flags))
- return PIPE_FORMAT_Z24_UNORM_S8_USCALED;
- if (screen->is_format_supported(screen, PIPE_FORMAT_S8_USCALED_Z24_UNORM,
- target, sample_count, bindings, geom_flags))
- return PIPE_FORMAT_S8_USCALED_Z24_UNORM;
- /* fall-through */
- case GL_DEPTH_COMPONENT32:
- if (screen->is_format_supported(screen, PIPE_FORMAT_Z32_UNORM, target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_Z32_UNORM;
- /* fall-through */
- case GL_DEPTH_COMPONENT:
- {
- static const enum pipe_format formats[] = {
- PIPE_FORMAT_Z32_UNORM,
- PIPE_FORMAT_Z24_UNORM_S8_USCALED,
- PIPE_FORMAT_S8_USCALED_Z24_UNORM,
- PIPE_FORMAT_Z16_UNORM
- };
- return find_supported_format(screen, formats, Elements(formats),
- target, sample_count, bindings, geom_flags);
- }
-
- case GL_STENCIL_INDEX:
- case GL_STENCIL_INDEX1_EXT:
- case GL_STENCIL_INDEX4_EXT:
- case GL_STENCIL_INDEX8_EXT:
- case GL_STENCIL_INDEX16_EXT:
- {
- static const enum pipe_format formats[] = {
- PIPE_FORMAT_S8_USCALED,
- PIPE_FORMAT_Z24_UNORM_S8_USCALED,
- PIPE_FORMAT_S8_USCALED_Z24_UNORM
- };
- return find_supported_format(screen, formats, Elements(formats),
- target, sample_count, bindings, geom_flags);
- }
-
- case GL_DEPTH_STENCIL_EXT:
- case GL_DEPTH24_STENCIL8_EXT:
- {
- static const enum pipe_format formats[] = {
- PIPE_FORMAT_Z24_UNORM_S8_USCALED,
- PIPE_FORMAT_S8_USCALED_Z24_UNORM
- };
- return find_supported_format(screen, formats, Elements(formats),
- target, sample_count, bindings, geom_flags);
- }
-
- case GL_SRGB_EXT:
- case GL_SRGB8_EXT:
- case GL_SRGB_ALPHA_EXT:
- case GL_SRGB8_ALPHA8_EXT:
- return default_srgba_format( screen, target, sample_count, bindings,
- geom_flags );
-
- case GL_COMPRESSED_SRGB_EXT:
- case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
- if (screen->is_format_supported(screen, PIPE_FORMAT_DXT1_SRGB, target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_DXT1_SRGB;
- return default_srgba_format( screen, target, sample_count, bindings,
- geom_flags );
-
- case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
- return PIPE_FORMAT_DXT1_SRGBA;
-
- case GL_COMPRESSED_SRGB_ALPHA_EXT:
- case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
- if (screen->is_format_supported(screen, PIPE_FORMAT_DXT3_SRGBA, target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_DXT3_SRGBA;
- return default_srgba_format( screen, target, sample_count, bindings,
- geom_flags );
-
- case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
- return PIPE_FORMAT_DXT5_SRGBA;
-
- case GL_SLUMINANCE_ALPHA_EXT:
- case GL_SLUMINANCE8_ALPHA8_EXT:
- case GL_COMPRESSED_SLUMINANCE_EXT:
- case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT:
- if (screen->is_format_supported(screen, PIPE_FORMAT_L8A8_SRGB, target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_L8A8_SRGB;
- return default_srgba_format( screen, target, sample_count, bindings,
- geom_flags );
-
- case GL_SLUMINANCE_EXT:
- case GL_SLUMINANCE8_EXT:
- if (screen->is_format_supported(screen, PIPE_FORMAT_L8_SRGB, target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_L8_SRGB;
- return default_srgba_format( screen, target, sample_count, bindings,
- geom_flags );
-
- case GL_RED:
- case GL_R8:
- if (screen->is_format_supported(screen, PIPE_FORMAT_R8_UNORM, target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_R8_UNORM;
- return PIPE_FORMAT_NONE;
- case GL_RG:
- case GL_RG8:
- if (screen->is_format_supported(screen, PIPE_FORMAT_R8G8_UNORM, target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_R8G8_UNORM;
- return PIPE_FORMAT_NONE;
-
- case GL_R16:
- if (screen->is_format_supported(screen, PIPE_FORMAT_R16_UNORM, target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_R16_UNORM;
- return PIPE_FORMAT_NONE;
-
- case GL_RG16:
- if (screen->is_format_supported(screen, PIPE_FORMAT_R16G16_UNORM, target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_R16G16_UNORM;
- return PIPE_FORMAT_NONE;
-
- case GL_COMPRESSED_RED_RGTC1:
- if (screen->is_format_supported(screen, PIPE_FORMAT_RGTC1_UNORM, target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_RGTC1_UNORM;
- return PIPE_FORMAT_NONE;
-
- case GL_COMPRESSED_SIGNED_RED_RGTC1:
- if (screen->is_format_supported(screen, PIPE_FORMAT_RGTC1_SNORM, target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_RGTC1_SNORM;
- return PIPE_FORMAT_NONE;
-
- case GL_COMPRESSED_RG_RGTC2:
- if (screen->is_format_supported(screen, PIPE_FORMAT_RGTC2_UNORM, target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_RGTC2_UNORM;
- return PIPE_FORMAT_NONE;
-
- case GL_COMPRESSED_SIGNED_RG_RGTC2:
- if (screen->is_format_supported(screen, PIPE_FORMAT_RGTC2_SNORM, target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_RGTC2_SNORM;
- return PIPE_FORMAT_NONE;
-
- /* signed/unsigned integer formats.
- * XXX Mesa only has formats for RGBA signed/unsigned integer formats.
- * If/when new formats are added this code should be updated.
- */
- case GL_RED_INTEGER_EXT:
- case GL_GREEN_INTEGER_EXT:
- case GL_BLUE_INTEGER_EXT:
- case GL_ALPHA_INTEGER_EXT:
- case GL_RGB_INTEGER_EXT:
- case GL_RGBA_INTEGER_EXT:
- case GL_BGR_INTEGER_EXT:
- case GL_BGRA_INTEGER_EXT:
- case GL_LUMINANCE_INTEGER_EXT:
- case GL_LUMINANCE_ALPHA_INTEGER_EXT:
- /* fall-through */
- case GL_RGBA8I_EXT:
- case GL_RGB8I_EXT:
- case GL_ALPHA8I_EXT:
- case GL_INTENSITY8I_EXT:
- case GL_LUMINANCE8I_EXT:
- case GL_LUMINANCE_ALPHA8I_EXT:
- if (screen->is_format_supported(screen, PIPE_FORMAT_R8G8B8A8_SSCALED,
- target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_R8G8B8A8_SSCALED;
- return PIPE_FORMAT_NONE;
- case GL_RGBA16I_EXT:
- case GL_RGB16I_EXT:
- case GL_ALPHA16I_EXT:
- case GL_INTENSITY16I_EXT:
- case GL_LUMINANCE16I_EXT:
- case GL_LUMINANCE_ALPHA16I_EXT:
- if (screen->is_format_supported(screen, PIPE_FORMAT_R16G16B16A16_SSCALED,
- target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_R16G16B16A16_SSCALED;
- return PIPE_FORMAT_NONE;
- case GL_RGBA32I_EXT:
- case GL_RGB32I_EXT:
- case GL_ALPHA32I_EXT:
- case GL_INTENSITY32I_EXT:
- case GL_LUMINANCE32I_EXT:
- case GL_LUMINANCE_ALPHA32I_EXT:
- /* xxx */
- if (screen->is_format_supported(screen, PIPE_FORMAT_R32G32B32A32_SSCALED,
- target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_R32G32B32A32_SSCALED;
- return PIPE_FORMAT_NONE;
-
- case GL_RGBA8UI_EXT:
- case GL_RGB8UI_EXT:
- case GL_ALPHA8UI_EXT:
- case GL_INTENSITY8UI_EXT:
- case GL_LUMINANCE8UI_EXT:
- case GL_LUMINANCE_ALPHA8UI_EXT:
- if (screen->is_format_supported(screen, PIPE_FORMAT_R8G8B8A8_USCALED,
- target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_R8G8B8A8_USCALED;
- return PIPE_FORMAT_NONE;
-
- case GL_RGBA16UI_EXT:
- case GL_RGB16UI_EXT:
- case GL_ALPHA16UI_EXT:
- case GL_INTENSITY16UI_EXT:
- case GL_LUMINANCE16UI_EXT:
- case GL_LUMINANCE_ALPHA16UI_EXT:
- if (screen->is_format_supported(screen, PIPE_FORMAT_R16G16B16A16_USCALED,
- target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_R16G16B16A16_USCALED;
- return PIPE_FORMAT_NONE;
-
- case GL_RGBA32UI_EXT:
- case GL_RGB32UI_EXT:
- case GL_ALPHA32UI_EXT:
- case GL_INTENSITY32UI_EXT:
- case GL_LUMINANCE32UI_EXT:
- case GL_LUMINANCE_ALPHA32UI_EXT:
- if (screen->is_format_supported(screen, PIPE_FORMAT_R32G32B32A32_USCALED,
- target,
- sample_count, bindings, geom_flags))
- return PIPE_FORMAT_R32G32B32A32_USCALED;
- return PIPE_FORMAT_NONE;
-
- default:
- return PIPE_FORMAT_NONE;
- }
-}
-
-
-/**
- * Called by FBO code to choose a PIPE_FORMAT_ for drawing surfaces.
- */
-enum pipe_format
-st_choose_renderbuffer_format(struct pipe_screen *screen,
- GLenum internalFormat, unsigned sample_count)
-{
- uint usage;
- if (_mesa_is_depth_or_stencil_format(internalFormat))
- usage = PIPE_BIND_DEPTH_STENCIL;
- else
- usage = PIPE_BIND_RENDER_TARGET;
- return st_choose_format(screen, internalFormat, PIPE_TEXTURE_2D,
- sample_count, usage);
-}
-
-
-/**
- * Called via ctx->Driver.chooseTextureFormat().
- */
-gl_format
-st_ChooseTextureFormat_renderable(struct gl_context *ctx, GLint internalFormat,
- GLenum format, GLenum type, GLboolean renderable)
-{
- struct pipe_screen *screen = st_context(ctx)->pipe->screen;
- enum pipe_format pFormat;
- uint bindings;
-
- (void) format;
- (void) type;
-
- /* GL textures may wind up being render targets, but we don't know
- * that in advance. Specify potential render target flags now.
- */
- bindings = PIPE_BIND_SAMPLER_VIEW;
- if (renderable == GL_TRUE) {
- if (_mesa_is_depth_format(internalFormat) ||
- _mesa_is_depth_or_stencil_format(internalFormat))
- bindings |= PIPE_BIND_DEPTH_STENCIL;
- else
- bindings |= PIPE_BIND_RENDER_TARGET;
- }
-
- pFormat = st_choose_format(screen, internalFormat,
- PIPE_TEXTURE_2D, 0, bindings);
-
- if (pFormat == PIPE_FORMAT_NONE) {
- /* try choosing format again, this time without render target bindings */
- pFormat = st_choose_format(screen, internalFormat,
- PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW);
- }
-
- if (pFormat == PIPE_FORMAT_NONE) {
- /* no luck at all */
- return MESA_FORMAT_NONE;
- }
-
- return st_pipe_format_to_mesa_format(pFormat);
-}
-
-gl_format
-st_ChooseTextureFormat(struct gl_context *ctx, GLint internalFormat,
- GLenum format, GLenum type)
-{
- boolean want_renderable =
- internalFormat == 3 || internalFormat == 4 ||
- internalFormat == GL_RGB || internalFormat == GL_RGBA ||
- internalFormat == GL_RGB8 || internalFormat == GL_RGBA8 ||
- internalFormat == GL_BGRA;
-
- return st_ChooseTextureFormat_renderable(ctx, internalFormat,
- format, type, want_renderable);
-}
-
-/**
- * Test if a gallium format is equivalent to a GL format/type.
- */
-GLboolean
-st_equal_formats(enum pipe_format pFormat, GLenum format, GLenum type)
-{
- switch (pFormat) {
- case PIPE_FORMAT_A8B8G8R8_UNORM:
- return format == GL_RGBA && type == GL_UNSIGNED_BYTE;
- case PIPE_FORMAT_A8R8G8B8_UNORM:
- return format == GL_BGRA && type == GL_UNSIGNED_BYTE;
- case PIPE_FORMAT_B5G6R5_UNORM:
- return format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5;
- /* XXX more combos... */
- default:
- return GL_FALSE;
- }
-}
-
-GLboolean
-st_sampler_compat_formats(enum pipe_format format1, enum pipe_format format2)
-{
- if (format1 == format2)
- return GL_TRUE;
-
- if (format1 == PIPE_FORMAT_B8G8R8A8_UNORM &&
- format2 == PIPE_FORMAT_B8G8R8X8_UNORM)
- return GL_TRUE;
-
- if (format1 == PIPE_FORMAT_B8G8R8X8_UNORM &&
- format2 == PIPE_FORMAT_B8G8R8A8_UNORM)
- return GL_TRUE;
-
- if (format1 == PIPE_FORMAT_A8B8G8R8_UNORM &&
- format2 == PIPE_FORMAT_X8B8G8R8_UNORM)
- return GL_TRUE;
-
- if (format1 == PIPE_FORMAT_X8B8G8R8_UNORM &&
- format2 == PIPE_FORMAT_A8B8G8R8_UNORM)
- return GL_TRUE;
-
- if (format1 == PIPE_FORMAT_A8R8G8B8_UNORM &&
- format2 == PIPE_FORMAT_X8R8G8B8_UNORM)
- return GL_TRUE;
-
- if (format1 == PIPE_FORMAT_X8R8G8B8_UNORM &&
- format2 == PIPE_FORMAT_A8R8G8B8_UNORM)
- return GL_TRUE;
-
- return GL_FALSE;
-}
-
-
-
-/**
- * This is used for translating texture border color and the clear
- * color. For example, the clear color is interpreted according to
- * the renderbuffer's base format. For example, if clearing a
- * GL_LUMINANCE buffer, ClearColor[0] = luminance and ClearColor[1] =
- * alpha. Similarly for texture border colors.
- */
-void
-st_translate_color(const GLfloat colorIn[4], GLenum baseFormat,
- GLfloat colorOut[4])
-{
- switch (baseFormat) {
- case GL_RED:
- colorOut[0] = colorIn[0];
- colorOut[1] = 0.0F;
- colorOut[2] = 0.0F;
- colorOut[3] = 1.0F;
- break;
- case GL_RG:
- colorOut[0] = colorIn[0];
- colorOut[1] = colorIn[1];
- colorOut[2] = 0.0F;
- colorOut[3] = 1.0F;
- break;
- case GL_RGB:
- colorOut[0] = colorIn[0];
- colorOut[1] = colorIn[1];
- colorOut[2] = colorIn[2];
- colorOut[3] = 1.0F;
- break;
- case GL_ALPHA:
- colorOut[0] = colorOut[1] = colorOut[2] = 0.0;
- colorOut[3] = colorIn[3];
- break;
- case GL_LUMINANCE:
- colorOut[0] = colorOut[1] = colorOut[2] = colorIn[0];
- colorOut[3] = 1.0;
- break;
- case GL_LUMINANCE_ALPHA:
- colorOut[0] = colorOut[1] = colorOut[2] = colorIn[0];
- colorOut[3] = colorIn[3];
- break;
- case GL_INTENSITY:
- colorOut[0] = colorOut[1] = colorOut[2] = colorOut[3] = colorIn[0];
- break;
- default:
- COPY_4V(colorOut, colorIn);
- }
-}
+/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright (c) 2008-2010 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, 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.
+ *
+ **************************************************************************/
+
+
+/**
+ * Mesa / Gallium format conversion and format selection code.
+ * \author Brian Paul
+ */
+
+#include "main/imports.h"
+#include "main/context.h"
+#include "main/texstore.h"
+#include "main/image.h"
+#include "main/macros.h"
+#include "main/mfeatures.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_screen.h"
+#include "util/u_format.h"
+#include "st_context.h"
+#include "st_format.h"
+
+
+static GLuint
+format_max_bits(enum pipe_format format)
+{
+ GLuint size = util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 0);
+
+ size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 1));
+ size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 2));
+ size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 3));
+ size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 0));
+ size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1));
+ return size;
+}
+
+
+/**
+ * Return basic GL datatype for the given gallium format.
+ */
+GLenum
+st_format_datatype(enum pipe_format format)
+{
+ const struct util_format_description *desc;
+
+ desc = util_format_description(format);
+ assert(desc);
+
+ if (desc->layout == UTIL_FORMAT_LAYOUT_PLAIN) {
+ if (format == PIPE_FORMAT_B5G5R5A1_UNORM ||
+ format == PIPE_FORMAT_B5G6R5_UNORM) {
+ return GL_UNSIGNED_SHORT;
+ }
+ else if (format == PIPE_FORMAT_Z24_UNORM_S8_USCALED ||
+ format == PIPE_FORMAT_S8_USCALED_Z24_UNORM ||
+ format == PIPE_FORMAT_Z24X8_UNORM ||
+ format == PIPE_FORMAT_X8Z24_UNORM) {
+ return GL_UNSIGNED_INT_24_8;
+ }
+ else {
+ const GLuint size = format_max_bits(format);
+ if (size == 8) {
+ if (desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED)
+ return GL_UNSIGNED_BYTE;
+ else
+ return GL_BYTE;
+ }
+ else if (size == 16) {
+ if (desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED)
+ return GL_UNSIGNED_SHORT;
+ else
+ return GL_SHORT;
+ }
+ else {
+ assert( size <= 32 );
+ if (desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED)
+ return GL_UNSIGNED_INT;
+ else
+ return GL_INT;
+ }
+ }
+ }
+ else if (format == PIPE_FORMAT_UYVY) {
+ return GL_UNSIGNED_SHORT;
+ }
+ else if (format == PIPE_FORMAT_YUYV) {
+ return GL_UNSIGNED_SHORT;
+ }
+ else {
+ /* probably a compressed format, unsupported anyway */
+ return GL_NONE;
+ }
+}
+
+
+/**
+ * Translate Mesa format to Gallium format.
+ */
+enum pipe_format
+st_mesa_format_to_pipe_format(gl_format mesaFormat)
+{
+ switch (mesaFormat) {
+ case MESA_FORMAT_RGBA8888:
+ return PIPE_FORMAT_A8B8G8R8_UNORM;
+ case MESA_FORMAT_RGBA8888_REV:
+ return PIPE_FORMAT_R8G8B8A8_UNORM;
+ case MESA_FORMAT_ARGB8888:
+ return PIPE_FORMAT_B8G8R8A8_UNORM;
+ case MESA_FORMAT_ARGB8888_REV:
+ return PIPE_FORMAT_A8R8G8B8_UNORM;
+ case MESA_FORMAT_XRGB8888:
+ return PIPE_FORMAT_B8G8R8X8_UNORM;
+ case MESA_FORMAT_XRGB8888_REV:
+ return PIPE_FORMAT_X8R8G8B8_UNORM;
+ case MESA_FORMAT_ARGB1555:
+ return PIPE_FORMAT_B5G5R5A1_UNORM;
+ case MESA_FORMAT_ARGB4444:
+ return PIPE_FORMAT_B4G4R4A4_UNORM;
+ case MESA_FORMAT_RGB565:
+ return PIPE_FORMAT_B5G6R5_UNORM;
+ case MESA_FORMAT_RGB332:
+ return PIPE_FORMAT_B2G3R3_UNORM;
+ case MESA_FORMAT_ARGB2101010:
+ return PIPE_FORMAT_B10G10R10A2_UNORM;
+ case MESA_FORMAT_AL44:
+ return PIPE_FORMAT_L4A4_UNORM;
+ case MESA_FORMAT_AL88:
+ return PIPE_FORMAT_L8A8_UNORM;
+ case MESA_FORMAT_AL1616:
+ return PIPE_FORMAT_L16A16_UNORM;
+ case MESA_FORMAT_A8:
+ return PIPE_FORMAT_A8_UNORM;
+ case MESA_FORMAT_A16:
+ return PIPE_FORMAT_A16_UNORM;
+ case MESA_FORMAT_L8:
+ return PIPE_FORMAT_L8_UNORM;
+ case MESA_FORMAT_L16:
+ return PIPE_FORMAT_L16_UNORM;
+ case MESA_FORMAT_I8:
+ return PIPE_FORMAT_I8_UNORM;
+ case MESA_FORMAT_I16:
+ return PIPE_FORMAT_I16_UNORM;
+ case MESA_FORMAT_Z16:
+ return PIPE_FORMAT_Z16_UNORM;
+ case MESA_FORMAT_Z32:
+ return PIPE_FORMAT_Z32_UNORM;
+ case MESA_FORMAT_Z24_S8:
+ return PIPE_FORMAT_S8_USCALED_Z24_UNORM;
+ case MESA_FORMAT_S8_Z24:
+ return PIPE_FORMAT_Z24_UNORM_S8_USCALED;
+ case MESA_FORMAT_Z24_X8:
+ return PIPE_FORMAT_X8Z24_UNORM;
+ case MESA_FORMAT_X8_Z24:
+ return PIPE_FORMAT_Z24X8_UNORM;
+ case MESA_FORMAT_S8:
+ return PIPE_FORMAT_S8_USCALED;
+ case MESA_FORMAT_YCBCR:
+ return PIPE_FORMAT_UYVY;
+#if FEATURE_texture_s3tc
+ case MESA_FORMAT_RGB_DXT1:
+ return PIPE_FORMAT_DXT1_RGB;
+ case MESA_FORMAT_RGBA_DXT1:
+ return PIPE_FORMAT_DXT1_RGBA;
+ case MESA_FORMAT_RGBA_DXT3:
+ return PIPE_FORMAT_DXT3_RGBA;
+ case MESA_FORMAT_RGBA_DXT5:
+ return PIPE_FORMAT_DXT5_RGBA;
+#if FEATURE_EXT_texture_sRGB
+ case MESA_FORMAT_SRGB_DXT1:
+ return PIPE_FORMAT_DXT1_SRGB;
+ case MESA_FORMAT_SRGBA_DXT1:
+ return PIPE_FORMAT_DXT1_SRGBA;
+ case MESA_FORMAT_SRGBA_DXT3:
+ return PIPE_FORMAT_DXT3_SRGBA;
+ case MESA_FORMAT_SRGBA_DXT5:
+ return PIPE_FORMAT_DXT5_SRGBA;
+#endif
+#endif
+#if FEATURE_EXT_texture_sRGB
+ case MESA_FORMAT_SLA8:
+ return PIPE_FORMAT_L8A8_SRGB;
+ case MESA_FORMAT_SL8:
+ return PIPE_FORMAT_L8_SRGB;
+ case MESA_FORMAT_SRGB8:
+ return PIPE_FORMAT_R8G8B8_SRGB;
+ case MESA_FORMAT_SRGBA8:
+ return PIPE_FORMAT_A8B8G8R8_SRGB;
+ case MESA_FORMAT_SARGB8:
+ return PIPE_FORMAT_B8G8R8A8_SRGB;
+#endif
+ case MESA_FORMAT_R8:
+ return PIPE_FORMAT_R8_UNORM;
+ case MESA_FORMAT_R16:
+ return PIPE_FORMAT_R16_UNORM;
+ case MESA_FORMAT_RG88:
+ return PIPE_FORMAT_R8G8_UNORM;
+ case MESA_FORMAT_RG1616:
+ return PIPE_FORMAT_R16G16_UNORM;
+ case MESA_FORMAT_RGBA_16:
+ return PIPE_FORMAT_R16G16B16A16_UNORM;
+
+ /* signed int formats */
+ case MESA_FORMAT_RGBA_INT8:
+ return PIPE_FORMAT_R8G8B8A8_SSCALED;
+ case MESA_FORMAT_RGBA_INT16:
+ return PIPE_FORMAT_R16G16B16A16_SSCALED;
+ case MESA_FORMAT_RGBA_INT32:
+ return PIPE_FORMAT_R32G32B32A32_SSCALED;
+
+ /* unsigned int formats */
+ case MESA_FORMAT_RGBA_UINT8:
+ return PIPE_FORMAT_R8G8B8A8_USCALED;
+ case MESA_FORMAT_RGBA_UINT16:
+ return PIPE_FORMAT_R16G16B16A16_USCALED;
+ case MESA_FORMAT_RGBA_UINT32:
+ return PIPE_FORMAT_R32G32B32A32_USCALED;
+
+ default:
+ assert(0);
+ return PIPE_FORMAT_NONE;
+ }
+}
+
+
+/**
+ * Translate Gallium format to Mesa format.
+ */
+gl_format
+st_pipe_format_to_mesa_format(enum pipe_format format)
+{
+ switch (format) {
+ case PIPE_FORMAT_A8B8G8R8_UNORM:
+ return MESA_FORMAT_RGBA8888;
+ case PIPE_FORMAT_R8G8B8A8_UNORM:
+ return MESA_FORMAT_RGBA8888_REV;
+ case PIPE_FORMAT_B8G8R8A8_UNORM:
+ return MESA_FORMAT_ARGB8888;
+ case PIPE_FORMAT_A8R8G8B8_UNORM:
+ return MESA_FORMAT_ARGB8888_REV;
+ case PIPE_FORMAT_B8G8R8X8_UNORM:
+ return MESA_FORMAT_XRGB8888;
+ case PIPE_FORMAT_X8R8G8B8_UNORM:
+ return MESA_FORMAT_XRGB8888_REV;
+ case PIPE_FORMAT_B5G5R5A1_UNORM:
+ return MESA_FORMAT_ARGB1555;
+ case PIPE_FORMAT_B4G4R4A4_UNORM:
+ return MESA_FORMAT_ARGB4444;
+ case PIPE_FORMAT_B5G6R5_UNORM:
+ return MESA_FORMAT_RGB565;
+ case PIPE_FORMAT_B2G3R3_UNORM:
+ return MESA_FORMAT_RGB332;
+ case PIPE_FORMAT_B10G10R10A2_UNORM:
+ return MESA_FORMAT_ARGB2101010;
+ case PIPE_FORMAT_L4A4_UNORM:
+ return MESA_FORMAT_AL44;
+ case PIPE_FORMAT_L8A8_UNORM:
+ return MESA_FORMAT_AL88;
+ case PIPE_FORMAT_L16A16_UNORM:
+ return MESA_FORMAT_AL1616;
+ case PIPE_FORMAT_A8_UNORM:
+ return MESA_FORMAT_A8;
+ case PIPE_FORMAT_A16_UNORM:
+ return MESA_FORMAT_A16;
+ case PIPE_FORMAT_L8_UNORM:
+ return MESA_FORMAT_L8;
+ case PIPE_FORMAT_L16_UNORM:
+ return MESA_FORMAT_L16;
+ case PIPE_FORMAT_I8_UNORM:
+ return MESA_FORMAT_I8;
+ case PIPE_FORMAT_I16_UNORM:
+ return MESA_FORMAT_I16;
+ case PIPE_FORMAT_S8_USCALED:
+ return MESA_FORMAT_S8;
+
+ case PIPE_FORMAT_R16G16B16A16_UNORM:
+ return MESA_FORMAT_RGBA_16;
+ case PIPE_FORMAT_R16G16B16A16_SNORM:
+ return MESA_FORMAT_SIGNED_RGBA_16;
+
+ case PIPE_FORMAT_Z16_UNORM:
+ return MESA_FORMAT_Z16;
+ case PIPE_FORMAT_Z32_UNORM:
+ return MESA_FORMAT_Z32;
+ case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
+ return MESA_FORMAT_Z24_S8;
+ case PIPE_FORMAT_X8Z24_UNORM:
+ return MESA_FORMAT_Z24_X8;
+ case PIPE_FORMAT_Z24X8_UNORM:
+ return MESA_FORMAT_X8_Z24;
+ case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
+ return MESA_FORMAT_S8_Z24;
+
+ case PIPE_FORMAT_UYVY:
+ return MESA_FORMAT_YCBCR;
+ case PIPE_FORMAT_YUYV:
+ return MESA_FORMAT_YCBCR_REV;
+
+#if FEATURE_texture_s3tc
+ case PIPE_FORMAT_DXT1_RGB:
+ return MESA_FORMAT_RGB_DXT1;
+ case PIPE_FORMAT_DXT1_RGBA:
+ return MESA_FORMAT_RGBA_DXT1;
+ case PIPE_FORMAT_DXT3_RGBA:
+ return MESA_FORMAT_RGBA_DXT3;
+ case PIPE_FORMAT_DXT5_RGBA:
+ return MESA_FORMAT_RGBA_DXT5;
+#if FEATURE_EXT_texture_sRGB
+ case PIPE_FORMAT_DXT1_SRGB:
+ return MESA_FORMAT_SRGB_DXT1;
+ case PIPE_FORMAT_DXT1_SRGBA:
+ return MESA_FORMAT_SRGBA_DXT1;
+ case PIPE_FORMAT_DXT3_SRGBA:
+ return MESA_FORMAT_SRGBA_DXT3;
+ case PIPE_FORMAT_DXT5_SRGBA:
+ return MESA_FORMAT_SRGBA_DXT5;
+#endif
+#endif
+
+#if FEATURE_EXT_texture_sRGB
+ case PIPE_FORMAT_L8A8_SRGB:
+ return MESA_FORMAT_SLA8;
+ case PIPE_FORMAT_L8_SRGB:
+ return MESA_FORMAT_SL8;
+ case PIPE_FORMAT_R8G8B8_SRGB:
+ return MESA_FORMAT_SRGB8;
+ case PIPE_FORMAT_A8B8G8R8_SRGB:
+ return MESA_FORMAT_SRGBA8;
+ case PIPE_FORMAT_B8G8R8A8_SRGB:
+ return MESA_FORMAT_SARGB8;
+#endif
+
+ case PIPE_FORMAT_R8_UNORM:
+ return MESA_FORMAT_R8;
+ case PIPE_FORMAT_R16_UNORM:
+ return MESA_FORMAT_R16;
+ case PIPE_FORMAT_R8G8_UNORM:
+ return MESA_FORMAT_RG88;
+ case PIPE_FORMAT_R16G16_UNORM:
+ return MESA_FORMAT_RG1616;
+
+ /* signed int formats */
+ case PIPE_FORMAT_R8G8B8A8_SSCALED:
+ return MESA_FORMAT_RGBA_INT8;
+ case PIPE_FORMAT_R16G16B16A16_SSCALED:
+ return MESA_FORMAT_RGBA_INT16;
+ case PIPE_FORMAT_R32G32B32A32_SSCALED:
+ return MESA_FORMAT_RGBA_INT32;
+
+ /* unsigned int formats */
+ case PIPE_FORMAT_R8G8B8A8_USCALED:
+ return MESA_FORMAT_RGBA_UINT8;
+ case PIPE_FORMAT_R16G16B16A16_USCALED:
+ return MESA_FORMAT_RGBA_UINT16;
+ case PIPE_FORMAT_R32G32B32A32_USCALED:
+ return MESA_FORMAT_RGBA_UINT32;
+
+ default:
+ assert(0);
+ return MESA_FORMAT_NONE;
+ }
+}
+
+
+/**
+ * Return first supported format from the given list.
+ */
+static enum pipe_format
+find_supported_format(struct pipe_screen *screen,
+ const enum pipe_format formats[],
+ uint num_formats,
+ enum pipe_texture_target target,
+ unsigned sample_count,
+ unsigned tex_usage,
+ unsigned geom_flags)
+{
+ uint i;
+ for (i = 0; i < num_formats; i++) {
+ if (screen->is_format_supported(screen, formats[i], target,
+ sample_count, tex_usage, geom_flags)) {
+ return formats[i];
+ }
+ }
+ return PIPE_FORMAT_NONE;
+}
+
+
+/**
+ * Find an RGBA format supported by the context/winsys.
+ */
+static enum pipe_format
+default_rgba_format(struct pipe_screen *screen,
+ enum pipe_texture_target target,
+ unsigned sample_count,
+ unsigned tex_usage,
+ unsigned geom_flags)
+{
+ static const enum pipe_format colorFormats[] = {
+ PIPE_FORMAT_B8G8R8A8_UNORM,
+ PIPE_FORMAT_A8R8G8B8_UNORM,
+ PIPE_FORMAT_A8B8G8R8_UNORM,
+ PIPE_FORMAT_B5G6R5_UNORM
+ };
+ return find_supported_format(screen, colorFormats, Elements(colorFormats),
+ target, sample_count, tex_usage, geom_flags);
+}
+
+
+/**
+ * Find an RGB format supported by the context/winsys.
+ */
+static enum pipe_format
+default_rgb_format(struct pipe_screen *screen,
+ enum pipe_texture_target target,
+ unsigned sample_count,
+ unsigned tex_usage,
+ unsigned geom_flags)
+{
+ static const enum pipe_format colorFormats[] = {
+ PIPE_FORMAT_B8G8R8X8_UNORM,
+ PIPE_FORMAT_X8R8G8B8_UNORM,
+ PIPE_FORMAT_X8B8G8R8_UNORM,
+ PIPE_FORMAT_B8G8R8A8_UNORM,
+ PIPE_FORMAT_A8R8G8B8_UNORM,
+ PIPE_FORMAT_A8B8G8R8_UNORM,
+ PIPE_FORMAT_B5G6R5_UNORM
+ };
+ return find_supported_format(screen, colorFormats, Elements(colorFormats),
+ target, sample_count, tex_usage, geom_flags);
+}
+
+/**
+ * Find an sRGBA format supported by the context/winsys.
+ */
+static enum pipe_format
+default_srgba_format(struct pipe_screen *screen,
+ enum pipe_texture_target target,
+ unsigned sample_count,
+ unsigned tex_usage,
+ unsigned geom_flags)
+{
+ static const enum pipe_format colorFormats[] = {
+ PIPE_FORMAT_B8G8R8A8_SRGB,
+ PIPE_FORMAT_A8R8G8B8_SRGB,
+ PIPE_FORMAT_A8B8G8R8_SRGB,
+ };
+ return find_supported_format(screen, colorFormats, Elements(colorFormats),
+ target, sample_count, tex_usage, geom_flags);
+}
+
+
+/**
+ * Given an OpenGL internalFormat value for a texture or surface, return
+ * the best matching PIPE_FORMAT_x, or PIPE_FORMAT_NONE if there's no match.
+ * This is called during glTexImage2D, for example.
+ *
+ * The bindings parameter typically has PIPE_BIND_SAMPLER_VIEW set, plus
+ * either PIPE_BINDING_RENDER_TARGET or PIPE_BINDING_DEPTH_STENCIL if
+ * we want render-to-texture ability.
+ *
+ * \param internalFormat the user value passed to glTexImage2D
+ * \param target one of PIPE_TEXTURE_x
+ * \param bindings bitmask of PIPE_BIND_x flags.
+ */
+enum pipe_format
+st_choose_format(struct pipe_screen *screen, GLenum internalFormat,
+ enum pipe_texture_target target, unsigned sample_count,
+ unsigned bindings)
+{
+ unsigned geom_flags = 0; /* we don't care about POT vs. NPOT here, yet */
+
+ switch (internalFormat) {
+ case GL_RGB10:
+ case GL_RGB10_A2:
+ if (screen->is_format_supported( screen, PIPE_FORMAT_B10G10R10A2_UNORM,
+ target, sample_count, bindings,
+ geom_flags ))
+ return PIPE_FORMAT_B10G10R10A2_UNORM;
+ /* Pass through. */
+ case 4:
+ case GL_RGBA:
+ case GL_RGBA8:
+ return default_rgba_format( screen, target, sample_count, bindings,
+ geom_flags );
+
+ case GL_BGRA:
+ if (screen->is_format_supported( screen, PIPE_FORMAT_B8G8R8A8_UNORM,
+ target, sample_count, bindings,
+ geom_flags ))
+ return PIPE_FORMAT_B8G8R8A8_UNORM;
+ return default_rgba_format( screen, target, sample_count, bindings,
+ geom_flags );
+
+ case 3:
+ case GL_RGB:
+ case GL_RGB8:
+ return default_rgb_format( screen, target, sample_count, bindings,
+ geom_flags );
+
+ case GL_RGB12:
+ case GL_RGB16:
+ case GL_RGBA12:
+ case GL_RGBA16:
+ if (screen->is_format_supported( screen, PIPE_FORMAT_R16G16B16A16_UNORM,
+ target, sample_count, bindings,
+ geom_flags ))
+ return PIPE_FORMAT_R16G16B16A16_UNORM;
+ return default_rgba_format( screen, target, sample_count, bindings,
+ geom_flags );
+
+ case GL_RGBA4:
+ case GL_RGBA2:
+ if (screen->is_format_supported( screen, PIPE_FORMAT_B4G4R4A4_UNORM,
+ target, sample_count, bindings,
+ geom_flags ))
+ return PIPE_FORMAT_B4G4R4A4_UNORM;
+ return default_rgba_format( screen, target, sample_count, bindings,
+ geom_flags );
+
+ case GL_RGB5_A1:
+ if (screen->is_format_supported( screen, PIPE_FORMAT_B5G5R5A1_UNORM,
+ target, sample_count, bindings,
+ geom_flags ))
+ return PIPE_FORMAT_B5G5R5A1_UNORM;
+ return default_rgba_format( screen, target, sample_count, bindings,
+ geom_flags );
+
+ case GL_R3_G3_B2:
+ if (screen->is_format_supported( screen, PIPE_FORMAT_B2G3R3_UNORM,
+ target, sample_count, bindings,
+ geom_flags ))
+ return PIPE_FORMAT_B2G3R3_UNORM;
+ /* Pass through. */
+ case GL_RGB5:
+ case GL_RGB4:
+ if (screen->is_format_supported( screen, PIPE_FORMAT_B5G6R5_UNORM,
+ target, sample_count, bindings,
+ geom_flags ))
+ return PIPE_FORMAT_B5G6R5_UNORM;
+ if (screen->is_format_supported( screen, PIPE_FORMAT_B5G5R5A1_UNORM,
+ target, sample_count, bindings,
+ geom_flags ))
+ return PIPE_FORMAT_B5G5R5A1_UNORM;
+ return default_rgba_format( screen, target, sample_count, bindings,
+ geom_flags );
+
+ case GL_ALPHA12:
+ case GL_ALPHA16:
+ if (screen->is_format_supported( screen, PIPE_FORMAT_A16_UNORM, target,
+ sample_count, bindings, geom_flags ))
+ return PIPE_FORMAT_A16_UNORM;
+ /* Pass through. */
+ case GL_ALPHA:
+ case GL_ALPHA4:
+ case GL_ALPHA8:
+ case GL_COMPRESSED_ALPHA:
+ if (screen->is_format_supported( screen, PIPE_FORMAT_A8_UNORM, target,
+ sample_count, bindings, geom_flags ))
+ return PIPE_FORMAT_A8_UNORM;
+ return default_rgba_format( screen, target, sample_count, bindings,
+ geom_flags );
+
+ case GL_LUMINANCE12:
+ case GL_LUMINANCE16:
+ if (screen->is_format_supported( screen, PIPE_FORMAT_L16_UNORM, target,
+ sample_count, bindings, geom_flags ))
+ return PIPE_FORMAT_L16_UNORM;
+ /* Pass through. */
+ case 1:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE4:
+ case GL_LUMINANCE8:
+ case GL_COMPRESSED_LUMINANCE:
+ if (screen->is_format_supported( screen, PIPE_FORMAT_L8_UNORM, target,
+ sample_count, bindings, geom_flags ))
+ return PIPE_FORMAT_L8_UNORM;
+ return default_rgba_format( screen, target, sample_count, bindings,
+ geom_flags );
+
+ case GL_LUMINANCE12_ALPHA4:
+ case GL_LUMINANCE12_ALPHA12:
+ case GL_LUMINANCE16_ALPHA16:
+ if (screen->is_format_supported( screen, PIPE_FORMAT_L16A16_UNORM, target,
+ sample_count, bindings, geom_flags ))
+ return PIPE_FORMAT_L16A16_UNORM;
+ /* Pass through. */
+ case 2:
+ case GL_LUMINANCE_ALPHA:
+ case GL_LUMINANCE6_ALPHA2:
+ case GL_LUMINANCE8_ALPHA8:
+ case GL_COMPRESSED_LUMINANCE_ALPHA:
+ if (screen->is_format_supported( screen, PIPE_FORMAT_L8A8_UNORM, target,
+ sample_count, bindings, geom_flags ))
+ return PIPE_FORMAT_L8A8_UNORM;
+ return default_rgba_format( screen, target, sample_count, bindings,
+ geom_flags );
+
+ case GL_LUMINANCE4_ALPHA4:
+ if (screen->is_format_supported( screen, PIPE_FORMAT_L4A4_UNORM, target,
+ sample_count, bindings, geom_flags ))
+ return PIPE_FORMAT_L4A4_UNORM;
+ if (screen->is_format_supported( screen, PIPE_FORMAT_L8A8_UNORM, target,
+ sample_count, bindings, geom_flags ))
+ return PIPE_FORMAT_L8A8_UNORM;
+ return default_rgba_format( screen, target, sample_count, bindings,
+ geom_flags );
+
+ case GL_INTENSITY12:
+ case GL_INTENSITY16:
+ if (screen->is_format_supported( screen, PIPE_FORMAT_I16_UNORM, target,
+ sample_count, bindings, geom_flags ))
+ return PIPE_FORMAT_I16_UNORM;
+ /* Pass through. */
+ case GL_INTENSITY:
+ case GL_INTENSITY4:
+ case GL_INTENSITY8:
+ case GL_COMPRESSED_INTENSITY:
+ if (screen->is_format_supported( screen, PIPE_FORMAT_I8_UNORM, target,
+ sample_count, bindings, geom_flags ))
+ return PIPE_FORMAT_I8_UNORM;
+ return default_rgba_format( screen, target, sample_count, bindings,
+ geom_flags );
+
+ case GL_YCBCR_MESA:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_UYVY, target,
+ sample_count, bindings, geom_flags)) {
+ return PIPE_FORMAT_UYVY;
+ }
+ if (screen->is_format_supported(screen, PIPE_FORMAT_YUYV, target,
+ sample_count, bindings, geom_flags)) {
+ return PIPE_FORMAT_YUYV;
+ }
+ return PIPE_FORMAT_NONE;
+
+ case GL_COMPRESSED_RED:
+ case GL_COMPRESSED_RG:
+ case GL_COMPRESSED_RGB:
+ /* can only sample from compressed formats */
+ if (bindings & ~PIPE_BIND_SAMPLER_VIEW)
+ return PIPE_FORMAT_NONE;
+ else if (screen->is_format_supported(screen, PIPE_FORMAT_DXT1_RGB,
+ target, sample_count, bindings,
+ geom_flags))
+ return PIPE_FORMAT_DXT1_RGB;
+ else
+ return default_rgb_format(screen, target, sample_count, bindings,
+ geom_flags);
+
+ case GL_COMPRESSED_RGBA:
+ /* can only sample from compressed formats */
+ if (bindings & ~PIPE_BIND_SAMPLER_VIEW)
+ return PIPE_FORMAT_NONE;
+ else if (screen->is_format_supported(screen, PIPE_FORMAT_DXT3_RGBA,
+ target, sample_count, bindings,
+ geom_flags))
+ return PIPE_FORMAT_DXT3_RGBA;
+ else
+ return default_rgba_format(screen, target, sample_count, bindings,
+ geom_flags);
+
+ case GL_RGB_S3TC:
+ case GL_RGB4_S3TC:
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_DXT1_RGB,
+ target, sample_count, bindings,
+ geom_flags))
+ return PIPE_FORMAT_DXT1_RGB;
+ else
+ return PIPE_FORMAT_NONE;
+
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_DXT1_RGBA,
+ target, sample_count, bindings,
+ geom_flags))
+ return PIPE_FORMAT_DXT1_RGBA;
+ else
+ return PIPE_FORMAT_NONE;
+
+ case GL_RGBA_S3TC:
+ case GL_RGBA4_S3TC:
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_DXT3_RGBA,
+ target, sample_count, bindings,
+ geom_flags))
+ return PIPE_FORMAT_DXT3_RGBA;
+ else
+ return PIPE_FORMAT_NONE;
+
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_DXT5_RGBA,
+ target, sample_count, bindings,
+ geom_flags))
+ return PIPE_FORMAT_DXT5_RGBA;
+ else
+ return PIPE_FORMAT_NONE;
+
+#if 0
+ case GL_COMPRESSED_RGB_FXT1_3DFX:
+ return PIPE_FORMAT_RGB_FXT1;
+ case GL_COMPRESSED_RGBA_FXT1_3DFX:
+ return PIPE_FORMAT_RGB_FXT1;
+#endif
+
+ case GL_DEPTH_COMPONENT16:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_Z16_UNORM, target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_Z16_UNORM;
+ /* fall-through */
+ case GL_DEPTH_COMPONENT24:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_Z24_UNORM_S8_USCALED,
+ target, sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_Z24_UNORM_S8_USCALED;
+ if (screen->is_format_supported(screen, PIPE_FORMAT_S8_USCALED_Z24_UNORM,
+ target, sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_S8_USCALED_Z24_UNORM;
+ /* fall-through */
+ case GL_DEPTH_COMPONENT32:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_Z32_UNORM, target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_Z32_UNORM;
+ /* fall-through */
+ case GL_DEPTH_COMPONENT:
+ {
+ static const enum pipe_format formats[] = {
+ PIPE_FORMAT_Z32_UNORM,
+ PIPE_FORMAT_Z24_UNORM_S8_USCALED,
+ PIPE_FORMAT_S8_USCALED_Z24_UNORM,
+ PIPE_FORMAT_Z16_UNORM
+ };
+ return find_supported_format(screen, formats, Elements(formats),
+ target, sample_count, bindings, geom_flags);
+ }
+
+ case GL_STENCIL_INDEX:
+ case GL_STENCIL_INDEX1_EXT:
+ case GL_STENCIL_INDEX4_EXT:
+ case GL_STENCIL_INDEX8_EXT:
+ case GL_STENCIL_INDEX16_EXT:
+ {
+ static const enum pipe_format formats[] = {
+ PIPE_FORMAT_S8_USCALED,
+ PIPE_FORMAT_Z24_UNORM_S8_USCALED,
+ PIPE_FORMAT_S8_USCALED_Z24_UNORM
+ };
+ return find_supported_format(screen, formats, Elements(formats),
+ target, sample_count, bindings, geom_flags);
+ }
+
+ case GL_DEPTH_STENCIL_EXT:
+ case GL_DEPTH24_STENCIL8_EXT:
+ {
+ static const enum pipe_format formats[] = {
+ PIPE_FORMAT_Z24_UNORM_S8_USCALED,
+ PIPE_FORMAT_S8_USCALED_Z24_UNORM
+ };
+ return find_supported_format(screen, formats, Elements(formats),
+ target, sample_count, bindings, geom_flags);
+ }
+
+ case GL_SRGB_EXT:
+ case GL_SRGB8_EXT:
+ case GL_SRGB_ALPHA_EXT:
+ case GL_SRGB8_ALPHA8_EXT:
+ return default_srgba_format( screen, target, sample_count, bindings,
+ geom_flags );
+
+ case GL_COMPRESSED_SRGB_EXT:
+ case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_DXT1_SRGB, target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_DXT1_SRGB;
+ return default_srgba_format( screen, target, sample_count, bindings,
+ geom_flags );
+
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
+ return PIPE_FORMAT_DXT1_SRGBA;
+
+ case GL_COMPRESSED_SRGB_ALPHA_EXT:
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_DXT3_SRGBA, target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_DXT3_SRGBA;
+ return default_srgba_format( screen, target, sample_count, bindings,
+ geom_flags );
+
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
+ return PIPE_FORMAT_DXT5_SRGBA;
+
+ case GL_SLUMINANCE_ALPHA_EXT:
+ case GL_SLUMINANCE8_ALPHA8_EXT:
+ case GL_COMPRESSED_SLUMINANCE_EXT:
+ case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_L8A8_SRGB, target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_L8A8_SRGB;
+ return default_srgba_format( screen, target, sample_count, bindings,
+ geom_flags );
+
+ case GL_SLUMINANCE_EXT:
+ case GL_SLUMINANCE8_EXT:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_L8_SRGB, target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_L8_SRGB;
+ return default_srgba_format( screen, target, sample_count, bindings,
+ geom_flags );
+
+ case GL_RED:
+ case GL_R8:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_R8_UNORM, target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_R8_UNORM;
+ return PIPE_FORMAT_NONE;
+ case GL_RG:
+ case GL_RG8:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_R8G8_UNORM, target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_R8G8_UNORM;
+ return PIPE_FORMAT_NONE;
+
+ case GL_R16:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_R16_UNORM, target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_R16_UNORM;
+ return PIPE_FORMAT_NONE;
+
+ case GL_RG16:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_R16G16_UNORM, target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_R16G16_UNORM;
+ return PIPE_FORMAT_NONE;
+
+ case GL_COMPRESSED_RED_RGTC1:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_RGTC1_UNORM, target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_RGTC1_UNORM;
+ return PIPE_FORMAT_NONE;
+
+ case GL_COMPRESSED_SIGNED_RED_RGTC1:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_RGTC1_SNORM, target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_RGTC1_SNORM;
+ return PIPE_FORMAT_NONE;
+
+ case GL_COMPRESSED_RG_RGTC2:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_RGTC2_UNORM, target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_RGTC2_UNORM;
+ return PIPE_FORMAT_NONE;
+
+ case GL_COMPRESSED_SIGNED_RG_RGTC2:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_RGTC2_SNORM, target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_RGTC2_SNORM;
+ return PIPE_FORMAT_NONE;
+
+ /* signed/unsigned integer formats.
+ * XXX Mesa only has formats for RGBA signed/unsigned integer formats.
+ * If/when new formats are added this code should be updated.
+ */
+ case GL_RED_INTEGER_EXT:
+ case GL_GREEN_INTEGER_EXT:
+ case GL_BLUE_INTEGER_EXT:
+ case GL_ALPHA_INTEGER_EXT:
+ case GL_RGB_INTEGER_EXT:
+ case GL_RGBA_INTEGER_EXT:
+ case GL_BGR_INTEGER_EXT:
+ case GL_BGRA_INTEGER_EXT:
+ case GL_LUMINANCE_INTEGER_EXT:
+ case GL_LUMINANCE_ALPHA_INTEGER_EXT:
+ /* fall-through */
+ case GL_RGBA8I_EXT:
+ case GL_RGB8I_EXT:
+ case GL_ALPHA8I_EXT:
+ case GL_INTENSITY8I_EXT:
+ case GL_LUMINANCE8I_EXT:
+ case GL_LUMINANCE_ALPHA8I_EXT:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_R8G8B8A8_SSCALED,
+ target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_R8G8B8A8_SSCALED;
+ return PIPE_FORMAT_NONE;
+ case GL_RGBA16I_EXT:
+ case GL_RGB16I_EXT:
+ case GL_ALPHA16I_EXT:
+ case GL_INTENSITY16I_EXT:
+ case GL_LUMINANCE16I_EXT:
+ case GL_LUMINANCE_ALPHA16I_EXT:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_R16G16B16A16_SSCALED,
+ target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_R16G16B16A16_SSCALED;
+ return PIPE_FORMAT_NONE;
+ case GL_RGBA32I_EXT:
+ case GL_RGB32I_EXT:
+ case GL_ALPHA32I_EXT:
+ case GL_INTENSITY32I_EXT:
+ case GL_LUMINANCE32I_EXT:
+ case GL_LUMINANCE_ALPHA32I_EXT:
+ /* xxx */
+ if (screen->is_format_supported(screen, PIPE_FORMAT_R32G32B32A32_SSCALED,
+ target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_R32G32B32A32_SSCALED;
+ return PIPE_FORMAT_NONE;
+
+ case GL_RGBA8UI_EXT:
+ case GL_RGB8UI_EXT:
+ case GL_ALPHA8UI_EXT:
+ case GL_INTENSITY8UI_EXT:
+ case GL_LUMINANCE8UI_EXT:
+ case GL_LUMINANCE_ALPHA8UI_EXT:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_R8G8B8A8_USCALED,
+ target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_R8G8B8A8_USCALED;
+ return PIPE_FORMAT_NONE;
+
+ case GL_RGBA16UI_EXT:
+ case GL_RGB16UI_EXT:
+ case GL_ALPHA16UI_EXT:
+ case GL_INTENSITY16UI_EXT:
+ case GL_LUMINANCE16UI_EXT:
+ case GL_LUMINANCE_ALPHA16UI_EXT:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_R16G16B16A16_USCALED,
+ target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_R16G16B16A16_USCALED;
+ return PIPE_FORMAT_NONE;
+
+ case GL_RGBA32UI_EXT:
+ case GL_RGB32UI_EXT:
+ case GL_ALPHA32UI_EXT:
+ case GL_INTENSITY32UI_EXT:
+ case GL_LUMINANCE32UI_EXT:
+ case GL_LUMINANCE_ALPHA32UI_EXT:
+ if (screen->is_format_supported(screen, PIPE_FORMAT_R32G32B32A32_USCALED,
+ target,
+ sample_count, bindings, geom_flags))
+ return PIPE_FORMAT_R32G32B32A32_USCALED;
+ return PIPE_FORMAT_NONE;
+
+ default:
+ return PIPE_FORMAT_NONE;
+ }
+}
+
+
+/**
+ * Called by FBO code to choose a PIPE_FORMAT_ for drawing surfaces.
+ */
+enum pipe_format
+st_choose_renderbuffer_format(struct pipe_screen *screen,
+ GLenum internalFormat, unsigned sample_count)
+{
+ uint usage;
+ if (_mesa_is_depth_or_stencil_format(internalFormat))
+ usage = PIPE_BIND_DEPTH_STENCIL;
+ else
+ usage = PIPE_BIND_RENDER_TARGET;
+ return st_choose_format(screen, internalFormat, PIPE_TEXTURE_2D,
+ sample_count, usage);
+}
+
+
+/**
+ * Called via ctx->Driver.chooseTextureFormat().
+ */
+gl_format
+st_ChooseTextureFormat_renderable(struct gl_context *ctx, GLint internalFormat,
+ GLenum format, GLenum type, GLboolean renderable)
+{
+ struct pipe_screen *screen = st_context(ctx)->pipe->screen;
+ enum pipe_format pFormat;
+ uint bindings;
+
+ (void) format;
+ (void) type;
+
+ /* GL textures may wind up being render targets, but we don't know
+ * that in advance. Specify potential render target flags now.
+ */
+ bindings = PIPE_BIND_SAMPLER_VIEW;
+ if (renderable == GL_TRUE) {
+ if (_mesa_is_depth_format(internalFormat) ||
+ _mesa_is_depth_or_stencil_format(internalFormat))
+ bindings |= PIPE_BIND_DEPTH_STENCIL;
+ else
+ bindings |= PIPE_BIND_RENDER_TARGET;
+ }
+
+ pFormat = st_choose_format(screen, internalFormat,
+ PIPE_TEXTURE_2D, 0, bindings);
+
+ if (pFormat == PIPE_FORMAT_NONE) {
+ /* try choosing format again, this time without render target bindings */
+ pFormat = st_choose_format(screen, internalFormat,
+ PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW);
+ }
+
+ if (pFormat == PIPE_FORMAT_NONE) {
+ /* no luck at all */
+ return MESA_FORMAT_NONE;
+ }
+
+ return st_pipe_format_to_mesa_format(pFormat);
+}
+
+gl_format
+st_ChooseTextureFormat(struct gl_context *ctx, GLint internalFormat,
+ GLenum format, GLenum type)
+{
+ boolean want_renderable =
+ internalFormat == 3 || internalFormat == 4 ||
+ internalFormat == GL_RGB || internalFormat == GL_RGBA ||
+ internalFormat == GL_RGB8 || internalFormat == GL_RGBA8 ||
+ internalFormat == GL_BGRA;
+
+ return st_ChooseTextureFormat_renderable(ctx, internalFormat,
+ format, type, want_renderable);
+}
+
+/**
+ * Test if a gallium format is equivalent to a GL format/type.
+ */
+GLboolean
+st_equal_formats(enum pipe_format pFormat, GLenum format, GLenum type)
+{
+ switch (pFormat) {
+ case PIPE_FORMAT_A8B8G8R8_UNORM:
+ return format == GL_RGBA && type == GL_UNSIGNED_BYTE;
+ case PIPE_FORMAT_A8R8G8B8_UNORM:
+ return format == GL_BGRA && type == GL_UNSIGNED_BYTE;
+ case PIPE_FORMAT_B5G6R5_UNORM:
+ return format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5;
+ /* XXX more combos... */
+ default:
+ return GL_FALSE;
+ }
+}
+
+GLboolean
+st_sampler_compat_formats(enum pipe_format format1, enum pipe_format format2)
+{
+ if (format1 == format2)
+ return GL_TRUE;
+
+ if (format1 == PIPE_FORMAT_B8G8R8A8_UNORM &&
+ format2 == PIPE_FORMAT_B8G8R8X8_UNORM)
+ return GL_TRUE;
+
+ if (format1 == PIPE_FORMAT_B8G8R8X8_UNORM &&
+ format2 == PIPE_FORMAT_B8G8R8A8_UNORM)
+ return GL_TRUE;
+
+ if (format1 == PIPE_FORMAT_A8B8G8R8_UNORM &&
+ format2 == PIPE_FORMAT_X8B8G8R8_UNORM)
+ return GL_TRUE;
+
+ if (format1 == PIPE_FORMAT_X8B8G8R8_UNORM &&
+ format2 == PIPE_FORMAT_A8B8G8R8_UNORM)
+ return GL_TRUE;
+
+ if (format1 == PIPE_FORMAT_A8R8G8B8_UNORM &&
+ format2 == PIPE_FORMAT_X8R8G8B8_UNORM)
+ return GL_TRUE;
+
+ if (format1 == PIPE_FORMAT_X8R8G8B8_UNORM &&
+ format2 == PIPE_FORMAT_A8R8G8B8_UNORM)
+ return GL_TRUE;
+
+ return GL_FALSE;
+}
+
+
+
+/**
+ * This is used for translating texture border color and the clear
+ * color. For example, the clear color is interpreted according to
+ * the renderbuffer's base format. For example, if clearing a
+ * GL_LUMINANCE buffer, ClearColor[0] = luminance and ClearColor[1] =
+ * alpha. Similarly for texture border colors.
+ */
+void
+st_translate_color(const GLfloat colorIn[4], GLenum baseFormat,
+ GLfloat colorOut[4])
+{
+ switch (baseFormat) {
+ case GL_RED:
+ colorOut[0] = colorIn[0];
+ colorOut[1] = 0.0F;
+ colorOut[2] = 0.0F;
+ colorOut[3] = 1.0F;
+ break;
+ case GL_RG:
+ colorOut[0] = colorIn[0];
+ colorOut[1] = colorIn[1];
+ colorOut[2] = 0.0F;
+ colorOut[3] = 1.0F;
+ break;
+ case GL_RGB:
+ colorOut[0] = colorIn[0];
+ colorOut[1] = colorIn[1];
+ colorOut[2] = colorIn[2];
+ colorOut[3] = 1.0F;
+ break;
+ case GL_ALPHA:
+ colorOut[0] = colorOut[1] = colorOut[2] = 0.0;
+ colorOut[3] = colorIn[3];
+ break;
+ case GL_LUMINANCE:
+ colorOut[0] = colorOut[1] = colorOut[2] = colorIn[0];
+ colorOut[3] = 1.0;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ colorOut[0] = colorOut[1] = colorOut[2] = colorIn[0];
+ colorOut[3] = colorIn[3];
+ break;
+ case GL_INTENSITY:
+ colorOut[0] = colorOut[1] = colorOut[2] = colorOut[3] = colorIn[0];
+ break;
+ default:
+ COPY_4V(colorOut, colorIn);
+ }
+}
diff --git a/mesalib/src/mesa/state_tracker/st_format.h b/mesalib/src/mesa/state_tracker/st_format.h
index 0fb570f6e..d31e60711 100644
--- a/mesalib/src/mesa/state_tracker/st_format.h
+++ b/mesalib/src/mesa/state_tracker/st_format.h
@@ -1,86 +1,86 @@
-/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * Copyright (c) 2010 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, 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.
- *
- **************************************************************************/
-
-
-#ifndef ST_FORMAT_H
-#define ST_FORMAT_H
-
-#include "main/formats.h"
-#include "main/glheader.h"
-
-#include "pipe/p_defines.h"
-#include "pipe/p_format.h"
-
-struct gl_context;
-struct pipe_screen;
-
-extern GLenum
-st_format_datatype(enum pipe_format format);
-
-
-extern enum pipe_format
-st_mesa_format_to_pipe_format(gl_format mesaFormat);
-
-extern gl_format
-st_pipe_format_to_mesa_format(enum pipe_format pipeFormat);
-
-
-extern enum pipe_format
-st_choose_format(struct pipe_screen *screen, GLenum internalFormat,
- enum pipe_texture_target target, unsigned sample_count,
- unsigned tex_usage);
-
-extern enum pipe_format
-st_choose_renderbuffer_format(struct pipe_screen *screen,
- GLenum internalFormat, unsigned sample_count);
-
-
-gl_format
-st_ChooseTextureFormat_renderable(struct gl_context *ctx, GLint internalFormat,
- GLenum format, GLenum type, GLboolean renderable);
-
-extern gl_format
-st_ChooseTextureFormat(struct gl_context * ctx, GLint internalFormat,
- GLenum format, GLenum type);
-
-
-extern GLboolean
-st_equal_formats(enum pipe_format pFormat, GLenum format, GLenum type);
-
-/* can we use a sampler view to translate these formats
- only used to make TFP so far */
-extern GLboolean
-st_sampler_compat_formats(enum pipe_format format1, enum pipe_format format2);
-
-
-extern void
-st_translate_color(const GLfloat colorIn[4], GLenum baseFormat,
- GLfloat colorOut[4]);
-
-
-#endif /* ST_FORMAT_H */
+/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright (c) 2010 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, 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.
+ *
+ **************************************************************************/
+
+
+#ifndef ST_FORMAT_H
+#define ST_FORMAT_H
+
+#include "main/formats.h"
+#include "main/glheader.h"
+
+#include "pipe/p_defines.h"
+#include "pipe/p_format.h"
+
+struct gl_context;
+struct pipe_screen;
+
+extern GLenum
+st_format_datatype(enum pipe_format format);
+
+
+extern enum pipe_format
+st_mesa_format_to_pipe_format(gl_format mesaFormat);
+
+extern gl_format
+st_pipe_format_to_mesa_format(enum pipe_format pipeFormat);
+
+
+extern enum pipe_format
+st_choose_format(struct pipe_screen *screen, GLenum internalFormat,
+ enum pipe_texture_target target, unsigned sample_count,
+ unsigned tex_usage);
+
+extern enum pipe_format
+st_choose_renderbuffer_format(struct pipe_screen *screen,
+ GLenum internalFormat, unsigned sample_count);
+
+
+gl_format
+st_ChooseTextureFormat_renderable(struct gl_context *ctx, GLint internalFormat,
+ GLenum format, GLenum type, GLboolean renderable);
+
+extern gl_format
+st_ChooseTextureFormat(struct gl_context * ctx, GLint internalFormat,
+ GLenum format, GLenum type);
+
+
+extern GLboolean
+st_equal_formats(enum pipe_format pFormat, GLenum format, GLenum type);
+
+/* can we use a sampler view to translate these formats
+ only used to make TFP so far */
+extern GLboolean
+st_sampler_compat_formats(enum pipe_format format1, enum pipe_format format2);
+
+
+extern void
+st_translate_color(const GLfloat colorIn[4], GLenum baseFormat,
+ GLfloat colorOut[4]);
+
+
+#endif /* ST_FORMAT_H */
diff --git a/mesalib/src/mesa/state_tracker/st_gen_mipmap.c b/mesalib/src/mesa/state_tracker/st_gen_mipmap.c
index 4bf682808..d04ec696f 100644
--- a/mesalib/src/mesa/state_tracker/st_gen_mipmap.c
+++ b/mesalib/src/mesa/state_tracker/st_gen_mipmap.c
@@ -1,422 +1,422 @@
-/**************************************************************************
- *
- * Copyright 2008 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/mipmap.h"
-#include "main/teximage.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "util/u_inlines.h"
-#include "util/u_format.h"
-#include "util/u_gen_mipmap.h"
-
-#include "st_debug.h"
-#include "st_context.h"
-#include "st_texture.h"
-#include "st_gen_mipmap.h"
-#include "st_cb_texture.h"
-
-
-/**
- * one-time init for generate mipmap
- * XXX Note: there may be other times we need no-op/simple state like this.
- * In that case, some code refactoring would be good.
- */
-void
-st_init_generate_mipmap(struct st_context *st)
-{
- st->gen_mipmap = util_create_gen_mipmap(st->pipe, st->cso_context);
-}
-
-
-void
-st_destroy_generate_mipmap(struct st_context *st)
-{
- util_destroy_gen_mipmap(st->gen_mipmap);
- st->gen_mipmap = NULL;
-}
-
-
-/**
- * Generate mipmap levels using hardware rendering.
- * \return TRUE if successful, FALSE if not possible
- */
-static boolean
-st_render_mipmap(struct st_context *st,
- GLenum target,
- struct st_texture_object *stObj,
- uint baseLevel, uint lastLevel)
-{
- struct pipe_context *pipe = st->pipe;
- struct pipe_screen *screen = pipe->screen;
- struct pipe_sampler_view *psv = st_get_texture_sampler_view(stObj, pipe);
- const uint face = _mesa_tex_target_to_face(target);
-
- assert(psv->texture == stObj->pt);
-#if 0
- assert(target != GL_TEXTURE_3D); /* implemented but untested */
-#endif
-
- /* check if we can render in the texture's format */
- /* XXX should probably kill this and always use util_gen_mipmap
- since this implements a sw fallback as well */
- if (!screen->is_format_supported(screen, psv->format, psv->texture->target,
- 0, PIPE_BIND_RENDER_TARGET, 0)) {
- return FALSE;
- }
-
- util_gen_mipmap(st->gen_mipmap, psv, face, baseLevel, lastLevel,
- PIPE_TEX_FILTER_LINEAR);
-
- return TRUE;
-}
-
-
-/**
- * Helper function to decompress an image. The result is a 32-bpp RGBA
- * image with stride==width.
- */
-static void
-decompress_image(enum pipe_format format,
- const uint8_t *src, uint8_t *dst,
- unsigned width, unsigned height, unsigned src_stride)
-{
- const struct util_format_description *desc = util_format_description(format);
- const uint bw = util_format_get_blockwidth(format);
- const uint bh = util_format_get_blockheight(format);
- const uint dst_stride = 4 * MAX2(width, bw);
-
- desc->unpack_rgba_8unorm(dst, dst_stride, src, src_stride, width, height);
-
- if (width < bw || height < bh) {
- /* We're decompressing an image smaller than the compression
- * block size. We don't want garbage pixel values in the region
- * outside (width x height) so replicate pixels from the (width
- * x height) region to fill out the (bw x bh) block size.
- */
- uint x, y;
- for (y = 0; y < bh; y++) {
- for (x = 0; x < bw; x++) {
- if (x >= width || y >= height) {
- uint p = (y * bw + x) * 4;
- dst[p + 0] = dst[0];
- dst[p + 1] = dst[1];
- dst[p + 2] = dst[2];
- dst[p + 3] = dst[3];
- }
- }
- }
- }
-}
-
-
-/**
- * Helper function to compress an image. The source is a 32-bpp RGBA image
- * with stride==width.
- */
-static void
-compress_image(enum pipe_format format,
- const uint8_t *src, uint8_t *dst,
- unsigned width, unsigned height, unsigned dst_stride)
-{
- const struct util_format_description *desc = util_format_description(format);
- const uint src_stride = 4 * width;
-
- desc->pack_rgba_8unorm(dst, dst_stride, src, src_stride, width, height);
-}
-
-
-/**
- * Software fallback for generate mipmap levels.
- */
-static void
-fallback_generate_mipmap(struct gl_context *ctx, GLenum target,
- struct gl_texture_object *texObj)
-{
- struct pipe_context *pipe = st_context(ctx)->pipe;
- struct pipe_resource *pt = st_get_texobj_resource(texObj);
- const uint baseLevel = texObj->BaseLevel;
- const uint lastLevel = pt->last_level;
- const uint face = _mesa_tex_target_to_face(target);
- uint dstLevel;
- GLenum datatype;
- GLuint comps;
- GLboolean compressed;
-
- if (ST_DEBUG & DEBUG_FALLBACK)
- debug_printf("%s: fallback processing\n", __FUNCTION__);
-
- assert(target != GL_TEXTURE_3D); /* not done yet */
-
- compressed =
- _mesa_is_format_compressed(texObj->Image[face][baseLevel]->TexFormat);
-
- if (compressed) {
- datatype = GL_UNSIGNED_BYTE;
- comps = 4;
- }
- else {
- _mesa_format_to_type_and_comps(texObj->Image[face][baseLevel]->TexFormat,
- &datatype, &comps);
- assert(comps > 0 && "bad texture format in fallback_generate_mipmap()");
- }
-
- for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
- const uint srcLevel = dstLevel - 1;
- const uint srcWidth = u_minify(pt->width0, srcLevel);
- const uint srcHeight = u_minify(pt->height0, srcLevel);
- const uint srcDepth = u_minify(pt->depth0, srcLevel);
- const uint dstWidth = u_minify(pt->width0, dstLevel);
- const uint dstHeight = u_minify(pt->height0, dstLevel);
- const uint dstDepth = u_minify(pt->depth0, dstLevel);
- struct pipe_transfer *srcTrans, *dstTrans;
- const ubyte *srcData;
- ubyte *dstData;
- int srcStride, dstStride;
-
- srcTrans = pipe_get_transfer(st_context(ctx)->pipe, pt, srcLevel,
- face,
- PIPE_TRANSFER_READ, 0, 0,
- srcWidth, srcHeight);
-
- dstTrans = pipe_get_transfer(st_context(ctx)->pipe, pt, dstLevel,
- face,
- PIPE_TRANSFER_WRITE, 0, 0,
- dstWidth, dstHeight);
-
- srcData = (ubyte *) pipe_transfer_map(pipe, srcTrans);
- dstData = (ubyte *) pipe_transfer_map(pipe, dstTrans);
-
- srcStride = srcTrans->stride / util_format_get_blocksize(srcTrans->resource->format);
- dstStride = dstTrans->stride / util_format_get_blocksize(dstTrans->resource->format);
-
- /* this cannot work correctly for 3d since it does
- not respect layerStride. */
- if (compressed) {
- const enum pipe_format format = pt->format;
- const uint bw = util_format_get_blockwidth(format);
- const uint bh = util_format_get_blockheight(format);
- const uint srcWidth2 = align(srcWidth, bw);
- const uint srcHeight2 = align(srcHeight, bh);
- const uint dstWidth2 = align(dstWidth, bw);
- const uint dstHeight2 = align(dstHeight, bh);
- uint8_t *srcTemp, *dstTemp;
-
- assert(comps == 4);
-
- srcTemp = malloc(srcWidth2 * srcHeight2 * comps + 000);
- dstTemp = malloc(dstWidth2 * dstHeight2 * comps + 000);
-
- /* decompress the src image: srcData -> srcTemp */
- decompress_image(format, srcData, srcTemp, srcWidth, srcHeight, srcTrans->stride);
-
- _mesa_generate_mipmap_level(target, datatype, comps,
- 0 /*border*/,
- srcWidth2, srcHeight2, srcDepth,
- srcTemp,
- srcWidth2, /* stride in texels */
- dstWidth2, dstHeight2, dstDepth,
- dstTemp,
- dstWidth2); /* stride in texels */
-
- /* compress the new image: dstTemp -> dstData */
- compress_image(format, dstTemp, dstData, dstWidth, dstHeight, dstTrans->stride);
-
- free(srcTemp);
- free(dstTemp);
- }
- else {
- _mesa_generate_mipmap_level(target, datatype, comps,
- 0 /*border*/,
- srcWidth, srcHeight, srcDepth,
- srcData,
- srcStride, /* stride in texels */
- dstWidth, dstHeight, dstDepth,
- dstData,
- dstStride); /* stride in texels */
- }
-
- pipe_transfer_unmap(pipe, srcTrans);
- pipe_transfer_unmap(pipe, dstTrans);
-
- pipe->transfer_destroy(pipe, srcTrans);
- pipe->transfer_destroy(pipe, dstTrans);
- }
-}
-
-
-/**
- * Compute the expected number of mipmap levels in the texture given
- * the width/height/depth of the base image and the GL_TEXTURE_BASE_LEVEL/
- * GL_TEXTURE_MAX_LEVEL settings. This will tell us how many mipmap
- * levels should be generated.
- */
-static GLuint
-compute_num_levels(struct gl_context *ctx,
- struct gl_texture_object *texObj,
- GLenum target)
-{
- if (target == GL_TEXTURE_RECTANGLE_ARB) {
- return 1;
- }
- else {
- const struct gl_texture_image *baseImage =
- _mesa_get_tex_image(ctx, texObj, target, texObj->BaseLevel);
- GLuint size, numLevels;
-
- size = MAX2(baseImage->Width2, baseImage->Height2);
- size = MAX2(size, baseImage->Depth2);
-
- numLevels = texObj->BaseLevel;
-
- while (size > 0) {
- numLevels++;
- size >>= 1;
- }
-
- numLevels = MIN2(numLevels, texObj->MaxLevel + 1);
-
- assert(numLevels >= 1);
-
- return numLevels;
- }
-}
-
-
-/**
- * Called via ctx->Driver.GenerateMipmap().
- */
-void
-st_generate_mipmap(struct gl_context *ctx, GLenum target,
- struct gl_texture_object *texObj)
-{
- struct st_context *st = st_context(ctx);
- struct st_texture_object *stObj = st_texture_object(texObj);
- struct pipe_resource *pt = st_get_texobj_resource(texObj);
- const uint baseLevel = texObj->BaseLevel;
- uint lastLevel;
- uint dstLevel;
-
- if (!pt)
- return;
-
- /* not sure if this ultimately actually should work,
- but we're not supporting multisampled textures yet. */
- assert(pt->nr_samples < 2);
-
- /* find expected last mipmap level to generate*/
- lastLevel = compute_num_levels(ctx, texObj, target) - 1;
-
- if (lastLevel == 0)
- return;
-
- /* The texture isn't in a "complete" state yet so set the expected
- * lastLevel here, since it won't get done in st_finalize_texture().
- */
- stObj->lastLevel = lastLevel;
-
- if (pt->last_level < lastLevel) {
- /* The current gallium texture doesn't have space for all the
- * mipmap levels we need to generate. So allocate a new texture.
- */
- struct pipe_resource *oldTex = stObj->pt;
-
- /* create new texture with space for more levels */
- stObj->pt = st_texture_create(st,
- oldTex->target,
- oldTex->format,
- lastLevel,
- oldTex->width0,
- oldTex->height0,
- oldTex->depth0,
- oldTex->array_size,
- oldTex->bind);
-
- /* This will copy the old texture's base image into the new texture
- * which we just allocated.
- */
- st_finalize_texture(ctx, st->pipe, texObj);
-
- /* release the old tex (will likely be freed too) */
- pipe_resource_reference(&oldTex, NULL);
- pipe_sampler_view_reference(&stObj->sampler_view, NULL);
- }
- else {
- /* Make sure that the base texture image data is present in the
- * texture buffer.
- */
- st_finalize_texture(ctx, st->pipe, texObj);
- }
-
- pt = stObj->pt;
-
- assert(pt->last_level >= lastLevel);
-
- /* Try to generate the mipmap by rendering/texturing. If that fails,
- * use the software fallback.
- */
- if (!st_render_mipmap(st, target, stObj, baseLevel, lastLevel)) {
- /* since the util code actually also has a fallback, should
- probably make it never fail and kill this */
- fallback_generate_mipmap(ctx, target, texObj);
- }
-
- /* Fill in the Mesa gl_texture_image fields */
- for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
- const uint srcLevel = dstLevel - 1;
- const struct gl_texture_image *srcImage
- = _mesa_get_tex_image(ctx, texObj, target, srcLevel);
- struct gl_texture_image *dstImage;
- struct st_texture_image *stImage;
- uint dstWidth = u_minify(pt->width0, dstLevel);
- uint dstHeight = u_minify(pt->height0, dstLevel);
- uint dstDepth = u_minify(pt->depth0, dstLevel);
- uint border = srcImage->Border;
-
- dstImage = _mesa_get_tex_image(ctx, texObj, target, dstLevel);
- if (!dstImage) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
- return;
- }
-
- /* Free old image data */
- if (dstImage->Data)
- ctx->Driver.FreeTexImageData(ctx, dstImage);
-
- /* initialize new image */
- _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
- dstDepth, border, srcImage->InternalFormat,
- srcImage->TexFormat);
-
- stImage = st_texture_image(dstImage);
- stImage->level = dstLevel;
-
- pipe_resource_reference(&stImage->pt, pt);
- }
-}
+/**************************************************************************
+ *
+ * Copyright 2008 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/mipmap.h"
+#include "main/teximage.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_defines.h"
+#include "util/u_inlines.h"
+#include "util/u_format.h"
+#include "util/u_gen_mipmap.h"
+
+#include "st_debug.h"
+#include "st_context.h"
+#include "st_texture.h"
+#include "st_gen_mipmap.h"
+#include "st_cb_texture.h"
+
+
+/**
+ * one-time init for generate mipmap
+ * XXX Note: there may be other times we need no-op/simple state like this.
+ * In that case, some code refactoring would be good.
+ */
+void
+st_init_generate_mipmap(struct st_context *st)
+{
+ st->gen_mipmap = util_create_gen_mipmap(st->pipe, st->cso_context);
+}
+
+
+void
+st_destroy_generate_mipmap(struct st_context *st)
+{
+ util_destroy_gen_mipmap(st->gen_mipmap);
+ st->gen_mipmap = NULL;
+}
+
+
+/**
+ * Generate mipmap levels using hardware rendering.
+ * \return TRUE if successful, FALSE if not possible
+ */
+static boolean
+st_render_mipmap(struct st_context *st,
+ GLenum target,
+ struct st_texture_object *stObj,
+ uint baseLevel, uint lastLevel)
+{
+ struct pipe_context *pipe = st->pipe;
+ struct pipe_screen *screen = pipe->screen;
+ struct pipe_sampler_view *psv = st_get_texture_sampler_view(stObj, pipe);
+ const uint face = _mesa_tex_target_to_face(target);
+
+ assert(psv->texture == stObj->pt);
+#if 0
+ assert(target != GL_TEXTURE_3D); /* implemented but untested */
+#endif
+
+ /* check if we can render in the texture's format */
+ /* XXX should probably kill this and always use util_gen_mipmap
+ since this implements a sw fallback as well */
+ if (!screen->is_format_supported(screen, psv->format, psv->texture->target,
+ 0, PIPE_BIND_RENDER_TARGET, 0)) {
+ return FALSE;
+ }
+
+ util_gen_mipmap(st->gen_mipmap, psv, face, baseLevel, lastLevel,
+ PIPE_TEX_FILTER_LINEAR);
+
+ return TRUE;
+}
+
+
+/**
+ * Helper function to decompress an image. The result is a 32-bpp RGBA
+ * image with stride==width.
+ */
+static void
+decompress_image(enum pipe_format format,
+ const uint8_t *src, uint8_t *dst,
+ unsigned width, unsigned height, unsigned src_stride)
+{
+ const struct util_format_description *desc = util_format_description(format);
+ const uint bw = util_format_get_blockwidth(format);
+ const uint bh = util_format_get_blockheight(format);
+ const uint dst_stride = 4 * MAX2(width, bw);
+
+ desc->unpack_rgba_8unorm(dst, dst_stride, src, src_stride, width, height);
+
+ if (width < bw || height < bh) {
+ /* We're decompressing an image smaller than the compression
+ * block size. We don't want garbage pixel values in the region
+ * outside (width x height) so replicate pixels from the (width
+ * x height) region to fill out the (bw x bh) block size.
+ */
+ uint x, y;
+ for (y = 0; y < bh; y++) {
+ for (x = 0; x < bw; x++) {
+ if (x >= width || y >= height) {
+ uint p = (y * bw + x) * 4;
+ dst[p + 0] = dst[0];
+ dst[p + 1] = dst[1];
+ dst[p + 2] = dst[2];
+ dst[p + 3] = dst[3];
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ * Helper function to compress an image. The source is a 32-bpp RGBA image
+ * with stride==width.
+ */
+static void
+compress_image(enum pipe_format format,
+ const uint8_t *src, uint8_t *dst,
+ unsigned width, unsigned height, unsigned dst_stride)
+{
+ const struct util_format_description *desc = util_format_description(format);
+ const uint src_stride = 4 * width;
+
+ desc->pack_rgba_8unorm(dst, dst_stride, src, src_stride, width, height);
+}
+
+
+/**
+ * Software fallback for generate mipmap levels.
+ */
+static void
+fallback_generate_mipmap(struct gl_context *ctx, GLenum target,
+ struct gl_texture_object *texObj)
+{
+ struct pipe_context *pipe = st_context(ctx)->pipe;
+ struct pipe_resource *pt = st_get_texobj_resource(texObj);
+ const uint baseLevel = texObj->BaseLevel;
+ const uint lastLevel = pt->last_level;
+ const uint face = _mesa_tex_target_to_face(target);
+ uint dstLevel;
+ GLenum datatype;
+ GLuint comps;
+ GLboolean compressed;
+
+ if (ST_DEBUG & DEBUG_FALLBACK)
+ debug_printf("%s: fallback processing\n", __FUNCTION__);
+
+ assert(target != GL_TEXTURE_3D); /* not done yet */
+
+ compressed =
+ _mesa_is_format_compressed(texObj->Image[face][baseLevel]->TexFormat);
+
+ if (compressed) {
+ datatype = GL_UNSIGNED_BYTE;
+ comps = 4;
+ }
+ else {
+ _mesa_format_to_type_and_comps(texObj->Image[face][baseLevel]->TexFormat,
+ &datatype, &comps);
+ assert(comps > 0 && "bad texture format in fallback_generate_mipmap()");
+ }
+
+ for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
+ const uint srcLevel = dstLevel - 1;
+ const uint srcWidth = u_minify(pt->width0, srcLevel);
+ const uint srcHeight = u_minify(pt->height0, srcLevel);
+ const uint srcDepth = u_minify(pt->depth0, srcLevel);
+ const uint dstWidth = u_minify(pt->width0, dstLevel);
+ const uint dstHeight = u_minify(pt->height0, dstLevel);
+ const uint dstDepth = u_minify(pt->depth0, dstLevel);
+ struct pipe_transfer *srcTrans, *dstTrans;
+ const ubyte *srcData;
+ ubyte *dstData;
+ int srcStride, dstStride;
+
+ srcTrans = pipe_get_transfer(st_context(ctx)->pipe, pt, srcLevel,
+ face,
+ PIPE_TRANSFER_READ, 0, 0,
+ srcWidth, srcHeight);
+
+ dstTrans = pipe_get_transfer(st_context(ctx)->pipe, pt, dstLevel,
+ face,
+ PIPE_TRANSFER_WRITE, 0, 0,
+ dstWidth, dstHeight);
+
+ srcData = (ubyte *) pipe_transfer_map(pipe, srcTrans);
+ dstData = (ubyte *) pipe_transfer_map(pipe, dstTrans);
+
+ srcStride = srcTrans->stride / util_format_get_blocksize(srcTrans->resource->format);
+ dstStride = dstTrans->stride / util_format_get_blocksize(dstTrans->resource->format);
+
+ /* this cannot work correctly for 3d since it does
+ not respect layerStride. */
+ if (compressed) {
+ const enum pipe_format format = pt->format;
+ const uint bw = util_format_get_blockwidth(format);
+ const uint bh = util_format_get_blockheight(format);
+ const uint srcWidth2 = align(srcWidth, bw);
+ const uint srcHeight2 = align(srcHeight, bh);
+ const uint dstWidth2 = align(dstWidth, bw);
+ const uint dstHeight2 = align(dstHeight, bh);
+ uint8_t *srcTemp, *dstTemp;
+
+ assert(comps == 4);
+
+ srcTemp = malloc(srcWidth2 * srcHeight2 * comps + 000);
+ dstTemp = malloc(dstWidth2 * dstHeight2 * comps + 000);
+
+ /* decompress the src image: srcData -> srcTemp */
+ decompress_image(format, srcData, srcTemp, srcWidth, srcHeight, srcTrans->stride);
+
+ _mesa_generate_mipmap_level(target, datatype, comps,
+ 0 /*border*/,
+ srcWidth2, srcHeight2, srcDepth,
+ srcTemp,
+ srcWidth2, /* stride in texels */
+ dstWidth2, dstHeight2, dstDepth,
+ dstTemp,
+ dstWidth2); /* stride in texels */
+
+ /* compress the new image: dstTemp -> dstData */
+ compress_image(format, dstTemp, dstData, dstWidth, dstHeight, dstTrans->stride);
+
+ free(srcTemp);
+ free(dstTemp);
+ }
+ else {
+ _mesa_generate_mipmap_level(target, datatype, comps,
+ 0 /*border*/,
+ srcWidth, srcHeight, srcDepth,
+ srcData,
+ srcStride, /* stride in texels */
+ dstWidth, dstHeight, dstDepth,
+ dstData,
+ dstStride); /* stride in texels */
+ }
+
+ pipe_transfer_unmap(pipe, srcTrans);
+ pipe_transfer_unmap(pipe, dstTrans);
+
+ pipe->transfer_destroy(pipe, srcTrans);
+ pipe->transfer_destroy(pipe, dstTrans);
+ }
+}
+
+
+/**
+ * Compute the expected number of mipmap levels in the texture given
+ * the width/height/depth of the base image and the GL_TEXTURE_BASE_LEVEL/
+ * GL_TEXTURE_MAX_LEVEL settings. This will tell us how many mipmap
+ * levels should be generated.
+ */
+static GLuint
+compute_num_levels(struct gl_context *ctx,
+ struct gl_texture_object *texObj,
+ GLenum target)
+{
+ if (target == GL_TEXTURE_RECTANGLE_ARB) {
+ return 1;
+ }
+ else {
+ const struct gl_texture_image *baseImage =
+ _mesa_get_tex_image(ctx, texObj, target, texObj->BaseLevel);
+ GLuint size, numLevels;
+
+ size = MAX2(baseImage->Width2, baseImage->Height2);
+ size = MAX2(size, baseImage->Depth2);
+
+ numLevels = texObj->BaseLevel;
+
+ while (size > 0) {
+ numLevels++;
+ size >>= 1;
+ }
+
+ numLevels = MIN2(numLevels, texObj->MaxLevel + 1);
+
+ assert(numLevels >= 1);
+
+ return numLevels;
+ }
+}
+
+
+/**
+ * Called via ctx->Driver.GenerateMipmap().
+ */
+void
+st_generate_mipmap(struct gl_context *ctx, GLenum target,
+ struct gl_texture_object *texObj)
+{
+ struct st_context *st = st_context(ctx);
+ struct st_texture_object *stObj = st_texture_object(texObj);
+ struct pipe_resource *pt = st_get_texobj_resource(texObj);
+ const uint baseLevel = texObj->BaseLevel;
+ uint lastLevel;
+ uint dstLevel;
+
+ if (!pt)
+ return;
+
+ /* not sure if this ultimately actually should work,
+ but we're not supporting multisampled textures yet. */
+ assert(pt->nr_samples < 2);
+
+ /* find expected last mipmap level to generate*/
+ lastLevel = compute_num_levels(ctx, texObj, target) - 1;
+
+ if (lastLevel == 0)
+ return;
+
+ /* The texture isn't in a "complete" state yet so set the expected
+ * lastLevel here, since it won't get done in st_finalize_texture().
+ */
+ stObj->lastLevel = lastLevel;
+
+ if (pt->last_level < lastLevel) {
+ /* The current gallium texture doesn't have space for all the
+ * mipmap levels we need to generate. So allocate a new texture.
+ */
+ struct pipe_resource *oldTex = stObj->pt;
+
+ /* create new texture with space for more levels */
+ stObj->pt = st_texture_create(st,
+ oldTex->target,
+ oldTex->format,
+ lastLevel,
+ oldTex->width0,
+ oldTex->height0,
+ oldTex->depth0,
+ oldTex->array_size,
+ oldTex->bind);
+
+ /* This will copy the old texture's base image into the new texture
+ * which we just allocated.
+ */
+ st_finalize_texture(ctx, st->pipe, texObj);
+
+ /* release the old tex (will likely be freed too) */
+ pipe_resource_reference(&oldTex, NULL);
+ pipe_sampler_view_reference(&stObj->sampler_view, NULL);
+ }
+ else {
+ /* Make sure that the base texture image data is present in the
+ * texture buffer.
+ */
+ st_finalize_texture(ctx, st->pipe, texObj);
+ }
+
+ pt = stObj->pt;
+
+ assert(pt->last_level >= lastLevel);
+
+ /* Try to generate the mipmap by rendering/texturing. If that fails,
+ * use the software fallback.
+ */
+ if (!st_render_mipmap(st, target, stObj, baseLevel, lastLevel)) {
+ /* since the util code actually also has a fallback, should
+ probably make it never fail and kill this */
+ fallback_generate_mipmap(ctx, target, texObj);
+ }
+
+ /* Fill in the Mesa gl_texture_image fields */
+ for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
+ const uint srcLevel = dstLevel - 1;
+ const struct gl_texture_image *srcImage
+ = _mesa_get_tex_image(ctx, texObj, target, srcLevel);
+ struct gl_texture_image *dstImage;
+ struct st_texture_image *stImage;
+ uint dstWidth = u_minify(pt->width0, dstLevel);
+ uint dstHeight = u_minify(pt->height0, dstLevel);
+ uint dstDepth = u_minify(pt->depth0, dstLevel);
+ uint border = srcImage->Border;
+
+ dstImage = _mesa_get_tex_image(ctx, texObj, target, dstLevel);
+ if (!dstImage) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
+ return;
+ }
+
+ /* Free old image data */
+ if (dstImage->Data)
+ ctx->Driver.FreeTexImageData(ctx, dstImage);
+
+ /* initialize new image */
+ _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
+ dstDepth, border, srcImage->InternalFormat,
+ srcImage->TexFormat);
+
+ stImage = st_texture_image(dstImage);
+ stImage->level = dstLevel;
+
+ pipe_resource_reference(&stImage->pt, pt);
+ }
+}
diff --git a/mesalib/src/mesa/state_tracker/st_program.c b/mesalib/src/mesa/state_tracker/st_program.c
index fc1dfb3ef..e5c26c563 100644
--- a/mesalib/src/mesa/state_tracker/st_program.c
+++ b/mesalib/src/mesa/state_tracker/st_program.c
@@ -1,1165 +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 <keith@tungstengraphics.com>
- * 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);
-}
+/**************************************************************************
+ *
+ * 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 <keith@tungstengraphics.com>
+ * 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);
+}
diff --git a/mesalib/src/mesa/tnl/t_draw.c b/mesalib/src/mesa/tnl/t_draw.c
index b1967e654..a2ca6225b 100644
--- a/mesalib/src/mesa/tnl/t_draw.c
+++ b/mesalib/src/mesa/tnl/t_draw.c
@@ -1,534 +1,534 @@
-/*
- * 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.
- *
- * Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
- */
-
-#include "main/glheader.h"
-#include "main/condrender.h"
-#include "main/context.h"
-#include "main/imports.h"
-#include "main/mtypes.h"
-#include "main/macros.h"
-#include "main/enums.h"
-
-#include "t_context.h"
-#include "tnl.h"
-
-
-
-static GLubyte *get_space(struct gl_context *ctx, GLuint bytes)
-{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- GLubyte *space = malloc(bytes);
-
- tnl->block[tnl->nr_blocks++] = space;
- return space;
-}
-
-
-static void free_space(struct gl_context *ctx)
-{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- GLuint i;
- for (i = 0; i < tnl->nr_blocks; i++)
- free(tnl->block[i]);
- tnl->nr_blocks = 0;
-}
-
-
-/* Convert the incoming array to GLfloats. Understands the
- * array->Normalized flag and selects the correct conversion method.
- */
-#define CONVERT( TYPE, MACRO ) do { \
- GLuint i, j; \
- if (input->Normalized) { \
- for (i = 0; i < count; i++) { \
- const TYPE *in = (TYPE *)ptr; \
- for (j = 0; j < sz; j++) { \
- *fptr++ = MACRO(*in); \
- in++; \
- } \
- ptr += input->StrideB; \
- } \
- } else { \
- for (i = 0; i < count; i++) { \
- const TYPE *in = (TYPE *)ptr; \
- for (j = 0; j < sz; j++) { \
- *fptr++ = (GLfloat)(*in); \
- in++; \
- } \
- ptr += input->StrideB; \
- } \
- } \
-} while (0)
-
-
-/**
- * Convert array of BGRA/GLubyte[4] values to RGBA/float[4]
- * \param ptr input/ubyte array
- * \param fptr output/float array
- */
-static void
-convert_bgra_to_float(const struct gl_client_array *input,
- const GLubyte *ptr, GLfloat *fptr,
- GLuint count )
-{
- GLuint i;
- assert(input->Normalized);
- assert(input->Size == 4);
- for (i = 0; i < count; i++) {
- const GLubyte *in = (GLubyte *) ptr; /* in is in BGRA order */
- *fptr++ = UBYTE_TO_FLOAT(in[2]); /* red */
- *fptr++ = UBYTE_TO_FLOAT(in[1]); /* green */
- *fptr++ = UBYTE_TO_FLOAT(in[0]); /* blue */
- *fptr++ = UBYTE_TO_FLOAT(in[3]); /* alpha */
- ptr += input->StrideB;
- }
-}
-
-static void
-convert_half_to_float(const struct gl_client_array *input,
- const GLubyte *ptr, GLfloat *fptr,
- GLuint count, GLuint sz)
-{
- GLuint i, j;
-
- for (i = 0; i < count; i++) {
- GLhalfARB *in = (GLhalfARB *)ptr;
-
- for (j = 0; j < sz; j++) {
- *fptr++ = _mesa_half_to_float(in[j]);
- }
- ptr += input->StrideB;
- }
-}
-
-/**
- * \brief Convert fixed-point to floating-point.
- *
- * In OpenGL, a fixed-point number is a "signed 2's complement 16.16 scaled
- * integer" (Table 2.2 of the OpenGL ES 2.0 spec).
- *
- * If the buffer has the \c normalized flag set, the formula
- * \code normalize(x) := (2*x + 1) / (2^16 - 1) \endcode
- * is used to map the fixed-point numbers into the range [-1, 1].
- */
-static void
-convert_fixed_to_float(const struct gl_client_array *input,
- const GLubyte *ptr, GLfloat *fptr,
- GLuint count)
-{
- GLuint i, j;
- const GLint size = input->Size;
-
- if (input->Normalized) {
- for (i = 0; i < count; ++i) {
- const GLfixed *in = (GLfixed *) ptr;
- for (j = 0; j < size; ++j) {
- *fptr++ = (GLfloat) (2 * in[j] + 1) / (GLfloat) ((1 << 16) - 1);
- }
- ptr += input->StrideB;
- }
- } else {
- for (i = 0; i < count; ++i) {
- const GLfixed *in = (GLfixed *) ptr;
- for (j = 0; j < size; ++j) {
- *fptr++ = in[j] / (GLfloat) (1 << 16);
- }
- ptr += input->StrideB;
- }
- }
-}
-
-/* Adjust pointer to point at first requested element, convert to
- * floating point, populate VB->AttribPtr[].
- */
-static void _tnl_import_array( struct gl_context *ctx,
- GLuint attrib,
- GLuint count,
- const struct gl_client_array *input,
- const GLubyte *ptr )
-{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- struct vertex_buffer *VB = &tnl->vb;
- GLuint stride = input->StrideB;
-
- if (input->Type != GL_FLOAT) {
- const GLuint sz = input->Size;
- GLubyte *buf = get_space(ctx, count * sz * sizeof(GLfloat));
- GLfloat *fptr = (GLfloat *)buf;
-
- switch (input->Type) {
- case GL_BYTE:
- CONVERT(GLbyte, BYTE_TO_FLOAT);
- break;
- case GL_UNSIGNED_BYTE:
- if (input->Format == GL_BGRA) {
- /* See GL_EXT_vertex_array_bgra */
- convert_bgra_to_float(input, ptr, fptr, count);
- }
- else {
- CONVERT(GLubyte, UBYTE_TO_FLOAT);
- }
- break;
- case GL_SHORT:
- CONVERT(GLshort, SHORT_TO_FLOAT);
- break;
- case GL_UNSIGNED_SHORT:
- CONVERT(GLushort, USHORT_TO_FLOAT);
- break;
- case GL_INT:
- CONVERT(GLint, INT_TO_FLOAT);
- break;
- case GL_UNSIGNED_INT:
- CONVERT(GLuint, UINT_TO_FLOAT);
- break;
- case GL_DOUBLE:
- CONVERT(GLdouble, (GLfloat));
- break;
- case GL_HALF_FLOAT:
- convert_half_to_float(input, ptr, fptr, count, sz);
- break;
- case GL_FIXED:
- convert_fixed_to_float(input, ptr, fptr, count);
- break;
- default:
- assert(0);
- break;
- }
-
- ptr = buf;
- stride = sz * sizeof(GLfloat);
- }
-
- VB->AttribPtr[attrib] = &tnl->tmp_inputs[attrib];
- VB->AttribPtr[attrib]->data = (GLfloat (*)[4])ptr;
- VB->AttribPtr[attrib]->start = (GLfloat *)ptr;
- VB->AttribPtr[attrib]->count = count;
- VB->AttribPtr[attrib]->stride = stride;
- VB->AttribPtr[attrib]->size = input->Size;
-
- /* This should die, but so should the whole GLvector4f concept:
- */
- VB->AttribPtr[attrib]->flags = (((1<<input->Size)-1) |
- VEC_NOT_WRITEABLE |
- (stride == 4*sizeof(GLfloat) ? 0 : VEC_BAD_STRIDE));
-
- VB->AttribPtr[attrib]->storage = NULL;
-}
-
-#define CLIPVERTS ((6 + MAX_CLIP_PLANES) * 2)
-
-
-static GLboolean *_tnl_import_edgeflag( struct gl_context *ctx,
- const GLvector4f *input,
- GLuint count)
-{
- const GLubyte *ptr = (const GLubyte *)input->data;
- const GLuint stride = input->stride;
- GLboolean *space = (GLboolean *)get_space(ctx, count + CLIPVERTS);
- GLboolean *bptr = space;
- GLuint i;
-
- for (i = 0; i < count; i++) {
- *bptr++ = ((GLfloat *)ptr)[0] == 1.0;
- ptr += stride;
- }
-
- return space;
-}
-
-
-static void bind_inputs( struct gl_context *ctx,
- const struct gl_client_array *inputs[],
- GLint count,
- struct gl_buffer_object **bo,
- GLuint *nr_bo )
-{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- struct vertex_buffer *VB = &tnl->vb;
- GLuint i;
-
- /* Map all the VBOs
- */
- for (i = 0; i < VERT_ATTRIB_MAX; i++) {
- const void *ptr;
-
- if (inputs[i]->BufferObj->Name) {
- if (!inputs[i]->BufferObj->Pointer) {
- bo[*nr_bo] = inputs[i]->BufferObj;
- (*nr_bo)++;
- ctx->Driver.MapBuffer(ctx,
- GL_ARRAY_BUFFER,
- GL_READ_ONLY_ARB,
- inputs[i]->BufferObj);
-
- assert(inputs[i]->BufferObj->Pointer);
- }
-
- ptr = ADD_POINTERS(inputs[i]->BufferObj->Pointer,
- inputs[i]->Ptr);
- }
- else
- ptr = inputs[i]->Ptr;
-
- /* Just make sure the array is floating point, otherwise convert to
- * temporary storage.
- *
- * XXX: remove the GLvector4f type at some stage and just use
- * client arrays.
- */
- _tnl_import_array(ctx, i, count, inputs[i], ptr);
- }
-
- /* We process only the vertices between min & max index:
- */
- VB->Count = count;
-
- /* These should perhaps be part of _TNL_ATTRIB_* */
- VB->BackfaceColorPtr = NULL;
- VB->BackfaceIndexPtr = NULL;
- VB->BackfaceSecondaryColorPtr = NULL;
-
- /* Clipping and drawing code still requires this to be a packed
- * array of ubytes which can be written into. TODO: Fix and
- * remove.
- */
- if (ctx->Polygon.FrontMode != GL_FILL ||
- ctx->Polygon.BackMode != GL_FILL)
- {
- VB->EdgeFlag = _tnl_import_edgeflag( ctx,
- VB->AttribPtr[_TNL_ATTRIB_EDGEFLAG],
- VB->Count );
- }
- else {
- /* the data previously pointed to by EdgeFlag may have been freed */
- VB->EdgeFlag = NULL;
- }
-}
-
-
-/* Translate indices to GLuints and store in VB->Elts.
- */
-static void bind_indices( struct gl_context *ctx,
- const struct _mesa_index_buffer *ib,
- struct gl_buffer_object **bo,
- GLuint *nr_bo)
-{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- struct vertex_buffer *VB = &tnl->vb;
- GLuint i;
- void *ptr;
-
- if (!ib) {
- VB->Elts = NULL;
- return;
- }
-
- if (ib->obj->Name && !ib->obj->Pointer) {
- bo[*nr_bo] = ib->obj;
- (*nr_bo)++;
- ctx->Driver.MapBuffer(ctx,
- GL_ELEMENT_ARRAY_BUFFER,
- GL_READ_ONLY_ARB,
- ib->obj);
-
- assert(ib->obj->Pointer);
- }
-
- ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr);
-
- if (ib->type == GL_UNSIGNED_INT && VB->Primitive[0].basevertex == 0) {
- VB->Elts = (GLuint *) ptr;
- }
- else {
- GLuint *elts = (GLuint *)get_space(ctx, ib->count * sizeof(GLuint));
- VB->Elts = elts;
-
- if (ib->type == GL_UNSIGNED_INT) {
- const GLuint *in = (GLuint *)ptr;
- for (i = 0; i < ib->count; i++)
- *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex;
- }
- else if (ib->type == GL_UNSIGNED_SHORT) {
- const GLushort *in = (GLushort *)ptr;
- for (i = 0; i < ib->count; i++)
- *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex;
- }
- else {
- const GLubyte *in = (GLubyte *)ptr;
- for (i = 0; i < ib->count; i++)
- *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex;
- }
- }
-}
-
-static void bind_prims( struct gl_context *ctx,
- const struct _mesa_prim *prim,
- GLuint nr_prims )
-{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- struct vertex_buffer *VB = &tnl->vb;
-
- VB->Primitive = prim;
- VB->PrimitiveCount = nr_prims;
-}
-
-static void unmap_vbos( struct gl_context *ctx,
- struct gl_buffer_object **bo,
- GLuint nr_bo )
-{
- GLuint i;
- for (i = 0; i < nr_bo; i++) {
- ctx->Driver.UnmapBuffer(ctx,
- 0, /* target -- I don't see why this would be needed */
- bo[i]);
- }
-}
-
-
-void _tnl_vbo_draw_prims(struct gl_context *ctx,
- const struct gl_client_array *arrays[],
- const struct _mesa_prim *prim,
- GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
- GLboolean index_bounds_valid,
- GLuint min_index,
- GLuint max_index)
-{
- if (!index_bounds_valid)
- vbo_get_minmax_index(ctx, prim, ib, &min_index, &max_index);
-
- _tnl_draw_prims(ctx, arrays, prim, nr_prims, ib, min_index, max_index);
-}
-
-/* This is the main entrypoint into the slimmed-down software tnl
- * module. In a regular swtnl driver, this can be plugged straight
- * into the vbo->Driver.DrawPrims() callback.
- */
-void _tnl_draw_prims( struct gl_context *ctx,
- const struct gl_client_array *arrays[],
- const struct _mesa_prim *prim,
- GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
- GLuint min_index,
- GLuint max_index)
-{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- const GLuint TEST_SPLIT = 0;
- const GLint max = TEST_SPLIT ? 8 : tnl->vb.Size - MAX_CLIPPED_VERTICES;
- GLint max_basevertex = prim->basevertex;
- GLuint i;
-
- /* Mesa core state should have been validated already */
- assert(ctx->NewState == 0x0);
-
- if (!_mesa_check_conditional_render(ctx))
- return; /* don't draw */
-
- for (i = 1; i < nr_prims; i++)
- max_basevertex = MAX2(max_basevertex, prim[i].basevertex);
-
- if (0)
- {
- printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
- for (i = 0; i < nr_prims; i++)
- printf("prim %d: %s start %d count %d\n", i,
- _mesa_lookup_enum_by_nr(prim[i].mode),
- prim[i].start,
- prim[i].count);
- }
-
- if (min_index) {
- /* We always translate away calls with min_index != 0.
- */
- vbo_rebase_prims( ctx, arrays, prim, nr_prims, ib,
- min_index, max_index,
- _tnl_vbo_draw_prims );
- return;
- }
- else if ((GLint)max_index + max_basevertex > max) {
- /* The software TNL pipeline has a fixed amount of storage for
- * vertices and it is necessary to split incoming drawing commands
- * if they exceed that limit.
- */
- struct split_limits limits;
- limits.max_verts = max;
- limits.max_vb_size = ~0;
- limits.max_indices = ~0;
-
- /* This will split the buffers one way or another and
- * recursively call back into this function.
- */
- vbo_split_prims( ctx, arrays, prim, nr_prims, ib,
- 0, max_index + prim->basevertex,
- _tnl_vbo_draw_prims,
- &limits );
- }
- else {
- /* May need to map a vertex buffer object for every attribute plus
- * one for the index buffer.
- */
- struct gl_buffer_object *bo[VERT_ATTRIB_MAX + 1];
- GLuint nr_bo = 0;
- GLuint inst;
-
- for (i = 0; i < nr_prims;) {
- GLuint this_nr_prims;
-
- /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices
- * will rebase the elements to the basevertex, and we'll only
- * emit strings of prims with the same basevertex in one draw call.
- */
- for (this_nr_prims = 1; i + this_nr_prims < nr_prims;
- this_nr_prims++) {
- if (prim[i].basevertex != prim[i + this_nr_prims].basevertex)
- break;
- }
-
- assert(prim[i].num_instances > 0);
-
- /* Binding inputs may imply mapping some vertex buffer objects.
- * They will need to be unmapped below.
- */
- for (inst = 0; inst < prim[i].num_instances; inst++) {
-
- bind_prims(ctx, &prim[i], this_nr_prims);
- bind_inputs(ctx, arrays, max_index + prim[i].basevertex + 1,
- bo, &nr_bo);
- bind_indices(ctx, ib, bo, &nr_bo);
-
- tnl->CurInstance = inst;
- TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx);
-
- unmap_vbos(ctx, bo, nr_bo);
- free_space(ctx);
- }
-
- i += this_nr_prims;
- }
- }
-}
-
+/*
+ * 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.
+ *
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "main/glheader.h"
+#include "main/condrender.h"
+#include "main/context.h"
+#include "main/imports.h"
+#include "main/mtypes.h"
+#include "main/macros.h"
+#include "main/enums.h"
+
+#include "t_context.h"
+#include "tnl.h"
+
+
+
+static GLubyte *get_space(struct gl_context *ctx, GLuint bytes)
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLubyte *space = malloc(bytes);
+
+ tnl->block[tnl->nr_blocks++] = space;
+ return space;
+}
+
+
+static void free_space(struct gl_context *ctx)
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint i;
+ for (i = 0; i < tnl->nr_blocks; i++)
+ free(tnl->block[i]);
+ tnl->nr_blocks = 0;
+}
+
+
+/* Convert the incoming array to GLfloats. Understands the
+ * array->Normalized flag and selects the correct conversion method.
+ */
+#define CONVERT( TYPE, MACRO ) do { \
+ GLuint i, j; \
+ if (input->Normalized) { \
+ for (i = 0; i < count; i++) { \
+ const TYPE *in = (TYPE *)ptr; \
+ for (j = 0; j < sz; j++) { \
+ *fptr++ = MACRO(*in); \
+ in++; \
+ } \
+ ptr += input->StrideB; \
+ } \
+ } else { \
+ for (i = 0; i < count; i++) { \
+ const TYPE *in = (TYPE *)ptr; \
+ for (j = 0; j < sz; j++) { \
+ *fptr++ = (GLfloat)(*in); \
+ in++; \
+ } \
+ ptr += input->StrideB; \
+ } \
+ } \
+} while (0)
+
+
+/**
+ * Convert array of BGRA/GLubyte[4] values to RGBA/float[4]
+ * \param ptr input/ubyte array
+ * \param fptr output/float array
+ */
+static void
+convert_bgra_to_float(const struct gl_client_array *input,
+ const GLubyte *ptr, GLfloat *fptr,
+ GLuint count )
+{
+ GLuint i;
+ assert(input->Normalized);
+ assert(input->Size == 4);
+ for (i = 0; i < count; i++) {
+ const GLubyte *in = (GLubyte *) ptr; /* in is in BGRA order */
+ *fptr++ = UBYTE_TO_FLOAT(in[2]); /* red */
+ *fptr++ = UBYTE_TO_FLOAT(in[1]); /* green */
+ *fptr++ = UBYTE_TO_FLOAT(in[0]); /* blue */
+ *fptr++ = UBYTE_TO_FLOAT(in[3]); /* alpha */
+ ptr += input->StrideB;
+ }
+}
+
+static void
+convert_half_to_float(const struct gl_client_array *input,
+ const GLubyte *ptr, GLfloat *fptr,
+ GLuint count, GLuint sz)
+{
+ GLuint i, j;
+
+ for (i = 0; i < count; i++) {
+ GLhalfARB *in = (GLhalfARB *)ptr;
+
+ for (j = 0; j < sz; j++) {
+ *fptr++ = _mesa_half_to_float(in[j]);
+ }
+ ptr += input->StrideB;
+ }
+}
+
+/**
+ * \brief Convert fixed-point to floating-point.
+ *
+ * In OpenGL, a fixed-point number is a "signed 2's complement 16.16 scaled
+ * integer" (Table 2.2 of the OpenGL ES 2.0 spec).
+ *
+ * If the buffer has the \c normalized flag set, the formula
+ * \code normalize(x) := (2*x + 1) / (2^16 - 1) \endcode
+ * is used to map the fixed-point numbers into the range [-1, 1].
+ */
+static void
+convert_fixed_to_float(const struct gl_client_array *input,
+ const GLubyte *ptr, GLfloat *fptr,
+ GLuint count)
+{
+ GLuint i, j;
+ const GLint size = input->Size;
+
+ if (input->Normalized) {
+ for (i = 0; i < count; ++i) {
+ const GLfixed *in = (GLfixed *) ptr;
+ for (j = 0; j < size; ++j) {
+ *fptr++ = (GLfloat) (2 * in[j] + 1) / (GLfloat) ((1 << 16) - 1);
+ }
+ ptr += input->StrideB;
+ }
+ } else {
+ for (i = 0; i < count; ++i) {
+ const GLfixed *in = (GLfixed *) ptr;
+ for (j = 0; j < size; ++j) {
+ *fptr++ = in[j] / (GLfloat) (1 << 16);
+ }
+ ptr += input->StrideB;
+ }
+ }
+}
+
+/* Adjust pointer to point at first requested element, convert to
+ * floating point, populate VB->AttribPtr[].
+ */
+static void _tnl_import_array( struct gl_context *ctx,
+ GLuint attrib,
+ GLuint count,
+ const struct gl_client_array *input,
+ const GLubyte *ptr )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLuint stride = input->StrideB;
+
+ if (input->Type != GL_FLOAT) {
+ const GLuint sz = input->Size;
+ GLubyte *buf = get_space(ctx, count * sz * sizeof(GLfloat));
+ GLfloat *fptr = (GLfloat *)buf;
+
+ switch (input->Type) {
+ case GL_BYTE:
+ CONVERT(GLbyte, BYTE_TO_FLOAT);
+ break;
+ case GL_UNSIGNED_BYTE:
+ if (input->Format == GL_BGRA) {
+ /* See GL_EXT_vertex_array_bgra */
+ convert_bgra_to_float(input, ptr, fptr, count);
+ }
+ else {
+ CONVERT(GLubyte, UBYTE_TO_FLOAT);
+ }
+ break;
+ case GL_SHORT:
+ CONVERT(GLshort, SHORT_TO_FLOAT);
+ break;
+ case GL_UNSIGNED_SHORT:
+ CONVERT(GLushort, USHORT_TO_FLOAT);
+ break;
+ case GL_INT:
+ CONVERT(GLint, INT_TO_FLOAT);
+ break;
+ case GL_UNSIGNED_INT:
+ CONVERT(GLuint, UINT_TO_FLOAT);
+ break;
+ case GL_DOUBLE:
+ CONVERT(GLdouble, (GLfloat));
+ break;
+ case GL_HALF_FLOAT:
+ convert_half_to_float(input, ptr, fptr, count, sz);
+ break;
+ case GL_FIXED:
+ convert_fixed_to_float(input, ptr, fptr, count);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ ptr = buf;
+ stride = sz * sizeof(GLfloat);
+ }
+
+ VB->AttribPtr[attrib] = &tnl->tmp_inputs[attrib];
+ VB->AttribPtr[attrib]->data = (GLfloat (*)[4])ptr;
+ VB->AttribPtr[attrib]->start = (GLfloat *)ptr;
+ VB->AttribPtr[attrib]->count = count;
+ VB->AttribPtr[attrib]->stride = stride;
+ VB->AttribPtr[attrib]->size = input->Size;
+
+ /* This should die, but so should the whole GLvector4f concept:
+ */
+ VB->AttribPtr[attrib]->flags = (((1<<input->Size)-1) |
+ VEC_NOT_WRITEABLE |
+ (stride == 4*sizeof(GLfloat) ? 0 : VEC_BAD_STRIDE));
+
+ VB->AttribPtr[attrib]->storage = NULL;
+}
+
+#define CLIPVERTS ((6 + MAX_CLIP_PLANES) * 2)
+
+
+static GLboolean *_tnl_import_edgeflag( struct gl_context *ctx,
+ const GLvector4f *input,
+ GLuint count)
+{
+ const GLubyte *ptr = (const GLubyte *)input->data;
+ const GLuint stride = input->stride;
+ GLboolean *space = (GLboolean *)get_space(ctx, count + CLIPVERTS);
+ GLboolean *bptr = space;
+ GLuint i;
+
+ for (i = 0; i < count; i++) {
+ *bptr++ = ((GLfloat *)ptr)[0] == 1.0;
+ ptr += stride;
+ }
+
+ return space;
+}
+
+
+static void bind_inputs( struct gl_context *ctx,
+ const struct gl_client_array *inputs[],
+ GLint count,
+ struct gl_buffer_object **bo,
+ GLuint *nr_bo )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLuint i;
+
+ /* Map all the VBOs
+ */
+ for (i = 0; i < VERT_ATTRIB_MAX; i++) {
+ const void *ptr;
+
+ if (inputs[i]->BufferObj->Name) {
+ if (!inputs[i]->BufferObj->Pointer) {
+ bo[*nr_bo] = inputs[i]->BufferObj;
+ (*nr_bo)++;
+ ctx->Driver.MapBuffer(ctx,
+ GL_ARRAY_BUFFER,
+ GL_READ_ONLY_ARB,
+ inputs[i]->BufferObj);
+
+ assert(inputs[i]->BufferObj->Pointer);
+ }
+
+ ptr = ADD_POINTERS(inputs[i]->BufferObj->Pointer,
+ inputs[i]->Ptr);
+ }
+ else
+ ptr = inputs[i]->Ptr;
+
+ /* Just make sure the array is floating point, otherwise convert to
+ * temporary storage.
+ *
+ * XXX: remove the GLvector4f type at some stage and just use
+ * client arrays.
+ */
+ _tnl_import_array(ctx, i, count, inputs[i], ptr);
+ }
+
+ /* We process only the vertices between min & max index:
+ */
+ VB->Count = count;
+
+ /* These should perhaps be part of _TNL_ATTRIB_* */
+ VB->BackfaceColorPtr = NULL;
+ VB->BackfaceIndexPtr = NULL;
+ VB->BackfaceSecondaryColorPtr = NULL;
+
+ /* Clipping and drawing code still requires this to be a packed
+ * array of ubytes which can be written into. TODO: Fix and
+ * remove.
+ */
+ if (ctx->Polygon.FrontMode != GL_FILL ||
+ ctx->Polygon.BackMode != GL_FILL)
+ {
+ VB->EdgeFlag = _tnl_import_edgeflag( ctx,
+ VB->AttribPtr[_TNL_ATTRIB_EDGEFLAG],
+ VB->Count );
+ }
+ else {
+ /* the data previously pointed to by EdgeFlag may have been freed */
+ VB->EdgeFlag = NULL;
+ }
+}
+
+
+/* Translate indices to GLuints and store in VB->Elts.
+ */
+static void bind_indices( struct gl_context *ctx,
+ const struct _mesa_index_buffer *ib,
+ struct gl_buffer_object **bo,
+ GLuint *nr_bo)
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLuint i;
+ void *ptr;
+
+ if (!ib) {
+ VB->Elts = NULL;
+ return;
+ }
+
+ if (ib->obj->Name && !ib->obj->Pointer) {
+ bo[*nr_bo] = ib->obj;
+ (*nr_bo)++;
+ ctx->Driver.MapBuffer(ctx,
+ GL_ELEMENT_ARRAY_BUFFER,
+ GL_READ_ONLY_ARB,
+ ib->obj);
+
+ assert(ib->obj->Pointer);
+ }
+
+ ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr);
+
+ if (ib->type == GL_UNSIGNED_INT && VB->Primitive[0].basevertex == 0) {
+ VB->Elts = (GLuint *) ptr;
+ }
+ else {
+ GLuint *elts = (GLuint *)get_space(ctx, ib->count * sizeof(GLuint));
+ VB->Elts = elts;
+
+ if (ib->type == GL_UNSIGNED_INT) {
+ const GLuint *in = (GLuint *)ptr;
+ for (i = 0; i < ib->count; i++)
+ *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex;
+ }
+ else if (ib->type == GL_UNSIGNED_SHORT) {
+ const GLushort *in = (GLushort *)ptr;
+ for (i = 0; i < ib->count; i++)
+ *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex;
+ }
+ else {
+ const GLubyte *in = (GLubyte *)ptr;
+ for (i = 0; i < ib->count; i++)
+ *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex;
+ }
+ }
+}
+
+static void bind_prims( struct gl_context *ctx,
+ const struct _mesa_prim *prim,
+ GLuint nr_prims )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+
+ VB->Primitive = prim;
+ VB->PrimitiveCount = nr_prims;
+}
+
+static void unmap_vbos( struct gl_context *ctx,
+ struct gl_buffer_object **bo,
+ GLuint nr_bo )
+{
+ GLuint i;
+ for (i = 0; i < nr_bo; i++) {
+ ctx->Driver.UnmapBuffer(ctx,
+ 0, /* target -- I don't see why this would be needed */
+ bo[i]);
+ }
+}
+
+
+void _tnl_vbo_draw_prims(struct gl_context *ctx,
+ const struct gl_client_array *arrays[],
+ const struct _mesa_prim *prim,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ GLboolean index_bounds_valid,
+ GLuint min_index,
+ GLuint max_index)
+{
+ if (!index_bounds_valid)
+ vbo_get_minmax_index(ctx, prim, ib, &min_index, &max_index);
+
+ _tnl_draw_prims(ctx, arrays, prim, nr_prims, ib, min_index, max_index);
+}
+
+/* This is the main entrypoint into the slimmed-down software tnl
+ * module. In a regular swtnl driver, this can be plugged straight
+ * into the vbo->Driver.DrawPrims() callback.
+ */
+void _tnl_draw_prims( struct gl_context *ctx,
+ const struct gl_client_array *arrays[],
+ const struct _mesa_prim *prim,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ GLuint min_index,
+ GLuint max_index)
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ const GLuint TEST_SPLIT = 0;
+ const GLint max = TEST_SPLIT ? 8 : tnl->vb.Size - MAX_CLIPPED_VERTICES;
+ GLint max_basevertex = prim->basevertex;
+ GLuint i;
+
+ /* Mesa core state should have been validated already */
+ assert(ctx->NewState == 0x0);
+
+ if (!_mesa_check_conditional_render(ctx))
+ return; /* don't draw */
+
+ for (i = 1; i < nr_prims; i++)
+ max_basevertex = MAX2(max_basevertex, prim[i].basevertex);
+
+ if (0)
+ {
+ printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
+ for (i = 0; i < nr_prims; i++)
+ printf("prim %d: %s start %d count %d\n", i,
+ _mesa_lookup_enum_by_nr(prim[i].mode),
+ prim[i].start,
+ prim[i].count);
+ }
+
+ if (min_index) {
+ /* We always translate away calls with min_index != 0.
+ */
+ vbo_rebase_prims( ctx, arrays, prim, nr_prims, ib,
+ min_index, max_index,
+ _tnl_vbo_draw_prims );
+ return;
+ }
+ else if ((GLint)max_index + max_basevertex > max) {
+ /* The software TNL pipeline has a fixed amount of storage for
+ * vertices and it is necessary to split incoming drawing commands
+ * if they exceed that limit.
+ */
+ struct split_limits limits;
+ limits.max_verts = max;
+ limits.max_vb_size = ~0;
+ limits.max_indices = ~0;
+
+ /* This will split the buffers one way or another and
+ * recursively call back into this function.
+ */
+ vbo_split_prims( ctx, arrays, prim, nr_prims, ib,
+ 0, max_index + prim->basevertex,
+ _tnl_vbo_draw_prims,
+ &limits );
+ }
+ else {
+ /* May need to map a vertex buffer object for every attribute plus
+ * one for the index buffer.
+ */
+ struct gl_buffer_object *bo[VERT_ATTRIB_MAX + 1];
+ GLuint nr_bo = 0;
+ GLuint inst;
+
+ for (i = 0; i < nr_prims;) {
+ GLuint this_nr_prims;
+
+ /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices
+ * will rebase the elements to the basevertex, and we'll only
+ * emit strings of prims with the same basevertex in one draw call.
+ */
+ for (this_nr_prims = 1; i + this_nr_prims < nr_prims;
+ this_nr_prims++) {
+ if (prim[i].basevertex != prim[i + this_nr_prims].basevertex)
+ break;
+ }
+
+ assert(prim[i].num_instances > 0);
+
+ /* Binding inputs may imply mapping some vertex buffer objects.
+ * They will need to be unmapped below.
+ */
+ for (inst = 0; inst < prim[i].num_instances; inst++) {
+
+ bind_prims(ctx, &prim[i], this_nr_prims);
+ bind_inputs(ctx, arrays, max_index + prim[i].basevertex + 1,
+ bo, &nr_bo);
+ bind_indices(ctx, ib, bo, &nr_bo);
+
+ tnl->CurInstance = inst;
+ TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx);
+
+ unmap_vbos(ctx, bo, nr_bo);
+ free_space(ctx);
+ }
+
+ i += this_nr_prims;
+ }
+ }
+}
+
diff --git a/mesalib/src/mesa/vbo/vbo_exec.h b/mesalib/src/mesa/vbo/vbo_exec.h
index ca100e428..0dd2286dc 100644
--- a/mesalib/src/mesa/vbo/vbo_exec.h
+++ b/mesalib/src/mesa/vbo/vbo_exec.h
@@ -1,198 +1,198 @@
-/**************************************************************************
-
-Copyright 2002 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
-on 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 THEIR 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 <keith@tungstengraphics.com>
- *
- */
-
-#ifndef __VBO_EXEC_H__
-#define __VBO_EXEC_H__
-
-#include "main/mfeatures.h"
-#include "main/mtypes.h"
-#include "vbo.h"
-#include "vbo_attrib.h"
-
-
-#define VBO_MAX_PRIM 64
-
-/* Wierd implementation stuff:
- */
-#define VBO_VERT_BUFFER_SIZE (1024*64) /* bytes */
-#define VBO_MAX_ATTR_CODEGEN 16
-#define ERROR_ATTRIB 16
-
-
-/** Current vertex program mode */
-enum vp_mode {
- VP_NONE, /**< fixed function */
- VP_NV, /**< NV vertex program */
- VP_ARB /**< ARB vertex program or GLSL vertex shader */
-};
-
-
-struct vbo_exec_eval1_map {
- struct gl_1d_map *map;
- GLuint sz;
-};
-
-struct vbo_exec_eval2_map {
- struct gl_2d_map *map;
- GLuint sz;
-};
-
-
-
-struct vbo_exec_copied_vtx {
- GLfloat buffer[VBO_ATTRIB_MAX * 4 * VBO_MAX_COPIED_VERTS];
- GLuint nr;
-};
-
-
-typedef void (*vbo_attrfv_func)( const GLfloat * );
-
-
-struct vbo_exec_context
-{
- struct gl_context *ctx;
- GLvertexformat vtxfmt;
-
- struct {
- struct gl_buffer_object *bufferobj;
-
- GLuint vertex_size; /* in dwords */
-
- struct _mesa_prim prim[VBO_MAX_PRIM];
- GLuint prim_count;
-
- GLfloat *buffer_map;
- GLfloat *buffer_ptr; /* cursor, points into buffer */
- GLuint buffer_used; /* in bytes */
- GLfloat vertex[VBO_ATTRIB_MAX*4]; /* current vertex */
-
- GLuint vert_count;
- GLuint max_vert;
- struct vbo_exec_copied_vtx copied;
-
- GLubyte attrsz[VBO_ATTRIB_MAX];
- GLubyte active_sz[VBO_ATTRIB_MAX];
-
- GLfloat *attrptr[VBO_ATTRIB_MAX];
- struct gl_client_array arrays[VERT_ATTRIB_MAX];
-
- /* According to program mode, the values above plus current
- * values are squashed down to the 32 attributes passed to the
- * vertex program below:
- */
- enum vp_mode program_mode;
- GLuint enabled_flags;
- const struct gl_client_array *inputs[VERT_ATTRIB_MAX];
- } vtx;
-
-
- struct {
- GLboolean recalculate_maps;
- struct vbo_exec_eval1_map map1[VERT_ATTRIB_MAX];
- struct vbo_exec_eval2_map map2[VERT_ATTRIB_MAX];
- } eval;
-
- struct {
- enum vp_mode program_mode;
- GLuint enabled_flags;
- GLuint array_obj;
-
- /* These just mirror the current arrayobj (todo: make arrayobj
- * look like this and remove the mirror):
- */
- const struct gl_client_array *legacy_array[16];
- const struct gl_client_array *generic_array[16];
-
- /* Arrays and current values manipulated according to program
- * mode, etc. These are the attributes as seen by vertex
- * programs:
- */
- const struct gl_client_array *inputs[VERT_ATTRIB_MAX];
- } array;
-
-#ifdef DEBUG
- GLint flush_call_depth;
-#endif
-};
-
-
-
-/* External API:
- */
-void vbo_exec_init( struct gl_context *ctx );
-void vbo_exec_destroy( struct gl_context *ctx );
-void vbo_exec_invalidate_state( struct gl_context *ctx, GLuint new_state );
-
-void vbo_exec_BeginVertices( struct gl_context *ctx );
-void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags );
-
-
-/* Internal functions:
- */
-void vbo_exec_array_init( struct vbo_exec_context *exec );
-void vbo_exec_array_destroy( struct vbo_exec_context *exec );
-
-
-void vbo_exec_vtx_init( struct vbo_exec_context *exec );
-void vbo_exec_vtx_destroy( struct vbo_exec_context *exec );
-
-#if FEATURE_beginend
-
-void vbo_exec_vtx_flush( struct vbo_exec_context *exec, GLboolean unmap );
-void vbo_exec_vtx_map( struct vbo_exec_context *exec );
-
-#else /* FEATURE_beginend */
-
-static INLINE void
-vbo_exec_vtx_flush( struct vbo_exec_context *exec, GLboolean unmap )
-{
-}
-
-static INLINE void
-vbo_exec_vtx_map( struct vbo_exec_context *exec )
-{
-}
-
-#endif /* FEATURE_beginend */
-
-void vbo_exec_vtx_wrap( struct vbo_exec_context *exec );
-
-void vbo_exec_eval_update( struct vbo_exec_context *exec );
-
-void vbo_exec_do_EvalCoord2f( struct vbo_exec_context *exec,
- GLfloat u, GLfloat v );
-
-void vbo_exec_do_EvalCoord1f( struct vbo_exec_context *exec,
- GLfloat u);
-
-#endif
+/**************************************************************************
+
+Copyright 2002 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
+on 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 THEIR 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 <keith@tungstengraphics.com>
+ *
+ */
+
+#ifndef __VBO_EXEC_H__
+#define __VBO_EXEC_H__
+
+#include "main/mfeatures.h"
+#include "main/mtypes.h"
+#include "vbo.h"
+#include "vbo_attrib.h"
+
+
+#define VBO_MAX_PRIM 64
+
+/* Wierd implementation stuff:
+ */
+#define VBO_VERT_BUFFER_SIZE (1024*64) /* bytes */
+#define VBO_MAX_ATTR_CODEGEN 16
+#define ERROR_ATTRIB 16
+
+
+/** Current vertex program mode */
+enum vp_mode {
+ VP_NONE, /**< fixed function */
+ VP_NV, /**< NV vertex program */
+ VP_ARB /**< ARB vertex program or GLSL vertex shader */
+};
+
+
+struct vbo_exec_eval1_map {
+ struct gl_1d_map *map;
+ GLuint sz;
+};
+
+struct vbo_exec_eval2_map {
+ struct gl_2d_map *map;
+ GLuint sz;
+};
+
+
+
+struct vbo_exec_copied_vtx {
+ GLfloat buffer[VBO_ATTRIB_MAX * 4 * VBO_MAX_COPIED_VERTS];
+ GLuint nr;
+};
+
+
+typedef void (*vbo_attrfv_func)( const GLfloat * );
+
+
+struct vbo_exec_context
+{
+ struct gl_context *ctx;
+ GLvertexformat vtxfmt;
+
+ struct {
+ struct gl_buffer_object *bufferobj;
+
+ GLuint vertex_size; /* in dwords */
+
+ struct _mesa_prim prim[VBO_MAX_PRIM];
+ GLuint prim_count;
+
+ GLfloat *buffer_map;
+ GLfloat *buffer_ptr; /* cursor, points into buffer */
+ GLuint buffer_used; /* in bytes */
+ GLfloat vertex[VBO_ATTRIB_MAX*4]; /* current vertex */
+
+ GLuint vert_count;
+ GLuint max_vert;
+ struct vbo_exec_copied_vtx copied;
+
+ GLubyte attrsz[VBO_ATTRIB_MAX];
+ GLubyte active_sz[VBO_ATTRIB_MAX];
+
+ GLfloat *attrptr[VBO_ATTRIB_MAX];
+ struct gl_client_array arrays[VERT_ATTRIB_MAX];
+
+ /* According to program mode, the values above plus current
+ * values are squashed down to the 32 attributes passed to the
+ * vertex program below:
+ */
+ enum vp_mode program_mode;
+ GLuint enabled_flags;
+ const struct gl_client_array *inputs[VERT_ATTRIB_MAX];
+ } vtx;
+
+
+ struct {
+ GLboolean recalculate_maps;
+ struct vbo_exec_eval1_map map1[VERT_ATTRIB_MAX];
+ struct vbo_exec_eval2_map map2[VERT_ATTRIB_MAX];
+ } eval;
+
+ struct {
+ enum vp_mode program_mode;
+ GLuint enabled_flags;
+ GLuint array_obj;
+
+ /* These just mirror the current arrayobj (todo: make arrayobj
+ * look like this and remove the mirror):
+ */
+ const struct gl_client_array *legacy_array[16];
+ const struct gl_client_array *generic_array[16];
+
+ /* Arrays and current values manipulated according to program
+ * mode, etc. These are the attributes as seen by vertex
+ * programs:
+ */
+ const struct gl_client_array *inputs[VERT_ATTRIB_MAX];
+ } array;
+
+#ifdef DEBUG
+ GLint flush_call_depth;
+#endif
+};
+
+
+
+/* External API:
+ */
+void vbo_exec_init( struct gl_context *ctx );
+void vbo_exec_destroy( struct gl_context *ctx );
+void vbo_exec_invalidate_state( struct gl_context *ctx, GLuint new_state );
+
+void vbo_exec_BeginVertices( struct gl_context *ctx );
+void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags );
+
+
+/* Internal functions:
+ */
+void vbo_exec_array_init( struct vbo_exec_context *exec );
+void vbo_exec_array_destroy( struct vbo_exec_context *exec );
+
+
+void vbo_exec_vtx_init( struct vbo_exec_context *exec );
+void vbo_exec_vtx_destroy( struct vbo_exec_context *exec );
+
+#if FEATURE_beginend
+
+void vbo_exec_vtx_flush( struct vbo_exec_context *exec, GLboolean unmap );
+void vbo_exec_vtx_map( struct vbo_exec_context *exec );
+
+#else /* FEATURE_beginend */
+
+static INLINE void
+vbo_exec_vtx_flush( struct vbo_exec_context *exec, GLboolean unmap )
+{
+}
+
+static INLINE void
+vbo_exec_vtx_map( struct vbo_exec_context *exec )
+{
+}
+
+#endif /* FEATURE_beginend */
+
+void vbo_exec_vtx_wrap( struct vbo_exec_context *exec );
+
+void vbo_exec_eval_update( struct vbo_exec_context *exec );
+
+void vbo_exec_do_EvalCoord2f( struct vbo_exec_context *exec,
+ GLfloat u, GLfloat v );
+
+void vbo_exec_do_EvalCoord1f( struct vbo_exec_context *exec,
+ GLfloat u);
+
+#endif
diff --git a/mesalib/src/mesa/vbo/vbo_exec_api.c b/mesalib/src/mesa/vbo/vbo_exec_api.c
index c4d39d8f1..859db5e2c 100644
--- a/mesalib/src/mesa/vbo/vbo_exec_api.c
+++ b/mesalib/src/mesa/vbo/vbo_exec_api.c
@@ -1,1107 +1,1107 @@
-/**************************************************************************
-
-Copyright 2002-2008 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
-on 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 THEIR 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 <keith@tungstengraphics.com>
- */
-
-#include "main/glheader.h"
-#include "main/bufferobj.h"
-#include "main/context.h"
-#include "main/macros.h"
-#include "main/mfeatures.h"
-#include "main/vtxfmt.h"
-#include "main/dlist.h"
-#include "main/eval.h"
-#include "main/state.h"
-#include "main/light.h"
-#include "main/api_arrayelt.h"
-#include "main/api_noop.h"
-#include "main/dispatch.h"
-
-#include "vbo_context.h"
-
-#ifdef ERROR
-#undef ERROR
-#endif
-
-
-/** ID/name for immediate-mode VBO */
-#define IMM_BUFFER_NAME 0xaabbccdd
-
-
-static void reset_attrfv( struct vbo_exec_context *exec );
-
-
-/**
- * Close off the last primitive, execute the buffer, restart the
- * primitive.
- */
-static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec )
-{
- if (exec->vtx.prim_count == 0) {
- exec->vtx.copied.nr = 0;
- exec->vtx.vert_count = 0;
- exec->vtx.buffer_ptr = exec->vtx.buffer_map;
- }
- else {
- GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin;
- GLuint last_count;
-
- if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
- GLint i = exec->vtx.prim_count - 1;
- assert(i >= 0);
- exec->vtx.prim[i].count = (exec->vtx.vert_count -
- exec->vtx.prim[i].start);
- }
-
- last_count = exec->vtx.prim[exec->vtx.prim_count-1].count;
-
- /* Execute the buffer and save copied vertices.
- */
- if (exec->vtx.vert_count)
- vbo_exec_vtx_flush( exec, GL_FALSE );
- else {
- exec->vtx.prim_count = 0;
- exec->vtx.copied.nr = 0;
- }
-
- /* Emit a glBegin to start the new list.
- */
- assert(exec->vtx.prim_count == 0);
-
- if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
- exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
- exec->vtx.prim[0].start = 0;
- exec->vtx.prim[0].count = 0;
- exec->vtx.prim_count++;
-
- if (exec->vtx.copied.nr == last_count)
- exec->vtx.prim[0].begin = last_begin;
- }
- }
-}
-
-
-/**
- * Deal with buffer wrapping where provoked by the vertex buffer
- * filling up, as opposed to upgrade_vertex().
- */
-void vbo_exec_vtx_wrap( struct vbo_exec_context *exec )
-{
- GLfloat *data = exec->vtx.copied.buffer;
- GLuint i;
-
- /* Run pipeline on current vertices, copy wrapped vertices
- * to exec->vtx.copied.
- */
- vbo_exec_wrap_buffers( exec );
-
- /* Copy stored stored vertices to start of new list.
- */
- assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
-
- for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
- memcpy( exec->vtx.buffer_ptr, data,
- exec->vtx.vertex_size * sizeof(GLfloat));
- exec->vtx.buffer_ptr += exec->vtx.vertex_size;
- data += exec->vtx.vertex_size;
- exec->vtx.vert_count++;
- }
-
- exec->vtx.copied.nr = 0;
-}
-
-
-/**
- * Copy the active vertex's values to the ctx->Current fields.
- */
-static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
-{
- struct gl_context *ctx = exec->ctx;
- struct vbo_context *vbo = vbo_context(ctx);
- GLuint i;
-
- for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
- if (exec->vtx.attrsz[i]) {
- /* Note: the exec->vtx.current[i] pointers point into the
- * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
- */
- GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
- GLfloat tmp[4];
-
- COPY_CLEAN_4V(tmp,
- exec->vtx.attrsz[i],
- exec->vtx.attrptr[i]);
-
- if (memcmp(current, tmp, sizeof(tmp)) != 0) {
- memcpy(current, tmp, sizeof(tmp));
-
- /* Given that we explicitly state size here, there is no need
- * for the COPY_CLEAN above, could just copy 16 bytes and be
- * done. The only problem is when Mesa accesses ctx->Current
- * directly.
- */
- vbo->currval[i].Size = exec->vtx.attrsz[i];
-
- /* This triggers rather too much recalculation of Mesa state
- * that doesn't get used (eg light positions).
- */
- if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
- i <= VBO_ATTRIB_MAT_BACK_INDEXES)
- ctx->NewState |= _NEW_LIGHT;
-
- ctx->NewState |= _NEW_CURRENT_ATTRIB;
- }
- }
- }
-
- /* Colormaterial -- this kindof sucks.
- */
- if (ctx->Light.ColorMaterialEnabled &&
- exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
- _mesa_update_color_material(ctx,
- ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
- }
-}
-
-
-/**
- * Copy current vertex attribute values into the current vertex.
- */
-static void
-vbo_exec_copy_from_current(struct vbo_exec_context *exec)
-{
- struct gl_context *ctx = exec->ctx;
- struct vbo_context *vbo = vbo_context(ctx);
- GLint i;
-
- for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
- const GLfloat *current = (GLfloat *) vbo->currval[i].Ptr;
- switch (exec->vtx.attrsz[i]) {
- case 4: exec->vtx.attrptr[i][3] = current[3];
- case 3: exec->vtx.attrptr[i][2] = current[2];
- case 2: exec->vtx.attrptr[i][1] = current[1];
- case 1: exec->vtx.attrptr[i][0] = current[0];
- break;
- }
- }
-}
-
-
-/**
- * Flush existing data, set new attrib size, replay copied vertices.
- * This is called when we transition from a small vertex attribute size
- * to a larger one. Ex: glTexCoord2f -> glTexCoord4f.
- * We need to go back over the previous 2-component texcoords and insert
- * zero and one values.
- */
-static void
-vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
- GLuint attr, GLuint newSize )
-{
- struct gl_context *ctx = exec->ctx;
- struct vbo_context *vbo = vbo_context(ctx);
- const GLint lastcount = exec->vtx.vert_count;
- GLfloat *old_attrptr[VBO_ATTRIB_MAX];
- const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
- const GLuint oldSize = exec->vtx.attrsz[attr];
- GLuint i;
-
- /* Run pipeline on current vertices, copy wrapped vertices
- * to exec->vtx.copied.
- */
- vbo_exec_wrap_buffers( exec );
-
- if (unlikely(exec->vtx.copied.nr)) {
- /* We're in the middle of a primitive, keep the old vertex
- * format around to be able to translate the copied vertices to
- * the new format.
- */
- memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
- }
-
- if (unlikely(oldSize)) {
- /* Do a COPY_TO_CURRENT to ensure back-copying works for the
- * case when the attribute already exists in the vertex and is
- * having its size increased.
- */
- vbo_exec_copy_to_current( exec );
- }
-
- /* Heuristic: Attempt to isolate attributes received outside
- * begin/end so that they don't bloat the vertices.
- */
- if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
- !oldSize && lastcount > 8 && exec->vtx.vertex_size) {
- vbo_exec_copy_to_current( exec );
- reset_attrfv( exec );
- }
-
- /* Fix up sizes:
- */
- exec->vtx.attrsz[attr] = newSize;
- exec->vtx.vertex_size += newSize - oldSize;
- exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
- (exec->vtx.vertex_size * sizeof(GLfloat)));
- exec->vtx.vert_count = 0;
- exec->vtx.buffer_ptr = exec->vtx.buffer_map;
-
- if (unlikely(oldSize)) {
- /* Size changed, recalculate all the attrptr[] values
- */
- GLfloat *tmp = exec->vtx.vertex;
-
- for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
- if (exec->vtx.attrsz[i]) {
- exec->vtx.attrptr[i] = tmp;
- tmp += exec->vtx.attrsz[i];
- }
- else
- exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
- }
-
- /* Copy from current to repopulate the vertex with correct
- * values.
- */
- vbo_exec_copy_from_current( exec );
- }
- else {
- /* Just have to append the new attribute at the end */
- exec->vtx.attrptr[attr] = exec->vtx.vertex +
- exec->vtx.vertex_size - newSize;
- }
-
- /* Replay stored vertices to translate them
- * to new format here.
- *
- * -- No need to replay - just copy piecewise
- */
- if (unlikely(exec->vtx.copied.nr)) {
- GLfloat *data = exec->vtx.copied.buffer;
- GLfloat *dest = exec->vtx.buffer_ptr;
- GLuint j;
-
- assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
-
- for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
- for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
- GLuint sz = exec->vtx.attrsz[j];
-
- if (sz) {
- GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
- GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
-
- if (j == attr) {
- if (oldSize) {
- GLfloat tmp[4];
- COPY_CLEAN_4V(tmp, oldSize, data + old_offset);
- COPY_SZ_4V(dest + new_offset, newSize, tmp);
- } else {
- GLfloat *current = (GLfloat *)vbo->currval[j].Ptr;
- COPY_SZ_4V(dest + new_offset, sz, current);
- }
- }
- else {
- COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
- }
- }
- }
-
- data += old_vtx_size;
- dest += exec->vtx.vertex_size;
- }
-
- exec->vtx.buffer_ptr = dest;
- exec->vtx.vert_count += exec->vtx.copied.nr;
- exec->vtx.copied.nr = 0;
- }
-}
-
-
-/**
- * This is when a vertex attribute transitions to a different size.
- * For example, we saw a bunch of glTexCoord2f() calls and now we got a
- * glTexCoord4f() call. We promote the array from size=2 to size=4.
- */
-static void
-vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint newSize)
-{
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
-
- if (newSize > exec->vtx.attrsz[attr]) {
- /* New size is larger. Need to flush existing vertices and get
- * an enlarged vertex format.
- */
- vbo_exec_wrap_upgrade_vertex( exec, attr, newSize );
- }
- else if (newSize < exec->vtx.active_sz[attr]) {
- static const GLfloat id[4] = { 0, 0, 0, 1 };
- GLuint i;
-
- /* New size is smaller - just need to fill in some
- * zeros. Don't need to flush or wrap.
- */
- for (i = newSize; i <= exec->vtx.attrsz[attr]; i++)
- exec->vtx.attrptr[attr][i-1] = id[i-1];
- }
-
- exec->vtx.active_sz[attr] = newSize;
-
- /* Does setting NeedFlush belong here? Necessitates resetting
- * vtxfmt on each flush (otherwise flags won't get reset
- * afterwards).
- */
- if (attr == 0)
- exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
-}
-
-
-/**
- * This macro is used to implement all the glVertex, glColor, glTexCoord,
- * glVertexAttrib, etc functions.
- */
-#define ATTR( A, N, V0, V1, V2, V3 ) \
-do { \
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
- \
- if (unlikely(!(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \
- ctx->Driver.BeginVertices( ctx ); \
- \
- if (unlikely(exec->vtx.active_sz[A] != N)) \
- vbo_exec_fixup_vertex(ctx, A, N); \
- \
- { \
- GLfloat *dest = exec->vtx.attrptr[A]; \
- if (N>0) dest[0] = V0; \
- if (N>1) dest[1] = V1; \
- if (N>2) dest[2] = V2; \
- if (N>3) dest[3] = V3; \
- } \
- \
- if ((A) == 0) { \
- /* This is a glVertex call */ \
- GLuint i; \
- \
- for (i = 0; i < exec->vtx.vertex_size; i++) \
- exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
- \
- exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
- \
- /* Set FLUSH_STORED_VERTICES to indicate that there's now */ \
- /* something to draw (not just updating a color or texcoord).*/ \
- ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
- \
- if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
- vbo_exec_vtx_wrap( exec ); \
- } \
-} while (0)
-
-
-#define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
-#define TAG(x) vbo_##x
-
-#include "vbo_attrib_tmp.h"
-
-
-#if FEATURE_beginend
-
-
-#if FEATURE_evaluators
-
-static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
-{
- GET_CURRENT_CONTEXT( ctx );
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
-
- {
- GLint i;
- if (exec->eval.recalculate_maps)
- vbo_exec_eval_update( exec );
-
- for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
- if (exec->eval.map1[i].map)
- if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
- vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz );
- }
- }
-
-
- memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
- exec->vtx.vertex_size * sizeof(GLfloat));
-
- vbo_exec_do_EvalCoord1f( exec, u );
-
- memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
- exec->vtx.vertex_size * sizeof(GLfloat));
-}
-
-static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
-{
- GET_CURRENT_CONTEXT( ctx );
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
-
- {
- GLint i;
- if (exec->eval.recalculate_maps)
- vbo_exec_eval_update( exec );
-
- for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
- if (exec->eval.map2[i].map)
- if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
- vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz );
- }
-
- if (ctx->Eval.AutoNormal)
- if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
- vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 );
- }
-
- memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
- exec->vtx.vertex_size * sizeof(GLfloat));
-
- vbo_exec_do_EvalCoord2f( exec, u, v );
-
- memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
- exec->vtx.vertex_size * sizeof(GLfloat));
-}
-
-static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
-{
- vbo_exec_EvalCoord1f( u[0] );
-}
-
-static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
-{
- vbo_exec_EvalCoord2f( u[0], u[1] );
-}
-
-static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
-{
- GET_CURRENT_CONTEXT( ctx );
- GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
- (GLfloat) ctx->Eval.MapGrid1un);
- GLfloat u = i * du + ctx->Eval.MapGrid1u1;
-
- vbo_exec_EvalCoord1f( u );
-}
-
-
-static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
-{
- GET_CURRENT_CONTEXT( ctx );
- GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
- (GLfloat) ctx->Eval.MapGrid2un);
- GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
- (GLfloat) ctx->Eval.MapGrid2vn);
- GLfloat u = i * du + ctx->Eval.MapGrid2u1;
- GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
-
- vbo_exec_EvalCoord2f( u, v );
-}
-
-/* use noop eval mesh */
-#define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1
-#define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2
-
-#endif /* FEATURE_evaluators */
-
-
-/**
- * Flush (draw) vertices.
- * \param unmap - leave VBO unmapped after flushing?
- */
-static void
-vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap)
-{
- if (exec->vtx.vert_count || unmap) {
- vbo_exec_vtx_flush( exec, unmap );
- }
-
- if (exec->vtx.vertex_size) {
- vbo_exec_copy_to_current( exec );
- reset_attrfv( exec );
- }
-}
-
-
-/**
- * Called via glBegin.
- */
-static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
-{
- GET_CURRENT_CONTEXT( ctx );
-
- if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
- int i;
-
- if (ctx->NewState) {
- _mesa_update_state( ctx );
-
- CALL_Begin(ctx->Exec, (mode));
- return;
- }
-
- if (!_mesa_valid_to_render(ctx, "glBegin")) {
- return;
- }
-
- /* Heuristic: attempt to isolate attributes occuring outside
- * begin/end pairs.
- */
- if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
- vbo_exec_FlushVertices_internal(exec, GL_FALSE);
-
- i = exec->vtx.prim_count++;
- exec->vtx.prim[i].mode = mode;
- exec->vtx.prim[i].begin = 1;
- exec->vtx.prim[i].end = 0;
- exec->vtx.prim[i].indexed = 0;
- exec->vtx.prim[i].weak = 0;
- exec->vtx.prim[i].pad = 0;
- exec->vtx.prim[i].start = exec->vtx.vert_count;
- exec->vtx.prim[i].count = 0;
- exec->vtx.prim[i].num_instances = 1;
-
- ctx->Driver.CurrentExecPrimitive = mode;
- }
- else
- _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
-
-}
-
-
-/**
- * Called via glEnd.
- */
-static void GLAPIENTRY vbo_exec_End( void )
-{
- GET_CURRENT_CONTEXT( ctx );
-
- if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
- int idx = exec->vtx.vert_count;
- int i = exec->vtx.prim_count - 1;
-
- exec->vtx.prim[i].end = 1;
- exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
-
- ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
-
- if (exec->vtx.prim_count == VBO_MAX_PRIM)
- vbo_exec_vtx_flush( exec, GL_FALSE );
- }
- else
- _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
-}
-
-
-/**
- * Called via glPrimitiveRestartNV()
- */
-static void GLAPIENTRY
-vbo_exec_PrimitiveRestartNV(void)
-{
- GLenum curPrim;
- GET_CURRENT_CONTEXT( ctx );
-
- curPrim = ctx->Driver.CurrentExecPrimitive;
-
- if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
- _mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" );
- }
- else {
- vbo_exec_End();
- vbo_exec_Begin(curPrim);
- }
-}
-
-
-
-static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
-{
- GLvertexformat *vfmt = &exec->vtxfmt;
-
- _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
-
- vfmt->Begin = vbo_exec_Begin;
- vfmt->End = vbo_exec_End;
- vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
-
- _MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_);
- _MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_);
-
- vfmt->Rectf = _mesa_noop_Rectf;
-
- /* from attrib_tmp.h:
- */
- vfmt->Color3f = vbo_Color3f;
- vfmt->Color3fv = vbo_Color3fv;
- vfmt->Color4f = vbo_Color4f;
- vfmt->Color4fv = vbo_Color4fv;
- vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
- vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
- vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
- vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
- vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
- vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
- vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
- vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
- vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
- vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
- vfmt->Normal3f = vbo_Normal3f;
- vfmt->Normal3fv = vbo_Normal3fv;
- vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
- vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
- vfmt->TexCoord1f = vbo_TexCoord1f;
- vfmt->TexCoord1fv = vbo_TexCoord1fv;
- vfmt->TexCoord2f = vbo_TexCoord2f;
- vfmt->TexCoord2fv = vbo_TexCoord2fv;
- vfmt->TexCoord3f = vbo_TexCoord3f;
- vfmt->TexCoord3fv = vbo_TexCoord3fv;
- vfmt->TexCoord4f = vbo_TexCoord4f;
- vfmt->TexCoord4fv = vbo_TexCoord4fv;
- vfmt->Vertex2f = vbo_Vertex2f;
- vfmt->Vertex2fv = vbo_Vertex2fv;
- vfmt->Vertex3f = vbo_Vertex3f;
- vfmt->Vertex3fv = vbo_Vertex3fv;
- vfmt->Vertex4f = vbo_Vertex4f;
- vfmt->Vertex4fv = vbo_Vertex4fv;
-
- vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
- vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
- vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
- vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
- vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
- vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
- vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
- vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
-
- vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
- vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
- vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
- vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
- vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
- vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
- vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
- vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
-
- /* integer-valued */
- vfmt->VertexAttribI1i = vbo_VertexAttribI1i;
- vfmt->VertexAttribI2i = vbo_VertexAttribI2i;
- vfmt->VertexAttribI3i = vbo_VertexAttribI3i;
- vfmt->VertexAttribI4i = vbo_VertexAttribI4i;
- vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv;
- vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv;
- vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv;
-
- /* unsigned integer-valued */
- vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui;
- vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui;
- vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui;
- vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui;
- vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv;
- vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv;
- vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv;
-
- vfmt->Materialfv = vbo_Materialfv;
-
- vfmt->EdgeFlag = vbo_EdgeFlag;
- vfmt->Indexf = vbo_Indexf;
- vfmt->Indexfv = vbo_Indexfv;
-
-}
-
-
-#else /* FEATURE_beginend */
-
-
-static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
-{
- /* silence warnings */
- (void) vbo_Color3f;
- (void) vbo_Color3fv;
- (void) vbo_Color4f;
- (void) vbo_Color4fv;
- (void) vbo_FogCoordfEXT;
- (void) vbo_FogCoordfvEXT;
- (void) vbo_MultiTexCoord1f;
- (void) vbo_MultiTexCoord1fv;
- (void) vbo_MultiTexCoord2f;
- (void) vbo_MultiTexCoord2fv;
- (void) vbo_MultiTexCoord3f;
- (void) vbo_MultiTexCoord3fv;
- (void) vbo_MultiTexCoord4f;
- (void) vbo_MultiTexCoord4fv;
- (void) vbo_Normal3f;
- (void) vbo_Normal3fv;
- (void) vbo_SecondaryColor3fEXT;
- (void) vbo_SecondaryColor3fvEXT;
- (void) vbo_TexCoord1f;
- (void) vbo_TexCoord1fv;
- (void) vbo_TexCoord2f;
- (void) vbo_TexCoord2fv;
- (void) vbo_TexCoord3f;
- (void) vbo_TexCoord3fv;
- (void) vbo_TexCoord4f;
- (void) vbo_TexCoord4fv;
- (void) vbo_Vertex2f;
- (void) vbo_Vertex2fv;
- (void) vbo_Vertex3f;
- (void) vbo_Vertex3fv;
- (void) vbo_Vertex4f;
- (void) vbo_Vertex4fv;
-
- (void) vbo_VertexAttrib1fARB;
- (void) vbo_VertexAttrib1fvARB;
- (void) vbo_VertexAttrib2fARB;
- (void) vbo_VertexAttrib2fvARB;
- (void) vbo_VertexAttrib3fARB;
- (void) vbo_VertexAttrib3fvARB;
- (void) vbo_VertexAttrib4fARB;
- (void) vbo_VertexAttrib4fvARB;
-
- (void) vbo_VertexAttrib1fNV;
- (void) vbo_VertexAttrib1fvNV;
- (void) vbo_VertexAttrib2fNV;
- (void) vbo_VertexAttrib2fvNV;
- (void) vbo_VertexAttrib3fNV;
- (void) vbo_VertexAttrib3fvNV;
- (void) vbo_VertexAttrib4fNV;
- (void) vbo_VertexAttrib4fvNV;
-
- (void) vbo_Materialfv;
-
- (void) vbo_EdgeFlag;
- (void) vbo_Indexf;
- (void) vbo_Indexfv;
-}
-
-
-#endif /* FEATURE_beginend */
-
-
-/**
- * Tell the VBO module to use a real OpenGL vertex buffer object to
- * store accumulated immediate-mode vertex data.
- * This replaces the malloced buffer which was created in
- * vb_exec_vtx_init() below.
- */
-void vbo_use_buffer_objects(struct gl_context *ctx)
-{
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
- /* Any buffer name but 0 can be used here since this bufferobj won't
- * go into the bufferobj hashtable.
- */
- GLuint bufName = IMM_BUFFER_NAME;
- GLenum target = GL_ARRAY_BUFFER_ARB;
- GLenum usage = GL_STREAM_DRAW_ARB;
- GLsizei size = VBO_VERT_BUFFER_SIZE;
-
- /* Make sure this func is only used once */
- assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
- if (exec->vtx.buffer_map) {
- _mesa_align_free(exec->vtx.buffer_map);
- exec->vtx.buffer_map = NULL;
- exec->vtx.buffer_ptr = NULL;
- }
-
- /* Allocate a real buffer object now */
- _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
- exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
- ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj);
-}
-
-
-
-void vbo_exec_vtx_init( struct vbo_exec_context *exec )
-{
- struct gl_context *ctx = exec->ctx;
- struct vbo_context *vbo = vbo_context(ctx);
- GLuint i;
-
- /* Allocate a buffer object. Will just reuse this object
- * continuously, unless vbo_use_buffer_objects() is called to enable
- * use of real VBOs.
- */
- _mesa_reference_buffer_object(ctx,
- &exec->vtx.bufferobj,
- ctx->Shared->NullBufferObj);
-
- ASSERT(!exec->vtx.buffer_map);
- exec->vtx.buffer_map = (GLfloat *)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
- exec->vtx.buffer_ptr = exec->vtx.buffer_map;
-
- vbo_exec_vtxfmt_init( exec );
-
- /* Hook our functions into the dispatch table.
- */
- _mesa_install_exec_vtxfmt( exec->ctx, &exec->vtxfmt );
-
- for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
- ASSERT(i < Elements(exec->vtx.attrsz));
- exec->vtx.attrsz[i] = 0;
- ASSERT(i < Elements(exec->vtx.active_sz));
- exec->vtx.active_sz[i] = 0;
- }
- for (i = 0 ; i < VERT_ATTRIB_MAX; i++) {
- ASSERT(i < Elements(exec->vtx.inputs));
- ASSERT(i < Elements(exec->vtx.arrays));
- exec->vtx.inputs[i] = &exec->vtx.arrays[i];
- }
-
- {
- struct gl_client_array *arrays = exec->vtx.arrays;
- unsigned i;
-
- memcpy(arrays, vbo->legacy_currval, 16 * sizeof(arrays[0]));
- memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0]));
-
- for (i = 0; i < 16; ++i) {
- arrays[i ].BufferObj = NULL;
- arrays[i + 16].BufferObj = NULL;
- _mesa_reference_buffer_object(ctx, &arrays[i ].BufferObj,
- vbo->legacy_currval[i].BufferObj);
- _mesa_reference_buffer_object(ctx, &arrays[i + 16].BufferObj,
- vbo->generic_currval[i].BufferObj);
- }
- }
-
- exec->vtx.vertex_size = 0;
-}
-
-
-void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
-{
- /* using a real VBO for vertex data */
- struct gl_context *ctx = exec->ctx;
- unsigned i;
-
- /* True VBOs should already be unmapped
- */
- if (exec->vtx.buffer_map) {
- ASSERT(exec->vtx.bufferobj->Name == 0 ||
- exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
- if (exec->vtx.bufferobj->Name == 0) {
- _mesa_align_free(exec->vtx.buffer_map);
- exec->vtx.buffer_map = NULL;
- exec->vtx.buffer_ptr = NULL;
- }
- }
-
- /* Drop any outstanding reference to the vertex buffer
- */
- for (i = 0; i < Elements(exec->vtx.arrays); i++) {
- _mesa_reference_buffer_object(ctx,
- &exec->vtx.arrays[i].BufferObj,
- NULL);
- }
-
- /* Free the vertex buffer. Unmap first if needed.
- */
- if (_mesa_bufferobj_mapped(exec->vtx.bufferobj)) {
- ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, exec->vtx.bufferobj);
- }
- _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
-}
-
-
-/**
- * Called upon first glVertex, glColor, glTexCoord, etc.
- */
-void vbo_exec_BeginVertices( struct gl_context *ctx )
-{
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
-
- vbo_exec_vtx_map( exec );
-
- assert((exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
- exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
-}
-
-
-/**
- * Called via ctx->Driver.FlushVertices()
- * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
- */
-void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags )
-{
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
-
-#ifdef DEBUG
- /* debug check: make sure we don't get called recursively */
- exec->flush_call_depth++;
- assert(exec->flush_call_depth == 1);
-#endif
-
- if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
- /* We've had glBegin but not glEnd! */
-#ifdef DEBUG
- exec->flush_call_depth--;
- assert(exec->flush_call_depth == 0);
-#endif
- return;
- }
-
- /* Flush (draw), and make sure VBO is left unmapped when done */
- vbo_exec_FlushVertices_internal(exec, GL_TRUE);
-
- /* Need to do this to ensure BeginVertices gets called again:
- */
- if (exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT)
- exec->ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
-
- exec->ctx->Driver.NeedFlush &= ~flags;
-
-#ifdef DEBUG
- exec->flush_call_depth--;
- assert(exec->flush_call_depth == 0);
-#endif
-}
-
-
-static void reset_attrfv( struct vbo_exec_context *exec )
-{
- GLuint i;
-
- for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
- exec->vtx.attrsz[i] = 0;
- exec->vtx.active_sz[i] = 0;
- }
-
- exec->vtx.vertex_size = 0;
-}
-
-
-void GLAPIENTRY
-_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
-{
- vbo_Color4f(r, g, b, a);
-}
-
-
-void GLAPIENTRY
-_es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
-{
- vbo_Normal3f(x, y, z);
-}
-
-
-void GLAPIENTRY
-_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
-{
- vbo_MultiTexCoord4f(target, s, t, r, q);
-}
-
-
-void GLAPIENTRY
-_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
-{
- vbo_Materialfv(face, pname, params);
-}
-
-
-void GLAPIENTRY
-_es_Materialf(GLenum face, GLenum pname, GLfloat param)
-{
- GLfloat p[4];
- p[0] = param;
- p[1] = p[2] = p[3] = 0.0F;
- vbo_Materialfv(face, pname, p);
-}
-
-
-/**
- * A special version of glVertexAttrib4f that does not treat index 0 as
- * VBO_ATTRIB_POS.
- */
-static void
-VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
- GET_CURRENT_CONTEXT(ctx);
- if (index < MAX_VERTEX_GENERIC_ATTRIBS)
- ATTR(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w);
- else
- ERROR();
-}
-
-void GLAPIENTRY
-_es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
- VertexAttrib4f_nopos(index, x, y, z, w);
-}
-
-
-void GLAPIENTRY
-_es_VertexAttrib1f(GLuint indx, GLfloat x)
-{
- VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
-}
-
-
-void GLAPIENTRY
-_es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
-{
- VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
-}
-
-
-void GLAPIENTRY
-_es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
-{
- VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
-}
-
-
-void GLAPIENTRY
-_es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
-{
- VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
-}
-
-
-void GLAPIENTRY
-_es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
-{
- VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
-}
-
-
-void GLAPIENTRY
-_es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
-{
- VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
-}
-
-
-void GLAPIENTRY
-_es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
-{
- VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
-}
+/**************************************************************************
+
+Copyright 2002-2008 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
+on 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 THEIR 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 <keith@tungstengraphics.com>
+ */
+
+#include "main/glheader.h"
+#include "main/bufferobj.h"
+#include "main/context.h"
+#include "main/macros.h"
+#include "main/mfeatures.h"
+#include "main/vtxfmt.h"
+#include "main/dlist.h"
+#include "main/eval.h"
+#include "main/state.h"
+#include "main/light.h"
+#include "main/api_arrayelt.h"
+#include "main/api_noop.h"
+#include "main/dispatch.h"
+
+#include "vbo_context.h"
+
+#ifdef ERROR
+#undef ERROR
+#endif
+
+
+/** ID/name for immediate-mode VBO */
+#define IMM_BUFFER_NAME 0xaabbccdd
+
+
+static void reset_attrfv( struct vbo_exec_context *exec );
+
+
+/**
+ * Close off the last primitive, execute the buffer, restart the
+ * primitive.
+ */
+static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec )
+{
+ if (exec->vtx.prim_count == 0) {
+ exec->vtx.copied.nr = 0;
+ exec->vtx.vert_count = 0;
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+ }
+ else {
+ GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin;
+ GLuint last_count;
+
+ if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
+ GLint i = exec->vtx.prim_count - 1;
+ assert(i >= 0);
+ exec->vtx.prim[i].count = (exec->vtx.vert_count -
+ exec->vtx.prim[i].start);
+ }
+
+ last_count = exec->vtx.prim[exec->vtx.prim_count-1].count;
+
+ /* Execute the buffer and save copied vertices.
+ */
+ if (exec->vtx.vert_count)
+ vbo_exec_vtx_flush( exec, GL_FALSE );
+ else {
+ exec->vtx.prim_count = 0;
+ exec->vtx.copied.nr = 0;
+ }
+
+ /* Emit a glBegin to start the new list.
+ */
+ assert(exec->vtx.prim_count == 0);
+
+ if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
+ exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
+ exec->vtx.prim[0].start = 0;
+ exec->vtx.prim[0].count = 0;
+ exec->vtx.prim_count++;
+
+ if (exec->vtx.copied.nr == last_count)
+ exec->vtx.prim[0].begin = last_begin;
+ }
+ }
+}
+
+
+/**
+ * Deal with buffer wrapping where provoked by the vertex buffer
+ * filling up, as opposed to upgrade_vertex().
+ */
+void vbo_exec_vtx_wrap( struct vbo_exec_context *exec )
+{
+ GLfloat *data = exec->vtx.copied.buffer;
+ GLuint i;
+
+ /* Run pipeline on current vertices, copy wrapped vertices
+ * to exec->vtx.copied.
+ */
+ vbo_exec_wrap_buffers( exec );
+
+ /* Copy stored stored vertices to start of new list.
+ */
+ assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
+
+ for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
+ memcpy( exec->vtx.buffer_ptr, data,
+ exec->vtx.vertex_size * sizeof(GLfloat));
+ exec->vtx.buffer_ptr += exec->vtx.vertex_size;
+ data += exec->vtx.vertex_size;
+ exec->vtx.vert_count++;
+ }
+
+ exec->vtx.copied.nr = 0;
+}
+
+
+/**
+ * Copy the active vertex's values to the ctx->Current fields.
+ */
+static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
+{
+ struct gl_context *ctx = exec->ctx;
+ struct vbo_context *vbo = vbo_context(ctx);
+ GLuint i;
+
+ for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
+ if (exec->vtx.attrsz[i]) {
+ /* Note: the exec->vtx.current[i] pointers point into the
+ * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
+ */
+ GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
+ GLfloat tmp[4];
+
+ COPY_CLEAN_4V(tmp,
+ exec->vtx.attrsz[i],
+ exec->vtx.attrptr[i]);
+
+ if (memcmp(current, tmp, sizeof(tmp)) != 0) {
+ memcpy(current, tmp, sizeof(tmp));
+
+ /* Given that we explicitly state size here, there is no need
+ * for the COPY_CLEAN above, could just copy 16 bytes and be
+ * done. The only problem is when Mesa accesses ctx->Current
+ * directly.
+ */
+ vbo->currval[i].Size = exec->vtx.attrsz[i];
+
+ /* This triggers rather too much recalculation of Mesa state
+ * that doesn't get used (eg light positions).
+ */
+ if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
+ i <= VBO_ATTRIB_MAT_BACK_INDEXES)
+ ctx->NewState |= _NEW_LIGHT;
+
+ ctx->NewState |= _NEW_CURRENT_ATTRIB;
+ }
+ }
+ }
+
+ /* Colormaterial -- this kindof sucks.
+ */
+ if (ctx->Light.ColorMaterialEnabled &&
+ exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
+ _mesa_update_color_material(ctx,
+ ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
+ }
+}
+
+
+/**
+ * Copy current vertex attribute values into the current vertex.
+ */
+static void
+vbo_exec_copy_from_current(struct vbo_exec_context *exec)
+{
+ struct gl_context *ctx = exec->ctx;
+ struct vbo_context *vbo = vbo_context(ctx);
+ GLint i;
+
+ for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
+ const GLfloat *current = (GLfloat *) vbo->currval[i].Ptr;
+ switch (exec->vtx.attrsz[i]) {
+ case 4: exec->vtx.attrptr[i][3] = current[3];
+ case 3: exec->vtx.attrptr[i][2] = current[2];
+ case 2: exec->vtx.attrptr[i][1] = current[1];
+ case 1: exec->vtx.attrptr[i][0] = current[0];
+ break;
+ }
+ }
+}
+
+
+/**
+ * Flush existing data, set new attrib size, replay copied vertices.
+ * This is called when we transition from a small vertex attribute size
+ * to a larger one. Ex: glTexCoord2f -> glTexCoord4f.
+ * We need to go back over the previous 2-component texcoords and insert
+ * zero and one values.
+ */
+static void
+vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
+ GLuint attr, GLuint newSize )
+{
+ struct gl_context *ctx = exec->ctx;
+ struct vbo_context *vbo = vbo_context(ctx);
+ const GLint lastcount = exec->vtx.vert_count;
+ GLfloat *old_attrptr[VBO_ATTRIB_MAX];
+ const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
+ const GLuint oldSize = exec->vtx.attrsz[attr];
+ GLuint i;
+
+ /* Run pipeline on current vertices, copy wrapped vertices
+ * to exec->vtx.copied.
+ */
+ vbo_exec_wrap_buffers( exec );
+
+ if (unlikely(exec->vtx.copied.nr)) {
+ /* We're in the middle of a primitive, keep the old vertex
+ * format around to be able to translate the copied vertices to
+ * the new format.
+ */
+ memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
+ }
+
+ if (unlikely(oldSize)) {
+ /* Do a COPY_TO_CURRENT to ensure back-copying works for the
+ * case when the attribute already exists in the vertex and is
+ * having its size increased.
+ */
+ vbo_exec_copy_to_current( exec );
+ }
+
+ /* Heuristic: Attempt to isolate attributes received outside
+ * begin/end so that they don't bloat the vertices.
+ */
+ if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
+ !oldSize && lastcount > 8 && exec->vtx.vertex_size) {
+ vbo_exec_copy_to_current( exec );
+ reset_attrfv( exec );
+ }
+
+ /* Fix up sizes:
+ */
+ exec->vtx.attrsz[attr] = newSize;
+ exec->vtx.vertex_size += newSize - oldSize;
+ exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
+ (exec->vtx.vertex_size * sizeof(GLfloat)));
+ exec->vtx.vert_count = 0;
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+
+ if (unlikely(oldSize)) {
+ /* Size changed, recalculate all the attrptr[] values
+ */
+ GLfloat *tmp = exec->vtx.vertex;
+
+ for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
+ if (exec->vtx.attrsz[i]) {
+ exec->vtx.attrptr[i] = tmp;
+ tmp += exec->vtx.attrsz[i];
+ }
+ else
+ exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
+ }
+
+ /* Copy from current to repopulate the vertex with correct
+ * values.
+ */
+ vbo_exec_copy_from_current( exec );
+ }
+ else {
+ /* Just have to append the new attribute at the end */
+ exec->vtx.attrptr[attr] = exec->vtx.vertex +
+ exec->vtx.vertex_size - newSize;
+ }
+
+ /* Replay stored vertices to translate them
+ * to new format here.
+ *
+ * -- No need to replay - just copy piecewise
+ */
+ if (unlikely(exec->vtx.copied.nr)) {
+ GLfloat *data = exec->vtx.copied.buffer;
+ GLfloat *dest = exec->vtx.buffer_ptr;
+ GLuint j;
+
+ assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
+
+ for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
+ for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
+ GLuint sz = exec->vtx.attrsz[j];
+
+ if (sz) {
+ GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
+ GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
+
+ if (j == attr) {
+ if (oldSize) {
+ GLfloat tmp[4];
+ COPY_CLEAN_4V(tmp, oldSize, data + old_offset);
+ COPY_SZ_4V(dest + new_offset, newSize, tmp);
+ } else {
+ GLfloat *current = (GLfloat *)vbo->currval[j].Ptr;
+ COPY_SZ_4V(dest + new_offset, sz, current);
+ }
+ }
+ else {
+ COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
+ }
+ }
+ }
+
+ data += old_vtx_size;
+ dest += exec->vtx.vertex_size;
+ }
+
+ exec->vtx.buffer_ptr = dest;
+ exec->vtx.vert_count += exec->vtx.copied.nr;
+ exec->vtx.copied.nr = 0;
+ }
+}
+
+
+/**
+ * This is when a vertex attribute transitions to a different size.
+ * For example, we saw a bunch of glTexCoord2f() calls and now we got a
+ * glTexCoord4f() call. We promote the array from size=2 to size=4.
+ */
+static void
+vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint newSize)
+{
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+
+ if (newSize > exec->vtx.attrsz[attr]) {
+ /* New size is larger. Need to flush existing vertices and get
+ * an enlarged vertex format.
+ */
+ vbo_exec_wrap_upgrade_vertex( exec, attr, newSize );
+ }
+ else if (newSize < exec->vtx.active_sz[attr]) {
+ static const GLfloat id[4] = { 0, 0, 0, 1 };
+ GLuint i;
+
+ /* New size is smaller - just need to fill in some
+ * zeros. Don't need to flush or wrap.
+ */
+ for (i = newSize; i <= exec->vtx.attrsz[attr]; i++)
+ exec->vtx.attrptr[attr][i-1] = id[i-1];
+ }
+
+ exec->vtx.active_sz[attr] = newSize;
+
+ /* Does setting NeedFlush belong here? Necessitates resetting
+ * vtxfmt on each flush (otherwise flags won't get reset
+ * afterwards).
+ */
+ if (attr == 0)
+ exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
+}
+
+
+/**
+ * This macro is used to implement all the glVertex, glColor, glTexCoord,
+ * glVertexAttrib, etc functions.
+ */
+#define ATTR( A, N, V0, V1, V2, V3 ) \
+do { \
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
+ \
+ if (unlikely(!(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \
+ ctx->Driver.BeginVertices( ctx ); \
+ \
+ if (unlikely(exec->vtx.active_sz[A] != N)) \
+ vbo_exec_fixup_vertex(ctx, A, N); \
+ \
+ { \
+ GLfloat *dest = exec->vtx.attrptr[A]; \
+ if (N>0) dest[0] = V0; \
+ if (N>1) dest[1] = V1; \
+ if (N>2) dest[2] = V2; \
+ if (N>3) dest[3] = V3; \
+ } \
+ \
+ if ((A) == 0) { \
+ /* This is a glVertex call */ \
+ GLuint i; \
+ \
+ for (i = 0; i < exec->vtx.vertex_size; i++) \
+ exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
+ \
+ exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
+ \
+ /* Set FLUSH_STORED_VERTICES to indicate that there's now */ \
+ /* something to draw (not just updating a color or texcoord).*/ \
+ ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
+ \
+ if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
+ vbo_exec_vtx_wrap( exec ); \
+ } \
+} while (0)
+
+
+#define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
+#define TAG(x) vbo_##x
+
+#include "vbo_attrib_tmp.h"
+
+
+#if FEATURE_beginend
+
+
+#if FEATURE_evaluators
+
+static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+
+ {
+ GLint i;
+ if (exec->eval.recalculate_maps)
+ vbo_exec_eval_update( exec );
+
+ for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
+ if (exec->eval.map1[i].map)
+ if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
+ vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz );
+ }
+ }
+
+
+ memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
+ exec->vtx.vertex_size * sizeof(GLfloat));
+
+ vbo_exec_do_EvalCoord1f( exec, u );
+
+ memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
+ exec->vtx.vertex_size * sizeof(GLfloat));
+}
+
+static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+
+ {
+ GLint i;
+ if (exec->eval.recalculate_maps)
+ vbo_exec_eval_update( exec );
+
+ for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
+ if (exec->eval.map2[i].map)
+ if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
+ vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz );
+ }
+
+ if (ctx->Eval.AutoNormal)
+ if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
+ vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 );
+ }
+
+ memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
+ exec->vtx.vertex_size * sizeof(GLfloat));
+
+ vbo_exec_do_EvalCoord2f( exec, u, v );
+
+ memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
+ exec->vtx.vertex_size * sizeof(GLfloat));
+}
+
+static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
+{
+ vbo_exec_EvalCoord1f( u[0] );
+}
+
+static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
+{
+ vbo_exec_EvalCoord2f( u[0], u[1] );
+}
+
+static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
+ (GLfloat) ctx->Eval.MapGrid1un);
+ GLfloat u = i * du + ctx->Eval.MapGrid1u1;
+
+ vbo_exec_EvalCoord1f( u );
+}
+
+
+static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
+ (GLfloat) ctx->Eval.MapGrid2un);
+ GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
+ (GLfloat) ctx->Eval.MapGrid2vn);
+ GLfloat u = i * du + ctx->Eval.MapGrid2u1;
+ GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
+
+ vbo_exec_EvalCoord2f( u, v );
+}
+
+/* use noop eval mesh */
+#define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1
+#define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2
+
+#endif /* FEATURE_evaluators */
+
+
+/**
+ * Flush (draw) vertices.
+ * \param unmap - leave VBO unmapped after flushing?
+ */
+static void
+vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap)
+{
+ if (exec->vtx.vert_count || unmap) {
+ vbo_exec_vtx_flush( exec, unmap );
+ }
+
+ if (exec->vtx.vertex_size) {
+ vbo_exec_copy_to_current( exec );
+ reset_attrfv( exec );
+ }
+}
+
+
+/**
+ * Called via glBegin.
+ */
+static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
+{
+ GET_CURRENT_CONTEXT( ctx );
+
+ if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+ int i;
+
+ if (ctx->NewState) {
+ _mesa_update_state( ctx );
+
+ CALL_Begin(ctx->Exec, (mode));
+ return;
+ }
+
+ if (!_mesa_valid_to_render(ctx, "glBegin")) {
+ return;
+ }
+
+ /* Heuristic: attempt to isolate attributes occuring outside
+ * begin/end pairs.
+ */
+ if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
+ vbo_exec_FlushVertices_internal(exec, GL_FALSE);
+
+ i = exec->vtx.prim_count++;
+ exec->vtx.prim[i].mode = mode;
+ exec->vtx.prim[i].begin = 1;
+ exec->vtx.prim[i].end = 0;
+ exec->vtx.prim[i].indexed = 0;
+ exec->vtx.prim[i].weak = 0;
+ exec->vtx.prim[i].pad = 0;
+ exec->vtx.prim[i].start = exec->vtx.vert_count;
+ exec->vtx.prim[i].count = 0;
+ exec->vtx.prim[i].num_instances = 1;
+
+ ctx->Driver.CurrentExecPrimitive = mode;
+ }
+ else
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
+
+}
+
+
+/**
+ * Called via glEnd.
+ */
+static void GLAPIENTRY vbo_exec_End( void )
+{
+ GET_CURRENT_CONTEXT( ctx );
+
+ if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+ int idx = exec->vtx.vert_count;
+ int i = exec->vtx.prim_count - 1;
+
+ exec->vtx.prim[i].end = 1;
+ exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
+
+ ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
+
+ if (exec->vtx.prim_count == VBO_MAX_PRIM)
+ vbo_exec_vtx_flush( exec, GL_FALSE );
+ }
+ else
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
+}
+
+
+/**
+ * Called via glPrimitiveRestartNV()
+ */
+static void GLAPIENTRY
+vbo_exec_PrimitiveRestartNV(void)
+{
+ GLenum curPrim;
+ GET_CURRENT_CONTEXT( ctx );
+
+ curPrim = ctx->Driver.CurrentExecPrimitive;
+
+ if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" );
+ }
+ else {
+ vbo_exec_End();
+ vbo_exec_Begin(curPrim);
+ }
+}
+
+
+
+static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
+{
+ GLvertexformat *vfmt = &exec->vtxfmt;
+
+ _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
+
+ vfmt->Begin = vbo_exec_Begin;
+ vfmt->End = vbo_exec_End;
+ vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
+
+ _MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_);
+ _MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_);
+
+ vfmt->Rectf = _mesa_noop_Rectf;
+
+ /* from attrib_tmp.h:
+ */
+ vfmt->Color3f = vbo_Color3f;
+ vfmt->Color3fv = vbo_Color3fv;
+ vfmt->Color4f = vbo_Color4f;
+ vfmt->Color4fv = vbo_Color4fv;
+ vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
+ vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
+ vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
+ vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
+ vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
+ vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
+ vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
+ vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
+ vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
+ vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
+ vfmt->Normal3f = vbo_Normal3f;
+ vfmt->Normal3fv = vbo_Normal3fv;
+ vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
+ vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
+ vfmt->TexCoord1f = vbo_TexCoord1f;
+ vfmt->TexCoord1fv = vbo_TexCoord1fv;
+ vfmt->TexCoord2f = vbo_TexCoord2f;
+ vfmt->TexCoord2fv = vbo_TexCoord2fv;
+ vfmt->TexCoord3f = vbo_TexCoord3f;
+ vfmt->TexCoord3fv = vbo_TexCoord3fv;
+ vfmt->TexCoord4f = vbo_TexCoord4f;
+ vfmt->TexCoord4fv = vbo_TexCoord4fv;
+ vfmt->Vertex2f = vbo_Vertex2f;
+ vfmt->Vertex2fv = vbo_Vertex2fv;
+ vfmt->Vertex3f = vbo_Vertex3f;
+ vfmt->Vertex3fv = vbo_Vertex3fv;
+ vfmt->Vertex4f = vbo_Vertex4f;
+ vfmt->Vertex4fv = vbo_Vertex4fv;
+
+ vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
+ vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
+ vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
+ vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
+ vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
+ vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
+ vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
+ vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
+
+ vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
+ vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
+ vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
+ vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
+ vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
+ vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
+ vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
+ vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
+
+ /* integer-valued */
+ vfmt->VertexAttribI1i = vbo_VertexAttribI1i;
+ vfmt->VertexAttribI2i = vbo_VertexAttribI2i;
+ vfmt->VertexAttribI3i = vbo_VertexAttribI3i;
+ vfmt->VertexAttribI4i = vbo_VertexAttribI4i;
+ vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv;
+ vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv;
+ vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv;
+
+ /* unsigned integer-valued */
+ vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui;
+ vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui;
+ vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui;
+ vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui;
+ vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv;
+ vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv;
+ vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv;
+
+ vfmt->Materialfv = vbo_Materialfv;
+
+ vfmt->EdgeFlag = vbo_EdgeFlag;
+ vfmt->Indexf = vbo_Indexf;
+ vfmt->Indexfv = vbo_Indexfv;
+
+}
+
+
+#else /* FEATURE_beginend */
+
+
+static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
+{
+ /* silence warnings */
+ (void) vbo_Color3f;
+ (void) vbo_Color3fv;
+ (void) vbo_Color4f;
+ (void) vbo_Color4fv;
+ (void) vbo_FogCoordfEXT;
+ (void) vbo_FogCoordfvEXT;
+ (void) vbo_MultiTexCoord1f;
+ (void) vbo_MultiTexCoord1fv;
+ (void) vbo_MultiTexCoord2f;
+ (void) vbo_MultiTexCoord2fv;
+ (void) vbo_MultiTexCoord3f;
+ (void) vbo_MultiTexCoord3fv;
+ (void) vbo_MultiTexCoord4f;
+ (void) vbo_MultiTexCoord4fv;
+ (void) vbo_Normal3f;
+ (void) vbo_Normal3fv;
+ (void) vbo_SecondaryColor3fEXT;
+ (void) vbo_SecondaryColor3fvEXT;
+ (void) vbo_TexCoord1f;
+ (void) vbo_TexCoord1fv;
+ (void) vbo_TexCoord2f;
+ (void) vbo_TexCoord2fv;
+ (void) vbo_TexCoord3f;
+ (void) vbo_TexCoord3fv;
+ (void) vbo_TexCoord4f;
+ (void) vbo_TexCoord4fv;
+ (void) vbo_Vertex2f;
+ (void) vbo_Vertex2fv;
+ (void) vbo_Vertex3f;
+ (void) vbo_Vertex3fv;
+ (void) vbo_Vertex4f;
+ (void) vbo_Vertex4fv;
+
+ (void) vbo_VertexAttrib1fARB;
+ (void) vbo_VertexAttrib1fvARB;
+ (void) vbo_VertexAttrib2fARB;
+ (void) vbo_VertexAttrib2fvARB;
+ (void) vbo_VertexAttrib3fARB;
+ (void) vbo_VertexAttrib3fvARB;
+ (void) vbo_VertexAttrib4fARB;
+ (void) vbo_VertexAttrib4fvARB;
+
+ (void) vbo_VertexAttrib1fNV;
+ (void) vbo_VertexAttrib1fvNV;
+ (void) vbo_VertexAttrib2fNV;
+ (void) vbo_VertexAttrib2fvNV;
+ (void) vbo_VertexAttrib3fNV;
+ (void) vbo_VertexAttrib3fvNV;
+ (void) vbo_VertexAttrib4fNV;
+ (void) vbo_VertexAttrib4fvNV;
+
+ (void) vbo_Materialfv;
+
+ (void) vbo_EdgeFlag;
+ (void) vbo_Indexf;
+ (void) vbo_Indexfv;
+}
+
+
+#endif /* FEATURE_beginend */
+
+
+/**
+ * Tell the VBO module to use a real OpenGL vertex buffer object to
+ * store accumulated immediate-mode vertex data.
+ * This replaces the malloced buffer which was created in
+ * vb_exec_vtx_init() below.
+ */
+void vbo_use_buffer_objects(struct gl_context *ctx)
+{
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+ /* Any buffer name but 0 can be used here since this bufferobj won't
+ * go into the bufferobj hashtable.
+ */
+ GLuint bufName = IMM_BUFFER_NAME;
+ GLenum target = GL_ARRAY_BUFFER_ARB;
+ GLenum usage = GL_STREAM_DRAW_ARB;
+ GLsizei size = VBO_VERT_BUFFER_SIZE;
+
+ /* Make sure this func is only used once */
+ assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
+ if (exec->vtx.buffer_map) {
+ _mesa_align_free(exec->vtx.buffer_map);
+ exec->vtx.buffer_map = NULL;
+ exec->vtx.buffer_ptr = NULL;
+ }
+
+ /* Allocate a real buffer object now */
+ _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
+ exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
+ ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj);
+}
+
+
+
+void vbo_exec_vtx_init( struct vbo_exec_context *exec )
+{
+ struct gl_context *ctx = exec->ctx;
+ struct vbo_context *vbo = vbo_context(ctx);
+ GLuint i;
+
+ /* Allocate a buffer object. Will just reuse this object
+ * continuously, unless vbo_use_buffer_objects() is called to enable
+ * use of real VBOs.
+ */
+ _mesa_reference_buffer_object(ctx,
+ &exec->vtx.bufferobj,
+ ctx->Shared->NullBufferObj);
+
+ ASSERT(!exec->vtx.buffer_map);
+ exec->vtx.buffer_map = (GLfloat *)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+
+ vbo_exec_vtxfmt_init( exec );
+
+ /* Hook our functions into the dispatch table.
+ */
+ _mesa_install_exec_vtxfmt( exec->ctx, &exec->vtxfmt );
+
+ for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
+ ASSERT(i < Elements(exec->vtx.attrsz));
+ exec->vtx.attrsz[i] = 0;
+ ASSERT(i < Elements(exec->vtx.active_sz));
+ exec->vtx.active_sz[i] = 0;
+ }
+ for (i = 0 ; i < VERT_ATTRIB_MAX; i++) {
+ ASSERT(i < Elements(exec->vtx.inputs));
+ ASSERT(i < Elements(exec->vtx.arrays));
+ exec->vtx.inputs[i] = &exec->vtx.arrays[i];
+ }
+
+ {
+ struct gl_client_array *arrays = exec->vtx.arrays;
+ unsigned i;
+
+ memcpy(arrays, vbo->legacy_currval, 16 * sizeof(arrays[0]));
+ memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0]));
+
+ for (i = 0; i < 16; ++i) {
+ arrays[i ].BufferObj = NULL;
+ arrays[i + 16].BufferObj = NULL;
+ _mesa_reference_buffer_object(ctx, &arrays[i ].BufferObj,
+ vbo->legacy_currval[i].BufferObj);
+ _mesa_reference_buffer_object(ctx, &arrays[i + 16].BufferObj,
+ vbo->generic_currval[i].BufferObj);
+ }
+ }
+
+ exec->vtx.vertex_size = 0;
+}
+
+
+void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
+{
+ /* using a real VBO for vertex data */
+ struct gl_context *ctx = exec->ctx;
+ unsigned i;
+
+ /* True VBOs should already be unmapped
+ */
+ if (exec->vtx.buffer_map) {
+ ASSERT(exec->vtx.bufferobj->Name == 0 ||
+ exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
+ if (exec->vtx.bufferobj->Name == 0) {
+ _mesa_align_free(exec->vtx.buffer_map);
+ exec->vtx.buffer_map = NULL;
+ exec->vtx.buffer_ptr = NULL;
+ }
+ }
+
+ /* Drop any outstanding reference to the vertex buffer
+ */
+ for (i = 0; i < Elements(exec->vtx.arrays); i++) {
+ _mesa_reference_buffer_object(ctx,
+ &exec->vtx.arrays[i].BufferObj,
+ NULL);
+ }
+
+ /* Free the vertex buffer. Unmap first if needed.
+ */
+ if (_mesa_bufferobj_mapped(exec->vtx.bufferobj)) {
+ ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, exec->vtx.bufferobj);
+ }
+ _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
+}
+
+
+/**
+ * Called upon first glVertex, glColor, glTexCoord, etc.
+ */
+void vbo_exec_BeginVertices( struct gl_context *ctx )
+{
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+
+ vbo_exec_vtx_map( exec );
+
+ assert((exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
+ exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
+}
+
+
+/**
+ * Called via ctx->Driver.FlushVertices()
+ * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
+ */
+void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags )
+{
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+
+#ifdef DEBUG
+ /* debug check: make sure we don't get called recursively */
+ exec->flush_call_depth++;
+ assert(exec->flush_call_depth == 1);
+#endif
+
+ if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
+ /* We've had glBegin but not glEnd! */
+#ifdef DEBUG
+ exec->flush_call_depth--;
+ assert(exec->flush_call_depth == 0);
+#endif
+ return;
+ }
+
+ /* Flush (draw), and make sure VBO is left unmapped when done */
+ vbo_exec_FlushVertices_internal(exec, GL_TRUE);
+
+ /* Need to do this to ensure BeginVertices gets called again:
+ */
+ if (exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT)
+ exec->ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
+
+ exec->ctx->Driver.NeedFlush &= ~flags;
+
+#ifdef DEBUG
+ exec->flush_call_depth--;
+ assert(exec->flush_call_depth == 0);
+#endif
+}
+
+
+static void reset_attrfv( struct vbo_exec_context *exec )
+{
+ GLuint i;
+
+ for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
+ exec->vtx.attrsz[i] = 0;
+ exec->vtx.active_sz[i] = 0;
+ }
+
+ exec->vtx.vertex_size = 0;
+}
+
+
+void GLAPIENTRY
+_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
+{
+ vbo_Color4f(r, g, b, a);
+}
+
+
+void GLAPIENTRY
+_es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
+{
+ vbo_Normal3f(x, y, z);
+}
+
+
+void GLAPIENTRY
+_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+{
+ vbo_MultiTexCoord4f(target, s, t, r, q);
+}
+
+
+void GLAPIENTRY
+_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
+{
+ vbo_Materialfv(face, pname, params);
+}
+
+
+void GLAPIENTRY
+_es_Materialf(GLenum face, GLenum pname, GLfloat param)
+{
+ GLfloat p[4];
+ p[0] = param;
+ p[1] = p[2] = p[3] = 0.0F;
+ vbo_Materialfv(face, pname, p);
+}
+
+
+/**
+ * A special version of glVertexAttrib4f that does not treat index 0 as
+ * VBO_ATTRIB_POS.
+ */
+static void
+VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w);
+ else
+ ERROR();
+}
+
+void GLAPIENTRY
+_es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ VertexAttrib4f_nopos(index, x, y, z, w);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib1f(GLuint indx, GLfloat x)
+{
+ VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
+{
+ VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
+{
+ VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
+{
+ VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+{
+ VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
+{
+ VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
+{
+ VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
+}
diff --git a/mesalib/src/mesa/vbo/vbo_exec_draw.c b/mesalib/src/mesa/vbo/vbo_exec_draw.c
index 539658021..7cc843779 100644
--- a/mesalib/src/mesa/vbo/vbo_exec_draw.c
+++ b/mesalib/src/mesa/vbo/vbo_exec_draw.c
@@ -1,426 +1,426 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.2
- *
- * Copyright (C) 1999-2008 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.
- *
- * Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
- */
-
-#include "main/glheader.h"
-#include "main/bufferobj.h"
-#include "main/compiler.h"
-#include "main/enums.h"
-#include "main/mfeatures.h"
-#include "main/state.h"
-
-#include "vbo_context.h"
-
-
-#if FEATURE_beginend
-
-
-static void
-vbo_exec_debug_verts( struct vbo_exec_context *exec )
-{
- GLuint count = exec->vtx.vert_count;
- GLuint i;
-
- printf("%s: %u vertices %d primitives, %d vertsize\n",
- __FUNCTION__,
- count,
- exec->vtx.prim_count,
- exec->vtx.vertex_size);
-
- for (i = 0 ; i < exec->vtx.prim_count ; i++) {
- struct _mesa_prim *prim = &exec->vtx.prim[i];
- printf(" prim %d: %s%s %d..%d %s %s\n",
- i,
- _mesa_lookup_prim_by_nr(prim->mode),
- prim->weak ? " (weak)" : "",
- prim->start,
- prim->start + prim->count,
- prim->begin ? "BEGIN" : "(wrap)",
- prim->end ? "END" : "(wrap)");
- }
-}
-
-
-/*
- * NOTE: Need to have calculated primitives by this point -- do it on the fly.
- * NOTE: Old 'parity' issue is gone.
- */
-static GLuint
-vbo_copy_vertices( struct vbo_exec_context *exec )
-{
- GLuint nr = exec->vtx.prim[exec->vtx.prim_count-1].count;
- GLuint ovf, i;
- GLuint sz = exec->vtx.vertex_size;
- GLfloat *dst = exec->vtx.copied.buffer;
- const GLfloat *src = (exec->vtx.buffer_map +
- exec->vtx.prim[exec->vtx.prim_count-1].start *
- exec->vtx.vertex_size);
-
-
- switch (exec->ctx->Driver.CurrentExecPrimitive) {
- case GL_POINTS:
- return 0;
- case GL_LINES:
- ovf = nr&1;
- for (i = 0 ; i < ovf ; i++)
- memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
- return i;
- case GL_TRIANGLES:
- ovf = nr%3;
- for (i = 0 ; i < ovf ; i++)
- memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
- return i;
- case GL_QUADS:
- ovf = nr&3;
- for (i = 0 ; i < ovf ; i++)
- memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
- return i;
- case GL_LINE_STRIP:
- if (nr == 0) {
- return 0;
- }
- else {
- memcpy( dst, src+(nr-1)*sz, sz * sizeof(GLfloat) );
- return 1;
- }
- case GL_LINE_LOOP:
- case GL_TRIANGLE_FAN:
- case GL_POLYGON:
- if (nr == 0) {
- return 0;
- }
- else if (nr == 1) {
- memcpy( dst, src+0, sz * sizeof(GLfloat) );
- return 1;
- }
- else {
- memcpy( dst, src+0, sz * sizeof(GLfloat) );
- memcpy( dst+sz, src+(nr-1)*sz, sz * sizeof(GLfloat) );
- return 2;
- }
- case GL_TRIANGLE_STRIP:
- /* no parity issue, but need to make sure the tri is not drawn twice */
- if (nr & 1) {
- exec->vtx.prim[exec->vtx.prim_count-1].count--;
- }
- /* fallthrough */
- case GL_QUAD_STRIP:
- switch (nr) {
- case 0:
- ovf = 0;
- break;
- case 1:
- ovf = 1;
- break;
- default:
- ovf = 2 + (nr & 1);
- break;
- }
- for (i = 0 ; i < ovf ; i++)
- memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
- return i;
- case PRIM_OUTSIDE_BEGIN_END:
- return 0;
- default:
- assert(0);
- return 0;
- }
-}
-
-
-
-/* TODO: populate these as the vertex is defined:
- */
-static void
-vbo_exec_bind_arrays( struct gl_context *ctx )
-{
- struct vbo_context *vbo = vbo_context(ctx);
- struct vbo_exec_context *exec = &vbo->exec;
- struct gl_client_array *arrays = exec->vtx.arrays;
- const GLuint count = exec->vtx.vert_count;
- const GLuint *map;
- GLuint attr;
- GLbitfield varying_inputs = 0x0;
-
- /* Install the default (ie Current) attributes first, then overlay
- * all active ones.
- */
- switch (get_program_mode(exec->ctx)) {
- case VP_NONE:
- for (attr = 0; attr < 16; attr++) {
- exec->vtx.inputs[attr] = &vbo->legacy_currval[attr];
- }
- for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) {
- ASSERT(attr + 16 < Elements(exec->vtx.inputs));
- exec->vtx.inputs[attr + 16] = &vbo->mat_currval[attr];
- }
- map = vbo->map_vp_none;
- break;
- case VP_NV:
- case VP_ARB:
- /* The aliasing of attributes for NV vertex programs has already
- * occurred. NV vertex programs cannot access material values,
- * nor attributes greater than VERT_ATTRIB_TEX7.
- */
- for (attr = 0; attr < 16; attr++) {
- exec->vtx.inputs[attr] = &vbo->legacy_currval[attr];
- ASSERT(attr + 16 < Elements(exec->vtx.inputs));
- exec->vtx.inputs[attr + 16] = &vbo->generic_currval[attr];
- }
- map = vbo->map_vp_arb;
-
- /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read.
- * In that case we effectively need to route the data from
- * glVertexAttrib(0, val) calls to feed into the GENERIC0 input.
- */
- if ((ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_POS) == 0 &&
- (ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_GENERIC0)) {
- exec->vtx.inputs[16] = exec->vtx.inputs[0];
- exec->vtx.attrsz[16] = exec->vtx.attrsz[0];
- exec->vtx.attrptr[16] = exec->vtx.attrptr[0];
- exec->vtx.attrsz[0] = 0;
- }
- break;
- default:
- assert(0);
- }
-
- /* Make all active attributes (including edgeflag) available as
- * arrays of floats.
- */
- for (attr = 0; attr < VERT_ATTRIB_MAX ; attr++) {
- const GLuint src = map[attr];
-
- if (exec->vtx.attrsz[src]) {
- GLsizeiptr offset = (GLbyte *)exec->vtx.attrptr[src] -
- (GLbyte *)exec->vtx.vertex;
-
- /* override the default array set above */
- ASSERT(attr < Elements(exec->vtx.inputs));
- ASSERT(attr < Elements(exec->vtx.arrays)); /* arrays[] */
- exec->vtx.inputs[attr] = &arrays[attr];
-
- if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
- /* a real buffer obj: Ptr is an offset, not a pointer*/
- assert(exec->vtx.bufferobj->Pointer); /* buf should be mapped */
- assert(offset >= 0);
- arrays[attr].Ptr = (GLubyte *)exec->vtx.bufferobj->Offset + offset;
- }
- else {
- /* Ptr into ordinary app memory */
- arrays[attr].Ptr = (GLubyte *)exec->vtx.buffer_map + offset;
- }
- arrays[attr].Size = exec->vtx.attrsz[src];
- arrays[attr].StrideB = exec->vtx.vertex_size * sizeof(GLfloat);
- arrays[attr].Stride = exec->vtx.vertex_size * sizeof(GLfloat);
- arrays[attr].Type = GL_FLOAT;
- arrays[attr].Format = GL_RGBA;
- arrays[attr].Enabled = 1;
- _mesa_reference_buffer_object(ctx,
- &arrays[attr].BufferObj,
- exec->vtx.bufferobj);
- arrays[attr]._MaxElement = count; /* ??? */
-
- varying_inputs |= 1 << attr;
- ctx->NewState |= _NEW_ARRAY;
- }
- }
-
- _mesa_set_varying_vp_inputs( ctx, varying_inputs );
-}
-
-
-/**
- * Unmap the VBO. This is called before drawing.
- */
-static void
-vbo_exec_vtx_unmap( struct vbo_exec_context *exec )
-{
- GLenum target = GL_ARRAY_BUFFER_ARB;
-
- if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
- struct gl_context *ctx = exec->ctx;
-
- if (ctx->Driver.FlushMappedBufferRange) {
- GLintptr offset = exec->vtx.buffer_used - exec->vtx.bufferobj->Offset;
- GLsizeiptr length = (exec->vtx.buffer_ptr - exec->vtx.buffer_map) * sizeof(float);
-
- if (length)
- ctx->Driver.FlushMappedBufferRange(ctx, target,
- offset, length,
- exec->vtx.bufferobj);
- }
-
- exec->vtx.buffer_used += (exec->vtx.buffer_ptr -
- exec->vtx.buffer_map) * sizeof(float);
-
- assert(exec->vtx.buffer_used <= VBO_VERT_BUFFER_SIZE);
- assert(exec->vtx.buffer_ptr != NULL);
-
- ctx->Driver.UnmapBuffer(ctx, target, exec->vtx.bufferobj);
- exec->vtx.buffer_map = NULL;
- exec->vtx.buffer_ptr = NULL;
- exec->vtx.max_vert = 0;
- }
-}
-
-
-/**
- * Map the vertex buffer to begin storing glVertex, glColor, etc data.
- */
-void
-vbo_exec_vtx_map( struct vbo_exec_context *exec )
-{
- struct gl_context *ctx = exec->ctx;
- const GLenum target = GL_ARRAY_BUFFER_ARB;
- const GLenum access = GL_READ_WRITE_ARB; /* for MapBuffer */
- const GLenum accessRange = GL_MAP_WRITE_BIT | /* for MapBufferRange */
- GL_MAP_INVALIDATE_RANGE_BIT |
- GL_MAP_UNSYNCHRONIZED_BIT |
- GL_MAP_FLUSH_EXPLICIT_BIT |
- MESA_MAP_NOWAIT_BIT;
- const GLenum usage = GL_STREAM_DRAW_ARB;
-
- if (!_mesa_is_bufferobj(exec->vtx.bufferobj))
- return;
-
- assert(!exec->vtx.buffer_map);
- assert(!exec->vtx.buffer_ptr);
-
- if (VBO_VERT_BUFFER_SIZE > exec->vtx.buffer_used + 1024 &&
- ctx->Driver.MapBufferRange) {
- /* The VBO exists and there's room for more */
- exec->vtx.buffer_map =
- (GLfloat *)ctx->Driver.MapBufferRange(ctx,
- target,
- exec->vtx.buffer_used,
- (VBO_VERT_BUFFER_SIZE -
- exec->vtx.buffer_used),
- accessRange,
- exec->vtx.bufferobj);
- exec->vtx.buffer_ptr = exec->vtx.buffer_map;
- }
-
- if (!exec->vtx.buffer_map) {
- /* Need to allocate a new VBO */
- exec->vtx.buffer_used = 0;
-
- ctx->Driver.BufferData(ctx, target,
- VBO_VERT_BUFFER_SIZE,
- NULL, usage, exec->vtx.bufferobj);
-
-
- if (ctx->Driver.MapBufferRange)
- exec->vtx.buffer_map =
- (GLfloat *)ctx->Driver.MapBufferRange(ctx, target,
- 0, VBO_VERT_BUFFER_SIZE,
- accessRange,
- exec->vtx.bufferobj);
- if (!exec->vtx.buffer_map)
- exec->vtx.buffer_map =
- (GLfloat *)ctx->Driver.MapBuffer(ctx, target, access, exec->vtx.bufferobj);
- assert(exec->vtx.buffer_map);
- exec->vtx.buffer_ptr = exec->vtx.buffer_map;
- }
-
- if (0)
- printf("map %d..\n", exec->vtx.buffer_used);
-}
-
-
-
-/**
- * Execute the buffer and save copied verts.
- * \param keep_unmapped if true, leave the VBO unmapped when we're done.
- */
-void
-vbo_exec_vtx_flush(struct vbo_exec_context *exec, GLboolean keepUnmapped)
-{
- if (0)
- vbo_exec_debug_verts( exec );
-
- if (exec->vtx.prim_count &&
- exec->vtx.vert_count) {
-
- exec->vtx.copied.nr = vbo_copy_vertices( exec );
-
- if (exec->vtx.copied.nr != exec->vtx.vert_count) {
- struct gl_context *ctx = exec->ctx;
-
- /* Before the update_state() as this may raise _NEW_ARRAY
- * from _mesa_set_varying_vp_inputs().
- */
- vbo_exec_bind_arrays( ctx );
-
- if (ctx->NewState)
- _mesa_update_state( ctx );
-
- if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
- vbo_exec_vtx_unmap( exec );
- }
-
- if (0)
- printf("%s %d %d\n", __FUNCTION__, exec->vtx.prim_count,
- exec->vtx.vert_count);
-
- vbo_context(ctx)->draw_prims( ctx,
- exec->vtx.inputs,
- exec->vtx.prim,
- exec->vtx.prim_count,
- NULL,
- GL_TRUE,
- 0,
- exec->vtx.vert_count - 1);
-
- /* If using a real VBO, get new storage -- unless asked not to.
- */
- if (_mesa_is_bufferobj(exec->vtx.bufferobj) && !keepUnmapped) {
- vbo_exec_vtx_map( exec );
- }
- }
- }
-
- /* May have to unmap explicitly if we didn't draw:
- */
- if (keepUnmapped &&
- _mesa_is_bufferobj(exec->vtx.bufferobj) &&
- exec->vtx.buffer_map) {
- vbo_exec_vtx_unmap( exec );
- }
-
- if (keepUnmapped || exec->vtx.vertex_size == 0)
- exec->vtx.max_vert = 0;
- else
- exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
- (exec->vtx.vertex_size * sizeof(GLfloat)));
-
- exec->vtx.buffer_ptr = exec->vtx.buffer_map;
- exec->vtx.prim_count = 0;
- exec->vtx.vert_count = 0;
-}
-
-
-#endif /* FEATURE_beginend */
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.2
+ *
+ * Copyright (C) 1999-2008 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.
+ *
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "main/glheader.h"
+#include "main/bufferobj.h"
+#include "main/compiler.h"
+#include "main/enums.h"
+#include "main/mfeatures.h"
+#include "main/state.h"
+
+#include "vbo_context.h"
+
+
+#if FEATURE_beginend
+
+
+static void
+vbo_exec_debug_verts( struct vbo_exec_context *exec )
+{
+ GLuint count = exec->vtx.vert_count;
+ GLuint i;
+
+ printf("%s: %u vertices %d primitives, %d vertsize\n",
+ __FUNCTION__,
+ count,
+ exec->vtx.prim_count,
+ exec->vtx.vertex_size);
+
+ for (i = 0 ; i < exec->vtx.prim_count ; i++) {
+ struct _mesa_prim *prim = &exec->vtx.prim[i];
+ printf(" prim %d: %s%s %d..%d %s %s\n",
+ i,
+ _mesa_lookup_prim_by_nr(prim->mode),
+ prim->weak ? " (weak)" : "",
+ prim->start,
+ prim->start + prim->count,
+ prim->begin ? "BEGIN" : "(wrap)",
+ prim->end ? "END" : "(wrap)");
+ }
+}
+
+
+/*
+ * NOTE: Need to have calculated primitives by this point -- do it on the fly.
+ * NOTE: Old 'parity' issue is gone.
+ */
+static GLuint
+vbo_copy_vertices( struct vbo_exec_context *exec )
+{
+ GLuint nr = exec->vtx.prim[exec->vtx.prim_count-1].count;
+ GLuint ovf, i;
+ GLuint sz = exec->vtx.vertex_size;
+ GLfloat *dst = exec->vtx.copied.buffer;
+ const GLfloat *src = (exec->vtx.buffer_map +
+ exec->vtx.prim[exec->vtx.prim_count-1].start *
+ exec->vtx.vertex_size);
+
+
+ switch (exec->ctx->Driver.CurrentExecPrimitive) {
+ case GL_POINTS:
+ return 0;
+ case GL_LINES:
+ ovf = nr&1;
+ for (i = 0 ; i < ovf ; i++)
+ memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
+ return i;
+ case GL_TRIANGLES:
+ ovf = nr%3;
+ for (i = 0 ; i < ovf ; i++)
+ memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
+ return i;
+ case GL_QUADS:
+ ovf = nr&3;
+ for (i = 0 ; i < ovf ; i++)
+ memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
+ return i;
+ case GL_LINE_STRIP:
+ if (nr == 0) {
+ return 0;
+ }
+ else {
+ memcpy( dst, src+(nr-1)*sz, sz * sizeof(GLfloat) );
+ return 1;
+ }
+ case GL_LINE_LOOP:
+ case GL_TRIANGLE_FAN:
+ case GL_POLYGON:
+ if (nr == 0) {
+ return 0;
+ }
+ else if (nr == 1) {
+ memcpy( dst, src+0, sz * sizeof(GLfloat) );
+ return 1;
+ }
+ else {
+ memcpy( dst, src+0, sz * sizeof(GLfloat) );
+ memcpy( dst+sz, src+(nr-1)*sz, sz * sizeof(GLfloat) );
+ return 2;
+ }
+ case GL_TRIANGLE_STRIP:
+ /* no parity issue, but need to make sure the tri is not drawn twice */
+ if (nr & 1) {
+ exec->vtx.prim[exec->vtx.prim_count-1].count--;
+ }
+ /* fallthrough */
+ case GL_QUAD_STRIP:
+ switch (nr) {
+ case 0:
+ ovf = 0;
+ break;
+ case 1:
+ ovf = 1;
+ break;
+ default:
+ ovf = 2 + (nr & 1);
+ break;
+ }
+ for (i = 0 ; i < ovf ; i++)
+ memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
+ return i;
+ case PRIM_OUTSIDE_BEGIN_END:
+ return 0;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+
+
+/* TODO: populate these as the vertex is defined:
+ */
+static void
+vbo_exec_bind_arrays( struct gl_context *ctx )
+{
+ struct vbo_context *vbo = vbo_context(ctx);
+ struct vbo_exec_context *exec = &vbo->exec;
+ struct gl_client_array *arrays = exec->vtx.arrays;
+ const GLuint count = exec->vtx.vert_count;
+ const GLuint *map;
+ GLuint attr;
+ GLbitfield varying_inputs = 0x0;
+
+ /* Install the default (ie Current) attributes first, then overlay
+ * all active ones.
+ */
+ switch (get_program_mode(exec->ctx)) {
+ case VP_NONE:
+ for (attr = 0; attr < 16; attr++) {
+ exec->vtx.inputs[attr] = &vbo->legacy_currval[attr];
+ }
+ for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) {
+ ASSERT(attr + 16 < Elements(exec->vtx.inputs));
+ exec->vtx.inputs[attr + 16] = &vbo->mat_currval[attr];
+ }
+ map = vbo->map_vp_none;
+ break;
+ case VP_NV:
+ case VP_ARB:
+ /* The aliasing of attributes for NV vertex programs has already
+ * occurred. NV vertex programs cannot access material values,
+ * nor attributes greater than VERT_ATTRIB_TEX7.
+ */
+ for (attr = 0; attr < 16; attr++) {
+ exec->vtx.inputs[attr] = &vbo->legacy_currval[attr];
+ ASSERT(attr + 16 < Elements(exec->vtx.inputs));
+ exec->vtx.inputs[attr + 16] = &vbo->generic_currval[attr];
+ }
+ map = vbo->map_vp_arb;
+
+ /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read.
+ * In that case we effectively need to route the data from
+ * glVertexAttrib(0, val) calls to feed into the GENERIC0 input.
+ */
+ if ((ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_POS) == 0 &&
+ (ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_GENERIC0)) {
+ exec->vtx.inputs[16] = exec->vtx.inputs[0];
+ exec->vtx.attrsz[16] = exec->vtx.attrsz[0];
+ exec->vtx.attrptr[16] = exec->vtx.attrptr[0];
+ exec->vtx.attrsz[0] = 0;
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ /* Make all active attributes (including edgeflag) available as
+ * arrays of floats.
+ */
+ for (attr = 0; attr < VERT_ATTRIB_MAX ; attr++) {
+ const GLuint src = map[attr];
+
+ if (exec->vtx.attrsz[src]) {
+ GLsizeiptr offset = (GLbyte *)exec->vtx.attrptr[src] -
+ (GLbyte *)exec->vtx.vertex;
+
+ /* override the default array set above */
+ ASSERT(attr < Elements(exec->vtx.inputs));
+ ASSERT(attr < Elements(exec->vtx.arrays)); /* arrays[] */
+ exec->vtx.inputs[attr] = &arrays[attr];
+
+ if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
+ /* a real buffer obj: Ptr is an offset, not a pointer*/
+ assert(exec->vtx.bufferobj->Pointer); /* buf should be mapped */
+ assert(offset >= 0);
+ arrays[attr].Ptr = (GLubyte *)exec->vtx.bufferobj->Offset + offset;
+ }
+ else {
+ /* Ptr into ordinary app memory */
+ arrays[attr].Ptr = (GLubyte *)exec->vtx.buffer_map + offset;
+ }
+ arrays[attr].Size = exec->vtx.attrsz[src];
+ arrays[attr].StrideB = exec->vtx.vertex_size * sizeof(GLfloat);
+ arrays[attr].Stride = exec->vtx.vertex_size * sizeof(GLfloat);
+ arrays[attr].Type = GL_FLOAT;
+ arrays[attr].Format = GL_RGBA;
+ arrays[attr].Enabled = 1;
+ _mesa_reference_buffer_object(ctx,
+ &arrays[attr].BufferObj,
+ exec->vtx.bufferobj);
+ arrays[attr]._MaxElement = count; /* ??? */
+
+ varying_inputs |= 1 << attr;
+ ctx->NewState |= _NEW_ARRAY;
+ }
+ }
+
+ _mesa_set_varying_vp_inputs( ctx, varying_inputs );
+}
+
+
+/**
+ * Unmap the VBO. This is called before drawing.
+ */
+static void
+vbo_exec_vtx_unmap( struct vbo_exec_context *exec )
+{
+ GLenum target = GL_ARRAY_BUFFER_ARB;
+
+ if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
+ struct gl_context *ctx = exec->ctx;
+
+ if (ctx->Driver.FlushMappedBufferRange) {
+ GLintptr offset = exec->vtx.buffer_used - exec->vtx.bufferobj->Offset;
+ GLsizeiptr length = (exec->vtx.buffer_ptr - exec->vtx.buffer_map) * sizeof(float);
+
+ if (length)
+ ctx->Driver.FlushMappedBufferRange(ctx, target,
+ offset, length,
+ exec->vtx.bufferobj);
+ }
+
+ exec->vtx.buffer_used += (exec->vtx.buffer_ptr -
+ exec->vtx.buffer_map) * sizeof(float);
+
+ assert(exec->vtx.buffer_used <= VBO_VERT_BUFFER_SIZE);
+ assert(exec->vtx.buffer_ptr != NULL);
+
+ ctx->Driver.UnmapBuffer(ctx, target, exec->vtx.bufferobj);
+ exec->vtx.buffer_map = NULL;
+ exec->vtx.buffer_ptr = NULL;
+ exec->vtx.max_vert = 0;
+ }
+}
+
+
+/**
+ * Map the vertex buffer to begin storing glVertex, glColor, etc data.
+ */
+void
+vbo_exec_vtx_map( struct vbo_exec_context *exec )
+{
+ struct gl_context *ctx = exec->ctx;
+ const GLenum target = GL_ARRAY_BUFFER_ARB;
+ const GLenum access = GL_READ_WRITE_ARB; /* for MapBuffer */
+ const GLenum accessRange = GL_MAP_WRITE_BIT | /* for MapBufferRange */
+ GL_MAP_INVALIDATE_RANGE_BIT |
+ GL_MAP_UNSYNCHRONIZED_BIT |
+ GL_MAP_FLUSH_EXPLICIT_BIT |
+ MESA_MAP_NOWAIT_BIT;
+ const GLenum usage = GL_STREAM_DRAW_ARB;
+
+ if (!_mesa_is_bufferobj(exec->vtx.bufferobj))
+ return;
+
+ assert(!exec->vtx.buffer_map);
+ assert(!exec->vtx.buffer_ptr);
+
+ if (VBO_VERT_BUFFER_SIZE > exec->vtx.buffer_used + 1024 &&
+ ctx->Driver.MapBufferRange) {
+ /* The VBO exists and there's room for more */
+ exec->vtx.buffer_map =
+ (GLfloat *)ctx->Driver.MapBufferRange(ctx,
+ target,
+ exec->vtx.buffer_used,
+ (VBO_VERT_BUFFER_SIZE -
+ exec->vtx.buffer_used),
+ accessRange,
+ exec->vtx.bufferobj);
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+ }
+
+ if (!exec->vtx.buffer_map) {
+ /* Need to allocate a new VBO */
+ exec->vtx.buffer_used = 0;
+
+ ctx->Driver.BufferData(ctx, target,
+ VBO_VERT_BUFFER_SIZE,
+ NULL, usage, exec->vtx.bufferobj);
+
+
+ if (ctx->Driver.MapBufferRange)
+ exec->vtx.buffer_map =
+ (GLfloat *)ctx->Driver.MapBufferRange(ctx, target,
+ 0, VBO_VERT_BUFFER_SIZE,
+ accessRange,
+ exec->vtx.bufferobj);
+ if (!exec->vtx.buffer_map)
+ exec->vtx.buffer_map =
+ (GLfloat *)ctx->Driver.MapBuffer(ctx, target, access, exec->vtx.bufferobj);
+ assert(exec->vtx.buffer_map);
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+ }
+
+ if (0)
+ printf("map %d..\n", exec->vtx.buffer_used);
+}
+
+
+
+/**
+ * Execute the buffer and save copied verts.
+ * \param keep_unmapped if true, leave the VBO unmapped when we're done.
+ */
+void
+vbo_exec_vtx_flush(struct vbo_exec_context *exec, GLboolean keepUnmapped)
+{
+ if (0)
+ vbo_exec_debug_verts( exec );
+
+ if (exec->vtx.prim_count &&
+ exec->vtx.vert_count) {
+
+ exec->vtx.copied.nr = vbo_copy_vertices( exec );
+
+ if (exec->vtx.copied.nr != exec->vtx.vert_count) {
+ struct gl_context *ctx = exec->ctx;
+
+ /* Before the update_state() as this may raise _NEW_ARRAY
+ * from _mesa_set_varying_vp_inputs().
+ */
+ vbo_exec_bind_arrays( ctx );
+
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
+ vbo_exec_vtx_unmap( exec );
+ }
+
+ if (0)
+ printf("%s %d %d\n", __FUNCTION__, exec->vtx.prim_count,
+ exec->vtx.vert_count);
+
+ vbo_context(ctx)->draw_prims( ctx,
+ exec->vtx.inputs,
+ exec->vtx.prim,
+ exec->vtx.prim_count,
+ NULL,
+ GL_TRUE,
+ 0,
+ exec->vtx.vert_count - 1);
+
+ /* If using a real VBO, get new storage -- unless asked not to.
+ */
+ if (_mesa_is_bufferobj(exec->vtx.bufferobj) && !keepUnmapped) {
+ vbo_exec_vtx_map( exec );
+ }
+ }
+ }
+
+ /* May have to unmap explicitly if we didn't draw:
+ */
+ if (keepUnmapped &&
+ _mesa_is_bufferobj(exec->vtx.bufferobj) &&
+ exec->vtx.buffer_map) {
+ vbo_exec_vtx_unmap( exec );
+ }
+
+ if (keepUnmapped || exec->vtx.vertex_size == 0)
+ exec->vtx.max_vert = 0;
+ else
+ exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
+ (exec->vtx.vertex_size * sizeof(GLfloat)));
+
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+ exec->vtx.prim_count = 0;
+ exec->vtx.vert_count = 0;
+}
+
+
+#endif /* FEATURE_beginend */
diff --git a/mesalib/src/mesa/vbo/vbo_save_draw.c b/mesalib/src/mesa/vbo/vbo_save_draw.c
index 634a6d3f8..5a19b0d62 100644
--- a/mesalib/src/mesa/vbo/vbo_save_draw.c
+++ b/mesalib/src/mesa/vbo/vbo_save_draw.c
@@ -1,305 +1,305 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.2
- *
- * Copyright (C) 1999-2008 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.
- */
-
-/* Author:
- * Keith Whitwell <keith@tungstengraphics.com>
- */
-
-#include "main/glheader.h"
-#include "main/bufferobj.h"
-#include "main/context.h"
-#include "main/imports.h"
-#include "main/mfeatures.h"
-#include "main/mtypes.h"
-#include "main/macros.h"
-#include "main/light.h"
-#include "main/state.h"
-
-#include "vbo_context.h"
-
-
-#if FEATURE_dlist
-
-
-/**
- * After playback, copy everything but the position from the
- * last vertex to the saved state
- */
-static void
-_playback_copy_to_current(struct gl_context *ctx,
- const struct vbo_save_vertex_list *node)
-{
- struct vbo_context *vbo = vbo_context(ctx);
- GLfloat vertex[VBO_ATTRIB_MAX * 4];
- GLfloat *data;
- GLuint i, offset;
-
- if (node->current_size == 0)
- return;
-
- if (node->current_data) {
- data = node->current_data;
- }
- else {
- data = vertex;
-
- if (node->count)
- offset = (node->buffer_offset +
- (node->count-1) * node->vertex_size * sizeof(GLfloat));
- else
- offset = node->buffer_offset;
-
- ctx->Driver.GetBufferSubData( ctx, 0, offset,
- node->vertex_size * sizeof(GLfloat),
- data, node->vertex_store->bufferobj );
-
- data += node->attrsz[0]; /* skip vertex position */
- }
-
- for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
- if (node->attrsz[i]) {
- GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
- GLfloat tmp[4];
-
- COPY_CLEAN_4V(tmp,
- node->attrsz[i],
- data);
-
- if (memcmp(current, tmp, 4 * sizeof(GLfloat)) != 0) {
- memcpy(current, tmp, 4 * sizeof(GLfloat));
-
- vbo->currval[i].Size = node->attrsz[i];
-
- if (i >= VBO_ATTRIB_FIRST_MATERIAL &&
- i <= VBO_ATTRIB_LAST_MATERIAL)
- ctx->NewState |= _NEW_LIGHT;
-
- ctx->NewState |= _NEW_CURRENT_ATTRIB;
- }
-
- data += node->attrsz[i];
- }
- }
-
- /* Colormaterial -- this kindof sucks.
- */
- if (ctx->Light.ColorMaterialEnabled) {
- _mesa_update_color_material(ctx, ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
- }
-
- /* CurrentExecPrimitive
- */
- if (node->prim_count) {
- const struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
- if (prim->end)
- ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
- else
- ctx->Driver.CurrentExecPrimitive = prim->mode;
- }
-}
-
-
-
-/**
- * Treat the vertex storage as a VBO, define vertex arrays pointing
- * into it:
- */
-static void vbo_bind_vertex_list(struct gl_context *ctx,
- const struct vbo_save_vertex_list *node)
-{
- struct vbo_context *vbo = vbo_context(ctx);
- struct vbo_save_context *save = &vbo->save;
- struct gl_client_array *arrays = save->arrays;
- GLuint buffer_offset = node->buffer_offset;
- const GLuint *map;
- GLuint attr;
- GLubyte node_attrsz[VBO_ATTRIB_MAX]; /* copy of node->attrsz[] */
- GLbitfield varying_inputs = 0x0;
-
- memcpy(node_attrsz, node->attrsz, sizeof(node->attrsz));
-
- /* Install the default (ie Current) attributes first, then overlay
- * all active ones.
- */
- switch (get_program_mode(ctx)) {
- case VP_NONE:
- for (attr = 0; attr < 16; attr++) {
- save->inputs[attr] = &vbo->legacy_currval[attr];
- }
- for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) {
- save->inputs[attr + 16] = &vbo->mat_currval[attr];
- }
- map = vbo->map_vp_none;
- break;
- case VP_NV:
- case VP_ARB:
- /* The aliasing of attributes for NV vertex programs has already
- * occurred. NV vertex programs cannot access material values,
- * nor attributes greater than VERT_ATTRIB_TEX7.
- */
- for (attr = 0; attr < 16; attr++) {
- save->inputs[attr] = &vbo->legacy_currval[attr];
- save->inputs[attr + 16] = &vbo->generic_currval[attr];
- }
- map = vbo->map_vp_arb;
-
- /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read.
- * In that case we effectively need to route the data from
- * glVertexAttrib(0, val) calls to feed into the GENERIC0 input.
- */
- if ((ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_POS) == 0 &&
- (ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_GENERIC0)) {
- save->inputs[16] = save->inputs[0];
- node_attrsz[16] = node_attrsz[0];
- node_attrsz[0] = 0;
- }
- break;
- default:
- assert(0);
- }
-
- for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
- const GLuint src = map[attr];
-
- if (node_attrsz[src]) {
- /* override the default array set above */
- save->inputs[attr] = &arrays[attr];
-
- arrays[attr].Ptr = (const GLubyte *) NULL + buffer_offset;
- arrays[attr].Size = node->attrsz[src];
- arrays[attr].StrideB = node->vertex_size * sizeof(GLfloat);
- arrays[attr].Stride = node->vertex_size * sizeof(GLfloat);
- arrays[attr].Type = GL_FLOAT;
- arrays[attr].Format = GL_RGBA;
- arrays[attr].Enabled = 1;
- _mesa_reference_buffer_object(ctx,
- &arrays[attr].BufferObj,
- node->vertex_store->bufferobj);
- arrays[attr]._MaxElement = node->count; /* ??? */
-
- assert(arrays[attr].BufferObj->Name);
-
- buffer_offset += node->attrsz[src] * sizeof(GLfloat);
- varying_inputs |= 1<<attr;
- ctx->NewState |= _NEW_ARRAY;
- }
- }
-
- _mesa_set_varying_vp_inputs( ctx, varying_inputs );
-}
-
-
-static void
-vbo_save_loopback_vertex_list(struct gl_context *ctx,
- const struct vbo_save_vertex_list *list)
-{
- const char *buffer = ctx->Driver.MapBuffer(ctx,
- GL_ARRAY_BUFFER_ARB,
- GL_READ_ONLY, /* ? */
- list->vertex_store->bufferobj);
-
- vbo_loopback_vertex_list(ctx,
- (const GLfloat *)(buffer + list->buffer_offset),
- list->attrsz,
- list->prim,
- list->prim_count,
- list->wrap_count,
- list->vertex_size);
-
- ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB,
- list->vertex_store->bufferobj);
-}
-
-
-/**
- * Execute the buffer and save copied verts.
- * This is called from the display list code when executing
- * a drawing command.
- */
-void
-vbo_save_playback_vertex_list(struct gl_context *ctx, void *data)
-{
- const struct vbo_save_vertex_list *node =
- (const struct vbo_save_vertex_list *) data;
- struct vbo_save_context *save = &vbo_context(ctx)->save;
-
- FLUSH_CURRENT(ctx, 0);
-
- if (node->prim_count > 0 && node->count > 0) {
-
- if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END &&
- node->prim[0].begin) {
-
- /* Degenerate case: list is called inside begin/end pair and
- * includes operations such as glBegin or glDrawArrays.
- */
- if (0)
- printf("displaylist recursive begin");
-
- vbo_save_loopback_vertex_list( ctx, node );
- return;
- }
- else if (save->replay_flags) {
- /* Various degnerate cases: translate into immediate mode
- * calls rather than trying to execute in place.
- */
- vbo_save_loopback_vertex_list( ctx, node );
- return;
- }
-
- if (ctx->NewState)
- _mesa_update_state( ctx );
-
- /* XXX also need to check if shader enabled, but invalid */
- if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
- (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBegin (invalid vertex/fragment program)");
- return;
- }
-
- vbo_bind_vertex_list( ctx, node );
-
- /* Again...
- */
- if (ctx->NewState)
- _mesa_update_state( ctx );
-
- vbo_context(ctx)->draw_prims(ctx,
- save->inputs,
- node->prim,
- node->prim_count,
- NULL,
- GL_TRUE,
- 0, /* Node is a VBO, so this is ok */
- node->count - 1);
- }
-
- /* Copy to current?
- */
- _playback_copy_to_current( ctx, node );
-}
-
-
-#endif /* FEATURE_dlist */
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.2
+ *
+ * Copyright (C) 1999-2008 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.
+ */
+
+/* Author:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "main/glheader.h"
+#include "main/bufferobj.h"
+#include "main/context.h"
+#include "main/imports.h"
+#include "main/mfeatures.h"
+#include "main/mtypes.h"
+#include "main/macros.h"
+#include "main/light.h"
+#include "main/state.h"
+
+#include "vbo_context.h"
+
+
+#if FEATURE_dlist
+
+
+/**
+ * After playback, copy everything but the position from the
+ * last vertex to the saved state
+ */
+static void
+_playback_copy_to_current(struct gl_context *ctx,
+ const struct vbo_save_vertex_list *node)
+{
+ struct vbo_context *vbo = vbo_context(ctx);
+ GLfloat vertex[VBO_ATTRIB_MAX * 4];
+ GLfloat *data;
+ GLuint i, offset;
+
+ if (node->current_size == 0)
+ return;
+
+ if (node->current_data) {
+ data = node->current_data;
+ }
+ else {
+ data = vertex;
+
+ if (node->count)
+ offset = (node->buffer_offset +
+ (node->count-1) * node->vertex_size * sizeof(GLfloat));
+ else
+ offset = node->buffer_offset;
+
+ ctx->Driver.GetBufferSubData( ctx, 0, offset,
+ node->vertex_size * sizeof(GLfloat),
+ data, node->vertex_store->bufferobj );
+
+ data += node->attrsz[0]; /* skip vertex position */
+ }
+
+ for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
+ if (node->attrsz[i]) {
+ GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
+ GLfloat tmp[4];
+
+ COPY_CLEAN_4V(tmp,
+ node->attrsz[i],
+ data);
+
+ if (memcmp(current, tmp, 4 * sizeof(GLfloat)) != 0) {
+ memcpy(current, tmp, 4 * sizeof(GLfloat));
+
+ vbo->currval[i].Size = node->attrsz[i];
+
+ if (i >= VBO_ATTRIB_FIRST_MATERIAL &&
+ i <= VBO_ATTRIB_LAST_MATERIAL)
+ ctx->NewState |= _NEW_LIGHT;
+
+ ctx->NewState |= _NEW_CURRENT_ATTRIB;
+ }
+
+ data += node->attrsz[i];
+ }
+ }
+
+ /* Colormaterial -- this kindof sucks.
+ */
+ if (ctx->Light.ColorMaterialEnabled) {
+ _mesa_update_color_material(ctx, ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
+ }
+
+ /* CurrentExecPrimitive
+ */
+ if (node->prim_count) {
+ const struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
+ if (prim->end)
+ ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
+ else
+ ctx->Driver.CurrentExecPrimitive = prim->mode;
+ }
+}
+
+
+
+/**
+ * Treat the vertex storage as a VBO, define vertex arrays pointing
+ * into it:
+ */
+static void vbo_bind_vertex_list(struct gl_context *ctx,
+ const struct vbo_save_vertex_list *node)
+{
+ struct vbo_context *vbo = vbo_context(ctx);
+ struct vbo_save_context *save = &vbo->save;
+ struct gl_client_array *arrays = save->arrays;
+ GLuint buffer_offset = node->buffer_offset;
+ const GLuint *map;
+ GLuint attr;
+ GLubyte node_attrsz[VBO_ATTRIB_MAX]; /* copy of node->attrsz[] */
+ GLbitfield varying_inputs = 0x0;
+
+ memcpy(node_attrsz, node->attrsz, sizeof(node->attrsz));
+
+ /* Install the default (ie Current) attributes first, then overlay
+ * all active ones.
+ */
+ switch (get_program_mode(ctx)) {
+ case VP_NONE:
+ for (attr = 0; attr < 16; attr++) {
+ save->inputs[attr] = &vbo->legacy_currval[attr];
+ }
+ for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) {
+ save->inputs[attr + 16] = &vbo->mat_currval[attr];
+ }
+ map = vbo->map_vp_none;
+ break;
+ case VP_NV:
+ case VP_ARB:
+ /* The aliasing of attributes for NV vertex programs has already
+ * occurred. NV vertex programs cannot access material values,
+ * nor attributes greater than VERT_ATTRIB_TEX7.
+ */
+ for (attr = 0; attr < 16; attr++) {
+ save->inputs[attr] = &vbo->legacy_currval[attr];
+ save->inputs[attr + 16] = &vbo->generic_currval[attr];
+ }
+ map = vbo->map_vp_arb;
+
+ /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read.
+ * In that case we effectively need to route the data from
+ * glVertexAttrib(0, val) calls to feed into the GENERIC0 input.
+ */
+ if ((ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_POS) == 0 &&
+ (ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_GENERIC0)) {
+ save->inputs[16] = save->inputs[0];
+ node_attrsz[16] = node_attrsz[0];
+ node_attrsz[0] = 0;
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
+ const GLuint src = map[attr];
+
+ if (node_attrsz[src]) {
+ /* override the default array set above */
+ save->inputs[attr] = &arrays[attr];
+
+ arrays[attr].Ptr = (const GLubyte *) NULL + buffer_offset;
+ arrays[attr].Size = node->attrsz[src];
+ arrays[attr].StrideB = node->vertex_size * sizeof(GLfloat);
+ arrays[attr].Stride = node->vertex_size * sizeof(GLfloat);
+ arrays[attr].Type = GL_FLOAT;
+ arrays[attr].Format = GL_RGBA;
+ arrays[attr].Enabled = 1;
+ _mesa_reference_buffer_object(ctx,
+ &arrays[attr].BufferObj,
+ node->vertex_store->bufferobj);
+ arrays[attr]._MaxElement = node->count; /* ??? */
+
+ assert(arrays[attr].BufferObj->Name);
+
+ buffer_offset += node->attrsz[src] * sizeof(GLfloat);
+ varying_inputs |= 1<<attr;
+ ctx->NewState |= _NEW_ARRAY;
+ }
+ }
+
+ _mesa_set_varying_vp_inputs( ctx, varying_inputs );
+}
+
+
+static void
+vbo_save_loopback_vertex_list(struct gl_context *ctx,
+ const struct vbo_save_vertex_list *list)
+{
+ const char *buffer = ctx->Driver.MapBuffer(ctx,
+ GL_ARRAY_BUFFER_ARB,
+ GL_READ_ONLY, /* ? */
+ list->vertex_store->bufferobj);
+
+ vbo_loopback_vertex_list(ctx,
+ (const GLfloat *)(buffer + list->buffer_offset),
+ list->attrsz,
+ list->prim,
+ list->prim_count,
+ list->wrap_count,
+ list->vertex_size);
+
+ ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB,
+ list->vertex_store->bufferobj);
+}
+
+
+/**
+ * Execute the buffer and save copied verts.
+ * This is called from the display list code when executing
+ * a drawing command.
+ */
+void
+vbo_save_playback_vertex_list(struct gl_context *ctx, void *data)
+{
+ const struct vbo_save_vertex_list *node =
+ (const struct vbo_save_vertex_list *) data;
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+
+ FLUSH_CURRENT(ctx, 0);
+
+ if (node->prim_count > 0 && node->count > 0) {
+
+ if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END &&
+ node->prim[0].begin) {
+
+ /* Degenerate case: list is called inside begin/end pair and
+ * includes operations such as glBegin or glDrawArrays.
+ */
+ if (0)
+ printf("displaylist recursive begin");
+
+ vbo_save_loopback_vertex_list( ctx, node );
+ return;
+ }
+ else if (save->replay_flags) {
+ /* Various degnerate cases: translate into immediate mode
+ * calls rather than trying to execute in place.
+ */
+ vbo_save_loopback_vertex_list( ctx, node );
+ return;
+ }
+
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ /* XXX also need to check if shader enabled, but invalid */
+ if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
+ (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBegin (invalid vertex/fragment program)");
+ return;
+ }
+
+ vbo_bind_vertex_list( ctx, node );
+
+ /* Again...
+ */
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ vbo_context(ctx)->draw_prims(ctx,
+ save->inputs,
+ node->prim,
+ node->prim_count,
+ NULL,
+ GL_TRUE,
+ 0, /* Node is a VBO, so this is ok */
+ node->count - 1);
+ }
+
+ /* Copy to current?
+ */
+ _playback_copy_to_current( ctx, node );
+}
+
+
+#endif /* FEATURE_dlist */