Beispiel #1
0
/**
 * Helper function to enable or disable state.
 *
 * \param ctx GL context.
 * \param cap  the state to enable/disable
 * \param state whether to enable or disable the specified capability.
 *
 * Updates the current context and flushes the vertices as needed. For
 * capabilities associated with extensions it verifies that those extensions
 * are effectivly present before updating. Notifies the driver via
 * dd_function_table::Enable.
 */
void
_mesa_set_enable(GLcontext *ctx, GLenum cap, GLboolean state)
{
   if (MESA_VERBOSE & VERBOSE_API)
      _mesa_debug(ctx, "%s %s (newstate is %x)\n",
                  state ? "glEnable" : "glDisable",
                  _mesa_lookup_enum_by_nr(cap),
                  ctx->NewState);

   switch (cap) {
      case GL_ALPHA_TEST:
         if (ctx->Color.AlphaEnabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_COLOR);
         ctx->Color.AlphaEnabled = state;
         break;
      case GL_AUTO_NORMAL:
         if (ctx->Eval.AutoNormal == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.AutoNormal = state;
         break;
      case GL_BLEND:
         if (ctx->Color.BlendEnabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_COLOR);
         ctx->Color.BlendEnabled = state;
         break;
#if FEATURE_userclip
      case GL_CLIP_PLANE0:
      case GL_CLIP_PLANE1:
      case GL_CLIP_PLANE2:
      case GL_CLIP_PLANE3:
      case GL_CLIP_PLANE4:
      case GL_CLIP_PLANE5:
         {
            const GLuint p = cap - GL_CLIP_PLANE0;

            if ((ctx->Transform.ClipPlanesEnabled & (1 << p)) == ((GLuint) state << p))
               return;

            FLUSH_VERTICES(ctx, _NEW_TRANSFORM);

            if (state) {
               ctx->Transform.ClipPlanesEnabled |= (1 << p);

               if (_math_matrix_is_dirty(ctx->ProjectionMatrixStack.Top))
                  _math_matrix_analyse( ctx->ProjectionMatrixStack.Top );

               /* This derived state also calculated in clip.c and
                * from _mesa_update_state() on changes to EyeUserPlane
                * and ctx->ProjectionMatrix respectively.
                */
               _mesa_transform_vector( ctx->Transform._ClipUserPlane[p],
                                    ctx->Transform.EyeUserPlane[p],
                                    ctx->ProjectionMatrixStack.Top->inv );
            }
            else {
               ctx->Transform.ClipPlanesEnabled &= ~(1 << p);
            }               
         }
         break;
#endif
      case GL_COLOR_MATERIAL:
         if (ctx->Light.ColorMaterialEnabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_LIGHT);
         FLUSH_CURRENT(ctx, 0);
         ctx->Light.ColorMaterialEnabled = state;
         if (state) {
            _mesa_update_color_material( ctx,
                                  ctx->Current.Attrib[VERT_ATTRIB_COLOR0] );
         }
         break;
      case GL_CULL_FACE:
         if (ctx->Polygon.CullFlag == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_POLYGON);
         ctx->Polygon.CullFlag = state;
         break;
      case GL_CULL_VERTEX_EXT:
         CHECK_EXTENSION(EXT_cull_vertex, cap);
         if (ctx->Transform.CullVertexFlag == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
         ctx->Transform.CullVertexFlag = state;
         break;
      case GL_DEPTH_TEST:
         if (ctx->Depth.Test == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_DEPTH);
         ctx->Depth.Test = state;
         break;
      case GL_DITHER:
         if (ctx->NoDither) {
            state = GL_FALSE; /* MESA_NO_DITHER env var */
         }
         if (ctx->Color.DitherFlag == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_COLOR);
         ctx->Color.DitherFlag = state;
         break;
      case GL_FOG:
         if (ctx->Fog.Enabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_FOG);
         ctx->Fog.Enabled = state;
         break;
      case GL_HISTOGRAM:
         CHECK_EXTENSION(EXT_histogram, cap);
         if (ctx->Pixel.HistogramEnabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.HistogramEnabled = state;
         break;
      case GL_LIGHT0:
      case GL_LIGHT1:
      case GL_LIGHT2:
      case GL_LIGHT3:
      case GL_LIGHT4:
      case GL_LIGHT5:
      case GL_LIGHT6:
      case GL_LIGHT7:
         if (ctx->Light.Light[cap-GL_LIGHT0].Enabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_LIGHT);
         ctx->Light.Light[cap-GL_LIGHT0].Enabled = state;
         if (state) {
            insert_at_tail(&ctx->Light.EnabledList,
                           &ctx->Light.Light[cap-GL_LIGHT0]);
         }
         else {
            remove_from_list(&ctx->Light.Light[cap-GL_LIGHT0]);
         }
         break;
      case GL_LIGHTING:
         if (ctx->Light.Enabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_LIGHT);
         ctx->Light.Enabled = state;
         if (ctx->Light.Enabled && ctx->Light.Model.TwoSide)
            ctx->_TriangleCaps |= DD_TRI_LIGHT_TWOSIDE;
         else
            ctx->_TriangleCaps &= ~DD_TRI_LIGHT_TWOSIDE;
         break;
      case GL_LINE_SMOOTH:
         if (ctx->Line.SmoothFlag == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_LINE);
         ctx->Line.SmoothFlag = state;
         ctx->_TriangleCaps ^= DD_LINE_SMOOTH;
         break;
      case GL_LINE_STIPPLE:
         if (ctx->Line.StippleFlag == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_LINE);
         ctx->Line.StippleFlag = state;
         ctx->_TriangleCaps ^= DD_LINE_STIPPLE;
         break;
      case GL_INDEX_LOGIC_OP:
         if (ctx->Color.IndexLogicOpEnabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_COLOR);
         ctx->Color.IndexLogicOpEnabled = state;
         break;
      case GL_COLOR_LOGIC_OP:
         if (ctx->Color.ColorLogicOpEnabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_COLOR);
         ctx->Color.ColorLogicOpEnabled = state;
         break;
      case GL_MAP1_COLOR_4:
         if (ctx->Eval.Map1Color4 == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map1Color4 = state;
         break;
      case GL_MAP1_INDEX:
         if (ctx->Eval.Map1Index == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map1Index = state;
         break;
      case GL_MAP1_NORMAL:
         if (ctx->Eval.Map1Normal == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map1Normal = state;
         break;
      case GL_MAP1_TEXTURE_COORD_1:
         if (ctx->Eval.Map1TextureCoord1 == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map1TextureCoord1 = state;
         break;
      case GL_MAP1_TEXTURE_COORD_2:
         if (ctx->Eval.Map1TextureCoord2 == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map1TextureCoord2 = state;
         break;
      case GL_MAP1_TEXTURE_COORD_3:
         if (ctx->Eval.Map1TextureCoord3 == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map1TextureCoord3 = state;
         break;
      case GL_MAP1_TEXTURE_COORD_4:
         if (ctx->Eval.Map1TextureCoord4 == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map1TextureCoord4 = state;
         break;
      case GL_MAP1_VERTEX_3:
         if (ctx->Eval.Map1Vertex3 == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map1Vertex3 = state;
         break;
      case GL_MAP1_VERTEX_4:
         if (ctx->Eval.Map1Vertex4 == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map1Vertex4 = state;
         break;
      case GL_MAP2_COLOR_4:
         if (ctx->Eval.Map2Color4 == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map2Color4 = state;
         break;
      case GL_MAP2_INDEX:
         if (ctx->Eval.Map2Index == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map2Index = state;
         break;
      case GL_MAP2_NORMAL:
         if (ctx->Eval.Map2Normal == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map2Normal = state;
         break;
      case GL_MAP2_TEXTURE_COORD_1:
         if (ctx->Eval.Map2TextureCoord1 == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map2TextureCoord1 = state;
         break;
      case GL_MAP2_TEXTURE_COORD_2:
         if (ctx->Eval.Map2TextureCoord2 == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map2TextureCoord2 = state;
         break;
      case GL_MAP2_TEXTURE_COORD_3:
         if (ctx->Eval.Map2TextureCoord3 == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map2TextureCoord3 = state;
         break;
      case GL_MAP2_TEXTURE_COORD_4:
         if (ctx->Eval.Map2TextureCoord4 == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map2TextureCoord4 = state;
         break;
      case GL_MAP2_VERTEX_3:
         if (ctx->Eval.Map2Vertex3 == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map2Vertex3 = state;
         break;
      case GL_MAP2_VERTEX_4:
         if (ctx->Eval.Map2Vertex4 == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_EVAL);
         ctx->Eval.Map2Vertex4 = state;
         break;
      case GL_MINMAX:
         if (ctx->Pixel.MinMaxEnabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.MinMaxEnabled = state;
         break;
      case GL_NORMALIZE:
         if (ctx->Transform.Normalize == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
         ctx->Transform.Normalize = state;
         break;
      case GL_POINT_SMOOTH:
         if (ctx->Point.SmoothFlag == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_POINT);
         ctx->Point.SmoothFlag = state;
         ctx->_TriangleCaps ^= DD_POINT_SMOOTH;
         break;
      case GL_POLYGON_SMOOTH:
         if (ctx->Polygon.SmoothFlag == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_POLYGON);
         ctx->Polygon.SmoothFlag = state;
         ctx->_TriangleCaps ^= DD_TRI_SMOOTH;
         break;
      case GL_POLYGON_STIPPLE:
         if (ctx->Polygon.StippleFlag == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_POLYGON);
         ctx->Polygon.StippleFlag = state;
         ctx->_TriangleCaps ^= DD_TRI_STIPPLE;
         break;
      case GL_POLYGON_OFFSET_POINT:
         if (ctx->Polygon.OffsetPoint == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_POLYGON);
         ctx->Polygon.OffsetPoint = state;
         break;
      case GL_POLYGON_OFFSET_LINE:
         if (ctx->Polygon.OffsetLine == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_POLYGON);
         ctx->Polygon.OffsetLine = state;
         break;
      case GL_POLYGON_OFFSET_FILL:
         /*case GL_POLYGON_OFFSET_EXT:*/
         if (ctx->Polygon.OffsetFill == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_POLYGON);
         ctx->Polygon.OffsetFill = state;
         break;
      case GL_RESCALE_NORMAL_EXT:
         if (ctx->Transform.RescaleNormals == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
         ctx->Transform.RescaleNormals = state;
         break;
      case GL_SCISSOR_TEST:
         if (ctx->Scissor.Enabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_SCISSOR);
         ctx->Scissor.Enabled = state;
         break;
      case GL_SHARED_TEXTURE_PALETTE_EXT:
         if (ctx->Texture.SharedPalette == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_TEXTURE);
         ctx->Texture.SharedPalette = state;
         break;
      case GL_STENCIL_TEST:
         if (ctx->Stencil.Enabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_STENCIL);
         ctx->Stencil.Enabled = state;
         break;
      case GL_TEXTURE_1D:
         if (!enable_texture(ctx, state, TEXTURE_1D_BIT)) {
            return;
         }
         break;
      case GL_TEXTURE_2D:
         if (!enable_texture(ctx, state, TEXTURE_2D_BIT)) {
            return;
         }
         break;
      case GL_TEXTURE_3D:
         if (!enable_texture(ctx, state, TEXTURE_3D_BIT)) {
            return;
         }
         break;
      case GL_TEXTURE_GEN_Q:
         {
            struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
            if (texUnit) {
               GLuint newenabled = texUnit->TexGenEnabled & ~Q_BIT;
               if (state)
                  newenabled |= Q_BIT;
               if (texUnit->TexGenEnabled == newenabled)
                  return;
               FLUSH_VERTICES(ctx, _NEW_TEXTURE);
               texUnit->TexGenEnabled = newenabled;
            }
         }
         break;
      case GL_TEXTURE_GEN_R:
         {
            struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
            if (texUnit) {
               GLuint newenabled = texUnit->TexGenEnabled & ~R_BIT;
               if (state)
                  newenabled |= R_BIT;
               if (texUnit->TexGenEnabled == newenabled)
                  return;
               FLUSH_VERTICES(ctx, _NEW_TEXTURE);
               texUnit->TexGenEnabled = newenabled;
            }
         }
         break;
      case GL_TEXTURE_GEN_S:
         {
            struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
            if (texUnit) {
               GLuint newenabled = texUnit->TexGenEnabled & ~S_BIT;
               if (state)
                  newenabled |= S_BIT;
               if (texUnit->TexGenEnabled == newenabled)
                  return;
               FLUSH_VERTICES(ctx, _NEW_TEXTURE);
               texUnit->TexGenEnabled = newenabled;
            }
         }
         break;
      case GL_TEXTURE_GEN_T:
         {
            struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
            if (texUnit) {
               GLuint newenabled = texUnit->TexGenEnabled & ~T_BIT;
               if (state)
                  newenabled |= T_BIT;
               if (texUnit->TexGenEnabled == newenabled)
                  return;
               FLUSH_VERTICES(ctx, _NEW_TEXTURE);
               texUnit->TexGenEnabled = newenabled;
            }
         }
         break;

      /*
       * CLIENT STATE!!!
       */
      case GL_VERTEX_ARRAY:
      case GL_NORMAL_ARRAY:
      case GL_COLOR_ARRAY:
      case GL_INDEX_ARRAY:
      case GL_TEXTURE_COORD_ARRAY:
      case GL_EDGE_FLAG_ARRAY:
      case GL_FOG_COORDINATE_ARRAY_EXT:
      case GL_SECONDARY_COLOR_ARRAY_EXT:
      case GL_POINT_SIZE_ARRAY_OES:
         client_state( ctx, cap, state );
         return;

      /* GL_SGI_color_table */
      case GL_COLOR_TABLE_SGI:
         CHECK_EXTENSION(SGI_color_table, cap);
         if (ctx->Pixel.ColorTableEnabled[COLORTABLE_PRECONVOLUTION] == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.ColorTableEnabled[COLORTABLE_PRECONVOLUTION] = state;
         break;
      case GL_POST_CONVOLUTION_COLOR_TABLE_SGI:
         CHECK_EXTENSION(SGI_color_table, cap);
         if (ctx->Pixel.ColorTableEnabled[COLORTABLE_POSTCONVOLUTION] == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.ColorTableEnabled[COLORTABLE_POSTCONVOLUTION] = state;
         break;
      case GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI:
         CHECK_EXTENSION(SGI_color_table, cap);
         if (ctx->Pixel.ColorTableEnabled[COLORTABLE_POSTCOLORMATRIX] == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.ColorTableEnabled[COLORTABLE_POSTCOLORMATRIX] = state;
         break;
      case GL_TEXTURE_COLOR_TABLE_SGI:
         CHECK_EXTENSION(SGI_texture_color_table, cap);
         if (ctx->Texture.Unit[ctx->Texture.CurrentUnit].ColorTableEnabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_TEXTURE);
         ctx->Texture.Unit[ctx->Texture.CurrentUnit].ColorTableEnabled = state;
         break;

      /* GL_EXT_convolution */
      case GL_CONVOLUTION_1D:
         CHECK_EXTENSION(EXT_convolution, cap);
         if (ctx->Pixel.Convolution1DEnabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.Convolution1DEnabled = state;
         break;
      case GL_CONVOLUTION_2D:
         CHECK_EXTENSION(EXT_convolution, cap);
         if (ctx->Pixel.Convolution2DEnabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.Convolution2DEnabled = state;
         break;
      case GL_SEPARABLE_2D:
         CHECK_EXTENSION(EXT_convolution, cap);
         if (ctx->Pixel.Separable2DEnabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.Separable2DEnabled = state;
         break;

      /* GL_ARB_texture_cube_map */
      case GL_TEXTURE_CUBE_MAP_ARB:
         CHECK_EXTENSION(ARB_texture_cube_map, cap);
         if (!enable_texture(ctx, state, TEXTURE_CUBE_BIT)) {
            return;
         }
         break;

      /* GL_EXT_secondary_color */
      case GL_COLOR_SUM_EXT:
         CHECK_EXTENSION2(EXT_secondary_color, ARB_vertex_program, cap);
         if (ctx->Fog.ColorSumEnabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_FOG);
         ctx->Fog.ColorSumEnabled = state;
         break;

      /* GL_ARB_multisample */
      case GL_MULTISAMPLE_ARB:
         if (ctx->Multisample.Enabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE);
         ctx->Multisample.Enabled = state;
         break;
      case GL_SAMPLE_ALPHA_TO_COVERAGE_ARB:
         if (ctx->Multisample.SampleAlphaToCoverage == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE);
         ctx->Multisample.SampleAlphaToCoverage = state;
         break;
      case GL_SAMPLE_ALPHA_TO_ONE_ARB:
         if (ctx->Multisample.SampleAlphaToOne == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE);
         ctx->Multisample.SampleAlphaToOne = state;
         break;
      case GL_SAMPLE_COVERAGE_ARB:
         if (ctx->Multisample.SampleCoverage == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE);
         ctx->Multisample.SampleCoverage = state;
         break;
      case GL_SAMPLE_COVERAGE_INVERT_ARB:
         if (ctx->Multisample.SampleCoverageInvert == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE);
         ctx->Multisample.SampleCoverageInvert = state;
         break;

      /* GL_IBM_rasterpos_clip */
      case GL_RASTER_POSITION_UNCLIPPED_IBM:
         CHECK_EXTENSION(IBM_rasterpos_clip, cap);
         if (ctx->Transform.RasterPositionUnclipped == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
         ctx->Transform.RasterPositionUnclipped = state;
         break;

      /* GL_NV_point_sprite */
      case GL_POINT_SPRITE_NV:
         CHECK_EXTENSION2(NV_point_sprite, ARB_point_sprite, cap);
         if (ctx->Point.PointSprite == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_POINT);
         ctx->Point.PointSprite = state;
         break;

#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
      case GL_VERTEX_PROGRAM_ARB:
         CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap);
         if (ctx->VertexProgram.Enabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_PROGRAM); 
         ctx->VertexProgram.Enabled = state;
         break;
      case GL_VERTEX_PROGRAM_POINT_SIZE_ARB:
         CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap);
         if (ctx->VertexProgram.PointSizeEnabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_PROGRAM);
         ctx->VertexProgram.PointSizeEnabled = state;
         break;
      case GL_VERTEX_PROGRAM_TWO_SIDE_ARB:
         CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap);
         if (ctx->VertexProgram.TwoSideEnabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_PROGRAM); 
         ctx->VertexProgram.TwoSideEnabled = state;
         break;
#endif
#if FEATURE_NV_vertex_program
      case GL_MAP1_VERTEX_ATTRIB0_4_NV:
      case GL_MAP1_VERTEX_ATTRIB1_4_NV:
      case GL_MAP1_VERTEX_ATTRIB2_4_NV:
      case GL_MAP1_VERTEX_ATTRIB3_4_NV:
      case GL_MAP1_VERTEX_ATTRIB4_4_NV:
      case GL_MAP1_VERTEX_ATTRIB5_4_NV:
      case GL_MAP1_VERTEX_ATTRIB6_4_NV:
      case GL_MAP1_VERTEX_ATTRIB7_4_NV:
      case GL_MAP1_VERTEX_ATTRIB8_4_NV:
      case GL_MAP1_VERTEX_ATTRIB9_4_NV:
      case GL_MAP1_VERTEX_ATTRIB10_4_NV:
      case GL_MAP1_VERTEX_ATTRIB11_4_NV:
      case GL_MAP1_VERTEX_ATTRIB12_4_NV:
      case GL_MAP1_VERTEX_ATTRIB13_4_NV:
      case GL_MAP1_VERTEX_ATTRIB14_4_NV:
      case GL_MAP1_VERTEX_ATTRIB15_4_NV:
         CHECK_EXTENSION(NV_vertex_program, cap);
         {
            const GLuint map = (GLuint) (cap - GL_MAP1_VERTEX_ATTRIB0_4_NV);
            FLUSH_VERTICES(ctx, _NEW_EVAL);
            ctx->Eval.Map1Attrib[map] = state;
         }
         break;
      case GL_MAP2_VERTEX_ATTRIB0_4_NV:
      case GL_MAP2_VERTEX_ATTRIB1_4_NV:
      case GL_MAP2_VERTEX_ATTRIB2_4_NV:
      case GL_MAP2_VERTEX_ATTRIB3_4_NV:
      case GL_MAP2_VERTEX_ATTRIB4_4_NV:
      case GL_MAP2_VERTEX_ATTRIB5_4_NV:
      case GL_MAP2_VERTEX_ATTRIB6_4_NV:
      case GL_MAP2_VERTEX_ATTRIB7_4_NV:
      case GL_MAP2_VERTEX_ATTRIB8_4_NV:
      case GL_MAP2_VERTEX_ATTRIB9_4_NV:
      case GL_MAP2_VERTEX_ATTRIB10_4_NV:
      case GL_MAP2_VERTEX_ATTRIB11_4_NV:
      case GL_MAP2_VERTEX_ATTRIB12_4_NV:
      case GL_MAP2_VERTEX_ATTRIB13_4_NV:
      case GL_MAP2_VERTEX_ATTRIB14_4_NV:
      case GL_MAP2_VERTEX_ATTRIB15_4_NV:
         CHECK_EXTENSION(NV_vertex_program, cap);
         {
            const GLuint map = (GLuint) (cap - GL_MAP2_VERTEX_ATTRIB0_4_NV);
            FLUSH_VERTICES(ctx, _NEW_EVAL);
            ctx->Eval.Map2Attrib[map] = state;
         }
         break;
#endif /* FEATURE_NV_vertex_program */

#if FEATURE_NV_fragment_program
      case GL_FRAGMENT_PROGRAM_NV:
         CHECK_EXTENSION(NV_fragment_program, cap);
         if (ctx->FragmentProgram.Enabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_PROGRAM);
         ctx->FragmentProgram.Enabled = state;
         break;
#endif /* FEATURE_NV_fragment_program */

      /* GL_NV_texture_rectangle */
      case GL_TEXTURE_RECTANGLE_NV:
         CHECK_EXTENSION(NV_texture_rectangle, cap);
         if (!enable_texture(ctx, state, TEXTURE_RECT_BIT)) {
            return;
         }
         break;

      /* GL_EXT_stencil_two_side */
      case GL_STENCIL_TEST_TWO_SIDE_EXT:
         CHECK_EXTENSION(EXT_stencil_two_side, cap);
         if (ctx->Stencil.TestTwoSide == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_STENCIL);
         ctx->Stencil.TestTwoSide = state;
         if (state) {
            ctx->Stencil._BackFace = 2;
            ctx->_TriangleCaps |= DD_TRI_TWOSTENCIL;
         } else {
            ctx->Stencil._BackFace = 1;
            ctx->_TriangleCaps &= ~DD_TRI_TWOSTENCIL;
         }
         break;

#if FEATURE_ARB_fragment_program
      case GL_FRAGMENT_PROGRAM_ARB:
         CHECK_EXTENSION(ARB_fragment_program, cap);
         if (ctx->FragmentProgram.Enabled == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_PROGRAM);
         ctx->FragmentProgram.Enabled = state;
         break;
#endif /* FEATURE_ARB_fragment_program */

      /* GL_EXT_depth_bounds_test */
      case GL_DEPTH_BOUNDS_TEST_EXT:
         CHECK_EXTENSION(EXT_depth_bounds_test, cap);
         if (ctx->Depth.BoundsTest == state)
            return;
         FLUSH_VERTICES(ctx, _NEW_DEPTH);
         ctx->Depth.BoundsTest = state;
         break;

      case GL_DEPTH_CLAMP:
         if (ctx->Transform.DepthClamp == state)
            return;
	 CHECK_EXTENSION(ARB_depth_clamp, cap);
         FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
	 ctx->Transform.DepthClamp = state;
	 break;

#if FEATURE_ATI_fragment_shader
      case GL_FRAGMENT_SHADER_ATI:
        CHECK_EXTENSION(ATI_fragment_shader, cap);
	if (ctx->ATIFragmentShader.Enabled == state)
	  return;
	FLUSH_VERTICES(ctx, _NEW_PROGRAM);
	ctx->ATIFragmentShader.Enabled = state;
        break;
#endif

      /* GL_MESA_texture_array */
      case GL_TEXTURE_1D_ARRAY_EXT:
         CHECK_EXTENSION(MESA_texture_array, cap);
         if (!enable_texture(ctx, state, TEXTURE_1D_ARRAY_BIT)) {
            return;
         }
         break;

      case GL_TEXTURE_2D_ARRAY_EXT:
         CHECK_EXTENSION(MESA_texture_array, cap);
         if (!enable_texture(ctx, state, TEXTURE_2D_ARRAY_BIT)) {
            return;
         }
         break;

      case GL_TEXTURE_CUBE_MAP_SEAMLESS:
	 CHECK_EXTENSION(ARB_seamless_cube_map, cap);
	 ctx->Texture.CubeMapSeamless = state;
	 break;

      default:
         _mesa_error(ctx, GL_INVALID_ENUM,
                     "%s(0x%x)", state ? "glEnable" : "glDisable", cap);
         return;
   }

   if (ctx->Driver.Enable) {
      ctx->Driver.Enable( ctx, cap, state );
   }
}
void GLAPIENTRY
_mesa_BeginQueryARB(GLenum target, GLuint id)
{
   struct gl_query_object *q;
   GET_CURRENT_CONTEXT(ctx);
   ASSERT_OUTSIDE_BEGIN_END(ctx);

   FLUSH_VERTICES(ctx, _NEW_DEPTH);

   switch (target) {
      case GL_SAMPLES_PASSED_ARB:
         if (!ctx->Extensions.ARB_occlusion_query) {
            _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
            return;
         }
         if (ctx->Query.CurrentOcclusionObject) {
            _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB");
            return;
         }
         break;
#if FEATURE_EXT_timer_query
      case GL_TIME_ELAPSED_EXT:
         if (!ctx->Extensions.EXT_timer_query) {
            _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
            return;
         }
         if (ctx->Query.CurrentTimerObject) {
            _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB");
            return;
         }
         break;
#endif
      default:
         _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
         return;
   }

   if (id == 0) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB(id==0)");
      return;
   }

   q = lookup_query_object(ctx, id);
   if (!q) {
      /* create new object */
      q = ctx->Driver.NewQueryObject(ctx, id);
      if (!q) {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQueryARB");
         return;
      }
      _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
   }
   else {
      /* pre-existing object */
      if (q->Active) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glBeginQueryARB(query already active)");
         return;
      }
   }

   q->Active = GL_TRUE;
   q->Result = 0;
   q->Ready = GL_FALSE;

   if (target == GL_SAMPLES_PASSED_ARB) {
      ctx->Query.CurrentOcclusionObject = q;
   }
#if FEATURE_EXT_timer_query
   else if (target == GL_TIME_ELAPSED_EXT) {
      ctx->Query.CurrentTimerObject = q;
   }
#endif

   if (ctx->Driver.BeginQuery) {
      ctx->Driver.BeginQuery(ctx, target, q);
   }
}
Beispiel #3
0
/**
 * Called by glUniformMatrix*() functions.
 * Note: cols=2, rows=4  ==>  array[2] of vec4
 */
extern "C" void
_mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg,
		     GLuint cols, GLuint rows,
                     GLint location, GLsizei count,
                     GLboolean transpose, const GLfloat *values)
{
   unsigned loc, offset;
   unsigned vectors;
   unsigned components;
   unsigned elements;
   struct gl_uniform_storage *uni;

   ASSERT_OUTSIDE_BEGIN_END(ctx);

   if (!validate_uniform_parameters(ctx, shProg, location, count,
				    &loc, &offset, "glUniformMatrix", false))
      return;

   uni = &shProg->UniformStorage[loc];
   if (!uni->type->is_matrix()) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
		  "glUniformMatrix(non-matrix uniform)");
      return;
   }

   assert(!uni->type->is_sampler());
   vectors = uni->type->matrix_columns;
   components = uni->type->vector_elements;

   /* Verify that the types are compatible.  This is greatly simplified for
    * matrices because they can only have a float base type.
    */
   if (vectors != cols || components != rows) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
		  "glUniformMatrix(matrix size mismatch)");
      return;
   }

   if (ctx->Shader.Flags & GLSL_UNIFORMS) {
      log_uniform(values, GLSL_TYPE_FLOAT, components, vectors, count,
		  bool(transpose), shProg, location, uni);
   }

   /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
    *
    *     "When loading N elements starting at an arbitrary position k in a
    *     uniform declared as an array, elements k through k + N - 1 in the
    *     array will be replaced with the new values. Values for any array
    *     element that exceeds the highest array element index used, as
    *     reported by GetActiveUniform, will be ignored by the GL."
    *
    * Clamp 'count' to a valid value.  Note that for non-arrays a count > 1
    * will have already generated an error.
    */
   if (uni->array_elements != 0) {
      if (offset >= uni->array_elements)
	 return;

      count = MIN2(count, (int) (uni->array_elements - offset));
   }

   FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);

   /* Store the data in the "actual type" backing storage for the uniform.
    */
   elements = components * vectors;

   if (!transpose) {
      memcpy(&uni->storage[elements * offset], values,
	     sizeof(uni->storage[0]) * elements * count);
   } else {
      /* Copy and transpose the matrix.
       */
      const float *src = values;
      float *dst = &uni->storage[elements * offset].f;

      for (int i = 0; i < count; i++) {
	 for (unsigned r = 0; r < rows; r++) {
	    for (unsigned c = 0; c < cols; c++) {
	       dst[(c * components) + r] = src[c + (r * vectors)];
	    }
	 }

	 dst += elements;
	 src += elements;
      }
   }

   uni->initialized = true;

   _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
}
Beispiel #4
0
/**
 * Called via ctx->Driver.Uniform().
 */
void
_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
              const GLvoid *values, GLenum type)
{
   struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
   GLint elems, i, k;
   GLenum uType;
   GLsizei maxCount;

   if (!shProg || !shProg->LinkStatus) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
      return;
   }

   if (location == -1)
      return;   /* The standard specifies this as a no-op */

   /* The spec says this is GL_INVALID_OPERATION, although it seems like it
    * ought to be GL_INVALID_VALUE
    */
   if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location)");
      return;
   }

   FLUSH_VERTICES(ctx, _NEW_PROGRAM);

   uType = shProg->Uniforms->Parameters[location].DataType;
   /*
    * If we're setting a sampler, we must use glUniformi1()!
    */
   if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
      GLint unit;
      if (type != GL_INT || count != 1) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glUniform(only glUniform1i can be used "
                     "to set sampler uniforms)");
         return;
      }
      /* check that the sampler (tex unit index) is legal */
      unit = ((GLint *) values)[0];
      if (unit >= ctx->Const.MaxTextureImageUnits) {
         _mesa_error(ctx, GL_INVALID_VALUE,
                     "glUniform1(invalid sampler/tex unit index)");
         return;
      }
   }

   if (count < 0) {
      _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
      return;
   }

   switch (type) {
   case GL_FLOAT:
   case GL_INT:
      elems = 1;
      break;
   case GL_FLOAT_VEC2:
   case GL_INT_VEC2:
      elems = 2;
      break;
   case GL_FLOAT_VEC3:
   case GL_INT_VEC3:
      elems = 3;
      break;
   case GL_FLOAT_VEC4:
   case GL_INT_VEC4:
      elems = 4;
      break;
   default:
      _mesa_problem(ctx, "Invalid type in _mesa_uniform");
      return;
   }

   /* OpenGL requires types to match exactly, except that one can convert
    * float or int array to boolean array.
    */
   switch (uType)
   {
      case GL_BOOL:
      case GL_BOOL_VEC2:
      case GL_BOOL_VEC3:
      case GL_BOOL_VEC4:
         if (elems != sizeof_glsl_type(uType)) {
            _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count mismatch)");
         }
         break;
      case PROGRAM_SAMPLER:
         break;
      default:
         if (shProg->Uniforms->Parameters[location].Type != PROGRAM_SAMPLER 
             && uType != type) {
            _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
         }
         break;
   }

   /* XXX if this is a base type, then count must equal 1. However, we
    * don't have enough information from the compiler to distinguish a
    * base type from a 1-element array of that type. The standard allows
    * count to overrun an array, in which case the overflow is ignored.
    */
   maxCount = shProg->Uniforms->Parameters[location].Size / elems;
   if (count > maxCount) count = maxCount;

   for (k = 0; k < count; k++) {
      GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k];
      if (type == GL_INT ||
          type == GL_INT_VEC2 ||
          type == GL_INT_VEC3 ||
          type == GL_INT_VEC4) {
         const GLint *iValues = ((const GLint *) values) + k * elems;
         for (i = 0; i < elems; i++) {
            uniformVal[i] = (GLfloat) iValues[i];
         }
      }
      else {
         const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
         for (i = 0; i < elems; i++) {
            uniformVal[i] = fValues[i];
         }
      }
      if (uType == GL_BOOL ||
          uType == GL_BOOL_VEC2 ||
          uType == GL_BOOL_VEC3 ||
          uType == GL_BOOL_VEC4) {
          for (i = 0; i < elems; i++)
              uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f;
      }
   }

   if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
      if (shProg->VertexProgram)
         _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
      if (shProg->FragmentProgram)
         _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
      FLUSH_VERTICES(ctx, _NEW_TEXTURE);
   }
}
Beispiel #5
0
void GLAPIENTRY
_mesa_Fogfv( GLenum pname, const GLfloat *params )
{
   GET_CURRENT_CONTEXT(ctx);
   GLenum m;
   ASSERT_OUTSIDE_BEGIN_END(ctx);

   switch (pname) {
      case GL_FOG_MODE:
         m = (GLenum) (GLint) *params;
	 switch (m) {
	 case GL_LINEAR:
	 case GL_EXP:
	 case GL_EXP2:
	    break;
	 default:
	    _mesa_error( ctx, GL_INVALID_ENUM, "glFog" );
            return;
	 }
	 if (ctx->Fog.Mode == m)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_FOG);
	 ctx->Fog.Mode = m;
	 break;
      case GL_FOG_DENSITY:
	 if (*params<0.0) {
	    _mesa_error( ctx, GL_INVALID_VALUE, "glFog" );
            return;
	 }
	 if (ctx->Fog.Density == *params)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_FOG);
	 ctx->Fog.Density = *params;
	 break;
      case GL_FOG_START:
         if (ctx->Fog.Start == *params)
            return;
         FLUSH_VERTICES(ctx, _NEW_FOG);
         ctx->Fog.Start = *params;
         UPDATE_FOG_SCALE(ctx);
         break;
      case GL_FOG_END:
         if (ctx->Fog.End == *params)
            return;
         FLUSH_VERTICES(ctx, _NEW_FOG);
         ctx->Fog.End = *params;
         UPDATE_FOG_SCALE(ctx);
         break;
      case GL_FOG_INDEX:
 	 if (ctx->Fog.Index == *params)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_FOG);
 	 ctx->Fog.Index = *params;
	 break;
      case GL_FOG_COLOR:
	 if (TEST_EQ_4V(ctx->Fog.Color, params))
	    return;
	 FLUSH_VERTICES(ctx, _NEW_FOG);
	 ctx->Fog.Color[0] = CLAMP(params[0], 0.0F, 1.0F);
	 ctx->Fog.Color[1] = CLAMP(params[1], 0.0F, 1.0F);
	 ctx->Fog.Color[2] = CLAMP(params[2], 0.0F, 1.0F);
	 ctx->Fog.Color[3] = CLAMP(params[3], 0.0F, 1.0F);
         break;
      case GL_FOG_COORDINATE_SOURCE_EXT: {
	 GLenum p = (GLenum) (GLint) *params;
         if (!ctx->Extensions.EXT_fog_coord ||
             (p != GL_FOG_COORDINATE_EXT && p != GL_FRAGMENT_DEPTH_EXT)) {
	    _mesa_error(ctx, GL_INVALID_ENUM, "glFog");
	    return;
	 }
	 if (ctx->Fog.FogCoordinateSource == p)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_FOG);
	 ctx->Fog.FogCoordinateSource = p;
	 break;
      }
      default:
         _mesa_error( ctx, GL_INVALID_ENUM, "glFog" );
         return;
   }

   if (ctx->Driver.Fogfv) {
      (*ctx->Driver.Fogfv)( ctx, pname, params );
   }
}
Beispiel #6
0
/*
 * Implements glPixelTransfer[fi] whether called immediately or from a
 * display list.
 */
void GLAPIENTRY
_mesa_PixelTransferf( GLenum pname, GLfloat param )
{
   GET_CURRENT_CONTEXT(ctx);
   ASSERT_OUTSIDE_BEGIN_END(ctx);

   switch (pname) {
      case GL_MAP_COLOR:
         if (ctx->Pixel.MapColorFlag == (param ? GL_TRUE : GL_FALSE))
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.MapColorFlag = param ? GL_TRUE : GL_FALSE;
	 break;
      case GL_MAP_STENCIL:
         if (ctx->Pixel.MapStencilFlag == (param ? GL_TRUE : GL_FALSE))
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.MapStencilFlag = param ? GL_TRUE : GL_FALSE;
	 break;
      case GL_INDEX_SHIFT:
         if (ctx->Pixel.IndexShift == (GLint) param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.IndexShift = (GLint) param;
	 break;
      case GL_INDEX_OFFSET:
         if (ctx->Pixel.IndexOffset == (GLint) param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.IndexOffset = (GLint) param;
	 break;
      case GL_RED_SCALE:
         if (ctx->Pixel.RedScale == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.RedScale = param;
	 break;
      case GL_RED_BIAS:
         if (ctx->Pixel.RedBias == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.RedBias = param;
	 break;
      case GL_GREEN_SCALE:
         if (ctx->Pixel.GreenScale == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.GreenScale = param;
	 break;
      case GL_GREEN_BIAS:
         if (ctx->Pixel.GreenBias == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.GreenBias = param;
	 break;
      case GL_BLUE_SCALE:
         if (ctx->Pixel.BlueScale == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.BlueScale = param;
	 break;
      case GL_BLUE_BIAS:
         if (ctx->Pixel.BlueBias == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.BlueBias = param;
	 break;
      case GL_ALPHA_SCALE:
         if (ctx->Pixel.AlphaScale == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.AlphaScale = param;
	 break;
      case GL_ALPHA_BIAS:
         if (ctx->Pixel.AlphaBias == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.AlphaBias = param;
	 break;
      case GL_DEPTH_SCALE:
         if (ctx->Pixel.DepthScale == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.DepthScale = param;
	 break;
      case GL_DEPTH_BIAS:
         if (ctx->Pixel.DepthBias == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.DepthBias = param;
	 break;
      case GL_POST_COLOR_MATRIX_RED_SCALE:
         if (ctx->Pixel.PostColorMatrixScale[0] == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.PostColorMatrixScale[0] = param;
	 break;
      case GL_POST_COLOR_MATRIX_RED_BIAS:
         if (ctx->Pixel.PostColorMatrixBias[0] == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.PostColorMatrixBias[0] = param;
	 break;
      case GL_POST_COLOR_MATRIX_GREEN_SCALE:
         if (ctx->Pixel.PostColorMatrixScale[1] == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.PostColorMatrixScale[1] = param;
	 break;
      case GL_POST_COLOR_MATRIX_GREEN_BIAS:
         if (ctx->Pixel.PostColorMatrixBias[1] == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.PostColorMatrixBias[1] = param;
	 break;
      case GL_POST_COLOR_MATRIX_BLUE_SCALE:
         if (ctx->Pixel.PostColorMatrixScale[2] == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.PostColorMatrixScale[2] = param;
	 break;
      case GL_POST_COLOR_MATRIX_BLUE_BIAS:
         if (ctx->Pixel.PostColorMatrixBias[2] == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.PostColorMatrixBias[2] = param;
	 break;
      case GL_POST_COLOR_MATRIX_ALPHA_SCALE:
         if (ctx->Pixel.PostColorMatrixScale[3] == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.PostColorMatrixScale[3] = param;
	 break;
      case GL_POST_COLOR_MATRIX_ALPHA_BIAS:
         if (ctx->Pixel.PostColorMatrixBias[3] == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.PostColorMatrixBias[3] = param;
	 break;
      case GL_POST_CONVOLUTION_RED_SCALE:
         if (ctx->Pixel.PostConvolutionScale[0] == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.PostConvolutionScale[0] = param;
	 break;
      case GL_POST_CONVOLUTION_RED_BIAS:
         if (ctx->Pixel.PostConvolutionBias[0] == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.PostConvolutionBias[0] = param;
	 break;
      case GL_POST_CONVOLUTION_GREEN_SCALE:
         if (ctx->Pixel.PostConvolutionScale[1] == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.PostConvolutionScale[1] = param;
	 break;
      case GL_POST_CONVOLUTION_GREEN_BIAS:
         if (ctx->Pixel.PostConvolutionBias[1] == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.PostConvolutionBias[1] = param;
	 break;
      case GL_POST_CONVOLUTION_BLUE_SCALE:
         if (ctx->Pixel.PostConvolutionScale[2] == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.PostConvolutionScale[2] = param;
	 break;
      case GL_POST_CONVOLUTION_BLUE_BIAS:
         if (ctx->Pixel.PostConvolutionBias[2] == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.PostConvolutionBias[2] = param;
	 break;
      case GL_POST_CONVOLUTION_ALPHA_SCALE:
         if (ctx->Pixel.PostConvolutionScale[3] == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.PostConvolutionScale[3] = param;
	 break;
      case GL_POST_CONVOLUTION_ALPHA_BIAS:
         if (ctx->Pixel.PostConvolutionBias[3] == param)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
         ctx->Pixel.PostConvolutionBias[3] = param;
	 break;
      default:
         _mesa_error( ctx, GL_INVALID_ENUM, "glPixelTransfer(pname)" );
         return;
   }
}
Beispiel #7
0
static bool
use_shader_program(struct gl_context *ctx, GLenum type,
		   struct gl_shader_program *shProg)
{
   struct gl_shader_program **target;

   switch (type) {
#if FEATURE_ARB_vertex_shader
   case GL_VERTEX_SHADER:
      target = &ctx->Shader.CurrentVertexProgram;
      if ((shProg == NULL)
	  || (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)) {
	 shProg = NULL;
      }
      break;
#endif
#if FEATURE_ARB_geometry_shader4
   case GL_GEOMETRY_SHADER_ARB:
      target = &ctx->Shader.CurrentGeometryProgram;
      if ((shProg == NULL)
	  || (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] == NULL)) {
	 shProg = NULL;
      }
      break;
#endif
#if FEATURE_ARB_fragment_shader
   case GL_FRAGMENT_SHADER:
      target = &ctx->Shader.CurrentFragmentProgram;
      if ((shProg == NULL)
	  || (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)) {
	 shProg = NULL;
      }
      break;
#endif
   default:
      return false;
   }

   if (*target != shProg) {
      FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);

      /* If the shader is also bound as the current rendering shader, unbind
       * it from that binding point as well.  This ensures that the correct
       * semantics of glDeleteProgram are maintained.
       */
      switch (type) {
#if FEATURE_ARB_vertex_shader
      case GL_VERTEX_SHADER:
	 /* Empty for now. */
	 break;
#endif
#if FEATURE_ARB_geometry_shader4
      case GL_GEOMETRY_SHADER_ARB:
	 /* Empty for now. */
	 break;
#endif
#if FEATURE_ARB_fragment_shader
      case GL_FRAGMENT_SHADER:
	 if (*target == ctx->Shader._CurrentFragmentProgram) {
	    _mesa_reference_shader_program(ctx,
					   &ctx->Shader._CurrentFragmentProgram,
					   NULL);
	 }
	 break;
#endif
      }

      _mesa_reference_shader_program(ctx, target, shProg);
      return true;
   }

   return false;
}
Beispiel #8
0
/**
 * Called via glUniform*() functions.
 */
extern "C" void
_mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg,
	      GLint location, GLsizei count,
              const GLvoid *values,
              enum glsl_base_type basicType,
              unsigned src_components)
{
   unsigned offset;
   int size_mul = basicType == GLSL_TYPE_DOUBLE ? 2 : 1;

   struct gl_uniform_storage *const uni =
      validate_uniform_parameters(ctx, shProg, location, count,
                                  &offset, "glUniform");
   if (uni == NULL)
      return;

   if (uni->type->is_matrix()) {
      /* Can't set matrix uniforms (like mat4) with glUniform */
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glUniform%u(uniform \"%s\"@%d is matrix)",
                  src_components, uni->name, location);
      return;
   }

   /* Verify that the types are compatible.
    */
   const unsigned components = uni->type->is_sampler()
      ? 1 : uni->type->vector_elements;

   if (components != src_components) {
      /* glUniformN() must match float/vecN type */
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glUniform%u(\"%s\"@%u has %u components, not %u)",
                  src_components, uni->name, location,
                  components, src_components);
      return;
   }

   bool match;
   switch (uni->type->base_type) {
   case GLSL_TYPE_BOOL:
      match = (basicType != GLSL_TYPE_DOUBLE);
      break;
   case GLSL_TYPE_SAMPLER:
   case GLSL_TYPE_IMAGE:
      match = (basicType == GLSL_TYPE_INT);
      break;
   default:
      match = (basicType == uni->type->base_type);
      break;
   }

   if (!match) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glUniform%u(\"%s\"@%d is %s, not %s)",
                  src_components, uni->name, location,
                  glsl_type_name(uni->type->base_type),
                  glsl_type_name(basicType));
      return;
   }

   if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) {
      log_uniform(values, basicType, components, 1, count,
		  false, shProg, location, uni);
   }

   /* Page 100 (page 116 of the PDF) of the OpenGL 3.0 spec says:
    *
    *     "Setting a sampler's value to i selects texture image unit number
    *     i. The values of i range from zero to the implementation- dependent
    *     maximum supported number of texture image units."
    *
    * In addition, table 2.3, "Summary of GL errors," on page 17 (page 33 of
    * the PDF) says:
    *
    *     "Error         Description                    Offending command
    *                                                   ignored?
    *     ...
    *     INVALID_VALUE  Numeric argument out of range  Yes"
    *
    * Based on that, when an invalid sampler is specified, we generate a
    * GL_INVALID_VALUE error and ignore the command.
    */
   if (uni->type->is_sampler()) {
      for (int i = 0; i < count; i++) {
	 const unsigned texUnit = ((unsigned *) values)[i];

         /* check that the sampler (tex unit index) is legal */
         if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) {
            _mesa_error(ctx, GL_INVALID_VALUE,
                        "glUniform1i(invalid sampler/tex unit index for "
			"uniform %d)",
                        location);
            return;
         }
      }
   }

   if (uni->type->is_image()) {
      for (int i = 0; i < count; i++) {
         const int unit = ((GLint *) values)[i];

         /* check that the image unit is legal */
         if (unit < 0 || unit >= (int)ctx->Const.MaxImageUnits) {
            _mesa_error(ctx, GL_INVALID_VALUE,
                        "glUniform1i(invalid image unit index for uniform %d)",
                        location);
            return;
         }
      }
   }

   /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
    *
    *     "When loading N elements starting at an arbitrary position k in a
    *     uniform declared as an array, elements k through k + N - 1 in the
    *     array will be replaced with the new values. Values for any array
    *     element that exceeds the highest array element index used, as
    *     reported by GetActiveUniform, will be ignored by the GL."
    *
    * Clamp 'count' to a valid value.  Note that for non-arrays a count > 1
    * will have already generated an error.
    */
   if (uni->array_elements != 0) {
      count = MIN2(count, (int) (uni->array_elements - offset));
   }

   FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);

   /* Store the data in the "actual type" backing storage for the uniform.
    */
   if (!uni->type->is_boolean()) {
      memcpy(&uni->storage[size_mul * components * offset], values,
	     sizeof(uni->storage[0]) * components * count * size_mul);
   } else {
      const union gl_constant_value *src =
	 (const union gl_constant_value *) values;
      union gl_constant_value *dst = &uni->storage[components * offset];
      const unsigned elems = components * count;

      for (unsigned i = 0; i < elems; i++) {
	 if (basicType == GLSL_TYPE_FLOAT) {
            dst[i].i = src[i].f != 0.0f ? ctx->Const.UniformBooleanTrue : 0;
	 } else {
            dst[i].i = src[i].i != 0    ? ctx->Const.UniformBooleanTrue : 0;
	 }
      }
   }

   uni->initialized = true;

   _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);

   /* If the uniform is a sampler, do the extra magic necessary to propagate
    * the changes through.
    */
   if (uni->type->is_sampler()) {
      bool flushed = false;
      for (int i = 0; i < MESA_SHADER_STAGES; i++) {
	 struct gl_shader *const sh = shProg->_LinkedShaders[i];

	 /* If the shader stage doesn't use the sampler uniform, skip this.
	  */
	 if (sh == NULL || !uni->sampler[i].active)
	    continue;

         for (int j = 0; j < count; j++) {
            sh->SamplerUnits[uni->sampler[i].index + offset + j] =
               ((unsigned *) values)[j];
         }

	 struct gl_program *const prog = sh->Program;

	 assert(sizeof(prog->SamplerUnits) == sizeof(sh->SamplerUnits));

	 /* Determine if any of the samplers used by this shader stage have
	  * been modified.
	  */
	 bool changed = false;
	 for (unsigned j = 0; j < ARRAY_SIZE(prog->SamplerUnits); j++) {
	    if ((sh->active_samplers & (1U << j)) != 0
		&& (prog->SamplerUnits[j] != sh->SamplerUnits[j])) {
	       changed = true;
	       break;
	    }
	 }

	 if (changed) {
	    if (!flushed) {
	       FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
	       flushed = true;
	    }

	    memcpy(prog->SamplerUnits,
		   sh->SamplerUnits,
		   sizeof(sh->SamplerUnits));

	    _mesa_update_shader_textures_used(shProg, prog);
            if (ctx->Driver.SamplerUniformChange)
	       ctx->Driver.SamplerUniformChange(ctx, prog->Target, prog);
	 }
      }
   }

   /* If the uniform is an image, update the mapping from image
    * uniforms to image units present in the shader data structure.
    */
   if (uni->type->is_image()) {
      for (int i = 0; i < MESA_SHADER_STAGES; i++) {
	 if (uni->image[i].active) {
            struct gl_shader *sh = shProg->_LinkedShaders[i];

            for (int j = 0; j < count; j++)
               sh->ImageUnits[uni->image[i].index + offset + j] =
                  ((GLint *) values)[j];
         }
      }

      ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits;
   }
}
Beispiel #9
0
/**
 * Called by glUniformMatrix*() functions.
 * Note: cols=2, rows=4  ==>  array[2] of vec4
 */
extern "C" void
_mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg,
		     GLuint cols, GLuint rows,
                     GLint location, GLsizei count,
                     GLboolean transpose,
                     const GLvoid *values, GLenum type)
{
   unsigned offset;
   unsigned vectors;
   unsigned components;
   unsigned elements;
   int size_mul;
   struct gl_uniform_storage *const uni =
      validate_uniform_parameters(ctx, shProg, location, count,
                                  &offset, "glUniformMatrix");
   if (uni == NULL)
      return;

   if (!uni->type->is_matrix()) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
		  "glUniformMatrix(non-matrix uniform)");
      return;
   }

   assert(type == GL_FLOAT || type == GL_DOUBLE);
   size_mul = type == GL_DOUBLE ? 2 : 1;

   assert(!uni->type->is_sampler());
   vectors = uni->type->matrix_columns;
   components = uni->type->vector_elements;

   /* Verify that the types are compatible.  This is greatly simplified for
    * matrices because they can only have a float base type.
    */
   if (vectors != cols || components != rows) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
		  "glUniformMatrix(matrix size mismatch)");
      return;
   }

   /* GL_INVALID_VALUE is generated if `transpose' is not GL_FALSE.
    * http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml
    */
   if (transpose) {
      if (ctx->API == API_OPENGLES2 && ctx->Version < 30) {
	 _mesa_error(ctx, GL_INVALID_VALUE,
		     "glUniformMatrix(matrix transpose is not GL_FALSE)");
	 return;
      }
   }

   if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) {
      log_uniform(values, uni->type->base_type, components, vectors, count,
		  bool(transpose), shProg, location, uni);
   }

   /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
    *
    *     "When loading N elements starting at an arbitrary position k in a
    *     uniform declared as an array, elements k through k + N - 1 in the
    *     array will be replaced with the new values. Values for any array
    *     element that exceeds the highest array element index used, as
    *     reported by GetActiveUniform, will be ignored by the GL."
    *
    * Clamp 'count' to a valid value.  Note that for non-arrays a count > 1
    * will have already generated an error.
    */
   if (uni->array_elements != 0) {
      count = MIN2(count, (int) (uni->array_elements - offset));
   }

   FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);

   /* Store the data in the "actual type" backing storage for the uniform.
    */
   elements = components * vectors;

   if (!transpose) {
      memcpy(&uni->storage[elements * offset], values,
	     sizeof(uni->storage[0]) * elements * count * size_mul);
   } else if (type == GL_FLOAT) {
      /* Copy and transpose the matrix.
       */
      const float *src = (const float *)values;
      float *dst = &uni->storage[elements * offset].f;

      for (int i = 0; i < count; i++) {
	 for (unsigned r = 0; r < rows; r++) {
	    for (unsigned c = 0; c < cols; c++) {
	       dst[(c * components) + r] = src[c + (r * vectors)];
	    }
	 }

	 dst += elements;
	 src += elements;
      }
   } else {
      assert(type == GL_DOUBLE);
      const double *src = (const double *)values;
      double *dst = (double *)&uni->storage[elements * offset].f;

      for (int i = 0; i < count; i++) {
	 for (unsigned r = 0; r < rows; r++) {
	    for (unsigned c = 0; c < cols; c++) {
	       dst[(c * components) + r] = src[c + (r * vectors)];
	    }
	 }

	 dst += elements;
	 src += elements;
      }
   }

   uni->initialized = true;

   _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
}
Beispiel #10
0
/**
 * Load/parse/compile a program.
 * \note Called from the GL API dispatcher.
 */
void GLAPIENTRY
_mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len,
                    const GLubyte *program)
{
   struct gl_program *prog;
   GET_CURRENT_CONTEXT(ctx);
   ASSERT_OUTSIDE_BEGIN_END(ctx);

   if (!ctx->Extensions.NV_vertex_program
       && !ctx->Extensions.NV_fragment_program) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV()");
      return;
   }

   if (id == 0) {
      _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)");
      return;
   }

   if (len < 0) {
      _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(len)");
      return;
   }

   FLUSH_VERTICES(ctx, _NEW_PROGRAM);

   prog = _mesa_lookup_program(ctx, id);

   if (prog && prog->Target != 0 && prog->Target != target) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)");
      return;
   }

   if ((target == GL_VERTEX_PROGRAM_NV ||
        target == GL_VERTEX_STATE_PROGRAM_NV)
       && ctx->Extensions.NV_vertex_program) {
      struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog;
      if (!vprog || prog == &_mesa_DummyProgram) {
         vprog = (struct gl_vertex_program *)
            ctx->Driver.NewProgram(ctx, target, id);
         if (!vprog) {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
            return;
         }
         _mesa_HashInsert(ctx->Shared->Programs, id, vprog);
      }

      if (ctx->Extensions.ARB_vertex_program
	  && (strncmp((char *) program, "!!ARB", 5) == 0)) {
	 _mesa_parse_arb_vertex_program(ctx, target, program, len, vprog);
      } else {
	 _mesa_parse_nv_vertex_program(ctx, target, program, len, vprog);
      }
   }
   else if (target == GL_FRAGMENT_PROGRAM_NV
            && ctx->Extensions.NV_fragment_program) {
      struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog;
      if (!fprog || prog == &_mesa_DummyProgram) {
         fprog = (struct gl_fragment_program *)
            ctx->Driver.NewProgram(ctx, target, id);
         if (!fprog) {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
            return;
         }
         _mesa_HashInsert(ctx->Shared->Programs, id, fprog);
      }
      _mesa_parse_nv_fragment_program(ctx, target, program, len, fprog);
   }
   else if (target == GL_FRAGMENT_PROGRAM_ARB
            && ctx->Extensions.ARB_fragment_program) {
      struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog;
      if (!fprog || prog == &_mesa_DummyProgram) {
         fprog = (struct gl_fragment_program *)
            ctx->Driver.NewProgram(ctx, target, id);
         if (!fprog) {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
            return;
         }
         _mesa_HashInsert(ctx->Shared->Programs, id, fprog);
      }
      _mesa_parse_arb_fragment_program(ctx, target, program, len, fprog);
   }
   else {
      _mesa_error(ctx, GL_INVALID_ENUM, "glLoadProgramNV(target)");
   }
}
Beispiel #11
0
/**
 * Set rasterization mode.
 *
 * \param mode rasterization mode.
 *
 * \note this function can't be put in a display list.
 *
 * \sa glRenderMode().
 * 
 * Flushes the vertices and do the necessary cleanup according to the previous
 * rasterization mode, such as writing the hit record or resent the select
 * buffer index when exiting the select mode. Updates
 * __struct gl_contextRec::RenderMode and notifies the driver via the
 * dd_function_table::RenderMode callback.
 */
GLint GLAPIENTRY
_mesa_RenderMode( GLenum mode )
{
   GET_CURRENT_CONTEXT(ctx);
   GLint result;
   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);

   if (MESA_VERBOSE & VERBOSE_API)
      _mesa_debug(ctx, "glRenderMode %s\n", _mesa_lookup_enum_by_nr(mode));

   FLUSH_VERTICES(ctx, _NEW_RENDERMODE);

   switch (ctx->RenderMode) {
      case GL_RENDER:
	 result = 0;
	 break;
      case GL_SELECT:
	 if (ctx->Select.HitFlag) {
	    write_hit_record( ctx );
	 }
	 if (ctx->Select.BufferCount > ctx->Select.BufferSize) {
	    /* overflow */
#ifdef DEBUG
            _mesa_warning(ctx, "Feedback buffer overflow");
#endif
	    result = -1;
	 }
	 else {
	    result = ctx->Select.Hits;
	 }
	 ctx->Select.BufferCount = 0;
	 ctx->Select.Hits = 0;
	 ctx->Select.NameStackDepth = 0;
	 break;
#if _HAVE_FULL_GL
      case GL_FEEDBACK:
	 if (ctx->Feedback.Count > ctx->Feedback.BufferSize) {
	    /* overflow */
	    result = -1;
	 }
	 else {
	    result = ctx->Feedback.Count;
	 }
	 ctx->Feedback.Count = 0;
	 break;
#endif
      default:
	 _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" );
	 return 0;
   }

   switch (mode) {
      case GL_RENDER:
         break;
      case GL_SELECT:
	 if (ctx->Select.BufferSize==0) {
	    /* haven't called glSelectBuffer yet */
	    _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" );
	 }
	 break;
#if _HAVE_FULL_GL
      case GL_FEEDBACK:
	 if (ctx->Feedback.BufferSize==0) {
	    /* haven't called glFeedbackBuffer yet */
	    _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" );
	 }
	 break;
#endif
      default:
	 _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" );
	 return 0;
   }

   ctx->RenderMode = mode;
   if (ctx->Driver.RenderMode)
      ctx->Driver.RenderMode( ctx, mode );

   return result;
}
Beispiel #12
0
void GLAPIENTRY
_mesa_BindImageTextures(GLuint first, GLsizei count, const GLuint *textures)
{
   GET_CURRENT_CONTEXT(ctx);
   int i;

   if (!ctx->Extensions.ARB_shader_image_load_store) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glBindImageTextures()");
      return;
   }

   if (first + count > ctx->Const.MaxImageUnits) {
      /* The ARB_multi_bind spec says:
       *
       *    "An INVALID_OPERATION error is generated if <first> + <count>
       *     is greater than the number of image units supported by
       *     the implementation."
       */
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glBindImageTextures(first=%u + count=%d > the value of "
                  "GL_MAX_IMAGE_UNITS=%u)",
                  first, count, ctx->Const.MaxImageUnits);
      return;
   }

   /* Assume that at least one binding will be changed */
   FLUSH_VERTICES(ctx, 0);
   ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits;

   /* Note that the error semantics for multi-bind commands differ from
    * those of other GL commands.
    *
    * The Issues section in the ARB_multi_bind spec says:
    *
    *    "(11) Typically, OpenGL specifies that if an error is generated by
    *          a command, that command has no effect.  This is somewhat
    *          unfortunate for multi-bind commands, because it would require
    *          a first pass to scan the entire list of bound objects for
    *          errors and then a second pass to actually perform the
    *          bindings.  Should we have different error semantics?
    *
    *       RESOLVED:  Yes.  In this specification, when the parameters for
    *       one of the <count> binding points are invalid, that binding
    *       point is not updated and an error will be generated.  However,
    *       other binding points in the same command will be updated if
    *       their parameters are valid and no other error occurs."
    */

   _mesa_begin_texture_lookups(ctx);

   for (i = 0; i < count; i++) {
      struct gl_image_unit *u = &ctx->ImageUnits[first + i];
      const GLuint texture = textures ? textures[i] : 0;

      if (texture != 0) {
         struct gl_texture_object *texObj;
         GLenum tex_format;

         if (!u->TexObj || u->TexObj->Name != texture) {
            texObj = _mesa_lookup_texture_locked(ctx, texture);
            if (!texObj) {
               /* The ARB_multi_bind spec says:
                *
                *    "An INVALID_OPERATION error is generated if any value
                *     in <textures> is not zero or the name of an existing
                *     texture object (per binding)."
                */
               _mesa_error(ctx, GL_INVALID_OPERATION,
                           "glBindImageTextures(textures[%d]=%u "
                           "is not zero or the name of an existing texture "
                           "object)", i, texture);
               continue;
            }
         } else {
            texObj = u->TexObj;
         }

         if (texObj->Target == GL_TEXTURE_BUFFER) {
            tex_format = texObj->BufferObjectFormat;
         } else {
            struct gl_texture_image *image = texObj->Image[0][0];

            if (!image || image->Width == 0 || image->Height == 0 ||
                image->Depth == 0) {
               /* The ARB_multi_bind spec says:
                *
                *    "An INVALID_OPERATION error is generated if the width,
                *     height, or depth of the level zero texture image of
                *     any texture in <textures> is zero (per binding)."
                */
               _mesa_error(ctx, GL_INVALID_OPERATION,
                           "glBindImageTextures(the width, height or depth "
                           "of the level zero texture image of "
                           "textures[%d]=%u is zero)", i, texture);
               continue;
            }

            tex_format = image->InternalFormat;
         }

         if (!is_image_format_supported(ctx, tex_format)) {
            /* The ARB_multi_bind spec says:
             *
             *   "An INVALID_OPERATION error is generated if the internal
             *    format of the level zero texture image of any texture
             *    in <textures> is not found in table 8.33 (per binding)."
             */
            _mesa_error(ctx, GL_INVALID_OPERATION,
                        "glBindImageTextures(the internal format %s of "
                        "the level zero texture image of textures[%d]=%u "
                        "is not supported)",
                        _mesa_enum_to_string(tex_format),
                        i, texture);
            continue;
         }

         /* Update the texture binding */
         _mesa_reference_texobj(&u->TexObj, texObj);
         u->Level = 0;
         u->Layered = _mesa_tex_target_is_layered(texObj->Target);
         u->_Layer = u->Layer = 0;
         u->Access = GL_READ_WRITE;
         u->Format = tex_format;
         u->_ActualFormat = _mesa_get_shader_image_format(tex_format);
      } else {
         /* Unbind the texture from the unit */
         _mesa_reference_texobj(&u->TexObj, NULL);
         u->Level = 0;
         u->Layered = GL_FALSE;
         u->_Layer = u->Layer = 0;
         u->Access = GL_READ_ONLY;
         u->Format = GL_R8;
         u->_ActualFormat = MESA_FORMAT_R_UNORM8;
      }

      /* Pass the BindImageTexture call down to the device driver */
      if (ctx->Driver.BindImageTexture)
         ctx->Driver.BindImageTexture(ctx, u, u->TexObj, u->Level, u->Layered,
                                      u->Layer, u->Access, u->Format);
   }

   _mesa_end_texture_lookups(ctx);
}
Beispiel #13
0
void GLAPIENTRY
_mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id)
{
   struct gl_query_object *q, **bindpt;
   GET_CURRENT_CONTEXT(ctx);

   if (MESA_VERBOSE & VERBOSE_API)
      _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n",
                  _mesa_lookup_enum_by_nr(target), index, id);

   if (!query_error_check_index(ctx, target, index))
      return;

   FLUSH_VERTICES(ctx, 0);

   bindpt = get_query_binding_point(ctx, target);
   if (!bindpt) {
      _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)");
      return;
   }

   /* From the GL_ARB_occlusion_query spec:
    *
    *     "If BeginQueryARB is called while another query is already in
    *      progress with the same target, an INVALID_OPERATION error is
    *      generated."
    */
   if (*bindpt) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glBeginQuery{Indexed}(target=%s is active)",
                  _mesa_lookup_enum_by_nr(target));
      return;
   }

   if (id == 0) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)");
      return;
   }

   q = _mesa_lookup_query_object(ctx, id);
   if (!q) {
      if (ctx->API != API_OPENGL_COMPAT) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glBeginQuery{Indexed}(non-gen name)");
         return;
      } else {
         /* create new object */
         q = ctx->Driver.NewQueryObject(ctx, id);
         if (!q) {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}");
            return;
         }
         _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
      }
   }
   else {
      /* pre-existing object */
      if (q->Active) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glBeginQuery{Indexed}(query already active)");
         return;
      }
   }

   q->Target = target;
   q->Active = GL_TRUE;
   q->Result = 0;
   q->Ready = GL_FALSE;
   q->EverBound = GL_TRUE;

   /* XXX should probably refcount query objects */
   *bindpt = q;

   ctx->Driver.BeginQuery(ctx, q);
}
Beispiel #14
0
/**
 * Helper to enable/disable client-side state.
 */
static void
client_state(GLcontext *ctx, GLenum cap, GLboolean state)
{
   struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
   GLuint flag;
   GLboolean *var;

   switch (cap) {
      case GL_VERTEX_ARRAY:
         var = &arrayObj->Vertex.Enabled;
         flag = _NEW_ARRAY_VERTEX;
         break;
      case GL_NORMAL_ARRAY:
         var = &arrayObj->Normal.Enabled;
         flag = _NEW_ARRAY_NORMAL;
         break;
      case GL_COLOR_ARRAY:
         var = &arrayObj->Color.Enabled;
         flag = _NEW_ARRAY_COLOR0;
         break;
      case GL_INDEX_ARRAY:
         var = &arrayObj->Index.Enabled;
         flag = _NEW_ARRAY_INDEX;
         break;
      case GL_TEXTURE_COORD_ARRAY:
         var = &arrayObj->TexCoord[ctx->Array.ActiveTexture].Enabled;
         flag = _NEW_ARRAY_TEXCOORD(ctx->Array.ActiveTexture);
         break;
      case GL_EDGE_FLAG_ARRAY:
         var = &arrayObj->EdgeFlag.Enabled;
         flag = _NEW_ARRAY_EDGEFLAG;
         break;
      case GL_FOG_COORDINATE_ARRAY_EXT:
         var = &arrayObj->FogCoord.Enabled;
         flag = _NEW_ARRAY_FOGCOORD;
         break;
      case GL_SECONDARY_COLOR_ARRAY_EXT:
         var = &arrayObj->SecondaryColor.Enabled;
         flag = _NEW_ARRAY_COLOR1;
         break;

#if FEATURE_point_size_array
      case GL_POINT_SIZE_ARRAY_OES:
         var = &arrayObj->PointSize.Enabled;
         flag = _NEW_ARRAY_POINT_SIZE;
         break;
#endif

#if FEATURE_NV_vertex_program
      case GL_VERTEX_ATTRIB_ARRAY0_NV:
      case GL_VERTEX_ATTRIB_ARRAY1_NV:
      case GL_VERTEX_ATTRIB_ARRAY2_NV:
      case GL_VERTEX_ATTRIB_ARRAY3_NV:
      case GL_VERTEX_ATTRIB_ARRAY4_NV:
      case GL_VERTEX_ATTRIB_ARRAY5_NV:
      case GL_VERTEX_ATTRIB_ARRAY6_NV:
      case GL_VERTEX_ATTRIB_ARRAY7_NV:
      case GL_VERTEX_ATTRIB_ARRAY8_NV:
      case GL_VERTEX_ATTRIB_ARRAY9_NV:
      case GL_VERTEX_ATTRIB_ARRAY10_NV:
      case GL_VERTEX_ATTRIB_ARRAY11_NV:
      case GL_VERTEX_ATTRIB_ARRAY12_NV:
      case GL_VERTEX_ATTRIB_ARRAY13_NV:
      case GL_VERTEX_ATTRIB_ARRAY14_NV:
      case GL_VERTEX_ATTRIB_ARRAY15_NV:
         CHECK_EXTENSION(NV_vertex_program, cap);
         {
            GLint n = (GLint) cap - GL_VERTEX_ATTRIB_ARRAY0_NV;
            ASSERT(n < Elements(ctx->Array.ArrayObj->VertexAttrib));
            var = &arrayObj->VertexAttrib[n].Enabled;
            flag = _NEW_ARRAY_ATTRIB(n);
         }
         break;
#endif /* FEATURE_NV_vertex_program */

      default:
         _mesa_error( ctx, GL_INVALID_ENUM,
                      "glEnable/DisableClientState(0x%x)", cap);
         return;
   }

   if (*var == state)
      return;

   FLUSH_VERTICES(ctx, _NEW_ARRAY);
   ctx->Array.NewState |= flag;

   _ae_invalidate_state(ctx, _NEW_ARRAY);

   *var = state;

   if (state)
      ctx->Array.ArrayObj->_Enabled |= flag;
   else
      ctx->Array.ArrayObj->_Enabled &= ~flag;

   if (ctx->Driver.Enable) {
      ctx->Driver.Enable( ctx, cap, state );
   }
}
Beispiel #15
0
/**
 * This is called just prior to changing any sampler object state.
 */
static inline void
flush(struct gl_context *ctx)
{
   FLUSH_VERTICES(ctx, _NEW_TEXTURE);
}
void GLAPIENTRY
_mesa_TexGenfv( GLenum coord, GLenum pname, const GLfloat *params )
{
   struct gl_texture_unit *texUnit;
   struct gl_texgen *texgen;
   GET_CURRENT_CONTEXT(ctx);
   ASSERT_OUTSIDE_BEGIN_END(ctx);

   if (MESA_VERBOSE&(VERBOSE_API|VERBOSE_TEXTURE))
      _mesa_debug(ctx, "glTexGen %s %s %.1f(%s)...\n",
                  _mesa_lookup_enum_by_nr(coord),
                  _mesa_lookup_enum_by_nr(pname),
                  *params,
		  _mesa_lookup_enum_by_nr((GLenum) (GLint) *params));

   if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glTexGen(current unit)");
      return;
   }

   texUnit = _mesa_get_current_tex_unit(ctx);

   texgen = get_texgen(ctx, texUnit, coord);
   if (!texgen) {
      _mesa_error(ctx, GL_INVALID_ENUM, "glTexGen(coord)");
      return;
   }

   switch (pname) {
   case GL_TEXTURE_GEN_MODE:
      {
         GLenum mode = (GLenum) (GLint) params[0];
         GLbitfield bit = 0x0;
         if (texgen->Mode == mode)
            return;
         switch (mode) {
         case GL_OBJECT_LINEAR:
            bit = TEXGEN_OBJ_LINEAR;
            break;
         case GL_EYE_LINEAR:
            bit = TEXGEN_EYE_LINEAR;
            break;
         case GL_SPHERE_MAP:
            if (coord == GL_S || coord == GL_T)
               bit = TEXGEN_SPHERE_MAP;
            break;
         case GL_REFLECTION_MAP_NV:
            if (coord != GL_Q)
               bit = TEXGEN_REFLECTION_MAP_NV;
            break;
         case GL_NORMAL_MAP_NV:
            if (coord != GL_Q)
               bit = TEXGEN_NORMAL_MAP_NV;
            break;
         default:
            ; /* nop */
         }
         if (!bit) {
            _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" );
            return;
         }
         if (ctx->API != API_OPENGL
             && (bit & (TEXGEN_REFLECTION_MAP_NV | TEXGEN_NORMAL_MAP_NV)) == 0) {
            _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" );
            return;
         }

         FLUSH_VERTICES(ctx, _NEW_TEXTURE);
         texgen->Mode = mode;
         texgen->_ModeBit = bit;
      }
      break;

   case GL_OBJECT_PLANE:
      {
         if (ctx->API != API_OPENGL) {
            _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" );
            return;
         }
         if (TEST_EQ_4V(texgen->ObjectPlane, params))
            return;
         FLUSH_VERTICES(ctx, _NEW_TEXTURE);
         COPY_4FV(texgen->ObjectPlane, params);
      }
      break;

   case GL_EYE_PLANE:
      {
         GLfloat tmp[4];

         if (ctx->API != API_OPENGL) {
            _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" );
            return;
         }

         /* Transform plane equation by the inverse modelview matrix */
         if (_math_matrix_is_dirty(ctx->ModelviewMatrixStack.Top)) {
            _math_matrix_analyse(ctx->ModelviewMatrixStack.Top);
         }
         _mesa_transform_vector(tmp, params,
                                ctx->ModelviewMatrixStack.Top->inv);
         if (TEST_EQ_4V(texgen->EyePlane, tmp))
            return;
         FLUSH_VERTICES(ctx, _NEW_TEXTURE);
         COPY_4FV(texgen->EyePlane, tmp);
      }
      break;

   default:
      _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(pname)" );
      return;
   }

   if (ctx->Driver.TexGen)
      ctx->Driver.TexGen( ctx, coord, pname, params );
}
Beispiel #17
0
void GLAPIENTRY
_mesa_PixelMapusv(GLenum map, GLsizei mapsize, const GLushort *values )
{
   GLfloat fvalues[MAX_PIXEL_MAP_TABLE];
   GET_CURRENT_CONTEXT(ctx);
   ASSERT_OUTSIDE_BEGIN_END(ctx);

   if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) {
      _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapusv(mapsize)" );
      return;
   }

   if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) {
      /* test that mapsize is a power of two */
      if (!_mesa_is_pow_two(mapsize)) {
	 _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" );
         return;
      }
   }

   FLUSH_VERTICES(ctx, _NEW_PIXEL);

   if (ctx->Unpack.BufferObj->Name) {
      /* unpack pixelmap from PBO */
      GLubyte *buf;
      /* Note, need to use DefaultPacking and Unpack's buffer object */
      ctx->DefaultPacking.BufferObj = ctx->Unpack.BufferObj;
      if (!_mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1,
                                     GL_INTENSITY, GL_UNSIGNED_SHORT,
                                     values)) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glPixelMapusv(invalid PBO access)");
         return;
      }
      /* restore */
      ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj;
      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
                                              GL_READ_ONLY_ARB,
                                              ctx->Unpack.BufferObj);
      if (!buf) {
         /* buffer is already mapped - that's an error */
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glPixelMapusv(PBO is mapped)");
         return;
      }
      values = (const GLushort *) ADD_POINTERS(buf, values);
   }
   else if (!values) {
      return;
   }

   /* convert to floats */
   if (map == GL_PIXEL_MAP_I_TO_I || map == GL_PIXEL_MAP_S_TO_S) {
      GLint i;
      for (i = 0; i < mapsize; i++) {
         fvalues[i] = (GLfloat) values[i];
      }
   }
   else {
      GLint i;
      for (i = 0; i < mapsize; i++) {
         fvalues[i] = USHORT_TO_FLOAT( values[i] );
      }
   }

   if (ctx->Unpack.BufferObj->Name) {
      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
                              ctx->Unpack.BufferObj);
   }

   store_pixelmap(ctx, map, mapsize, fvalues);
}
Beispiel #18
0
void GLAPIENTRY
_mesa_Fogfv( GLenum pname, const GLfloat *params )
{
   GET_CURRENT_CONTEXT(ctx);
   GLenum m;

   switch (pname) {
      case GL_FOG_MODE:
         m = (GLenum) (GLint) *params;
	 switch (m) {
	 case GL_LINEAR:
	 case GL_EXP:
	 case GL_EXP2:
	    break;
	 default:
	    _mesa_error( ctx, GL_INVALID_ENUM, "glFog" );
            return;
	 }
	 if (ctx->Fog.Mode == m)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_FOG);
	 ctx->Fog.Mode = m;
	 break;
      case GL_FOG_DENSITY:
	 if (*params<0.0) {
	    _mesa_error( ctx, GL_INVALID_VALUE, "glFog" );
            return;
	 }
	 if (ctx->Fog.Density == *params)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_FOG);
	 ctx->Fog.Density = *params;
	 break;
      case GL_FOG_START:
         if (ctx->Fog.Start == *params)
            return;
         FLUSH_VERTICES(ctx, _NEW_FOG);
         ctx->Fog.Start = *params;
         update_fog_scale(ctx);
         break;
      case GL_FOG_END:
         if (ctx->Fog.End == *params)
            return;
         FLUSH_VERTICES(ctx, _NEW_FOG);
         ctx->Fog.End = *params;
         update_fog_scale(ctx);
         break;
      case GL_FOG_INDEX:
         if (ctx->API != API_OPENGL_COMPAT)
            goto invalid_pname;
 	 if (ctx->Fog.Index == *params)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_FOG);
 	 ctx->Fog.Index = *params;
	 break;
      case GL_FOG_COLOR:
	 if (TEST_EQ_4V(ctx->Fog.Color, params))
	    return;
	 FLUSH_VERTICES(ctx, _NEW_FOG);
	 ctx->Fog.ColorUnclamped[0] = params[0];
	 ctx->Fog.ColorUnclamped[1] = params[1];
	 ctx->Fog.ColorUnclamped[2] = params[2];
	 ctx->Fog.ColorUnclamped[3] = params[3];
	 ctx->Fog.Color[0] = CLAMP(params[0], 0.0F, 1.0F);
	 ctx->Fog.Color[1] = CLAMP(params[1], 0.0F, 1.0F);
	 ctx->Fog.Color[2] = CLAMP(params[2], 0.0F, 1.0F);
	 ctx->Fog.Color[3] = CLAMP(params[3], 0.0F, 1.0F);
         break;
      case GL_FOG_COORDINATE_SOURCE_EXT: {
	 GLenum p = (GLenum) (GLint) *params;
         if (ctx->API != API_OPENGL_COMPAT ||
             (p != GL_FOG_COORDINATE_EXT && p != GL_FRAGMENT_DEPTH_EXT)) {
	    _mesa_error(ctx, GL_INVALID_ENUM, "glFog");
	    return;
	 }
	 if (ctx->Fog.FogCoordinateSource == p)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_FOG);
	 ctx->Fog.FogCoordinateSource = p;
	 break;
      }
      case GL_FOG_DISTANCE_MODE_NV: {
	 GLenum p = (GLenum) (GLint) *params;
         if (ctx->API != API_OPENGL_COMPAT || !ctx->Extensions.NV_fog_distance ||
             (p != GL_EYE_RADIAL_NV && p != GL_EYE_PLANE && p != GL_EYE_PLANE_ABSOLUTE_NV)) {
	    _mesa_error(ctx, GL_INVALID_ENUM, "glFog");
	    return;
	 }
	 if (ctx->Fog.FogDistanceMode == p)
	    return;
	 FLUSH_VERTICES(ctx, _NEW_FOG);
	 ctx->Fog.FogDistanceMode = p;
	 break;
      }
      default:
         goto invalid_pname;
   }

   if (ctx->Driver.Fogfv) {
      (*ctx->Driver.Fogfv)( ctx, pname, params );
   }

   return;

