Ejemplo n.º 1
0
/**
 * Basically, translate Mesa's index buffer information into
 * a pipe_index_buffer object.
 * \return TRUE or FALSE for success/failure
 */
static boolean
setup_index_buffer(struct st_context *st,
                   const struct _mesa_index_buffer *ib,
                   struct pipe_index_buffer *ibuffer)
{
   struct gl_buffer_object *bufobj = ib->obj;

   ibuffer->index_size = vbo_sizeof_ib_type(ib->type);

   /* get/create the index buffer object */
   if (_mesa_is_bufferobj(bufobj)) {
      /* indices are in a real VBO */
      ibuffer->buffer = st_buffer_object(bufobj)->buffer;
      ibuffer->offset = pointer_to_offset(ib->ptr);
   }
   else if (st->indexbuf_uploader) {
      /* upload indexes from user memory into a real buffer */
      if (u_upload_data(st->indexbuf_uploader, 0,
                        ib->count * ibuffer->index_size, ib->ptr,
                        &ibuffer->offset, &ibuffer->buffer) != PIPE_OK) {
         /* out of memory */
         return FALSE;
      }
      u_upload_unmap(st->indexbuf_uploader);
   }
   else {
      /* indices are in user space memory */
      ibuffer->user_buffer = ib->ptr;
   }

   cso_set_index_buffer(st->cso_context, ibuffer);
   return TRUE;
}
Ejemplo n.º 2
0
static void
setup_index_buffer(struct st_context *st,
                   const struct _mesa_index_buffer *ib,
                   struct pipe_index_buffer *ibuffer)
{
   struct gl_buffer_object *bufobj = ib->obj;

   ibuffer->index_size = vbo_sizeof_ib_type(ib->type);

   /* get/create the index buffer object */
   if (_mesa_is_bufferobj(bufobj)) {
      /* indices are in a real VBO */
      ibuffer->buffer = st_buffer_object(bufobj)->buffer;
      ibuffer->offset = pointer_to_offset(ib->ptr);
   }
   else if (st->indexbuf_uploader) {
      u_upload_data(st->indexbuf_uploader, 0, ib->count * ibuffer->index_size,
                    ib->ptr, &ibuffer->offset, &ibuffer->buffer);
      u_upload_unmap(st->indexbuf_uploader);
   }
   else {
      /* indices are in user space memory */
      ibuffer->user_buffer = ib->ptr;
   }

   cso_set_index_buffer(st->cso_context, ibuffer);
}
Ejemplo n.º 3
0
/* Translate indices to GLuints and store in VB->Elts.
 */
static void bind_indices( struct gl_context *ctx,
			  const struct _mesa_index_buffer *ib,
			  struct gl_buffer_object **bo,
			  GLuint *nr_bo)
{
   TNLcontext *tnl = TNL_CONTEXT(ctx);
   struct vertex_buffer *VB = &tnl->vb;
   GLuint i;
   const void *ptr;

   if (!ib) {
      VB->Elts = NULL;
      return;
   }

   if (_mesa_is_bufferobj(ib->obj) &&
       !_mesa_bufferobj_mapped(ib->obj, MAP_INTERNAL)) {
      /* if the buffer object isn't mapped yet, map it now */
      bo[*nr_bo] = ib->obj;
      (*nr_bo)++;
      ptr = ctx->Driver.MapBufferRange(ctx, (GLsizeiptr) ib->ptr,
                                       ib->count * vbo_sizeof_ib_type(ib->type),
				       GL_MAP_READ_BIT, ib->obj,
                                       MAP_INTERNAL);
      assert(ib->obj->Mappings[MAP_INTERNAL].Pointer);
   } else {
      /* user-space elements, or buffer already mapped */
      ptr = ADD_POINTERS(ib->obj->Mappings[MAP_INTERNAL].Pointer, ib->ptr);
   }

   if (ib->type == GL_UNSIGNED_INT && VB->Primitive[0].basevertex == 0) {
      VB->Elts = (GLuint *) ptr;
   }
   else {
      GLuint *elts = (GLuint *)get_space(ctx, ib->count * sizeof(GLuint));
      VB->Elts = elts;

      if (ib->type == GL_UNSIGNED_INT) {
	 const GLuint *in = (GLuint *)ptr;
	 for (i = 0; i < ib->count; i++)
	    *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex;
      }
      else if (ib->type == GL_UNSIGNED_SHORT) {
	 const GLushort *in = (GLushort *)ptr;
	 for (i = 0; i < ib->count; i++) 
	    *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex;
      }
      else {
	 const GLubyte *in = (GLubyte *)ptr;
	 for (i = 0; i < ib->count; i++) 
	    *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex;
      }
   }
}
Ejemplo n.º 4
0
/**
 * Compute min and max elements by scanning the index buffer for
 * glDraw[Range]Elements() calls.
 * If primitive restart is enabled, we need to ignore restart
 * indexes when computing min/max.
 */
