diff options
Diffstat (limited to 'src/mesa')
108 files changed, 2937 insertions, 1151 deletions
diff --git a/src/mesa/Makefile b/src/mesa/Makefile index 4ff28dae9bb..bb18bee8eaf 100644 --- a/src/mesa/Makefile +++ b/src/mesa/Makefile @@ -103,7 +103,8 @@ gl_pcedit = sed \ -e 's,@VERSION@,$(MESA_MAJOR).$(MESA_MINOR).$(MESA_TINY),' \ -e 's,@GL_PC_REQ_PRIV@,$(GL_PC_REQ_PRIV),' \ -e 's,@GL_PC_LIB_PRIV@,$(GL_PC_LIB_PRIV),' \ - -e 's,@GL_PC_CFLAGS@,$(GL_PC_CFLAGS),' + -e 's,@GL_PC_CFLAGS@,$(GL_PC_CFLAGS),' \ + -e 's,@GL_LIB@,$(GL_LIB),' gl.pc: gl.pc.in $(gl_pcedit) $< > $@ diff --git a/src/mesa/drivers/dri/i915/i830_context.c b/src/mesa/drivers/dri/i915/i830_context.c index 10b9bf371c3..840946f908d 100644 --- a/src/mesa/drivers/dri/i915/i830_context.c +++ b/src/mesa/drivers/dri/i915/i830_context.c @@ -98,6 +98,8 @@ i830CreateContext(const __GLcontextModes * mesaVis, ctx->Const.MaxTextureRectSize = (1 << 11); ctx->Const.MaxTextureUnits = I830_TEX_UNITS; + ctx->Const.MaxTextureMaxAnisotropy = 2.0; + ctx->Const.MaxDrawBuffers = 1; _tnl_init_vertices(ctx, ctx->Const.MaxArrayLockSize + 12, diff --git a/src/mesa/drivers/dri/i915/i915_context.c b/src/mesa/drivers/dri/i915/i915_context.c index fdd2cf61096..367d2a3b648 100644 --- a/src/mesa/drivers/dri/i915/i915_context.c +++ b/src/mesa/drivers/dri/i915/i915_context.c @@ -73,7 +73,7 @@ i915InvalidateState(GLcontext * ctx, GLuint new_state) p->params_uptodate = 0; } - if (new_state & (_NEW_FOG | _NEW_HINT | _NEW_PROGRAM)) + if (new_state & (_NEW_FOG | _NEW_HINT | _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS)) i915_update_fog(ctx); } @@ -145,6 +145,8 @@ i915CreateContext(const __GLcontextModes * mesaVis, ctx->Const.MaxTextureRectSize = (1 << 11); ctx->Const.MaxTextureUnits = I915_TEX_UNITS; + ctx->Const.MaxTextureMaxAnisotropy = 4.0; + /* GL_ARB_fragment_program limits - don't think Mesa actually * validates programs against these, and in any case one ARB * instruction can translate to more than one HW instruction, so diff --git a/src/mesa/drivers/dri/i915/i915_texstate.c b/src/mesa/drivers/dri/i915/i915_texstate.c index 43f65392b56..a37dd7f4fb5 100644 --- a/src/mesa/drivers/dri/i915/i915_texstate.c +++ b/src/mesa/drivers/dri/i915/i915_texstate.c @@ -132,7 +132,7 @@ i915_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3) struct intel_texture_object *intelObj = intel_texture_object(tObj); struct gl_texture_image *firstImage; GLuint *state = i915->state.Tex[unit], format, pitch; - GLint lodbias; + GLint lodbias, aniso = 0; GLubyte border[4]; memset(state, 0, sizeof(state)); @@ -230,6 +230,10 @@ i915_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3) if (tObj->MaxAnisotropy > 1.0) { minFilt = FILTER_ANISOTROPIC; magFilt = FILTER_ANISOTROPIC; + if (tObj->MaxAnisotropy > 2.0) + aniso = SS2_MAX_ANISO_4; + else + aniso = SS2_MAX_ANISO_2; } else { switch (tObj->MagFilter) { @@ -275,7 +279,8 @@ i915_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3) state[I915_TEXREG_SS2] |= ((minFilt << SS2_MIN_FILTER_SHIFT) | (mipFilt << SS2_MIP_FILTER_SHIFT) | - (magFilt << SS2_MAG_FILTER_SHIFT)); + (magFilt << SS2_MAG_FILTER_SHIFT) | + aniso); } { diff --git a/src/mesa/drivers/dri/i915/intel_generatemipmap.c b/src/mesa/drivers/dri/i915/intel_generatemipmap.c new file mode 120000 index 00000000000..4c6b37ada01 --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_generatemipmap.c @@ -0,0 +1 @@ +../intel/intel_generatemipmap.c
\ No newline at end of file diff --git a/src/mesa/drivers/dri/i965/Makefile b/src/mesa/drivers/dri/i965/Makefile index 2934414d99a..9712c387254 100644 --- a/src/mesa/drivers/dri/i965/Makefile +++ b/src/mesa/drivers/dri/i965/Makefile @@ -14,6 +14,7 @@ DRIVER_SOURCES = \ intel_decode.c \ intel_extensions.c \ intel_fbo.c \ + intel_generatemipmap.c \ intel_mipmap_tree.c \ intel_regions.c \ intel_screen.c \ @@ -69,6 +70,7 @@ DRIVER_SOURCES = \ brw_vs_constval.c \ brw_vs_emit.c \ brw_vs_state.c \ + brw_vs_surface_state.c \ brw_vtbl.c \ brw_wm.c \ brw_wm_debug.c \ diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c index d96ff293102..4dbe551d832 100644 --- a/src/mesa/drivers/dri/i965/brw_context.c +++ b/src/mesa/drivers/dri/i965/brw_context.c @@ -118,6 +118,8 @@ GLboolean brwCreateContext( const __GLcontextModes *mesaVis, ctx->Const.MaxCubeTextureLevels = 12; ctx->Const.MaxTextureRectSize = (1<<12); + ctx->Const.MaxTextureMaxAnisotropy = 16.0; + /* if conformance mode is set, swrast can handle any size AA point */ ctx->Const.MaxPointSizeAA = 255.0; diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h index a0b3b06309f..873fc8ffff6 100644 --- a/src/mesa/drivers/dri/i965/brw_context.h +++ b/src/mesa/drivers/dri/i965/brw_context.h @@ -131,6 +131,7 @@ struct brw_context; #define BRW_NEW_WM_INPUT_DIMENSIONS 0x100 #define BRW_NEW_INPUT_VARYING 0x200 #define BRW_NEW_PSP 0x800 +#define BRW_NEW_WM_SURFACES 0x1000 #define BRW_NEW_FENCE 0x2000 #define BRW_NEW_INDICES 0x4000 #define BRW_NEW_VERTICES 0x8000 @@ -161,6 +162,7 @@ struct brw_vertex_program { struct gl_vertex_program program; GLuint id; dri_bo *const_buffer; /** Program constant buffer/surface */ + GLboolean use_const_buffer; }; @@ -171,6 +173,7 @@ struct brw_fragment_program { GLboolean isGLSL; /**< really, any IF/LOOP/CONT/BREAK instructions */ dri_bo *const_buffer; /** Program constant buffer/surface */ + GLboolean use_const_buffer; }; @@ -243,6 +246,9 @@ struct brw_vs_ouput_sizes { }; +/** Number of general purpose registers (VS, WM, etc) */ +#define BRW_MAX_GRF 128 + /** Number of texture sampler units */ #define BRW_MAX_TEX_UNIT 16 @@ -448,8 +454,6 @@ struct brw_context struct { struct brw_state_flags dirty; - struct brw_tracked_state **atoms; - GLuint nr_atoms; GLuint nr_color_regions; struct intel_region *color_regions[MAX_DRAW_BUFFERS]; @@ -469,7 +473,8 @@ struct brw_context int validated_bo_count; } state; - struct brw_cache cache; + struct brw_cache cache; /** non-surface items */ + struct brw_cache surface_cache; /* surface items */ struct brw_cached_batch_item *cached_batch_items; struct { @@ -553,11 +558,6 @@ struct brw_context GLuint vs_size; GLuint total_size; - /* Dynamic tracker which changes to reflect the state referenced - * by active fp and vp program parameters: - */ - struct brw_tracked_state tracked_state; - dri_bo *curbe_bo; /** Offset within curbe_bo of space for current curbe entry */ GLuint curbe_offset; diff --git a/src/mesa/drivers/dri/i965/brw_curbe.c b/src/mesa/drivers/dri/i965/brw_curbe.c index 18b187ed1dc..a1a6c53d0e0 100644 --- a/src/mesa/drivers/dri/i965/brw_curbe.c +++ b/src/mesa/drivers/dri/i965/brw_curbe.c @@ -36,6 +36,7 @@ #include "main/macros.h" #include "main/enums.h" #include "shader/prog_parameter.h" +#include "shader/prog_print.h" #include "shader/prog_statevars.h" #include "intel_batchbuffer.h" #include "intel_regions.h" @@ -188,13 +189,6 @@ static void prepare_constant_buffer(struct brw_context *brw) GLfloat *buf; GLuint i; - /* Update our own dependency flags. This works because this - * function will also be called whenever fp or vp changes. - */ - brw->curbe.tracked_state.dirty.mesa = (_NEW_TRANSFORM|_NEW_PROJECTION); - brw->curbe.tracked_state.dirty.mesa |= vp->program.Base.Parameters->StateFlags; - brw->curbe.tracked_state.dirty.mesa |= fp->program.Base.Parameters->StateFlags; - if (sz == 0) { if (brw->curbe.last_buf) { free(brw->curbe.last_buf); @@ -335,72 +329,11 @@ static void prepare_constant_buffer(struct brw_context *brw) */ } - -/** - * Copy Mesa program parameters into given constant buffer. - */ -static void -update_constant_buffer(struct brw_context *brw, - const struct gl_program_parameter_list *params, - dri_bo *const_buffer) -{ - const int size = params->NumParameters * 4 * sizeof(GLfloat); - - /* copy Mesa program constants into the buffer */ - if (const_buffer && size > 0) { - GLubyte *map; - - assert(const_buffer); - assert(const_buffer->size >= size); - - dri_bo_map(const_buffer, GL_TRUE); - map = const_buffer->virtual; - memcpy(map, params->ParameterValues, size); - dri_bo_unmap(const_buffer); - - if (0) { - int i; - for (i = 0; i < params->NumParameters; i++) { - float *p = params->ParameterValues[i]; - printf("%d: %f %f %f %f\n", i, p[0], p[1], p[2], p[3]); - } - } - } -} - - -/** Copy current vertex program's parameters into the constant buffer */ -static void -update_vertex_constant_buffer(struct brw_context *brw) -{ - struct brw_vertex_program *vp = - (struct brw_vertex_program *) brw->vertex_program; - if (0) { - printf("update VS constants in buffer %p\n", vp->const_buffer); - printf("program %u\n", vp->program.Base.Id); - } - update_constant_buffer(brw, vp->program.Base.Parameters, vp->const_buffer); -} - - -/** Copy current fragment program's parameters into the constant buffer */ -static void -update_fragment_constant_buffer(struct brw_context *brw) -{ - struct brw_fragment_program *fp = - (struct brw_fragment_program *) brw->fragment_program; - update_constant_buffer(brw, fp->program.Base.Parameters, fp->const_buffer); -} - - static void emit_constant_buffer(struct brw_context *brw) { struct intel_context *intel = &brw->intel; GLuint sz = brw->curbe.total_size; - update_vertex_constant_buffer(brw); - update_fragment_constant_buffer(brw); - BEGIN_BATCH(2, IGNORE_CLIPRECTS); if (sz == 0) { OUT_BATCH((CMD_CONST_BUFFER << 16) | (2 - 2)); @@ -422,7 +355,7 @@ static void emit_constant_buffer(struct brw_context *brw) */ const struct brw_tracked_state brw_constant_buffer = { .dirty = { - .mesa = (_NEW_TRANSFORM|_NEW_PROJECTION), /* plus fp and vp flags */ + .mesa = _NEW_PROGRAM_CONSTANTS, .brw = (BRW_NEW_FRAGMENT_PROGRAM | BRW_NEW_VERTEX_PROGRAM | BRW_NEW_URB_FENCE | /* Implicit - hardware requires this, not used above */ diff --git a/src/mesa/drivers/dri/i965/brw_misc_state.c b/src/mesa/drivers/dri/i965/brw_misc_state.c index 9bc5c35139c..4784254bc7d 100644 --- a/src/mesa/drivers/dri/i965/brw_misc_state.c +++ b/src/mesa/drivers/dri/i965/brw_misc_state.c @@ -118,7 +118,10 @@ static void upload_binding_table_pointers(struct brw_context *brw) BEGIN_BATCH(6, IGNORE_CLIPRECTS); OUT_BATCH(CMD_BINDING_TABLE_PTRS << 16 | (6 - 2)); - OUT_RELOC(brw->vs.bind_bo, I915_GEM_DOMAIN_SAMPLER, 0, 0); /* vs */ + if (brw->vs.bind_bo != NULL) + OUT_RELOC(brw->vs.bind_bo, I915_GEM_DOMAIN_SAMPLER, 0, 0); /* vs */ + else + OUT_BATCH(0); OUT_BATCH(0); /* gs */ OUT_BATCH(0); /* clip */ OUT_BATCH(0); /* sf */ diff --git a/src/mesa/drivers/dri/i965/brw_sf_state.c b/src/mesa/drivers/dri/i965/brw_sf_state.c index fc4eddda0a5..68fa9820b6f 100644 --- a/src/mesa/drivers/dri/i965/brw_sf_state.c +++ b/src/mesa/drivers/dri/i965/brw_sf_state.c @@ -147,7 +147,7 @@ sf_unit_populate_key(struct brw_context *brw, struct brw_sf_unit_key *key) key->line_smooth = ctx->Line.SmoothFlag; key->point_sprite = ctx->Point.PointSprite; - key->point_size = ctx->Point.Size; + key->point_size = CLAMP(ctx->Point.Size, ctx->Point.MinSize, ctx->Point.MaxSize); key->point_attenuated = ctx->Point._Attenuated; key->render_to_fbo = brw->intel.ctx.DrawBuffer->Name != 0; diff --git a/src/mesa/drivers/dri/i965/brw_state.h b/src/mesa/drivers/dri/i965/brw_state.h index 81b0a45998f..bf9f6cae55e 100644 --- a/src/mesa/drivers/dri/i965/brw_state.h +++ b/src/mesa/drivers/dri/i965/brw_state.h @@ -72,11 +72,13 @@ const struct brw_tracked_state brw_sf_vp; const struct brw_tracked_state brw_state_base_address; const struct brw_tracked_state brw_urb_fence; const struct brw_tracked_state brw_vertex_state; +const struct brw_tracked_state brw_vs_surfaces; const struct brw_tracked_state brw_vs_prog; const struct brw_tracked_state brw_vs_unit; const struct brw_tracked_state brw_wm_input_sizes; const struct brw_tracked_state brw_wm_prog; const struct brw_tracked_state brw_wm_samplers; +const struct brw_tracked_state brw_wm_constant_surface; const struct brw_tracked_state brw_wm_surfaces; const struct brw_tracked_state brw_wm_unit; @@ -91,6 +93,20 @@ const struct brw_tracked_state brw_drawing_rect; const struct brw_tracked_state brw_indices; const struct brw_tracked_state brw_vertices; +/** + * Use same key for WM and VS surfaces. + */ +struct brw_surface_key { + GLenum target, depthmode; + dri_bo *bo; + GLint format, internal_format; + GLint first_level, last_level; + GLint width, height, depth; + GLint pitch, cpp; + uint32_t tiling; + GLuint offset; +}; + /*********************************************************************** * brw_state.c */ @@ -135,8 +151,8 @@ dri_bo *brw_search_cache( struct brw_cache *cache, void *aux_return); void brw_state_cache_check_size( struct brw_context *brw ); -void brw_init_cache( struct brw_context *brw ); -void brw_destroy_cache( struct brw_context *brw ); +void brw_init_caches( struct brw_context *brw ); +void brw_destroy_caches( struct brw_context *brw ); /*********************************************************************** * brw_state_batch.c @@ -150,4 +166,9 @@ GLboolean brw_cached_batch_struct( struct brw_context *brw, void brw_destroy_batch_cache( struct brw_context *brw ); void brw_clear_batch_cache_flush( struct brw_context *brw ); +/* brw_wm_surface_state.c */ +dri_bo * +brw_create_constant_surface( struct brw_context *brw, + struct brw_surface_key *key ); + #endif diff --git a/src/mesa/drivers/dri/i965/brw_state_cache.c b/src/mesa/drivers/dri/i965/brw_state_cache.c index d5b51664066..e40d7a04164 100644 --- a/src/mesa/drivers/dri/i965/brw_state_cache.c +++ b/src/mesa/drivers/dri/i965/brw_state_cache.c @@ -56,9 +56,9 @@ * incorrect program is run for the other instance. */ +#include "main/imports.h" #include "brw_state.h" #include "intel_batchbuffer.h" -#include "main/imports.h" /* XXX: Fixme - have to include these to get the sizes of the prog_key * structs: @@ -69,8 +69,10 @@ #include "brw_sf.h" #include "brw_gs.h" -static GLuint hash_key( const void *key, GLuint key_size, - dri_bo **reloc_bufs, GLuint nr_reloc_bufs) + +static GLuint +hash_key(const void *key, GLuint key_size, + dri_bo **reloc_bufs, GLuint nr_reloc_bufs) { GLuint *ikey = (GLuint *)key; GLuint hash = 0, i; @@ -95,6 +97,7 @@ static GLuint hash_key( const void *key, GLuint key_size, return hash; } + /** * Marks a new buffer as being chosen for the given cache id. */ @@ -111,6 +114,7 @@ update_cache_last(struct brw_cache *cache, enum brw_cache_id cache_id, cache->brw->state.dirty.cache |= 1 << cache_id; } + static struct brw_cache_item * search_cache(struct brw_cache *cache, enum brw_cache_id cache_id, GLuint hash, const void *key, GLuint key_size, @@ -143,7 +147,8 @@ search_cache(struct brw_cache *cache, enum brw_cache_id cache_id, } -static void rehash( struct brw_cache *cache ) +static void +rehash(struct brw_cache *cache) { struct brw_cache_item **items; struct brw_cache_item *c, *next; @@ -164,15 +169,17 @@ static void rehash( struct brw_cache *cache ) cache->size = size; } + /** * Returns the buffer object matching cache_id and key, or NULL. */ -dri_bo *brw_search_cache( struct brw_cache *cache, - enum brw_cache_id cache_id, - const void *key, - GLuint key_size, - dri_bo **reloc_bufs, GLuint nr_reloc_bufs, - void *aux_return ) +dri_bo * +brw_search_cache(struct brw_cache *cache, + enum brw_cache_id cache_id, + const void *key, + GLuint key_size, + dri_bo **reloc_bufs, GLuint nr_reloc_bufs, + void *aux_return) { struct brw_cache_item *item; GLuint hash = hash_key(key, key_size, reloc_bufs, nr_reloc_bufs); @@ -192,6 +199,7 @@ dri_bo *brw_search_cache( struct brw_cache *cache, return item->bo; } + dri_bo * brw_upload_cache( struct brw_cache *cache, enum brw_cache_id cache_id, @@ -265,7 +273,9 @@ brw_upload_cache( struct brw_cache *cache, return bo; } -/* This doesn't really work with aux data. Use search/upload instead + +/** + * This doesn't really work with aux data. Use search/upload instead */ dri_bo * brw_cache_data_sz(struct brw_cache *cache, @@ -296,6 +306,7 @@ brw_cache_data_sz(struct brw_cache *cache, return bo; } + /** * Wrapper around brw_cache_data_sz using the cache_id's canonical key size. * @@ -319,21 +330,22 @@ enum pool_type { DW_GENERAL_STATE }; + static void -brw_init_cache_id( struct brw_context *brw, - const char *name, - enum brw_cache_id id, - GLuint key_size, - GLuint aux_size) +brw_init_cache_id(struct brw_cache *cache, + const char *name, + enum brw_cache_id id, + GLuint key_size, + GLuint aux_size) { - struct brw_cache *cache = &brw->cache; - cache->name[id] = strdup(name); cache->key_size[id] = key_size; cache->aux_size[id] = aux_size; } -void brw_init_cache( struct brw_context *brw ) + +static void +brw_init_non_surface_cache(struct brw_context *brw) { struct brw_cache *cache = &brw->cache; @@ -342,114 +354,136 @@ void brw_init_cache( struct brw_context *brw ) cache->size = 7; cache->n_items = 0; cache->items = (struct brw_cache_item **) - _mesa_calloc(cache->size * - sizeof(struct brw_cache_item)); + _mesa_calloc(cache->size * sizeof(struct brw_cache_item)); - brw_init_cache_id(brw, + brw_init_cache_id(cache, "CC_VP", BRW_CC_VP, sizeof(struct brw_cc_viewport), 0); - brw_init_cache_id(brw, + brw_init_cache_id(cache, "CC_UNIT", BRW_CC_UNIT, sizeof(struct brw_cc_unit_state), 0); - brw_init_cache_id(brw, + brw_init_cache_id(cache, "WM_PROG", BRW_WM_PROG, sizeof(struct brw_wm_prog_key), sizeof(struct brw_wm_prog_data)); - brw_init_cache_id(brw, + brw_init_cache_id(cache, "SAMPLER_DEFAULT_COLOR", BRW_SAMPLER_DEFAULT_COLOR, sizeof(struct brw_sampler_default_color), 0); - brw_init_cache_id(brw, + brw_init_cache_id(cache, "SAMPLER", BRW_SAMPLER, 0, /* variable key/data size */ 0); - brw_init_cache_id(brw, + brw_init_cache_id(cache, "WM_UNIT", BRW_WM_UNIT, sizeof(struct brw_wm_unit_state), 0); - brw_init_cache_id(brw, + brw_init_cache_id(cache, "SF_PROG", BRW_SF_PROG, sizeof(struct brw_sf_prog_key), sizeof(struct brw_sf_prog_data)); - brw_init_cache_id(brw, + brw_init_cache_id(cache, "SF_VP", BRW_SF_VP, sizeof(struct brw_sf_viewport), 0); - brw_init_cache_id(brw, + brw_init_cache_id(cache, "SF_UNIT", BRW_SF_UNIT, sizeof(struct brw_sf_unit_state), 0); - brw_init_cache_id(brw, + brw_init_cache_id(cache, "VS_UNIT", BRW_VS_UNIT, sizeof(struct brw_vs_unit_state), 0); - brw_init_cache_id(brw, + brw_init_cache_id(cache, "VS_PROG", BRW_VS_PROG, sizeof(struct brw_vs_prog_key), sizeof(struct brw_vs_prog_data)); - brw_init_cache_id(brw, + brw_init_cache_id(cache, "CLIP_UNIT", BRW_CLIP_UNIT, sizeof(struct brw_clip_unit_state), 0); - brw_init_cache_id(brw, + brw_init_cache_id(cache, "CLIP_PROG", BRW_CLIP_PROG, sizeof(struct brw_clip_prog_key), sizeof(struct brw_clip_prog_data)); - brw_init_cache_id(brw, + brw_init_cache_id(cache, "GS_UNIT", BRW_GS_UNIT, sizeof(struct brw_gs_unit_state), 0); - brw_init_cache_id(brw, + brw_init_cache_id(cache, "GS_PROG", BRW_GS_PROG, sizeof(struct brw_gs_prog_key), sizeof(struct brw_gs_prog_data)); +} + + +static void +brw_init_surface_cache(struct brw_context *brw) +{ + struct brw_cache *cache = &brw->surface_cache; + + cache->brw = brw; - brw_init_cache_id(brw, + cache->size = 7; + cache->n_items = 0; + cache->items = (struct brw_cache_item **) + _mesa_calloc(cache->size * sizeof(struct brw_cache_item)); + + brw_init_cache_id(cache, "SS_SURFACE", BRW_SS_SURFACE, sizeof(struct brw_surface_state), 0); - brw_init_cache_id(brw, + brw_init_cache_id(cache, "SS_SURF_BIND", BRW_SS_SURF_BIND, 0, 0); } + +void +brw_init_caches(struct brw_context *brw) +{ + brw_init_non_surface_cache(brw); + brw_init_surface_cache(brw); +} + + static void -brw_clear_cache( struct brw_context *brw ) +brw_clear_cache(struct brw_context *brw, struct brw_cache *cache) { struct brw_cache_item *c, *next; GLuint i; @@ -457,8 +491,8 @@ brw_clear_cache( struct brw_context *brw ) if (INTEL_DEBUG & DEBUG_STATE) _mesa_printf("%s\n", __FUNCTION__); - for (i = 0; i < brw->cache.size; i++) { - for (c = brw->cache.items[i]; c; c = next) { + for (i = 0; i < cache->size; i++) { + for (c = cache->items[i]; c; c = next) { int j; next = c->next; @@ -468,10 +502,10 @@ brw_clear_cache( struct brw_context *brw ) free((void *)c->key); free(c); } - brw->cache.items[i] = NULL; + cache->items[i] = NULL; } - brw->cache.n_items = 0; + cache->n_items = 0; if (brw->curbe.last_buf) { _mesa_free(brw->curbe.last_buf); @@ -483,25 +517,46 @@ brw_clear_cache( struct brw_context *brw ) brw->state.dirty.cache |= ~0; } -void brw_state_cache_check_size( struct brw_context *brw ) + +void +brw_state_cache_check_size(struct brw_context *brw) { + if (INTEL_DEBUG & DEBUG_STATE) + _mesa_printf("%s (n_items=%d)\n", __FUNCTION__, brw->cache.n_items); + /* un-tuned guess. We've got around 20 state objects for a total of around * 32k, so 1000 of them is around 1.5MB. */ if (brw->cache.n_items > 1000) - brw_clear_cache(brw); + brw_clear_cache(brw, &brw->cache); + + if (brw->surface_cache.n_items > 1000) + brw_clear_cache(brw, &brw->surface_cache); } -void brw_destroy_cache( struct brw_context *brw ) + +static void +brw_destroy_cache(struct brw_context *brw, struct brw_cache *cache) { GLuint i; - brw_clear_cache(brw); + if (INTEL_DEBUG & DEBUG_STATE) + _mesa_printf("%s\n", __FUNCTION__); + + brw_clear_cache(brw, cache); for (i = 0; i < BRW_MAX_CACHE; i++) { - dri_bo_unreference(brw->cache.last_bo[i]); - free(brw->cache.name[i]); + dri_bo_unreference(cache->last_bo[i]); + free(cache->name[i]); } - free(brw->cache.items); - brw->cache.items = NULL; - brw->cache.size = 0; + free(cache->items); + cache->items = NULL; + cache->size = 0; +} + + +void +brw_destroy_caches(struct brw_context *brw) +{ + brw_destroy_cache(brw, &brw->cache); + brw_destroy_cache(brw, &brw->surface_cache); } diff --git a/src/mesa/drivers/dri/i965/brw_state_upload.c b/src/mesa/drivers/dri/i965/brw_state_upload.c index 5de1450e612..c6dfea4743c 100644 --- a/src/mesa/drivers/dri/i965/brw_state_upload.c +++ b/src/mesa/drivers/dri/i965/brw_state_upload.c @@ -59,11 +59,12 @@ const struct brw_tracked_state *atoms[] = &brw_curbe_offsets, &brw_recalculate_urb_fence, - &brw_cc_vp, &brw_cc_unit, - &brw_wm_surfaces, /* must do before samplers */ + &brw_vs_surfaces, /* must do before unit */ + &brw_wm_constant_surface, /* must do before wm surfaces/bind bo */ + &brw_wm_surfaces, /* must do before samplers and unit */ &brw_wm_samplers, &brw_wm_unit, @@ -88,54 +89,26 @@ const struct brw_tracked_state *atoms[] = &brw_line_stipple, &brw_aa_line_parameters, - /* Ordering of the commands below is documented as fixed. - */ -#if 0 - &brw_pipelined_state_pointers, - &brw_urb_fence, - &brw_constant_buffer_state, -#else + &brw_psp_urb_cbs, -#endif &brw_drawing_rect, &brw_indices, &brw_vertices, - NULL, /* brw_constant_buffer */ + &brw_constant_buffer }; void brw_init_state( struct brw_context *brw ) { - GLuint i; - - brw_init_cache(brw); - - brw->state.atoms = _mesa_malloc(sizeof(atoms)); - brw->state.nr_atoms = sizeof(atoms)/sizeof(*atoms); - _mesa_memcpy(brw->state.atoms, atoms, sizeof(atoms)); - - /* Patch in a pointer to the dynamic state atom: - */ - for (i = 0; i < brw->state.nr_atoms; i++) - if (brw->state.atoms[i] == NULL) - brw->state.atoms[i] = &brw->curbe.tracked_state; - - _mesa_memcpy(&brw->curbe.tracked_state, - &brw_constant_buffer, - sizeof(brw_constant_buffer)); + brw_init_caches(brw); } void brw_destroy_state( struct brw_context *brw ) { - if (brw->state.atoms) { - _mesa_free(brw->state.atoms); - brw->state.atoms = NULL; - } - - brw_destroy_cache(brw); + brw_destroy_caches(brw); brw_destroy_batch_cache(brw); } @@ -218,6 +191,7 @@ static struct dirty_bit_map mesa_bits[] = { DEFINE_BIT(_NEW_MULTISAMPLE), DEFINE_BIT(_NEW_TRACK_MATRIX), DEFINE_BIT(_NEW_PROGRAM), + DEFINE_BIT(_NEW_PROGRAM_CONSTANTS), {0, 0, 0} }; @@ -336,7 +310,7 @@ void brw_validate_state( struct brw_context *brw ) /* do prepare stage for all atoms */ for (i = 0; i < Elements(atoms); i++) { - const struct brw_tracked_state *atom = brw->state.atoms[i]; + const struct brw_tracked_state *atom = atoms[i]; if (brw->intel.Fallback) break; @@ -367,8 +341,8 @@ void brw_upload_state(struct brw_context *brw) _mesa_memset(&examined, 0, sizeof(examined)); prev = *state; - for (i = 0; i < brw->state.nr_atoms; i++) { - const struct brw_tracked_state *atom = brw->state.atoms[i]; + for (i = 0; i < Elements(atoms); i++) { + const struct brw_tracked_state *atom = atoms[i]; struct brw_state_flags generated; assert(atom->dirty.mesa || @@ -397,7 +371,7 @@ void brw_upload_state(struct brw_context *brw) } else { for (i = 0; i < Elements(atoms); i++) { - const struct brw_tracked_state *atom = brw->state.atoms[i]; + const struct brw_tracked_state *atom = atoms[i]; if (brw->intel.Fallback) break; diff --git a/src/mesa/drivers/dri/i965/brw_vs.h b/src/mesa/drivers/dri/i965/brw_vs.h index d20cf78b8af..1e4f66091e3 100644 --- a/src/mesa/drivers/dri/i965/brw_vs.h +++ b/src/mesa/drivers/dri/i965/brw_vs.h @@ -75,8 +75,6 @@ struct brw_vs_compile { struct brw_reg userplane[6]; - /** using a real constant buffer? */ - GLboolean use_const_buffer; /** we may need up to 3 constants per instruction (if use_const_buffer) */ struct { GLint index; diff --git a/src/mesa/drivers/dri/i965/brw_vs_emit.c b/src/mesa/drivers/dri/i965/brw_vs_emit.c index 524f1211cee..d7f75e3685e 100644 --- a/src/mesa/drivers/dri/i965/brw_vs_emit.c +++ b/src/mesa/drivers/dri/i965/brw_vs_emit.c @@ -69,13 +69,18 @@ static void brw_vs_alloc_regs( struct brw_vs_compile *c ) { GLuint i, reg = 0, mrf; -#if 0 - if (c->vp->program.Base.Parameters->NumParameters >= 6) - c->use_const_buffer = 1; + /* Determine whether to use a real constant buffer or use a block + * of GRF registers for constants. The later is faster but only + * works if everything fits in the GRF. + * XXX this heuristic/check may need some fine tuning... + */ + if (c->vp->program.Base.Parameters->NumParameters + + c->vp->program.Base.NumTemporaries + 20 > BRW_MAX_GRF) + c->vp->use_const_buffer = GL_TRUE; else -#endif - c->use_const_buffer = GL_FALSE; - /*printf("use_const_buffer = %d\n", c->use_const_buffer);*/ + c->vp->use_const_buffer = GL_FALSE; + + /*printf("use_const_buffer = %d\n", c->vp->use_const_buffer);*/ /* r0 -- reserved as usual */ @@ -96,7 +101,7 @@ static void brw_vs_alloc_regs( struct brw_vs_compile *c ) /* Vertex program parameters from curbe: */ - if (c->use_const_buffer) { + if (c->vp->use_const_buffer) { /* get constants from a real constant buffer */ c->prog_data.curb_read_length = 0; c->prog_data.nr_params = 4; /* XXX 0 causes a bug elsewhere... */ @@ -172,7 +177,7 @@ static void brw_vs_alloc_regs( struct brw_vs_compile *c ) reg++; } - if (c->use_const_buffer) { + if (c->vp->use_const_buffer) { for (i = 0; i < 3; i++) { c->current_const[i].index = -1; c->current_const[i].reg = brw_vec8_grf(reg, 0); @@ -709,10 +714,11 @@ get_constant(struct brw_vs_compile *c, struct brw_compile *p = &c->func; struct brw_reg const_reg; struct brw_reg const2_reg; + const GLboolean relAddr = src->RelAddr; assert(argIndex < 3); - if (c->current_const[argIndex].index != src->Index || src->RelAddr) { + if (c->current_const[argIndex].index != src->Index || relAddr) { struct brw_reg addrReg = c->regs[PROGRAM_ADDRESS][0]; c->current_const[argIndex].index = src->Index; @@ -725,13 +731,13 @@ get_constant(struct brw_vs_compile *c, brw_dp_READ_4_vs(p, c->current_const[argIndex].reg,/* writeback dest */ 0, /* oword */ - src->RelAddr, /* relative indexing? */ + relAddr, /* relative indexing? */ addrReg, /* address register */ 16 * src->Index, /* byte offset */ SURF_INDEX_VERT_CONST_BUFFER /* binding table index */ ); - if (src->RelAddr) { + if (relAddr) { /* second read */ const2_reg = get_tmp(c); @@ -742,7 +748,7 @@ get_constant(struct brw_vs_compile *c, brw_dp_READ_4_vs(p, const2_reg, /* writeback dest */ 1, /* oword */ - src->RelAddr, /* relative indexing? */ + relAddr, /* relative indexing? */ addrReg, /* address register */ 16 * src->Index, /* byte offset */ SURF_INDEX_VERT_CONST_BUFFER @@ -752,7 +758,7 @@ get_constant(struct brw_vs_compile *c, const_reg = c->current_const[argIndex].reg; - if (src->RelAddr) { + if (relAddr) { /* merge the two Owords into the constant register */ /* const_reg[7..4] = const2_reg[7..4] */ brw_MOV(p, @@ -869,7 +875,7 @@ get_src_reg( struct brw_vs_compile *c, case PROGRAM_STATE_VAR: case PROGRAM_CONSTANT: case PROGRAM_UNIFORM: - if (c->use_const_buffer) { + if (c->vp->use_const_buffer) { return get_constant(c, inst, argIndex); } else if (relAddr) { @@ -1219,7 +1225,7 @@ void brw_vs_emit(struct brw_vs_compile *c ) for (insn = 0; insn < nr_insns; insn++) { - struct prog_instruction *inst = &c->vp->program.Base.Instructions[insn]; + const struct prog_instruction *inst = &c->vp->program.Base.Instructions[insn]; struct brw_reg args[3], dst; GLuint i; @@ -1232,7 +1238,7 @@ void brw_vs_emit(struct brw_vs_compile *c ) */ if (inst->Opcode != OPCODE_SWZ) for (i = 0; i < 3; i++) { - struct prog_src_register *src = &inst->SrcReg[i]; + const struct prog_src_register *src = &inst->SrcReg[i]; index = src->Index; file = src->File; if (file == PROGRAM_OUTPUT && c->output_regs[index].used_in_src) diff --git a/src/mesa/drivers/dri/i965/brw_vs_surface_state.c b/src/mesa/drivers/dri/i965/brw_vs_surface_state.c new file mode 100644 index 00000000000..89f47522a1c --- /dev/null +++ b/src/mesa/drivers/dri/i965/brw_vs_surface_state.c @@ -0,0 +1,226 @@ +/* + Copyright (C) Intel Corp. 2006. All Rights Reserved. + Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to + develop this 3D driver. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice (including the + next paragraph) shall be included in all copies or substantial + portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + **********************************************************************/ + /* + * Authors: + * Keith Whitwell <[email protected]> + */ + +#include "main/mtypes.h" +#include "main/texformat.h" +#include "main/texstore.h" +#include "shader/prog_parameter.h" + +#include "brw_context.h" +#include "brw_state.h" +#include "brw_defines.h" + +/* Creates a new VS constant buffer reflecting the current VS program's + * constants, if needed by the VS program. + * + * Otherwise, constants go through the CURBEs using the brw_constant_buffer + * state atom. + */ +static drm_intel_bo * +brw_vs_update_constant_buffer(struct brw_context *brw) +{ + struct intel_context *intel = &brw->intel; + struct brw_vertex_program *vp = + (struct brw_vertex_program *) brw->vertex_program; + const struct gl_program_parameter_list *params = vp->program.Base.Parameters; + const int size = params->NumParameters * 4 * sizeof(GLfloat); + drm_intel_bo *const_buffer; + + /* BRW_NEW_VERTEX_PROGRAM */ + if (!vp->use_const_buffer) + return NULL; + + const_buffer = drm_intel_bo_alloc(intel->bufmgr, "vp_const_buffer", + size, 64); + + /* _NEW_PROGRAM_CONSTANTS */ + dri_bo_subdata(const_buffer, 0, size, params->ParameterValues); + + return const_buffer; +} + +/** + * Update the surface state for a VS constant buffer. + * + * Sets brw->vs.surf_bo[surf] and brw->vp->const_buffer. + */ +static void +brw_update_vs_constant_surface( GLcontext *ctx, + GLuint surf) +{ + struct brw_context *brw = brw_context(ctx); + struct brw_surface_key key; + struct brw_vertex_program *vp = + (struct brw_vertex_program *) brw->vertex_program; + const struct gl_program_parameter_list *params = vp->program.Base.Parameters; + + assert(surf == 0); + + /* If we're in this state update atom, we need to update VS constants, so + * free the old buffer and create a new one for the new contents. + */ + dri_bo_unreference(vp->const_buffer); + vp->const_buffer = brw_vs_update_constant_buffer(brw); + + /* If there's no constant buffer, then no surface BO is needed to point at + * it. + */ + if (vp->const_buffer == 0) { + drm_intel_bo_unreference(brw->vs.surf_bo[surf]); + brw->vs.surf_bo[surf] = NULL; + return; + } + + memset(&key, 0, sizeof(key)); + + key.format = MESA_FORMAT_RGBA_FLOAT32; + key.internal_format = GL_RGBA; + key.bo = vp->const_buffer; + key.depthmode = GL_NONE; + key.pitch = params->NumParameters; + key.width = params->NumParameters; + key.height = 1; + key.depth = 1; + key.cpp = 16; + + /* + printf("%s:\n", __FUNCTION__); + printf(" width %d height %d depth %d cpp %d pitch %d\n", + key.width, key.height, key.depth, key.cpp, key.pitch); + */ + + drm_intel_bo_unreference(brw->vs.surf_bo[surf]); + brw->vs.surf_bo[surf] = brw_search_cache(&brw->surface_cache, + BRW_SS_SURFACE, + &key, sizeof(key), + &key.bo, key.bo ? 1 : 0, + NULL); + if (brw->vs.surf_bo[surf] == NULL) { + brw->vs.surf_bo[surf] = brw_create_constant_surface(brw, &key); + } +} + + +/** + * Constructs the binding table for the VS surface state. + */ +static dri_bo * +brw_vs_get_binding_table(struct brw_context *brw) +{ + dri_bo *bind_bo; + + bind_bo = brw_search_cache(&brw->surface_cache, BRW_SS_SURF_BIND, + NULL, 0, + brw->vs.surf_bo, BRW_VS_MAX_SURF, + NULL); + + if (bind_bo == NULL) { + GLuint data_size = BRW_VS_MAX_SURF * sizeof(GLuint); + uint32_t *data = malloc(data_size); + int i; + + for (i = 0; i < BRW_VS_MAX_SURF; i++) + if (brw->vs.surf_bo[i]) + data[i] = brw->vs.surf_bo[i]->offset; + else + data[i] = 0; + + bind_bo = brw_upload_cache( &brw->surface_cache, BRW_SS_SURF_BIND, + NULL, 0, + brw->vs.surf_bo, BRW_VS_MAX_SURF, + data, data_size, + NULL, NULL); + + /* Emit binding table relocations to surface state */ + for (i = 0; i < BRW_VS_MAX_SURF; i++) { + if (brw->vs.surf_bo[i] != NULL) { + /* The presumed offsets were set in the data values for + * brw_upload_cache. + */ + drm_intel_bo_emit_reloc(bind_bo, i * 4, + brw->vs.surf_bo[i], 0, + I915_GEM_DOMAIN_INSTRUCTION, 0); + } + } + + free(data); + } + + return bind_bo; +} + +/** + * Vertex shader surfaces (constant buffer). + * + * This consumes the state updates for the constant buffer needing + * to be updated, and produces BRW_NEW_NR_VS_SURFACES for the VS unit and + * CACHE_NEW_SURF_BIND for the binding table upload. + */ +static void prepare_vs_surfaces(struct brw_context *brw ) +{ + GLcontext *ctx = &brw->intel.ctx; + int i; + int nr_surfaces = 0; + + brw_update_vs_constant_surface(ctx, SURF_INDEX_VERT_CONST_BUFFER); + + for (i = 0; i < BRW_VS_MAX_SURF; i++) { + if (brw->vs.surf_bo[i] != NULL) { + nr_surfaces = i + 1; + } + } + + if (brw->vs.nr_surfaces != nr_surfaces) { + brw->state.dirty.brw |= BRW_NEW_NR_VS_SURFACES; + brw->vs.nr_surfaces = nr_surfaces; + } + + /* Note that we don't end up updating the bind_bo if we don't have a + * surface to be pointing at. This should be relatively harmless, as it + * just slightly increases our working set size. + */ + if (brw->vs.nr_surfaces != 0) { + dri_bo_unreference(brw->vs.bind_bo); + brw->vs.bind_bo = brw_vs_get_binding_table(brw); + } +} + +const struct brw_tracked_state brw_vs_surfaces = { + .dirty = { + .mesa = (_NEW_PROGRAM_CONSTANTS), + .brw = (BRW_NEW_VERTEX_PROGRAM), + .cache = 0 + }, + .prepare = prepare_vs_surfaces, +}; + + + diff --git a/src/mesa/drivers/dri/i965/brw_wm.c b/src/mesa/drivers/dri/i965/brw_wm.c index 90d74c2885c..cd65f57bbc9 100644 --- a/src/mesa/drivers/dri/i965/brw_wm.c +++ b/src/mesa/drivers/dri/i965/brw_wm.c @@ -146,6 +146,13 @@ static void do_wm_prog( struct brw_context *brw, if (c == NULL) { brw->wm.compile_data = calloc(1, sizeof(*brw->wm.compile_data)); c = brw->wm.compile_data; + if (c == NULL) { + /* Ouch - big out of memory problem. Can't continue + * without triggering a segfault, no way to signal, + * so just return. + */ + return; + } } else { memset(c, 0, sizeof(*brw->wm.compile_data)); } diff --git a/src/mesa/drivers/dri/i965/brw_wm.h b/src/mesa/drivers/dri/i965/brw_wm.h index d0ab3bdc65f..59ead757b51 100644 --- a/src/mesa/drivers/dri/i965/brw_wm.h +++ b/src/mesa/drivers/dri/i965/brw_wm.h @@ -240,22 +240,25 @@ struct brw_wm_compile { GLuint max_wm_grf; GLuint last_scratch; + GLuint cur_inst; /**< index of current instruction */ + + GLboolean out_of_regs; /**< ran out of GRF registers? */ + /** Mapping from Mesa registers to hardware registers */ struct { GLboolean inited; struct brw_reg reg; } wm_regs[PROGRAM_PAYLOAD+1][256][4]; + GLboolean used_grf[BRW_WM_MAX_GRF]; + GLuint first_free_grf; struct brw_reg stack; struct brw_reg emit_mask_reg; - GLuint reg_index; /**< Index of next free GRF register */ GLuint tmp_regs[BRW_WM_MAX_GRF]; GLuint tmp_index; GLuint tmp_max; GLuint subroutines[BRW_WM_MAX_SUBROUTINE]; - /** using a real constant buffer? */ - GLboolean use_const_buffer; /** we may need up to 3 constants per instruction (if use_const_buffer) */ struct { GLint index; diff --git a/src/mesa/drivers/dri/i965/brw_wm_glsl.c b/src/mesa/drivers/dri/i965/brw_wm_glsl.c index 22e17622c6d..efe8b5126c8 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_glsl.c +++ b/src/mesa/drivers/dri/i965/brw_wm_glsl.c @@ -1,5 +1,7 @@ #include "main/macros.h" #include "shader/prog_parameter.h" +#include "shader/prog_print.h" +#include "shader/prog_optimize.h" #include "brw_context.h" #include "brw_eu.h" #include "brw_wm.h" @@ -42,6 +44,83 @@ GLboolean brw_wm_is_glsl(const struct gl_fragment_program *fp) } + +static void +reclaim_temps(struct brw_wm_compile *c); + + +/** Mark GRF register as used. */ +static void +prealloc_grf(struct brw_wm_compile *c, int r) +{ + c->used_grf[r] = GL_TRUE; +} + + +/** Mark given GRF register as not in use. */ +static void +release_grf(struct brw_wm_compile *c, int r) +{ + /*assert(c->used_grf[r]);*/ + c->used_grf[r] = GL_FALSE; + c->first_free_grf = MIN2(c->first_free_grf, r); +} + + +/** Return index of a free GRF, mark it as used. */ +static int +alloc_grf(struct brw_wm_compile *c) +{ + GLuint r; + for (r = c->first_free_grf; r < BRW_WM_MAX_GRF; r++) { + if (!c->used_grf[r]) { + c->used_grf[r] = GL_TRUE; + c->first_free_grf = r + 1; /* a guess */ + return r; + } + } + + /* no free temps, try to reclaim some */ + reclaim_temps(c); + c->first_free_grf = 0; + + /* try alloc again */ + for (r = c->first_free_grf; r < BRW_WM_MAX_GRF; r++) { + if (!c->used_grf[r]) { + c->used_grf[r] = GL_TRUE; + c->first_free_grf = r + 1; /* a guess */ + return r; + } + } + + for (r = 0; r < BRW_WM_MAX_GRF; r++) { + assert(c->used_grf[r]); + } + + /* really, no free GRF regs found */ + if (!c->out_of_regs) { + /* print warning once per compilation */ + _mesa_warning(NULL, "i965: ran out of registers for fragment program"); + c->out_of_regs = GL_TRUE; + } + + return -1; +} + + +/** Return number of GRF registers used */ +static int +num_grf_used(const struct brw_wm_compile *c) +{ + int r; + for (r = BRW_WM_MAX_GRF - 1; r >= 0; r--) + if (c->used_grf[r]) + return r + 1; + return 0; +} + + + /** * Record the mapping of a Mesa register to a hardware register. */ @@ -68,11 +147,23 @@ static int get_scalar_dst_index(const struct prog_instruction *inst) static struct brw_reg alloc_tmp(struct brw_wm_compile *c) { struct brw_reg reg; - if(c->tmp_index == c->tmp_max) - c->tmp_regs[ c->tmp_max++ ] = c->reg_index++; - + + /* if we need to allocate another temp, grow the tmp_regs[] array */ + if (c->tmp_index == c->tmp_max) { + int r = alloc_grf(c); + if (r < 0) { + /*printf("Out of temps in %s\n", __FUNCTION__);*/ + r = 50; /* XXX random register! */ + } + c->tmp_regs[ c->tmp_max++ ] = r; + } + + /* form the GRF register */ reg = brw_vec8_grf(c->tmp_regs[ c->tmp_index++ ], 0); + /*printf("alloc_temp %d\n", reg.nr);*/ + assert(reg.nr < BRW_WM_MAX_GRF); return reg; + } /** @@ -130,35 +221,29 @@ get_reg(struct brw_wm_compile *c, int file, int index, int component, return brw_null_reg(); } + assert(index < 256); + assert(component < 4); + /* see if we've already allocated a HW register for this Mesa register */ if (c->wm_regs[file][index][component].inited) { - /* yes, re-use */ - reg = c->wm_regs[file][index][component].reg; + /* yes, re-use */ + reg = c->wm_regs[file][index][component].reg; } else { /* no, allocate new register */ - reg = brw_vec8_grf(c->reg_index, 0); - } + int grf = alloc_grf(c); + /*printf("alloc grf %d for reg %d:%d.%d\n", grf, file, index, component);*/ + if (grf < 0) { + /* totally out of temps */ + grf = 51; /* XXX random register! */ + } - /* if this is a new register allocation, record it in the table */ - if (!c->wm_regs[file][index][component].inited) { - set_reg(c, file, index, component, reg); - c->reg_index++; - } + reg = brw_vec8_grf(grf, 0); + /*printf("Alloc new grf %d for %d.%d\n", reg.nr, index, component);*/ - if (c->reg_index >= BRW_WM_MAX_GRF - 12) { - /* ran out of temporary registers! */ -#if 1 - /* This is a big hack for now. - * Return bad register index, just don't hang the GPU. - */ - _mesa_fprintf(stderr, "out of regs %d\n", c->reg_index); - c->reg_index = BRW_WM_MAX_GRF - 13; -#else - return brw_null_reg(); -#endif + set_reg(c, file, index, component, reg); } - + if (neg & (1 << component)) { reg = negate(reg); } @@ -168,6 +253,46 @@ get_reg(struct brw_wm_compile *c, int file, int index, int component, } + +/** + * This is called if we run out of GRF registers. Examine the live intervals + * of temp regs in the program and free those which won't be used again. + */ +static void +reclaim_temps(struct brw_wm_compile *c) +{ + GLint intBegin[MAX_PROGRAM_TEMPS]; + GLint intEnd[MAX_PROGRAM_TEMPS]; + int index; + + /*printf("Reclaim temps:\n");*/ + + _mesa_find_temp_intervals(c->prog_instructions, c->nr_fp_insns, + intBegin, intEnd); + + for (index = 0; index < MAX_PROGRAM_TEMPS; index++) { + if (intEnd[index] != -1 && intEnd[index] < c->cur_inst) { + /* program temp[i] can be freed */ + int component; + /*printf(" temp[%d] is dead\n", index);*/ + for (component = 0; component < 4; component++) { + if (c->wm_regs[PROGRAM_TEMPORARY][index][component].inited) { + int r = c->wm_regs[PROGRAM_TEMPORARY][index][component].reg.nr; + release_grf(c, r); + /* + printf(" Reclaim temp %d, reg %d at inst %d\n", + index, r, c->cur_inst); + */ + c->wm_regs[PROGRAM_TEMPORARY][index][component].inited = GL_FALSE; + } + } + } + } +} + + + + /** * Preallocate registers. This sets up the Mesa to hardware register * mapping for certain registers, such as constants (uniforms/state vars) @@ -179,6 +304,10 @@ static void prealloc_reg(struct brw_wm_compile *c) struct brw_reg reg; int nr_interp_regs = 0; GLuint inputs = FRAG_BIT_WPOS | c->fp_interp_emitted | c->fp_deriv_emitted; + GLuint reg_index = 0; + + memset(c->used_grf, GL_FALSE, sizeof(c->used_grf)); + c->first_free_grf = 0; for (i = 0; i < 4; i++) { if (i < c->key.nr_depth_regs) @@ -187,16 +316,22 @@ static void prealloc_reg(struct brw_wm_compile *c) reg = brw_vec8_grf(0, 0); set_reg(c, PROGRAM_PAYLOAD, PAYLOAD_DEPTH, i, reg); } - c->reg_index += 2 * c->key.nr_depth_regs; + reg_index += 2 * c->key.nr_depth_regs; /* constants */ { - const int nr_params = c->fp->program.Base.Parameters->NumParameters; + const GLuint nr_params = c->fp->program.Base.Parameters->NumParameters; + const GLuint nr_temps = c->fp->program.Base.NumTemporaries; /* use a real constant buffer, or just use a section of the GRF? */ - c->use_const_buffer = GL_FALSE; /* (nr_params > 8);*/ + /* XXX this heuristic may need adjustment... */ + if ((nr_params + nr_temps) * 4 + reg_index > 80) + c->fp->use_const_buffer = GL_TRUE; + else + c->fp->use_const_buffer = GL_FALSE; + /*printf("WM use_const_buffer = %d\n", c->fp->use_const_buffer);*/ - if (c->use_const_buffer) { + if (c->fp->use_const_buffer) { /* We'll use a real constant buffer and fetch constants from * it with a dataport read message. */ @@ -216,7 +351,7 @@ static void prealloc_reg(struct brw_wm_compile *c) for (i = 0; i < nr_params; i++) { /* loop over XYZW channels */ for (j = 0; j < 4; j++, index++) { - reg = brw_vec1_grf(c->reg_index + index / 8, index % 8); + reg = brw_vec1_grf(reg_index + index / 8, index % 8); /* Save pointer to parameter/constant value. * Constants will be copied in prepare_constant_buffer() */ @@ -226,7 +361,7 @@ static void prealloc_reg(struct brw_wm_compile *c) } /* number of constant regs used (each reg is float[8]) */ c->nr_creg = 2 * ((4 * nr_params + 15) / 16); - c->reg_index += c->nr_creg; + reg_index += c->nr_creg; } } @@ -234,34 +369,42 @@ static void prealloc_reg(struct brw_wm_compile *c) for (i = 0; i < FRAG_ATTRIB_MAX; i++) { if (inputs & (1<<i)) { nr_interp_regs++; - reg = brw_vec8_grf(c->reg_index, 0); + reg = brw_vec8_grf(reg_index, 0); for (j = 0; j < 4; j++) set_reg(c, PROGRAM_PAYLOAD, i, j, reg); - c->reg_index += 2; + reg_index += 2; } } c->prog_data.first_curbe_grf = c->key.nr_depth_regs * 2; c->prog_data.urb_read_length = nr_interp_regs * 2; c->prog_data.curb_read_length = c->nr_creg; - c->emit_mask_reg = brw_uw1_reg(BRW_GENERAL_REGISTER_FILE, c->reg_index, 0); - c->reg_index++; - c->stack = brw_uw16_reg(BRW_GENERAL_REGISTER_FILE, c->reg_index, 0); - c->reg_index += 2; + c->emit_mask_reg = brw_uw1_reg(BRW_GENERAL_REGISTER_FILE, reg_index, 0); + reg_index++; + c->stack = brw_uw16_reg(BRW_GENERAL_REGISTER_FILE, reg_index, 0); + reg_index += 2; + + /* mark GRF regs [0..reg_index-1] as in-use */ + for (i = 0; i < reg_index; i++) + prealloc_grf(c, i); + + /* Don't use GRF 126, 127. Using them seems to lead to GPU lock-ups */ + prealloc_grf(c, 126); + prealloc_grf(c, 127); /* An instruction may reference up to three constants. * They'll be found in these registers. * XXX alloc these on demand! */ - if (c->use_const_buffer) { + if (c->fp->use_const_buffer) { for (i = 0; i < 3; i++) { c->current_const[i].index = -1; - c->current_const[i].reg = alloc_tmp(c); + c->current_const[i].reg = brw_vec8_grf(alloc_grf(c), 0); } } #if 0 - printf("USE CONST BUFFER? %d\n", c->use_const_buffer); - printf("AFTER PRE_ALLOC, reg_index = %d\n", c->reg_index); + printf("USE CONST BUFFER? %d\n", c->fp->use_const_buffer); + printf("AFTER PRE_ALLOC, reg_index = %d\n", reg_index); #endif } @@ -283,23 +426,21 @@ static void fetch_constants(struct brw_wm_compile *c, if (src->File == PROGRAM_STATE_VAR || src->File == PROGRAM_CONSTANT || src->File == PROGRAM_UNIFORM) { - if (c->current_const[i].index != src->Index) { - c->current_const[i].index = src->Index; + c->current_const[i].index = src->Index; #if 0 - printf(" fetch const[%d] for arg %d into reg %d\n", - src->Index, i, c->current_const[i].reg.nr); + printf(" fetch const[%d] for arg %d into reg %d\n", + src->Index, i, c->current_const[i].reg.nr); #endif - /* need to fetch the constant now */ - brw_dp_READ_4(p, - c->current_const[i].reg, /* writeback dest */ - 1, /* msg_reg */ - src->RelAddr, /* relative indexing? */ - 16 * src->Index, /* byte offset */ - SURF_INDEX_FRAG_CONST_BUFFER/* binding table index */ - ); - } + /* need to fetch the constant now */ + brw_dp_READ_4(p, + c->current_const[i].reg, /* writeback dest */ + 1, /* msg_reg */ + src->RelAddr, /* relative indexing? */ + 16 * src->Index, /* byte offset */ + SURF_INDEX_FRAG_CONST_BUFFER/* binding table index */ + ); } } } @@ -368,7 +509,7 @@ static struct brw_reg get_src_reg(struct brw_wm_compile *c, const GLuint nr = 1; const GLuint component = GET_SWZ(src->Swizzle, channel); - if (c->use_const_buffer && + if (c->fp->use_const_buffer && (src->File == PROGRAM_STATE_VAR || src->File == PROGRAM_CONSTANT || src->File == PROGRAM_UNIFORM)) { @@ -2595,7 +2736,8 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c) struct brw_compile *p = &c->func; struct brw_indirect stack_index = brw_indirect(0, 0); - c->reg_index = 0; + c->out_of_regs = GL_FALSE; + prealloc_reg(c); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_MOV(p, get_addr_reg(stack_index), brw_address(c->stack)); @@ -2603,13 +2745,15 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c) for (i = 0; i < c->nr_fp_insns; i++) { const struct prog_instruction *inst = &c->prog_instructions[i]; + c->cur_inst = i; + #if 0 _mesa_printf("Inst %d: ", i); _mesa_print_instruction(inst); #endif /* fetch any constants that this instruction needs */ - if (c->use_const_buffer) + if (c->fp->use_const_buffer) fetch_constants(c, inst); if (inst->CondUpdate) @@ -2833,17 +2977,13 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c) _mesa_printf("unsupported IR in fragment shader %d\n", inst->Opcode); } + if (inst->CondUpdate) brw_set_predicate_control(p, BRW_PREDICATE_NORMAL); else brw_set_predicate_control(p, BRW_PREDICATE_NONE); } post_wm_emit(c); - - if (c->reg_index >= BRW_WM_MAX_GRF) { - _mesa_problem(NULL, "Ran out of registers in brw_wm_emit_glsl()"); - /* XXX we need to do some proper error recovery here */ - } } @@ -2867,6 +3007,6 @@ void brw_wm_glsl_emit(struct brw_context *brw, struct brw_wm_compile *c) brw_wm_print_program(c, "brw_wm_glsl_emit done"); } - c->prog_data.total_grf = c->reg_index; + c->prog_data.total_grf = num_grf_used(c); c->prog_data.total_scratch = 0; } diff --git a/src/mesa/drivers/dri/i965/brw_wm_sampler_state.c b/src/mesa/drivers/dri/i965/brw_wm_sampler_state.c index 1fc9f013727..c604ef0162a 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_sampler_state.c +++ b/src/mesa/drivers/dri/i965/brw_wm_sampler_state.c @@ -152,7 +152,7 @@ static void brw_update_sampler_state(struct wm_sampler_entry *key, sampler->ss0.mag_filter = BRW_MAPFILTER_ANISOTROPIC; if (key->max_aniso > 2.0) { - sampler->ss3.max_aniso = MAX2((key->max_aniso - 2) / 2, + sampler->ss3.max_aniso = MIN2((key->max_aniso - 2) / 2, BRW_ANISORATIO_16); } } diff --git a/src/mesa/drivers/dri/i965/brw_wm_surface_state.c b/src/mesa/drivers/dri/i965/brw_wm_surface_state.c index 71840d1e4e8..c49a5f6b4ec 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_surface_state.c +++ b/src/mesa/drivers/dri/i965/brw_wm_surface_state.c @@ -176,22 +176,6 @@ static GLuint translate_tex_format( GLuint mesa_format, GLenum internal_format, } } - -/** - * Use same key for WM and VS surfaces. - */ -struct brw_surface_key { - GLenum target, depthmode; - dri_bo *bo; - GLint format, internal_format; - GLint first_level, last_level; - GLint width, height, depth; - GLint pitch, cpp; - uint32_t tiling; - GLuint offset; -}; - - static void brw_set_surface_tiling(struct brw_surface_state *surf, uint32_t tiling) { @@ -268,7 +252,7 @@ brw_create_texture_surface( struct brw_context *brw, surf.ss0.cube_neg_z = 1; } - bo = brw_upload_cache(&brw->cache, BRW_SS_SURFACE, + bo = brw_upload_cache(&brw->surface_cache, BRW_SS_SURFACE, key, sizeof(*key), &key->bo, key->bo ? 1 : 0, &surf, sizeof(surf), @@ -321,10 +305,11 @@ brw_update_texture_surface( GLcontext *ctx, GLuint unit ) key.tiling = intelObj->mt->region->tiling; dri_bo_unreference(brw->wm.surf_bo[surf]); - brw->wm.surf_bo[surf] = brw_search_cache(&brw->cache, BRW_SS_SURFACE, - &key, sizeof(key), - &key.bo, key.bo ? 1 : 0, - NULL); + brw->wm.surf_bo[surf] = brw_search_cache(&brw->surface_cache, + BRW_SS_SURFACE, + &key, sizeof(key), + &key.bo, key.bo ? 1 : 0, + NULL); if (brw->wm.surf_bo[surf] == NULL) { brw->wm.surf_bo[surf] = brw_create_texture_surface(brw, &key); } @@ -336,7 +321,7 @@ brw_update_texture_surface( GLcontext *ctx, GLuint unit ) * Create the constant buffer surface. Vertex/fragment shader constants will be * read from this buffer with Data Port Read instructions/messages. */ -static dri_bo * +dri_bo * brw_create_constant_surface( struct brw_context *brw, struct brw_surface_key *key ) { @@ -362,7 +347,7 @@ brw_create_constant_surface( struct brw_context *brw, surf.ss3.pitch = (key->pitch * key->cpp) - 1; /* ignored?? */ brw_set_surface_tiling(&surf, key->tiling); /* tiling now allowed */ - bo = brw_upload_cache(&brw->cache, BRW_SS_SURFACE, + bo = brw_upload_cache(&brw->surface_cache, BRW_SS_SURFACE, key, sizeof(*key), &key->bo, key->bo ? 1 : 0, &surf, sizeof(surf), @@ -380,39 +365,70 @@ brw_create_constant_surface( struct brw_context *brw, return bo; } +/* Creates a new WM constant buffer reflecting the current fragment program's + * constants, if needed by the fragment program. + * + * Otherwise, constants go through the CURBEs using the brw_constant_buffer + * state atom. + */ +static drm_intel_bo * +brw_wm_update_constant_buffer(struct brw_context *brw) +{ + struct intel_context *intel = &brw->intel; + struct brw_fragment_program *fp = + (struct brw_fragment_program *) brw->fragment_program; + const struct gl_program_parameter_list *params = fp->program.Base.Parameters; + const int size = params->NumParameters * 4 * sizeof(GLfloat); + drm_intel_bo *const_buffer; + + /* BRW_NEW_FRAGMENT_PROGRAM */ + if (!fp->use_const_buffer) + return NULL; + + const_buffer = drm_intel_bo_alloc(intel->bufmgr, "fp_const_buffer", + size, 64); + + /* _NEW_PROGRAM_CONSTANTS */ + dri_bo_subdata(const_buffer, 0, size, params->ParameterValues); + + return const_buffer; +} /** * Update the surface state for a WM constant buffer. * The constant buffer will be (re)allocated here if needed. */ -static dri_bo * +static void brw_update_wm_constant_surface( GLcontext *ctx, - GLuint surf, - dri_bo *const_buffer, - const struct gl_program_parameter_list *params) + GLuint surf) { struct brw_context *brw = brw_context(ctx); struct brw_surface_key key; - struct intel_context *intel = &brw->intel; - const int size = params->NumParameters * 4 * sizeof(GLfloat); + struct brw_fragment_program *fp = + (struct brw_fragment_program *) brw->fragment_program; + const struct gl_program_parameter_list *params = + fp->program.Base.Parameters; - /* free old const buffer if too small */ - if (const_buffer && const_buffer->size < size) { - dri_bo_unreference(const_buffer); - const_buffer = NULL; - } + /* If we're in this state update atom, we need to update WM constants, so + * free the old buffer and create a new one for the new contents. + */ + dri_bo_unreference(fp->const_buffer); + fp->const_buffer = brw_wm_update_constant_buffer(brw); - /* alloc new buffer if needed */ - if (!const_buffer) { - const_buffer = - drm_intel_bo_alloc(intel->bufmgr, "fp_const_buffer", size, 64); + /* If there's no constant buffer, then no surface BO is needed to point at + * it. + */ + if (fp->const_buffer == 0) { + drm_intel_bo_unreference(brw->wm.surf_bo[surf]); + brw->wm.surf_bo[surf] = NULL; + return; } memset(&key, 0, sizeof(key)); key.format = MESA_FORMAT_RGBA_FLOAT32; key.internal_format = GL_RGBA; - key.bo = const_buffer; + key.bo = fp->const_buffer; key.depthmode = GL_NONE; key.pitch = params->NumParameters; key.width = params->NumParameters; @@ -427,77 +443,59 @@ brw_update_wm_constant_surface( GLcontext *ctx, */ dri_bo_unreference(brw->wm.surf_bo[surf]); - brw->wm.surf_bo[surf] = brw_search_cache(&brw->cache, BRW_SS_SURFACE, + brw->wm.surf_bo[surf] = brw_search_cache(&brw->surface_cache, + BRW_SS_SURFACE, &key, sizeof(key), &key.bo, key.bo ? 1 : 0, NULL); if (brw->wm.surf_bo[surf] == NULL) { brw->wm.surf_bo[surf] = brw_create_constant_surface(brw, &key); } - - return const_buffer; + brw->state.dirty.brw |= BRW_NEW_WM_SURFACES; } - /** - * Update the surface state for a VS constant buffer. - * The constant buffer will be (re)allocated here if needed. + * Updates surface / buffer for fragment shader constant buffer, if + * one is required. + * + * This consumes the state updates for the constant buffer, and produces + * BRW_NEW_WM_SURFACES to get picked up by brw_prepare_wm_surfaces for + * inclusion in the binding table. */ -static dri_bo * -brw_update_vs_constant_surface( GLcontext *ctx, - GLuint surf, - dri_bo *const_buffer, - const struct gl_program_parameter_list *params) +static void prepare_wm_constant_surface(struct brw_context *brw ) { - struct brw_context *brw = brw_context(ctx); - struct brw_surface_key key; - struct intel_context *intel = &brw->intel; - const int size = params->NumParameters * 4 * sizeof(GLfloat); - - assert(surf == 0); - - /* free old const buffer if too small */ - if (const_buffer && const_buffer->size < size) { - dri_bo_unreference(const_buffer); - const_buffer = NULL; - } - - /* alloc new buffer if needed */ - if (!const_buffer) { - const_buffer = - drm_intel_bo_alloc(intel->bufmgr, "vp_const_buffer", size, 64); - } - - memset(&key, 0, sizeof(key)); - - key.format = MESA_FORMAT_RGBA_FLOAT32; - key.internal_format = GL_RGBA; - key.bo = const_buffer; - key.depthmode = GL_NONE; - key.pitch = params->NumParameters; - key.width = params->NumParameters; - key.height = 1; - key.depth = 1; - key.cpp = 16; + GLcontext *ctx = &brw->intel.ctx; + struct brw_fragment_program *fp = + (struct brw_fragment_program *) brw->fragment_program; + GLuint surf = SURF_INDEX_FRAG_CONST_BUFFER; - /* - printf("%s:\n", __FUNCTION__); - printf(" width %d height %d depth %d cpp %d pitch %d\n", - key.width, key.height, key.depth, key.cpp, key.pitch); - */ + drm_intel_bo_unreference(fp->const_buffer); + fp->const_buffer = brw_wm_update_constant_buffer(brw); - dri_bo_unreference(brw->vs.surf_bo[surf]); - brw->vs.surf_bo[surf] = brw_search_cache(&brw->cache, BRW_SS_SURFACE, - &key, sizeof(key), - &key.bo, key.bo ? 1 : 0, - NULL); - if (brw->vs.surf_bo[surf] == NULL) { - brw->vs.surf_bo[surf] = brw_create_constant_surface(brw, &key); + /* If there's no constant buffer, then no surface BO is needed to point at + * it. + */ + if (fp->const_buffer == 0) { + if (brw->wm.surf_bo[surf] != NULL) { + drm_intel_bo_unreference(brw->wm.surf_bo[surf]); + brw->wm.surf_bo[surf] = NULL; + brw->state.dirty.brw |= BRW_NEW_WM_SURFACES; + } + return; } - return const_buffer; + brw_update_wm_constant_surface(ctx, surf); } +const struct brw_tracked_state brw_wm_constant_surface = { + .dirty = { + .mesa = (_NEW_PROGRAM_CONSTANTS), + .brw = (BRW_NEW_FRAGMENT_PROGRAM), + .cache = 0 + }, + .prepare = prepare_wm_constant_surface, +}; + /** * Sets up a surface state structure to point at the given region. @@ -507,7 +505,7 @@ brw_update_vs_constant_surface( GLcontext *ctx, static void brw_update_renderbuffer_surface(struct brw_context *brw, struct gl_renderbuffer *rb, - unsigned int unit, GLboolean cached) + unsigned int unit) { GLcontext *ctx = &brw->intel.ctx; dri_bo *region_bo = NULL; @@ -520,6 +518,7 @@ brw_update_renderbuffer_surface(struct brw_context *brw, GLubyte color_mask[4]; GLboolean color_blend; uint32_t tiling; + uint32_t draw_offset; } key; memset(&key, 0, sizeof(key)); @@ -550,6 +549,7 @@ brw_update_renderbuffer_surface(struct brw_context *brw, key.height = region->height; key.pitch = region->pitch; key.cpp = region->cpp; + key.draw_offset = region->draw_offset; /* cur 3d or cube face offset */ } else { key.surface_type = BRW_SURFACE_NULL; key.surface_format = BRW_SURFACEFORMAT_B8G8R8A8_UNORM; @@ -557,6 +557,7 @@ brw_update_renderbuffer_surface(struct brw_context *brw, key.width = 1; key.height = 1; key.cpp = 4; + key.draw_offset = 0; } memcpy(key.color_mask, ctx->Color.ColorMask, sizeof(key.color_mask)); @@ -564,12 +565,11 @@ brw_update_renderbuffer_surface(struct brw_context *brw, ctx->Color.BlendEnabled); dri_bo_unreference(brw->wm.surf_bo[unit]); - brw->wm.surf_bo[unit] = NULL; - if (cached) - brw->wm.surf_bo[unit] = brw_search_cache(&brw->cache, BRW_SS_SURFACE, - &key, sizeof(key), - ®ion_bo, 1, - NULL); + brw->wm.surf_bo[unit] = brw_search_cache(&brw->surface_cache, + BRW_SS_SURFACE, + &key, sizeof(key), + ®ion_bo, 1, + NULL); if (brw->wm.surf_bo[unit] == NULL) { struct brw_surface_state surf; @@ -578,8 +578,9 @@ brw_update_renderbuffer_surface(struct brw_context *brw, surf.ss0.surface_format = key.surface_format; surf.ss0.surface_type = key.surface_type; + surf.ss1.base_addr = key.draw_offset; if (region_bo != NULL) - surf.ss1.base_addr = region_bo->offset; /* reloc */ + surf.ss1.base_addr += region_bo->offset; /* reloc */ surf.ss2.width = key.width - 1; surf.ss2.height = key.height - 1; @@ -594,7 +595,8 @@ brw_update_renderbuffer_surface(struct brw_context *brw, surf.ss0.writedisable_alpha = !key.color_mask[3]; /* Key size will never match key size for textures, so we're safe. */ - brw->wm.surf_bo[unit] = brw_upload_cache(&brw->cache, BRW_SS_SURFACE, + brw->wm.surf_bo[unit] = brw_upload_cache(&brw->surface_cache, + BRW_SS_SURFACE, &key, sizeof(key), ®ion_bo, 1, &surf, sizeof(surf), @@ -604,12 +606,12 @@ brw_update_renderbuffer_surface(struct brw_context *brw, * them both. We might be able to figure out from other state * a more restrictive relocation to emit. */ - dri_bo_emit_reloc(brw->wm.surf_bo[unit], - I915_GEM_DOMAIN_RENDER, - I915_GEM_DOMAIN_RENDER, - 0, - offsetof(struct brw_surface_state, ss1), - region_bo); + drm_intel_bo_emit_reloc(brw->wm.surf_bo[unit], + offsetof(struct brw_surface_state, ss1), + region_bo, + key.draw_offset, + I915_GEM_DOMAIN_RENDER, + I915_GEM_DOMAIN_RENDER); } } } @@ -626,7 +628,7 @@ brw_wm_get_binding_table(struct brw_context *brw) assert(brw->wm.nr_surfaces <= BRW_WM_MAX_SURF); - bind_bo = brw_search_cache(&brw->cache, BRW_SS_SURF_BIND, + bind_bo = brw_search_cache(&brw->surface_cache, BRW_SS_SURF_BIND, NULL, 0, brw->wm.surf_bo, brw->wm.nr_surfaces, NULL); @@ -642,7 +644,7 @@ brw_wm_get_binding_table(struct brw_context *brw) else data[i] = 0; - bind_bo = brw_upload_cache( &brw->cache, BRW_SS_SURF_BIND, + bind_bo = brw_upload_cache( &brw->surface_cache, BRW_SS_SURF_BIND, NULL, 0, brw->wm.surf_bo, brw->wm.nr_surfaces, data, data_size, @@ -678,27 +680,17 @@ static void prepare_wm_surfaces(struct brw_context *brw ) for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { brw_update_renderbuffer_surface(brw, ctx->DrawBuffer->_ColorDrawBuffers[i], - i, - GL_FALSE); + i); } } else { - brw_update_renderbuffer_surface(brw, NULL, 0, GL_TRUE); + brw_update_renderbuffer_surface(brw, NULL, 0); } old_nr_surfaces = brw->wm.nr_surfaces; brw->wm.nr_surfaces = MAX_DRAW_BUFFERS; - /* Update surface / buffer for fragment shader constant buffer */ - { - const GLuint surf = SURF_INDEX_FRAG_CONST_BUFFER; - struct brw_fragment_program *fp = - (struct brw_fragment_program *) brw->fragment_program; - fp->const_buffer = - brw_update_wm_constant_surface(ctx, surf, fp->const_buffer, - fp->program.Base.Parameters); - - brw->wm.nr_surfaces = surf + 1; - } + if (brw->wm.surf_bo[SURF_INDEX_FRAG_CONST_BUFFER] != NULL) + brw->wm.nr_surfaces = SURF_INDEX_FRAG_CONST_BUFFER + 1; /* Update surfaces for textures */ for (i = 0; i < BRW_MAX_TEX_UNIT; i++) { @@ -731,100 +723,16 @@ static void prepare_wm_surfaces(struct brw_context *brw ) brw->state.dirty.brw |= BRW_NEW_NR_WM_SURFACES; } - -/** - * Constructs the binding table for the VS surface state. - */ -static dri_bo * -brw_vs_get_binding_table(struct brw_context *brw) -{ - dri_bo *bind_bo; - - assert(brw->vs.nr_surfaces <= BRW_VS_MAX_SURF); - - bind_bo = brw_search_cache(&brw->cache, BRW_SS_SURF_BIND, - NULL, 0, - brw->vs.surf_bo, brw->vs.nr_surfaces, - NULL); - - if (bind_bo == NULL) { - GLuint data_size = brw->vs.nr_surfaces * sizeof(GLuint); - uint32_t *data = malloc(data_size); - int i; - - for (i = 0; i < brw->vs.nr_surfaces; i++) - if (brw->vs.surf_bo[i]) - data[i] = brw->vs.surf_bo[i]->offset; - else - data[i] = 0; - - bind_bo = brw_upload_cache( &brw->cache, BRW_SS_SURF_BIND, - NULL, 0, - brw->vs.surf_bo, brw->vs.nr_surfaces, - data, data_size, - NULL, NULL); - - /* Emit binding table relocations to surface state */ - for (i = 0; i < BRW_VS_MAX_SURF; i++) { - if (brw->vs.surf_bo[i] != NULL) { - dri_bo_emit_reloc(bind_bo, - I915_GEM_DOMAIN_INSTRUCTION, 0, - 0, - i * sizeof(GLuint), - brw->vs.surf_bo[i]); - } - } - - free(data); - } - - return bind_bo; -} - - -/** - * Vertex shader surfaces. Just constant buffer for now. Could add vertex - * shader textures in the future. - */ -static void prepare_vs_surfaces(struct brw_context *brw ) -{ - GLcontext *ctx = &brw->intel.ctx; - - /* Update surface / buffer for vertex shader constant buffer */ - { - const GLuint surf = SURF_INDEX_VERT_CONST_BUFFER; - struct brw_vertex_program *vp = - (struct brw_vertex_program *) brw->vertex_program; - vp->const_buffer = - brw_update_vs_constant_surface(ctx, surf, vp->const_buffer, - vp->program.Base.Parameters); - - brw->vs.nr_surfaces = 1; - } - - dri_bo_unreference(brw->vs.bind_bo); - brw->vs.bind_bo = brw_vs_get_binding_table(brw); - - if (1) - brw->state.dirty.brw |= BRW_NEW_NR_VS_SURFACES; -} - - -static void -prepare_surfaces(struct brw_context *brw) -{ - prepare_wm_surfaces(brw); - prepare_vs_surfaces(brw); -} - - const struct brw_tracked_state brw_wm_surfaces = { .dirty = { - .mesa = _NEW_COLOR | _NEW_TEXTURE | _NEW_BUFFERS | _NEW_PROGRAM, - .brw = BRW_NEW_CONTEXT, + .mesa = (_NEW_COLOR | + _NEW_TEXTURE | + _NEW_BUFFERS), + .brw = (BRW_NEW_CONTEXT | + BRW_NEW_WM_SURFACES), .cache = 0 }, - .prepare = prepare_surfaces, + .prepare = prepare_wm_surfaces, }; diff --git a/src/mesa/drivers/dri/i965/intel_generatemipmap.c b/src/mesa/drivers/dri/i965/intel_generatemipmap.c new file mode 120000 index 00000000000..4c6b37ada01 --- /dev/null +++ b/src/mesa/drivers/dri/i965/intel_generatemipmap.c @@ -0,0 +1 @@ +../intel/intel_generatemipmap.c
\ No newline at end of file diff --git a/src/mesa/drivers/dri/intel/intel_buffer_objects.c b/src/mesa/drivers/dri/intel/intel_buffer_objects.c index b7c7eeb368f..f6b0d769c6b 100644 --- a/src/mesa/drivers/dri/intel/intel_buffer_objects.c +++ b/src/mesa/drivers/dri/intel/intel_buffer_objects.c @@ -35,6 +35,9 @@ #include "intel_batchbuffer.h" #include "intel_regions.h" +static GLboolean +intel_bufferobj_unmap(GLcontext * ctx, + GLenum target, struct gl_buffer_object *obj); /** Allocates a new dri_bo to store the data for the buffer object. */ static void @@ -100,7 +103,13 @@ intel_bufferobj_free(GLcontext * ctx, struct gl_buffer_object *obj) struct intel_buffer_object *intel_obj = intel_buffer_object(obj); assert(intel_obj); - assert(!obj->Pointer); /* Mesa should have unmapped it */ + + /* Buffer objects are automatically unmapped when deleting according + * to the spec, but Mesa doesn't do UnmapBuffer for us at context destroy + * (though it does if you call glDeleteBuffers) + */ + if (obj->Pointer) + intel_bufferobj_unmap(ctx, 0, obj); if (intel_obj->region) { intel_bufferobj_release_region(intel, intel_obj); @@ -204,9 +213,8 @@ intel_bufferobj_map(GLcontext * ctx, { struct intel_context *intel = intel_context(ctx); struct intel_buffer_object *intel_obj = intel_buffer_object(obj); + GLboolean read_only = (access == GL_READ_ONLY_ARB); - /* XXX: Translate access to flags arg below: - */ assert(intel_obj); if (intel_obj->region) @@ -217,7 +225,7 @@ intel_bufferobj_map(GLcontext * ctx, return NULL; } - dri_bo_map(intel_obj->buffer, GL_TRUE); + dri_bo_map(intel_obj->buffer, !read_only); obj->Pointer = intel_obj->buffer->virtual; return obj->Pointer; } diff --git a/src/mesa/drivers/dri/intel/intel_buffers.c b/src/mesa/drivers/dri/intel/intel_buffers.c index 90964df3553..4f4ea45b74f 100644 --- a/src/mesa/drivers/dri/intel/intel_buffers.c +++ b/src/mesa/drivers/dri/intel/intel_buffers.c @@ -157,7 +157,7 @@ intel_draw_buffer(GLcontext * ctx, struct gl_framebuffer *fb) /* Do this here, not core Mesa, since this function is called from * many places within the driver. */ - if (ctx->NewState & (_NEW_BUFFERS | _NEW_COLOR | _NEW_PIXEL)) { + if (ctx->NewState & _NEW_BUFFERS) { /* this updates the DrawBuffer->_NumColorDrawBuffers fields, etc */ _mesa_update_framebuffer(ctx); /* this updates the DrawBuffer's Width/Height if it's a FBO */ @@ -323,8 +323,19 @@ intelDrawBuffer(GLcontext * ctx, GLenum mode) { if ((ctx->DrawBuffer != NULL) && (ctx->DrawBuffer->Name == 0)) { struct intel_context *const intel = intel_context(ctx); + const GLboolean was_front_buffer_rendering = + intel->is_front_buffer_rendering; - intel->is_front_buffer_rendering = (mode == GL_FRONT_LEFT); + intel->is_front_buffer_rendering = (mode == GL_FRONT_LEFT) + || (mode == GL_FRONT); + + /* If we weren't front-buffer rendering before but we are now, make sure + * that the front-buffer has actually been allocated. + */ + if (!was_front_buffer_rendering && intel->is_front_buffer_rendering) { + intel_update_renderbuffers(intel->driContext, + intel->driContext->driDrawablePriv); + } } intel_draw_buffer(ctx, ctx->DrawBuffer); diff --git a/src/mesa/drivers/dri/intel/intel_context.c b/src/mesa/drivers/dri/intel/intel_context.c index 3436b8ecd30..8b3e50f9b62 100644 --- a/src/mesa/drivers/dri/intel/intel_context.c +++ b/src/mesa/drivers/dri/intel/intel_context.c @@ -173,6 +173,24 @@ intelGetString(GLcontext * ctx, GLenum name) } } +static unsigned +intel_bits_per_pixel(const struct intel_renderbuffer *rb) +{ + switch (rb->Base._ActualFormat) { + case GL_RGB5: + case GL_DEPTH_COMPONENT16: + return 16; + case GL_RGB8: + case GL_RGBA8: + case GL_DEPTH_COMPONENT24: + case GL_DEPTH24_STENCIL8_EXT: + case GL_STENCIL_INDEX8_EXT: + return 32; + default: + return 0; + } +} + void intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable) { @@ -180,7 +198,7 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable) struct intel_renderbuffer *rb; struct intel_region *region, *depth_region; struct intel_context *intel = context->driverPrivate; - __DRIbuffer *buffers; + __DRIbuffer *buffers = NULL; __DRIscreen *screen; int i, count; unsigned int attachments[10]; @@ -192,22 +210,63 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable) screen = intel->intelScreen->driScrnPriv; - i = 0; - if (intel_fb->color_rb[0]) - attachments[i++] = __DRI_BUFFER_FRONT_LEFT; - if (intel_fb->color_rb[1]) - attachments[i++] = __DRI_BUFFER_BACK_LEFT; - if (intel_get_renderbuffer(&intel_fb->Base, BUFFER_DEPTH)) - attachments[i++] = __DRI_BUFFER_DEPTH; - if (intel_get_renderbuffer(&intel_fb->Base, BUFFER_STENCIL)) - attachments[i++] = __DRI_BUFFER_STENCIL; - - buffers = (*screen->dri2.loader->getBuffers)(drawable, - &drawable->w, - &drawable->h, - attachments, i, - &count, - drawable->loaderPrivate); + if (screen->dri2.loader + && (screen->dri2.loader->base.version > 2) + && (screen->dri2.loader->getBuffersWithFormat != NULL)) { + struct intel_renderbuffer *depth_rb; + struct intel_renderbuffer *stencil_rb; + + i = 0; + if ((intel->is_front_buffer_rendering || !intel_fb->color_rb[1]) + && intel_fb->color_rb[0]) { + attachments[i++] = __DRI_BUFFER_FRONT_LEFT; + attachments[i++] = intel_bits_per_pixel(intel_fb->color_rb[0]); + } + + if (intel_fb->color_rb[1]) { + attachments[i++] = __DRI_BUFFER_BACK_LEFT; + attachments[i++] = intel_bits_per_pixel(intel_fb->color_rb[1]); + } + + depth_rb = intel_get_renderbuffer(&intel_fb->Base, BUFFER_DEPTH); + stencil_rb = intel_get_renderbuffer(&intel_fb->Base, BUFFER_STENCIL); + + if ((depth_rb != NULL) && (stencil_rb != NULL)) { + attachments[i++] = __DRI_BUFFER_DEPTH_STENCIL; + attachments[i++] = intel_bits_per_pixel(depth_rb); + } else if (depth_rb != NULL) { + attachments[i++] = __DRI_BUFFER_DEPTH; + attachments[i++] = intel_bits_per_pixel(depth_rb); + } else if (stencil_rb != NULL) { + attachments[i++] = __DRI_BUFFER_STENCIL; + attachments[i++] = intel_bits_per_pixel(stencil_rb); + } + + buffers = + (*screen->dri2.loader->getBuffersWithFormat)(drawable, + &drawable->w, + &drawable->h, + attachments, i / 2, + &count, + drawable->loaderPrivate); + } else if (screen->dri2.loader) { + i = 0; + if (intel_fb->color_rb[0]) + attachments[i++] = __DRI_BUFFER_FRONT_LEFT; + if (intel_fb->color_rb[1]) + attachments[i++] = __DRI_BUFFER_BACK_LEFT; + if (intel_get_renderbuffer(&intel_fb->Base, BUFFER_DEPTH)) + attachments[i++] = __DRI_BUFFER_DEPTH; + if (intel_get_renderbuffer(&intel_fb->Base, BUFFER_STENCIL)) + attachments[i++] = __DRI_BUFFER_STENCIL; + + buffers = (*screen->dri2.loader->getBuffers)(drawable, + &drawable->w, + &drawable->h, + attachments, i, + &count, + drawable->loaderPrivate); + } if (buffers == NULL) return; @@ -250,6 +309,11 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable) region_name = "dri2 depth buffer"; break; + case __DRI_BUFFER_DEPTH_STENCIL: + rb = intel_get_renderbuffer(&intel_fb->Base, BUFFER_DEPTH); + region_name = "dri2 depth / stencil buffer"; + break; + case __DRI_BUFFER_STENCIL: rb = intel_get_renderbuffer(&intel_fb->Base, BUFFER_STENCIL); region_name = "dri2 stencil buffer"; @@ -296,6 +360,23 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable) intel_renderbuffer_set_region(rb, region); intel_region_release(®ion); + + if (buffers[i].attachment == __DRI_BUFFER_DEPTH_STENCIL) { + rb = intel_get_renderbuffer(&intel_fb->Base, BUFFER_STENCIL); + if (rb != NULL) { + struct intel_region *stencil_region = NULL; + + if (rb->region) { + dri_bo_flink(rb->region->buffer, &name); + if (name == buffers[i].name) + continue; + } + + intel_region_reference(&stencil_region, region); + intel_renderbuffer_set_region(rb, stencil_region); + intel_region_release(&stencil_region); + } + } } driUpdateFramebufferSize(&intel->ctx, drawable); @@ -528,8 +609,6 @@ intelInitContext(struct intel_context *intel, } } - ctx->Const.MaxTextureMaxAnisotropy = 2.0; - /* This doesn't yet catch all non-conformant rendering, but it's a * start. */ @@ -695,13 +774,64 @@ intelDestroyContext(__DRIcontextPrivate * driContextPriv) intel->prim.vb_bo = NULL; if (release_texture_heaps) { - /* This share group is about to go away, free our private - * texture object data. + /* Nothing is currently done here to free texture heaps; + * but we're not using the texture heap utilities, so I + * rather think we shouldn't. I've taken a look, and can't + * find any private texture data hanging around anywhere, but + * I'm not yet certain there isn't any at all... */ - if (INTEL_DEBUG & DEBUG_TEXTURE) + /* if (INTEL_DEBUG & DEBUG_TEXTURE) fprintf(stderr, "do something to free texture heaps\n"); + */ } + /* XXX In intelMakeCurrent() below, the context's static regions are + * referenced inside the frame buffer; it's listed as a hack, + * with a comment of "XXX FBO temporary fix-ups!", but + * as long as it's there, we should release the regions here. + * The do/while loop around the block is used to allow the + * "continue" statements inside the block to exit the block, + * to avoid many layers of "if" constructs. + */ + do { + __DRIdrawablePrivate * driDrawPriv = intel->driDrawable; + struct intel_framebuffer *intel_fb; + struct intel_renderbuffer *irbDepth, *irbStencil; + if (!driDrawPriv) { + /* We're already detached from the drawable; exit this block. */ + continue; + } + intel_fb = (struct intel_framebuffer *) driDrawPriv->driverPrivate; + if (!intel_fb) { + /* The frame buffer is already gone; exit this block. */ + continue; + } + irbDepth = intel_get_renderbuffer(&intel_fb->Base, BUFFER_DEPTH); + irbStencil = intel_get_renderbuffer(&intel_fb->Base, BUFFER_STENCIL); + + /* If the regions of the frame buffer still match the regions + * of the context, release them. If they've changed somehow, + * leave them alone. + */ + if (intel_fb->color_rb[0] && intel_fb->color_rb[0]->region == intel->front_region) { + intel_renderbuffer_set_region(intel_fb->color_rb[0], NULL); + } + if (intel_fb->color_rb[1] && intel_fb->color_rb[1]->region == intel->back_region) { + intel_renderbuffer_set_region(intel_fb->color_rb[1], NULL); + } + + if (irbDepth && irbDepth->region == intel->depth_region) { + intel_renderbuffer_set_region(irbDepth, NULL); + } + /* Usually, the stencil buffer is the same as the depth buffer; + * but they're handled separately in MakeCurrent, so we'll + * handle them separately here. + */ + if (irbStencil && irbStencil->region == intel->depth_region) { + intel_renderbuffer_set_region(irbStencil, NULL); + } + } while (0); + intel_region_release(&intel->front_region); intel_region_release(&intel->back_region); intel_region_release(&intel->depth_region); @@ -710,6 +840,8 @@ intelDestroyContext(__DRIcontextPrivate * driContextPriv) /* free the Mesa context */ _mesa_free_context_data(&intel->ctx); + + } } @@ -738,7 +870,10 @@ intelMakeCurrent(__DRIcontextPrivate * driContextPriv, if (driDrawPriv != driReadPriv) intel_update_renderbuffers(driContextPriv, driReadPriv); } else { - /* XXX FBO temporary fix-ups! */ + /* XXX FBO temporary fix-ups! These are released in + * intelDextroyContext(), above. Changes here should be + * reflected there. + */ /* if the renderbuffers don't have regions, init them from the context */ struct intel_renderbuffer *irbDepth = intel_get_renderbuffer(&intel_fb->Base, BUFFER_DEPTH); diff --git a/src/mesa/drivers/dri/intel/intel_context.h b/src/mesa/drivers/dri/intel/intel_context.h index d798225ddd9..c16732d7b52 100644 --- a/src/mesa/drivers/dri/intel/intel_context.h +++ b/src/mesa/drivers/dri/intel/intel_context.h @@ -161,12 +161,22 @@ struct intel_context struct { 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; diff --git a/src/mesa/drivers/dri/intel/intel_generatemipmap.c b/src/mesa/drivers/dri/intel/intel_generatemipmap.c new file mode 100644 index 00000000000..02804b51fa8 --- /dev/null +++ b/src/mesa/drivers/dri/intel/intel_generatemipmap.c @@ -0,0 +1,283 @@ +/* + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * Copyright © 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt <[email protected]> + * + */ + +#include "main/glheader.h" +#include "main/enums.h" +#include "main/image.h" +#include "main/mtypes.h" +#include "main/macros.h" +#include "main/bufferobj.h" +#include "main/teximage.h" +#include "main/texenv.h" +#include "main/texobj.h" +#include "main/texstate.h" +#include "main/texparam.h" +#include "main/varray.h" +#include "main/attrib.h" +#include "main/enable.h" +#include "main/buffers.h" +#include "main/fbobject.h" +#include "main/framebuffer.h" +#include "main/renderbuffer.h" +#include "main/depth.h" +#include "main/hash.h" +#include "main/mipmap.h" +#include "main/blend.h" +#include "glapi/dispatch.h" +#include "swrast/swrast.h" + +#include "intel_screen.h" +#include "intel_context.h" +#include "intel_batchbuffer.h" +#include "intel_pixel.h" +#include "intel_tex.h" +#include "intel_mipmap_tree.h" + +static const char *intel_fp_tex2d = + "!!ARBfp1.0\n" + "TEX result.color, fragment.texcoord[0], texture[0], 2D;\n" + "END\n"; + +static GLboolean +intel_generate_mipmap_level(GLcontext *ctx, GLuint tex_name, + int level, int width, int height) +{ + struct intel_context *intel = intel_context(ctx); + GLfloat vertices[4][2]; + GLint status; + + /* Set to source from the previous level */ + _mesa_TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, level - 1); + _mesa_TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level - 1); + + /* Set to draw into the current level */ + _mesa_FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, + tex_name, + level); + /* Choose to render to the color attachment. */ + _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + + status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT); + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + return GL_FALSE; + + intel_meta_set_passthrough_transform(intel); + + /* XXX: Doing it right would involve setting up the transformation to do + * 0-1 mapping or something, and not changing the vertex data. + */ + vertices[0][0] = 0; + vertices[0][1] = 0; + vertices[1][0] = width; + vertices[1][1] = 0; + vertices[2][0] = width; + vertices[2][1] = height; + vertices[3][0] = 0; + vertices[3][1] = height; + + _mesa_VertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), &vertices); + _mesa_Enable(GL_VERTEX_ARRAY); + intel_meta_set_default_texrect(intel); + + CALL_DrawArrays(ctx->Exec, (GL_TRIANGLE_FAN, 0, 4)); + + intel_meta_restore_texcoords(intel); + intel_meta_restore_transform(intel); + + return GL_TRUE; +} + +static GLboolean +intel_generate_mipmap_2d(GLcontext *ctx, + GLenum target, + struct gl_texture_object *texObj) +{ + struct intel_context *intel = intel_context(ctx); + GLint old_active_texture; + int level, max_levels, start_level, end_level; + GLuint fb_name; + GLboolean success = GL_FALSE; + struct gl_framebuffer *saved_fbo = NULL; + + _mesa_PushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | + GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT | + GL_DEPTH_BUFFER_BIT); + _mesa_PushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); + old_active_texture = ctx->Texture.CurrentUnit; + _mesa_reference_framebuffer(&saved_fbo, ctx->DrawBuffer); + + _mesa_Disable(GL_POLYGON_STIPPLE); + _mesa_Disable(GL_DEPTH_TEST); + _mesa_Disable(GL_STENCIL_TEST); + _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + _mesa_DepthMask(GL_FALSE); + + /* Bind the given texture to GL_TEXTURE_2D with linear filtering for our + * minification. + */ + _mesa_ActiveTextureARB(GL_TEXTURE0_ARB); + _mesa_Enable(GL_TEXTURE_2D); + _mesa_BindTexture(GL_TEXTURE_2D, texObj->Name); + _mesa_TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_LINEAR_MIPMAP_NEAREST); + _mesa_TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + /* Bind the new renderbuffer to the color attachment point. */ + _mesa_GenFramebuffersEXT(1, &fb_name); + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb_name); + + intel_meta_set_fragment_program(intel, &intel->meta.tex2d_fp, + intel_fp_tex2d); + intel_meta_set_passthrough_vertex_program(intel); + + max_levels = _mesa_max_texture_levels(ctx, texObj->Target); + start_level = texObj->BaseLevel; + end_level = texObj->MaxLevel; + + /* Loop generating level+1 from level. */ + for (level = start_level; level < end_level && level < max_levels - 1; level++) { + const struct gl_texture_image *srcImage; + int width, height; + + srcImage = _mesa_select_tex_image(ctx, texObj, target, level); + if (srcImage->Border != 0) + goto fail; + + width = srcImage->Width / 2; + if (width < 1) + width = 1; + height = srcImage->Height / 2; + if (height < 1) + height = 1; + + if (width == srcImage->Width && + height == srcImage->Height) { + /* Neither _mesa_max_texture_levels nor texObj->MaxLevel are the + * maximum texture level for the object, so break out when we've gone + * over the edge. + */ + break; + } + + /* Make sure that there's space allocated for the target level. + * We could skip this if there's already space allocated and save some + * time. + */ + _mesa_TexImage2D(GL_TEXTURE_2D, level + 1, srcImage->InternalFormat, + width, height, 0, + GL_RGBA, GL_UNSIGNED_INT, NULL); + + if (!intel_generate_mipmap_level(ctx, texObj->Name, level + 1, + width, height)) + goto fail; + } + + success = GL_TRUE; + +fail: + intel_meta_restore_fragment_program(intel); + intel_meta_restore_vertex_program(intel); + + _mesa_DeleteFramebuffersEXT(1, &fb_name); + _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + old_active_texture); + if (saved_fbo) + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, saved_fbo->Name); + _mesa_reference_framebuffer(&saved_fbo, NULL); + _mesa_PopClientAttrib(); + _mesa_PopAttrib(); + + return success; +} + + +/** + * Generate new mipmap data from BASE+1 to BASE+p (the minimally-sized mipmap + * level). + * + * The texture object's miptree must be mapped. + * + * It would be really nice if this was just called by Mesa whenever mipmaps + * needed to be regenerated, rather than us having to remember to do so in + * each texture image modification path. + * + * This function should also include an accelerated path. + */ +void +intel_generate_mipmap(GLcontext *ctx, GLenum target, + struct gl_texture_object *texObj) +{ + struct intel_context *intel = intel_context(ctx); + struct intel_texture_object *intelObj = intel_texture_object(texObj); + GLuint nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; + int face, i; + + /* HW path */ + if (target == GL_TEXTURE_2D && + ctx->Extensions.EXT_framebuffer_object && + ctx->Extensions.ARB_fragment_program && + ctx->Extensions.ARB_vertex_program) { + GLboolean success; + + /* We'll be accessing this texture using GL entrypoints, which should + * be resilient against other access to this texture. + */ + _mesa_unlock_texture(ctx, texObj); + success = intel_generate_mipmap_2d(ctx, target, texObj); + _mesa_lock_texture(ctx, texObj); + + if (success) + return; + } + + /* SW path */ + intel_tex_map_level_images(intel, intelObj, texObj->BaseLevel); + _mesa_generate_mipmap(ctx, target, texObj); + intel_tex_unmap_level_images(intel, intelObj, texObj->BaseLevel); + + /* Update the level information in our private data in the new images, since + * it didn't get set as part of a normal TexImage path. + */ + for (face = 0; face < nr_faces; face++) { + for (i = texObj->BaseLevel + 1; i < texObj->MaxLevel; i++) { + struct intel_texture_image *intelImage; + + intelImage = intel_texture_image(texObj->Image[face][i]); + if (intelImage == NULL) + break; + + intelImage->level = i; + intelImage->face = face; + /* Unreference the miptree to signal that the new Data is a bare + * pointer from mesa. + */ + intel_miptree_release(intel, &intelImage->mt); + } + } +} diff --git a/src/mesa/drivers/dri/intel/intel_mipmap_tree.c b/src/mesa/drivers/dri/intel/intel_mipmap_tree.c index 6e1e034e53d..f3652720ece 100644 --- a/src/mesa/drivers/dri/intel/intel_mipmap_tree.c +++ b/src/mesa/drivers/dri/intel/intel_mipmap_tree.c @@ -62,9 +62,10 @@ intel_miptree_create_internal(struct intel_context *intel, GLboolean ok; struct intel_mipmap_tree *mt = calloc(sizeof(*mt), 1); - DBG("%s target %s format %s level %d..%d\n", __FUNCTION__, + DBG("%s target %s format %s level %d..%d <-- %p\n", __FUNCTION__, _mesa_lookup_enum_by_nr(target), - _mesa_lookup_enum_by_nr(internal_format), first_level, last_level); + _mesa_lookup_enum_by_nr(internal_format), + first_level, last_level, mt); mt->target = target_to_target(target); mt->internal_format = internal_format; @@ -89,6 +90,7 @@ intel_miptree_create_internal(struct intel_context *intel, if (!ok) { free(mt); + DBG("%s not okay - returning NULL\n", __FUNCTION__); return NULL; } diff --git a/src/mesa/drivers/dri/intel/intel_pixel.c b/src/mesa/drivers/dri/intel/intel_pixel.c index fc0ac0b79c0..36a684b3b85 100644 --- a/src/mesa/drivers/dri/intel/intel_pixel.c +++ b/src/mesa/drivers/dri/intel/intel_pixel.c @@ -27,9 +27,12 @@ #include "main/enums.h" #include "main/state.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 "swrast/swrast.h" #include "shader/arbprogram.h" @@ -334,6 +337,85 @@ intel_meta_restore_fragment_program(struct intel_context *intel) _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 +intel_meta_set_default_texrect(struct intel_context *intel) +{ + GLcontext *ctx = &intel->ctx; + struct gl_client_array *old_texcoord_array; + + intel->meta.saved_active_texture = ctx->Texture.CurrentUnit; + if (intel->meta.saved_array_vbo == NULL) { + _mesa_reference_buffer_object(ctx, &intel->meta.saved_array_vbo, + ctx->Array.ArrayBufferObj); + } + + old_texcoord_array = &ctx->Array.ArrayObj->TexCoord[0]; + intel->meta.saved_texcoord_type = old_texcoord_array->Type; + intel->meta.saved_texcoord_size = old_texcoord_array->Size; + intel->meta.saved_texcoord_stride = old_texcoord_array->Stride; + intel->meta.saved_texcoord_enable = old_texcoord_array->Enabled; + intel->meta.saved_texcoord_ptr = old_texcoord_array->Ptr; + _mesa_reference_buffer_object(ctx, &intel->meta.saved_texcoord_vbo, + old_texcoord_array->BufferObj); + + _mesa_ClientActiveTextureARB(GL_TEXTURE0); + + if (intel->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, &intel->meta.texcoord_vbo, + ctx->Array.ArrayBufferObj); + } else { + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, + intel->meta.texcoord_vbo->Name); + } + _mesa_TexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), NULL); + + _mesa_Enable(GL_TEXTURE_COORD_ARRAY); +} + +void +intel_meta_restore_texcoords(struct intel_context *intel) +{ + GLcontext *ctx = &intel->ctx; + + /* Restore the old TexCoordPointer */ + if (intel->meta.saved_texcoord_vbo) { + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, + intel->meta.saved_texcoord_vbo->Name); + _mesa_reference_buffer_object(ctx, &intel->meta.saved_texcoord_vbo, NULL); + } else { + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + } + + _mesa_TexCoordPointer(intel->meta.saved_texcoord_size, + intel->meta.saved_texcoord_type, + intel->meta.saved_texcoord_stride, + intel->meta.saved_texcoord_ptr); + if (!intel->meta.saved_texcoord_enable) + _mesa_Disable(GL_TEXTURE_COORD_ARRAY); + + _mesa_ClientActiveTextureARB(GL_TEXTURE0 + + intel->meta.saved_active_texture); + + if (intel->meta.saved_array_vbo) { + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, + intel->meta.saved_array_vbo->Name); + _mesa_reference_buffer_object(ctx, &intel->meta.saved_array_vbo, NULL); + } else { + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + } +} + void intelInitPixelFuncs(struct dd_function_table *functions) { @@ -355,5 +437,7 @@ intel_free_pixel_state(struct intel_context *intel) _mesa_reference_vertprog(ctx, &intel->meta.passthrough_vp, NULL); _mesa_reference_fragprog(ctx, &intel->meta.bitmap_fp, NULL); + _mesa_reference_fragprog(ctx, &intel->meta.tex2d_fp, NULL); + _mesa_reference_buffer_object(ctx, &intel->meta.texcoord_vbo, NULL); } diff --git a/src/mesa/drivers/dri/intel/intel_pixel.h b/src/mesa/drivers/dri/intel/intel_pixel.h index cb41fa182cb..6acf0813c8c 100644 --- a/src/mesa/drivers/dri/intel/intel_pixel.h +++ b/src/mesa/drivers/dri/intel/intel_pixel.h @@ -40,6 +40,9 @@ void intel_meta_set_fragment_program(struct intel_context *intel, const char *prog_string); void intel_meta_restore_fragment_program(struct intel_context *intel); void intel_free_pixel_state(struct intel_context *intel); +void intel_meta_set_default_texrect(struct intel_context *intel); +void intel_meta_set_default_texrect(struct intel_context *intel); +void intel_meta_restore_texcoords(struct intel_context *intel); GLboolean intel_check_blit_fragment_ops(GLcontext * ctx, GLboolean src_alpha_is_one); diff --git a/src/mesa/drivers/dri/intel/intel_pixel_bitmap.c b/src/mesa/drivers/dri/intel/intel_pixel_bitmap.c index 1db7f5594e9..b20840b9a06 100644 --- a/src/mesa/drivers/dri/intel/intel_pixel_bitmap.c +++ b/src/mesa/drivers/dri/intel/intel_pixel_bitmap.c @@ -360,7 +360,6 @@ intel_texture_bitmap(GLcontext * ctx, "END\n"; GLuint texname; GLfloat vertices[4][4]; - GLfloat texcoords[4][2]; GLint old_active_texture; GLubyte *unpacked_bitmap; GLubyte *a8_bitmap; @@ -485,22 +484,12 @@ intel_texture_bitmap(GLcontext * ctx, vertices[3][2] = dst_z; vertices[3][3] = 1.0; - texcoords[0][0] = 0.0; - texcoords[0][1] = 0.0; - texcoords[1][0] = 1.0; - texcoords[1][1] = 0.0; - texcoords[2][0] = 1.0; - texcoords[2][1] = 1.0; - texcoords[3][0] = 0.0; - texcoords[3][1] = 1.0; - _mesa_VertexPointer(4, GL_FLOAT, 4 * sizeof(GLfloat), &vertices); - _mesa_ClientActiveTextureARB(GL_TEXTURE0); - _mesa_TexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), &texcoords); _mesa_Enable(GL_VERTEX_ARRAY); - _mesa_Enable(GL_TEXTURE_COORD_ARRAY); + intel_meta_set_default_texrect(intel); CALL_DrawArrays(ctx->Exec, (GL_TRIANGLE_FAN, 0, 4)); + intel_meta_restore_texcoords(intel); intel_meta_restore_transform(intel); intel_meta_restore_fragment_program(intel); intel_meta_restore_vertex_program(intel); diff --git a/src/mesa/drivers/dri/intel/intel_pixel_draw.c b/src/mesa/drivers/dri/intel/intel_pixel_draw.c index e8d5ac8569d..abcdcd5724c 100644 --- a/src/mesa/drivers/dri/intel/intel_pixel_draw.c +++ b/src/mesa/drivers/dri/intel/intel_pixel_draw.c @@ -70,7 +70,6 @@ intel_texture_drawpixels(GLcontext * ctx, struct intel_context *intel = intel_context(ctx); GLuint texname; GLfloat vertices[4][4]; - GLfloat texcoords[4][2]; GLfloat z; GLint old_active_texture; GLenum internalFormat; @@ -169,22 +168,13 @@ intel_texture_drawpixels(GLcontext * ctx, vertices[3][2] = z; vertices[3][3] = 1.0; - texcoords[0][0] = 0.0; - texcoords[0][1] = 0.0; - texcoords[1][0] = 1.0; - texcoords[1][1] = 0.0; - texcoords[2][0] = 1.0; - texcoords[2][1] = 1.0; - texcoords[3][0] = 0.0; - texcoords[3][1] = 1.0; - _mesa_VertexPointer(4, GL_FLOAT, 4 * sizeof(GLfloat), &vertices); - _mesa_ClientActiveTextureARB(GL_TEXTURE0); - _mesa_TexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), &texcoords); _mesa_Enable(GL_VERTEX_ARRAY); - _mesa_Enable(GL_TEXTURE_COORD_ARRAY); + intel_meta_set_default_texrect(intel); + CALL_DrawArrays(ctx->Exec, (GL_TRIANGLE_FAN, 0, 4)); + intel_meta_restore_texcoords(intel); intel_meta_restore_transform(intel); _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + old_active_texture); @@ -208,7 +198,6 @@ intel_stencil_drawpixels(GLcontext * ctx, struct intel_context *intel = intel_context(ctx); GLuint texname, rb_name, fb_name, old_fb_name; GLfloat vertices[4][2]; - GLfloat texcoords[4][2]; struct intel_renderbuffer *irb; struct intel_renderbuffer *depth_irb; struct gl_renderbuffer *rb; @@ -343,7 +332,6 @@ intel_stencil_drawpixels(GLcontext * ctx, _mesa_free(stencil_pixels); intel_meta_set_passthrough_transform(intel); - vertices[0][0] = x; vertices[0][1] = y; vertices[1][0] = x + width * ctx->Pixel.ZoomX; @@ -353,22 +341,13 @@ intel_stencil_drawpixels(GLcontext * ctx, vertices[3][0] = x; vertices[3][1] = y + height * ctx->Pixel.ZoomY; - texcoords[0][0] = 0.0; - texcoords[0][1] = 0.0; - texcoords[1][0] = 1.0; - texcoords[1][1] = 0.0; - texcoords[2][0] = 1.0; - texcoords[2][1] = 1.0; - texcoords[3][0] = 0.0; - texcoords[3][1] = 1.0; - _mesa_VertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), &vertices); - _mesa_ClientActiveTextureARB(GL_TEXTURE0); - _mesa_TexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), &texcoords); _mesa_Enable(GL_VERTEX_ARRAY); - _mesa_Enable(GL_TEXTURE_COORD_ARRAY); + intel_meta_set_default_texrect(intel); + CALL_DrawArrays(ctx->Exec, (GL_TRIANGLE_FAN, 0, 4)); + intel_meta_restore_texcoords(intel); intel_meta_restore_transform(intel); _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + old_active_texture); diff --git a/src/mesa/drivers/dri/intel/intel_regions.c b/src/mesa/drivers/dri/intel/intel_regions.c index 0aa5b8c02c9..534e75efe1f 100644 --- a/src/mesa/drivers/dri/intel/intel_regions.c +++ b/src/mesa/drivers/dri/intel/intel_regions.c @@ -52,12 +52,66 @@ #define FILE_DEBUG_FLAG DEBUG_REGION +/* This should be set to the maximum backtrace size desired. + * Set it to 0 to disable backtrace debugging. + */ +#define DEBUG_BACKTRACE_SIZE 0 + +#if DEBUG_BACKTRACE_SIZE == 0 +/* Use the standard debug output */ +#define _DBG(...) DBG(__VA_ARGS__) +#else +/* Use backtracing debug output */ +#define _DBG(...) {debug_backtrace(); DBG(__VA_ARGS__);} + +/* Backtracing debug support */ +#include <execinfo.h> + +static void +debug_backtrace(void) +{ + void *trace[DEBUG_BACKTRACE_SIZE]; + char **strings = NULL; + int traceSize; + register int i; + + traceSize = backtrace(trace, DEBUG_BACKTRACE_SIZE); + strings = backtrace_symbols(trace, traceSize); + if (strings == NULL) { + DBG("no backtrace:"); + return; + } + + /* Spit out all the strings with a colon separator. Ignore + * the first, since we don't really care about the call + * to debug_backtrace() itself. Skip until the final "/" in + * the trace to avoid really long lines. + */ + for (i = 1; i < traceSize; i++) { + char *p = strings[i], *slash = strings[i]; + while (*p) { + if (*p++ == '/') { + slash = p; + } + } + + DBG("%s:", slash); + } + + /* Free up the memory, and we're done */ + free(strings); +} + +#endif + + + /* XXX: Thread safety? */ GLubyte * intel_region_map(struct intel_context *intel, struct intel_region *region) { - DBG("%s\n", __FUNCTION__); + _DBG("%s %p\n", __FUNCTION__, region); if (!region->map_refcount++) { if (region->pbo) intel_region_cow(intel, region); @@ -72,7 +126,7 @@ intel_region_map(struct intel_context *intel, struct intel_region *region) void intel_region_unmap(struct intel_context *intel, struct intel_region *region) { - DBG("%s\n", __FUNCTION__); + _DBG("%s %p\n", __FUNCTION__, region); if (!--region->map_refcount) { dri_bo_unmap(region->buffer); region->map = NULL; @@ -87,10 +141,10 @@ intel_region_alloc_internal(struct intel_context *intel, { struct intel_region *region; - DBG("%s\n", __FUNCTION__); - - if (buffer == NULL) + if (buffer == NULL) { + _DBG("%s <-- NULL\n", __FUNCTION__); return NULL; + } region = calloc(sizeof(*region), 1); region->cpp = cpp; @@ -104,6 +158,7 @@ intel_region_alloc_internal(struct intel_context *intel, region->tiling = I915_TILING_NONE; region->bit_6_swizzle = I915_BIT_6_SWIZZLE_NONE; + _DBG("%s <-- %p\n", __FUNCTION__, region); return region; } @@ -158,7 +213,7 @@ void intel_region_reference(struct intel_region **dst, struct intel_region *src) { if (src) - DBG("%s %p %d\n", __FUNCTION__, src, src->refcount); + _DBG("%s %p %d\n", __FUNCTION__, src, src->refcount); assert(*dst == NULL); if (src) { @@ -172,10 +227,12 @@ intel_region_release(struct intel_region **region_handle) { struct intel_region *region = *region_handle; - if (region == NULL) + if (region == NULL) { + _DBG("%s NULL\n", __FUNCTION__); return; + } - DBG("%s %p %d\n", __FUNCTION__, region, region->refcount - 1); + _DBG("%s %p %d\n", __FUNCTION__, region, region->refcount - 1); ASSERT(region->refcount > 0); region->refcount--; @@ -251,7 +308,7 @@ intel_region_data(struct intel_context *intel, { GLboolean locked = GL_FALSE; - DBG("%s\n", __FUNCTION__); + _DBG("%s\n", __FUNCTION__); if (intel == NULL) return; @@ -293,7 +350,7 @@ intel_region_copy(struct intel_context *intel, GLuint src_offset, GLuint srcx, GLuint srcy, GLuint width, GLuint height) { - DBG("%s\n", __FUNCTION__); + _DBG("%s\n", __FUNCTION__); if (intel == NULL) return; @@ -326,7 +383,7 @@ intel_region_fill(struct intel_context *intel, GLuint dstx, GLuint dsty, GLuint width, GLuint height, GLuint color) { - DBG("%s\n", __FUNCTION__); + _DBG("%s\n", __FUNCTION__); if (intel == NULL) return; @@ -356,6 +413,8 @@ intel_region_attach_pbo(struct intel_context *intel, if (region->pbo == pbo) return; + _DBG("%s %p %p\n", __FUNCTION__, region, pbo); + /* If there is already a pbo attached, break the cow tie now. * Don't call intel_region_release_pbo() as that would * unnecessarily allocate a new buffer we would have to immediately @@ -385,6 +444,7 @@ void intel_region_release_pbo(struct intel_context *intel, struct intel_region *region) { + _DBG("%s %p\n", __FUNCTION__, region); assert(region->buffer == region->pbo->buffer); region->pbo->region = NULL; region->pbo = NULL; @@ -412,7 +472,7 @@ intel_region_cow(struct intel_context *intel, struct intel_region *region) assert(region->cpp * region->pitch * region->height == pbo->Base.Size); - DBG("%s (%d bytes)\n", __FUNCTION__, pbo->Base.Size); + _DBG("%s %p (%d bytes)\n", __FUNCTION__, region, pbo->Base.Size); /* Now blit from the texture buffer to the new buffer: */ @@ -459,6 +519,10 @@ intel_recreate_static(struct intel_context *intel, if (region == NULL) { region = calloc(sizeof(*region), 1); region->refcount = 1; + _DBG("%s creating new region %p\n", __FUNCTION__, region); + } + else { + _DBG("%s %p\n", __FUNCTION__, region); } if (intel->ctx.Visual.rgbBits == 24) diff --git a/src/mesa/drivers/dri/intel/intel_tex.c b/src/mesa/drivers/dri/intel/intel_tex.c index ae0994b183a..fbd6e1d0c36 100644 --- a/src/mesa/drivers/dri/intel/intel_tex.c +++ b/src/mesa/drivers/dri/intel/intel_tex.c @@ -158,60 +158,6 @@ timed_memcpy(void *dest, const void *src, size_t n) } #endif /* DO_DEBUG */ -/** - * Generate new mipmap data from BASE+1 to BASE+p (the minimally-sized mipmap - * level). - * - * The texture object's miptree must be mapped. - * - * It would be really nice if this was just called by Mesa whenever mipmaps - * needed to be regenerated, rather than us having to remember to do so in - * each texture image modification path. - * - * This function should also include an accelerated path. - */ -void -intel_generate_mipmap(GLcontext *ctx, GLenum target, - struct gl_texture_object *texObj) -{ - struct intel_context *intel = intel_context(ctx); - struct intel_texture_object *intelObj = intel_texture_object(texObj); - GLuint nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; - int face, i; - - _mesa_generate_mipmap(ctx, target, texObj); - - /* Update the level information in our private data in the new images, since - * it didn't get set as part of a normal TexImage path. - */ - for (face = 0; face < nr_faces; face++) { - for (i = texObj->BaseLevel + 1; i < texObj->MaxLevel; i++) { - struct intel_texture_image *intelImage; - - intelImage = intel_texture_image(texObj->Image[face][i]); - if (intelImage == NULL) - break; - - intelImage->level = i; - intelImage->face = face; - /* Unreference the miptree to signal that the new Data is a bare - * pointer from mesa. - */ - intel_miptree_release(intel, &intelImage->mt); - } - } -} - -static void intelGenerateMipmap(GLcontext *ctx, GLenum target, struct gl_texture_object *texObj) -{ - struct intel_context *intel = intel_context(ctx); - struct intel_texture_object *intelObj = intel_texture_object(texObj); - - intel_tex_map_level_images(intel, intelObj, texObj->BaseLevel); - intel_generate_mipmap(ctx, target, texObj); - intel_tex_unmap_level_images(intel, intelObj, texObj->BaseLevel); -} - void intelInitTextureFuncs(struct dd_function_table *functions) { @@ -227,7 +173,7 @@ intelInitTextureFuncs(struct dd_function_table *functions) functions->CopyTexSubImage1D = intelCopyTexSubImage1D; functions->CopyTexSubImage2D = intelCopyTexSubImage2D; functions->GetTexImage = intelGetTexImage; - functions->GenerateMipmap = intelGenerateMipmap; + functions->GenerateMipmap = intel_generate_mipmap; /* compressed texture functions */ functions->CompressedTexImage2D = intelCompressedTexImage2D; diff --git a/src/mesa/drivers/dri/intel/intel_tex_copy.c b/src/mesa/drivers/dri/intel/intel_tex_copy.c index 08437aa0e2b..7c2b26ef1d4 100644 --- a/src/mesa/drivers/dri/intel/intel_tex_copy.c +++ b/src/mesa/drivers/dri/intel/intel_tex_copy.c @@ -158,7 +158,7 @@ do_copy_texsubimage(struct intel_context *intel, /* GL_SGIS_generate_mipmap */ if (intelImage->level == texObj->BaseLevel && texObj->GenerateMipmap) { - ctx->Driver.GenerateMipmap(ctx, target, texObj); + intel_generate_mipmap(ctx, target, texObj); } return GL_TRUE; diff --git a/src/mesa/drivers/dri/intel/intel_tex_image.c b/src/mesa/drivers/dri/intel/intel_tex_image.c index 1f192dafbe1..b71fe2a7ae0 100644 --- a/src/mesa/drivers/dri/intel/intel_tex_image.c +++ b/src/mesa/drivers/dri/intel/intel_tex_image.c @@ -316,7 +316,6 @@ intelTexImage(GLcontext * ctx, GLint postConvHeight = height; GLint texelBytes, sizeInBytes; GLuint dstRowStride = 0, srcRowStride = texImage->RowStride; - GLboolean needs_map; DBG("%s target %s level %d %dx%dx%d border %d\n", __FUNCTION__, _mesa_lookup_enum_by_nr(target), level, width, height, depth, border); @@ -482,15 +481,8 @@ intelTexImage(GLcontext * ctx, LOCK_HARDWARE(intel); - /* Two cases where we need a mapping of the miptree: when the user supplied - * data is mapped as well (non-PBO, memcpy upload) or when we're going to do - * (software) mipmap generation. - */ - needs_map = (pixels != NULL) || (level == texObj->BaseLevel && - texObj->GenerateMipmap); - if (intelImage->mt) { - if (needs_map) + if (pixels != NULL) texImage->Data = intel_miptree_image_map(intel, intelImage->mt, intelImage->face, @@ -547,22 +539,22 @@ intelTexImage(GLcontext * ctx, format, type, pixels, unpack)) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); } - - /* GL_SGIS_generate_mipmap */ - if (level == texObj->BaseLevel && texObj->GenerateMipmap) { - intel_generate_mipmap(ctx, target, texObj); - } } _mesa_unmap_teximage_pbo(ctx, unpack); if (intelImage->mt) { - if (needs_map) + if (pixels != NULL) intel_miptree_image_unmap(intel, intelImage->mt); texImage->Data = NULL; } UNLOCK_HARDWARE(intel); + + /* GL_SGIS_generate_mipmap */ + if (level == texObj->BaseLevel && texObj->GenerateMipmap) { + intel_generate_mipmap(ctx, target, texObj); + } } void diff --git a/src/mesa/drivers/dri/intel/intel_tex_subimage.c b/src/mesa/drivers/dri/intel/intel_tex_subimage.c index f86de568976..48104de2a9b 100644 --- a/src/mesa/drivers/dri/intel/intel_tex_subimage.c +++ b/src/mesa/drivers/dri/intel/intel_tex_subimage.c @@ -101,11 +101,6 @@ intelTexSubimage(GLcontext * ctx, _mesa_error(ctx, GL_OUT_OF_MEMORY, "intelTexSubImage"); } - /* GL_SGIS_generate_mipmap */ - if (level == texObj->BaseLevel && texObj->GenerateMipmap) { - intel_generate_mipmap(ctx, target, texObj); - } - _mesa_unmap_teximage_pbo(ctx, packing); if (intelImage->mt) { @@ -114,6 +109,11 @@ intelTexSubimage(GLcontext * ctx, } UNLOCK_HARDWARE(intel); + + /* GL_SGIS_generate_mipmap */ + if (level == texObj->BaseLevel && texObj->GenerateMipmap) { + intel_generate_mipmap(ctx, target, texObj); + } } diff --git a/src/mesa/drivers/dri/r200/r200_state.c b/src/mesa/drivers/dri/r200/r200_state.c index ebf389efe26..a06ea17e799 100644 --- a/src/mesa/drivers/dri/r200/r200_state.c +++ b/src/mesa/drivers/dri/r200/r200_state.c @@ -2327,7 +2327,7 @@ GLboolean r200ValidateState( GLcontext *ctx ) R200_STATECHANGE(rmesa, ctx); } - if (new_state & (_NEW_TEXTURE | _NEW_PROGRAM)) { + if (new_state & (_NEW_TEXTURE | _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS)) { r200UpdateTextureState( ctx ); new_state |= rmesa->radeon.NewGLState; /* may add TEXTURE_MATRIX */ r200UpdateLocalViewer( ctx ); @@ -2370,6 +2370,7 @@ GLboolean r200ValidateState( GLcontext *ctx ) } if (new_state & (_NEW_PROGRAM| + _NEW_PROGRAM_CONSTANTS | /* need to test for pretty much anything due to possible parameter bindings */ _NEW_MODELVIEW|_NEW_PROJECTION|_NEW_TRANSFORM| _NEW_LIGHT|_NEW_TEXTURE|_NEW_TEXTURE_MATRIX| diff --git a/src/mesa/drivers/dri/r300/r300_state.c b/src/mesa/drivers/dri/r300/r300_state.c index 330f1dab493..217a16818e3 100644 --- a/src/mesa/drivers/dri/r300/r300_state.c +++ b/src/mesa/drivers/dri/r300/r300_state.c @@ -464,7 +464,9 @@ static void r300SetEarlyZState(GLcontext * ctx) if (ctx->Color.AlphaEnabled && ctx->Color.AlphaFunc != GL_ALWAYS) topZ = R300_ZTOP_DISABLE; - if (current_fragment_program_writes_depth(ctx)) + else if (current_fragment_program_writes_depth(ctx)) + topZ = R300_ZTOP_DISABLE; + else if (ctx->FragmentProgram._Current && ctx->FragmentProgram._Current->UsesKill) topZ = R300_ZTOP_DISABLE; if (topZ != r300->hw.zstencil_format.cmd[2]) { @@ -1060,7 +1062,7 @@ void r300UpdateStateParameters(GLcontext * ctx, GLuint new_state) struct gl_program_parameter_list *paramList; GLuint i; - if (!(new_state & (_NEW_BUFFERS | _NEW_PROGRAM))) + if (!(new_state & (_NEW_BUFFERS | _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS))) return; fp = (struct r300_fragment_program *)ctx->FragmentProgram._Current; @@ -2218,11 +2220,12 @@ void r300UpdateShaders(r300ContextPtr rmesa) hw_tcl_on = future_hw_tcl_on = 0; r300ResetHwState(rmesa); - r300UpdateStateParameters(ctx, _NEW_PROGRAM); + r300UpdateStateParameters(ctx, _NEW_PROGRAM | + _NEW_PROGRAM_CONSTANTS); return; } } - r300UpdateStateParameters(ctx, _NEW_PROGRAM); + r300UpdateStateParameters(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); } static const GLfloat *get_fragmentprogram_constant(GLcontext *ctx, diff --git a/src/mesa/drivers/x11/xm_dd.c b/src/mesa/drivers/x11/xm_dd.c index 305df548fa2..9a01465bdf9 100644 --- a/src/mesa/drivers/x11/xm_dd.c +++ b/src/mesa/drivers/x11/xm_dd.c @@ -912,8 +912,9 @@ xmesa_update_state( GLcontext *ctx, GLbitfield new_state ) /* * GL_DITHER, GL_READ/DRAW_BUFFER, buffer binding state, etc. effect * renderbuffer span/clear funcs. + * Check _NEW_COLOR to detect dither enable/disable. */ - if (new_state & (_NEW_COLOR | _NEW_PIXEL | _NEW_BUFFERS)) { + if (new_state & (_NEW_COLOR | _NEW_BUFFERS)) { XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); struct xmesa_renderbuffer *front_xrb, *back_xrb; diff --git a/src/mesa/gl.pc.in b/src/mesa/gl.pc.in index 0462b9fca2b..97b86596fcf 100644 --- a/src/mesa/gl.pc.in +++ b/src/mesa/gl.pc.in @@ -7,6 +7,6 @@ Name: gl Description: Mesa OpenGL library Requires.private: @GL_PC_REQ_PRIV@ Version: @VERSION@ -Libs: -L${libdir} -lGL +Libs: -L${libdir} -l@GL_LIB@ Libs.private: @GL_PC_LIB_PRIV@ Cflags: -I${includedir} @GL_PC_CFLAGS@ diff --git a/src/mesa/main/api_validate.c b/src/mesa/main/api_validate.c index 42d1e579e08..d5c604c56a2 100644 --- a/src/mesa/main/api_validate.c +++ b/src/mesa/main/api_validate.c @@ -30,6 +30,26 @@ #include "state.h" + +/** + * \return number of bytes in array [count] of type. + */ +static GLsizei +index_bytes(GLenum type, GLsizei count) +{ + if (type == GL_UNSIGNED_INT) { + return count * sizeof(GLuint); + } + else if (type == GL_UNSIGNED_BYTE) { + return count * sizeof(GLubyte); + } + else { + ASSERT(type == GL_UNSIGNED_SHORT); + return count * sizeof(GLushort); + } +} + + /** * Find the max index in the given element/index buffer */ @@ -44,10 +64,8 @@ max_buffer_index(GLcontext *ctx, GLuint count, GLenum type, if (elementBuf->Name) { /* elements are in a user-defined buffer object. need to map it */ - map = ctx->Driver.MapBuffer(ctx, - GL_ELEMENT_ARRAY_BUFFER_ARB, - GL_READ_ONLY, - elementBuf); + map = ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, + GL_READ_ONLY, elementBuf); /* Actual address is the sum of pointers */ indices = (const GLvoid *) ADD_POINTERS(map, (const GLubyte *) indices); } @@ -70,14 +88,16 @@ max_buffer_index(GLcontext *ctx, GLuint count, GLenum type, } if (map) { - ctx->Driver.UnmapBuffer(ctx, - GL_ELEMENT_ARRAY_BUFFER_ARB, - ctx->Array.ElementArrayBufferObj); + ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, elementBuf); } return max; } + +/** + * Check if OK to render by examining framebuffer status and vertex arrays. + */ static GLboolean check_valid_to_render(GLcontext *ctx, char *function) { @@ -105,6 +125,12 @@ check_valid_to_render(GLcontext *ctx, char *function) return GL_TRUE; } + +/** + * Error checking for glDrawElements(). Includes parameter checking + * and VBO bounds checking. + * \return GL_TRUE if OK to render, GL_FALSE if error found + */ GLboolean _mesa_validate_DrawElements(GLcontext *ctx, GLenum mode, GLsizei count, GLenum type, @@ -140,27 +166,8 @@ _mesa_validate_DrawElements(GLcontext *ctx, /* Vertex buffer object tests */ if (ctx->Array.ElementArrayBufferObj->Name) { /* use indices in the buffer object */ - GLuint indexBytes; - - if (!ctx->Array.ElementArrayBufferObj->Size) { - _mesa_warning(ctx, - "glDrawElements called with empty array elements buffer"); - return GL_FALSE; - } - - if (type == GL_UNSIGNED_INT) { - indexBytes = count * sizeof(GLuint); - } - else if (type == GL_UNSIGNED_BYTE) { - indexBytes = count * sizeof(GLubyte); - } - else { - ASSERT(type == GL_UNSIGNED_SHORT); - indexBytes = count * sizeof(GLushort); - } - /* make sure count doesn't go outside buffer bounds */ - if (indexBytes > (GLuint) ctx->Array.ElementArrayBufferObj->Size) { + if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) { _mesa_warning(ctx, "glDrawElements index out of buffer bounds"); return GL_FALSE; } @@ -177,6 +184,8 @@ _mesa_validate_DrawElements(GLcontext *ctx, ctx->Array.ElementArrayBufferObj); if (max >= ctx->Array._MaxElement) { /* the max element is out of bounds of one or more enabled arrays */ + _mesa_warning(ctx, "glDrawElements() index=%u is " + "out of bounds (max=%u)", max, ctx->Array._MaxElement); return GL_FALSE; } } @@ -184,6 +193,12 @@ _mesa_validate_DrawElements(GLcontext *ctx, return GL_TRUE; } + +/** + * Error checking for glDrawRangeElements(). Includes parameter checking + * and VBO bounds checking. + * \return GL_TRUE if OK to render, GL_FALSE if error found + */ GLboolean _mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, GLuint start, GLuint end, @@ -224,21 +239,8 @@ _mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, /* Vertex buffer object tests */ if (ctx->Array.ElementArrayBufferObj->Name) { /* use indices in the buffer object */ - GLuint indexBytes; - - if (type == GL_UNSIGNED_INT) { - indexBytes = count * sizeof(GLuint); - } - else if (type == GL_UNSIGNED_BYTE) { - indexBytes = count * sizeof(GLubyte); - } - else { - ASSERT(type == GL_UNSIGNED_SHORT); - indexBytes = count * sizeof(GLushort); - } - /* make sure count doesn't go outside buffer bounds */ - if (indexBytes > ctx->Array.ElementArrayBufferObj->Size) { + if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) { _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds"); return GL_FALSE; } @@ -265,6 +267,7 @@ _mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, /** * Called from the tnl module to error check the function parameters and * verify that we really can draw something. + * \return GL_TRUE if OK to render, GL_FALSE if error found */ GLboolean _mesa_validate_DrawArrays(GLcontext *ctx, diff --git a/src/mesa/main/arrayobj.c b/src/mesa/main/arrayobj.c index b04095fd16b..8ec73b9526c 100644 --- a/src/mesa/main/arrayobj.c +++ b/src/mesa/main/arrayobj.c @@ -69,6 +69,32 @@ lookup_arrayobj(GLcontext *ctx, GLuint id) /** + * For all the vertex arrays in the array object, unbind any pointers + * to any buffer objects (VBOs). + * This is done just prior to array object destruction. + */ +static void +unbind_array_object_vbos(GLcontext *ctx, struct gl_array_object *obj) +{ + GLuint i; + + _mesa_reference_buffer_object(ctx, &obj->Vertex.BufferObj, NULL); + _mesa_reference_buffer_object(ctx, &obj->Normal.BufferObj, NULL); + _mesa_reference_buffer_object(ctx, &obj->Color.BufferObj, NULL); + _mesa_reference_buffer_object(ctx, &obj->SecondaryColor.BufferObj, NULL); + _mesa_reference_buffer_object(ctx, &obj->FogCoord.BufferObj, NULL); + _mesa_reference_buffer_object(ctx, &obj->Index.BufferObj, NULL); + _mesa_reference_buffer_object(ctx, &obj->EdgeFlag.BufferObj, NULL); + + for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) + _mesa_reference_buffer_object(ctx, &obj->TexCoord[i].BufferObj, NULL); + + for (i = 0; i < VERT_ATTRIB_MAX; i++) + _mesa_reference_buffer_object(ctx, &obj->VertexAttrib[i].BufferObj,NULL); +} + + +/** * Allocate and initialize a new vertex array object. * * This function is intended to be called via @@ -94,10 +120,70 @@ void _mesa_delete_array_object( GLcontext *ctx, struct gl_array_object *obj ) { (void) ctx; + unbind_array_object_vbos(ctx, obj); + _glthread_DESTROY_MUTEX(obj->Mutex); _mesa_free(obj); } +/** + * Set ptr to arrayObj w/ reference counting. + */ +void +_mesa_reference_array_object(GLcontext *ctx, + struct gl_array_object **ptr, + struct gl_array_object *arrayObj) +{ + if (*ptr == arrayObj) + return; + + if (*ptr) { + /* Unreference the old array object */ + GLboolean deleteFlag = GL_FALSE; + struct gl_array_object *oldObj = *ptr; + + _glthread_LOCK_MUTEX(oldObj->Mutex); + ASSERT(oldObj->RefCount > 0); + oldObj->RefCount--; +#if 0 + printf("ArrayObj %p %d DECR to %d\n", + (void *) oldObj, oldObj->Name, oldObj->RefCount); +#endif + deleteFlag = (oldObj->RefCount == 0); + _glthread_UNLOCK_MUTEX(oldObj->Mutex); + + if (deleteFlag) { + ASSERT(ctx->Driver.DeleteArrayObject); + ctx->Driver.DeleteArrayObject(ctx, oldObj); + } + + *ptr = NULL; + } + ASSERT(!*ptr); + + if (arrayObj) { + /* reference new array object */ + _glthread_LOCK_MUTEX(arrayObj->Mutex); + if (arrayObj->RefCount == 0) { + /* this array's being deleted (look just above) */ + /* Not sure this can every really happen. Warn if it does. */ + _mesa_problem(NULL, "referencing deleted array object"); + *ptr = NULL; + } + else { + arrayObj->RefCount++; +#if 0 + printf("ArrayObj %p %d INCR to %d\n", + (void *) arrayObj, arrayObj->Name, arrayObj->RefCount); +#endif + *ptr = arrayObj; + } + _glthread_UNLOCK_MUTEX(arrayObj->Mutex); + } +} + + + static void init_array(GLcontext *ctx, struct gl_client_array *array, GLint size, GLint type) @@ -112,7 +198,8 @@ init_array(GLcontext *ctx, array->Normalized = GL_FALSE; #if FEATURE_ARB_vertex_buffer_object /* Vertex array buffers */ - array->BufferObj = ctx->Array.NullBufferObj; + _mesa_reference_buffer_object(ctx, &array->BufferObj, + ctx->Shared->NullBufferObj); #endif } @@ -129,6 +216,9 @@ _mesa_initialize_array_object( GLcontext *ctx, obj->Name = name; + _glthread_INIT_MUTEX(obj->Mutex); + obj->RefCount = 1; + /* Init the individual arrays */ init_array(ctx, &obj->Vertex, 4, GL_FLOAT); init_array(ctx, &obj->Normal, 3, GL_FLOAT); @@ -153,8 +243,8 @@ _mesa_initialize_array_object( GLcontext *ctx, /** * Add the given array object to the array object pool. */ -void -_mesa_save_array_object( GLcontext *ctx, struct gl_array_object *obj ) +static void +save_array_object( GLcontext *ctx, struct gl_array_object *obj ) { if (obj->Name > 0) { /* insert into hash table */ @@ -167,8 +257,8 @@ _mesa_save_array_object( GLcontext *ctx, struct gl_array_object *obj ) * Remove the given array object from the array object pool. * Do not deallocate the array object though. */ -void -_mesa_remove_array_object( GLcontext *ctx, struct gl_array_object *obj ) +static void +remove_array_object( GLcontext *ctx, struct gl_array_object *obj ) { if (obj->Name > 0) { /* remove from hash table */ @@ -177,15 +267,6 @@ _mesa_remove_array_object( GLcontext *ctx, struct gl_array_object *obj ) } -static void -unbind_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj ) -{ - if (bufObj != ctx->Array.NullBufferObj) { - _mesa_reference_buffer_object(ctx, &bufObj, NULL); - } -} - - /**********************************************************************/ /* API Functions */ /**********************************************************************/ @@ -212,7 +293,7 @@ _mesa_BindVertexArrayAPPLE( GLuint id ) return; /* rebinding the same array object- no change */ /* - * Get pointer to new array object (newBufObj) + * Get pointer to new array object (newObj) */ if (id == 0) { /* The spec says there is no array object named 0, but we use @@ -226,21 +307,18 @@ _mesa_BindVertexArrayAPPLE( GLuint id ) if (!newObj) { /* If this is a new array object id, allocate an array object now. */ - newObj = (*ctx->Driver.NewArrayObject)(ctx, id); if (!newObj) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindVertexArrayAPPLE"); return; } - _mesa_save_array_object(ctx, newObj); + save_array_object(ctx, newObj); } } - ctx->NewState |= _NEW_ARRAY; ctx->Array.NewState |= _NEW_ARRAY_ALL; - ctx->Array.ArrayObj = newObj; - + _mesa_reference_array_object(ctx, &ctx->Array.ArrayObj, newObj); /* Pass BindVertexArray call to device driver */ if (ctx->Driver.BindArrayObject && newObj) @@ -274,7 +352,6 @@ _mesa_DeleteVertexArraysAPPLE(GLsizei n, const GLuint *ids) if ( obj != NULL ) { ASSERT( obj->Name == ids[i] ); - /* If the array object is currently bound, the spec says "the binding * for that object reverts to zero and the default vertex array * becomes current." @@ -283,28 +360,13 @@ _mesa_DeleteVertexArraysAPPLE(GLsizei n, const GLuint *ids) CALL_BindVertexArrayAPPLE( ctx->Exec, (0) ); } -#if FEATURE_ARB_vertex_buffer_object - /* Unbind any buffer objects that might be bound to arrays in - * this array object. - */ - unbind_buffer_object( ctx, obj->Vertex.BufferObj ); - unbind_buffer_object( ctx, obj->Normal.BufferObj ); - unbind_buffer_object( ctx, obj->Color.BufferObj ); - unbind_buffer_object( ctx, obj->SecondaryColor.BufferObj ); - unbind_buffer_object( ctx, obj->FogCoord.BufferObj ); - unbind_buffer_object( ctx, obj->Index.BufferObj ); - for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) { - unbind_buffer_object( ctx, obj->TexCoord[i].BufferObj ); - } - unbind_buffer_object( ctx, obj->EdgeFlag.BufferObj ); - for (i = 0; i < VERT_ATTRIB_MAX; i++) { - unbind_buffer_object( ctx, obj->VertexAttrib[i].BufferObj ); - } -#endif - /* The ID is immediately freed for re-use */ - _mesa_remove_array_object(ctx, obj); - ctx->Driver.DeleteArrayObject(ctx, obj); + remove_array_object(ctx, obj); + + /* Unreference the array object. + * If refcount hits zero, the object will be deleted. + */ + _mesa_reference_array_object(ctx, &obj, NULL); } } @@ -353,7 +415,7 @@ _mesa_GenVertexArraysAPPLE(GLsizei n, GLuint *arrays) _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenVertexArraysAPPLE"); return; } - _mesa_save_array_object(ctx, obj); + save_array_object(ctx, obj); arrays[i] = first + i; } diff --git a/src/mesa/main/arrayobj.h b/src/mesa/main/arrayobj.h index c7d66ec1669..9c2f340cfae 100644 --- a/src/mesa/main/arrayobj.h +++ b/src/mesa/main/arrayobj.h @@ -41,18 +41,20 @@ * Internal functions */ -struct gl_array_object * _mesa_new_array_object( GLcontext *ctx, - GLuint name ); +extern struct gl_array_object * +_mesa_new_array_object( GLcontext *ctx, GLuint name ); -void _mesa_delete_array_object( GLcontext *ctx, struct gl_array_object *obj ); +extern void +_mesa_delete_array_object( GLcontext *ctx, struct gl_array_object *obj ); -void _mesa_initialize_array_object( GLcontext *ctx, - struct gl_array_object *obj, GLuint name ); - -void _mesa_save_array_object( GLcontext *ctx, struct gl_array_object *obj ); - -void _mesa_remove_array_object( GLcontext *ctx, struct gl_array_object *obj ); +extern void +_mesa_reference_array_object(GLcontext *ctx, + struct gl_array_object **ptr, + struct gl_array_object *arrayObj); +extern void +_mesa_initialize_array_object( GLcontext *ctx, + struct gl_array_object *obj, GLuint name ); /* diff --git a/src/mesa/main/bufferobj.c b/src/mesa/main/bufferobj.c index c8d160baa9a..1f2070ef473 100644 --- a/src/mesa/main/bufferobj.c +++ b/src/mesa/main/bufferobj.c @@ -194,7 +194,7 @@ _mesa_reference_buffer_object(GLcontext *ctx, return; if (*ptr) { - /* Unreference the old texture */ + /* Unreference the old buffer */ GLboolean deleteFlag = GL_FALSE; struct gl_buffer_object *oldObj = *ptr; @@ -227,7 +227,7 @@ _mesa_reference_buffer_object(GLcontext *ctx, ASSERT(!*ptr); if (bufObj) { - /* reference new texture */ + /* reference new buffer */ /*_glthread_LOCK_MUTEX(tex->Mutex);*/ if (bufObj->RefCount == 0) { /* this buffer's being deleted (look just above) */ @@ -389,7 +389,6 @@ _mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access, (void) ctx; (void) target; (void) access; - ASSERT(!bufObj->OnCard); /* Just return a direct pointer to the data */ if (bufObj->Pointer) { /* already mapped! */ @@ -413,7 +412,6 @@ _mesa_buffer_unmap( GLcontext *ctx, GLenum target, { (void) ctx; (void) target; - ASSERT(!bufObj->OnCard); /* XXX we might assert here that bufObj->Pointer is non-null */ bufObj->Pointer = NULL; return GL_TRUE; @@ -426,16 +424,8 @@ _mesa_buffer_unmap( GLcontext *ctx, GLenum target, void _mesa_init_buffer_objects( GLcontext *ctx ) { - /* Allocate the default buffer object and set refcount so high that - * it never gets deleted. - * XXX with recent/improved refcounting this may not longer be needed. - */ - ctx->Array.NullBufferObj = _mesa_new_buffer_object(ctx, 0, 0); - if (ctx->Array.NullBufferObj) - ctx->Array.NullBufferObj->RefCount = 1000; - - ctx->Array.ArrayBufferObj = ctx->Array.NullBufferObj; - ctx->Array.ElementArrayBufferObj = ctx->Array.NullBufferObj; + ctx->Array.ArrayBufferObj = ctx->Shared->NullBufferObj; + ctx->Array.ElementArrayBufferObj = ctx->Shared->NullBufferObj; } @@ -479,7 +469,7 @@ bind_buffer_object(GLcontext *ctx, GLenum target, GLuint buffer) /* The spec says there's not a buffer object named 0, but we use * one internally because it simplifies things. */ - newBufObj = ctx->Array.NullBufferObj; + newBufObj = ctx->Shared->NullBufferObj; } else { /* non-default buffer object */ @@ -746,7 +736,7 @@ unbind(GLcontext *ctx, struct gl_buffer_object *obj) { if (*ptr == obj) { - _mesa_reference_buffer_object(ctx, ptr, ctx->Array.NullBufferObj); + _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj); } } @@ -958,8 +948,12 @@ _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size, bufObj->Pointer = NULL; } + FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT); + ASSERT(ctx->Driver.BufferData); + bufObj->Written = GL_TRUE; + /* Give the buffer object to the driver! <data> may be null! */ ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj ); } @@ -980,6 +974,8 @@ _mesa_BufferSubDataARB(GLenum target, GLintptrARB offset, return; } + bufObj->Written = GL_TRUE; + ASSERT(ctx->Driver.BufferSubData); ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj ); } @@ -1044,6 +1040,8 @@ _mesa_MapBufferARB(GLenum target, GLenum access) } bufObj->Access = access; + if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB) + bufObj->Written = GL_TRUE; return bufObj->Pointer; } diff --git a/src/mesa/main/buffers.c b/src/mesa/main/buffers.c index c5f13345f04..d8b5f3b1f4a 100644 --- a/src/mesa/main/buffers.c +++ b/src/mesa/main/buffers.c @@ -443,7 +443,7 @@ _mesa_readbuffer(GLcontext *ctx, GLenum buffer, GLint bufferIndex) fb->ColorReadBuffer = buffer; fb->_ColorReadBufferIndex = bufferIndex; - ctx->NewState |= _NEW_PIXEL; + ctx->NewState |= _NEW_BUFFERS; } diff --git a/src/mesa/main/config.h b/src/mesa/main/config.h index 2a9fdf9ca05..888e08ff934 100644 --- a/src/mesa/main/config.h +++ b/src/mesa/main/config.h @@ -187,7 +187,7 @@ #define MAX_PROGRAM_TEMPS 256 #define MAX_PROGRAM_ADDRESS_REGS 2 #define MAX_UNIFORMS 1024 /**< number of vec4 uniforms */ -#define MAX_VARYING 8 /**< number of float[4] vectors */ +#define MAX_VARYING 16 /**< number of float[4] vectors */ #define MAX_SAMPLERS MAX_TEXTURE_IMAGE_UNITS #define MAX_PROGRAM_INPUTS 32 #define MAX_PROGRAM_OUTPUTS 32 diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c index 5726dbd983e..5e0f2d7b1bd 100644 --- a/src/mesa/main/context.c +++ b/src/mesa/main/context.c @@ -434,7 +434,7 @@ one_time_init( GLcontext *ctx ) } #if defined(DEBUG) && defined(__DATE__) && defined(__TIME__) - _mesa_debug(ctx, "Mesa %s DEBUG build %s %s", + _mesa_debug(ctx, "Mesa %s DEBUG build %s %s\n", MESA_VERSION_STRING, __DATE__, __TIME__); #endif @@ -602,6 +602,10 @@ _mesa_init_constants(GLcontext *ctx) ASSERT(MAX_NV_VERTEX_PROGRAM_TEMPS <= MAX_PROGRAM_TEMPS); ASSERT(MAX_NV_VERTEX_PROGRAM_INPUTS <= VERT_ATTRIB_MAX); ASSERT(MAX_NV_VERTEX_PROGRAM_OUTPUTS <= VERT_RESULT_MAX); + + /* check that we don't exceed various 32-bit bitfields */ + ASSERT(VERT_RESULT_MAX <= 32); + ASSERT(FRAG_ATTRIB_MAX <= 32); } @@ -1005,9 +1009,6 @@ _mesa_free_context_data( GLcontext *ctx ) _mesa_free_query_data(ctx); #endif -#if FEATURE_ARB_vertex_buffer_object - _mesa_delete_buffer_object(ctx, ctx->Array.NullBufferObj); -#endif _mesa_delete_array_object(ctx, ctx->Array.DefaultArrayObj); /* free dispatch tables */ @@ -1397,14 +1398,21 @@ _mesa_share_state(GLcontext *ctx, GLcontext *ctxToShare) { if (ctx && ctxToShare && ctx->Shared && ctxToShare->Shared) { struct gl_shared_state *oldSharedState = ctx->Shared; + GLint RefCount; ctx->Shared = ctxToShare->Shared; + + _glthread_LOCK_MUTEX(ctx->Shared->Mutex); ctx->Shared->RefCount++; + _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); update_default_objects(ctx); - oldSharedState->RefCount--; - if (oldSharedState->RefCount == 0) { + _glthread_LOCK_MUTEX(oldSharedState->Mutex); + RefCount = --oldSharedState->RefCount; + _glthread_UNLOCK_MUTEX(oldSharedState->Mutex); + + if (RefCount == 0) { _mesa_free_shared_state(ctx, oldSharedState); } @@ -1497,6 +1505,7 @@ _mesa_Finish(void) { GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + FLUSH_CURRENT( ctx, 0 ); if (ctx->Driver.Finish) { ctx->Driver.Finish(ctx); } @@ -1521,4 +1530,17 @@ _mesa_Flush(void) } +/** + * Set mvp_with_dp4 flag. If a driver has a preference for DP4 over + * MUL/MAD, or vice versa, call this function to register that. + * Otherwise we default to MUL/MAD. + */ +void +_mesa_set_mvp_with_dp4( GLcontext *ctx, + GLboolean flag ) +{ + ctx->mvp_with_dp4 = flag; +} + + /*@}*/ diff --git a/src/mesa/main/context.h b/src/mesa/main/context.h index ecc1cec7799..5b57d88029c 100644 --- a/src/mesa/main/context.h +++ b/src/mesa/main/context.h @@ -151,6 +151,10 @@ extern struct _glapi_table * _mesa_get_dispatch(GLcontext *ctx); +void +_mesa_set_mvp_with_dp4( GLcontext *ctx, + GLboolean flag ); + /** \name Miscellaneous */ /*@{*/ diff --git a/src/mesa/main/debug.c b/src/mesa/main/debug.c index fdd10dd3074..2eabcdaf493 100644 --- a/src/mesa/main/debug.c +++ b/src/mesa/main/debug.c @@ -3,6 +3,7 @@ * Version: 6.5 * * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -262,7 +263,7 @@ static void write_texture_image(struct gl_texture_object *texObj) { const struct gl_texture_image *img = texObj->Image[0][0]; - if (img) { + if (img && img->Data) { char s[100]; /* make filename */ @@ -338,5 +339,5 @@ _mesa_dump_textures(GLboolean dumpImages) { GET_CURRENT_CONTEXT(ctx); DumpImages = dumpImages; - _mesa_HashDeleteAll(ctx->Shared->TexObjects, dump_texture_cb, ctx); + _mesa_HashWalk(ctx->Shared->TexObjects, dump_texture_cb, ctx); } diff --git a/src/mesa/main/enable.c b/src/mesa/main/enable.c index f432be183cb..2e7baa48ff5 100644 --- a/src/mesa/main/enable.c +++ b/src/mesa/main/enable.c @@ -222,14 +222,16 @@ get_texcoord_unit(GLcontext *ctx) /** * Helper function to enable or disable a texture target. + * \param bit one of the TEXTURE_x_BIT values + * \return GL_TRUE if state is changing or GL_FALSE if no change */ static GLboolean -enable_texture(GLcontext *ctx, GLboolean state, GLbitfield bit) +enable_texture(GLcontext *ctx, GLboolean state, GLbitfield texBit) { const GLuint curr = ctx->Texture.CurrentUnit; struct gl_texture_unit *texUnit = &ctx->Texture.Unit[curr]; - const GLuint newenabled = (!state) - ? (texUnit->Enabled & ~bit) : (texUnit->Enabled | bit); + const GLbitfield newenabled = state + ? (texUnit->Enabled | texBit) : (texUnit->Enabled & ~texBit); if (!ctx->DrawBuffer->Visual.rgbMode || texUnit->Enabled == newenabled) return GL_FALSE; diff --git a/src/mesa/main/ffvertex_prog.c b/src/mesa/main/ffvertex_prog.c index 1ce5685af45..43325b13529 100644 --- a/src/mesa/main/ffvertex_prog.c +++ b/src/mesa/main/ffvertex_prog.c @@ -315,12 +315,6 @@ static void make_state_key( GLcontext *ctx, struct state_key *key ) */ #define DISASSEM 0 -/* Should be tunable by the driver - do we want to do matrix - * multiplications with DP4's or with MUL/MAD's? SSE works better - * with the latter, drivers may differ. - */ -#define PREFER_DP4 0 - /* Use uregs to represent registers internally, translate to Mesa's * expected formats on emit. @@ -348,6 +342,7 @@ struct tnl_program { const struct state_key *state; struct gl_vertex_program *program; GLint max_inst; /** number of instructions allocated for program */ + GLboolean mvp_with_dp4; GLuint temp_in_use; GLuint temp_reserved; @@ -775,7 +770,7 @@ static struct ureg get_eye_position( struct tnl_program *p ) p->eye_position = reserve_temp(p); - if (PREFER_DP4) { + if (p->mvp_with_dp4) { register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3, 0, modelview ); @@ -881,7 +876,7 @@ static void build_hpos( struct tnl_program *p ) struct ureg hpos = register_output( p, VERT_RESULT_HPOS ); struct ureg mvp[4]; - if (PREFER_DP4) { + if (p->mvp_with_dp4) { register_matrix_param5( p, STATE_MVP_MATRIX, 0, 0, 3, 0, mvp ); emit_matrix_transform_vec4( p, hpos, mvp, pos ); @@ -1574,7 +1569,7 @@ static void build_texture_transform( struct tnl_program *p ) struct ureg in = (!is_undef(out_texgen) ? out_texgen : register_input(p, VERT_ATTRIB_TEX0+i)); - if (PREFER_DP4) { + if (p->mvp_with_dp4) { register_matrix_param5( p, STATE_TEXTURE_MATRIX, i, 0, 3, 0, texmat ); emit_matrix_transform_vec4( p, out, texmat, in ); @@ -1708,6 +1703,7 @@ static void build_tnl_program( struct tnl_program *p ) static void create_new_program( const struct state_key *key, struct gl_vertex_program *program, + GLboolean mvp_with_dp4, GLuint max_temps) { struct tnl_program p; @@ -1721,6 +1717,7 @@ create_new_program( const struct state_key *key, p.transformed_normal = undef; p.identity = undef; p.temp_in_use = 0; + p.mvp_with_dp4 = mvp_with_dp4; if (max_temps >= sizeof(int) * 8) p.temp_reserved = 0; @@ -1776,6 +1773,7 @@ _mesa_get_fixed_func_vertex_program(GLcontext *ctx) return NULL; create_new_program( &key, prog, + ctx->mvp_with_dp4, ctx->Const.VertexProgram.MaxTemps ); #if 0 diff --git a/src/mesa/main/histogram.c b/src/mesa/main/histogram.c index 905c1ad8301..5fee4fd0e34 100644 --- a/src/mesa/main/histogram.c +++ b/src/mesa/main/histogram.c @@ -975,6 +975,8 @@ _mesa_Histogram(GLenum target, GLsizei width, GLenum internalFormat, GLboolean s } } + FLUSH_VERTICES(ctx, _NEW_PIXEL); + /* reset histograms */ for (i = 0; i < HISTOGRAM_TABLE_SIZE; i++) { ctx->Histogram.Count[i][0] = 0; @@ -1002,8 +1004,6 @@ _mesa_Histogram(GLenum target, GLsizei width, GLenum internalFormat, GLboolean s ctx->Histogram.AlphaSize = 8 * sizeof(GLuint); ctx->Histogram.LuminanceSize = 8 * sizeof(GLuint); } - - ctx->NewState |= _NEW_PIXEL; } @@ -1058,8 +1058,6 @@ _mesa_ResetHistogram(GLenum target) ctx->Histogram.Count[i][2] = 0; ctx->Histogram.Count[i][3] = 0; } - - ctx->NewState |= _NEW_PIXEL; } @@ -1083,7 +1081,6 @@ _mesa_ResetMinmax(GLenum target) ctx->MinMax.Min[GCOMP] = 1000; ctx->MinMax.Max[GCOMP] = -1000; ctx->MinMax.Min[BCOMP] = 1000; ctx->MinMax.Max[BCOMP] = -1000; ctx->MinMax.Min[ACOMP] = 1000; ctx->MinMax.Max[ACOMP] = -1000; - ctx->NewState |= _NEW_PIXEL; } diff --git a/src/mesa/main/image.c b/src/mesa/main/image.c index ddae456fa12..ea76ed04e4f 100644 --- a/src/mesa/main/image.c +++ b/src/mesa/main/image.c @@ -181,6 +181,8 @@ _mesa_sizeof_type( GLenum type ) return sizeof(GLint); case GL_FLOAT: return sizeof(GLfloat); + case GL_DOUBLE: + return sizeof(GLdouble); case GL_HALF_FLOAT_ARB: return sizeof(GLhalfARB); default: diff --git a/src/mesa/main/imports.c b/src/mesa/main/imports.c index 2ac93a52371..615f7c9a6da 100644 --- a/src/mesa/main/imports.c +++ b/src/mesa/main/imports.c @@ -980,7 +980,8 @@ _mesa_vsprintf( char *str, const char *fmt, va_list args ) /*@{*/ static void -output_if_debug(const char *prefixString, const char *outputString) +output_if_debug(const char *prefixString, const char *outputString, + GLboolean newline) { static int debug = -1; @@ -1004,16 +1005,19 @@ output_if_debug(const char *prefixString, const char *outputString) /* Now only print the string if we're required to do so. */ if (debug) { - fprintf(stderr, "%s: %s\n", prefixString, outputString); + fprintf(stderr, "%s: %s", prefixString, outputString); + if (newline) + fprintf(stderr, "\n"); } } + /** * Report a warning (a recoverable error condition) to stderr if * either DEBUG is defined or the MESA_DEBUG env var is set. * * \param ctx GL context. - * \param fmtString printf() alike format string. + * \param fmtString printf()-like format string. */ void _mesa_warning( GLcontext *ctx, const char *fmtString, ... ) @@ -1025,11 +1029,12 @@ _mesa_warning( GLcontext *ctx, const char *fmtString, ... ) (void) vsnprintf( str, MAXSTRING, fmtString, args ); va_end( args ); - output_if_debug("Mesa warning", str); + output_if_debug("Mesa warning", str, GL_TRUE); } + /** - * Report an internla implementation problem. + * Report an internal implementation problem. * Prints the message to stderr via fprintf(). * * \param ctx GL context. @@ -1050,8 +1055,9 @@ _mesa_problem( const GLcontext *ctx, const char *fmtString, ... ) fprintf(stderr, "Please report at bugzilla.freedesktop.org\n"); } + /** - * Record an OpenGL state error. These usually occur when the users + * Record an OpenGL state error. These usually occur when the user * passes invalid parameters to a GL function. * * If debugging is enabled (either at compile-time via the DEBUG macro, or @@ -1123,11 +1129,22 @@ _mesa_error( GLcontext *ctx, GLenum error, const char *fmtString, ... ) errstr = "unknown"; break; } - _mesa_debug(ctx, "User error: %s in %s\n", errstr, where); + + { + char s[MAXSTRING], s2[MAXSTRING]; + va_list args; + va_start(args, fmtString); + vsnprintf(s, MAXSTRING, fmtString, args); + va_end(args); + + _mesa_snprintf(s2, MAXSTRING, "%s in %s", errstr, s); + output_if_debug("Mesa: User error", s2, GL_TRUE); + } } _mesa_record_error(ctx, error); -} +} + /** * Report debug information. Print error message to stderr via fprintf(). @@ -1145,7 +1162,7 @@ _mesa_debug( const GLcontext *ctx, const char *fmtString, ... ) va_start(args, fmtString); vsnprintf(s, MAXSTRING, fmtString, args); va_end(args); - output_if_debug("Mesa", s); + output_if_debug("Mesa", s, GL_FALSE); #endif /* DEBUG */ (void) ctx; (void) fmtString; diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 30c7cca3b5a..d11df535f24 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -1028,7 +1028,7 @@ struct gl_stencil_attrib /** * An index for each type of texture object. These correspond to the GL - * target target enums, such as GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP, etc. + * texture target enums, such as GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP, etc. * Note: the order is from highest priority to lowest priority. */ typedef enum @@ -1505,7 +1505,7 @@ struct gl_buffer_object GLsizeiptr Length; /**< mapped length */ GLsizeiptrARB Size; /**< Size of storage in bytes */ GLubyte *Data; /**< Location of storage either in RAM or VRAM. */ - GLboolean OnCard; /**< Is buffer in VRAM? (hardware drivers) */ + GLboolean Written; /**< Ever written to? (for debugging) */ }; @@ -1541,10 +1541,10 @@ struct gl_client_array const GLubyte *Ptr; /**< Points to array data */ GLboolean Enabled; /**< Enabled flag is a boolean */ GLboolean Normalized; /**< GL_ARB_vertex_program */ + GLuint _ElementSize; /**< size of each element in bytes */ - /**< GL_ARB_vertex_buffer_object */ - struct gl_buffer_object *BufferObj; - GLuint _MaxElement; + struct gl_buffer_object *BufferObj;/**< GL_ARB_vertex_buffer_object */ + GLuint _MaxElement; /**< max element index into array buffer */ }; @@ -1557,6 +1557,9 @@ struct gl_array_object /** Name of the array object as received from glGenVertexArrayAPPLE. */ GLuint Name; + GLint RefCount; + _glthread_Mutex Mutex; + /** Conventional vertex arrays */ /*@{*/ struct gl_client_array Vertex; @@ -1583,7 +1586,10 @@ struct gl_array_object */ struct gl_array_attrib { + /** Currently bound array object. See _mesa_BindVertexArrayAPPLE() */ struct gl_array_object *ArrayObj; + + /** The default vertex array object */ struct gl_array_object *DefaultArrayObj; GLint ActiveTexture; /**< Client Active Texture */ @@ -1593,7 +1599,6 @@ struct gl_array_attrib GLbitfield NewState; /**< mask of _NEW_ARRAY_* values */ #if FEATURE_ARB_vertex_buffer_object - struct gl_buffer_object *NullBufferObj; struct gl_buffer_object *ArrayBufferObj; struct gl_buffer_object *ElementArrayBufferObj; #endif @@ -2050,6 +2055,9 @@ struct gl_shared_state /** Default texture objects (shared by all texture units) */ struct gl_texture_object *DefaultTex[NUM_TEXTURE_TARGETS]; + /** Fallback texture used when a bound texture is incomplete */ + struct gl_texture_object *FallbackTex; + /** * \name Thread safety and statechange notification for texture * objects. @@ -2061,6 +2069,8 @@ struct gl_shared_state GLuint TextureStateStamp; /**< state notification for shared tex */ /*@}*/ + /** Default buffer object for vertex arrays that aren't in VBOs */ + struct gl_buffer_object *NullBufferObj; /** * \name Vertex/fragment programs @@ -2616,6 +2626,7 @@ struct gl_matrix_stack #define _NEW_PROGRAM 0x8000000 /**< __GLcontextRec::VertexProgram */ #define _NEW_CURRENT_ATTRIB 0x10000000 /**< __GLcontextRec::Current */ #define _NEW_PROGRAM_CONSTANTS 0x20000000 +#define _NEW_BUFFER_OBJECT 0x40000000 #define _NEW_ALL ~0 /*@}*/ @@ -2977,6 +2988,12 @@ struct __GLcontextRec /** software compression/decompression supported or not */ GLboolean Mesa_DXTn; + /** + * Use dp4 (rather than mul/mad) instructions for position + * transformation? + */ + GLboolean mvp_with_dp4; + /** Core tnl module support */ struct gl_tnl_module TnlModule; diff --git a/src/mesa/main/pixel.c b/src/mesa/main/pixel.c index 52781e048ec..d9f3e476e81 100644 --- a/src/mesa/main/pixel.c +++ b/src/mesa/main/pixel.c @@ -170,7 +170,7 @@ _mesa_PixelMapfv( GLenum map, GLsizei mapsize, const GLfloat *values ) return; } /* restore */ - ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj; + ctx->DefaultPacking.BufferObj = ctx->Shared->NullBufferObj; buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, GL_READ_ONLY_ARB, ctx->Unpack.BufferObj); @@ -229,7 +229,7 @@ _mesa_PixelMapuiv(GLenum map, GLsizei mapsize, const GLuint *values ) return; } /* restore */ - ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj; + ctx->DefaultPacking.BufferObj = ctx->Shared->NullBufferObj; buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, GL_READ_ONLY_ARB, ctx->Unpack.BufferObj); @@ -303,7 +303,7 @@ _mesa_PixelMapusv(GLenum map, GLsizei mapsize, const GLushort *values ) return; } /* restore */ - ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj; + ctx->DefaultPacking.BufferObj = ctx->Shared->NullBufferObj; buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, GL_READ_ONLY_ARB, ctx->Unpack.BufferObj); @@ -371,7 +371,7 @@ _mesa_GetPixelMapfv( GLenum map, GLfloat *values ) return; } /* restore */ - ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj; + ctx->DefaultPacking.BufferObj = ctx->Shared->NullBufferObj; buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj); @@ -432,7 +432,7 @@ _mesa_GetPixelMapuiv( GLenum map, GLuint *values ) return; } /* restore */ - ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj; + ctx->DefaultPacking.BufferObj = ctx->Shared->NullBufferObj; buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj); @@ -494,7 +494,7 @@ _mesa_GetPixelMapusv( GLenum map, GLushort *values ) return; } /* restore */ - ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj; + ctx->DefaultPacking.BufferObj = ctx->Shared->NullBufferObj; buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj); @@ -819,7 +819,7 @@ update_image_transfer_state(GLcontext *ctx) /** - * Update meas pixel transfer derived state. + * Update mesa pixel transfer derived state. */ void _mesa_update_pixel( GLcontext *ctx, GLuint new_state ) { diff --git a/src/mesa/main/pixelstore.c b/src/mesa/main/pixelstore.c index ff1a6344cc9..6a641f83f27 100644 --- a/src/mesa/main/pixelstore.c +++ b/src/mesa/main/pixelstore.c @@ -245,7 +245,8 @@ _mesa_init_pixelstore( GLcontext *ctx ) ctx->Pack.ClientStorage = GL_FALSE; ctx->Pack.Invert = GL_FALSE; #if FEATURE_EXT_pixel_buffer_object - ctx->Pack.BufferObj = ctx->Array.NullBufferObj; + _mesa_reference_buffer_object(ctx, &ctx->Pack.BufferObj, + ctx->Shared->NullBufferObj); #endif ctx->Unpack.Alignment = 4; ctx->Unpack.RowLength = 0; @@ -258,7 +259,8 @@ _mesa_init_pixelstore( GLcontext *ctx ) ctx->Unpack.ClientStorage = GL_FALSE; ctx->Unpack.Invert = GL_FALSE; #if FEATURE_EXT_pixel_buffer_object - ctx->Unpack.BufferObj = ctx->Array.NullBufferObj; + _mesa_reference_buffer_object(ctx, &ctx->Unpack.BufferObj, + ctx->Shared->NullBufferObj); #endif /* @@ -278,6 +280,7 @@ _mesa_init_pixelstore( GLcontext *ctx ) ctx->DefaultPacking.ClientStorage = GL_FALSE; ctx->DefaultPacking.Invert = GL_FALSE; #if FEATURE_EXT_pixel_buffer_object - ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj; + _mesa_reference_buffer_object(ctx, &ctx->DefaultPacking.BufferObj, + ctx->Shared->NullBufferObj); #endif } diff --git a/src/mesa/main/shared.c b/src/mesa/main/shared.c index 193ac8970cf..759883743da 100644 --- a/src/mesa/main/shared.c +++ b/src/mesa/main/shared.c @@ -33,6 +33,7 @@ #include "mtypes.h" #include "hash.h" #include "arrayobj.h" +#include "bufferobj.h" #include "shared.h" #include "shader/program.h" #include "shader/shader_api.h" @@ -92,6 +93,13 @@ _mesa_alloc_shared_state(GLcontext *ctx) shared->BufferObjects = _mesa_NewHashTable(); #endif + /* Allocate the default buffer object and set refcount so high that + * it never gets deleted. + * XXX with recent/improved refcounting this may not longer be needed. + */ + shared->NullBufferObj = _mesa_new_buffer_object(ctx, 0, 0); + shared->NullBufferObj->RefCount = 1000; + shared->ArrayObjects = _mesa_NewHashTable(); /* Create default texture objects */ @@ -190,6 +198,10 @@ delete_bufferobj_cb(GLuint id, void *data, void *userData) { struct gl_buffer_object *bufObj = (struct gl_buffer_object *) data; GLcontext *ctx = (GLcontext *) userData; + if (bufObj->Pointer) { + ctx->Driver.UnmapBuffer(ctx, 0, bufObj); + bufObj->Pointer = NULL; + } ctx->Driver.DeleteBuffer(ctx, bufObj); } @@ -337,6 +349,10 @@ _mesa_free_shared_state(GLcontext *ctx, struct gl_shared_state *shared) _mesa_DeleteHashTable(shared->RenderBuffers); #endif +#if FEATURE_ARB_vertex_buffer_object + _mesa_delete_buffer_object(ctx, shared->NullBufferObj); +#endif + /* * Free texture objects (after FBOs since some textures might have * been bound to FBOs). diff --git a/src/mesa/main/state.c b/src/mesa/main/state.c index f18fc8f6837..a6411f7b621 100644 --- a/src/mesa/main/state.c +++ b/src/mesa/main/state.c @@ -64,110 +64,145 @@ update_separate_specular(GLcontext *ctx) /** - * Update state dependent on vertex arrays. + * Compute the index of the last array element that can be safely accessed + * in a vertex array. We can really only do this when the array lives in + * a VBO. + * The array->_MaxElement field will be updated. + * Later in glDrawArrays/Elements/etc we can do some bounds checking. + */ +static void +compute_max_element(struct gl_client_array *array) +{ + assert(array->Enabled); + if (array->BufferObj->Name) { + /* Compute the max element we can access in the VBO without going + * out of bounds. + */ + array->_MaxElement = ((GLsizeiptrARB) array->BufferObj->Size + - (GLsizeiptrARB) array->Ptr + array->StrideB + - array->_ElementSize) / array->StrideB; + } + else { + /* user-space array, no idea how big it is */ + array->_MaxElement = 2 * 1000 * 1000 * 1000; /* just a big number */ + } +} + + +/** + * Helper for update_arrays(). + * \return min(current min, array->_MaxElement). + */ +static GLuint +update_min(GLuint min, struct gl_client_array *array) +{ + compute_max_element(array); + return MIN2(min, array->_MaxElement); +} + + +/** + * Update ctx->Array._MaxElement (the max legal index into all enabled arrays). + * Need to do this upon new array state or new buffer object state. */ static void update_arrays( GLcontext *ctx ) { - GLuint i, min; + struct gl_array_object *arrayObj = ctx->Array.ArrayObj; + GLuint i, min = ~0; /* find min of _MaxElement values for all enabled arrays */ /* 0 */ if (ctx->VertexProgram._Current - && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled) { - min = ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS]._MaxElement; + && arrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled) { + min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_POS]); } - else if (ctx->Array.ArrayObj->Vertex.Enabled) { - min = ctx->Array.ArrayObj->Vertex._MaxElement; - } - else { - /* can't draw anything without vertex positions! */ - min = 0; + else if (arrayObj->Vertex.Enabled) { + min = update_min(min, &arrayObj->Vertex); } /* 1 */ if (ctx->VertexProgram._Enabled - && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT].Enabled) { - min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT]._MaxElement); + && arrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT].Enabled) { + min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT]); } /* no conventional vertex weight array */ /* 2 */ if (ctx->VertexProgram._Enabled - && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_NORMAL].Enabled) { - min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_NORMAL]._MaxElement); + && arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL].Enabled) { + min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL]); } - else if (ctx->Array.ArrayObj->Normal.Enabled) { - min = MIN2(min, ctx->Array.ArrayObj->Normal._MaxElement); + else if (arrayObj->Normal.Enabled) { + min = update_min(min, &arrayObj->Normal); } /* 3 */ if (ctx->VertexProgram._Enabled - && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR0].Enabled) { - min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR0]._MaxElement); + && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0].Enabled) { + min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0]); } - else if (ctx->Array.ArrayObj->Color.Enabled) { - min = MIN2(min, ctx->Array.ArrayObj->Color._MaxElement); + else if (arrayObj->Color.Enabled) { + min = update_min(min, &arrayObj->Color); } /* 4 */ if (ctx->VertexProgram._Enabled - && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR1].Enabled) { - min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR1]._MaxElement); + && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1].Enabled) { + min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1]); } - else if (ctx->Array.ArrayObj->SecondaryColor.Enabled) { - min = MIN2(min, ctx->Array.ArrayObj->SecondaryColor._MaxElement); + else if (arrayObj->SecondaryColor.Enabled) { + min = update_min(min, &arrayObj->SecondaryColor); } /* 5 */ if (ctx->VertexProgram._Enabled - && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_FOG].Enabled) { - min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_FOG]._MaxElement); + && arrayObj->VertexAttrib[VERT_ATTRIB_FOG].Enabled) { + min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_FOG]); } - else if (ctx->Array.ArrayObj->FogCoord.Enabled) { - min = MIN2(min, ctx->Array.ArrayObj->FogCoord._MaxElement); + else if (arrayObj->FogCoord.Enabled) { + min = update_min(min, &arrayObj->FogCoord); } /* 6 */ if (ctx->VertexProgram._Enabled - && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled) { - min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX]._MaxElement); + && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled) { + min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX]); } - else if (ctx->Array.ArrayObj->Index.Enabled) { - min = MIN2(min, ctx->Array.ArrayObj->Index._MaxElement); + else if (arrayObj->Index.Enabled) { + min = update_min(min, &arrayObj->Index); } - /* 7 */ if (ctx->VertexProgram._Enabled - && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled) { - min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG]._MaxElement); + && arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled) { + min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG]); } /* 8..15 */ for (i = VERT_ATTRIB_TEX0; i <= VERT_ATTRIB_TEX7; i++) { if (ctx->VertexProgram._Enabled - && ctx->Array.ArrayObj->VertexAttrib[i].Enabled) { - min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[i]._MaxElement); + && arrayObj->VertexAttrib[i].Enabled) { + min = update_min(min, &arrayObj->VertexAttrib[i]); } else if (i - VERT_ATTRIB_TEX0 < ctx->Const.MaxTextureCoordUnits - && ctx->Array.ArrayObj->TexCoord[i - VERT_ATTRIB_TEX0].Enabled) { - min = MIN2(min, ctx->Array.ArrayObj->TexCoord[i - VERT_ATTRIB_TEX0]._MaxElement); + && arrayObj->TexCoord[i - VERT_ATTRIB_TEX0].Enabled) { + min = update_min(min, &arrayObj->TexCoord[i - VERT_ATTRIB_TEX0]); } } /* 16..31 */ if (ctx->VertexProgram._Current) { for (i = VERT_ATTRIB_GENERIC0; i < VERT_ATTRIB_MAX; i++) { - if (ctx->Array.ArrayObj->VertexAttrib[i].Enabled) { - min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[i]._MaxElement); + if (arrayObj->VertexAttrib[i].Enabled) { + min = update_min(min, &arrayObj->VertexAttrib[i]); } } } - if (ctx->Array.ArrayObj->EdgeFlag.Enabled) { - min = MIN2(min, ctx->Array.ArrayObj->EdgeFlag._MaxElement); + if (arrayObj->EdgeFlag.Enabled) { + min = update_min(min, &arrayObj->EdgeFlag); } /* _MaxElement is one past the last legal array element */ @@ -547,7 +582,7 @@ _mesa_update_state_locked( GLcontext *ctx ) if (new_state & _DD_NEW_SEPARATE_SPECULAR) update_separate_specular( ctx ); - if (new_state & (_NEW_ARRAY | _NEW_PROGRAM)) + if (new_state & (_NEW_ARRAY | _NEW_PROGRAM | _NEW_BUFFER_OBJECT)) update_arrays( ctx ); if (new_state & (_NEW_BUFFERS | _NEW_VIEWPORT)) diff --git a/src/mesa/main/teximage.c b/src/mesa/main/teximage.c index 8c03c36c753..76b46d700b5 100644 --- a/src/mesa/main/teximage.c +++ b/src/mesa/main/teximage.c @@ -52,6 +52,17 @@ /** + * State changes which we care about for glCopyTex[Sub]Image() calls. + * In particular, we care about pixel transfer state and buffer state + * (such as glReadBuffer to make sure we read from the right renderbuffer). + */ +#define NEW_COPY_TEX_STATE (_MESA_NEW_TRANSFER_STATE | \ + _NEW_BUFFERS | \ + _NEW_PIXEL) + + + +/** * We allocate texture memory on 512-byte boundaries so we can use MMX/SSE * elsewhere. */ @@ -3008,7 +3019,7 @@ _mesa_CopyTexImage1D( GLenum target, GLint level, GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - if (ctx->NewState & _MESA_NEW_TRANSFER_STATE) + if (ctx->NewState & NEW_COPY_TEX_STATE) _mesa_update_state(ctx); #if FEATURE_convolve @@ -3073,7 +3084,7 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat, GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - if (ctx->NewState & _MESA_NEW_TRANSFER_STATE) + if (ctx->NewState & NEW_COPY_TEX_STATE) _mesa_update_state(ctx); #if FEATURE_convolve @@ -3141,7 +3152,7 @@ _mesa_CopyTexSubImage1D( GLenum target, GLint level, GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - if (ctx->NewState & _MESA_NEW_TRANSFER_STATE) + if (ctx->NewState & NEW_COPY_TEX_STATE) _mesa_update_state(ctx); if (copytexsubimage_error_check1(ctx, 1, target, level)) @@ -3196,7 +3207,7 @@ _mesa_CopyTexSubImage2D( GLenum target, GLint level, GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - if (ctx->NewState & _MESA_NEW_TRANSFER_STATE) + if (ctx->NewState & NEW_COPY_TEX_STATE) _mesa_update_state(ctx); if (copytexsubimage_error_check1(ctx, 2, target, level)) @@ -3251,7 +3262,7 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level, GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - if (ctx->NewState & _MESA_NEW_TRANSFER_STATE) + if (ctx->NewState & NEW_COPY_TEX_STATE) _mesa_update_state(ctx); if (copytexsubimage_error_check1(ctx, 3, target, level)) diff --git a/src/mesa/main/texobj.c b/src/mesa/main/texobj.c index b63f747fe8d..0024efc0e64 100644 --- a/src/mesa/main/texobj.c +++ b/src/mesa/main/texobj.c @@ -662,6 +662,59 @@ _mesa_test_texobj_completeness( const GLcontext *ctx, } } + +/** + * Return pointer to a default/fallback texture. + * The texture is a 2D 8x8 RGBA texture with all texels = (0,0,0,1). + * That's the value a sampler should get when sampling from an + * incomplete texture. + */ +struct gl_texture_object * +_mesa_get_fallback_texture(GLcontext *ctx) +{ + if (!ctx->Shared->FallbackTex) { + /* create fallback texture now */ + static GLubyte texels[8 * 8][4]; + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GLuint i; + + for (i = 0; i < 8 * 8; i++) { + texels[i][0] = + texels[i][1] = + texels[i][2] = 0x0; + texels[i][3] = 0xff; + } + + /* create texture object */ + texObj = ctx->Driver.NewTextureObject(ctx, 0, GL_TEXTURE_2D); + assert(texObj->RefCount == 1); + texObj->MinFilter = GL_NEAREST; + texObj->MagFilter = GL_NEAREST; + + /* create level[0] texture image */ + texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, 0); + + /* init the image fields */ + _mesa_init_teximage_fields(ctx, GL_TEXTURE_2D, texImage, + 8, 8, 1, 0, GL_RGBA); + + /* set image data */ + ctx->Driver.TexImage2D(ctx, GL_TEXTURE_2D, 0, GL_RGBA, + 8, 8, 0, + GL_RGBA, GL_UNSIGNED_BYTE, texels, + &ctx->DefaultPacking, texObj, texImage); + + _mesa_test_texobj_completeness(ctx, texObj); + assert(texObj->_Complete); + + ctx->Shared->FallbackTex = texObj; + } + return ctx->Shared->FallbackTex; +} + + + /*@}*/ diff --git a/src/mesa/main/texobj.h b/src/mesa/main/texobj.h index d5374c5d6c4..2599c0816a9 100644 --- a/src/mesa/main/texobj.h +++ b/src/mesa/main/texobj.h @@ -65,6 +65,9 @@ extern void _mesa_test_texobj_completeness( const GLcontext *ctx, struct gl_texture_object *obj ); +extern struct gl_texture_object * +_mesa_get_fallback_texture(GLcontext *ctx); + extern void _mesa_unlock_context_textures( GLcontext *ctx ); diff --git a/src/mesa/main/texparam.c b/src/mesa/main/texparam.c index 515a35cdfcf..2195a334d3e 100644 --- a/src/mesa/main/texparam.c +++ b/src/mesa/main/texparam.c @@ -69,7 +69,7 @@ validate_texture_wrap_mode(GLcontext * ctx, GLenum target, GLenum wrap) return GL_TRUE; } - _mesa_error( ctx, GL_INVALID_VALUE, "glTexParameter(param)" ); + _mesa_error( ctx, GL_INVALID_VALUE, "glTexParameter(param=0x%x)", wrap ); return GL_FALSE; } @@ -209,7 +209,8 @@ set_tex_parameteri(GLcontext *ctx, } /* fall-through */ default: - _mesa_error( ctx, GL_INVALID_VALUE, "glTexParameter(param)" ); + _mesa_error( ctx, GL_INVALID_VALUE, "glTexParameter(param=0x%x)", + params[0] ); } return GL_FALSE; @@ -223,7 +224,8 @@ set_tex_parameteri(GLcontext *ctx, texObj->MagFilter = params[0]; return GL_TRUE; default: - _mesa_error( ctx, GL_INVALID_VALUE, "glTexParameter(param)" ); + _mesa_error( ctx, GL_INVALID_VALUE, "glTexParameter(param=0x%x)", + params[0]); } return GL_FALSE; @@ -262,7 +264,8 @@ set_tex_parameteri(GLcontext *ctx, return GL_FALSE; if (params[0] < 0 || (texObj->Target == GL_TEXTURE_RECTANGLE_ARB && params[0] != 0)) { - _mesa_error(ctx, GL_INVALID_VALUE, "glTexParameter(param)"); + _mesa_error(ctx, GL_INVALID_VALUE, + "glTexParameter(param=%d)", params[0]); return GL_FALSE; } flush(ctx, texObj); @@ -273,7 +276,8 @@ set_tex_parameteri(GLcontext *ctx, if (texObj->MaxLevel == params[0]) return GL_FALSE; if (params[0] < 0 || texObj->Target == GL_TEXTURE_RECTANGLE_ARB) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glTexParameter(param)"); + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTexParameter(param=%d)", params[0]); return GL_FALSE; } flush(ctx, texObj); @@ -340,7 +344,7 @@ set_tex_parameteri(GLcontext *ctx, } } else { - _mesa_error(ctx, GL_INVALID_ENUM, "glTexParameter(param)"); + _mesa_error(ctx, GL_INVALID_ENUM, "glTexParameter(pname=0x%x)", pname); } return GL_FALSE; @@ -465,8 +469,10 @@ set_tex_parameterf(GLcontext *ctx, return GL_TRUE; } else { - _mesa_error(ctx, GL_INVALID_ENUM, - "glTexParameter(pname=GL_TEXTURE_MAX_ANISOTROPY_EXT)"); + static GLuint count = 0; + if (count++ < 10) + _mesa_error(ctx, GL_INVALID_ENUM, + "glTexParameter(pname=GL_TEXTURE_MAX_ANISOTROPY_EXT)"); } return GL_FALSE; diff --git a/src/mesa/main/texstate.c b/src/mesa/main/texstate.c index 73f8a5339ec..6e0c0c688a1 100644 --- a/src/mesa/main/texstate.c +++ b/src/mesa/main/texstate.c @@ -561,8 +561,19 @@ update_texture_state( GLcontext *ctx ) } if (!texUnit->_ReallyEnabled) { - _mesa_reference_texobj(&texUnit->_Current, NULL); - continue; + if (fprog) { + /* If we get here it means the shader is expecting a texture + * object, but there isn't one (or it's incomplete). Use the + * fallback texture. + */ + struct gl_texture_object *texObj = _mesa_get_fallback_texture(ctx); + texUnit->_ReallyEnabled = 1 << TEXTURE_2D_INDEX; + _mesa_reference_texobj(&texUnit->_Current, texObj); + } + else { + /* fixed-function: texture unit is really disabled */ + continue; + } } /* if we get here, we know this texture unit is enabled */ @@ -780,6 +791,9 @@ _mesa_free_texture_data(GLcontext *ctx) /* unreference current textures */ for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) { + /* The _Current texture could account for another reference */ + _mesa_reference_texobj(&ctx->Texture.Unit[u]._Current, NULL); + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { _mesa_reference_texobj(&ctx->Texture.Unit[u].CurrentTex[tgt], NULL); } diff --git a/src/mesa/main/varray.c b/src/mesa/main/varray.c index 106252e4609..a9c9162be1b 100644 --- a/src/mesa/main/varray.c +++ b/src/mesa/main/varray.c @@ -63,22 +63,11 @@ update_array(GLcontext *ctx, struct gl_client_array *array, array->StrideB = stride ? stride : elementSize; array->Normalized = normalized; array->Ptr = (const GLubyte *) ptr; -#if FEATURE_ARB_vertex_buffer_object + array->_ElementSize = elementSize; + _mesa_reference_buffer_object(ctx, &array->BufferObj, ctx->Array.ArrayBufferObj); - /* Compute the index of the last array element that's inside the buffer. - * Later in glDrawArrays we'll check if start + count > _MaxElement to - * be sure we won't go out of bounds. - */ - if (ctx->Array.ArrayBufferObj->Name) - array->_MaxElement = ((GLsizeiptrARB) ctx->Array.ArrayBufferObj->Size - - (GLsizeiptrARB) array->Ptr + array->StrideB - - elementSize) / array->StrideB; - else -#endif - array->_MaxElement = 2 * 1000 * 1000 * 1000; /* just a big number */ - ctx->NewState |= _NEW_ARRAY; ctx->Array.NewState |= dirtyBit; } @@ -1050,7 +1039,7 @@ void _mesa_init_varray(GLcontext *ctx) { ctx->Array.DefaultArrayObj = _mesa_new_array_object(ctx, 0); - ctx->Array.ArrayObj = ctx->Array.DefaultArrayObj; - + _mesa_reference_array_object(ctx, &ctx->Array.ArrayObj, + ctx->Array.DefaultArrayObj); ctx->Array.ActiveTexture = 0; /* GL_ARB_multitexture */ } diff --git a/src/mesa/main/version.h b/src/mesa/main/version.h index f5bf6e2c855..d4d3dd1a94e 100644 --- a/src/mesa/main/version.h +++ b/src/mesa/main/version.h @@ -1,8 +1,9 @@ /* * Mesa 3-D graphics library - * Version: 7.5 + * Version: 7.6 * * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -29,9 +30,9 @@ /* Mesa version */ #define MESA_MAJOR 7 -#define MESA_MINOR 5 +#define MESA_MINOR 6 #define MESA_PATCH 0 -#define MESA_VERSION_STRING "7.5-devel" +#define MESA_VERSION_STRING "7.6-devel" /* To make version comparison easy */ #define MESA_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) diff --git a/src/mesa/math/m_vector.c b/src/mesa/math/m_vector.c index c5e2fd1de12..4cbab11a358 100644 --- a/src/mesa/math/m_vector.c +++ b/src/mesa/math/m_vector.c @@ -1,4 +1,3 @@ - /* * Mesa 3-D graphics library * Version: 3.5 @@ -37,11 +36,12 @@ -/* +/** * Given a vector [count][4] of floats, set all the [][elt] values * to 0 (if elt = 0, 1, 2) or 1.0 (if elt = 3). */ -void _mesa_vector4f_clean_elem( GLvector4f *vec, GLuint count, GLuint elt ) +void +_mesa_vector4f_clean_elem( GLvector4f *vec, GLuint count, GLuint elt ) { static const GLubyte elem_bits[4] = { VEC_DIRTY_0, @@ -54,12 +54,13 @@ void _mesa_vector4f_clean_elem( GLvector4f *vec, GLuint count, GLuint elt ) GLfloat (*data)[4] = (GLfloat (*)[4])vec->start; GLuint i; - for (i = 0 ; i < count ; i++) + for (i = 0; i < count; i++) data[i][elt] = v; vec->flags &= ~elem_bits[elt]; } + static const GLubyte size_bits[5] = { 0, VEC_SIZE_1, @@ -69,61 +70,53 @@ static const GLubyte size_bits[5] = { }; - -/* +/** * Initialize GLvector objects. - * Input: v - the vector object to initialize. - * flags - bitwise-OR of VEC_* flags - * storage - pointer to storage for the vector's data + * \param v the vector object to initialize. + * \param flags bitwise-OR of VEC_* flags + * \param storage pointer to storage for the vector's data */ - - -void _mesa_vector4f_init( GLvector4f *v, GLuint flags, GLfloat (*storage)[4] ) +void +_mesa_vector4f_init( GLvector4f *v, GLbitfield flags, GLfloat (*storage)[4] ) { v->stride = 4 * sizeof(GLfloat); v->size = 2; /* may change: 2-4 for vertices and 1-4 for texcoords */ v->data = storage; v->start = (GLfloat *) storage; v->count = 0; - v->flags = size_bits[4] | flags ; + v->flags = size_bits[4] | flags; } - - -/* +/** * Initialize GLvector objects and allocate storage. - * Input: v - the vector object - * sz - unused???? - * flags - bitwise-OR of VEC_* flags - * count - number of elements to allocate in vector - * alignment - desired memory alignment for the data (in bytes) + * \param v the vector object + * \param flags bitwise-OR of VEC_* flags + * \param count number of elements to allocate in vector + * \param alignment desired memory alignment for the data (in bytes) */ - - -void _mesa_vector4f_alloc( GLvector4f *v, GLuint flags, GLuint count, - GLuint alignment ) +void +_mesa_vector4f_alloc( GLvector4f *v, GLbitfield flags, GLuint count, + GLuint alignment ) { v->stride = 4 * sizeof(GLfloat); v->size = 2; v->storage = ALIGN_MALLOC( count * 4 * sizeof(GLfloat), alignment ); + v->storage_count = count; v->start = (GLfloat *) v->storage; v->data = (GLfloat (*)[4]) v->storage; v->count = 0; - v->flags = size_bits[4] | flags | VEC_MALLOC ; + v->flags = size_bits[4] | flags | VEC_MALLOC; } - - -/* +/** * Vector deallocation. Free whatever memory is pointed to by the * vector's storage field if the VEC_MALLOC flag is set. * DO NOT free the GLvector object itself, though. */ - - -void _mesa_vector4f_free( GLvector4f *v ) +void +_mesa_vector4f_free( GLvector4f *v ) { if (v->flags & VEC_MALLOC) { ALIGN_FREE( v->storage ); @@ -135,13 +128,15 @@ void _mesa_vector4f_free( GLvector4f *v ) } -/* +/** * For debugging */ -void _mesa_vector4f_print( GLvector4f *v, GLubyte *cullmask, GLboolean culling ) +void +_mesa_vector4f_print( const GLvector4f *v, const GLubyte *cullmask, + GLboolean culling ) { - GLfloat c[4] = { 0, 0, 0, 1 }; - const char *templates[5] = { + static const GLfloat c[4] = { 0, 0, 0, 1 }; + static const char *templates[5] = { "%d:\t0, 0, 0, 1\n", "%d:\t%f, 0, 0, 1\n", "%d:\t%f, %f, 0, 1\n", @@ -154,30 +149,32 @@ void _mesa_vector4f_print( GLvector4f *v, GLubyte *cullmask, GLboolean culling ) GLuint j, i = 0, count; _mesa_printf("data-start\n"); - for ( ; d != v->start ; STRIDE_F(d, v->stride), i++) + for (; d != v->start; STRIDE_F(d, v->stride), i++) _mesa_printf(t, i, d[0], d[1], d[2], d[3]); _mesa_printf("start-count(%u)\n", v->count); count = i + v->count; if (culling) { - for ( ; i < count ; STRIDE_F(d, v->stride), i++) + for (; i < count; STRIDE_F(d, v->stride), i++) if (cullmask[i]) _mesa_printf(t, i, d[0], d[1], d[2], d[3]); } else { - for ( ; i < count ; STRIDE_F(d, v->stride), i++) + for (; i < count; STRIDE_F(d, v->stride), i++) _mesa_printf(t, i, d[0], d[1], d[2], d[3]); } - for (j = v->size ; j < 4; j++) { + for (j = v->size; j < 4; j++) { if ((v->flags & (1<<j)) == 0) { _mesa_printf("checking col %u is clean as advertised ", j); - for (i = 0, d = (GLfloat *) v->data ; - i < count && d[j] == c[j] ; - i++, STRIDE_F(d, v->stride)) {}; + for (i = 0, d = (GLfloat *) v->data; + i < count && d[j] == c[j]; + i++, STRIDE_F(d, v->stride)) { + /* no-op */ + } if (i == count) _mesa_printf(" --> ok\n"); @@ -186,5 +183,3 @@ void _mesa_vector4f_print( GLvector4f *v, GLubyte *cullmask, GLboolean culling ) } } } - - diff --git a/src/mesa/math/m_vector.h b/src/mesa/math/m_vector.h index 647388ac7d0..71281d57589 100644 --- a/src/mesa/math/m_vector.h +++ b/src/mesa/math/m_vector.h @@ -31,7 +31,6 @@ #define _M_VECTOR_H_ #include "main/glheader.h" -#include "main/mtypes.h" /* hack for GLchan */ #define VEC_DIRTY_0 0x1 @@ -50,7 +49,8 @@ -/* Wrap all the information about vectors up in a struct. Has +/** + * Wrap all the information about vectors up in a struct. Has * additional fields compared to the other vectors to help us track of * different vertex sizes, and whether we need to clean columns out * because they contain non-(0,0,0,1) values. @@ -60,29 +60,27 @@ * the transformation routines. */ typedef struct { - GLfloat (*data)[4]; /* may be malloc'd or point to client data */ - GLfloat *start; /* points somewhere inside of <data> */ - GLuint count; /* size of the vector (in elements) */ - GLuint stride; /* stride from one element to the next (in bytes) */ - GLuint size; /* 2-4 for vertices and 1-4 for texcoords */ - GLuint flags; /* which columns are dirty */ - void *storage; /* self-allocated storage */ + GLfloat (*data)[4]; /**< may be malloc'd or point to client data */ + GLfloat *start; /**< points somewhere inside of <data> */ + GLuint count; /**< size of the vector (in elements) */ + GLuint stride; /**< stride from one element to the next (in bytes) */ + GLuint size; /**< 2-4 for vertices and 1-4 for texcoords */ + GLbitfield flags; /**< bitmask of VEC_x flags */ + void *storage; /**< self-allocated storage */ + GLuint storage_count; /**< storage size in elements */ } GLvector4f; -extern void _mesa_vector4f_init( GLvector4f *v, GLuint flags, +extern void _mesa_vector4f_init( GLvector4f *v, GLbitfield flags, GLfloat (*storage)[4] ); -extern void _mesa_vector4f_alloc( GLvector4f *v, GLuint flags, +extern void _mesa_vector4f_alloc( GLvector4f *v, GLbitfield flags, GLuint count, GLuint alignment ); extern void _mesa_vector4f_free( GLvector4f *v ); -extern void _mesa_vector4f_print( GLvector4f *v, GLubyte *, GLboolean ); +extern void _mesa_vector4f_print( const GLvector4f *v, const GLubyte *, GLboolean ); extern void _mesa_vector4f_clean_elem( GLvector4f *vec, GLuint nr, GLuint elt ); - - - -/* +/** * Given vector <v>, return a pointer (cast to <type *> to the <i>-th element. * * End up doing a lot of slow imuls if not careful. diff --git a/src/mesa/shader/arbprogparse.c b/src/mesa/shader/arbprogparse.c index b47bf360cf5..36267c336f6 100644 --- a/src/mesa/shader/arbprogparse.c +++ b/src/mesa/shader/arbprogparse.c @@ -563,6 +563,7 @@ struct var_cache * we take up with our state tokens or constants. Note that * this is _not_ the same as the number of param registers * we eventually use */ + GLuint swizzle; /**< swizzle to access this variable */ struct var_cache *next; }; @@ -581,6 +582,7 @@ var_cache_create (struct var_cache **va) (**va).param_binding_begin = ~0; (**va).param_binding_length = ~0; (**va).alias_binding = NULL; + (**va).swizzle = SWIZZLE_XYZW; (**va).next = NULL; } } @@ -872,15 +874,16 @@ parse_signed_float (const GLubyte ** inst, struct arb_program *Program) * This picks out a constant value from the parsed array. The constant vector is r * returned in the *values array, which should be of length 4. * - * \param values - The 4 component vector with the constant value in it + * \param values - return the vector constant values. + * \param size - returns the number elements in valuesOut [1..4] */ static GLvoid -parse_constant (const GLubyte ** inst, GLfloat *values, struct arb_program *Program, - GLboolean use) +parse_constant(const GLubyte ** inst, GLfloat *values, GLint *size, + struct arb_program *Program, + GLboolean use) { GLuint components, i; - switch (*(*inst)++) { case CONSTANT_SCALAR: if (use == GL_TRUE) { @@ -893,7 +896,7 @@ parse_constant (const GLubyte ** inst, GLfloat *values, struct arb_program *Prog values[1] = values[2] = values[3] = parse_signed_float (inst, Program); } - + *size = 1; break; case CONSTANT_VECTOR: values[0] = values[1] = values[2] = 0; @@ -902,7 +905,12 @@ parse_constant (const GLubyte ** inst, GLfloat *values, struct arb_program *Prog for (i = 0; i < components; i++) { values[i] = parse_signed_float (inst, Program); } + *size = 4; break; + default: + _mesa_problem(NULL, "unexpected case in parse_constant()"); + values[0] = 0.0F; + *size = 0; } } @@ -1513,10 +1521,16 @@ generic_attrib_check(struct var_cache *vc_head) curr = vc_head; while (curr) { if (curr->type == vt_attrib) { - if (curr->attrib_is_generic) - genericAttrib[ curr->attrib_binding ] = GL_TRUE; - else + if (curr->attrib_is_generic) { + GLuint attr = (curr->attrib_binding == 0) + ? 0 : (curr->attrib_binding - VERT_ATTRIB_GENERIC0); + assert(attr < MAX_VERTEX_PROGRAM_ATTRIBS); + genericAttrib[attr] = GL_TRUE; + } + else { + assert(curr->attrib_binding < MAX_VERTEX_PROGRAM_ATTRIBS); explicitAttrib[ curr->attrib_binding ] = GL_TRUE; + } } curr = curr->next; @@ -1810,7 +1824,6 @@ parse_param_elements (GLcontext * ctx, const GLubyte ** inst, GLint idx; GLuint err = 0; gl_state_index state_tokens[STATE_LENGTH] = {0, 0, 0, 0, 0}; - GLfloat const_values[4]; GLubyte token = *(*inst)++; @@ -1902,18 +1915,31 @@ parse_param_elements (GLcontext * ctx, const GLubyte ** inst, case PARAM_CONSTANT: /* parsing something like {1.0, 2.0, 3.0, 4.0} */ - parse_constant (inst, const_values, Program, use); - idx = _mesa_add_named_constant(Program->Base.Parameters, - (char *) param_var->name, - const_values, 4); - if (param_var->param_binding_begin == ~0U) - param_var->param_binding_begin = idx; - param_var->param_binding_type = PROGRAM_STATE_VAR; - /* Note: when we reference this parameter in an instruction later, - * we'll check if it's really a constant/immediate and set the - * instruction register type appropriately. - */ - param_var->param_binding_length++; + { + GLfloat const_values[4]; + GLint size; + parse_constant(inst, const_values, &size, Program, use); + if (param_var->name[0] == ' ') { + /* this is an unnamed constant */ + idx = _mesa_add_unnamed_constant(Program->Base.Parameters, + const_values, size, + ¶m_var->swizzle); + } + else { + /* named parameter/constant */ + idx = _mesa_add_named_constant(Program->Base.Parameters, + (char *) param_var->name, + const_values, size); + } + if (param_var->param_binding_begin == ~0U) + param_var->param_binding_begin = idx; + param_var->param_binding_type = PROGRAM_STATE_VAR; + /* Note: when we reference this parameter in an instruction later, + * we'll check if it's really a constant/immediate and set the + * instruction register type appropriately. + */ + param_var->param_binding_length++; + } break; default: @@ -2422,6 +2448,9 @@ parse_swizzle_mask(const GLubyte ** inst, GLubyte *swizzle, GLint len) return; } } + + if (len == 1) + swizzle[1] = swizzle[2] = swizzle[3] = swizzle[0]; } @@ -2476,7 +2505,7 @@ static GLuint parse_src_reg (GLcontext * ctx, const GLubyte ** inst, struct var_cache **vc_head, struct arb_program *Program, - gl_register_file * File, GLint * Index, + gl_register_file * File, GLint * Index, GLuint *swizzle, GLboolean *IsRelOffset ) { struct var_cache *src; @@ -2485,6 +2514,8 @@ parse_src_reg (GLcontext * ctx, const GLubyte ** inst, *IsRelOffset = 0; + *swizzle = SWIZZLE_XYZW; /* default */ + /* And the binding for the src */ switch (*(*inst)++) { case REGISTER_ATTRIB: @@ -2540,6 +2571,7 @@ parse_src_reg (GLcontext * ctx, const GLubyte ** inst, } *Index = src->param_binding_begin + offset; + *swizzle = src->swizzle; break; case ARRAY_INDEX_RELATIVE: @@ -2562,6 +2594,7 @@ parse_src_reg (GLcontext * ctx, const GLubyte ** inst, /* And store it properly */ *Index = src->param_binding_begin + rel_off; *IsRelOffset = 1; + *swizzle = src->swizzle; } break; } @@ -2573,6 +2606,7 @@ parse_src_reg (GLcontext * ctx, const GLubyte ** inst, *File = (gl_register_file) src->param_binding_type; *Index = src->param_binding_begin; + *swizzle = src->swizzle; break; } break; @@ -2641,6 +2675,21 @@ parse_src_reg (GLcontext * ctx, const GLubyte ** inst, } +static GLuint +swizzle_swizzle(GLuint baseSwizzle, const GLubyte swizzle[4]) +{ + GLuint i, swz, s[4]; + for (i = 0; i < 4; i++) { + GLuint c = swizzle[i]; + if (c <= SWIZZLE_W) + s[i] = GET_SWZ(baseSwizzle, c); + else + s[i] = c; + } + swz = MAKE_SWIZZLE4(s[0], s[1], s[2], s[3]); + return swz; +} + /** * Parse vertex/fragment program vector source register. */ @@ -2655,12 +2704,14 @@ parse_vector_src_reg(GLcontext *ctx, const GLubyte **inst, GLubyte negateMask; GLubyte swizzle[4]; GLboolean isRelOffset; + GLuint baseSwizzle; /* Grab the sign */ negateMask = (parse_sign (inst) == -1) ? NEGATE_XYZW : NEGATE_NONE; /* And the src reg */ - if (parse_src_reg(ctx, inst, vc_head, program, &file, &index, &isRelOffset)) + if (parse_src_reg(ctx, inst, vc_head, program, &file, &index, &baseSwizzle, + &isRelOffset)) return 1; /* finally, the swizzle */ @@ -2668,7 +2719,7 @@ parse_vector_src_reg(GLcontext *ctx, const GLubyte **inst, reg->File = file; reg->Index = index; - reg->Swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1], swizzle[2], swizzle[3]); + reg->Swizzle = swizzle_swizzle(baseSwizzle, swizzle); reg->Negate = negateMask; reg->RelAddr = isRelOffset; return 0; @@ -2689,12 +2740,14 @@ parse_scalar_src_reg(GLcontext *ctx, const GLubyte **inst, GLubyte negateMask; GLubyte swizzle[4]; GLboolean isRelOffset; + GLuint baseSwizzle; /* Grab the sign */ negateMask = (parse_sign (inst) == -1) ? NEGATE_XYZW : NEGATE_NONE; /* And the src reg */ - if (parse_src_reg(ctx, inst, vc_head, program, &file, &index, &isRelOffset)) + if (parse_src_reg(ctx, inst, vc_head, program, &file, &index, &baseSwizzle, + &isRelOffset)) return 1; /* finally, the swizzle */ @@ -2702,7 +2755,7 @@ parse_scalar_src_reg(GLcontext *ctx, const GLubyte **inst, reg->File = file; reg->Index = index; - reg->Swizzle = (swizzle[0] << 0); + reg->Swizzle = swizzle_swizzle(baseSwizzle, swizzle); reg->Negate = negateMask; reg->RelAddr = isRelOffset; return 0; @@ -3013,8 +3066,10 @@ parse_fp_instruction (GLcontext * ctx, const GLubyte ** inst, GLubyte negateMask; gl_register_file file; GLint index; + GLuint baseSwizzle; - if (parse_src_reg(ctx, inst, vc_head, Program, &file, &index, &rel)) + if (parse_src_reg(ctx, inst, vc_head, Program, &file, &index, + &baseSwizzle, &rel)) return 1; parse_extended_swizzle_mask(inst, swizzle, &negateMask); fp->SrcReg[0].File = file; @@ -3354,11 +3409,13 @@ parse_vp_instruction (GLcontext * ctx, const GLubyte ** inst, GLboolean relAddr; gl_register_file file; GLint index; + GLuint baseSwizzle; if (parse_dst_reg(ctx, inst, vc_head, Program, &vp->DstReg)) return 1; - if (parse_src_reg(ctx, inst, vc_head, Program, &file, &index, &relAddr)) + if (parse_src_reg(ctx, inst, vc_head, Program, &file, &index, + &baseSwizzle, &relAddr)) return 1; parse_extended_swizzle_mask (inst, swizzle, &negateMask); vp->SrcReg[0].File = file; diff --git a/src/mesa/shader/arbprogram.c b/src/mesa/shader/arbprogram.c index 981565ab8f1..317d623a228 100644 --- a/src/mesa/shader/arbprogram.c +++ b/src/mesa/shader/arbprogram.c @@ -74,8 +74,6 @@ _mesa_BindProgram(GLenum target, GLuint id) GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - /* Error-check target and get curProg */ if ((target == GL_VERTEX_PROGRAM_ARB) && /* == GL_VERTEX_PROGRAM_NV */ (ctx->Extensions.NV_vertex_program || @@ -132,6 +130,9 @@ _mesa_BindProgram(GLenum target, GLuint id) return; } + /* signal new program (and its new constants) */ + FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); + /* bind newProg */ if (target == GL_VERTEX_PROGRAM_ARB) { /* == GL_VERTEX_PROGRAM_NV */ _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, @@ -489,7 +490,7 @@ _mesa_ProgramEnvParameter4fARB(GLenum target, GLuint index, GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); - FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); if (target == GL_FRAGMENT_PROGRAM_ARB && ctx->Extensions.ARB_fragment_program) { @@ -537,7 +538,7 @@ _mesa_ProgramEnvParameters4fvEXT(GLenum target, GLuint index, GLsizei count, GLfloat * dest; ASSERT_OUTSIDE_BEGIN_END(ctx); - FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); if (count <= 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(count)"); @@ -631,7 +632,7 @@ _mesa_ProgramLocalParameter4fARB(GLenum target, GLuint index, struct gl_program *prog; ASSERT_OUTSIDE_BEGIN_END(ctx); - FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); if ((target == GL_FRAGMENT_PROGRAM_NV && ctx->Extensions.NV_fragment_program) || @@ -685,7 +686,7 @@ _mesa_ProgramLocalParameters4fvEXT(GLenum target, GLuint index, GLsizei count, GLint i; ASSERT_OUTSIDE_BEGIN_END(ctx); - FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); if (count <= 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fv(count)"); diff --git a/src/mesa/shader/nvprogram.c b/src/mesa/shader/nvprogram.c index 5142c2a4a59..8ba521182b8 100644 --- a/src/mesa/shader/nvprogram.c +++ b/src/mesa/shader/nvprogram.c @@ -706,7 +706,7 @@ _mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name, GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); - FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); prog = _mesa_lookup_program(ctx, id); if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) { diff --git a/src/mesa/shader/prog_instruction.c b/src/mesa/shader/prog_instruction.c index ca7565c0911..ae3a003feed 100644 --- a/src/mesa/shader/prog_instruction.c +++ b/src/mesa/shader/prog_instruction.c @@ -286,6 +286,56 @@ _mesa_is_tex_instruction(gl_inst_opcode opcode) /** + * Check if there's a potential src/dst register data dependency when + * using SOA execution. + * Example: + * MOV T, T.yxwz; + * This would expand into: + * MOV t0, t1; + * MOV t1, t0; + * MOV t2, t3; + * MOV t3, t2; + * The second instruction will have the wrong value for t0 if executed as-is. + */ +GLboolean +_mesa_check_soa_dependencies(const struct prog_instruction *inst) +{ + GLuint i, chan; + + if (inst->DstReg.WriteMask == WRITEMASK_X || + inst->DstReg.WriteMask == WRITEMASK_Y || + inst->DstReg.WriteMask == WRITEMASK_Z || + inst->DstReg.WriteMask == WRITEMASK_W || + inst->DstReg.WriteMask == 0x0) { + /* no chance of data dependency */ + return GL_FALSE; + } + + /* loop over src regs */ + for (i = 0; i < 3; i++) { + if (inst->SrcReg[i].File == inst->DstReg.File && + inst->SrcReg[i].Index == inst->DstReg.Index) { + /* loop over dest channels */ + GLuint channelsWritten = 0x0; + for (chan = 0; chan < 4; chan++) { + if (inst->DstReg.WriteMask & (1 << chan)) { + /* check if we're reading a channel that's been written */ + GLuint swizzle = GET_SWZ(inst->SrcReg[i].Swizzle, chan); + if (swizzle <= SWIZZLE_W && + (channelsWritten & (1 << swizzle))) { + return GL_TRUE; + } + + channelsWritten |= (1 << chan); + } + } + } + } + return GL_FALSE; +} + + +/** * Return string name for given program opcode. */ const char * diff --git a/src/mesa/shader/prog_instruction.h b/src/mesa/shader/prog_instruction.h index 3109f6cbae5..40ad998f79d 100644 --- a/src/mesa/shader/prog_instruction.h +++ b/src/mesa/shader/prog_instruction.h @@ -428,6 +428,9 @@ _mesa_num_inst_dst_regs(gl_inst_opcode opcode); extern GLboolean _mesa_is_tex_instruction(gl_inst_opcode opcode); +extern GLboolean +_mesa_check_soa_dependencies(const struct prog_instruction *inst); + extern const char * _mesa_opcode_string(gl_inst_opcode opcode); diff --git a/src/mesa/shader/prog_optimize.c b/src/mesa/shader/prog_optimize.c index 6ba2e76ff96..be903106a08 100644 --- a/src/mesa/shader/prog_optimize.c +++ b/src/mesa/shader/prog_optimize.c @@ -547,15 +547,13 @@ update_interval(GLint intBegin[], GLint intEnd[], GLuint index, GLuint ic) /** - * Find the live intervals for each temporary register in the program. - * For register R, the interval [A,B] indicates that R is referenced - * from instruction A through instruction B. - * Special consideration is needed for loops and subroutines. - * \return GL_TRUE if success, GL_FALSE if we cannot proceed for some reason + * Find first/last instruction that references each temporary register. */ -static GLboolean -find_live_intervals(struct gl_program *prog, - struct interval_list *liveIntervals) +GLboolean +_mesa_find_temp_intervals(const struct prog_instruction *instructions, + GLuint numInstructions, + GLint intBegin[MAX_PROGRAM_TEMPS], + GLint intEnd[MAX_PROGRAM_TEMPS]) { struct loop_info { @@ -563,26 +561,15 @@ find_live_intervals(struct gl_program *prog, }; struct loop_info loopStack[MAX_LOOP_NESTING]; GLuint loopStackDepth = 0; - GLint intBegin[MAX_PROGRAM_TEMPS], intEnd[MAX_PROGRAM_TEMPS]; GLuint i; - /* - * Note: we'll return GL_FALSE below if we find relative indexing - * into the TEMP register file. We can't handle that yet. - * We also give up on subroutines for now. - */ - - if (dbg) { - _mesa_printf("Optimize: Begin find intervals\n"); - } - for (i = 0; i < MAX_PROGRAM_TEMPS; i++){ intBegin[i] = intEnd[i] = -1; } /* Scan instructions looking for temporary registers */ - for (i = 0; i < prog->NumInstructions; i++) { - const struct prog_instruction *inst = prog->Instructions + i; + for (i = 0; i < numInstructions; i++) { + const struct prog_instruction *inst = instructions + i; if (inst->Opcode == OPCODE_BGNLOOP) { loopStack[loopStackDepth].Start = i; loopStack[loopStackDepth].End = inst->BranchTarget; @@ -595,7 +582,7 @@ find_live_intervals(struct gl_program *prog, return GL_FALSE; } else { - const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); + const GLuint numSrc = 3;/*_mesa_num_inst_src_regs(inst->Opcode);*/ GLuint j; for (j = 0; j < numSrc; j++) { if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { @@ -624,6 +611,39 @@ find_live_intervals(struct gl_program *prog, } } + return GL_TRUE; +} + + +/** + * Find the live intervals for each temporary register in the program. + * For register R, the interval [A,B] indicates that R is referenced + * from instruction A through instruction B. + * Special consideration is needed for loops and subroutines. + * \return GL_TRUE if success, GL_FALSE if we cannot proceed for some reason + */ +static GLboolean +find_live_intervals(struct gl_program *prog, + struct interval_list *liveIntervals) +{ + GLint intBegin[MAX_PROGRAM_TEMPS], intEnd[MAX_PROGRAM_TEMPS]; + GLuint i; + + /* + * Note: we'll return GL_FALSE below if we find relative indexing + * into the TEMP register file. We can't handle that yet. + * We also give up on subroutines for now. + */ + + if (dbg) { + _mesa_printf("Optimize: Begin find intervals\n"); + } + + /* build intermediate arrays */ + if (!_mesa_find_temp_intervals(prog->Instructions, prog->NumInstructions, + intBegin, intEnd)) + return GL_FALSE; + /* Build live intervals list from intermediate arrays */ liveIntervals->Num = 0; for (i = 0; i < MAX_PROGRAM_TEMPS; i++) { @@ -792,8 +812,6 @@ _mesa_reallocate_registers(struct gl_program *prog) } - - /** * Apply optimizations to the given program to eliminate unnecessary * instructions, temp regs, etc. diff --git a/src/mesa/shader/prog_optimize.h b/src/mesa/shader/prog_optimize.h index d102cfd9fc1..43894a27237 100644 --- a/src/mesa/shader/prog_optimize.h +++ b/src/mesa/shader/prog_optimize.h @@ -25,7 +25,19 @@ #ifndef PROG_OPT_H #define PROG_OPT_H + +#include "main/config.h" + + struct gl_program; +struct prog_instruction; + + +extern GLboolean +_mesa_find_temp_intervals(const struct prog_instruction *instructions, + GLuint numInstructions, + GLint intBegin[MAX_PROGRAM_TEMPS], + GLint intEnd[MAX_PROGRAM_TEMPS]); extern void _mesa_optimize_program(GLcontext *ctx, struct gl_program *program); diff --git a/src/mesa/shader/prog_print.c b/src/mesa/shader/prog_print.c index 9967f2978de..e6f9a910690 100644 --- a/src/mesa/shader/prog_print.c +++ b/src/mesa/shader/prog_print.c @@ -941,6 +941,10 @@ _mesa_write_shader_to_file(const struct gl_shader *shader) fprintf(f, "/*\n"); _mesa_fprint_program_opt(f, shader->Program, PROG_PRINT_DEBUG, GL_TRUE); fprintf(f, "*/\n"); + fprintf(f, "/* Parameters / constants */\n"); + fprintf(f, "/*\n"); + _mesa_fprint_parameter_list(f, shader->Program->Parameters); + fprintf(f, "*/\n"); } fclose(f); diff --git a/src/mesa/shader/programopt.c b/src/mesa/shader/programopt.c index ecd98dc85c5..f70c75cec8e 100644 --- a/src/mesa/shader/programopt.c +++ b/src/mesa/shader/programopt.c @@ -45,8 +45,8 @@ * into a vertex program. * May be used to implement the position_invariant option. */ -void -_mesa_insert_mvp_code(GLcontext *ctx, struct gl_vertex_program *vprog) +static void +_mesa_insert_mvp_dp4_code(GLcontext *ctx, struct gl_vertex_program *vprog) { struct prog_instruction *newInst; const GLuint origLen = vprog->Base.NumInstructions; @@ -113,6 +113,121 @@ _mesa_insert_mvp_code(GLcontext *ctx, struct gl_vertex_program *vprog) } +static void +_mesa_insert_mvp_mad_code(GLcontext *ctx, struct gl_vertex_program *vprog) +{ + struct prog_instruction *newInst; + const GLuint origLen = vprog->Base.NumInstructions; + const GLuint newLen = origLen + 4; + GLuint hposTemp; + GLuint i; + + /* + * Setup state references for the modelview/projection matrix. + * XXX we should check if these state vars are already declared. + */ + static const gl_state_index mvpState[4][STATE_LENGTH] = { + { STATE_MVP_MATRIX, 0, 0, 0, STATE_MATRIX_TRANSPOSE }, + { STATE_MVP_MATRIX, 0, 1, 1, STATE_MATRIX_TRANSPOSE }, + { STATE_MVP_MATRIX, 0, 2, 2, STATE_MATRIX_TRANSPOSE }, + { STATE_MVP_MATRIX, 0, 3, 3, STATE_MATRIX_TRANSPOSE }, + }; + GLint mvpRef[4]; + + for (i = 0; i < 4; i++) { + mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters, + mvpState[i]); + } + + /* Alloc storage for new instructions */ + newInst = _mesa_alloc_instructions(newLen); + if (!newInst) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, + "glProgramString(inserting position_invariant code)"); + return; + } + + /* TEMP hposTemp; */ + hposTemp = vprog->Base.NumTemporaries++; + + /* + * Generated instructions: + * emit_op2(p, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]); + * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp); + * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp); + * emit_op3(p, OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp); + */ + _mesa_init_instructions(newInst, 4); + + newInst[0].Opcode = OPCODE_MUL; + newInst[0].DstReg.File = PROGRAM_TEMPORARY; + newInst[0].DstReg.Index = hposTemp; + newInst[0].DstReg.WriteMask = WRITEMASK_XYZW; + newInst[0].SrcReg[0].File = PROGRAM_INPUT; + newInst[0].SrcReg[0].Index = VERT_ATTRIB_POS; + newInst[0].SrcReg[0].Swizzle = SWIZZLE_XXXX; + newInst[0].SrcReg[1].File = PROGRAM_STATE_VAR; + newInst[0].SrcReg[1].Index = mvpRef[0]; + newInst[0].SrcReg[1].Swizzle = SWIZZLE_NOOP; + + for (i = 1; i <= 2; i++) { + newInst[i].Opcode = OPCODE_MAD; + newInst[i].DstReg.File = PROGRAM_TEMPORARY; + newInst[i].DstReg.Index = hposTemp; + newInst[i].DstReg.WriteMask = WRITEMASK_XYZW; + newInst[i].SrcReg[0].File = PROGRAM_INPUT; + newInst[i].SrcReg[0].Index = VERT_ATTRIB_POS; + newInst[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(i,i,i,i); + newInst[i].SrcReg[1].File = PROGRAM_STATE_VAR; + newInst[i].SrcReg[1].Index = mvpRef[i]; + newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; + newInst[i].SrcReg[2].File = PROGRAM_TEMPORARY; + newInst[i].SrcReg[2].Index = hposTemp; + newInst[1].SrcReg[2].Swizzle = SWIZZLE_NOOP; + } + + newInst[3].Opcode = OPCODE_MAD; + newInst[3].DstReg.File = PROGRAM_OUTPUT; + newInst[3].DstReg.Index = VERT_RESULT_HPOS; + newInst[3].DstReg.WriteMask = WRITEMASK_XYZW; + newInst[3].SrcReg[0].File = PROGRAM_INPUT; + newInst[3].SrcReg[0].Index = VERT_ATTRIB_POS; + newInst[3].SrcReg[0].Swizzle = SWIZZLE_WWWW; + newInst[3].SrcReg[1].File = PROGRAM_STATE_VAR; + newInst[3].SrcReg[1].Index = mvpRef[3]; + newInst[3].SrcReg[1].Swizzle = SWIZZLE_NOOP; + newInst[3].SrcReg[2].File = PROGRAM_TEMPORARY; + newInst[3].SrcReg[2].Index = hposTemp; + newInst[3].SrcReg[2].Swizzle = SWIZZLE_NOOP; + + + /* Append original instructions after new instructions */ + _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen); + + /* free old instructions */ + _mesa_free_instructions(vprog->Base.Instructions, origLen); + + /* install new instructions */ + vprog->Base.Instructions = newInst; + vprog->Base.NumInstructions = newLen; + vprog->Base.InputsRead |= VERT_BIT_POS; + vprog->Base.OutputsWritten |= (1 << VERT_RESULT_HPOS); +} + + +void +_mesa_insert_mvp_code(GLcontext *ctx, struct gl_vertex_program *vprog) +{ + if (ctx->mvp_with_dp4) + _mesa_insert_mvp_dp4_code( ctx, vprog ); + else + _mesa_insert_mvp_mad_code( ctx, vprog ); +} + + + + + /** * Append extra instructions onto the given fragment program to implement diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c index 644cd39185c..a8390d30942 100644 --- a/src/mesa/shader/shader_api.c +++ b/src/mesa/shader/shader_api.c @@ -1487,7 +1487,7 @@ _mesa_use_program(GLcontext *ctx, GLuint program) return; } - FLUSH_VERTICES(ctx, _NEW_PROGRAM); + FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); if (program) { shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram"); @@ -1509,6 +1509,10 @@ _mesa_use_program(GLcontext *ctx, GLuint program) shProg->Shaders[i]->Name, shProg->Shaders[i]->Type); } + if (shProg->VertexProgram) + printf(" vert prog %u\n", shProg->VertexProgram->Base.Id); + if (shProg->FragmentProgram) + printf(" frag prog %u\n", shProg->FragmentProgram->Base.Id); } } else { @@ -1789,7 +1793,7 @@ _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count, return; } - FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); uniform = &shProg->Uniforms->Uniforms[location]; @@ -1929,7 +1933,7 @@ _mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows, return; } - FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); uniform = &shProg->Uniforms->Uniforms[location]; diff --git a/src/mesa/shader/slang/slang_compile.c b/src/mesa/shader/slang/slang_compile.c index ba2fc4f85c9..d7ad879e97a 100644 --- a/src/mesa/shader/slang/slang_compile.c +++ b/src/mesa/shader/slang/slang_compile.c @@ -2161,6 +2161,12 @@ parse_function(slang_parse_ctx * C, slang_output_ctx * O, int definition, (O->funs->num_functions + 1) * sizeof(slang_function)); if (O->funs->functions == NULL) { + /* Make sure that there are no functions marked, as the + * allocation is currently NULL, in order to avoid + * a potental segfault as we clean up later. + */ + O->funs->num_functions = 0; + slang_info_log_memory(C->L); slang_function_destruct(&parsed_func); return GL_FALSE; diff --git a/src/mesa/shader/slang/slang_link.c b/src/mesa/shader/slang/slang_link.c index 1fdf4db054c..2bc8809661d 100644 --- a/src/mesa/shader/slang/slang_link.c +++ b/src/mesa/shader/slang/slang_link.c @@ -97,7 +97,8 @@ bits_agree(GLbitfield flags1, GLbitfield flags2, GLbitfield bit) * which inputs are centroid-sampled, invariant, etc. */ static GLboolean -link_varying_vars(struct gl_shader_program *shProg, struct gl_program *prog) +link_varying_vars(GLcontext *ctx, + struct gl_shader_program *shProg, struct gl_program *prog) { GLuint *map, i, firstVarying, newFile; GLbitfield *inOutFlags; @@ -156,8 +157,12 @@ link_varying_vars(struct gl_shader_program *shProg, struct gl_program *prog) var->Flags); } + if (shProg->Varying->NumParameters > ctx->Const.MaxVarying) { + link_error(shProg, "Too many varying variables"); + return GL_FALSE; + } + /* Map varying[i] to varying[j]. - * Plus, set prog->Input/OutputFlags[] as described above. * Note: the loop here takes care of arrays or large (sz>4) vars. */ { @@ -712,6 +717,8 @@ _slang_link(GLcontext *ctx, struct gl_vertex_program *linked_vprog = vertex_program(_mesa_clone_program(ctx, &vertProg->Base)); shProg->VertexProgram = linked_vprog; /* refcount OK */ + /* vertex program ID not significant; just set Id for debugging purposes */ + shProg->VertexProgram->Base.Id = shProg->Name; ASSERT(shProg->VertexProgram->Base.RefCount == 1); } @@ -720,16 +727,18 @@ _slang_link(GLcontext *ctx, struct gl_fragment_program *linked_fprog = fragment_program(_mesa_clone_program(ctx, &fragProg->Base)); shProg->FragmentProgram = linked_fprog; /* refcount OK */ + /* vertex program ID not significant; just set Id for debugging purposes */ + shProg->FragmentProgram->Base.Id = shProg->Name; ASSERT(shProg->FragmentProgram->Base.RefCount == 1); } /* link varying vars */ if (shProg->VertexProgram) { - if (!link_varying_vars(shProg, &shProg->VertexProgram->Base)) + if (!link_varying_vars(ctx, shProg, &shProg->VertexProgram->Base)) return; } if (shProg->FragmentProgram) { - if (!link_varying_vars(shProg, &shProg->FragmentProgram->Base)) + if (!link_varying_vars(ctx, shProg, &shProg->FragmentProgram->Base)) return; } diff --git a/src/mesa/state_tracker/st_atom_constbuf.c b/src/mesa/state_tracker/st_atom_constbuf.c index 77ecd0719e6..3ba7b269285 100644 --- a/src/mesa/state_tracker/st_atom_constbuf.c +++ b/src/mesa/state_tracker/st_atom_constbuf.c @@ -105,7 +105,7 @@ static void update_vs_constants(struct st_context *st ) const struct st_tracked_state st_update_vs_constants = { "st_update_vs_constants", /* name */ { /* dirty */ - _NEW_PROGRAM_CONSTANTS, + (_NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS), /* mesa */ ST_NEW_VERTEX_PROGRAM, /* st */ }, update_vs_constants /* update */ diff --git a/src/mesa/state_tracker/st_atom_framebuffer.c b/src/mesa/state_tracker/st_atom_framebuffer.c index df0f0931eab..f23186c73de 100644 --- a/src/mesa/state_tracker/st_atom_framebuffer.c +++ b/src/mesa/state_tracker/st_atom_framebuffer.c @@ -123,6 +123,7 @@ update_framebuffer_state( struct st_context *st ) framebuffer->cbufs[framebuffer->nr_cbufs] = strb->surface; framebuffer->nr_cbufs++; } + strb->defined = GL_TRUE; /* we'll be drawing something */ } } diff --git a/src/mesa/state_tracker/st_atom_rasterizer.c b/src/mesa/state_tracker/st_atom_rasterizer.c index 61687fbc3e2..4e70510c0c0 100644 --- a/src/mesa/state_tracker/st_atom_rasterizer.c +++ b/src/mesa/state_tracker/st_atom_rasterizer.c @@ -180,22 +180,7 @@ static void update_raster_state( struct st_context *st ) if (ctx->Polygon.StippleFlag) raster->poly_stipple_enable = 1; - - - /* _NEW_BUFFERS, _NEW_POLYGON - */ - if (raster->fill_cw != PIPE_POLYGON_MODE_FILL || - raster->fill_ccw != PIPE_POLYGON_MODE_FILL) - { - GLfloat mrd = (ctx->DrawBuffer ? - ctx->DrawBuffer->_MRD : - 1.0f); - - raster->offset_units = ctx->Polygon.OffsetFactor * mrd; - raster->offset_scale = (ctx->Polygon.OffsetUnits * mrd * - st->polygon_offset_scale); - } - + /* _NEW_POINT */ raster->point_size = ctx->Point.Size; diff --git a/src/mesa/state_tracker/st_cb_drawpixels.c b/src/mesa/state_tracker/st_cb_drawpixels.c index 08dc7c930e2..89725cfe8dc 100644 --- a/src/mesa/state_tracker/st_cb_drawpixels.c +++ b/src/mesa/state_tracker/st_cb_drawpixels.c @@ -910,6 +910,34 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy, st_validate_state(st); + if (srcx < 0) { + width -= -srcx; + dstx += -srcx; + srcx = 0; + } + + if (srcy < 0) { + height -= -srcy; + dsty += -srcy; + srcy = 0; + } + + if (dstx < 0) { + width -= -dstx; + srcx += -dstx; + dstx = 0; + } + + if (dsty < 0) { + height -= -dsty; + srcy += -dsty; + dsty = 0; + } + + if (width < 0 || height < 0) + return; + + if (type == GL_STENCIL) { /* can't use texturing to do stencil */ copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty); @@ -951,15 +979,24 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy, } } + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + srcy = ctx->DrawBuffer->Height - srcy - height; + + if (srcy < 0) { + height -= -srcy; + srcy = 0; + } + + if (height < 0) + return; + } + pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, texFormat, 0, width, height, 1, PIPE_TEXTURE_USAGE_SAMPLER); if (!pt) return; - if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { - srcy = ctx->DrawBuffer->Height - srcy - height; - } if (srcFormat == texFormat) { /* copy source framebuffer surface into mipmap/texture */ diff --git a/src/mesa/state_tracker/st_cb_fbo.c b/src/mesa/state_tracker/st_cb_fbo.c index 1590f275e2a..c249f3b3578 100644 --- a/src/mesa/state_tracker/st_cb_fbo.c +++ b/src/mesa/state_tracker/st_cb_fbo.c @@ -125,6 +125,8 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb, strb->Base.Height = height; init_renderbuffer_bits(strb, template.format); + strb->defined = GL_FALSE; /* undefined contents now */ + /* Probably need dedicated flags for surface usage too: */ surface_usage = (PIPE_BUFFER_USAGE_GPU_READ | @@ -343,6 +345,7 @@ st_render_texture(GLcontext *ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att) { + struct pipe_screen *screen = ctx->st->pipe->screen; struct st_renderbuffer *strb; struct gl_renderbuffer *rb; struct pipe_texture *pt = st_get_texobj_texture(att->Texture); @@ -365,6 +368,8 @@ st_render_texture(GLcontext *ctx, rb->AllocStorage = NULL; /* should not get called */ strb = st_renderbuffer(rb); + assert(strb->Base.RefCount > 0); + /* get the texture for the texture object */ stObj = st_texture_object(att->Texture); @@ -384,7 +389,14 @@ st_render_texture(GLcontext *ctx, pipe_surface_reference(&strb->surface, NULL); - /* the new surface will be created during framebuffer validation */ + /* new surface for rendering into the texture */ + strb->surface = screen->get_tex_surface(screen, + strb->texture, + strb->rtt_face, + strb->rtt_level, + strb->rtt_slice, + PIPE_BUFFER_USAGE_GPU_READ | + PIPE_BUFFER_USAGE_GPU_WRITE); init_renderbuffer_bits(strb, pt->format); @@ -452,6 +464,134 @@ st_validate_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb) } +/** + * Copy back color buffer to front color buffer. + */ +static void +copy_back_to_front(struct st_context *st, + struct gl_framebuffer *fb, + gl_buffer_index frontIndex, + gl_buffer_index backIndex) + +{ + struct st_framebuffer *stfb = (struct st_framebuffer *) fb; + struct pipe_surface *surf_front, *surf_back; + + (void) st_get_framebuffer_surface(stfb, frontIndex, &surf_front); + (void) st_get_framebuffer_surface(stfb, backIndex, &surf_back); + + if (surf_front && surf_back) { + st->pipe->surface_copy(st->pipe, + surf_front, 0, 0, /* dest */ + surf_back, 0, 0, /* src */ + fb->Width, fb->Height); + } +} + + +/** + * Check if we're drawing into, or read from, a front color buffer. If the + * front buffer is missing, create it now. + * + * The back color buffer must exist since we'll use its format/samples info + * for creating the front buffer. + * + * \param frontIndex either BUFFER_FRONT_LEFT or BUFFER_FRONT_RIGHT + * \param backIndex either BUFFER_BACK_LEFT or BUFFER_BACK_RIGHT + */ +static void +check_create_front_buffer(GLcontext *ctx, struct gl_framebuffer *fb, + gl_buffer_index frontIndex, + gl_buffer_index backIndex) +{ + if (fb->Attachment[frontIndex].Renderbuffer == NULL) { + GLboolean create = GL_FALSE; + + /* check if drawing to or reading from front buffer */ + if (fb->_ColorReadBufferIndex == frontIndex) { + create = GL_TRUE; + } + else { + GLuint b; + for (b = 0; b < fb->_NumColorDrawBuffers; b++) { + if (fb->_ColorDrawBufferIndexes[b] == frontIndex) { + create = GL_TRUE; + break; + } + } + } + + if (create) { + struct st_renderbuffer *back; + struct gl_renderbuffer *front; + enum pipe_format colorFormat; + uint samples; + + if (0) + _mesa_debug(ctx, "Allocate new front buffer\n"); + + /* get back renderbuffer info */ + back = st_renderbuffer(fb->Attachment[backIndex].Renderbuffer); + colorFormat = back->format; + samples = back->Base.NumSamples; + + /* create front renderbuffer */ + front = st_new_renderbuffer_fb(colorFormat, samples); + _mesa_add_renderbuffer(fb, frontIndex, front); + + /* alloc texture/surface for new front buffer */ + front->AllocStorage(ctx, front, front->InternalFormat, + fb->Width, fb->Height); + + /* initialize the front color buffer contents by copying + * the back buffer. + */ + copy_back_to_front(ctx->st, fb, frontIndex, backIndex); + } + } +} + + +/** + * If front left/right color buffers are missing, create them now. + */ +static void +check_create_front_buffers(GLcontext *ctx, struct gl_framebuffer *fb) +{ + /* check if we need to create the front left buffer now */ + check_create_front_buffer(ctx, fb, BUFFER_FRONT_LEFT, BUFFER_BACK_LEFT); + + if (fb->Visual.stereoMode) { + check_create_front_buffer(ctx, fb, BUFFER_FRONT_RIGHT, BUFFER_BACK_RIGHT); + } + + st_invalidate_state(ctx, _NEW_BUFFERS); +} + + +/** + * Called via glDrawBuffer. + */ +static void +st_DrawBuffers(GLcontext *ctx, GLsizei count, const GLenum *buffers) +{ + (void) count; + (void) buffers; + check_create_front_buffers(ctx, ctx->DrawBuffer); +} + + +/** + * Called via glReadBuffer. + */ +static void +st_ReadBuffer(GLcontext *ctx, GLenum buffer) +{ + (void) buffer; + check_create_front_buffers(ctx, ctx->ReadBuffer); +} + + void st_init_fbo_functions(struct dd_function_table *functions) { functions->NewFramebuffer = st_new_framebuffer; @@ -464,4 +604,7 @@ void st_init_fbo_functions(struct dd_function_table *functions) /* no longer needed by core Mesa, drivers handle resizes... functions->ResizeBuffers = st_resize_buffers; */ + + functions->DrawBuffers = st_DrawBuffers; + functions->ReadBuffer = st_ReadBuffer; } diff --git a/src/mesa/state_tracker/st_cb_fbo.h b/src/mesa/state_tracker/st_cb_fbo.h index 44fa9fe9a4f..fd77d0a95b0 100644 --- a/src/mesa/state_tracker/st_cb_fbo.h +++ b/src/mesa/state_tracker/st_cb_fbo.h @@ -44,6 +44,7 @@ struct st_renderbuffer struct pipe_texture *texture; struct pipe_surface *surface; /* temporary view into texture */ enum pipe_format format; /** preferred format, or PIPE_FORMAT_NONE */ + GLboolean defined; /**< defined contents? */ struct st_texture_object *rtt; /**< GL render to texture's texture */ int rtt_level, rtt_face, rtt_slice; diff --git a/src/mesa/state_tracker/st_cb_flush.c b/src/mesa/state_tracker/st_cb_flush.c index 7d7d3823c99..8ceeeabcd37 100644 --- a/src/mesa/state_tracker/st_cb_flush.c +++ b/src/mesa/state_tracker/st_cb_flush.c @@ -47,10 +47,19 @@ #include "util/u_blit.h" +/** Check if we have a front color buffer and if it's been drawn to. */ static INLINE GLboolean is_front_buffer_dirty(struct st_context *st) { - return st->frontbuffer_status == FRONT_STATUS_DIRTY; + if (st->frontbuffer_status == FRONT_STATUS_DIRTY) { + return GL_TRUE; + } + else { + GLframebuffer *fb = st->ctx->DrawBuffer; + struct st_renderbuffer *strb + = st_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer); + return strb && strb->defined; + } } @@ -82,7 +91,7 @@ display_front_buffer(struct st_context *st) void st_flush( struct st_context *st, uint pipeFlushFlags, struct pipe_fence_handle **fence ) { - FLUSH_VERTICES(st->ctx, 0); + FLUSH_CURRENT(st->ctx, 0); /* Release any vertex buffers that might potentially be accessed in * successive frames: diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c index c3e990e0775..b182106fd56 100644 --- a/src/mesa/state_tracker/st_cb_texture.c +++ b/src/mesa/state_tracker/st_cb_texture.c @@ -51,6 +51,7 @@ #include "state_tracker/st_texture.h" #include "state_tracker/st_gen_mipmap.h" #include "state_tracker/st_inlines.h" +#include "state_tracker/st_atom.h" #include "pipe/p_context.h" #include "pipe/p_defines.h" @@ -418,7 +419,6 @@ compress_with_blit(GLcontext * ctx, const GLuint dstImageOffsets[1] = {0}; struct st_texture_image *stImage = st_texture_image(texImage); struct pipe_screen *screen = ctx->st->pipe->screen; - const GLuint face = _mesa_tex_target_to_face(target); const struct gl_texture_format *mesa_format; struct pipe_texture templ; struct pipe_texture *src_tex; @@ -467,7 +467,7 @@ compress_with_blit(GLcontext * ctx, /* Put user's tex data into the temporary texture */ tex_xfer = st_cond_flush_get_tex_transfer(st_context(ctx), src_tex, - face, level, 0, + 0, 0, 0, /* face, level are zero */ PIPE_TRANSFER_WRITE, 0, 0, width, height); /* x, y, w, h */ map = screen->transfer_map(screen, tex_xfer); @@ -1315,8 +1315,9 @@ st_copy_texsubimage(GLcontext *ctx, GLboolean use_fallback = GL_TRUE; GLboolean matching_base_formats; - /* any rendering in progress must complete before we grab the fb image */ - st_finish(ctx->st); + /* make sure finalize_textures has been called? + */ + if (0) st_validate_state(ctx->st); /* determine if copying depth or color data */ if (texBaseFormat == GL_DEPTH_COMPONENT || @@ -1331,6 +1332,39 @@ st_copy_texsubimage(GLcontext *ctx, strb = st_renderbuffer(fb->_ColorReadBuffer); } + if (!strb || !strb->surface || !stImage->pt) { + debug_printf("%s: null strb or stImage\n", __FUNCTION__); + return; + } + + if (srcX < 0) { + width -= -srcX; + destX += -srcX; + srcX = 0; + } + + if (srcY < 0) { + height -= -srcY; + destY += -srcY; + srcY = 0; + } + + if (destX < 0) { + width -= -destX; + srcX += -destX; + destX = 0; + } + + if (destY < 0) { + height -= -destY; + srcY += -destY; + destY = 0; + } + + if (width < 0 || height < 0) + return; + + assert(strb); assert(strb->surface); assert(stImage->pt); diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c index b27274725fc..2a1f21c51ca 100644 --- a/src/mesa/state_tracker/st_context.c +++ b/src/mesa/state_tracker/st_context.c @@ -177,6 +177,12 @@ struct st_context *st_create_context(struct pipe_context *pipe, ctx = _mesa_create_context(visual, shareCtx, &funcs, NULL); + /* XXX: need a capability bit in gallium to query if the pipe + * driver prefers DP4 or MUL/MAD for vertex transformation. + */ + if (debug_get_bool_option("MESA_MVP_DP4", FALSE)) + _mesa_set_mvp_with_dp4( ctx, GL_TRUE ); + return st_create_context_priv(ctx, pipe); } @@ -279,6 +285,12 @@ void st_make_current(struct st_context *st, } } +struct st_context *st_get_current(void) +{ + GET_CURRENT_CONTEXT(ctx); + + return (ctx == NULL) ? NULL : ctx->st; +} void st_copy_context_state(struct st_context *dst, struct st_context *src, diff --git a/src/mesa/state_tracker/st_context.h b/src/mesa/state_tracker/st_context.h index f840579a404..18adb35e872 100644 --- a/src/mesa/state_tracker/st_context.h +++ b/src/mesa/state_tracker/st_context.h @@ -45,6 +45,7 @@ struct blit_state; struct bitmap_cache; +/** XXX we'd like to get rid of these */ #define FRONT_STATUS_UNDEFINED 0 #define FRONT_STATUS_DIRTY 1 #define FRONT_STATUS_COPY_OF_BACK 2 @@ -111,7 +112,7 @@ struct st_context struct gl_fragment_program *fragment_program; } cb; - GLuint frontbuffer_status; /**< one of FRONT_STATUS_ */ + GLuint frontbuffer_status; /**< one of FRONT_STATUS_ (XXX to be removed) */ char vendor[100]; char renderer[100]; @@ -120,8 +121,6 @@ struct st_context GLboolean missing_textures; - GLfloat polygon_offset_scale; /* ?? */ - /** Mapping from VERT_RESULT_x to post-transformed vertex slot */ const GLuint *vertex_result_to_slot; diff --git a/src/mesa/state_tracker/st_draw_feedback.c b/src/mesa/state_tracker/st_draw_feedback.c index e533afd051e..32502a9cda4 100644 --- a/src/mesa/state_tracker/st_draw_feedback.c +++ b/src/mesa/state_tracker/st_draw_feedback.c @@ -196,13 +196,10 @@ st_feedback_draw_vbo(GLcontext *ctx, draw_set_vertex_elements(draw, vp->num_inputs, velements); if (ib) { - unsigned indexSize; struct gl_buffer_object *bufobj = ib->obj; - struct st_buffer_object *stobj = st_buffer_object(bufobj); + unsigned indexSize; void *map; - index_buffer_handle = stobj->buffer; - switch (ib->type) { case GL_UNSIGNED_INT: indexSize = 4; @@ -215,9 +212,19 @@ st_feedback_draw_vbo(GLcontext *ctx, return; } - map = pipe_buffer_map(pipe->screen, index_buffer_handle, - PIPE_BUFFER_USAGE_CPU_READ); - draw_set_mapped_element_buffer(draw, indexSize, map); + if (bufobj && bufobj->Name) { + struct st_buffer_object *stobj = st_buffer_object(bufobj); + + index_buffer_handle = stobj->buffer; + + map = pipe_buffer_map(pipe->screen, index_buffer_handle, + PIPE_BUFFER_USAGE_CPU_READ); + + draw_set_mapped_element_buffer(draw, indexSize, map); + } + else { + draw_set_mapped_element_buffer(draw, indexSize, (void *) ib->ptr); + } } else { /* no index/element buffer */ @@ -252,7 +259,7 @@ st_feedback_draw_vbo(GLcontext *ctx, draw_set_mapped_vertex_buffer(draw, i, NULL); } } - if (ib) { + if (index_buffer_handle) { pipe_buffer_unmap(pipe->screen, index_buffer_handle); draw_set_mapped_element_buffer(draw, 0, NULL); } diff --git a/src/mesa/state_tracker/st_framebuffer.c b/src/mesa/state_tracker/st_framebuffer.c index daaad65ccaf..ef800291ccd 100644 --- a/src/mesa/state_tracker/st_framebuffer.c +++ b/src/mesa/state_tracker/st_framebuffer.c @@ -58,19 +58,19 @@ st_create_framebuffer( const __GLcontextModes *visual, _mesa_initialize_framebuffer(&stfb->Base, visual); - { - /* fake frontbuffer */ - /* XXX allocation should only happen in the unusual case - it's actually needed */ + if (visual->doubleBufferMode) { struct gl_renderbuffer *rb = st_new_renderbuffer_fb(colorFormat, samples); - _mesa_add_renderbuffer(&stfb->Base, BUFFER_FRONT_LEFT, rb); + _mesa_add_renderbuffer(&stfb->Base, BUFFER_BACK_LEFT, rb); } - - if (visual->doubleBufferMode) { + else { + /* Only allocate front buffer right now if we're single buffered. + * If double-buffered, allocate front buffer on demand later. + * See check_create_front_buffers(). + */ struct gl_renderbuffer *rb = st_new_renderbuffer_fb(colorFormat, samples); - _mesa_add_renderbuffer(&stfb->Base, BUFFER_BACK_LEFT, rb); + _mesa_add_renderbuffer(&stfb->Base, BUFFER_FRONT_LEFT, rb); } if (depthFormat == stencilFormat && depthFormat != PIPE_FORMAT_NONE) { @@ -293,6 +293,115 @@ st_notify_swapbuffers(struct st_framebuffer *stfb) } +/** + * Swap the front/back color buffers. Exchange the front/back pointers + * and update some derived state. + * No need to call st_notify_swapbuffers() first. + * + * For a single-buffered framebuffer, no swap occurs, but we still return + * the pointer(s) to the front color buffer(s). + * + * \param front_left returns pointer to front-left renderbuffer after swap + * \param front_right returns pointer to front-right renderbuffer after swap + */ +void +st_swapbuffers(struct st_framebuffer *stfb, + struct pipe_surface **front_left, + struct pipe_surface **front_right) +{ + struct gl_framebuffer *fb = &stfb->Base; + + GET_CURRENT_CONTEXT(ctx); + + if (ctx && ctx->DrawBuffer == &stfb->Base) { + st_flush( ctx->st, + PIPE_FLUSH_RENDER_CACHE | + PIPE_FLUSH_SWAPBUFFERS | + PIPE_FLUSH_FRAME, + NULL ); + } + + if (!fb->Visual.doubleBufferMode) { + /* single buffer mode - return pointers to front surfaces */ + if (front_left) { + struct st_renderbuffer *strb = + st_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer); + *front_left = strb->surface; + } + if (front_right) { + struct st_renderbuffer *strb = + st_renderbuffer(fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer); + *front_right = strb ? strb->surface : NULL; + } + return; + } + + /* swap left buffers */ + if (fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer && + fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer) { + struct gl_renderbuffer *rbTemp; + rbTemp = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer; + fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer = + fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer; + fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer = rbTemp; + if (front_left) { + struct st_renderbuffer *strb = + st_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer); + *front_left = strb->surface; + } + /* mark back buffer contents as undefined */ + { + struct st_renderbuffer *back = + st_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer); + back->defined = GL_FALSE; + } + } + else { + /* no front buffer, display the back buffer */ + if (front_left) { + struct st_renderbuffer *strb = + st_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer); + *front_left = strb->surface; + } + } + + /* swap right buffers (for stereo) */ + if (fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer && + fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer) { + struct gl_renderbuffer *rbTemp; + rbTemp = fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer; + fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer = + fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer; + fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer = rbTemp; + if (front_right) { + struct st_renderbuffer *strb = + st_renderbuffer(fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer); + *front_right = strb->surface; + } + /* mark back buffer contents as undefined */ + { + struct st_renderbuffer *back = + st_renderbuffer(fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer); + back->defined = GL_FALSE; + } + } + else { + /* no front right buffer, display back right buffer (if exists) */ + if (front_right) { + struct st_renderbuffer *strb = + st_renderbuffer(fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer); + *front_right = strb ? strb->surface : NULL; + } + } + + /* Update the _ColorDrawBuffers[] array and _ColorReadBuffer pointer */ + _mesa_update_framebuffer(ctx); + + /* Make sure we draw into the new back surface */ + st_invalidate_state(ctx, _NEW_BUFFERS); +} + + void *st_framebuffer_private( struct st_framebuffer *stfb ) { return stfb->Private; diff --git a/src/mesa/state_tracker/st_inlines.h b/src/mesa/state_tracker/st_inlines.h index 0322d5dfa6e..a41cfeb96f7 100644 --- a/src/mesa/state_tracker/st_inlines.h +++ b/src/mesa/state_tracker/st_inlines.h @@ -1,3 +1,35 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * Functions for checking if buffers/textures are referenced when we need + * to read/write from/to them. Flush when needed. + */ + #ifndef ST_INLINES_H #define ST_INLINES_H diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c index 2795570cf10..6ec633c0b46 100644 --- a/src/mesa/state_tracker/st_program.c +++ b/src/mesa/state_tracker/st_program.c @@ -169,6 +169,14 @@ st_translate_vertex_program(struct st_context *st, case VERT_ATTRIB_GENERIC5: case VERT_ATTRIB_GENERIC6: case VERT_ATTRIB_GENERIC7: + case VERT_ATTRIB_GENERIC8: + case VERT_ATTRIB_GENERIC9: + case VERT_ATTRIB_GENERIC10: + case VERT_ATTRIB_GENERIC11: + case VERT_ATTRIB_GENERIC12: + case VERT_ATTRIB_GENERIC13: + case VERT_ATTRIB_GENERIC14: + case VERT_ATTRIB_GENERIC15: assert(attr < VERT_ATTRIB_MAX); vs_input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; vs_input_semantic_index[slot] = num_generic++; diff --git a/src/mesa/state_tracker/st_public.h b/src/mesa/state_tracker/st_public.h index 030314372f9..174fbc63941 100644 --- a/src/mesa/state_tracker/st_public.h +++ b/src/mesa/state_tracker/st_public.h @@ -95,12 +95,18 @@ void st_make_current(struct st_context *st, struct st_framebuffer *draw, struct st_framebuffer *read); +struct st_context *st_get_current(void); + void st_flush( struct st_context *st, uint pipeFlushFlags, struct pipe_fence_handle **fence ); void st_finish( struct st_context *st ); void st_notify_swapbuffers(struct st_framebuffer *stfb); +void st_swapbuffers(struct st_framebuffer *stfb, + struct pipe_surface **front_left, + struct pipe_surface **front_right); + int st_set_teximage(struct pipe_texture *pt, int target); /** Redirect rendering into stfb's surface to a texture image */ diff --git a/src/mesa/swrast/s_imaging.c b/src/mesa/swrast/s_imaging.c index d6be3aa022e..3578b713f61 100644 --- a/src/mesa/swrast/s_imaging.c +++ b/src/mesa/swrast/s_imaging.c @@ -60,7 +60,7 @@ _swrast_CopyColorTable( GLcontext *ctx, /* save PBO binding */ bufferSave = ctx->Unpack.BufferObj; - ctx->Unpack.BufferObj = ctx->Array.NullBufferObj; + ctx->Unpack.BufferObj = ctx->Shared->NullBufferObj; _mesa_ColorTable(target, internalformat, width, GL_RGBA, CHAN_TYPE, data); @@ -94,7 +94,7 @@ _swrast_CopyColorSubTable( GLcontext *ctx,GLenum target, GLsizei start, /* save PBO binding */ bufferSave = ctx->Unpack.BufferObj; - ctx->Unpack.BufferObj = ctx->Array.NullBufferObj; + ctx->Unpack.BufferObj = ctx->Shared->NullBufferObj; _mesa_ColorSubTable(target, start, width, GL_RGBA, CHAN_TYPE, data); @@ -126,7 +126,7 @@ _swrast_CopyConvolutionFilter1D(GLcontext *ctx, GLenum target, /* save PBO binding */ bufferSave = ctx->Unpack.BufferObj; - ctx->Unpack.BufferObj = ctx->Array.NullBufferObj; + ctx->Unpack.BufferObj = ctx->Shared->NullBufferObj; /* store as convolution filter */ _mesa_ConvolutionFilter1D(target, internalFormat, width, @@ -178,12 +178,12 @@ _swrast_CopyConvolutionFilter2D(GLcontext *ctx, GLenum target, ctx->Unpack.SkipImages = 0; ctx->Unpack.SwapBytes = GL_FALSE; ctx->Unpack.LsbFirst = GL_FALSE; - ctx->Unpack.BufferObj = ctx->Array.NullBufferObj; + ctx->Unpack.BufferObj = ctx->Shared->NullBufferObj; ctx->NewState |= _NEW_PACKUNPACK; /* save PBO binding */ bufferSave = ctx->Unpack.BufferObj; - ctx->Unpack.BufferObj = ctx->Array.NullBufferObj; + ctx->Unpack.BufferObj = ctx->Shared->NullBufferObj; _mesa_ConvolutionFilter2D(target, internalFormat, width, height, GL_RGBA, CHAN_TYPE, rgba); diff --git a/src/mesa/swrast/s_span.c b/src/mesa/swrast/s_span.c index cfff82b0513..fa8ca1d0e26 100644 --- a/src/mesa/swrast/s_span.c +++ b/src/mesa/swrast/s_span.c @@ -1,8 +1,9 @@ /* * Mesa 3-D graphics library - * Version: 7.1 + * Version: 7.5 * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -188,10 +189,10 @@ interpolate_active_attribs(GLcontext *ctx, SWspan *span, GLbitfield attrMask) const GLfloat dv1dx = span->attrStepX[attr][1]; const GLfloat dv2dx = span->attrStepX[attr][2]; const GLfloat dv3dx = span->attrStepX[attr][3]; - GLfloat v0 = span->attrStart[attr][0]; - GLfloat v1 = span->attrStart[attr][1]; - GLfloat v2 = span->attrStart[attr][2]; - GLfloat v3 = span->attrStart[attr][3]; + GLfloat v0 = span->attrStart[attr][0] + span->leftClip * dv0dx; + GLfloat v1 = span->attrStart[attr][1] + span->leftClip * dv1dx; + GLfloat v2 = span->attrStart[attr][2] + span->leftClip * dv2dx; + GLfloat v3 = span->attrStart[attr][3] + span->leftClip * dv3dx; GLuint k; for (k = 0; k < span->end; k++) { const GLfloat invW = 1.0f / w; @@ -521,10 +522,10 @@ interpolate_texcoords(GLcontext *ctx, SWspan *span) const GLfloat drdx = span->attrStepX[attr][2]; const GLfloat dqdx = span->attrStepX[attr][3]; const GLfloat dqdy = span->attrStepY[attr][3]; - GLfloat s = span->attrStart[attr][0]; - GLfloat t = span->attrStart[attr][1]; - GLfloat r = span->attrStart[attr][2]; - GLfloat q = span->attrStart[attr][3]; + GLfloat s = span->attrStart[attr][0] + span->leftClip * dsdx; + GLfloat t = span->attrStart[attr][1] + span->leftClip * dtdx; + GLfloat r = span->attrStart[attr][2] + span->leftClip * drdx; + GLfloat q = span->attrStart[attr][3] + span->leftClip * dqdx; if (obj) { const struct gl_texture_image *img = obj->Image[0][obj->BaseLevel]; @@ -546,7 +547,7 @@ interpolate_texcoords(GLcontext *ctx, SWspan *span) || ctx->ATIFragmentShader._Enabled) { /* do perspective correction but don't divide s, t, r by q */ const GLfloat dwdx = span->attrStepX[FRAG_ATTRIB_WPOS][3]; - GLfloat w = span->attrStart[FRAG_ATTRIB_WPOS][3]; + GLfloat w = span->attrStart[FRAG_ATTRIB_WPOS][3] + span->leftClip * dwdx; for (i = 0; i < span->end; i++) { const GLfloat invW = 1.0F / w; texcoord[i][0] = s * invW; @@ -587,7 +588,7 @@ interpolate_texcoords(GLcontext *ctx, SWspan *span) ctx->ATIFragmentShader._Enabled) { /* do perspective correction but don't divide s, t, r by q */ const GLfloat dwdx = span->attrStepX[FRAG_ATTRIB_WPOS][3]; - GLfloat w = span->attrStart[FRAG_ATTRIB_WPOS][3]; + GLfloat w = span->attrStart[FRAG_ATTRIB_WPOS][3] + span->leftClip * dwdx; for (i = 0; i < span->end; i++) { const GLfloat invW = 1.0F / w; texcoord[i][0] = s * invW; @@ -660,8 +661,8 @@ interpolate_wpos(GLcontext *ctx, SWspan *span) } } - w = span->attrStart[FRAG_ATTRIB_WPOS][3]; dw = span->attrStepX[FRAG_ATTRIB_WPOS][3]; + w = span->attrStart[FRAG_ATTRIB_WPOS][3] + span->leftClip * dw; for (i = 0; i < span->end; i++) { wpos[i][2] = (GLfloat) span->array->z[i] * zScale; wpos[i][3] = w; @@ -726,6 +727,8 @@ clip_span( GLcontext *ctx, SWspan *span ) const GLint ymin = ctx->DrawBuffer->_Ymin; const GLint ymax = ctx->DrawBuffer->_Ymax; + span->leftClip = 0; + if (span->arrayMask & SPAN_XY) { /* arrays of x/y pixel coords */ const GLint *x = span->array->x; @@ -753,7 +756,7 @@ clip_span( GLcontext *ctx, SWspan *span ) /* horizontal span of pixels */ const GLint x = span->x; const GLint y = span->y; - const GLint n = span->end; + GLint n = span->end; /* Trivial rejection tests */ if (y < ymin || y >= ymax || x + n <= xmin || x >= xmax) { @@ -761,18 +764,44 @@ clip_span( GLcontext *ctx, SWspan *span ) return GL_FALSE; /* all pixels clipped */ } + /* Clip to right */ + if (x + n > xmax) { + ASSERT(x < xmax); + n = span->end = xmax - x; + } + /* Clip to the left */ if (x < xmin) { + const GLint leftClip = xmin - x; + GLuint i; + + ASSERT(leftClip > 0); ASSERT(x + n > xmin); + + /* Clip 'leftClip' pixels from the left side. + * The span->leftClip field will be applied when we interpolate + * fragment attributes. + * For arrays of values, shift them left. + */ + for (i = 0; i < FRAG_ATTRIB_MAX; i++) { + if (span->arrayAttribs & (1 << i)) { + /* shift array elements left by 'leftClip' */ + _mesa_memcpy(span->array->attribs[i], + span->array->attribs[i] + leftClip, + (n - leftClip) * 4 * sizeof(GLfloat)); + } + } + + span->leftClip = leftClip; + span->x = xmin; + span->end -= leftClip; span->writeAll = GL_FALSE; - _mesa_bzero(span->array->mask, (xmin - x) * sizeof(GLubyte)); } - /* Clip to right */ - if (x + n > xmax) { - ASSERT(x < xmax); - span->end = xmax - x; - } + ASSERT(span->x >= xmin); + ASSERT(span->x + span->end <= xmax); + ASSERT(span->y >= ymin); + ASSERT(span->y < ymax); return GL_TRUE; /* some pixels visible */ } @@ -818,6 +847,12 @@ _swrast_write_index_span( GLcontext *ctx, SWspan *span) } } + if (!(span->arrayMask & SPAN_MASK)) { + /* post-clip sanity check */ + assert(span->x >= 0); + assert(span->y >= 0); + } + /* Depth bounds test */ if (ctx->Depth.BoundsTest && fb->Visual.depthBits > 0) { if (!_swrast_depth_bounds_test(ctx, span)) { @@ -1284,6 +1319,7 @@ _swrast_write_rgba_span( GLcontext *ctx, SWspan *span) #ifdef DEBUG /* Make sure all fragments are within window bounds */ if (span->arrayMask & SPAN_XY) { + /* array of pixel locations */ GLuint i; for (i = 0; i < span->end; i++) { if (span->array->mask[i]) { @@ -1321,6 +1357,14 @@ _swrast_write_rgba_span( GLcontext *ctx, SWspan *span) if (!(span->arrayMask & SPAN_Z)) _swrast_span_interpolate_z(ctx, span); + if ((span->arrayMask & SPAN_XY) == 0) { + if (span->x < fb->_Xmin || span->x + span->end > fb->_Xmax || + span->y < fb->_Ymin || span->y >= fb->_Ymax) { + printf("Bad span clipping at %d, %d\n", span->x, span->y); + return; + } + } + if (ctx->Stencil._Enabled) { /* Combined Z/stencil tests */ if (!_swrast_stencil_and_ztest_span(ctx, span)) { diff --git a/src/mesa/swrast/s_span.h b/src/mesa/swrast/s_span.h index c4b47df58ff..0eabae20e03 100644 --- a/src/mesa/swrast/s_span.h +++ b/src/mesa/swrast/s_span.h @@ -1,8 +1,9 @@ /* * Mesa 3-D graphics library - * Version: 6.5 + * Version: 7.5 * - * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -106,6 +107,9 @@ typedef struct sw_span /** Number of fragments in the span */ GLuint end; + /** for clipping left edge of spans */ + GLuint leftClip; + /** This flag indicates that mask[] array is effectively filled with ones */ GLboolean writeAll; @@ -165,6 +169,7 @@ do { \ (S).arrayMask = 0x0; \ (S).arrayAttribs = 0x0; \ (S).end = 0; \ + (S).leftClip = 0; \ (S).facing = 0; \ (S).array = SWRAST_CONTEXT(ctx)->SpanArrays; \ } while (0) diff --git a/src/mesa/swrast/s_texfilter.c b/src/mesa/swrast/s_texfilter.c index a483023a503..31bfb5c9520 100644 --- a/src/mesa/swrast/s_texfilter.c +++ b/src/mesa/swrast/s_texfilter.c @@ -462,6 +462,7 @@ clamp_rect_coord_linear(GLenum wrapMode, GLfloat coord, GLint max, fcol -= 0.5F; i0 = IFLOOR(fcol); i1 = i0 + 1; + break; default: _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_linear"); i0 = i1 = 0; diff --git a/src/mesa/tnl/t_vb_cliptmp.h b/src/mesa/tnl/t_vb_cliptmp.h index 788fe329ed8..61b0a89554c 100644 --- a/src/mesa/tnl/t_vb_cliptmp.h +++ b/src/mesa/tnl/t_vb_cliptmp.h @@ -127,7 +127,7 @@ TAG(clip_line)( GLcontext *ctx, GLuint v0, GLuint v1, GLubyte mask ) GLuint p; const GLuint v0_orig = v0; - if (mask & 0x3f) { + if (mask & CLIP_FRUSTUM_BITS) { LINE_CLIP( CLIP_RIGHT_BIT, -1, 0, 0, 1 ); LINE_CLIP( CLIP_LEFT_BIT, 1, 0, 0, 1 ); LINE_CLIP( CLIP_TOP_BIT, 0, -1, 0, 1 ); @@ -199,7 +199,7 @@ TAG(clip_tri)( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLubyte mask ) ASSIGN_3V(inlist, v2, v0, v1 ); /* pv rotated to slot zero */ - if (mask & 0x3f) { + if (mask & CLIP_FRUSTUM_BITS) { POLY_CLIP( CLIP_RIGHT_BIT, -1, 0, 0, 1 ); POLY_CLIP( CLIP_LEFT_BIT, 1, 0, 0, 1 ); POLY_CLIP( CLIP_TOP_BIT, 0, -1, 0, 1 ); @@ -227,6 +227,25 @@ TAG(clip_tri)( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLubyte mask ) } } + if (0) { + /* print pre/post-clip vertex coords */ + GLuint i, j; + _mesa_printf("pre clip\n"); + for (i = 0; i < 3; i++) { + j = outlist[i]; + _mesa_printf(" %u: %u: %f, %f, %f, %f\n", + i, j, + coord[j][0], coord[j][1], coord[j][2], coord[j][3]); + } + _mesa_printf("post clip\n"); + for (i = 0; i < n; i++) { + j = inlist[i]; + _mesa_printf(" %u: %u: %f, %f, %f, %f\n", + i, j, + coord[j][0], coord[j][1], coord[j][2], coord[j][3]); + } + } + tnl->Driver.Render.ClippedPolygon( ctx, inlist, n ); } @@ -250,7 +269,7 @@ TAG(clip_quad)( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint v3, ASSIGN_4V(inlist, v3, v0, v1, v2 ); /* pv rotated to slot zero */ - if (mask & 0x3f) { + if (mask & CLIP_FRUSTUM_BITS) { POLY_CLIP( CLIP_RIGHT_BIT, -1, 0, 0, 1 ); POLY_CLIP( CLIP_LEFT_BIT, 1, 0, 0, 1 ); POLY_CLIP( CLIP_TOP_BIT, 0, -1, 0, 1 ); diff --git a/src/mesa/vbo/vbo_context.c b/src/mesa/vbo/vbo_context.c index ca8190fd059..f193a4bf1e0 100644 --- a/src/mesa/vbo/vbo_context.c +++ b/src/mesa/vbo/vbo_context.c @@ -28,6 +28,7 @@ #include "main/imports.h" #include "main/mtypes.h" #include "main/api_arrayelt.h" +#include "main/bufferobj.h" #include "math/m_eval.h" #include "vbo.h" #include "vbo_context.h" @@ -81,7 +82,8 @@ static void init_legacy_currval(GLcontext *ctx) cl->Type = GL_FLOAT; cl->Format = GL_RGBA; cl->Ptr = (const void *)ctx->Current.Attrib[i]; - cl->BufferObj = ctx->Array.NullBufferObj; + _mesa_reference_buffer_object(ctx, &cl->BufferObj, + ctx->Shared->NullBufferObj); } } @@ -106,7 +108,8 @@ static void init_generic_currval(GLcontext *ctx) cl->Stride = 0; cl->StrideB = 0; cl->Enabled = 1; - cl->BufferObj = ctx->Array.NullBufferObj; + _mesa_reference_buffer_object(ctx, &cl->BufferObj, + ctx->Shared->NullBufferObj); } } @@ -150,7 +153,7 @@ static void init_mat_currval(GLcontext *ctx) cl->Stride = 0; cl->StrideB = 0; cl->Enabled = 1; - cl->BufferObj = ctx->Array.NullBufferObj; + cl->BufferObj = ctx->Shared->NullBufferObj; } } diff --git a/src/mesa/vbo/vbo_exec_api.c b/src/mesa/vbo/vbo_exec_api.c index 5d35ec9c111..6871ee5cab1 100644 --- a/src/mesa/vbo/vbo_exec_api.c +++ b/src/mesa/vbo/vbo_exec_api.c @@ -671,7 +671,7 @@ void vbo_use_buffer_objects(GLcontext *ctx) GLsizei size = VBO_VERT_BUFFER_SIZE; /* Make sure this func is only used once */ - assert(exec->vtx.bufferobj == ctx->Array.NullBufferObj); + assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj); if (exec->vtx.buffer_map) { _mesa_align_free(exec->vtx.buffer_map); exec->vtx.buffer_map = NULL; @@ -697,7 +697,7 @@ void vbo_exec_vtx_init( struct vbo_exec_context *exec ) */ _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, - ctx->Array.NullBufferObj); + ctx->Shared->NullBufferObj); ASSERT(!exec->vtx.buffer_map); exec->vtx.buffer_map = (GLfloat *)ALIGN_MALLOC(VBO_VERT_BUFFER_SIZE, 64); diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c index 0d4cbe9a1e5..f4ad394f516 100644 --- a/src/mesa/vbo/vbo_exec_array.c +++ b/src/mesa/vbo/vbo_exec_array.c @@ -352,6 +352,13 @@ vbo_exec_DrawRangeElements(GLenum mode, if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count, type, indices )) return; + if (end >= ctx->Array._MaxElement) { + /* the max element is out of bounds of one or more enabled arrays */ + _mesa_warning(ctx, "glDraw[Range]Elements() index=%u is " + "out of bounds (max=%u)", end, ctx->Array._MaxElement); + return; + } + FLUSH_CURRENT( ctx, 0 ); if (ctx->NewState) diff --git a/src/mesa/vbo/vbo_rebase.c b/src/mesa/vbo/vbo_rebase.c index dae778e741e..ea87dede646 100644 --- a/src/mesa/vbo/vbo_rebase.c +++ b/src/mesa/vbo/vbo_rebase.c @@ -161,7 +161,7 @@ void vbo_rebase_prims( GLcontext *ctx, GL_ELEMENT_ARRAY_BUFFER, ib->obj); - tmp_ib.obj = ctx->Array.NullBufferObj; + tmp_ib.obj = ctx->Shared->NullBufferObj; tmp_ib.ptr = tmp_indices; tmp_ib.count = ib->count; tmp_ib.type = ib->type; diff --git a/src/mesa/vbo/vbo_split_copy.c b/src/mesa/vbo/vbo_split_copy.c index 5fb66d3318f..2f6a1998eaa 100644 --- a/src/mesa/vbo/vbo_split_copy.c +++ b/src/mesa/vbo/vbo_split_copy.c @@ -31,6 +31,7 @@ #include "main/glheader.h" #include "main/imports.h" +#include "main/image.h" #include "main/macros.h" #include "main/enums.h" #include "main/mtypes.h" @@ -41,7 +42,8 @@ #define ELT_TABLE_SIZE 16 -/* Used for vertex-level splitting of indexed buffers. Note that +/** + * Used for vertex-level splitting of indexed buffers. Note that * non-indexed primitives may be converted to indexed in some cases * (eg loops, fans) in order to use this splitting path. */ @@ -73,23 +75,21 @@ struct copy_context { GLuint *translated_elt_buf; const GLuint *srcelt; - /* A baby hash table to avoid re-emitting (some) duplicate + /** A baby hash table to avoid re-emitting (some) duplicate * vertices when splitting indexed primitives. */ struct { GLuint in; GLuint out; } vert_cache[ELT_TABLE_SIZE]; - GLuint vertex_size; GLubyte *dstbuf; - GLubyte *dstptr; /* dstptr == dstbuf + dstelt_max * vertsize */ - GLuint dstbuf_size; /* in vertices */ - GLuint dstbuf_nr; /* count of emitted vertices, also the - * largest value in dstelt. Our - * MaxIndex. - */ + GLubyte *dstptr; /**< dstptr == dstbuf + dstelt_max * vertsize */ + GLuint dstbuf_size; /**< in vertices */ + GLuint dstbuf_nr; /**< count of emitted vertices, also the largest value + * in dstelt. Our MaxIndex. + */ GLuint *dstelt; GLuint dstelt_nr; @@ -102,32 +102,19 @@ struct copy_context { }; -static GLuint type_size( GLenum type ) -{ - switch(type) { - case GL_BYTE: return sizeof(GLbyte); - case GL_UNSIGNED_BYTE: return sizeof(GLubyte); - case GL_SHORT: return sizeof(GLshort); - case GL_UNSIGNED_SHORT: return sizeof(GLushort); - case GL_INT: return sizeof(GLint); - case GL_UNSIGNED_INT: return sizeof(GLuint); - case GL_FLOAT: return sizeof(GLfloat); - case GL_DOUBLE: return sizeof(GLdouble); - default: return 0; - } -} - static GLuint attr_size( const struct gl_client_array *array ) { - return array->Size * type_size(array->Type); + return array->Size * _mesa_sizeof_type(array->Type); } -/* Starts returning true slightly before the buffer fills, to ensure +/** + * Starts returning true slightly before the buffer fills, to ensure * that there is sufficient room for any remaining vertices to finish * off the prim: */ -static GLboolean check_flush( struct copy_context *copy ) +static GLboolean +check_flush( struct copy_context *copy ) { GLenum mode = copy->dstprim[copy->dstprim_nr].mode; @@ -145,7 +132,9 @@ static GLboolean check_flush( struct copy_context *copy ) return GL_FALSE; } -static void flush( struct copy_context *copy ) + +static void +flush( struct copy_context *copy ) { GLuint i; @@ -175,8 +164,11 @@ static void flush( struct copy_context *copy ) } - -static void begin( struct copy_context *copy, GLenum mode, GLboolean begin_flag ) +/** + * Called at begin of each primitive during replay. + */ +static void +begin( struct copy_context *copy, GLenum mode, GLboolean begin_flag ) { struct _mesa_prim *prim = ©->dstprim[copy->dstprim_nr]; @@ -187,10 +179,12 @@ static void begin( struct copy_context *copy, GLenum mode, GLboolean begin_flag } -/* Use a hashtable to attempt to identify recently-emitted vertices +/** + * Use a hashtable to attempt to identify recently-emitted vertices * and avoid re-emitting them. */ -static GLuint elt(struct copy_context *copy, GLuint elt_idx) +static GLuint +elt(struct copy_context *copy, GLuint elt_idx) { GLuint elt = copy->srcelt[elt_idx]; GLuint slot = elt & (ELT_TABLE_SIZE-1); @@ -222,7 +216,6 @@ static GLuint elt(struct copy_context *copy, GLuint elt_idx) _mesa_printf("%x ", f[j]); _mesa_printf("\n"); } - } copy->vert_cache[slot].in = elt; @@ -230,9 +223,8 @@ static GLuint elt(struct copy_context *copy, GLuint elt_idx) copy->dstptr += copy->vertex_size; assert(csr == copy->dstptr); - assert(copy->dstptr == (copy->dstbuf + - copy->dstbuf_nr * - copy->vertex_size)); + assert(copy->dstptr == (copy->dstbuf + + copy->dstbuf_nr * copy->vertex_size)); } /* else */ /* _mesa_printf(" --> reuse vertex\n"); */ @@ -242,7 +234,12 @@ static GLuint elt(struct copy_context *copy, GLuint elt_idx) return check_flush(copy); } -static void end( struct copy_context *copy, GLboolean end_flag ) + +/** + * Called at end of each primitive during replay. + */ +static void +end( struct copy_context *copy, GLboolean end_flag ) { struct _mesa_prim *prim = ©->dstprim[copy->dstprim_nr]; @@ -257,8 +254,8 @@ static void end( struct copy_context *copy, GLboolean end_flag ) } - -static void replay_elts( struct copy_context *copy ) +static void +replay_elts( struct copy_context *copy ) { GLuint i, j, k; GLboolean split; @@ -362,7 +359,8 @@ static void replay_elts( struct copy_context *copy ) } -static void replay_init( struct copy_context *copy ) +static void +replay_init( struct copy_context *copy ) { GLcontext *ctx = copy->ctx; GLuint i; @@ -388,10 +386,7 @@ static void replay_init( struct copy_context *copy ) copy->vertex_size += attr_size(copy->array[i]); if (vbo->Name && !vbo->Pointer) - ctx->Driver.MapBuffer(ctx, - GL_ARRAY_BUFFER_ARB, - GL_WRITE_ONLY, /* XXX */ - vbo); + ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER, GL_READ_ONLY, vbo); copy->varying[j].src_ptr = ADD_POINTERS(vbo->Pointer, copy->array[i]->Ptr); @@ -405,12 +400,11 @@ static void replay_init( struct copy_context *copy ) * do it internally. */ if (copy->ib->obj->Name && !copy->ib->obj->Pointer) - ctx->Driver.MapBuffer(ctx, - GL_ARRAY_BUFFER_ARB, /* XXX */ - GL_WRITE_ONLY, /* XXX */ + ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY, copy->ib->obj); - srcptr = (const GLubyte *)ADD_POINTERS(copy->ib->obj->Pointer, copy->ib->ptr); + srcptr = (const GLubyte *) ADD_POINTERS(copy->ib->obj->Pointer, + copy->ib->ptr); switch (copy->ib->type) { case GL_UNSIGNED_BYTE: @@ -434,7 +428,6 @@ static void replay_init( struct copy_context *copy ) copy->srcelt = (const GLuint *)srcptr; break; } - /* Figure out the maximum allowed vertex buffer size: */ @@ -449,8 +442,7 @@ static void replay_init( struct copy_context *copy ) * * XXX: This should be a VBO! */ - copy->dstbuf = _mesa_malloc(copy->dstbuf_size * - copy->vertex_size); + copy->dstbuf = _mesa_malloc(copy->dstbuf_size * copy->vertex_size); copy->dstptr = copy->dstbuf; /* Setup new vertex arrays to point into the output buffer: @@ -467,7 +459,7 @@ static void replay_init( struct copy_context *copy ) dst->Ptr = copy->dstbuf + offset; dst->Enabled = GL_TRUE; dst->Normalized = src->Normalized; - dst->BufferObj = ctx->Array.NullBufferObj; + dst->BufferObj = ctx->Shared->NullBufferObj; dst->_MaxElement = copy->dstbuf_size; /* may be less! */ offset += copy->varying[i].size; @@ -487,12 +479,16 @@ static void replay_init( struct copy_context *copy ) */ copy->dstib.count = 0; /* duplicates dstelt_nr */ copy->dstib.type = GL_UNSIGNED_INT; - copy->dstib.obj = ctx->Array.NullBufferObj; + copy->dstib.obj = ctx->Shared->NullBufferObj; copy->dstib.ptr = copy->dstelt; } -static void replay_finish( struct copy_context *copy ) +/** + * Free up everything allocated during split/replay. + */ +static void +replay_finish( struct copy_context *copy ) { GLcontext *ctx = copy->ctx; GLuint i; @@ -502,25 +498,26 @@ static void replay_finish( struct copy_context *copy ) _mesa_free(copy->translated_elt_buf); _mesa_free(copy->dstbuf); _mesa_free(copy->dstelt); - + /* Unmap VBO's */ for (i = 0; i < copy->nr_varying; i++) { struct gl_buffer_object *vbo = copy->varying[i].array->BufferObj; - if (vbo->Name && vbo->Pointer) - ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, vbo); + ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, vbo); } /* Unmap index buffer: */ if (copy->ib->obj->Name && copy->ib->obj->Pointer) { - ctx->Driver.UnmapBuffer(ctx, - GL_ARRAY_BUFFER_ARB, /* XXX */ - copy->ib->obj); + ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, copy->ib->obj); } } + +/** + * Split VBO into smaller pieces, draw the pieces. + */ void vbo_split_copy( GLcontext *ctx, const struct gl_client_array *arrays[], const struct _mesa_prim *prim, @@ -546,13 +543,11 @@ void vbo_split_copy( GLcontext *ctx, copy.draw = draw; copy.limits = limits; - /* Clear the vertex cache: */ for (i = 0; i < ELT_TABLE_SIZE; i++) copy.vert_cache[i].in = ~0; - replay_init(©); replay_elts(©); replay_finish(©); diff --git a/src/mesa/vbo/vbo_split_inplace.c b/src/mesa/vbo/vbo_split_inplace.c index fbc856e93b0..3ed6b34fbf0 100644 --- a/src/mesa/vbo/vbo_split_inplace.c +++ b/src/mesa/vbo/vbo_split_inplace.c @@ -221,7 +221,7 @@ static void split_prims( struct split_context *split) ib.count = count; ib.type = GL_UNSIGNED_INT; - ib.obj = split->ctx->Array.NullBufferObj; + ib.obj = split->ctx->Shared->NullBufferObj; ib.ptr = elts; tmpprim = *prim; |