invalid_pname:
   _mesa_error( ctx, GL_INVALID_ENUM, "glFog" );
   return;
}
Beispiel #19
0
void GLAPIENTRY
_mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height,
		      GLenum format, GLenum type, GLsizei bufSize,
                      GLvoid *pixels )
{
   GLenum err = GL_NO_ERROR;
   struct gl_renderbuffer *rb;
   struct gl_pixelstore_attrib clippedPacking;

   GET_CURRENT_CONTEXT(ctx);

   FLUSH_VERTICES(ctx, 0);
   FLUSH_CURRENT(ctx, 0);

   if (MESA_VERBOSE & VERBOSE_API)
      _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n",
                  width, height,
                  _mesa_enum_to_string(format),
                  _mesa_enum_to_string(type),
                  pixels);

   if (width < 0 || height < 0) {
      _mesa_error( ctx, GL_INVALID_VALUE,
                   "glReadPixels(width=%d height=%d)", width, height );
      return;
   }

   if (ctx->NewState)
      _mesa_update_state(ctx);

   if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
                  "glReadPixels(incomplete framebuffer)" );
      return;
   }

   rb = _mesa_get_read_renderbuffer_for_format(ctx, format);
   if (rb == NULL) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glReadPixels(read buffer)");
      return;
   }

   /* OpenGL ES 1.x and OpenGL ES 2.0 impose additional restrictions on the
    * combinations of format and type that can be used.
    *
    * Technically, only two combinations are actually allowed:
    * GL_RGBA/GL_UNSIGNED_BYTE, and some implementation-specific internal
    * preferred combination.  This code doesn't know what that preferred
    * combination is, and Mesa can handle anything valid.  Just work instead.
    */
   if (_mesa_is_gles(ctx)) {
      if (ctx->API == API_OPENGLES2 &&
          _mesa_is_color_format(format) &&
          _mesa_get_color_read_format(ctx) == format &&
          _mesa_get_color_read_type(ctx) == type) {
         err = GL_NO_ERROR;
      } else if (ctx->Version < 30) {
         err = _mesa_es_error_check_format_and_type(ctx, format, type, 2);
         if (err == GL_NO_ERROR) {
            if (type == GL_FLOAT || type == GL_HALF_FLOAT_OES) {
               err = GL_INVALID_OPERATION;
            }
         }
      } else {
         err = read_pixels_es3_error_check(format, type, rb);
      }

      if (err != GL_NO_ERROR) {
         _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)",
                     _mesa_enum_to_string(format),
                     _mesa_enum_to_string(type));
         return;
      }
   }

   err = _mesa_error_check_format_and_type(ctx, format, type);
   if (err != GL_NO_ERROR) {
      _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)",
                  _mesa_enum_to_string(format),
                  _mesa_enum_to_string(type));
      return;
   }

   if (_mesa_is_user_fbo(ctx->ReadBuffer) &&
       ctx->ReadBuffer->Visual.samples > 0) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(multisample FBO)");
      return;
   }

   if (!_mesa_source_buffer_exists(ctx, format)) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)");
      return;
   }

   /* Check that the destination format and source buffer are both
    * integer-valued or both non-integer-valued.
    */
   if (ctx->Extensions.EXT_texture_integer && _mesa_is_color_format(format)) {
      const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
      const GLboolean srcInteger = _mesa_is_format_integer_color(rb->Format);
      const GLboolean dstInteger = _mesa_is_enum_format_integer(format);
      if (dstInteger != srcInteger) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glReadPixels(integer / non-integer format mismatch");
         return;
      }
   }

   /* Do all needed clipping here, so that we can forget about it later */
   clippedPacking = ctx->Pack;
   if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking))
      return; /* nothing to do */

   if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1,
                                  format, type, bufSize, pixels)) {
      if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glReadPixels(out of bounds PBO access)");
      } else {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glReadnPixelsARB(out of bounds access:"
                     " bufSize (%d) is too small)", bufSize);
      }
      return;
   }

   if (_mesa_is_bufferobj(ctx->Pack.BufferObj) &&
       _mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) {
      /* buffer is mapped - that's an error */
      _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)");
      return;
   }

   ctx->Driver.ReadPixels(ctx, x, y, width, height,
                          format, type, &clippedPacking, pixels);
}
Beispiel #20
0
void GLAPIENTRY
_mesa_PointParameterfv( GLenum pname, const GLfloat *params)
{
   GET_CURRENT_CONTEXT(ctx);
   ASSERT_OUTSIDE_BEGIN_END(ctx);

   switch (pname) {
      case GL_DISTANCE_ATTENUATION_EXT:
         if (ctx->Extensions.EXT_point_parameters) {
            if (TEST_EQ_3V(ctx->Point.Params, params))
	       return;
	    FLUSH_VERTICES(ctx, _NEW_POINT);
            COPY_3V(ctx->Point.Params, params);
            ctx->Point._Attenuated = (ctx->Point.Params[0] != 1.0 ||
                                      ctx->Point.Params[1] != 0.0 ||
                                      ctx->Point.Params[2] != 0.0);

            if (ctx->Point._Attenuated)
               ctx->_TriangleCaps |= DD_POINT_ATTEN;
            else
               ctx->_TriangleCaps &= ~DD_POINT_ATTEN;
         }
         else {
            _mesa_error(ctx, GL_INVALID_ENUM,
                        "glPointParameterf[v]{EXT,ARB}(pname)");
            return;
         }
         break;
      case GL_POINT_SIZE_MIN_EXT:
         if (ctx->Extensions.EXT_point_parameters) {
            if (params[0] < 0.0F) {
               _mesa_error( ctx, GL_INVALID_VALUE,
                            "glPointParameterf[v]{EXT,ARB}(param)" );
               return;
            }
            if (ctx->Point.MinSize == params[0])
               return;
            FLUSH_VERTICES(ctx, _NEW_POINT);
            ctx->Point.MinSize = params[0];
         }
         else {
            _mesa_error(ctx, GL_INVALID_ENUM,
                        "glPointParameterf[v]{EXT,ARB}(pname)");
            return;
         }
         break;
      case GL_POINT_SIZE_MAX_EXT:
         if (ctx->Extensions.EXT_point_parameters) {
            if (params[0] < 0.0F) {
               _mesa_error( ctx, GL_INVALID_VALUE,
                            "glPointParameterf[v]{EXT,ARB}(param)" );
               return;
            }
            if (ctx->Point.MaxSize == params[0])
               return;
            FLUSH_VERTICES(ctx, _NEW_POINT);
            ctx->Point.MaxSize = params[0];
         }
         else {
            _mesa_error(ctx, GL_INVALID_ENUM,
                        "glPointParameterf[v]{EXT,ARB}(pname)");
            return;
         }
         break;
      case GL_POINT_FADE_THRESHOLD_SIZE_EXT:
         if (ctx->Extensions.EXT_point_parameters) {
            if (params[0] < 0.0F) {
               _mesa_error( ctx, GL_INVALID_VALUE,
                            "glPointParameterf[v]{EXT,ARB}(param)" );
               return;
            }
            if (ctx->Point.Threshold == params[0])
               return;
            FLUSH_VERTICES(ctx, _NEW_POINT);
            ctx->Point.Threshold = params[0];
         }
         else {
            _mesa_error(ctx, GL_INVALID_ENUM,
                        "glPointParameterf[v]{EXT,ARB}(pname)");
            return;
         }
         break;
      case GL_POINT_SPRITE_R_MODE_NV:
         /* This is one area where ARB_point_sprite and NV_point_sprite
	  * differ.  In ARB_point_sprite the POINT_SPRITE_R_MODE is
	  * always ZERO.  NV_point_sprite adds the S and R modes.
	  */
         if (ctx->Extensions.NV_point_sprite) {
            GLenum value = (GLenum) params[0];
            if (value != GL_ZERO && value != GL_S && value != GL_R) {
               _mesa_error(ctx, GL_INVALID_VALUE,
                           "glPointParameterf[v]{EXT,ARB}(param)");
               return;
            }
            if (ctx->Point.SpriteRMode == value)
               return;
            FLUSH_VERTICES(ctx, _NEW_POINT);
            ctx->Point.SpriteRMode = value;
         }
         else {
            _mesa_error(ctx, GL_INVALID_ENUM,
                        "glPointParameterf[v]{EXT,ARB}(pname)");
            return;
         }
         break;
      case GL_POINT_SPRITE_COORD_ORIGIN:
         if (ctx->Extensions.ARB_point_sprite || ctx->Extensions.NV_point_sprite) {
            GLenum value = (GLenum) params[0];
            if (value != GL_LOWER_LEFT && value != GL_UPPER_LEFT) {
               _mesa_error(ctx, GL_INVALID_VALUE,
                           "glPointParameterf[v]{EXT,ARB}(param)");
               return;
            }
            if (ctx->Point.SpriteOrigin == value)
               return;
            FLUSH_VERTICES(ctx, _NEW_POINT);
            ctx->Point.SpriteOrigin = value;
         }
         else {
            _mesa_error(ctx, GL_INVALID_ENUM,
                        "glPointParameterf[v]{EXT,ARB}(pname)");
            return;
         }
         break;
      default:
         _mesa_error( ctx, GL_INVALID_ENUM,
                      "glPointParameterf[v]{EXT,ARB}(pname)" );
         return;
   }

   if (ctx->Driver.PointParameterfv)
      (*ctx->Driver.PointParameterfv)(ctx, pname, params);
}
Beispiel #21
0
/**
 * Bind a named texture to a texturing target.
 * 
 * \param target texture target.
 * \param texName texture name.
 * 
 * \sa glBindTexture().
 *
 * Determines the old texture object bound and returns immediately if rebinding
 * the same texture.  Get the current texture which is either a default texture
 * if name is null, a named texture from the hash, or a new texture if the
 * given texture name is new. Increments its reference count, binds it, and
 * calls dd_function_table::BindTexture. Decrements the old texture reference
 * count and deletes it if it reaches zero.
 */
