Exemplo n.º 1
0
static void
upload_sol_state(struct brw_context *brw)
{
   struct intel_context *intel = &brw->intel;
   struct gl_context *ctx = &intel->ctx;
   /* BRW_NEW_TRANSFORM_FEEDBACK */
   bool active = _mesa_is_xfb_active_and_unpaused(ctx);

   if (active) {
      upload_3dstate_so_buffers(brw);
      /* BRW_NEW_VUE_MAP_GEOM_OUT */
      upload_3dstate_so_decl_list(brw, &brw->vue_map_geom_out);

      /* If we don't have hardware contexts, then some other client may have
       * changed the SO write offsets, and we need to rewrite them.
       */
      if (!intel->hw_ctx)
         intel->batch.needs_sol_reset = true;
   }

   /* Finally, set up the SOL stage.  This command must always follow updates to
    * the nonpipelined SOL state (3DSTATE_SO_BUFFER, 3DSTATE_SO_DECL_LIST) or
    * MMIO register updates (current performed by the kernel at each batch
    * emit).
    */
   upload_3dstate_streamout(brw, active, &brw->vue_map_geom_out);
}
Exemplo n.º 2
0
static void
gen6_update_sol_surfaces(struct brw_context *brw)
{
   struct gl_context *ctx = &brw->ctx;
   /* BRW_NEW_TRANSFORM_FEEDBACK */
   struct gl_transform_feedback_object *xfb_obj =
      ctx->TransformFeedback.CurrentObject;
   /* BRW_NEW_VERTEX_PROGRAM */
   const struct gl_shader_program *shaderprog =
      ctx->Shader.CurrentVertexProgram;
   const struct gl_transform_feedback_info *linked_xfb_info =
      &shaderprog->LinkedTransformFeedback;
   int i;

   for (i = 0; i < BRW_MAX_SOL_BINDINGS; ++i) {
      const int surf_index = SURF_INDEX_GEN6_SOL_BINDING(i);
      if (_mesa_is_xfb_active_and_unpaused(ctx) &&
          i < linked_xfb_info->NumOutputs) {
         unsigned buffer = linked_xfb_info->Outputs[i].OutputBuffer;
         unsigned buffer_offset =
            xfb_obj->Offset[buffer] / 4 +
            linked_xfb_info->Outputs[i].DstOffset;
         brw_update_sol_surface(
            brw, xfb_obj->Buffers[buffer], &brw->ff_gs.surf_offset[surf_index],
            linked_xfb_info->Outputs[i].NumComponents,
            linked_xfb_info->BufferStride[buffer], buffer_offset);
      } else {
         brw->ff_gs.surf_offset[surf_index] = 0;
      }
   }

   brw->state.dirty.brw |= BRW_NEW_SURFACES;
}
Exemplo n.º 3
0
/**
 * For GL_EXT_separate_shader_objects
 */
void GLAPIENTRY
_mesa_UseShaderProgramEXT(GLenum type, GLuint program)
{
   GET_CURRENT_CONTEXT(ctx);
   struct gl_shader_program *shProg = NULL;

   if (!validate_shader_target(ctx, type)) {
      _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)");
      return;
   }

   if (_mesa_is_xfb_active_and_unpaused(ctx)) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glUseShaderProgramEXT(transform feedback is active)");
      return;
   }

   if (program) {
      shProg = _mesa_lookup_shader_program_err(ctx, program,
					       "glUseShaderProgramEXT");
      if (shProg == NULL)
	 return;

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

   _mesa_use_shader_program(ctx, type, shProg);
}
Exemplo n.º 4
0
void GLAPIENTRY
_mesa_UseProgram(GLhandleARB program)
{
   GET_CURRENT_CONTEXT(ctx);
   struct gl_shader_program *shProg;

   if (_mesa_is_xfb_active_and_unpaused(ctx)) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glUseProgram(transform feedback active)");
      return;
   }

   if (program) {
      shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
      if (!shProg) {
         return;
      }
      if (!shProg->LinkStatus) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glUseProgram(program %u not linked)", program);
         return;
      }

      /* debug code */
      if (ctx->Shader.Flags & GLSL_USE_PROG) {
         print_shader_info(shProg);
      }
   }
   else {
      shProg = NULL;
   }

   _mesa_use_program(ctx, shProg);
}
Exemplo n.º 5
0
/**
 * Update internal counters based on the the drawing operation described in
 * prim.
 */
static void
brw_update_primitive_count(struct brw_context *brw,
                           const struct _mesa_prim *prim)
{
   uint32_t count
      = vbo_count_tessellated_primitives(prim->mode, prim->count,
                                         prim->num_instances);
   brw->sol.primitives_generated += count;
   if (_mesa_is_xfb_active_and_unpaused(&brw->intel.ctx)) {
      /* Update brw->sol.svbi_0_max_index to reflect the amount by which the
       * hardware is going to increment SVBI 0 when this drawing operation
       * occurs.  This is necessary because the kernel does not (yet) save and
       * restore GPU registers when context switching, so we'll need to be
       * able to reload SVBI 0 with the correct value in case we have to start
       * a new batch buffer.
       */
      unsigned verts = verts_per_prim(prim->mode);
      uint32_t space_avail =
         (brw->sol.svbi_0_max_index - brw->sol.svbi_0_starting_index) / verts;
      uint32_t primitives_written = MIN2 (space_avail, count);
      brw->sol.svbi_0_starting_index += verts * primitives_written;

      /* And update the TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query. */
      brw->sol.primitives_written += primitives_written;
   }
}
Exemplo n.º 6
0
/**
 * Bind the given transform feedback object.
 * Part of GL_ARB_transform_feedback2.
 */