static void
vbo_get_minmax_index(struct gl_context *ctx,
		     const struct _mesa_prim *prim,
		     const struct _mesa_index_buffer *ib,
		     GLuint *min_index, GLuint *max_index,
		     const GLuint count)
{
   const GLboolean restart = ctx->Array._PrimitiveRestart;
   const GLuint restartIndex = _mesa_primitive_restart_index(ctx, ib->type);
   const int index_size = vbo_sizeof_ib_type(ib->type);
   const char *indices;
   GLuint i;

   indices = (char *) ib->ptr + prim->start * index_size;
   if (_mesa_is_bufferobj(ib->obj)) {
      GLsizeiptr size = MIN2(count * index_size, ib->obj->Size);
      indices = ctx->Driver.MapBufferRange(ctx, (GLintptr) indices, size,
                                           GL_MAP_READ_BIT, ib->obj);
   }

   switch (ib->type) {
   case GL_UNSIGNED_INT: {
      const GLuint *ui_indices = (const GLuint *)indices;
      GLuint max_ui = 0;
      GLuint min_ui = ~0U;
      if (restart) {
         for (i = 0; i < count; i++) {
            if (ui_indices[i] != restartIndex) {
               if (ui_indices[i] > max_ui) max_ui = ui_indices[i];
               if (ui_indices[i] < min_ui) min_ui = ui_indices[i];
            }
         }
      }
      else {
         for (i = 0; i < count; i++) {
            if (ui_indices[i] > max_ui) max_ui = ui_indices[i];
            if (ui_indices[i] < min_ui) min_ui = ui_indices[i];
         }
      }
      *min_index = min_ui;
      *max_index = max_ui;
      break;
   }
   case GL_UNSIGNED_SHORT: {
      const GLushort *us_indices = (const GLushort *)indices;
      GLuint max_us = 0;
      GLuint min_us = ~0U;
      if (restart) {
         for (i = 0; i < count; i++) {
            if (us_indices[i] != restartIndex) {
               if (us_indices[i] > max_us) max_us = us_indices[i];
               if (us_indices[i] < min_us) min_us = us_indices[i];
            }
         }
      }
      else {
         for (i = 0; i < count; i++) {
            if (us_indices[i] > max_us) max_us = us_indices[i];
            if (us_indices[i] < min_us) min_us = us_indices[i];
         }
      }
      *min_index = min_us;
      *max_index = max_us;
      break;
   }
   case GL_UNSIGNED_BYTE: {
      const GLubyte *ub_indices = (const GLubyte *)indices;
      GLuint max_ub = 0;
      GLuint min_ub = ~0U;
      if (restart) {
         for (i = 0; i < count; i++) {
            if (ub_indices[i] != restartIndex) {
               if (ub_indices[i] > max_ub) max_ub = ub_indices[i];
               if (ub_indices[i] < min_ub) min_ub = ub_indices[i];
            }
         }
      }
      else {
         for (i = 0; i < count; i++) {
            if (ub_indices[i] > max_ub) max_ub = ub_indices[i];
            if (ub_indices[i] < min_ub) min_ub = ub_indices[i];
         }
      }
      *min_index = min_ub;
      *max_index = max_ub;
      break;
   }
   default:
      assert(0);
      break;
   }

   if (_mesa_is_bufferobj(ib->obj)) {
      ctx->Driver.UnmapBuffer(ctx, ib->obj);
   }
}
Ejemplo n.º 5
0
/**
 * Inner support for both _mesa_MultiDrawElements() and
 * _mesa_MultiDrawRangeElements().
 * This does the actual rendering after we've checked array indexes, etc.
 */