void GLAPIENTRY
_mesa_BindTexture( GLenum target, GLuint texName )
{
   GET_CURRENT_CONTEXT(ctx);
   struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
   struct gl_texture_object *newTexObj = NULL;
   GLint targetIndex;
   ASSERT_OUTSIDE_BEGIN_END(ctx);

   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
      _mesa_debug(ctx, "glBindTexture %s %d\n",
                  _mesa_lookup_enum_by_nr(target), (GLint) texName);

   targetIndex = target_enum_to_index(target);
   if (targetIndex < 0) {
      _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)");
      return;
   }
   assert(targetIndex < NUM_TEXTURE_TARGETS);

   /*
    * Get pointer to new texture object (newTexObj)
    */
   if (texName == 0) {
      /* Use a default texture object */
      newTexObj = ctx->Shared->DefaultTex[targetIndex];
   }
   else {
      /* non-default texture object */
      newTexObj = _mesa_lookup_texture(ctx, texName);
      if (newTexObj) {
         /* error checking */
         if (newTexObj->Target != 0 && newTexObj->Target != target) {
            /* the named texture object's target doesn't match the given target */
            _mesa_error( ctx, GL_INVALID_OPERATION,
                         "glBindTexture(target mismatch)" );
            return;
         }
         if (newTexObj->Target == 0) {
            finish_texture_init(ctx, target, newTexObj);
         }
      }
      else {
         /* if this is a new texture id, allocate a texture object now */
         newTexObj = ctx->Driver.NewTextureObject(ctx, texName, target);
         if (!newTexObj) {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture");
            return;
         }

         /* and insert it into hash table */
         _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
         _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj);
         _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
      }
      newTexObj->Target = target;
   }

   assert(valid_texture_object(newTexObj));

   /* Check if this texture is only used by this context and is already bound.
    * If so, just return.
    */
   {
      GLboolean early_out;
      _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
      early_out = ((ctx->Shared->RefCount == 1)
                   && (newTexObj == texUnit->CurrentTex[targetIndex]));
      _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
      if (early_out) {
         return;
      }
   }

   /* flush before changing binding */
   FLUSH_VERTICES(ctx, _NEW_TEXTURE);

   /* Do the actual binding.  The refcount on the previously bound
    * texture object will be decremented.  It'll be deleted if the
    * count hits zero.
    */
   _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], newTexObj);
   ASSERT(texUnit->CurrentTex[targetIndex]);

   /* Pass BindTexture call to device driver */
   if (ctx->Driver.BindTexture)
      ctx->Driver.BindTexture(ctx, target, newTexObj);
}
Beispiel #22
0
/**
 * Clear buffers.
 * 
 * \param mask bit-mask indicating the buffers to be cleared.
 *
 * Flushes the vertices and verifies the parameter. If __struct gl_contextRec::NewState
 * is set then calls _mesa_update_state() to update gl_frame_buffer::_Xmin,
 * etc. If the rasterization mode is set to GL_RENDER then requests the driver
 * to clear the buffers, via the dd_function_table::Clear callback.
 */ 