void GLAPIENTRY
_mesa_BindTransformFeedback(GLenum target, GLuint name)
{
   struct gl_transform_feedback_object *obj;
   GET_CURRENT_CONTEXT(ctx);

   if (target != GL_TRANSFORM_FEEDBACK) {
      _mesa_error(ctx, GL_INVALID_ENUM, "glBindTransformFeedback(target)");
      return;
   }

   if (_mesa_is_xfb_active_and_unpaused(ctx)) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
              "glBindTransformFeedback(transform is active, or not paused)");
      return;
   }

   obj = _mesa_lookup_transform_feedback_object(ctx, name);
   if (!obj) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glBindTransformFeedback(name=%u)", name);
      return;
   }

   reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject,
                                       obj);
}
Exemplo n.º 7
0
/**
 * Error checking for glDrawElements().  Includes parameter checking
 * and VBO bounds checking.
 * \return GL_TRUE if OK to render, GL_FALSE if error found
 */
GLboolean
_mesa_validate_DrawElements(struct gl_context *ctx,
			    GLenum mode, GLsizei count, GLenum type,
			    const GLvoid *indices, GLint basevertex)
{
   FLUSH_CURRENT(ctx, 0);

   /* From the GLES3 specification, section 2.14.2 (Transform Feedback
    * Primitive Capture):
    *
    *   The error INVALID_OPERATION is also generated by DrawElements,
    *   DrawElementsInstanced, and DrawRangeElements while transform feedback
    *   is active and not paused, regardless of mode.
    */
   if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glDrawElements(transform feedback active)");
      return GL_FALSE;
   }

   if (count <= 0) {
      if (count < 0)
	 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" );
      return GL_FALSE;
   }

   if (!_mesa_valid_prim_mode(ctx, mode, "glDrawElements")) {
      return GL_FALSE;
   }

   if (!valid_elements_type(ctx, type, "glDrawElements"))
      return GL_FALSE;

   if (!check_valid_to_render(ctx, "glDrawElements"))
      return GL_FALSE;

   /* Vertex buffer object tests */
   if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
      /* use indices in the buffer object */
      /* make sure count doesn't go outside buffer bounds */
      if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
         _mesa_warning(ctx, "glDrawElements index out of buffer bounds");
         return GL_FALSE;
      }
   }
   else {
      /* not using a VBO */
      if (!indices)
         return GL_FALSE;
   }

   if (!check_index_bounds(ctx, count, type, indices, basevertex))
      return GL_FALSE;

   return GL_TRUE;
}
Exemplo n.º 8
0
static void
gen6_update_sol_surfaces(struct brw_context *brw)
{
   struct gl_context *ctx = &brw->ctx;
   /* BRW_NEW_TRANSFORM_FEEDBACK */
   struct gl_transform_feedback_object *xfb_obj =
      ctx->TransformFeedback.CurrentObject;
   const struct gl_shader_program *shaderprog;
   const struct gl_transform_feedback_info *linked_xfb_info;
   int i;

   if (brw->geometry_program) {
      /* BRW_NEW_GEOMETRY_PROGRAM */
      shaderprog =
         ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY];
   } else {
      /* BRW_NEW_VERTEX_PROGRAM */
      shaderprog =
         ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX];
   }
   linked_xfb_info = &shaderprog->LinkedTransformFeedback;

   for (i = 0; i < BRW_MAX_SOL_BINDINGS; ++i) {
      const int surf_index = SURF_INDEX_GEN6_SOL_BINDING(i);
      if (_mesa_is_xfb_active_and_unpaused(ctx) &&
          i < linked_xfb_info->NumOutputs) {
         unsigned buffer = linked_xfb_info->Outputs[i].OutputBuffer;
         unsigned buffer_offset =
            xfb_obj->Offset[buffer] / 4 +
            linked_xfb_info->Outputs[i].DstOffset;
         if (brw->geometry_program) {
            brw_update_sol_surface(
               brw, xfb_obj->Buffers[buffer],
               &brw->gs.base.surf_offset[surf_index],
               linked_xfb_info->Outputs[i].NumComponents,
               linked_xfb_info->Buffers[buffer].Stride, buffer_offset);
         } else {
            brw_update_sol_surface(
               brw, xfb_obj->Buffers[buffer],
               &brw->ff_gs.surf_offset[surf_index],
               linked_xfb_info->Outputs[i].NumComponents,
               linked_xfb_info->Buffers[buffer].Stride, buffer_offset);
         }
      } else {
         if (!brw->geometry_program)
            brw->ff_gs.surf_offset[surf_index] = 0;
         else
            brw->gs.base.surf_offset[surf_index] = 0;
      }
   }

   brw->ctx.NewDriverState |= BRW_NEW_SURFACES;
}
Exemplo n.º 9
0
/**
 * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(),
 * etc?  Also, do additional checking related to transformation feedback.
 * Note: this function cannot be called during glNewList(GL_COMPILE) because
 * this code depends on current transform feedback state.
 */