static void
vbo_validated_multidrawelements(struct gl_context *ctx, GLenum mode,
				const GLsizei *count, GLenum type,
				const GLvoid * const *indices,
				GLsizei primcount,
				const GLint *basevertex)
{
   struct vbo_context *vbo = vbo_context(ctx);
   struct vbo_exec_context *exec = &vbo->exec;
   struct _mesa_index_buffer ib;
   struct _mesa_prim *prim;
   unsigned int index_type_size = vbo_sizeof_ib_type(type);
   uintptr_t min_index_ptr, max_index_ptr;
   GLboolean fallback = GL_FALSE;
   int i;

   if (primcount == 0)
      return;

   prim = calloc(1, primcount * sizeof(*prim));
   if (prim == NULL) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawElements");
      return;
   }

   vbo_bind_arrays(ctx);

   min_index_ptr = (uintptr_t)indices[0];
   max_index_ptr = 0;
   for (i = 0; i < primcount; i++) {
      min_index_ptr = MIN2(min_index_ptr, (uintptr_t)indices[i]);
      max_index_ptr = MAX2(max_index_ptr, (uintptr_t)indices[i] +
			   index_type_size * count[i]);
   }

   /* Check if we can handle this thing as a bunch of index offsets from the
    * same index pointer.  If we can't, then we have to fall back to doing
    * a draw_prims per primitive.
    * Check that the difference between each prim's indexes is a multiple of
    * the index/element size.
    */
   if (index_type_size != 1) {
      for (i = 0; i < primcount; i++) {
	 if ((((uintptr_t)indices[i] - min_index_ptr) % index_type_size) != 0) {
	    fallback = GL_TRUE;
	    break;
	 }
      }
   }

   /* If the index buffer isn't in a VBO, then treating the application's
    * subranges of the index buffer as one large index buffer may lead to
    * us reading unmapped memory.
    */
   if (!_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj))
      fallback = GL_TRUE;

   if (!fallback) {
      ib.count = (max_index_ptr - min_index_ptr) / index_type_size;
      ib.type = type;
      ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj;
      ib.ptr = (void *)min_index_ptr;

      for (i = 0; i < primcount; i++) {
	 prim[i].begin = (i == 0);
	 prim[i].end = (i == primcount - 1);
	 prim[i].weak = 0;
	 prim[i].pad = 0;
	 prim[i].mode = mode;
	 prim[i].start = ((uintptr_t)indices[i] - min_index_ptr) / index_type_size;
	 prim[i].count = count[i];
	 prim[i].indexed = 1;
         prim[i].num_instances = 1;
         prim[i].base_instance = 0;
	 if (basevertex != NULL)
	    prim[i].basevertex = basevertex[i];
	 else
	    prim[i].basevertex = 0;
      }

      check_buffers_are_unmapped(exec->array.inputs);
      vbo_handle_primitive_restart(ctx, prim, primcount, &ib,
                                   GL_FALSE, ~0, ~0);
   } else {
      /* render one prim at a time */
      for (i = 0; i < primcount; i++) {
	 ib.count = count[i];
	 ib.type = type;
	 ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj;
	 ib.ptr = indices[i];

	 prim[0].begin = 1;
	 prim[0].end = 1;
	 prim[0].weak = 0;
	 prim[0].pad = 0;
	 prim[0].mode = mode;
	 prim[0].start = 0;
	 prim[0].count = count[i];
	 prim[0].indexed = 1;
         prim[0].num_instances = 1;
         prim[0].base_instance = 0;
	 if (basevertex != NULL)
	    prim[0].basevertex = basevertex[i];
	 else
	    prim[0].basevertex = 0;

         check_buffers_are_unmapped(exec->array.inputs);
         vbo_handle_primitive_restart(ctx, prim, 1, &ib,
                                      GL_FALSE, ~0, ~0);
      }
   }

   free(prim);

   if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
      _mesa_flush(ctx);
   }
}
Ejemplo n.º 6
0
/**
 * Called by VBO to draw arrays when in selection or feedback mode and
 * to implement glRasterPos.
 * This is very much like the normal draw_vbo() function above.
 * Look at code refactoring some day.
 */