void GLAPIENTRY
_mesa_Clear( GLbitfield mask )
{
   GET_CURRENT_CONTEXT(ctx);
   FLUSH_VERTICES(ctx, 0);

   FLUSH_CURRENT(ctx, 0);

   if (MESA_VERBOSE & VERBOSE_API)
      _mesa_debug(ctx, "glClear 0x%x\n", mask);

   if (mask & ~(GL_COLOR_BUFFER_BIT |
                GL_DEPTH_BUFFER_BIT |
                GL_STENCIL_BUFFER_BIT |
                GL_ACCUM_BUFFER_BIT)) {
      /* invalid bit set */
      _mesa_error( ctx, GL_INVALID_VALUE, "glClear(0x%x)", mask);
      return;
   }

   /* Accumulation buffers were removed in core contexts, and they never
    * existed in OpenGL ES.
    */
   if ((mask & GL_ACCUM_BUFFER_BIT) != 0
       && (ctx->API == API_OPENGL_CORE || _mesa_is_gles(ctx))) {
      _mesa_error( ctx, GL_INVALID_VALUE, "glClear(GL_ACCUM_BUFFER_BIT)");
      return;
   }

   if (ctx->NewState) {
      _mesa_update_state( ctx );	/* update _Xmin, etc */
   }

   if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
                  "glClear(incomplete framebuffer)");
      return;
   }

   if (ctx->DrawBuffer->Width == 0 || ctx->DrawBuffer->Height == 0 ||
       ctx->DrawBuffer->_Xmin >= ctx->DrawBuffer->_Xmax ||
       ctx->DrawBuffer->_Ymin >= ctx->DrawBuffer->_Ymax)
      return;

   if (ctx->RasterDiscard)
      return;

   if (ctx->RenderMode == GL_RENDER) {
      GLbitfield bufferMask;

      /* don't clear depth buffer if depth writing disabled */
      if (!ctx->Depth.Mask)
         mask &= ~GL_DEPTH_BUFFER_BIT;

      /* Build the bitmask to send to device driver's Clear function.
       * Note that the GL_COLOR_BUFFER_BIT flag will expand to 0, 1, 2 or 4
       * of the BUFFER_BIT_FRONT/BACK_LEFT/RIGHT flags, or one of the
       * BUFFER_BIT_COLORn flags.
       */
      bufferMask = 0;
      if (mask & GL_COLOR_BUFFER_BIT) {
         GLuint i;
         for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
            bufferMask |= (1 << ctx->DrawBuffer->_ColorDrawBufferIndexes[i]);
         }
      }

      if ((mask & GL_DEPTH_BUFFER_BIT)
          && ctx->DrawBuffer->Visual.haveDepthBuffer) {
         bufferMask |= BUFFER_BIT_DEPTH;
      }

      if ((mask & GL_STENCIL_BUFFER_BIT)
          && ctx->DrawBuffer->Visual.haveStencilBuffer) {
         bufferMask |= BUFFER_BIT_STENCIL;
      }

      if ((mask & GL_ACCUM_BUFFER_BIT)
          && ctx->DrawBuffer->Visual.haveAccumBuffer) {
         bufferMask |= BUFFER_BIT_ACCUM;
      }

      ASSERT(ctx->Driver.Clear);
      ctx->Driver.Clear(ctx, bufferMask);
   }
}
Beispiel #23
0
/**
 * Called by ctx->Driver.UniformMatrix().
 */