GLboolean
_mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name)
{
   bool valid_enum = _mesa_is_valid_prim_mode(ctx, mode);

   if (!valid_enum) {
      _mesa_error(ctx, GL_INVALID_ENUM, "%s(mode=%x)", name, mode);
      return GL_FALSE;
   }

   /* From the GL_EXT_transform_feedback spec:
    *
    *     "The error INVALID_OPERATION is generated if Begin, or any command
    *      that performs an explicit Begin, is called when:
    *
    *      * a geometry shader is not active and <mode> does not match the
    *        allowed begin modes for the current transform feedback state as
    *        given by table X.1.
    *
    *      * a geometry shader is active and the output primitive type of the
    *        geometry shader does not match the allowed begin modes for the
    *        current transform feedback state as given by table X.1.
    *
    */
   if (_mesa_is_xfb_active_and_unpaused(ctx)) {
      GLboolean pass = GL_TRUE;

      switch (mode) {
      case GL_POINTS:
         pass = ctx->TransformFeedback.Mode == GL_POINTS;
	 break;
      case GL_LINES:
      case GL_LINE_STRIP:
      case GL_LINE_LOOP:
         pass = ctx->TransformFeedback.Mode == GL_LINES;
	 break;
      default:
         pass = ctx->TransformFeedback.Mode == GL_TRIANGLES;
	 break;
      }
      if (!pass) {
	 _mesa_error(ctx, GL_INVALID_OPERATION,
		     "%s(mode=%s vs transform feedback %s)",
		     name,
		     _mesa_lookup_prim_by_nr(mode),
		     _mesa_lookup_prim_by_nr(ctx->TransformFeedback.Mode));
	 return GL_FALSE;
      }
   }

   return GL_TRUE;
}
Exemplo n.º 10
0
/**
 * Called from the tnl module to error check the function parameters and
 * verify that we really can draw something.
 * \return GL_TRUE if OK to render, GL_FALSE if error found
 */
GLboolean
_mesa_validate_DrawArrays(struct gl_context *ctx,
			  GLenum mode, GLint start, GLsizei count)
{
   struct gl_transform_feedback_object *xfb_obj
      = ctx->TransformFeedback.CurrentObject;
   FLUSH_CURRENT(ctx, 0);

   if (count <= 0) {
      if (count < 0)
         _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
      return GL_FALSE;
   }

   if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArrays")) {
      return GL_FALSE;
   }

   if (!check_valid_to_render(ctx, "glDrawArrays"))
      return GL_FALSE;

   if (ctx->Const.CheckArrayBounds) {
      if (start + count > (GLint) ctx->Array.ArrayObj->_MaxElement)
         return GL_FALSE;
   }

   /* From the GLES3 specification, section 2.14.2 (Transform Feedback
    * Primitive Capture):
    *
    *   The error INVALID_OPERATION is generated by DrawArrays and
    *   DrawArraysInstanced if recording the vertices of a primitive to the
    *   buffer objects being used for transform feedback purposes would result
    *   in either exceeding the limits of any buffer object’s size, or in
    *   exceeding the end position offset + size − 1, as set by
    *   BindBufferRange.
    *
    * This is in contrast to the behaviour of desktop GL, where the extra
    * primitives are silently dropped from the transform feedback buffer.
    */
   if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
      size_t prim_count = vbo_count_tessellated_primitives(mode, count, 1);
      if (xfb_obj->GlesRemainingPrims < prim_count) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glDrawArrays(exceeds transform feedback size)");
         return GL_FALSE;
      }
      xfb_obj->GlesRemainingPrims -= prim_count;
   }

   return GL_TRUE;
}
/**
 * Make program of the pipeline current
 */
void GLAPIENTRY
_mesa_BindProgramPipeline(GLuint pipeline)
{
   GET_CURRENT_CONTEXT(ctx);
   struct gl_pipeline_object *newObj = NULL;

   if (MESA_VERBOSE & VERBOSE_API)
      _mesa_debug(ctx, "glBindProgramPipeline(%u)\n", pipeline);

   /* Rebinding the same pipeline object: no change.
    */
   if (ctx->_Shader->Name == pipeline)
      return;

   /* Section 2.17.2 (Transform Feedback Primitive Capture) of the OpenGL 4.1
    * spec says:
    *
    *     "The error INVALID_OPERATION is generated:
    *
    *      ...
    *
    *         - by BindProgramPipeline if the current transform feedback
    *           object is active and not paused;
    */
   if (_mesa_is_xfb_active_and_unpaused(ctx)) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
            "glBindProgramPipeline(transform feedback active)");
      return;
   }

   /* Get pointer to new pipeline object (newObj)
    */
   if (pipeline) {
      /* non-default pipeline object */
      newObj = _mesa_lookup_pipeline_object(ctx, pipeline);
      if (!newObj) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glBindProgramPipeline(non-gen name)");
         return;
      }

      /* Object is created by any Pipeline call but glGenProgramPipelines,
       * glIsProgramPipeline and GetProgramPipelineInfoLog
       */
      newObj->EverBound = GL_TRUE;
   }

   _mesa_bind_pipeline(ctx, newObj);
}
Exemplo n.º 12
0
static void
upload_sol_state(struct brw_context *brw)
{
   struct gl_context *ctx = &brw->ctx;
   /* BRW_NEW_TRANSFORM_FEEDBACK */
   bool active = _mesa_is_xfb_active_and_unpaused(ctx);

   if (active) {
      gen8_upload_3dstate_so_buffers(brw);
      /* BRW_NEW_VUE_MAP_GEOM_OUT */
      gen7_upload_3dstate_so_decl_list(brw, &brw->vue_map_geom_out);
   }

   gen8_upload_3dstate_streamout(brw, active, &brw->vue_map_geom_out);
}
Exemplo n.º 13
0
static bool
validate_DrawElements_common(struct gl_context *ctx,
                             GLenum mode, GLsizei count, GLenum type,
                             const GLvoid *indices,
                             const char *caller)
{
   /* From the GLES3 specification, section 2.14.2 (Transform Feedback
    * Primitive Capture):
    *
    *   The error INVALID_OPERATION is also generated by DrawElements,
    *   DrawElementsInstanced, and DrawRangeElements while transform feedback
    *   is active and not paused, regardless of mode.
    */
   if (_mesa_is_gles3(ctx) && !ctx->Extensions.OES_geometry_shader &&
       _mesa_is_xfb_active_and_unpaused(ctx)) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "%s(transform feedback active)", caller);
      return false;
   }

   if (count < 0) {
      _mesa_error(ctx, GL_INVALID_VALUE, "%s(count)", caller);
      return false;
   }

   if (!_mesa_valid_prim_mode(ctx, mode, caller)) {
      return false;
   }

   if (!valid_elements_type(ctx, type, caller))
      return false;

   if (!check_valid_to_render(ctx, caller))
      return false;

   /* Not using a VBO for indices, so avoid NULL pointer derefs later.
    */
   if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj) && indices == NULL)
      return false;

   if (count == 0)
      return false;

   return true;
}
Exemplo n.º 14
0
static void
upload_sol_state(struct brw_context *brw)
{
    struct gl_context *ctx = &brw->ctx;
    /* BRW_NEW_TRANSFORM_FEEDBACK */
    bool active = _mesa_is_xfb_active_and_unpaused(ctx);

    if (active) {
        upload_3dstate_so_buffers(brw);
        /* BRW_NEW_VUE_MAP_GEOM_OUT */
        gen7_upload_3dstate_so_decl_list(brw, &brw->vue_map_geom_out);
    }

    /* Finally, set up the SOL stage.  This command must always follow updates to
     * the nonpipelined SOL state (3DSTATE_SO_BUFFER, 3DSTATE_SO_DECL_LIST) or
     * MMIO register updates (current performed by the kernel at each batch
     * emit).
     */
    upload_3dstate_streamout(brw, active, &brw->vue_map_geom_out);
}
Exemplo n.º 15
0
/**
 * Pause transform feedback.
 * Part of GL_ARB_transform_feedback2.
 */
