/************************************************************************** * * Copyright 2005 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * **************************************************************************/ #include "swrast_setup/swrast_setup.h" #include "swrast/swrast.h" #include "tnl/tnl.h" #include "context.h" #include "brw_context.h" #include "brw_exec.h" #include "brw_save.h" #include "brw_fallback.h" #include "glheader.h" #include "enums.h" #include "glapi.h" #include "imports.h" #include "macros.h" #include "mtypes.h" #include "dispatch.h" typedef void (*attr_func)( GLcontext *ctx, GLint target, const GLfloat * ); /* Wrapper functions in case glVertexAttrib*fvNV doesn't exist */ static void VertexAttrib1fvNV(GLcontext *ctx, GLint target, const GLfloat *v) { CALL_VertexAttrib1fvNV(ctx->Exec, (target, v)); } static void VertexAttrib2fvNV(GLcontext *ctx, GLint target, const GLfloat *v) { CALL_VertexAttrib2fvNV(ctx->Exec, (target, v)); } static void VertexAttrib3fvNV(GLcontext *ctx, GLint target, const GLfloat *v) { CALL_VertexAttrib3fvNV(ctx->Exec, (target, v)); } static void VertexAttrib4fvNV(GLcontext *ctx, GLint target, const GLfloat *v) { CALL_VertexAttrib4fvNV(ctx->Exec, (target, v)); } static attr_func vert_attrfunc[4] = { VertexAttrib1fvNV, VertexAttrib2fvNV, VertexAttrib3fvNV, VertexAttrib4fvNV }; #if 0 static void VertexAttrib1fvARB(GLcontext *ctx, GLint target, const GLfloat *v) { CALL_VertexAttrib1fvARB(ctx->Exec, (target, v)); } static void VertexAttrib2fvARB(GLcontext *ctx, GLint target, const GLfloat *v) { CALL_VertexAttrib2fvARB(ctx->Exec, (target, v)); } static void VertexAttrib3fvARB(GLcontext *ctx, GLint target, const GLfloat *v) { CALL_VertexAttrib3fvARB(ctx->Exec, (target, v)); } static void VertexAttrib4fvARB(GLcontext *ctx, GLint target, const GLfloat *v) { CALL_VertexAttrib4fvARB(ctx->Exec, (target, v)); } static attr_func vert_attrfunc_arb[4] = { VertexAttrib1fvARB, VertexAttrib2fvARB, VertexAttrib3fvARB, VertexAttrib4fvARB }; #endif static void mat_attr1fv( GLcontext *ctx, GLint target, const GLfloat *v ) { switch (target) { case BRW_ATTRIB_MAT_FRONT_SHININESS: CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_SHININESS, v )); break; case BRW_ATTRIB_MAT_BACK_SHININESS: CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_SHININESS, v )); break; } } static void mat_attr3fv( GLcontext *ctx, GLint target, const GLfloat *v ) { switch (target) { case BRW_ATTRIB_MAT_FRONT_INDEXES: CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_COLOR_INDEXES, v )); break; case BRW_ATTRIB_MAT_BACK_INDEXES: CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_COLOR_INDEXES, v )); break; } } static void mat_attr4fv( GLcontext *ctx, GLint target, const GLfloat *v ) { switch (target) { case BRW_ATTRIB_MAT_FRONT_EMISSION: CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_EMISSION, v )); break; case BRW_ATTRIB_MAT_BACK_EMISSION: CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_EMISSION, v )); break; case BRW_ATTRIB_MAT_FRONT_AMBIENT: CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_AMBIENT, v )); break; case BRW_ATTRIB_MAT_BACK_AMBIENT: CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_AMBIENT, v )); break; case BRW_ATTRIB_MAT_FRONT_DIFFUSE: CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_DIFFUSE, v )); break; case BRW_ATTRIB_MAT_BACK_DIFFUSE: CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_DIFFUSE, v )); break; case BRW_ATTRIB_MAT_FRONT_SPECULAR: CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_SPECULAR, v )); break; case BRW_ATTRIB_MAT_BACK_SPECULAR: CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_SPECULAR, v )); break; } } static attr_func mat_attrfunc[4] = { mat_attr1fv, NULL, mat_attr3fv, mat_attr4fv }; static void index_attr1fv(GLcontext *ctx, GLint target, const GLfloat *v) { (void) target; CALL_Indexf(ctx->Exec, (v[0])); } static void edgeflag_attr1fv(GLcontext *ctx, GLint target, const GLfloat *v) { (void) target; CALL_EdgeFlag(ctx->Exec, ((GLboolean)(v[0] == 1.0))); } struct loopback_attr { GLint target; GLint sz; attr_func func; }; /* Don't emit ends and begins on wrapped primitives. Don't replay * wrapped vertices. If we get here, it's probably because the the * precalculated wrapping is wrong. */ static void loopback_prim( GLcontext *ctx, const GLfloat *buffer, const struct brw_draw_prim *prim, GLuint wrap_count, GLuint vertex_size, const struct loopback_attr *la, GLuint nr ) { GLint start = prim->start; GLint end = start + prim->count; const GLfloat *data; GLint j; GLuint k; if (0) _mesa_printf("loopback prim %s(%s,%s) verts %d..%d\n", _mesa_lookup_enum_by_nr(prim->mode), prim->begin ? "begin" : "..", prim->end ? "end" : "..", start, end); if (prim->begin) { CALL_Begin(GET_DISPATCH(), ( prim->mode )); } else { assert(start == 0); start += wrap_count; } data = buffer + start * vertex_size; for (j = start ; j < end ; j++) { const GLfloat *tmp = data + la[0].sz; for (k = 1 ; k < nr ; k++) { la[k].func( ctx, la[k].target, tmp ); tmp += la[k].sz; } /* Fire the vertex */ la[0].func( ctx, BRW_ATTRIB_POS, data ); data = tmp; } if (prim->end) { CALL_End(GET_DISPATCH(), ()); } } /* Primitives generated by DrawArrays/DrawElements/Rectf may be * caught here. If there is no primitive in progress, execute them * normally, otherwise need to track and discard the generated * primitives. */ static void loopback_weak_prim( GLcontext *ctx, const struct brw_draw_prim *prim ) { /* Use the prim_weak flag to ensure that if this primitive * wraps, we don't mistake future vertex_lists for part of the * surrounding primitive. * * While this flag is set, we are simply disposing of data * generated by an operation now known to be a noop. */ if (prim->begin) ctx->Driver.CurrentExecPrimitive |= BRW_SAVE_PRIM_WEAK; if (prim->end) ctx->Driver.CurrentExecPrimitive &= ~BRW_SAVE_PRIM_WEAK; } void brw_loopback_vertex_list( GLcontext *ctx, const GLfloat *buffer, const GLubyte *attrsz, const struct brw_draw_prim *prim, GLuint prim_count, GLuint wrap_count, GLuint vertex_size) { struct loopback_attr la[BRW_ATTRIB_MAX]; GLuint i, nr = 0; for (i = 0 ; i <= BRW_ATTRIB_TEX7 ; i++) { if (attrsz[i]) { la[nr].target = i; la[nr].sz = attrsz[i]; la[nr].func = vert_attrfunc[attrsz[i]-1]; nr++; } } for (i = BRW_ATTRIB_MAT_FRONT_AMBIENT ; i <= BRW_ATTRIB_MAT_BACK_INDEXES ; i++) { if (attrsz[i]) { la[nr].target = i; la[nr].sz = attrsz[i]; la[nr].func = mat_attrfunc[attrsz[i]-1]; nr++; } } if (attrsz[BRW_ATTRIB_EDGEFLAG]) { la[nr].target = BRW_ATTRIB_EDGEFLAG; la[nr].sz = attrsz[BRW_ATTRIB_EDGEFLAG]; la[nr].func = edgeflag_attr1fv; nr++; } if (attrsz[BRW_ATTRIB_INDEX]) { la[nr].target = BRW_ATTRIB_INDEX; la[nr].sz = attrsz[BRW_ATTRIB_INDEX]; la[nr].func = index_attr1fv; nr++; } /* XXX ARB vertex attribs */ for (i = 0 ; i < prim_count ; i++) { if ((prim[i].mode & BRW_SAVE_PRIM_WEAK) && (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END)) { loopback_weak_prim( ctx, &prim[i] ); } else { loopback_prim( ctx, buffer, &prim[i], wrap_count, vertex_size, la, nr ); } } } static GLboolean do_check_fallback(struct brw_context *brw) { GLcontext *ctx = &brw->intel.ctx; GLuint i; /* BRW_NEW_METAOPS */ if (brw->metaops.active) return GL_FALSE; if (brw->intel.no_rast) return GL_TRUE; /* _NEW_BUFFERS */ if (ctx->DrawBuffer->_ColorDrawBufferMask[0] != BUFFER_BIT_FRONT_LEFT && ctx->DrawBuffer->_ColorDrawBufferMask[0] != BUFFER_BIT_BACK_LEFT) return GL_TRUE; /* _NEW_RENDERMODE * * XXX: need to save/restore RenderMode in metaops state, or * somehow move to a new attribs pointer: */ if (ctx->RenderMode != GL_RENDER) return GL_TRUE; /* _NEW_TEXTURE: */ for (i = 0; i < BRW_MAX_TEX_UNIT; i++) { struct gl_texture_unit *texUnit = &brw->attribs.Texture->Unit[i]; if (texUnit->_ReallyEnabled) { struct intel_texture_object *intelObj = intel_texture_object(texUnit->_Current); struct gl_texture_image *texImage = intelObj->base.Image[0][intelObj->firstLevel]; if (texImage->Border) return GL_TRUE; } } /* _NEW_STENCIL */ if (brw->attribs.Stencil->Enabled && !brw->intel.hw_stencil) { return GL_TRUE; } return GL_FALSE; } static void check_fallback(struct brw_context *brw) { brw->intel.Fallback = do_check_fallback(brw); } const struct brw_tracked_state brw_check_fallback = { .dirty = { .mesa = _NEW_BUFFERS | _NEW_RENDERMODE | _NEW_TEXTURE | _NEW_STENCIL, .brw = BRW_NEW_METAOPS, .cache = 0 }, .update = check_fallback }; /* If there is a fallback, fallback to software rasterization and * transformation together. There is never a requirement to have * software t&l but hardware rasterization. * * Further, all fallbacks are based on GL state, not on eg. primitive * or vertex data. */ static void do_fallback( struct brw_context *brw, GLboolean fallback ) { GLcontext *ctx = &brw->intel.ctx; /* flush: */ ctx->Driver.Flush( ctx ); if (fallback) { _swsetup_Wakeup( ctx ); _tnl_wakeup_exec( ctx ); /* Need this because tnl_wakeup_exec does too much: */ brw_save_wakeup(ctx); brw_save_fallback(ctx, GL_TRUE); } else { /* Flush vertices and copy-to-current: */ FLUSH_CURRENT(ctx, 0); _swrast_flush( ctx ); brw_exec_wakeup(ctx); /* Need this because tnl_wakeup_exec does too much: */ brw_save_wakeup(ctx); brw_save_fallback(ctx, GL_FALSE); } } void brw_fallback( GLcontext *ctx ) { struct brw_context *brw = brw_context(ctx); do_fallback(brw, 1); } void brw_unfallback( GLcontext *ctx ) { struct brw_context *brw = brw_context(ctx); do_fallback(brw, 0); } /* Not used: */ void intelFallback( struct intel_context *intel, GLuint bit, GLboolean mode ) { }