void
st_feedback_draw_vbo(struct gl_context *ctx,
                     const struct gl_client_array **arrays,
                     const struct _mesa_prim *prims,
                     GLuint nr_prims,
                     const struct _mesa_index_buffer *ib,
		     GLboolean index_bounds_valid,
                     GLuint min_index,
                     GLuint max_index,
                     struct gl_transform_feedback_object *tfb_vertcount)
{
   struct st_context *st = st_context(ctx);
   struct pipe_context *pipe = st->pipe;
   struct draw_context *draw = st->draw;
   const struct st_vertex_program *vp;
   const struct pipe_shader_state *vs;
   struct pipe_vertex_buffer vbuffers[PIPE_MAX_SHADER_INPUTS];
   struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS];
   struct pipe_index_buffer ibuffer;
   struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS];
   struct pipe_transfer *ib_transfer = NULL;
   GLuint attr, i;
   const GLubyte *low_addr = NULL;
   const void *mapped_indices = NULL;

   assert(draw);

   st_validate_state(st);

   if (!index_bounds_valid)
      vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index, nr_prims);

   /* must get these after state validation! */
   vp = st->vp;
   vs = &st->vp_variant->tgsi;

   if (!st->vp_variant->draw_shader) {
      st->vp_variant->draw_shader = draw_create_vertex_shader(draw, vs);
   }

   /*
    * Set up the draw module's state.
    *
    * We'd like to do this less frequently, but the normal state-update
    * code sends state updates to the pipe, not to our private draw module.
    */
   assert(draw);
   draw_set_viewport_state(draw, &st->state.viewport);
   draw_set_clip_state(draw, &st->state.clip);
   draw_set_rasterizer_state(draw, &st->state.rasterizer, NULL);
   draw_bind_vertex_shader(draw, st->vp_variant->draw_shader);
   set_feedback_vertex_format(ctx);

   /* Find the lowest address of the arrays we're drawing */
   if (vp->num_inputs) {
      low_addr = arrays[vp->index_to_input[0]]->Ptr;

      for (attr = 1; attr < vp->num_inputs; attr++) {
         const GLubyte *start = arrays[vp->index_to_input[attr]]->Ptr;
         low_addr = MIN2(low_addr, start);
      }
   }

   /* loop over TGSI shader inputs to determine vertex buffer
    * and attribute info
    */
   for (attr = 0; attr < vp->num_inputs; attr++) {
      const GLuint mesaAttr = vp->index_to_input[attr];
      struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj;
      void *map;

      if (bufobj && bufobj->Name) {
         /* Attribute data is in a VBO.
          * Recall that for VBOs, the gl_client_array->Ptr field is
          * really an offset from the start of the VBO, not a pointer.
          */
         struct st_buffer_object *stobj = st_buffer_object(bufobj);
         assert(stobj->buffer);

         vbuffers[attr].buffer = NULL;
         pipe_resource_reference(&vbuffers[attr].buffer, stobj->buffer);
         vbuffers[attr].buffer_offset = pointer_to_offset(low_addr);
         velements[attr].src_offset = arrays[mesaAttr]->Ptr - low_addr;
      }
      else {
         /* attribute data is in user-space memory, not a VBO */
         uint bytes = (arrays[mesaAttr]->Size
                       * _mesa_sizeof_type(arrays[mesaAttr]->Type)
                       * (max_index + 1));

         /* wrap user data */
         vbuffers[attr].buffer
            = pipe_user_buffer_create(pipe->screen, (void *) arrays[mesaAttr]->Ptr,
                                      bytes,
				      PIPE_BIND_VERTEX_BUFFER);
         vbuffers[attr].buffer_offset = 0;
         velements[attr].src_offset = 0;
      }

      /* common-case setup */
      vbuffers[attr].stride = arrays[mesaAttr]->StrideB; /* in bytes */
      velements[attr].instance_divisor = 0;
      velements[attr].vertex_buffer_index = attr;
      velements[attr].src_format = 
         st_pipe_vertex_format(arrays[mesaAttr]->Type,
                               arrays[mesaAttr]->Size,
                               arrays[mesaAttr]->Format,
                               arrays[mesaAttr]->Normalized,
                               arrays[mesaAttr]->Integer);
      assert(velements[attr].src_format);

      /* tell draw about this attribute */
#if 0
      draw_set_vertex_buffer(draw, attr, &vbuffer[attr]);
#endif

      /* map the attrib buffer */
      map = pipe_buffer_map(pipe, vbuffers[attr].buffer,
                            PIPE_TRANSFER_READ,
			    &vb_transfer[attr]);
      draw_set_mapped_vertex_buffer(draw, attr, map);
   }

   draw_set_vertex_buffers(draw, vp->num_inputs, vbuffers);
   draw_set_vertex_elements(draw, vp->num_inputs, velements);

   memset(&ibuffer, 0, sizeof(ibuffer));
   if (ib) {
      struct gl_buffer_object *bufobj = ib->obj;

      ibuffer.index_size = vbo_sizeof_ib_type(ib->type);
      if (ibuffer.index_size == 0)
         goto out_unref_vertex;

      if (bufobj && bufobj->Name) {
         struct st_buffer_object *stobj = st_buffer_object(bufobj);

         pipe_resource_reference(&ibuffer.buffer, stobj->buffer);
         ibuffer.offset = pointer_to_offset(ib->ptr);

         mapped_indices = pipe_buffer_map(pipe, stobj->buffer,
                                          PIPE_TRANSFER_READ, &ib_transfer);
      }
      else {
         /* skip setting ibuffer.buffer as the draw module does not use it */
         mapped_indices = ib->ptr;
      }

      draw_set_index_buffer(draw, &ibuffer);
      draw_set_mapped_index_buffer(draw, mapped_indices);
   }

   /* set the constant buffer */
   draw_set_mapped_constant_buffer(st->draw, PIPE_SHADER_VERTEX, 0,
                                   st->state.constants[PIPE_SHADER_VERTEX].ptr,
                                   st->state.constants[PIPE_SHADER_VERTEX].size);


   /* draw here */
   for (i = 0; i < nr_prims; i++) {
      draw_arrays(draw, prims[i].mode, prims[i].start, prims[i].count);
   }


   /*
    * unmap vertex/index buffers
    */
   if (ib) {
      draw_set_mapped_index_buffer(draw, NULL);
      draw_set_index_buffer(draw, NULL);

      if (ib_transfer)
         pipe_buffer_unmap(pipe, ib_transfer);
      pipe_resource_reference(&ibuffer.buffer, NULL);
   }

 out_unref_vertex:
   for (attr = 0; attr < vp->num_inputs; attr++) {
      pipe_buffer_unmap(pipe, vb_transfer[attr]);
      draw_set_mapped_vertex_buffer(draw, attr, NULL);
      pipe_resource_reference(&vbuffers[attr].buffer, NULL);
   }
   draw_set_vertex_buffers(draw, 0, NULL);
}
/**
 * Handle primitive restart in software.
 *
 * This function breaks up calls into the driver so primitive restart
 * support is not required in the driver.
 */