void GLAPIENTRY
_mesa_PauseTransformFeedback(void)
{
   struct gl_transform_feedback_object *obj;
   GET_CURRENT_CONTEXT(ctx);

   obj = ctx->TransformFeedback.CurrentObject;

   if (!_mesa_is_xfb_active_and_unpaused(ctx)) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
           "glPauseTransformFeedback(feedback not active or already paused)");
      return;
   }

   FLUSH_VERTICES(ctx, 0);
   ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;

   obj->Paused = GL_TRUE;

   assert(ctx->Driver.PauseTransformFeedback);
   ctx->Driver.PauseTransformFeedback(ctx, obj);
}
Exemplo n.º 16
0
/**
 * Bound program to severals stages of the pipeline
 */
void GLAPIENTRY
_mesa_UseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program)
{
   GET_CURRENT_CONTEXT(ctx);

   struct gl_pipeline_object *pipe = lookup_pipeline_object(ctx, pipeline);
   struct gl_shader_program *shProg = NULL;
   GLbitfield any_valid_stages;

   if (!pipe) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgramStages(pipeline)");
      return;
   }

   /* Object is created by any Pipeline call but glGenProgramPipelines,
    * glIsProgramPipeline and GetProgramPipelineInfoLog
    */
   pipe->EverBound = GL_TRUE;

   /* Section 2.11.4 (Program Pipeline Objects) of the OpenGL 4.1 spec says:
    *
    *     "If stages is not the special value ALL_SHADER_BITS, and has a bit
    *     set that is not recognized, the error INVALID_VALUE is generated."
    *
    * NOT YET SUPPORTED:
    * GL_TESS_CONTROL_SHADER_BIT
    * GL_TESS_EVALUATION_SHADER_BIT
    */
   any_valid_stages = GL_VERTEX_SHADER_BIT | GL_FRAGMENT_SHADER_BIT;
   if (_mesa_has_geometry_shaders(ctx))
      any_valid_stages |= GL_GEOMETRY_SHADER_BIT;

   if (stages != GL_ALL_SHADER_BITS && (stages & ~any_valid_stages) != 0) {
      _mesa_error(ctx, GL_INVALID_VALUE, "glUseProgramStages(Stages)");
      return;
   }

   /* Section 2.17.2 (Transform Feedback Primitive Capture) of the OpenGL 4.1
    * spec says:
    *
    *     "The error INVALID_OPERATION is generated:
    *
    *      ...
    *
    *         - by UseProgramStages if the program pipeline object it refers
    *           to is current and the current transform feedback object is
    *           active and not paused;
    */
   if (ctx->_Shader == pipe) {
      if (_mesa_is_xfb_active_and_unpaused(ctx)) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
               "glUseProgramStages(transform feedback active)");
         return;
      }
   }

   if (program) {
      shProg = _mesa_lookup_shader_program_err(ctx, program,
                                               "glUseProgramStages");
      if (shProg == NULL)
         return;

      /* Section 2.11.4 (Program Pipeline Objects) of the OpenGL 4.1 spec
       * says:
       *
       *     "If the program object named by program was linked without the
       *     PROGRAM_SEPARABLE parameter set, or was not linked successfully,
       *     the error INVALID_OPERATION is generated and the corresponding
       *     shader stages in the pipeline program pipeline object are not
       *     modified."
       */
      if (!shProg->LinkStatus) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glUseProgramStages(program not linked)");
         return;
      }

      if (!shProg->SeparateShader) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glUseProgramStages(program wasn't linked with the "
                     "PROGRAM_SEPARABLE flag)");
         return;
      }
   }

   /* Enable individual stages from the program as requested by the
    * application.  If there is no shader for a requested stage in the
    * program, _mesa_use_shader_program will enable fixed-function processing
    * as dictated by the spec.
    *
    * Section 2.11.4 (Program Pipeline Objects) of the OpenGL 4.1 spec
    * says:
    *
    *     "If UseProgramStages is called with program set to zero or with a
    *     program object that contains no executable code for the given
    *     stages, it is as if the pipeline object has no programmable stage
    *     configured for the indicated shader stages."
    */
   if ((stages & GL_VERTEX_SHADER_BIT) != 0)
      _mesa_use_shader_program(ctx, GL_VERTEX_SHADER, shProg, pipe);

   if ((stages & GL_FRAGMENT_SHADER_BIT) != 0)
      _mesa_use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg, pipe);

   if ((stages & GL_GEOMETRY_SHADER_BIT) != 0)
      _mesa_use_shader_program(ctx, GL_GEOMETRY_SHADER, shProg, pipe);
}
Exemplo n.º 17
0
static GLboolean
valid_draw_indirect(struct gl_context *ctx,
                    GLenum mode, const GLvoid *indirect,
                    GLsizei size, const char *name)
{
   const uint64_t end = (uint64_t) (uintptr_t) indirect + size;

   /* OpenGL ES 3.1 spec. section 10.5:
    *
    *      "DrawArraysIndirect requires that all data sourced for the
    *      command, including the DrawArraysIndirectCommand
    *      structure,  be in buffer objects,  and may not be called when
    *      the default vertex array object is bound."
    */
   if (ctx->Array.VAO == ctx->Array.DefaultVAO) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "(no VAO bound)");
      return GL_FALSE;
   }

   /* From OpenGL ES 3.1 spec. section 10.5:
    *     "An INVALID_OPERATION error is generated if zero is bound to
    *     VERTEX_ARRAY_BINDING, DRAW_INDIRECT_BUFFER or to any enabled
    *     vertex array."
    *
    * Here we check that for each enabled vertex array we have a vertex
    * buffer bound.
    */
   if (_mesa_is_gles31(ctx) &&
       ctx->Array.VAO->_Enabled != ctx->Array.VAO->VertexAttribBufferMask) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(No VBO bound)", name);
      return GL_FALSE;
   }

   if (!_mesa_valid_prim_mode(ctx, mode, name))
      return GL_FALSE;

   /* OpenGL ES 3.1 specification, section 10.5:
    *
    *      "An INVALID_OPERATION error is generated if
    *      transform feedback is active and not paused."
    */
   if (_mesa_is_gles31(ctx) && !ctx->Extensions.OES_geometry_shader &&
       _mesa_is_xfb_active_and_unpaused(ctx)) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "%s(TransformFeedback is active and not paused)", name);
   }

   /* From OpenGL version 4.4. section 10.5
    * and OpenGL ES 3.1, section 10.6:
    *
    *      "An INVALID_VALUE error is generated if indirect is not a
    *       multiple of the size, in basic machine units, of uint."
    */
   if ((GLsizeiptr)indirect & (sizeof(GLuint) - 1)) {
      _mesa_error(ctx, GL_INVALID_VALUE,
                  "%s(indirect is not aligned)", name);
      return GL_FALSE;
   }

   if (!_mesa_is_bufferobj(ctx->DrawIndirectBuffer)) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "%s: no buffer bound to DRAW_INDIRECT_BUFFER", name);
      return GL_FALSE;
   }

   if (_mesa_check_disallowed_mapping(ctx->DrawIndirectBuffer)) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "%s(DRAW_INDIRECT_BUFFER is mapped)", name);
      return GL_FALSE;
   }

   /* From the ARB_draw_indirect specification:
    * "An INVALID_OPERATION error is generated if the commands source data
    *  beyond the end of the buffer object [...]"
    */
   if (ctx->DrawIndirectBuffer->Size < end) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "%s(DRAW_INDIRECT_BUFFER too small)", name);
      return GL_FALSE;
   }

   if (!check_valid_to_render(ctx, name))
      return GL_FALSE;

   return GL_TRUE;
}
Exemplo n.º 18
0
/**
 * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(),
 * etc?  Also, do additional checking related to transformation feedback.
 * Note: this function cannot be called during glNewList(GL_COMPILE) because
 * this code depends on current transform feedback state.
 * Also, do additional checking related to tessellation shaders.
 */