void
_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
                     GLenum matrixType, GLint location, GLsizei count,
                     GLboolean transpose, const GLfloat *values)
{
   GLsizei maxCount, i;
   struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
   if (!shProg || !shProg->LinkStatus) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
         "glUniformMatrix(program not linked)");
      return;
   }
   if (location == -1)
      return;   /* The standard specifies this as a no-op */
   /* The spec says this is GL_INVALID_OPERATION, although it seems like it
    * ought to be GL_INVALID_VALUE
    */
   if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)");
      return;
   }
   if (values == NULL) {
      _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
      return;
   }
   if (count < 0) {
      _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(count < 0)");
      return;
   }

   FLUSH_VERTICES(ctx, _NEW_PROGRAM);

   /*
    * Note: the _columns_ of a matrix are stored in program registers, not
    * the rows.
    */
   /* XXXX need to test 3x3 and 2x2 matrices... */
   maxCount = shProg->Uniforms->Parameters[location].Size / (4 * cols);
   if (count > maxCount)
      count = maxCount;
   for (i = 0; i < count; i++) {
      if (transpose) {
         GLuint row, col;
         for (col = 0; col < cols; col++) {
            GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
            for (row = 0; row < rows; row++) {
               v[row] = values[row * cols + col];
            }
         }
      }
      else {
         GLuint row, col;
         for (col = 0; col < cols; col++) {
            GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
            for (row = 0; row < rows; row++) {
               v[row] = values[col * rows + row];
            }
         }
      }
      location += cols;
      values += rows * cols;
   }
}
Beispiel #24
0
/**
 * New in GL 3.0
 * Clear unsigned integer color buffer (not depth, not stencil).
 */
