/* May fail if out of video memory for texture or vbo upload, or on * fallback conditions. */ static bool brw_try_draw_prims( struct gl_context *ctx, const struct gl_client_array *arrays[], const struct _mesa_prim *prim, GLuint nr_prims, const struct _mesa_index_buffer *ib, GLuint min_index, GLuint max_index ) { struct intel_context *intel = intel_context(ctx); struct brw_context *brw = brw_context(ctx); bool retval = true; GLuint i; bool fail_next = false; if (ctx->NewState) _mesa_update_state( ctx ); /* We have to validate the textures *before* checking for fallbacks; * otherwise, the software fallback won't be able to rely on the * texture state, the firstLevel and lastLevel fields won't be * set in the intel texture object (they'll both be 0), and the * software fallback will segfault if it attempts to access any * texture level other than level 0. */ brw_validate_textures( brw ); /* Resolves must occur after updating state and finalizing textures but * before setting up any hardware state for this draw call. */ brw_predraw_resolve_buffers(brw); /* Bind all inputs, derive varying and size information: */ brw_merge_inputs( brw, arrays ); brw->ib.ib = ib; brw->state.dirty.brw |= BRW_NEW_INDICES; brw->vb.min_index = min_index; brw->vb.max_index = max_index; brw->state.dirty.brw |= BRW_NEW_VERTICES; /* Have to validate state quite late. Will rebuild tnl_program, * which depends on varying information. * * Note this is where brw->vs->prog_data.inputs_read is calculated, * so can't access it earlier. */ intel_prepare_render(intel); for (i = 0; i < nr_prims; i++) { int estimated_max_prim_size; estimated_max_prim_size = 512; /* batchbuffer commands */ estimated_max_prim_size += (BRW_MAX_TEX_UNIT * (sizeof(struct brw_sampler_state) + sizeof(struct gen5_sampler_default_color))); estimated_max_prim_size += 1024; /* gen6 VS push constants */ estimated_max_prim_size += 1024; /* gen6 WM push constants */ estimated_max_prim_size += 512; /* misc. pad */ /* Flush the batch if it's approaching full, so that we don't wrap while * we've got validated state that needs to be in the same batch as the * primitives. */ intel_batchbuffer_require_space(intel, estimated_max_prim_size, false); intel_batchbuffer_save_state(intel); if (intel->gen < 6) brw_set_prim(brw, &prim[i]); else gen6_set_prim(brw, &prim[i]); retry: /* Note that before the loop, brw->state.dirty.brw was set to != 0, and * that the state updated in the loop outside of this block is that in * *_set_prim or intel_batchbuffer_flush(), which only impacts * brw->state.dirty.brw. */ if (brw->state.dirty.brw) { intel->no_batch_wrap = true; brw_upload_state(brw); if (unlikely(brw->intel.Fallback)) { intel->no_batch_wrap = false; retval = false; goto out; } } if (intel->gen >= 7) gen7_emit_prim(brw, &prim[i], brw->primitive); else brw_emit_prim(brw, &prim[i], brw->primitive); intel->no_batch_wrap = false; if (dri_bufmgr_check_aperture_space(&intel->batch.bo, 1)) { if (!fail_next) { intel_batchbuffer_reset_to_saved(intel); intel_batchbuffer_flush(intel); fail_next = true; goto retry; } else { if (intel_batchbuffer_flush(intel) == -ENOSPC) { static bool warned = false; if (!warned) { fprintf(stderr, "i965: Single primitive emit exceeded" "available aperture space\n"); warned = true; } retval = false; } } } if (!_mesa_meta_in_progress(ctx)) brw_update_primitive_count(brw, &prim[i]); } if (intel->always_flush_batch) intel_batchbuffer_flush(intel); out: brw_state_cache_check_size(brw); brw_postdraw_set_buffers_need_resolve(brw); return retval; }
static inline void brw_upload_pipeline_state(struct brw_context *brw, enum brw_pipeline pipeline) { struct gl_context *ctx = &brw->ctx; int i; static int dirty_count = 0; struct brw_state_flags state = brw->state.pipelines[pipeline]; unsigned int fb_samples = _mesa_geometric_samples(ctx->DrawBuffer); brw_select_pipeline(brw, pipeline); if (0) { /* Always re-emit all state. */ brw->NewGLState = ~0; ctx->NewDriverState = ~0ull; } if (pipeline == BRW_RENDER_PIPELINE) { if (brw->fragment_program != ctx->FragmentProgram._Current) { brw->fragment_program = ctx->FragmentProgram._Current; brw->ctx.NewDriverState |= BRW_NEW_FRAGMENT_PROGRAM; } if (brw->tess_eval_program != ctx->TessEvalProgram._Current) { brw->tess_eval_program = ctx->TessEvalProgram._Current; brw->ctx.NewDriverState |= BRW_NEW_TESS_PROGRAMS; } if (brw->tess_ctrl_program != ctx->TessCtrlProgram._Current) { brw->tess_ctrl_program = ctx->TessCtrlProgram._Current; brw->ctx.NewDriverState |= BRW_NEW_TESS_PROGRAMS; } if (brw->geometry_program != ctx->GeometryProgram._Current) { brw->geometry_program = ctx->GeometryProgram._Current; brw->ctx.NewDriverState |= BRW_NEW_GEOMETRY_PROGRAM; } if (brw->vertex_program != ctx->VertexProgram._Current) { brw->vertex_program = ctx->VertexProgram._Current; brw->ctx.NewDriverState |= BRW_NEW_VERTEX_PROGRAM; } } if (brw->compute_program != ctx->ComputeProgram._Current) { brw->compute_program = ctx->ComputeProgram._Current; brw->ctx.NewDriverState |= BRW_NEW_COMPUTE_PROGRAM; } if (brw->meta_in_progress != _mesa_meta_in_progress(ctx)) { brw->meta_in_progress = _mesa_meta_in_progress(ctx); brw->ctx.NewDriverState |= BRW_NEW_META_IN_PROGRESS; } if (brw->num_samples != fb_samples) { brw->num_samples = fb_samples; brw->ctx.NewDriverState |= BRW_NEW_NUM_SAMPLES; } /* Exit early if no state is flagged as dirty */ merge_ctx_state(brw, &state); if ((state.mesa | state.brw) == 0) return; /* Emit Sandybridge workaround flushes on every primitive, for safety. */ if (brw->gen == 6) brw_emit_post_sync_nonzero_flush(brw); brw_upload_programs(brw, pipeline); merge_ctx_state(brw, &state); const struct brw_tracked_state *atoms = brw_get_pipeline_atoms(brw, pipeline); const int num_atoms = brw->num_atoms[pipeline]; if (unlikely(INTEL_DEBUG)) { /* Debug version which enforces various sanity checks on the * state flags which are generated and checked to help ensure * state atoms are ordered correctly in the list. */ struct brw_state_flags examined, prev; memset(&examined, 0, sizeof(examined)); prev = state; for (i = 0; i < num_atoms; i++) { const struct brw_tracked_state *atom = &atoms[i]; struct brw_state_flags generated; check_and_emit_atom(brw, &state, atom); accumulate_state(&examined, &atom->dirty); /* generated = (prev ^ state) * if (examined & generated) * fail; */ xor_states(&generated, &prev, &state); assert(!check_state(&examined, &generated)); prev = state; } } else { for (i = 0; i < num_atoms; i++) { const struct brw_tracked_state *atom = &atoms[i]; check_and_emit_atom(brw, &state, atom); } } if (unlikely(INTEL_DEBUG & DEBUG_STATE)) { STATIC_ASSERT(ARRAY_SIZE(brw_bits) == BRW_NUM_STATE_BITS + 1); brw_update_dirty_count(mesa_bits, state.mesa); brw_update_dirty_count(brw_bits, state.brw); if (dirty_count++ % 1000 == 0) { brw_print_dirty_count(mesa_bits); brw_print_dirty_count(brw_bits); fprintf(stderr, "\n"); } } }
/*********************************************************************** * Emit all state: */ void brw_upload_state(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; struct brw_state_flags *state = &brw->state.dirty; int i; static int dirty_count = 0; state->mesa |= brw->NewGLState; brw->NewGLState = 0; state->brw |= ctx->NewDriverState; ctx->NewDriverState = 0; if (0) { /* Always re-emit all state. */ state->mesa |= ~0; state->brw |= ~0ull; } if (brw->fragment_program != ctx->FragmentProgram._Current) { brw->fragment_program = ctx->FragmentProgram._Current; brw->state.dirty.brw |= BRW_NEW_FRAGMENT_PROGRAM; } if (brw->geometry_program != ctx->GeometryProgram._Current) { brw->geometry_program = ctx->GeometryProgram._Current; brw->state.dirty.brw |= BRW_NEW_GEOMETRY_PROGRAM; } if (brw->vertex_program != ctx->VertexProgram._Current) { brw->vertex_program = ctx->VertexProgram._Current; brw->state.dirty.brw |= BRW_NEW_VERTEX_PROGRAM; } if (brw->meta_in_progress != _mesa_meta_in_progress(ctx)) { brw->meta_in_progress = _mesa_meta_in_progress(ctx); brw->state.dirty.brw |= BRW_NEW_META_IN_PROGRESS; } if (brw->num_samples != ctx->DrawBuffer->Visual.samples) { brw->num_samples = ctx->DrawBuffer->Visual.samples; brw->state.dirty.brw |= BRW_NEW_NUM_SAMPLES; } if ((state->mesa | state->brw) == 0) return; if (unlikely(INTEL_DEBUG)) { /* Debug version which enforces various sanity checks on the * state flags which are generated and checked to help ensure * state atoms are ordered correctly in the list. */ struct brw_state_flags examined, prev; memset(&examined, 0, sizeof(examined)); prev = *state; for (i = 0; i < brw->num_atoms; i++) { const struct brw_tracked_state *atom = brw->atoms[i]; struct brw_state_flags generated; if (check_state(state, &atom->dirty)) { atom->emit(brw); } accumulate_state(&examined, &atom->dirty); /* generated = (prev ^ state) * if (examined & generated) * fail; */ xor_states(&generated, &prev, state); assert(!check_state(&examined, &generated)); prev = *state; } } else { for (i = 0; i < brw->num_atoms; i++) { const struct brw_tracked_state *atom = brw->atoms[i]; if (check_state(state, &atom->dirty)) { atom->emit(brw); } } } if (unlikely(INTEL_DEBUG & DEBUG_STATE)) { STATIC_ASSERT(ARRAY_SIZE(brw_bits) == BRW_NUM_STATE_BITS + 1); brw_update_dirty_count(mesa_bits, state->mesa); brw_update_dirty_count(brw_bits, state->brw); if (dirty_count++ % 1000 == 0) { brw_print_dirty_count(mesa_bits); brw_print_dirty_count(brw_bits); fprintf(stderr, "\n"); } } }