GLboolean
_mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name)
{
   bool valid_enum = _mesa_is_valid_prim_mode(ctx, mode);

   if (!valid_enum) {
      _mesa_error(ctx, GL_INVALID_ENUM, "%s(mode=%x)", name, mode);
      return GL_FALSE;
   }

   /* From the OpenGL 4.5 specification, section 11.3.1:
    *
    * The error INVALID_OPERATION is generated if Begin, or any command that
    * implicitly calls Begin, is called when a geometry shader is active and:
    *
    * * the input primitive type of the current geometry shader is
    *   POINTS and <mode> is not POINTS,
    *
    * * the input primitive type of the current geometry shader is
    *   LINES and <mode> is not LINES, LINE_STRIP, or LINE_LOOP,
    *
    * * the input primitive type of the current geometry shader is
    *   TRIANGLES and <mode> is not TRIANGLES, TRIANGLE_STRIP or
    *   TRIANGLE_FAN,
    *
    * * the input primitive type of the current geometry shader is
    *   LINES_ADJACENCY_ARB and <mode> is not LINES_ADJACENCY_ARB or
    *   LINE_STRIP_ADJACENCY_ARB, or
    *
    * * the input primitive type of the current geometry shader is
    *   TRIANGLES_ADJACENCY_ARB and <mode> is not
    *   TRIANGLES_ADJACENCY_ARB or TRIANGLE_STRIP_ADJACENCY_ARB.
    *
    * The GL spec doesn't mention any interaction with tessellation, which
    * is clearly a spec bug. The same rule should apply, but instead of
    * the draw primitive mode, the tessellation evaluation shader primitive
    * mode should be used for the checking.
   */
   if (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) {
      const GLenum geom_mode =
         ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->
            _LinkedShaders[MESA_SHADER_GEOMETRY]->Geom.InputType;
      struct gl_shader_program *tes =
         ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL];
      GLenum mode_before_gs = mode;

      if (tes) {
         struct gl_shader *tes_sh = tes->_LinkedShaders[MESA_SHADER_TESS_EVAL];
         if (tes_sh->TessEval.PointMode)
            mode_before_gs = GL_POINTS;
         else if (tes_sh->TessEval.PrimitiveMode == GL_ISOLINES)
            mode_before_gs = GL_LINES;
         else
            /* the GL_QUADS mode generates triangles too */
            mode_before_gs = GL_TRIANGLES;
      }

      switch (mode_before_gs) {
      case GL_POINTS:
         valid_enum = (geom_mode == GL_POINTS);
         break;
      case GL_LINES:
      case GL_LINE_LOOP:
      case GL_LINE_STRIP:
         valid_enum = (geom_mode == GL_LINES);
         break;
      case GL_TRIANGLES:
      case GL_TRIANGLE_STRIP:
      case GL_TRIANGLE_FAN:
         valid_enum = (geom_mode == GL_TRIANGLES);
         break;
      case GL_QUADS:
      case GL_QUAD_STRIP:
      case GL_POLYGON:
         valid_enum = false;
         break;
      case GL_LINES_ADJACENCY:
      case GL_LINE_STRIP_ADJACENCY:
         valid_enum = (geom_mode == GL_LINES_ADJACENCY);
         break;
      case GL_TRIANGLES_ADJACENCY:
      case GL_TRIANGLE_STRIP_ADJACENCY:
         valid_enum = (geom_mode == GL_TRIANGLES_ADJACENCY);
         break;
      default:
         valid_enum = false;
         break;
      }
      if (!valid_enum) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "%s(mode=%s vs geometry shader input %s)",
                     name,
                     _mesa_lookup_prim_by_nr(mode_before_gs),
                     _mesa_lookup_prim_by_nr(geom_mode));
         return GL_FALSE;
      }
   }

   /* From the OpenGL 4.0 (Core Profile) spec (section 2.12):
    *
    *     "Tessellation operates only on patch primitives. If tessellation is
    *      active, any command that transfers vertices to the GL will
    *      generate an INVALID_OPERATION error if the primitive mode is not
    *      PATCHES.
    *      Patch primitives are not supported by pipeline stages below the
    *      tessellation evaluation shader. If there is no active program
    *      object or the active program object does not contain a tessellation
    *      evaluation shader, the error INVALID_OPERATION is generated by any
    *      command that transfers vertices to the GL if the primitive mode is
    *      PATCHES."
    *
    */
   if (ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL] ||
       ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_CTRL]) {
      if (mode != GL_PATCHES) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "only GL_PATCHES valid with tessellation");
         return GL_FALSE;
      }
   }
   else {
      if (mode == GL_PATCHES) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "GL_PATCHES only valid with tessellation");
         return GL_FALSE;
      }
   }

   /* From the GL_EXT_transform_feedback spec:
    *
    *     "The error INVALID_OPERATION is generated if Begin, or any command
    *      that performs an explicit Begin, is called when:
    *
    *      * a geometry shader is not active and <mode> does not match the
    *        allowed begin modes for the current transform feedback state as
    *        given by table X.1.
    *
    *      * a geometry shader is active and the output primitive type of the
    *        geometry shader does not match the allowed begin modes for the
    *        current transform feedback state as given by table X.1.
    *
    */
   if (_mesa_is_xfb_active_and_unpaused(ctx)) {
      GLboolean pass = GL_TRUE;

      if(ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) {
         switch (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->
                    _LinkedShaders[MESA_SHADER_GEOMETRY]->Geom.OutputType) {
         case GL_POINTS:
            pass = ctx->TransformFeedback.Mode == GL_POINTS;
            break;
         case GL_LINE_STRIP:
            pass = ctx->TransformFeedback.Mode == GL_LINES;
            break;
         case GL_TRIANGLE_STRIP:
            pass = ctx->TransformFeedback.Mode == GL_TRIANGLES;
            break;
         default:
            pass = GL_FALSE;
         }
      }
      else if (ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL]) {
         struct gl_shader_program *tes =
            ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL];
         struct gl_shader *tes_sh = tes->_LinkedShaders[MESA_SHADER_TESS_EVAL];
         if (tes_sh->TessEval.PointMode)
            pass = ctx->TransformFeedback.Mode == GL_POINTS;
         else if (tes_sh->TessEval.PrimitiveMode == GL_ISOLINES)
            pass = ctx->TransformFeedback.Mode == GL_LINES;
         else
            pass = ctx->TransformFeedback.Mode == GL_TRIANGLES;
      }
      else {
         switch (mode) {
         case GL_POINTS:
            pass = ctx->TransformFeedback.Mode == GL_POINTS;
            break;
         case GL_LINES:
         case GL_LINE_STRIP:
         case GL_LINE_LOOP:
            pass = ctx->TransformFeedback.Mode == GL_LINES;
            break;
         default:
            pass = ctx->TransformFeedback.Mode == GL_TRIANGLES;
            break;
         }
      }
      if (!pass) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                         "%s(mode=%s vs transform feedback %s)",
                         name,
                         _mesa_lookup_prim_by_nr(mode),
                         _mesa_lookup_prim_by_nr(ctx->TransformFeedback.Mode));
         return GL_FALSE;
      }
   }

   return GL_TRUE;
}
Exemplo n.º 19
0
static bool
validate_draw_arrays(struct gl_context *ctx, const char *func,
                     GLenum mode, GLsizei count, GLsizei numInstances)
{
   struct gl_transform_feedback_object *xfb_obj
      = ctx->TransformFeedback.CurrentObject;
   FLUSH_CURRENT(ctx, 0);

   if (count < 0) {
      _mesa_error(ctx, GL_INVALID_VALUE, "%s(count)", func);
      return false;
   }

   if (!_mesa_valid_prim_mode(ctx, mode, func))
      return false;

   if (!check_valid_to_render(ctx, func))
      return false;

   /* From the GLES3 specification, section 2.14.2 (Transform Feedback
    * Primitive Capture):
    *
    *   The error INVALID_OPERATION is generated by DrawArrays and
    *   DrawArraysInstanced if recording the vertices of a primitive to the
    *   buffer objects being used for transform feedback purposes would result
    *   in either exceeding the limits of any buffer object’s size, or in
    *   exceeding the end position offset + size − 1, as set by
    *   BindBufferRange.
    *
    * This is in contrast to the behaviour of desktop GL, where the extra
    * primitives are silently dropped from the transform feedback buffer.
    *
    * This text is removed in ES 3.2, presumably because it's not really
    * implementable with geometry and tessellation shaders.  In fact,
    * the OES_geometry_shader spec says:
    *
    *    "(13) Does this extension change how transform feedback operates
    *     compared to unextended OpenGL ES 3.0 or 3.1?
    *
    *     RESOLVED: Yes. Because dynamic geometry amplification in a geometry
    *     shader can make it difficult if not impossible to predict the amount
    *     of geometry that may be generated in advance of executing the shader,
    *     the draw-time error for transform feedback buffer overflow conditions
    *     is removed and replaced with the GL behavior (primitives are not
    *     written and the corresponding counter is not updated)..."
    */
   if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx) &&
       !_mesa_has_OES_geometry_shader(ctx) &&
       !_mesa_has_OES_tessellation_shader(ctx)) {
      size_t prim_count = vbo_count_tessellated_primitives(mode, count, 1);
      if (xfb_obj->GlesRemainingPrims < prim_count) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "%s(exceeds transform feedback size)", func);
         return false;
      }
      xfb_obj->GlesRemainingPrims -= prim_count;
   }

   if (count == 0)
      return false;

   return true;
}
Exemplo n.º 20
0
static bool
validate_DrawElements_common(struct gl_context *ctx,
                             GLenum mode, GLsizei count, GLenum type,
                             const GLvoid *indices,
                             const char *caller)
{
   /* Section 2.14.2 (Transform Feedback Primitive Capture) of the OpenGL ES
    * 3.1 spec says:
    *
    *   The error INVALID_OPERATION is also generated by DrawElements,
    *   DrawElementsInstanced, and DrawRangeElements while transform feedback
    *   is active and not paused, regardless of mode.
    *
    * The OES_geometry_shader_spec says:
    *
    *    Issues:
    *
    *    ...
    *
    *    (13) Does this extension change how transform feedback operates
    *    compared to unextended OpenGL ES 3.0 or 3.1?
    *
    *    RESOLVED: Yes... Since we no longer require being able to predict how
    *    much geometry will be generated, we also lift the restriction that
    *    only DrawArray* commands are supported and also support the
    *    DrawElements* commands for transform feedback.
    *
    * This should also be reflected in the body of the spec, but that appears
    * to have been overlooked.  The body of the spec only explicitly allows
    * the indirect versions.
    */
   if (_mesa_is_gles3(ctx) && !ctx->Extensions.OES_geometry_shader &&
       _mesa_is_xfb_active_and_unpaused(ctx)) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "%s(transform feedback active)", caller);
      return false;
   }

   if (count < 0) {
      _mesa_error(ctx, GL_INVALID_VALUE, "%s(count)", caller);
      return false;
   }

   if (!_mesa_valid_prim_mode(ctx, mode, caller)) {
      return false;
   }

   if (!valid_elements_type(ctx, type, caller))
      return false;

   if (!check_valid_to_render(ctx, caller))
      return false;

   /* Not using a VBO for indices, so avoid NULL pointer derefs later.
    */
   if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj) && indices == NULL)
      return false;

   if (count == 0)
      return false;

   return true;
}
Exemplo n.º 21
0
static void populate_key(struct brw_context *brw,
                         struct brw_ff_gs_prog_key *key)
{
   static const unsigned swizzle_for_offset[4] = {
      BRW_SWIZZLE4(0, 1, 2, 3),
      BRW_SWIZZLE4(1, 2, 3, 3),
      BRW_SWIZZLE4(2, 3, 3, 3),
      BRW_SWIZZLE4(3, 3, 3, 3)
   };