void GLAPIENTRY
_mesa_ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value)
{
   GET_CURRENT_CONTEXT(ctx);

   FLUSH_VERTICES(ctx, 0);
   FLUSH_CURRENT(ctx, 0);

   if (ctx->NewState) {
      _mesa_update_state( ctx );
   }

   switch (buffer) {
   case GL_COLOR:
      {
         const GLbitfield mask = make_color_buffer_mask(ctx, drawbuffer);
         if (mask == INVALID_MASK) {
            _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferuiv(drawbuffer=%d)",
                        drawbuffer);
            return;
         }
         else if (mask && !ctx->RasterDiscard) {
            union gl_color_union clearSave;

            /* save color */
            clearSave = ctx->Color.ClearColor;
            /* set color */
            COPY_4V(ctx->Color.ClearColor.ui, value);
            /* clear buffer(s) */
            ctx->Driver.Clear(ctx, mask);
            /* restore color */
            ctx->Color.ClearColor = clearSave;
         }
      }
      break;
   case GL_DEPTH:
   case GL_STENCIL:
      /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
       *
       *     "The result of ClearBuffer is undefined if no conversion between
       *     the type of the specified value and the type of the buffer being
       *     cleared is defined (for example, if ClearBufferiv is called for a
       *     fixed- or floating-point buffer, or if ClearBufferfv is called
       *     for a signed or unsigned integer buffer). This is not an error."
       *
       * In this case we take "undefined" and "not an error" to mean "ignore."
       * Even though we could do something sensible for GL_STENCIL, page 263
       * (page 279 of the PDF) says:
       *
       *     "Only ClearBufferiv should be used to clear stencil buffers."
       *
       * Note that we still need to generate an error for the invalid
       * drawbuffer case (see the GL_STENCIL case in _mesa_ClearBufferiv).
       */
      if (drawbuffer != 0) {
         _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferuiv(drawbuffer=%d)",
                     drawbuffer);
         return;
      }
      return;
   default:
      _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferuiv(buffer=%s)",
                  _mesa_lookup_enum_by_nr(buffer));
      return;
   }
}
Beispiel #25
0
static void
map2( GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder,
      GLfloat v1, GLfloat v2, GLint vstride, GLint vorder,
      const GLvoid *points, GLenum type )
{
   GET_CURRENT_CONTEXT(ctx);
   GLint k;
   GLfloat *pnts;
   struct gl_2d_map *map = NULL;

   ASSERT_OUTSIDE_BEGIN_END(ctx);
   ASSERT(type == GL_FLOAT || type == GL_DOUBLE);

   if (u1==u2) {
      _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(u1,u2)" );
      return;
   }

   if (v1==v2) {
      _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(v1,v2)" );
      return;
   }

   if (uorder<1 || uorder>MAX_EVAL_ORDER) {
      _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(uorder)" );
      return;
   }

   if (vorder<1 || vorder>MAX_EVAL_ORDER) {
      _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(vorder)" );
      return;
   }

   k = _mesa_evaluator_components( target );
   if (k==0) {
      _mesa_error( ctx, GL_INVALID_ENUM, "glMap2(target)" );
   }

   if (ustride < k) {
      _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(ustride)" );
      return;
   }
   if (vstride < k) {
      _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(vstride)" );
      return;
   }

   map = get_2d_map(ctx, target);
   if (!map) {
      _mesa_error( ctx, GL_INVALID_ENUM, "glMap2(target)" );
      return;
   }

   /* make copy of the control points */
   if (type == GL_FLOAT)
      pnts = _mesa_copy_map_points2f(target, ustride, uorder,
                                  vstride, vorder, (GLfloat*) points);
   else
      pnts = _mesa_copy_map_points2d(target, ustride, uorder,
                                  vstride, vorder, (GLdouble*) points);


   FLUSH_VERTICES(ctx, _NEW_EVAL);
   map->Uorder = uorder;
   map->u1 = u1;
   map->u2 = u2;
   map->du = 1.0F / (u2 - u1);
   map->Vorder = vorder;
   map->v1 = v1;
   map->v2 = v2;
   map->dv = 1.0F / (v2 - v1);
   if (map->Points)
      FREE( map->Points );
   map->Points = pnts;
}
Beispiel #26
0
/**
 * New in GL 3.0
 * Clear fixed-pt or float color buffer or depth buffer (not stencil).
 */