void
vbo_sw_primitive_restart(struct gl_context *ctx,
                         const struct _mesa_prim *prims,
                         GLuint nr_prims,
                         const struct _mesa_index_buffer *ib,
                         struct gl_buffer_object *indirect)
{
   GLuint prim_num;
   struct sub_primitive *sub_prims;
   struct sub_primitive *sub_prim;
   GLuint num_sub_prims;
   GLuint sub_prim_num;
   GLuint end_index;
   GLuint sub_end_index;
   GLuint restart_index = _mesa_primitive_restart_index(ctx, ib->type);
   struct _mesa_prim temp_prim;
   struct vbo_context *vbo = vbo_context(ctx);
   vbo_draw_func draw_prims_func = vbo->draw_prims;
   GLboolean map_ib = ib->obj->Name && !ib->obj->Pointer;
   void *ptr;

   /* If there is an indirect buffer, map it and extract the draw params */
   if (indirect && prims[0].is_indirect) {
      struct _mesa_prim new_prim = *prims;
      struct _mesa_index_buffer new_ib = *ib;
      const uint32_t *indirect_params;
      if (!ctx->Driver.MapBufferRange(ctx, 0, indirect->Size, GL_MAP_READ_BIT,
            indirect)) {

         /* something went wrong with mapping, give up */
         _mesa_error(ctx, GL_OUT_OF_MEMORY,
                     "failed to map indirect buffer for sw primitive restart");
         return;
      }

      assert(nr_prims == 1);
      indirect_params = (const uint32_t *) ADD_POINTERS(indirect->Pointer,
            new_prim.indirect_offset);

      new_prim.is_indirect = 0;
      new_prim.count = indirect_params[0];
      new_prim.num_instances = indirect_params[1];
      new_prim.start = indirect_params[2];
      new_prim.basevertex = indirect_params[3];
      new_prim.base_instance = indirect_params[4];

      new_ib.count = new_prim.count;

      prims = &new_prim;
      ib = &new_ib;

      ctx->Driver.UnmapBuffer(ctx, indirect);
   }

