/**
 * 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);
}
Exemplo n.º 2
0
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();
}
Exemplo n.º 3
0
/**
 * 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);
}
Exemplo n.º 4
0
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();
}
Exemplo n.º 5
0
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();
   }
}
Exemplo n.º 6
0
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);
}
Exemplo n.º 7
0
/**
 * 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;
   }
}