void GLAPIENTRY
_mesa_ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value)
{
   GET_CURRENT_CONTEXT(ctx);

   FLUSH_VERTICES(ctx, 0);
   FLUSH_CURRENT(ctx, 0);

   if (ctx->NewState) {
      _mesa_update_state( ctx );
   }

   switch (buffer) {
   case GL_DEPTH:
      /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
       *
       *     "ClearBuffer generates an INVALID VALUE error if buffer is
       *     COLOR and drawbuffer is less than zero, or greater than the
       *     value of MAX DRAW BUFFERS minus one; or if buffer is DEPTH,
       *     STENCIL, or DEPTH STENCIL and drawbuffer is not zero."
       */
      if (drawbuffer != 0) {
         _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)",
                     drawbuffer);
         return;
      }
      else if (ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer && !ctx->RasterDiscard) {
         /* Save current depth clear value, set to 'value', do the
          * depth clear and restore the clear value.
          * XXX in the future we may have a new ctx->Driver.ClearBuffer()
          * hook instead.
          */
         const GLclampd clearSave = ctx->Depth.Clear;
         ctx->Depth.Clear = *value;
         ctx->Driver.Clear(ctx, BUFFER_BIT_DEPTH);
         ctx->Depth.Clear = clearSave;
      }
      /* clear depth buffer to value */
      break;
   case GL_COLOR:
      {
         const GLbitfield mask = make_color_buffer_mask(ctx, drawbuffer);
         if (mask == INVALID_MASK) {
            _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)",
                        drawbuffer);
            return;
         }
         else if (mask && !ctx->RasterDiscard) {
            union gl_color_union clearSave;

            /* save color */
            clearSave = ctx->Color.ClearColor;
            /* set color */
            COPY_4V(ctx->Color.ClearColor.f, value);
            /* clear buffer(s) */
            ctx->Driver.Clear(ctx, mask);
            /* restore color */
            ctx->Color.ClearColor = clearSave;
         }
      }
      break;
   case GL_STENCIL:
      /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
       *
       *     "The result of ClearBuffer is undefined if no conversion between
       *     the type of the specified value and the type of the buffer being
       *     cleared is defined (for example, if ClearBufferiv is called for a
       *     fixed- or floating-point buffer, or if ClearBufferfv is called
       *     for a signed or unsigned integer buffer). This is not an error."
       *
       * In this case we take "undefined" and "not an error" to mean "ignore."
       * Note that we still need to generate an error for the invalid
       * drawbuffer case (see the GL_DEPTH case above).
       */
      if (drawbuffer != 0) {
         _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)",
                     drawbuffer);
         return;
      }
      return;
   default:
      _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferfv(buffer=%s)",
                  _mesa_lookup_enum_by_nr(buffer));
      return;
   }
}
Beispiel #27
0
/**
 * Called via glUniform*() functions.
 */