   /* Find the sub-primitives. These are regions in the index buffer which
    * are split based on the primitive restart index value.
    */
   if (map_ib) {
      ctx->Driver.MapBufferRange(ctx, 0, ib->obj->Size, GL_MAP_READ_BIT,
                                 ib->obj);
   }

   ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr);

   sub_prims = find_sub_primitives(ptr, vbo_sizeof_ib_type(ib->type),
                                   0, ib->count, restart_index,
                                   &num_sub_prims);

   if (map_ib) {
      ctx->Driver.UnmapBuffer(ctx, ib->obj);
   }

   /* Loop over the primitives, and use the located sub-primitives to draw
    * each primitive with a break to implement each primitive restart.
    */
   for (prim_num = 0; prim_num < nr_prims; prim_num++) {
      end_index = prims[prim_num].start + prims[prim_num].count;
      memcpy(&temp_prim, &prims[prim_num], sizeof (temp_prim));
      /* Loop over the sub-primitives drawing sub-ranges of the primitive. */
      for (sub_prim_num = 0; sub_prim_num < num_sub_prims; sub_prim_num++) {
         sub_prim = &sub_prims[sub_prim_num];
         sub_end_index = sub_prim->start + sub_prim->count;
         if (prims[prim_num].start <= sub_prim->start) {
            temp_prim.start = MAX2(prims[prim_num].start, sub_prim->start);
            temp_prim.count = MIN2(sub_end_index, end_index) - temp_prim.start;
            if ((temp_prim.start == sub_prim->start) &&
                (temp_prim.count == sub_prim->count)) {
               draw_prims_func(ctx, &temp_prim, 1, ib,
                               GL_TRUE, sub_prim->min_index, sub_prim->max_index,
                               NULL, NULL);
            } else {
               draw_prims_func(ctx, &temp_prim, 1, ib,
                               GL_FALSE, -1, -1,
                               NULL, NULL);
            }
         }
         if (sub_end_index >= end_index) {
            break;
         }
      }
   }

   free(sub_prims);
}
Ejemplo n.º 8
0
/**
 * Compute min and max elements by scanning the index buffer for
 * glDraw[Range]Elements() calls.
 * If primitive restart is enabled, we need to ignore restart
 * indexes when computing min/max.
 */
