/** * Is alpha to coverage enabled and applicable to the currently bound * framebuffer? */ bool _mesa_is_alpha_to_coverage_enabled(const struct gl_context *ctx) { bool buffer0_is_integer = ctx->DrawBuffer->_IntegerBuffers & 0x1; return (ctx->Multisample.SampleAlphaToCoverage && _mesa_is_multisample_enabled(ctx) && !buffer0_is_integer); }
static void upload_sf(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; uint32_t dw1 = 0, dw2 = 0, dw3 = 0; float point_size; dw1 = GEN6_SF_STATISTICS_ENABLE; if (brw->sf.viewport_transform_enable) dw1 |= GEN6_SF_VIEWPORT_TRANSFORM_ENABLE; /* _NEW_LINE */ uint32_t line_width_u3_7 = brw_get_line_width(brw); if (brw->gen >= 9 || brw->is_cherryview) { dw1 |= line_width_u3_7 << GEN9_SF_LINE_WIDTH_SHIFT; } else { dw2 |= line_width_u3_7 << GEN6_SF_LINE_WIDTH_SHIFT; } if (ctx->Line.SmoothFlag) { dw2 |= GEN6_SF_LINE_END_CAP_WIDTH_1_0; } /* _NEW_POINT - 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_PROGRAM | _NEW_POINT, BRW_NEW_VUE_MAP_GEOM_OUT */ if (use_state_point_size(brw)) dw3 |= GEN6_SF_USE_STATE_POINT_WIDTH; /* _NEW_POINT | _NEW_MULTISAMPLE */ if ((ctx->Point.SmoothFlag || _mesa_is_multisample_enabled(ctx)) && !ctx->Point.PointSprite) { dw3 |= GEN8_SF_SMOOTH_POINT_ENABLE; } dw3 |= GEN6_SF_LINE_AA_MODE_TRUE; /* _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(4); OUT_BATCH(_3DSTATE_SF << 16 | (4 - 2)); OUT_BATCH(dw1); OUT_BATCH(dw2); OUT_BATCH(dw3); ADVANCE_BATCH(); }
/** * 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); }
static void upload_raster(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; uint32_t dw1 = 0; /* _NEW_BUFFERS */ bool render_to_fbo = _mesa_is_user_fbo(brw->ctx.DrawBuffer); /* _NEW_POLYGON */ if (ctx->Polygon._FrontBit == render_to_fbo) dw1 |= GEN8_RASTER_FRONT_WINDING_CCW; if (ctx->Polygon.CullFlag) { switch (ctx->Polygon.CullFaceMode) { case GL_FRONT: dw1 |= GEN8_RASTER_CULL_FRONT; break; case GL_BACK: dw1 |= GEN8_RASTER_CULL_BACK; break; case GL_FRONT_AND_BACK: dw1 |= GEN8_RASTER_CULL_BOTH; break; default: unreachable("not reached"); } } else { dw1 |= GEN8_RASTER_CULL_NONE; } /* _NEW_POINT */ if (ctx->Point.SmoothFlag) dw1 |= GEN8_RASTER_SMOOTH_POINT_ENABLE; if (_mesa_is_multisample_enabled(ctx)) dw1 |= GEN8_RASTER_API_MULTISAMPLE_ENABLE; 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"); } /* _NEW_LINE */ if (ctx->Line.SmoothFlag) dw1 |= GEN8_RASTER_LINE_AA_ENABLE; /* _NEW_SCISSOR */ if (ctx->Scissor.EnableFlags) dw1 |= GEN8_RASTER_SCISSOR_ENABLE; /* _NEW_TRANSFORM */ if (!ctx->Transform.DepthClamp) { if (brw->gen >= 9) { dw1 |= GEN9_RASTER_VIEWPORT_Z_NEAR_CLIP_TEST_ENABLE | GEN9_RASTER_VIEWPORT_Z_FAR_CLIP_TEST_ENABLE; } else { dw1 |= GEN8_RASTER_VIEWPORT_Z_CLIP_TEST_ENABLE; } } BEGIN_BATCH(5); OUT_BATCH(_3DSTATE_RASTER << 16 | (5 - 2)); OUT_BATCH(dw1); 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 gen6_upload_blend_state(struct brw_context *brw) { bool is_buffer_zero_integer_format = false; struct gl_context *ctx = &brw->ctx; struct gen6_blend_state *blend; int b; int nr_draw_buffers = ctx->DrawBuffer->_NumColorDrawBuffers; int size; /* We need at least one BLEND_STATE written, because we might do * thread dispatch even if _NumColorDrawBuffers is 0 (for example * for computed depth or alpha test), which will do an FB write * with render target 0, which will reference BLEND_STATE[0] for * alpha test enable. */ if (nr_draw_buffers == 0) nr_draw_buffers = 1; size = sizeof(*blend) * nr_draw_buffers; blend = brw_state_batch(brw, AUB_TRACE_BLEND_STATE, size, 64, &brw->cc.blend_state_offset); memset(blend, 0, size); for (b = 0; b < nr_draw_buffers; b++) { /* _NEW_BUFFERS */ struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[b]; GLenum rb_type; bool integer; if (rb) rb_type = _mesa_get_format_datatype(rb->Format); else rb_type = GL_UNSIGNED_NORMALIZED; /* Used for implementing the following bit of GL_EXT_texture_integer: * "Per-fragment operations that require floating-point color * components, including multisample alpha operations, alpha test, * blending, and dithering, have no effect when the corresponding * colors are written to an integer color buffer." */ integer = (rb_type == GL_INT || rb_type == GL_UNSIGNED_INT); if(b == 0 && integer) is_buffer_zero_integer_format = true; /* _NEW_COLOR */ if (ctx->Color.ColorLogicOpEnabled) { /* Floating point RTs should have no effect from LogicOp, * except for disabling of blending, but other types should. * * However, from the Sandy Bridge PRM, Vol 2 Par 1, Section 8.1.11, * "Logic Ops", * * "Logic Ops are only supported on *_UNORM surfaces (excluding * _SRGB variants), otherwise Logic Ops must be DISABLED." */ WARN_ONCE(ctx->Color.LogicOp != GL_COPY && rb_type != GL_UNSIGNED_NORMALIZED && rb_type != GL_FLOAT, "Ignoring %s logic op on %s " "renderbuffer\n", _mesa_enum_to_string(ctx->Color.LogicOp), _mesa_enum_to_string(rb_type)); if (rb_type == GL_UNSIGNED_NORMALIZED) { blend[b].blend1.logic_op_enable = 1; blend[b].blend1.logic_op_func = intel_translate_logic_op(ctx->Color.LogicOp); } } else if (ctx->Color.BlendEnabled & (1 << b) && !integer) { GLenum eqRGB = ctx->Color.Blend[b].EquationRGB; GLenum eqA = ctx->Color.Blend[b].EquationA; GLenum srcRGB = ctx->Color.Blend[b].SrcRGB; GLenum dstRGB = ctx->Color.Blend[b].DstRGB; GLenum srcA = ctx->Color.Blend[b].SrcA; GLenum dstA = ctx->Color.Blend[b].DstA; if (eqRGB == GL_MIN || eqRGB == GL_MAX) { srcRGB = dstRGB = GL_ONE; } if (eqA == GL_MIN || eqA == GL_MAX) { srcA = dstA = GL_ONE; } /* Due to hardware limitations, the destination may have information * in an alpha channel even when the format specifies no alpha * channel. In order to avoid getting any incorrect blending due to * that alpha channel, coerce the blend factors to values that will * not read the alpha channel, but will instead use the correct * implicit value for alpha. */ if (rb && !_mesa_base_format_has_channel(rb->_BaseFormat, GL_TEXTURE_ALPHA_TYPE)) { srcRGB = brw_fix_xRGB_alpha(srcRGB); srcA = brw_fix_xRGB_alpha(srcA); dstRGB = brw_fix_xRGB_alpha(dstRGB); dstA = brw_fix_xRGB_alpha(dstA); } blend[b].blend0.dest_blend_factor = brw_translate_blend_factor(dstRGB); blend[b].blend0.source_blend_factor = brw_translate_blend_factor(srcRGB); blend[b].blend0.blend_func = brw_translate_blend_equation(eqRGB); blend[b].blend0.ia_dest_blend_factor = brw_translate_blend_factor(dstA); blend[b].blend0.ia_source_blend_factor = brw_translate_blend_factor(srcA); blend[b].blend0.ia_blend_func = brw_translate_blend_equation(eqA); blend[b].blend0.blend_enable = 1; blend[b].blend0.ia_blend_enable = (srcA != srcRGB || dstA != dstRGB || eqA != eqRGB); } /* See section 8.1.6 "Pre-Blend Color Clamping" of the * SandyBridge PRM Volume 2 Part 1 for HW requirements. * * We do our ARB_color_buffer_float CLAMP_FRAGMENT_COLOR * clamping in the fragment shader. For its clamping of * blending, the spec says: * * "RESOLVED: For fixed-point color buffers, the inputs and * the result of the blending equation are clamped. For * floating-point color buffers, no clamping occurs." * * So, generally, we want clamping to the render target's range. * And, good news, the hardware tables for both pre- and * post-blend color clamping are either ignored, or any are * allowed, or clamping is required but RT range clamping is a * valid option. */ blend[b].blend1.pre_blend_clamp_enable = 1; blend[b].blend1.post_blend_clamp_enable = 1; blend[b].blend1.clamp_range = BRW_RENDERTARGET_CLAMPRANGE_FORMAT; /* _NEW_COLOR */ if (ctx->Color.AlphaEnabled && !integer) { blend[b].blend1.alpha_test_enable = 1; blend[b].blend1.alpha_test_func = intel_translate_compare_func(ctx->Color.AlphaFunc); } /* _NEW_COLOR */ if (ctx->Color.DitherFlag && !integer) { blend[b].blend1.dither_enable = 1; blend[b].blend1.y_dither_offset = 0; blend[b].blend1.x_dither_offset = 0; } blend[b].blend1.write_disable_r = !ctx->Color.ColorMask[b][0]; blend[b].blend1.write_disable_g = !ctx->Color.ColorMask[b][1]; blend[b].blend1.write_disable_b = !ctx->Color.ColorMask[b][2]; blend[b].blend1.write_disable_a = !ctx->Color.ColorMask[b][3]; /* OpenGL specification 3.3 (page 196), section 4.1.3 says: * "If drawbuffer zero is not NONE and the buffer it references has an * integer format, the SAMPLE_ALPHA_TO_COVERAGE and SAMPLE_ALPHA_TO_ONE * operations are skipped." */ if(!is_buffer_zero_integer_format) { /* _NEW_MULTISAMPLE */ blend[b].blend1.alpha_to_coverage = _mesa_is_multisample_enabled(ctx) && ctx->Multisample.SampleAlphaToCoverage; /* From SandyBridge PRM, volume 2 Part 1, section 8.2.3, BLEND_STATE: * DWord 1, Bit 30 (AlphaToOne Enable): * "If Dual Source Blending is enabled, this bit must be disabled" */ WARN_ONCE(ctx->Color.Blend[b]._UsesDualSrc && _mesa_is_multisample_enabled(ctx) && ctx->Multisample.SampleAlphaToOne, "HW workaround: disabling alpha to one with dual src " "blending\n"); if (ctx->Color.Blend[b]._UsesDualSrc) blend[b].blend1.alpha_to_one = false; else blend[b].blend1.alpha_to_one = _mesa_is_multisample_enabled(ctx) && ctx->Multisample.SampleAlphaToOne; blend[b].blend1.alpha_to_coverage_dither = (brw->gen >= 7); } else { blend[b].blend1.alpha_to_coverage = false; blend[b].blend1.alpha_to_one = false; } } /* Point the GPU at the new indirect state. */ if (brw->gen == 6) { BEGIN_BATCH(4); OUT_BATCH(_3DSTATE_CC_STATE_POINTERS << 16 | (4 - 2)); OUT_BATCH(brw->cc.blend_state_offset | 1); OUT_BATCH(0); OUT_BATCH(0); ADVANCE_BATCH(); } else { BEGIN_BATCH(2); OUT_BATCH(_3DSTATE_BLEND_STATE_POINTERS << 16 | (2 - 2)); OUT_BATCH(brw->cc.blend_state_offset | 1); 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; } }