/** * \file radeon_subset_vtx.c * \brief Vertex buffering. * * \author Keith Whitwell */ /* * Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and * Tungsten Graphics Inc., Cedar Park, Texas. * * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * on the rights to use, copy, modify, merge, publish, distribute, sub * license, and/or sell copies of the Software, and to permit persons to whom * the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * ATI, TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /* $XFree86$ */ #include "glheader.h" #include "imports.h" #include "api_noop.h" #include "context.h" /*#include "mmath.h" */ #include "mtypes.h" #include "enums.h" #include "glapi.h" #include "colormac.h" #include "state.h" #include "radeon_context.h" #include "radeon_state.h" #include "radeon_ioctl.h" #include "radeon_subset.h" /** * \brief Union for vertex data. */ union vertex_dword { float f; /**< \brief floating point value */ int i; /**< \brief integer point value */ }; /** * \brief Maximum number of dwords per vertex. * * Defined as 10 to hold: \code xyzw rgba st \endcode */ #define MAX_VERTEX_DWORDS 10 /** * \brief Global vertex buffer data. */ static struct vb_t { /** * \brief Notification mechanism. * * These are treated as a stack to allow us to do things like build quads in * temporary storage and then emit them as triangles. */ struct { GLint vertspace; /**< \brief free vertices count */ GLint initial_vertspace; /**< \brief total vertices count */ GLint *dmaptr; /**< \brief */ void (*notify)( void ); /**< \brief notification callback */ } stack[2]; /** * \brief Storage for current vertex. */ union vertex_dword vertex[MAX_VERTEX_DWORDS]; /** * \brief Temporary storage for quads, etc. */ union vertex_dword vertex_store[MAX_VERTEX_DWORDS * 4]; /** * \name Color/texture * * Pointers to either vertex or ctx->Current.Attrib, depending on whether * color/texture participates in the current vertex. */ /*@{*/ GLfloat *floatcolorptr; /**< \brief color */ GLfloat *texcoordptr; /**< \brief texture */ /*@}*/ /** * \brief Pointer to the GL context. */ GLcontext *context; /** * \brief Active primitive. * * \note May differ from ctx->Driver.CurrentExecPrimitive. */ /*@{*/ GLenum prim; /**< \brief primitive */ GLuint vertex_format; /**< \brief vertex format */ GLint vertex_size; /**< \brief vertex size */ GLboolean recheck; /**< \brief set if it's needed to validate this information */ /*@}*/ } vb; static void radeonFlushVertices( GLcontext *, GLuint ); /** * \brief Primitive information table. */ static struct prims_t { int start, /**< \brief vertex count for the starting primitive */ incr, /**< \brief vertex increment for a further primitive */ hwprim; /**< \brief hardware primitive */ } prims[10] = { { 1, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_POINT }, { 2, 2, RADEON_CP_VC_CNTL_PRIM_TYPE_LINE }, { 2, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP }, { 2, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP }, { 3, 3, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST }, { 3, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP }, { 3, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN }, { 4, 4, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST }, { 4, 2, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP }, { 3, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN }, }; /** * \brief Finish the primitive in the vertex buffer. * * \param rmesa Radeon context. * * Truncates any redundant vertices off the end of the buffer, emit the * remaining vertices and advances the current DMA region. */ static void finish_prim( radeonContextPtr rmesa ) { GLuint prim_end = vb.stack[0].initial_vertspace - vb.stack[0].vertspace; /* Too few vertices? (eg: 2 vertices for a triangles prim?) */ if (prim_end < prims[vb.prim].start) return; /* Drop redundant vertices off end of primitive. (eg: 5 vertices * for triangles prim?) */ prim_end -= (prim_end - prims[vb.prim].start) % prims[vb.prim].incr; radeonEmitVertexAOS( rmesa, vb.vertex_size, GET_START(&rmesa->dma.current) ); radeonEmitVbufPrim( rmesa, vb.vertex_format, prims[vb.prim].hwprim | rmesa->tcl.tcl_flag, prim_end ); rmesa->dma.current.ptr = rmesa->dma.current.start += prim_end * vb.vertex_size * 4; } /** * \brief Copy a vertex from the current DMA region * * \param rmesa Radeon context. * \param n vertex index relative to the current DMA region. * \param dst destination pointer. * * Used internally by copy_dma_verts(). */ static void copy_vertex( radeonContextPtr rmesa, GLuint n, GLfloat *dst ) { GLuint i; GLfloat *src = (GLfloat *)(rmesa->dma.current.address + rmesa->dma.current.ptr + n * vb.vertex_size * 4); for (i = 0 ; i < vb.vertex_size; i++) dst[i] = src[i]; } /** * \brief Copy last vertices from the current DMA buffer to resume in a new buffer. * * \param rmesa Radeon context. * \param tmp destination buffer. * * Takes from the current DMA buffer the last vertices necessary to resume in a * new buffer, according to the current primitive. Uses internally * copy_vertex() for the vertex copying. * */ static GLuint copy_dma_verts( radeonContextPtr rmesa, GLfloat (*tmp)[MAX_VERTEX_DWORDS] ) { GLuint ovf, i; GLuint nr = vb.stack[0].initial_vertspace - vb.stack[0].vertspace; switch( vb.prim ) { case GL_POINTS: return 0; case GL_LINES: ovf = nr&1; for (i = 0 ; i < ovf ; i++) copy_vertex( rmesa, nr-ovf+i, tmp[i] ); return i; case GL_LINE_STRIP: if (nr == 0) return 0; copy_vertex( rmesa, nr-1, tmp[0] ); return 1; case GL_LINE_LOOP: case GL_TRIANGLE_FAN: case GL_POLYGON: if (nr == 0) return 0; else if (nr == 1) { copy_vertex( rmesa, 0, tmp[0] ); return 1; } else { copy_vertex( rmesa, 0, tmp[0] ); copy_vertex( rmesa, nr-1, tmp[1] ); return 2; } case GL_TRIANGLES: ovf = nr % 3; for (i = 0 ; i < ovf ; i++) copy_vertex( rmesa, nr-ovf+i, tmp[i] ); return i; case GL_QUADS: ovf = nr % 4; for (i = 0 ; i < ovf ; i++) copy_vertex( rmesa, nr-ovf+i, tmp[i] ); return i; case GL_TRIANGLE_STRIP: case GL_QUAD_STRIP: ovf = MIN2(nr, 2); for (i = 0 ; i < ovf ; i++) copy_vertex( rmesa, nr-ovf+i, tmp[i] ); return i; default: return 0; } } static void notify_wrap_buffer( void ); /** * \brief Resets the vertex buffer notification mechanism. * * Fills in vb_t::stack with the values from the current DMA region in * radeon_dma::current and sets the notification callback to * notify_wrap_buffer(). */ static void reset_notify( void ) { radeonContextPtr rmesa = RADEON_CONTEXT( vb.context ); vb.stack[0].dmaptr = (int *)(rmesa->dma.current.address + rmesa->dma.current.ptr); vb.stack[0].vertspace = ((rmesa->dma.current.end - rmesa->dma.current.ptr) / (vb.vertex_size * 4)); vb.stack[0].vertspace &= ~1; /* even numbers only -- avoid tristrip parity */ vb.stack[0].initial_vertspace = vb.stack[0].vertspace; vb.stack[0].notify = notify_wrap_buffer; } /** * \brief Full buffer notification callback. * * Makes a copy of the necessary vertices of the current buffer via * copy_dma_verts(), gets and resets new buffer via radeon and re-emits the * saved vertices. */ static void notify_wrap_buffer( void ) { GLcontext *ctx = vb.context; radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLfloat tmp[3][MAX_VERTEX_DWORDS]; GLuint i, nrverts = 0; /* Copy vertices out of dma: */ nrverts = copy_dma_verts( rmesa, tmp ); finish_prim( rmesa ); /* Get new buffer */ radeonRefillCurrentDmaRegion( rmesa ); /* Reset vertspace[0], dmaptr */ reset_notify(); /* Reemit saved vertices */ for (i = 0 ; i < nrverts; i++) { memcpy( vb.stack[0].dmaptr, tmp[i], vb.vertex_size * 4 ); vb.stack[0].dmaptr += vb.vertex_size; vb.stack[0].vertspace--; } } static void notify_noop( void ) { vb.stack[0].dmaptr = (int *)vb.vertex; vb.stack[0].notify = notify_noop; vb.stack[0].vertspace = 1; } /** * \brief Pop the notification mechanism stack. * * Simply copy the second stack array element into the first. * * \sa vb_t::stack and push_notify(). */ static void pop_notify( void ) { vb.stack[0] = vb.stack[1]; } /** * \brief Push the notification mechanism stack. * * \param notify new notify callback for the stack head. * \param space space available for vertices in \p store. * \param store buffer where to store the vertices. * * Copy the second stack array element into the first and makes the stack head * use the given resources. * * \sa vb_t::stack and pop_notify(). */ static void push_notify( void (*notify)( void ), int space, union vertex_dword *store ) { vb.stack[1] = vb.stack[0]; vb.stack[0].notify = notify; vb.stack[0].initial_vertspace = space; vb.stack[0].vertspace = space; vb.stack[0].dmaptr = (int *)store; } /** * \brief Emit a stored vertex (in vb_t::vertex_store) to DMA. * * \param v vertex index. * * Adds the vertex into the current vertex buffer and calls the notification * callback vb_t::notify(). */ static void emit_vertex( int v ) { int i, *tmp = (int *)vb.vertex_store + v * vb.vertex_size; for (i = 0 ; i < vb.vertex_size ; i++) *vb.stack[0].dmaptr++ = *tmp++; if (--vb.stack[0].vertspace == 0) vb.stack[0].notify(); } /** * \brief Emit a quad (in vb_t::vertex_store) to DMA as two triangles. * * \param v0 first vertex index. * \param v1 second vertex index. * \param v2 third vertex index. * \param v3 fourth vertex index. * * Calls emit_vertex() to emit the triangles' vertices. */ static void emit_quad( int v0, int v1, int v2, int v3 ) { emit_vertex( v0 ); emit_vertex( v1 ); emit_vertex( v3 ); emit_vertex( v1 ); emit_vertex( v2 ); emit_vertex( v3 ); } /** * \brief Every fourth vertex in a quad primitive, this is called to emit it. * * Pops the notification stack, calls emit_quad() and pushes the notification * stack again, with itself and the vb_t::vertex_store to process another four * vertices. */ static void notify_quad( void ) { pop_notify(); emit_quad( 0, 1, 2, 3 ); push_notify( notify_quad, 4, vb.vertex_store ); } static void notify_qstrip1( void ); /** * \brief After the 4th vertex, emit either a quad or a flipped quad each two * vertices. * * Pops the notification stack, calls emit_quad() with the flipped vertices and * pushes the notification stack again, with notify_qstrip1() and the * vb_t::vertex_store to process another two vertices. * * \sa notify_qstrip1(). */ static void notify_qstrip0( void ) { pop_notify(); emit_quad( 0, 1, 3, 2 ); push_notify( notify_qstrip1, 2, vb.vertex_store ); } /** * \brief After the 4th vertex, emit either a quad or a flipped quad each two * vertices. * * Pops the notification stack, calls emit_quad() with the straight vertices * and pushes the notification stack again, with notify_qstrip0() and the * vb_t::vertex_store to process another two vertices. * * \sa notify_qstrip0(). */ static void notify_qstrip1( void ) { pop_notify(); emit_quad( 2, 3, 1, 0 ); push_notify( notify_qstrip0, 2, vb.vertex_store + 2*vb.vertex_size ); } /** * \brief Emit the saved vertex (but hang on to it for later). * * Continue processing this primitive as a linestrip. * * Pops the notification stack and calls emit_quad with the first vertex. */ static void notify_lineloop0( void ) { pop_notify(); emit_vertex(0); } /** * \brief Invalidate the current vertex format. * * \param ctx GL context. * * Sets the vb_t::recheck flag. */ void radeonVtxfmtInvalidate( GLcontext *ctx ) { vb.recheck = GL_TRUE; } /** * \brief Validate the vertex format from the context. * * \param ctx GL context. * * Signals a new primitive and determines the appropriate vertex format and * size. Points vb_t::floatcolorptr and vb_t::texcoordptr to the current vertex * and sets them to the current color and texture attributes. * * Clears the vb_t::recheck flag on exit. */ static void radeonVtxfmtValidate( GLcontext *ctx ) { radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); GLuint ind = (RADEON_CP_VC_FRMT_Z | RADEON_CP_VC_FRMT_FPCOLOR | RADEON_CP_VC_FRMT_FPALPHA); if (ctx->Driver.NeedFlush) ctx->Driver.FlushVertices( ctx, ctx->Driver.NeedFlush ); if (ctx->Texture.Unit[0]._ReallyEnabled) ind |= RADEON_CP_VC_FRMT_ST0; RADEON_NEWPRIM(rmesa); vb.vertex_format = ind; vb.vertex_size = 3; /* Would prefer to use ubyte floats in the vertex: */ vb.floatcolorptr = &vb.vertex[vb.vertex_size].f; vb.vertex_size += 4; vb.floatcolorptr[0] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0]; vb.floatcolorptr[1] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1]; vb.floatcolorptr[2] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2]; vb.floatcolorptr[3] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3]; if (ind & RADEON_CP_VC_FRMT_ST0) { vb.texcoordptr = &vb.vertex[vb.vertex_size].f; vb.vertex_size += 2; vb.texcoordptr[0] = ctx->Current.Attrib[VERT_ATTRIB_TEX0][0]; vb.texcoordptr[1] = ctx->Current.Attrib[VERT_ATTRIB_TEX0][1]; } else vb.texcoordptr = ctx->Current.Attrib[VERT_ATTRIB_TEX0]; vb.recheck = GL_FALSE; ctx->Driver.NeedFlush = FLUSH_UPDATE_CURRENT; } #define RESET_STIPPLE() do { \ RADEON_STATECHANGE( rmesa, lin ); \ radeonEmitState( rmesa ); \ } while (0) #define AUTO_STIPPLE( mode ) do { \ RADEON_STATECHANGE( rmesa, lin ); \ if (mode) \ rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] |= \ RADEON_LINE_PATTERN_AUTO_RESET; \ else \ rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] &= \ ~RADEON_LINE_PATTERN_AUTO_RESET; \ radeonEmitState( rmesa ); \ } while (0) /** * \brief Process glBegin(). * * \param mode primitive. */ static void radeon_Begin( GLenum mode ) { GLcontext *ctx = vb.context; radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLuint se_cntl; if (mode > GL_POLYGON) { _mesa_error( ctx, GL_INVALID_ENUM, "glBegin" ); return; } if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) { _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" ); return; } if (ctx->NewState) _mesa_update_state( ctx ); if (rmesa->NewGLState) radeonValidateState( ctx ); if (vb.recheck) radeonVtxfmtValidate( ctx ); /* Do we need to grab a new DMA region for the vertices? */ if (rmesa->dma.current.ptr + 12*vb.vertex_size*4 > rmesa->dma.current.end) { RADEON_NEWPRIM( rmesa ); radeonRefillCurrentDmaRegion( rmesa ); } reset_notify(); vb.prim = ctx->Driver.CurrentExecPrimitive = mode; se_cntl = rmesa->hw.set.cmd[SET_SE_CNTL] | RADEON_FLAT_SHADE_VTX_LAST; if (ctx->Line.StippleFlag && (mode == GL_LINES || mode == GL_LINE_LOOP || mode == GL_LINE_STRIP)) RESET_STIPPLE(); switch( mode ) { case GL_LINES: if (ctx->Line.StippleFlag) AUTO_STIPPLE( GL_TRUE ); break; case GL_LINE_LOOP: vb.prim = GL_LINE_STRIP; push_notify( notify_lineloop0, 1, vb.vertex_store ); break; case GL_QUADS: vb.prim = GL_TRIANGLES; push_notify( notify_quad, 4, vb.vertex_store ); break; case GL_QUAD_STRIP: if (ctx->_TriangleCaps & DD_FLATSHADE) { vb.prim = GL_TRIANGLES; push_notify( notify_qstrip0, 4, vb.vertex_store ); } break; case GL_POLYGON: if (ctx->_TriangleCaps & DD_FLATSHADE) se_cntl &= ~RADEON_FLAT_SHADE_VTX_LAST; break; default: break; } if (se_cntl != rmesa->hw.set.cmd[SET_SE_CNTL]) { RADEON_STATECHANGE( rmesa, set ); rmesa->hw.set.cmd[SET_SE_CNTL] = se_cntl; } } /** * \brief Process glEnd(). * */ static void radeon_End( void ) { GLcontext *ctx = vb.context; radeonContextPtr rmesa = RADEON_CONTEXT(ctx); if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) { _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" ); return; } /* Need to finish a line loop? */ if (ctx->Driver.CurrentExecPrimitive == GL_LINE_LOOP) emit_vertex( 0 ); /* Need to pop off quads/quadstrip/etc notification? */ if (vb.stack[0].notify != notify_wrap_buffer) pop_notify(); finish_prim( rmesa ); if (ctx->Driver.CurrentExecPrimitive == GL_LINES && ctx->Line.StippleFlag) AUTO_STIPPLE( GL_FALSE ); ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1; notify_noop(); } /** * \brief Flush vertices. * * \param ctx GL context. * \param flags flags. * * If FLUSH_UPDATE_CURRENT is et in \p flags then the current vertex attributes * in the GL context is updated from vb_t::floatcolorptr and vb_t::texcoordptr. */ static void radeonFlushVertices( GLcontext *ctx, GLuint flags ) { if (flags & FLUSH_UPDATE_CURRENT) { ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0] = vb.floatcolorptr[0]; ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1] = vb.floatcolorptr[1]; ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2] = vb.floatcolorptr[2]; ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = vb.floatcolorptr[3]; if (vb.vertex_format & RADEON_CP_VC_FRMT_ST0) { ctx->Current.Attrib[VERT_ATTRIB_TEX0][0] = vb.texcoordptr[0]; ctx->Current.Attrib[VERT_ATTRIB_TEX0][1] = vb.texcoordptr[1]; ctx->Current.Attrib[VERT_ATTRIB_TEX0][2] = 0.0F; ctx->Current.Attrib[VERT_ATTRIB_TEX0][3] = 1.0F; } } ctx->Driver.NeedFlush &= ~FLUSH_STORED_VERTICES; } /** * \brief Set current vertex coordinates. * * \param x x vertex coordinate. * \param y y vertex coordinate. * \param z z vertex coordinate. * * Set the current vertex coordinates. If run out of space in this buffer call * the notification callback. */ static __inline__ void radeon_Vertex3f( GLfloat x, GLfloat y, GLfloat z ) { int i; *vb.stack[0].dmaptr++ = *(int *)&x; *vb.stack[0].dmaptr++ = *(int *)&y; *vb.stack[0].dmaptr++ = *(int *)&z; for (i = 3; i < vb.vertex_size; i++) *vb.stack[0].dmaptr++ = vb.vertex[i].i; if (--vb.stack[0].vertspace == 0) vb.stack[0].notify(); } /** * \brief Set current vertex color. * * \param r red color component. * \param g gree color component. * \param b blue color component. * \param a alpha color component. * * Sets the current vertex color via vb_t::floatcolorptr. */ static __inline__ void radeon_Color4f( GLfloat r, GLfloat g, GLfloat b, GLfloat a ) { GLfloat *dest = vb.floatcolorptr; dest[0] = r; dest[1] = g; dest[2] = b; dest[3] = a; } /** * \brief Set current vertex texture coordinates. * * \param s texture coordinate. * \param t texture coordinate. * * Sets the current vertex color via vb_t::texcoordptr. */ static __inline__ void radeon_TexCoord2f( GLfloat s, GLfloat t ) { GLfloat *dest = vb.texcoordptr; dest[0] = s; dest[1] = t; } /** * Calls radeon_Vertex3f(), which is expanded inline by the compiler to be * efficient. */ static void radeon_Vertex3fv( const GLfloat *v ) { radeon_Vertex3f( v[0], v[1], v[2] ); } /** * Calls radeon_Vertex3f(), which is expanded inline by the compiler to be * efficient. */ static void radeon_Vertex2f( GLfloat x, GLfloat y ) { radeon_Vertex3f( x, y, 0 ); } /** * Calls radeon_Vertex3f(), which is expanded inline by the compiler to be * efficient. */ static void radeon_Vertex2fv( const GLfloat *v ) { radeon_Vertex3f( v[0], v[1], 0 ); } /** * Calls radeon_Vertex3f(), which is expanded inline by the compiler to be * efficient. */ static void radeon_Color4fv( const GLfloat *v ) { radeon_Color4f( v[0], v[1], v[2], v[3] ); } /** * Calls radeon_Color4f(), which is expanded inline by the compiler to be * efficient. */ static void radeon_Color3f( GLfloat r, GLfloat g, GLfloat b ) { radeon_Color4f( r, g, b, 1.0 ); } /** * Calls radeon_Color4f(), which is expanded inline by the compiler to be * efficient. */ static void radeon_Color3fv( const GLfloat *v ) { radeon_Color4f( v[0], v[1], v[2], 1.0 ); } /** * Calls radeon_TexCoord2f(), which is expanded inline by the compiler to be * efficient. */ static void radeon_TexCoord2fv( const GLfloat *v ) { radeon_TexCoord2f( v[0], v[1] ); } /** * No-op. */ void radeonVtxfmtUnbindContext( GLcontext *ctx ) { } /** * No-op. */ void radeonVtxfmtMakeCurrent( GLcontext *ctx ) { } /** * No-op. */ void radeonVtxfmtDestroy( GLcontext *ctx ) { } /** * \brief Software rendering fallback. * * \param ctx GL context. * \param bit fallback bitmask. * \param mode enable or disable. * * Does nothing except display a warning message if \p mode is set. */ void radeonFallback( GLcontext *ctx, GLuint bit, GLboolean mode ) { if (mode) fprintf(stderr, "Warning: hit nonexistant fallback path!\n"); } /** * \brief Software TCL fallback. * * \param ctx GL context. * \param bit fallback bitmask. * \param mode enable or disable. * * Does nothing except display a warning message if \p mode is set. */ void radeonTclFallback( GLcontext *ctx, GLuint bit, GLboolean mode ) { if (mode) fprintf(stderr, "Warning: hit nonexistant fallback path!\n"); } /** * \brief Called by radeonPointsBitmap() to disable TCL. * * \param rmesa Radeon context. * \param flag whether to enable or disable TCL. * * Updates radeon_tcl_info::tcl_flag. */ void radeonSubsetVtxEnableTCL( radeonContextPtr rmesa, GLboolean flag ) { rmesa->tcl.tcl_flag = flag ? RADEON_CP_VC_CNTL_TCL_ENABLE : 0; } /**********************************************************************/ /** \name Noop mode for operation without focus */ /**********************************************************************/ /*@{*/ /** * \brief Process glBegin(). * * \param mode primitive. */ static void radeon_noop_Begin(GLenum mode) { GET_CURRENT_CONTEXT(ctx); if (mode > GL_POLYGON) { _mesa_error( ctx, GL_INVALID_ENUM, "glBegin" ); return; } if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) { _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" ); return; } ctx->Driver.CurrentExecPrimitive = mode; } /** * \brief Process glEnd(). */ static void radeon_noop_End(void) { GET_CURRENT_CONTEXT(ctx); ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1; } /** * \brief Install the noop callbacks. * * \param ctx GL context. * * Installs the noop callbacks into the glapi table. These functions * will not attempt to emit any DMA vertices, but will keep internal * GL state updated. Borrows heavily from the select code. */ static void radeon_noop_Install( GLcontext *ctx ) { ctx->Exec->Begin = radeon_noop_Begin; ctx->Exec->End = radeon_noop_End; vb.texcoordptr = ctx->Current.Attrib[VERT_ATTRIB_TEX0]; vb.floatcolorptr = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; notify_noop(); } /** * \brief Setup the GL context callbacks. * * \param ctx GL context. * * Setups the GL context callbacks and links _glapi_table entries related to * the glBegin()/glEnd() pairs to the functions in this module. * * Called by radeonCreateContext() and radeonRenderMode(). */ void radeonVtxfmtInit( GLcontext *ctx ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); struct _glapi_table *exec = ctx->Exec; exec->Color3f = radeon_Color3f; exec->Color3fv = radeon_Color3fv; exec->Color4f = radeon_Color4f; exec->Color4fv = radeon_Color4fv; exec->TexCoord2f = radeon_TexCoord2f; exec->TexCoord2fv = radeon_TexCoord2fv; exec->Vertex2f = radeon_Vertex2f; exec->Vertex2fv = radeon_Vertex2fv; exec->Vertex3f = radeon_Vertex3f; exec->Vertex3fv = radeon_Vertex3fv; exec->Begin = radeon_Begin; exec->End = radeon_End; vb.context = ctx; ctx->Driver.FlushVertices = radeonFlushVertices; ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1; if (rmesa->radeonScreen->buffers) { radeonVtxfmtValidate( ctx ); notify_noop(); } else radeon_noop_Install( ctx ); } /*@}*/