static void
vbo_get_minmax_index(struct gl_context *ctx,
                     const struct _mesa_prim *prim,
                     const struct _mesa_index_buffer *ib,
                     GLuint *min_index, GLuint *max_index,
                     const GLuint count)
{
   const GLboolean restart = ctx->Array._PrimitiveRestart;
   const GLuint restartIndex = _mesa_primitive_restart_index(ctx, ib->type);
   const int index_size = vbo_sizeof_ib_type(ib->type);
   const char *indices;
   GLuint i;

   indices = (char *) ib->ptr + prim->start * index_size;
   if (_mesa_is_bufferobj(ib->obj)) {
      GLsizeiptr size = MIN2(count * index_size, ib->obj->Size);

      if (vbo_get_minmax_cached(ib->obj, ib->type, (GLintptr) indices, count,
                                min_index, max_index))
         return;

      indices = ctx->Driver.MapBufferRange(ctx, (GLintptr) indices, size,
                                           GL_MAP_READ_BIT, ib->obj,
                                           MAP_INTERNAL);
   }

   switch (ib->type) {
   case GL_UNSIGNED_INT: {
      const GLuint *ui_indices = (const GLuint *)indices;
      GLuint max_ui = 0;
      GLuint min_ui = ~0U;
      if (restart) {
         for (i = 0; i < count; i++) {
            if (ui_indices[i] != restartIndex) {
               if (ui_indices[i] > max_ui) max_ui = ui_indices[i];
               if (ui_indices[i] < min_ui) min_ui = ui_indices[i];
            }
         }
      }
      else {
#if defined(USE_SSE41)
         if (cpu_has_sse4_1) {
            _mesa_uint_array_min_max(ui_indices, &min_ui, &max_ui, count);
         }
         else
#endif
            for (i = 0; i < count; i++) {
               if (ui_indices[i] > max_ui) max_ui = ui_indices[i];
               if (ui_indices[i] < min_ui) min_ui = ui_indices[i];
            }
      }
      *min_index = min_ui;
      *max_index = max_ui;
      break;
   }
   case GL_UNSIGNED_SHORT: {
      const GLushort *us_indices = (const GLushort *)indices;
      GLuint max_us = 0;
      GLuint min_us = ~0U;
      if (restart) {
         for (i = 0; i < count; i++) {
            if (us_indices[i] != restartIndex) {
               if (us_indices[i] > max_us) max_us = us_indices[i];
               if (us_indices[i] < min_us) min_us = us_indices[i];
            }
         }
      }
      else {
         for (i = 0; i < count; i++) {
            if (us_indices[i] > max_us) max_us = us_indices[i];
            if (us_indices[i] < min_us) min_us = us_indices[i];
         }
      }
      *min_index = min_us;
      *max_index = max_us;
      break;
   }
   case GL_UNSIGNED_BYTE: {
      const GLubyte *ub_indices = (const GLubyte *)indices;
      GLuint max_ub = 0;
      GLuint min_ub = ~0U;
      if (restart) {
         for (i = 0; i < count; i++) {
            if (ub_indices[i] != restartIndex) {
               if (ub_indices[i] > max_ub) max_ub = ub_indices[i];
               if (ub_indices[i] < min_ub) min_ub = ub_indices[i];
            }
         }
      }
      else {
         for (i = 0; i < count; i++) {
            if (ub_indices[i] > max_ub) max_ub = ub_indices[i];
            if (ub_indices[i] < min_ub) min_ub = ub_indices[i];
         }
      }
      *min_index = min_ub;
      *max_index = max_ub;
      break;
   }
   default:
      unreachable("not reached");
   }

   if (_mesa_is_bufferobj(ib->obj)) {
      vbo_minmax_cache_store(ctx, ib->obj, ib->type, prim->start, count,
                             *min_index, *max_index);
      ctx->Driver.UnmapBuffer(ctx, ib->obj, MAP_INTERNAL);
   }
}
Ejemplo n.º 9
0
/**
 * Handle primitive restart in software.
 *
 * This function breaks up calls into the driver so primitive restart
 * support is not required in the driver.
 */
