diff options
Diffstat (limited to 'mesalib/src/mesa/drivers/dri/common')
20 files changed, 8646 insertions, 8314 deletions
diff --git a/mesalib/src/mesa/drivers/dri/common/depthtmp.h b/mesalib/src/mesa/drivers/dri/common/depthtmp.h index fd2dab3b4..8e751d7b2 100644 --- a/mesalib/src/mesa/drivers/dri/common/depthtmp.h +++ b/mesalib/src/mesa/drivers/dri/common/depthtmp.h @@ -1,270 +1,270 @@ - -/* - * Notes: - * 1. These functions plug into the gl_renderbuffer structure. - * 2. The 'values' parameter always points to GLuint values, regardless of - * the actual Z buffer depth. - */ - - -#include "spantmp_common.h" - -#ifndef DBG -#define DBG 0 -#endif - -#ifndef HAVE_HW_DEPTH_SPANS -#define HAVE_HW_DEPTH_SPANS 0 -#endif - -#ifndef HAVE_HW_DEPTH_PIXELS -#define HAVE_HW_DEPTH_PIXELS 0 -#endif - -static void TAG(WriteDepthSpan)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const void *values, - const GLubyte mask[] ) -{ - HW_WRITE_LOCK() - { - const VALUE_TYPE *depth = (const VALUE_TYPE *) values; - GLint x1; - GLint n1; - LOCAL_DEPTH_VARS; - - y = Y_FLIP( y ); - -#if HAVE_HW_DEPTH_SPANS - (void) x1; (void) n1; - - if ( DBG ) fprintf( stderr, "WriteDepthSpan 0..%d (x1 %d)\n", - (int)n, (int)x ); - - WRITE_DEPTH_SPAN(); -#else - HW_CLIPLOOP() - { - GLint i = 0; - CLIPSPAN( x, y, n, x1, n1, i ); - - if ( DBG ) fprintf( stderr, "WriteDepthSpan %d..%d (x1 %d) (mask %p)\n", - (int)i, (int)n1, (int)x1, mask ); - - if ( mask ) { - for ( ; n1>0 ; i++, x1++, n1-- ) { - if ( mask[i] ) WRITE_DEPTH( x1, y, depth[i] ); - } - } else { - for ( ; n1>0 ; i++, x1++, n1-- ) { - WRITE_DEPTH( x1, y, depth[i] ); - } - } - } - HW_ENDCLIPLOOP(); -#endif - } - HW_WRITE_UNLOCK(); -} - - -#if HAVE_HW_DEPTH_SPANS -/* implement MonoWriteDepthSpan() in terms of WriteDepthSpan() */ -static void -TAG(WriteMonoDepthSpan)( GLcontext *ctx, struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const void *value, const GLubyte mask[] ) -{ - const GLuint depthVal = *((GLuint *) value); - GLuint depths[MAX_WIDTH]; - GLuint i; - for (i = 0; i < n; i++) - depths[i] = depthVal; - TAG(WriteDepthSpan)(ctx, rb, n, x, y, depths, mask); -} -#else -static void TAG(WriteMonoDepthSpan)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const void *value, - const GLubyte mask[] ) -{ - HW_WRITE_LOCK() - { - const GLuint depth = *((GLuint *) value); - GLint x1; - GLint n1; - LOCAL_DEPTH_VARS; - - y = Y_FLIP( y ); - - HW_CLIPLOOP() - { - GLint i = 0; - CLIPSPAN( x, y, n, x1, n1, i ); - - if ( DBG ) fprintf( stderr, "%s %d..%d (x1 %d) = %u\n", - __FUNCTION__, (int)i, (int)n1, (int)x1, (GLuint)depth ); - - if ( mask ) { - for ( ; n1>0 ; i++, x1++, n1-- ) { - if ( mask[i] ) WRITE_DEPTH( x1, y, depth ); - } - } else { - for ( ; n1>0 ; x1++, n1-- ) { - WRITE_DEPTH( x1, y, depth ); - } - } - } - HW_ENDCLIPLOOP(); - } - HW_WRITE_UNLOCK(); -} -#endif - - -static void TAG(WriteDepthPixels)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, - const GLint x[], - const GLint y[], - const void *values, - const GLubyte mask[] ) -{ - HW_WRITE_LOCK() - { - const VALUE_TYPE *depth = (const VALUE_TYPE *) values; - GLuint i; - LOCAL_DEPTH_VARS; - - if ( DBG ) fprintf( stderr, "WriteDepthPixels\n" ); - -#if HAVE_HW_DEPTH_PIXELS - (void) i; - - WRITE_DEPTH_PIXELS(); -#else - HW_CLIPLOOP() - { - if ( mask ) { - for ( i = 0 ; i < n ; i++ ) { - if ( mask[i] ) { - const int fy = Y_FLIP( y[i] ); - if ( CLIPPIXEL( x[i], fy ) ) - WRITE_DEPTH( x[i], fy, depth[i] ); - } - } - } - else { - for ( i = 0 ; i < n ; i++ ) { - const int fy = Y_FLIP( y[i] ); - if ( CLIPPIXEL( x[i], fy ) ) - WRITE_DEPTH( x[i], fy, depth[i] ); - } - } - } - HW_ENDCLIPLOOP(); -#endif - } - HW_WRITE_UNLOCK(); -} - - -/* Read depth spans and pixels - */ -static void TAG(ReadDepthSpan)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - void *values ) -{ - HW_READ_LOCK() - { - VALUE_TYPE *depth = (VALUE_TYPE *) values; - GLint x1, n1; - LOCAL_DEPTH_VARS; - - y = Y_FLIP( y ); - - if ( DBG ) fprintf( stderr, "ReadDepthSpan\n" ); - -#if HAVE_HW_DEPTH_SPANS - (void) x1; (void) n1; - - READ_DEPTH_SPAN(); -#else - HW_CLIPLOOP() - { - GLint i = 0; - CLIPSPAN( x, y, n, x1, n1, i ); - for ( ; n1>0 ; i++, n1-- ) { - READ_DEPTH( depth[i], x+i, y ); - } - } - HW_ENDCLIPLOOP(); -#endif - } - HW_READ_UNLOCK(); -} - -static void TAG(ReadDepthPixels)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, - const GLint x[], const GLint y[], - void *values ) -{ - HW_READ_LOCK() - { - VALUE_TYPE *depth = (VALUE_TYPE *) values; - GLuint i; - LOCAL_DEPTH_VARS; - - if ( DBG ) fprintf( stderr, "ReadDepthPixels\n" ); - -#if HAVE_HW_DEPTH_PIXELS - (void) i; - - READ_DEPTH_PIXELS(); -#else - HW_CLIPLOOP() - { - for ( i = 0 ; i < n ;i++ ) { - int fy = Y_FLIP( y[i] ); - if ( CLIPPIXEL( x[i], fy ) ) - READ_DEPTH( depth[i], x[i], fy ); - } - } - HW_ENDCLIPLOOP(); -#endif - } - HW_READ_UNLOCK(); -} - - -/** - * Initialize the given renderbuffer's span routines to point to - * the depth/z functions we generated above. - */ -static void TAG(InitDepthPointers)(struct gl_renderbuffer *rb) -{ - rb->GetRow = TAG(ReadDepthSpan); - rb->GetValues = TAG(ReadDepthPixels); - rb->PutRow = TAG(WriteDepthSpan); - rb->PutRowRGB = NULL; - rb->PutMonoRow = TAG(WriteMonoDepthSpan); - rb->PutValues = TAG(WriteDepthPixels); - rb->PutMonoValues = NULL; -} - - -#if HAVE_HW_DEPTH_SPANS -#undef WRITE_DEPTH_SPAN -#undef WRITE_DEPTH_PIXELS -#undef READ_DEPTH_SPAN -#undef READ_DEPTH_PIXELS -#else -#undef WRITE_DEPTH -#undef READ_DEPTH -#endif -#undef TAG -#undef VALUE_TYPE +
+/*
+ * Notes:
+ * 1. These functions plug into the gl_renderbuffer structure.
+ * 2. The 'values' parameter always points to GLuint values, regardless of
+ * the actual Z buffer depth.
+ */
+
+
+#include "spantmp_common.h"
+
+#ifndef DBG
+#define DBG 0
+#endif
+
+#ifndef HAVE_HW_DEPTH_SPANS
+#define HAVE_HW_DEPTH_SPANS 0
+#endif
+
+#ifndef HAVE_HW_DEPTH_PIXELS
+#define HAVE_HW_DEPTH_PIXELS 0
+#endif
+
+static void TAG(WriteDepthSpan)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const void *values,
+ const GLubyte mask[] )
+{
+ HW_WRITE_LOCK()
+ {
+ const VALUE_TYPE *depth = (const VALUE_TYPE *) values;
+ GLint x1;
+ GLint n1;
+ LOCAL_DEPTH_VARS;
+
+ y = Y_FLIP( y );
+
+#if HAVE_HW_DEPTH_SPANS
+ (void) x1; (void) n1;
+
+ if ( DBG ) fprintf( stderr, "WriteDepthSpan 0..%d (x1 %d)\n",
+ (int)n, (int)x );
+
+ WRITE_DEPTH_SPAN();
+#else
+ HW_CLIPLOOP()
+ {
+ GLint i = 0;
+ CLIPSPAN( x, y, n, x1, n1, i );
+
+ if ( DBG ) fprintf( stderr, "WriteDepthSpan %d..%d (x1 %d) (mask %p)\n",
+ (int)i, (int)n1, (int)x1, mask );
+
+ if ( mask ) {
+ for ( ; n1>0 ; i++, x1++, n1-- ) {
+ if ( mask[i] ) WRITE_DEPTH( x1, y, depth[i] );
+ }
+ } else {
+ for ( ; n1>0 ; i++, x1++, n1-- ) {
+ WRITE_DEPTH( x1, y, depth[i] );
+ }
+ }
+ }
+ HW_ENDCLIPLOOP();
+#endif
+ }
+ HW_WRITE_UNLOCK();
+}
+
+
+#if HAVE_HW_DEPTH_SPANS
+/* implement MonoWriteDepthSpan() in terms of WriteDepthSpan() */
+static void
+TAG(WriteMonoDepthSpan)( struct gl_context *ctx, struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const void *value, const GLubyte mask[] )
+{
+ const GLuint depthVal = *((GLuint *) value);
+ GLuint depths[MAX_WIDTH];
+ GLuint i;
+ for (i = 0; i < n; i++)
+ depths[i] = depthVal;
+ TAG(WriteDepthSpan)(ctx, rb, n, x, y, depths, mask);
+}
+#else
+static void TAG(WriteMonoDepthSpan)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const void *value,
+ const GLubyte mask[] )
+{
+ HW_WRITE_LOCK()
+ {
+ const GLuint depth = *((GLuint *) value);
+ GLint x1;
+ GLint n1;
+ LOCAL_DEPTH_VARS;
+
+ y = Y_FLIP( y );
+
+ HW_CLIPLOOP()
+ {
+ GLint i = 0;
+ CLIPSPAN( x, y, n, x1, n1, i );
+
+ if ( DBG ) fprintf( stderr, "%s %d..%d (x1 %d) = %u\n",
+ __FUNCTION__, (int)i, (int)n1, (int)x1, (GLuint)depth );
+
+ if ( mask ) {
+ for ( ; n1>0 ; i++, x1++, n1-- ) {
+ if ( mask[i] ) WRITE_DEPTH( x1, y, depth );
+ }
+ } else {
+ for ( ; n1>0 ; x1++, n1-- ) {
+ WRITE_DEPTH( x1, y, depth );
+ }
+ }
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_WRITE_UNLOCK();
+}
+#endif
+
+
+static void TAG(WriteDepthPixels)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n,
+ const GLint x[],
+ const GLint y[],
+ const void *values,
+ const GLubyte mask[] )
+{
+ HW_WRITE_LOCK()
+ {
+ const VALUE_TYPE *depth = (const VALUE_TYPE *) values;
+ GLuint i;
+ LOCAL_DEPTH_VARS;
+
+ if ( DBG ) fprintf( stderr, "WriteDepthPixels\n" );
+
+#if HAVE_HW_DEPTH_PIXELS
+ (void) i;
+
+ WRITE_DEPTH_PIXELS();
+#else
+ HW_CLIPLOOP()
+ {
+ if ( mask ) {
+ for ( i = 0 ; i < n ; i++ ) {
+ if ( mask[i] ) {
+ const int fy = Y_FLIP( y[i] );
+ if ( CLIPPIXEL( x[i], fy ) )
+ WRITE_DEPTH( x[i], fy, depth[i] );
+ }
+ }
+ }
+ else {
+ for ( i = 0 ; i < n ; i++ ) {
+ const int fy = Y_FLIP( y[i] );
+ if ( CLIPPIXEL( x[i], fy ) )
+ WRITE_DEPTH( x[i], fy, depth[i] );
+ }
+ }
+ }
+ HW_ENDCLIPLOOP();
+#endif
+ }
+ HW_WRITE_UNLOCK();
+}
+
+
+/* Read depth spans and pixels
+ */
+static void TAG(ReadDepthSpan)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ void *values )
+{
+ HW_READ_LOCK()
+ {
+ VALUE_TYPE *depth = (VALUE_TYPE *) values;
+ GLint x1, n1;
+ LOCAL_DEPTH_VARS;
+
+ y = Y_FLIP( y );
+
+ if ( DBG ) fprintf( stderr, "ReadDepthSpan\n" );
+
+#if HAVE_HW_DEPTH_SPANS
+ (void) x1; (void) n1;
+
+ READ_DEPTH_SPAN();
+#else
+ HW_CLIPLOOP()
+ {
+ GLint i = 0;
+ CLIPSPAN( x, y, n, x1, n1, i );
+ for ( ; n1>0 ; i++, n1-- ) {
+ READ_DEPTH( depth[i], x+i, y );
+ }
+ }
+ HW_ENDCLIPLOOP();
+#endif
+ }
+ HW_READ_UNLOCK();
+}
+
+static void TAG(ReadDepthPixels)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n,
+ const GLint x[], const GLint y[],
+ void *values )
+{
+ HW_READ_LOCK()
+ {
+ VALUE_TYPE *depth = (VALUE_TYPE *) values;
+ GLuint i;
+ LOCAL_DEPTH_VARS;
+
+ if ( DBG ) fprintf( stderr, "ReadDepthPixels\n" );
+
+#if HAVE_HW_DEPTH_PIXELS
+ (void) i;
+
+ READ_DEPTH_PIXELS();
+#else
+ HW_CLIPLOOP()
+ {
+ for ( i = 0 ; i < n ;i++ ) {
+ int fy = Y_FLIP( y[i] );
+ if ( CLIPPIXEL( x[i], fy ) )
+ READ_DEPTH( depth[i], x[i], fy );
+ }
+ }
+ HW_ENDCLIPLOOP();
+#endif
+ }
+ HW_READ_UNLOCK();
+}
+
+
+/**
+ * Initialize the given renderbuffer's span routines to point to
+ * the depth/z functions we generated above.
+ */
+static void TAG(InitDepthPointers)(struct gl_renderbuffer *rb)
+{
+ rb->GetRow = TAG(ReadDepthSpan);
+ rb->GetValues = TAG(ReadDepthPixels);
+ rb->PutRow = TAG(WriteDepthSpan);
+ rb->PutRowRGB = NULL;
+ rb->PutMonoRow = TAG(WriteMonoDepthSpan);
+ rb->PutValues = TAG(WriteDepthPixels);
+ rb->PutMonoValues = NULL;
+}
+
+
+#if HAVE_HW_DEPTH_SPANS
+#undef WRITE_DEPTH_SPAN
+#undef WRITE_DEPTH_PIXELS
+#undef READ_DEPTH_SPAN
+#undef READ_DEPTH_PIXELS
+#else
+#undef WRITE_DEPTH
+#undef READ_DEPTH
+#endif
+#undef TAG
+#undef VALUE_TYPE
diff --git a/mesalib/src/mesa/drivers/dri/common/dri_metaops.c b/mesalib/src/mesa/drivers/dri/common/dri_metaops.c index a2f404b61..e259f11df 100644 --- a/mesalib/src/mesa/drivers/dri/common/dri_metaops.c +++ b/mesalib/src/mesa/drivers/dri/common/dri_metaops.c @@ -1,291 +1,291 @@ -/************************************************************************** - * - * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. - * Copyright 2009 Intel Corporation. - * 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/arbprogram.h" -#include "main/arrayobj.h" -#include "main/bufferobj.h" -#include "main/context.h" -#include "main/enable.h" -#include "main/matrix.h" -#include "main/texstate.h" -#include "main/varray.h" -#include "main/viewport.h" -#include "program/program.h" -#include "dri_metaops.h" - -void -meta_set_passthrough_transform(struct dri_metaops *meta) -{ - GLcontext *ctx = meta->ctx; - - meta->saved_vp_x = ctx->Viewport.X; - meta->saved_vp_y = ctx->Viewport.Y; - meta->saved_vp_width = ctx->Viewport.Width; - meta->saved_vp_height = ctx->Viewport.Height; - meta->saved_matrix_mode = ctx->Transform.MatrixMode; - - meta->internal_viewport_call = GL_TRUE; - _mesa_Viewport(0, 0, ctx->DrawBuffer->Width, ctx->DrawBuffer->Height); - meta->internal_viewport_call = GL_FALSE; - - _mesa_MatrixMode(GL_PROJECTION); - _mesa_PushMatrix(); - _mesa_LoadIdentity(); - _mesa_Ortho(0, ctx->DrawBuffer->Width, 0, ctx->DrawBuffer->Height, 1, -1); - - _mesa_MatrixMode(GL_MODELVIEW); - _mesa_PushMatrix(); - _mesa_LoadIdentity(); -} - -void -meta_restore_transform(struct dri_metaops *meta) -{ - _mesa_MatrixMode(GL_PROJECTION); - _mesa_PopMatrix(); - _mesa_MatrixMode(GL_MODELVIEW); - _mesa_PopMatrix(); - - _mesa_MatrixMode(meta->saved_matrix_mode); - - meta->internal_viewport_call = GL_TRUE; - _mesa_Viewport(meta->saved_vp_x, meta->saved_vp_y, - meta->saved_vp_width, meta->saved_vp_height); - meta->internal_viewport_call = GL_FALSE; -} - - -/** - * Set up a vertex program to pass through the position and first texcoord - * for pixel path. - */ -void -meta_set_passthrough_vertex_program(struct dri_metaops *meta) -{ - GLcontext *ctx = meta->ctx; - static const char *vp = - "!!ARBvp1.0\n" - "TEMP vertexClip;\n" - "DP4 vertexClip.x, state.matrix.mvp.row[0], vertex.position;\n" - "DP4 vertexClip.y, state.matrix.mvp.row[1], vertex.position;\n" - "DP4 vertexClip.z, state.matrix.mvp.row[2], vertex.position;\n" - "DP4 vertexClip.w, state.matrix.mvp.row[3], vertex.position;\n" - "MOV result.position, vertexClip;\n" - "MOV result.texcoord[0], vertex.texcoord[0];\n" - "MOV result.color, vertex.color;\n" - "END\n"; - - assert(meta->saved_vp == NULL); - - _mesa_reference_vertprog(ctx, &meta->saved_vp, - ctx->VertexProgram.Current); - if (meta->passthrough_vp == NULL) { - GLuint prog_name; - _mesa_GenPrograms(1, &prog_name); - _mesa_BindProgram(GL_VERTEX_PROGRAM_ARB, prog_name); - _mesa_ProgramStringARB(GL_VERTEX_PROGRAM_ARB, - GL_PROGRAM_FORMAT_ASCII_ARB, - strlen(vp), (const GLubyte *)vp); - _mesa_reference_vertprog(ctx, &meta->passthrough_vp, - ctx->VertexProgram.Current); - _mesa_DeletePrograms(1, &prog_name); - } - - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, - meta->passthrough_vp); - ctx->Driver.BindProgram(ctx, GL_VERTEX_PROGRAM_ARB, - &meta->passthrough_vp->Base); - - meta->saved_vp_enable = ctx->VertexProgram.Enabled; - _mesa_Enable(GL_VERTEX_PROGRAM_ARB); -} - -/** - * Restores the previous vertex program after - * meta_set_passthrough_vertex_program() - */ -void -meta_restore_vertex_program(struct dri_metaops *meta) -{ - GLcontext *ctx = meta->ctx; - - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, - meta->saved_vp); - _mesa_reference_vertprog(ctx, &meta->saved_vp, NULL); - ctx->Driver.BindProgram(ctx, GL_VERTEX_PROGRAM_ARB, - &ctx->VertexProgram.Current->Base); - - if (!meta->saved_vp_enable) - _mesa_Disable(GL_VERTEX_PROGRAM_ARB); -} - -/** - * Binds the given program string to GL_FRAGMENT_PROGRAM_ARB, caching the - * program object. - */ -void -meta_set_fragment_program(struct dri_metaops *meta, - struct gl_fragment_program **prog, - const char *prog_string) -{ - GLcontext *ctx = meta->ctx; - assert(meta->saved_fp == NULL); - - _mesa_reference_fragprog(ctx, &meta->saved_fp, - ctx->FragmentProgram.Current); - if (*prog == NULL) { - GLuint prog_name; - _mesa_GenPrograms(1, &prog_name); - _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, prog_name); - _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, - GL_PROGRAM_FORMAT_ASCII_ARB, - strlen(prog_string), (const GLubyte *)prog_string); - _mesa_reference_fragprog(ctx, prog, ctx->FragmentProgram.Current); - /* Note that DeletePrograms unbinds the program on us */ - _mesa_DeletePrograms(1, &prog_name); - } - - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, *prog); - ctx->Driver.BindProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, &((*prog)->Base)); - - meta->saved_fp_enable = ctx->FragmentProgram.Enabled; - _mesa_Enable(GL_FRAGMENT_PROGRAM_ARB); -} - -/** - * Restores the previous fragment program after - * meta_set_fragment_program() - */ -void -meta_restore_fragment_program(struct dri_metaops *meta) -{ - GLcontext *ctx = meta->ctx; - - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, - meta->saved_fp); - _mesa_reference_fragprog(ctx, &meta->saved_fp, NULL); - ctx->Driver.BindProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, - &ctx->FragmentProgram.Current->Base); - - if (!meta->saved_fp_enable) - _mesa_Disable(GL_FRAGMENT_PROGRAM_ARB); -} - -static const float default_texcoords[4][2] = { { 0.0, 0.0 }, - { 1.0, 0.0 }, - { 1.0, 1.0 }, - { 0.0, 1.0 } }; - -void -meta_set_default_texrect(struct dri_metaops *meta) -{ - GLcontext *ctx = meta->ctx; - struct gl_client_array *old_texcoord_array; - - meta->saved_active_texture = ctx->Texture.CurrentUnit; - if (meta->saved_array_vbo == NULL) { - _mesa_reference_buffer_object(ctx, &meta->saved_array_vbo, - ctx->Array.ArrayBufferObj); - } - - old_texcoord_array = &ctx->Array.ArrayObj->TexCoord[0]; - meta->saved_texcoord_type = old_texcoord_array->Type; - meta->saved_texcoord_size = old_texcoord_array->Size; - meta->saved_texcoord_stride = old_texcoord_array->Stride; - meta->saved_texcoord_enable = old_texcoord_array->Enabled; - meta->saved_texcoord_ptr = old_texcoord_array->Ptr; - _mesa_reference_buffer_object(ctx, &meta->saved_texcoord_vbo, - old_texcoord_array->BufferObj); - - _mesa_ClientActiveTextureARB(GL_TEXTURE0); - - if (meta->texcoord_vbo == NULL) { - GLuint vbo_name; - - _mesa_GenBuffersARB(1, &vbo_name); - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, vbo_name); - _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(default_texcoords), - default_texcoords, GL_STATIC_DRAW_ARB); - _mesa_reference_buffer_object(ctx, &meta->texcoord_vbo, - ctx->Array.ArrayBufferObj); - } else { - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, - meta->texcoord_vbo->Name); - } - _mesa_TexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), NULL); - - _mesa_Enable(GL_TEXTURE_COORD_ARRAY); -} - -void -meta_restore_texcoords(struct dri_metaops *meta) -{ - GLcontext *ctx = meta->ctx; - - /* Restore the old TexCoordPointer */ - if (meta->saved_texcoord_vbo) { - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, - meta->saved_texcoord_vbo->Name); - _mesa_reference_buffer_object(ctx, &meta->saved_texcoord_vbo, NULL); - } else { - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - } - - _mesa_TexCoordPointer(meta->saved_texcoord_size, - meta->saved_texcoord_type, - meta->saved_texcoord_stride, - meta->saved_texcoord_ptr); - if (!meta->saved_texcoord_enable) - _mesa_Disable(GL_TEXTURE_COORD_ARRAY); - - _mesa_ClientActiveTextureARB(GL_TEXTURE0 + - meta->saved_active_texture); - - if (meta->saved_array_vbo) { - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, - meta->saved_array_vbo->Name); - _mesa_reference_buffer_object(ctx, &meta->saved_array_vbo, NULL); - } else { - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - } -} - - -void meta_init_metaops(GLcontext *ctx, struct dri_metaops *meta) -{ - meta->ctx = ctx; -} - -void meta_destroy_metaops(struct dri_metaops *meta) -{ - -} +/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2009 Intel Corporation.
+ * 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/arbprogram.h"
+#include "main/arrayobj.h"
+#include "main/bufferobj.h"
+#include "main/context.h"
+#include "main/enable.h"
+#include "main/matrix.h"
+#include "main/texstate.h"
+#include "main/varray.h"
+#include "main/viewport.h"
+#include "program/program.h"
+#include "dri_metaops.h"
+
+void
+meta_set_passthrough_transform(struct dri_metaops *meta)
+{
+ struct gl_context *ctx = meta->ctx;
+
+ meta->saved_vp_x = ctx->Viewport.X;
+ meta->saved_vp_y = ctx->Viewport.Y;
+ meta->saved_vp_width = ctx->Viewport.Width;
+ meta->saved_vp_height = ctx->Viewport.Height;
+ meta->saved_matrix_mode = ctx->Transform.MatrixMode;
+
+ meta->internal_viewport_call = GL_TRUE;
+ _mesa_Viewport(0, 0, ctx->DrawBuffer->Width, ctx->DrawBuffer->Height);
+ meta->internal_viewport_call = GL_FALSE;
+
+ _mesa_MatrixMode(GL_PROJECTION);
+ _mesa_PushMatrix();
+ _mesa_LoadIdentity();
+ _mesa_Ortho(0, ctx->DrawBuffer->Width, 0, ctx->DrawBuffer->Height, 1, -1);
+
+ _mesa_MatrixMode(GL_MODELVIEW);
+ _mesa_PushMatrix();
+ _mesa_LoadIdentity();
+}
+
+void
+meta_restore_transform(struct dri_metaops *meta)
+{
+ _mesa_MatrixMode(GL_PROJECTION);
+ _mesa_PopMatrix();
+ _mesa_MatrixMode(GL_MODELVIEW);
+ _mesa_PopMatrix();
+
+ _mesa_MatrixMode(meta->saved_matrix_mode);
+
+ meta->internal_viewport_call = GL_TRUE;
+ _mesa_Viewport(meta->saved_vp_x, meta->saved_vp_y,
+ meta->saved_vp_width, meta->saved_vp_height);
+ meta->internal_viewport_call = GL_FALSE;
+}
+
+
+/**
+ * Set up a vertex program to pass through the position and first texcoord
+ * for pixel path.
+ */
+void
+meta_set_passthrough_vertex_program(struct dri_metaops *meta)
+{
+ struct gl_context *ctx = meta->ctx;
+ static const char *vp =
+ "!!ARBvp1.0\n"
+ "TEMP vertexClip;\n"
+ "DP4 vertexClip.x, state.matrix.mvp.row[0], vertex.position;\n"
+ "DP4 vertexClip.y, state.matrix.mvp.row[1], vertex.position;\n"
+ "DP4 vertexClip.z, state.matrix.mvp.row[2], vertex.position;\n"
+ "DP4 vertexClip.w, state.matrix.mvp.row[3], vertex.position;\n"
+ "MOV result.position, vertexClip;\n"
+ "MOV result.texcoord[0], vertex.texcoord[0];\n"
+ "MOV result.color, vertex.color;\n"
+ "END\n";
+
+ assert(meta->saved_vp == NULL);
+
+ _mesa_reference_vertprog(ctx, &meta->saved_vp,
+ ctx->VertexProgram.Current);
+ if (meta->passthrough_vp == NULL) {
+ GLuint prog_name;
+ _mesa_GenPrograms(1, &prog_name);
+ _mesa_BindProgram(GL_VERTEX_PROGRAM_ARB, prog_name);
+ _mesa_ProgramStringARB(GL_VERTEX_PROGRAM_ARB,
+ GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(vp), (const GLubyte *)vp);
+ _mesa_reference_vertprog(ctx, &meta->passthrough_vp,
+ ctx->VertexProgram.Current);
+ _mesa_DeletePrograms(1, &prog_name);
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
+ meta->passthrough_vp);
+ ctx->Driver.BindProgram(ctx, GL_VERTEX_PROGRAM_ARB,
+ &meta->passthrough_vp->Base);
+
+ meta->saved_vp_enable = ctx->VertexProgram.Enabled;
+ _mesa_Enable(GL_VERTEX_PROGRAM_ARB);
+}
+
+/**
+ * Restores the previous vertex program after
+ * meta_set_passthrough_vertex_program()
+ */
+void
+meta_restore_vertex_program(struct dri_metaops *meta)
+{
+ struct gl_context *ctx = meta->ctx;
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
+ meta->saved_vp);
+ _mesa_reference_vertprog(ctx, &meta->saved_vp, NULL);
+ ctx->Driver.BindProgram(ctx, GL_VERTEX_PROGRAM_ARB,
+ &ctx->VertexProgram.Current->Base);
+
+ if (!meta->saved_vp_enable)
+ _mesa_Disable(GL_VERTEX_PROGRAM_ARB);
+}
+
+/**
+ * Binds the given program string to GL_FRAGMENT_PROGRAM_ARB, caching the
+ * program object.
+ */
+void
+meta_set_fragment_program(struct dri_metaops *meta,
+ struct gl_fragment_program **prog,
+ const char *prog_string)
+{
+ struct gl_context *ctx = meta->ctx;
+ assert(meta->saved_fp == NULL);
+
+ _mesa_reference_fragprog(ctx, &meta->saved_fp,
+ ctx->FragmentProgram.Current);
+ if (*prog == NULL) {
+ GLuint prog_name;
+ _mesa_GenPrograms(1, &prog_name);
+ _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, prog_name);
+ _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(prog_string), (const GLubyte *)prog_string);
+ _mesa_reference_fragprog(ctx, prog, ctx->FragmentProgram.Current);
+ /* Note that DeletePrograms unbinds the program on us */
+ _mesa_DeletePrograms(1, &prog_name);
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, *prog);
+ ctx->Driver.BindProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, &((*prog)->Base));
+
+ meta->saved_fp_enable = ctx->FragmentProgram.Enabled;
+ _mesa_Enable(GL_FRAGMENT_PROGRAM_ARB);
+}
+
+/**
+ * Restores the previous fragment program after
+ * meta_set_fragment_program()
+ */
+void
+meta_restore_fragment_program(struct dri_metaops *meta)
+{
+ struct gl_context *ctx = meta->ctx;
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
+ meta->saved_fp);
+ _mesa_reference_fragprog(ctx, &meta->saved_fp, NULL);
+ ctx->Driver.BindProgram(ctx, GL_FRAGMENT_PROGRAM_ARB,
+ &ctx->FragmentProgram.Current->Base);
+
+ if (!meta->saved_fp_enable)
+ _mesa_Disable(GL_FRAGMENT_PROGRAM_ARB);
+}
+
+static const float default_texcoords[4][2] = { { 0.0, 0.0 },
+ { 1.0, 0.0 },
+ { 1.0, 1.0 },
+ { 0.0, 1.0 } };
+
+void
+meta_set_default_texrect(struct dri_metaops *meta)
+{
+ struct gl_context *ctx = meta->ctx;
+ struct gl_client_array *old_texcoord_array;
+
+ meta->saved_active_texture = ctx->Texture.CurrentUnit;
+ if (meta->saved_array_vbo == NULL) {
+ _mesa_reference_buffer_object(ctx, &meta->saved_array_vbo,
+ ctx->Array.ArrayBufferObj);
+ }
+
+ old_texcoord_array = &ctx->Array.ArrayObj->TexCoord[0];
+ meta->saved_texcoord_type = old_texcoord_array->Type;
+ meta->saved_texcoord_size = old_texcoord_array->Size;
+ meta->saved_texcoord_stride = old_texcoord_array->Stride;
+ meta->saved_texcoord_enable = old_texcoord_array->Enabled;
+ meta->saved_texcoord_ptr = old_texcoord_array->Ptr;
+ _mesa_reference_buffer_object(ctx, &meta->saved_texcoord_vbo,
+ old_texcoord_array->BufferObj);
+
+ _mesa_ClientActiveTextureARB(GL_TEXTURE0);
+
+ if (meta->texcoord_vbo == NULL) {
+ GLuint vbo_name;
+
+ _mesa_GenBuffersARB(1, &vbo_name);
+ _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, vbo_name);
+ _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(default_texcoords),
+ default_texcoords, GL_STATIC_DRAW_ARB);
+ _mesa_reference_buffer_object(ctx, &meta->texcoord_vbo,
+ ctx->Array.ArrayBufferObj);
+ } else {
+ _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB,
+ meta->texcoord_vbo->Name);
+ }
+ _mesa_TexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), NULL);
+
+ _mesa_Enable(GL_TEXTURE_COORD_ARRAY);
+}
+
+void
+meta_restore_texcoords(struct dri_metaops *meta)
+{
+ struct gl_context *ctx = meta->ctx;
+
+ /* Restore the old TexCoordPointer */
+ if (meta->saved_texcoord_vbo) {
+ _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB,
+ meta->saved_texcoord_vbo->Name);
+ _mesa_reference_buffer_object(ctx, &meta->saved_texcoord_vbo, NULL);
+ } else {
+ _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ }
+
+ _mesa_TexCoordPointer(meta->saved_texcoord_size,
+ meta->saved_texcoord_type,
+ meta->saved_texcoord_stride,
+ meta->saved_texcoord_ptr);
+ if (!meta->saved_texcoord_enable)
+ _mesa_Disable(GL_TEXTURE_COORD_ARRAY);
+
+ _mesa_ClientActiveTextureARB(GL_TEXTURE0 +
+ meta->saved_active_texture);
+
+ if (meta->saved_array_vbo) {
+ _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB,
+ meta->saved_array_vbo->Name);
+ _mesa_reference_buffer_object(ctx, &meta->saved_array_vbo, NULL);
+ } else {
+ _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ }
+}
+
+
+void meta_init_metaops(struct gl_context *ctx, struct dri_metaops *meta)
+{
+ meta->ctx = ctx;
+}
+
+void meta_destroy_metaops(struct dri_metaops *meta)
+{
+
+}
diff --git a/mesalib/src/mesa/drivers/dri/common/dri_metaops.h b/mesalib/src/mesa/drivers/dri/common/dri_metaops.h index 248714532..e72094e62 100644 --- a/mesalib/src/mesa/drivers/dri/common/dri_metaops.h +++ b/mesalib/src/mesa/drivers/dri/common/dri_metaops.h @@ -1,81 +1,81 @@ -/************************************************************************** - * - * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. - * Copyright 2009 Intel Corporation. - * 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 DRI_METAOPS_H -#define DRI_METAOPS_H - - -struct dri_metaops { - GLcontext *ctx; - GLboolean internal_viewport_call; - struct gl_fragment_program *bitmap_fp; - struct gl_vertex_program *passthrough_vp; - struct gl_buffer_object *texcoord_vbo; - - struct gl_fragment_program *saved_fp; - GLboolean saved_fp_enable; - struct gl_vertex_program *saved_vp; - GLboolean saved_vp_enable; - - struct gl_fragment_program *tex2d_fp; - - GLboolean saved_texcoord_enable; - struct gl_buffer_object *saved_array_vbo, *saved_texcoord_vbo; - GLenum saved_texcoord_type; - GLsizei saved_texcoord_size, saved_texcoord_stride; - const void *saved_texcoord_ptr; - int saved_active_texture; - - GLint saved_vp_x, saved_vp_y; - GLsizei saved_vp_width, saved_vp_height; - GLenum saved_matrix_mode; -}; - - -void meta_set_passthrough_transform(struct dri_metaops *meta); - -void meta_restore_transform(struct dri_metaops *meta); - -void meta_set_passthrough_vertex_program(struct dri_metaops *meta); - -void meta_restore_vertex_program(struct dri_metaops *meta); - -void meta_set_fragment_program(struct dri_metaops *meta, - struct gl_fragment_program **prog, - const char *prog_string); - -void meta_restore_fragment_program(struct dri_metaops *meta); - -void meta_set_default_texrect(struct dri_metaops *meta); - -void meta_restore_texcoords(struct dri_metaops *meta); - -void meta_init_metaops(GLcontext *ctx, struct dri_metaops *meta); -void meta_destroy_metaops(struct dri_metaops *meta); - -#endif +/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2009 Intel Corporation.
+ * 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 DRI_METAOPS_H
+#define DRI_METAOPS_H
+
+
+struct dri_metaops {
+ struct gl_context *ctx;
+ GLboolean internal_viewport_call;
+ struct gl_fragment_program *bitmap_fp;
+ struct gl_vertex_program *passthrough_vp;
+ struct gl_buffer_object *texcoord_vbo;
+
+ struct gl_fragment_program *saved_fp;
+ GLboolean saved_fp_enable;
+ struct gl_vertex_program *saved_vp;
+ GLboolean saved_vp_enable;
+
+ struct gl_fragment_program *tex2d_fp;
+
+ GLboolean saved_texcoord_enable;
+ struct gl_buffer_object *saved_array_vbo, *saved_texcoord_vbo;
+ GLenum saved_texcoord_type;
+ GLsizei saved_texcoord_size, saved_texcoord_stride;
+ const void *saved_texcoord_ptr;
+ int saved_active_texture;
+
+ GLint saved_vp_x, saved_vp_y;
+ GLsizei saved_vp_width, saved_vp_height;
+ GLenum saved_matrix_mode;
+};
+
+
+void meta_set_passthrough_transform(struct dri_metaops *meta);
+
+void meta_restore_transform(struct dri_metaops *meta);
+
+void meta_set_passthrough_vertex_program(struct dri_metaops *meta);
+
+void meta_restore_vertex_program(struct dri_metaops *meta);
+
+void meta_set_fragment_program(struct dri_metaops *meta,
+ struct gl_fragment_program **prog,
+ const char *prog_string);
+
+void meta_restore_fragment_program(struct dri_metaops *meta);
+
+void meta_set_default_texrect(struct dri_metaops *meta);
+
+void meta_restore_texcoords(struct dri_metaops *meta);
+
+void meta_init_metaops(struct gl_context *ctx, struct dri_metaops *meta);
+void meta_destroy_metaops(struct dri_metaops *meta);
+
+#endif
diff --git a/mesalib/src/mesa/drivers/dri/common/dri_util.c b/mesalib/src/mesa/drivers/dri/common/dri_util.c index d46f622d5..3bf782a1b 100644 --- a/mesalib/src/mesa/drivers/dri/common/dri_util.c +++ b/mesalib/src/mesa/drivers/dri/common/dri_util.c @@ -1,1010 +1,1009 @@ -/** - * \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, - renderType == GLX_PIXMAP_BIT)) { - free(pdp); - return NULL; - } - - pdp->msc_base = 0; - - /* This special default value is replaced with the configured - * default value when the drawable is first bound to a direct - * rendering context. - */ - pdp->swap_interval = (unsigned)-1; - - return pdp; -} - - -static __DRIdrawable * -dri2CreateNewDrawable(__DRIscreen *screen, - const __DRIconfig *config, - void *loaderPrivate) -{ - __DRIdrawable *pdraw; - - pdraw = driCreateNewDrawable(screen, config, 0, 0, NULL, loaderPrivate); - if (!pdraw) - return NULL; - - pdraw->pClipRects = &pdraw->dri2.clipRect; - pdraw->pBackClipRects = &pdraw->dri2.clipRect; - - pdraw->pStamp = &pdraw->dri2.stamp; - *pdraw->pStamp = pdraw->lastStamp + 1; - - return pdraw; -} - -static int -dri2ConfigQueryb(__DRIscreen *screen, const char *var, GLboolean *val) -{ - if (!driCheckOption(&screen->optionCache, var, DRI_BOOL)) - return -1; - - *val = driQueryOptionb(&screen->optionCache, var); - - return 0; -} - -static int -dri2ConfigQueryi(__DRIscreen *screen, const char *var, GLint *val) -{ - if (!driCheckOption(&screen->optionCache, var, DRI_INT) && - !driCheckOption(&screen->optionCache, var, DRI_ENUM)) - return -1; - - *val = driQueryOptioni(&screen->optionCache, var); - - return 0; -} - -static int -dri2ConfigQueryf(__DRIscreen *screen, const char *var, GLfloat *val) -{ - if (!driCheckOption(&screen->optionCache, var, DRI_FLOAT)) - return -1; - - *val = driQueryOptionf(&screen->optionCache, var); - - return 0; -} - - -static void dri_get_drawable(__DRIdrawable *pdp) -{ - pdp->refcount++; -} - -static void dri_put_drawable(__DRIdrawable *pdp) -{ - __DRIscreen *psp; - - if (pdp) { - pdp->refcount--; - if (pdp->refcount) - return; - - psp = pdp->driScreenPriv; - (*psp->DriverAPI.DestroyBuffer)(pdp); - if (pdp->pClipRects && pdp->pClipRects != &pdp->dri2.clipRect) { - free(pdp->pClipRects); - pdp->pClipRects = NULL; - } - if (pdp->pBackClipRects && pdp->pClipRects != &pdp->dri2.clipRect) { - free(pdp->pBackClipRects); - pdp->pBackClipRects = NULL; - } - free(pdp); - } -} - -static void -driDestroyDrawable(__DRIdrawable *pdp) -{ - dri_put_drawable(pdp); -} - -/*@}*/ - - -/*****************************************************************/ -/** \name Context handling functions */ -/*****************************************************************/ -/*@{*/ - -/** - * Destroy the per-context private information. - * - * \internal - * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls - * drmDestroyContext(), and finally frees \p contextPrivate. - */ -static void -driDestroyContext(__DRIcontext *pcp) -{ - if (pcp) { - (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp); - free(pcp); - } -} - - -/** - * Create the per-drawable private driver information. - * - * \param render_type Type of rendering target. \c GLX_RGBA is the only - * type likely to ever be supported for direct-rendering. - * \param shared Context with which to share textures, etc. or NULL - * - * \returns An opaque pointer to the per-context private information on - * success, or \c NULL on failure. - * - * \internal - * This function allocates and fills a __DRIcontextRec structure. It - * performs some device independent initialization and passes all the - * relevent information to __DriverAPIRec::CreateContext to create the - * context. - * - */ -static __DRIcontext * -driCreateNewContext(__DRIscreen *psp, const __DRIconfig *config, - int render_type, __DRIcontext *shared, - drm_context_t hwContext, void *data) -{ - __DRIcontext *pcp; - void * const shareCtx = (shared != NULL) ? shared->driverPrivate : NULL; - - pcp = malloc(sizeof *pcp); - if (!pcp) - return NULL; - - pcp->driScreenPriv = psp; - pcp->driDrawablePriv = NULL; - pcp->loaderPrivate = data; - - pcp->dri2.draw_stamp = 0; - pcp->dri2.read_stamp = 0; - - pcp->hHWContext = hwContext; - - if ( !(*psp->DriverAPI.CreateContext)(API_OPENGL, - &config->modes, pcp, shareCtx) ) { - free(pcp); - return NULL; - } - - return pcp; -} - -static unsigned int -dri2GetAPIMask(__DRIscreen *screen) -{ - return screen->api_mask; -} - -static __DRIcontext * -dri2CreateNewContextForAPI(__DRIscreen *screen, int api, - const __DRIconfig *config, - __DRIcontext *shared, void *data) -{ - __DRIcontext *context; - const __GLcontextModes *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 __GLcontextModes that the driver can support for windows or - * pbuffers. - * - * For legacy DRI. - * - * \param scrn Index of the screen - * \param ddx_version Version of the 2D DDX. This may not be meaningful for - * all drivers. - * \param dri_version Version of the "server-side" DRI. - * \param drm_version Version of the kernel DRM. - * \param frame_buffer Data describing the location and layout of the - * framebuffer. - * \param pSAREA Pointer 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; - - psp = calloc(1, sizeof *psp); - if (!psp) - return NULL; - - setupLoaderExtensions(psp, extensions); - - /* - ** NOT_DONE: This is used by the X server to detect when the client - ** has died while holding the drawable lock. The client sets the - ** drawable lock to this value. - */ - psp->drawLockID = 1; - - psp->drm_version = *drm_version; - psp->ddx_version = *ddx_version; - psp->dri_version = *dri_version; - - psp->pSAREA = pSAREA; - psp->lock = (drmLock *) &psp->pSAREA->lock; - - psp->pFB = frame_buffer->base; - psp->fbSize = frame_buffer->size; - psp->fbStride = frame_buffer->stride; - psp->fbWidth = frame_buffer->width; - psp->fbHeight = frame_buffer->height; - psp->devPrivSize = frame_buffer->dev_priv_size; - psp->pDevPriv = frame_buffer->dev_priv; - psp->fbBPP = psp->fbStride * 8 / frame_buffer->width; - - psp->extensions = emptyExtensionList; - psp->fd = fd; - psp->myNum = scrn; - psp->dri2.enabled = GL_FALSE; - - psp->DriverAPI = driDriverAPI; - psp->api_mask = (1 << __DRI_API_OPENGL); - - *driver_modes = driDriverAPI.InitScreen(psp); - if (*driver_modes == NULL) { - free(psp); - return NULL; - } - - return psp; -} - -/** - * DRI2 - */ -static __DRIscreen * -dri2CreateNewScreen(int scrn, int fd, - const __DRIextension **extensions, - const __DRIconfig ***driver_configs, void *data) -{ - static const __DRIextension *emptyExtensionList[] = { NULL }; - __DRIscreen *psp; - drmVersionPtr version; - - if (driDriverAPI.InitScreen2 == NULL) - return NULL; - - psp = calloc(1, sizeof(*psp)); - if (!psp) - return NULL; - - setupLoaderExtensions(psp, extensions); - - version = drmGetVersion(fd); - if (version) { - psp->drm_version.major = version->version_major; - psp->drm_version.minor = version->version_minor; - psp->drm_version.patch = version->version_patchlevel; - drmFreeVersion(version); - } - - psp->extensions = emptyExtensionList; - psp->fd = fd; - psp->myNum = scrn; - psp->dri2.enabled = GL_TRUE; - - psp->DriverAPI = driDriverAPI; - psp->api_mask = (1 << __DRI_API_OPENGL); - *driver_configs = driDriverAPI.InitScreen2(psp); - if (*driver_configs == NULL) { - free(psp); - return NULL; - } - - psp->DriverAPI = driDriverAPI; - psp->loaderPrivate = data; - - driParseOptionInfo(&psp->optionInfo, __dri2ConfigOptions, - __dri2NConfigOptions); - driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum, - "dri2"); - - return psp; -} - -static const __DRIextension **driGetExtensions(__DRIscreen *psp) -{ - return psp->extensions; -} - -/** Core interface */ -const __DRIcoreExtension driCoreExtension = { - { __DRI_CORE, __DRI_CORE_VERSION }, - NULL, - driDestroyScreen, - driGetExtensions, - driGetConfigAttrib, - driIndexConfigAttrib, - NULL, - driDestroyDrawable, - driSwapBuffers, - NULL, - driCopyContext, - driDestroyContext, - driBindContext, - driUnbindContext -}; - -/** Legacy DRI interface */ -const __DRIlegacyExtension driLegacyExtension = { - { __DRI_LEGACY, __DRI_LEGACY_VERSION }, - driCreateNewScreen, - driCreateNewDrawable, - driCreateNewContext, -}; - -/** DRI2 interface */ -const __DRIdri2Extension driDRI2Extension = { - { __DRI_DRI2, __DRI_DRI2_VERSION }, - dri2CreateNewScreen, - dri2CreateNewDrawable, - dri2CreateNewContext, - dri2GetAPIMask, - dri2CreateNewContextForAPI -}; - -const __DRI2configQueryExtension dri2ConfigQueryExtension = { - { __DRI2_CONFIG_QUERY, __DRI2_CONFIG_QUERY_VERSION }, - dri2ConfigQueryb, - dri2ConfigQueryi, - dri2ConfigQueryf, -}; - -/** - * Calculate amount of swap interval used between GLX buffer swaps. - * - * The usage value, on the range [0,max], is the fraction of total swap - * interval time used between GLX buffer swaps is calculated. - * - * \f$p = t_d / (i * t_r)\f$ - * - * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the - * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time - * required for a single vertical refresh period (as returned by \c - * glXGetMscRateOML). - * - * See the documentation for the GLX_MESA_swap_frame_usage extension for more - * details. - * - * \param dPriv Pointer to the private drawable structure. - * \return If less than a single swap interval time period was required - * between GLX buffer swaps, a number greater than 0 and less than - * 1.0 is returned. If exactly one swap interval time period is - * required, 1.0 is returned, and if more than one is required then - * a number greater than 1.0 will be returned. - * - * \sa glXSwapIntervalSGI glXGetMscRateOML - * - * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it - * be possible to cache the sync rate? - */ -float -driCalculateSwapUsage( __DRIdrawable *dPriv, int64_t last_swap_ust, - int64_t current_ust ) -{ - int32_t n; - int32_t d; - int interval; - float usage = 1.0; - __DRIscreen *psp = dPriv->driScreenPriv; - - if ( (*psp->systemTime->getMSCRate)(dPriv, &n, &d, dPriv->loaderPrivate) ) { - interval = (dPriv->swap_interval != 0) ? dPriv->swap_interval : 1; - - - /* We want to calculate - * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get - * current_UST by calling __glXGetUST. last_swap_UST is stored in - * dPriv->swap_ust. interval has already been calculated. - * - * The only tricky part is us_per_refresh. us_per_refresh is - * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it - * around and say us_per_refresh = 1000000 * d / n. Since this goes in - * the denominator of the final calculation, we calculate - * (interval * 1000000 * d) and move n into the numerator. - */ - - usage = (current_ust - last_swap_ust); - usage *= n; - usage /= (interval * d); - usage /= 1000000.0; - } - - return usage; -} - -void -dri2InvalidateDrawable(__DRIdrawable *drawable) -{ - drawable->dri2.stamp++; -} - -/*@}*/ +/**
+ * \file dri_util.c
+ * DRI utility functions.
+ *
+ * This module acts as glue between GLX and the actual hardware driver. A DRI
+ * driver doesn't really \e have to use any of this - it's optional. But, some
+ * useful stuff is done here that otherwise would have to be duplicated in most
+ * drivers.
+ *
+ * Basically, these utility functions take care of some of the dirty details of
+ * screen initialization, context creation, context binding, DRM setup, etc.
+ *
+ * These functions are compiled into each DRI driver so libGL.so knows nothing
+ * about them.
+ */
+
+
+#include <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 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;
+
+ psp = calloc(1, sizeof *psp);
+ if (!psp)
+ return NULL;
+
+ setupLoaderExtensions(psp, extensions);
+
+ /*
+ ** NOT_DONE: This is used by the X server to detect when the client
+ ** has died while holding the drawable lock. The client sets the
+ ** drawable lock to this value.
+ */
+ psp->drawLockID = 1;
+
+ psp->drm_version = *drm_version;
+ psp->ddx_version = *ddx_version;
+ psp->dri_version = *dri_version;
+
+ psp->pSAREA = pSAREA;
+ psp->lock = (drmLock *) &psp->pSAREA->lock;
+
+ psp->pFB = frame_buffer->base;
+ psp->fbSize = frame_buffer->size;
+ psp->fbStride = frame_buffer->stride;
+ psp->fbWidth = frame_buffer->width;
+ psp->fbHeight = frame_buffer->height;
+ psp->devPrivSize = frame_buffer->dev_priv_size;
+ psp->pDevPriv = frame_buffer->dev_priv;
+ psp->fbBPP = psp->fbStride * 8 / frame_buffer->width;
+
+ psp->extensions = emptyExtensionList;
+ psp->fd = fd;
+ psp->myNum = scrn;
+ psp->dri2.enabled = GL_FALSE;
+
+ psp->DriverAPI = driDriverAPI;
+ psp->api_mask = (1 << __DRI_API_OPENGL);
+
+ *driver_modes = driDriverAPI.InitScreen(psp);
+ if (*driver_modes == NULL) {
+ free(psp);
+ return NULL;
+ }
+
+ return psp;
+}
+
+/**
+ * DRI2
+ */
+static __DRIscreen *
+dri2CreateNewScreen(int scrn, int fd,
+ const __DRIextension **extensions,
+ const __DRIconfig ***driver_configs, void *data)
+{
+ static const __DRIextension *emptyExtensionList[] = { NULL };
+ __DRIscreen *psp;
+ drmVersionPtr version;
+
+ if (driDriverAPI.InitScreen2 == NULL)
+ return NULL;
+
+ psp = calloc(1, sizeof(*psp));
+ if (!psp)
+ return NULL;
+
+ setupLoaderExtensions(psp, extensions);
+
+ version = drmGetVersion(fd);
+ if (version) {
+ psp->drm_version.major = version->version_major;
+ psp->drm_version.minor = version->version_minor;
+ psp->drm_version.patch = version->version_patchlevel;
+ drmFreeVersion(version);
+ }
+
+ psp->extensions = emptyExtensionList;
+ psp->fd = fd;
+ psp->myNum = scrn;
+ psp->dri2.enabled = GL_TRUE;
+
+ psp->DriverAPI = driDriverAPI;
+ psp->api_mask = (1 << __DRI_API_OPENGL);
+ *driver_configs = driDriverAPI.InitScreen2(psp);
+ if (*driver_configs == NULL) {
+ free(psp);
+ return NULL;
+ }
+
+ psp->DriverAPI = driDriverAPI;
+ psp->loaderPrivate = data;
+
+ driParseOptionInfo(&psp->optionInfo, __dri2ConfigOptions,
+ __dri2NConfigOptions);
+ driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum,
+ "dri2");
+
+ return psp;
+}
+
+static const __DRIextension **driGetExtensions(__DRIscreen *psp)
+{
+ return psp->extensions;
+}
+
+/** Core interface */
+const __DRIcoreExtension driCoreExtension = {
+ { __DRI_CORE, __DRI_CORE_VERSION },
+ NULL,
+ driDestroyScreen,
+ driGetExtensions,
+ driGetConfigAttrib,
+ driIndexConfigAttrib,
+ NULL,
+ driDestroyDrawable,
+ driSwapBuffers,
+ NULL,
+ driCopyContext,
+ driDestroyContext,
+ driBindContext,
+ driUnbindContext
+};
+
+/** Legacy DRI interface */
+const __DRIlegacyExtension driLegacyExtension = {
+ { __DRI_LEGACY, __DRI_LEGACY_VERSION },
+ driCreateNewScreen,
+ driCreateNewDrawable,
+ driCreateNewContext,
+};
+
+/** DRI2 interface */
+const __DRIdri2Extension driDRI2Extension = {
+ { __DRI_DRI2, __DRI_DRI2_VERSION },
+ dri2CreateNewScreen,
+ dri2CreateNewDrawable,
+ dri2CreateNewContext,
+ dri2GetAPIMask,
+ dri2CreateNewContextForAPI
+};
+
+const __DRI2configQueryExtension dri2ConfigQueryExtension = {
+ { __DRI2_CONFIG_QUERY, __DRI2_CONFIG_QUERY_VERSION },
+ dri2ConfigQueryb,
+ dri2ConfigQueryi,
+ dri2ConfigQueryf,
+};
+
+/**
+ * Calculate amount of swap interval used between GLX buffer swaps.
+ *
+ * The usage value, on the range [0,max], is the fraction of total swap
+ * interval time used between GLX buffer swaps is calculated.
+ *
+ * \f$p = t_d / (i * t_r)\f$
+ *
+ * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
+ * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
+ * required for a single vertical refresh period (as returned by \c
+ * glXGetMscRateOML).
+ *
+ * See the documentation for the GLX_MESA_swap_frame_usage extension for more
+ * details.
+ *
+ * \param dPriv Pointer to the private drawable structure.
+ * \return If less than a single swap interval time period was required
+ * between GLX buffer swaps, a number greater than 0 and less than
+ * 1.0 is returned. If exactly one swap interval time period is
+ * required, 1.0 is returned, and if more than one is required then
+ * a number greater than 1.0 will be returned.
+ *
+ * \sa glXSwapIntervalSGI glXGetMscRateOML
+ *
+ * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
+ * be possible to cache the sync rate?
+ */
+float
+driCalculateSwapUsage( __DRIdrawable *dPriv, int64_t last_swap_ust,
+ int64_t current_ust )
+{
+ int32_t n;
+ int32_t d;
+ int interval;
+ float usage = 1.0;
+ __DRIscreen *psp = dPriv->driScreenPriv;
+
+ if ( (*psp->systemTime->getMSCRate)(dPriv, &n, &d, dPriv->loaderPrivate) ) {
+ interval = (dPriv->swap_interval != 0) ? dPriv->swap_interval : 1;
+
+
+ /* We want to calculate
+ * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
+ * current_UST by calling __glXGetUST. last_swap_UST is stored in
+ * dPriv->swap_ust. interval has already been calculated.
+ *
+ * The only tricky part is us_per_refresh. us_per_refresh is
+ * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
+ * around and say us_per_refresh = 1000000 * d / n. Since this goes in
+ * the denominator of the final calculation, we calculate
+ * (interval * 1000000 * d) and move n into the numerator.
+ */
+
+ usage = (current_ust - last_swap_ust);
+ usage *= n;
+ usage /= (interval * d);
+ usage /= 1000000.0;
+ }
+
+ return usage;
+}
+
+void
+dri2InvalidateDrawable(__DRIdrawable *drawable)
+{
+ drawable->dri2.stamp++;
+}
+
+/*@}*/
diff --git a/mesalib/src/mesa/drivers/dri/common/dri_util.h b/mesalib/src/mesa/drivers/dri/common/dri_util.h index 785beacd8..b6f04993e 100644 --- a/mesalib/src/mesa/drivers/dri/common/dri_util.h +++ b/mesalib/src/mesa/drivers/dri/common/dri_util.h @@ -1,558 +1,557 @@ -/* - * 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/glcore.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 __GLcontextModes *glVis, - __DRIcontext *driContextPriv, - void *sharedContextPrivate); - - /** - * Context destruction callback - */ - void (*DestroyContext)(__DRIcontext *driContextPriv); - - /** - * Buffer (drawable) creation callback - */ - GLboolean (*CreateBuffer)(__DRIscreen *driScrnPriv, - __DRIdrawable *driDrawPriv, - const __GLcontextModes *glVis, - GLboolean pixmapBuffer); - - /** - * Buffer (drawable) destruction callback - */ - void (*DestroyBuffer)(__DRIdrawable *driDrawPriv); - - /** - * Buffer swapping callback - */ - void (*SwapBuffers)(__DRIdrawable *driDrawPriv); - - /** - * Context activation callback - */ - GLboolean (*MakeCurrent)(__DRIcontext *driContextPriv, - __DRIdrawable *driDrawPriv, - __DRIdrawable *driReadPriv); - - /** - * Context unbinding callback - */ - GLboolean (*UnbindContext)(__DRIcontext *driContextPriv); - - /** - * Retrieves statistics about buffer swap operations. Required if - * GLX_OML_sync_control or GLX_MESA_swap_frame_usage is supported. - */ - int (*GetSwapInfo)( __DRIdrawable *dPriv, __DRIswapInfo * sInfo ); - - - /** - * These are required if GLX_OML_sync_control is supported. - */ - /*@{*/ - int (*WaitForMSC)( __DRIdrawable *priv, int64_t target_msc, - int64_t divisor, int64_t remainder, - int64_t * msc ); - int (*WaitForSBC)( __DRIdrawable *priv, int64_t target_sbc, - int64_t * msc, int64_t * sbc ); - - int64_t (*SwapBuffersMSC)( __DRIdrawable *priv, int64_t target_msc, - int64_t divisor, int64_t remainder ); - /*@}*/ - void (*CopySubBuffer)(__DRIdrawable *driDrawPriv, - int x, int y, int w, int h); - - /** - * New version of GetMSC so we can pass drawable data to the low - * level DRM driver (e.g. pipe info). Required if - * GLX_SGI_video_sync or GLX_OML_sync_control is supported. - */ - int (*GetDrawableMSC) ( __DRIscreen * priv, - __DRIdrawable *drawablePrivate, - int64_t *count); - - - - /* DRI2 Entry point */ - const __DRIconfig **(*InitScreen2) (__DRIscreen * priv); -}; - -extern const struct __DriverAPIRec driDriverAPI; - - -struct __DRIswapInfoRec { - /** - * Number of swapBuffers operations that have been *completed*. - */ - uint64_t swap_count; - - /** - * Unadjusted system time of the last buffer swap. This is the time - * when the swap completed, not the time when swapBuffers was called. - */ - int64_t swap_ust; - - /** - * Number of swap operations that occurred after the swap deadline. That - * is if a swap happens more than swap_interval frames after the previous - * swap, it has missed its deadline. If swap_interval is 0, then the - * swap deadline is 1 frame after the previous swap. - */ - uint64_t swap_missed_count; - - /** - * Amount of time used by the last swap that missed its deadline. This - * is calculated as (__glXGetUST() - swap_ust) / (swap_interval * - * time_for_single_vrefresh)). If the actual value of swap_interval is - * 0, then 1 is used instead. If swap_missed_count is non-zero, this - * should be greater-than 1.0. - */ - float swap_missed_usage; -}; - - -/** - * Per-drawable private DRI driver information. - */ -struct __DRIdrawableRec { - /** - * Kernel drawable handle - */ - drm_drawable_t hHWDrawable; - - /** - * Driver's private drawable information. - * - * This structure is opaque. - */ - void *driverPrivate; - - /** - * Private data from the loader. We just hold on to it and pass - * it back when calling into loader provided functions. - */ - void *loaderPrivate; - - /** - * Reference count for number of context's currently bound to this - * drawable. - * - * Once it reaches zero, the drawable can be destroyed. - * - * \note This behavior will change with GLX 1.3. - */ - int refcount; - - /** - * Index of this drawable information in the SAREA. - */ - unsigned int index; - - /** - * Pointer to the "drawable has changed ID" stamp in the SAREA (or - * to dri2.stamp if DRI2 is being used). - */ - unsigned int *pStamp; - - /** - * Last value of the stamp. - * - * If this differs from the value stored at __DRIdrawable::pStamp, - * then the drawable information has been modified by the X server, and the - * drawable information (below) should be retrieved from the X server. - */ - unsigned int lastStamp; - - /** - * \name Drawable - * - * Drawable information used in software fallbacks. - */ - /*@{*/ - int x; - int y; - int w; - int h; - int numClipRects; - drm_clip_rect_t *pClipRects; - /*@}*/ - - /** - * \name Back and depthbuffer - * - * Information about the back and depthbuffer where different from above. - */ - /*@{*/ - int backX; - int backY; - int backClipRectType; - int numBackClipRects; - drm_clip_rect_t *pBackClipRects; - /*@}*/ - - /** - * \name Vertical blank tracking information - * Used for waiting on vertical blank events. - */ - /*@{*/ - unsigned int vblSeq; - unsigned int vblFlags; - /*@}*/ - - /** - * \name Monotonic MSC tracking - * - * Low level driver is responsible for updating msc_base and - * vblSeq values so that higher level code can calculate - * a new msc value or msc target for a WaitMSC call. The new value - * will be: - * msc = msc_base + get_vblank_count() - vblank_base; - * - * And for waiting on a value, core code will use: - * actual_target = target_msc - msc_base + vblank_base; - */ - /*@{*/ - int64_t vblank_base; - int64_t msc_base; - /*@}*/ - - /** - * Pointer to context to which this drawable is currently bound. - */ - __DRIcontext *driContextPriv; - - /** - * Pointer to screen on which this drawable was created. - */ - __DRIscreen *driScreenPriv; - - /** - * Controls swap interval as used by GLX_SGI_swap_control and - * GLX_MESA_swap_control. - */ - unsigned int swap_interval; - - struct { - unsigned int stamp; - drm_clip_rect_t clipRect; - } dri2; -}; - -/** - * Per-context private driver information. - */ -struct __DRIcontextRec { - /** - * Kernel context handle used to access the device lock. - */ - drm_context_t hHWContext; - - /** - * Device driver's private context data. This structure is opaque. - */ - void *driverPrivate; - - /** - * Pointer to drawable currently bound to this context for drawing. - */ - __DRIdrawable *driDrawablePriv; - - /** - * Pointer to drawable currently bound to this context for reading. - */ - __DRIdrawable *driReadablePriv; - - /** - * Pointer to screen on which this context was created. - */ - __DRIscreen *driScreenPriv; - - /** - * The loaders's private context data. This structure is opaque. - */ - void *loaderPrivate; - - struct { - int draw_stamp; - int read_stamp; - } dri2; -}; - -/** - * Per-screen private driver information. - */ -struct __DRIscreenRec { - /** - * Current screen's number - */ - int myNum; - - /** - * Callback functions into the hardware-specific DRI driver code. - */ - struct __DriverAPIRec DriverAPI; - - const __DRIextension **extensions; - /** - * DDX / 2D driver version information. - */ - __DRIversion ddx_version; - - /** - * DRI X extension version information. - */ - __DRIversion dri_version; - - /** - * DRM (kernel module) version information. - */ - __DRIversion drm_version; - - /** - * ID used when the client sets the drawable lock. - * - * The X server uses this value to detect if the client has died while - * holding the drawable lock. - */ - int drawLockID; - - /** - * File descriptor returned when the kernel device driver is opened. - * - * Used to: - * - authenticate client to kernel - * - map the frame buffer, SAREA, etc. - * - close the kernel device driver - */ - int fd; - - /** - * SAREA pointer - * - * Used to access: - * - the device lock - * - the device-independent per-drawable and per-context(?) information - */ - drm_sarea_t *pSAREA; - - /** - * \name Direct frame buffer access information - * Used for software fallbacks. - */ - /*@{*/ - unsigned char *pFB; - int fbSize; - int fbOrigin; - int fbStride; - int fbWidth; - int fbHeight; - int fbBPP; - /*@}*/ - - /** - * \name Device-dependent private information (stored in the SAREA). - * - * This data is accessed by the client driver only. - */ - /*@{*/ - void *pDevPriv; - int devPrivSize; - /*@}*/ - - /** - * Device-dependent private information (not stored in the SAREA). - * - * This pointer is never touched by the DRI layer. - */ -#ifdef __cplusplus - void *priv; -#else - void *private; -#endif - - /* Extensions provided by the loader. */ - const __DRIgetDrawableInfoExtension *getDrawableInfo; - const __DRIsystemTimeExtension *systemTime; - const __DRIdamageExtension *damage; - - struct { - /* Flag to indicate that this is a DRI2 screen. Many of the above - * fields will not be valid or initializaed in that case. */ - int enabled; - __DRIdri2LoaderExtension *loader; - __DRIimageLookupExtension *image; - __DRIuseInvalidateExtension *useInvalidate; - } dri2; - - /* The lock actually in use, old sarea or DRI2 */ - drmLock *lock; - - driOptionCache optionInfo; - driOptionCache optionCache; - unsigned int api_mask; - void *loaderPrivate; -}; - -extern void -__driUtilUpdateDrawableInfo(__DRIdrawable *pdp); - -extern float -driCalculateSwapUsage( __DRIdrawable *dPriv, - int64_t last_swap_ust, int64_t current_ust ); - -extern GLint -driIntersectArea( drm_clip_rect_t rect1, drm_clip_rect_t rect2 ); - -extern void -dri2InvalidateDrawable(__DRIdrawable *drawable); - -#endif /* _DRI_UTIL_H_ */ +/*
+ * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file dri_util.h
+ * DRI utility functions definitions.
+ *
+ * This module acts as glue between GLX and the actual hardware driver. A DRI
+ * driver doesn't really \e have to use any of this - it's optional. But, some
+ * useful stuff is done here that otherwise would have to be duplicated in most
+ * drivers.
+ *
+ * Basically, these utility functions take care of some of the dirty details of
+ * screen initialization, context creation, context binding, DRM setup, etc.
+ *
+ * These functions are compiled into each DRI driver so libGL.so knows nothing
+ * about them.
+ *
+ * \sa dri_util.c.
+ *
+ * \author Kevin E. Martin <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);
+};
+
+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/drirenderbuffer.c b/mesalib/src/mesa/drivers/dri/common/drirenderbuffer.c index c9ce6e3cb..5e032bd15 100644 --- a/mesalib/src/mesa/drivers/dri/common/drirenderbuffer.c +++ b/mesalib/src/mesa/drivers/dri/common/drirenderbuffer.c @@ -1,200 +1,200 @@ - -#include "main/mtypes.h" -#include "main/formats.h" -#include "main/renderbuffer.h" -#include "main/imports.h" -#include "drirenderbuffer.h" - - -/** - * This will get called when a window (gl_framebuffer) is resized (probably - * via driUpdateFramebufferSize(), below). - * Just update width, height and internal format fields for now. - * There's usually no memory allocation above because the present - * DRI drivers use statically-allocated full-screen buffers. If that's not - * the case for a DRI driver, a different AllocStorage method should - * be used. - */ -static GLboolean -driRenderbufferStorage(GLcontext *ctx, struct gl_renderbuffer *rb, - GLenum internalFormat, GLuint width, GLuint height) -{ - rb->Width = width; - rb->Height = height; - rb->InternalFormat = internalFormat; - return GL_TRUE; -} - - -static void -driDeleteRenderbuffer(struct gl_renderbuffer *rb) -{ - /* don't free rb->Data Chances are it's a memory mapped region for - * the dri drivers. - */ - free(rb); -} - - -/** - * Allocate a new driRenderbuffer object. - * Individual drivers are free to implement different versions of - * this function. - * - * At this time, this function can only be used for window-system - * renderbuffers, not user-created RBOs. - * - * \param format Either GL_RGBA, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, - * GL_DEPTH_COMPONENT32, or GL_STENCIL_INDEX8_EXT (for now). - * \param addr address in main memory of the buffer. Probably a memory - * mapped region. - * \param cpp chars or bytes per pixel - * \param offset start of renderbuffer with respect to start of framebuffer - * \param pitch pixels per row - */ -driRenderbuffer * -driNewRenderbuffer(gl_format format, GLvoid *addr, - GLint cpp, GLint offset, GLint pitch, - __DRIdrawable *dPriv) -{ - driRenderbuffer *drb; - - assert(cpp > 0); - assert(pitch > 0); - - drb = calloc(1, sizeof(driRenderbuffer)); - if (drb) { - const GLuint name = 0; - - _mesa_init_renderbuffer(&drb->Base, name); - - /* Make sure we're using a null-valued GetPointer routine */ - assert(drb->Base.GetPointer(NULL, &drb->Base, 0, 0) == NULL); - - switch (format) { - case MESA_FORMAT_ARGB8888: - if (cpp == 2) { - /* override format */ - format = MESA_FORMAT_RGB565; - } - drb->Base.DataType = GL_UNSIGNED_BYTE; - break; - case MESA_FORMAT_Z16: - /* Depth */ - /* we always Get/Put 32-bit Z values */ - drb->Base.DataType = GL_UNSIGNED_INT; - assert(cpp == 2); - break; - case MESA_FORMAT_Z32: - /* Depth */ - /* we always Get/Put 32-bit Z values */ - drb->Base.DataType = GL_UNSIGNED_INT; - assert(cpp == 4); - break; - case MESA_FORMAT_Z24_S8: - drb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT; - assert(cpp == 4); - break; - case MESA_FORMAT_S8_Z24: - drb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT; - assert(cpp == 4); - break; - case MESA_FORMAT_S8: - /* Stencil */ - drb->Base.DataType = GL_UNSIGNED_BYTE; - break; - default: - _mesa_problem(NULL, "Bad format 0x%x in driNewRenderbuffer", format); - return NULL; - } - - drb->Base.Format = format; - - drb->Base.InternalFormat = - drb->Base._BaseFormat = _mesa_get_format_base_format(format); - - drb->Base.AllocStorage = driRenderbufferStorage; - drb->Base.Delete = driDeleteRenderbuffer; - - drb->Base.Data = addr; - - /* DRI renderbuffer-specific fields: */ - drb->dPriv = dPriv; - drb->offset = offset; - drb->pitch = pitch; - drb->cpp = cpp; - - /* may be changed if page flipping is active: */ - drb->flippedOffset = offset; - drb->flippedPitch = pitch; - drb->flippedData = addr; - } - return drb; -} - - -/** - * Update the front and back renderbuffers' flippedPitch/Offset/Data fields. - * If stereo, flip both the left and right pairs. - * This is used when we do double buffering via page flipping. - * \param fb the framebuffer we're page flipping - * \param flipped if true, set flipped values, else set non-flipped values - */ -void -driFlipRenderbuffers(struct gl_framebuffer *fb, GLboolean flipped) -{ - const GLuint count = fb->Visual.stereoMode ? 2 : 1; - GLuint lr; /* left or right */ - - /* we shouldn't really call this function if single-buffered, but - * play it safe. - */ - if (!fb->Visual.doubleBufferMode) - return; - - for (lr = 0; lr < count; lr++) { - GLuint frontBuf = (lr == 0) ? BUFFER_FRONT_LEFT : BUFFER_FRONT_RIGHT; - GLuint backBuf = (lr == 0) ? BUFFER_BACK_LEFT : BUFFER_BACK_RIGHT; - driRenderbuffer *front_drb - = (driRenderbuffer *) fb->Attachment[frontBuf].Renderbuffer; - driRenderbuffer *back_drb - = (driRenderbuffer *) fb->Attachment[backBuf].Renderbuffer; - - if (flipped) { - front_drb->flippedOffset = back_drb->offset; - front_drb->flippedPitch = back_drb->pitch; - front_drb->flippedData = back_drb->Base.Data; - back_drb->flippedOffset = front_drb->offset; - back_drb->flippedPitch = front_drb->pitch; - back_drb->flippedData = front_drb->Base.Data; - } - else { - front_drb->flippedOffset = front_drb->offset; - front_drb->flippedPitch = front_drb->pitch; - front_drb->flippedData = front_drb->Base.Data; - back_drb->flippedOffset = back_drb->offset; - back_drb->flippedPitch = back_drb->pitch; - back_drb->flippedData = back_drb->Base.Data; - } - } -} - - -/** - * Check that the gl_framebuffer associated with dPriv is the right size. - * Resize the gl_framebuffer if needed. - * It's expected that the dPriv->driverPrivate member points to a - * gl_framebuffer object. - */ -void -driUpdateFramebufferSize(GLcontext *ctx, const __DRIdrawable *dPriv) -{ - struct gl_framebuffer *fb = (struct gl_framebuffer *) dPriv->driverPrivate; - if (fb && (dPriv->w != fb->Width || dPriv->h != fb->Height)) { - ctx->Driver.ResizeBuffers(ctx, fb, dPriv->w, dPriv->h); - /* if the driver needs the hw lock for ResizeBuffers, the drawable - might have changed again by now */ - assert(fb->Width == dPriv->w); - assert(fb->Height == dPriv->h); - } -} +
+#include "main/mtypes.h"
+#include "main/formats.h"
+#include "main/renderbuffer.h"
+#include "main/imports.h"
+#include "drirenderbuffer.h"
+
+
+/**
+ * This will get called when a window (gl_framebuffer) is resized (probably
+ * via driUpdateFramebufferSize(), below).
+ * Just update width, height and internal format fields for now.
+ * There's usually no memory allocation above because the present
+ * DRI drivers use statically-allocated full-screen buffers. If that's not
+ * the case for a DRI driver, a different AllocStorage method should
+ * be used.
+ */
+static GLboolean
+driRenderbufferStorage(struct gl_context *ctx, struct gl_renderbuffer *rb,
+ GLenum internalFormat, GLuint width, GLuint height)
+{
+ rb->Width = width;
+ rb->Height = height;
+ rb->InternalFormat = internalFormat;
+ return GL_TRUE;
+}
+
+
+static void
+driDeleteRenderbuffer(struct gl_renderbuffer *rb)
+{
+ /* don't free rb->Data Chances are it's a memory mapped region for
+ * the dri drivers.
+ */
+ free(rb);
+}
+
+
+/**
+ * Allocate a new driRenderbuffer object.
+ * Individual drivers are free to implement different versions of
+ * this function.
+ *
+ * At this time, this function can only be used for window-system
+ * renderbuffers, not user-created RBOs.
+ *
+ * \param format Either GL_RGBA, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24,
+ * GL_DEPTH_COMPONENT32, or GL_STENCIL_INDEX8_EXT (for now).
+ * \param addr address in main memory of the buffer. Probably a memory
+ * mapped region.
+ * \param cpp chars or bytes per pixel
+ * \param offset start of renderbuffer with respect to start of framebuffer
+ * \param pitch pixels per row
+ */
+driRenderbuffer *
+driNewRenderbuffer(gl_format format, GLvoid *addr,
+ GLint cpp, GLint offset, GLint pitch,
+ __DRIdrawable *dPriv)
+{
+ driRenderbuffer *drb;
+
+ assert(cpp > 0);
+ assert(pitch > 0);
+
+ drb = calloc(1, sizeof(driRenderbuffer));
+ if (drb) {
+ const GLuint name = 0;
+
+ _mesa_init_renderbuffer(&drb->Base, name);
+
+ /* Make sure we're using a null-valued GetPointer routine */
+ assert(drb->Base.GetPointer(NULL, &drb->Base, 0, 0) == NULL);
+
+ switch (format) {
+ case MESA_FORMAT_ARGB8888:
+ if (cpp == 2) {
+ /* override format */
+ format = MESA_FORMAT_RGB565;
+ }
+ drb->Base.DataType = GL_UNSIGNED_BYTE;
+ break;
+ case MESA_FORMAT_Z16:
+ /* Depth */
+ /* we always Get/Put 32-bit Z values */
+ drb->Base.DataType = GL_UNSIGNED_INT;
+ assert(cpp == 2);
+ break;
+ case MESA_FORMAT_Z32:
+ /* Depth */
+ /* we always Get/Put 32-bit Z values */
+ drb->Base.DataType = GL_UNSIGNED_INT;
+ assert(cpp == 4);
+ break;
+ case MESA_FORMAT_Z24_S8:
+ drb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT;
+ assert(cpp == 4);
+ break;
+ case MESA_FORMAT_S8_Z24:
+ drb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT;
+ assert(cpp == 4);
+ break;
+ case MESA_FORMAT_S8:
+ /* Stencil */
+ drb->Base.DataType = GL_UNSIGNED_BYTE;
+ break;
+ default:
+ _mesa_problem(NULL, "Bad format 0x%x in driNewRenderbuffer", format);
+ return NULL;
+ }
+
+ drb->Base.Format = format;
+
+ drb->Base.InternalFormat =
+ drb->Base._BaseFormat = _mesa_get_format_base_format(format);
+
+ drb->Base.AllocStorage = driRenderbufferStorage;
+ drb->Base.Delete = driDeleteRenderbuffer;
+
+ drb->Base.Data = addr;
+
+ /* DRI renderbuffer-specific fields: */
+ drb->dPriv = dPriv;
+ drb->offset = offset;
+ drb->pitch = pitch;
+ drb->cpp = cpp;
+
+ /* may be changed if page flipping is active: */
+ drb->flippedOffset = offset;
+ drb->flippedPitch = pitch;
+ drb->flippedData = addr;
+ }
+ return drb;
+}
+
+
+/**
+ * Update the front and back renderbuffers' flippedPitch/Offset/Data fields.
+ * If stereo, flip both the left and right pairs.
+ * This is used when we do double buffering via page flipping.
+ * \param fb the framebuffer we're page flipping
+ * \param flipped if true, set flipped values, else set non-flipped values
+ */
+void
+driFlipRenderbuffers(struct gl_framebuffer *fb, GLboolean flipped)
+{
+ const GLuint count = fb->Visual.stereoMode ? 2 : 1;
+ GLuint lr; /* left or right */
+
+ /* we shouldn't really call this function if single-buffered, but
+ * play it safe.
+ */
+ if (!fb->Visual.doubleBufferMode)
+ return;
+
+ for (lr = 0; lr < count; lr++) {
+ GLuint frontBuf = (lr == 0) ? BUFFER_FRONT_LEFT : BUFFER_FRONT_RIGHT;
+ GLuint backBuf = (lr == 0) ? BUFFER_BACK_LEFT : BUFFER_BACK_RIGHT;
+ driRenderbuffer *front_drb
+ = (driRenderbuffer *) fb->Attachment[frontBuf].Renderbuffer;
+ driRenderbuffer *back_drb
+ = (driRenderbuffer *) fb->Attachment[backBuf].Renderbuffer;
+
+ if (flipped) {
+ front_drb->flippedOffset = back_drb->offset;
+ front_drb->flippedPitch = back_drb->pitch;
+ front_drb->flippedData = back_drb->Base.Data;
+ back_drb->flippedOffset = front_drb->offset;
+ back_drb->flippedPitch = front_drb->pitch;
+ back_drb->flippedData = front_drb->Base.Data;
+ }
+ else {
+ front_drb->flippedOffset = front_drb->offset;
+ front_drb->flippedPitch = front_drb->pitch;
+ front_drb->flippedData = front_drb->Base.Data;
+ back_drb->flippedOffset = back_drb->offset;
+ back_drb->flippedPitch = back_drb->pitch;
+ back_drb->flippedData = back_drb->Base.Data;
+ }
+ }
+}
+
+
+/**
+ * Check that the gl_framebuffer associated with dPriv is the right size.
+ * Resize the gl_framebuffer if needed.
+ * It's expected that the dPriv->driverPrivate member points to a
+ * gl_framebuffer object.
+ */
+void
+driUpdateFramebufferSize(struct gl_context *ctx, const __DRIdrawable *dPriv)
+{
+ struct gl_framebuffer *fb = (struct gl_framebuffer *) dPriv->driverPrivate;
+ if (fb && (dPriv->w != fb->Width || dPriv->h != fb->Height)) {
+ ctx->Driver.ResizeBuffers(ctx, fb, dPriv->w, dPriv->h);
+ /* if the driver needs the hw lock for ResizeBuffers, the drawable
+ might have changed again by now */
+ assert(fb->Width == dPriv->w);
+ assert(fb->Height == dPriv->h);
+ }
+}
diff --git a/mesalib/src/mesa/drivers/dri/common/drirenderbuffer.h b/mesalib/src/mesa/drivers/dri/common/drirenderbuffer.h index 677511334..6c11d350d 100644 --- a/mesalib/src/mesa/drivers/dri/common/drirenderbuffer.h +++ b/mesalib/src/mesa/drivers/dri/common/drirenderbuffer.h @@ -1,79 +1,79 @@ - -/** - * A driRenderbuffer is dervied from gl_renderbuffer. - * It describes a color buffer (front or back), a depth buffer, or stencil - * buffer etc. - * Specific to DRI drivers are the offset and pitch fields. - */ - - -#ifndef DRIRENDERBUFFER_H -#define DRIRENDERBUFFER_H - -#include "main/mtypes.h" -#include "main/formats.h" -#include "dri_util.h" - - -typedef struct { - struct gl_renderbuffer Base; - - /* Chars or bytes per pixel. If Z and Stencil are stored together this - * will typically be 32 whether this a depth or stencil renderbuffer. - */ - GLint cpp; - - /* Buffer position and pitch (row stride). Recall that for today's DRI - * drivers, we have statically allocated color/depth/stencil buffers. - * So this information describes the whole screen, not just a window. - * To address pixels in a window, we need to know the window's position - * and size with respect to the screen. - */ - GLint offset; /* in bytes */ - GLint pitch; /* in pixels */ - - /* If the driver can do page flipping (full-screen double buffering) - * the current front/back buffers may get swapped. - * If page flipping is disabled, these fields will be identical to - * the offset/pitch/Data above. - * If page flipping is enabled, and this is the front(back) renderbuffer, - * flippedOffset/Pitch/Data will have the back(front) renderbuffer's values. - */ - GLint flippedOffset; - GLint flippedPitch; - GLvoid *flippedData; /* mmap'd address of buffer memory, if used */ - - /* Pointer to corresponding __DRIdrawable. This is used to compute - * the window's position within the framebuffer. - */ - __DRIdrawable *dPriv; - - /* XXX this is for radeon/r200 only. We should really create a new - * r200Renderbuffer class, derived from this class... not a huge deal. - */ - GLboolean depthHasSurface; - - /** - * A handy flag to know if this is the back color buffer. - * - * \note - * This is currently only used by tdfx. - */ - GLboolean backBuffer; -} driRenderbuffer; - - -extern driRenderbuffer * -driNewRenderbuffer(gl_format format, GLvoid *addr, - GLint cpp, GLint offset, GLint pitch, - __DRIdrawable *dPriv); - -extern void -driFlipRenderbuffers(struct gl_framebuffer *fb, GLboolean flipped); - - -extern void -driUpdateFramebufferSize(GLcontext *ctx, const __DRIdrawable *dPriv); - - -#endif /* DRIRENDERBUFFER_H */ +
+/**
+ * A driRenderbuffer is dervied from gl_renderbuffer.
+ * It describes a color buffer (front or back), a depth buffer, or stencil
+ * buffer etc.
+ * Specific to DRI drivers are the offset and pitch fields.
+ */
+
+
+#ifndef DRIRENDERBUFFER_H
+#define DRIRENDERBUFFER_H
+
+#include "main/mtypes.h"
+#include "main/formats.h"
+#include "dri_util.h"
+
+
+typedef struct {
+ struct gl_renderbuffer Base;
+
+ /* Chars or bytes per pixel. If Z and Stencil are stored together this
+ * will typically be 32 whether this a depth or stencil renderbuffer.
+ */
+ GLint cpp;
+
+ /* Buffer position and pitch (row stride). Recall that for today's DRI
+ * drivers, we have statically allocated color/depth/stencil buffers.
+ * So this information describes the whole screen, not just a window.
+ * To address pixels in a window, we need to know the window's position
+ * and size with respect to the screen.
+ */
+ GLint offset; /* in bytes */
+ GLint pitch; /* in pixels */
+
+ /* If the driver can do page flipping (full-screen double buffering)
+ * the current front/back buffers may get swapped.
+ * If page flipping is disabled, these fields will be identical to
+ * the offset/pitch/Data above.
+ * If page flipping is enabled, and this is the front(back) renderbuffer,
+ * flippedOffset/Pitch/Data will have the back(front) renderbuffer's values.
+ */
+ GLint flippedOffset;
+ GLint flippedPitch;
+ GLvoid *flippedData; /* mmap'd address of buffer memory, if used */
+
+ /* Pointer to corresponding __DRIdrawable. This is used to compute
+ * the window's position within the framebuffer.
+ */
+ __DRIdrawable *dPriv;
+
+ /* XXX this is for radeon/r200 only. We should really create a new
+ * r200Renderbuffer class, derived from this class... not a huge deal.
+ */
+ GLboolean depthHasSurface;
+
+ /**
+ * A handy flag to know if this is the back color buffer.
+ *
+ * \note
+ * This is currently only used by tdfx.
+ */
+ GLboolean backBuffer;
+} driRenderbuffer;
+
+
+extern driRenderbuffer *
+driNewRenderbuffer(gl_format format, GLvoid *addr,
+ GLint cpp, GLint offset, GLint pitch,
+ __DRIdrawable *dPriv);
+
+extern void
+driFlipRenderbuffers(struct gl_framebuffer *fb, GLboolean flipped);
+
+
+extern void
+driUpdateFramebufferSize(struct gl_context *ctx, const __DRIdrawable *dPriv);
+
+
+#endif /* DRIRENDERBUFFER_H */
diff --git a/mesalib/src/mesa/drivers/dri/common/drisw_util.h b/mesalib/src/mesa/drivers/dri/common/drisw_util.h index 9c3d01c99..cae47e1f6 100644 --- a/mesalib/src/mesa/drivers/dri/common/drisw_util.h +++ b/mesalib/src/mesa/drivers/dri/common/drisw_util.h @@ -1,135 +1,134 @@ -/* - * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. - * All Rights Reserved. - * Copyright 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. - */ - -/** - * @file - * Binding of the DRI interface (dri_interface.h) for DRISW. - * - * The DRISW structs are 'base classes' of the corresponding DRI1 / DRI2 (DRM) - * structs. The bindings for SW and DRM can be unified by making the DRM structs - * 'sub-classes' of the SW structs, either proper or with field re-ordering. - * - * The code can also be unified but that requires cluttering the common code - * with ifdef's and guarding with (__DRIscreen::fd >= 0) for DRM. - */ - -#ifndef _DRISW_UTIL_H -#define _DRISW_UTIL_H - -#include "main/mtypes.h" - -#include <GL/gl.h> -#include <GL/internal/glcore.h> -#include <GL/internal/dri_interface.h> -typedef struct _drmLock drmLock; - - -/** - * Extensions - */ -extern const __DRIcoreExtension driCoreExtension; -extern const __DRIswrastExtension driSWRastExtension; - - -/** - * Driver callback functions - */ -struct __DriverAPIRec { - const __DRIconfig **(*InitScreen) (__DRIscreen * priv); - - void (*DestroyScreen)(__DRIscreen *driScrnPriv); - - GLboolean (*CreateContext)(gl_api glapi, - const __GLcontextModes *glVis, - __DRIcontext *driContextPriv, - void *sharedContextPrivate); - - void (*DestroyContext)(__DRIcontext *driContextPriv); - - GLboolean (*CreateBuffer)(__DRIscreen *driScrnPriv, - __DRIdrawable *driDrawPriv, - const __GLcontextModes *glVis, - GLboolean pixmapBuffer); - - void (*DestroyBuffer)(__DRIdrawable *driDrawPriv); - - void (*SwapBuffers)(__DRIdrawable *driDrawPriv); - - GLboolean (*MakeCurrent)(__DRIcontext *driContextPriv, - __DRIdrawable *driDrawPriv, - __DRIdrawable *driReadPriv); - - GLboolean (*UnbindContext)(__DRIcontext *driContextPriv); -}; - -extern const struct __DriverAPIRec driDriverAPI; - - -/** - * Data types - */ -struct __DRIscreenRec { - int myNum; - - int fd; - - void *private; - - const __DRIextension **extensions; - - const __DRIswrastLoaderExtension *swrast_loader; -}; - -struct __DRIcontextRec { - - void *driverPrivate; - - void *loaderPrivate; - - __DRIdrawable *driDrawablePriv; - - __DRIdrawable *driReadablePriv; - - __DRIscreen *driScreenPriv; -}; - -struct __DRIdrawableRec { - - void *driverPrivate; - - void *loaderPrivate; - - __DRIcontext *driContextPriv; - - __DRIscreen *driScreenPriv; - - int refcount; - - /* gallium */ - unsigned int lastStamp; - - int w; - int h; -}; - -#endif /* _DRISW_UTIL_H */ +/*
+ * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * Copyright 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.
+ */
+
+/**
+ * @file
+ * Binding of the DRI interface (dri_interface.h) for DRISW.
+ *
+ * The DRISW structs are 'base classes' of the corresponding DRI1 / DRI2 (DRM)
+ * structs. The bindings for SW and DRM can be unified by making the DRM structs
+ * 'sub-classes' of the SW structs, either proper or with field re-ordering.
+ *
+ * The code can also be unified but that requires cluttering the common code
+ * with ifdef's and guarding with (__DRIscreen::fd >= 0) for DRM.
+ */
+
+#ifndef _DRISW_UTIL_H
+#define _DRISW_UTIL_H
+
+#include "main/mtypes.h"
+
+#include <GL/gl.h>
+#include <GL/internal/dri_interface.h>
+typedef struct _drmLock drmLock;
+
+
+/**
+ * Extensions
+ */
+extern const __DRIcoreExtension driCoreExtension;
+extern const __DRIswrastExtension driSWRastExtension;
+
+
+/**
+ * Driver callback functions
+ */
+struct __DriverAPIRec {
+ const __DRIconfig **(*InitScreen) (__DRIscreen * priv);
+
+ void (*DestroyScreen)(__DRIscreen *driScrnPriv);
+
+ GLboolean (*CreateContext)(gl_api glapi,
+ const struct gl_config *glVis,
+ __DRIcontext *driContextPriv,
+ void *sharedContextPrivate);
+
+ void (*DestroyContext)(__DRIcontext *driContextPriv);
+
+ GLboolean (*CreateBuffer)(__DRIscreen *driScrnPriv,
+ __DRIdrawable *driDrawPriv,
+ const struct gl_config *glVis,
+ GLboolean pixmapBuffer);
+
+ void (*DestroyBuffer)(__DRIdrawable *driDrawPriv);
+
+ void (*SwapBuffers)(__DRIdrawable *driDrawPriv);
+
+ GLboolean (*MakeCurrent)(__DRIcontext *driContextPriv,
+ __DRIdrawable *driDrawPriv,
+ __DRIdrawable *driReadPriv);
+
+ GLboolean (*UnbindContext)(__DRIcontext *driContextPriv);
+};
+
+extern const struct __DriverAPIRec driDriverAPI;
+
+
+/**
+ * Data types
+ */
+struct __DRIscreenRec {
+ int myNum;
+
+ int fd;
+
+ void *private;
+
+ const __DRIextension **extensions;
+
+ const __DRIswrastLoaderExtension *swrast_loader;
+};
+
+struct __DRIcontextRec {
+
+ void *driverPrivate;
+
+ void *loaderPrivate;
+
+ __DRIdrawable *driDrawablePriv;
+
+ __DRIdrawable *driReadablePriv;
+
+ __DRIscreen *driScreenPriv;
+};
+
+struct __DRIdrawableRec {
+
+ void *driverPrivate;
+
+ void *loaderPrivate;
+
+ __DRIcontext *driContextPriv;
+
+ __DRIscreen *driScreenPriv;
+
+ int refcount;
+
+ /* gallium */
+ unsigned int lastStamp;
+
+ int w;
+ int h;
+};
+
+#endif /* _DRISW_UTIL_H */
diff --git a/mesalib/src/mesa/drivers/dri/common/spantmp.h b/mesalib/src/mesa/drivers/dri/common/spantmp.h index cdc4f422c..9aea3660c 100644 --- a/mesalib/src/mesa/drivers/dri/common/spantmp.h +++ b/mesalib/src/mesa/drivers/dri/common/spantmp.h @@ -1,325 +1,325 @@ -/* - * Copyright 2000-2001 VA Linux Systems, Inc. - * (C) Copyright IBM Corporation 2002, 2003 - * 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 - * VA LINUX SYSTEM, IBM 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 <keithw@tungstengraphics.com> - * Gareth Hughes <gareth@nvidia.com> - */ - -#include "spantmp_common.h" - -#ifndef DBG -#define DBG 0 -#endif - -#ifndef HW_READ_CLIPLOOP -#define HW_READ_CLIPLOOP() HW_CLIPLOOP() -#endif - -#ifndef HW_WRITE_CLIPLOOP -#define HW_WRITE_CLIPLOOP() HW_CLIPLOOP() -#endif - - -static void TAG(WriteRGBASpan)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const void *values, const GLubyte mask[] ) -{ - HW_WRITE_LOCK() - { - const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) values; - GLint x1; - GLint n1; - LOCAL_VARS; - - y = Y_FLIP(y); - - HW_WRITE_CLIPLOOP() - { - GLint i = 0; - CLIPSPAN(x,y,n,x1,n1,i); - - if (DBG) fprintf(stderr, "WriteRGBASpan %d..%d (x1 %d)\n", - (int)i, (int)n1, (int)x1); - - if (mask) - { - for (;n1>0;i++,x1++,n1--) - if (mask[i]) - WRITE_RGBA( x1, y, - rgba[i][0], rgba[i][1], - rgba[i][2], rgba[i][3] ); - } - else - { - for (;n1>0;i++,x1++,n1--) - WRITE_RGBA( x1, y, - rgba[i][0], rgba[i][1], - rgba[i][2], rgba[i][3] ); - } - } - HW_ENDCLIPLOOP(); - } - HW_WRITE_UNLOCK(); -} - -static void TAG(WriteRGBSpan)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const void *values, const GLubyte mask[] ) -{ - HW_WRITE_LOCK() - { - const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) values; - GLint x1; - GLint n1; - LOCAL_VARS; - - y = Y_FLIP(y); - - HW_WRITE_CLIPLOOP() - { - GLint i = 0; - CLIPSPAN(x,y,n,x1,n1,i); - - if (DBG) fprintf(stderr, "WriteRGBSpan %d..%d (x1 %d)\n", - (int)i, (int)n1, (int)x1); - - if (mask) - { - for (;n1>0;i++,x1++,n1--) - if (mask[i]) - WRITE_RGBA( x1, y, rgb[i][0], rgb[i][1], rgb[i][2], 255 ); - } - else - { - for (;n1>0;i++,x1++,n1--) - WRITE_RGBA( x1, y, rgb[i][0], rgb[i][1], rgb[i][2], 255 ); - } - } - HW_ENDCLIPLOOP(); - } - HW_WRITE_UNLOCK(); -} - -static void TAG(WriteRGBAPixels)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, const GLint x[], const GLint y[], - const void *values, const GLubyte mask[] ) -{ - HW_WRITE_LOCK() - { - const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) values; - GLuint i; - LOCAL_VARS; - - if (DBG) fprintf(stderr, "WriteRGBAPixels\n"); - - HW_WRITE_CLIPLOOP() - { - if (mask) - { - for (i=0;i<n;i++) - { - if (mask[i]) { - const int fy = Y_FLIP(y[i]); - if (CLIPPIXEL(x[i],fy)) - WRITE_RGBA( x[i], fy, - rgba[i][0], rgba[i][1], - rgba[i][2], rgba[i][3] ); - } - } - } - else - { - for (i=0;i<n;i++) - { - const int fy = Y_FLIP(y[i]); - if (CLIPPIXEL(x[i],fy)) - WRITE_RGBA( x[i], fy, - rgba[i][0], rgba[i][1], - rgba[i][2], rgba[i][3] ); - } - } - } - HW_ENDCLIPLOOP(); - } - HW_WRITE_UNLOCK(); -} - - -static void TAG(WriteMonoRGBASpan)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const void *value, - const GLubyte mask[] ) -{ - HW_WRITE_LOCK() - { - const GLubyte *color = (const GLubyte *) value; - GLint x1; - GLint n1; - LOCAL_VARS; - INIT_MONO_PIXEL(p, color); - - y = Y_FLIP( y ); - - if (DBG) fprintf(stderr, "WriteMonoRGBASpan\n"); - - HW_WRITE_CLIPLOOP() - { - GLint i = 0; - CLIPSPAN(x,y,n,x1,n1,i); - if (mask) - { - for (;n1>0;i++,x1++,n1--) - if (mask[i]) - WRITE_PIXEL( x1, y, p ); - } - else - { - for (;n1>0;i++,x1++,n1--) - WRITE_PIXEL( x1, y, p ); - } - } - HW_ENDCLIPLOOP(); - } - HW_WRITE_UNLOCK(); -} - - -static void TAG(WriteMonoRGBAPixels)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, - const GLint x[], const GLint y[], - const void *value, - const GLubyte mask[] ) -{ - HW_WRITE_LOCK() - { - const GLubyte *color = (const GLubyte *) value; - GLuint i; - LOCAL_VARS; - INIT_MONO_PIXEL(p, color); - - if (DBG) fprintf(stderr, "WriteMonoRGBAPixels\n"); - - HW_WRITE_CLIPLOOP() - { - if (mask) - { - for (i=0;i<n;i++) - if (mask[i]) { - int fy = Y_FLIP(y[i]); - if (CLIPPIXEL( x[i], fy )) - WRITE_PIXEL( x[i], fy, p ); - } - } - else - { - for (i=0;i<n;i++) { - int fy = Y_FLIP(y[i]); - if (CLIPPIXEL( x[i], fy )) - WRITE_PIXEL( x[i], fy, p ); - } - } - } - HW_ENDCLIPLOOP(); - } - HW_WRITE_UNLOCK(); -} - - -static void TAG(ReadRGBASpan)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - void *values) -{ - HW_READ_LOCK() - { - GLubyte (*rgba)[4] = (GLubyte (*)[4]) values; - GLint x1,n1; - LOCAL_VARS; - - y = Y_FLIP(y); - - if (DBG) fprintf(stderr, "ReadRGBASpan\n"); - - HW_READ_CLIPLOOP() - { - GLint i = 0; - CLIPSPAN(x,y,n,x1,n1,i); - for (;n1>0;i++,x1++,n1--) - READ_RGBA( rgba[i], x1, y ); - } - HW_ENDCLIPLOOP(); - } - HW_READ_UNLOCK(); -} - - -static void TAG(ReadRGBAPixels)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, const GLint x[], const GLint y[], - void *values ) -{ - HW_READ_LOCK() - { - GLubyte (*rgba)[4] = (GLubyte (*)[4]) values; - GLuint i; - LOCAL_VARS; - - if (DBG) fprintf(stderr, "ReadRGBAPixels\n"); - - HW_READ_CLIPLOOP() - { - for (i=0;i<n;i++) { - int fy = Y_FLIP( y[i] ); - if (CLIPPIXEL( x[i], fy )) - READ_RGBA( rgba[i], x[i], fy ); - } - } - HW_ENDCLIPLOOP(); - } - HW_READ_UNLOCK(); -} - - -static void TAG(InitPointers)(struct gl_renderbuffer *rb) -{ - rb->PutRow = TAG(WriteRGBASpan); - rb->PutRowRGB = TAG(WriteRGBSpan); - rb->PutMonoRow = TAG(WriteMonoRGBASpan); - rb->PutValues = TAG(WriteRGBAPixels); - rb->PutMonoValues = TAG(WriteMonoRGBAPixels); - rb->GetValues = TAG(ReadRGBAPixels); - rb->GetRow = TAG(ReadRGBASpan); -} - - -#undef WRITE_PIXEL -#undef WRITE_RGBA -#undef READ_RGBA -#undef TAG +/*
+ * Copyright 2000-2001 VA Linux Systems, Inc.
+ * (C) Copyright IBM Corporation 2002, 2003
+ * 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
+ * VA LINUX SYSTEM, IBM 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 <keithw@tungstengraphics.com>
+ * Gareth Hughes <gareth@nvidia.com>
+ */
+
+#include "spantmp_common.h"
+
+#ifndef DBG
+#define DBG 0
+#endif
+
+#ifndef HW_READ_CLIPLOOP
+#define HW_READ_CLIPLOOP() HW_CLIPLOOP()
+#endif
+
+#ifndef HW_WRITE_CLIPLOOP
+#define HW_WRITE_CLIPLOOP() HW_CLIPLOOP()
+#endif
+
+
+static void TAG(WriteRGBASpan)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const void *values, const GLubyte mask[] )
+{
+ HW_WRITE_LOCK()
+ {
+ const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) values;
+ GLint x1;
+ GLint n1;
+ LOCAL_VARS;
+
+ y = Y_FLIP(y);
+
+ HW_WRITE_CLIPLOOP()
+ {
+ GLint i = 0;
+ CLIPSPAN(x,y,n,x1,n1,i);
+
+ if (DBG) fprintf(stderr, "WriteRGBASpan %d..%d (x1 %d)\n",
+ (int)i, (int)n1, (int)x1);
+
+ if (mask)
+ {
+ for (;n1>0;i++,x1++,n1--)
+ if (mask[i])
+ WRITE_RGBA( x1, y,
+ rgba[i][0], rgba[i][1],
+ rgba[i][2], rgba[i][3] );
+ }
+ else
+ {
+ for (;n1>0;i++,x1++,n1--)
+ WRITE_RGBA( x1, y,
+ rgba[i][0], rgba[i][1],
+ rgba[i][2], rgba[i][3] );
+ }
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_WRITE_UNLOCK();
+}
+
+static void TAG(WriteRGBSpan)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const void *values, const GLubyte mask[] )
+{
+ HW_WRITE_LOCK()
+ {
+ const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) values;
+ GLint x1;
+ GLint n1;
+ LOCAL_VARS;
+
+ y = Y_FLIP(y);
+
+ HW_WRITE_CLIPLOOP()
+ {
+ GLint i = 0;
+ CLIPSPAN(x,y,n,x1,n1,i);
+
+ if (DBG) fprintf(stderr, "WriteRGBSpan %d..%d (x1 %d)\n",
+ (int)i, (int)n1, (int)x1);
+
+ if (mask)
+ {
+ for (;n1>0;i++,x1++,n1--)
+ if (mask[i])
+ WRITE_RGBA( x1, y, rgb[i][0], rgb[i][1], rgb[i][2], 255 );
+ }
+ else
+ {
+ for (;n1>0;i++,x1++,n1--)
+ WRITE_RGBA( x1, y, rgb[i][0], rgb[i][1], rgb[i][2], 255 );
+ }
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_WRITE_UNLOCK();
+}
+
+static void TAG(WriteRGBAPixels)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, const GLint x[], const GLint y[],
+ const void *values, const GLubyte mask[] )
+{
+ HW_WRITE_LOCK()
+ {
+ const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) values;
+ GLuint i;
+ LOCAL_VARS;
+
+ if (DBG) fprintf(stderr, "WriteRGBAPixels\n");
+
+ HW_WRITE_CLIPLOOP()
+ {
+ if (mask)
+ {
+ for (i=0;i<n;i++)
+ {
+ if (mask[i]) {
+ const int fy = Y_FLIP(y[i]);
+ if (CLIPPIXEL(x[i],fy))
+ WRITE_RGBA( x[i], fy,
+ rgba[i][0], rgba[i][1],
+ rgba[i][2], rgba[i][3] );
+ }
+ }
+ }
+ else
+ {
+ for (i=0;i<n;i++)
+ {
+ const int fy = Y_FLIP(y[i]);
+ if (CLIPPIXEL(x[i],fy))
+ WRITE_RGBA( x[i], fy,
+ rgba[i][0], rgba[i][1],
+ rgba[i][2], rgba[i][3] );
+ }
+ }
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_WRITE_UNLOCK();
+}
+
+
+static void TAG(WriteMonoRGBASpan)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const void *value,
+ const GLubyte mask[] )
+{
+ HW_WRITE_LOCK()
+ {
+ const GLubyte *color = (const GLubyte *) value;
+ GLint x1;
+ GLint n1;
+ LOCAL_VARS;
+ INIT_MONO_PIXEL(p, color);
+
+ y = Y_FLIP( y );
+
+ if (DBG) fprintf(stderr, "WriteMonoRGBASpan\n");
+
+ HW_WRITE_CLIPLOOP()
+ {
+ GLint i = 0;
+ CLIPSPAN(x,y,n,x1,n1,i);
+ if (mask)
+ {
+ for (;n1>0;i++,x1++,n1--)
+ if (mask[i])
+ WRITE_PIXEL( x1, y, p );
+ }
+ else
+ {
+ for (;n1>0;i++,x1++,n1--)
+ WRITE_PIXEL( x1, y, p );
+ }
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_WRITE_UNLOCK();
+}
+
+
+static void TAG(WriteMonoRGBAPixels)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n,
+ const GLint x[], const GLint y[],
+ const void *value,
+ const GLubyte mask[] )
+{
+ HW_WRITE_LOCK()
+ {
+ const GLubyte *color = (const GLubyte *) value;
+ GLuint i;
+ LOCAL_VARS;
+ INIT_MONO_PIXEL(p, color);
+
+ if (DBG) fprintf(stderr, "WriteMonoRGBAPixels\n");
+
+ HW_WRITE_CLIPLOOP()
+ {
+ if (mask)
+ {
+ for (i=0;i<n;i++)
+ if (mask[i]) {
+ int fy = Y_FLIP(y[i]);
+ if (CLIPPIXEL( x[i], fy ))
+ WRITE_PIXEL( x[i], fy, p );
+ }
+ }
+ else
+ {
+ for (i=0;i<n;i++) {
+ int fy = Y_FLIP(y[i]);
+ if (CLIPPIXEL( x[i], fy ))
+ WRITE_PIXEL( x[i], fy, p );
+ }
+ }
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_WRITE_UNLOCK();
+}
+
+
+static void TAG(ReadRGBASpan)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ void *values)
+{
+ HW_READ_LOCK()
+ {
+ GLubyte (*rgba)[4] = (GLubyte (*)[4]) values;
+ GLint x1,n1;
+ LOCAL_VARS;
+
+ y = Y_FLIP(y);
+
+ if (DBG) fprintf(stderr, "ReadRGBASpan\n");
+
+ HW_READ_CLIPLOOP()
+ {
+ GLint i = 0;
+ CLIPSPAN(x,y,n,x1,n1,i);
+ for (;n1>0;i++,x1++,n1--)
+ READ_RGBA( rgba[i], x1, y );
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_READ_UNLOCK();
+}
+
+
+static void TAG(ReadRGBAPixels)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, const GLint x[], const GLint y[],
+ void *values )
+{
+ HW_READ_LOCK()
+ {
+ GLubyte (*rgba)[4] = (GLubyte (*)[4]) values;
+ GLuint i;
+ LOCAL_VARS;
+
+ if (DBG) fprintf(stderr, "ReadRGBAPixels\n");
+
+ HW_READ_CLIPLOOP()
+ {
+ for (i=0;i<n;i++) {
+ int fy = Y_FLIP( y[i] );
+ if (CLIPPIXEL( x[i], fy ))
+ READ_RGBA( rgba[i], x[i], fy );
+ }
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_READ_UNLOCK();
+}
+
+
+static void TAG(InitPointers)(struct gl_renderbuffer *rb)
+{
+ rb->PutRow = TAG(WriteRGBASpan);
+ rb->PutRowRGB = TAG(WriteRGBSpan);
+ rb->PutMonoRow = TAG(WriteMonoRGBASpan);
+ rb->PutValues = TAG(WriteRGBAPixels);
+ rb->PutMonoValues = TAG(WriteMonoRGBAPixels);
+ rb->GetValues = TAG(ReadRGBAPixels);
+ rb->GetRow = TAG(ReadRGBASpan);
+}
+
+
+#undef WRITE_PIXEL
+#undef WRITE_RGBA
+#undef READ_RGBA
+#undef TAG
diff --git a/mesalib/src/mesa/drivers/dri/common/spantmp2.h b/mesalib/src/mesa/drivers/dri/common/spantmp2.h index 1dab7336b..160836a77 100644 --- a/mesalib/src/mesa/drivers/dri/common/spantmp2.h +++ b/mesalib/src/mesa/drivers/dri/common/spantmp2.h @@ -1,916 +1,1038 @@ -/* - * Copyright 2000-2001 VA Linux Systems, Inc. - * (C) Copyright IBM Corporation 2004 - * 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 - * VA LINUX SYSTEM, IBM 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. - */ - -/** - * \file spantmp2.h - * - * Template file of span read / write functions. - * - * \author Keith Whitwell <keithw@tungstengraphics.com> - * \author Gareth Hughes <gareth@nvidia.com> - * \author Ian Romanick <idr@us.ibm.com> - */ - -#include "main/colormac.h" -#include "spantmp_common.h" - -#ifndef DBG -#define DBG 0 -#endif - -#ifndef HW_READ_CLIPLOOP -#define HW_READ_CLIPLOOP() HW_CLIPLOOP() -#endif - -#ifndef HW_WRITE_CLIPLOOP -#define HW_WRITE_CLIPLOOP() HW_CLIPLOOP() -#endif - -#if (SPANTMP_PIXEL_FMT == GL_RGB) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_5_6_5) - -/** - ** GL_RGB, GL_UNSIGNED_SHORT_5_6_5 - **/ - -#ifndef GET_VALUE -#ifndef GET_PTR -#define GET_PTR(_x, _y) (buf + (_x) * 2 + (_y) * pitch) -#endif - -#define GET_VALUE(_x, _y) *(volatile GLushort *)(GET_PTR(_x, _y)) -#define PUT_VALUE(_x, _y, _v) *(volatile GLushort *)(GET_PTR(_x, _y)) = (_v) -#endif /* GET_VALUE */ - -#define INIT_MONO_PIXEL(p, color) \ - p = PACK_COLOR_565( color[0], color[1], color[2] ) - -#define WRITE_RGBA( _x, _y, r, g, b, a ) \ - PUT_VALUE(_x, _y, ((((int)r & 0xf8) << 8) | \ - (((int)g & 0xfc) << 3) | \ - (((int)b & 0xf8) >> 3))) \ - -#define WRITE_PIXEL( _x, _y, p ) PUT_VALUE(_x, _y, p) - -#define READ_RGBA( rgba, _x, _y ) \ - do { \ - GLushort p = GET_VALUE(_x, _y); \ - rgba[0] = ((p >> 8) & 0xf8) * 255 / 0xf8; \ - rgba[1] = ((p >> 3) & 0xfc) * 255 / 0xfc; \ - rgba[2] = ((p << 3) & 0xf8) * 255 / 0xf8; \ - rgba[3] = 0xff; \ - } while (0) - -#elif (SPANTMP_PIXEL_FMT == GL_RGB) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_5_6_5_REV) - -/** - ** GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV - **/ - -#ifndef GET_VALUE -#ifndef GET_PTR -#define GET_PTR(_x, _y) (buf + (_x) * 2 + (_y) * pitch) -#endif - -#define GET_VALUE(_x, _y) *(volatile GLushort *)(GET_PTR(_x, _y)) -#define PUT_VALUE(_x, _y, _v) *(volatile GLushort *)(GET_PTR(_x, _y)) = (_v) -#endif /* GET_VALUE */ - -#define INIT_MONO_PIXEL(p, color) \ - p = PACK_COLOR_565_REV( color[0], color[1], color[2] ) - -#define WRITE_RGBA( _x, _y, r, g, b, a ) \ - PUT_VALUE(_x, _y, PACK_COLOR_565_REV( r, g, b )) - -#define WRITE_PIXEL( _x, _y, p ) PUT_VALUE(_x, _y, p) - -#define READ_RGBA( rgba, _x, _y ) \ - do { \ - GLushort p = GET_VALUE(_x, _y); \ - p = p << 8 | p >> 8; \ - rgba[0] = ((p >> 8) & 0xf8) * 255 / 0xf8; \ - rgba[1] = ((p >> 3) & 0xfc) * 255 / 0xfc; \ - rgba[2] = ((p << 3) & 0xf8) * 255 / 0xf8; \ - rgba[3] = 0xff; \ - } while (0) - -#elif (SPANTMP_PIXEL_FMT == GL_BGRA) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_4_4_4_4) - -/** - ** GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4 - **/ - -#ifndef GET_VALUE -#ifndef GET_PTR -#define GET_PTR(_x, _y) (buf + (_x) * 2 + (_y) * pitch) -#endif - -#define GET_VALUE(_x, _y) *(volatile GLushort *)(GET_PTR(_x, _y)) -#define PUT_VALUE(_x, _y, _v) *(volatile GLushort *)(GET_PTR(_x, _y)) = (_v) -#endif /* GET_VALUE */ - -#define INIT_MONO_PIXEL(p, color) \ - p = PACK_COLOR_4444_REV(color[3], color[0], color[1], color[2]) - -#define WRITE_RGBA( _x, _y, r, g, b, a ) \ - PUT_VALUE(_x, _y, PACK_COLOR_4444_REV(a, r, g, b)) \ - -#define WRITE_PIXEL( _x, _y, p ) PUT_VALUE(_x, _y, p) - -#define READ_RGBA( rgba, _x, _y ) \ - do { \ - GLushort p = GET_VALUE(_x, _y); \ - rgba[0] = ((p >> 0) & 0xf) * 0x11; \ - rgba[1] = ((p >> 12) & 0xf) * 0x11; \ - rgba[2] = ((p >> 4) & 0xf) * 0x11; \ - rgba[3] = ((p >> 8) & 0xf) * 0x11; \ - } while (0) - - -#elif (SPANTMP_PIXEL_FMT == GL_BGRA) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_4_4_4_4_REV) - -/** - ** GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV - **/ - -#ifndef GET_VALUE -#ifndef GET_PTR -#define GET_PTR(_x, _y) (buf + (_x) * 2 + (_y) * pitch) -#endif - -#define GET_VALUE(_x, _y) *(volatile GLushort *)(GET_PTR(_x, _y)) -#define PUT_VALUE(_x, _y, _v) *(volatile GLushort *)(GET_PTR(_x, _y)) = (_v) -#endif /* GET_VALUE */ - -#define INIT_MONO_PIXEL(p, color) \ - p = PACK_COLOR_4444(color[3], color[0], color[1], color[2]) - -#define WRITE_RGBA( _x, _y, r, g, b, a ) \ - PUT_VALUE(_x, _y, PACK_COLOR_4444(a, r, g, b)) \ - -#define WRITE_PIXEL( _x, _y, p ) PUT_VALUE(_x, _y, p) - -#define READ_RGBA( rgba, _x, _y ) \ - do { \ - GLushort p = GET_VALUE(_x, _y); \ - rgba[0] = ((p >> 8) & 0xf) * 0x11; \ - rgba[1] = ((p >> 4) & 0xf) * 0x11; \ - rgba[2] = ((p >> 0) & 0xf) * 0x11; \ - rgba[3] = ((p >> 12) & 0xf) * 0x11; \ - } while (0) - - -#elif (SPANTMP_PIXEL_FMT == GL_BGRA) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_1_5_5_5_REV) - -/** - ** GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV - **/ - -#ifndef GET_VALUE -#ifndef GET_PTR -#define GET_PTR(_x, _y) (buf + (_x) * 2 + (_y) * pitch) -#endif - -#define GET_VALUE(_x, _y) *(volatile GLushort *)(GET_PTR(_x, _y)) -#define PUT_VALUE(_x, _y, _v) *(volatile GLushort *)(GET_PTR(_x, _y)) = (_v) -#endif /* GET_VALUE */ - -#define INIT_MONO_PIXEL(p, color) \ - p = PACK_COLOR_1555(color[3], color[0], color[1], color[2]) - -#define WRITE_RGBA( _x, _y, r, g, b, a ) \ - PUT_VALUE(_x, _y, PACK_COLOR_1555(a, r, g, b)) \ - -#define WRITE_PIXEL( _x, _y, p ) PUT_VALUE(_x, _y, p) - -#define READ_RGBA( rgba, _x, _y ) \ - do { \ - GLushort p = GET_VALUE(_x, _y); \ - rgba[0] = ((p >> 7) & 0xf8) * 255 / 0xf8; \ - rgba[1] = ((p >> 2) & 0xf8) * 255 / 0xf8; \ - rgba[2] = ((p << 3) & 0xf8) * 255 / 0xf8; \ - rgba[3] = ((p >> 15) & 0x1) * 0xff; \ - } while (0) - -#elif (SPANTMP_PIXEL_FMT == GL_BGRA) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_1_5_5_5) - -/** - ** GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5 - **/ - -#ifndef GET_VALUE -#ifndef GET_PTR -#define GET_PTR(_x, _y) (buf + (_x) * 2 + (_y) * pitch) -#endif - -#define GET_VALUE(_x, _y) *(volatile GLushort *)(GET_PTR(_x, _y)) -#define PUT_VALUE(_x, _y, _v) *(volatile GLushort *)(GET_PTR(_x, _y)) = (_v) -#endif /* GET_VALUE */ - -#define INIT_MONO_PIXEL(p, color) \ - p = PACK_COLOR_1555_REV(color[3], color[0], color[1], color[2]) - -#define WRITE_RGBA( _x, _y, r, g, b, a ) \ - PUT_VALUE(_x, _y, PACK_COLOR_1555_REV(a, r, g, b)) \ - -#define WRITE_PIXEL( _x, _y, p ) PUT_VALUE(_x, _y, p) - -#define READ_RGBA( rgba, _x, _y ) \ - do { \ - GLushort p = GET_VALUE(_x, _y); \ - p = p << 8 | p >> 8; \ - rgba[0] = ((p >> 7) & 0xf8) * 255 / 0xf8; \ - rgba[1] = ((p >> 2) & 0xf8) * 255 / 0xf8; \ - rgba[2] = ((p << 3) & 0xf8) * 255 / 0xf8; \ - rgba[3] = ((p >> 15) & 0x1) * 0xff; \ - } while (0) - -#elif (SPANTMP_PIXEL_FMT == GL_BGRA) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8_REV) - -/** - ** GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV - **/ - -#ifndef GET_VALUE -#ifndef GET_PTR -#define GET_PTR(_x, _y) ( buf + (_x) * 4 + (_y) * pitch) -#endif - -#define GET_VALUE(_x, _y) *(volatile GLuint *)(GET_PTR(_x, _y)) -#define PUT_VALUE(_x, _y, _v) *(volatile GLuint *)(GET_PTR(_x, _y)) = (_v) -#endif /* GET_VALUE */ - -# define INIT_MONO_PIXEL(p, color) \ - p = PACK_COLOR_8888(color[3], color[0], color[1], color[2]) - -# define WRITE_RGBA(_x, _y, r, g, b, a) \ - PUT_VALUE(_x, _y, ((r << 16) | \ - (g << 8) | \ - (b << 0) | \ - (a << 24))) - -#define WRITE_PIXEL(_x, _y, p) PUT_VALUE(_x, _y, p) - -# if defined( USE_X86_ASM ) -# define READ_RGBA(rgba, _x, _y) \ - do { \ - GLuint p = GET_VALUE(_x, _y); \ - __asm__ __volatile__( "bswap %0; rorl $8, %0" \ - : "=r" (p) : "0" (p) ); \ - ((GLuint *)rgba)[0] = p; \ - } while (0) -# elif defined( MESA_BIG_ENDIAN ) - /* On PowerPC with GCC 3.4.2 the shift madness below becomes a single - * rotlwi instruction. It also produces good code on SPARC. - */ -# define READ_RGBA( rgba, _x, _y ) \ - do { \ - GLuint p = GET_VALUE(_x, _y); \ - GLuint t = p; \ - *((uint32_t *) rgba) = (t >> 24) | (p << 8); \ - } while (0) -# else -# define READ_RGBA( rgba, _x, _y ) \ - do { \ - GLuint p = GET_VALUE(_x, _y); \ - rgba[0] = (p >> 16) & 0xff; \ - rgba[1] = (p >> 8) & 0xff; \ - rgba[2] = (p >> 0) & 0xff; \ - rgba[3] = (p >> 24) & 0xff; \ - } while (0) -# endif - -#elif (SPANTMP_PIXEL_FMT == GL_BGRA) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8) - -/** - ** GL_BGRA, GL_UNSIGNED_INT_8_8_8_8 - **/ - -#ifndef GET_VALUE -#ifndef GET_PTR -#define GET_PTR(_x, _y) ( buf + (_x) * 4 + (_y) * pitch) -#endif - -#define GET_VALUE(_x, _y) *(volatile GLuint *)(GET_PTR(_x, _y)) -#define PUT_VALUE(_x, _y, _v) *(volatile GLuint *)(GET_PTR(_x, _y)) = (_v) -#endif /* GET_VALUE */ - -# define INIT_MONO_PIXEL(p, color) \ - p = PACK_COLOR_8888(color[2], color[1], color[0], color[3]) - -# define WRITE_RGBA(_x, _y, r, g, b, a) \ - PUT_VALUE(_x, _y, ((r << 8) | \ - (g << 16) | \ - (b << 24) | \ - (a << 0))) - -#define WRITE_PIXEL(_x, _y, p) PUT_VALUE(_x, _y, p) - -# if defined( USE_X86_ASM ) -# define READ_RGBA(rgba, _x, _y) \ - do { \ - GLuint p = GET_VALUE(_x, _y); \ - __asm__ __volatile__( "rorl $8, %0" \ - : "=r" (p) : "0" (p) ); \ - ((GLuint *)rgba)[0] = p; \ - } while (0) -# elif defined( MESA_BIG_ENDIAN ) - /* On PowerPC with GCC 3.4.2 the shift madness below becomes a single - * rotlwi instruction. It also produces good code on SPARC. - */ -# define READ_RGBA( rgba, _x, _y ) \ - do { \ - GLuint p = CPU_TO_LE32(GET_VALUE(_x, _y)); \ - GLuint t = p; \ - *((uint32_t *) rgba) = (t >> 24) | (p << 8); \ - } while (0) -# else -# define READ_RGBA( rgba, _x, _y ) \ - do { \ - GLuint p = GET_VALUE(_x, _y); \ - rgba[0] = (p >> 8) & 0xff; \ - rgba[1] = (p >> 16) & 0xff; \ - rgba[2] = (p >> 24) & 0xff; \ - rgba[3] = (p >> 0) & 0xff; \ - } while (0) -# endif - -#elif (SPANTMP_PIXEL_FMT == GL_BGR) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8_REV) - -/** - ** GL_BGR, GL_UNSIGNED_INT_8_8_8_8_REV - ** - ** This is really for MESA_FORMAT_XRGB8888. The spantmp code needs to be - ** kicked to the curb, and we need to just code-gen this. - **/ - -#ifndef GET_VALUE -#ifndef GET_PTR -#define GET_PTR(_x, _y) ( buf + (_x) * 4 + (_y) * pitch) -#endif - -#define GET_VALUE(_x, _y) *(volatile GLuint *)(GET_PTR(_x, _y)) -#define PUT_VALUE(_x, _y, _v) *(volatile GLuint *)(GET_PTR(_x, _y)) = (_v) -#endif /* GET_VALUE */ - -# define INIT_MONO_PIXEL(p, color) \ - p = PACK_COLOR_8888(0xff, color[0], color[1], color[2]) - -# define WRITE_RGBA(_x, _y, r, g, b, a) \ - PUT_VALUE(_x, _y, ((r << 16) | \ - (g << 8) | \ - (b << 0) | \ - (0xff << 24))) - -#define WRITE_PIXEL(_x, _y, p) PUT_VALUE(_x, _y, p) - -# if defined( USE_X86_ASM ) -# define READ_RGBA(rgba, _x, _y) \ - do { \ - GLuint p = GET_VALUE(_x, _y); \ - __asm__ __volatile__( "bswap %0; rorl $8, %0" \ - : "=r" (p) : "0" (p) ); \ - ((GLuint *)rgba)[0] = p | 0xff000000; \ - } while (0) -# elif defined( MESA_BIG_ENDIAN ) - /* On PowerPC with GCC 3.4.2 the shift madness below becomes a single - * rotlwi instruction. It also produces good code on SPARC. - */ -# define READ_RGBA( rgba, _x, _y ) \ - do { \ - GLuint p = GET_VALUE(_x, _y); \ - *((uint32_t *) rgba) = (p << 8) | 0xff; \ - } while (0) -# else -# define READ_RGBA( rgba, _x, _y ) \ - do { \ - GLuint p = GET_VALUE(_x, _y); \ - rgba[0] = (p >> 16) & 0xff; \ - rgba[1] = (p >> 8) & 0xff; \ - rgba[2] = (p >> 0) & 0xff; \ - rgba[3] = 0xff; \ - } while (0) -# endif - -#elif (SPANTMP_PIXEL_FMT == GL_ALPHA) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_BYTE) - -/** - ** GL_ALPHA, GL_UNSIGNED_BYTE - **/ - -#ifndef GET_VALUE -#ifndef GET_PTR -#define GET_PTR(_x, _y) ( buf + (_x) + (_y) * pitch) -#endif - -#define GET_VALUE(_x, _y) *(volatile GLubyte *)(GET_PTR(_x, _y)) -#define PUT_VALUE(_x, _y, _v) *(volatile GLubyte *)(GET_PTR(_x, _y)) = (_v) -#endif /* GET_VALUE */ - -# define INIT_MONO_PIXEL(p, color) \ - p = color[3] - -# define WRITE_RGBA(_x, _y, r, g, b, a) \ - PUT_VALUE(_x, _y, a | (r & 0 /* quiet warnings */)) - -#define WRITE_PIXEL(_x, _y, p) PUT_VALUE(_x, _y, p) - -#define READ_RGBA( rgba, _x, _y ) \ - do { \ - GLubyte p = GET_VALUE(_x, _y); \ - rgba[0] = 0; \ - rgba[1] = 0; \ - rgba[2] = 0; \ - rgba[3] = p; \ - } while (0) - -#else -#error SPANTMP_PIXEL_FMT must be set to a valid value! -#endif - - - -/** - ** Assembly routines. - **/ - -#if defined( USE_MMX_ASM ) || defined( USE_SSE_ASM ) -#include "x86/read_rgba_span_x86.h" -#include "x86/common_x86_asm.h" -#endif - -static void TAG(WriteRGBASpan)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const void *values, const GLubyte mask[] ) -{ - HW_WRITE_LOCK() - { - const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) values; - GLint x1; - GLint n1; - LOCAL_VARS; - - y = Y_FLIP(y); - - HW_WRITE_CLIPLOOP() - { - GLint i = 0; - CLIPSPAN(x,y,n,x1,n1,i); - - if (DBG) fprintf(stderr, "WriteRGBASpan %d..%d (x1 %d)\n", - (int)i, (int)n1, (int)x1); - - if (mask) - { - for (;n1>0;i++,x1++,n1--) - if (mask[i]) - WRITE_RGBA( x1, y, - rgba[i][0], rgba[i][1], - rgba[i][2], rgba[i][3] ); - } - else - { - for (;n1>0;i++,x1++,n1--) - WRITE_RGBA( x1, y, - rgba[i][0], rgba[i][1], - rgba[i][2], rgba[i][3] ); - } - } - HW_ENDCLIPLOOP(); - } - HW_WRITE_UNLOCK(); -} - -static void TAG(WriteRGBSpan)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const void *values, const GLubyte mask[] ) -{ - HW_WRITE_LOCK() - { - const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) values; - GLint x1; - GLint n1; - LOCAL_VARS; - - y = Y_FLIP(y); - - HW_WRITE_CLIPLOOP() - { - GLint i = 0; - CLIPSPAN(x,y,n,x1,n1,i); - - if (DBG) fprintf(stderr, "WriteRGBSpan %d..%d (x1 %d)\n", - (int)i, (int)n1, (int)x1); - - if (mask) - { - for (;n1>0;i++,x1++,n1--) - if (mask[i]) - WRITE_RGBA( x1, y, rgb[i][0], rgb[i][1], rgb[i][2], 255 ); - } - else - { - for (;n1>0;i++,x1++,n1--) - WRITE_RGBA( x1, y, rgb[i][0], rgb[i][1], rgb[i][2], 255 ); - } - } - HW_ENDCLIPLOOP(); - } - HW_WRITE_UNLOCK(); -} - -static void TAG(WriteRGBAPixels)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, const GLint x[], const GLint y[], - const void *values, const GLubyte mask[] ) -{ - HW_WRITE_LOCK() - { - const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) values; - GLint i; - LOCAL_VARS; - - if (DBG) fprintf(stderr, "WriteRGBAPixels\n"); - - HW_WRITE_CLIPLOOP() - { - if (mask) - { - for (i=0;i<n;i++) - { - if (mask[i]) { - const int fy = Y_FLIP(y[i]); - if (CLIPPIXEL(x[i],fy)) - WRITE_RGBA( x[i], fy, - rgba[i][0], rgba[i][1], - rgba[i][2], rgba[i][3] ); - } - } - } - else - { - for (i=0;i<n;i++) - { - const int fy = Y_FLIP(y[i]); - if (CLIPPIXEL(x[i],fy)) - WRITE_RGBA( x[i], fy, - rgba[i][0], rgba[i][1], - rgba[i][2], rgba[i][3] ); - } - } - } - HW_ENDCLIPLOOP(); - } - HW_WRITE_UNLOCK(); -} - - -static void TAG(WriteMonoRGBASpan)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const void *value, const GLubyte mask[] ) -{ - HW_WRITE_LOCK() - { - const GLubyte *color = (const GLubyte *) value; - GLint x1; - GLint n1; - LOCAL_VARS; - INIT_MONO_PIXEL(p, color); - - y = Y_FLIP( y ); - - if (DBG) fprintf(stderr, "WriteMonoRGBASpan\n"); - - HW_WRITE_CLIPLOOP() - { - GLint i = 0; - CLIPSPAN(x,y,n,x1,n1,i); - if (mask) - { - for (;n1>0;i++,x1++,n1--) - if (mask[i]) - WRITE_PIXEL( x1, y, p ); - } - else - { - for (;n1>0;i++,x1++,n1--) - WRITE_PIXEL( x1, y, p ); - } - } - HW_ENDCLIPLOOP(); - } - HW_WRITE_UNLOCK(); -} - - -static void TAG(WriteMonoRGBAPixels)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, - const GLint x[], const GLint y[], - const void *value, - const GLubyte mask[] ) -{ - HW_WRITE_LOCK() - { - const GLubyte *color = (const GLubyte *) value; - GLint i; - LOCAL_VARS; - INIT_MONO_PIXEL(p, color); - - if (DBG) fprintf(stderr, "WriteMonoRGBAPixels\n"); - - HW_WRITE_CLIPLOOP() - { - if (mask) - { - for (i=0;i<n;i++) - if (mask[i]) { - int fy = Y_FLIP(y[i]); - if (CLIPPIXEL( x[i], fy )) - WRITE_PIXEL( x[i], fy, p ); - } - } - else - { - for (i=0;i<n;i++) { - int fy = Y_FLIP(y[i]); - if (CLIPPIXEL( x[i], fy )) - WRITE_PIXEL( x[i], fy, p ); - } - } - } - HW_ENDCLIPLOOP(); - } - HW_WRITE_UNLOCK(); -} - - -static void TAG(ReadRGBASpan)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, void *values) -{ - HW_READ_LOCK() - { - GLubyte (*rgba)[4] = (GLubyte (*)[4]) values; - GLint x1,n1; - LOCAL_VARS; - - y = Y_FLIP(y); - - if (DBG) fprintf(stderr, "ReadRGBASpan\n"); - - HW_READ_CLIPLOOP() - { - GLint i = 0; - CLIPSPAN(x,y,n,x1,n1,i); - for (;n1>0;i++,x1++,n1--) - READ_RGBA( rgba[i], x1, y ); - } - HW_ENDCLIPLOOP(); - } - HW_READ_UNLOCK(); -} - - -#if defined(GET_PTR) && \ - defined(USE_MMX_ASM) && \ - (((SPANTMP_PIXEL_FMT == GL_BGRA) && \ - (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8_REV)) || \ - ((SPANTMP_PIXEL_FMT == GL_RGB) && \ - (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_5_6_5))) -static void TAG2(ReadRGBASpan,_MMX)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, void *values) -{ -#ifndef USE_INNER_EMMS - /* The EMMS instruction is directly in-lined here because using GCC's - * built-in _mm_empty function was found to utterly destroy performance. - */ - __asm__ __volatile__( "emms" ); -#endif - - HW_READ_LOCK() - { - GLubyte (*rgba)[4] = (GLubyte (*)[4]) values; - GLint x1,n1; - LOCAL_VARS; - - y = Y_FLIP(y); - - if (DBG) fprintf(stderr, "ReadRGBASpan\n"); - - HW_READ_CLIPLOOP() - { - GLint i = 0; - CLIPSPAN(x,y,n,x1,n1,i); - - { - const void * src = GET_PTR( x1, y ); -#if (SPANTMP_PIXEL_FMT == GL_RGB) && \ - (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_5_6_5) - _generic_read_RGBA_span_RGB565_MMX( src, rgba[i], n1 ); -#else - _generic_read_RGBA_span_BGRA8888_REV_MMX( src, rgba[i], n1 ); -#endif - } - } - HW_ENDCLIPLOOP(); - } - HW_READ_UNLOCK(); -#ifndef USE_INNER_EMMS - __asm__ __volatile__( "emms" ); -#endif -} -#endif - - -#if defined(GET_PTR) && \ - defined(USE_SSE_ASM) && \ - (SPANTMP_PIXEL_FMT == GL_BGRA) && \ - (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8_REV) -static void TAG2(ReadRGBASpan,_SSE2)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - void *values) -{ - HW_READ_LOCK() - { - GLubyte (*rgba)[4] = (GLubyte (*)[4]) values; - GLint x1,n1; - LOCAL_VARS; - - y = Y_FLIP(y); - - if (DBG) fprintf(stderr, "ReadRGBASpan\n"); - - HW_READ_CLIPLOOP() - { - GLint i = 0; - CLIPSPAN(x,y,n,x1,n1,i); - - { - const void * src = GET_PTR( x1, y ); - _generic_read_RGBA_span_BGRA8888_REV_SSE2( src, rgba[i], n1 ); - } - } - HW_ENDCLIPLOOP(); - } - HW_READ_UNLOCK(); -} -#endif - -#if defined(GET_PTR) && \ - defined(USE_SSE_ASM) && \ - (SPANTMP_PIXEL_FMT == GL_BGRA) && \ - (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8_REV) -static void TAG2(ReadRGBASpan,_SSE)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - void *values) -{ -#ifndef USE_INNER_EMMS - /* The EMMS instruction is directly in-lined here because using GCC's - * built-in _mm_empty function was found to utterly destroy performance. - */ - __asm__ __volatile__( "emms" ); -#endif - - HW_READ_LOCK() - { - GLubyte (*rgba)[4] = (GLubyte (*)[4]) values; - GLint x1,n1; - LOCAL_VARS; - - y = Y_FLIP(y); - - if (DBG) fprintf(stderr, "ReadRGBASpan\n"); - - HW_READ_CLIPLOOP() - { - GLint i = 0; - CLIPSPAN(x,y,n,x1,n1,i); - - { - const void * src = GET_PTR( x1, y ); - _generic_read_RGBA_span_BGRA8888_REV_SSE( src, rgba[i], n1 ); - } - } - HW_ENDCLIPLOOP(); - } - HW_READ_UNLOCK(); -#ifndef USE_INNER_EMMS - __asm__ __volatile__( "emms" ); -#endif -} -#endif - - -static void TAG(ReadRGBAPixels)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, const GLint x[], const GLint y[], - void *values ) -{ - HW_READ_LOCK() - { - GLubyte (*rgba)[4] = (GLubyte (*)[4]) values; - GLint i; - LOCAL_VARS; - - if (DBG) fprintf(stderr, "ReadRGBAPixels\n"); - - HW_READ_CLIPLOOP() - { - for (i=0;i<n;i++) { - int fy = Y_FLIP( y[i] ); - if (CLIPPIXEL( x[i], fy )) - READ_RGBA( rgba[i], x[i], fy ); - } - } - HW_ENDCLIPLOOP(); - } - HW_READ_UNLOCK(); -} - -static void TAG(InitPointers)(struct gl_renderbuffer *rb) -{ - rb->PutRow = TAG(WriteRGBASpan); - rb->PutRowRGB = TAG(WriteRGBSpan); - rb->PutMonoRow = TAG(WriteMonoRGBASpan); - rb->PutValues = TAG(WriteRGBAPixels); - rb->PutMonoValues = TAG(WriteMonoRGBAPixels); - rb->GetValues = TAG(ReadRGBAPixels); - -#if defined(GET_PTR) -#if defined(USE_SSE_ASM) && \ - (SPANTMP_PIXEL_FMT == GL_BGRA) && \ - (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8_REV) - if ( cpu_has_xmm2 ) { - if (DBG) fprintf( stderr, "Using %s version of GetRow\n", "SSE2" ); - rb->GetRow = TAG2(ReadRGBASpan, _SSE2); - } - else -#endif -#if defined(USE_SSE_ASM) && \ - (SPANTMP_PIXEL_FMT == GL_BGRA) && \ - (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8_REV) - if ( cpu_has_xmm ) { - if (DBG) fprintf( stderr, "Using %s version of GetRow\n", "SSE" ); - rb->GetRow = TAG2(ReadRGBASpan, _SSE); - } - else -#endif -#if defined(USE_MMX_ASM) && \ - (((SPANTMP_PIXEL_FMT == GL_BGRA) && \ - (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8_REV)) || \ - ((SPANTMP_PIXEL_FMT == GL_RGB) && \ - (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_5_6_5))) - if ( cpu_has_mmx ) { - if (DBG) fprintf( stderr, "Using %s version of GetRow\n", "MMX" ); - rb->GetRow = TAG2(ReadRGBASpan, _MMX); - } - else -#endif -#endif /* GET_PTR */ - { - if (DBG) fprintf( stderr, "Using %s version of GetRow\n", "C" ); - rb->GetRow = TAG(ReadRGBASpan); - } - -} - - -#undef INIT_MONO_PIXEL -#undef WRITE_PIXEL -#undef WRITE_RGBA -#undef READ_RGBA -#undef TAG -#undef TAG2 -#undef GET_VALUE -#undef PUT_VALUE -#undef GET_PTR -#undef SPANTMP_PIXEL_FMT -#undef SPANTMP_PIXEL_TYPE +/*
+ * Copyright 2000-2001 VA Linux Systems, Inc.
+ * (C) Copyright IBM Corporation 2004
+ * 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
+ * VA LINUX SYSTEM, IBM 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.
+ */
+
+/**
+ * \file spantmp2.h
+ *
+ * Template file of span read / write functions.
+ *
+ * \author Keith Whitwell <keithw@tungstengraphics.com>
+ * \author Gareth Hughes <gareth@nvidia.com>
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include "main/colormac.h"
+#include "spantmp_common.h"
+
+#ifndef DBG
+#define DBG 0
+#endif
+
+#ifndef HW_READ_CLIPLOOP
+#define HW_READ_CLIPLOOP() HW_CLIPLOOP()
+#endif
+
+#ifndef HW_WRITE_CLIPLOOP
+#define HW_WRITE_CLIPLOOP() HW_CLIPLOOP()
+#endif
+
+#ifdef SPANTMP_MESA_FMT
+#define SPANTMP_PIXEL_FMT GL_NONE
+#define SPANTMP_PIXEL_TYPE GL_NONE
+#endif
+
+#ifndef SPANTMP_MESA_FMT
+#define SPANTMP_MESA_FMT MESA_FORMAT_COUNT
+#endif
+
+#if (SPANTMP_PIXEL_FMT == GL_RGB) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_5_6_5)
+
+/**
+ ** GL_RGB, GL_UNSIGNED_SHORT_5_6_5
+ **/
+
+#ifndef GET_VALUE
+#ifndef GET_PTR
+#define GET_PTR(_x, _y) (buf + (_x) * 2 + (_y) * pitch)
+#endif
+
+#define GET_VALUE(_x, _y) *(volatile GLushort *)(GET_PTR(_x, _y))
+#define PUT_VALUE(_x, _y, _v) *(volatile GLushort *)(GET_PTR(_x, _y)) = (_v)
+#endif /* GET_VALUE */
+
+#define INIT_MONO_PIXEL(p, color) \
+ p = PACK_COLOR_565( color[0], color[1], color[2] )
+
+#define WRITE_RGBA( _x, _y, r, g, b, a ) \
+ PUT_VALUE(_x, _y, ((((int)r & 0xf8) << 8) | \
+ (((int)g & 0xfc) << 3) | \
+ (((int)b & 0xf8) >> 3))) \
+
+#define WRITE_PIXEL( _x, _y, p ) PUT_VALUE(_x, _y, p)
+
+#define READ_RGBA( rgba, _x, _y ) \
+ do { \
+ GLushort p = GET_VALUE(_x, _y); \
+ rgba[0] = ((p >> 8) & 0xf8) * 255 / 0xf8; \
+ rgba[1] = ((p >> 3) & 0xfc) * 255 / 0xfc; \
+ rgba[2] = ((p << 3) & 0xf8) * 255 / 0xf8; \
+ rgba[3] = 0xff; \
+ } while (0)
+
+#elif (SPANTMP_PIXEL_FMT == GL_RGB) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_5_6_5_REV)
+
+/**
+ ** GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV
+ **/
+
+#ifndef GET_VALUE
+#ifndef GET_PTR
+#define GET_PTR(_x, _y) (buf + (_x) * 2 + (_y) * pitch)
+#endif
+
+#define GET_VALUE(_x, _y) *(volatile GLushort *)(GET_PTR(_x, _y))
+#define PUT_VALUE(_x, _y, _v) *(volatile GLushort *)(GET_PTR(_x, _y)) = (_v)
+#endif /* GET_VALUE */
+
+#define INIT_MONO_PIXEL(p, color) \
+ p = PACK_COLOR_565_REV( color[0], color[1], color[2] )
+
+#define WRITE_RGBA( _x, _y, r, g, b, a ) \
+ PUT_VALUE(_x, _y, PACK_COLOR_565_REV( r, g, b ))
+
+#define WRITE_PIXEL( _x, _y, p ) PUT_VALUE(_x, _y, p)
+
+#define READ_RGBA( rgba, _x, _y ) \
+ do { \
+ GLushort p = GET_VALUE(_x, _y); \
+ p = p << 8 | p >> 8; \
+ rgba[0] = ((p >> 8) & 0xf8) * 255 / 0xf8; \
+ rgba[1] = ((p >> 3) & 0xfc) * 255 / 0xfc; \
+ rgba[2] = ((p << 3) & 0xf8) * 255 / 0xf8; \
+ rgba[3] = 0xff; \
+ } while (0)
+
+#elif (SPANTMP_PIXEL_FMT == GL_BGRA) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_4_4_4_4)
+
+/**
+ ** GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4
+ **/
+
+#ifndef GET_VALUE
+#ifndef GET_PTR
+#define GET_PTR(_x, _y) (buf + (_x) * 2 + (_y) * pitch)
+#endif
+
+#define GET_VALUE(_x, _y) *(volatile GLushort *)(GET_PTR(_x, _y))
+#define PUT_VALUE(_x, _y, _v) *(volatile GLushort *)(GET_PTR(_x, _y)) = (_v)
+#endif /* GET_VALUE */
+
+#define INIT_MONO_PIXEL(p, color) \
+ p = PACK_COLOR_4444_REV(color[3], color[0], color[1], color[2])
+
+#define WRITE_RGBA( _x, _y, r, g, b, a ) \
+ PUT_VALUE(_x, _y, PACK_COLOR_4444_REV(a, r, g, b)) \
+
+#define WRITE_PIXEL( _x, _y, p ) PUT_VALUE(_x, _y, p)
+
+#define READ_RGBA( rgba, _x, _y ) \
+ do { \
+ GLushort p = GET_VALUE(_x, _y); \
+ rgba[0] = ((p >> 0) & 0xf) * 0x11; \
+ rgba[1] = ((p >> 12) & 0xf) * 0x11; \
+ rgba[2] = ((p >> 4) & 0xf) * 0x11; \
+ rgba[3] = ((p >> 8) & 0xf) * 0x11; \
+ } while (0)
+
+
+#elif (SPANTMP_PIXEL_FMT == GL_BGRA) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_4_4_4_4_REV)
+
+/**
+ ** GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV
+ **/
+
+#ifndef GET_VALUE
+#ifndef GET_PTR
+#define GET_PTR(_x, _y) (buf + (_x) * 2 + (_y) * pitch)
+#endif
+
+#define GET_VALUE(_x, _y) *(volatile GLushort *)(GET_PTR(_x, _y))
+#define PUT_VALUE(_x, _y, _v) *(volatile GLushort *)(GET_PTR(_x, _y)) = (_v)
+#endif /* GET_VALUE */
+
+#define INIT_MONO_PIXEL(p, color) \
+ p = PACK_COLOR_4444(color[3], color[0], color[1], color[2])
+
+#define WRITE_RGBA( _x, _y, r, g, b, a ) \
+ PUT_VALUE(_x, _y, PACK_COLOR_4444(a, r, g, b)) \
+
+#define WRITE_PIXEL( _x, _y, p ) PUT_VALUE(_x, _y, p)
+
+#define READ_RGBA( rgba, _x, _y ) \
+ do { \
+ GLushort p = GET_VALUE(_x, _y); \
+ rgba[0] = ((p >> 8) & 0xf) * 0x11; \
+ rgba[1] = ((p >> 4) & 0xf) * 0x11; \
+ rgba[2] = ((p >> 0) & 0xf) * 0x11; \
+ rgba[3] = ((p >> 12) & 0xf) * 0x11; \
+ } while (0)
+
+
+#elif (SPANTMP_PIXEL_FMT == GL_BGRA) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_1_5_5_5_REV)
+
+/**
+ ** GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV
+ **/
+
+#ifndef GET_VALUE
+#ifndef GET_PTR
+#define GET_PTR(_x, _y) (buf + (_x) * 2 + (_y) * pitch)
+#endif
+
+#define GET_VALUE(_x, _y) *(volatile GLushort *)(GET_PTR(_x, _y))
+#define PUT_VALUE(_x, _y, _v) *(volatile GLushort *)(GET_PTR(_x, _y)) = (_v)
+#endif /* GET_VALUE */
+
+#define INIT_MONO_PIXEL(p, color) \
+ p = PACK_COLOR_1555(color[3], color[0], color[1], color[2])
+
+#define WRITE_RGBA( _x, _y, r, g, b, a ) \
+ PUT_VALUE(_x, _y, PACK_COLOR_1555(a, r, g, b)) \
+
+#define WRITE_PIXEL( _x, _y, p ) PUT_VALUE(_x, _y, p)
+
+#define READ_RGBA( rgba, _x, _y ) \
+ do { \
+ GLushort p = GET_VALUE(_x, _y); \
+ rgba[0] = ((p >> 7) & 0xf8) * 255 / 0xf8; \
+ rgba[1] = ((p >> 2) & 0xf8) * 255 / 0xf8; \
+ rgba[2] = ((p << 3) & 0xf8) * 255 / 0xf8; \
+ rgba[3] = ((p >> 15) & 0x1) * 0xff; \
+ } while (0)
+
+#elif (SPANTMP_PIXEL_FMT == GL_BGRA) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_1_5_5_5)
+
+/**
+ ** GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5
+ **/
+
+#ifndef GET_VALUE
+#ifndef GET_PTR
+#define GET_PTR(_x, _y) (buf + (_x) * 2 + (_y) * pitch)
+#endif
+
+#define GET_VALUE(_x, _y) *(volatile GLushort *)(GET_PTR(_x, _y))
+#define PUT_VALUE(_x, _y, _v) *(volatile GLushort *)(GET_PTR(_x, _y)) = (_v)
+#endif /* GET_VALUE */
+
+#define INIT_MONO_PIXEL(p, color) \
+ p = PACK_COLOR_1555_REV(color[3], color[0], color[1], color[2])
+
+#define WRITE_RGBA( _x, _y, r, g, b, a ) \
+ PUT_VALUE(_x, _y, PACK_COLOR_1555_REV(a, r, g, b)) \
+
+#define WRITE_PIXEL( _x, _y, p ) PUT_VALUE(_x, _y, p)
+
+#define READ_RGBA( rgba, _x, _y ) \
+ do { \
+ GLushort p = GET_VALUE(_x, _y); \
+ p = p << 8 | p >> 8; \
+ rgba[0] = ((p >> 7) & 0xf8) * 255 / 0xf8; \
+ rgba[1] = ((p >> 2) & 0xf8) * 255 / 0xf8; \
+ rgba[2] = ((p << 3) & 0xf8) * 255 / 0xf8; \
+ rgba[3] = ((p >> 15) & 0x1) * 0xff; \
+ } while (0)
+
+#elif (SPANTMP_PIXEL_FMT == GL_BGRA) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8_REV)
+
+/**
+ ** GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV
+ **/
+
+#ifndef GET_VALUE
+#ifndef GET_PTR
+#define GET_PTR(_x, _y) ( buf + (_x) * 4 + (_y) * pitch)
+#endif
+
+#define GET_VALUE(_x, _y) *(volatile GLuint *)(GET_PTR(_x, _y))
+#define PUT_VALUE(_x, _y, _v) *(volatile GLuint *)(GET_PTR(_x, _y)) = (_v)
+#endif /* GET_VALUE */
+
+# define INIT_MONO_PIXEL(p, color) \
+ p = PACK_COLOR_8888(color[3], color[0], color[1], color[2])
+
+# define WRITE_RGBA(_x, _y, r, g, b, a) \
+ PUT_VALUE(_x, _y, ((r << 16) | \
+ (g << 8) | \
+ (b << 0) | \
+ (a << 24)))
+
+#define WRITE_PIXEL(_x, _y, p) PUT_VALUE(_x, _y, p)
+
+# if defined( USE_X86_ASM )
+# define READ_RGBA(rgba, _x, _y) \
+ do { \
+ GLuint p = GET_VALUE(_x, _y); \
+ __asm__ __volatile__( "bswap %0; rorl $8, %0" \
+ : "=r" (p) : "0" (p) ); \
+ ((GLuint *)rgba)[0] = p; \
+ } while (0)
+# elif defined( MESA_BIG_ENDIAN )
+ /* On PowerPC with GCC 3.4.2 the shift madness below becomes a single
+ * rotlwi instruction. It also produces good code on SPARC.
+ */
+# define READ_RGBA( rgba, _x, _y ) \
+ do { \
+ GLuint p = GET_VALUE(_x, _y); \
+ GLuint t = p; \
+ *((uint32_t *) rgba) = (t >> 24) | (p << 8); \
+ } while (0)
+# else
+# define READ_RGBA( rgba, _x, _y ) \
+ do { \
+ GLuint p = GET_VALUE(_x, _y); \
+ rgba[0] = (p >> 16) & 0xff; \
+ rgba[1] = (p >> 8) & 0xff; \
+ rgba[2] = (p >> 0) & 0xff; \
+ rgba[3] = (p >> 24) & 0xff; \
+ } while (0)
+# endif
+
+#elif (SPANTMP_PIXEL_FMT == GL_BGRA) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8)
+
+/**
+ ** GL_BGRA, GL_UNSIGNED_INT_8_8_8_8
+ **/
+
+#ifndef GET_VALUE
+#ifndef GET_PTR
+#define GET_PTR(_x, _y) ( buf + (_x) * 4 + (_y) * pitch)
+#endif
+
+#define GET_VALUE(_x, _y) *(volatile GLuint *)(GET_PTR(_x, _y))
+#define PUT_VALUE(_x, _y, _v) *(volatile GLuint *)(GET_PTR(_x, _y)) = (_v)
+#endif /* GET_VALUE */
+
+# define INIT_MONO_PIXEL(p, color) \
+ p = PACK_COLOR_8888(color[2], color[1], color[0], color[3])
+
+# define WRITE_RGBA(_x, _y, r, g, b, a) \
+ PUT_VALUE(_x, _y, ((r << 8) | \
+ (g << 16) | \
+ (b << 24) | \
+ (a << 0)))
+
+#define WRITE_PIXEL(_x, _y, p) PUT_VALUE(_x, _y, p)
+
+# if defined( USE_X86_ASM )
+# define READ_RGBA(rgba, _x, _y) \
+ do { \
+ GLuint p = GET_VALUE(_x, _y); \
+ __asm__ __volatile__( "rorl $8, %0" \
+ : "=r" (p) : "0" (p) ); \
+ ((GLuint *)rgba)[0] = p; \
+ } while (0)
+# elif defined( MESA_BIG_ENDIAN )
+ /* On PowerPC with GCC 3.4.2 the shift madness below becomes a single
+ * rotlwi instruction. It also produces good code on SPARC.
+ */
+# define READ_RGBA( rgba, _x, _y ) \
+ do { \
+ GLuint p = CPU_TO_LE32(GET_VALUE(_x, _y)); \
+ GLuint t = p; \
+ *((uint32_t *) rgba) = (t >> 24) | (p << 8); \
+ } while (0)
+# else
+# define READ_RGBA( rgba, _x, _y ) \
+ do { \
+ GLuint p = GET_VALUE(_x, _y); \
+ rgba[0] = (p >> 8) & 0xff; \
+ rgba[1] = (p >> 16) & 0xff; \
+ rgba[2] = (p >> 24) & 0xff; \
+ rgba[3] = (p >> 0) & 0xff; \
+ } while (0)
+# endif
+
+#elif (SPANTMP_PIXEL_FMT == GL_BGR) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8_REV)
+
+/**
+ ** GL_BGR, GL_UNSIGNED_INT_8_8_8_8_REV
+ **
+ ** This is really for MESA_FORMAT_XRGB8888. The spantmp code needs to be
+ ** kicked to the curb, and we need to just code-gen this.
+ **/
+
+#ifndef GET_VALUE
+#ifndef GET_PTR
+#define GET_PTR(_x, _y) ( buf + (_x) * 4 + (_y) * pitch)
+#endif
+
+#define GET_VALUE(_x, _y) *(volatile GLuint *)(GET_PTR(_x, _y))
+#define PUT_VALUE(_x, _y, _v) *(volatile GLuint *)(GET_PTR(_x, _y)) = (_v)
+#endif /* GET_VALUE */
+
+# define INIT_MONO_PIXEL(p, color) \
+ p = PACK_COLOR_8888(0xff, color[0], color[1], color[2])
+
+# define WRITE_RGBA(_x, _y, r, g, b, a) \
+ PUT_VALUE(_x, _y, ((r << 16) | \
+ (g << 8) | \
+ (b << 0) | \
+ (0xff << 24)))
+
+#define WRITE_PIXEL(_x, _y, p) PUT_VALUE(_x, _y, p)
+
+# if defined( USE_X86_ASM )
+# define READ_RGBA(rgba, _x, _y) \
+ do { \
+ GLuint p = GET_VALUE(_x, _y); \
+ __asm__ __volatile__( "bswap %0; rorl $8, %0" \
+ : "=r" (p) : "0" (p) ); \
+ ((GLuint *)rgba)[0] = p | 0xff000000; \
+ } while (0)
+# elif defined( MESA_BIG_ENDIAN )
+ /* On PowerPC with GCC 3.4.2 the shift madness below becomes a single
+ * rotlwi instruction. It also produces good code on SPARC.
+ */
+# define READ_RGBA( rgba, _x, _y ) \
+ do { \
+ GLuint p = GET_VALUE(_x, _y); \
+ *((uint32_t *) rgba) = (p << 8) | 0xff; \
+ } while (0)
+# else
+# define READ_RGBA( rgba, _x, _y ) \
+ do { \
+ GLuint p = GET_VALUE(_x, _y); \
+ rgba[0] = (p >> 16) & 0xff; \
+ rgba[1] = (p >> 8) & 0xff; \
+ rgba[2] = (p >> 0) & 0xff; \
+ rgba[3] = 0xff; \
+ } while (0)
+# endif
+
+#elif (SPANTMP_PIXEL_FMT == GL_ALPHA) && (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_BYTE)
+
+/**
+ ** GL_ALPHA, GL_UNSIGNED_BYTE
+ **/
+
+#ifndef GET_VALUE
+#ifndef GET_PTR
+#define GET_PTR(_x, _y) ( buf + (_x) + (_y) * pitch)
+#endif
+
+#define GET_VALUE(_x, _y) *(volatile GLubyte *)(GET_PTR(_x, _y))
+#define PUT_VALUE(_x, _y, _v) *(volatile GLubyte *)(GET_PTR(_x, _y)) = (_v)
+#endif /* GET_VALUE */
+
+# define INIT_MONO_PIXEL(p, color) \
+ p = color[3]
+
+# define WRITE_RGBA(_x, _y, r, g, b, a) \
+ PUT_VALUE(_x, _y, a | (r & 0 /* quiet warnings */))
+
+#define WRITE_PIXEL(_x, _y, p) PUT_VALUE(_x, _y, p)
+
+#define READ_RGBA( rgba, _x, _y ) \
+ do { \
+ GLubyte p = GET_VALUE(_x, _y); \
+ rgba[0] = 0; \
+ rgba[1] = 0; \
+ rgba[2] = 0; \
+ rgba[3] = p; \
+ } while (0)
+
+#elif (SPANTMP_MESA_FMT == MESA_FORMAT_R8)
+
+#ifndef GET_VALUE
+#ifndef GET_PTR
+#define GET_PTR(_x, _y) ( buf + (_x) + (_y) * pitch)
+#endif
+
+#define GET_VALUE(_x, _y) *(volatile GLubyte *)(GET_PTR(_x, _y))
+#define PUT_VALUE(_x, _y, _v) *(volatile GLubyte *)(GET_PTR(_x, _y)) = (_v)
+#endif /* GET_VALUE */
+
+# define INIT_MONO_PIXEL(p, color) \
+ p = color[0]
+
+# define WRITE_RGBA(_x, _y, r, g, b, a) \
+ PUT_VALUE(_x, _y, r)
+
+#define WRITE_PIXEL(_x, _y, p) PUT_VALUE(_x, _y, p)
+
+#define READ_RGBA( rgba, _x, _y ) \
+ do { \
+ GLubyte p = GET_VALUE(_x, _y); \
+ rgba[0] = p; \
+ rgba[1] = 0; \
+ rgba[2] = 0; \
+ rgba[3] = 0; \
+ } while (0)
+
+#elif (SPANTMP_MESA_FMT == MESA_FORMAT_RG88)
+
+#ifndef GET_VALUE
+#ifndef GET_PTR
+#define GET_PTR(_x, _y) ( buf + (_x) * 2 + (_y) * pitch)
+#endif
+
+#define GET_VALUE(_x, _y) *(volatile GLushort *)(GET_PTR(_x, _y))
+#define PUT_VALUE(_x, _y, _v) *(volatile GLushort *)(GET_PTR(_x, _y)) = (_v)
+#endif /* GET_VALUE */
+
+# define INIT_MONO_PIXEL(p, color) \
+ PACK_COLOR_8888(color[0], color[1], 0, 0)
+
+# define WRITE_RGBA(_x, _y, r, g, b, a) \
+ PUT_VALUE(_x, _y, r)
+
+#define WRITE_PIXEL(_x, _y, p) PUT_VALUE(_x, _y, p)
+
+#define READ_RGBA( rgba, _x, _y ) \
+ do { \
+ GLushort p = GET_VALUE(_x, _y); \
+ rgba[0] = p & 0xff; \
+ rgba[1] = (p >> 8) & 0xff; \
+ rgba[2] = 0; \
+ rgba[3] = 0; \
+ } while (0)
+
+#elif (SPANTMP_MESA_FMT == MESA_FORMAT_R16)
+
+#ifndef GET_VALUE
+#ifndef GET_PTR
+#define GET_PTR(_x, _y) ( buf + (_x) * 2 + (_y) * pitch)
+#endif
+
+#define GET_VALUE(_x, _y) *(volatile GLushort *)(GET_PTR(_x, _y))
+#define PUT_VALUE(_x, _y, _v) *(volatile GLushort *)(GET_PTR(_x, _y)) = (_v)
+#endif /* GET_VALUE */
+
+# define INIT_MONO_PIXEL(p, color) \
+ p = color[0]
+
+# define WRITE_RGBA(_x, _y, r, g, b, a) \
+ PUT_VALUE(_x, _y, r)
+
+#define WRITE_PIXEL(_x, _y, p) PUT_VALUE(_x, _y, p)
+
+#define READ_RGBA( rgba, _x, _y ) \
+ do { \
+ GLushort p = GET_VALUE(_x, _y); \
+ rgba[0] = p; \
+ rgba[1] = 0; \
+ rgba[2] = 0; \
+ rgba[3] = 0; \
+ } while (0)
+
+#elif (SPANTMP_MESA_FMT == MESA_FORMAT_RG1616)
+
+#ifndef GET_VALUE
+#ifndef GET_PTR
+#define GET_PTR(_x, _y) ( buf + (_x) * 4 + (_y) * pitch)
+#endif
+
+#define GET_VALUE(_x, _y) *(volatile GLuint *)(GET_PTR(_x, _y))
+#define PUT_VALUE(_x, _y, _v) *(volatile GLuint *)(GET_PTR(_x, _y)) = (_v)
+#endif /* GET_VALUE */
+
+# define INIT_MONO_PIXEL(p, color) \
+ ((color[1] << 16) | (color[0]))
+
+# define WRITE_RGBA(_x, _y, r, g, b, a) \
+ PUT_VALUE(_x, _y, r)
+
+#define WRITE_PIXEL(_x, _y, p) PUT_VALUE(_x, _y, p)
+
+#define READ_RGBA( rgba, _x, _y ) \
+ do { \
+ GLuint p = GET_VALUE(_x, _y); \
+ rgba[0] = p & 0xffff; \
+ rgba[1] = (p >> 16) & 0xffff; \
+ rgba[2] = 0; \
+ rgba[3] = 0; \
+ } while (0)
+
+#else
+#error SPANTMP_PIXEL_FMT must be set to a valid value!
+#endif
+
+
+
+/**
+ ** Assembly routines.
+ **/
+
+#if defined( USE_MMX_ASM ) || defined( USE_SSE_ASM )
+#include "x86/read_rgba_span_x86.h"
+#include "x86/common_x86_asm.h"
+#endif
+
+static void TAG(WriteRGBASpan)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const void *values, const GLubyte mask[] )
+{
+ HW_WRITE_LOCK()
+ {
+ const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) values;
+ GLint x1;
+ GLint n1;
+ LOCAL_VARS;
+
+ y = Y_FLIP(y);
+
+ HW_WRITE_CLIPLOOP()
+ {
+ GLint i = 0;
+ CLIPSPAN(x,y,n,x1,n1,i);
+
+ if (DBG) fprintf(stderr, "WriteRGBASpan %d..%d (x1 %d)\n",
+ (int)i, (int)n1, (int)x1);
+
+ if (mask)
+ {
+ for (;n1>0;i++,x1++,n1--)
+ if (mask[i])
+ WRITE_RGBA( x1, y,
+ rgba[i][0], rgba[i][1],
+ rgba[i][2], rgba[i][3] );
+ }
+ else
+ {
+ for (;n1>0;i++,x1++,n1--)
+ WRITE_RGBA( x1, y,
+ rgba[i][0], rgba[i][1],
+ rgba[i][2], rgba[i][3] );
+ }
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_WRITE_UNLOCK();
+}
+
+static void TAG(WriteRGBSpan)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const void *values, const GLubyte mask[] )
+{
+ HW_WRITE_LOCK()
+ {
+ const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) values;
+ GLint x1;
+ GLint n1;
+ LOCAL_VARS;
+
+ y = Y_FLIP(y);
+
+ HW_WRITE_CLIPLOOP()
+ {
+ GLint i = 0;
+ CLIPSPAN(x,y,n,x1,n1,i);
+
+ if (DBG) fprintf(stderr, "WriteRGBSpan %d..%d (x1 %d)\n",
+ (int)i, (int)n1, (int)x1);
+
+ if (mask)
+ {
+ for (;n1>0;i++,x1++,n1--)
+ if (mask[i])
+ WRITE_RGBA( x1, y, rgb[i][0], rgb[i][1], rgb[i][2], 255 );
+ }
+ else
+ {
+ for (;n1>0;i++,x1++,n1--)
+ WRITE_RGBA( x1, y, rgb[i][0], rgb[i][1], rgb[i][2], 255 );
+ }
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_WRITE_UNLOCK();
+}
+
+static void TAG(WriteRGBAPixels)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, const GLint x[], const GLint y[],
+ const void *values, const GLubyte mask[] )
+{
+ HW_WRITE_LOCK()
+ {
+ const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) values;
+ GLint i;
+ LOCAL_VARS;
+
+ if (DBG) fprintf(stderr, "WriteRGBAPixels\n");
+
+ HW_WRITE_CLIPLOOP()
+ {
+ if (mask)
+ {
+ for (i=0;i<n;i++)
+ {
+ if (mask[i]) {
+ const int fy = Y_FLIP(y[i]);
+ if (CLIPPIXEL(x[i],fy))
+ WRITE_RGBA( x[i], fy,
+ rgba[i][0], rgba[i][1],
+ rgba[i][2], rgba[i][3] );
+ }
+ }
+ }
+ else
+ {
+ for (i=0;i<n;i++)
+ {
+ const int fy = Y_FLIP(y[i]);
+ if (CLIPPIXEL(x[i],fy))
+ WRITE_RGBA( x[i], fy,
+ rgba[i][0], rgba[i][1],
+ rgba[i][2], rgba[i][3] );
+ }
+ }
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_WRITE_UNLOCK();
+}
+
+
+static void TAG(WriteMonoRGBASpan)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const void *value, const GLubyte mask[] )
+{
+ HW_WRITE_LOCK()
+ {
+ const GLubyte *color = (const GLubyte *) value;
+ GLint x1;
+ GLint n1;
+ LOCAL_VARS;
+ INIT_MONO_PIXEL(p, color);
+
+ y = Y_FLIP( y );
+
+ if (DBG) fprintf(stderr, "WriteMonoRGBASpan\n");
+
+ HW_WRITE_CLIPLOOP()
+ {
+ GLint i = 0;
+ CLIPSPAN(x,y,n,x1,n1,i);
+ if (mask)
+ {
+ for (;n1>0;i++,x1++,n1--)
+ if (mask[i])
+ WRITE_PIXEL( x1, y, p );
+ }
+ else
+ {
+ for (;n1>0;i++,x1++,n1--)
+ WRITE_PIXEL( x1, y, p );
+ }
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_WRITE_UNLOCK();
+}
+
+
+static void TAG(WriteMonoRGBAPixels)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n,
+ const GLint x[], const GLint y[],
+ const void *value,
+ const GLubyte mask[] )
+{
+ HW_WRITE_LOCK()
+ {
+ const GLubyte *color = (const GLubyte *) value;
+ GLint i;
+ LOCAL_VARS;
+ INIT_MONO_PIXEL(p, color);
+
+ if (DBG) fprintf(stderr, "WriteMonoRGBAPixels\n");
+
+ HW_WRITE_CLIPLOOP()
+ {
+ if (mask)
+ {
+ for (i=0;i<n;i++)
+ if (mask[i]) {
+ int fy = Y_FLIP(y[i]);
+ if (CLIPPIXEL( x[i], fy ))
+ WRITE_PIXEL( x[i], fy, p );
+ }
+ }
+ else
+ {
+ for (i=0;i<n;i++) {
+ int fy = Y_FLIP(y[i]);
+ if (CLIPPIXEL( x[i], fy ))
+ WRITE_PIXEL( x[i], fy, p );
+ }
+ }
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_WRITE_UNLOCK();
+}
+
+
+static void TAG(ReadRGBASpan)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y, void *values)
+{
+ HW_READ_LOCK()
+ {
+ GLubyte (*rgba)[4] = (GLubyte (*)[4]) values;
+ GLint x1,n1;
+ LOCAL_VARS;
+
+ y = Y_FLIP(y);
+
+ if (DBG) fprintf(stderr, "ReadRGBASpan\n");
+
+ HW_READ_CLIPLOOP()
+ {
+ GLint i = 0;
+ CLIPSPAN(x,y,n,x1,n1,i);
+ for (;n1>0;i++,x1++,n1--)
+ READ_RGBA( rgba[i], x1, y );
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_READ_UNLOCK();
+}
+
+
+#if defined(GET_PTR) && \
+ defined(USE_MMX_ASM) && \
+ (((SPANTMP_PIXEL_FMT == GL_BGRA) && \
+ (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8_REV)) || \
+ ((SPANTMP_PIXEL_FMT == GL_RGB) && \
+ (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_5_6_5)))
+static void TAG2(ReadRGBASpan,_MMX)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y, void *values)
+{
+#ifndef USE_INNER_EMMS
+ /* The EMMS instruction is directly in-lined here because using GCC's
+ * built-in _mm_empty function was found to utterly destroy performance.
+ */
+ __asm__ __volatile__( "emms" );
+#endif
+
+ HW_READ_LOCK()
+ {
+ GLubyte (*rgba)[4] = (GLubyte (*)[4]) values;
+ GLint x1,n1;
+ LOCAL_VARS;
+
+ y = Y_FLIP(y);
+
+ if (DBG) fprintf(stderr, "ReadRGBASpan\n");
+
+ HW_READ_CLIPLOOP()
+ {
+ GLint i = 0;
+ CLIPSPAN(x,y,n,x1,n1,i);
+
+ {
+ const void * src = GET_PTR( x1, y );
+#if (SPANTMP_PIXEL_FMT == GL_RGB) && \
+ (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_5_6_5)
+ _generic_read_RGBA_span_RGB565_MMX( src, rgba[i], n1 );
+#else
+ _generic_read_RGBA_span_BGRA8888_REV_MMX( src, rgba[i], n1 );
+#endif
+ }
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_READ_UNLOCK();
+#ifndef USE_INNER_EMMS
+ __asm__ __volatile__( "emms" );
+#endif
+}
+#endif
+
+
+#if defined(GET_PTR) && \
+ defined(USE_SSE_ASM) && \
+ (SPANTMP_PIXEL_FMT == GL_BGRA) && \
+ (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8_REV)
+static void TAG2(ReadRGBASpan,_SSE2)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ void *values)
+{
+ HW_READ_LOCK()
+ {
+ GLubyte (*rgba)[4] = (GLubyte (*)[4]) values;
+ GLint x1,n1;
+ LOCAL_VARS;
+
+ y = Y_FLIP(y);
+
+ if (DBG) fprintf(stderr, "ReadRGBASpan\n");
+
+ HW_READ_CLIPLOOP()
+ {
+ GLint i = 0;
+ CLIPSPAN(x,y,n,x1,n1,i);
+
+ {
+ const void * src = GET_PTR( x1, y );
+ _generic_read_RGBA_span_BGRA8888_REV_SSE2( src, rgba[i], n1 );
+ }
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_READ_UNLOCK();
+}
+#endif
+
+#if defined(GET_PTR) && \
+ defined(USE_SSE_ASM) && \
+ (SPANTMP_PIXEL_FMT == GL_BGRA) && \
+ (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8_REV)
+static void TAG2(ReadRGBASpan,_SSE)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ void *values)
+{
+#ifndef USE_INNER_EMMS
+ /* The EMMS instruction is directly in-lined here because using GCC's
+ * built-in _mm_empty function was found to utterly destroy performance.
+ */
+ __asm__ __volatile__( "emms" );
+#endif
+
+ HW_READ_LOCK()
+ {
+ GLubyte (*rgba)[4] = (GLubyte (*)[4]) values;
+ GLint x1,n1;
+ LOCAL_VARS;
+
+ y = Y_FLIP(y);
+
+ if (DBG) fprintf(stderr, "ReadRGBASpan\n");
+
+ HW_READ_CLIPLOOP()
+ {
+ GLint i = 0;
+ CLIPSPAN(x,y,n,x1,n1,i);
+
+ {
+ const void * src = GET_PTR( x1, y );
+ _generic_read_RGBA_span_BGRA8888_REV_SSE( src, rgba[i], n1 );
+ }
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_READ_UNLOCK();
+#ifndef USE_INNER_EMMS
+ __asm__ __volatile__( "emms" );
+#endif
+}
+#endif
+
+
+static void TAG(ReadRGBAPixels)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, const GLint x[], const GLint y[],
+ void *values )
+{
+ HW_READ_LOCK()
+ {
+ GLubyte (*rgba)[4] = (GLubyte (*)[4]) values;
+ GLint i;
+ LOCAL_VARS;
+
+ if (DBG) fprintf(stderr, "ReadRGBAPixels\n");
+
+ HW_READ_CLIPLOOP()
+ {
+ for (i=0;i<n;i++) {
+ int fy = Y_FLIP( y[i] );
+ if (CLIPPIXEL( x[i], fy ))
+ READ_RGBA( rgba[i], x[i], fy );
+ }
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_READ_UNLOCK();
+}
+
+static void TAG(InitPointers)(struct gl_renderbuffer *rb)
+{
+ rb->PutRow = TAG(WriteRGBASpan);
+ rb->PutRowRGB = TAG(WriteRGBSpan);
+ rb->PutMonoRow = TAG(WriteMonoRGBASpan);
+ rb->PutValues = TAG(WriteRGBAPixels);
+ rb->PutMonoValues = TAG(WriteMonoRGBAPixels);
+ rb->GetValues = TAG(ReadRGBAPixels);
+
+#if defined(GET_PTR)
+#if defined(USE_SSE_ASM) && \
+ (SPANTMP_PIXEL_FMT == GL_BGRA) && \
+ (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8_REV)
+ if ( cpu_has_xmm2 ) {
+ if (DBG) fprintf( stderr, "Using %s version of GetRow\n", "SSE2" );
+ rb->GetRow = TAG2(ReadRGBASpan, _SSE2);
+ }
+ else
+#endif
+#if defined(USE_SSE_ASM) && \
+ (SPANTMP_PIXEL_FMT == GL_BGRA) && \
+ (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8_REV)
+ if ( cpu_has_xmm ) {
+ if (DBG) fprintf( stderr, "Using %s version of GetRow\n", "SSE" );
+ rb->GetRow = TAG2(ReadRGBASpan, _SSE);
+ }
+ else
+#endif
+#if defined(USE_MMX_ASM) && \
+ (((SPANTMP_PIXEL_FMT == GL_BGRA) && \
+ (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_INT_8_8_8_8_REV)) || \
+ ((SPANTMP_PIXEL_FMT == GL_RGB) && \
+ (SPANTMP_PIXEL_TYPE == GL_UNSIGNED_SHORT_5_6_5)))
+ if ( cpu_has_mmx ) {
+ if (DBG) fprintf( stderr, "Using %s version of GetRow\n", "MMX" );
+ rb->GetRow = TAG2(ReadRGBASpan, _MMX);
+ }
+ else
+#endif
+#endif /* GET_PTR */
+ {
+ if (DBG) fprintf( stderr, "Using %s version of GetRow\n", "C" );
+ rb->GetRow = TAG(ReadRGBASpan);
+ }
+
+}
+
+
+#undef INIT_MONO_PIXEL
+#undef WRITE_PIXEL
+#undef WRITE_RGBA
+#undef READ_RGBA
+#undef TAG
+#undef TAG2
+#undef GET_VALUE
+#undef PUT_VALUE
+#undef GET_PTR
+#undef SPANTMP_PIXEL_FMT
+#undef SPANTMP_PIXEL_TYPE
+#undef SPANTMP_MESA_FMT
diff --git a/mesalib/src/mesa/drivers/dri/common/stenciltmp.h b/mesalib/src/mesa/drivers/dri/common/stenciltmp.h index 2b10b9ecf..2ea2e207a 100644 --- a/mesalib/src/mesa/drivers/dri/common/stenciltmp.h +++ b/mesalib/src/mesa/drivers/dri/common/stenciltmp.h @@ -1,245 +1,245 @@ - -#include "spantmp_common.h" - -#ifndef DBG -#define DBG 0 -#endif - -#ifndef HAVE_HW_STENCIL_SPANS -#define HAVE_HW_STENCIL_SPANS 0 -#endif - -#ifndef HAVE_HW_STENCIL_PIXELS -#define HAVE_HW_STENCIL_PIXELS 0 -#endif - -static void TAG(WriteStencilSpan)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const void *values, const GLubyte mask[] ) -{ - HW_WRITE_LOCK() - { - const GLubyte *stencil = (const GLubyte *) values; - GLint x1; - GLint n1; - LOCAL_STENCIL_VARS; - - y = Y_FLIP(y); - -#if HAVE_HW_STENCIL_SPANS - (void) x1; (void) n1; - - if (DBG) fprintf(stderr, "WriteStencilSpan 0..%d (x1 %d)\n", - (int)n1, (int)x1); - - WRITE_STENCIL_SPAN(); -#else /* HAVE_HW_STENCIL_SPANS */ - HW_CLIPLOOP() - { - GLint i = 0; - CLIPSPAN(x,y,n,x1,n1,i); - - if (DBG) fprintf(stderr, "WriteStencilSpan %d..%d (x1 %d)\n", - (int)i, (int)n1, (int)x1); - - if (mask) - { - for (;n1>0;i++,x1++,n1--) - if (mask[i]) - WRITE_STENCIL( x1, y, stencil[i] ); - } - else - { - for (;n1>0;i++,x1++,n1--) - WRITE_STENCIL( x1, y, stencil[i] ); - } - } - HW_ENDCLIPLOOP(); -#endif /* !HAVE_HW_STENCIL_SPANS */ - } - HW_WRITE_UNLOCK(); -} - -#if HAVE_HW_STENCIL_SPANS -/* implement MonoWriteDepthSpan() in terms of WriteDepthSpan() */ -static void -TAG(WriteMonoStencilSpan)( GLcontext *ctx, struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const void *value, const GLubyte mask[] ) -{ - const GLuint stenVal = *((GLuint *) value); - GLuint stens[MAX_WIDTH]; - GLuint i; - for (i = 0; i < n; i++) - stens[i] = stenVal; - TAG(WriteStencilSpan)(ctx, rb, n, x, y, stens, mask); -} -#else /* HAVE_HW_STENCIL_SPANS */ -static void TAG(WriteMonoStencilSpan)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const void *value, - const GLubyte mask[] ) -{ - HW_WRITE_LOCK() - { - const GLubyte stencil = *((const GLubyte *) value); - GLint x1; - GLint n1; - LOCAL_STENCIL_VARS; - - y = Y_FLIP(y); - - HW_CLIPLOOP() - { - GLint i = 0; - CLIPSPAN(x,y,n,x1,n1,i); - - if (DBG) fprintf(stderr, "WriteStencilSpan %d..%d (x1 %d)\n", - (int)i, (int)n1, (int)x1); - - if (mask) - { - for (;n1>0;i++,x1++,n1--) - if (mask[i]) - WRITE_STENCIL( x1, y, stencil ); - } - else - { - for (;n1>0;i++,x1++,n1--) - WRITE_STENCIL( x1, y, stencil ); - } - } - HW_ENDCLIPLOOP(); - } - HW_WRITE_UNLOCK(); -} -#endif /* !HAVE_HW_STENCIL_SPANS */ - - -static void TAG(WriteStencilPixels)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, - const GLint x[], const GLint y[], - const void *values, const GLubyte mask[] ) -{ - HW_WRITE_LOCK() - { - const GLubyte *stencil = (const GLubyte *) values; - GLuint i; - LOCAL_STENCIL_VARS; - - if (DBG) fprintf(stderr, "WriteStencilPixels\n"); - -#if HAVE_HW_STENCIL_PIXELS - (void) i; - - WRITE_STENCIL_PIXELS(); -#else /* HAVE_HW_STENCIL_PIXELS */ - HW_CLIPLOOP() - { - for (i=0;i<n;i++) - { - if (mask[i]) { - const int fy = Y_FLIP(y[i]); - if (CLIPPIXEL(x[i],fy)) - WRITE_STENCIL( x[i], fy, stencil[i] ); - } - } - } - HW_ENDCLIPLOOP(); -#endif /* !HAVE_HW_STENCIL_PIXELS */ - } - HW_WRITE_UNLOCK(); -} - - -/* Read stencil spans and pixels - */ -static void TAG(ReadStencilSpan)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - void *values) -{ - HW_READ_LOCK() - { - GLubyte *stencil = (GLubyte *) values; - GLint x1,n1; - LOCAL_STENCIL_VARS; - - y = Y_FLIP(y); - - if (DBG) fprintf(stderr, "ReadStencilSpan\n"); - -#if HAVE_HW_STENCIL_SPANS - (void) x1; (void) n1; - - READ_STENCIL_SPAN(); -#else /* HAVE_HW_STENCIL_SPANS */ - HW_CLIPLOOP() - { - GLint i = 0; - CLIPSPAN(x,y,n,x1,n1,i); - for (;n1>0;i++,n1--) - READ_STENCIL( stencil[i], (x+i), y ); - } - HW_ENDCLIPLOOP(); -#endif /* !HAVE_HW_STENCIL_SPANS */ - } - HW_READ_UNLOCK(); -} - -static void TAG(ReadStencilPixels)( GLcontext *ctx, - struct gl_renderbuffer *rb, - GLuint n, const GLint x[], const GLint y[], - void *values ) -{ - HW_READ_LOCK() - { - GLubyte *stencil = (GLubyte *) values; - GLuint i; - LOCAL_STENCIL_VARS; - - if (DBG) fprintf(stderr, "ReadStencilPixels\n"); - -#if HAVE_HW_STENCIL_PIXELS - (void) i; - - READ_STENCIL_PIXELS(); -#else /* HAVE_HW_STENCIL_PIXELS */ - HW_CLIPLOOP() - { - for (i=0;i<n;i++) { - int fy = Y_FLIP( y[i] ); - if (CLIPPIXEL( x[i], fy )) - READ_STENCIL( stencil[i], x[i], fy ); - } - } - HW_ENDCLIPLOOP(); -#endif /* !HAVE_HW_STENCIL_PIXELS */ - } - HW_READ_UNLOCK(); -} - - - -/** - * Initialize the given renderbuffer's span routines to point to - * the stencil functions we generated above. - */ -static void TAG(InitStencilPointers)(struct gl_renderbuffer *rb) -{ - rb->GetRow = TAG(ReadStencilSpan); - rb->GetValues = TAG(ReadStencilPixels); - rb->PutRow = TAG(WriteStencilSpan); - rb->PutRowRGB = NULL; - rb->PutMonoRow = TAG(WriteMonoStencilSpan); - rb->PutValues = TAG(WriteStencilPixels); - rb->PutMonoValues = NULL; -} - - -#undef WRITE_STENCIL -#undef READ_STENCIL -#undef TAG +
+#include "spantmp_common.h"
+
+#ifndef DBG
+#define DBG 0
+#endif
+
+#ifndef HAVE_HW_STENCIL_SPANS
+#define HAVE_HW_STENCIL_SPANS 0
+#endif
+
+#ifndef HAVE_HW_STENCIL_PIXELS
+#define HAVE_HW_STENCIL_PIXELS 0
+#endif
+
+static void TAG(WriteStencilSpan)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const void *values, const GLubyte mask[] )
+{
+ HW_WRITE_LOCK()
+ {
+ const GLubyte *stencil = (const GLubyte *) values;
+ GLint x1;
+ GLint n1;
+ LOCAL_STENCIL_VARS;
+
+ y = Y_FLIP(y);
+
+#if HAVE_HW_STENCIL_SPANS
+ (void) x1; (void) n1;
+
+ if (DBG) fprintf(stderr, "WriteStencilSpan 0..%d (x1 %d)\n",
+ (int)n1, (int)x1);
+
+ WRITE_STENCIL_SPAN();
+#else /* HAVE_HW_STENCIL_SPANS */
+ HW_CLIPLOOP()
+ {
+ GLint i = 0;
+ CLIPSPAN(x,y,n,x1,n1,i);
+
+ if (DBG) fprintf(stderr, "WriteStencilSpan %d..%d (x1 %d)\n",
+ (int)i, (int)n1, (int)x1);
+
+ if (mask)
+ {
+ for (;n1>0;i++,x1++,n1--)
+ if (mask[i])
+ WRITE_STENCIL( x1, y, stencil[i] );
+ }
+ else
+ {
+ for (;n1>0;i++,x1++,n1--)
+ WRITE_STENCIL( x1, y, stencil[i] );
+ }
+ }
+ HW_ENDCLIPLOOP();
+#endif /* !HAVE_HW_STENCIL_SPANS */
+ }
+ HW_WRITE_UNLOCK();
+}
+
+#if HAVE_HW_STENCIL_SPANS
+/* implement MonoWriteDepthSpan() in terms of WriteDepthSpan() */
+static void
+TAG(WriteMonoStencilSpan)( struct gl_context *ctx, struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const void *value, const GLubyte mask[] )
+{
+ const GLuint stenVal = *((GLuint *) value);
+ GLuint stens[MAX_WIDTH];
+ GLuint i;
+ for (i = 0; i < n; i++)
+ stens[i] = stenVal;
+ TAG(WriteStencilSpan)(ctx, rb, n, x, y, stens, mask);
+}
+#else /* HAVE_HW_STENCIL_SPANS */
+static void TAG(WriteMonoStencilSpan)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const void *value,
+ const GLubyte mask[] )
+{
+ HW_WRITE_LOCK()
+ {
+ const GLubyte stencil = *((const GLubyte *) value);
+ GLint x1;
+ GLint n1;
+ LOCAL_STENCIL_VARS;
+
+ y = Y_FLIP(y);
+
+ HW_CLIPLOOP()
+ {
+ GLint i = 0;
+ CLIPSPAN(x,y,n,x1,n1,i);
+
+ if (DBG) fprintf(stderr, "WriteStencilSpan %d..%d (x1 %d)\n",
+ (int)i, (int)n1, (int)x1);
+
+ if (mask)
+ {
+ for (;n1>0;i++,x1++,n1--)
+ if (mask[i])
+ WRITE_STENCIL( x1, y, stencil );
+ }
+ else
+ {
+ for (;n1>0;i++,x1++,n1--)
+ WRITE_STENCIL( x1, y, stencil );
+ }
+ }
+ HW_ENDCLIPLOOP();
+ }
+ HW_WRITE_UNLOCK();
+}
+#endif /* !HAVE_HW_STENCIL_SPANS */
+
+
+static void TAG(WriteStencilPixels)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n,
+ const GLint x[], const GLint y[],
+ const void *values, const GLubyte mask[] )
+{
+ HW_WRITE_LOCK()
+ {
+ const GLubyte *stencil = (const GLubyte *) values;
+ GLuint i;
+ LOCAL_STENCIL_VARS;
+
+ if (DBG) fprintf(stderr, "WriteStencilPixels\n");
+
+#if HAVE_HW_STENCIL_PIXELS
+ (void) i;
+
+ WRITE_STENCIL_PIXELS();
+#else /* HAVE_HW_STENCIL_PIXELS */
+ HW_CLIPLOOP()
+ {
+ for (i=0;i<n;i++)
+ {
+ if (mask[i]) {
+ const int fy = Y_FLIP(y[i]);
+ if (CLIPPIXEL(x[i],fy))
+ WRITE_STENCIL( x[i], fy, stencil[i] );
+ }
+ }
+ }
+ HW_ENDCLIPLOOP();
+#endif /* !HAVE_HW_STENCIL_PIXELS */
+ }
+ HW_WRITE_UNLOCK();
+}
+
+
+/* Read stencil spans and pixels
+ */
+static void TAG(ReadStencilSpan)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ void *values)
+{
+ HW_READ_LOCK()
+ {
+ GLubyte *stencil = (GLubyte *) values;
+ GLint x1,n1;
+ LOCAL_STENCIL_VARS;
+
+ y = Y_FLIP(y);
+
+ if (DBG) fprintf(stderr, "ReadStencilSpan\n");
+
+#if HAVE_HW_STENCIL_SPANS
+ (void) x1; (void) n1;
+
+ READ_STENCIL_SPAN();
+#else /* HAVE_HW_STENCIL_SPANS */
+ HW_CLIPLOOP()
+ {
+ GLint i = 0;
+ CLIPSPAN(x,y,n,x1,n1,i);
+ for (;n1>0;i++,n1--)
+ READ_STENCIL( stencil[i], (x+i), y );
+ }
+ HW_ENDCLIPLOOP();
+#endif /* !HAVE_HW_STENCIL_SPANS */
+ }
+ HW_READ_UNLOCK();
+}
+
+static void TAG(ReadStencilPixels)( struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, const GLint x[], const GLint y[],
+ void *values )
+{
+ HW_READ_LOCK()
+ {
+ GLubyte *stencil = (GLubyte *) values;
+ GLuint i;
+ LOCAL_STENCIL_VARS;
+
+ if (DBG) fprintf(stderr, "ReadStencilPixels\n");
+
+#if HAVE_HW_STENCIL_PIXELS
+ (void) i;
+
+ READ_STENCIL_PIXELS();
+#else /* HAVE_HW_STENCIL_PIXELS */
+ HW_CLIPLOOP()
+ {
+ for (i=0;i<n;i++) {
+ int fy = Y_FLIP( y[i] );
+ if (CLIPPIXEL( x[i], fy ))
+ READ_STENCIL( stencil[i], x[i], fy );
+ }
+ }
+ HW_ENDCLIPLOOP();
+#endif /* !HAVE_HW_STENCIL_PIXELS */
+ }
+ HW_READ_UNLOCK();
+}
+
+
+
+/**
+ * Initialize the given renderbuffer's span routines to point to
+ * the stencil functions we generated above.
+ */
+static void TAG(InitStencilPointers)(struct gl_renderbuffer *rb)
+{
+ rb->GetRow = TAG(ReadStencilSpan);
+ rb->GetValues = TAG(ReadStencilPixels);
+ rb->PutRow = TAG(WriteStencilSpan);
+ rb->PutRowRGB = NULL;
+ rb->PutMonoRow = TAG(WriteMonoStencilSpan);
+ rb->PutValues = TAG(WriteStencilPixels);
+ rb->PutMonoValues = NULL;
+}
+
+
+#undef WRITE_STENCIL
+#undef READ_STENCIL
+#undef TAG
diff --git a/mesalib/src/mesa/drivers/dri/common/texmem.c b/mesalib/src/mesa/drivers/dri/common/texmem.c index 895139b55..3c4f3373f 100644 --- a/mesalib/src/mesa/drivers/dri/common/texmem.c +++ b/mesalib/src/mesa/drivers/dri/common/texmem.c @@ -1,1341 +1,1341 @@ -/* - * Copyright 2000-2001 VA Linux Systems, Inc. - * (C) Copyright IBM Corporation 2002, 2003 - * 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 - * VA LINUX SYSTEM, IBM 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: - * Ian Romanick <idr@us.ibm.com> - * Keith Whitwell <keithw@tungstengraphics.com> - * Kevin E. Martin <kem@users.sourceforge.net> - * Gareth Hughes <gareth@nvidia.com> - */ - -/** \file texmem.c - * Implements all of the device-independent texture memory management. - * - * Currently, only a simple LRU texture memory management policy is - * implemented. In the (hopefully very near) future, better policies will be - * implemented. The idea is that the DRI should be able to run in one of two - * modes. In the default mode the DRI will dynamically attempt to discover - * the best texture management policy for the running application. In the - * other mode, the user (via some sort of as yet TBD mechanism) will select - * a texture management policy that is known to work well with the - * application. - */ - -#include "main/imports.h" -#include "main/macros.h" -#include "main/simple_list.h" -#include "texmem.h" - - -static unsigned dummy_swap_counter; - - -/** - * Calculate \f$\log_2\f$ of a value. This is a particularly poor - * implementation of this function. However, since system performance is in - * no way dependent on this function, the slowness of the implementation is - * irrelevent. - * - * \param n Value whose \f$\log_2\f$ is to be calculated - */ - -static GLuint -driLog2( GLuint n ) -{ - GLuint log2; - - for ( log2 = 1 ; n > 1 ; log2++ ) { - n >>= 1; - } - - return log2; -} - - - - -/** - * Determine if a texture is resident in textureable memory. Depending on - * the driver, this may or may not be on-card memory. It could be AGP memory - * or anyother type of memory from which the hardware can directly read - * texels. - * - * This function is intended to be used as the \c IsTextureResident function - * in the device's \c dd_function_table. - * - * \param ctx GL context pointer (currently unused) - * \param texObj Texture object to be tested - */ - -GLboolean -driIsTextureResident( GLcontext * ctx, - struct gl_texture_object * texObj ) -{ - driTextureObject * t; - - - t = (driTextureObject *) texObj->DriverData; - return( (t != NULL) && (t->memBlock != NULL) ); -} - - - - -/** - * (Re)initialize the global circular LRU list. The last element - * in the array (\a heap->nrRegions) is the sentinal. Keeping it - * at the end of the array allows the other elements of the array - * to be addressed rationally when looking up objects at a particular - * location in texture memory. - * - * \param heap Texture heap to be reset - */ - -static void resetGlobalLRU( driTexHeap * heap ) -{ - drmTextureRegionPtr list = heap->global_regions; - unsigned sz = 1U << heap->logGranularity; - unsigned i; - - for (i = 0 ; (i+1) * sz <= heap->size ; i++) { - list[i].prev = i-1; - list[i].next = i+1; - list[i].age = 0; - } - - i--; - list[0].prev = heap->nrRegions; - list[i].prev = i-1; - list[i].next = heap->nrRegions; - list[heap->nrRegions].prev = i; - list[heap->nrRegions].next = 0; - heap->global_age[0] = 0; -} - -/** - * Print out debugging information about the local texture LRU. - * - * \param heap Texture heap to be printed - * \param callername Name of calling function - */ -static void printLocalLRU( driTexHeap * heap, const char *callername ) -{ - driTextureObject *t; - unsigned sz = 1U << heap->logGranularity; - - fprintf( stderr, "%s in %s:\nLocal LRU, heap %d:\n", - __FUNCTION__, callername, heap->heapId ); - - foreach ( t, &heap->texture_objects ) { - if (!t->memBlock) - continue; - if (!t->tObj) { - fprintf( stderr, "Placeholder (%p) %d at 0x%x sz 0x%x\n", - (void *)t, - t->memBlock->ofs / sz, - t->memBlock->ofs, - t->memBlock->size ); - } else { - fprintf( stderr, "Texture (%p) at 0x%x sz 0x%x\n", - (void *)t, - t->memBlock->ofs, - t->memBlock->size ); - } - } - foreach ( t, heap->swapped_objects ) { - if (!t->tObj) { - fprintf( stderr, "Swapped Placeholder (%p)\n", (void *)t ); - } else { - fprintf( stderr, "Swapped Texture (%p)\n", (void *)t ); - } - } - - fprintf( stderr, "\n" ); -} - -/** - * Print out debugging information about the global texture LRU. - * - * \param heap Texture heap to be printed - * \param callername Name of calling function - */ -static void printGlobalLRU( driTexHeap * heap, const char *callername ) -{ - drmTextureRegionPtr list = heap->global_regions; - unsigned int i, j; - - fprintf( stderr, "%s in %s:\nGlobal LRU, heap %d list %p:\n", - __FUNCTION__, callername, heap->heapId, (void *)list ); - - for ( i = 0, j = heap->nrRegions ; i < heap->nrRegions ; i++ ) { - fprintf( stderr, "list[%d] age %d next %d prev %d in_use %d\n", - j, list[j].age, list[j].next, list[j].prev, list[j].in_use ); - j = list[j].next; - if ( j == heap->nrRegions ) break; - } - - if ( j != heap->nrRegions ) { - fprintf( stderr, "Loop detected in global LRU\n" ); - for ( i = 0 ; i < heap->nrRegions ; i++ ) { - fprintf( stderr, "list[%d] age %d next %d prev %d in_use %d\n", - i, list[i].age, list[i].next, list[i].prev, list[i].in_use ); - } - } - - fprintf( stderr, "\n" ); -} - - -/** - * Called by the client whenever it touches a local texture. - * - * \param t Texture object that the client has accessed - */ - -void driUpdateTextureLRU( driTextureObject * t ) -{ - driTexHeap * heap; - drmTextureRegionPtr list; - unsigned shift; - unsigned start; - unsigned end; - unsigned i; - - - heap = t->heap; - if ( heap != NULL ) { - shift = heap->logGranularity; - start = t->memBlock->ofs >> shift; - end = (t->memBlock->ofs + t->memBlock->size - 1) >> shift; - - - heap->local_age = ++heap->global_age[0]; - list = heap->global_regions; - - - /* Update the context's local LRU - */ - - move_to_head( & heap->texture_objects, t ); - - - for (i = start ; i <= end ; i++) { - list[i].age = heap->local_age; - - /* remove_from_list(i) - */ - list[(unsigned)list[i].next].prev = list[i].prev; - list[(unsigned)list[i].prev].next = list[i].next; - - /* insert_at_head(list, i) - */ - list[i].prev = heap->nrRegions; - list[i].next = list[heap->nrRegions].next; - list[(unsigned)list[heap->nrRegions].next].prev = i; - list[heap->nrRegions].next = i; - } - - if ( 0 ) { - printGlobalLRU( heap, __FUNCTION__ ); - printLocalLRU( heap, __FUNCTION__ ); - } - } -} - - - - -/** - * Keep track of swapped out texture objects. - * - * \param t Texture object to be "swapped" out of its texture heap - */ - -void driSwapOutTextureObject( driTextureObject * t ) -{ - unsigned face; - - - if ( t->memBlock != NULL ) { - assert( t->heap != NULL ); - mmFreeMem( t->memBlock ); - t->memBlock = NULL; - - if (t->timestamp > t->heap->timestamp) - t->heap->timestamp = t->timestamp; - - t->heap->texture_swaps[0]++; - move_to_tail( t->heap->swapped_objects, t ); - t->heap = NULL; - } - else { - assert( t->heap == NULL ); - } - - - for ( face = 0 ; face < 6 ; face++ ) { - t->dirty_images[face] = ~0; - } -} - - - - -/** - * Destroy hardware state associated with texture \a t. Calls the - * \a destroy_texture_object method associated with the heap from which - * \a t was allocated. - * - * \param t Texture object to be destroyed - */ - -void driDestroyTextureObject( driTextureObject * t ) -{ - driTexHeap * heap; - - - if ( 0 ) { - fprintf( stderr, "[%s:%d] freeing %p (tObj = %p, DriverData = %p)\n", - __FILE__, __LINE__, - (void *)t, - (void *)((t != NULL) ? t->tObj : NULL), - (void *)((t != NULL && t->tObj != NULL) ? t->tObj->DriverData : NULL )); - } - - if ( t != NULL ) { - if ( t->memBlock ) { - heap = t->heap; - assert( heap != NULL ); - - heap->texture_swaps[0]++; - - mmFreeMem( t->memBlock ); - t->memBlock = NULL; - - if (t->timestamp > t->heap->timestamp) - t->heap->timestamp = t->timestamp; - - heap->destroy_texture_object( heap->driverContext, t ); - t->heap = NULL; - } - - if ( t->tObj != NULL ) { - assert( t->tObj->DriverData == t ); - t->tObj->DriverData = NULL; - } - - remove_from_list( t ); - FREE( t ); - } - - if ( 0 ) { - fprintf( stderr, "[%s:%d] done freeing %p\n", __FILE__, __LINE__, (void *)t ); - } -} - - - - -/** - * Update the local heap's representation of texture memory based on - * data in the SAREA. This is done each time it is detected that some other - * direct rendering client has held the lock. This pertains to both our local - * textures and the textures belonging to other clients. Keep track of other - * client's textures by pushing a placeholder texture onto the LRU list -- - * these are denoted by \a tObj being \a NULL. - * - * \param heap Heap whose state is to be updated - * \param offset Byte offset in the heap that has been stolen - * \param size Size, in bytes, of the stolen block - * \param in_use Non-zero if the block is pinned/reserved by the kernel - */ - -static void driTexturesGone( driTexHeap * heap, int offset, int size, - int in_use ) -{ - driTextureObject * t; - driTextureObject * tmp; - - - foreach_s ( t, tmp, & heap->texture_objects ) { - if ( (t->memBlock->ofs < (offset + size)) - && ((t->memBlock->ofs + t->memBlock->size) > offset) ) { - /* It overlaps - kick it out. If the texture object is just a - * place holder, then destroy it all together. Otherwise, mark - * it as being swapped out. - */ - - if ( t->tObj != NULL ) { - driSwapOutTextureObject( t ); - } - else { - driDestroyTextureObject( t ); - } - } - } - - - { - t = (driTextureObject *) CALLOC( heap->texture_object_size ); - if ( t == NULL ) return; - - t->memBlock = mmAllocMem( heap->memory_heap, size, 0, offset ); - if ( t->memBlock == NULL ) { - fprintf( stderr, "Couldn't alloc placeholder: heap %u sz %x ofs %x\n", heap->heapId, - (int)size, (int)offset ); - mmDumpMemInfo( heap->memory_heap ); - FREE(t); - return; - } - t->heap = heap; - if (in_use) - t->reserved = 1; - insert_at_head( & heap->texture_objects, t ); - } -} - - - - -/** - * Called by the client on lock contention to determine whether textures have - * been stolen. If another client has modified a region in which we have - * textures, then we need to figure out which of our textures have been - * removed and update our global LRU. - * - * \param heap Texture heap to be updated - */ - -void driAgeTextures( driTexHeap * heap ) -{ - drmTextureRegionPtr list = heap->global_regions; - unsigned sz = 1U << (heap->logGranularity); - unsigned i, nr = 0; - - - /* Have to go right round from the back to ensure stuff ends up - * LRU in the local list... Fix with a cursor pointer. - */ - - for (i = list[heap->nrRegions].prev ; - i != heap->nrRegions && nr < heap->nrRegions ; - i = list[i].prev, nr++) { - /* If switching texturing schemes, then the SAREA might not have been - * properly cleared, so we need to reset the global texture LRU. - */ - - if ( (i * sz) > heap->size ) { - nr = heap->nrRegions; - break; - } - - if (list[i].age > heap->local_age) - driTexturesGone( heap, i * sz, sz, list[i].in_use); - } - - /* Loop or uninitialized heap detected. Reset. - */ - - if (nr == heap->nrRegions) { - driTexturesGone( heap, 0, heap->size, 0); - resetGlobalLRU( heap ); - } - - if ( 0 ) { - printGlobalLRU( heap, __FUNCTION__ ); - printLocalLRU( heap, __FUNCTION__ ); - } - - heap->local_age = heap->global_age[0]; -} - - - - -#define INDEX_ARRAY_SIZE 6 /* I'm not aware of driver with more than 2 heaps */ - -/** - * Allocate memory from a texture heap to hold a texture object. This - * routine will attempt to allocate memory for the texture from the heaps - * specified by \c heap_array in order. That is, first it will try to - * allocate from \c heap_array[0], then \c heap_array[1], and so on. - * - * \param heap_array Array of pointers to texture heaps to use - * \param nr_heaps Number of heap pointer in \a heap_array - * \param t Texture object for which space is needed - * \return The ID of the heap from which memory was allocated, or -1 if - * memory could not be allocated. - * - * \bug The replacement policy implemented by this function is horrible. - */ - - -int -driAllocateTexture( driTexHeap * const * heap_array, unsigned nr_heaps, - driTextureObject * t ) -{ - driTexHeap * heap; - driTextureObject * temp; - driTextureObject * cursor; - unsigned id; - - - /* In case it already has texture space, initialize heap. This also - * prevents GCC from issuing a warning that heap might be used - * uninitialized. - */ - - heap = t->heap; - - - /* Run through each of the existing heaps and try to allocate a buffer - * to hold the texture. - */ - - for ( id = 0 ; (t->memBlock == NULL) && (id < nr_heaps) ; id++ ) { - heap = heap_array[ id ]; - if ( heap != NULL ) { - t->memBlock = mmAllocMem( heap->memory_heap, t->totalSize, - heap->alignmentShift, 0 ); - } - } - - - /* Kick textures out until the requested texture fits. - */ - - if ( t->memBlock == NULL ) { - unsigned index[INDEX_ARRAY_SIZE]; - unsigned nrGoodHeaps = 0; - - /* Trying to avoid dynamic memory allocation. If you have more - * heaps, increase INDEX_ARRAY_SIZE. I'm not aware of any - * drivers with more than 2 tex heaps. */ - assert( nr_heaps < INDEX_ARRAY_SIZE ); - - /* Sort large enough heaps by duty. Insertion sort should be - * fast enough for such a short array. */ - for ( id = 0 ; id < nr_heaps ; id++ ) { - heap = heap_array[ id ]; - - if ( heap != NULL && t->totalSize <= heap->size ) { - unsigned j; - - for ( j = 0 ; j < nrGoodHeaps; j++ ) { - if ( heap->duty > heap_array[ index[ j ] ]->duty ) - break; - } - - if ( j < nrGoodHeaps ) { - memmove( &index[ j+1 ], &index[ j ], - sizeof(index[ 0 ]) * (nrGoodHeaps - j) ); - } - - index[ j ] = id; - - nrGoodHeaps++; - } - } - - for ( id = 0 ; (t->memBlock == NULL) && (id < nrGoodHeaps) ; id++ ) { - heap = heap_array[ index[ id ] ]; - - for ( cursor = heap->texture_objects.prev, temp = cursor->prev; - cursor != &heap->texture_objects ; - cursor = temp, temp = cursor->prev ) { - - /* The the LRU element. If the texture is bound to one of - * the texture units, then we cannot kick it out. - */ - if ( cursor->bound || cursor->reserved ) { - continue; - } - - if ( cursor->memBlock ) - heap->duty -= cursor->memBlock->size; - - /* If this is a placeholder, there's no need to keep it */ - if (cursor->tObj) - driSwapOutTextureObject( cursor ); - else - driDestroyTextureObject( cursor ); - - t->memBlock = mmAllocMem( heap->memory_heap, t->totalSize, - heap->alignmentShift, 0 ); - - if (t->memBlock) - break; - } - } - - /* Rebalance duties. If a heap kicked more data than its duty, - * then all other heaps get that amount multiplied with their - * relative weight added to their duty. The negative duty is - * reset to 0. In the end all heaps have a duty >= 0. - * - * CAUTION: we must not change the heap pointer here, because it - * is used below to update the texture object. - */ - for ( id = 0 ; id < nr_heaps ; id++ ) - if ( heap_array[ id ] != NULL && heap_array[ id ]->duty < 0) { - int duty = -heap_array[ id ]->duty; - double weight = heap_array[ id ]->weight; - unsigned j; - - for ( j = 0 ; j < nr_heaps ; j++ ) - if ( j != id && heap_array[ j ] != NULL ) { - heap_array[ j ]->duty += (double) duty * - heap_array[ j ]->weight / weight; - } - - heap_array[ id ]->duty = 0; - } - } - - - if ( t->memBlock != NULL ) { - /* id and heap->heapId may or may not be the same value here. - */ - - assert( heap != NULL ); - assert( (t->heap == NULL) || (t->heap == heap) ); - - t->heap = heap; - return heap->heapId; - } - else { - assert( t->heap == NULL ); - - fprintf( stderr, "[%s:%d] unable to allocate texture\n", - __FUNCTION__, __LINE__ ); - return -1; - } -} - - - - - - -/** - * Set the location where the texture-swap counter is stored. - */ - -void -driSetTextureSwapCounterLocation( driTexHeap * heap, unsigned * counter ) -{ - heap->texture_swaps = (counter == NULL) ? & dummy_swap_counter : counter; -} - - - - -/** - * Create a new heap for texture data. - * - * \param heap_id Device-dependent heap identifier. This value - * will returned by driAllocateTexture when memory - * is allocated from this heap. - * \param context Device-dependent driver context. This is - * supplied as the first parameter to the - * \c destroy_tex_obj function. - * \param size Size, in bytes, of the texture region - * \param alignmentShift Alignment requirement for textures. If textures - * must be allocated on a 4096 byte boundry, this - * would be 12. - * \param nr_regions Number of regions into which this texture space - * should be partitioned - * \param global_regions Array of \c drmTextureRegion structures in the SAREA - * \param global_age Pointer to the global texture age in the SAREA - * \param swapped_objects Pointer to the list of texture objects that are - * not in texture memory (i.e., have been swapped - * out). - * \param texture_object_size Size, in bytes, of a device-dependent texture - * object - * \param destroy_tex_obj Function used to destroy a device-dependent - * texture object - * - * \sa driDestroyTextureHeap - */ - -driTexHeap * -driCreateTextureHeap( unsigned heap_id, void * context, unsigned size, - unsigned alignmentShift, unsigned nr_regions, - drmTextureRegionPtr global_regions, unsigned * global_age, - driTextureObject * swapped_objects, - unsigned texture_object_size, - destroy_texture_object_t * destroy_tex_obj - ) -{ - driTexHeap * heap; - unsigned l; - - - if ( 0 ) - fprintf( stderr, "%s( %u, %p, %u, %u, %u )\n", - __FUNCTION__, - heap_id, (void *)context, size, alignmentShift, nr_regions ); - - heap = (driTexHeap *) CALLOC( sizeof( driTexHeap ) ); - if ( heap != NULL ) { - l = driLog2( (size - 1) / nr_regions ); - if ( l < alignmentShift ) - { - l = alignmentShift; - } - - heap->logGranularity = l; - heap->size = size & ~((1L << l) - 1); - - heap->memory_heap = mmInit( 0, heap->size ); - if ( heap->memory_heap != NULL ) { - heap->heapId = heap_id; - heap->driverContext = context; - - heap->alignmentShift = alignmentShift; - heap->nrRegions = nr_regions; - heap->global_regions = global_regions; - heap->global_age = global_age; - heap->swapped_objects = swapped_objects; - heap->texture_object_size = texture_object_size; - heap->destroy_texture_object = destroy_tex_obj; - - /* Force global heap init */ - if (heap->global_age[0] == 0) - heap->local_age = ~0; - else - heap->local_age = 0; - - make_empty_list( & heap->texture_objects ); - driSetTextureSwapCounterLocation( heap, NULL ); - - heap->weight = heap->size; - heap->duty = 0; - } - else { - FREE( heap ); - heap = NULL; - } - } - - - if ( 0 ) - fprintf( stderr, "%s returning %p\n", __FUNCTION__, (void *)heap ); - - return heap; -} - - - - -/** Destroys a texture heap - * - * \param heap Texture heap to be destroyed - */ - -void -driDestroyTextureHeap( driTexHeap * heap ) -{ - driTextureObject * t; - driTextureObject * temp; - - - if ( heap != NULL ) { - foreach_s( t, temp, & heap->texture_objects ) { - driDestroyTextureObject( t ); - } - foreach_s( t, temp, heap->swapped_objects ) { - driDestroyTextureObject( t ); - } - - mmDestroy( heap->memory_heap ); - FREE( heap ); - } -} - - - - -/****************************************************************************/ -/** - * Determine how many texels (including all mipmap levels) would be required - * for a texture map of size \f$2^^\c base_size_log2\f$ would require. - * - * \param base_size_log2 \f$log_2\f$ of the size of a side of the texture - * \param dimensions Number of dimensions of the texture. Either 2 or 3. - * \param faces Number of faces of the texture. Either 1 or 6 (for cube maps). - * \return Number of texels - */ - -static unsigned -texels_this_map_size( int base_size_log2, unsigned dimensions, unsigned faces ) -{ - unsigned texels; - - - assert( (faces == 1) || (faces == 6) ); - assert( (dimensions == 2) || (dimensions == 3) ); - - texels = 0; - if ( base_size_log2 >= 0 ) { - texels = (1U << (dimensions * base_size_log2)); - - /* See http://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg03636.html - * for the complete explaination of why this formulation is used. - * Basically, the smaller mipmap levels sum to 0.333 the size of the - * level 0 map. The total size is therefore the size of the map - * multipled by 1.333. The +2 is there to round up. - */ - - texels = (texels * 4 * faces + 2) / 3; - } - - return texels; -} - - - - -struct maps_per_heap { - unsigned c[32]; -}; - -static void -fill_in_maximums( driTexHeap * const * heaps, unsigned nr_heaps, - unsigned max_bytes_per_texel, unsigned max_size, - unsigned mipmaps_at_once, unsigned dimensions, - unsigned faces, struct maps_per_heap * max_textures ) -{ - unsigned heap; - unsigned log2_size; - unsigned mask; - - - /* Determine how many textures of each size can be stored in each - * texture heap. - */ - - for ( heap = 0 ; heap < nr_heaps ; heap++ ) { - if ( heaps[ heap ] == NULL ) { - (void) memset( max_textures[ heap ].c, 0, - sizeof( max_textures[ heap ].c ) ); - continue; - } - - mask = (1U << heaps[ heap ]->logGranularity) - 1; - - if ( 0 ) { - fprintf( stderr, "[%s:%d] heap[%u] = %u bytes, mask = 0x%08x\n", - __FILE__, __LINE__, - heap, heaps[ heap ]->size, mask ); - } - - for ( log2_size = max_size ; log2_size > 0 ; log2_size-- ) { - unsigned total; - - - /* Determine the total number of bytes required by a texture of - * size log2_size. - */ - - total = texels_this_map_size( log2_size, dimensions, faces ) - - texels_this_map_size( log2_size - mipmaps_at_once, - dimensions, faces ); - total *= max_bytes_per_texel; - total = (total + mask) & ~mask; - - /* The number of textures of a given size that will fit in a heap - * is equal to the size of the heap divided by the size of the - * texture. - */ - - max_textures[ heap ].c[ log2_size ] = heaps[ heap ]->size / total; - - if ( 0 ) { - fprintf( stderr, "[%s:%d] max_textures[%u].c[%02u] " - "= 0x%08x / 0x%08x " - "= %u (%u)\n", - __FILE__, __LINE__, - heap, log2_size, - heaps[ heap ]->size, total, - heaps[ heap ]->size / total, - max_textures[ heap ].c[ log2_size ] ); - } - } - } -} - - -static unsigned -get_max_size( unsigned nr_heaps, - unsigned texture_units, - unsigned max_size, - int all_textures_one_heap, - struct maps_per_heap * max_textures ) -{ - unsigned heap; - unsigned log2_size; - - - /* Determine the largest texture size such that a texture of that size - * can be bound to each texture unit at the same time. Some hardware - * may require that all textures be in the same texture heap for - * multitexturing. - */ - - for ( log2_size = max_size ; log2_size > 0 ; log2_size-- ) { - unsigned total = 0; - - for ( heap = 0 ; heap < nr_heaps ; heap++ ) - { - total += max_textures[ heap ].c[ log2_size ]; - - if ( 0 ) { - fprintf( stderr, "[%s:%d] max_textures[%u].c[%02u] = %u, " - "total = %u\n", __FILE__, __LINE__, heap, log2_size, - max_textures[ heap ].c[ log2_size ], total ); - } - - if ( (max_textures[ heap ].c[ log2_size ] >= texture_units) - || (!all_textures_one_heap && (total >= texture_units)) ) { - /* The number of mipmap levels is the log-base-2 of the - * maximum texture size plus 1. If the maximum texture size - * is 1x1, the log-base-2 is 0 and 1 mipmap level (the base - * level) is available. - */ - - return log2_size + 1; - } - } - } - - /* This should NEVER happen. It should always be possible to have at - * *least* a 1x1 texture in memory! - */ - assert( log2_size != 0 ); - return 0; -} - -#define SET_MAX(f,v) \ - do { if ( max_sizes[v] != 0 ) { limits-> f = max_sizes[v]; } } while( 0 ) - -#define SET_MAX_RECT(f,v) \ - do { if ( max_sizes[v] != 0 ) { limits-> f = 1 << (max_sizes[v] - 1); } } while( 0 ) - - -/** - * Given the amount of texture memory, the number of texture units, and the - * maximum size of a texel, calculate the maximum texture size the driver can - * advertise. - * - * \param heaps Texture heaps for this card - * \param nr_heap Number of texture heaps - * \param limits OpenGL contants. MaxTextureUnits must be set. - * \param max_bytes_per_texel Maximum size of a single texel, in bytes - * \param max_2D_size \f$\log_2\f$ of the maximum 2D texture size (i.e., - * 1024x1024 textures, this would be 10) - * \param max_3D_size \f$\log_2\f$ of the maximum 3D texture size (i.e., - * 1024x1024x1024 textures, this would be 10) - * \param max_cube_size \f$\log_2\f$ of the maximum cube texture size (i.e., - * 1024x1024 textures, this would be 10) - * \param max_rect_size \f$\log_2\f$ of the maximum texture rectangle size - * (i.e., 1024x1024 textures, this would be 10). This is a power-of-2 - * even though texture rectangles need not be a power-of-2. - * \param mipmaps_at_once Total number of mipmaps that can be used - * at one time. For most hardware this will be \f$\c max_size + 1\f$. - * For hardware that does not support mipmapping, this will be 1. - * \param all_textures_one_heap True if the hardware requires that all - * textures be in a single texture heap for multitexturing. - * \param allow_larger_textures 0 conservative, 1 calculate limits - * so at least one worst-case texture can fit, 2 just use hw limits. - */ - -void -driCalculateMaxTextureLevels( driTexHeap * const * heaps, - unsigned nr_heaps, - struct gl_constants * limits, - unsigned max_bytes_per_texel, - unsigned max_2D_size, - unsigned max_3D_size, - unsigned max_cube_size, - unsigned max_rect_size, - unsigned mipmaps_at_once, - int all_textures_one_heap, - int allow_larger_textures ) -{ - struct maps_per_heap max_textures[8]; - unsigned i; - const unsigned dimensions[4] = { 2, 3, 2, 2 }; - const unsigned faces[4] = { 1, 1, 6, 1 }; - unsigned max_sizes[4]; - unsigned mipmaps[4]; - - - max_sizes[0] = max_2D_size; - max_sizes[1] = max_3D_size; - max_sizes[2] = max_cube_size; - max_sizes[3] = max_rect_size; - - mipmaps[0] = mipmaps_at_once; - mipmaps[1] = mipmaps_at_once; - mipmaps[2] = mipmaps_at_once; - mipmaps[3] = 1; - - - /* Calculate the maximum number of texture levels in two passes. The - * first pass determines how many textures of each power-of-two size - * (including all mipmap levels for that size) can fit in each texture - * heap. The second pass finds the largest texture size that allows - * a texture of that size to be bound to every texture unit. - */ - - for ( i = 0 ; i < 4 ; i++ ) { - if ( (allow_larger_textures != 2) && (max_sizes[ i ] != 0) ) { - fill_in_maximums( heaps, nr_heaps, max_bytes_per_texel, - max_sizes[ i ], mipmaps[ i ], - dimensions[ i ], faces[ i ], - max_textures ); - - max_sizes[ i ] = get_max_size( nr_heaps, - allow_larger_textures == 1 ? - 1 : limits->MaxTextureUnits, - max_sizes[ i ], - all_textures_one_heap, - max_textures ); - } - else if (max_sizes[ i ] != 0) { - max_sizes[ i ] += 1; - } - } - - SET_MAX( MaxTextureLevels, 0 ); - SET_MAX( Max3DTextureLevels, 1 ); - SET_MAX( MaxCubeTextureLevels, 2 ); - SET_MAX_RECT( MaxTextureRectSize, 3 ); -} - - - - -/** - * Perform initial binding of default textures objects on a per unit, per - * texture target basis. - * - * \param ctx Current OpenGL context - * \param swapped List of swapped-out textures - * \param targets Bit-mask of value texture targets - */ - -void driInitTextureObjects( GLcontext *ctx, driTextureObject * swapped, - GLuint targets ) -{ - struct gl_texture_object *texObj; - GLuint tmp = ctx->Texture.CurrentUnit; - unsigned i; - - - for ( i = 0 ; i < ctx->Const.MaxTextureUnits ; i++ ) { - ctx->Texture.CurrentUnit = i; - - if ( (targets & DRI_TEXMGR_DO_TEXTURE_1D) != 0 ) { - texObj = ctx->Texture.Unit[i].CurrentTex[TEXTURE_1D_INDEX]; - ctx->Driver.BindTexture( ctx, GL_TEXTURE_1D, texObj ); - move_to_tail( swapped, (driTextureObject *) texObj->DriverData ); - } - - if ( (targets & DRI_TEXMGR_DO_TEXTURE_2D) != 0 ) { - texObj = ctx->Texture.Unit[i].CurrentTex[TEXTURE_2D_INDEX]; - ctx->Driver.BindTexture( ctx, GL_TEXTURE_2D, texObj ); - move_to_tail( swapped, (driTextureObject *) texObj->DriverData ); - } - - if ( (targets & DRI_TEXMGR_DO_TEXTURE_3D) != 0 ) { - texObj = ctx->Texture.Unit[i].CurrentTex[TEXTURE_3D_INDEX]; - ctx->Driver.BindTexture( ctx, GL_TEXTURE_3D, texObj ); - move_to_tail( swapped, (driTextureObject *) texObj->DriverData ); - } - - if ( (targets & DRI_TEXMGR_DO_TEXTURE_CUBE) != 0 ) { - texObj = ctx->Texture.Unit[i].CurrentTex[TEXTURE_CUBE_INDEX]; - ctx->Driver.BindTexture( ctx, GL_TEXTURE_CUBE_MAP_ARB, texObj ); - move_to_tail( swapped, (driTextureObject *) texObj->DriverData ); - } - - if ( (targets & DRI_TEXMGR_DO_TEXTURE_RECT) != 0 ) { - texObj = ctx->Texture.Unit[i].CurrentTex[TEXTURE_RECT_INDEX]; - ctx->Driver.BindTexture( ctx, GL_TEXTURE_RECTANGLE_NV, texObj ); - move_to_tail( swapped, (driTextureObject *) texObj->DriverData ); - } - } - - ctx->Texture.CurrentUnit = tmp; -} - - - - -/** - * Verify that the specified texture is in the specificed heap. - * - * \param tex Texture to be tested. - * \param heap Texture memory heap to be tested. - * \return True if the texture is in the heap, false otherwise. - */ - -static GLboolean -check_in_heap( const driTextureObject * tex, const driTexHeap * heap ) -{ -#if 1 - return tex->heap == heap; -#else - driTextureObject * curr; - - foreach( curr, & heap->texture_objects ) { - if ( curr == tex ) { - break; - } - } - - return curr == tex; -#endif -} - - - -/****************************************************************************/ -/** - * Validate the consistency of a set of texture heaps. - * Original version by Keith Whitwell in r200/r200_sanity.c. - */ - -GLboolean -driValidateTextureHeaps( driTexHeap * const * texture_heaps, - unsigned nr_heaps, const driTextureObject * swapped ) -{ - driTextureObject *t; - unsigned i; - - for ( i = 0 ; i < nr_heaps ; i++ ) { - int last_end = 0; - unsigned textures_in_heap = 0; - unsigned blocks_in_mempool = 0; - const driTexHeap * heap = texture_heaps[i]; - const struct mem_block *p = heap->memory_heap; - - /* Check each texture object has a MemBlock, and is linked into - * the correct heap. - * - * Check the texobj base address corresponds to the MemBlock - * range. Check the texobj size (recalculate?) fits within - * the MemBlock. - * - * Count the number of texobj's using this heap. - */ - - foreach ( t, &heap->texture_objects ) { - if ( !check_in_heap( t, heap ) ) { - fprintf( stderr, "%s memory block for texture object @ %p not " - "found in heap #%d\n", - __FUNCTION__, (void *)t, i ); - return GL_FALSE; - } - - - if ( t->totalSize > t->memBlock->size ) { - fprintf( stderr, "%s: Memory block for texture object @ %p is " - "only %u bytes, but %u are required\n", - __FUNCTION__, (void *)t, t->totalSize, t->memBlock->size ); - return GL_FALSE; - } - - textures_in_heap++; - } - - /* Validate the contents of the heap: - * - Ordering - * - Overlaps - * - Bounds - */ - - while ( p != NULL ) { - if (p->reserved) { - fprintf( stderr, "%s: Block (%08x,%x), is reserved?!\n", - __FUNCTION__, p->ofs, p->size ); - return GL_FALSE; - } - - if (p->ofs != last_end) { - fprintf( stderr, "%s: blocks_in_mempool = %d, last_end = %d, p->ofs = %d\n", - __FUNCTION__, blocks_in_mempool, last_end, p->ofs ); - return GL_FALSE; - } - - if (!p->reserved && !p->free) { - blocks_in_mempool++; - } - - last_end = p->ofs + p->size; - p = p->next; - } - - if (textures_in_heap != blocks_in_mempool) { - fprintf( stderr, "%s: Different number of textures objects (%u) and " - "inuse memory blocks (%u)\n", - __FUNCTION__, textures_in_heap, blocks_in_mempool ); - return GL_FALSE; - } - -#if 0 - fprintf( stderr, "%s: textures_in_heap = %u\n", - __FUNCTION__, textures_in_heap ); -#endif - } - - - /* Check swapped texobj's have zero memblocks - */ - i = 0; - foreach ( t, swapped ) { - if ( t->memBlock != NULL ) { - fprintf( stderr, "%s: Swapped texobj %p has non-NULL memblock %p\n", - __FUNCTION__, (void *)t, (void *)t->memBlock ); - return GL_FALSE; - } - i++; - } - -#if 0 - fprintf( stderr, "%s: swapped texture count = %u\n", __FUNCTION__, i ); -#endif - - return GL_TRUE; -} - - - - -/****************************************************************************/ -/** - * Compute which mipmap levels that really need to be sent to the hardware. - * This depends on the base image size, GL_TEXTURE_MIN_LOD, - * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL. - */ - -void -driCalculateTextureFirstLastLevel( driTextureObject * t ) -{ - struct gl_texture_object * const tObj = t->tObj; - const struct gl_texture_image * const baseImage = - tObj->Image[0][tObj->BaseLevel]; - - /* These must be signed values. MinLod and MaxLod can be negative numbers, - * and having firstLevel and lastLevel as signed prevents the need for - * extra sign checks. - */ - int firstLevel; - int lastLevel; - - /* Yes, this looks overly complicated, but it's all needed. - */ - - switch (tObj->Target) { - case GL_TEXTURE_1D: - case GL_TEXTURE_2D: - case GL_TEXTURE_3D: - case GL_TEXTURE_CUBE_MAP: - if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) { - /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL. - */ - - firstLevel = lastLevel = tObj->BaseLevel; - } - else { - firstLevel = tObj->BaseLevel + (GLint)(tObj->MinLod + 0.5); - firstLevel = MAX2(firstLevel, tObj->BaseLevel); - firstLevel = MIN2(firstLevel, tObj->BaseLevel + baseImage->MaxLog2); - lastLevel = tObj->BaseLevel + (GLint)(tObj->MaxLod + 0.5); - lastLevel = MAX2(lastLevel, t->tObj->BaseLevel); - lastLevel = MIN2(lastLevel, t->tObj->BaseLevel + baseImage->MaxLog2); - lastLevel = MIN2(lastLevel, t->tObj->MaxLevel); - lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */ - } - break; - case GL_TEXTURE_RECTANGLE_NV: - case GL_TEXTURE_4D_SGIS: - firstLevel = lastLevel = 0; - break; - default: - return; - } - - /* save these values */ - t->firstLevel = firstLevel; - t->lastLevel = lastLevel; -} - - - - -/** - * \name DRI texture formats. These vars are initialized to either the - * big- or little-endian Mesa formats. - */ -/*@{*/ -gl_format _dri_texformat_rgba8888 = MESA_FORMAT_NONE; -gl_format _dri_texformat_argb8888 = MESA_FORMAT_NONE; -gl_format _dri_texformat_rgb565 = MESA_FORMAT_NONE; -gl_format _dri_texformat_argb4444 = MESA_FORMAT_NONE; -gl_format _dri_texformat_argb1555 = MESA_FORMAT_NONE; -gl_format _dri_texformat_al88 = MESA_FORMAT_NONE; -gl_format _dri_texformat_a8 = MESA_FORMAT_A8; -gl_format _dri_texformat_ci8 = MESA_FORMAT_CI8; -gl_format _dri_texformat_i8 = MESA_FORMAT_I8; -gl_format _dri_texformat_l8 = MESA_FORMAT_L8; -/*@}*/ - - -/** - * Initialize _dri_texformat_* vars according to whether we're on - * a big or little endian system. - */ -void -driInitTextureFormats(void) -{ - if (_mesa_little_endian()) { - _dri_texformat_rgba8888 = MESA_FORMAT_RGBA8888; - _dri_texformat_argb8888 = MESA_FORMAT_ARGB8888; - _dri_texformat_rgb565 = MESA_FORMAT_RGB565; - _dri_texformat_argb4444 = MESA_FORMAT_ARGB4444; - _dri_texformat_argb1555 = MESA_FORMAT_ARGB1555; - _dri_texformat_al88 = MESA_FORMAT_AL88; - } - else { - _dri_texformat_rgba8888 = MESA_FORMAT_RGBA8888_REV; - _dri_texformat_argb8888 = MESA_FORMAT_ARGB8888_REV; - _dri_texformat_rgb565 = MESA_FORMAT_RGB565_REV; - _dri_texformat_argb4444 = MESA_FORMAT_ARGB4444_REV; - _dri_texformat_argb1555 = MESA_FORMAT_ARGB1555_REV; - _dri_texformat_al88 = MESA_FORMAT_AL88_REV; - } -} +/*
+ * Copyright 2000-2001 VA Linux Systems, Inc.
+ * (C) Copyright IBM Corporation 2002, 2003
+ * 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
+ * VA LINUX SYSTEM, IBM 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:
+ * Ian Romanick <idr@us.ibm.com>
+ * Keith Whitwell <keithw@tungstengraphics.com>
+ * Kevin E. Martin <kem@users.sourceforge.net>
+ * Gareth Hughes <gareth@nvidia.com>
+ */
+
+/** \file texmem.c
+ * Implements all of the device-independent texture memory management.
+ *
+ * Currently, only a simple LRU texture memory management policy is
+ * implemented. In the (hopefully very near) future, better policies will be
+ * implemented. The idea is that the DRI should be able to run in one of two
+ * modes. In the default mode the DRI will dynamically attempt to discover
+ * the best texture management policy for the running application. In the
+ * other mode, the user (via some sort of as yet TBD mechanism) will select
+ * a texture management policy that is known to work well with the
+ * application.
+ */
+
+#include "main/imports.h"
+#include "main/macros.h"
+#include "main/simple_list.h"
+#include "texmem.h"
+
+
+static unsigned dummy_swap_counter;
+
+
+/**
+ * Calculate \f$\log_2\f$ of a value. This is a particularly poor
+ * implementation of this function. However, since system performance is in
+ * no way dependent on this function, the slowness of the implementation is
+ * irrelevent.
+ *
+ * \param n Value whose \f$\log_2\f$ is to be calculated
+ */
+
+static GLuint
+driLog2( GLuint n )
+{
+ GLuint log2;
+
+ for ( log2 = 1 ; n > 1 ; log2++ ) {
+ n >>= 1;
+ }
+
+ return log2;
+}
+
+
+
+
+/**
+ * Determine if a texture is resident in textureable memory. Depending on
+ * the driver, this may or may not be on-card memory. It could be AGP memory
+ * or anyother type of memory from which the hardware can directly read
+ * texels.
+ *
+ * This function is intended to be used as the \c IsTextureResident function
+ * in the device's \c dd_function_table.
+ *
+ * \param ctx GL context pointer (currently unused)
+ * \param texObj Texture object to be tested
+ */
+
+GLboolean
+driIsTextureResident( struct gl_context * ctx,
+ struct gl_texture_object * texObj )
+{
+ driTextureObject * t;
+
+
+ t = (driTextureObject *) texObj->DriverData;
+ return( (t != NULL) && (t->memBlock != NULL) );
+}
+
+
+
+
+/**
+ * (Re)initialize the global circular LRU list. The last element
+ * in the array (\a heap->nrRegions) is the sentinal. Keeping it
+ * at the end of the array allows the other elements of the array
+ * to be addressed rationally when looking up objects at a particular
+ * location in texture memory.
+ *
+ * \param heap Texture heap to be reset
+ */
+
+static void resetGlobalLRU( driTexHeap * heap )
+{
+ drmTextureRegionPtr list = heap->global_regions;
+ unsigned sz = 1U << heap->logGranularity;
+ unsigned i;
+
+ for (i = 0 ; (i+1) * sz <= heap->size ; i++) {
+ list[i].prev = i-1;
+ list[i].next = i+1;
+ list[i].age = 0;
+ }
+
+ i--;
+ list[0].prev = heap->nrRegions;
+ list[i].prev = i-1;
+ list[i].next = heap->nrRegions;
+ list[heap->nrRegions].prev = i;
+ list[heap->nrRegions].next = 0;
+ heap->global_age[0] = 0;
+}
+
+/**
+ * Print out debugging information about the local texture LRU.
+ *
+ * \param heap Texture heap to be printed
+ * \param callername Name of calling function
+ */
+static void printLocalLRU( driTexHeap * heap, const char *callername )
+{
+ driTextureObject *t;
+ unsigned sz = 1U << heap->logGranularity;
+
+ fprintf( stderr, "%s in %s:\nLocal LRU, heap %d:\n",
+ __FUNCTION__, callername, heap->heapId );
+
+ foreach ( t, &heap->texture_objects ) {
+ if (!t->memBlock)
+ continue;
+ if (!t->tObj) {
+ fprintf( stderr, "Placeholder (%p) %d at 0x%x sz 0x%x\n",
+ (void *)t,
+ t->memBlock->ofs / sz,
+ t->memBlock->ofs,
+ t->memBlock->size );
+ } else {
+ fprintf( stderr, "Texture (%p) at 0x%x sz 0x%x\n",
+ (void *)t,
+ t->memBlock->ofs,
+ t->memBlock->size );
+ }
+ }
+ foreach ( t, heap->swapped_objects ) {
+ if (!t->tObj) {
+ fprintf( stderr, "Swapped Placeholder (%p)\n", (void *)t );
+ } else {
+ fprintf( stderr, "Swapped Texture (%p)\n", (void *)t );
+ }
+ }
+
+ fprintf( stderr, "\n" );
+}
+
+/**
+ * Print out debugging information about the global texture LRU.
+ *
+ * \param heap Texture heap to be printed
+ * \param callername Name of calling function
+ */
+static void printGlobalLRU( driTexHeap * heap, const char *callername )
+{
+ drmTextureRegionPtr list = heap->global_regions;
+ unsigned int i, j;
+
+ fprintf( stderr, "%s in %s:\nGlobal LRU, heap %d list %p:\n",
+ __FUNCTION__, callername, heap->heapId, (void *)list );
+
+ for ( i = 0, j = heap->nrRegions ; i < heap->nrRegions ; i++ ) {
+ fprintf( stderr, "list[%d] age %d next %d prev %d in_use %d\n",
+ j, list[j].age, list[j].next, list[j].prev, list[j].in_use );
+ j = list[j].next;
+ if ( j == heap->nrRegions ) break;
+ }
+
+ if ( j != heap->nrRegions ) {
+ fprintf( stderr, "Loop detected in global LRU\n" );
+ for ( i = 0 ; i < heap->nrRegions ; i++ ) {
+ fprintf( stderr, "list[%d] age %d next %d prev %d in_use %d\n",
+ i, list[i].age, list[i].next, list[i].prev, list[i].in_use );
+ }
+ }
+
+ fprintf( stderr, "\n" );
+}
+
+
+/**
+ * Called by the client whenever it touches a local texture.
+ *
+ * \param t Texture object that the client has accessed
+ */
+
+void driUpdateTextureLRU( driTextureObject * t )
+{
+ driTexHeap * heap;
+ drmTextureRegionPtr list;
+ unsigned shift;
+ unsigned start;
+ unsigned end;
+ unsigned i;
+
+
+ heap = t->heap;
+ if ( heap != NULL ) {
+ shift = heap->logGranularity;
+ start = t->memBlock->ofs >> shift;
+ end = (t->memBlock->ofs + t->memBlock->size - 1) >> shift;
+
+
+ heap->local_age = ++heap->global_age[0];
+ list = heap->global_regions;
+
+
+ /* Update the context's local LRU
+ */
+
+ move_to_head( & heap->texture_objects, t );
+
+
+ for (i = start ; i <= end ; i++) {
+ list[i].age = heap->local_age;
+
+ /* remove_from_list(i)
+ */
+ list[(unsigned)list[i].next].prev = list[i].prev;
+ list[(unsigned)list[i].prev].next = list[i].next;
+
+ /* insert_at_head(list, i)
+ */
+ list[i].prev = heap->nrRegions;
+ list[i].next = list[heap->nrRegions].next;
+ list[(unsigned)list[heap->nrRegions].next].prev = i;
+ list[heap->nrRegions].next = i;
+ }
+
+ if ( 0 ) {
+ printGlobalLRU( heap, __FUNCTION__ );
+ printLocalLRU( heap, __FUNCTION__ );
+ }
+ }
+}
+
+
+
+
+/**
+ * Keep track of swapped out texture objects.
+ *
+ * \param t Texture object to be "swapped" out of its texture heap
+ */
+
+void driSwapOutTextureObject( driTextureObject * t )
+{
+ unsigned face;
+
+
+ if ( t->memBlock != NULL ) {
+ assert( t->heap != NULL );
+ mmFreeMem( t->memBlock );
+ t->memBlock = NULL;
+
+ if (t->timestamp > t->heap->timestamp)
+ t->heap->timestamp = t->timestamp;
+
+ t->heap->texture_swaps[0]++;
+ move_to_tail( t->heap->swapped_objects, t );
+ t->heap = NULL;
+ }
+ else {
+ assert( t->heap == NULL );
+ }
+
+
+ for ( face = 0 ; face < 6 ; face++ ) {
+ t->dirty_images[face] = ~0;
+ }
+}
+
+
+
+
+/**
+ * Destroy hardware state associated with texture \a t. Calls the
+ * \a destroy_texture_object method associated with the heap from which
+ * \a t was allocated.
+ *
+ * \param t Texture object to be destroyed
+ */
+
+void driDestroyTextureObject( driTextureObject * t )
+{
+ driTexHeap * heap;
+
+
+ if ( 0 ) {
+ fprintf( stderr, "[%s:%d] freeing %p (tObj = %p, DriverData = %p)\n",
+ __FILE__, __LINE__,
+ (void *)t,
+ (void *)((t != NULL) ? t->tObj : NULL),
+ (void *)((t != NULL && t->tObj != NULL) ? t->tObj->DriverData : NULL ));
+ }
+
+ if ( t != NULL ) {
+ if ( t->memBlock ) {
+ heap = t->heap;
+ assert( heap != NULL );
+
+ heap->texture_swaps[0]++;
+
+ mmFreeMem( t->memBlock );
+ t->memBlock = NULL;
+
+ if (t->timestamp > t->heap->timestamp)
+ t->heap->timestamp = t->timestamp;
+
+ heap->destroy_texture_object( heap->driverContext, t );
+ t->heap = NULL;
+ }
+
+ if ( t->tObj != NULL ) {
+ assert( t->tObj->DriverData == t );
+ t->tObj->DriverData = NULL;
+ }
+
+ remove_from_list( t );
+ FREE( t );
+ }
+
+ if ( 0 ) {
+ fprintf( stderr, "[%s:%d] done freeing %p\n", __FILE__, __LINE__, (void *)t );
+ }
+}
+
+
+
+
+/**
+ * Update the local heap's representation of texture memory based on
+ * data in the SAREA. This is done each time it is detected that some other
+ * direct rendering client has held the lock. This pertains to both our local
+ * textures and the textures belonging to other clients. Keep track of other
+ * client's textures by pushing a placeholder texture onto the LRU list --
+ * these are denoted by \a tObj being \a NULL.
+ *
+ * \param heap Heap whose state is to be updated
+ * \param offset Byte offset in the heap that has been stolen
+ * \param size Size, in bytes, of the stolen block
+ * \param in_use Non-zero if the block is pinned/reserved by the kernel
+ */
+
+static void driTexturesGone( driTexHeap * heap, int offset, int size,
+ int in_use )
+{
+ driTextureObject * t;
+ driTextureObject * tmp;
+
+
+ foreach_s ( t, tmp, & heap->texture_objects ) {
+ if ( (t->memBlock->ofs < (offset + size))
+ && ((t->memBlock->ofs + t->memBlock->size) > offset) ) {
+ /* It overlaps - kick it out. If the texture object is just a
+ * place holder, then destroy it all together. Otherwise, mark
+ * it as being swapped out.
+ */
+
+ if ( t->tObj != NULL ) {
+ driSwapOutTextureObject( t );
+ }
+ else {
+ driDestroyTextureObject( t );
+ }
+ }
+ }
+
+
+ {
+ t = (driTextureObject *) CALLOC( heap->texture_object_size );
+ if ( t == NULL ) return;
+
+ t->memBlock = mmAllocMem( heap->memory_heap, size, 0, offset );
+ if ( t->memBlock == NULL ) {
+ fprintf( stderr, "Couldn't alloc placeholder: heap %u sz %x ofs %x\n", heap->heapId,
+ (int)size, (int)offset );
+ mmDumpMemInfo( heap->memory_heap );
+ FREE(t);
+ return;
+ }
+ t->heap = heap;
+ if (in_use)
+ t->reserved = 1;
+ insert_at_head( & heap->texture_objects, t );
+ }
+}
+
+
+
+
+/**
+ * Called by the client on lock contention to determine whether textures have
+ * been stolen. If another client has modified a region in which we have
+ * textures, then we need to figure out which of our textures have been
+ * removed and update our global LRU.
+ *
+ * \param heap Texture heap to be updated
+ */
+
+void driAgeTextures( driTexHeap * heap )
+{
+ drmTextureRegionPtr list = heap->global_regions;
+ unsigned sz = 1U << (heap->logGranularity);
+ unsigned i, nr = 0;
+
+
+ /* Have to go right round from the back to ensure stuff ends up
+ * LRU in the local list... Fix with a cursor pointer.
+ */
+
+ for (i = list[heap->nrRegions].prev ;
+ i != heap->nrRegions && nr < heap->nrRegions ;
+ i = list[i].prev, nr++) {
+ /* If switching texturing schemes, then the SAREA might not have been
+ * properly cleared, so we need to reset the global texture LRU.
+ */
+
+ if ( (i * sz) > heap->size ) {
+ nr = heap->nrRegions;
+ break;
+ }
+
+ if (list[i].age > heap->local_age)
+ driTexturesGone( heap, i * sz, sz, list[i].in_use);
+ }
+
+ /* Loop or uninitialized heap detected. Reset.
+ */
+
+ if (nr == heap->nrRegions) {
+ driTexturesGone( heap, 0, heap->size, 0);
+ resetGlobalLRU( heap );
+ }
+
+ if ( 0 ) {
+ printGlobalLRU( heap, __FUNCTION__ );
+ printLocalLRU( heap, __FUNCTION__ );
+ }
+
+ heap->local_age = heap->global_age[0];
+}
+
+
+
+
+#define INDEX_ARRAY_SIZE 6 /* I'm not aware of driver with more than 2 heaps */
+
+/**
+ * Allocate memory from a texture heap to hold a texture object. This
+ * routine will attempt to allocate memory for the texture from the heaps
+ * specified by \c heap_array in order. That is, first it will try to
+ * allocate from \c heap_array[0], then \c heap_array[1], and so on.
+ *
+ * \param heap_array Array of pointers to texture heaps to use
+ * \param nr_heaps Number of heap pointer in \a heap_array
+ * \param t Texture object for which space is needed
+ * \return The ID of the heap from which memory was allocated, or -1 if
+ * memory could not be allocated.
+ *
+ * \bug The replacement policy implemented by this function is horrible.
+ */
+
+
+int
+driAllocateTexture( driTexHeap * const * heap_array, unsigned nr_heaps,
+ driTextureObject * t )
+{
+ driTexHeap * heap;
+ driTextureObject * temp;
+ driTextureObject * cursor;
+ unsigned id;
+
+
+ /* In case it already has texture space, initialize heap. This also
+ * prevents GCC from issuing a warning that heap might be used
+ * uninitialized.
+ */
+
+ heap = t->heap;
+
+
+ /* Run through each of the existing heaps and try to allocate a buffer
+ * to hold the texture.
+ */
+
+ for ( id = 0 ; (t->memBlock == NULL) && (id < nr_heaps) ; id++ ) {
+ heap = heap_array[ id ];
+ if ( heap != NULL ) {
+ t->memBlock = mmAllocMem( heap->memory_heap, t->totalSize,
+ heap->alignmentShift, 0 );
+ }
+ }
+
+
+ /* Kick textures out until the requested texture fits.
+ */
+
+ if ( t->memBlock == NULL ) {
+ unsigned index[INDEX_ARRAY_SIZE];
+ unsigned nrGoodHeaps = 0;
+
+ /* Trying to avoid dynamic memory allocation. If you have more
+ * heaps, increase INDEX_ARRAY_SIZE. I'm not aware of any
+ * drivers with more than 2 tex heaps. */
+ assert( nr_heaps < INDEX_ARRAY_SIZE );
+
+ /* Sort large enough heaps by duty. Insertion sort should be
+ * fast enough for such a short array. */
+ for ( id = 0 ; id < nr_heaps ; id++ ) {
+ heap = heap_array[ id ];
+
+ if ( heap != NULL && t->totalSize <= heap->size ) {
+ unsigned j;
+
+ for ( j = 0 ; j < nrGoodHeaps; j++ ) {
+ if ( heap->duty > heap_array[ index[ j ] ]->duty )
+ break;
+ }
+
+ if ( j < nrGoodHeaps ) {
+ memmove( &index[ j+1 ], &index[ j ],
+ sizeof(index[ 0 ]) * (nrGoodHeaps - j) );
+ }
+
+ index[ j ] = id;
+
+ nrGoodHeaps++;
+ }
+ }
+
+ for ( id = 0 ; (t->memBlock == NULL) && (id < nrGoodHeaps) ; id++ ) {
+ heap = heap_array[ index[ id ] ];
+
+ for ( cursor = heap->texture_objects.prev, temp = cursor->prev;
+ cursor != &heap->texture_objects ;
+ cursor = temp, temp = cursor->prev ) {
+
+ /* The the LRU element. If the texture is bound to one of
+ * the texture units, then we cannot kick it out.
+ */
+ if ( cursor->bound || cursor->reserved ) {
+ continue;
+ }
+
+ if ( cursor->memBlock )
+ heap->duty -= cursor->memBlock->size;
+
+ /* If this is a placeholder, there's no need to keep it */
+ if (cursor->tObj)
+ driSwapOutTextureObject( cursor );
+ else
+ driDestroyTextureObject( cursor );
+
+ t->memBlock = mmAllocMem( heap->memory_heap, t->totalSize,
+ heap->alignmentShift, 0 );
+
+ if (t->memBlock)
+ break;
+ }
+ }
+
+ /* Rebalance duties. If a heap kicked more data than its duty,
+ * then all other heaps get that amount multiplied with their
+ * relative weight added to their duty. The negative duty is
+ * reset to 0. In the end all heaps have a duty >= 0.
+ *
+ * CAUTION: we must not change the heap pointer here, because it
+ * is used below to update the texture object.
+ */
+ for ( id = 0 ; id < nr_heaps ; id++ )
+ if ( heap_array[ id ] != NULL && heap_array[ id ]->duty < 0) {
+ int duty = -heap_array[ id ]->duty;
+ double weight = heap_array[ id ]->weight;
+ unsigned j;
+
+ for ( j = 0 ; j < nr_heaps ; j++ )
+ if ( j != id && heap_array[ j ] != NULL ) {
+ heap_array[ j ]->duty += (double) duty *
+ heap_array[ j ]->weight / weight;
+ }
+
+ heap_array[ id ]->duty = 0;
+ }
+ }
+
+
+ if ( t->memBlock != NULL ) {
+ /* id and heap->heapId may or may not be the same value here.
+ */
+
+ assert( heap != NULL );
+ assert( (t->heap == NULL) || (t->heap == heap) );
+
+ t->heap = heap;
+ return heap->heapId;
+ }
+ else {
+ assert( t->heap == NULL );
+
+ fprintf( stderr, "[%s:%d] unable to allocate texture\n",
+ __FUNCTION__, __LINE__ );
+ return -1;
+ }
+}
+
+
+
+
+
+
+/**
+ * Set the location where the texture-swap counter is stored.
+ */
+
+void
+driSetTextureSwapCounterLocation( driTexHeap * heap, unsigned * counter )
+{
+ heap->texture_swaps = (counter == NULL) ? & dummy_swap_counter : counter;
+}
+
+
+
+
+/**
+ * Create a new heap for texture data.
+ *
+ * \param heap_id Device-dependent heap identifier. This value
+ * will returned by driAllocateTexture when memory
+ * is allocated from this heap.
+ * \param context Device-dependent driver context. This is
+ * supplied as the first parameter to the
+ * \c destroy_tex_obj function.
+ * \param size Size, in bytes, of the texture region
+ * \param alignmentShift Alignment requirement for textures. If textures
+ * must be allocated on a 4096 byte boundry, this
+ * would be 12.
+ * \param nr_regions Number of regions into which this texture space
+ * should be partitioned
+ * \param global_regions Array of \c drmTextureRegion structures in the SAREA
+ * \param global_age Pointer to the global texture age in the SAREA
+ * \param swapped_objects Pointer to the list of texture objects that are
+ * not in texture memory (i.e., have been swapped
+ * out).
+ * \param texture_object_size Size, in bytes, of a device-dependent texture
+ * object
+ * \param destroy_tex_obj Function used to destroy a device-dependent
+ * texture object
+ *
+ * \sa driDestroyTextureHeap
+ */
+
+driTexHeap *
+driCreateTextureHeap( unsigned heap_id, void * context, unsigned size,
+ unsigned alignmentShift, unsigned nr_regions,
+ drmTextureRegionPtr global_regions, unsigned * global_age,
+ driTextureObject * swapped_objects,
+ unsigned texture_object_size,
+ destroy_texture_object_t * destroy_tex_obj
+ )
+{
+ driTexHeap * heap;
+ unsigned l;
+
+
+ if ( 0 )
+ fprintf( stderr, "%s( %u, %p, %u, %u, %u )\n",
+ __FUNCTION__,
+ heap_id, (void *)context, size, alignmentShift, nr_regions );
+
+ heap = (driTexHeap *) CALLOC( sizeof( driTexHeap ) );
+ if ( heap != NULL ) {
+ l = driLog2( (size - 1) / nr_regions );
+ if ( l < alignmentShift )
+ {
+ l = alignmentShift;
+ }
+
+ heap->logGranularity = l;
+ heap->size = size & ~((1L << l) - 1);
+
+ heap->memory_heap = mmInit( 0, heap->size );
+ if ( heap->memory_heap != NULL ) {
+ heap->heapId = heap_id;
+ heap->driverContext = context;
+
+ heap->alignmentShift = alignmentShift;
+ heap->nrRegions = nr_regions;
+ heap->global_regions = global_regions;
+ heap->global_age = global_age;
+ heap->swapped_objects = swapped_objects;
+ heap->texture_object_size = texture_object_size;
+ heap->destroy_texture_object = destroy_tex_obj;
+
+ /* Force global heap init */
+ if (heap->global_age[0] == 0)
+ heap->local_age = ~0;
+ else
+ heap->local_age = 0;
+
+ make_empty_list( & heap->texture_objects );
+ driSetTextureSwapCounterLocation( heap, NULL );
+
+ heap->weight = heap->size;
+ heap->duty = 0;
+ }
+ else {
+ FREE( heap );
+ heap = NULL;
+ }
+ }
+
+
+ if ( 0 )
+ fprintf( stderr, "%s returning %p\n", __FUNCTION__, (void *)heap );
+
+ return heap;
+}
+
+
+
+
+/** Destroys a texture heap
+ *
+ * \param heap Texture heap to be destroyed
+ */
+
+void
+driDestroyTextureHeap( driTexHeap * heap )
+{
+ driTextureObject * t;
+ driTextureObject * temp;
+
+
+ if ( heap != NULL ) {
+ foreach_s( t, temp, & heap->texture_objects ) {
+ driDestroyTextureObject( t );
+ }
+ foreach_s( t, temp, heap->swapped_objects ) {
+ driDestroyTextureObject( t );
+ }
+
+ mmDestroy( heap->memory_heap );
+ FREE( heap );
+ }
+}
+
+
+
+
+/****************************************************************************/
+/**
+ * Determine how many texels (including all mipmap levels) would be required
+ * for a texture map of size \f$2^^\c base_size_log2\f$ would require.
+ *
+ * \param base_size_log2 \f$log_2\f$ of the size of a side of the texture
+ * \param dimensions Number of dimensions of the texture. Either 2 or 3.
+ * \param faces Number of faces of the texture. Either 1 or 6 (for cube maps).
+ * \return Number of texels
+ */
+
+static unsigned
+texels_this_map_size( int base_size_log2, unsigned dimensions, unsigned faces )
+{
+ unsigned texels;
+
+
+ assert( (faces == 1) || (faces == 6) );
+ assert( (dimensions == 2) || (dimensions == 3) );
+
+ texels = 0;
+ if ( base_size_log2 >= 0 ) {
+ texels = (1U << (dimensions * base_size_log2));
+
+ /* See http://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg03636.html
+ * for the complete explaination of why this formulation is used.
+ * Basically, the smaller mipmap levels sum to 0.333 the size of the
+ * level 0 map. The total size is therefore the size of the map
+ * multipled by 1.333. The +2 is there to round up.
+ */
+
+ texels = (texels * 4 * faces + 2) / 3;
+ }
+
+ return texels;
+}
+
+
+
+
+struct maps_per_heap {
+ unsigned c[32];
+};
+
+static void
+fill_in_maximums( driTexHeap * const * heaps, unsigned nr_heaps,
+ unsigned max_bytes_per_texel, unsigned max_size,
+ unsigned mipmaps_at_once, unsigned dimensions,
+ unsigned faces, struct maps_per_heap * max_textures )
+{
+ unsigned heap;
+ unsigned log2_size;
+ unsigned mask;
+
+
+ /* Determine how many textures of each size can be stored in each
+ * texture heap.
+ */
+
+ for ( heap = 0 ; heap < nr_heaps ; heap++ ) {
+ if ( heaps[ heap ] == NULL ) {
+ (void) memset( max_textures[ heap ].c, 0,
+ sizeof( max_textures[ heap ].c ) );
+ continue;
+ }
+
+ mask = (1U << heaps[ heap ]->logGranularity) - 1;
+
+ if ( 0 ) {
+ fprintf( stderr, "[%s:%d] heap[%u] = %u bytes, mask = 0x%08x\n",
+ __FILE__, __LINE__,
+ heap, heaps[ heap ]->size, mask );
+ }
+
+ for ( log2_size = max_size ; log2_size > 0 ; log2_size-- ) {
+ unsigned total;
+
+
+ /* Determine the total number of bytes required by a texture of
+ * size log2_size.
+ */
+
+ total = texels_this_map_size( log2_size, dimensions, faces )
+ - texels_this_map_size( log2_size - mipmaps_at_once,
+ dimensions, faces );
+ total *= max_bytes_per_texel;
+ total = (total + mask) & ~mask;
+
+ /* The number of textures of a given size that will fit in a heap
+ * is equal to the size of the heap divided by the size of the
+ * texture.
+ */
+
+ max_textures[ heap ].c[ log2_size ] = heaps[ heap ]->size / total;
+
+ if ( 0 ) {
+ fprintf( stderr, "[%s:%d] max_textures[%u].c[%02u] "
+ "= 0x%08x / 0x%08x "
+ "= %u (%u)\n",
+ __FILE__, __LINE__,
+ heap, log2_size,
+ heaps[ heap ]->size, total,
+ heaps[ heap ]->size / total,
+ max_textures[ heap ].c[ log2_size ] );
+ }
+ }
+ }
+}
+
+
+static unsigned
+get_max_size( unsigned nr_heaps,
+ unsigned texture_units,
+ unsigned max_size,
+ int all_textures_one_heap,
+ struct maps_per_heap * max_textures )
+{
+ unsigned heap;
+ unsigned log2_size;
+
+
+ /* Determine the largest texture size such that a texture of that size
+ * can be bound to each texture unit at the same time. Some hardware
+ * may require that all textures be in the same texture heap for
+ * multitexturing.
+ */
+
+ for ( log2_size = max_size ; log2_size > 0 ; log2_size-- ) {
+ unsigned total = 0;
+
+ for ( heap = 0 ; heap < nr_heaps ; heap++ )
+ {
+ total += max_textures[ heap ].c[ log2_size ];
+
+ if ( 0 ) {
+ fprintf( stderr, "[%s:%d] max_textures[%u].c[%02u] = %u, "
+ "total = %u\n", __FILE__, __LINE__, heap, log2_size,
+ max_textures[ heap ].c[ log2_size ], total );
+ }
+
+ if ( (max_textures[ heap ].c[ log2_size ] >= texture_units)
+ || (!all_textures_one_heap && (total >= texture_units)) ) {
+ /* The number of mipmap levels is the log-base-2 of the
+ * maximum texture size plus 1. If the maximum texture size
+ * is 1x1, the log-base-2 is 0 and 1 mipmap level (the base
+ * level) is available.
+ */
+
+ return log2_size + 1;
+ }
+ }
+ }
+
+ /* This should NEVER happen. It should always be possible to have at
+ * *least* a 1x1 texture in memory!
+ */
+ assert( log2_size != 0 );
+ return 0;
+}
+
+#define SET_MAX(f,v) \
+ do { if ( max_sizes[v] != 0 ) { limits-> f = max_sizes[v]; } } while( 0 )
+
+#define SET_MAX_RECT(f,v) \
+ do { if ( max_sizes[v] != 0 ) { limits-> f = 1 << (max_sizes[v] - 1); } } while( 0 )
+
+
+/**
+ * Given the amount of texture memory, the number of texture units, and the
+ * maximum size of a texel, calculate the maximum texture size the driver can
+ * advertise.
+ *
+ * \param heaps Texture heaps for this card
+ * \param nr_heap Number of texture heaps
+ * \param limits OpenGL contants. MaxTextureUnits must be set.
+ * \param max_bytes_per_texel Maximum size of a single texel, in bytes
+ * \param max_2D_size \f$\log_2\f$ of the maximum 2D texture size (i.e.,
+ * 1024x1024 textures, this would be 10)
+ * \param max_3D_size \f$\log_2\f$ of the maximum 3D texture size (i.e.,
+ * 1024x1024x1024 textures, this would be 10)
+ * \param max_cube_size \f$\log_2\f$ of the maximum cube texture size (i.e.,
+ * 1024x1024 textures, this would be 10)
+ * \param max_rect_size \f$\log_2\f$ of the maximum texture rectangle size
+ * (i.e., 1024x1024 textures, this would be 10). This is a power-of-2
+ * even though texture rectangles need not be a power-of-2.
+ * \param mipmaps_at_once Total number of mipmaps that can be used
+ * at one time. For most hardware this will be \f$\c max_size + 1\f$.
+ * For hardware that does not support mipmapping, this will be 1.
+ * \param all_textures_one_heap True if the hardware requires that all
+ * textures be in a single texture heap for multitexturing.
+ * \param allow_larger_textures 0 conservative, 1 calculate limits
+ * so at least one worst-case texture can fit, 2 just use hw limits.
+ */
+
+void
+driCalculateMaxTextureLevels( driTexHeap * const * heaps,
+ unsigned nr_heaps,
+ struct gl_constants * limits,
+ unsigned max_bytes_per_texel,
+ unsigned max_2D_size,
+ unsigned max_3D_size,
+ unsigned max_cube_size,
+ unsigned max_rect_size,
+ unsigned mipmaps_at_once,
+ int all_textures_one_heap,
+ int allow_larger_textures )
+{
+ struct maps_per_heap max_textures[8];
+ unsigned i;
+ const unsigned dimensions[4] = { 2, 3, 2, 2 };
+ const unsigned faces[4] = { 1, 1, 6, 1 };
+ unsigned max_sizes[4];
+ unsigned mipmaps[4];
+
+
+ max_sizes[0] = max_2D_size;
+ max_sizes[1] = max_3D_size;
+ max_sizes[2] = max_cube_size;
+ max_sizes[3] = max_rect_size;
+
+ mipmaps[0] = mipmaps_at_once;
+ mipmaps[1] = mipmaps_at_once;
+ mipmaps[2] = mipmaps_at_once;
+ mipmaps[3] = 1;
+
+
+ /* Calculate the maximum number of texture levels in two passes. The
+ * first pass determines how many textures of each power-of-two size
+ * (including all mipmap levels for that size) can fit in each texture
+ * heap. The second pass finds the largest texture size that allows
+ * a texture of that size to be bound to every texture unit.
+ */
+
+ for ( i = 0 ; i < 4 ; i++ ) {
+ if ( (allow_larger_textures != 2) && (max_sizes[ i ] != 0) ) {
+ fill_in_maximums( heaps, nr_heaps, max_bytes_per_texel,
+ max_sizes[ i ], mipmaps[ i ],
+ dimensions[ i ], faces[ i ],
+ max_textures );
+
+ max_sizes[ i ] = get_max_size( nr_heaps,
+ allow_larger_textures == 1 ?
+ 1 : limits->MaxTextureUnits,
+ max_sizes[ i ],
+ all_textures_one_heap,
+ max_textures );
+ }
+ else if (max_sizes[ i ] != 0) {
+ max_sizes[ i ] += 1;
+ }
+ }
+
+ SET_MAX( MaxTextureLevels, 0 );
+ SET_MAX( Max3DTextureLevels, 1 );
+ SET_MAX( MaxCubeTextureLevels, 2 );
+ SET_MAX_RECT( MaxTextureRectSize, 3 );
+}
+
+
+
+
+/**
+ * Perform initial binding of default textures objects on a per unit, per
+ * texture target basis.
+ *
+ * \param ctx Current OpenGL context
+ * \param swapped List of swapped-out textures
+ * \param targets Bit-mask of value texture targets
+ */
+
+void driInitTextureObjects( struct gl_context *ctx, driTextureObject * swapped,
+ GLuint targets )
+{
+ struct gl_texture_object *texObj;
+ GLuint tmp = ctx->Texture.CurrentUnit;
+ unsigned i;
+
+
+ for ( i = 0 ; i < ctx->Const.MaxTextureUnits ; i++ ) {
+ ctx->Texture.CurrentUnit = i;
+
+ if ( (targets & DRI_TEXMGR_DO_TEXTURE_1D) != 0 ) {
+ texObj = ctx->Texture.Unit[i].CurrentTex[TEXTURE_1D_INDEX];
+ ctx->Driver.BindTexture( ctx, GL_TEXTURE_1D, texObj );
+ move_to_tail( swapped, (driTextureObject *) texObj->DriverData );
+ }
+
+ if ( (targets & DRI_TEXMGR_DO_TEXTURE_2D) != 0 ) {
+ texObj = ctx->Texture.Unit[i].CurrentTex[TEXTURE_2D_INDEX];
+ ctx->Driver.BindTexture( ctx, GL_TEXTURE_2D, texObj );
+ move_to_tail( swapped, (driTextureObject *) texObj->DriverData );
+ }
+
+ if ( (targets & DRI_TEXMGR_DO_TEXTURE_3D) != 0 ) {
+ texObj = ctx->Texture.Unit[i].CurrentTex[TEXTURE_3D_INDEX];
+ ctx->Driver.BindTexture( ctx, GL_TEXTURE_3D, texObj );
+ move_to_tail( swapped, (driTextureObject *) texObj->DriverData );
+ }
+
+ if ( (targets & DRI_TEXMGR_DO_TEXTURE_CUBE) != 0 ) {
+ texObj = ctx->Texture.Unit[i].CurrentTex[TEXTURE_CUBE_INDEX];
+ ctx->Driver.BindTexture( ctx, GL_TEXTURE_CUBE_MAP_ARB, texObj );
+ move_to_tail( swapped, (driTextureObject *) texObj->DriverData );
+ }
+
+ if ( (targets & DRI_TEXMGR_DO_TEXTURE_RECT) != 0 ) {
+ texObj = ctx->Texture.Unit[i].CurrentTex[TEXTURE_RECT_INDEX];
+ ctx->Driver.BindTexture( ctx, GL_TEXTURE_RECTANGLE_NV, texObj );
+ move_to_tail( swapped, (driTextureObject *) texObj->DriverData );
+ }
+ }
+
+ ctx->Texture.CurrentUnit = tmp;
+}
+
+
+
+
+/**
+ * Verify that the specified texture is in the specificed heap.
+ *
+ * \param tex Texture to be tested.
+ * \param heap Texture memory heap to be tested.
+ * \return True if the texture is in the heap, false otherwise.
+ */
+
+static GLboolean
+check_in_heap( const driTextureObject * tex, const driTexHeap * heap )
+{
+#if 1
+ return tex->heap == heap;
+#else
+ driTextureObject * curr;
+
+ foreach( curr, & heap->texture_objects ) {
+ if ( curr == tex ) {
+ break;
+ }
+ }
+
+ return curr == tex;
+#endif
+}
+
+
+
+/****************************************************************************/
+/**
+ * Validate the consistency of a set of texture heaps.
+ * Original version by Keith Whitwell in r200/r200_sanity.c.
+ */
+
+GLboolean
+driValidateTextureHeaps( driTexHeap * const * texture_heaps,
+ unsigned nr_heaps, const driTextureObject * swapped )
+{
+ driTextureObject *t;
+ unsigned i;
+
+ for ( i = 0 ; i < nr_heaps ; i++ ) {
+ int last_end = 0;
+ unsigned textures_in_heap = 0;
+ unsigned blocks_in_mempool = 0;
+ const driTexHeap * heap = texture_heaps[i];
+ const struct mem_block *p = heap->memory_heap;
+
+ /* Check each texture object has a MemBlock, and is linked into
+ * the correct heap.
+ *
+ * Check the texobj base address corresponds to the MemBlock
+ * range. Check the texobj size (recalculate?) fits within
+ * the MemBlock.
+ *
+ * Count the number of texobj's using this heap.
+ */
+
+ foreach ( t, &heap->texture_objects ) {
+ if ( !check_in_heap( t, heap ) ) {
+ fprintf( stderr, "%s memory block for texture object @ %p not "
+ "found in heap #%d\n",
+ __FUNCTION__, (void *)t, i );
+ return GL_FALSE;
+ }
+
+
+ if ( t->totalSize > t->memBlock->size ) {
+ fprintf( stderr, "%s: Memory block for texture object @ %p is "
+ "only %u bytes, but %u are required\n",
+ __FUNCTION__, (void *)t, t->totalSize, t->memBlock->size );
+ return GL_FALSE;
+ }
+
+ textures_in_heap++;
+ }
+
+ /* Validate the contents of the heap:
+ * - Ordering
+ * - Overlaps
+ * - Bounds
+ */
+
+ while ( p != NULL ) {
+ if (p->reserved) {
+ fprintf( stderr, "%s: Block (%08x,%x), is reserved?!\n",
+ __FUNCTION__, p->ofs, p->size );
+ return GL_FALSE;
+ }
+
+ if (p->ofs != last_end) {
+ fprintf( stderr, "%s: blocks_in_mempool = %d, last_end = %d, p->ofs = %d\n",
+ __FUNCTION__, blocks_in_mempool, last_end, p->ofs );
+ return GL_FALSE;
+ }
+
+ if (!p->reserved && !p->free) {
+ blocks_in_mempool++;
+ }
+
+ last_end = p->ofs + p->size;
+ p = p->next;
+ }
+
+ if (textures_in_heap != blocks_in_mempool) {
+ fprintf( stderr, "%s: Different number of textures objects (%u) and "
+ "inuse memory blocks (%u)\n",
+ __FUNCTION__, textures_in_heap, blocks_in_mempool );
+ return GL_FALSE;
+ }
+
+#if 0
+ fprintf( stderr, "%s: textures_in_heap = %u\n",
+ __FUNCTION__, textures_in_heap );
+#endif
+ }
+
+
+ /* Check swapped texobj's have zero memblocks
+ */
+ i = 0;
+ foreach ( t, swapped ) {
+ if ( t->memBlock != NULL ) {
+ fprintf( stderr, "%s: Swapped texobj %p has non-NULL memblock %p\n",
+ __FUNCTION__, (void *)t, (void *)t->memBlock );
+ return GL_FALSE;
+ }
+ i++;
+ }
+
+#if 0
+ fprintf( stderr, "%s: swapped texture count = %u\n", __FUNCTION__, i );
+#endif
+
+ return GL_TRUE;
+}
+
+
+
+
+/****************************************************************************/
+/**
+ * Compute which mipmap levels that really need to be sent to the hardware.
+ * This depends on the base image size, GL_TEXTURE_MIN_LOD,
+ * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
+ */
+
+void
+driCalculateTextureFirstLastLevel( driTextureObject * t )
+{
+ struct gl_texture_object * const tObj = t->tObj;
+ const struct gl_texture_image * const baseImage =
+ tObj->Image[0][tObj->BaseLevel];
+
+ /* These must be signed values. MinLod and MaxLod can be negative numbers,
+ * and having firstLevel and lastLevel as signed prevents the need for
+ * extra sign checks.
+ */
+ int firstLevel;
+ int lastLevel;
+
+ /* Yes, this looks overly complicated, but it's all needed.
+ */
+
+ switch (tObj->Target) {
+ case GL_TEXTURE_1D:
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_3D:
+ case GL_TEXTURE_CUBE_MAP:
+ if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) {
+ /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL.
+ */
+
+ firstLevel = lastLevel = tObj->BaseLevel;
+ }
+ else {
+ firstLevel = tObj->BaseLevel + (GLint)(tObj->MinLod + 0.5);
+ firstLevel = MAX2(firstLevel, tObj->BaseLevel);
+ firstLevel = MIN2(firstLevel, tObj->BaseLevel + baseImage->MaxLog2);
+ lastLevel = tObj->BaseLevel + (GLint)(tObj->MaxLod + 0.5);
+ lastLevel = MAX2(lastLevel, t->tObj->BaseLevel);
+ lastLevel = MIN2(lastLevel, t->tObj->BaseLevel + baseImage->MaxLog2);
+ lastLevel = MIN2(lastLevel, t->tObj->MaxLevel);
+ lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */
+ }
+ break;
+ case GL_TEXTURE_RECTANGLE_NV:
+ case GL_TEXTURE_4D_SGIS:
+ firstLevel = lastLevel = 0;
+ break;
+ default:
+ return;
+ }
+
+ /* save these values */
+ t->firstLevel = firstLevel;
+ t->lastLevel = lastLevel;
+}
+
+
+
+
+/**
+ * \name DRI texture formats. These vars are initialized to either the
+ * big- or little-endian Mesa formats.
+ */
+/*@{*/
+gl_format _dri_texformat_rgba8888 = MESA_FORMAT_NONE;
+gl_format _dri_texformat_argb8888 = MESA_FORMAT_NONE;
+gl_format _dri_texformat_rgb565 = MESA_FORMAT_NONE;
+gl_format _dri_texformat_argb4444 = MESA_FORMAT_NONE;
+gl_format _dri_texformat_argb1555 = MESA_FORMAT_NONE;
+gl_format _dri_texformat_al88 = MESA_FORMAT_NONE;
+gl_format _dri_texformat_a8 = MESA_FORMAT_A8;
+gl_format _dri_texformat_ci8 = MESA_FORMAT_CI8;
+gl_format _dri_texformat_i8 = MESA_FORMAT_I8;
+gl_format _dri_texformat_l8 = MESA_FORMAT_L8;
+/*@}*/
+
+
+/**
+ * Initialize _dri_texformat_* vars according to whether we're on
+ * a big or little endian system.
+ */
+void
+driInitTextureFormats(void)
+{
+ if (_mesa_little_endian()) {
+ _dri_texformat_rgba8888 = MESA_FORMAT_RGBA8888;
+ _dri_texformat_argb8888 = MESA_FORMAT_ARGB8888;
+ _dri_texformat_rgb565 = MESA_FORMAT_RGB565;
+ _dri_texformat_argb4444 = MESA_FORMAT_ARGB4444;
+ _dri_texformat_argb1555 = MESA_FORMAT_ARGB1555;
+ _dri_texformat_al88 = MESA_FORMAT_AL88;
+ }
+ else {
+ _dri_texformat_rgba8888 = MESA_FORMAT_RGBA8888_REV;
+ _dri_texformat_argb8888 = MESA_FORMAT_ARGB8888_REV;
+ _dri_texformat_rgb565 = MESA_FORMAT_RGB565_REV;
+ _dri_texformat_argb4444 = MESA_FORMAT_ARGB4444_REV;
+ _dri_texformat_argb1555 = MESA_FORMAT_ARGB1555_REV;
+ _dri_texformat_al88 = MESA_FORMAT_AL88_REV;
+ }
+}
diff --git a/mesalib/src/mesa/drivers/dri/common/texmem.h b/mesalib/src/mesa/drivers/dri/common/texmem.h index 725ba2e11..3815c4107 100644 --- a/mesalib/src/mesa/drivers/dri/common/texmem.h +++ b/mesalib/src/mesa/drivers/dri/common/texmem.h @@ -1,334 +1,334 @@ -/* - * Copyright 2000-2001 VA Linux Systems, Inc. - * (c) Copyright IBM Corporation 2002 - * 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 - * VA LINUX SYSTEM, IBM 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: - * Ian Romanick <idr@us.ibm.com> - * Keith Whitwell <keithw@tungstengraphics.com> - * Kevin E. Martin <kem@users.sourceforge.net> - * Gareth Hughes <gareth@nvidia.com> - */ - -/** \file texmem.h - * Public interface to the DRI texture memory management routines. - * - * \sa texmem.c - */ - -#ifndef DRI_TEXMEM_H -#define DRI_TEXMEM_H - -#include "main/mtypes.h" -#include "main/formats.h" -#include "main/mm.h" -#include "xf86drm.h" - -struct dri_tex_heap; -typedef struct dri_tex_heap driTexHeap; - -struct dri_texture_object; -typedef struct dri_texture_object driTextureObject; - - -/** - * Base texture object type. Each driver will extend this type with its own - * private data members. - */ - -struct dri_texture_object { - struct dri_texture_object * next; - struct dri_texture_object * prev; - - driTexHeap * heap; /**< Texture heap currently stored in */ - struct gl_texture_object * tObj;/**< Pointer to Mesa texture object - * If NULL, this texture object is a - * "placeholder" object representing - * texture memory in use by another context. - * A placeholder should have a heap and a memBlock. - */ - struct mem_block *memBlock; /**< Memory block containing texture */ - - unsigned reserved; /**< Cannot be swapped out by user contexts. */ - - unsigned bound; /**< Bitmask indicating which tex units - * this texture object is bound to. - * Bit 0 = unit 0, Bit 1 = unit 1, etc - */ - - unsigned totalSize; /**< Total size of the texture, - * including all mipmap levels - */ - - unsigned dirty_images[6]; /**< Flags for whether or not images - * need to be uploaded to local or - * AGP texture space. One flag set - * for each cube face for cubic - * textures. Bit zero corresponds to - * the base-level, which may or may - * not be the level zero mipmap. - */ - - unsigned timestamp; /**< Timestamp used to - * synchronize with 3d engine - * in hardware where textures - * are uploaded directly to - * the framebuffer. - */ - - unsigned firstLevel; /**< Image in \c tObj->Image[0] that - * corresponds to the base-level of - * this texture object. - */ - - unsigned lastLevel; /**< Last image in \c tObj->Image[0] - * used by the - * current LOD settings of - * this texture object. This - * value must be greater than - * or equal to \c firstLevel. - */ -}; - - -typedef void (destroy_texture_object_t)( void * driverContext, - driTextureObject * t ); - -/** - * Client-private representation of texture memory state. - * - * Clients will place one or more of these structs in their driver - * context struct to manage one or more global texture heaps. - */ - -struct dri_tex_heap { - - /** Client-supplied heap identifier - */ - unsigned heapId; - - /** Pointer to the client's private context - */ - void *driverContext; - - /** Total size of the heap, in bytes - */ - unsigned size; - - /** \brief \f$log_2\f$ of size of single heap region - * - * Each context takes memory from the global texture heap in - * \f$2^{logGranularity}\f$ byte blocks. The value of - * \a logGranularity is based on the amount of memory represented - * by the heap and the maximum number of regions in the SAREA. Given - * \a b bytes of texture memory an \a n regions in the SAREA, - * \a logGranularity will be \f$\lfloor\log_2( b / n )\rfloor\f$. - */ - unsigned logGranularity; - - /** \brief Required alignment of allocations in this heap - * - * The alignment shift is supplied to \a mmAllocMem when memory is - * allocated from this heap. The value of \a alignmentShift will - * typically reflect some require of the hardware. This value has - * \b no \b relation to \a logGranularity. \a alignmentShift is a - * per-context value. - * - * \sa mmAllocMem - */ - unsigned alignmentShift; - - /** Number of elements in global list (the SAREA). - */ - unsigned nrRegions; - - /** Pointer to SAREA \a driTexRegion array - */ - drmTextureRegionPtr global_regions; - - /** Pointer to the texture state age (generation number) in the SAREA - */ - unsigned * global_age; - - /** Local age (generation number) of texture state - */ - unsigned local_age; - - /** Memory heap used to manage texture memory represented by - * this texture heap. - */ - struct mem_block * memory_heap; - - /** List of objects that we currently believe to be in texture - * memory. - */ - driTextureObject texture_objects; - - /** Pointer to the list of texture objects that are not in - * texture memory. - */ - driTextureObject * swapped_objects; - - /** Size of the driver-speicific texture object. - */ - unsigned texture_object_size; - - - /** - * \brief Function to destroy driver-specific texture object data. - * - * This function is supplied by the driver so that the texture manager - * can release all resources associated with a texture object. This - * function should only release driver-specific data. That is, - * \a driDestroyTextureObject will release the texture memory - * associated with the texture object, it will release the memory - * for the texture object itself, and it will unlink the texture - * object from the texture object lists. - * - * \param driverContext Pointer to the driver supplied context - * \param t Texture object that is to be destroyed - * \sa driDestroyTextureObject - */ - - destroy_texture_object_t * destroy_texture_object; - - - /** - */ - unsigned * texture_swaps; - - /** - * Timestamp used to synchronize with 3d engine in hardware - * where textures are uploaded directly to the - * framebuffer. - */ - unsigned timestamp; - - /** \brief Kick/upload weight - * - * When not enough free space is available this weight - * influences the choice of the heap from which textures are - * kicked. By default the weight is equal to the heap size. - */ - double weight; - - /** \brief Kick/upload duty - * - * The heap with the highest duty will be chosen for kicking - * textures if not enough free space is available. The duty is - * reduced by the amount of data kicked. Rebalancing of - * negative duties takes the weights into account. - */ - int duty; -}; - - - - -/** - * Called by the client on lock contention to determine whether textures have - * been stolen. If another client has modified a region in which we have - * textures, then we need to figure out which of our textures have been - * removed and update our global LRU. - * - * \param heap Texture heap to be updated - * \hideinitializer - */ - -#define DRI_AGE_TEXTURES( heap ) \ - do { \ - if ( ((heap) != NULL) \ - && ((heap)->local_age != (heap)->global_age[0]) ) \ - driAgeTextures( heap ); \ - } while( 0 ) - - - - -/* This should be called whenever there has been contention on the hardware - * lock. driAgeTextures should not be called directly. Instead, clients - * should use DRI_AGE_TEXTURES, above. - */ - -void driAgeTextures( driTexHeap * heap ); - -void driUpdateTextureLRU( driTextureObject * t ); -void driSwapOutTextureObject( driTextureObject * t ); -void driDestroyTextureObject( driTextureObject * t ); -int driAllocateTexture( driTexHeap * const * heap_array, unsigned nr_heaps, - driTextureObject * t ); - -GLboolean driIsTextureResident( GLcontext * ctx, - struct gl_texture_object * texObj ); - -driTexHeap * driCreateTextureHeap( unsigned heap_id, void * context, - unsigned size, unsigned alignmentShift, unsigned nr_regions, - drmTextureRegionPtr global_regions, unsigned * global_age, - driTextureObject * swapped_objects, unsigned texture_object_size, - destroy_texture_object_t * destroy_tex_obj ); -void driDestroyTextureHeap( driTexHeap * heap ); - -void -driCalculateMaxTextureLevels( driTexHeap * const * heaps, - unsigned nr_heaps, - struct gl_constants * limits, - unsigned max_bytes_per_texel, - unsigned max_2D_size, - unsigned max_3D_size, - unsigned max_cube_size, - unsigned max_rect_size, - unsigned mipmaps_at_once, - int all_textures_one_heap, - int allow_larger_textures ); - -void -driSetTextureSwapCounterLocation( driTexHeap * heap, unsigned * counter ); - -#define DRI_TEXMGR_DO_TEXTURE_1D 0x0001 -#define DRI_TEXMGR_DO_TEXTURE_2D 0x0002 -#define DRI_TEXMGR_DO_TEXTURE_3D 0x0004 -#define DRI_TEXMGR_DO_TEXTURE_CUBE 0x0008 -#define DRI_TEXMGR_DO_TEXTURE_RECT 0x0010 - -void driInitTextureObjects( GLcontext *ctx, driTextureObject * swapped, - GLuint targets ); - -GLboolean driValidateTextureHeaps( driTexHeap * const * texture_heaps, - unsigned nr_heaps, const driTextureObject * swapped ); - -extern void driCalculateTextureFirstLastLevel( driTextureObject * t ); - - -extern gl_format _dri_texformat_rgba8888; -extern gl_format _dri_texformat_argb8888; -extern gl_format _dri_texformat_rgb565; -extern gl_format _dri_texformat_argb4444; -extern gl_format _dri_texformat_argb1555; -extern gl_format _dri_texformat_al88; -extern gl_format _dri_texformat_a8; -extern gl_format _dri_texformat_ci8; -extern gl_format _dri_texformat_i8; -extern gl_format _dri_texformat_l8; - -extern void driInitTextureFormats( void ); - -#endif /* DRI_TEXMEM_H */ +/*
+ * Copyright 2000-2001 VA Linux Systems, Inc.
+ * (c) Copyright IBM Corporation 2002
+ * 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
+ * VA LINUX SYSTEM, IBM 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:
+ * Ian Romanick <idr@us.ibm.com>
+ * Keith Whitwell <keithw@tungstengraphics.com>
+ * Kevin E. Martin <kem@users.sourceforge.net>
+ * Gareth Hughes <gareth@nvidia.com>
+ */
+
+/** \file texmem.h
+ * Public interface to the DRI texture memory management routines.
+ *
+ * \sa texmem.c
+ */
+
+#ifndef DRI_TEXMEM_H
+#define DRI_TEXMEM_H
+
+#include "main/mtypes.h"
+#include "main/formats.h"
+#include "main/mm.h"
+#include "xf86drm.h"
+
+struct dri_tex_heap;
+typedef struct dri_tex_heap driTexHeap;
+
+struct dri_texture_object;
+typedef struct dri_texture_object driTextureObject;
+
+
+/**
+ * Base texture object type. Each driver will extend this type with its own
+ * private data members.
+ */
+
+struct dri_texture_object {
+ struct dri_texture_object * next;
+ struct dri_texture_object * prev;
+
+ driTexHeap * heap; /**< Texture heap currently stored in */
+ struct gl_texture_object * tObj;/**< Pointer to Mesa texture object
+ * If NULL, this texture object is a
+ * "placeholder" object representing
+ * texture memory in use by another context.
+ * A placeholder should have a heap and a memBlock.
+ */
+ struct mem_block *memBlock; /**< Memory block containing texture */
+
+ unsigned reserved; /**< Cannot be swapped out by user contexts. */
+
+ unsigned bound; /**< Bitmask indicating which tex units
+ * this texture object is bound to.
+ * Bit 0 = unit 0, Bit 1 = unit 1, etc
+ */
+
+ unsigned totalSize; /**< Total size of the texture,
+ * including all mipmap levels
+ */
+
+ unsigned dirty_images[6]; /**< Flags for whether or not images
+ * need to be uploaded to local or
+ * AGP texture space. One flag set
+ * for each cube face for cubic
+ * textures. Bit zero corresponds to
+ * the base-level, which may or may
+ * not be the level zero mipmap.
+ */
+
+ unsigned timestamp; /**< Timestamp used to
+ * synchronize with 3d engine
+ * in hardware where textures
+ * are uploaded directly to
+ * the framebuffer.
+ */
+
+ unsigned firstLevel; /**< Image in \c tObj->Image[0] that
+ * corresponds to the base-level of
+ * this texture object.
+ */
+
+ unsigned lastLevel; /**< Last image in \c tObj->Image[0]
+ * used by the
+ * current LOD settings of
+ * this texture object. This
+ * value must be greater than
+ * or equal to \c firstLevel.
+ */
+};
+
+
+typedef void (destroy_texture_object_t)( void * driverContext,
+ driTextureObject * t );
+
+/**
+ * Client-private representation of texture memory state.
+ *
+ * Clients will place one or more of these structs in their driver
+ * context struct to manage one or more global texture heaps.
+ */
+
+struct dri_tex_heap {
+
+ /** Client-supplied heap identifier
+ */
+ unsigned heapId;
+
+ /** Pointer to the client's private context
+ */
+ void *driverContext;
+
+ /** Total size of the heap, in bytes
+ */
+ unsigned size;
+
+ /** \brief \f$log_2\f$ of size of single heap region
+ *
+ * Each context takes memory from the global texture heap in
+ * \f$2^{logGranularity}\f$ byte blocks. The value of
+ * \a logGranularity is based on the amount of memory represented
+ * by the heap and the maximum number of regions in the SAREA. Given
+ * \a b bytes of texture memory an \a n regions in the SAREA,
+ * \a logGranularity will be \f$\lfloor\log_2( b / n )\rfloor\f$.
+ */
+ unsigned logGranularity;
+
+ /** \brief Required alignment of allocations in this heap
+ *
+ * The alignment shift is supplied to \a mmAllocMem when memory is
+ * allocated from this heap. The value of \a alignmentShift will
+ * typically reflect some require of the hardware. This value has
+ * \b no \b relation to \a logGranularity. \a alignmentShift is a
+ * per-context value.
+ *
+ * \sa mmAllocMem
+ */
+ unsigned alignmentShift;
+
+ /** Number of elements in global list (the SAREA).
+ */
+ unsigned nrRegions;
+
+ /** Pointer to SAREA \a driTexRegion array
+ */
+ drmTextureRegionPtr global_regions;
+
+ /** Pointer to the texture state age (generation number) in the SAREA
+ */
+ unsigned * global_age;
+
+ /** Local age (generation number) of texture state
+ */
+ unsigned local_age;
+
+ /** Memory heap used to manage texture memory represented by
+ * this texture heap.
+ */
+ struct mem_block * memory_heap;
+
+ /** List of objects that we currently believe to be in texture
+ * memory.
+ */
+ driTextureObject texture_objects;
+
+ /** Pointer to the list of texture objects that are not in
+ * texture memory.
+ */
+ driTextureObject * swapped_objects;
+
+ /** Size of the driver-speicific texture object.
+ */
+ unsigned texture_object_size;
+
+
+ /**
+ * \brief Function to destroy driver-specific texture object data.
+ *
+ * This function is supplied by the driver so that the texture manager
+ * can release all resources associated with a texture object. This
+ * function should only release driver-specific data. That is,
+ * \a driDestroyTextureObject will release the texture memory
+ * associated with the texture object, it will release the memory
+ * for the texture object itself, and it will unlink the texture
+ * object from the texture object lists.
+ *
+ * \param driverContext Pointer to the driver supplied context
+ * \param t Texture object that is to be destroyed
+ * \sa driDestroyTextureObject
+ */
+
+ destroy_texture_object_t * destroy_texture_object;
+
+
+ /**
+ */
+ unsigned * texture_swaps;
+
+ /**
+ * Timestamp used to synchronize with 3d engine in hardware
+ * where textures are uploaded directly to the
+ * framebuffer.
+ */
+ unsigned timestamp;
+
+ /** \brief Kick/upload weight
+ *
+ * When not enough free space is available this weight
+ * influences the choice of the heap from which textures are
+ * kicked. By default the weight is equal to the heap size.
+ */
+ double weight;
+
+ /** \brief Kick/upload duty
+ *
+ * The heap with the highest duty will be chosen for kicking
+ * textures if not enough free space is available. The duty is
+ * reduced by the amount of data kicked. Rebalancing of
+ * negative duties takes the weights into account.
+ */
+ int duty;
+};
+
+
+
+
+/**
+ * Called by the client on lock contention to determine whether textures have
+ * been stolen. If another client has modified a region in which we have
+ * textures, then we need to figure out which of our textures have been
+ * removed and update our global LRU.
+ *
+ * \param heap Texture heap to be updated
+ * \hideinitializer
+ */
+
+#define DRI_AGE_TEXTURES( heap ) \
+ do { \
+ if ( ((heap) != NULL) \
+ && ((heap)->local_age != (heap)->global_age[0]) ) \
+ driAgeTextures( heap ); \
+ } while( 0 )
+
+
+
+
+/* This should be called whenever there has been contention on the hardware
+ * lock. driAgeTextures should not be called directly. Instead, clients
+ * should use DRI_AGE_TEXTURES, above.
+ */
+
+void driAgeTextures( driTexHeap * heap );
+
+void driUpdateTextureLRU( driTextureObject * t );
+void driSwapOutTextureObject( driTextureObject * t );
+void driDestroyTextureObject( driTextureObject * t );
+int driAllocateTexture( driTexHeap * const * heap_array, unsigned nr_heaps,
+ driTextureObject * t );
+
+GLboolean driIsTextureResident( struct gl_context * ctx,
+ struct gl_texture_object * texObj );
+
+driTexHeap * driCreateTextureHeap( unsigned heap_id, void * context,
+ unsigned size, unsigned alignmentShift, unsigned nr_regions,
+ drmTextureRegionPtr global_regions, unsigned * global_age,
+ driTextureObject * swapped_objects, unsigned texture_object_size,
+ destroy_texture_object_t * destroy_tex_obj );
+void driDestroyTextureHeap( driTexHeap * heap );
+
+void
+driCalculateMaxTextureLevels( driTexHeap * const * heaps,
+ unsigned nr_heaps,
+ struct gl_constants * limits,
+ unsigned max_bytes_per_texel,
+ unsigned max_2D_size,
+ unsigned max_3D_size,
+ unsigned max_cube_size,
+ unsigned max_rect_size,
+ unsigned mipmaps_at_once,
+ int all_textures_one_heap,
+ int allow_larger_textures );
+
+void
+driSetTextureSwapCounterLocation( driTexHeap * heap, unsigned * counter );
+
+#define DRI_TEXMGR_DO_TEXTURE_1D 0x0001
+#define DRI_TEXMGR_DO_TEXTURE_2D 0x0002
+#define DRI_TEXMGR_DO_TEXTURE_3D 0x0004
+#define DRI_TEXMGR_DO_TEXTURE_CUBE 0x0008
+#define DRI_TEXMGR_DO_TEXTURE_RECT 0x0010
+
+void driInitTextureObjects( struct gl_context *ctx, driTextureObject * swapped,
+ GLuint targets );
+
+GLboolean driValidateTextureHeaps( driTexHeap * const * texture_heaps,
+ unsigned nr_heaps, const driTextureObject * swapped );
+
+extern void driCalculateTextureFirstLastLevel( driTextureObject * t );
+
+
+extern gl_format _dri_texformat_rgba8888;
+extern gl_format _dri_texformat_argb8888;
+extern gl_format _dri_texformat_rgb565;
+extern gl_format _dri_texformat_argb4444;
+extern gl_format _dri_texformat_argb1555;
+extern gl_format _dri_texformat_al88;
+extern gl_format _dri_texformat_a8;
+extern gl_format _dri_texformat_ci8;
+extern gl_format _dri_texformat_i8;
+extern gl_format _dri_texformat_l8;
+
+extern void driInitTextureFormats( void );
+
+#endif /* DRI_TEXMEM_H */
diff --git a/mesalib/src/mesa/drivers/dri/common/utils.c b/mesalib/src/mesa/drivers/dri/common/utils.c index 771cb64ca..02c8cc6f5 100644 --- a/mesalib/src/mesa/drivers/dri/common/utils.c +++ b/mesalib/src/mesa/drivers/dri/common/utils.c @@ -1,800 +1,823 @@ -/* - * (C) Copyright IBM Corporation 2002, 2004 - * 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 - * VA LINUX SYSTEM, IBM 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. - */ - -/** - * \file utils.c - * Utility functions for DRI drivers. - * - * \author Ian Romanick <idr@us.ibm.com> - */ - -#include <string.h> -#include <stdlib.h> -#include "main/mtypes.h" -#include "main/cpuinfo.h" -#include "main/extensions.h" -#include "utils.h" - - -/** - * Print message to \c stderr if the \c LIBGL_DEBUG environment variable - * is set. - * - * Is called from the drivers. - * - * \param f \c printf like format string. - */ -void -__driUtilMessage(const char *f, ...) -{ - va_list args; - - if (getenv("LIBGL_DEBUG")) { - fprintf(stderr, "libGL: "); - va_start(args, f); - vfprintf(stderr, f, args); - va_end(args); - fprintf(stderr, "\n"); - } -} - - -unsigned -driParseDebugString( const char * debug, - const struct dri_debug_control * control ) -{ - unsigned flag; - - - flag = 0; - if ( debug != NULL ) { - while( control->string != NULL ) { - if ( !strcmp( debug, "all" ) || - strstr( debug, control->string ) != NULL ) { - flag |= control->flag; - } - - control++; - } - } - - return flag; -} - - - -/** - * Create the \c GL_RENDERER string for DRI drivers. - * - * Almost all DRI drivers use a \c GL_RENDERER string of the form: - * - * "Mesa DRI <chip> <driver date> <AGP speed) <CPU information>" - * - * Using the supplied chip name, driver data, and AGP speed, this function - * creates the string. - * - * \param buffer Buffer to hold the \c GL_RENDERER string. - * \param hardware_name Name of the hardware. - * \param driver_date Driver date. - * \param agp_mode AGP mode (speed). - * - * \returns - * The length of the string stored in \c buffer. This does \b not include - * the terminating \c NUL character. - */ -unsigned -driGetRendererString( char * buffer, const char * hardware_name, - const char * driver_date, GLuint agp_mode ) -{ - unsigned offset; - char *cpu; - - offset = sprintf( buffer, "Mesa DRI %s %s", hardware_name, driver_date ); - - /* Append any AGP-specific information. - */ - switch ( agp_mode ) { - case 1: - case 2: - case 4: - case 8: - offset += sprintf( & buffer[ offset ], " AGP %ux", agp_mode ); - break; - - default: - break; - } - - /* Append any CPU-specific information. - */ - cpu = _mesa_get_cpu_string(); - if (cpu) { - offset += sprintf(buffer + offset, " %s", cpu); - free(cpu); - } - - return offset; -} - - - - -#define need_GL_ARB_draw_buffers -#define need_GL_ARB_multisample -#define need_GL_ARB_texture_compression -#define need_GL_ARB_transpose_matrix -#define need_GL_ARB_vertex_buffer_object -#define need_GL_ARB_window_pos -#define need_GL_EXT_compiled_vertex_array -#define need_GL_EXT_multi_draw_arrays -#define need_GL_EXT_polygon_offset -#define need_GL_EXT_texture_object -#define need_GL_EXT_vertex_array -#define need_GL_IBM_multimode_draw_arrays -#define need_GL_MESA_window_pos - -/* These are needed in *all* drivers because Mesa internally implements - * certain functionality in terms of functions provided by these extensions. - * For example, glBlendFunc is implemented by calling glBlendFuncSeparateEXT. - */ -#define need_GL_EXT_blend_func_separate -#define need_GL_NV_vertex_program - -#include "main/remap_helper.h" - -static const struct dri_extension all_mesa_extensions[] = { - { "GL_ARB_draw_buffers", GL_ARB_draw_buffers_functions }, - { "GL_ARB_multisample", GL_ARB_multisample_functions }, - { "GL_ARB_texture_compression", GL_ARB_texture_compression_functions }, - { "GL_ARB_transpose_matrix", GL_ARB_transpose_matrix_functions }, - { "GL_ARB_vertex_buffer_object", GL_ARB_vertex_buffer_object_functions}, - { "GL_ARB_window_pos", GL_ARB_window_pos_functions }, - { "GL_EXT_blend_func_separate", GL_EXT_blend_func_separate_functions }, - { "GL_EXT_compiled_vertex_array", GL_EXT_compiled_vertex_array_functions }, - { "GL_EXT_multi_draw_arrays", GL_EXT_multi_draw_arrays_functions }, - { "GL_EXT_polygon_offset", GL_EXT_polygon_offset_functions }, - { "GL_EXT_texture_object", GL_EXT_texture_object_functions }, - { "GL_EXT_vertex_array", GL_EXT_vertex_array_functions }, - { "GL_IBM_multimode_draw_arrays", GL_IBM_multimode_draw_arrays_functions }, - { "GL_MESA_window_pos", GL_MESA_window_pos_functions }, - { "GL_NV_vertex_program", GL_NV_vertex_program_functions }, - { NULL, NULL } -}; - - -/** - * Enable and map extensions supported by the driver. - * - * When ctx is NULL, extensions are not enabled, but their functions - * are still mapped. When extensions_to_enable is NULL, all static - * functions known to mesa core are mapped. - * - * \bug - * ARB_imaging isn't handled properly. In Mesa, enabling ARB_imaging also - * enables all the sub-extensions that are folded into it. This means that - * we need to add entry-points (via \c driInitSingleExtension) for those - * new functions here. - */ -void driInitExtensions( GLcontext * ctx, - const struct dri_extension * extensions_to_enable, - GLboolean enable_imaging ) -{ - static int first_time = 1; - unsigned i; - - if ( first_time ) { - first_time = 0; - driInitExtensions( NULL, all_mesa_extensions, GL_FALSE ); - } - - if ( (ctx != NULL) && enable_imaging ) { - _mesa_enable_imaging_extensions( ctx ); - } - - /* The caller is too lazy to list any extension */ - if ( extensions_to_enable == NULL ) { - /* 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; - } - - for ( i = 0 ; extensions_to_enable[i].name != NULL ; i++ ) { - driInitSingleExtension( ctx, & extensions_to_enable[i] ); - } -} - - - - -/** - * Enable and map functions for a single extension - * - * \param ctx Context where extension is to be enabled. - * \param ext Extension that is to be enabled. - * - * \sa driInitExtensions, _mesa_enable_extension, _mesa_map_function_array - */ -void driInitSingleExtension( GLcontext * ctx, - const struct dri_extension * ext ) -{ - if ( ext->functions != NULL ) { - _mesa_map_function_array(ext->functions); - } - - if ( ctx != NULL ) { - _mesa_enable_extension( ctx, ext->name ); - } -} - - -/** - * Utility function used by drivers to test the verions of other components. - * - * \param driver_name Name of the driver. Used in error messages. - * \param driActual Actual DRI version supplied __driCreateNewScreen. - * \param driExpected Minimum DRI version required by the driver. - * \param ddxActual Actual DDX version supplied __driCreateNewScreen. - * \param ddxExpected Minimum DDX minor and range of DDX major version required by the driver. - * \param drmActual Actual DRM version supplied __driCreateNewScreen. - * \param drmExpected Minimum DRM version required by the driver. - * - * \returns \c GL_TRUE if all version requirements are met. Otherwise, - * \c GL_FALSE is returned. - * - * \sa __driCreateNewScreen, driCheckDriDdxDrmVersions2 - * - * \todo - * Now that the old \c driCheckDriDdxDrmVersions function is gone, this - * function and \c driCheckDriDdxDrmVersions2 should be renamed. - */ -GLboolean -driCheckDriDdxDrmVersions3(const char * driver_name, - const __DRIversion * driActual, - const __DRIversion * driExpected, - const __DRIversion * ddxActual, - const __DRIutilversion2 * ddxExpected, - const __DRIversion * drmActual, - const __DRIversion * drmExpected) -{ - static const char format[] = "%s DRI driver expected %s version %d.%d.x " - "but got version %d.%d.%d\n"; - static const char format2[] = "%s DRI driver expected %s version %d-%d.%d.x " - "but got version %d.%d.%d\n"; - - - /* Check the DRI version */ - if ( (driActual->major != driExpected->major) - || (driActual->minor < driExpected->minor) ) { - fprintf(stderr, format, driver_name, "DRI", - driExpected->major, driExpected->minor, - driActual->major, driActual->minor, driActual->patch); - return GL_FALSE; - } - - /* Check that the DDX driver version is compatible */ - if ( (ddxActual->major < ddxExpected->major_min) - || (ddxActual->major > ddxExpected->major_max) - || (ddxActual->minor < ddxExpected->minor) ) { - fprintf(stderr, format2, driver_name, "DDX", - ddxExpected->major_min, ddxExpected->major_max, ddxExpected->minor, - ddxActual->major, ddxActual->minor, ddxActual->patch); - return GL_FALSE; - } - - /* Check that the DRM driver version is compatible */ - if ( (drmActual->major != drmExpected->major) - || (drmActual->minor < drmExpected->minor) ) { - fprintf(stderr, format, driver_name, "DRM", - drmExpected->major, drmExpected->minor, - drmActual->major, drmActual->minor, drmActual->patch); - return GL_FALSE; - } - - return GL_TRUE; -} - -GLboolean -driCheckDriDdxDrmVersions2(const char * driver_name, - const __DRIversion * driActual, - const __DRIversion * driExpected, - const __DRIversion * ddxActual, - const __DRIversion * ddxExpected, - const __DRIversion * drmActual, - const __DRIversion * drmExpected) -{ - __DRIutilversion2 ddx_expected; - ddx_expected.major_min = ddxExpected->major; - ddx_expected.major_max = ddxExpected->major; - ddx_expected.minor = ddxExpected->minor; - ddx_expected.patch = ddxExpected->patch; - return driCheckDriDdxDrmVersions3(driver_name, driActual, - driExpected, ddxActual, & ddx_expected, - drmActual, drmExpected); -} - -GLboolean driClipRectToFramebuffer( const GLframebuffer *buffer, - GLint *x, GLint *y, - GLsizei *width, GLsizei *height ) -{ - /* left clipping */ - if (*x < buffer->_Xmin) { - *width -= (buffer->_Xmin - *x); - *x = buffer->_Xmin; - } - - /* right clipping */ - if (*x + *width > buffer->_Xmax) - *width -= (*x + *width - buffer->_Xmax - 1); - - if (*width <= 0) - return GL_FALSE; - - /* bottom clipping */ - if (*y < buffer->_Ymin) { - *height -= (buffer->_Ymin - *y); - *y = buffer->_Ymin; - } - - /* top clipping */ - if (*y + *height > buffer->_Ymax) - *height -= (*y + *height - buffer->_Ymax - 1); - - if (*height <= 0) - return GL_FALSE; - - return GL_TRUE; -} - -/** - * Creates a set of \c __GLcontextModes that a driver will expose. - * - * A set of \c __GLcontextModes will be created based on the supplied - * parameters. The number of modes processed will be 2 * - * \c num_depth_stencil_bits * \c num_db_modes. - * - * For the most part, data is just copied from \c depth_bits, \c stencil_bits, - * \c db_modes, and \c visType into each \c __GLcontextModes element. - * However, the meanings of \c fb_format and \c fb_type require further - * explanation. The \c fb_format specifies which color components are in - * each pixel and what the default order is. For example, \c GL_RGB specifies - * that red, green, blue are available and red is in the "most significant" - * position and blue is in the "least significant". The \c fb_type specifies - * the bit sizes of each component and the actual ordering. For example, if - * \c GL_UNSIGNED_SHORT_5_6_5_REV is specified with \c GL_RGB, bits [15:11] - * are the blue value, bits [10:5] are the green value, and bits [4:0] are - * the red value. - * - * One sublte issue is the combination of \c GL_RGB or \c GL_BGR and either - * of the \c GL_UNSIGNED_INT_8_8_8_8 modes. The resulting mask values in the - * \c __GLcontextModes structure is \b identical to the \c GL_RGBA or - * \c GL_BGRA case, except the \c alphaMask is zero. This means that, as - * far as this routine is concerned, \c GL_RGB with \c GL_UNSIGNED_INT_8_8_8_8 - * still uses 32-bits. - * - * If in doubt, look at the tables used in the function. - * - * \param ptr_to_modes Pointer to a pointer to a linked list of - * \c __GLcontextModes. Upon completion, a pointer to - * the next element to be process will be stored here. - * If the function fails and returns \c GL_FALSE, this - * value will be unmodified, but some elements in the - * linked list may be modified. - * \param fb_format Format of the framebuffer. Currently only \c GL_RGB, - * \c GL_RGBA, \c GL_BGR, and \c GL_BGRA are supported. - * \param fb_type Type of the pixels in the framebuffer. Currently only - * \c GL_UNSIGNED_SHORT_5_6_5, - * \c GL_UNSIGNED_SHORT_5_6_5_REV, - * \c GL_UNSIGNED_INT_8_8_8_8, and - * \c GL_UNSIGNED_INT_8_8_8_8_REV are supported. - * \param depth_bits Array of depth buffer sizes to be exposed. - * \param stencil_bits Array of stencil buffer sizes to be exposed. - * \param num_depth_stencil_bits Number of entries in both \c depth_bits and - * \c stencil_bits. - * \param db_modes Array of buffer swap modes. If an element has a - * value of \c GLX_NONE, then it represents a - * single-buffered mode. Other valid values are - * \c GLX_SWAP_EXCHANGE_OML, \c GLX_SWAP_COPY_OML, and - * \c GLX_SWAP_UNDEFINED_OML. See the - * GLX_OML_swap_method extension spec for more details. - * \param num_db_modes Number of entries in \c db_modes. - * \param msaa_samples Array of msaa sample count. 0 represents a visual - * without a multisample buffer. - * \param num_msaa_modes Number of entries in \c msaa_samples. - * \param visType GLX visual type. Usually either \c GLX_TRUE_COLOR or - * \c GLX_DIRECT_COLOR. - * - * \returns - * \c GL_TRUE on success or \c GL_FALSE on failure. Currently the only - * cause of failure is a bad parameter (i.e., unsupported \c fb_format or - * \c fb_type). - * - * \todo - * There is currently no way to support packed RGB modes (i.e., modes with - * exactly 3 bytes per pixel) or floating-point modes. This could probably - * be done by creating some new, private enums with clever names likes - * \c GL_UNSIGNED_3BYTE_8_8_8, \c GL_4FLOAT_32_32_32_32, - * \c GL_4HALF_16_16_16_16, etc. We can cross that bridge when we come to it. - */ -__DRIconfig ** -driCreateConfigs(GLenum fb_format, GLenum fb_type, - const uint8_t * depth_bits, const uint8_t * stencil_bits, - unsigned num_depth_stencil_bits, - const GLenum * db_modes, unsigned num_db_modes, - const uint8_t * msaa_samples, unsigned num_msaa_modes, - GLboolean enable_accum) -{ - static const uint8_t bits_table[4][4] = { - /* R G B A */ - { 3, 3, 2, 0 }, /* Any GL_UNSIGNED_BYTE_3_3_2 */ - { 5, 6, 5, 0 }, /* Any GL_UNSIGNED_SHORT_5_6_5 */ - { 8, 8, 8, 0 }, /* Any RGB with any GL_UNSIGNED_INT_8_8_8_8 */ - { 8, 8, 8, 8 } /* Any RGBA with any GL_UNSIGNED_INT_8_8_8_8 */ - }; - - static const uint32_t masks_table_rgb[6][4] = { - { 0x000000E0, 0x0000001C, 0x00000003, 0x00000000 }, /* 3_3_2 */ - { 0x00000007, 0x00000038, 0x000000C0, 0x00000000 }, /* 2_3_3_REV */ - { 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 }, /* 5_6_5 */ - { 0x0000001F, 0x000007E0, 0x0000F800, 0x00000000 }, /* 5_6_5_REV */ - { 0xFF000000, 0x00FF0000, 0x0000FF00, 0x00000000 }, /* 8_8_8_8 */ - { 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000 } /* 8_8_8_8_REV */ - }; - - static const uint32_t masks_table_rgba[6][4] = { - { 0x000000E0, 0x0000001C, 0x00000003, 0x00000000 }, /* 3_3_2 */ - { 0x00000007, 0x00000038, 0x000000C0, 0x00000000 }, /* 2_3_3_REV */ - { 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 }, /* 5_6_5 */ - { 0x0000001F, 0x000007E0, 0x0000F800, 0x00000000 }, /* 5_6_5_REV */ - { 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF }, /* 8_8_8_8 */ - { 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 }, /* 8_8_8_8_REV */ - }; - - static const uint32_t masks_table_bgr[6][4] = { - { 0x00000007, 0x00000038, 0x000000C0, 0x00000000 }, /* 3_3_2 */ - { 0x000000E0, 0x0000001C, 0x00000003, 0x00000000 }, /* 2_3_3_REV */ - { 0x0000001F, 0x000007E0, 0x0000F800, 0x00000000 }, /* 5_6_5 */ - { 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 }, /* 5_6_5_REV */ - { 0x0000FF00, 0x00FF0000, 0xFF000000, 0x00000000 }, /* 8_8_8_8 */ - { 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 }, /* 8_8_8_8_REV */ - }; - - static const uint32_t masks_table_bgra[6][4] = { - { 0x00000007, 0x00000038, 0x000000C0, 0x00000000 }, /* 3_3_2 */ - { 0x000000E0, 0x0000001C, 0x00000003, 0x00000000 }, /* 2_3_3_REV */ - { 0x0000001F, 0x000007E0, 0x0000F800, 0x00000000 }, /* 5_6_5 */ - { 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 }, /* 5_6_5_REV */ - { 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF }, /* 8_8_8_8 */ - { 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000 }, /* 8_8_8_8_REV */ - }; - - static const uint8_t bytes_per_pixel[6] = { - 1, /* 3_3_2 */ - 1, /* 2_3_3_REV */ - 2, /* 5_6_5 */ - 2, /* 5_6_5_REV */ - 4, /* 8_8_8_8 */ - 4 /* 8_8_8_8_REV */ - }; - - const uint8_t * bits; - const uint32_t * masks; - int index; - __DRIconfig **configs, **c; - __GLcontextModes *modes; - unsigned i, j, k, h; - unsigned num_modes; - unsigned num_accum_bits = (enable_accum) ? 2 : 1; - - switch ( fb_type ) { - case GL_UNSIGNED_BYTE_3_3_2: - index = 0; - break; - case GL_UNSIGNED_BYTE_2_3_3_REV: - index = 1; - break; - case GL_UNSIGNED_SHORT_5_6_5: - index = 2; - break; - case GL_UNSIGNED_SHORT_5_6_5_REV: - index = 3; - break; - case GL_UNSIGNED_INT_8_8_8_8: - index = 4; - break; - case GL_UNSIGNED_INT_8_8_8_8_REV: - index = 5; - break; - default: - fprintf( stderr, "[%s:%u] Unknown framebuffer type 0x%04x.\n", - __FUNCTION__, __LINE__, fb_type ); - return NULL; - } - - - /* Valid types are GL_UNSIGNED_SHORT_5_6_5 and GL_UNSIGNED_INT_8_8_8_8 and - * the _REV versions. - * - * Valid formats are GL_RGBA, GL_RGB, and GL_BGRA. - */ - - switch ( fb_format ) { - case GL_RGB: - masks = masks_table_rgb[ index ]; - break; - - case GL_RGBA: - masks = masks_table_rgba[ index ]; - break; - - case GL_BGR: - masks = masks_table_bgr[ index ]; - break; - - case GL_BGRA: - masks = masks_table_bgra[ index ]; - break; - - default: - fprintf( stderr, "[%s:%u] Unknown framebuffer format 0x%04x.\n", - __FUNCTION__, __LINE__, fb_format ); - return NULL; - } - - switch ( bytes_per_pixel[ index ] ) { - case 1: - bits = bits_table[0]; - break; - case 2: - bits = bits_table[1]; - break; - default: - bits = ((fb_format == GL_RGB) || (fb_format == GL_BGR)) - ? bits_table[2] - : bits_table[3]; - break; - } - - num_modes = num_depth_stencil_bits * num_db_modes * num_accum_bits * num_msaa_modes; - configs = calloc(1, (num_modes + 1) * sizeof *configs); - if (configs == NULL) - return NULL; - - c = configs; - for ( k = 0 ; k < num_depth_stencil_bits ; k++ ) { - for ( i = 0 ; i < num_db_modes ; i++ ) { - for ( h = 0 ; h < num_msaa_modes; h++ ) { - for ( j = 0 ; j < num_accum_bits ; j++ ) { - *c = malloc (sizeof **c); - modes = &(*c)->modes; - c++; - - memset(modes, 0, sizeof *modes); - modes->redBits = bits[0]; - modes->greenBits = bits[1]; - modes->blueBits = bits[2]; - modes->alphaBits = bits[3]; - modes->redMask = masks[0]; - modes->greenMask = masks[1]; - modes->blueMask = masks[2]; - modes->alphaMask = masks[3]; - modes->rgbBits = modes->redBits + modes->greenBits - + modes->blueBits + modes->alphaBits; - - modes->accumRedBits = 16 * j; - modes->accumGreenBits = 16 * j; - modes->accumBlueBits = 16 * j; - modes->accumAlphaBits = (masks[3] != 0) ? 16 * j : 0; - modes->visualRating = (j == 0) ? GLX_NONE : GLX_SLOW_CONFIG; - - modes->stencilBits = stencil_bits[k]; - modes->depthBits = depth_bits[k]; - - modes->transparentPixel = GLX_NONE; - modes->transparentRed = GLX_DONT_CARE; - modes->transparentGreen = GLX_DONT_CARE; - modes->transparentBlue = GLX_DONT_CARE; - modes->transparentAlpha = GLX_DONT_CARE; - modes->transparentIndex = GLX_DONT_CARE; - modes->visualType = GLX_DONT_CARE; - modes->renderType = GLX_RGBA_BIT; - modes->drawableType = GLX_WINDOW_BIT; - modes->rgbMode = GL_TRUE; - - if ( db_modes[i] == GLX_NONE ) { - modes->doubleBufferMode = GL_FALSE; - } - else { - modes->doubleBufferMode = GL_TRUE; - modes->swapMethod = db_modes[i]; - } - - modes->samples = msaa_samples[h]; - modes->sampleBuffers = modes->samples ? 1 : 0; - - - modes->haveAccumBuffer = ((modes->accumRedBits + - modes->accumGreenBits + - modes->accumBlueBits + - modes->accumAlphaBits) > 0); - modes->haveDepthBuffer = (modes->depthBits > 0); - modes->haveStencilBuffer = (modes->stencilBits > 0); - - modes->bindToTextureRgb = GL_TRUE; - modes->bindToTextureRgba = GL_TRUE; - modes->bindToMipmapTexture = GL_FALSE; - modes->bindToTextureTargets = - __DRI_ATTRIB_TEXTURE_1D_BIT | - __DRI_ATTRIB_TEXTURE_2D_BIT | - __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT; - } - } - } - } - *c = NULL; - - return configs; -} - -__DRIconfig **driConcatConfigs(__DRIconfig **a, - __DRIconfig **b) -{ - __DRIconfig **all; - int i, j, index; - - i = 0; - while (a[i] != NULL) - i++; - j = 0; - while (b[j] != NULL) - j++; - - all = malloc((i + j + 1) * sizeof *all); - index = 0; - for (i = 0; a[i] != NULL; i++) - all[index++] = a[i]; - for (j = 0; b[j] != NULL; j++) - all[index++] = b[j]; - all[index++] = NULL; - - free(a); - free(b); - - return all; -} - -#define __ATTRIB(attrib, field) \ - { attrib, offsetof(__GLcontextModes, field) } - -static const struct { unsigned int attrib, offset; } attribMap[] = { - __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits), - __ATTRIB(__DRI_ATTRIB_LEVEL, level), - __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits), - __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits), - __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits), - __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits), - __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits), - __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits), - __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits), - __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits), - __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits), - __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits), - __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers), - __ATTRIB(__DRI_ATTRIB_SAMPLES, samples), - __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode), - __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode), - __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers), - __ATTRIB(__DRI_ATTRIB_TRANSPARENT_TYPE, transparentPixel), - __ATTRIB(__DRI_ATTRIB_TRANSPARENT_INDEX_VALUE, transparentPixel), - __ATTRIB(__DRI_ATTRIB_TRANSPARENT_RED_VALUE, transparentRed), - __ATTRIB(__DRI_ATTRIB_TRANSPARENT_GREEN_VALUE, transparentGreen), - __ATTRIB(__DRI_ATTRIB_TRANSPARENT_BLUE_VALUE, transparentBlue), - __ATTRIB(__DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE, transparentAlpha), - __ATTRIB(__DRI_ATTRIB_FLOAT_MODE, floatMode), - __ATTRIB(__DRI_ATTRIB_RED_MASK, redMask), - __ATTRIB(__DRI_ATTRIB_GREEN_MASK, greenMask), - __ATTRIB(__DRI_ATTRIB_BLUE_MASK, blueMask), - __ATTRIB(__DRI_ATTRIB_ALPHA_MASK, alphaMask), - __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_WIDTH, maxPbufferWidth), - __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_HEIGHT, maxPbufferHeight), - __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_PIXELS, maxPbufferPixels), - __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH, optimalPbufferWidth), - __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT, optimalPbufferHeight), - __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, swapMethod), - __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb), - __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba), - __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE, bindToMipmapTexture), - __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS, bindToTextureTargets), - __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted), - - /* The struct field doesn't matter here, these are handled by the - * switch in driGetConfigAttribIndex. We need them in the array - * so the iterator includes them though.*/ - __ATTRIB(__DRI_ATTRIB_RENDER_TYPE, level), - __ATTRIB(__DRI_ATTRIB_CONFIG_CAVEAT, level), - __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, level) -}; - -#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) - -static int -driGetConfigAttribIndex(const __DRIconfig *config, - unsigned int index, unsigned int *value) -{ - switch (attribMap[index].attrib) { - case __DRI_ATTRIB_RENDER_TYPE: - *value = __DRI_ATTRIB_RGBA_BIT; - break; - case __DRI_ATTRIB_CONFIG_CAVEAT: - if (config->modes.visualRating == GLX_NON_CONFORMANT_CONFIG) - *value = __DRI_ATTRIB_NON_CONFORMANT_CONFIG; - else if (config->modes.visualRating == GLX_SLOW_CONFIG) - *value = __DRI_ATTRIB_SLOW_BIT; - else - *value = 0; - break; - case __DRI_ATTRIB_SWAP_METHOD: - break; - - case __DRI_ATTRIB_FLOAT_MODE: - *value = config->modes.floatMode; - break; - - default: - *value = *(unsigned int *) - ((char *) &config->modes + attribMap[index].offset); - - break; - } - - return GL_TRUE; -} - -int -driGetConfigAttrib(const __DRIconfig *config, - unsigned int attrib, unsigned int *value) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(attribMap); i++) - if (attribMap[i].attrib == attrib) - return driGetConfigAttribIndex(config, i, value); - - return GL_FALSE; -} - -int -driIndexConfigAttrib(const __DRIconfig *config, int index, - unsigned int *attrib, unsigned int *value) -{ - if (index >= 0 && index < ARRAY_SIZE(attribMap)) { - *attrib = attribMap[index].attrib; - return driGetConfigAttribIndex(config, index, value); - } - - return GL_FALSE; -} +/*
+ * (C) Copyright IBM Corporation 2002, 2004
+ * 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
+ * VA LINUX SYSTEM, IBM 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.
+ */
+
+/**
+ * \file utils.c
+ * Utility functions for DRI drivers.
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "main/mtypes.h"
+#include "main/cpuinfo.h"
+#include "main/extensions.h"
+#include "utils.h"
+
+
+/**
+ * Print message to \c stderr if the \c LIBGL_DEBUG environment variable
+ * is set.
+ *
+ * Is called from the drivers.
+ *
+ * \param f \c printf like format string.
+ */
+void
+__driUtilMessage(const char *f, ...)
+{
+ va_list args;
+
+ if (getenv("LIBGL_DEBUG")) {
+ fprintf(stderr, "libGL: ");
+ va_start(args, f);
+ vfprintf(stderr, f, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ }
+}
+
+
+unsigned
+driParseDebugString( const char * debug,
+ const struct dri_debug_control * control )
+{
+ unsigned flag;
+
+
+ flag = 0;
+ if ( debug != NULL ) {
+ while( control->string != NULL ) {
+ if ( !strcmp( debug, "all" ) ||
+ strstr( debug, control->string ) != NULL ) {
+ flag |= control->flag;
+ }
+
+ control++;
+ }
+ }
+
+ return flag;
+}
+
+
+
+/**
+ * Create the \c GL_RENDERER string for DRI drivers.
+ *
+ * Almost all DRI drivers use a \c GL_RENDERER string of the form:
+ *
+ * "Mesa DRI <chip> <driver date> <AGP speed) <CPU information>"
+ *
+ * Using the supplied chip name, driver data, and AGP speed, this function
+ * creates the string.
+ *
+ * \param buffer Buffer to hold the \c GL_RENDERER string.
+ * \param hardware_name Name of the hardware.
+ * \param driver_date Driver date.
+ * \param agp_mode AGP mode (speed).
+ *
+ * \returns
+ * The length of the string stored in \c buffer. This does \b not include
+ * the terminating \c NUL character.
+ */
+unsigned
+driGetRendererString( char * buffer, const char * hardware_name,
+ const char * driver_date, GLuint agp_mode )
+{
+ unsigned offset;
+ char *cpu;
+
+ offset = sprintf( buffer, "Mesa DRI %s %s", hardware_name, driver_date );
+
+ /* Append any AGP-specific information.
+ */
+ switch ( agp_mode ) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ offset += sprintf( & buffer[ offset ], " AGP %ux", agp_mode );
+ break;
+
+ default:
+ break;
+ }
+
+ /* Append any CPU-specific information.
+ */
+ cpu = _mesa_get_cpu_string();
+ if (cpu) {
+ offset += sprintf(buffer + offset, " %s", cpu);
+ free(cpu);
+ }
+
+ return offset;
+}
+
+
+
+
+#define need_GL_ARB_copy_buffer
+#define need_GL_ARB_draw_buffers
+#define need_GL_ARB_multisample
+#define need_GL_ARB_texture_compression
+#define need_GL_ARB_transpose_matrix
+#define need_GL_ARB_vertex_buffer_object
+#define need_GL_ARB_window_pos
+#define need_GL_EXT_compiled_vertex_array
+#define need_GL_EXT_multi_draw_arrays
+#define need_GL_EXT_polygon_offset
+#define need_GL_EXT_texture_object
+#define need_GL_EXT_vertex_array
+#define need_GL_IBM_multimode_draw_arrays
+#define need_GL_MESA_window_pos
+
+/* These are needed in *all* drivers because Mesa internally implements
+ * certain functionality in terms of functions provided by these extensions.
+ * For example, glBlendFunc is implemented by calling glBlendFuncSeparateEXT.
+ */
+#define need_GL_EXT_blend_func_separate
+#define need_GL_NV_vertex_program
+
+#include "main/remap_helper.h"
+
+static const struct dri_extension all_mesa_extensions[] = {
+ { "GL_ARB_copy_buffer", GL_ARB_copy_buffer_functions },
+ { "GL_ARB_draw_buffers", GL_ARB_draw_buffers_functions },
+ { "GL_ARB_multisample", GL_ARB_multisample_functions },
+ { "GL_ARB_texture_compression", GL_ARB_texture_compression_functions },
+ { "GL_ARB_transpose_matrix", GL_ARB_transpose_matrix_functions },
+ { "GL_ARB_vertex_buffer_object", GL_ARB_vertex_buffer_object_functions},
+ { "GL_ARB_window_pos", GL_ARB_window_pos_functions },
+ { "GL_EXT_blend_func_separate", GL_EXT_blend_func_separate_functions },
+ { "GL_EXT_compiled_vertex_array", GL_EXT_compiled_vertex_array_functions },
+ { "GL_EXT_multi_draw_arrays", GL_EXT_multi_draw_arrays_functions },
+ { "GL_EXT_polygon_offset", GL_EXT_polygon_offset_functions },
+ { "GL_EXT_texture_object", GL_EXT_texture_object_functions },
+ { "GL_EXT_vertex_array", GL_EXT_vertex_array_functions },
+ { "GL_IBM_multimode_draw_arrays", GL_IBM_multimode_draw_arrays_functions },
+ { "GL_MESA_window_pos", GL_MESA_window_pos_functions },
+ { "GL_NV_vertex_program", GL_NV_vertex_program_functions },
+ { NULL, NULL }
+};
+
+
+/**
+ * Enable and map extensions supported by the driver.
+ *
+ * When ctx is NULL, extensions are not enabled, but their functions
+ * are still mapped. When extensions_to_enable is NULL, all static
+ * functions known to mesa core are mapped.
+ *
+ * \bug
+ * ARB_imaging isn't handled properly. In Mesa, enabling ARB_imaging also
+ * enables all the sub-extensions that are folded into it. This means that
+ * we need to add entry-points (via \c driInitSingleExtension) for those
+ * new functions here.
+ */
+void driInitExtensions( struct gl_context * ctx,
+ const struct dri_extension * extensions_to_enable,
+ GLboolean enable_imaging )
+{
+ static int first_time = 1;
+ unsigned i;
+
+ if ( first_time ) {
+ first_time = 0;
+ driInitExtensions( NULL, all_mesa_extensions, GL_FALSE );
+ }
+
+ if ( (ctx != NULL) && enable_imaging ) {
+ _mesa_enable_imaging_extensions( ctx );
+ }
+
+ /* The caller is too lazy to list any extension */
+ if ( extensions_to_enable == NULL ) {
+ /* 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;
+ }
+
+ for ( i = 0 ; extensions_to_enable[i].name != NULL ; i++ ) {
+ driInitSingleExtension( ctx, & extensions_to_enable[i] );
+ }
+}
+
+
+
+
+/**
+ * Enable and map functions for a single extension
+ *
+ * \param ctx Context where extension is to be enabled.
+ * \param ext Extension that is to be enabled.
+ *
+ * \sa driInitExtensions, _mesa_enable_extension, _mesa_map_function_array
+ */
+void driInitSingleExtension( struct gl_context * ctx,
+ const struct dri_extension * ext )
+{
+ if ( ext->functions != NULL ) {
+ _mesa_map_function_array(ext->functions);
+ }
+
+ if ( ctx != NULL ) {
+ _mesa_enable_extension( ctx, ext->name );
+ }
+}
+
+
+/**
+ * Utility function used by drivers to test the verions of other components.
+ *
+ * \param driver_name Name of the driver. Used in error messages.
+ * \param driActual Actual DRI version supplied __driCreateNewScreen.
+ * \param driExpected Minimum DRI version required by the driver.
+ * \param ddxActual Actual DDX version supplied __driCreateNewScreen.
+ * \param ddxExpected Minimum DDX minor and range of DDX major version required by the driver.
+ * \param drmActual Actual DRM version supplied __driCreateNewScreen.
+ * \param drmExpected Minimum DRM version required by the driver.
+ *
+ * \returns \c GL_TRUE if all version requirements are met. Otherwise,
+ * \c GL_FALSE is returned.
+ *
+ * \sa __driCreateNewScreen, driCheckDriDdxDrmVersions2
+ *
+ * \todo
+ * Now that the old \c driCheckDriDdxDrmVersions function is gone, this
+ * function and \c driCheckDriDdxDrmVersions2 should be renamed.
+ */
+GLboolean
+driCheckDriDdxDrmVersions3(const char * driver_name,
+ const __DRIversion * driActual,
+ const __DRIversion * driExpected,
+ const __DRIversion * ddxActual,
+ const __DRIutilversion2 * ddxExpected,
+ const __DRIversion * drmActual,
+ const __DRIversion * drmExpected)
+{
+ static const char format[] = "%s DRI driver expected %s version %d.%d.x "
+ "but got version %d.%d.%d\n";
+ static const char format2[] = "%s DRI driver expected %s version %d-%d.%d.x "
+ "but got version %d.%d.%d\n";
+
+
+ /* Check the DRI version */
+ if ( (driActual->major != driExpected->major)
+ || (driActual->minor < driExpected->minor) ) {
+ fprintf(stderr, format, driver_name, "DRI",
+ driExpected->major, driExpected->minor,
+ driActual->major, driActual->minor, driActual->patch);
+ return GL_FALSE;
+ }
+
+ /* Check that the DDX driver version is compatible */
+ if ( (ddxActual->major < ddxExpected->major_min)
+ || (ddxActual->major > ddxExpected->major_max)
+ || (ddxActual->minor < ddxExpected->minor) ) {
+ fprintf(stderr, format2, driver_name, "DDX",
+ ddxExpected->major_min, ddxExpected->major_max, ddxExpected->minor,
+ ddxActual->major, ddxActual->minor, ddxActual->patch);
+ return GL_FALSE;
+ }
+
+ /* Check that the DRM driver version is compatible */
+ if ( (drmActual->major != drmExpected->major)
+ || (drmActual->minor < drmExpected->minor) ) {
+ fprintf(stderr, format, driver_name, "DRM",
+ drmExpected->major, drmExpected->minor,
+ drmActual->major, drmActual->minor, drmActual->patch);
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+GLboolean
+driCheckDriDdxDrmVersions2(const char * driver_name,
+ const __DRIversion * driActual,
+ const __DRIversion * driExpected,
+ const __DRIversion * ddxActual,
+ const __DRIversion * ddxExpected,
+ const __DRIversion * drmActual,
+ const __DRIversion * drmExpected)
+{
+ __DRIutilversion2 ddx_expected;
+ ddx_expected.major_min = ddxExpected->major;
+ ddx_expected.major_max = ddxExpected->major;
+ ddx_expected.minor = ddxExpected->minor;
+ ddx_expected.patch = ddxExpected->patch;
+ return driCheckDriDdxDrmVersions3(driver_name, driActual,
+ driExpected, ddxActual, & ddx_expected,
+ drmActual, drmExpected);
+}
+
+GLboolean driClipRectToFramebuffer( const struct gl_framebuffer *buffer,
+ GLint *x, GLint *y,
+ GLsizei *width, GLsizei *height )
+{
+ /* left clipping */
+ if (*x < buffer->_Xmin) {
+ *width -= (buffer->_Xmin - *x);
+ *x = buffer->_Xmin;
+ }
+
+ /* right clipping */
+ if (*x + *width > buffer->_Xmax)
+ *width -= (*x + *width - buffer->_Xmax - 1);
+
+ if (*width <= 0)
+ return GL_FALSE;
+
+ /* bottom clipping */
+ if (*y < buffer->_Ymin) {
+ *height -= (buffer->_Ymin - *y);
+ *y = buffer->_Ymin;
+ }
+
+ /* top clipping */
+ if (*y + *height > buffer->_Ymax)
+ *height -= (*y + *height - buffer->_Ymax - 1);
+
+ if (*height <= 0)
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+
+/**
+ * Creates a set of \c struct gl_config that a driver will expose.
+ *
+ * A set of \c struct gl_config will be created based on the supplied
+ * parameters. The number of modes processed will be 2 *
+ * \c num_depth_stencil_bits * \c num_db_modes.
+ *
+ * For the most part, data is just copied from \c depth_bits, \c stencil_bits,
+ * \c db_modes, and \c visType into each \c struct gl_config element.
+ * However, the meanings of \c fb_format and \c fb_type require further
+ * explanation. The \c fb_format specifies which color components are in
+ * each pixel and what the default order is. For example, \c GL_RGB specifies
+ * that red, green, blue are available and red is in the "most significant"
+ * position and blue is in the "least significant". The \c fb_type specifies
+ * the bit sizes of each component and the actual ordering. For example, if
+ * \c GL_UNSIGNED_SHORT_5_6_5_REV is specified with \c GL_RGB, bits [15:11]
+ * are the blue value, bits [10:5] are the green value, and bits [4:0] are
+ * the red value.
+ *
+ * One sublte issue is the combination of \c GL_RGB or \c GL_BGR and either
+ * of the \c GL_UNSIGNED_INT_8_8_8_8 modes. The resulting mask values in the
+ * \c struct gl_config structure is \b identical to the \c GL_RGBA or
+ * \c GL_BGRA case, except the \c alphaMask is zero. This means that, as
+ * far as this routine is concerned, \c GL_RGB with \c GL_UNSIGNED_INT_8_8_8_8
+ * still uses 32-bits.
+ *
+ * If in doubt, look at the tables used in the function.
+ *
+ * \param ptr_to_modes Pointer to a pointer to a linked list of
+ * \c struct gl_config. Upon completion, a pointer to
+ * the next element to be process will be stored here.
+ * If the function fails and returns \c GL_FALSE, this
+ * value will be unmodified, but some elements in the
+ * linked list may be modified.
+ * \param fb_format Format of the framebuffer. Currently only \c GL_RGB,
+ * \c GL_RGBA, \c GL_BGR, and \c GL_BGRA are supported.
+ * \param fb_type Type of the pixels in the framebuffer. Currently only
+ * \c GL_UNSIGNED_SHORT_5_6_5,
+ * \c GL_UNSIGNED_SHORT_5_6_5_REV,
+ * \c GL_UNSIGNED_INT_8_8_8_8, and
+ * \c GL_UNSIGNED_INT_8_8_8_8_REV are supported.
+ * \param depth_bits Array of depth buffer sizes to be exposed.
+ * \param stencil_bits Array of stencil buffer sizes to be exposed.
+ * \param num_depth_stencil_bits Number of entries in both \c depth_bits and
+ * \c stencil_bits.
+ * \param db_modes Array of buffer swap modes. If an element has a
+ * value of \c GLX_NONE, then it represents a
+ * single-buffered mode. Other valid values are
+ * \c GLX_SWAP_EXCHANGE_OML, \c GLX_SWAP_COPY_OML, and
+ * \c GLX_SWAP_UNDEFINED_OML. See the
+ * GLX_OML_swap_method extension spec for more details.
+ * \param num_db_modes Number of entries in \c db_modes.
+ * \param msaa_samples Array of msaa sample count. 0 represents a visual
+ * without a multisample buffer.
+ * \param num_msaa_modes Number of entries in \c msaa_samples.
+ * \param visType GLX visual type. Usually either \c GLX_TRUE_COLOR or
+ * \c GLX_DIRECT_COLOR.
+ *
+ * \returns
+ * \c GL_TRUE on success or \c GL_FALSE on failure. Currently the only
+ * cause of failure is a bad parameter (i.e., unsupported \c fb_format or
+ * \c fb_type).
+ *
+ * \todo
+ * There is currently no way to support packed RGB modes (i.e., modes with
+ * exactly 3 bytes per pixel) or floating-point modes. This could probably
+ * be done by creating some new, private enums with clever names likes
+ * \c GL_UNSIGNED_3BYTE_8_8_8, \c GL_4FLOAT_32_32_32_32,
+ * \c GL_4HALF_16_16_16_16, etc. We can cross that bridge when we come to it.
+ */
+__DRIconfig **
+driCreateConfigs(GLenum fb_format, GLenum fb_type,
+ const uint8_t * depth_bits, const uint8_t * stencil_bits,
+ unsigned num_depth_stencil_bits,
+ const GLenum * db_modes, unsigned num_db_modes,
+ const uint8_t * msaa_samples, unsigned num_msaa_modes,
+ GLboolean enable_accum)
+{
+ static const uint8_t bits_table[4][4] = {
+ /* R G B A */
+ { 3, 3, 2, 0 }, /* Any GL_UNSIGNED_BYTE_3_3_2 */
+ { 5, 6, 5, 0 }, /* Any GL_UNSIGNED_SHORT_5_6_5 */
+ { 8, 8, 8, 0 }, /* Any RGB with any GL_UNSIGNED_INT_8_8_8_8 */
+ { 8, 8, 8, 8 } /* Any RGBA with any GL_UNSIGNED_INT_8_8_8_8 */
+ };
+
+ static const uint32_t masks_table_rgb[6][4] = {
+ { 0x000000E0, 0x0000001C, 0x00000003, 0x00000000 }, /* 3_3_2 */
+ { 0x00000007, 0x00000038, 0x000000C0, 0x00000000 }, /* 2_3_3_REV */
+ { 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 }, /* 5_6_5 */
+ { 0x0000001F, 0x000007E0, 0x0000F800, 0x00000000 }, /* 5_6_5_REV */
+ { 0xFF000000, 0x00FF0000, 0x0000FF00, 0x00000000 }, /* 8_8_8_8 */
+ { 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000 } /* 8_8_8_8_REV */
+ };
+
+ static const uint32_t masks_table_rgba[6][4] = {
+ { 0x000000E0, 0x0000001C, 0x00000003, 0x00000000 }, /* 3_3_2 */
+ { 0x00000007, 0x00000038, 0x000000C0, 0x00000000 }, /* 2_3_3_REV */
+ { 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 }, /* 5_6_5 */
+ { 0x0000001F, 0x000007E0, 0x0000F800, 0x00000000 }, /* 5_6_5_REV */
+ { 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF }, /* 8_8_8_8 */
+ { 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 }, /* 8_8_8_8_REV */
+ };
+
+ static const uint32_t masks_table_bgr[6][4] = {
+ { 0x00000007, 0x00000038, 0x000000C0, 0x00000000 }, /* 3_3_2 */
+ { 0x000000E0, 0x0000001C, 0x00000003, 0x00000000 }, /* 2_3_3_REV */
+ { 0x0000001F, 0x000007E0, 0x0000F800, 0x00000000 }, /* 5_6_5 */
+ { 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 }, /* 5_6_5_REV */
+ { 0x0000FF00, 0x00FF0000, 0xFF000000, 0x00000000 }, /* 8_8_8_8 */
+ { 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 }, /* 8_8_8_8_REV */
+ };
+
+ static const uint32_t masks_table_bgra[6][4] = {
+ { 0x00000007, 0x00000038, 0x000000C0, 0x00000000 }, /* 3_3_2 */
+ { 0x000000E0, 0x0000001C, 0x00000003, 0x00000000 }, /* 2_3_3_REV */
+ { 0x0000001F, 0x000007E0, 0x0000F800, 0x00000000 }, /* 5_6_5 */
+ { 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 }, /* 5_6_5_REV */
+ { 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF }, /* 8_8_8_8 */
+ { 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000 }, /* 8_8_8_8_REV */
+ };
+
+ static const uint8_t bytes_per_pixel[6] = {
+ 1, /* 3_3_2 */
+ 1, /* 2_3_3_REV */
+ 2, /* 5_6_5 */
+ 2, /* 5_6_5_REV */
+ 4, /* 8_8_8_8 */
+ 4 /* 8_8_8_8_REV */
+ };
+
+ const uint8_t * bits;
+ const uint32_t * masks;
+ int index;
+ __DRIconfig **configs, **c;
+ struct gl_config *modes;
+ unsigned i, j, k, h;
+ unsigned num_modes;
+ unsigned num_accum_bits = (enable_accum) ? 2 : 1;
+
+ switch ( fb_type ) {
+ case GL_UNSIGNED_BYTE_3_3_2:
+ index = 0;
+ break;
+ case GL_UNSIGNED_BYTE_2_3_3_REV:
+ index = 1;
+ break;
+ case GL_UNSIGNED_SHORT_5_6_5:
+ index = 2;
+ break;
+ case GL_UNSIGNED_SHORT_5_6_5_REV:
+ index = 3;
+ break;
+ case GL_UNSIGNED_INT_8_8_8_8:
+ index = 4;
+ break;
+ case GL_UNSIGNED_INT_8_8_8_8_REV:
+ index = 5;
+ break;
+ default:
+ fprintf( stderr, "[%s:%u] Unknown framebuffer type 0x%04x.\n",
+ __FUNCTION__, __LINE__, fb_type );
+ return NULL;
+ }
+
+
+ /* Valid types are GL_UNSIGNED_SHORT_5_6_5 and GL_UNSIGNED_INT_8_8_8_8 and
+ * the _REV versions.
+ *
+ * Valid formats are GL_RGBA, GL_RGB, and GL_BGRA.
+ */
+
+ switch ( fb_format ) {
+ case GL_RGB:
+ masks = masks_table_rgb[ index ];
+ break;
+
+ case GL_RGBA:
+ masks = masks_table_rgba[ index ];
+ break;
+
+ case GL_BGR:
+ masks = masks_table_bgr[ index ];
+ break;
+
+ case GL_BGRA:
+ masks = masks_table_bgra[ index ];
+ break;
+
+ default:
+ fprintf( stderr, "[%s:%u] Unknown framebuffer format 0x%04x.\n",
+ __FUNCTION__, __LINE__, fb_format );
+ return NULL;
+ }
+
+ switch ( bytes_per_pixel[ index ] ) {
+ case 1:
+ bits = bits_table[0];
+ break;
+ case 2:
+ bits = bits_table[1];
+ break;
+ default:
+ bits = ((fb_format == GL_RGB) || (fb_format == GL_BGR))
+ ? bits_table[2]
+ : bits_table[3];
+ break;
+ }
+
+ num_modes = num_depth_stencil_bits * num_db_modes * num_accum_bits * num_msaa_modes;
+ configs = calloc(1, (num_modes + 1) * sizeof *configs);
+ if (configs == NULL)
+ return NULL;
+
+ c = configs;
+ for ( k = 0 ; k < num_depth_stencil_bits ; k++ ) {
+ for ( i = 0 ; i < num_db_modes ; i++ ) {
+ for ( h = 0 ; h < num_msaa_modes; h++ ) {
+ for ( j = 0 ; j < num_accum_bits ; j++ ) {
+ *c = malloc (sizeof **c);
+ modes = &(*c)->modes;
+ c++;
+
+ memset(modes, 0, sizeof *modes);
+ modes->redBits = bits[0];
+ modes->greenBits = bits[1];
+ modes->blueBits = bits[2];
+ modes->alphaBits = bits[3];
+ modes->redMask = masks[0];
+ modes->greenMask = masks[1];
+ modes->blueMask = masks[2];
+ modes->alphaMask = masks[3];
+ modes->rgbBits = modes->redBits + modes->greenBits
+ + modes->blueBits + modes->alphaBits;
+
+ modes->accumRedBits = 16 * j;
+ modes->accumGreenBits = 16 * j;
+ modes->accumBlueBits = 16 * j;
+ modes->accumAlphaBits = (masks[3] != 0) ? 16 * j : 0;
+ modes->visualRating = (j == 0) ? GLX_NONE : GLX_SLOW_CONFIG;
+
+ modes->stencilBits = stencil_bits[k];
+ modes->depthBits = depth_bits[k];
+
+ modes->transparentPixel = GLX_NONE;
+ modes->transparentRed = GLX_DONT_CARE;
+ modes->transparentGreen = GLX_DONT_CARE;
+ modes->transparentBlue = GLX_DONT_CARE;
+ modes->transparentAlpha = GLX_DONT_CARE;
+ modes->transparentIndex = GLX_DONT_CARE;
+ modes->rgbMode = GL_TRUE;
+
+ if ( db_modes[i] == GLX_NONE ) {
+ modes->doubleBufferMode = GL_FALSE;
+ }
+ else {
+ modes->doubleBufferMode = GL_TRUE;
+ modes->swapMethod = db_modes[i];
+ }
+
+ modes->samples = msaa_samples[h];
+ modes->sampleBuffers = modes->samples ? 1 : 0;
+
+
+ modes->haveAccumBuffer = ((modes->accumRedBits +
+ modes->accumGreenBits +
+ modes->accumBlueBits +
+ modes->accumAlphaBits) > 0);
+ modes->haveDepthBuffer = (modes->depthBits > 0);
+ modes->haveStencilBuffer = (modes->stencilBits > 0);
+
+ modes->bindToTextureRgb = GL_TRUE;
+ modes->bindToTextureRgba = GL_TRUE;
+ modes->bindToMipmapTexture = GL_FALSE;
+ modes->bindToTextureTargets =
+ __DRI_ATTRIB_TEXTURE_1D_BIT |
+ __DRI_ATTRIB_TEXTURE_2D_BIT |
+ __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT;
+ }
+ }
+ }
+ }
+ *c = NULL;
+
+ return configs;
+}
+
+__DRIconfig **driConcatConfigs(__DRIconfig **a,
+ __DRIconfig **b)
+{
+ __DRIconfig **all;
+ int i, j, index;
+
+ i = 0;
+ while (a[i] != NULL)
+ i++;
+ j = 0;
+ while (b[j] != NULL)
+ j++;
+
+ all = malloc((i + j + 1) * sizeof *all);
+ index = 0;
+ for (i = 0; a[i] != NULL; i++)
+ all[index++] = a[i];
+ for (j = 0; b[j] != NULL; j++)
+ all[index++] = b[j];
+ all[index++] = NULL;
+
+ free(a);
+ free(b);
+
+ return all;
+}
+
+#define __ATTRIB(attrib, field) \
+ { attrib, offsetof(struct gl_config, field) }
+
+static const struct { unsigned int attrib, offset; } attribMap[] = {
+ __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits),
+ __ATTRIB(__DRI_ATTRIB_LEVEL, level),
+ __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits),
+ __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits),
+ __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits),
+ __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits),
+ __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits),
+ __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits),
+ __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits),
+ __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits),
+ __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits),
+ __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits),
+ __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers),
+ __ATTRIB(__DRI_ATTRIB_SAMPLES, samples),
+ __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode),
+ __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode),
+ __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers),
+ __ATTRIB(__DRI_ATTRIB_TRANSPARENT_TYPE, transparentPixel),
+ __ATTRIB(__DRI_ATTRIB_TRANSPARENT_INDEX_VALUE, transparentPixel),
+ __ATTRIB(__DRI_ATTRIB_TRANSPARENT_RED_VALUE, transparentRed),
+ __ATTRIB(__DRI_ATTRIB_TRANSPARENT_GREEN_VALUE, transparentGreen),
+ __ATTRIB(__DRI_ATTRIB_TRANSPARENT_BLUE_VALUE, transparentBlue),
+ __ATTRIB(__DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE, transparentAlpha),
+ __ATTRIB(__DRI_ATTRIB_FLOAT_MODE, floatMode),
+ __ATTRIB(__DRI_ATTRIB_RED_MASK, redMask),
+ __ATTRIB(__DRI_ATTRIB_GREEN_MASK, greenMask),
+ __ATTRIB(__DRI_ATTRIB_BLUE_MASK, blueMask),
+ __ATTRIB(__DRI_ATTRIB_ALPHA_MASK, alphaMask),
+ __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_WIDTH, maxPbufferWidth),
+ __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_HEIGHT, maxPbufferHeight),
+ __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_PIXELS, maxPbufferPixels),
+ __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH, optimalPbufferWidth),
+ __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT, optimalPbufferHeight),
+ __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, swapMethod),
+ __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb),
+ __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba),
+ __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE, bindToMipmapTexture),
+ __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS, bindToTextureTargets),
+ __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted),
+
+ /* The struct field doesn't matter here, these are handled by the
+ * switch in driGetConfigAttribIndex. We need them in the array
+ * so the iterator includes them though.*/
+ __ATTRIB(__DRI_ATTRIB_RENDER_TYPE, level),
+ __ATTRIB(__DRI_ATTRIB_CONFIG_CAVEAT, level),
+ __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, level)
+};
+
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
+
+
+/**
+ * Return the value of a configuration attribute. The attribute is
+ * indicated by the index.
+ */
+static int
+driGetConfigAttribIndex(const __DRIconfig *config,
+ unsigned int index, unsigned int *value)
+{
+ switch (attribMap[index].attrib) {
+ case __DRI_ATTRIB_RENDER_TYPE:
+ /* no support for color index mode */
+ *value = __DRI_ATTRIB_RGBA_BIT;
+ break;
+ case __DRI_ATTRIB_CONFIG_CAVEAT:
+ if (config->modes.visualRating == GLX_NON_CONFORMANT_CONFIG)
+ *value = __DRI_ATTRIB_NON_CONFORMANT_CONFIG;
+ else if (config->modes.visualRating == GLX_SLOW_CONFIG)
+ *value = __DRI_ATTRIB_SLOW_BIT;
+ else
+ *value = 0;
+ break;
+ case __DRI_ATTRIB_SWAP_METHOD:
+ /* XXX no return value??? */
+ break;
+
+ case __DRI_ATTRIB_FLOAT_MODE:
+ /* this field is not int-sized */
+ *value = config->modes.floatMode;
+ break;
+
+ default:
+ /* any other int-sized field */
+ *value = *(unsigned int *)
+ ((char *) &config->modes + attribMap[index].offset);
+
+ break;
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Get the value of a configuration attribute.
+ * \param attrib the attribute (one of the _DRI_ATTRIB_x tokens)
+ * \param value returns the attribute's value
+ * \return 1 for success, 0 for failure
+ */
+int
+driGetConfigAttrib(const __DRIconfig *config,
+ unsigned int attrib, unsigned int *value)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(attribMap); i++)
+ if (attribMap[i].attrib == attrib)
+ return driGetConfigAttribIndex(config, i, value);
+
+ return GL_FALSE;
+}
+
+
+/**
+ * Get a configuration attribute name and value, given an index.
+ * \param index which field of the __DRIconfig to query
+ * \param attrib returns the attribute name (one of the _DRI_ATTRIB_x tokens)
+ * \param value returns the attribute's value
+ * \return 1 for success, 0 for failure
+ */
+int
+driIndexConfigAttrib(const __DRIconfig *config, int index,
+ unsigned int *attrib, unsigned int *value)
+{
+ if (index >= 0 && index < ARRAY_SIZE(attribMap)) {
+ *attrib = attribMap[index].attrib;
+ return driGetConfigAttribIndex(config, index, value);
+ }
+
+ return GL_FALSE;
+}
diff --git a/mesalib/src/mesa/drivers/dri/common/utils.h b/mesalib/src/mesa/drivers/dri/common/utils.h index de6070c39..2c952dc19 100644 --- a/mesalib/src/mesa/drivers/dri/common/utils.h +++ b/mesalib/src/mesa/drivers/dri/common/utils.h @@ -1,123 +1,123 @@ -/* - * (C) Copyright IBM Corporation 2002, 2004 - * 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 - * VA LINUX SYSTEM, IBM 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: - * Ian Romanick <idr@us.ibm.com> - */ - -#ifndef DRI_DEBUG_H -#define DRI_DEBUG_H - -#include <GL/gl.h> -#include <GL/internal/dri_interface.h> -#include "main/context.h" -#include "main/remap.h" - -typedef struct __DRIutilversionRec2 __DRIutilversion2; - -struct dri_debug_control { - const char * string; - unsigned flag; -}; - -/** - * Description of the API for an extension to OpenGL. - */ -struct dri_extension { - /** - * Name of the extension. - */ - const char * name; - - - /** - * Pointer to a list of \c dri_extension_function structures. The list - * is terminated by a structure with a \c NULL - * \c dri_extension_function::strings pointer. - */ - const struct gl_function_remap * functions; -}; - -/** - * Used to store a version which includes a major range instead of a single - * major version number. - */ -struct __DRIutilversionRec2 { - int major_min; /** min allowed Major version number. */ - int major_max; /** max allowed Major version number. */ - int minor; /**< Minor version number. */ - int patch; /**< Patch-level. */ -}; - -extern void -__driUtilMessage(const char *f, ...); - -extern unsigned driParseDebugString( const char * debug, - const struct dri_debug_control * control ); - -extern unsigned driGetRendererString( char * buffer, - const char * hardware_name, const char * driver_date, GLuint agp_mode ); - -extern void driInitExtensions( GLcontext * ctx, - const struct dri_extension * card_extensions, GLboolean enable_imaging ); - -extern void driInitSingleExtension( GLcontext * ctx, - const struct dri_extension * ext ); - -extern GLboolean driCheckDriDdxDrmVersions2(const char * driver_name, - const __DRIversion * driActual, const __DRIversion * driExpected, - const __DRIversion * ddxActual, const __DRIversion * ddxExpected, - const __DRIversion * drmActual, const __DRIversion * drmExpected); - -extern GLboolean driCheckDriDdxDrmVersions3(const char * driver_name, - const __DRIversion * driActual, const __DRIversion * driExpected, - const __DRIversion * ddxActual, const __DRIutilversion2 * ddxExpected, - const __DRIversion * drmActual, const __DRIversion * drmExpected); - -extern GLboolean driClipRectToFramebuffer( const GLframebuffer *buffer, - GLint *x, GLint *y, - GLsizei *width, GLsizei *height ); - -struct __DRIconfigRec { - __GLcontextModes modes; -}; - -extern __DRIconfig ** -driCreateConfigs(GLenum fb_format, GLenum fb_type, - const uint8_t * depth_bits, const uint8_t * stencil_bits, - unsigned num_depth_stencil_bits, - const GLenum * db_modes, unsigned num_db_modes, - const uint8_t * msaa_samples, unsigned num_msaa_modes, - GLboolean enable_accum); - -__DRIconfig **driConcatConfigs(__DRIconfig **a, - __DRIconfig **b); - -int -driGetConfigAttrib(const __DRIconfig *config, - unsigned int attrib, unsigned int *value); -int -driIndexConfigAttrib(const __DRIconfig *config, int index, - unsigned int *attrib, unsigned int *value); - -#endif /* DRI_DEBUG_H */ +/*
+ * (C) Copyright IBM Corporation 2002, 2004
+ * 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
+ * VA LINUX SYSTEM, IBM 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:
+ * Ian Romanick <idr@us.ibm.com>
+ */
+
+#ifndef DRI_DEBUG_H
+#define DRI_DEBUG_H
+
+#include <GL/gl.h>
+#include <GL/internal/dri_interface.h>
+#include "main/context.h"
+#include "main/remap.h"
+
+typedef struct __DRIutilversionRec2 __DRIutilversion2;
+
+struct dri_debug_control {
+ const char * string;
+ unsigned flag;
+};
+
+/**
+ * Description of the API for an extension to OpenGL.
+ */
+struct dri_extension {
+ /**
+ * Name of the extension.
+ */
+ const char * name;
+
+
+ /**
+ * Pointer to a list of \c dri_extension_function structures. The list
+ * is terminated by a structure with a \c NULL
+ * \c dri_extension_function::strings pointer.
+ */
+ const struct gl_function_remap * functions;
+};
+
+/**
+ * Used to store a version which includes a major range instead of a single
+ * major version number.
+ */
+struct __DRIutilversionRec2 {
+ int major_min; /** min allowed Major version number. */
+ int major_max; /** max allowed Major version number. */
+ int minor; /**< Minor version number. */
+ int patch; /**< Patch-level. */
+};
+
+extern void
+__driUtilMessage(const char *f, ...);
+
+extern unsigned driParseDebugString( const char * debug,
+ const struct dri_debug_control * control );
+
+extern unsigned driGetRendererString( char * buffer,
+ const char * hardware_name, const char * driver_date, GLuint agp_mode );
+
+extern void driInitExtensions( struct gl_context * ctx,
+ const struct dri_extension * card_extensions, GLboolean enable_imaging );
+
+extern void driInitSingleExtension( struct gl_context * ctx,
+ const struct dri_extension * ext );
+
+extern GLboolean driCheckDriDdxDrmVersions2(const char * driver_name,
+ const __DRIversion * driActual, const __DRIversion * driExpected,
+ const __DRIversion * ddxActual, const __DRIversion * ddxExpected,
+ const __DRIversion * drmActual, const __DRIversion * drmExpected);
+
+extern GLboolean driCheckDriDdxDrmVersions3(const char * driver_name,
+ const __DRIversion * driActual, const __DRIversion * driExpected,
+ const __DRIversion * ddxActual, const __DRIutilversion2 * ddxExpected,
+ const __DRIversion * drmActual, const __DRIversion * drmExpected);
+
+extern GLboolean driClipRectToFramebuffer( const struct gl_framebuffer *buffer,
+ GLint *x, GLint *y,
+ GLsizei *width, GLsizei *height );
+
+struct __DRIconfigRec {
+ struct gl_config modes;
+};
+
+extern __DRIconfig **
+driCreateConfigs(GLenum fb_format, GLenum fb_type,
+ const uint8_t * depth_bits, const uint8_t * stencil_bits,
+ unsigned num_depth_stencil_bits,
+ const GLenum * db_modes, unsigned num_db_modes,
+ const uint8_t * msaa_samples, unsigned num_msaa_modes,
+ GLboolean enable_accum);
+
+__DRIconfig **driConcatConfigs(__DRIconfig **a,
+ __DRIconfig **b);
+
+int
+driGetConfigAttrib(const __DRIconfig *config,
+ unsigned int attrib, unsigned int *value);
+int
+driIndexConfigAttrib(const __DRIconfig *config, int index,
+ unsigned int *attrib, unsigned int *value);
+
+#endif /* DRI_DEBUG_H */
diff --git a/mesalib/src/mesa/drivers/dri/common/vblank.c b/mesalib/src/mesa/drivers/dri/common/vblank.c index 49b22a2dc..3b8136844 100644 --- a/mesalib/src/mesa/drivers/dri/common/vblank.c +++ b/mesalib/src/mesa/drivers/dri/common/vblank.c @@ -1,434 +1,434 @@ -/* -*- mode: c; c-basic-offset: 3 -*- */ -/* - * (c) Copyright IBM Corporation 2002 - * 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 - * VA LINUX SYSTEM, IBM 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: - * Ian Romanick <idr@us.ibm.com> - */ - -#include "main/glheader.h" -#include "xf86drm.h" -#include "main/mtypes.h" -#include "main/macros.h" -#include "main/dd.h" -#include "vblank.h" -#include "xmlpool.h" - -static unsigned int msc_to_vblank(__DRIdrawable * dPriv, int64_t msc) -{ - return (unsigned int)(msc - dPriv->msc_base + dPriv->vblank_base); -} - -static int64_t vblank_to_msc(__DRIdrawable * dPriv, unsigned int vblank) -{ - return (int64_t)(vblank - dPriv->vblank_base + dPriv->msc_base); -} - - -/****************************************************************************/ -/** - * Get the current MSC refresh counter. - * - * Stores the 64-bit count of vertical refreshes since some (arbitrary) - * point in time in \c count. Unless the value wraps around, which it - * may, it will never decrease for a given drawable. - * - * \warning This function is called from \c glXGetVideoSyncSGI, which expects - * a \c count of type \c unsigned (32-bit), and \c glXGetSyncValuesOML, which - * expects a \c count of type \c int64_t (signed 64-bit). The kernel ioctl - * currently always returns a \c sequence of type \c unsigned. - * - * \param priv Pointer to the DRI screen private struct. - * \param dPriv Pointer to the DRI drawable private struct - * \param count Storage to hold MSC counter. - * \return Zero is returned on success. A negative errno value - * is returned on failure. - */ -int driDrawableGetMSC32( __DRIscreen * priv, - __DRIdrawable * dPriv, - int64_t * count) -{ - drmVBlank vbl; - int ret; - - /* Don't wait for anything. Just get the current refresh count. */ - - vbl.request.type = DRM_VBLANK_RELATIVE; - vbl.request.sequence = 0; - if ( dPriv && dPriv->vblFlags & VBLANK_FLAG_SECONDARY ) - vbl.request.type |= DRM_VBLANK_SECONDARY; - - ret = drmWaitVBlank( priv->fd, &vbl ); - - if (dPriv) { - *count = vblank_to_msc(dPriv, vbl.reply.sequence); - } else { - /* Old driver (no knowledge of drawable MSC callback) */ - *count = vbl.reply.sequence; - } - - return ret; -} - -/****************************************************************************/ -/** - * Wait for a specified refresh count. This implements most of the - * functionality of \c glXWaitForMscOML from the GLX_OML_sync_control spec. - * Waits for the \c target_msc refresh. If that has already passed, it - * waits until \f$(MSC \bmod divisor)\f$ is equal to \c remainder. If - * \c target_msc is 0, use the behavior of glXWaitVideoSyncSGI(), which - * omits the initial check against a target MSC value. - * - * This function is actually something of a hack. The problem is that, at - * the time of this writing, none of the existing DRM modules support an - * ioctl that returns a 64-bit count (at least not on 32-bit platforms). - * However, this function exists to support a GLX function that requires - * the use of 64-bit counts. As such, there is a little bit of ugly - * hackery at the end of this function to make the 32-bit count act like - * a 64-bit count. There are still some cases where this will break, but - * I believe it catches the most common cases. - * - * The real solution is to provide an ioctl that uses a 64-bit count. - * - * \param dpy Pointer to the \c Display. - * \param priv Pointer to the DRI drawable private. - * \param target_msc Desired refresh count to wait for. A value of 0 - * means to use the glXWaitVideoSyncSGI() behavior. - * \param divisor MSC divisor if \c target_msc is already reached. - * \param remainder Desired MSC remainder if \c target_msc is already - * reached. - * \param msc Buffer to hold MSC when done waiting. - * - * \return Zero on success or \c GLX_BAD_CONTEXT on failure. - */ - -int driWaitForMSC32( __DRIdrawable *priv, - int64_t target_msc, int64_t divisor, int64_t remainder, - int64_t * msc ) -{ - drmVBlank vbl; - - - if ( divisor != 0 ) { - int64_t next = target_msc; - int64_t r; - int dont_wait = (target_msc == 0); - - do { - /* dont_wait means we're using the glXWaitVideoSyncSGI() behavior. - * The first time around, just get the current count and proceed - * to the test for (MSC % divisor) == remainder. - */ - vbl.request.type = dont_wait ? DRM_VBLANK_RELATIVE : - DRM_VBLANK_ABSOLUTE; - vbl.request.sequence = next ? msc_to_vblank(priv, next) : 0; - if ( priv->vblFlags & VBLANK_FLAG_SECONDARY ) - vbl.request.type |= DRM_VBLANK_SECONDARY; - - if ( drmWaitVBlank( priv->driScreenPriv->fd, &vbl ) != 0 ) { - /* FIXME: This doesn't seem like the right thing to return here. - */ - return GLX_BAD_CONTEXT; - } - - *msc = vblank_to_msc(priv, vbl.reply.sequence); - - if (!dont_wait && *msc == next) - break; - dont_wait = 0; - - /* Assuming the wait-done test fails, the next refresh to wait for - * will be one that satisfies (MSC % divisor) == remainder. The - * value (MSC - (MSC % divisor) + remainder) is the refresh value - * closest to the current value that would satisfy the equation. - * If this refresh has already happened, we add divisor to obtain - * the next refresh after the current one that will satisfy it. - */ - r = ((uint64_t)*msc % divisor); - next = (*msc - r + remainder); - if (next <= *msc) - next += divisor; - - } while (r != remainder); - } - else { - /* If the \c divisor is zero, just wait until the MSC is greater - * than or equal to \c target_msc. - */ - - vbl.request.type = DRM_VBLANK_ABSOLUTE; - vbl.request.sequence = target_msc ? msc_to_vblank(priv, target_msc) : 0; - - if ( priv->vblFlags & VBLANK_FLAG_SECONDARY ) - vbl.request.type |= DRM_VBLANK_SECONDARY; - - if ( drmWaitVBlank( priv->driScreenPriv->fd, &vbl ) != 0 ) { - /* FIXME: This doesn't seem like the right thing to return here. - */ - return GLX_BAD_CONTEXT; - } - } - - *msc = vblank_to_msc(priv, vbl.reply.sequence); - - if ( *msc < target_msc ) { - *msc += 0x0000000100000000LL; - } - - return 0; -} - - -/****************************************************************************/ -/** - * Gets a set of default vertical-blank-wait flags based on the internal GLX - * API version and several configuration options. - */ - -GLuint driGetDefaultVBlankFlags( const driOptionCache *optionCache ) -{ - GLuint flags = VBLANK_FLAG_INTERVAL; - int vblank_mode; - - - if ( driCheckOption( optionCache, "vblank_mode", DRI_ENUM ) ) - vblank_mode = driQueryOptioni( optionCache, "vblank_mode" ); - else - vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; - - switch (vblank_mode) { - case DRI_CONF_VBLANK_NEVER: - flags = 0; - break; - case DRI_CONF_VBLANK_DEF_INTERVAL_0: - break; - case DRI_CONF_VBLANK_DEF_INTERVAL_1: - flags |= VBLANK_FLAG_THROTTLE; - break; - case DRI_CONF_VBLANK_ALWAYS_SYNC: - flags |= VBLANK_FLAG_SYNC; - break; - } - - return flags; -} - - -/****************************************************************************/ -/** - * Wrapper to call \c drmWaitVBlank. The main purpose of this function is to - * wrap the error message logging. The error message should only be logged - * the first time the \c drmWaitVBlank fails. If \c drmWaitVBlank is - * successful, \c vbl_seq will be set the sequence value in the reply. - * - * \param vbl Pointer to drmVBlank packet desribing how to wait. - * \param vbl_seq Location to store the current refresh counter. - * \param fd File descriptor use to call into the DRM. - * \return Zero on success or -1 on failure. - */ - -static int do_wait( drmVBlank * vbl, GLuint * vbl_seq, int fd ) -{ - int ret; - - - ret = drmWaitVBlank( fd, vbl ); - if ( ret != 0 ) { - static GLboolean first_time = GL_TRUE; - - if ( first_time ) { - fprintf(stderr, - "%s: drmWaitVBlank returned %d, IRQs don't seem to be" - " working correctly.\nTry adjusting the vblank_mode" - " configuration parameter.\n", __FUNCTION__, ret); - first_time = GL_FALSE; - } - - return -1; - } - - *vbl_seq = vbl->reply.sequence; - return 0; -} - - -/****************************************************************************/ -/** - * Returns the default swap interval of the given drawable. - */ - -static unsigned -driGetDefaultVBlankInterval( const __DRIdrawable *priv ) -{ - if ( (priv->vblFlags & (VBLANK_FLAG_THROTTLE | VBLANK_FLAG_SYNC)) != 0 ) { - return 1; - } - else { - return 0; - } -} - - -/****************************************************************************/ -/** - * Sets the default swap interval when the drawable is first bound to a - * direct rendering context. - */ - -void driDrawableInitVBlank( __DRIdrawable *priv ) -{ - if ( priv->swap_interval == (unsigned)-1 && - !( priv->vblFlags & VBLANK_FLAG_NO_IRQ ) ) { - /* Get current vertical blank sequence */ - drmVBlank vbl; - - vbl.request.type = DRM_VBLANK_RELATIVE; - if ( priv->vblFlags & VBLANK_FLAG_SECONDARY ) - vbl.request.type |= DRM_VBLANK_SECONDARY; - vbl.request.sequence = 0; - do_wait( &vbl, &priv->vblSeq, priv->driScreenPriv->fd ); - priv->vblank_base = priv->vblSeq; - - priv->swap_interval = driGetDefaultVBlankInterval( priv ); - } -} - - -/****************************************************************************/ -/** - * Returns the current swap interval of the given drawable. - */ - -unsigned -driGetVBlankInterval( const __DRIdrawable *priv ) -{ - if ( (priv->vblFlags & VBLANK_FLAG_INTERVAL) != 0 ) { - /* this must have been initialized when the drawable was first bound - * to a direct rendering context. */ - assert ( priv->swap_interval != (unsigned)-1 ); - - return priv->swap_interval; - } - else - return driGetDefaultVBlankInterval( priv ); -} - - -/****************************************************************************/ -/** - * Returns the current vertical blank sequence number of the given drawable. - */ - -void -driGetCurrentVBlank( __DRIdrawable *priv ) -{ - drmVBlank vbl; - - vbl.request.type = DRM_VBLANK_RELATIVE; - if ( priv->vblFlags & VBLANK_FLAG_SECONDARY ) { - vbl.request.type |= DRM_VBLANK_SECONDARY; - } - vbl.request.sequence = 0; - - (void) do_wait( &vbl, &priv->vblSeq, priv->driScreenPriv->fd ); -} - - -/****************************************************************************/ -/** - * Waits for the vertical blank for use with glXSwapBuffers. - * - * \param missed_deadline Set to \c GL_TRUE if the MSC after waiting is later - * than the "target" based on \c priv->vblFlags. The idea is - * that if \c missed_deadline is set, then the application is - * not achieving its desired framerate. - * \return Zero on success, -1 on error. - */ - -int -driWaitForVBlank( __DRIdrawable *priv, GLboolean * missed_deadline ) -{ - drmVBlank vbl; - unsigned original_seq; - unsigned deadline; - unsigned interval; - unsigned diff; - - *missed_deadline = GL_FALSE; - if ( (priv->vblFlags & (VBLANK_FLAG_INTERVAL | - VBLANK_FLAG_THROTTLE | - VBLANK_FLAG_SYNC)) == 0 || - (priv->vblFlags & VBLANK_FLAG_NO_IRQ) != 0 ) { - return 0; - } - - - /* VBLANK_FLAG_SYNC means to wait for at least one vertical blank. If - * that flag is not set, do a fake wait for zero vertical blanking - * periods so that we can get the current MSC. - * - * VBLANK_FLAG_INTERVAL and VBLANK_FLAG_THROTTLE mean to wait for at - * least one vertical blank since the last wait. Since do_wait modifies - * priv->vblSeq, we have to save the original value of priv->vblSeq for the - * VBLANK_FLAG_INTERVAL / VBLANK_FLAG_THROTTLE calculation later. - */ - - original_seq = priv->vblSeq; - interval = driGetVBlankInterval(priv); - deadline = original_seq + interval; - - vbl.request.type = DRM_VBLANK_RELATIVE; - if ( priv->vblFlags & VBLANK_FLAG_SECONDARY ) { - vbl.request.type |= DRM_VBLANK_SECONDARY; - } - vbl.request.sequence = ((priv->vblFlags & VBLANK_FLAG_SYNC) != 0) ? 1 : 0; - - if ( do_wait( & vbl, &priv->vblSeq, priv->driScreenPriv->fd ) != 0 ) { - return -1; - } - - diff = priv->vblSeq - deadline; - - /* No need to wait again if we've already reached the target */ - if (diff <= (1 << 23)) { - *missed_deadline = (priv->vblFlags & VBLANK_FLAG_SYNC) ? (diff > 0) : - GL_TRUE; - return 0; - } - - /* Wait until the target vertical blank. */ - vbl.request.type = DRM_VBLANK_ABSOLUTE; - if ( priv->vblFlags & VBLANK_FLAG_SECONDARY ) { - vbl.request.type |= DRM_VBLANK_SECONDARY; - } - vbl.request.sequence = deadline; - - if ( do_wait( & vbl, &priv->vblSeq, priv->driScreenPriv->fd ) != 0 ) { - return -1; - } - - diff = priv->vblSeq - deadline; - *missed_deadline = diff > 0 && diff <= (1 << 23); - - return 0; -} +/* -*- mode: c; c-basic-offset: 3 -*- */
+/*
+ * (c) Copyright IBM Corporation 2002
+ * 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
+ * VA LINUX SYSTEM, IBM 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:
+ * Ian Romanick <idr@us.ibm.com>
+ */
+
+#include "main/glheader.h"
+#include "xf86drm.h"
+#include "main/mtypes.h"
+#include "main/macros.h"
+#include "main/dd.h"
+#include "vblank.h"
+#include "xmlpool.h"
+
+static unsigned int msc_to_vblank(__DRIdrawable * dPriv, int64_t msc)
+{
+ return (unsigned int)(msc - dPriv->msc_base + dPriv->vblank_base);
+}
+
+static int64_t vblank_to_msc(__DRIdrawable * dPriv, unsigned int vblank)
+{
+ return (int64_t)(vblank - dPriv->vblank_base + dPriv->msc_base);
+}
+
+
+/****************************************************************************/
+/**
+ * Get the current MSC refresh counter.
+ *
+ * Stores the 64-bit count of vertical refreshes since some (arbitrary)
+ * point in time in \c count. Unless the value wraps around, which it
+ * may, it will never decrease for a given drawable.
+ *
+ * \warning This function is called from \c glXGetVideoSyncSGI, which expects
+ * a \c count of type \c unsigned (32-bit), and \c glXGetSyncValuesOML, which
+ * expects a \c count of type \c int64_t (signed 64-bit). The kernel ioctl
+ * currently always returns a \c sequence of type \c unsigned.
+ *
+ * \param priv Pointer to the DRI screen private struct.
+ * \param dPriv Pointer to the DRI drawable private struct
+ * \param count Storage to hold MSC counter.
+ * \return Zero is returned on success. A negative errno value
+ * is returned on failure.
+ */
+int driDrawableGetMSC32( __DRIscreen * priv,
+ __DRIdrawable * dPriv,
+ int64_t * count)
+{
+ drmVBlank vbl;
+ int ret;
+
+ /* Don't wait for anything. Just get the current refresh count. */
+
+ vbl.request.type = DRM_VBLANK_RELATIVE;
+ vbl.request.sequence = 0;
+ if ( dPriv && dPriv->vblFlags & VBLANK_FLAG_SECONDARY )
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+
+ ret = drmWaitVBlank( priv->fd, &vbl );
+
+ if (dPriv) {
+ *count = vblank_to_msc(dPriv, vbl.reply.sequence);
+ } else {
+ /* Old driver (no knowledge of drawable MSC callback) */
+ *count = vbl.reply.sequence;
+ }
+
+ return ret;
+}
+
+/****************************************************************************/
+/**
+ * Wait for a specified refresh count. This implements most of the
+ * functionality of \c glXWaitForMscOML from the GLX_OML_sync_control spec.
+ * Waits for the \c target_msc refresh. If that has already passed, it
+ * waits until \f$(MSC \bmod divisor)\f$ is equal to \c remainder. If
+ * \c target_msc is 0, use the behavior of glXWaitVideoSyncSGI(), which
+ * omits the initial check against a target MSC value.
+ *
+ * This function is actually something of a hack. The problem is that, at
+ * the time of this writing, none of the existing DRM modules support an
+ * ioctl that returns a 64-bit count (at least not on 32-bit platforms).
+ * However, this function exists to support a GLX function that requires
+ * the use of 64-bit counts. As such, there is a little bit of ugly
+ * hackery at the end of this function to make the 32-bit count act like
+ * a 64-bit count. There are still some cases where this will break, but
+ * I believe it catches the most common cases.
+ *
+ * The real solution is to provide an ioctl that uses a 64-bit count.
+ *
+ * \param dpy Pointer to the \c Display.
+ * \param priv Pointer to the DRI drawable private.
+ * \param target_msc Desired refresh count to wait for. A value of 0
+ * means to use the glXWaitVideoSyncSGI() behavior.
+ * \param divisor MSC divisor if \c target_msc is already reached.
+ * \param remainder Desired MSC remainder if \c target_msc is already
+ * reached.
+ * \param msc Buffer to hold MSC when done waiting.
+ *
+ * \return Zero on success or \c GLX_BAD_CONTEXT on failure.
+ */
+
+int driWaitForMSC32( __DRIdrawable *priv,
+ int64_t target_msc, int64_t divisor, int64_t remainder,
+ int64_t * msc )
+{
+ drmVBlank vbl;
+
+
+ if ( divisor != 0 ) {
+ int64_t next = target_msc;
+ int64_t r;
+ int dont_wait = (target_msc == 0);
+
+ do {
+ /* dont_wait means we're using the glXWaitVideoSyncSGI() behavior.
+ * The first time around, just get the current count and proceed
+ * to the test for (MSC % divisor) == remainder.
+ */
+ vbl.request.type = dont_wait ? DRM_VBLANK_RELATIVE :
+ DRM_VBLANK_ABSOLUTE;
+ vbl.request.sequence = next ? msc_to_vblank(priv, next) : 0;
+ if ( priv->vblFlags & VBLANK_FLAG_SECONDARY )
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+
+ if ( drmWaitVBlank( priv->driScreenPriv->fd, &vbl ) != 0 ) {
+ /* FIXME: This doesn't seem like the right thing to return here.
+ */
+ return GLX_BAD_CONTEXT;
+ }
+
+ *msc = vblank_to_msc(priv, vbl.reply.sequence);
+
+ if (!dont_wait && *msc == next)
+ break;
+ dont_wait = 0;
+
+ /* Assuming the wait-done test fails, the next refresh to wait for
+ * will be one that satisfies (MSC % divisor) == remainder. The
+ * value (MSC - (MSC % divisor) + remainder) is the refresh value
+ * closest to the current value that would satisfy the equation.
+ * If this refresh has already happened, we add divisor to obtain
+ * the next refresh after the current one that will satisfy it.
+ */
+ r = ((uint64_t)*msc % divisor);
+ next = (*msc - r + remainder);
+ if (next <= *msc)
+ next += divisor;
+
+ } while (r != remainder);
+ }
+ else {
+ /* If the \c divisor is zero, just wait until the MSC is greater
+ * than or equal to \c target_msc.
+ */
+
+ vbl.request.type = DRM_VBLANK_ABSOLUTE;
+ vbl.request.sequence = target_msc ? msc_to_vblank(priv, target_msc) : 0;
+
+ if ( priv->vblFlags & VBLANK_FLAG_SECONDARY )
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+
+ if ( drmWaitVBlank( priv->driScreenPriv->fd, &vbl ) != 0 ) {
+ /* FIXME: This doesn't seem like the right thing to return here.
+ */
+ return GLX_BAD_CONTEXT;
+ }
+ }
+
+ *msc = vblank_to_msc(priv, vbl.reply.sequence);
+
+ if ( *msc < target_msc ) {
+ *msc += 0x0000000100000000LL;
+ }
+
+ return 0;
+}
+
+
+/****************************************************************************/
+/**
+ * Gets a set of default vertical-blank-wait flags based on the internal GLX
+ * API version and several configuration options.
+ */
+
+GLuint driGetDefaultVBlankFlags( const driOptionCache *optionCache )
+{
+ GLuint flags = VBLANK_FLAG_INTERVAL;
+ int vblank_mode;
+
+
+ if ( driCheckOption( optionCache, "vblank_mode", DRI_ENUM ) )
+ vblank_mode = driQueryOptioni( optionCache, "vblank_mode" );
+ else
+ vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
+
+ switch (vblank_mode) {
+ case DRI_CONF_VBLANK_NEVER:
+ flags = 0;
+ break;
+ case DRI_CONF_VBLANK_DEF_INTERVAL_0:
+ break;
+ case DRI_CONF_VBLANK_DEF_INTERVAL_1:
+ flags |= VBLANK_FLAG_THROTTLE;
+ break;
+ case DRI_CONF_VBLANK_ALWAYS_SYNC:
+ flags |= VBLANK_FLAG_SYNC;
+ break;
+ }
+
+ return flags;
+}
+
+
+/****************************************************************************/
+/**
+ * Wrapper to call \c drmWaitVBlank. The main purpose of this function is to
+ * wrap the error message logging. The error message should only be logged
+ * the first time the \c drmWaitVBlank fails. If \c drmWaitVBlank is
+ * successful, \c vbl_seq will be set the sequence value in the reply.
+ *
+ * \param vbl Pointer to drmVBlank packet describing how to wait.
+ * \param vbl_seq Location to store the current refresh counter.
+ * \param fd File descriptor use to call into the DRM.
+ * \return Zero on success or -1 on failure.
+ */
+
+static int do_wait( drmVBlank * vbl, GLuint * vbl_seq, int fd )
+{
+ int ret;
+
+
+ ret = drmWaitVBlank( fd, vbl );
+ if ( ret != 0 ) {
+ static GLboolean first_time = GL_TRUE;
+
+ if ( first_time ) {
+ fprintf(stderr,
+ "%s: drmWaitVBlank returned %d, IRQs don't seem to be"
+ " working correctly.\nTry adjusting the vblank_mode"
+ " configuration parameter.\n", __FUNCTION__, ret);
+ first_time = GL_FALSE;
+ }
+
+ return -1;
+ }
+
+ *vbl_seq = vbl->reply.sequence;
+ return 0;
+}
+
+
+/****************************************************************************/
+/**
+ * Returns the default swap interval of the given drawable.
+ */
+
+static unsigned
+driGetDefaultVBlankInterval( const __DRIdrawable *priv )
+{
+ if ( (priv->vblFlags & (VBLANK_FLAG_THROTTLE | VBLANK_FLAG_SYNC)) != 0 ) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+/****************************************************************************/
+/**
+ * Sets the default swap interval when the drawable is first bound to a
+ * direct rendering context.
+ */
+
+void driDrawableInitVBlank( __DRIdrawable *priv )
+{
+ if ( priv->swap_interval == (unsigned)-1 &&
+ !( priv->vblFlags & VBLANK_FLAG_NO_IRQ ) ) {
+ /* Get current vertical blank sequence */
+ drmVBlank vbl;
+
+ vbl.request.type = DRM_VBLANK_RELATIVE;
+ if ( priv->vblFlags & VBLANK_FLAG_SECONDARY )
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+ vbl.request.sequence = 0;
+ do_wait( &vbl, &priv->vblSeq, priv->driScreenPriv->fd );
+ priv->vblank_base = priv->vblSeq;
+
+ priv->swap_interval = driGetDefaultVBlankInterval( priv );
+ }
+}
+
+
+/****************************************************************************/
+/**
+ * Returns the current swap interval of the given drawable.
+ */
+
+unsigned
+driGetVBlankInterval( const __DRIdrawable *priv )
+{
+ if ( (priv->vblFlags & VBLANK_FLAG_INTERVAL) != 0 ) {
+ /* this must have been initialized when the drawable was first bound
+ * to a direct rendering context. */
+ assert ( priv->swap_interval != (unsigned)-1 );
+
+ return priv->swap_interval;
+ }
+ else
+ return driGetDefaultVBlankInterval( priv );
+}
+
+
+/****************************************************************************/
+/**
+ * Returns the current vertical blank sequence number of the given drawable.
+ */
+
+void
+driGetCurrentVBlank( __DRIdrawable *priv )
+{
+ drmVBlank vbl;
+
+ vbl.request.type = DRM_VBLANK_RELATIVE;
+ if ( priv->vblFlags & VBLANK_FLAG_SECONDARY ) {
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+ }
+ vbl.request.sequence = 0;
+
+ (void) do_wait( &vbl, &priv->vblSeq, priv->driScreenPriv->fd );
+}
+
+
+/****************************************************************************/
+/**
+ * Waits for the vertical blank for use with glXSwapBuffers.
+ *
+ * \param missed_deadline Set to \c GL_TRUE if the MSC after waiting is later
+ * than the "target" based on \c priv->vblFlags. The idea is
+ * that if \c missed_deadline is set, then the application is
+ * not achieving its desired framerate.
+ * \return Zero on success, -1 on error.
+ */
+
+int
+driWaitForVBlank( __DRIdrawable *priv, GLboolean * missed_deadline )
+{
+ drmVBlank vbl;
+ unsigned original_seq;
+ unsigned deadline;
+ unsigned interval;
+ unsigned diff;
+
+ *missed_deadline = GL_FALSE;
+ if ( (priv->vblFlags & (VBLANK_FLAG_INTERVAL |
+ VBLANK_FLAG_THROTTLE |
+ VBLANK_FLAG_SYNC)) == 0 ||
+ (priv->vblFlags & VBLANK_FLAG_NO_IRQ) != 0 ) {
+ return 0;
+ }
+
+
+ /* VBLANK_FLAG_SYNC means to wait for at least one vertical blank. If
+ * that flag is not set, do a fake wait for zero vertical blanking
+ * periods so that we can get the current MSC.
+ *
+ * VBLANK_FLAG_INTERVAL and VBLANK_FLAG_THROTTLE mean to wait for at
+ * least one vertical blank since the last wait. Since do_wait modifies
+ * priv->vblSeq, we have to save the original value of priv->vblSeq for the
+ * VBLANK_FLAG_INTERVAL / VBLANK_FLAG_THROTTLE calculation later.
+ */
+
+ original_seq = priv->vblSeq;
+ interval = driGetVBlankInterval(priv);
+ deadline = original_seq + interval;
+
+ vbl.request.type = DRM_VBLANK_RELATIVE;
+ if ( priv->vblFlags & VBLANK_FLAG_SECONDARY ) {
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+ }
+ vbl.request.sequence = ((priv->vblFlags & VBLANK_FLAG_SYNC) != 0) ? 1 : 0;
+
+ if ( do_wait( & vbl, &priv->vblSeq, priv->driScreenPriv->fd ) != 0 ) {
+ return -1;
+ }
+
+ diff = priv->vblSeq - deadline;
+
+ /* No need to wait again if we've already reached the target */
+ if (diff <= (1 << 23)) {
+ *missed_deadline = (priv->vblFlags & VBLANK_FLAG_SYNC) ? (diff > 0) :
+ GL_TRUE;
+ return 0;
+ }
+
+ /* Wait until the target vertical blank. */
+ vbl.request.type = DRM_VBLANK_ABSOLUTE;
+ if ( priv->vblFlags & VBLANK_FLAG_SECONDARY ) {
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+ }
+ vbl.request.sequence = deadline;
+
+ if ( do_wait( & vbl, &priv->vblSeq, priv->driScreenPriv->fd ) != 0 ) {
+ return -1;
+ }
+
+ diff = priv->vblSeq - deadline;
+ *missed_deadline = diff > 0 && diff <= (1 << 23);
+
+ return 0;
+}
diff --git a/mesalib/src/mesa/drivers/dri/common/vblank.h b/mesalib/src/mesa/drivers/dri/common/vblank.h index 29d1ad800..c46f4ccc3 100644 --- a/mesalib/src/mesa/drivers/dri/common/vblank.h +++ b/mesalib/src/mesa/drivers/dri/common/vblank.h @@ -1,75 +1,71 @@ -/* -*- mode: c; c-basic-offset: 3 -*- */ -/* - * (c) Copyright IBM Corporation 2002 - * 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 - * VA LINUX SYSTEM, IBM 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: - * Ian Romanick <idr@us.ibm.com> - */ - -#ifndef DRI_VBLANK_H -#define DRI_VBLANK_H - -#include "main/context.h" -#include "dri_util.h" -#include "xmlconfig.h" - -#define VBLANK_FLAG_INTERVAL (1U << 0) /* Respect the swap_interval setting - */ -#define VBLANK_FLAG_THROTTLE (1U << 1) /* Wait 1 refresh since last call. - */ -#define VBLANK_FLAG_SYNC (1U << 2) /* Sync to the next refresh. - */ -#define VBLANK_FLAG_NO_IRQ (1U << 7) /* DRM has no IRQ to wait on. - */ -#define VBLANK_FLAG_SECONDARY (1U << 8) /* Wait for secondary vblank. - */ - -extern int driGetMSC32( __DRIscreen * priv, int64_t * count ); -extern int driDrawableGetMSC32( __DRIscreen * priv, - __DRIdrawable * drawablePrivate, - int64_t * count); -extern int driWaitForMSC32( __DRIdrawable *priv, - int64_t target_msc, int64_t divisor, int64_t remainder, int64_t * msc ); -extern GLuint driGetDefaultVBlankFlags( const driOptionCache *optionCache ); -extern void driDrawableInitVBlank ( __DRIdrawable *priv ); -extern unsigned driGetVBlankInterval( const __DRIdrawable *priv ); -extern void driGetCurrentVBlank( __DRIdrawable *priv ); -extern int driWaitForVBlank( __DRIdrawable *priv, - GLboolean * missed_deadline ); - -#undef usleep -#include <unistd.h> /* for usleep() */ -#include <sched.h> /* for sched_yield() */ - -#ifdef linux -#include <sched.h> /* for sched_yield() */ -#endif - -#define DO_USLEEP(nr) \ - do { \ - if (0) fprintf(stderr, "%s: usleep for %u\n", __FUNCTION__, nr ); \ - if (1) usleep( nr ); \ - sched_yield(); \ - } while( 0 ) - -#endif /* DRI_VBLANK_H */ +/* -*- mode: c; c-basic-offset: 3 -*- */
+/*
+ * (c) Copyright IBM Corporation 2002
+ * 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
+ * VA LINUX SYSTEM, IBM 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:
+ * Ian Romanick <idr@us.ibm.com>
+ */
+
+#ifndef DRI_VBLANK_H
+#define DRI_VBLANK_H
+
+#include "main/context.h"
+#include "dri_util.h"
+#include "xmlconfig.h"
+
+#define VBLANK_FLAG_INTERVAL (1U << 0) /* Respect the swap_interval setting
+ */
+#define VBLANK_FLAG_THROTTLE (1U << 1) /* Wait 1 refresh since last call.
+ */
+#define VBLANK_FLAG_SYNC (1U << 2) /* Sync to the next refresh.
+ */
+#define VBLANK_FLAG_NO_IRQ (1U << 7) /* DRM has no IRQ to wait on.
+ */
+#define VBLANK_FLAG_SECONDARY (1U << 8) /* Wait for secondary vblank.
+ */
+
+extern int driGetMSC32( __DRIscreen * priv, int64_t * count );
+extern int driDrawableGetMSC32( __DRIscreen * priv,
+ __DRIdrawable * drawablePrivate,
+ int64_t * count);
+extern int driWaitForMSC32( __DRIdrawable *priv,
+ int64_t target_msc, int64_t divisor, int64_t remainder, int64_t * msc );
+extern GLuint driGetDefaultVBlankFlags( const driOptionCache *optionCache );
+extern void driDrawableInitVBlank ( __DRIdrawable *priv );
+extern unsigned driGetVBlankInterval( const __DRIdrawable *priv );
+extern void driGetCurrentVBlank( __DRIdrawable *priv );
+extern int driWaitForVBlank( __DRIdrawable *priv,
+ GLboolean * missed_deadline );
+
+#undef usleep
+#include <unistd.h> /* for usleep() */
+#include <sched.h> /* for sched_yield() */
+
+#define DO_USLEEP(nr) \
+ do { \
+ if (0) fprintf(stderr, "%s: usleep for %u\n", __FUNCTION__, nr ); \
+ if (1) usleep( nr ); \
+ sched_yield(); \
+ } while( 0 )
+
+#endif /* DRI_VBLANK_H */
diff --git a/mesalib/src/mesa/drivers/dri/common/xmlconfig.c b/mesalib/src/mesa/drivers/dri/common/xmlconfig.c index 738b1ae97..eaba335a4 100644 --- a/mesalib/src/mesa/drivers/dri/common/xmlconfig.c +++ b/mesalib/src/mesa/drivers/dri/common/xmlconfig.c @@ -1,1001 +1,1004 @@ -/* - * XML DRI client-side driver configuration - * Copyright (C) 2003 Felix Kuehling - * - * 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 - * FELIX KUEHLING, OR ANY OTHER CONTRIBUTORS 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 xmlconfig.c - * \brief Driver-independent client-side part of the XML configuration - * \author Felix Kuehling - */ - -#include "main/glheader.h" - -#include <string.h> -#include <assert.h> -#include <expat.h> -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> -#include "main/imports.h" -#include "utils.h" -#include "xmlconfig.h" - -#undef GET_PROGRAM_NAME - -#if (defined(__GNU_LIBRARY__) || defined(__GLIBC__)) && !defined(__UCLIBC__) -# if !defined(__GLIBC__) || (__GLIBC__ < 2) -/* These aren't declared in any libc5 header */ -extern char *program_invocation_name, *program_invocation_short_name; -# endif -# define GET_PROGRAM_NAME() program_invocation_short_name -#elif defined(__FreeBSD__) && (__FreeBSD__ >= 2) -# include <osreldate.h> -# if (__FreeBSD_version >= 440000) -# include <stdlib.h> -# define GET_PROGRAM_NAME() getprogname() -# endif -#elif defined(__NetBSD__) && defined(__NetBSD_Version) && (__NetBSD_Version >= 106000100) -# include <stdlib.h> -# define GET_PROGRAM_NAME() getprogname() -#elif defined(__sun) -/* Solaris has getexecname() which returns the full path - return just - the basename to match BSD getprogname() */ -# include <stdlib.h> -# include <libgen.h> -# define GET_PROGRAM_NAME() basename(getexecname()) -#endif - -#if !defined(GET_PROGRAM_NAME) -# if defined(__OpenBSD__) || defined(NetBSD) || defined(__UCLIBC__) -/* This is a hack. It's said to work on OpenBSD, NetBSD and GNU. - * Rogelio M.Serrano Jr. reported it's also working with UCLIBC. It's - * used as a last resort, if there is no documented facility available. */ -static const char *__getProgramName () { - extern const char *__progname; - char * arg = strrchr(__progname, '/'); - if (arg) - return arg+1; - else - return __progname; -} -# define GET_PROGRAM_NAME() __getProgramName() -# else -# define GET_PROGRAM_NAME() "" -# warning "Per application configuration won't work with your OS version." -# endif -#endif - -/** \brief Find an option in an option cache with the name as key */ -static GLuint findOption (const driOptionCache *cache, const char *name) { - GLuint len = strlen (name); - GLuint size = 1 << cache->tableSize, mask = size - 1; - GLuint hash = 0; - GLuint i, shift; - - /* compute a hash from the variable length name */ - for (i = 0, shift = 0; i < len; ++i, shift = (shift+8) & 31) - hash += (GLuint)name[i] << shift; - hash *= hash; - hash = (hash >> (16-cache->tableSize/2)) & mask; - - /* this is just the starting point of the linear search for the option */ - for (i = 0; i < size; ++i, hash = (hash+1) & mask) { - /* if we hit an empty entry then the option is not defined (yet) */ - if (cache->info[hash].name == 0) - break; - else if (!strcmp (name, cache->info[hash].name)) - break; - } - /* this assertion fails if the hash table is full */ - assert (i < size); - - return hash; -} - -/** \brief Count the real number of options in an option cache */ -static GLuint countOptions (const driOptionCache *cache) { - GLuint size = 1 << cache->tableSize; - GLuint i, count = 0; - for (i = 0; i < size; ++i) - if (cache->info[i].name) - count++; - return count; -} - -/** \brief Like strdup but using MALLOC and with error checking. */ -#define XSTRDUP(dest,source) do { \ - GLuint len = strlen (source); \ - if (!(dest = MALLOC (len+1))) { \ - fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__); \ - abort(); \ - } \ - memcpy (dest, source, len+1); \ -} while (0) - -static int compare (const void *a, const void *b) { - return strcmp (*(char *const*)a, *(char *const*)b); -} -/** \brief Binary search in a string array. */ -static GLuint bsearchStr (const XML_Char *name, - const XML_Char *elems[], GLuint count) { - const XML_Char **found; - found = bsearch (&name, elems, count, sizeof (XML_Char *), compare); - if (found) - return found - elems; - else - return count; -} - -/** \brief Locale-independent integer parser. - * - * Works similar to strtol. Leading space is NOT skipped. The input - * number may have an optional sign. Radix is specified by base. If - * base is 0 then decimal is assumed unless the input number is - * prefixed by 0x or 0X for hexadecimal or 0 for octal. After - * returning tail points to the first character that is not part of - * the integer number. If no number was found then tail points to the - * start of the input string. */ -static GLint strToI (const XML_Char *string, const XML_Char **tail, int base) { - GLint radix = base == 0 ? 10 : base; - GLint result = 0; - GLint sign = 1; - GLboolean numberFound = GL_FALSE; - const XML_Char *start = string; - - assert (radix >= 2 && radix <= 36); - - if (*string == '-') { - sign = -1; - string++; - } else if (*string == '+') - string++; - if (base == 0 && *string == '0') { - numberFound = GL_TRUE; - if (*(string+1) == 'x' || *(string+1) == 'X') { - radix = 16; - string += 2; - } else { - radix = 8; - string++; - } - } - do { - GLint digit = -1; - if (radix <= 10) { - if (*string >= '0' && *string < '0' + radix) - digit = *string - '0'; - } else { - if (*string >= '0' && *string <= '9') - digit = *string - '0'; - else if (*string >= 'a' && *string < 'a' + radix - 10) - digit = *string - 'a' + 10; - else if (*string >= 'A' && *string < 'A' + radix - 10) - digit = *string - 'A' + 10; - } - if (digit != -1) { - numberFound = GL_TRUE; - result = radix*result + digit; - string++; - } else - break; - } while (GL_TRUE); - *tail = numberFound ? string : start; - return sign * result; -} - -/** \brief Locale-independent floating-point parser. - * - * Works similar to strtod. Leading space is NOT skipped. The input - * number may have an optional sign. '.' is interpreted as decimal - * point and may occor at most once. Optionally the number may end in - * [eE]<exponent>, where <exponent> is an integer as recognized by - * strToI. In that case the result is number * 10^exponent. After - * returning tail points to the first character that is not part of - * the floating point number. If no number was found then tail points - * to the start of the input string. - * - * Uses two passes for maximum accuracy. */ -static GLfloat strToF (const XML_Char *string, const XML_Char **tail) { - GLint nDigits = 0, pointPos, exponent; - GLfloat sign = 1.0f, result = 0.0f, scale; - const XML_Char *start = string, *numStart; - - /* sign */ - if (*string == '-') { - sign = -1.0f; - string++; - } else if (*string == '+') - string++; - - /* first pass: determine position of decimal point, number of - * digits, exponent and the end of the number. */ - numStart = string; - while (*string >= '0' && *string <= '9') { - string++; - nDigits++; - } - pointPos = nDigits; - if (*string == '.') { - string++; - while (*string >= '0' && *string <= '9') { - string++; - nDigits++; - } - } - if (nDigits == 0) { - /* no digits, no number */ - *tail = start; - return 0.0f; - } - *tail = string; - if (*string == 'e' || *string == 'E') { - const XML_Char *expTail; - exponent = strToI (string+1, &expTail, 10); - if (expTail == string+1) - exponent = 0; - else - *tail = expTail; - } else - exponent = 0; - string = numStart; - - /* scale of the first digit */ - scale = sign * (GLfloat)pow (10.0, (GLdouble)(pointPos-1 + exponent)); - - /* second pass: parse digits */ - do { - if (*string != '.') { - assert (*string >= '0' && *string <= '9'); - result += scale * (GLfloat)(*string - '0'); - scale *= 0.1f; - nDigits--; - } - string++; - } while (nDigits > 0); - - return result; -} - -/** \brief Parse a value of a given type. */ -static GLboolean parseValue (driOptionValue *v, driOptionType type, - const XML_Char *string) { - const XML_Char *tail = NULL; - /* skip leading white-space */ - string += strspn (string, " \f\n\r\t\v"); - switch (type) { - case DRI_BOOL: - if (!strcmp (string, "false")) { - v->_bool = GL_FALSE; - tail = string + 5; - } else if (!strcmp (string, "true")) { - v->_bool = GL_TRUE; - tail = string + 4; - } - else - return GL_FALSE; - break; - case DRI_ENUM: /* enum is just a special integer */ - case DRI_INT: - v->_int = strToI (string, &tail, 0); - break; - case DRI_FLOAT: - v->_float = strToF (string, &tail); - break; - } - - if (tail == string) - return GL_FALSE; /* empty string (or containing only white-space) */ - /* skip trailing white space */ - if (*tail) - tail += strspn (tail, " \f\n\r\t\v"); - if (*tail) - return GL_FALSE; /* something left over that is not part of value */ - - return GL_TRUE; -} - -/** \brief Parse a list of ranges of type info->type. */ -static GLboolean parseRanges (driOptionInfo *info, const XML_Char *string) { - XML_Char *cp, *range; - GLuint nRanges, i; - driOptionRange *ranges; - - XSTRDUP (cp, string); - /* pass 1: determine the number of ranges (number of commas + 1) */ - range = cp; - for (nRanges = 1; *range; ++range) - if (*range == ',') - ++nRanges; - - if ((ranges = MALLOC (nRanges*sizeof(driOptionRange))) == NULL) { - fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__); - abort(); - } - - /* pass 2: parse all ranges into preallocated array */ - range = cp; - for (i = 0; i < nRanges; ++i) { - XML_Char *end, *sep; - assert (range); - end = strchr (range, ','); - if (end) - *end = '\0'; - sep = strchr (range, ':'); - if (sep) { /* non-empty interval */ - *sep = '\0'; - if (!parseValue (&ranges[i].start, info->type, range) || - !parseValue (&ranges[i].end, info->type, sep+1)) - break; - if (info->type == DRI_INT && - ranges[i].start._int > ranges[i].end._int) - break; - if (info->type == DRI_FLOAT && - ranges[i].start._float > ranges[i].end._float) - break; - } else { /* empty interval */ - if (!parseValue (&ranges[i].start, info->type, range)) - break; - ranges[i].end = ranges[i].start; - } - if (end) - range = end+1; - else - range = NULL; - } - FREE (cp); - if (i < nRanges) { - FREE (ranges); - return GL_FALSE; - } else - assert (range == NULL); - - info->nRanges = nRanges; - info->ranges = ranges; - return GL_TRUE; -} - -/** \brief Check if a value is in one of info->ranges. */ -static GLboolean checkValue (const driOptionValue *v, const driOptionInfo *info) { - GLuint i; - assert (info->type != DRI_BOOL); /* should be caught by the parser */ - if (info->nRanges == 0) - return GL_TRUE; - switch (info->type) { - case DRI_ENUM: /* enum is just a special integer */ - case DRI_INT: - for (i = 0; i < info->nRanges; ++i) - if (v->_int >= info->ranges[i].start._int && - v->_int <= info->ranges[i].end._int) - return GL_TRUE; - break; - case DRI_FLOAT: - for (i = 0; i < info->nRanges; ++i) - if (v->_float >= info->ranges[i].start._float && - v->_float <= info->ranges[i].end._float) - return GL_TRUE; - break; - default: - assert (0); /* should never happen */ - } - return GL_FALSE; -} - -/** \brief Output a warning message. */ -#define XML_WARNING1(msg) do {\ - __driUtilMessage ("Warning in %s line %d, column %d: "msg, data->name, \ - (int) XML_GetCurrentLineNumber(data->parser), \ - (int) XML_GetCurrentColumnNumber(data->parser)); \ -} while (0) -#define XML_WARNING(msg,args...) do { \ - __driUtilMessage ("Warning in %s line %d, column %d: "msg, data->name, \ - (int) XML_GetCurrentLineNumber(data->parser), \ - (int) XML_GetCurrentColumnNumber(data->parser), \ - args); \ -} while (0) -/** \brief Output an error message. */ -#define XML_ERROR1(msg) do { \ - __driUtilMessage ("Error in %s line %d, column %d: "msg, data->name, \ - (int) XML_GetCurrentLineNumber(data->parser), \ - (int) XML_GetCurrentColumnNumber(data->parser)); \ -} while (0) -#define XML_ERROR(msg,args...) do { \ - __driUtilMessage ("Error in %s line %d, column %d: "msg, data->name, \ - (int) XML_GetCurrentLineNumber(data->parser), \ - (int) XML_GetCurrentColumnNumber(data->parser), \ - args); \ -} while (0) -/** \brief Output a fatal error message and abort. */ -#define XML_FATAL1(msg) do { \ - fprintf (stderr, "Fatal error in %s line %d, column %d: "msg"\n", \ - data->name, \ - (int) XML_GetCurrentLineNumber(data->parser), \ - (int) XML_GetCurrentColumnNumber(data->parser)); \ - abort();\ -} while (0) -#define XML_FATAL(msg,args...) do { \ - fprintf (stderr, "Fatal error in %s line %d, column %d: "msg"\n", \ - data->name, \ - (int) XML_GetCurrentLineNumber(data->parser), \ - (int) XML_GetCurrentColumnNumber(data->parser), \ - args); \ - abort();\ -} while (0) - -/** \brief Parser context for __driConfigOptions. */ -struct OptInfoData { - const char *name; - XML_Parser parser; - driOptionCache *cache; - GLboolean inDriInfo; - GLboolean inSection; - GLboolean inDesc; - GLboolean inOption; - GLboolean inEnum; - int curOption; -}; - -/** \brief Elements in __driConfigOptions. */ -enum OptInfoElem { - OI_DESCRIPTION = 0, OI_DRIINFO, OI_ENUM, OI_OPTION, OI_SECTION, OI_COUNT -}; -static const XML_Char *OptInfoElems[] = { - "description", "driinfo", "enum", "option", "section" -}; - -/** \brief Parse attributes of an enum element. - * - * We're not actually interested in the data. Just make sure this is ok - * for external configuration tools. - */ -static void parseEnumAttr (struct OptInfoData *data, const XML_Char **attr) { - GLuint i; - const XML_Char *value = NULL, *text = NULL; - driOptionValue v; - GLuint opt = data->curOption; - for (i = 0; attr[i]; i += 2) { - if (!strcmp (attr[i], "value")) value = attr[i+1]; - else if (!strcmp (attr[i], "text")) text = attr[i+1]; - else XML_FATAL("illegal enum attribute: %s.", attr[i]); - } - if (!value) XML_FATAL1 ("value attribute missing in enum."); - if (!text) XML_FATAL1 ("text attribute missing in enum."); - if (!parseValue (&v, data->cache->info[opt].type, value)) - XML_FATAL ("illegal enum value: %s.", value); - if (!checkValue (&v, &data->cache->info[opt])) - XML_FATAL ("enum value out of valid range: %s.", value); -} - -/** \brief Parse attributes of a description element. - * - * We're not actually interested in the data. Just make sure this is ok - * for external configuration tools. - */ -static void parseDescAttr (struct OptInfoData *data, const XML_Char **attr) { - GLuint i; - const XML_Char *lang = NULL, *text = NULL; - for (i = 0; attr[i]; i += 2) { - if (!strcmp (attr[i], "lang")) lang = attr[i+1]; - else if (!strcmp (attr[i], "text")) text = attr[i+1]; - else XML_FATAL("illegal description attribute: %s.", attr[i]); - } - if (!lang) XML_FATAL1 ("lang attribute missing in description."); - if (!text) XML_FATAL1 ("text attribute missing in description."); -} - -/** \brief Parse attributes of an option element. */ -static void parseOptInfoAttr (struct OptInfoData *data, const XML_Char **attr) { - enum OptAttr {OA_DEFAULT = 0, OA_NAME, OA_TYPE, OA_VALID, OA_COUNT}; - static const XML_Char *optAttr[] = {"default", "name", "type", "valid"}; - const XML_Char *attrVal[OA_COUNT] = {NULL, NULL, NULL, NULL}; - const char *defaultVal; - driOptionCache *cache = data->cache; - GLuint opt, i; - for (i = 0; attr[i]; i += 2) { - GLuint attrName = bsearchStr (attr[i], optAttr, OA_COUNT); - if (attrName >= OA_COUNT) - XML_FATAL ("illegal option attribute: %s", attr[i]); - attrVal[attrName] = attr[i+1]; - } - if (!attrVal[OA_NAME]) XML_FATAL1 ("name attribute missing in option."); - if (!attrVal[OA_TYPE]) XML_FATAL1 ("type attribute missing in option."); - if (!attrVal[OA_DEFAULT]) XML_FATAL1 ("default attribute missing in option."); - - opt = findOption (cache, attrVal[OA_NAME]); - if (cache->info[opt].name) - XML_FATAL ("option %s redefined.", attrVal[OA_NAME]); - data->curOption = opt; - - XSTRDUP (cache->info[opt].name, attrVal[OA_NAME]); - - if (!strcmp (attrVal[OA_TYPE], "bool")) - cache->info[opt].type = DRI_BOOL; - else if (!strcmp (attrVal[OA_TYPE], "enum")) - cache->info[opt].type = DRI_ENUM; - else if (!strcmp (attrVal[OA_TYPE], "int")) - cache->info[opt].type = DRI_INT; - else if (!strcmp (attrVal[OA_TYPE], "float")) - cache->info[opt].type = DRI_FLOAT; - else - XML_FATAL ("illegal type in option: %s.", attrVal[OA_TYPE]); - - defaultVal = getenv (cache->info[opt].name); - if (defaultVal != NULL) { - /* don't use XML_WARNING, we want the user to see this! */ - fprintf (stderr, - "ATTENTION: default value of option %s overridden by environment.\n", - cache->info[opt].name); - } else - defaultVal = attrVal[OA_DEFAULT]; - if (!parseValue (&cache->values[opt], cache->info[opt].type, defaultVal)) - XML_FATAL ("illegal default value: %s.", defaultVal); - - if (attrVal[OA_VALID]) { - if (cache->info[opt].type == DRI_BOOL) - XML_FATAL1 ("boolean option with valid attribute."); - if (!parseRanges (&cache->info[opt], attrVal[OA_VALID])) - XML_FATAL ("illegal valid attribute: %s.", attrVal[OA_VALID]); - if (!checkValue (&cache->values[opt], &cache->info[opt])) - XML_FATAL ("default value out of valid range '%s': %s.", - attrVal[OA_VALID], defaultVal); - } else if (cache->info[opt].type == DRI_ENUM) { - XML_FATAL1 ("valid attribute missing in option (mandatory for enums)."); - } else { - cache->info[opt].nRanges = 0; - cache->info[opt].ranges = NULL; - } -} - -/** \brief Handler for start element events. */ -static void optInfoStartElem (void *userData, const XML_Char *name, - const XML_Char **attr) { - struct OptInfoData *data = (struct OptInfoData *)userData; - enum OptInfoElem elem = bsearchStr (name, OptInfoElems, OI_COUNT); - switch (elem) { - case OI_DRIINFO: - if (data->inDriInfo) - XML_FATAL1 ("nested <driinfo> elements."); - if (attr[0]) - XML_FATAL1 ("attributes specified on <driinfo> element."); - data->inDriInfo = GL_TRUE; - break; - case OI_SECTION: - if (!data->inDriInfo) - XML_FATAL1 ("<section> must be inside <driinfo>."); - if (data->inSection) - XML_FATAL1 ("nested <section> elements."); - if (attr[0]) - XML_FATAL1 ("attributes specified on <section> element."); - data->inSection = GL_TRUE; - break; - case OI_DESCRIPTION: - if (!data->inSection && !data->inOption) - XML_FATAL1 ("<description> must be inside <description> or <option."); - if (data->inDesc) - XML_FATAL1 ("nested <description> elements."); - data->inDesc = GL_TRUE; - parseDescAttr (data, attr); - break; - case OI_OPTION: - if (!data->inSection) - XML_FATAL1 ("<option> must be inside <section>."); - if (data->inDesc) - XML_FATAL1 ("<option> nested in <description> element."); - if (data->inOption) - XML_FATAL1 ("nested <option> elements."); - data->inOption = GL_TRUE; - parseOptInfoAttr (data, attr); - break; - case OI_ENUM: - if (!(data->inOption && data->inDesc)) - XML_FATAL1 ("<enum> must be inside <option> and <description>."); - if (data->inEnum) - XML_FATAL1 ("nested <enum> elements."); - data->inEnum = GL_TRUE; - parseEnumAttr (data, attr); - break; - default: - XML_FATAL ("unknown element: %s.", name); - } -} - -/** \brief Handler for end element events. */ -static void optInfoEndElem (void *userData, const XML_Char *name) { - struct OptInfoData *data = (struct OptInfoData *)userData; - enum OptInfoElem elem = bsearchStr (name, OptInfoElems, OI_COUNT); - switch (elem) { - case OI_DRIINFO: - data->inDriInfo = GL_FALSE; - break; - case OI_SECTION: - data->inSection = GL_FALSE; - break; - case OI_DESCRIPTION: - data->inDesc = GL_FALSE; - break; - case OI_OPTION: - data->inOption = GL_FALSE; - break; - case OI_ENUM: - data->inEnum = GL_FALSE; - break; - default: - assert (0); /* should have been caught by StartElem */ - } -} - -void driParseOptionInfo (driOptionCache *info, - const char *configOptions, GLuint nConfigOptions) { - XML_Parser p; - int status; - struct OptInfoData userData; - struct OptInfoData *data = &userData; - GLuint realNoptions; - - /* determine hash table size and allocate memory: - * 3/2 of the number of options, rounded up, so there remains always - * at least one free entry. This is needed for detecting undefined - * options in configuration files without getting a hash table overflow. - * Round this up to a power of two. */ - GLuint minSize = (nConfigOptions*3 + 1) / 2; - GLuint size, log2size; - for (size = 1, log2size = 0; size < minSize; size <<= 1, ++log2size); - info->tableSize = log2size; - info->info = CALLOC (size * sizeof (driOptionInfo)); - info->values = CALLOC (size * sizeof (driOptionValue)); - if (info->info == NULL || info->values == NULL) { - fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__); - abort(); - } - - p = XML_ParserCreate ("UTF-8"); /* always UTF-8 */ - XML_SetElementHandler (p, optInfoStartElem, optInfoEndElem); - XML_SetUserData (p, data); - - userData.name = "__driConfigOptions"; - userData.parser = p; - userData.cache = info; - userData.inDriInfo = GL_FALSE; - userData.inSection = GL_FALSE; - userData.inDesc = GL_FALSE; - userData.inOption = GL_FALSE; - userData.inEnum = GL_FALSE; - userData.curOption = -1; - - status = XML_Parse (p, configOptions, strlen (configOptions), 1); - if (!status) - XML_FATAL ("%s.", XML_ErrorString(XML_GetErrorCode(p))); - - XML_ParserFree (p); - - /* Check if the actual number of options matches nConfigOptions. - * A mismatch is not fatal (a hash table overflow would be) but we - * want the driver developer's attention anyway. */ - realNoptions = countOptions (info); - if (realNoptions != nConfigOptions) { - fprintf (stderr, - "Error: nConfigOptions (%u) does not match the actual number of options in\n" - " __driConfigOptions (%u).\n", - nConfigOptions, realNoptions); - } -} - -/** \brief Parser context for configuration files. */ -struct OptConfData { - const char *name; - XML_Parser parser; - driOptionCache *cache; - GLint screenNum; - const char *driverName, *execName; - GLuint ignoringDevice; - GLuint ignoringApp; - GLuint inDriConf; - GLuint inDevice; - GLuint inApp; - GLuint inOption; -}; - -/** \brief Elements in configuration files. */ -enum OptConfElem { - OC_APPLICATION = 0, OC_DEVICE, OC_DRICONF, OC_OPTION, OC_COUNT -}; -static const XML_Char *OptConfElems[] = { - "application", "device", "driconf", "option" -}; - -/** \brief Parse attributes of a device element. */ -static void parseDeviceAttr (struct OptConfData *data, const XML_Char **attr) { - GLuint i; - const XML_Char *driver = NULL, *screen = NULL; - for (i = 0; attr[i]; i += 2) { - if (!strcmp (attr[i], "driver")) driver = attr[i+1]; - else if (!strcmp (attr[i], "screen")) screen = attr[i+1]; - else XML_WARNING("unkown device attribute: %s.", attr[i]); - } - if (driver && strcmp (driver, data->driverName)) - data->ignoringDevice = data->inDevice; - else if (screen) { - driOptionValue screenNum; - if (!parseValue (&screenNum, DRI_INT, screen)) - XML_WARNING("illegal screen number: %s.", screen); - else if (screenNum._int != data->screenNum) - data->ignoringDevice = data->inDevice; - } -} - -/** \brief Parse attributes of an application element. */ -static void parseAppAttr (struct OptConfData *data, const XML_Char **attr) { - GLuint i; - const XML_Char *name = NULL, *exec = NULL; - for (i = 0; attr[i]; i += 2) { - if (!strcmp (attr[i], "name")) name = attr[i+1]; - else if (!strcmp (attr[i], "executable")) exec = attr[i+1]; - else XML_WARNING("unkown application attribute: %s.", attr[i]); - } - if (exec && strcmp (exec, data->execName)) - data->ignoringApp = data->inApp; -} - -/** \brief Parse attributes of an option element. */ -static void parseOptConfAttr (struct OptConfData *data, const XML_Char **attr) { - GLuint i; - const XML_Char *name = NULL, *value = NULL; - for (i = 0; attr[i]; i += 2) { - if (!strcmp (attr[i], "name")) name = attr[i+1]; - else if (!strcmp (attr[i], "value")) value = attr[i+1]; - else XML_WARNING("unkown option attribute: %s.", attr[i]); - } - if (!name) XML_WARNING1 ("name attribute missing in option."); - if (!value) XML_WARNING1 ("value attribute missing in option."); - if (name && value) { - driOptionCache *cache = data->cache; - GLuint opt = findOption (cache, name); - if (cache->info[opt].name == NULL) - XML_WARNING ("undefined option: %s.", name); - else if (getenv (cache->info[opt].name)) - /* don't use XML_WARNING, we want the user to see this! */ - fprintf (stderr, "ATTENTION: option value of option %s ignored.\n", - cache->info[opt].name); - else if (!parseValue (&cache->values[opt], cache->info[opt].type, value)) - XML_WARNING ("illegal option value: %s.", value); - } -} - -/** \brief Handler for start element events. */ -static void optConfStartElem (void *userData, const XML_Char *name, - const XML_Char **attr) { - struct OptConfData *data = (struct OptConfData *)userData; - enum OptConfElem elem = bsearchStr (name, OptConfElems, OC_COUNT); - switch (elem) { - case OC_DRICONF: - if (data->inDriConf) - XML_WARNING1 ("nested <driconf> elements."); - if (attr[0]) - XML_WARNING1 ("attributes specified on <driconf> element."); - data->inDriConf++; - break; - case OC_DEVICE: - if (!data->inDriConf) - XML_WARNING1 ("<device> should be inside <driconf>."); - if (data->inDevice) - XML_WARNING1 ("nested <device> elements."); - data->inDevice++; - if (!data->ignoringDevice && !data->ignoringApp) - parseDeviceAttr (data, attr); - break; - case OC_APPLICATION: - if (!data->inDevice) - XML_WARNING1 ("<application> should be inside <device>."); - if (data->inApp) - XML_WARNING1 ("nested <application> elements."); - data->inApp++; - if (!data->ignoringDevice && !data->ignoringApp) - parseAppAttr (data, attr); - break; - case OC_OPTION: - if (!data->inApp) - XML_WARNING1 ("<option> should be inside <application>."); - if (data->inOption) - XML_WARNING1 ("nested <option> elements."); - data->inOption++; - if (!data->ignoringDevice && !data->ignoringApp) - parseOptConfAttr (data, attr); - break; - default: - XML_WARNING ("unknown element: %s.", name); - } -} - -/** \brief Handler for end element events. */ -static void optConfEndElem (void *userData, const XML_Char *name) { - struct OptConfData *data = (struct OptConfData *)userData; - enum OptConfElem elem = bsearchStr (name, OptConfElems, OC_COUNT); - switch (elem) { - case OC_DRICONF: - data->inDriConf--; - break; - case OC_DEVICE: - if (data->inDevice-- == data->ignoringDevice) - data->ignoringDevice = 0; - break; - case OC_APPLICATION: - if (data->inApp-- == data->ignoringApp) - data->ignoringApp = 0; - break; - case OC_OPTION: - data->inOption--; - break; - default: - /* unknown element, warning was produced on start tag */; - } -} - -/** \brief Initialize an option cache based on info */ -static void initOptionCache (driOptionCache *cache, const driOptionCache *info) { - cache->info = info->info; - cache->tableSize = info->tableSize; - cache->values = MALLOC ((1<<info->tableSize) * sizeof (driOptionValue)); - if (cache->values == NULL) { - fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__); - abort(); - } - memcpy (cache->values, info->values, - (1<<info->tableSize) * sizeof (driOptionValue)); -} - -/** \brief Parse the named configuration file */ -static void parseOneConfigFile (XML_Parser p) { -#define BUF_SIZE 0x1000 - struct OptConfData *data = (struct OptConfData *)XML_GetUserData (p); - int status; - int fd; - - if ((fd = open (data->name, O_RDONLY)) == -1) { - __driUtilMessage ("Can't open configuration file %s: %s.", - data->name, strerror (errno)); - return; - } - - while (1) { - int bytesRead; - void *buffer = XML_GetBuffer (p, BUF_SIZE); - if (!buffer) { - __driUtilMessage ("Can't allocate parser buffer."); - break; - } - bytesRead = read (fd, buffer, BUF_SIZE); - if (bytesRead == -1) { - __driUtilMessage ("Error reading from configuration file %s: %s.", - data->name, strerror (errno)); - break; - } - status = XML_ParseBuffer (p, bytesRead, bytesRead == 0); - if (!status) { - XML_ERROR ("%s.", XML_ErrorString(XML_GetErrorCode(p))); - break; - } - if (bytesRead == 0) - break; - } - - close (fd); -#undef BUF_SIZE -} - -void driParseConfigFiles (driOptionCache *cache, const driOptionCache *info, - GLint screenNum, const char *driverName) { - char *filenames[2] = {"/etc/drirc", NULL}; - char *home; - GLuint i; - struct OptConfData userData; - - initOptionCache (cache, info); - - userData.cache = cache; - userData.screenNum = screenNum; - userData.driverName = driverName; - userData.execName = GET_PROGRAM_NAME(); - - if ((home = getenv ("HOME"))) { - GLuint len = strlen (home); - filenames[1] = MALLOC (len + 7+1); - if (filenames[1] == NULL) - __driUtilMessage ("Can't allocate memory for %s/.drirc.", home); - else { - memcpy (filenames[1], home, len); - memcpy (filenames[1] + len, "/.drirc", 7+1); - } - } - - for (i = 0; i < 2; ++i) { - XML_Parser p; - if (filenames[i] == NULL) - continue; - - p = XML_ParserCreate (NULL); /* use encoding specified by file */ - XML_SetElementHandler (p, optConfStartElem, optConfEndElem); - XML_SetUserData (p, &userData); - userData.parser = p; - userData.name = filenames[i]; - userData.ignoringDevice = 0; - userData.ignoringApp = 0; - userData.inDriConf = 0; - userData.inDevice = 0; - userData.inApp = 0; - userData.inOption = 0; - - parseOneConfigFile (p); - XML_ParserFree (p); - } - - if (filenames[1]) - FREE (filenames[1]); -} - -void driDestroyOptionInfo (driOptionCache *info) { - driDestroyOptionCache (info); - if (info->info) { - GLuint i, size = 1 << info->tableSize; - for (i = 0; i < size; ++i) { - if (info->info[i].name) { - FREE (info->info[i].name); - if (info->info[i].ranges) - FREE (info->info[i].ranges); - } - } - FREE (info->info); - } -} - -void driDestroyOptionCache (driOptionCache *cache) { - if (cache->values) - FREE (cache->values); -} - -GLboolean driCheckOption (const driOptionCache *cache, const char *name, - driOptionType type) { - GLuint i = findOption (cache, name); - return cache->info[i].name != NULL && cache->info[i].type == type; -} - -GLboolean driQueryOptionb (const driOptionCache *cache, const char *name) { - GLuint i = findOption (cache, name); - /* make sure the option is defined and has the correct type */ - assert (cache->info[i].name != NULL); - assert (cache->info[i].type == DRI_BOOL); - return cache->values[i]._bool; -} - -GLint driQueryOptioni (const driOptionCache *cache, const char *name) { - GLuint i = findOption (cache, name); - /* make sure the option is defined and has the correct type */ - assert (cache->info[i].name != NULL); - assert (cache->info[i].type == DRI_INT || cache->info[i].type == DRI_ENUM); - return cache->values[i]._int; -} - -GLfloat driQueryOptionf (const driOptionCache *cache, const char *name) { - GLuint i = findOption (cache, name); - /* make sure the option is defined and has the correct type */ - assert (cache->info[i].name != NULL); - assert (cache->info[i].type == DRI_FLOAT); - return cache->values[i]._float; -} +/*
+ * XML DRI client-side driver configuration
+ * Copyright (C) 2003 Felix Kuehling
+ *
+ * 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
+ * FELIX KUEHLING, OR ANY OTHER CONTRIBUTORS 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 xmlconfig.c
+ * \brief Driver-independent client-side part of the XML configuration
+ * \author Felix Kuehling
+ */
+
+#include "main/glheader.h"
+
+#include <string.h>
+#include <assert.h>
+#include <expat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include "main/imports.h"
+#include "utils.h"
+#include "xmlconfig.h"
+
+#undef GET_PROGRAM_NAME
+
+#if (defined(__GNU_LIBRARY__) || defined(__GLIBC__)) && !defined(__UCLIBC__)
+# if !defined(__GLIBC__) || (__GLIBC__ < 2)
+/* These aren't declared in any libc5 header */
+extern char *program_invocation_name, *program_invocation_short_name;
+# endif
+# define GET_PROGRAM_NAME() program_invocation_short_name
+#elif defined(__FreeBSD__) && (__FreeBSD__ >= 2)
+# include <osreldate.h>
+# if (__FreeBSD_version >= 440000)
+# include <stdlib.h>
+# define GET_PROGRAM_NAME() getprogname()
+# endif
+#elif defined(__NetBSD__) && defined(__NetBSD_Version) && (__NetBSD_Version >= 106000100)
+# include <stdlib.h>
+# define GET_PROGRAM_NAME() getprogname()
+#elif defined(__APPLE__)
+# include <stdlib.h>
+# define GET_PROGRAM_NAME() getprogname()
+#elif defined(__sun)
+/* Solaris has getexecname() which returns the full path - return just
+ the basename to match BSD getprogname() */
+# include <stdlib.h>
+# include <libgen.h>
+# define GET_PROGRAM_NAME() basename(getexecname())
+#endif
+
+#if !defined(GET_PROGRAM_NAME)
+# if defined(__OpenBSD__) || defined(NetBSD) || defined(__UCLIBC__)
+/* This is a hack. It's said to work on OpenBSD, NetBSD and GNU.
+ * Rogelio M.Serrano Jr. reported it's also working with UCLIBC. It's
+ * used as a last resort, if there is no documented facility available. */
+static const char *__getProgramName () {
+ extern const char *__progname;
+ char * arg = strrchr(__progname, '/');
+ if (arg)
+ return arg+1;
+ else
+ return __progname;
+}
+# define GET_PROGRAM_NAME() __getProgramName()
+# else
+# define GET_PROGRAM_NAME() ""
+# warning "Per application configuration won't work with your OS version."
+# endif
+#endif
+
+/** \brief Find an option in an option cache with the name as key */
+static GLuint findOption (const driOptionCache *cache, const char *name) {
+ GLuint len = strlen (name);
+ GLuint size = 1 << cache->tableSize, mask = size - 1;
+ GLuint hash = 0;
+ GLuint i, shift;
+
+ /* compute a hash from the variable length name */
+ for (i = 0, shift = 0; i < len; ++i, shift = (shift+8) & 31)
+ hash += (GLuint)name[i] << shift;
+ hash *= hash;
+ hash = (hash >> (16-cache->tableSize/2)) & mask;
+
+ /* this is just the starting point of the linear search for the option */
+ for (i = 0; i < size; ++i, hash = (hash+1) & mask) {
+ /* if we hit an empty entry then the option is not defined (yet) */
+ if (cache->info[hash].name == 0)
+ break;
+ else if (!strcmp (name, cache->info[hash].name))
+ break;
+ }
+ /* this assertion fails if the hash table is full */
+ assert (i < size);
+
+ return hash;
+}
+
+/** \brief Count the real number of options in an option cache */
+static GLuint countOptions (const driOptionCache *cache) {
+ GLuint size = 1 << cache->tableSize;
+ GLuint i, count = 0;
+ for (i = 0; i < size; ++i)
+ if (cache->info[i].name)
+ count++;
+ return count;
+}
+
+/** \brief Like strdup but using MALLOC and with error checking. */
+#define XSTRDUP(dest,source) do { \
+ GLuint len = strlen (source); \
+ if (!(dest = MALLOC (len+1))) { \
+ fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__); \
+ abort(); \
+ } \
+ memcpy (dest, source, len+1); \
+} while (0)
+
+static int compare (const void *a, const void *b) {
+ return strcmp (*(char *const*)a, *(char *const*)b);
+}
+/** \brief Binary search in a string array. */
+static GLuint bsearchStr (const XML_Char *name,
+ const XML_Char *elems[], GLuint count) {
+ const XML_Char **found;
+ found = bsearch (&name, elems, count, sizeof (XML_Char *), compare);
+ if (found)
+ return found - elems;
+ else
+ return count;
+}
+
+/** \brief Locale-independent integer parser.
+ *
+ * Works similar to strtol. Leading space is NOT skipped. The input
+ * number may have an optional sign. Radix is specified by base. If
+ * base is 0 then decimal is assumed unless the input number is
+ * prefixed by 0x or 0X for hexadecimal or 0 for octal. After
+ * returning tail points to the first character that is not part of
+ * the integer number. If no number was found then tail points to the
+ * start of the input string. */
+static GLint strToI (const XML_Char *string, const XML_Char **tail, int base) {
+ GLint radix = base == 0 ? 10 : base;
+ GLint result = 0;
+ GLint sign = 1;
+ GLboolean numberFound = GL_FALSE;
+ const XML_Char *start = string;
+
+ assert (radix >= 2 && radix <= 36);
+
+ if (*string == '-') {
+ sign = -1;
+ string++;
+ } else if (*string == '+')
+ string++;
+ if (base == 0 && *string == '0') {
+ numberFound = GL_TRUE;
+ if (*(string+1) == 'x' || *(string+1) == 'X') {
+ radix = 16;
+ string += 2;
+ } else {
+ radix = 8;
+ string++;
+ }
+ }
+ do {
+ GLint digit = -1;
+ if (radix <= 10) {
+ if (*string >= '0' && *string < '0' + radix)
+ digit = *string - '0';
+ } else {
+ if (*string >= '0' && *string <= '9')
+ digit = *string - '0';
+ else if (*string >= 'a' && *string < 'a' + radix - 10)
+ digit = *string - 'a' + 10;
+ else if (*string >= 'A' && *string < 'A' + radix - 10)
+ digit = *string - 'A' + 10;
+ }
+ if (digit != -1) {
+ numberFound = GL_TRUE;
+ result = radix*result + digit;
+ string++;
+ } else
+ break;
+ } while (GL_TRUE);
+ *tail = numberFound ? string : start;
+ return sign * result;
+}
+
+/** \brief Locale-independent floating-point parser.
+ *
+ * Works similar to strtod. Leading space is NOT skipped. The input
+ * number may have an optional sign. '.' is interpreted as decimal
+ * point and may occur at most once. Optionally the number may end in
+ * [eE]<exponent>, where <exponent> is an integer as recognized by
+ * strToI. In that case the result is number * 10^exponent. After
+ * returning tail points to the first character that is not part of
+ * the floating point number. If no number was found then tail points
+ * to the start of the input string.
+ *
+ * Uses two passes for maximum accuracy. */
+static GLfloat strToF (const XML_Char *string, const XML_Char **tail) {
+ GLint nDigits = 0, pointPos, exponent;
+ GLfloat sign = 1.0f, result = 0.0f, scale;
+ const XML_Char *start = string, *numStart;
+
+ /* sign */
+ if (*string == '-') {
+ sign = -1.0f;
+ string++;
+ } else if (*string == '+')
+ string++;
+
+ /* first pass: determine position of decimal point, number of
+ * digits, exponent and the end of the number. */
+ numStart = string;
+ while (*string >= '0' && *string <= '9') {
+ string++;
+ nDigits++;
+ }
+ pointPos = nDigits;
+ if (*string == '.') {
+ string++;
+ while (*string >= '0' && *string <= '9') {
+ string++;
+ nDigits++;
+ }
+ }
+ if (nDigits == 0) {
+ /* no digits, no number */
+ *tail = start;
+ return 0.0f;
+ }
+ *tail = string;
+ if (*string == 'e' || *string == 'E') {
+ const XML_Char *expTail;
+ exponent = strToI (string+1, &expTail, 10);
+ if (expTail == string+1)
+ exponent = 0;
+ else
+ *tail = expTail;
+ } else
+ exponent = 0;
+ string = numStart;
+
+ /* scale of the first digit */
+ scale = sign * (GLfloat)pow (10.0, (GLdouble)(pointPos-1 + exponent));
+
+ /* second pass: parse digits */
+ do {
+ if (*string != '.') {
+ assert (*string >= '0' && *string <= '9');
+ result += scale * (GLfloat)(*string - '0');
+ scale *= 0.1f;
+ nDigits--;
+ }
+ string++;
+ } while (nDigits > 0);
+
+ return result;
+}
+
+/** \brief Parse a value of a given type. */
+static GLboolean parseValue (driOptionValue *v, driOptionType type,
+ const XML_Char *string) {
+ const XML_Char *tail = NULL;
+ /* skip leading white-space */
+ string += strspn (string, " \f\n\r\t\v");
+ switch (type) {
+ case DRI_BOOL:
+ if (!strcmp (string, "false")) {
+ v->_bool = GL_FALSE;
+ tail = string + 5;
+ } else if (!strcmp (string, "true")) {
+ v->_bool = GL_TRUE;
+ tail = string + 4;
+ }
+ else
+ return GL_FALSE;
+ break;
+ case DRI_ENUM: /* enum is just a special integer */
+ case DRI_INT:
+ v->_int = strToI (string, &tail, 0);
+ break;
+ case DRI_FLOAT:
+ v->_float = strToF (string, &tail);
+ break;
+ }
+
+ if (tail == string)
+ return GL_FALSE; /* empty string (or containing only white-space) */
+ /* skip trailing white space */
+ if (*tail)
+ tail += strspn (tail, " \f\n\r\t\v");
+ if (*tail)
+ return GL_FALSE; /* something left over that is not part of value */
+
+ return GL_TRUE;
+}
+
+/** \brief Parse a list of ranges of type info->type. */
+static GLboolean parseRanges (driOptionInfo *info, const XML_Char *string) {
+ XML_Char *cp, *range;
+ GLuint nRanges, i;
+ driOptionRange *ranges;
+
+ XSTRDUP (cp, string);
+ /* pass 1: determine the number of ranges (number of commas + 1) */
+ range = cp;
+ for (nRanges = 1; *range; ++range)
+ if (*range == ',')
+ ++nRanges;
+
+ if ((ranges = MALLOC (nRanges*sizeof(driOptionRange))) == NULL) {
+ fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
+ abort();
+ }
+
+ /* pass 2: parse all ranges into preallocated array */
+ range = cp;
+ for (i = 0; i < nRanges; ++i) {
+ XML_Char *end, *sep;
+ assert (range);
+ end = strchr (range, ',');
+ if (end)
+ *end = '\0';
+ sep = strchr (range, ':');
+ if (sep) { /* non-empty interval */
+ *sep = '\0';
+ if (!parseValue (&ranges[i].start, info->type, range) ||
+ !parseValue (&ranges[i].end, info->type, sep+1))
+ break;
+ if (info->type == DRI_INT &&
+ ranges[i].start._int > ranges[i].end._int)
+ break;
+ if (info->type == DRI_FLOAT &&
+ ranges[i].start._float > ranges[i].end._float)
+ break;
+ } else { /* empty interval */
+ if (!parseValue (&ranges[i].start, info->type, range))
+ break;
+ ranges[i].end = ranges[i].start;
+ }
+ if (end)
+ range = end+1;
+ else
+ range = NULL;
+ }
+ FREE (cp);
+ if (i < nRanges) {
+ FREE (ranges);
+ return GL_FALSE;
+ } else
+ assert (range == NULL);
+
+ info->nRanges = nRanges;
+ info->ranges = ranges;
+ return GL_TRUE;
+}
+
+/** \brief Check if a value is in one of info->ranges. */
+static GLboolean checkValue (const driOptionValue *v, const driOptionInfo *info) {
+ GLuint i;
+ assert (info->type != DRI_BOOL); /* should be caught by the parser */
+ if (info->nRanges == 0)
+ return GL_TRUE;
+ switch (info->type) {
+ case DRI_ENUM: /* enum is just a special integer */
+ case DRI_INT:
+ for (i = 0; i < info->nRanges; ++i)
+ if (v->_int >= info->ranges[i].start._int &&
+ v->_int <= info->ranges[i].end._int)
+ return GL_TRUE;
+ break;
+ case DRI_FLOAT:
+ for (i = 0; i < info->nRanges; ++i)
+ if (v->_float >= info->ranges[i].start._float &&
+ v->_float <= info->ranges[i].end._float)
+ return GL_TRUE;
+ break;
+ default:
+ assert (0); /* should never happen */
+ }
+ return GL_FALSE;
+}
+
+/** \brief Output a warning message. */
+#define XML_WARNING1(msg) do {\
+ __driUtilMessage ("Warning in %s line %d, column %d: "msg, data->name, \
+ (int) XML_GetCurrentLineNumber(data->parser), \
+ (int) XML_GetCurrentColumnNumber(data->parser)); \
+} while (0)
+#define XML_WARNING(msg,args...) do { \
+ __driUtilMessage ("Warning in %s line %d, column %d: "msg, data->name, \
+ (int) XML_GetCurrentLineNumber(data->parser), \
+ (int) XML_GetCurrentColumnNumber(data->parser), \
+ args); \
+} while (0)
+/** \brief Output an error message. */
+#define XML_ERROR1(msg) do { \
+ __driUtilMessage ("Error in %s line %d, column %d: "msg, data->name, \
+ (int) XML_GetCurrentLineNumber(data->parser), \
+ (int) XML_GetCurrentColumnNumber(data->parser)); \
+} while (0)
+#define XML_ERROR(msg,args...) do { \
+ __driUtilMessage ("Error in %s line %d, column %d: "msg, data->name, \
+ (int) XML_GetCurrentLineNumber(data->parser), \
+ (int) XML_GetCurrentColumnNumber(data->parser), \
+ args); \
+} while (0)
+/** \brief Output a fatal error message and abort. */
+#define XML_FATAL1(msg) do { \
+ fprintf (stderr, "Fatal error in %s line %d, column %d: "msg"\n", \
+ data->name, \
+ (int) XML_GetCurrentLineNumber(data->parser), \
+ (int) XML_GetCurrentColumnNumber(data->parser)); \
+ abort();\
+} while (0)
+#define XML_FATAL(msg,args...) do { \
+ fprintf (stderr, "Fatal error in %s line %d, column %d: "msg"\n", \
+ data->name, \
+ (int) XML_GetCurrentLineNumber(data->parser), \
+ (int) XML_GetCurrentColumnNumber(data->parser), \
+ args); \
+ abort();\
+} while (0)
+
+/** \brief Parser context for __driConfigOptions. */
+struct OptInfoData {
+ const char *name;
+ XML_Parser parser;
+ driOptionCache *cache;
+ GLboolean inDriInfo;
+ GLboolean inSection;
+ GLboolean inDesc;
+ GLboolean inOption;
+ GLboolean inEnum;
+ int curOption;
+};
+
+/** \brief Elements in __driConfigOptions. */
+enum OptInfoElem {
+ OI_DESCRIPTION = 0, OI_DRIINFO, OI_ENUM, OI_OPTION, OI_SECTION, OI_COUNT
+};
+static const XML_Char *OptInfoElems[] = {
+ "description", "driinfo", "enum", "option", "section"
+};
+
+/** \brief Parse attributes of an enum element.
+ *
+ * We're not actually interested in the data. Just make sure this is ok
+ * for external configuration tools.
+ */
+static void parseEnumAttr (struct OptInfoData *data, const XML_Char **attr) {
+ GLuint i;
+ const XML_Char *value = NULL, *text = NULL;
+ driOptionValue v;
+ GLuint opt = data->curOption;
+ for (i = 0; attr[i]; i += 2) {
+ if (!strcmp (attr[i], "value")) value = attr[i+1];
+ else if (!strcmp (attr[i], "text")) text = attr[i+1];
+ else XML_FATAL("illegal enum attribute: %s.", attr[i]);
+ }
+ if (!value) XML_FATAL1 ("value attribute missing in enum.");
+ if (!text) XML_FATAL1 ("text attribute missing in enum.");
+ if (!parseValue (&v, data->cache->info[opt].type, value))
+ XML_FATAL ("illegal enum value: %s.", value);
+ if (!checkValue (&v, &data->cache->info[opt]))
+ XML_FATAL ("enum value out of valid range: %s.", value);
+}
+
+/** \brief Parse attributes of a description element.
+ *
+ * We're not actually interested in the data. Just make sure this is ok
+ * for external configuration tools.
+ */
+static void parseDescAttr (struct OptInfoData *data, const XML_Char **attr) {
+ GLuint i;
+ const XML_Char *lang = NULL, *text = NULL;
+ for (i = 0; attr[i]; i += 2) {
+ if (!strcmp (attr[i], "lang")) lang = attr[i+1];
+ else if (!strcmp (attr[i], "text")) text = attr[i+1];
+ else XML_FATAL("illegal description attribute: %s.", attr[i]);
+ }
+ if (!lang) XML_FATAL1 ("lang attribute missing in description.");
+ if (!text) XML_FATAL1 ("text attribute missing in description.");
+}
+
+/** \brief Parse attributes of an option element. */
+static void parseOptInfoAttr (struct OptInfoData *data, const XML_Char **attr) {
+ enum OptAttr {OA_DEFAULT = 0, OA_NAME, OA_TYPE, OA_VALID, OA_COUNT};
+ static const XML_Char *optAttr[] = {"default", "name", "type", "valid"};
+ const XML_Char *attrVal[OA_COUNT] = {NULL, NULL, NULL, NULL};
+ const char *defaultVal;
+ driOptionCache *cache = data->cache;
+ GLuint opt, i;
+ for (i = 0; attr[i]; i += 2) {
+ GLuint attrName = bsearchStr (attr[i], optAttr, OA_COUNT);
+ if (attrName >= OA_COUNT)
+ XML_FATAL ("illegal option attribute: %s", attr[i]);
+ attrVal[attrName] = attr[i+1];
+ }
+ if (!attrVal[OA_NAME]) XML_FATAL1 ("name attribute missing in option.");
+ if (!attrVal[OA_TYPE]) XML_FATAL1 ("type attribute missing in option.");
+ if (!attrVal[OA_DEFAULT]) XML_FATAL1 ("default attribute missing in option.");
+
+ opt = findOption (cache, attrVal[OA_NAME]);
+ if (cache->info[opt].name)
+ XML_FATAL ("option %s redefined.", attrVal[OA_NAME]);
+ data->curOption = opt;
+
+ XSTRDUP (cache->info[opt].name, attrVal[OA_NAME]);
+
+ if (!strcmp (attrVal[OA_TYPE], "bool"))
+ cache->info[opt].type = DRI_BOOL;
+ else if (!strcmp (attrVal[OA_TYPE], "enum"))
+ cache->info[opt].type = DRI_ENUM;
+ else if (!strcmp (attrVal[OA_TYPE], "int"))
+ cache->info[opt].type = DRI_INT;
+ else if (!strcmp (attrVal[OA_TYPE], "float"))
+ cache->info[opt].type = DRI_FLOAT;
+ else
+ XML_FATAL ("illegal type in option: %s.", attrVal[OA_TYPE]);
+
+ defaultVal = getenv (cache->info[opt].name);
+ if (defaultVal != NULL) {
+ /* don't use XML_WARNING, we want the user to see this! */
+ fprintf (stderr,
+ "ATTENTION: default value of option %s overridden by environment.\n",
+ cache->info[opt].name);
+ } else
+ defaultVal = attrVal[OA_DEFAULT];
+ if (!parseValue (&cache->values[opt], cache->info[opt].type, defaultVal))
+ XML_FATAL ("illegal default value: %s.", defaultVal);
+
+ if (attrVal[OA_VALID]) {
+ if (cache->info[opt].type == DRI_BOOL)
+ XML_FATAL1 ("boolean option with valid attribute.");
+ if (!parseRanges (&cache->info[opt], attrVal[OA_VALID]))
+ XML_FATAL ("illegal valid attribute: %s.", attrVal[OA_VALID]);
+ if (!checkValue (&cache->values[opt], &cache->info[opt]))
+ XML_FATAL ("default value out of valid range '%s': %s.",
+ attrVal[OA_VALID], defaultVal);
+ } else if (cache->info[opt].type == DRI_ENUM) {
+ XML_FATAL1 ("valid attribute missing in option (mandatory for enums).");
+ } else {
+ cache->info[opt].nRanges = 0;
+ cache->info[opt].ranges = NULL;
+ }
+}
+
+/** \brief Handler for start element events. */
+static void optInfoStartElem (void *userData, const XML_Char *name,
+ const XML_Char **attr) {
+ struct OptInfoData *data = (struct OptInfoData *)userData;
+ enum OptInfoElem elem = bsearchStr (name, OptInfoElems, OI_COUNT);
+ switch (elem) {
+ case OI_DRIINFO:
+ if (data->inDriInfo)
+ XML_FATAL1 ("nested <driinfo> elements.");
+ if (attr[0])
+ XML_FATAL1 ("attributes specified on <driinfo> element.");
+ data->inDriInfo = GL_TRUE;
+ break;
+ case OI_SECTION:
+ if (!data->inDriInfo)
+ XML_FATAL1 ("<section> must be inside <driinfo>.");
+ if (data->inSection)
+ XML_FATAL1 ("nested <section> elements.");
+ if (attr[0])
+ XML_FATAL1 ("attributes specified on <section> element.");
+ data->inSection = GL_TRUE;
+ break;
+ case OI_DESCRIPTION:
+ if (!data->inSection && !data->inOption)
+ XML_FATAL1 ("<description> must be inside <description> or <option.");
+ if (data->inDesc)
+ XML_FATAL1 ("nested <description> elements.");
+ data->inDesc = GL_TRUE;
+ parseDescAttr (data, attr);
+ break;
+ case OI_OPTION:
+ if (!data->inSection)
+ XML_FATAL1 ("<option> must be inside <section>.");
+ if (data->inDesc)
+ XML_FATAL1 ("<option> nested in <description> element.");
+ if (data->inOption)
+ XML_FATAL1 ("nested <option> elements.");
+ data->inOption = GL_TRUE;
+ parseOptInfoAttr (data, attr);
+ break;
+ case OI_ENUM:
+ if (!(data->inOption && data->inDesc))
+ XML_FATAL1 ("<enum> must be inside <option> and <description>.");
+ if (data->inEnum)
+ XML_FATAL1 ("nested <enum> elements.");
+ data->inEnum = GL_TRUE;
+ parseEnumAttr (data, attr);
+ break;
+ default:
+ XML_FATAL ("unknown element: %s.", name);
+ }
+}
+
+/** \brief Handler for end element events. */
+static void optInfoEndElem (void *userData, const XML_Char *name) {
+ struct OptInfoData *data = (struct OptInfoData *)userData;
+ enum OptInfoElem elem = bsearchStr (name, OptInfoElems, OI_COUNT);
+ switch (elem) {
+ case OI_DRIINFO:
+ data->inDriInfo = GL_FALSE;
+ break;
+ case OI_SECTION:
+ data->inSection = GL_FALSE;
+ break;
+ case OI_DESCRIPTION:
+ data->inDesc = GL_FALSE;
+ break;
+ case OI_OPTION:
+ data->inOption = GL_FALSE;
+ break;
+ case OI_ENUM:
+ data->inEnum = GL_FALSE;
+ break;
+ default:
+ assert (0); /* should have been caught by StartElem */
+ }
+}
+
+void driParseOptionInfo (driOptionCache *info,
+ const char *configOptions, GLuint nConfigOptions) {
+ XML_Parser p;
+ int status;
+ struct OptInfoData userData;
+ struct OptInfoData *data = &userData;
+ GLuint realNoptions;
+
+ /* determine hash table size and allocate memory:
+ * 3/2 of the number of options, rounded up, so there remains always
+ * at least one free entry. This is needed for detecting undefined
+ * options in configuration files without getting a hash table overflow.
+ * Round this up to a power of two. */
+ GLuint minSize = (nConfigOptions*3 + 1) / 2;
+ GLuint size, log2size;
+ for (size = 1, log2size = 0; size < minSize; size <<= 1, ++log2size);
+ info->tableSize = log2size;
+ info->info = CALLOC (size * sizeof (driOptionInfo));
+ info->values = CALLOC (size * sizeof (driOptionValue));
+ if (info->info == NULL || info->values == NULL) {
+ fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
+ abort();
+ }
+
+ p = XML_ParserCreate ("UTF-8"); /* always UTF-8 */
+ XML_SetElementHandler (p, optInfoStartElem, optInfoEndElem);
+ XML_SetUserData (p, data);
+
+ userData.name = "__driConfigOptions";
+ userData.parser = p;
+ userData.cache = info;
+ userData.inDriInfo = GL_FALSE;
+ userData.inSection = GL_FALSE;
+ userData.inDesc = GL_FALSE;
+ userData.inOption = GL_FALSE;
+ userData.inEnum = GL_FALSE;
+ userData.curOption = -1;
+
+ status = XML_Parse (p, configOptions, strlen (configOptions), 1);
+ if (!status)
+ XML_FATAL ("%s.", XML_ErrorString(XML_GetErrorCode(p)));
+
+ XML_ParserFree (p);
+
+ /* Check if the actual number of options matches nConfigOptions.
+ * A mismatch is not fatal (a hash table overflow would be) but we
+ * want the driver developer's attention anyway. */
+ realNoptions = countOptions (info);
+ if (realNoptions != nConfigOptions) {
+ fprintf (stderr,
+ "Error: nConfigOptions (%u) does not match the actual number of options in\n"
+ " __driConfigOptions (%u).\n",
+ nConfigOptions, realNoptions);
+ }
+}
+
+/** \brief Parser context for configuration files. */
+struct OptConfData {
+ const char *name;
+ XML_Parser parser;
+ driOptionCache *cache;
+ GLint screenNum;
+ const char *driverName, *execName;
+ GLuint ignoringDevice;
+ GLuint ignoringApp;
+ GLuint inDriConf;
+ GLuint inDevice;
+ GLuint inApp;
+ GLuint inOption;
+};
+
+/** \brief Elements in configuration files. */
+enum OptConfElem {
+ OC_APPLICATION = 0, OC_DEVICE, OC_DRICONF, OC_OPTION, OC_COUNT
+};
+static const XML_Char *OptConfElems[] = {
+ "application", "device", "driconf", "option"
+};
+
+/** \brief Parse attributes of a device element. */
+static void parseDeviceAttr (struct OptConfData *data, const XML_Char **attr) {
+ GLuint i;
+ const XML_Char *driver = NULL, *screen = NULL;
+ for (i = 0; attr[i]; i += 2) {
+ if (!strcmp (attr[i], "driver")) driver = attr[i+1];
+ else if (!strcmp (attr[i], "screen")) screen = attr[i+1];
+ else XML_WARNING("unknown device attribute: %s.", attr[i]);
+ }
+ if (driver && strcmp (driver, data->driverName))
+ data->ignoringDevice = data->inDevice;
+ else if (screen) {
+ driOptionValue screenNum;
+ if (!parseValue (&screenNum, DRI_INT, screen))
+ XML_WARNING("illegal screen number: %s.", screen);
+ else if (screenNum._int != data->screenNum)
+ data->ignoringDevice = data->inDevice;
+ }
+}
+
+/** \brief Parse attributes of an application element. */
+static void parseAppAttr (struct OptConfData *data, const XML_Char **attr) {
+ GLuint i;
+ const XML_Char *name = NULL, *exec = NULL;
+ for (i = 0; attr[i]; i += 2) {
+ if (!strcmp (attr[i], "name")) name = attr[i+1];
+ else if (!strcmp (attr[i], "executable")) exec = attr[i+1];
+ else XML_WARNING("unknown application attribute: %s.", attr[i]);
+ }
+ if (exec && strcmp (exec, data->execName))
+ data->ignoringApp = data->inApp;
+}
+
+/** \brief Parse attributes of an option element. */
+static void parseOptConfAttr (struct OptConfData *data, const XML_Char **attr) {
+ GLuint i;
+ const XML_Char *name = NULL, *value = NULL;
+ for (i = 0; attr[i]; i += 2) {
+ if (!strcmp (attr[i], "name")) name = attr[i+1];
+ else if (!strcmp (attr[i], "value")) value = attr[i+1];
+ else XML_WARNING("unknown option attribute: %s.", attr[i]);
+ }
+ if (!name) XML_WARNING1 ("name attribute missing in option.");
+ if (!value) XML_WARNING1 ("value attribute missing in option.");
+ if (name && value) {
+ driOptionCache *cache = data->cache;
+ GLuint opt = findOption (cache, name);
+ if (cache->info[opt].name == NULL)
+ XML_WARNING ("undefined option: %s.", name);
+ else if (getenv (cache->info[opt].name))
+ /* don't use XML_WARNING, we want the user to see this! */
+ fprintf (stderr, "ATTENTION: option value of option %s ignored.\n",
+ cache->info[opt].name);
+ else if (!parseValue (&cache->values[opt], cache->info[opt].type, value))
+ XML_WARNING ("illegal option value: %s.", value);
+ }
+}
+
+/** \brief Handler for start element events. */
+static void optConfStartElem (void *userData, const XML_Char *name,
+ const XML_Char **attr) {
+ struct OptConfData *data = (struct OptConfData *)userData;
+ enum OptConfElem elem = bsearchStr (name, OptConfElems, OC_COUNT);
+ switch (elem) {
+ case OC_DRICONF:
+ if (data->inDriConf)
+ XML_WARNING1 ("nested <driconf> elements.");
+ if (attr[0])
+ XML_WARNING1 ("attributes specified on <driconf> element.");
+ data->inDriConf++;
+ break;
+ case OC_DEVICE:
+ if (!data->inDriConf)
+ XML_WARNING1 ("<device> should be inside <driconf>.");
+ if (data->inDevice)
+ XML_WARNING1 ("nested <device> elements.");
+ data->inDevice++;
+ if (!data->ignoringDevice && !data->ignoringApp)
+ parseDeviceAttr (data, attr);
+ break;
+ case OC_APPLICATION:
+ if (!data->inDevice)
+ XML_WARNING1 ("<application> should be inside <device>.");
+ if (data->inApp)
+ XML_WARNING1 ("nested <application> elements.");
+ data->inApp++;
+ if (!data->ignoringDevice && !data->ignoringApp)
+ parseAppAttr (data, attr);
+ break;
+ case OC_OPTION:
+ if (!data->inApp)
+ XML_WARNING1 ("<option> should be inside <application>.");
+ if (data->inOption)
+ XML_WARNING1 ("nested <option> elements.");
+ data->inOption++;
+ if (!data->ignoringDevice && !data->ignoringApp)
+ parseOptConfAttr (data, attr);
+ break;
+ default:
+ XML_WARNING ("unknown element: %s.", name);
+ }
+}
+
+/** \brief Handler for end element events. */
+static void optConfEndElem (void *userData, const XML_Char *name) {
+ struct OptConfData *data = (struct OptConfData *)userData;
+ enum OptConfElem elem = bsearchStr (name, OptConfElems, OC_COUNT);
+ switch (elem) {
+ case OC_DRICONF:
+ data->inDriConf--;
+ break;
+ case OC_DEVICE:
+ if (data->inDevice-- == data->ignoringDevice)
+ data->ignoringDevice = 0;
+ break;
+ case OC_APPLICATION:
+ if (data->inApp-- == data->ignoringApp)
+ data->ignoringApp = 0;
+ break;
+ case OC_OPTION:
+ data->inOption--;
+ break;
+ default:
+ /* unknown element, warning was produced on start tag */;
+ }
+}
+
+/** \brief Initialize an option cache based on info */
+static void initOptionCache (driOptionCache *cache, const driOptionCache *info) {
+ cache->info = info->info;
+ cache->tableSize = info->tableSize;
+ cache->values = MALLOC ((1<<info->tableSize) * sizeof (driOptionValue));
+ if (cache->values == NULL) {
+ fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
+ abort();
+ }
+ memcpy (cache->values, info->values,
+ (1<<info->tableSize) * sizeof (driOptionValue));
+}
+
+/** \brief Parse the named configuration file */
+static void parseOneConfigFile (XML_Parser p) {
+#define BUF_SIZE 0x1000
+ struct OptConfData *data = (struct OptConfData *)XML_GetUserData (p);
+ int status;
+ int fd;
+
+ if ((fd = open (data->name, O_RDONLY)) == -1) {
+ __driUtilMessage ("Can't open configuration file %s: %s.",
+ data->name, strerror (errno));
+ return;
+ }
+
+ while (1) {
+ int bytesRead;
+ void *buffer = XML_GetBuffer (p, BUF_SIZE);
+ if (!buffer) {
+ __driUtilMessage ("Can't allocate parser buffer.");
+ break;
+ }
+ bytesRead = read (fd, buffer, BUF_SIZE);
+ if (bytesRead == -1) {
+ __driUtilMessage ("Error reading from configuration file %s: %s.",
+ data->name, strerror (errno));
+ break;
+ }
+ status = XML_ParseBuffer (p, bytesRead, bytesRead == 0);
+ if (!status) {
+ XML_ERROR ("%s.", XML_ErrorString(XML_GetErrorCode(p)));
+ break;
+ }
+ if (bytesRead == 0)
+ break;
+ }
+
+ close (fd);
+#undef BUF_SIZE
+}
+
+void driParseConfigFiles (driOptionCache *cache, const driOptionCache *info,
+ GLint screenNum, const char *driverName) {
+ char *filenames[2] = {"/etc/drirc", NULL};
+ char *home;
+ GLuint i;
+ struct OptConfData userData;
+
+ initOptionCache (cache, info);
+
+ userData.cache = cache;
+ userData.screenNum = screenNum;
+ userData.driverName = driverName;
+ userData.execName = GET_PROGRAM_NAME();
+
+ if ((home = getenv ("HOME"))) {
+ GLuint len = strlen (home);
+ filenames[1] = MALLOC (len + 7+1);
+ if (filenames[1] == NULL)
+ __driUtilMessage ("Can't allocate memory for %s/.drirc.", home);
+ else {
+ memcpy (filenames[1], home, len);
+ memcpy (filenames[1] + len, "/.drirc", 7+1);
+ }
+ }
+
+ for (i = 0; i < 2; ++i) {
+ XML_Parser p;
+ if (filenames[i] == NULL)
+ continue;
+
+ p = XML_ParserCreate (NULL); /* use encoding specified by file */
+ XML_SetElementHandler (p, optConfStartElem, optConfEndElem);
+ XML_SetUserData (p, &userData);
+ userData.parser = p;
+ userData.name = filenames[i];
+ userData.ignoringDevice = 0;
+ userData.ignoringApp = 0;
+ userData.inDriConf = 0;
+ userData.inDevice = 0;
+ userData.inApp = 0;
+ userData.inOption = 0;
+
+ parseOneConfigFile (p);
+ XML_ParserFree (p);
+ }
+
+ if (filenames[1])
+ FREE (filenames[1]);
+}
+
+void driDestroyOptionInfo (driOptionCache *info) {
+ driDestroyOptionCache (info);
+ if (info->info) {
+ GLuint i, size = 1 << info->tableSize;
+ for (i = 0; i < size; ++i) {
+ if (info->info[i].name) {
+ FREE (info->info[i].name);
+ if (info->info[i].ranges)
+ FREE (info->info[i].ranges);
+ }
+ }
+ FREE (info->info);
+ }
+}
+
+void driDestroyOptionCache (driOptionCache *cache) {
+ if (cache->values)
+ FREE (cache->values);
+}
+
+GLboolean driCheckOption (const driOptionCache *cache, const char *name,
+ driOptionType type) {
+ GLuint i = findOption (cache, name);
+ return cache->info[i].name != NULL && cache->info[i].type == type;
+}
+
+GLboolean driQueryOptionb (const driOptionCache *cache, const char *name) {
+ GLuint i = findOption (cache, name);
+ /* make sure the option is defined and has the correct type */
+ assert (cache->info[i].name != NULL);
+ assert (cache->info[i].type == DRI_BOOL);
+ return cache->values[i]._bool;
+}
+
+GLint driQueryOptioni (const driOptionCache *cache, const char *name) {
+ GLuint i = findOption (cache, name);
+ /* make sure the option is defined and has the correct type */
+ assert (cache->info[i].name != NULL);
+ assert (cache->info[i].type == DRI_INT || cache->info[i].type == DRI_ENUM);
+ return cache->values[i]._int;
+}
+
+GLfloat driQueryOptionf (const driOptionCache *cache, const char *name) {
+ GLuint i = findOption (cache, name);
+ /* make sure the option is defined and has the correct type */
+ assert (cache->info[i].name != NULL);
+ assert (cache->info[i].type == DRI_FLOAT);
+ return cache->values[i]._float;
+}
diff --git a/mesalib/src/mesa/drivers/dri/common/xmlpool/Makefile b/mesalib/src/mesa/drivers/dri/common/xmlpool/Makefile index 62ec919ea..ae3d89938 100644 --- a/mesalib/src/mesa/drivers/dri/common/xmlpool/Makefile +++ b/mesalib/src/mesa/drivers/dri/common/xmlpool/Makefile @@ -1,96 +1,96 @@ -# Convenient makefile for managing translations. - -# Prerequisites: -# - GNU gettext -# - Python - -# Adding new translations -# ----------------------- - -# To start working on a new translation edit the POS=... line -# below. If you want to add for example a french translation, add -# fr.po. - -# Then run "make po" to generate a fresh .po file from translatable -# strings in t_options.h. Now you can edit the new .po file (fr.po in -# the example above) to translate the strings. Please make sure that -# your editor encodes the file in UTF-8. - -# Updating existing translations -# ------------------------------ - -# Run "make po" to update .po files with new translatable strings from -# t_options.h. Now you can edit the .po files you're interested -# in. Please make sure that your editor encodes the file in UTF-8. - -# Updating options.h -# ------------------ - -# Finally run "make" to generate options.h from t_options.h with all -# translations. Now you can rebuild the drivers. Any common options -# used by the drivers will have option descriptions with the latest -# translations. - -# Publishing translations -# ----------------------- - -# To get your translation(s) into Mesa CVS, please send me your -# <lang>.po file. - -# More information: -# - info gettext - -# The set of supported languages. Add languages as needed. -POS=de.po es.po nl.po fr.po sv.po - -# -# Don't change anything below, unless you know what you're doing. -# -LANGS=$(POS:%.po=%) -MOS=$(POS:%.po=%/LC_MESSAGES/options.mo) -POT=xmlpool.pot - -.PHONY: all clean pot po mo - -all: options.h - -# Only intermediate files are cleaned up. options.h is not deleted because -# it's in CVS. -clean: - -rm -f $(POT) *~ - -rm -rf $(LANGS) - -# Default target options.h -options.h: t_options.h mo - python gen_xmlpool.py $(LANGS) > options.h - -# Update .mo files from the corresponding .po files. -mo: - @for mo in $(MOS); do \ - lang=$${mo%%/*}; \ - echo "Updating $$mo from $$lang.po."; \ - mkdir -p $${mo%/*}; \ - msgfmt -o $$mo $$lang.po; \ - done - -# Use this target to create or update .po files with new messages in -# driconf.py. -po: $(POS) - -pot: $(POT) - -# Extract message catalog from driconf.py. -$(POT): t_options.h - xgettext -L C --from-code utf-8 -o $(POT) t_options.h - -# Create or update a .po file for a specific language. -%.po: $(POT) - @if [ -f $@ ]; then \ - echo "Merging new strings from $(POT) into $@."; \ - mv $@ $@~; \ - msgmerge -o $@ $@~ $(POT); \ - else \ - echo "Initializing $@ from $(POT)."; \ - msginit -i $(POT) -o $@~ --locale=$*; \ - sed -e 's/charset=.*\\n/charset=UTF-8\\n/' $@~ > $@; \ - fi +# Convenient makefile for managing translations.
+
+# Prerequisites:
+# - GNU gettext
+# - Python
+
+# Adding new translations
+# -----------------------
+
+# To start working on a new translation edit the POS=... line
+# below. If you want to add for example a french translation, add
+# fr.po.
+
+# Then run "make po" to generate a fresh .po file from translatable
+# strings in t_options.h. Now you can edit the new .po file (fr.po in
+# the example above) to translate the strings. Please make sure that
+# your editor encodes the file in UTF-8.
+
+# Updating existing translations
+# ------------------------------
+
+# Run "make po" to update .po files with new translatable strings from
+# t_options.h. Now you can edit the .po files you're interested
+# in. Please make sure that your editor encodes the file in UTF-8.
+
+# Updating options.h
+# ------------------
+
+# Finally run "make" to generate options.h from t_options.h with all
+# translations. Now you can rebuild the drivers. Any common options
+# used by the drivers will have option descriptions with the latest
+# translations.
+
+# Publishing translations
+# -----------------------
+
+# To get your translation(s) into Mesa CVS, please send me your
+# <lang>.po file.
+
+# More information:
+# - info gettext
+
+# The set of supported languages. Add languages as needed.
+POS=de.po es.po nl.po fr.po sv.po
+
+#
+# Don't change anything below, unless you know what you're doing.
+#
+LANGS=$(POS:%.po=%)
+MOS=$(POS:%.po=%/LC_MESSAGES/options.mo)
+POT=xmlpool.pot
+
+.PHONY: all clean pot po mo
+
+all: options.h
+
+# Only intermediate files are cleaned up. options.h is not deleted because
+# it's in CVS.
+clean:
+ -rm -f $(POT) *~
+ -rm -rf $(LANGS)
+
+# Default target options.h
+options.h: t_options.h mo
+ $(PYTHON2) $(PYTHON_FLAGS) gen_xmlpool.py $(LANGS) > options.h
+
+# Update .mo files from the corresponding .po files.
+mo:
+ @for mo in $(MOS); do \
+ lang=$${mo%%/*}; \
+ echo "Updating $$mo from $$lang.po."; \
+ mkdir -p $${mo%/*}; \
+ msgfmt -o $$mo $$lang.po; \
+ done
+
+# Use this target to create or update .po files with new messages in
+# driconf.py.
+po: $(POS)
+
+pot: $(POT)
+
+# Extract message catalog from driconf.py.
+$(POT): t_options.h
+ xgettext -L C --from-code utf-8 -o $(POT) t_options.h
+
+# Create or update a .po file for a specific language.
+%.po: $(POT)
+ @if [ -f $@ ]; then \
+ echo "Merging new strings from $(POT) into $@."; \
+ mv $@ $@~; \
+ msgmerge -o $@ $@~ $(POT); \
+ else \
+ echo "Initializing $@ from $(POT)."; \
+ msginit -i $(POT) -o $@~ --locale=$*; \
+ sed -e 's/charset=.*\\n/charset=UTF-8\\n/' $@~ > $@; \
+ fi
diff --git a/mesalib/src/mesa/drivers/dri/common/xmlpool/gen_xmlpool.py b/mesalib/src/mesa/drivers/dri/common/xmlpool/gen_xmlpool.py new file mode 100644 index 000000000..f5ac5e25b --- /dev/null +++ b/mesalib/src/mesa/drivers/dri/common/xmlpool/gen_xmlpool.py @@ -0,0 +1,191 @@ +#!/usr/bin/python
+
+import sys
+import gettext
+import re
+
+# List of supported languages
+languages = sys.argv[1:]
+
+# Escape special characters in C strings
+def escapeCString (s):
+ escapeSeqs = {'\a' : '\\a', '\b' : '\\b', '\f' : '\\f', '\n' : '\\n',
+ '\r' : '\\r', '\t' : '\\t', '\v' : '\\v', '\\' : '\\\\'}
+ # " -> '' is a hack. Quotes (") aren't possible in XML attributes.
+ # Better use Unicode characters for typographic quotes in option
+ # descriptions and translations.
+ i = 0
+ r = ''
+ while i < len(s):
+ # Special case: escape double quote with \u201c or \u201d, depending
+ # on whether it's an open or close quote. This is needed because plain
+ # double quotes are not possible in XML attributes.
+ if s[i] == '"':
+ if i == len(s)-1 or s[i+1].isspace():
+ # close quote
+ q = u'\u201c'
+ else:
+ # open quote
+ q = u'\u201d'
+ r = r + q
+ elif escapeSeqs.has_key(s[i]):
+ r = r + escapeSeqs[s[i]]
+ else:
+ r = r + s[i]
+ i = i + 1
+ return r
+
+# Expand escape sequences in C strings (needed for gettext lookup)
+def expandCString (s):
+ escapeSeqs = {'a' : '\a', 'b' : '\b', 'f' : '\f', 'n' : '\n',
+ 'r' : '\r', 't' : '\t', 'v' : '\v',
+ '"' : '"', '\\' : '\\'}
+ i = 0
+ escape = False
+ hexa = False
+ octa = False
+ num = 0
+ digits = 0
+ r = ''
+ while i < len(s):
+ if not escape:
+ if s[i] == '\\':
+ escape = True
+ else:
+ r = r + s[i]
+ elif hexa:
+ if (s[i] >= '0' and s[i] <= '9') or \
+ (s[i] >= 'a' and s[i] <= 'f') or \
+ (s[i] >= 'A' and s[i] <= 'F'):
+ num = num * 16 + int(s[i],16)
+ digits = digits + 1
+ else:
+ digits = 2
+ if digits >= 2:
+ hexa = False
+ escape = False
+ r = r + chr(num)
+ elif octa:
+ if s[i] >= '0' and s[i] <= '7':
+ num = num * 8 + int(s[i],8)
+ digits = digits + 1
+ else:
+ digits = 3
+ if digits >= 3:
+ octa = False
+ escape = False
+ r = r + chr(num)
+ else:
+ if escapeSeqs.has_key(s[i]):
+ r = r + escapeSeqs[s[i]]
+ escape = False
+ elif s[i] >= '0' and s[i] <= '7':
+ octa = True
+ num = int(s[i],8)
+ if num <= 3:
+ digits = 1
+ else:
+ digits = 2
+ elif s[i] == 'x' or s[i] == 'X':
+ hexa = True
+ num = 0
+ digits = 0
+ else:
+ r = r + s[i]
+ escape = False
+ i = i + 1
+ return r
+
+# Expand matches. The first match is always a DESC or DESC_BEGIN match.
+# Subsequent matches are ENUM matches.
+#
+# DESC, DESC_BEGIN format: \1 \2=<lang> \3 \4=gettext(" \5=<text> \6=") \7
+# ENUM format: \1 \2=gettext(" \3=<text> \4=") \5
+def expandMatches (matches, translations, end=None):
+ assert len(matches) > 0
+ nTranslations = len(translations)
+ i = 0
+ # Expand the description+enums for all translations
+ for lang,trans in translations:
+ i = i + 1
+ # Make sure that all but the last line of a simple description
+ # are extended with a backslash.
+ suffix = ''
+ if len(matches) == 1 and i < len(translations) and \
+ not matches[0].expand (r'\7').endswith('\\'):
+ suffix = ' \\'
+ # Expand the description line. Need to use ugettext in order to allow
+ # non-ascii unicode chars in the original English descriptions.
+ text = escapeCString (trans.ugettext (unicode (expandCString (
+ matches[0].expand (r'\5')), "utf-8"))).encode("utf-8")
+ print matches[0].expand (r'\1' + lang + r'\3"' + text + r'"\7') + suffix
+ # Expand any subsequent enum lines
+ for match in matches[1:]:
+ text = escapeCString (trans.ugettext (unicode (expandCString (
+ match.expand (r'\3')), "utf-8"))).encode("utf-8")
+ print match.expand (r'\1"' + text + r'"\5')
+
+ # Expand description end
+ if end:
+ print end,
+
+# Compile a list of translation classes to all supported languages.
+# The first translation is always a NullTranslations.
+translations = [("en", gettext.NullTranslations())]
+for lang in languages:
+ try:
+ trans = gettext.translation ("options", ".", [lang])
+ except IOError:
+ sys.stderr.write ("Warning: language '%s' not found.\n" % lang)
+ continue
+ translations.append ((lang, trans))
+
+# Regular expressions:
+reLibintl_h = re.compile (r'#\s*include\s*<libintl.h>')
+reDESC = re.compile (r'(\s*DRI_CONF_DESC\s*\(\s*)([a-z]+)(\s*,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$')
+reDESC_BEGIN = re.compile (r'(\s*DRI_CONF_DESC_BEGIN\s*\(\s*)([a-z]+)(\s*,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$')
+reENUM = re.compile (r'(\s*DRI_CONF_ENUM\s*\([^,]+,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$')
+reDESC_END = re.compile (r'\s*DRI_CONF_DESC_END')
+
+# Print a header
+print \
+"/***********************************************************************\n" \
+" *** THIS FILE IS GENERATED AUTOMATICALLY. DON'T EDIT! ***\n" \
+" ***********************************************************************/"
+
+# Process the options template and generate options.h with all
+# translations.
+template = file ("t_options.h", "r")
+descMatches = []
+for line in template:
+ if len(descMatches) > 0:
+ matchENUM = reENUM .match (line)
+ matchDESC_END = reDESC_END.match (line)
+ if matchENUM:
+ descMatches.append (matchENUM)
+ elif matchDESC_END:
+ expandMatches (descMatches, translations, line)
+ descMatches = []
+ else:
+ sys.stderr.write (
+ "Warning: unexpected line inside description dropped:\n%s\n" \
+ % line)
+ continue
+ if reLibintl_h.search (line):
+ # Ignore (comment out) #include <libintl.h>
+ print "/* %s * commented out by gen_xmlpool.py */" % line
+ continue
+ matchDESC = reDESC .match (line)
+ matchDESC_BEGIN = reDESC_BEGIN.match (line)
+ if matchDESC:
+ assert len(descMatches) == 0
+ expandMatches ([matchDESC], translations)
+ elif matchDESC_BEGIN:
+ assert len(descMatches) == 0
+ descMatches = [matchDESC_BEGIN]
+ else:
+ print line,
+
+if len(descMatches) > 0:
+ sys.stderr.write ("Warning: unterminated description at end of file.\n")
+ expandMatches (descMatches, translations)
|