   struct gl_context *ctx = &brw->ctx;

   memset(key, 0, sizeof(*key));

   /* CACHE_NEW_VS_PROG (part of VUE map) */
   key->attrs = brw->vs.prog_data->base.vue_map.slots_valid;

   /* BRW_NEW_PRIMITIVE */
   key->primitive = brw->primitive;

   /* _NEW_LIGHT */
   key->pv_first = (ctx->Light.ProvokingVertex == GL_FIRST_VERTEX_CONVENTION);
   if (key->primitive == _3DPRIM_QUADLIST && ctx->Light.ShadeModel != GL_FLAT) {
      /* Provide consistent primitive order with brw_set_prim's
       * optimization of single quads to trifans.
       */
      key->pv_first = true;
   }

   if (brw->gen >= 7) {
      /* On Gen7 and later, we don't use GS (yet). */
      key->need_gs_prog = false;
   } else if (brw->gen == 6) {
      /* On Gen6, GS is used for transform feedback. */
      /* BRW_NEW_TRANSFORM_FEEDBACK */
      if (_mesa_is_xfb_active_and_unpaused(ctx)) {
         const struct gl_shader_program *shaderprog =
            ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX];
         const struct gl_transform_feedback_info *linked_xfb_info =
            &shaderprog->LinkedTransformFeedback;
         int i;

         /* Make sure that the VUE slots won't overflow the unsigned chars in
          * key->transform_feedback_bindings[].
          */
         STATIC_ASSERT(BRW_VARYING_SLOT_COUNT <= 256);

         /* Make sure that we don't need more binding table entries than we've
          * set aside for use in transform feedback.  (We shouldn't, since we
          * set aside enough binding table entries to have one per component).
          */
         assert(linked_xfb_info->NumOutputs <= BRW_MAX_SOL_BINDINGS);

         key->need_gs_prog = true;
         key->num_transform_feedback_bindings = linked_xfb_info->NumOutputs;
         for (i = 0; i < key->num_transform_feedback_bindings; ++i) {
            key->transform_feedback_bindings[i] =
               linked_xfb_info->Outputs[i].OutputRegister;
            key->transform_feedback_swizzles[i] =
               swizzle_for_offset[linked_xfb_info->Outputs[i].ComponentOffset];
         }
      }
   } else {
      /* Pre-gen6, GS is used to transform QUADLIST, QUADSTRIP, and LINELOOP
       * into simpler primitives.
       */
      key->need_gs_prog = (brw->primitive == _3DPRIM_QUADLIST ||
                           brw->primitive == _3DPRIM_QUADSTRIP ||
                           brw->primitive == _3DPRIM_LINELOOP);
   }
}
Exemplo n.º 22
0
/**
 * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(),
 * etc?  Also, do additional checking related to transformation feedback.
 * Note: this function cannot be called during glNewList(GL_COMPILE) because
 * this code depends on current transform feedback state.
 */
