/** * 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); assert(array->_ElementSize == _mesa_bytes_per_vertex_attrib(array->Size, 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; }
/** * 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 == _mesa_bytes_per_vertex_attrib(array->Size, 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; }
/** * Return a PIPE_FORMAT_x for the given GL datatype and size. */ static enum pipe_format st_pipe_vertex_format(const struct gl_vertex_format *vformat) { const GLubyte size = vformat->Size; const GLenum16 format = vformat->Format; const bool normalized = vformat->Normalized; const bool integer = vformat->Integer; GLenum16 type = vformat->Type; unsigned index; assert(size >= 1 && size <= 4); assert(format == GL_RGBA || format == GL_BGRA); assert(vformat->_ElementSize == _mesa_bytes_per_vertex_attrib(size, type)); switch (type) { case GL_HALF_FLOAT_OES: type = GL_HALF_FLOAT; break; case GL_INT_2_10_10_10_REV: assert(size == 4 && !integer); if (format == GL_BGRA) { if (normalized) return PIPE_FORMAT_B10G10R10A2_SNORM; else return PIPE_FORMAT_B10G10R10A2_SSCALED; } else { if (normalized) return PIPE_FORMAT_R10G10B10A2_SNORM; else return PIPE_FORMAT_R10G10B10A2_SSCALED; } break; case GL_UNSIGNED_INT_2_10_10_10_REV: assert(size == 4 && !integer); if (format == GL_BGRA) { if (normalized) return PIPE_FORMAT_B10G10R10A2_UNORM; else return PIPE_FORMAT_B10G10R10A2_USCALED; } else { if (normalized) return PIPE_FORMAT_R10G10B10A2_UNORM; else return PIPE_FORMAT_R10G10B10A2_USCALED; } break; case GL_UNSIGNED_INT_10F_11F_11F_REV: assert(size == 3 && !integer && format == GL_RGBA); return PIPE_FORMAT_R11G11B10_FLOAT; case GL_UNSIGNED_BYTE: if (format == GL_BGRA) { /* this is an odd-ball case */ assert(normalized); return PIPE_FORMAT_B8G8R8A8_UNORM; } break; } index = integer*2 + normalized; assert(index <= 2); assert(type >= GL_BYTE && type <= GL_FIXED); return vertex_formats[type - GL_BYTE][index][size-1]; }