extern "C" void
_mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg,
	      GLint location, GLsizei count,
              const GLvoid *values, GLenum type)
{
   unsigned loc, offset;
   unsigned components;
   unsigned src_components;
   enum glsl_base_type basicType;
   struct gl_uniform_storage *uni;

   ASSERT_OUTSIDE_BEGIN_END(ctx);

   if (!validate_uniform_parameters(ctx, shProg, location, count,
				    &loc, &offset, "glUniform", false))
      return;

   uni = &shProg->UniformStorage[loc];

   /* Verify that the types are compatible.
    */
   switch (type) {
   case GL_FLOAT:
      basicType = GLSL_TYPE_FLOAT;
      src_components = 1;
      break;
   case GL_FLOAT_VEC2:
      basicType = GLSL_TYPE_FLOAT;
      src_components = 2;
      break;
   case GL_FLOAT_VEC3:
      basicType = GLSL_TYPE_FLOAT;
      src_components = 3;
      break;
   case GL_FLOAT_VEC4:
      basicType = GLSL_TYPE_FLOAT;
      src_components = 4;
      break;
   case GL_UNSIGNED_INT:
      basicType = GLSL_TYPE_UINT;
      src_components = 1;
      break;
   case GL_UNSIGNED_INT_VEC2:
      basicType = GLSL_TYPE_UINT;
      src_components = 2;
      break;
   case GL_UNSIGNED_INT_VEC3:
      basicType = GLSL_TYPE_UINT;
      src_components = 3;
      break;
   case GL_UNSIGNED_INT_VEC4:
      basicType = GLSL_TYPE_UINT;
      src_components = 4;
      break;
   case GL_INT:
      basicType = GLSL_TYPE_INT;
      src_components = 1;
      break;
   case GL_INT_VEC2:
      basicType = GLSL_TYPE_INT;
      src_components = 2;
      break;
   case GL_INT_VEC3:
      basicType = GLSL_TYPE_INT;
      src_components = 3;
      break;
   case GL_INT_VEC4:
      basicType = GLSL_TYPE_INT;
      src_components = 4;
      break;
   case GL_BOOL:
   case GL_BOOL_VEC2:
   case GL_BOOL_VEC3:
   case GL_BOOL_VEC4:
   case GL_FLOAT_MAT2:
   case GL_FLOAT_MAT2x3:
   case GL_FLOAT_MAT2x4:
   case GL_FLOAT_MAT3x2:
   case GL_FLOAT_MAT3:
   case GL_FLOAT_MAT3x4:
   case GL_FLOAT_MAT4x2:
   case GL_FLOAT_MAT4x3:
   case GL_FLOAT_MAT4:
   default:
      _mesa_problem(NULL, "Invalid type in %s", __func__);
      return;
   }

   if (uni->type->is_sampler()) {
      components = 1;
   } else {
      components = uni->type->vector_elements;
   }

   bool match;
   switch (uni->type->base_type) {
   case GLSL_TYPE_BOOL:
      match = true;
      break;
   case GLSL_TYPE_SAMPLER:
      match = (basicType == GLSL_TYPE_INT);
      break;
   default:
      match = (basicType == uni->type->base_type);
      break;
   }

   if (uni->type->is_matrix() || components != src_components || !match) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
      return;
   }

   if (ctx->Shader.Flags & GLSL_UNIFORMS) {
      log_uniform(values, basicType, components, 1, count,
		  false, shProg, location, uni);
   }

   /* Page 100 (page 116 of the PDF) of the OpenGL 3.0 spec says:
    *
    *     "Setting a sampler's value to i selects texture image unit number
    *     i. The values of i range from zero to the implementation- dependent
    *     maximum supported number of texture image units."
    *
    * In addition, table 2.3, "Summary of GL errors," on page 17 (page 33 of
    * the PDF) says:
    *
    *     "Error         Description                    Offending command
    *                                                   ignored?
    *     ...
    *     INVALID_VALUE  Numeric argument out of range  Yes"
    *
    * Based on that, when an invalid sampler is specified, we generate a
    * GL_INVALID_VALUE error and ignore the command.
    */
   if (uni->type->is_sampler()) {
      int i;

      for (i = 0; i < count; i++) {
	 const unsigned texUnit = ((unsigned *) values)[i];

         /* check that the sampler (tex unit index) is legal */
         if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) {
            _mesa_error(ctx, GL_INVALID_VALUE,
                        "glUniform1i(invalid sampler/tex unit index for "
			"uniform %d)",
                        location);
            return;
         }
      }
   }

   /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
    *
    *     "When loading N elements starting at an arbitrary position k in a
    *     uniform declared as an array, elements k through k + N - 1 in the
    *     array will be replaced with the new values. Values for any array
    *     element that exceeds the highest array element index used, as
    *     reported by GetActiveUniform, will be ignored by the GL."
    *
    * Clamp 'count' to a valid value.  Note that for non-arrays a count > 1
    * will have already generated an error.
    */
   if (uni->array_elements != 0) {
      if (offset >= uni->array_elements)
	 return;

      count = MIN2(count, (int) (uni->array_elements - offset));
   }

   FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);

   /* Store the data in the "actual type" backing storage for the uniform.
    */
   if (!uni->type->is_boolean()) {
      memcpy(&uni->storage[components * offset], values,
	     sizeof(uni->storage[0]) * components * count);
   } else {
      const union gl_constant_value *src =
	 (const union gl_constant_value *) values;
      union gl_constant_value *dst = &uni->storage[components * offset];
      const unsigned elems = components * count;
      unsigned i;

      for (i = 0; i < elems; i++) {
	 if (basicType == GLSL_TYPE_FLOAT) {
	    dst[i].i = src[i].f != 0.0f ? 1 : 0;
	 } else {
	    dst[i].i = src[i].i != 0    ? 1 : 0;
	 }
      }
   }

   uni->initialized = true;

   _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);

   /* If the uniform is a sampler, do the extra magic necessary to propagate
    * the changes through.
    */
   if (uni->type->is_sampler()) {
      int i;

      for (i = 0; i < count; i++) {
	 shProg->SamplerUnits[uni->sampler + offset + i] =
	    ((unsigned *) values)[i];
      }

      bool flushed = false;
      for (i = 0; i < MESA_SHADER_TYPES; i++) {
	 struct gl_shader *const sh = shProg->_LinkedShaders[i];

	 /* If the shader stage doesn't use any samplers, don't bother
	  * checking if any samplers have changed.
	  */
	 if (sh == NULL || sh->active_samplers == 0)
	    continue;

	 struct gl_program *const prog = sh->Program;

	 assert(sizeof(prog->SamplerUnits) == sizeof(shProg->SamplerUnits));

	 /* Determine if any of the samplers used by this shader stage have
	  * been modified.
	  */
	 bool changed = false;
	 for (unsigned j = 0; j < Elements(prog->SamplerUnits); j++) {
	    if ((sh->active_samplers & (1U << j)) != 0
		&& (prog->SamplerUnits[j] != shProg->SamplerUnits[j])) {
	       changed = true;
	       break;
	    }
	 }

	 if (changed) {
	    if (!flushed) {
	       FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
	       flushed = true;
	    }

	    memcpy(prog->SamplerUnits,
		   shProg->SamplerUnits,
		   sizeof(shProg->SamplerUnits));

	    _mesa_update_shader_textures_used(shProg, prog);
	    (void) ctx->Driver.ProgramStringNotify(ctx, prog->Target, prog);
	 }
      }
   }
}
Beispiel #28
0
void GLAPIENTRY
_mesa_BindSamplers(GLuint first, GLsizei count, const GLuint *samplers)
{
   GET_CURRENT_CONTEXT(ctx);
   GLint i;

   /* The ARB_multi_bind spec says:
    *
    *   "An INVALID_OPERATION error is generated if <first> + <count> is
    *    greater than the number of texture image units supported by
    *    the implementation."
    */
   if (first + count > ctx->Const.MaxCombinedTextureImageUnits) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glBindSamplers(first=%u + count=%d > the value of "
                  "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS=%u)",
                  first, count, ctx->Const.MaxCombinedTextureImageUnits);
      return;
   }

   FLUSH_VERTICES(ctx, 0);

   if (samplers) {
      /* Note that the error semantics for multi-bind commands differ from
       * those of other GL commands.
       *
       * The Issues section in the ARB_multi_bind spec says:
       *
       *    "(11) Typically, OpenGL specifies that if an error is generated by
       *          a command, that command has no effect.  This is somewhat
       *          unfortunate for multi-bind commands, because it would require
       *          a first pass to scan the entire list of bound objects for
       *          errors and then a second pass to actually perform the
       *          bindings.  Should we have different error semantics?
       *
       *       RESOLVED:  Yes.  In this specification, when the parameters for
       *       one of the <count> binding points are invalid, that binding
       *       point is not updated and an error will be generated.  However,
       *       other binding points in the same command will be updated if
       *       their parameters are valid and no other error occurs."
       */

      begin_samplerobj_lookups(ctx);

      for (i = 0; i < count; i++) {
         const GLuint unit = first + i;
         struct gl_sampler_object * const currentSampler =
             ctx->Texture.Unit[unit].Sampler;
         struct gl_sampler_object *sampObj;

         if (samplers[i] != 0) {
            if (currentSampler && currentSampler->Name == samplers[i])
               sampObj = currentSampler;
            else
               sampObj = lookup_samplerobj_locked(ctx, samplers[i]);

            /* The ARB_multi_bind spec says:
             *
             *    "An INVALID_OPERATION error is generated if any value
             *     in <samplers> is not zero or the name of an existing
             *     sampler object (per binding)."
             */
            if (!sampObj) {
               _mesa_error(ctx, GL_INVALID_OPERATION,
                           "glBindSamplers(samplers[%d]=%u is not zero or "
                           "the name of an existing sampler object)",
                           i, samplers[i]);
               continue;
            }
         } else {
            sampObj = NULL;
         }

         /* Bind the new sampler */
         if (sampObj != currentSampler) {
            _mesa_reference_sampler_object(ctx,
                                           &ctx->Texture.Unit[unit].Sampler,
                                           sampObj);
            ctx->NewState |= _NEW_TEXTURE;
         }
      }

      end_samplerobj_lookups(ctx);
   } else {
      /* Unbind all samplers in the range <first> through <first>+<count>-1 */
      for (i = 0; i < count; i++) {
         const GLuint unit = first + i;

         if (ctx->Texture.Unit[unit].Sampler) {
            _mesa_reference_sampler_object(ctx,
                                           &ctx->Texture.Unit[unit].Sampler,
                                           NULL);
            ctx->NewState |= _NEW_TEXTURE;
         }
      }
   }
}
Beispiel #29
0
static void GLAPIENTRY
_mesa_Histogram(GLenum target, GLsizei width, GLenum internalFormat, GLboolean sink)
{
   GLuint i;
   GLboolean error = GL_FALSE;
   GET_CURRENT_CONTEXT(ctx);
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* sideeffects */

   if (!ctx->Extensions.EXT_histogram && !ctx->Extensions.ARB_imaging) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glHistogram");
      return;
   }

   if (target != GL_HISTOGRAM && target != GL_PROXY_HISTOGRAM) {
      _mesa_error(ctx, GL_INVALID_ENUM, "glHistogram(target)");
      return;
   }

   if (width < 0 || width > HISTOGRAM_TABLE_SIZE) {
      if (target == GL_PROXY_HISTOGRAM) {
         error = GL_TRUE;
      }
      else {
         if (width < 0)
            _mesa_error(ctx, GL_INVALID_VALUE, "glHistogram(width)");
         else
            _mesa_error(ctx, GL_TABLE_TOO_LARGE, "glHistogram(width)");
         return;
      }
   }

   if (width != 0 && !_mesa_is_pow_two(width)) {
      if (target == GL_PROXY_HISTOGRAM) {
         error = GL_TRUE;
      }
      else {
         _mesa_error(ctx, GL_INVALID_VALUE, "glHistogram(width)");
         return;
      }
   }

   if (base_histogram_format(internalFormat) < 0) {
      if (target == GL_PROXY_HISTOGRAM) {
         error = GL_TRUE;
      }
      else {
         _mesa_error(ctx, GL_INVALID_ENUM, "glHistogram(internalFormat)");
         return;
      }
   }

   FLUSH_VERTICES(ctx, _NEW_PIXEL);

   /* reset histograms */
   for (i = 0; i < HISTOGRAM_TABLE_SIZE; i++) {
      ctx->Histogram.Count[i][0] = 0;
      ctx->Histogram.Count[i][1] = 0;
      ctx->Histogram.Count[i][2] = 0;
      ctx->Histogram.Count[i][3] = 0;
   }

   if (error) {
      ctx->Histogram.Width = 0;
      ctx->Histogram.Format = 0;
      ctx->Histogram.RedSize       = 0;
      ctx->Histogram.GreenSize     = 0;
      ctx->Histogram.BlueSize      = 0;
      ctx->Histogram.AlphaSize     = 0;
      ctx->Histogram.LuminanceSize = 0;
   }
   else {
      ctx->Histogram.Width = width;
      ctx->Histogram.Format = internalFormat;
      ctx->Histogram.Sink = sink;
      ctx->Histogram.RedSize       = 8 * sizeof(GLuint);
      ctx->Histogram.GreenSize     = 8 * sizeof(GLuint);
      ctx->Histogram.BlueSize      = 8 * sizeof(GLuint);
      ctx->Histogram.AlphaSize     = 8 * sizeof(GLuint);
      ctx->Histogram.LuminanceSize = 8 * sizeof(GLuint);
   }
}
Beispiel #30
0
/**
 * Helper function to set the GL_DRAW_BUFFER state in the context and
 * current FBO.  Called via glDrawBuffer(), glDrawBuffersARB()
 *
 * All error checking will have been done prior to calling this function
 * so nothing should go wrong at this point.
 *
 * \param ctx  current context
 * \param n    number of color outputs to set
 * \param buffers  array[n] of colorbuffer names, like GL_LEFT.
 * \param destMask  array[n] of BUFFER_BIT_* bitmasks which correspond to the
 *                  colorbuffer names.  (i.e. GL_FRONT_AND_BACK =>
 *                  BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT).
 */
void
_mesa_drawbuffers(GLcontext *ctx, GLuint n, const GLenum *buffers,
                  const GLbitfield *destMask)
{
   struct gl_framebuffer *fb = ctx->DrawBuffer;
   GLbitfield mask[MAX_DRAW_BUFFERS];
   GLboolean newState = GL_FALSE;

   if (!destMask) {
      /* compute destMask values now */
      const GLbitfield supportedMask = supported_buffer_bitmask(ctx, fb);
      GLuint output;
      for (output = 0; output < n; output++) {
         mask[output] = draw_buffer_enum_to_bitmask(buffers[output]);
         ASSERT(mask[output] != BAD_MASK);
         mask[output] &= supportedMask;
      }
      destMask = mask;
   }

   /*
    * If n==1, destMask[0] may have up to four bits set.
    * Otherwise, destMask[x] can only have one bit set.
    */
   if (n == 1) {
      GLuint count = 0, destMask0 = destMask[0];
      while (destMask0) {
         GLint bufIndex = _mesa_ffs(destMask0) - 1;
         if (fb->_ColorDrawBufferIndexes[count] != bufIndex) {
            fb->_ColorDrawBufferIndexes[count] = bufIndex;
            newState = GL_TRUE;
         }
         count++;
         destMask0 &= ~(1 << bufIndex);
      }
      fb->ColorDrawBuffer[0] = buffers[0];
      if (fb->_NumColorDrawBuffers != count) {
         fb->_NumColorDrawBuffers = count;
         newState = GL_TRUE;
      }
   }
   else {
      GLuint buf, count = 0;
      for (buf = 0; buf < n; buf++ ) {
         if (destMask[buf]) {
            GLint bufIndex = _mesa_ffs(destMask[buf]) - 1;
            /* only one bit should be set in the destMask[buf] field */
            ASSERT(_mesa_bitcount(destMask[buf]) == 1);
            if (fb->_ColorDrawBufferIndexes[buf] != bufIndex) {
               fb->_ColorDrawBufferIndexes[buf] = bufIndex;
               newState = GL_TRUE;
            }
            fb->ColorDrawBuffer[buf] = buffers[buf];
            count = buf + 1;
         }
         else {
            if (fb->_ColorDrawBufferIndexes[buf] != -1) {
               fb->_ColorDrawBufferIndexes[buf] = -1;
               newState = GL_TRUE;
            }
         }
      }
      /* set remaining outputs to -1 (GL_NONE) */
      while (buf < ctx->Const.MaxDrawBuffers) {
         if (fb->_ColorDrawBufferIndexes[buf] != -1) {
            fb->_ColorDrawBufferIndexes[buf] = -1;
            newState = GL_TRUE;
         }
         fb->ColorDrawBuffer[buf] = GL_NONE;
         buf++;
      }
      fb->_NumColorDrawBuffers = count;
   }

   if (fb->Name == 0) {
      /* also set context drawbuffer state */
      GLuint buf;
      for (buf = 0; buf < ctx->Const.MaxDrawBuffers; buf++) {
         if (ctx->Color.DrawBuffer[buf] != fb->ColorDrawBuffer[buf]) {
            ctx->Color.DrawBuffer[buf] = fb->ColorDrawBuffer[buf];
            newState = GL_TRUE;
         }
      }
   }

   if (newState)
      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
}