GLboolean
_mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name)
{
   bool valid_enum = _mesa_is_valid_prim_mode(ctx, mode);

   if (!valid_enum) {
      _mesa_error(ctx, GL_INVALID_ENUM, "%s(mode=%x)", name, mode);
      return GL_FALSE;
   }

   /* From the ARB_geometry_shader4 spec:
    *
    * The error INVALID_OPERATION is generated if Begin, or any command that
    * implicitly calls Begin, is called when a geometry shader is active and:
    *
    * * the input primitive type of the current geometry shader is
    *   POINTS and <mode> is not POINTS,
    *
    * * the input primitive type of the current geometry shader is
    *   LINES and <mode> is not LINES, LINE_STRIP, or LINE_LOOP,
    *
    * * the input primitive type of the current geometry shader is
    *   TRIANGLES and <mode> is not TRIANGLES, TRIANGLE_STRIP or
    *   TRIANGLE_FAN,
    *
    * * the input primitive type of the current geometry shader is
    *   LINES_ADJACENCY_ARB and <mode> is not LINES_ADJACENCY_ARB or
    *   LINE_STRIP_ADJACENCY_ARB, or
    *
    * * the input primitive type of the current geometry shader is
    *   TRIANGLES_ADJACENCY_ARB and <mode> is not
    *   TRIANGLES_ADJACENCY_ARB or TRIANGLE_STRIP_ADJACENCY_ARB.
    *
   */
   if (ctx->Shader.CurrentGeometryProgram) {
      const GLenum geom_mode =
         ctx->Shader.CurrentGeometryProgram->Geom.InputType;
      switch (mode) {
      case GL_POINTS:
         valid_enum = (geom_mode == GL_POINTS);
         break;
      case GL_LINES:
      case GL_LINE_LOOP:
      case GL_LINE_STRIP:
         valid_enum = (geom_mode == GL_LINES);
         break;
      case GL_TRIANGLES:
      case GL_TRIANGLE_STRIP:
      case GL_TRIANGLE_FAN:
         valid_enum = (geom_mode == GL_TRIANGLES);
         break;
      case GL_QUADS:
      case GL_QUAD_STRIP:
      case GL_POLYGON:
         valid_enum = false;
         break;
      case GL_LINES_ADJACENCY:
      case GL_LINE_STRIP_ADJACENCY:
         valid_enum = (geom_mode == GL_LINES_ADJACENCY);
         break;
      case GL_TRIANGLES_ADJACENCY:
      case GL_TRIANGLE_STRIP_ADJACENCY:
         valid_enum = (geom_mode == GL_TRIANGLES_ADJACENCY);
         break;
      default:
         valid_enum = false;
         break;
      }
      if (!valid_enum) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "%s(mode=%s vs geometry shader input %s)",
                     name,
                     _mesa_lookup_prim_by_nr(mode),
                     _mesa_lookup_prim_by_nr(geom_mode));
         return GL_FALSE;
      }
   }

   /* From the GL_EXT_transform_feedback spec:
    *
    *     "The error INVALID_OPERATION is generated if Begin, or any command
    *      that performs an explicit Begin, is called when:
    *
    *      * a geometry shader is not active and <mode> does not match the
    *        allowed begin modes for the current transform feedback state as
    *        given by table X.1.
    *
    *      * a geometry shader is active and the output primitive type of the
    *        geometry shader does not match the allowed begin modes for the
    *        current transform feedback state as given by table X.1.
    *
    */
   if (_mesa_is_xfb_active_and_unpaused(ctx)) {
      GLboolean pass = GL_TRUE;

      switch (mode) {
      case GL_POINTS:
         pass = ctx->TransformFeedback.Mode == GL_POINTS;
	 break;
      case GL_LINES:
      case GL_LINE_STRIP:
      case GL_LINE_LOOP:
         pass = ctx->TransformFeedback.Mode == GL_LINES;
	 break;
      default:
         pass = ctx->TransformFeedback.Mode == GL_TRIANGLES;
	 break;
      }
      if (!pass) {
	 _mesa_error(ctx, GL_INVALID_OPERATION,
		     "%s(mode=%s vs transform feedback %s)",
		     name,
		     _mesa_lookup_prim_by_nr(mode),
		     _mesa_lookup_prim_by_nr(ctx->TransformFeedback.Mode));
	 return GL_FALSE;
      }
   }

   return GL_TRUE;
}