/* Gets the minimum number of shader invocations per fragment. * This function is useful to determine if we need to do per * sample shading or per fragment shading. */ GLint _mesa_get_min_invocations_per_fragment(struct gl_context *ctx, const struct gl_program *prog, bool ignore_sample_qualifier) { /* From ARB_sample_shading specification: * "Using gl_SampleID in a fragment shader causes the entire shader * to be evaluated per-sample." * * "Using gl_SamplePosition in a fragment shader causes the entire * shader to be evaluated per-sample." * * "If MULTISAMPLE or SAMPLE_SHADING_ARB is disabled, sample shading * has no effect." */ if (ctx->Multisample.Enabled) { /* The ARB_gpu_shader5 specification says: * * "Use of the "sample" qualifier on a fragment shader input * forces per-sample shading" */ if (prog->info.fs.uses_sample_qualifier && !ignore_sample_qualifier) return MAX2(_mesa_geometric_samples(ctx->DrawBuffer), 1); if (prog->info.system_values_read & (SYSTEM_BIT_SAMPLE_ID | SYSTEM_BIT_SAMPLE_POS)) return MAX2(_mesa_geometric_samples(ctx->DrawBuffer), 1); else if (ctx->Multisample.SampleShading) return MAX2(ceil(ctx->Multisample.MinSampleShadingValue * _mesa_geometric_samples(ctx->DrawBuffer)), 1); else return 1; } return 1; }
static void upload_wm_state(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; /* BRW_NEW_FS_PROG_DATA */ const struct brw_wm_prog_data *prog_data = brw->wm.prog_data; /* _NEW_BUFFERS */ const bool multisampled_fbo = _mesa_geometric_samples(ctx->DrawBuffer) > 1; /* BRW_NEW_FS_PROG_DATA | _NEW_COLOR */ const bool dual_src_blend_enable = prog_data->dual_src_blend && (ctx->Color.BlendEnabled & 1) && ctx->Color.Blend[0]._UsesDualSrc; /* _NEW_COLOR, _NEW_MULTISAMPLE */ const bool kill_enable = prog_data->uses_kill || ctx->Color.AlphaEnabled || ctx->Multisample.SampleAlphaToCoverage || prog_data->uses_omask; /* Rendering against the gl-context is always taken into account. */ const bool statistic_enable = true; /* _NEW_LINE | _NEW_POLYGON | _NEW_BUFFERS | _NEW_COLOR | * _NEW_MULTISAMPLE */ gen6_upload_wm_state(brw, prog_data, &brw->wm.base, multisampled_fbo, dual_src_blend_enable, kill_enable, brw_color_buffer_write_enabled(brw), ctx->Multisample.Enabled, ctx->Line.StippleFlag, ctx->Polygon.StippleFlag, statistic_enable); }
static void upload_wm_state(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; /* BRW_NEW_FRAGMENT_PROGRAM */ const struct brw_fragment_program *fp = brw_fragment_program_const(brw->fragment_program); /* BRW_NEW_FS_PROG_DATA */ const struct brw_wm_prog_data *prog_data = brw->wm.prog_data; /* _NEW_BUFFERS */ const bool multisampled_fbo = _mesa_geometric_samples(ctx->DrawBuffer) > 1; /* In case of non 1x per sample shading, only one of SIMD8 and SIMD16 * should be enabled. We do 'SIMD16 only' dispatch if a SIMD16 shader * is successfully compiled. In majority of the cases that bring us * better performance than 'SIMD8 only' dispatch. */ const int min_inv_per_frag = _mesa_get_min_invocations_per_fragment( ctx, brw->fragment_program, false); /* BRW_NEW_FS_PROG_DATA | _NEW_COLOR */ const bool dual_src_blend_enable = prog_data->dual_src_blend && (ctx->Color.BlendEnabled & 1) && ctx->Color.Blend[0]._UsesDualSrc; /* _NEW_COLOR, _NEW_MULTISAMPLE */ const bool kill_enable = prog_data->uses_kill || ctx->Color.AlphaEnabled || ctx->Multisample.SampleAlphaToCoverage || prog_data->uses_omask; /* Rendering against the gl-context is always taken into account. */ const bool statistic_enable = true; /* _NEW_LINE | _NEW_POLYGON | _NEW_BUFFERS | _NEW_COLOR | * _NEW_MULTISAMPLE */ gen6_upload_wm_state(brw, fp, prog_data, &brw->wm.base, multisampled_fbo, min_inv_per_frag, dual_src_blend_enable, kill_enable, brw_color_buffer_write_enabled(brw), ctx->Multisample.Enabled, ctx->Line.StippleFlag, ctx->Polygon.StippleFlag, statistic_enable); }
/** * Update fragment program state/atom. This involves translating the * Mesa fragment program into a gallium fragment program and binding it. */ static void update_fp( struct st_context *st ) { struct st_fragment_program *stfp; struct st_fp_variant_key key; assert(st->ctx->FragmentProgram._Current); stfp = st_fragment_program(st->ctx->FragmentProgram._Current); assert(stfp->Base.Base.Target == GL_FRAGMENT_PROGRAM_ARB); memset(&key, 0, sizeof(key)); key.st = st->has_shareable_shaders ? NULL : st; /* _NEW_FRAG_CLAMP */ key.clamp_color = st->clamp_frag_color_in_shader && st->ctx->Color._ClampFragmentColor; /* _NEW_MULTISAMPLE | _NEW_BUFFERS */ key.persample_shading = st->force_persample_in_shader && _mesa_is_multisample_enabled(st->ctx) && st->ctx->Multisample.SampleShading && st->ctx->Multisample.MinSampleShadingValue * _mesa_geometric_samples(st->ctx->DrawBuffer) > 1; if (stfp->ati_fs) { unsigned u; if (st->ctx->Fog.Enabled) { key.fog = translate_fog_mode(st->ctx->Fog.Mode); } for (u = 0; u < MAX_NUM_FRAGMENT_REGISTERS_ATI; u++) { key.texture_targets[u] = get_texture_target(st->ctx, u); } } st->fp_variant = st_get_fp_variant(st, stfp, &key); st_reference_fragprog(st, &st->fp, stfp); cso_set_fragment_shader_handle(st->cso_context, st->fp_variant->driver_shader); }
void brw_wm_populate_key(struct brw_context *brw, struct brw_wm_prog_key *key) { const struct gen_device_info *devinfo = &brw->screen->devinfo; struct gl_context *ctx = &brw->ctx; /* BRW_NEW_FRAGMENT_PROGRAM */ const struct gl_program *prog = brw->programs[MESA_SHADER_FRAGMENT]; const struct brw_program *fp = brw_program_const(prog); GLuint lookup = 0; GLuint line_aa; memset(key, 0, sizeof(*key)); /* Build the index for table lookup */ if (devinfo->gen < 6) { struct intel_renderbuffer *depth_irb = intel_get_renderbuffer(ctx->DrawBuffer, BUFFER_DEPTH); /* _NEW_COLOR */ if (prog->info.fs.uses_discard || ctx->Color.AlphaEnabled) { lookup |= BRW_WM_IZ_PS_KILL_ALPHATEST_BIT; } if (prog->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) { lookup |= BRW_WM_IZ_PS_COMPUTES_DEPTH_BIT; } /* _NEW_DEPTH */ if (depth_irb && ctx->Depth.Test) { lookup |= BRW_WM_IZ_DEPTH_TEST_ENABLE_BIT; if (brw_depth_writes_enabled(brw)) lookup |= BRW_WM_IZ_DEPTH_WRITE_ENABLE_BIT; } /* _NEW_STENCIL | _NEW_BUFFERS */ if (brw->stencil_enabled) { lookup |= BRW_WM_IZ_STENCIL_TEST_ENABLE_BIT; if (ctx->Stencil.WriteMask[0] || ctx->Stencil.WriteMask[ctx->Stencil._BackFace]) lookup |= BRW_WM_IZ_STENCIL_WRITE_ENABLE_BIT; } key->iz_lookup = lookup; } line_aa = BRW_WM_AA_NEVER; /* _NEW_LINE, _NEW_POLYGON, BRW_NEW_REDUCED_PRIMITIVE */ if (ctx->Line.SmoothFlag) { if (brw->reduced_primitive == GL_LINES) { line_aa = BRW_WM_AA_ALWAYS; } else if (brw->reduced_primitive == GL_TRIANGLES) { if (ctx->Polygon.FrontMode == GL_LINE) { line_aa = BRW_WM_AA_SOMETIMES; if (ctx->Polygon.BackMode == GL_LINE || (ctx->Polygon.CullFlag && ctx->Polygon.CullFaceMode == GL_BACK)) line_aa = BRW_WM_AA_ALWAYS; } else if (ctx->Polygon.BackMode == GL_LINE) { line_aa = BRW_WM_AA_SOMETIMES; if ((ctx->Polygon.CullFlag && ctx->Polygon.CullFaceMode == GL_FRONT)) line_aa = BRW_WM_AA_ALWAYS; } } } key->line_aa = line_aa; /* _NEW_HINT */ key->high_quality_derivatives = prog->info.uses_fddx_fddy && ctx->Hint.FragmentShaderDerivative == GL_NICEST; if (devinfo->gen < 6) key->stats_wm = brw->stats_wm; /* _NEW_LIGHT */ key->flat_shade = (prog->info.inputs_read & (VARYING_BIT_COL0 | VARYING_BIT_COL1)) && (ctx->Light.ShadeModel == GL_FLAT); /* _NEW_FRAG_CLAMP | _NEW_BUFFERS */ key->clamp_fragment_color = ctx->Color._ClampFragmentColor; /* _NEW_TEXTURE */ brw_populate_sampler_prog_key_data(ctx, prog, &key->tex); /* _NEW_BUFFERS */ key->nr_color_regions = ctx->DrawBuffer->_NumColorDrawBuffers; /* _NEW_COLOR */ key->force_dual_color_blend = brw->dual_color_blend_by_location && (ctx->Color.BlendEnabled & 1) && ctx->Color.Blend[0]._UsesDualSrc; /* _NEW_MULTISAMPLE, _NEW_BUFFERS */ key->alpha_to_coverage = _mesa_is_alpha_to_coverage_enabled(ctx); /* _NEW_COLOR, _NEW_BUFFERS */ key->alpha_test_replicate_alpha = ctx->DrawBuffer->_NumColorDrawBuffers > 1 && _mesa_is_alpha_test_enabled(ctx); /* _NEW_BUFFERS _NEW_MULTISAMPLE */ /* Ignore sample qualifier while computing this flag. */ if (ctx->Multisample.Enabled) { key->persample_interp = ctx->Multisample.SampleShading && (ctx->Multisample.MinSampleShadingValue * _mesa_geometric_samples(ctx->DrawBuffer) > 1); key->multisample_fbo = _mesa_geometric_samples(ctx->DrawBuffer) > 1; } /* BRW_NEW_VUE_MAP_GEOM_OUT */ if (devinfo->gen < 6 || util_bitcount64(prog->info.inputs_read & BRW_FS_VARYING_INPUT_MASK) > 16) { key->input_slots_valid = brw->vue_map_geom_out.slots_valid; } /* _NEW_COLOR | _NEW_BUFFERS */ /* Pre-gen6, the hardware alpha test always used each render * target's alpha to do alpha test, as opposed to render target 0's alpha * like GL requires. Fix that by building the alpha test into the * shader, and we'll skip enabling the fixed function alpha test. */ if (devinfo->gen < 6 && ctx->DrawBuffer->_NumColorDrawBuffers > 1 && ctx->Color.AlphaEnabled) { key->alpha_test_func = ctx->Color.AlphaFunc; key->alpha_test_ref = ctx->Color.AlphaRef; } /* The unique fragment program ID */ key->program_string_id = fp->id; /* Whether reads from the framebuffer should behave coherently. */ key->coherent_fb_fetch = ctx->Extensions.EXT_shader_framebuffer_fetch; }
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"); } } }
static void brw_wm_populate_key(struct brw_context *brw, struct brw_wm_prog_key *key) { struct gl_context *ctx = &brw->ctx; /* BRW_NEW_FRAGMENT_PROGRAM */ const struct brw_fragment_program *fp = (struct brw_fragment_program *) brw->fragment_program; const struct gl_program *prog = (struct gl_program *) brw->fragment_program; GLuint lookup = 0; GLuint line_aa; bool program_uses_dfdy = fp->program.UsesDFdy; const bool multisample_fbo = _mesa_geometric_samples(ctx->DrawBuffer) > 1; memset(key, 0, sizeof(*key)); /* Build the index for table lookup */ if (brw->gen < 6) { /* _NEW_COLOR */ if (fp->program.UsesKill || ctx->Color.AlphaEnabled) lookup |= IZ_PS_KILL_ALPHATEST_BIT; if (fp->program.Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) lookup |= IZ_PS_COMPUTES_DEPTH_BIT; /* _NEW_DEPTH */ if (ctx->Depth.Test) lookup |= IZ_DEPTH_TEST_ENABLE_BIT; if (ctx->Depth.Test && ctx->Depth.Mask) /* ?? */ lookup |= IZ_DEPTH_WRITE_ENABLE_BIT; /* _NEW_STENCIL | _NEW_BUFFERS */ if (ctx->Stencil._Enabled) { lookup |= IZ_STENCIL_TEST_ENABLE_BIT; if (ctx->Stencil.WriteMask[0] || ctx->Stencil.WriteMask[ctx->Stencil._BackFace]) lookup |= IZ_STENCIL_WRITE_ENABLE_BIT; } key->iz_lookup = lookup; } line_aa = AA_NEVER; /* _NEW_LINE, _NEW_POLYGON, BRW_NEW_REDUCED_PRIMITIVE */ if (ctx->Line.SmoothFlag) { if (brw->reduced_primitive == GL_LINES) { line_aa = AA_ALWAYS; } else if (brw->reduced_primitive == GL_TRIANGLES) { if (ctx->Polygon.FrontMode == GL_LINE) { line_aa = AA_SOMETIMES; if (ctx->Polygon.BackMode == GL_LINE || (ctx->Polygon.CullFlag && ctx->Polygon.CullFaceMode == GL_BACK)) line_aa = AA_ALWAYS; } else if (ctx->Polygon.BackMode == GL_LINE) { line_aa = AA_SOMETIMES; if ((ctx->Polygon.CullFlag && ctx->Polygon.CullFaceMode == GL_FRONT)) line_aa = AA_ALWAYS; } } } key->line_aa = line_aa; /* _NEW_HINT */ key->high_quality_derivatives = ctx->Hint.FragmentShaderDerivative == GL_NICEST; if (brw->gen < 6) key->stats_wm = brw->stats_wm; /* _NEW_LIGHT */ key->flat_shade = (ctx->Light.ShadeModel == GL_FLAT); /* _NEW_FRAG_CLAMP | _NEW_BUFFERS */ key->clamp_fragment_color = ctx->Color._ClampFragmentColor; /* _NEW_TEXTURE */ brw_populate_sampler_prog_key_data(ctx, prog, brw->wm.base.sampler_count, &key->tex); /* _NEW_BUFFERS */ /* * Include the draw buffer origin and height so that we can calculate * fragment position values relative to the bottom left of the drawable, * from the incoming screen origin relative position we get as part of our * payload. * * This is only needed for the WM_WPOSXY opcode when the fragment program * uses the gl_FragCoord input. * * We could avoid recompiling by including this as a constant referenced by * our program, but if we were to do that it would also be nice to handle * getting that constant updated at batchbuffer submit time (when we * hold the lock and know where the buffer really is) rather than at emit * time when we don't hold the lock and are just guessing. We could also * just avoid using this as key data if the program doesn't use * fragment.position. * * For DRI2 the origin_x/y will always be (0,0) but we still need the * drawable height in order to invert the Y axis. */ if (fp->program.Base.InputsRead & VARYING_BIT_POS) { key->drawable_height = _mesa_geometric_height(ctx->DrawBuffer); } if ((fp->program.Base.InputsRead & VARYING_BIT_POS) || program_uses_dfdy) { key->render_to_fbo = _mesa_is_user_fbo(ctx->DrawBuffer); } /* _NEW_BUFFERS */ key->nr_color_regions = ctx->DrawBuffer->_NumColorDrawBuffers; /* _NEW_MULTISAMPLE, _NEW_COLOR, _NEW_BUFFERS */ key->replicate_alpha = ctx->DrawBuffer->_NumColorDrawBuffers > 1 && (ctx->Multisample.SampleAlphaToCoverage || ctx->Color.AlphaEnabled); /* _NEW_BUFFERS _NEW_MULTISAMPLE */ /* Ignore sample qualifier while computing this flag. */ key->persample_shading = _mesa_get_min_invocations_per_fragment(ctx, &fp->program, true) > 1; if (key->persample_shading) key->persample_2x = _mesa_geometric_samples(ctx->DrawBuffer) == 2; key->compute_pos_offset = _mesa_get_min_invocations_per_fragment(ctx, &fp->program, false) > 1 && fp->program.Base.SystemValuesRead & SYSTEM_BIT_SAMPLE_POS; key->compute_sample_id = multisample_fbo && ctx->Multisample.Enabled && (fp->program.Base.SystemValuesRead & SYSTEM_BIT_SAMPLE_ID); /* BRW_NEW_VUE_MAP_GEOM_OUT */ if (brw->gen < 6 || _mesa_bitcount_64(fp->program.Base.InputsRead & BRW_FS_VARYING_INPUT_MASK) > 16) key->input_slots_valid = brw->vue_map_geom_out.slots_valid; /* _NEW_COLOR | _NEW_BUFFERS */ /* Pre-gen6, the hardware alpha test always used each render * target's alpha to do alpha test, as opposed to render target 0's alpha * like GL requires. Fix that by building the alpha test into the * shader, and we'll skip enabling the fixed function alpha test. */ if (brw->gen < 6 && ctx->DrawBuffer->_NumColorDrawBuffers > 1 && ctx->Color.AlphaEnabled) { key->alpha_test_func = ctx->Color.AlphaFunc; key->alpha_test_ref = ctx->Color.AlphaRef; } /* The unique fragment program ID */ key->program_string_id = fp->id; }
static void upload_wm_state(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; /* BRW_NEW_FS_PROG_DATA */ const struct brw_wm_prog_data *prog_data = brw_wm_prog_data(brw->wm.base.prog_data); bool writes_depth = prog_data->computed_depth_mode != BRW_PSCDEPTH_OFF; uint32_t dw1, dw2; /* _NEW_BUFFERS */ const bool multisampled_fbo = _mesa_geometric_samples(ctx->DrawBuffer) > 1; dw1 = dw2 = 0; dw1 |= GEN7_WM_STATISTICS_ENABLE; dw1 |= GEN7_WM_LINE_AA_WIDTH_1_0; dw1 |= GEN7_WM_LINE_END_CAP_AA_WIDTH_0_5; /* _NEW_LINE */ if (ctx->Line.StippleFlag) dw1 |= GEN7_WM_LINE_STIPPLE_ENABLE; /* _NEW_POLYGON */ if (ctx->Polygon.StippleFlag) dw1 |= GEN7_WM_POLYGON_STIPPLE_ENABLE; if (prog_data->uses_src_depth) dw1 |= GEN7_WM_USES_SOURCE_DEPTH; if (prog_data->uses_src_w) dw1 |= GEN7_WM_USES_SOURCE_W; dw1 |= prog_data->computed_depth_mode << GEN7_WM_COMPUTED_DEPTH_MODE_SHIFT; dw1 |= prog_data->barycentric_interp_modes << GEN7_WM_BARYCENTRIC_INTERPOLATION_MODE_SHIFT; /* _NEW_COLOR, _NEW_MULTISAMPLE _NEW_BUFFERS */ /* Enable if the pixel shader kernel generates and outputs oMask. */ if (prog_data->uses_kill || _mesa_is_alpha_test_enabled(ctx) || _mesa_is_alpha_to_coverage_enabled(ctx) || prog_data->uses_omask) { dw1 |= GEN7_WM_KILL_ENABLE; } /* _NEW_BUFFERS | _NEW_COLOR */ if (brw_color_buffer_write_enabled(brw) || writes_depth || prog_data->has_side_effects || dw1 & GEN7_WM_KILL_ENABLE) { dw1 |= GEN7_WM_DISPATCH_ENABLE; } if (multisampled_fbo) { /* _NEW_MULTISAMPLE */ if (ctx->Multisample.Enabled) dw1 |= GEN7_WM_MSRAST_ON_PATTERN; else dw1 |= GEN7_WM_MSRAST_OFF_PIXEL; if (prog_data->persample_dispatch) dw2 |= GEN7_WM_MSDISPMODE_PERSAMPLE; else dw2 |= GEN7_WM_MSDISPMODE_PERPIXEL; } else { dw1 |= GEN7_WM_MSRAST_OFF_PIXEL; dw2 |= GEN7_WM_MSDISPMODE_PERSAMPLE; } if (prog_data->uses_sample_mask) { dw1 |= GEN7_WM_USES_INPUT_COVERAGE_MASK; } /* BRW_NEW_FS_PROG_DATA */ if (prog_data->early_fragment_tests) dw1 |= GEN7_WM_EARLY_DS_CONTROL_PREPS; else if (prog_data->has_side_effects) dw1 |= GEN7_WM_EARLY_DS_CONTROL_PSEXEC; /* The "UAV access enable" bits are unnecessary on HSW because they only * seem to have an effect on the HW-assisted coherency mechanism which we * don't need, and the rasterization-related UAV_ONLY flag and the * DISPATCH_ENABLE bit can be set independently from it. * C.f. gen8_upload_ps_extra(). * * BRW_NEW_FRAGMENT_PROGRAM | BRW_NEW_FS_PROG_DATA | _NEW_BUFFERS | _NEW_COLOR */ if (brw->is_haswell && !(brw_color_buffer_write_enabled(brw) || writes_depth) && prog_data->has_side_effects) dw2 |= HSW_WM_UAV_ONLY; BEGIN_BATCH(3); OUT_BATCH(_3DSTATE_WM << 16 | (3 - 2)); OUT_BATCH(dw1); OUT_BATCH(dw2); ADVANCE_BATCH(); }
static void upload_wm_state(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; /* BRW_NEW_FRAGMENT_PROGRAM */ const struct brw_fragment_program *fp = brw_fragment_program_const(brw->fragment_program); /* BRW_NEW_FS_PROG_DATA */ const struct brw_wm_prog_data *prog_data = brw->wm.prog_data; bool writes_depth = prog_data->computed_depth_mode != BRW_PSCDEPTH_OFF; uint32_t dw1, dw2; /* _NEW_BUFFERS */ const bool multisampled_fbo = _mesa_geometric_samples(ctx->DrawBuffer) > 1; dw1 = dw2 = 0; dw1 |= GEN7_WM_STATISTICS_ENABLE; dw1 |= GEN7_WM_LINE_AA_WIDTH_1_0; dw1 |= GEN7_WM_LINE_END_CAP_AA_WIDTH_0_5; /* _NEW_LINE */ if (ctx->Line.StippleFlag) dw1 |= GEN7_WM_LINE_STIPPLE_ENABLE; /* _NEW_POLYGON */ if (ctx->Polygon.StippleFlag) dw1 |= GEN7_WM_POLYGON_STIPPLE_ENABLE; if (fp->program.Base.InputsRead & VARYING_BIT_POS) dw1 |= GEN7_WM_USES_SOURCE_DEPTH | GEN7_WM_USES_SOURCE_W; dw1 |= prog_data->computed_depth_mode << GEN7_WM_COMPUTED_DEPTH_MODE_SHIFT; dw1 |= prog_data->barycentric_interp_modes << GEN7_WM_BARYCENTRIC_INTERPOLATION_MODE_SHIFT; /* _NEW_COLOR, _NEW_MULTISAMPLE */ /* Enable if the pixel shader kernel generates and outputs oMask. */ if (prog_data->uses_kill || ctx->Color.AlphaEnabled || ctx->Multisample.SampleAlphaToCoverage || prog_data->uses_omask) { dw1 |= GEN7_WM_KILL_ENABLE; } if (_mesa_active_fragment_shader_has_atomic_ops(&brw->ctx)) { dw1 |= GEN7_WM_DISPATCH_ENABLE; } /* _NEW_BUFFERS | _NEW_COLOR */ if (brw_color_buffer_write_enabled(brw) || writes_depth || dw1 & GEN7_WM_KILL_ENABLE) { dw1 |= GEN7_WM_DISPATCH_ENABLE; } if (multisampled_fbo) { /* _NEW_MULTISAMPLE */ if (ctx->Multisample.Enabled) dw1 |= GEN7_WM_MSRAST_ON_PATTERN; else dw1 |= GEN7_WM_MSRAST_OFF_PIXEL; if (_mesa_get_min_invocations_per_fragment(ctx, brw->fragment_program, false) > 1) dw2 |= GEN7_WM_MSDISPMODE_PERSAMPLE; else dw2 |= GEN7_WM_MSDISPMODE_PERPIXEL; } else { dw1 |= GEN7_WM_MSRAST_OFF_PIXEL; dw2 |= GEN7_WM_MSDISPMODE_PERSAMPLE; } if (fp->program.Base.SystemValuesRead & SYSTEM_BIT_SAMPLE_MASK_IN) { dw1 |= GEN7_WM_USES_INPUT_COVERAGE_MASK; } BEGIN_BATCH(3); OUT_BATCH(_3DSTATE_WM << 16 | (3 - 2)); OUT_BATCH(dw1); OUT_BATCH(dw2); ADVANCE_BATCH(); }
/** * Update framebuffer state (color, depth, stencil, etc. buffers) */ void st_update_framebuffer_state( struct st_context *st ) { struct pipe_framebuffer_state framebuffer; struct gl_framebuffer *fb = st->ctx->DrawBuffer; struct st_renderbuffer *strb; GLuint i; st_flush_bitmap_cache(st); st_invalidate_readpix_cache(st); st->state.fb_orientation = st_fb_orientation(fb); /** * Quantize the derived default number of samples: * * A query to the driver of supported MSAA values the * hardware supports is done as to legalize the number * of application requested samples, NumSamples. * See commit eb9cf3c for more information. */ fb->DefaultGeometry._NumSamples = framebuffer_quantize_num_samples(st, fb->DefaultGeometry.NumSamples); framebuffer.width = _mesa_geometric_width(fb); framebuffer.height = _mesa_geometric_height(fb); framebuffer.samples = _mesa_geometric_samples(fb); framebuffer.layers = _mesa_geometric_layers(fb); /* Examine Mesa's ctx->DrawBuffer->_ColorDrawBuffers state * to determine which surfaces to draw to */ framebuffer.nr_cbufs = fb->_NumColorDrawBuffers; for (i = 0; i < fb->_NumColorDrawBuffers; i++) { framebuffer.cbufs[i] = NULL; strb = st_renderbuffer(fb->_ColorDrawBuffers[i]); if (strb) { if (strb->is_rtt || (strb->texture && _mesa_get_format_color_encoding(strb->Base.Format) == GL_SRGB)) { /* rendering to a GL texture, may have to update surface */ st_update_renderbuffer_surface(st, strb); } if (strb->surface) { framebuffer.cbufs[i] = strb->surface; update_framebuffer_size(&framebuffer, strb->surface); } strb->defined = GL_TRUE; /* we'll be drawing something */ } } for (i = framebuffer.nr_cbufs; i < PIPE_MAX_COLOR_BUFS; i++) { framebuffer.cbufs[i] = NULL; } /* Remove trailing GL_NONE draw buffers. */ while (framebuffer.nr_cbufs && !framebuffer.cbufs[framebuffer.nr_cbufs-1]) { framebuffer.nr_cbufs--; } /* * Depth/Stencil renderbuffer/surface. */ strb = st_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer); if (!strb) strb = st_renderbuffer(fb->Attachment[BUFFER_STENCIL].Renderbuffer); if (strb) { if (strb->is_rtt) { /* rendering to a GL texture, may have to update surface */ st_update_renderbuffer_surface(st, strb); } framebuffer.zsbuf = strb->surface; update_framebuffer_size(&framebuffer, strb->surface); } else framebuffer.zsbuf = NULL; #ifdef DEBUG /* Make sure the resource binding flags were set properly */ for (i = 0; i < framebuffer.nr_cbufs; i++) { assert(!framebuffer.cbufs[i] || framebuffer.cbufs[i]->texture->bind & PIPE_BIND_RENDER_TARGET); } if (framebuffer.zsbuf) { assert(framebuffer.zsbuf->texture->bind & PIPE_BIND_DEPTH_STENCIL); } #endif if (framebuffer.width == USHRT_MAX) framebuffer.width = 0; if (framebuffer.height == USHRT_MAX) framebuffer.height = 0; cso_set_framebuffer(st->cso_context, &framebuffer); st->state.fb_width = framebuffer.width; st->state.fb_height = framebuffer.height; st->state.fb_num_samples = util_framebuffer_get_num_samples(&framebuffer); st->state.fb_num_layers = util_framebuffer_get_num_layers(&framebuffer); st->state.fb_num_cb = framebuffer.nr_cbufs; }
static void upload_sf_state(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; uint32_t dw1, dw2, dw3; float point_size; /* _NEW_BUFFERS */ bool render_to_fbo = _mesa_is_user_fbo(ctx->DrawBuffer); const bool multisampled_fbo = _mesa_geometric_samples(ctx->DrawBuffer) > 1; dw1 = GEN6_SF_STATISTICS_ENABLE; if (brw->sf.viewport_transform_enable) dw1 |= GEN6_SF_VIEWPORT_TRANSFORM_ENABLE; /* _NEW_BUFFERS */ dw1 |= (brw_depthbuffer_format(brw) << GEN7_SF_DEPTH_BUFFER_SURFACE_FORMAT_SHIFT); /* _NEW_POLYGON */ if (ctx->Polygon._FrontBit == render_to_fbo) dw1 |= GEN6_SF_WINDING_CCW; if (ctx->Polygon.OffsetFill) dw1 |= GEN6_SF_GLOBAL_DEPTH_OFFSET_SOLID; if (ctx->Polygon.OffsetLine) dw1 |= GEN6_SF_GLOBAL_DEPTH_OFFSET_WIREFRAME; if (ctx->Polygon.OffsetPoint) dw1 |= GEN6_SF_GLOBAL_DEPTH_OFFSET_POINT; switch (ctx->Polygon.FrontMode) { case GL_FILL: dw1 |= GEN6_SF_FRONT_SOLID; break; case GL_LINE: dw1 |= GEN6_SF_FRONT_WIREFRAME; break; case GL_POINT: dw1 |= GEN6_SF_FRONT_POINT; break; default: unreachable("not reached"); } switch (ctx->Polygon.BackMode) { case GL_FILL: dw1 |= GEN6_SF_BACK_SOLID; break; case GL_LINE: dw1 |= GEN6_SF_BACK_WIREFRAME; break; case GL_POINT: dw1 |= GEN6_SF_BACK_POINT; break; default: unreachable("not reached"); } dw2 = 0; if (ctx->Polygon.CullFlag) { switch (ctx->Polygon.CullFaceMode) { case GL_FRONT: dw2 |= GEN6_SF_CULL_FRONT; break; case GL_BACK: dw2 |= GEN6_SF_CULL_BACK; break; case GL_FRONT_AND_BACK: dw2 |= GEN6_SF_CULL_BOTH; break; default: unreachable("not reached"); } } else { dw2 |= GEN6_SF_CULL_NONE; } /* _NEW_SCISSOR _NEW_POLYGON BRW_NEW_GEOMETRY_PROGRAM BRW_NEW_PRIMITIVE */ if (ctx->Scissor.EnableFlags || is_drawing_points(brw) || is_drawing_lines(brw)) dw2 |= GEN6_SF_SCISSOR_ENABLE; /* _NEW_LINE */ { uint32_t line_width_u3_7 = brw_get_line_width(brw); dw2 |= line_width_u3_7 << GEN6_SF_LINE_WIDTH_SHIFT; } if (ctx->Line.SmoothFlag) { dw2 |= GEN6_SF_LINE_AA_ENABLE; dw2 |= GEN6_SF_LINE_END_CAP_WIDTH_1_0; } if (ctx->Line.StippleFlag && brw->is_haswell) { dw2 |= HSW_SF_LINE_STIPPLE_ENABLE; } /* _NEW_MULTISAMPLE */ if (multisampled_fbo && ctx->Multisample.Enabled) dw2 |= GEN6_SF_MSRAST_ON_PATTERN; /* FINISHME: Last Pixel Enable? Vertex Sub Pixel Precision Select? */ dw3 = GEN6_SF_LINE_AA_MODE_TRUE; /* _NEW_PROGRAM | _NEW_POINT */ if (!(ctx->VertexProgram.PointSizeEnabled || ctx->Point._Attenuated)) dw3 |= GEN6_SF_USE_STATE_POINT_WIDTH; /* Clamp to ARB_point_parameters user limits */ point_size = CLAMP(ctx->Point.Size, ctx->Point.MinSize, ctx->Point.MaxSize); /* Clamp to the hardware limits and convert to fixed point */ dw3 |= U_FIXED(CLAMP(point_size, 0.125f, 255.875f), 3); /* _NEW_LIGHT */ if (ctx->Light.ProvokingVertex != GL_FIRST_VERTEX_CONVENTION) { dw3 |= (2 << GEN6_SF_TRI_PROVOKE_SHIFT) | (2 << GEN6_SF_TRIFAN_PROVOKE_SHIFT) | (1 << GEN6_SF_LINE_PROVOKE_SHIFT); } else { dw3 |= (1 << GEN6_SF_TRIFAN_PROVOKE_SHIFT); } BEGIN_BATCH(7); OUT_BATCH(_3DSTATE_SF << 16 | (7 - 2)); OUT_BATCH(dw1); OUT_BATCH(dw2); OUT_BATCH(dw3); OUT_BATCH_F(ctx->Polygon.OffsetUnits * 2); /* constant. copied from gen4 */ OUT_BATCH_F(ctx->Polygon.OffsetFactor); /* scale */ OUT_BATCH_F(ctx->Polygon.OffsetClamp); /* global depth offset clamp */ ADVANCE_BATCH(); }
static void update_raster_state( struct st_context *st ) { struct gl_context *ctx = st->ctx; struct pipe_rasterizer_state *raster = &st->state.rasterizer; const struct gl_vertex_program *vertProg = ctx->VertexProgram._Current; const struct gl_fragment_program *fragProg = ctx->FragmentProgram._Current; uint i; memset(raster, 0, sizeof(*raster)); /* _NEW_POLYGON, _NEW_BUFFERS */ { raster->front_ccw = (ctx->Polygon.FrontFace == GL_CCW); /* _NEW_TRANSFORM */ if (ctx->Transform.ClipOrigin == GL_UPPER_LEFT) { raster->front_ccw ^= 1; } /* * Gallium's surfaces are Y=0=TOP orientation. OpenGL is the * opposite. Window system surfaces are Y=0=TOP. Mesa's FBOs * must match OpenGL conventions so FBOs use Y=0=BOTTOM. In that * case, we must invert Y and flip the notion of front vs. back. */ if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) { /* Drawing to an FBO. The viewport will be inverted. */ raster->front_ccw ^= 1; } } /* _NEW_LIGHT */ raster->flatshade = ctx->Light.ShadeModel == GL_FLAT; raster->flatshade_first = ctx->Light.ProvokingVertex == GL_FIRST_VERTEX_CONVENTION_EXT; /* _NEW_LIGHT | _NEW_PROGRAM */ raster->light_twoside = ctx->VertexProgram._TwoSideEnabled; /*_NEW_LIGHT | _NEW_BUFFERS */ raster->clamp_vertex_color = !st->clamp_vert_color_in_shader && ctx->Light._ClampVertexColor; /* _NEW_POLYGON */ if (ctx->Polygon.CullFlag) { switch (ctx->Polygon.CullFaceMode) { case GL_FRONT: raster->cull_face = PIPE_FACE_FRONT; break; case GL_BACK: raster->cull_face = PIPE_FACE_BACK; break; case GL_FRONT_AND_BACK: raster->cull_face = PIPE_FACE_FRONT_AND_BACK; break; } } else { raster->cull_face = PIPE_FACE_NONE; } /* _NEW_POLYGON */ { if (ST_DEBUG & DEBUG_WIREFRAME) { raster->fill_front = PIPE_POLYGON_MODE_LINE; raster->fill_back = PIPE_POLYGON_MODE_LINE; } else { raster->fill_front = translate_fill( ctx->Polygon.FrontMode ); raster->fill_back = translate_fill( ctx->Polygon.BackMode ); } /* Simplify when culling is active: */ if (raster->cull_face & PIPE_FACE_FRONT) { raster->fill_front = raster->fill_back; } if (raster->cull_face & PIPE_FACE_BACK) { raster->fill_back = raster->fill_front; } } /* _NEW_POLYGON */ if (ctx->Polygon.OffsetPoint || ctx->Polygon.OffsetLine || ctx->Polygon.OffsetFill) { raster->offset_point = ctx->Polygon.OffsetPoint; raster->offset_line = ctx->Polygon.OffsetLine; raster->offset_tri = ctx->Polygon.OffsetFill; raster->offset_units = ctx->Polygon.OffsetUnits; raster->offset_scale = ctx->Polygon.OffsetFactor; raster->offset_clamp = ctx->Polygon.OffsetClamp; } raster->poly_smooth = ctx->Polygon.SmoothFlag; raster->poly_stipple_enable = ctx->Polygon.StippleFlag; /* _NEW_POINT */ raster->point_size = ctx->Point.Size; raster->point_smooth = !ctx->Point.PointSprite && ctx->Point.SmoothFlag; /* _NEW_POINT | _NEW_PROGRAM */ if (ctx->Point.PointSprite) { /* origin */ if ((ctx->Point.SpriteOrigin == GL_UPPER_LEFT) ^ (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM)) raster->sprite_coord_mode = PIPE_SPRITE_COORD_UPPER_LEFT; else raster->sprite_coord_mode = PIPE_SPRITE_COORD_LOWER_LEFT; /* Coord replacement flags. If bit 'k' is set that means * that we need to replace GENERIC[k] attrib with an automatically * computed texture coord. */ for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) { if (ctx->Point.CoordReplace[i]) { raster->sprite_coord_enable |= 1 << i; } } if (!st->needs_texcoord_semantic && fragProg->Base.InputsRead & VARYING_BIT_PNTC) { raster->sprite_coord_enable |= 1 << st_get_generic_varying_index(st, VARYING_SLOT_PNTC); } raster->point_quad_rasterization = 1; } /* ST_NEW_VERTEX_PROGRAM */ if (vertProg) { if (vertProg->Base.Id == 0) { if (vertProg->Base.OutputsWritten & BITFIELD64_BIT(VARYING_SLOT_PSIZ)) { /* generated program which emits point size */ raster->point_size_per_vertex = TRUE; } } else if (ctx->API != API_OPENGLES2) { /* PointSizeEnabled is always set in ES2 contexts */ raster->point_size_per_vertex = ctx->VertexProgram.PointSizeEnabled; } else { /* ST_NEW_TESSEVAL_PROGRAM | ST_NEW_GEOMETRY_PROGRAM */ /* We have to check the last bound stage and see if it writes psize */ struct gl_program *last = NULL; if (ctx->GeometryProgram._Current) last = &ctx->GeometryProgram._Current->Base; else if (ctx->TessEvalProgram._Current) last = &ctx->TessEvalProgram._Current->Base; else if (ctx->VertexProgram._Current) last = &ctx->VertexProgram._Current->Base; if (last) raster->point_size_per_vertex = !!(last->OutputsWritten & BITFIELD64_BIT(VARYING_SLOT_PSIZ)); } } if (!raster->point_size_per_vertex) { /* clamp size now */ raster->point_size = CLAMP(ctx->Point.Size, ctx->Point.MinSize, ctx->Point.MaxSize); } /* _NEW_LINE */ raster->line_smooth = ctx->Line.SmoothFlag; if (ctx->Line.SmoothFlag) { raster->line_width = CLAMP(ctx->Line.Width, ctx->Const.MinLineWidthAA, ctx->Const.MaxLineWidthAA); } else { raster->line_width = CLAMP(ctx->Line.Width, ctx->Const.MinLineWidth, ctx->Const.MaxLineWidth); } raster->line_stipple_enable = ctx->Line.StippleFlag; raster->line_stipple_pattern = ctx->Line.StipplePattern; /* GL stipple factor is in [1,256], remap to [0, 255] here */ raster->line_stipple_factor = ctx->Line.StippleFactor - 1; /* _NEW_MULTISAMPLE */ raster->multisample = _mesa_is_multisample_enabled(ctx); /* _NEW_MULTISAMPLE | _NEW_BUFFERS */ raster->force_persample_interp = !st->force_persample_in_shader && _mesa_is_multisample_enabled(ctx) && ctx->Multisample.SampleShading && ctx->Multisample.MinSampleShadingValue * _mesa_geometric_samples(ctx->DrawBuffer) > 1; /* _NEW_SCISSOR */ raster->scissor = ctx->Scissor.EnableFlags; /* _NEW_FRAG_CLAMP */ raster->clamp_fragment_color = !st->clamp_frag_color_in_shader && ctx->Color._ClampFragmentColor; raster->half_pixel_center = 1; if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) raster->bottom_edge_rule = 1; /* _NEW_TRANSFORM */ if (ctx->Transform.ClipOrigin == GL_UPPER_LEFT) raster->bottom_edge_rule ^= 1; /* ST_NEW_RASTERIZER */ raster->rasterizer_discard = ctx->RasterDiscard; if (st->edgeflag_culls_prims) { /* All edge flags are FALSE. Cull the affected faces. */ if (raster->fill_front != PIPE_POLYGON_MODE_FILL) raster->cull_face |= PIPE_FACE_FRONT; if (raster->fill_back != PIPE_POLYGON_MODE_FILL) raster->cull_face |= PIPE_FACE_BACK; } /* _NEW_TRANSFORM */ raster->depth_clip = !ctx->Transform.DepthClamp; raster->clip_plane_enable = ctx->Transform.ClipPlanesEnabled; raster->clip_halfz = (ctx->Transform.ClipDepthMode == GL_ZERO_TO_ONE); cso_set_rasterizer(st->cso_context, raster); }
/** * Use the list of tokens in the state[] array to find global GL state * and return it in <value>. Usually, four values are returned in <value> * but matrix queries may return as many as 16 values. * This function is used for ARB vertex/fragment programs. * The program parser will produce the state[] values. */ static void _mesa_fetch_state(struct gl_context *ctx, const gl_state_index state[], gl_constant_value *val) { GLfloat *value = &val->f; switch (state[0]) { case STATE_MATERIAL: { /* state[1] is either 0=front or 1=back side */ const GLuint face = (GLuint) state[1]; const struct gl_material *mat = &ctx->Light.Material; assert(face == 0 || face == 1); /* we rely on tokens numbered so that _BACK_ == _FRONT_+ 1 */ assert(MAT_ATTRIB_FRONT_AMBIENT + 1 == MAT_ATTRIB_BACK_AMBIENT); /* XXX we could get rid of this switch entirely with a little * work in arbprogparse.c's parse_state_single_item(). */ /* state[2] is the material attribute */ switch (state[2]) { case STATE_AMBIENT: COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_AMBIENT + face]); return; case STATE_DIFFUSE: COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_DIFFUSE + face]); return; case STATE_SPECULAR: COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_SPECULAR + face]); return; case STATE_EMISSION: COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_EMISSION + face]); return; case STATE_SHININESS: value[0] = mat->Attrib[MAT_ATTRIB_FRONT_SHININESS + face][0]; value[1] = 0.0F; value[2] = 0.0F; value[3] = 1.0F; return; default: _mesa_problem(ctx, "Invalid material state in fetch_state"); return; } } case STATE_LIGHT: { /* state[1] is the light number */ const GLuint ln = (GLuint) state[1]; /* state[2] is the light attribute */ switch (state[2]) { case STATE_AMBIENT: COPY_4V(value, ctx->Light.Light[ln].Ambient); return; case STATE_DIFFUSE: COPY_4V(value, ctx->Light.Light[ln].Diffuse); return; case STATE_SPECULAR: COPY_4V(value, ctx->Light.Light[ln].Specular); return; case STATE_POSITION: COPY_4V(value, ctx->Light.Light[ln].EyePosition); return; case STATE_ATTENUATION: value[0] = ctx->Light.Light[ln].ConstantAttenuation; value[1] = ctx->Light.Light[ln].LinearAttenuation; value[2] = ctx->Light.Light[ln].QuadraticAttenuation; value[3] = ctx->Light.Light[ln].SpotExponent; return; case STATE_SPOT_DIRECTION: COPY_3V(value, ctx->Light.Light[ln].SpotDirection); value[3] = ctx->Light.Light[ln]._CosCutoff; return; case STATE_SPOT_CUTOFF: value[0] = ctx->Light.Light[ln].SpotCutoff; return; case STATE_HALF_VECTOR: { static const GLfloat eye_z[] = {0, 0, 1}; GLfloat p[3]; /* Compute infinite half angle vector: * halfVector = normalize(normalize(lightPos) + (0, 0, 1)) * light.EyePosition.w should be 0 for infinite lights. */ COPY_3V(p, ctx->Light.Light[ln].EyePosition); NORMALIZE_3FV(p); ADD_3V(value, p, eye_z); NORMALIZE_3FV(value); value[3] = 1.0; } return; default: _mesa_problem(ctx, "Invalid light state in fetch_state"); return; } } case STATE_LIGHTMODEL_AMBIENT: COPY_4V(value, ctx->Light.Model.Ambient); return; case STATE_LIGHTMODEL_SCENECOLOR: if (state[1] == 0) { /* front */ GLint i; for (i = 0; i < 3; i++) { value[i] = ctx->Light.Model.Ambient[i] * ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT][i] + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION][i]; } value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3]; } else { /* back */ GLint i; for (i = 0; i < 3; i++) { value[i] = ctx->Light.Model.Ambient[i] * ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT][i] + ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION][i]; } value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3]; } return; case STATE_LIGHTPROD: { const GLuint ln = (GLuint) state[1]; const GLuint face = (GLuint) state[2]; GLint i; assert(face == 0 || face == 1); switch (state[3]) { case STATE_AMBIENT: for (i = 0; i < 3; i++) { value[i] = ctx->Light.Light[ln].Ambient[i] * ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT+face][i]; } /* [3] = material alpha */ value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT+face][3]; return; case STATE_DIFFUSE: for (i = 0; i < 3; i++) { value[i] = ctx->Light.Light[ln].Diffuse[i] * ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][i]; } /* [3] = material alpha */ value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3]; return; case STATE_SPECULAR: for (i = 0; i < 3; i++) { value[i] = ctx->Light.Light[ln].Specular[i] * ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR+face][i]; } /* [3] = material alpha */ value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR+face][3]; return; default: _mesa_problem(ctx, "Invalid lightprod state in fetch_state"); return; } } case STATE_TEXGEN: { /* state[1] is the texture unit */ const GLuint unit = (GLuint) state[1]; /* state[2] is the texgen attribute */ switch (state[2]) { case STATE_TEXGEN_EYE_S: COPY_4V(value, ctx->Texture.Unit[unit].GenS.EyePlane); return; case STATE_TEXGEN_EYE_T: COPY_4V(value, ctx->Texture.Unit[unit].GenT.EyePlane); return; case STATE_TEXGEN_EYE_R: COPY_4V(value, ctx->Texture.Unit[unit].GenR.EyePlane); return; case STATE_TEXGEN_EYE_Q: COPY_4V(value, ctx->Texture.Unit[unit].GenQ.EyePlane); return; case STATE_TEXGEN_OBJECT_S: COPY_4V(value, ctx->Texture.Unit[unit].GenS.ObjectPlane); return; case STATE_TEXGEN_OBJECT_T: COPY_4V(value, ctx->Texture.Unit[unit].GenT.ObjectPlane); return; case STATE_TEXGEN_OBJECT_R: COPY_4V(value, ctx->Texture.Unit[unit].GenR.ObjectPlane); return; case STATE_TEXGEN_OBJECT_Q: COPY_4V(value, ctx->Texture.Unit[unit].GenQ.ObjectPlane); return; default: _mesa_problem(ctx, "Invalid texgen state in fetch_state"); return; } } case STATE_TEXENV_COLOR: { /* state[1] is the texture unit */ const GLuint unit = (GLuint) state[1]; if (_mesa_get_clamp_fragment_color(ctx, ctx->DrawBuffer)) COPY_4V(value, ctx->Texture.Unit[unit].EnvColor); else COPY_4V(value, ctx->Texture.Unit[unit].EnvColorUnclamped); } return; case STATE_FOG_COLOR: if (_mesa_get_clamp_fragment_color(ctx, ctx->DrawBuffer)) COPY_4V(value, ctx->Fog.Color); else COPY_4V(value, ctx->Fog.ColorUnclamped); return; case STATE_FOG_PARAMS: value[0] = ctx->Fog.Density; value[1] = ctx->Fog.Start; value[2] = ctx->Fog.End; value[3] = 1.0f / (ctx->Fog.End - ctx->Fog.Start); return; case STATE_CLIPPLANE: { const GLuint plane = (GLuint) state[1]; COPY_4V(value, ctx->Transform.EyeUserPlane[plane]); } return; case STATE_POINT_SIZE: value[0] = ctx->Point.Size; value[1] = ctx->Point.MinSize; value[2] = ctx->Point.MaxSize; value[3] = ctx->Point.Threshold; return; case STATE_POINT_ATTENUATION: value[0] = ctx->Point.Params[0]; value[1] = ctx->Point.Params[1]; value[2] = ctx->Point.Params[2]; value[3] = 1.0F; return; case STATE_MODELVIEW_MATRIX: case STATE_PROJECTION_MATRIX: case STATE_MVP_MATRIX: case STATE_TEXTURE_MATRIX: case STATE_PROGRAM_MATRIX: { /* state[0] = modelview, projection, texture, etc. */ /* state[1] = which texture matrix or program matrix */ /* state[2] = first row to fetch */ /* state[3] = last row to fetch */ /* state[4] = transpose, inverse or invtrans */ const GLmatrix *matrix; const gl_state_index mat = state[0]; const GLuint index = (GLuint) state[1]; const GLuint firstRow = (GLuint) state[2]; const GLuint lastRow = (GLuint) state[3]; const gl_state_index modifier = state[4]; const GLfloat *m; GLuint row, i; assert(firstRow < 4); assert(lastRow < 4); if (mat == STATE_MODELVIEW_MATRIX) { matrix = ctx->ModelviewMatrixStack.Top; } else if (mat == STATE_PROJECTION_MATRIX) { matrix = ctx->ProjectionMatrixStack.Top; } else if (mat == STATE_MVP_MATRIX) { matrix = &ctx->_ModelProjectMatrix; } else if (mat == STATE_TEXTURE_MATRIX) { assert(index < ARRAY_SIZE(ctx->TextureMatrixStack)); matrix = ctx->TextureMatrixStack[index].Top; } else if (mat == STATE_PROGRAM_MATRIX) { assert(index < ARRAY_SIZE(ctx->ProgramMatrixStack)); matrix = ctx->ProgramMatrixStack[index].Top; } else { _mesa_problem(ctx, "Bad matrix name in _mesa_fetch_state()"); return; } if (modifier == STATE_MATRIX_INVERSE || modifier == STATE_MATRIX_INVTRANS) { /* Be sure inverse is up to date: */ _math_matrix_analyse( (GLmatrix*) matrix ); m = matrix->inv; } else { m = matrix->m; } if (modifier == STATE_MATRIX_TRANSPOSE || modifier == STATE_MATRIX_INVTRANS) { for (i = 0, row = firstRow; row <= lastRow; row++) { value[i++] = m[row * 4 + 0]; value[i++] = m[row * 4 + 1]; value[i++] = m[row * 4 + 2]; value[i++] = m[row * 4 + 3]; } } else { for (i = 0, row = firstRow; row <= lastRow; row++) { value[i++] = m[row + 0]; value[i++] = m[row + 4]; value[i++] = m[row + 8]; value[i++] = m[row + 12]; } } } return; case STATE_NUM_SAMPLES: val[0].i = MAX2(1, _mesa_geometric_samples(ctx->DrawBuffer)); return; case STATE_DEPTH_RANGE: value[0] = ctx->ViewportArray[0].Near; /* near */ value[1] = ctx->ViewportArray[0].Far; /* far */ value[2] = ctx->ViewportArray[0].Far - ctx->ViewportArray[0].Near; /* far - near */ value[3] = 1.0; return; case STATE_FRAGMENT_PROGRAM: { /* state[1] = {STATE_ENV, STATE_LOCAL} */ /* state[2] = parameter index */ const int idx = (int) state[2]; switch (state[1]) { case STATE_ENV: COPY_4V(value, ctx->FragmentProgram.Parameters[idx]); return; case STATE_LOCAL: if (!ctx->FragmentProgram.Current->arb.LocalParams) { ctx->FragmentProgram.Current->arb.LocalParams = rzalloc_array_size(ctx->FragmentProgram.Current, sizeof(float[4]), MAX_PROGRAM_LOCAL_PARAMS); if (!ctx->FragmentProgram.Current->arb.LocalParams) return; } COPY_4V(value, ctx->FragmentProgram.Current->arb.LocalParams[idx]); return; default: _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()"); return; } } return; case STATE_VERTEX_PROGRAM: { /* state[1] = {STATE_ENV, STATE_LOCAL} */ /* state[2] = parameter index */ const int idx = (int) state[2]; switch (state[1]) { case STATE_ENV: COPY_4V(value, ctx->VertexProgram.Parameters[idx]); return; case STATE_LOCAL: if (!ctx->VertexProgram.Current->arb.LocalParams) { ctx->VertexProgram.Current->arb.LocalParams = rzalloc_array_size(ctx->VertexProgram.Current, sizeof(float[4]), MAX_PROGRAM_LOCAL_PARAMS); if (!ctx->VertexProgram.Current->arb.LocalParams) return; } COPY_4V(value, ctx->VertexProgram.Current->arb.LocalParams[idx]); return; default: _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()"); return; } } return; case STATE_NORMAL_SCALE: ASSIGN_4V(value, ctx->_ModelViewInvScale, 0, 0, 1); return; case STATE_INTERNAL: switch (state[1]) { case STATE_CURRENT_ATTRIB: { const GLuint idx = (GLuint) state[2]; COPY_4V(value, ctx->Current.Attrib[idx]); } return; case STATE_CURRENT_ATTRIB_MAYBE_VP_CLAMPED: { const GLuint idx = (GLuint) state[2]; if(ctx->Light._ClampVertexColor && (idx == VERT_ATTRIB_COLOR0 || idx == VERT_ATTRIB_COLOR1)) { value[0] = CLAMP(ctx->Current.Attrib[idx][0], 0.0f, 1.0f); value[1] = CLAMP(ctx->Current.Attrib[idx][1], 0.0f, 1.0f); value[2] = CLAMP(ctx->Current.Attrib[idx][2], 0.0f, 1.0f); value[3] = CLAMP(ctx->Current.Attrib[idx][3], 0.0f, 1.0f); } else COPY_4V(value, ctx->Current.Attrib[idx]); } return; case STATE_NORMAL_SCALE: ASSIGN_4V(value, ctx->_ModelViewInvScale, ctx->_ModelViewInvScale, ctx->_ModelViewInvScale, 1); return; case STATE_FOG_PARAMS_OPTIMIZED: /* for simpler per-vertex/pixel fog calcs. POW (for EXP/EXP2 fog) * might be more expensive than EX2 on some hw, plus it needs * another constant (e) anyway. Linear fog can now be done with a * single MAD. * linear: fogcoord * -1/(end-start) + end/(end-start) * exp: 2^-(density/ln(2) * fogcoord) * exp2: 2^-((density/(sqrt(ln(2))) * fogcoord)^2) */ value[0] = (ctx->Fog.End == ctx->Fog.Start) ? 1.0f : (GLfloat)(-1.0F / (ctx->Fog.End - ctx->Fog.Start)); value[1] = ctx->Fog.End * -value[0]; value[2] = (GLfloat)(ctx->Fog.Density * M_LOG2E); /* M_LOG2E == 1/ln(2) */ value[3] = (GLfloat)(ctx->Fog.Density * ONE_DIV_SQRT_LN2); return; case STATE_POINT_SIZE_CLAMPED: { /* this includes implementation dependent limits, to avoid * another potentially necessary clamp. * Note: for sprites, point smooth (point AA) is ignored * and we'll clamp to MinPointSizeAA and MaxPointSize, because we * expect drivers will want to say their minimum for AA size is 0.0 * but for non-AA it's 1.0 (because normal points with size below 1.0 * need to get rounded up to 1.0, hence never disappear). GL does * not specify max clamp size for sprites, other than it needs to be * at least as large as max AA size, hence use non-AA size there. */ GLfloat minImplSize; GLfloat maxImplSize; if (ctx->Point.PointSprite) { minImplSize = ctx->Const.MinPointSizeAA; maxImplSize = ctx->Const.MaxPointSize; } else if (ctx->Point.SmoothFlag || _mesa_is_multisample_enabled(ctx)) { minImplSize = ctx->Const.MinPointSizeAA; maxImplSize = ctx->Const.MaxPointSizeAA; } else { minImplSize = ctx->Const.MinPointSize; maxImplSize = ctx->Const.MaxPointSize; } value[0] = ctx->Point.Size; value[1] = ctx->Point.MinSize >= minImplSize ? ctx->Point.MinSize : minImplSize; value[2] = ctx->Point.MaxSize <= maxImplSize ? ctx->Point.MaxSize : maxImplSize; value[3] = ctx->Point.Threshold; } return; case STATE_LIGHT_SPOT_DIR_NORMALIZED: { /* here, state[2] is the light number */ /* pre-normalize spot dir */ const GLuint ln = (GLuint) state[2]; COPY_3V(value, ctx->Light.Light[ln]._NormSpotDirection); value[3] = ctx->Light.Light[ln]._CosCutoff; } return; case STATE_LIGHT_POSITION: { const GLuint ln = (GLuint) state[2]; COPY_4V(value, ctx->Light.Light[ln]._Position); } return; case STATE_LIGHT_POSITION_NORMALIZED: { const GLuint ln = (GLuint) state[2]; COPY_4V(value, ctx->Light.Light[ln]._Position); NORMALIZE_3FV( value ); } return; case STATE_LIGHT_HALF_VECTOR: { const GLuint ln = (GLuint) state[2]; GLfloat p[3]; /* Compute infinite half angle vector: * halfVector = normalize(normalize(lightPos) + (0, 0, 1)) * light.EyePosition.w should be 0 for infinite lights. */ COPY_3V(p, ctx->Light.Light[ln]._Position); NORMALIZE_3FV(p); ADD_3V(value, p, ctx->_EyeZDir); NORMALIZE_3FV(value); value[3] = 1.0; } return; case STATE_PT_SCALE: value[0] = ctx->Pixel.RedScale; value[1] = ctx->Pixel.GreenScale; value[2] = ctx->Pixel.BlueScale; value[3] = ctx->Pixel.AlphaScale; return; case STATE_PT_BIAS: value[0] = ctx->Pixel.RedBias; value[1] = ctx->Pixel.GreenBias; value[2] = ctx->Pixel.BlueBias; value[3] = ctx->Pixel.AlphaBias; return; case STATE_FB_SIZE: value[0] = (GLfloat) (ctx->DrawBuffer->Width - 1); value[1] = (GLfloat) (ctx->DrawBuffer->Height - 1); value[2] = 0.0F; value[3] = 0.0F; return; case STATE_FB_WPOS_Y_TRANSFORM: /* A driver may negate this conditional by using ZW swizzle * instead of XY (based on e.g. some other state). */ if (_mesa_is_user_fbo(ctx->DrawBuffer)) { /* Identity (XY) followed by flipping Y upside down (ZW). */ value[0] = 1.0F; value[1] = 0.0F; value[2] = -1.0F; value[3] = (GLfloat) ctx->DrawBuffer->Height; } else { /* Flipping Y upside down (XY) followed by identity (ZW). */ value[0] = -1.0F; value[1] = (GLfloat) ctx->DrawBuffer->Height; value[2] = 1.0F; value[3] = 0.0F; } return; case STATE_TCS_PATCH_VERTICES_IN: val[0].i = ctx->TessCtrlProgram.patch_vertices; return; case STATE_TES_PATCH_VERTICES_IN: if (ctx->TessCtrlProgram._Current) val[0].i = ctx->TessCtrlProgram._Current->info.tess.tcs_vertices_out; else val[0].i = ctx->TessCtrlProgram.patch_vertices; return; case STATE_ADVANCED_BLENDING_MODE: val[0].i = ctx->Color.BlendEnabled ? ctx->Color._AdvancedBlendMode : 0; return; /* XXX: make sure new tokens added here are also handled in the * _mesa_program_state_flags() switch, below. */ default: /* Unknown state indexes are silently ignored here. * Drivers may do something special. */ return; } return; default: _mesa_problem(ctx, "Invalid state in _mesa_fetch_state"); return; } }
static void brw_wm_populate_key(struct brw_context *brw, struct brw_wm_prog_key *key) { struct gl_context *ctx = &brw->ctx; /* BRW_NEW_FRAGMENT_PROGRAM */ const struct brw_fragment_program *fp = (struct brw_fragment_program *) brw->fragment_program; const struct gl_program *prog = (struct gl_program *) brw->fragment_program; GLuint lookup = 0; GLuint line_aa; memset(key, 0, sizeof(*key)); /* Build the index for table lookup */ if (brw->gen < 6) { /* _NEW_COLOR */ if (fp->program.UsesKill || ctx->Color.AlphaEnabled) lookup |= IZ_PS_KILL_ALPHATEST_BIT; if (fp->program.Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) lookup |= IZ_PS_COMPUTES_DEPTH_BIT; /* _NEW_DEPTH */ if (ctx->Depth.Test) lookup |= IZ_DEPTH_TEST_ENABLE_BIT; if (ctx->Depth.Test && ctx->Depth.Mask) /* ?? */ lookup |= IZ_DEPTH_WRITE_ENABLE_BIT; /* _NEW_STENCIL | _NEW_BUFFERS */ if (ctx->Stencil._Enabled) { lookup |= IZ_STENCIL_TEST_ENABLE_BIT; if (ctx->Stencil.WriteMask[0] || ctx->Stencil.WriteMask[ctx->Stencil._BackFace]) lookup |= IZ_STENCIL_WRITE_ENABLE_BIT; } key->iz_lookup = lookup; } line_aa = AA_NEVER; /* _NEW_LINE, _NEW_POLYGON, BRW_NEW_REDUCED_PRIMITIVE */ if (ctx->Line.SmoothFlag) { if (brw->reduced_primitive == GL_LINES) { line_aa = AA_ALWAYS; } else if (brw->reduced_primitive == GL_TRIANGLES) { if (ctx->Polygon.FrontMode == GL_LINE) { line_aa = AA_SOMETIMES; if (ctx->Polygon.BackMode == GL_LINE || (ctx->Polygon.CullFlag && ctx->Polygon.CullFaceMode == GL_BACK)) line_aa = AA_ALWAYS; } else if (ctx->Polygon.BackMode == GL_LINE) { line_aa = AA_SOMETIMES; if ((ctx->Polygon.CullFlag && ctx->Polygon.CullFaceMode == GL_FRONT)) line_aa = AA_ALWAYS; } } } key->line_aa = line_aa; /* _NEW_HINT */ key->high_quality_derivatives = ctx->Hint.FragmentShaderDerivative == GL_NICEST; if (brw->gen < 6) key->stats_wm = brw->stats_wm; /* _NEW_LIGHT */ key->flat_shade = (ctx->Light.ShadeModel == GL_FLAT); /* _NEW_FRAG_CLAMP | _NEW_BUFFERS */ key->clamp_fragment_color = ctx->Color._ClampFragmentColor; /* _NEW_TEXTURE */ brw_populate_sampler_prog_key_data(ctx, prog, brw->wm.base.sampler_count, &key->tex); /* _NEW_BUFFERS */ key->nr_color_regions = ctx->DrawBuffer->_NumColorDrawBuffers; /* _NEW_COLOR */ key->force_dual_color_blend = brw->dual_color_blend_by_location && (ctx->Color.BlendEnabled & 1) && ctx->Color.Blend[0]._UsesDualSrc; /* _NEW_MULTISAMPLE, _NEW_COLOR, _NEW_BUFFERS */ key->replicate_alpha = ctx->DrawBuffer->_NumColorDrawBuffers > 1 && (ctx->Multisample.SampleAlphaToCoverage || ctx->Color.AlphaEnabled); /* _NEW_BUFFERS _NEW_MULTISAMPLE */ /* Ignore sample qualifier while computing this flag. */ if (ctx->Multisample.Enabled) { key->persample_interp = ctx->Multisample.SampleShading && (ctx->Multisample.MinSampleShadingValue * _mesa_geometric_samples(ctx->DrawBuffer) > 1); key->multisample_fbo = _mesa_geometric_samples(ctx->DrawBuffer) > 1; } /* BRW_NEW_VUE_MAP_GEOM_OUT */ if (brw->gen < 6 || _mesa_bitcount_64(fp->program.Base.InputsRead & BRW_FS_VARYING_INPUT_MASK) > 16) key->input_slots_valid = brw->vue_map_geom_out.slots_valid; /* _NEW_COLOR | _NEW_BUFFERS */ /* Pre-gen6, the hardware alpha test always used each render * target's alpha to do alpha test, as opposed to render target 0's alpha * like GL requires. Fix that by building the alpha test into the * shader, and we'll skip enabling the fixed function alpha test. */ if (brw->gen < 6 && ctx->DrawBuffer->_NumColorDrawBuffers > 1 && ctx->Color.AlphaEnabled) { key->alpha_test_func = ctx->Color.AlphaFunc; key->alpha_test_ref = ctx->Color.AlphaRef; } /* The unique fragment program ID */ key->program_string_id = fp->id; }