static void init_array(struct gl_context *ctx, struct gl_vertex_array_object *obj, GLuint index, GLint size, GLint type) { struct gl_vertex_attrib_array *array = &obj->VertexAttrib[index]; struct gl_vertex_buffer_binding *binding = &obj->VertexBinding[index]; array->Size = size; array->Type = type; array->Format = GL_RGBA; /* only significant for GL_EXT_vertex_array_bgra */ array->Stride = 0; array->Ptr = NULL; array->RelativeOffset = 0; array->Enabled = GL_FALSE; array->Normalized = GL_FALSE; array->Integer = GL_FALSE; array->Doubles = GL_FALSE; array->_ElementSize = size * _mesa_sizeof_type(type); array->VertexBinding = index; binding->Offset = 0; binding->Stride = array->_ElementSize; binding->BufferObj = NULL; binding->_BoundArrays = BITFIELD64_BIT(index); /* Vertex array buffers */ _mesa_reference_buffer_object(ctx, &binding->BufferObj, ctx->Shared->NullBufferObj); }
/** * Do error checking and update state for glVertex/Color/TexCoord/...Pointer * functions. * * \param func name of calling function used for error reporting * \param attrib the attribute array index to update * \param legalTypes bitmask of *_BIT above indicating legal datatypes * \param sizeMin min allowable size value * \param sizeMax max allowable size value * \param size components per element (1, 2, 3 or 4) * \param type datatype of each component (GL_FLOAT, GL_INT, etc) * \param stride stride between elements, in elements * \param normalized are integer types converted to floats in [-1, 1]? * \param integer integer-valued values (will not be normalized to [-1,1]) * \param ptr the address (or offset inside VBO) of the array data */ static void update_array(struct gl_context *ctx, const char *func, GLuint attrib, GLbitfield legalTypesMask, GLint sizeMin, GLint sizeMax, GLint size, GLenum type, GLsizei stride, GLboolean normalized, GLboolean integer, const GLvoid *ptr) { struct gl_client_array *array; GLbitfield typeBit; GLsizei elementSize; typeBit = type_to_bit(ctx, type); if (typeBit == 0x0 || (typeBit & legalTypesMask) == 0x0) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(type = %s)", func, _mesa_lookup_enum_by_nr(type)); return; } /* Do size parameter checking. */ if (size < sizeMin || size > sizeMax || size > 4) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(size=%d)", func, size); return; } ASSERT(size <= 4); if (stride < 0) { _mesa_error( ctx, GL_INVALID_VALUE, "%s(stride=%d)", func, stride ); return; } if (ctx->Array.ArrayObj->ARBsemantics && !_mesa_is_bufferobj(ctx->Array.ArrayBufferObj)) { /* GL_ARB_vertex_array_object requires that all arrays reside in VBOs. * Generate GL_INVALID_OPERATION if that's not true. */ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-VBO array)", func); return; } elementSize = _mesa_sizeof_type(type) * size; array = &ctx->Array.ArrayObj->VertexAttrib[attrib]; array->Size = size; array->Type = type; array->Stride = stride; array->StrideB = stride ? stride : elementSize; array->Normalized = normalized; array->Integer = integer; array->Ptr = (const GLubyte *) ptr; array->_ElementSize = elementSize; _mesa_reference_buffer_object(ctx, &array->BufferObj, ctx->Array.ArrayBufferObj); ctx->NewState |= _NEW_ARRAY; ctx->Array.NewState |= VERT_BIT(attrib); }
static void flush_vertex( struct split_context *split ) { struct _mesa_index_buffer ib; GLuint i; if (!split->dstprim_nr) return; if (split->ib) { ib = *split->ib; ib.count = split->max_index - split->min_index + 1; ib.ptr = (const void *)((const char *)ib.ptr + split->min_index * _mesa_sizeof_type(ib.type)); /* Rebase the primitives to save index buffer entries. */ for (i = 0; i < split->dstprim_nr; i++) split->dstprim[i].start -= split->min_index; } assert(split->max_index >= split->min_index); split->draw(split->ctx, split->array, split->dstprim, split->dstprim_nr, split->ib ? &ib : NULL, !split->ib, split->min_index, split->max_index); split->dstprim_nr = 0; split->min_index = ~0; split->max_index = 0; }
static int get_array_stride(struct gl_context *ctx, const struct gl_client_array *a) { struct nouveau_render_state *render = to_render_state(ctx); if (render->mode == VBO && !_mesa_is_bufferobj(a->BufferObj)) /* Pack client buffers. */ return align(_mesa_sizeof_type(a->Type) * a->Size, 4); else return a->StrideB; }
/** * Do error checking and update state for glVertex/Color/TexCoord/...Pointer * functions. * * \param func name of calling function used for error reporting * \param attrib the attribute array index to update * \param legalTypes bitmask of *_BIT above indicating legal datatypes * \param sizeMin min allowable size value * \param sizeMax max allowable size value * \param size components per element (1, 2, 3 or 4) * \param type datatype of each component (GL_FLOAT, GL_INT, etc) * \param stride stride between elements, in elements * \param normalized are integer types converted to floats in [-1, 1]? * \param integer integer-valued values (will not be normalized to [-1,1]) * \param ptr the address (or offset inside VBO) of the array data */ static void update_array(struct gl_context *ctx, const char *func, GLuint attrib, GLbitfield legalTypesMask, GLint sizeMin, GLint sizeMax, GLint size, GLenum type, GLsizei stride, GLboolean normalized, GLboolean integer, const GLvoid *ptr) { struct gl_client_array *array; GLbitfield typeBit; GLsizei elementSize; typeBit = type_to_bit(ctx, type); if (typeBit == 0x0 || (typeBit & legalTypesMask) == 0x0) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(type = %s)", func, _mesa_lookup_enum_by_nr(type)); return; } /* Do size parameter checking. */ if (size < sizeMin || size > sizeMax || size > 4) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(size=%d)", func, size); return; } ASSERT(size <= 4); if (stride < 0) { _mesa_error( ctx, GL_INVALID_VALUE, "%s(stride=%d)", func, stride ); return; } elementSize = _mesa_sizeof_type(type) * size; array = &ctx->Array.VertexAttrib[attrib]; array->Size = size; array->Type = type; array->Stride = stride; array->StrideB = stride ? stride : elementSize; array->Normalized = normalized; array->Integer = integer; array->Ptr = (const GLubyte *) ptr; array->_ElementSize = elementSize; ctx->NewState |= _NEW_ARRAY; ctx->Array.NewState |= VERT_BIT(attrib); }
static void init_array(struct gl_context *ctx, struct gl_client_array *array, GLint size, GLint type) { array->Size = size; array->Type = type; array->Stride = 0; array->StrideB = 0; array->Ptr = NULL; array->Enabled = GL_FALSE; array->Normalized = GL_FALSE; array->Integer = GL_FALSE; array->_ElementSize = size * _mesa_sizeof_type(type); /* Vertex array buffers */ _mesa_reference_buffer_object(ctx, &array->BufferObj, ctx->Shared->NullBufferObj); }
static void flush_vertex( struct split_context *split ) { struct gl_context *ctx = split->ctx; const struct gl_vertex_array **saved_arrays = ctx->Array._DrawArrays; struct _mesa_index_buffer ib; GLuint i; if (!split->dstprim_nr) return; if (split->ib) { ib = *split->ib; ib.count = split->max_index - split->min_index + 1; ib.ptr = (const void *)((const char *)ib.ptr + split->min_index * _mesa_sizeof_type(ib.type)); /* Rebase the primitives to save index buffer entries. */ for (i = 0; i < split->dstprim_nr; i++) split->dstprim[i].start -= split->min_index; } assert(split->max_index >= split->min_index); ctx->Array._DrawArrays = split->array; ctx->NewDriverState |= ctx->DriverFlags.NewArray; split->draw(ctx, split->dstprim, split->dstprim_nr, split->ib ? &ib : NULL, !split->ib, split->min_index, split->max_index, NULL, 0, NULL); ctx->Array._DrawArrays = saved_arrays; ctx->NewDriverState |= ctx->DriverFlags.NewArray; split->dstprim_nr = 0; split->min_index = ~0; split->max_index = 0; }
static void init_array(struct gl_context *ctx, struct gl_client_array *array, GLint size, GLint type) { array->Size = size; array->Type = type; array->Format = GL_RGBA; /* only significant for GL_EXT_vertex_array_bgra */ array->Stride = 0; array->StrideB = 0; array->Ptr = NULL; array->Enabled = GL_FALSE; array->Normalized = GL_FALSE; array->_ElementSize = size * _mesa_sizeof_type(type); #if FEATURE_ARB_vertex_buffer_object /* Vertex array buffers */ _mesa_reference_buffer_object(ctx, &array->BufferObj, ctx->Shared->NullBufferObj); #endif }
static GLuint attr_size( const struct gl_client_array *array ) { return array->Size * _mesa_sizeof_type(array->Type); }
static void brw_upload_indices(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; const struct _mesa_index_buffer *index_buffer = brw->ib.ib; GLuint ib_size; drm_intel_bo *old_bo = brw->ib.bo; struct gl_buffer_object *bufferobj; GLuint offset; GLuint ib_type_size; if (index_buffer == NULL) return; ib_type_size = _mesa_sizeof_type(index_buffer->type); ib_size = ib_type_size * index_buffer->count; bufferobj = index_buffer->obj; /* Turn into a proper VBO: */ if (!_mesa_is_bufferobj(bufferobj)) { /* Get new bufferobj, offset: */ intel_upload_data(brw, index_buffer->ptr, ib_size, ib_type_size, &brw->ib.bo, &offset); } else { offset = (GLuint) (unsigned long) index_buffer->ptr; /* If the index buffer isn't aligned to its element size, we have to * rebase it into a temporary. */ if ((ib_type_size - 1) & offset) { perf_debug("copying index buffer to a temporary to work around " "misaligned offset %d\n", offset); GLubyte *map = ctx->Driver.MapBufferRange(ctx, offset, ib_size, GL_MAP_READ_BIT, bufferobj, MAP_INTERNAL); intel_upload_data(brw, map, ib_size, ib_type_size, &brw->ib.bo, &offset); ctx->Driver.UnmapBuffer(ctx, bufferobj, MAP_INTERNAL); } else { drm_intel_bo *bo = intel_bufferobj_buffer(brw, intel_buffer_object(bufferobj), offset, ib_size); if (bo != brw->ib.bo) { drm_intel_bo_unreference(brw->ib.bo); brw->ib.bo = bo; drm_intel_bo_reference(bo); } } } /* Use 3DPRIMITIVE's start_vertex_offset to avoid re-uploading * the index buffer state when we're just moving the start index * of our drawing. */ brw->ib.start_vertex_offset = offset / ib_type_size; if (brw->ib.bo != old_bo) brw->state.dirty.brw |= BRW_NEW_INDEX_BUFFER; if (index_buffer->type != brw->ib.type) { brw->ib.type = index_buffer->type; brw->state.dirty.brw |= BRW_NEW_INDEX_BUFFER; } }
/** * 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. * Might move this into the failover module some day. */ void st_feedback_draw_vbo(GLcontext *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 st_context *st = ctx->st; 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_buffer *index_buffer_handle = 0; struct pipe_vertex_buffer vbuffers[PIPE_MAX_SHADER_INPUTS]; struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS]; GLuint attr, i; ubyte *mapped_constants; assert(draw); st_validate_state(ctx->st); if (!index_bounds_valid) vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index); /* must get these after state validation! */ vp = ctx->st->vp; vs = &st->vp->state; if (!st->vp->draw_shader) { st->vp->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); draw_bind_vertex_shader(draw, st->vp->draw_shader); set_feedback_vertex_format(ctx); /* 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_buffer_reference(&vbuffers[attr].buffer, stobj->buffer); vbuffers[attr].buffer_offset = pointer_to_offset(arrays[0]->Ptr); velements[attr].src_offset = arrays[mesaAttr]->Ptr - arrays[0]->Ptr; } 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); vbuffers[attr].buffer_offset = 0; velements[attr].src_offset = 0; } /* common-case setup */ vbuffers[attr].stride = arrays[mesaAttr]->StrideB; /* in bytes */ vbuffers[attr].max_index = max_index; velements[attr].vertex_buffer_index = attr; velements[attr].nr_components = arrays[mesaAttr]->Size; velements[attr].src_format = st_pipe_vertex_format(arrays[mesaAttr]->Type, arrays[mesaAttr]->Size, arrays[mesaAttr]->Format, arrays[mesaAttr]->Normalized); 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->screen, vbuffers[attr].buffer, PIPE_BUFFER_USAGE_CPU_READ); 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); if (ib) { struct gl_buffer_object *bufobj = ib->obj; unsigned indexSize; void *map; switch (ib->type) { case GL_UNSIGNED_INT: indexSize = 4; break; case GL_UNSIGNED_SHORT: indexSize = 2; break; default: assert(0); return; } if (bufobj && bufobj->Name) { struct st_buffer_object *stobj = st_buffer_object(bufobj); index_buffer_handle = stobj->buffer; map = pipe_buffer_map(pipe->screen, index_buffer_handle, PIPE_BUFFER_USAGE_CPU_READ); draw_set_mapped_element_buffer(draw, indexSize, map); } else { draw_set_mapped_element_buffer(draw, indexSize, (void *) ib->ptr); } } else { /* no index/element buffer */ draw_set_mapped_element_buffer(draw, 0, NULL); } /* map constant buffers */ mapped_constants = pipe_buffer_map(pipe->screen, st->state.constants[PIPE_SHADER_VERTEX].buffer, PIPE_BUFFER_USAGE_CPU_READ); draw_set_mapped_constant_buffer(st->draw, mapped_constants, st->state.constants[PIPE_SHADER_VERTEX].buffer->size); /* draw here */ for (i = 0; i < nr_prims; i++) { draw_arrays(draw, prims[i].mode, prims[i].start, prims[i].count); } /* unmap constant buffers */ pipe_buffer_unmap(pipe->screen, st->state.constants[PIPE_SHADER_VERTEX].buffer); /* * unmap vertex/index buffers */ for (i = 0; i < PIPE_MAX_ATTRIBS; i++) { if (draw->pt.vertex_buffer[i].buffer) { pipe_buffer_unmap(pipe->screen, draw->pt.vertex_buffer[i].buffer); pipe_buffer_reference(&draw->pt.vertex_buffer[i].buffer, NULL); draw_set_mapped_vertex_buffer(draw, i, NULL); } } if (index_buffer_handle) { pipe_buffer_unmap(pipe->screen, index_buffer_handle); draw_set_mapped_element_buffer(draw, 0, NULL); } }
/** * 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); }
/** * Do error checking and update state for glVertex/Color/TexCoord/...Pointer * functions. * * \param func name of calling function used for error reporting * \param attrib the attribute array index to update * \param legalTypes bitmask of *_BIT above indicating legal datatypes * \param sizeMin min allowable size value * \param sizeMax max allowable size value (may also be BGRA_OR_4) * \param size components per element (1, 2, 3 or 4) * \param type datatype of each component (GL_FLOAT, GL_INT, etc) * \param stride stride between elements, in elements * \param normalized are integer types converted to floats in [-1, 1]? * \param integer integer-valued values (will not be normalized to [-1,1]) * \param ptr the address (or offset inside VBO) of the array data */ static void update_array(struct gl_context *ctx, const char *func, GLuint attrib, GLbitfield legalTypesMask, GLint sizeMin, GLint sizeMax, GLint size, GLenum type, GLsizei stride, GLboolean normalized, GLboolean integer, const GLvoid *ptr) { struct gl_client_array *array; GLbitfield typeBit; GLsizei elementSize; GLenum format = GL_RGBA; if (_mesa_is_gles(ctx)) { /* Once Mesa gets support for GL_OES_vertex_half_float this mask will * change. Adding support for this extension isn't quite as trivial as * we'd like because ES uses a different enum value for GL_HALF_FLOAT. */ legalTypesMask &= ~(FIXED_GL_BIT | HALF_BIT | DOUBLE_BIT); /* GL_INT and GL_UNSIGNED_INT data is not allowed in OpenGL ES until * 3.0. The 2_10_10_10 types are added in OpenGL ES 3.0 or * GL_OES_vertex_type_10_10_10_2. */ if (ctx->Version < 30) { legalTypesMask &= ~(UNSIGNED_INT_BIT | INT_BIT | UNSIGNED_INT_2_10_10_10_REV_BIT | INT_2_10_10_10_REV_BIT); } /* BGRA ordering is not supported in ES contexts. */ if (sizeMax == BGRA_OR_4) sizeMax = 4; } else { legalTypesMask &= ~FIXED_ES_BIT; if (!ctx->Extensions.ARB_ES2_compatibility) legalTypesMask &= ~FIXED_GL_BIT; if (!ctx->Extensions.ARB_vertex_type_2_10_10_10_rev) legalTypesMask &= ~(UNSIGNED_INT_2_10_10_10_REV_BIT | INT_2_10_10_10_REV_BIT); } typeBit = type_to_bit(ctx, type); if (typeBit == 0x0 || (typeBit & legalTypesMask) == 0x0) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(type = %s)", func, _mesa_lookup_enum_by_nr(type)); return; } /* Do size parameter checking. * If sizeMax = BGRA_OR_4 it means that size = GL_BGRA is legal and * must be handled specially. */ if (ctx->Extensions.EXT_vertex_array_bgra && sizeMax == BGRA_OR_4 && size == GL_BGRA) { GLboolean bgra_error = GL_FALSE; if (ctx->Extensions.ARB_vertex_type_2_10_10_10_rev) { if (type != GL_UNSIGNED_INT_2_10_10_10_REV && type != GL_INT_2_10_10_10_REV && type != GL_UNSIGNED_BYTE) bgra_error = GL_TRUE; } else if (type != GL_UNSIGNED_BYTE) bgra_error = GL_TRUE; if (bgra_error) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(GL_BGRA/GLubyte)", func); return; } format = GL_BGRA; size = 4; } else if (size < sizeMin || size > sizeMax || size > 4) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(size=%d)", func, size); return; } if (ctx->Extensions.ARB_vertex_type_2_10_10_10_rev && (type == GL_UNSIGNED_INT_2_10_10_10_REV || type == GL_INT_2_10_10_10_REV) && size != 4) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(size=%d)", func, size); return; } ASSERT(size <= 4); if (stride < 0) { _mesa_error( ctx, GL_INVALID_VALUE, "%s(stride=%d)", func, stride ); return; } if (ctx->Array.ArrayObj->ARBsemantics && !_mesa_is_bufferobj(ctx->Array.ArrayBufferObj)) { /* GL_ARB_vertex_array_object requires that all arrays reside in VBOs. * Generate GL_INVALID_OPERATION if that's not true. */ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-VBO array)", func); return; } elementSize = _mesa_sizeof_type(type) * size; array = &ctx->Array.ArrayObj->VertexAttrib[attrib]; array->Size = size; array->Type = type; array->Format = format; array->Stride = stride; array->StrideB = stride ? stride : elementSize; array->Normalized = normalized; array->Integer = integer; array->Ptr = (const GLubyte *) ptr; array->_ElementSize = elementSize; _mesa_reference_buffer_object(ctx, &array->BufferObj, ctx->Array.ArrayBufferObj); ctx->NewState |= _NEW_ARRAY; ctx->Array.ArrayObj->NewArrays |= VERT_BIT(attrib); }
/** * Set up a separate pipe_vertex_buffer and pipe_vertex_element for each * vertex attribute. * \param vbuffer returns vertex buffer info * \param velements returns vertex element info */ static boolean setup_non_interleaved_attribs(struct st_context *st, const struct st_vertex_program *vp, const struct st_vp_variant *vpv, const struct gl_client_array **arrays, struct pipe_vertex_buffer vbuffer[], struct pipe_vertex_element velements[]) { struct gl_context *ctx = st->ctx; GLuint attr; for (attr = 0; attr < vpv->num_inputs; attr++) { const GLuint mesaAttr = vp->index_to_input[attr]; const struct gl_client_array *array = arrays[mesaAttr]; struct gl_buffer_object *bufobj = array->BufferObj; GLsizei stride = array->StrideB; assert(array->_ElementSize == array->Size * _mesa_sizeof_type(array->Type)); if (_mesa_is_bufferobj(bufobj)) { /* 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); if (!stobj || !stobj->buffer) { return FALSE; /* out-of-memory error probably */ } vbuffer[attr].buffer = stobj->buffer; vbuffer[attr].user_buffer = NULL; vbuffer[attr].buffer_offset = pointer_to_offset(array->Ptr); } else { /* wrap user data */ void *ptr; if (array->Ptr) { ptr = (void *) array->Ptr; } else { /* no array, use ctx->Current.Attrib[] value */ ptr = (void *) ctx->Current.Attrib[mesaAttr]; stride = 0; } assert(ptr); vbuffer[attr].buffer = NULL; vbuffer[attr].user_buffer = ptr; vbuffer[attr].buffer_offset = 0; } /* common-case setup */ vbuffer[attr].stride = stride; /* in bytes */ velements[attr].src_offset = 0; velements[attr].instance_divisor = array->InstanceDivisor; velements[attr].vertex_buffer_index = attr; velements[attr].src_format = st_pipe_vertex_format(array->Type, array->Size, array->Format, array->Normalized, array->Integer); assert(velements[attr].src_format); } return TRUE; }
/** * Set up for drawing interleaved arrays that all live in one VBO * or all live in user space. * \param vbuffer returns vertex buffer info * \param velements returns vertex element info */ static boolean setup_interleaved_attribs(const struct st_vertex_program *vp, const struct st_vp_variant *vpv, const struct gl_client_array **arrays, struct pipe_vertex_buffer *vbuffer, struct pipe_vertex_element velements[]) { GLuint attr; const GLubyte *low_addr = NULL; GLboolean usingVBO; /* all arrays in a VBO? */ struct gl_buffer_object *bufobj; GLsizei stride; /* Find the lowest address of the arrays we're drawing, * Init bufobj and stride. */ if (vpv->num_inputs) { const GLuint mesaAttr0 = vp->index_to_input[0]; const struct gl_client_array *array = arrays[mesaAttr0]; /* Since we're doing interleaved arrays, we know there'll be at most * one buffer object and the stride will be the same for all arrays. * Grab them now. */ bufobj = array->BufferObj; stride = array->StrideB; low_addr = arrays[vp->index_to_input[0]]->Ptr; for (attr = 1; attr < vpv->num_inputs; attr++) { const GLubyte *start = arrays[vp->index_to_input[attr]]->Ptr; low_addr = MIN2(low_addr, start); } } else { /* not sure we'll ever have zero inputs, but play it safe */ bufobj = NULL; stride = 0; low_addr = 0; } /* are the arrays in user space? */ usingVBO = _mesa_is_bufferobj(bufobj); for (attr = 0; attr < vpv->num_inputs; attr++) { const GLuint mesaAttr = vp->index_to_input[attr]; const struct gl_client_array *array = arrays[mesaAttr]; unsigned src_offset = (unsigned) (array->Ptr - low_addr); GLuint element_size = array->_ElementSize; assert(element_size == array->Size * _mesa_sizeof_type(array->Type)); velements[attr].src_offset = src_offset; velements[attr].instance_divisor = array->InstanceDivisor; velements[attr].vertex_buffer_index = 0; velements[attr].src_format = st_pipe_vertex_format(array->Type, array->Size, array->Format, array->Normalized, array->Integer); assert(velements[attr].src_format); } /* * Return the vbuffer info and setup user-space attrib info, if needed. */ if (vpv->num_inputs == 0) { /* just defensive coding here */ vbuffer->buffer = NULL; vbuffer->user_buffer = NULL; vbuffer->buffer_offset = 0; vbuffer->stride = 0; } else if (usingVBO) { /* all interleaved arrays in a VBO */ struct st_buffer_object *stobj = st_buffer_object(bufobj); if (!stobj || !stobj->buffer) { return FALSE; /* out-of-memory error probably */ } vbuffer->buffer = stobj->buffer; vbuffer->user_buffer = NULL; vbuffer->buffer_offset = pointer_to_offset(low_addr); vbuffer->stride = stride; } else { /* all interleaved arrays in user memory */ vbuffer->buffer = NULL; vbuffer->user_buffer = low_addr; vbuffer->buffer_offset = 0; vbuffer->stride = stride; } return TRUE; }
/** * Do error checking and update state for glVertex/Color/TexCoord/...Pointer * functions. * * \param func name of calling function used for error reporting * \param attrib the attribute array index to update * \param legalTypes bitmask of *_BIT above indicating legal datatypes * \param sizeMin min allowable size value * \param sizeMax max allowable size value (may also be BGRA_OR_4) * \param size components per element (1, 2, 3 or 4) * \param type datatype of each component (GL_FLOAT, GL_INT, etc) * \param stride stride between elements, in elements * \param normalized are integer types converted to floats in [-1, 1]? * \param integer integer-valued values (will not be normalized to [-1,1]) * \param ptr the address (or offset inside VBO) of the array data */ static void update_array(struct gl_context *ctx, const char *func, GLuint attrib, GLbitfield legalTypesMask, GLint sizeMin, GLint sizeMax, GLint size, GLenum type, GLsizei stride, GLboolean normalized, GLboolean integer, const GLvoid *ptr) { struct gl_client_array *array; GLbitfield typeBit; GLsizei elementSize; GLenum format = GL_RGBA; if (ctx->API != API_OPENGLES && ctx->API != API_OPENGLES2) { /* fixed point arrays / data is only allowed with OpenGL ES 1.x/2.0 */ legalTypesMask &= ~FIXED_ES_BIT; } if (!ctx->Extensions.ARB_ES2_compatibility) { legalTypesMask &= ~FIXED_GL_BIT; } if (!ctx->Extensions.ARB_vertex_type_2_10_10_10_rev) { legalTypesMask &= ~(UNSIGNED_INT_2_10_10_10_REV_BIT | INT_2_10_10_10_REV_BIT); } typeBit = type_to_bit(ctx, type); if (typeBit == 0x0 || (typeBit & legalTypesMask) == 0x0) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(type = %s)", func, _mesa_lookup_enum_by_nr(type)); return; } /* Do size parameter checking. * If sizeMax = BGRA_OR_4 it means that size = GL_BGRA is legal and * must be handled specially. */ if (ctx->Extensions.EXT_vertex_array_bgra && sizeMax == BGRA_OR_4 && size == GL_BGRA) { GLboolean bgra_error = GL_FALSE; if (ctx->Extensions.ARB_vertex_type_2_10_10_10_rev) { if (type != GL_UNSIGNED_INT_2_10_10_10_REV && type != GL_INT_2_10_10_10_REV && type != GL_UNSIGNED_BYTE) bgra_error = GL_TRUE; } else if (type != GL_UNSIGNED_BYTE) bgra_error = GL_TRUE; if (bgra_error) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(GL_BGRA/GLubyte)", func); return; } format = GL_BGRA; size = 4; } else if (size < sizeMin || size > sizeMax || size > 4) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(size=%d)", func, size); return; } if (ctx->Extensions.ARB_vertex_type_2_10_10_10_rev && (type == GL_UNSIGNED_INT_2_10_10_10_REV || type == GL_INT_2_10_10_10_REV) && size != 4) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(size=%d)", func, size); } ASSERT(size <= 4); if (stride < 0) { _mesa_error( ctx, GL_INVALID_VALUE, "%s(stride=%d)", func, stride ); return; } if (ctx->Array.ArrayObj->ARBsemantics && !_mesa_is_bufferobj(ctx->Array.ArrayBufferObj)) { /* GL_ARB_vertex_array_object requires that all arrays reside in VBOs. * Generate GL_INVALID_OPERATION if that's not true. */ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-VBO array)", func); return; } elementSize = _mesa_sizeof_type(type) * size; array = &ctx->Array.ArrayObj->VertexAttrib[attrib]; array->Size = size; array->Type = type; array->Format = format; array->Stride = stride; array->StrideB = stride ? stride : elementSize; array->Normalized = normalized; array->Integer = integer; array->Ptr = (const GLubyte *) ptr; array->_ElementSize = elementSize; _mesa_reference_buffer_object(ctx, &array->BufferObj, ctx->Array.ArrayBufferObj); ctx->NewState |= _NEW_ARRAY; ctx->Array.NewState |= VERT_BIT(attrib); }