void
vbo_sw_primitive_restart(struct gl_context *ctx,
                         const struct _mesa_prim *prims,
                         GLuint nr_prims,
                         const struct _mesa_index_buffer *ib)
{
   GLuint prim_num;
   struct sub_primitive *sub_prims;
   struct sub_primitive *sub_prim;
   GLuint num_sub_prims;
   GLuint sub_prim_num;
   GLuint end_index;
   GLuint sub_end_index;
   GLuint restart_index = ctx->Array.RestartIndex;
   struct _mesa_prim temp_prim;
   struct vbo_context *vbo = vbo_context(ctx);
   vbo_draw_func draw_prims_func = vbo->draw_prims;
   GLboolean map_ib = ib->obj->Name && !ib->obj->Pointer;
   void *ptr;

   /* Find the sub-primitives. These are regions in the index buffer which
    * are split based on the primitive restart index value.
    */
   if (map_ib) {
      ctx->Driver.MapBufferRange(ctx, 0, ib->obj->Size, GL_MAP_READ_BIT,
                                 ib->obj);
   }

   ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr);

   sub_prims = find_sub_primitives(ptr, vbo_sizeof_ib_type(ib->type),
                                   0, ib->count, restart_index,
                                   &num_sub_prims);

   if (map_ib) {
      ctx->Driver.UnmapBuffer(ctx, ib->obj);
   }

   /* Loop over the primitives, and use the located sub-primitives to draw
    * each primitive with a break to implement each primitive restart.
    */
   for (prim_num = 0; prim_num < nr_prims; prim_num++) {
      end_index = prims[prim_num].start + prims[prim_num].count;
      memcpy(&temp_prim, &prims[prim_num], sizeof (temp_prim));
      /* Loop over the sub-primitives drawing sub-ranges of the primitive. */
      for (sub_prim_num = 0; sub_prim_num < num_sub_prims; sub_prim_num++) {
         sub_prim = &sub_prims[sub_prim_num];
         sub_end_index = sub_prim->start + sub_prim->count;
         if (prims[prim_num].start <= sub_prim->start) {
            temp_prim.start = MAX2(prims[prim_num].start, sub_prim->start);
            temp_prim.count = MIN2(sub_end_index, end_index) - temp_prim.start;
            if ((temp_prim.start == sub_prim->start) &&
                (temp_prim.count == sub_prim->count)) {
               draw_prims_func(ctx, &temp_prim, 1, ib,
                               GL_TRUE, sub_prim->min_index, sub_prim->max_index,
                               NULL);
            } else {
               draw_prims_func(ctx, &temp_prim, 1, ib,
                               GL_FALSE, -1, -1,
                               NULL);
            }
         }
         if (sub_end_index >= end_index) {
            break;
         }
      }
   }

   free(sub_prims);
}