aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src')
-rw-r--r--mesalib/src/mesa/drivers/dri/common/xmlconfig.c20
-rw-r--r--mesalib/src/mesa/main/arrayobj.c2
-rw-r--r--mesalib/src/mesa/main/buffers.c2
-rw-r--r--mesalib/src/mesa/main/texcompress_rgtc.c8
-rw-r--r--mesalib/src/mesa/state_tracker/st_atom_sampler.c11
-rw-r--r--mesalib/src/mesa/state_tracker/st_atom_texture.c650
-rw-r--r--mesalib/src/mesa/state_tracker/st_context.c4
-rw-r--r--mesalib/src/mesa/state_tracker/st_context.h13
-rw-r--r--mesalib/src/mesa/state_tracker/st_draw.c78
-rw-r--r--mesalib/src/mesa/state_tracker/st_draw.h2
-rw-r--r--mesalib/src/mesa/state_tracker/st_draw_feedback.c15
-rw-r--r--mesalib/src/mesa/vbo/vbo_context.c3
-rw-r--r--mesalib/src/mesa/vbo/vbo_exec_api.c2
-rw-r--r--mesalib/src/mesa/vbo/vbo_exec_array.c7
-rw-r--r--mesalib/src/mesa/vbo/vbo_exec_draw.c1
-rw-r--r--mesalib/src/mesa/vbo/vbo_save_draw.c3
-rw-r--r--mesalib/src/mesa/vbo/vbo_split_copy.c1253
17 files changed, 1067 insertions, 1007 deletions
diff --git a/mesalib/src/mesa/drivers/dri/common/xmlconfig.c b/mesalib/src/mesa/drivers/dri/common/xmlconfig.c
index eaba335a4..30075f253 100644
--- a/mesalib/src/mesa/drivers/dri/common/xmlconfig.c
+++ b/mesalib/src/mesa/drivers/dri/common/xmlconfig.c
@@ -64,7 +64,25 @@ extern char *program_invocation_name, *program_invocation_short_name;
the basename to match BSD getprogname() */
# include <stdlib.h>
# include <libgen.h>
-# define GET_PROGRAM_NAME() basename(getexecname())
+
+static const char *__getProgramName () {
+ static const char *progname;
+
+ if (progname == NULL) {
+ const char *e = getexecname();
+ if (e != NULL) {
+ /* Have to make a copy since getexecname can return a readonly
+ string, but basename expects to be able to modify its arg. */
+ char *n = strdup(e);
+ if (n != NULL) {
+ progname = basename(n);
+ }
+ }
+ }
+ return progname;
+}
+
+# define GET_PROGRAM_NAME() __getProgramName()
#endif
#if !defined(GET_PROGRAM_NAME)
diff --git a/mesalib/src/mesa/main/arrayobj.c b/mesalib/src/mesa/main/arrayobj.c
index 8fff3c0e2..ce1e277bd 100644
--- a/mesalib/src/mesa/main/arrayobj.c
+++ b/mesalib/src/mesa/main/arrayobj.c
@@ -41,6 +41,7 @@
#include "glheader.h"
#include "hash.h"
+#include "image.h"
#include "imports.h"
#include "context.h"
#include "mfeatures.h"
@@ -207,6 +208,7 @@ init_array(struct gl_context *ctx,
array->Ptr = NULL;
array->Enabled = GL_FALSE;
array->Normalized = GL_FALSE;
+ array->_ElementSize = size * _mesa_sizeof_type(type);
#if FEATURE_ARB_vertex_buffer_object
/* Vertex array buffers */
_mesa_reference_buffer_object(ctx, &array->BufferObj,
diff --git a/mesalib/src/mesa/main/buffers.c b/mesalib/src/mesa/main/buffers.c
index 1ddf5b2c8..928450f0f 100644
--- a/mesalib/src/mesa/main/buffers.c
+++ b/mesalib/src/mesa/main/buffers.c
@@ -407,7 +407,6 @@ _mesa_drawbuffers(struct gl_context *ctx, GLuint n, const GLenum *buffers,
fb->_ColorDrawBufferIndexes[buf] = bufIndex;
newState = GL_TRUE;
}
- fb->ColorDrawBuffer[buf] = buffers[buf];
count = buf + 1;
}
else {
@@ -416,6 +415,7 @@ _mesa_drawbuffers(struct gl_context *ctx, GLuint n, const GLenum *buffers,
newState = GL_TRUE;
}
}
+ fb->ColorDrawBuffer[buf] = buffers[buf];
}
/* set remaining outputs to -1 (GL_NONE) */
while (buf < ctx->Const.MaxDrawBuffers) {
diff --git a/mesalib/src/mesa/main/texcompress_rgtc.c b/mesalib/src/mesa/main/texcompress_rgtc.c
index 60146d09b..d75546a92 100644
--- a/mesalib/src/mesa/main/texcompress_rgtc.c
+++ b/mesalib/src/mesa/main/texcompress_rgtc.c
@@ -121,7 +121,7 @@ _mesa_texstore_red_rgtc1(TEXSTORE_PARAMS)
texWidth, (GLubyte *) dstAddr);
blkaddr = dst;
- dstRowDiff = dstRowStride >= (srcWidth * 4) ? dstRowStride - (((srcWidth + 3) & ~3) * 4) : 0;
+ dstRowDiff = dstRowStride >= (srcWidth * 2) ? dstRowStride - (((srcWidth + 3) & ~3) * 2) : 0;
for (j = 0; j < srcHeight; j+=4) {
if (srcHeight > j + 3) numypixels = 4;
else numypixels = srcHeight - j;
@@ -176,7 +176,7 @@ _mesa_texstore_signed_red_rgtc1(TEXSTORE_PARAMS)
texWidth, (GLubyte *) dstAddr);
blkaddr = dst;
- dstRowDiff = dstRowStride >= (srcWidth * 4) ? dstRowStride - (((srcWidth + 3) & ~3) * 4) : 0;
+ dstRowDiff = dstRowStride >= (srcWidth * 2) ? dstRowStride - (((srcWidth + 3) & ~3) * 2) : 0;
for (j = 0; j < srcHeight; j+=4) {
if (srcHeight > j + 3) numypixels = 4;
else numypixels = srcHeight - j;
@@ -232,7 +232,7 @@ _mesa_texstore_rg_rgtc2(TEXSTORE_PARAMS)
texWidth, (GLubyte *) dstAddr);
blkaddr = dst;
- dstRowDiff = dstRowStride >= (srcWidth * 8) ? dstRowStride - (((srcWidth + 7) & ~7) * 8) : 0;
+ dstRowDiff = dstRowStride >= (srcWidth * 4) ? dstRowStride - (((srcWidth + 3) & ~3) * 4) : 0;
for (j = 0; j < srcHeight; j+=4) {
if (srcHeight > j + 3) numypixels = 4;
else numypixels = srcHeight - j;
@@ -294,7 +294,7 @@ _mesa_texstore_signed_rg_rgtc2(TEXSTORE_PARAMS)
texWidth, (GLubyte *) dstAddr);
blkaddr = dst;
- dstRowDiff = dstRowStride >= (srcWidth * 8) ? dstRowStride - (((srcWidth + 7) & ~7) * 8) : 0;
+ dstRowDiff = dstRowStride >= (srcWidth * 4) ? dstRowStride - (((srcWidth + 3) & ~3) * 4) : 0;
for (j = 0; j < srcHeight; j += 4) {
if (srcHeight > j + 3) numypixels = 4;
else numypixels = srcHeight - j;
diff --git a/mesalib/src/mesa/state_tracker/st_atom_sampler.c b/mesalib/src/mesa/state_tracker/st_atom_sampler.c
index d1ab1ac3e..48b94500d 100644
--- a/mesalib/src/mesa/state_tracker/st_atom_sampler.c
+++ b/mesalib/src/mesa/state_tracker/st_atom_sampler.c
@@ -166,12 +166,11 @@ update_samplers(struct st_context *st)
sampler->lod_bias = st->ctx->Texture.Unit[texUnit].LodBias +
texobj->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));
+ sampler->min_lod = CLAMP(texobj->MinLod,
+ 0.0f,
+ (GLfloat) texobj->MaxLevel - texobj->BaseLevel);
+ sampler->max_lod = MIN2((GLfloat) texobj->MaxLevel - texobj->BaseLevel,
+ texobj->MaxLod);
if (sampler->max_lod < sampler->min_lod) {
/* The GL spec doesn't seem to specify what to do in this case.
* Swap the values.
diff --git a/mesalib/src/mesa/state_tracker/st_atom_texture.c b/mesalib/src/mesa/state_tracker/st_atom_texture.c
index fd03669e6..04825ba4a 100644
--- a/mesalib/src/mesa/state_tracker/st_atom_texture.c
+++ b/mesalib/src/mesa/state_tracker/st_atom_texture.c
@@ -1,324 +1,326 @@
-/**************************************************************************
- *
- * 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 "program/prog_instruction.h"
-
-#include "st_context.h"
-#include "st_atom.h"
-#include "st_texture.h"
-#include "st_format.h"
-#include "st_cb_texture.h"
-#include "pipe/p_context.h"
-#include "util/u_format.h"
-#include "util/u_inlines.h"
-#include "cso_cache/cso_context.h"
-
-
-/**
- * Combine depth texture mode with "swizzle" so that depth mode swizzling
- * takes place before texture swizzling, and return the resulting swizzle.
- * If the format is not a depth format, return "swizzle" unchanged.
- *
- * \param format PIPE_FORMAT_*.
- * \param swizzle Texture swizzle, a bitmask computed using MAKE_SWIZZLE4.
- * \param depthmode One of GL_LUMINANCE, GL_INTENSITY, GL_ALPHA, GL_RED.
- */
-static GLuint
-apply_depthmode(enum pipe_format format, GLuint swizzle, GLenum depthmode)
-{
- const struct util_format_description *desc =
- util_format_description(format);
- unsigned char swiz[4];
- unsigned i;
-
- if (desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS ||
- desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_NONE) {
- /* Not a depth format. */
- return swizzle;
- }
-
- for (i = 0; i < 4; i++)
- swiz[i] = GET_SWZ(swizzle, i);
-
- switch (depthmode) {
- case GL_LUMINANCE:
- /* Rewrite reads from W to ONE, and reads from XYZ to XXX. */
- for (i = 0; i < 4; i++)
- if (swiz[i] == SWIZZLE_W)
- swiz[i] = SWIZZLE_ONE;
- else if (swiz[i] < SWIZZLE_W)
- swiz[i] = SWIZZLE_X;
- break;
-
- case GL_INTENSITY:
- /* Rewrite reads from XYZW to XXXX. */
- for (i = 0; i < 4; i++)
- if (swiz[i] <= SWIZZLE_W)
- swiz[i] = SWIZZLE_X;
- break;
-
- case GL_ALPHA:
- /* Rewrite reads from W to X, and reads from XYZ to 000. */
- for (i = 0; i < 4; i++)
- if (swiz[i] == SWIZZLE_W)
- swiz[i] = SWIZZLE_X;
- else if (swiz[i] < SWIZZLE_W)
- swiz[i] = SWIZZLE_ZERO;
- break;
- case GL_RED:
- /* Rewrite reads W to 1, XYZ to X00 */
- for (i = 0; i < 4; i++)
- if (swiz[i] == SWIZZLE_W)
- swiz[i] = SWIZZLE_ONE;
- else if (swiz[i] == SWIZZLE_Y || swiz[i] == SWIZZLE_Z)
- swiz[i] = SWIZZLE_ZERO;
- break;
- }
-
- return MAKE_SWIZZLE4(swiz[0], swiz[1], swiz[2], swiz[3]);
-}
-
-
-/**
- * Return TRUE if the swizzling described by "swizzle" and
- * "depthmode" (for depth textures only) is different from the swizzling
- * set in the given sampler view.
- *
- * \param sv A sampler view.
- * \param swizzle Texture swizzle, a bitmask computed using MAKE_SWIZZLE4.
- * \param depthmode One of GL_LUMINANCE, GL_INTENSITY, GL_ALPHA.
- */
-static boolean
-check_sampler_swizzle(struct pipe_sampler_view *sv,
- GLuint swizzle, GLenum depthmode)
-{
- swizzle = apply_depthmode(sv->texture->format, swizzle, depthmode);
-
- if ((sv->swizzle_r != GET_SWZ(swizzle, 0)) ||
- (sv->swizzle_g != GET_SWZ(swizzle, 1)) ||
- (sv->swizzle_b != GET_SWZ(swizzle, 2)) ||
- (sv->swizzle_a != GET_SWZ(swizzle, 3)))
- return TRUE;
- return FALSE;
-}
-
-
-static INLINE struct pipe_sampler_view *
-st_create_texture_sampler_view_from_stobj(struct pipe_context *pipe,
- struct st_texture_object *stObj,
- enum pipe_format format)
-{
- struct pipe_sampler_view templ;
- GLuint swizzle = apply_depthmode(stObj->pt->format,
- stObj->base._Swizzle,
- stObj->base.DepthMode);
-
- u_sampler_view_default_template(&templ,
- stObj->pt,
- format);
-
- if (swizzle != SWIZZLE_NOOP) {
- templ.swizzle_r = GET_SWZ(swizzle, 0);
- templ.swizzle_g = GET_SWZ(swizzle, 1);
- templ.swizzle_b = GET_SWZ(swizzle, 2);
- templ.swizzle_a = GET_SWZ(swizzle, 3);
- }
-
- return pipe->create_sampler_view(pipe, stObj->pt, &templ);
-}
-
-
-static INLINE struct pipe_sampler_view *
-st_get_texture_sampler_view_from_stobj(struct st_texture_object *stObj,
- struct pipe_context *pipe,
- enum pipe_format format)
-{
- if (!stObj || !stObj->pt) {
- return NULL;
- }
-
- if (!stObj->sampler_view) {
- stObj->sampler_view =
- st_create_texture_sampler_view_from_stobj(pipe, stObj, format);
- }
-
- return stObj->sampler_view;
-}
-
-
-static void
-update_textures(struct st_context *st)
-{
- struct pipe_context *pipe = st->pipe;
- 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_textures = 0;
-
- /* loop over sampler units (aka tex image units) */
- for (su = 0; su < st->ctx->Const.MaxTextureImageUnits; su++) {
- struct pipe_sampler_view *sampler_view = NULL;
- enum pipe_format st_view_format;
- if (samplersUsed & (1 << su)) {
- struct gl_texture_object *texObj;
- struct st_texture_object *stObj;
- GLboolean retval;
- 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);
- }
- stObj = st_texture_object(texObj);
-
- retval = st_finalize_texture(st->ctx, st->pipe, texObj);
- if (!retval) {
- /* out of mem */
- continue;
- }
-
- /* Determine the format of the texture sampler view */
- st_view_format = stObj->pt->format;
- {
- const struct st_texture_image *firstImage =
- st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]);
- const gl_format texFormat = firstImage->base.TexFormat;
- enum pipe_format firstImageFormat =
- st_mesa_format_to_pipe_format(texFormat);
-
- if ((stObj->base.sRGBDecode == GL_SKIP_DECODE_EXT) &&
- (_mesa_get_format_color_encoding(texFormat) == GL_SRGB)) {
- /* don't do sRGB->RGB conversion. Interpret the texture
- * texture data as linear values.
- */
- const gl_format linearFormat =
- _mesa_get_srgb_format_linear(texFormat);
- firstImageFormat = st_mesa_format_to_pipe_format(linearFormat);
- }
-
- if (firstImageFormat != stObj->pt->format)
- st_view_format = firstImageFormat;
- }
-
- st->state.num_textures = su + 1;
-
- /* if sampler view has changed dereference it */
- if (stObj->sampler_view)
- if (check_sampler_swizzle(stObj->sampler_view,
- stObj->base._Swizzle,
- stObj->base.DepthMode) ||
- (st_view_format != stObj->sampler_view->format))
- pipe_sampler_view_reference(&stObj->sampler_view, NULL);
-
- sampler_view = st_get_texture_sampler_view_from_stobj(stObj, pipe, st_view_format);
- }
- pipe_sampler_view_reference(&st->state.sampler_views[su], sampler_view);
- }
-
- cso_set_fragment_sampler_views(st->cso_context,
- st->state.num_textures,
- st->state.sampler_views);
- if (st->ctx->Const.MaxVertexTextureImageUnits > 0) {
- cso_set_vertex_sampler_views(st->cso_context,
- MIN2(st->state.num_textures,
- st->ctx->Const.MaxVertexTextureImageUnits),
- st->state.sampler_views);
- }
-}
-
-
-const struct st_tracked_state st_update_texture = {
- "st_update_texture", /* name */
- { /* dirty */
- _NEW_TEXTURE, /* mesa */
- ST_NEW_FRAGMENT_PROGRAM, /* st */
- },
- update_textures /* update */
-};
-
-
-
-
-static void
-finalize_textures(struct st_context *st)
-{
- struct gl_fragment_program *fprog = st->ctx->FragmentProgram._Current;
- const GLboolean prev_missing_textures = st->missing_textures;
- GLuint su;
-
- st->missing_textures = GL_FALSE;
-
- for (su = 0; su < st->ctx->Const.MaxTextureCoordUnits; su++) {
- if (fprog->Base.SamplersUsed & (1 << su)) {
- const GLuint texUnit = fprog->Base.SamplerUnits[su];
- struct gl_texture_object *texObj
- = st->ctx->Texture.Unit[texUnit]._Current;
-
- if (texObj) {
- GLboolean retval;
-
- retval = st_finalize_texture(st->ctx, st->pipe, texObj);
- if (!retval) {
- /* out of mem */
- st->missing_textures = GL_TRUE;
- continue;
- }
- }
- }
- }
-
- if (prev_missing_textures != st->missing_textures)
- st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM;
-}
-
-
-
-const struct st_tracked_state st_finalize_textures = {
- "st_finalize_textures", /* name */
- { /* dirty */
- _NEW_TEXTURE, /* mesa */
- 0, /* st */
- },
- finalize_textures /* 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 "program/prog_instruction.h"
+
+#include "st_context.h"
+#include "st_atom.h"
+#include "st_texture.h"
+#include "st_format.h"
+#include "st_cb_texture.h"
+#include "pipe/p_context.h"
+#include "util/u_format.h"
+#include "util/u_inlines.h"
+#include "cso_cache/cso_context.h"
+
+
+/**
+ * Combine depth texture mode with "swizzle" so that depth mode swizzling
+ * takes place before texture swizzling, and return the resulting swizzle.
+ * If the format is not a depth format, return "swizzle" unchanged.
+ *
+ * \param format PIPE_FORMAT_*.
+ * \param swizzle Texture swizzle, a bitmask computed using MAKE_SWIZZLE4.
+ * \param depthmode One of GL_LUMINANCE, GL_INTENSITY, GL_ALPHA, GL_RED.
+ */
+static GLuint
+apply_depthmode(enum pipe_format format, GLuint swizzle, GLenum depthmode)
+{
+ const struct util_format_description *desc =
+ util_format_description(format);
+ unsigned char swiz[4];
+ unsigned i;
+
+ if (desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS ||
+ desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_NONE) {
+ /* Not a depth format. */
+ return swizzle;
+ }
+
+ for (i = 0; i < 4; i++)
+ swiz[i] = GET_SWZ(swizzle, i);
+
+ switch (depthmode) {
+ case GL_LUMINANCE:
+ /* Rewrite reads from W to ONE, and reads from XYZ to XXX. */
+ for (i = 0; i < 4; i++)
+ if (swiz[i] == SWIZZLE_W)
+ swiz[i] = SWIZZLE_ONE;
+ else if (swiz[i] < SWIZZLE_W)
+ swiz[i] = SWIZZLE_X;
+ break;
+
+ case GL_INTENSITY:
+ /* Rewrite reads from XYZW to XXXX. */
+ for (i = 0; i < 4; i++)
+ if (swiz[i] <= SWIZZLE_W)
+ swiz[i] = SWIZZLE_X;
+ break;
+
+ case GL_ALPHA:
+ /* Rewrite reads from W to X, and reads from XYZ to 000. */
+ for (i = 0; i < 4; i++)
+ if (swiz[i] == SWIZZLE_W)
+ swiz[i] = SWIZZLE_X;
+ else if (swiz[i] < SWIZZLE_W)
+ swiz[i] = SWIZZLE_ZERO;
+ break;
+ case GL_RED:
+ /* Rewrite reads W to 1, XYZ to X00 */
+ for (i = 0; i < 4; i++)
+ if (swiz[i] == SWIZZLE_W)
+ swiz[i] = SWIZZLE_ONE;
+ else if (swiz[i] == SWIZZLE_Y || swiz[i] == SWIZZLE_Z)
+ swiz[i] = SWIZZLE_ZERO;
+ break;
+ }
+
+ return MAKE_SWIZZLE4(swiz[0], swiz[1], swiz[2], swiz[3]);
+}
+
+
+/**
+ * Return TRUE if the swizzling described by "swizzle" and
+ * "depthmode" (for depth textures only) is different from the swizzling
+ * set in the given sampler view.
+ *
+ * \param sv A sampler view.
+ * \param swizzle Texture swizzle, a bitmask computed using MAKE_SWIZZLE4.
+ * \param depthmode One of GL_LUMINANCE, GL_INTENSITY, GL_ALPHA.
+ */
+static boolean
+check_sampler_swizzle(struct pipe_sampler_view *sv,
+ GLuint swizzle, GLenum depthmode)
+{
+ swizzle = apply_depthmode(sv->texture->format, swizzle, depthmode);
+
+ if ((sv->swizzle_r != GET_SWZ(swizzle, 0)) ||
+ (sv->swizzle_g != GET_SWZ(swizzle, 1)) ||
+ (sv->swizzle_b != GET_SWZ(swizzle, 2)) ||
+ (sv->swizzle_a != GET_SWZ(swizzle, 3)))
+ return TRUE;
+ return FALSE;
+}
+
+
+static INLINE struct pipe_sampler_view *
+st_create_texture_sampler_view_from_stobj(struct pipe_context *pipe,
+ struct st_texture_object *stObj,
+ enum pipe_format format)
+{
+ struct pipe_sampler_view templ;
+ GLuint swizzle = apply_depthmode(stObj->pt->format,
+ stObj->base._Swizzle,
+ stObj->base.DepthMode);
+
+ u_sampler_view_default_template(&templ,
+ stObj->pt,
+ format);
+ templ.u.tex.first_level = stObj->base.BaseLevel;
+
+ if (swizzle != SWIZZLE_NOOP) {
+ templ.swizzle_r = GET_SWZ(swizzle, 0);
+ templ.swizzle_g = GET_SWZ(swizzle, 1);
+ templ.swizzle_b = GET_SWZ(swizzle, 2);
+ templ.swizzle_a = GET_SWZ(swizzle, 3);
+ }
+
+ return pipe->create_sampler_view(pipe, stObj->pt, &templ);
+}
+
+
+static INLINE struct pipe_sampler_view *
+st_get_texture_sampler_view_from_stobj(struct st_texture_object *stObj,
+ struct pipe_context *pipe,
+ enum pipe_format format)
+{
+ if (!stObj || !stObj->pt) {
+ return NULL;
+ }
+
+ if (!stObj->sampler_view) {
+ stObj->sampler_view =
+ st_create_texture_sampler_view_from_stobj(pipe, stObj, format);
+ }
+
+ return stObj->sampler_view;
+}
+
+
+static void
+update_textures(struct st_context *st)
+{
+ struct pipe_context *pipe = st->pipe;
+ 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_textures = 0;
+
+ /* loop over sampler units (aka tex image units) */
+ for (su = 0; su < st->ctx->Const.MaxTextureImageUnits; su++) {
+ struct pipe_sampler_view *sampler_view = NULL;
+ enum pipe_format st_view_format;
+ if (samplersUsed & (1 << su)) {
+ struct gl_texture_object *texObj;
+ struct st_texture_object *stObj;
+ GLboolean retval;
+ 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);
+ }
+ stObj = st_texture_object(texObj);
+
+ retval = st_finalize_texture(st->ctx, st->pipe, texObj);
+ if (!retval) {
+ /* out of mem */
+ continue;
+ }
+
+ /* Determine the format of the texture sampler view */
+ st_view_format = stObj->pt->format;
+ {
+ const struct st_texture_image *firstImage =
+ st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]);
+ const gl_format texFormat = firstImage->base.TexFormat;
+ enum pipe_format firstImageFormat =
+ st_mesa_format_to_pipe_format(texFormat);
+
+ if ((stObj->base.sRGBDecode == GL_SKIP_DECODE_EXT) &&
+ (_mesa_get_format_color_encoding(texFormat) == GL_SRGB)) {
+ /* don't do sRGB->RGB conversion. Interpret the texture
+ * texture data as linear values.
+ */
+ const gl_format linearFormat =
+ _mesa_get_srgb_format_linear(texFormat);
+ firstImageFormat = st_mesa_format_to_pipe_format(linearFormat);
+ }
+
+ if (firstImageFormat != stObj->pt->format)
+ st_view_format = firstImageFormat;
+ }
+
+ st->state.num_textures = su + 1;
+
+ /* if sampler view has changed dereference it */
+ if (stObj->sampler_view)
+ if (check_sampler_swizzle(stObj->sampler_view,
+ stObj->base._Swizzle,
+ stObj->base.DepthMode) ||
+ (st_view_format != stObj->sampler_view->format) ||
+ stObj->base.BaseLevel != stObj->sampler_view->u.tex.first_level)
+ pipe_sampler_view_reference(&stObj->sampler_view, NULL);
+
+ sampler_view = st_get_texture_sampler_view_from_stobj(stObj, pipe, st_view_format);
+ }
+ pipe_sampler_view_reference(&st->state.sampler_views[su], sampler_view);
+ }
+
+ cso_set_fragment_sampler_views(st->cso_context,
+ st->state.num_textures,
+ st->state.sampler_views);
+ if (st->ctx->Const.MaxVertexTextureImageUnits > 0) {
+ cso_set_vertex_sampler_views(st->cso_context,
+ MIN2(st->state.num_textures,
+ st->ctx->Const.MaxVertexTextureImageUnits),
+ st->state.sampler_views);
+ }
+}
+
+
+const struct st_tracked_state st_update_texture = {
+ "st_update_texture", /* name */
+ { /* dirty */
+ _NEW_TEXTURE, /* mesa */
+ ST_NEW_FRAGMENT_PROGRAM, /* st */
+ },
+ update_textures /* update */
+};
+
+
+
+
+static void
+finalize_textures(struct st_context *st)
+{
+ struct gl_fragment_program *fprog = st->ctx->FragmentProgram._Current;
+ const GLboolean prev_missing_textures = st->missing_textures;
+ GLuint su;
+
+ st->missing_textures = GL_FALSE;
+
+ for (su = 0; su < st->ctx->Const.MaxTextureCoordUnits; su++) {
+ if (fprog->Base.SamplersUsed & (1 << su)) {
+ const GLuint texUnit = fprog->Base.SamplerUnits[su];
+ struct gl_texture_object *texObj
+ = st->ctx->Texture.Unit[texUnit]._Current;
+
+ if (texObj) {
+ GLboolean retval;
+
+ retval = st_finalize_texture(st->ctx, st->pipe, texObj);
+ if (!retval) {
+ /* out of mem */
+ st->missing_textures = GL_TRUE;
+ continue;
+ }
+ }
+ }
+ }
+
+ if (prev_missing_textures != st->missing_textures)
+ st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM;
+}
+
+
+
+const struct st_tracked_state st_finalize_textures = {
+ "st_finalize_textures", /* name */
+ { /* dirty */
+ _NEW_TEXTURE, /* mesa */
+ 0, /* st */
+ },
+ finalize_textures /* update */
+};
diff --git a/mesalib/src/mesa/state_tracker/st_context.c b/mesalib/src/mesa/state_tracker/st_context.c
index afd85f0de..458968486 100644
--- a/mesalib/src/mesa/state_tracker/st_context.c
+++ b/mesalib/src/mesa/state_tracker/st_context.c
@@ -206,8 +206,8 @@ static void st_destroy_context_priv( struct st_context *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 < st->num_user_attribs; i++) {
+ pipe_resource_reference(&st->user_attrib[i].buffer, NULL);
}
for (i = 0; i < Elements(st->state.sampler_views); i++) {
diff --git a/mesalib/src/mesa/state_tracker/st_context.h b/mesalib/src/mesa/state_tracker/st_context.h
index ef54fd7cd..a35439741 100644
--- a/mesalib/src/mesa/state_tracker/st_context.h
+++ b/mesalib/src/mesa/state_tracker/st_context.h
@@ -187,9 +187,16 @@ struct st_context
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;
+ struct {
+ struct pipe_resource *buffer;
+
+ /** Element size */
+ GLuint element_size;
+
+ /** Attribute stride */
+ GLsizei stride;
+ } user_attrib[PIPE_MAX_ATTRIBS];
+ unsigned num_user_attribs;
};
diff --git a/mesalib/src/mesa/state_tracker/st_draw.c b/mesalib/src/mesa/state_tracker/st_draw.c
index 52e46d628..61e127776 100644
--- a/mesalib/src/mesa/state_tracker/st_draw.c
+++ b/mesalib/src/mesa/state_tracker/st_draw.c
@@ -329,8 +329,12 @@ setup_interleaved_attribs(struct gl_context *ctx,
const struct gl_client_array *array = arrays[mesaAttr];
struct gl_buffer_object *bufobj = array->BufferObj;
struct st_buffer_object *stobj = st_buffer_object(bufobj);
+ unsigned src_offset = (unsigned) (array->Ptr - low_addr);
+ GLuint element_size = array->_ElementSize;
GLsizei stride = array->StrideB;
+ assert(element_size == array->Size * _mesa_sizeof_type(array->Type));
+
if (attr == 0) {
if (bufobj && bufobj->Name) {
vbuffer->buffer = NULL;
@@ -339,22 +343,25 @@ setup_interleaved_attribs(struct gl_context *ctx,
}
else {
uint divisor = array->InstanceDivisor;
- uint length = (divisor ? num_instances / divisor : max_index) + 1;
+ uint last_index = divisor ? num_instances / divisor : max_index;
+ uint bytes = src_offset + stride * last_index + element_size;
+
vbuffer->buffer = pipe_user_buffer_create(pipe->screen,
(void*) low_addr,
- stride * length,
+ bytes,
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;
+ pipe_resource_reference(&st->user_attrib[0].buffer, vbuffer->buffer);
+ st->user_attrib[0].element_size = element_size;
+ st->user_attrib[0].stride = stride;
+ st->num_user_attribs = 1;
}
vbuffer->stride = stride; /* in bytes */
}
- velements[attr].src_offset = (unsigned) (array->Ptr - low_addr);
+ velements[attr].src_offset = src_offset;
velements[attr].instance_divisor = array->InstanceDivisor;
velements[attr].vertex_buffer_index = 0;
velements[attr].src_format = st_pipe_vertex_format(array->Type,
@@ -390,8 +397,11 @@ setup_non_interleaved_attribs(struct gl_context *ctx,
const GLuint mesaAttr = vp->index_to_input[attr];
const struct gl_client_array *array = arrays[mesaAttr];
struct gl_buffer_object *bufobj = array->BufferObj;
+ GLuint element_size = array->_ElementSize;
GLsizei stride = array->StrideB;
+ assert(element_size == array->Size * _mesa_sizeof_type(array->Type));
+
if (bufobj && bufobj->Name) {
/* Attribute data is in a VBO.
* Recall that for VBOs, the gl_client_array->Ptr field is
@@ -410,20 +420,16 @@ setup_non_interleaved_attribs(struct gl_context *ctx,
void *ptr;
if (array->Ptr) {
- if (stride == 0) {
- bytes = _mesa_sizeof_type(array->Type) * array->Size;
- }
- else {
- uint divisor = array->InstanceDivisor;
- uint length = (divisor ? num_instances / divisor : max_index) + 1;
- bytes = stride * length;
- }
+ uint divisor = array->InstanceDivisor;
+ uint last_index = divisor ? num_instances / divisor : max_index;
+
+ bytes = stride * last_index + element_size;
ptr = (void *) array->Ptr;
}
else {
/* no array, use ctx->Current.Attrib[] value */
- bytes = sizeof(ctx->Current.Attrib[0]);
+ bytes = element_size = sizeof(ctx->Current.Attrib[0]);
ptr = (void *) ctx->Current.Attrib[mesaAttr];
stride = 0;
}
@@ -438,9 +444,10 @@ setup_non_interleaved_attribs(struct gl_context *ctx,
vbuffer[attr].buffer_offset = 0;
/* Track user vertex buffers. */
- pipe_resource_reference(&st->user_vb[attr], vbuffer[attr].buffer);
- st->user_vb_stride[attr] = stride;
- st->num_user_vbs = MAX2(st->num_user_vbs, attr+1);
+ pipe_resource_reference(&st->user_attrib[attr].buffer, vbuffer[attr].buffer);
+ st->user_attrib[attr].element_size = element_size;
+ st->user_attrib[attr].stride = stride;
+ st->num_user_attribs = MAX2(st->num_user_attribs, attr + 1);
}
/* common-case setup */
@@ -583,10 +590,10 @@ st_validate_varrays(struct gl_context *ctx,
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);
+ for (i = 0; i < st->num_user_attribs; i++) {
+ pipe_resource_reference(&st->user_attrib[i].buffer, NULL);
}
- st->num_user_vbs = 0;
+ st->num_user_attribs = 0;
/*
* Setup the vbuffer[] and velements[] arrays.
@@ -700,21 +707,20 @@ st_draw_vbo(struct gl_context *ctx,
/* 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);
- }
+ assert(max_index >= min_index);
+ if (!new_array && st->num_user_attribs) {
+ for (i = 0; i < st->num_user_attribs; i++) {
+ if (st->user_attrib[i].buffer) {
+ unsigned element_size = st->user_attrib[i].element_size;
+ unsigned stride = st->user_attrib[i].stride;
+ unsigned min_offset = min_index * stride;
+ unsigned max_offset = max_index * stride + element_size;
+
+ assert(max_offset > min_offset);
+
+ pipe->redefine_user_buffer(pipe, st->user_attrib[i].buffer,
+ min_offset,
+ max_offset - min_offset);
}
}
}
diff --git a/mesalib/src/mesa/state_tracker/st_draw.h b/mesalib/src/mesa/state_tracker/st_draw.h
index 6c8b78c76..23e1c7821 100644
--- a/mesalib/src/mesa/state_tracker/st_draw.h
+++ b/mesalib/src/mesa/state_tracker/st_draw.h
@@ -69,7 +69,7 @@ st_feedback_draw_vbo(struct gl_context *ctx,
/* Internal function:
*/
-extern GLuint
+extern enum pipe_format
st_pipe_vertex_format(GLenum type, GLuint size, GLenum format,
GLboolean normalized);
diff --git a/mesalib/src/mesa/state_tracker/st_draw_feedback.c b/mesalib/src/mesa/state_tracker/st_draw_feedback.c
index f0734eae0..bbf2ef67e 100644
--- a/mesalib/src/mesa/state_tracker/st_draw_feedback.c
+++ b/mesalib/src/mesa/state_tracker/st_draw_feedback.c
@@ -111,6 +111,7 @@ st_feedback_draw_vbo(struct gl_context *ctx,
struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS];
struct pipe_transfer *ib_transfer = NULL;
GLuint attr, i;
+ const GLubyte *low_addr = NULL;
const void *mapped_indices = NULL;
assert(draw);
@@ -141,6 +142,16 @@ st_feedback_draw_vbo(struct gl_context *ctx,
draw_bind_vertex_shader(draw, st->vp_variant->draw_shader);
set_feedback_vertex_format(ctx);
+ /* Find the lowest address of the arrays we're drawing */
+ if (vp->num_inputs) {
+ low_addr = arrays[vp->index_to_input[0]]->Ptr;
+
+ for (attr = 1; attr < vp->num_inputs; attr++) {
+ const GLubyte *start = arrays[vp->index_to_input[attr]]->Ptr;
+ low_addr = MIN2(low_addr, start);
+ }
+ }
+
/* loop over TGSI shader inputs to determine vertex buffer
* and attribute info
*/
@@ -159,8 +170,8 @@ st_feedback_draw_vbo(struct gl_context *ctx,
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;
+ vbuffers[attr].buffer_offset = pointer_to_offset(low_addr);
+ velements[attr].src_offset = arrays[mesaAttr]->Ptr - low_addr;
}
else {
/* attribute data is in user-space memory, not a VBO */
diff --git a/mesalib/src/mesa/vbo/vbo_context.c b/mesalib/src/mesa/vbo/vbo_context.c
index bbf422f74..5f03ce547 100644
--- a/mesalib/src/mesa/vbo/vbo_context.c
+++ b/mesalib/src/mesa/vbo/vbo_context.c
@@ -72,6 +72,7 @@ static void init_legacy_currval(struct gl_context *ctx)
cl->Type = GL_FLOAT;
cl->Format = GL_RGBA;
cl->Ptr = (const void *)ctx->Current.Attrib[i];
+ cl->_ElementSize = cl->Size * sizeof(GLfloat);
_mesa_reference_buffer_object(ctx, &cl->BufferObj,
ctx->Shared->NullBufferObj);
}
@@ -98,6 +99,7 @@ static void init_generic_currval(struct gl_context *ctx)
cl->Stride = 0;
cl->StrideB = 0;
cl->Enabled = 1;
+ cl->_ElementSize = cl->Size * sizeof(GLfloat);
_mesa_reference_buffer_object(ctx, &cl->BufferObj,
ctx->Shared->NullBufferObj);
}
@@ -143,6 +145,7 @@ static void init_mat_currval(struct gl_context *ctx)
cl->Stride = 0;
cl->StrideB = 0;
cl->Enabled = 1;
+ cl->_ElementSize = cl->Size * sizeof(GLfloat);
_mesa_reference_buffer_object(ctx, &cl->BufferObj,
ctx->Shared->NullBufferObj);
}
diff --git a/mesalib/src/mesa/vbo/vbo_exec_api.c b/mesalib/src/mesa/vbo/vbo_exec_api.c
index 790310903..6b919e8b4 100644
--- a/mesalib/src/mesa/vbo/vbo_exec_api.c
+++ b/mesalib/src/mesa/vbo/vbo_exec_api.c
@@ -168,6 +168,8 @@ static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
* directly.
*/
vbo->currval[i].Size = exec->vtx.attrsz[i];
+ assert(vbo->currval[i].Type == GL_FLOAT);
+ vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat);
/* This triggers rather too much recalculation of Mesa state
* that doesn't get used (eg light positions).
diff --git a/mesalib/src/mesa/vbo/vbo_exec_array.c b/mesalib/src/mesa/vbo/vbo_exec_array.c
index 37656c23a..a189ab76b 100644
--- a/mesalib/src/mesa/vbo/vbo_exec_array.c
+++ b/mesalib/src/mesa/vbo/vbo_exec_array.c
@@ -943,8 +943,13 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
/* Set 'end' to the max possible legal value */
assert(ctx->Array.ArrayObj->_MaxElement >= 1);
end = ctx->Array.ArrayObj->_MaxElement - 1;
+
+ if (end < start) {
+ return;
+ }
}
- else if (0) {
+
+ if (0) {
printf("glDraw[Range]Elements{,BaseVertex}"
"(start %u, end %u, type 0x%x, count %d) ElemBuf %u, "
"base %d\n",
diff --git a/mesalib/src/mesa/vbo/vbo_exec_draw.c b/mesalib/src/mesa/vbo/vbo_exec_draw.c
index 7cc843779..98f585792 100644
--- a/mesalib/src/mesa/vbo/vbo_exec_draw.c
+++ b/mesalib/src/mesa/vbo/vbo_exec_draw.c
@@ -239,6 +239,7 @@ vbo_exec_bind_arrays( struct gl_context *ctx )
arrays[attr].Type = GL_FLOAT;
arrays[attr].Format = GL_RGBA;
arrays[attr].Enabled = 1;
+ arrays[attr]._ElementSize = arrays[attr].Size * sizeof(GLfloat);
_mesa_reference_buffer_object(ctx,
&arrays[attr].BufferObj,
exec->vtx.bufferobj);
diff --git a/mesalib/src/mesa/vbo/vbo_save_draw.c b/mesalib/src/mesa/vbo/vbo_save_draw.c
index 5a19b0d62..d0f627a35 100644
--- a/mesalib/src/mesa/vbo/vbo_save_draw.c
+++ b/mesalib/src/mesa/vbo/vbo_save_draw.c
@@ -90,6 +90,8 @@ _playback_copy_to_current(struct gl_context *ctx,
memcpy(current, tmp, 4 * sizeof(GLfloat));
vbo->currval[i].Size = node->attrsz[i];
+ assert(vbo->currval[i].Type == GL_FLOAT);
+ vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat);
if (i >= VBO_ATTRIB_FIRST_MATERIAL &&
i <= VBO_ATTRIB_LAST_MATERIAL)
@@ -193,6 +195,7 @@ static void vbo_bind_vertex_list(struct gl_context *ctx,
arrays[attr].Type = GL_FLOAT;
arrays[attr].Format = GL_RGBA;
arrays[attr].Enabled = 1;
+ arrays[attr]._ElementSize = arrays[attr].Size * sizeof(GLfloat);
_mesa_reference_buffer_object(ctx,
&arrays[attr].BufferObj,
node->vertex_store->bufferobj);
diff --git a/mesalib/src/mesa/vbo/vbo_split_copy.c b/mesalib/src/mesa/vbo/vbo_split_copy.c
index 8c981f93e..3a869d712 100644
--- a/mesalib/src/mesa/vbo/vbo_split_copy.c
+++ b/mesalib/src/mesa/vbo/vbo_split_copy.c
@@ -1,626 +1,627 @@
-
-/*
- * Mesa 3-D graphics library
- * Version: 6.5
- *
- * 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.
- *
- * Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
- */
-
-/* Split indexed primitives with per-vertex copying.
- */
-
-#include "main/glheader.h"
-#include "main/bufferobj.h"
-#include "main/imports.h"
-#include "main/image.h"
-#include "main/macros.h"
-#include "main/mtypes.h"
-
-#include "vbo_split.h"
-#include "vbo.h"
-
-
-#define ELT_TABLE_SIZE 16
-
-/**
- * Used for vertex-level splitting of indexed buffers. Note that
- * non-indexed primitives may be converted to indexed in some cases
- * (eg loops, fans) in order to use this splitting path.
- */
-struct copy_context {
-
- struct gl_context *ctx;
- const struct gl_client_array **array;
- const struct _mesa_prim *prim;
- GLuint nr_prims;
- const struct _mesa_index_buffer *ib;
- vbo_draw_func draw;
-
- const struct split_limits *limits;
-
- struct {
- GLuint attr;
- GLuint size;
- const struct gl_client_array *array;
- const GLubyte *src_ptr;
-
- struct gl_client_array dstarray;
-
- } varying[VERT_ATTRIB_MAX];
- GLuint nr_varying;
-
- const struct gl_client_array *dstarray_ptr[VERT_ATTRIB_MAX];
- struct _mesa_index_buffer dstib;
-
- GLuint *translated_elt_buf;
- const GLuint *srcelt;
-
- /** A baby hash table to avoid re-emitting (some) duplicate
- * vertices when splitting indexed primitives.
- */
- struct {
- GLuint in;
- GLuint out;
- } vert_cache[ELT_TABLE_SIZE];
-
- GLuint vertex_size;
- GLubyte *dstbuf;
- GLubyte *dstptr; /**< dstptr == dstbuf + dstelt_max * vertsize */
- GLuint dstbuf_size; /**< in vertices */
- GLuint dstbuf_nr; /**< count of emitted vertices, also the largest value
- * in dstelt. Our MaxIndex.
- */
-
- GLuint *dstelt;
- GLuint dstelt_nr;
- GLuint dstelt_size;
-
-#define MAX_PRIM 32
- struct _mesa_prim dstprim[MAX_PRIM];
- GLuint dstprim_nr;
-
-};
-
-
-static GLuint attr_size( const struct gl_client_array *array )
-{
- return array->Size * _mesa_sizeof_type(array->Type);
-}
-
-
-/**
- * Starts returning true slightly before the buffer fills, to ensure
- * that there is sufficient room for any remaining vertices to finish
- * off the prim:
- */
-static GLboolean
-check_flush( struct copy_context *copy )
-{
- GLenum mode = copy->dstprim[copy->dstprim_nr].mode;
-
- if (GL_TRIANGLE_STRIP == mode &&
- copy->dstelt_nr & 1) { /* see bug9962 */
- return GL_FALSE;
- }
-
- if (copy->dstbuf_nr + 4 > copy->dstbuf_size)
- return GL_TRUE;
-
- if (copy->dstelt_nr + 4 > copy->dstelt_size)
- return GL_TRUE;
-
- return GL_FALSE;
-}
-
-
-/**
- * Dump the parameters/info for a vbo->draw() call.
- */
-static void
-dump_draw_info(struct gl_context *ctx,
- const struct gl_client_array **arrays,
- const struct _mesa_prim *prims,
- GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
- GLuint min_index,
- GLuint max_index)
-{
- GLuint i, j;
-
- printf("VBO Draw:\n");
- for (i = 0; i < nr_prims; i++) {
- printf("Prim %u of %u\n", i, nr_prims);
- printf(" Prim mode 0x%x\n", prims[i].mode);
- printf(" IB: %p\n", (void*) ib);
- for (j = 0; j < VERT_ATTRIB_MAX; j++) {
- printf(" array %d at %p:\n", j, (void*) arrays[j]);
- printf(" enabled %d, ptr %p, size %d, type 0x%x, stride %d\n",
- arrays[j]->Enabled, arrays[j]->Ptr,
- arrays[j]->Size, arrays[j]->Type, arrays[j]->StrideB);
- if (0) {
- GLint k = prims[i].start + prims[i].count - 1;
- GLfloat *last = (GLfloat *) (arrays[j]->Ptr + arrays[j]->Stride * k);
- printf(" last: %f %f %f\n",
- last[0], last[1], last[2]);
- }
- }
- }
-}
-
-
-static void
-flush( struct copy_context *copy )
-{
- GLuint i;
-
- /* Set some counters:
- */
- copy->dstib.count = copy->dstelt_nr;
-
-#if 0
- dump_draw_info(copy->ctx,
- copy->dstarray_ptr,
- copy->dstprim,
- copy->dstprim_nr,
- &copy->dstib,
- 0,
- copy->dstbuf_nr);
-#else
- (void) dump_draw_info;
-#endif
-
- copy->draw( copy->ctx,
- copy->dstarray_ptr,
- copy->dstprim,
- copy->dstprim_nr,
- &copy->dstib,
- GL_TRUE,
- 0,
- copy->dstbuf_nr - 1 );
-
- /* Reset all pointers:
- */
- copy->dstprim_nr = 0;
- copy->dstelt_nr = 0;
- copy->dstbuf_nr = 0;
- copy->dstptr = copy->dstbuf;
-
- /* Clear the vertex cache:
- */
- for (i = 0; i < ELT_TABLE_SIZE; i++)
- copy->vert_cache[i].in = ~0;
-}
-
-
-/**
- * Called at begin of each primitive during replay.
- */
-static void
-begin( struct copy_context *copy, GLenum mode, GLboolean begin_flag )
-{
- struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
-
- prim->mode = mode;
- prim->begin = begin_flag;
- prim->num_instances = 1;
-}
-
-
-/**
- * Use a hashtable to attempt to identify recently-emitted vertices
- * and avoid re-emitting them.
- */
-static GLuint
-elt(struct copy_context *copy, GLuint elt_idx)
-{
- GLuint elt = copy->srcelt[elt_idx];
- GLuint slot = elt & (ELT_TABLE_SIZE-1);
-
-/* printf("elt %d\n", elt); */
-
- /* Look up the incoming element in the vertex cache. Re-emit if
- * necessary.
- */
- if (copy->vert_cache[slot].in != elt) {
- GLubyte *csr = copy->dstptr;
- GLuint i;
-
-/* printf(" --> emit to dstelt %d\n", copy->dstbuf_nr); */
-
- for (i = 0; i < copy->nr_varying; i++) {
- const struct gl_client_array *srcarray = copy->varying[i].array;
- const GLubyte *srcptr = copy->varying[i].src_ptr + elt * srcarray->StrideB;
-
- memcpy(csr, srcptr, copy->varying[i].size);
- csr += copy->varying[i].size;
-
-#ifdef NAN_CHECK
- if (srcarray->Type == GL_FLOAT) {
- GLuint k;
- GLfloat *f = (GLfloat *) srcptr;
- for (k = 0; k < srcarray->Size; k++) {
- assert(!IS_INF_OR_NAN(f[k]));
- assert(f[k] <= 1.0e20 && f[k] >= -1.0e20);
- }
- }
-#endif
-
- if (0)
- {
- const GLuint *f = (const GLuint *)srcptr;
- GLuint j;
- printf(" varying %d: ", i);
- for(j = 0; j < copy->varying[i].size / 4; j++)
- printf("%x ", f[j]);
- printf("\n");
- }
- }
-
- copy->vert_cache[slot].in = elt;
- copy->vert_cache[slot].out = copy->dstbuf_nr++;
- copy->dstptr += copy->vertex_size;
-
- assert(csr == copy->dstptr);
- assert(copy->dstptr == (copy->dstbuf +
- copy->dstbuf_nr * copy->vertex_size));
- }
-/* else */
-/* printf(" --> reuse vertex\n"); */
-
-/* printf(" --> emit %d\n", copy->vert_cache[slot].out); */
- copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out;
- return check_flush(copy);
-}
-
-
-/**
- * Called at end of each primitive during replay.
- */
-static void
-end( struct copy_context *copy, GLboolean end_flag )
-{
- struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
-
-/* printf("end (%d)\n", end_flag); */
-
- prim->end = end_flag;
- prim->count = copy->dstelt_nr - prim->start;
-
- if (++copy->dstprim_nr == MAX_PRIM ||
- check_flush(copy))
- flush(copy);
-}
-
-
-static void
-replay_elts( struct copy_context *copy )
-{
- GLuint i, j, k;
- GLboolean split;
-
- for (i = 0; i < copy->nr_prims; i++) {
- const struct _mesa_prim *prim = &copy->prim[i];
- const GLuint start = prim->start;
- GLuint first, incr;
-
- switch (prim->mode) {
-
- case GL_LINE_LOOP:
- /* Convert to linestrip and emit the final vertex explicitly,
- * but only in the resultant strip that requires it.
- */
- j = 0;
- while (j != prim->count) {
- begin(copy, GL_LINE_STRIP, prim->begin && j == 0);
-
- for (split = GL_FALSE; j != prim->count && !split; j++)
- split = elt(copy, start + j);
-
- if (j == prim->count) {
- /* Done, emit final line. Split doesn't matter as
- * it is always raised a bit early so we can emit
- * the last verts if necessary!
- */
- if (prim->end)
- (void)elt(copy, start + 0);
-
- end(copy, prim->end);
- }
- else {
- /* Wrap
- */
- assert(split);
- end(copy, 0);
- j--;
- }
- }
- break;
-
- case GL_TRIANGLE_FAN:
- case GL_POLYGON:
- j = 2;
- while (j != prim->count) {
- begin(copy, prim->mode, prim->begin && j == 0);
-
- split = elt(copy, start+0);
- assert(!split);
-
- split = elt(copy, start+j-1);
- assert(!split);
-
- for (; j != prim->count && !split; j++)
- split = elt(copy, start+j);
-
- end(copy, prim->end && j == prim->count);
-
- if (j != prim->count) {
- /* Wrapped the primitive, need to repeat some vertices:
- */
- j -= 1;
- }
- }
- break;
-
- default:
- (void)split_prim_inplace(prim->mode, &first, &incr);
-
- j = 0;
- while (j != prim->count) {
-
- begin(copy, prim->mode, prim->begin && j == 0);
-
- split = 0;
- for (k = 0; k < first; k++, j++)
- split |= elt(copy, start+j);
-
- assert(!split);
-
- for (; j != prim->count && !split; )
- for (k = 0; k < incr; k++, j++)
- split |= elt(copy, start+j);
-
- end(copy, prim->end && j == prim->count);
-
- if (j != prim->count) {
- /* Wrapped the primitive, need to repeat some vertices:
- */
- assert(j > first - incr);
- j -= (first - incr);
- }
- }
- break;
- }
- }
-
- if (copy->dstprim_nr)
- flush(copy);
-}
-
-
-static void
-replay_init( struct copy_context *copy )
-{
- struct gl_context *ctx = copy->ctx;
- GLuint i;
- GLuint offset;
- const GLvoid *srcptr;
-
- /* Make a list of varying attributes and their vbo's. Also
- * calculate vertex size.
- */
- copy->vertex_size = 0;
- for (i = 0; i < VERT_ATTRIB_MAX; i++) {
- struct gl_buffer_object *vbo = copy->array[i]->BufferObj;
-
- if (copy->array[i]->StrideB == 0) {
- copy->dstarray_ptr[i] = copy->array[i];
- }
- else {
- GLuint j = copy->nr_varying++;
-
- copy->varying[j].attr = i;
- copy->varying[j].array = copy->array[i];
- copy->varying[j].size = attr_size(copy->array[i]);
- copy->vertex_size += attr_size(copy->array[i]);
-
- if (_mesa_is_bufferobj(vbo) && !_mesa_bufferobj_mapped(vbo))
- ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER, GL_READ_ONLY, vbo);
-
- copy->varying[j].src_ptr = ADD_POINTERS(vbo->Pointer,
- copy->array[i]->Ptr);
-
- copy->dstarray_ptr[i] = &copy->varying[j].dstarray;
- }
- }
-
- /* There must always be an index buffer. Currently require the
- * caller convert non-indexed prims to indexed. Could alternately
- * do it internally.
- */
- if (_mesa_is_bufferobj(copy->ib->obj) &&
- !_mesa_bufferobj_mapped(copy->ib->obj))
- ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY,
- copy->ib->obj);
-
- srcptr = (const GLubyte *) ADD_POINTERS(copy->ib->obj->Pointer,
- copy->ib->ptr);
-
- switch (copy->ib->type) {
- case GL_UNSIGNED_BYTE:
- copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
- copy->srcelt = copy->translated_elt_buf;
-
- for (i = 0; i < copy->ib->count; i++)
- copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i];
- break;
-
- case GL_UNSIGNED_SHORT:
- copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
- copy->srcelt = copy->translated_elt_buf;
-
- for (i = 0; i < copy->ib->count; i++)
- copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i];
- break;
-
- case GL_UNSIGNED_INT:
- copy->translated_elt_buf = NULL;
- copy->srcelt = (const GLuint *)srcptr;
- break;
- }
-
- /* Figure out the maximum allowed vertex buffer size:
- */
- if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) {
- copy->dstbuf_size = copy->limits->max_verts;
- }
- else {
- copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size;
- }
-
- /* Allocate an output vertex buffer:
- *
- * XXX: This should be a VBO!
- */
- copy->dstbuf = malloc(copy->dstbuf_size * copy->vertex_size);
- copy->dstptr = copy->dstbuf;
-
- /* Setup new vertex arrays to point into the output buffer:
- */
- for (offset = 0, i = 0; i < copy->nr_varying; i++) {
- const struct gl_client_array *src = copy->varying[i].array;
- struct gl_client_array *dst = &copy->varying[i].dstarray;
-
- dst->Size = src->Size;
- dst->Type = src->Type;
- dst->Format = GL_RGBA;
- dst->Stride = copy->vertex_size;
- dst->StrideB = copy->vertex_size;
- dst->Ptr = copy->dstbuf + offset;
- dst->Enabled = GL_TRUE;
- dst->Normalized = src->Normalized;
- dst->BufferObj = ctx->Shared->NullBufferObj;
- dst->_MaxElement = copy->dstbuf_size; /* may be less! */
-
- offset += copy->varying[i].size;
- }
-
- /* Allocate an output element list:
- */
- copy->dstelt_size = MIN2(65536,
- copy->ib->count * 2 + 3);
- copy->dstelt_size = MIN2(copy->dstelt_size,
- copy->limits->max_indices);
- copy->dstelt = malloc(sizeof(GLuint) * copy->dstelt_size);
- copy->dstelt_nr = 0;
-
- /* Setup the new index buffer to point to the allocated element
- * list:
- */
- copy->dstib.count = 0; /* duplicates dstelt_nr */
- copy->dstib.type = GL_UNSIGNED_INT;
- copy->dstib.obj = ctx->Shared->NullBufferObj;
- copy->dstib.ptr = copy->dstelt;
-}
-
-
-/**
- * Free up everything allocated during split/replay.
- */
-static void
-replay_finish( struct copy_context *copy )
-{
- struct gl_context *ctx = copy->ctx;
- GLuint i;
-
- /* Free our vertex and index buffers:
- */
- free(copy->translated_elt_buf);
- free(copy->dstbuf);
- free(copy->dstelt);
-
- /* Unmap VBO's
- */
- for (i = 0; i < copy->nr_varying; i++) {
- struct gl_buffer_object *vbo = copy->varying[i].array->BufferObj;
- if (_mesa_is_bufferobj(vbo) && _mesa_bufferobj_mapped(vbo))
- ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, vbo);
- }
-
- /* Unmap index buffer:
- */
- if (_mesa_is_bufferobj(copy->ib->obj) &&
- _mesa_bufferobj_mapped(copy->ib->obj)) {
- ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, copy->ib->obj);
- }
-}
-
-
-/**
- * Split VBO into smaller pieces, draw the pieces.
- */
-void vbo_split_copy( struct gl_context *ctx,
- const struct gl_client_array *arrays[],
- const struct _mesa_prim *prim,
- GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
- vbo_draw_func draw,
- const struct split_limits *limits )
-{
- struct copy_context copy;
- GLuint i, this_nr_prims;
-
- for (i = 0; i < 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;
- }
-
- memset(&copy, 0, sizeof(copy));
-
- /* Require indexed primitives:
- */
- assert(ib);
-
- copy.ctx = ctx;
- copy.array = arrays;
- copy.prim = &prim[i];
- copy.nr_prims = this_nr_prims;
- copy.ib = ib;
- copy.draw = draw;
- copy.limits = limits;
-
- /* Clear the vertex cache:
- */
- for (i = 0; i < ELT_TABLE_SIZE; i++)
- copy.vert_cache[i].in = ~0;
-
- replay_init(&copy);
- replay_elts(&copy);
- replay_finish(&copy);
- }
-}
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * 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.
+ *
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+/* Split indexed primitives with per-vertex copying.
+ */
+
+#include "main/glheader.h"
+#include "main/bufferobj.h"
+#include "main/imports.h"
+#include "main/image.h"
+#include "main/macros.h"
+#include "main/mtypes.h"
+
+#include "vbo_split.h"
+#include "vbo.h"
+
+
+#define ELT_TABLE_SIZE 16
+
+/**
+ * Used for vertex-level splitting of indexed buffers. Note that
+ * non-indexed primitives may be converted to indexed in some cases
+ * (eg loops, fans) in order to use this splitting path.
+ */
+struct copy_context {
+
+ struct gl_context *ctx;
+ const struct gl_client_array **array;
+ const struct _mesa_prim *prim;
+ GLuint nr_prims;
+ const struct _mesa_index_buffer *ib;
+ vbo_draw_func draw;
+
+ const struct split_limits *limits;
+
+ struct {
+ GLuint attr;
+ GLuint size;
+ const struct gl_client_array *array;
+ const GLubyte *src_ptr;
+
+ struct gl_client_array dstarray;
+
+ } varying[VERT_ATTRIB_MAX];
+ GLuint nr_varying;
+
+ const struct gl_client_array *dstarray_ptr[VERT_ATTRIB_MAX];
+ struct _mesa_index_buffer dstib;
+
+ GLuint *translated_elt_buf;
+ const GLuint *srcelt;
+
+ /** A baby hash table to avoid re-emitting (some) duplicate
+ * vertices when splitting indexed primitives.
+ */
+ struct {
+ GLuint in;
+ GLuint out;
+ } vert_cache[ELT_TABLE_SIZE];
+
+ GLuint vertex_size;
+ GLubyte *dstbuf;
+ GLubyte *dstptr; /**< dstptr == dstbuf + dstelt_max * vertsize */
+ GLuint dstbuf_size; /**< in vertices */
+ GLuint dstbuf_nr; /**< count of emitted vertices, also the largest value
+ * in dstelt. Our MaxIndex.
+ */
+
+ GLuint *dstelt;
+ GLuint dstelt_nr;
+ GLuint dstelt_size;
+
+#define MAX_PRIM 32
+ struct _mesa_prim dstprim[MAX_PRIM];
+ GLuint dstprim_nr;
+
+};
+
+
+static GLuint attr_size( const struct gl_client_array *array )
+{
+ return array->Size * _mesa_sizeof_type(array->Type);
+}
+
+
+/**
+ * Starts returning true slightly before the buffer fills, to ensure
+ * that there is sufficient room for any remaining vertices to finish
+ * off the prim:
+ */
+static GLboolean
+check_flush( struct copy_context *copy )
+{
+ GLenum mode = copy->dstprim[copy->dstprim_nr].mode;
+
+ if (GL_TRIANGLE_STRIP == mode &&
+ copy->dstelt_nr & 1) { /* see bug9962 */
+ return GL_FALSE;
+ }
+
+ if (copy->dstbuf_nr + 4 > copy->dstbuf_size)
+ return GL_TRUE;
+
+ if (copy->dstelt_nr + 4 > copy->dstelt_size)
+ return GL_TRUE;
+
+ return GL_FALSE;
+}
+
+
+/**
+ * Dump the parameters/info for a vbo->draw() call.
+ */
+static void
+dump_draw_info(struct gl_context *ctx,
+ const struct gl_client_array **arrays,
+ const struct _mesa_prim *prims,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ GLuint min_index,
+ GLuint max_index)
+{
+ GLuint i, j;
+
+ printf("VBO Draw:\n");
+ for (i = 0; i < nr_prims; i++) {
+ printf("Prim %u of %u\n", i, nr_prims);
+ printf(" Prim mode 0x%x\n", prims[i].mode);
+ printf(" IB: %p\n", (void*) ib);
+ for (j = 0; j < VERT_ATTRIB_MAX; j++) {
+ printf(" array %d at %p:\n", j, (void*) arrays[j]);
+ printf(" enabled %d, ptr %p, size %d, type 0x%x, stride %d\n",
+ arrays[j]->Enabled, arrays[j]->Ptr,
+ arrays[j]->Size, arrays[j]->Type, arrays[j]->StrideB);
+ if (0) {
+ GLint k = prims[i].start + prims[i].count - 1;
+ GLfloat *last = (GLfloat *) (arrays[j]->Ptr + arrays[j]->Stride * k);
+ printf(" last: %f %f %f\n",
+ last[0], last[1], last[2]);
+ }
+ }
+ }
+}
+
+
+static void
+flush( struct copy_context *copy )
+{
+ GLuint i;
+
+ /* Set some counters:
+ */
+ copy->dstib.count = copy->dstelt_nr;
+
+#if 0
+ dump_draw_info(copy->ctx,
+ copy->dstarray_ptr,
+ copy->dstprim,
+ copy->dstprim_nr,
+ &copy->dstib,
+ 0,
+ copy->dstbuf_nr);
+#else
+ (void) dump_draw_info;
+#endif
+
+ copy->draw( copy->ctx,
+ copy->dstarray_ptr,
+ copy->dstprim,
+ copy->dstprim_nr,
+ &copy->dstib,
+ GL_TRUE,
+ 0,
+ copy->dstbuf_nr - 1 );
+
+ /* Reset all pointers:
+ */
+ copy->dstprim_nr = 0;
+ copy->dstelt_nr = 0;
+ copy->dstbuf_nr = 0;
+ copy->dstptr = copy->dstbuf;
+
+ /* Clear the vertex cache:
+ */
+ for (i = 0; i < ELT_TABLE_SIZE; i++)
+ copy->vert_cache[i].in = ~0;
+}
+
+
+/**
+ * Called at begin of each primitive during replay.
+ */
+static void
+begin( struct copy_context *copy, GLenum mode, GLboolean begin_flag )
+{
+ struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
+
+ prim->mode = mode;
+ prim->begin = begin_flag;
+ prim->num_instances = 1;
+}
+
+
+/**
+ * Use a hashtable to attempt to identify recently-emitted vertices
+ * and avoid re-emitting them.
+ */
+static GLuint
+elt(struct copy_context *copy, GLuint elt_idx)
+{
+ GLuint elt = copy->srcelt[elt_idx];
+ GLuint slot = elt & (ELT_TABLE_SIZE-1);
+
+/* printf("elt %d\n", elt); */
+
+ /* Look up the incoming element in the vertex cache. Re-emit if
+ * necessary.
+ */
+ if (copy->vert_cache[slot].in != elt) {
+ GLubyte *csr = copy->dstptr;
+ GLuint i;
+
+/* printf(" --> emit to dstelt %d\n", copy->dstbuf_nr); */
+
+ for (i = 0; i < copy->nr_varying; i++) {
+ const struct gl_client_array *srcarray = copy->varying[i].array;
+ const GLubyte *srcptr = copy->varying[i].src_ptr + elt * srcarray->StrideB;
+
+ memcpy(csr, srcptr, copy->varying[i].size);
+ csr += copy->varying[i].size;
+
+#ifdef NAN_CHECK
+ if (srcarray->Type == GL_FLOAT) {
+ GLuint k;
+ GLfloat *f = (GLfloat *) srcptr;
+ for (k = 0; k < srcarray->Size; k++) {
+ assert(!IS_INF_OR_NAN(f[k]));
+ assert(f[k] <= 1.0e20 && f[k] >= -1.0e20);
+ }
+ }
+#endif
+
+ if (0)
+ {
+ const GLuint *f = (const GLuint *)srcptr;
+ GLuint j;
+ printf(" varying %d: ", i);
+ for(j = 0; j < copy->varying[i].size / 4; j++)
+ printf("%x ", f[j]);
+ printf("\n");
+ }
+ }
+
+ copy->vert_cache[slot].in = elt;
+ copy->vert_cache[slot].out = copy->dstbuf_nr++;
+ copy->dstptr += copy->vertex_size;
+
+ assert(csr == copy->dstptr);
+ assert(copy->dstptr == (copy->dstbuf +
+ copy->dstbuf_nr * copy->vertex_size));
+ }
+/* else */
+/* printf(" --> reuse vertex\n"); */
+
+/* printf(" --> emit %d\n", copy->vert_cache[slot].out); */
+ copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out;
+ return check_flush(copy);
+}
+
+
+/**
+ * Called at end of each primitive during replay.
+ */
+static void
+end( struct copy_context *copy, GLboolean end_flag )
+{
+ struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
+
+/* printf("end (%d)\n", end_flag); */
+
+ prim->end = end_flag;
+ prim->count = copy->dstelt_nr - prim->start;
+
+ if (++copy->dstprim_nr == MAX_PRIM ||
+ check_flush(copy))
+ flush(copy);
+}
+
+
+static void
+replay_elts( struct copy_context *copy )
+{
+ GLuint i, j, k;
+ GLboolean split;
+
+ for (i = 0; i < copy->nr_prims; i++) {
+ const struct _mesa_prim *prim = &copy->prim[i];
+ const GLuint start = prim->start;
+ GLuint first, incr;
+
+ switch (prim->mode) {
+
+ case GL_LINE_LOOP:
+ /* Convert to linestrip and emit the final vertex explicitly,
+ * but only in the resultant strip that requires it.
+ */
+ j = 0;
+ while (j != prim->count) {
+ begin(copy, GL_LINE_STRIP, prim->begin && j == 0);
+
+ for (split = GL_FALSE; j != prim->count && !split; j++)
+ split = elt(copy, start + j);
+
+ if (j == prim->count) {
+ /* Done, emit final line. Split doesn't matter as
+ * it is always raised a bit early so we can emit
+ * the last verts if necessary!
+ */
+ if (prim->end)
+ (void)elt(copy, start + 0);
+
+ end(copy, prim->end);
+ }
+ else {
+ /* Wrap
+ */
+ assert(split);
+ end(copy, 0);
+ j--;
+ }
+ }
+ break;
+
+ case GL_TRIANGLE_FAN:
+ case GL_POLYGON:
+ j = 2;
+ while (j != prim->count) {
+ begin(copy, prim->mode, prim->begin && j == 0);
+
+ split = elt(copy, start+0);
+ assert(!split);
+
+ split = elt(copy, start+j-1);
+ assert(!split);
+
+ for (; j != prim->count && !split; j++)
+ split = elt(copy, start+j);
+
+ end(copy, prim->end && j == prim->count);
+
+ if (j != prim->count) {
+ /* Wrapped the primitive, need to repeat some vertices:
+ */
+ j -= 1;
+ }
+ }
+ break;
+
+ default:
+ (void)split_prim_inplace(prim->mode, &first, &incr);
+
+ j = 0;
+ while (j != prim->count) {
+
+ begin(copy, prim->mode, prim->begin && j == 0);
+
+ split = 0;
+ for (k = 0; k < first; k++, j++)
+ split |= elt(copy, start+j);
+
+ assert(!split);
+
+ for (; j != prim->count && !split; )
+ for (k = 0; k < incr; k++, j++)
+ split |= elt(copy, start+j);
+
+ end(copy, prim->end && j == prim->count);
+
+ if (j != prim->count) {
+ /* Wrapped the primitive, need to repeat some vertices:
+ */
+ assert(j > first - incr);
+ j -= (first - incr);
+ }
+ }
+ break;
+ }
+ }
+
+ if (copy->dstprim_nr)
+ flush(copy);
+}
+
+
+static void
+replay_init( struct copy_context *copy )
+{
+ struct gl_context *ctx = copy->ctx;
+ GLuint i;
+ GLuint offset;
+ const GLvoid *srcptr;
+
+ /* Make a list of varying attributes and their vbo's. Also
+ * calculate vertex size.
+ */
+ copy->vertex_size = 0;
+ for (i = 0; i < VERT_ATTRIB_MAX; i++) {
+ struct gl_buffer_object *vbo = copy->array[i]->BufferObj;
+
+ if (copy->array[i]->StrideB == 0) {
+ copy->dstarray_ptr[i] = copy->array[i];
+ }
+ else {
+ GLuint j = copy->nr_varying++;
+
+ copy->varying[j].attr = i;
+ copy->varying[j].array = copy->array[i];
+ copy->varying[j].size = attr_size(copy->array[i]);
+ copy->vertex_size += attr_size(copy->array[i]);
+
+ if (_mesa_is_bufferobj(vbo) && !_mesa_bufferobj_mapped(vbo))
+ ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER, GL_READ_ONLY, vbo);
+
+ copy->varying[j].src_ptr = ADD_POINTERS(vbo->Pointer,
+ copy->array[i]->Ptr);
+
+ copy->dstarray_ptr[i] = &copy->varying[j].dstarray;
+ }
+ }
+
+ /* There must always be an index buffer. Currently require the
+ * caller convert non-indexed prims to indexed. Could alternately
+ * do it internally.
+ */
+ if (_mesa_is_bufferobj(copy->ib->obj) &&
+ !_mesa_bufferobj_mapped(copy->ib->obj))
+ ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY,
+ copy->ib->obj);
+
+ srcptr = (const GLubyte *) ADD_POINTERS(copy->ib->obj->Pointer,
+ copy->ib->ptr);
+
+ switch (copy->ib->type) {
+ case GL_UNSIGNED_BYTE:
+ copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
+ copy->srcelt = copy->translated_elt_buf;
+
+ for (i = 0; i < copy->ib->count; i++)
+ copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i];
+ break;
+
+ case GL_UNSIGNED_SHORT:
+ copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
+ copy->srcelt = copy->translated_elt_buf;
+
+ for (i = 0; i < copy->ib->count; i++)
+ copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i];
+ break;
+
+ case GL_UNSIGNED_INT:
+ copy->translated_elt_buf = NULL;
+ copy->srcelt = (const GLuint *)srcptr;
+ break;
+ }
+
+ /* Figure out the maximum allowed vertex buffer size:
+ */
+ if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) {
+ copy->dstbuf_size = copy->limits->max_verts;
+ }
+ else {
+ copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size;
+ }
+
+ /* Allocate an output vertex buffer:
+ *
+ * XXX: This should be a VBO!
+ */
+ copy->dstbuf = malloc(copy->dstbuf_size * copy->vertex_size);
+ copy->dstptr = copy->dstbuf;
+
+ /* Setup new vertex arrays to point into the output buffer:
+ */
+ for (offset = 0, i = 0; i < copy->nr_varying; i++) {
+ const struct gl_client_array *src = copy->varying[i].array;
+ struct gl_client_array *dst = &copy->varying[i].dstarray;
+
+ dst->Size = src->Size;
+ dst->Type = src->Type;
+ dst->Format = GL_RGBA;
+ dst->Stride = copy->vertex_size;
+ dst->StrideB = copy->vertex_size;
+ dst->Ptr = copy->dstbuf + offset;
+ dst->Enabled = GL_TRUE;
+ dst->Normalized = src->Normalized;
+ dst->BufferObj = ctx->Shared->NullBufferObj;
+ dst->_ElementSize = src->_ElementSize;
+ dst->_MaxElement = copy->dstbuf_size; /* may be less! */
+
+ offset += copy->varying[i].size;
+ }
+
+ /* Allocate an output element list:
+ */
+ copy->dstelt_size = MIN2(65536,
+ copy->ib->count * 2 + 3);
+ copy->dstelt_size = MIN2(copy->dstelt_size,
+ copy->limits->max_indices);
+ copy->dstelt = malloc(sizeof(GLuint) * copy->dstelt_size);
+ copy->dstelt_nr = 0;
+
+ /* Setup the new index buffer to point to the allocated element
+ * list:
+ */
+ copy->dstib.count = 0; /* duplicates dstelt_nr */
+ copy->dstib.type = GL_UNSIGNED_INT;
+ copy->dstib.obj = ctx->Shared->NullBufferObj;
+ copy->dstib.ptr = copy->dstelt;
+}
+
+
+/**
+ * Free up everything allocated during split/replay.
+ */
+static void
+replay_finish( struct copy_context *copy )
+{
+ struct gl_context *ctx = copy->ctx;
+ GLuint i;
+
+ /* Free our vertex and index buffers:
+ */
+ free(copy->translated_elt_buf);
+ free(copy->dstbuf);
+ free(copy->dstelt);
+
+ /* Unmap VBO's
+ */
+ for (i = 0; i < copy->nr_varying; i++) {
+ struct gl_buffer_object *vbo = copy->varying[i].array->BufferObj;
+ if (_mesa_is_bufferobj(vbo) && _mesa_bufferobj_mapped(vbo))
+ ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, vbo);
+ }
+
+ /* Unmap index buffer:
+ */
+ if (_mesa_is_bufferobj(copy->ib->obj) &&
+ _mesa_bufferobj_mapped(copy->ib->obj)) {
+ ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, copy->ib->obj);
+ }
+}
+
+
+/**
+ * Split VBO into smaller pieces, draw the pieces.
+ */
+void vbo_split_copy( struct gl_context *ctx,
+ const struct gl_client_array *arrays[],
+ const struct _mesa_prim *prim,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ vbo_draw_func draw,
+ const struct split_limits *limits )
+{
+ struct copy_context copy;
+ GLuint i, this_nr_prims;
+
+ for (i = 0; i < 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;
+ }
+
+ memset(&copy, 0, sizeof(copy));
+
+ /* Require indexed primitives:
+ */
+ assert(ib);
+
+ copy.ctx = ctx;
+ copy.array = arrays;
+ copy.prim = &prim[i];
+ copy.nr_prims = this_nr_prims;
+ copy.ib = ib;
+ copy.draw = draw;
+ copy.limits = limits;
+
+ /* Clear the vertex cache:
+ */
+ for (i = 0; i < ELT_TABLE_SIZE; i++)
+ copy.vert_cache[i].in = ~0;
+
+ replay_init(&copy);
+ replay_elts(&copy);
+ replay_finish(&copy);
+ }
+}