#include "st_context.h"
#include "st_atom.h"
#include "st_cb_bufferobjects.h"
+#include "st_cb_xformfb.h"
#include "st_draw.h"
#include "st_program.h"
#include "util/u_format.h"
#include "util/u_prim.h"
#include "util/u_draw_quad.h"
+#include "util/u_upload_mgr.h"
#include "draw/draw_context.h"
#include "cso_cache/cso_context.h"
PIPE_FORMAT_R32G32B32A32_USCALED
};
+static GLuint uint_types_int[4] = {
+ PIPE_FORMAT_R32_UINT,
+ PIPE_FORMAT_R32G32_UINT,
+ PIPE_FORMAT_R32G32B32_UINT,
+ PIPE_FORMAT_R32G32B32A32_UINT
+};
+
static GLuint int_types_norm[4] = {
PIPE_FORMAT_R32_SNORM,
PIPE_FORMAT_R32G32_SNORM,
PIPE_FORMAT_R32G32B32A32_SSCALED
};
+static GLuint int_types_int[4] = {
+ PIPE_FORMAT_R32_SINT,
+ PIPE_FORMAT_R32G32_SINT,
+ PIPE_FORMAT_R32G32B32_SINT,
+ PIPE_FORMAT_R32G32B32A32_SINT
+};
+
static GLuint ushort_types_norm[4] = {
PIPE_FORMAT_R16_UNORM,
PIPE_FORMAT_R16G16_UNORM,
PIPE_FORMAT_R16G16B16A16_USCALED
};
+static GLuint ushort_types_int[4] = {
+ PIPE_FORMAT_R16_UINT,
+ PIPE_FORMAT_R16G16_UINT,
+ PIPE_FORMAT_R16G16B16_UINT,
+ PIPE_FORMAT_R16G16B16A16_UINT
+};
+
static GLuint short_types_norm[4] = {
PIPE_FORMAT_R16_SNORM,
PIPE_FORMAT_R16G16_SNORM,
PIPE_FORMAT_R16G16B16A16_SSCALED
};
+static GLuint short_types_int[4] = {
+ PIPE_FORMAT_R16_SINT,
+ PIPE_FORMAT_R16G16_SINT,
+ PIPE_FORMAT_R16G16B16_SINT,
+ PIPE_FORMAT_R16G16B16A16_SINT
+};
+
static GLuint ubyte_types_norm[4] = {
PIPE_FORMAT_R8_UNORM,
PIPE_FORMAT_R8G8_UNORM,
PIPE_FORMAT_R8G8B8A8_USCALED
};
+static GLuint ubyte_types_int[4] = {
+ PIPE_FORMAT_R8_UINT,
+ PIPE_FORMAT_R8G8_UINT,
+ PIPE_FORMAT_R8G8B8_UINT,
+ PIPE_FORMAT_R8G8B8A8_UINT
+};
+
static GLuint byte_types_norm[4] = {
PIPE_FORMAT_R8_SNORM,
PIPE_FORMAT_R8G8_SNORM,
PIPE_FORMAT_R8G8B8A8_SSCALED
};
+static GLuint byte_types_int[4] = {
+ PIPE_FORMAT_R8_SINT,
+ PIPE_FORMAT_R8G8_SINT,
+ PIPE_FORMAT_R8G8B8_SINT,
+ PIPE_FORMAT_R8G8B8A8_SINT
+};
+
static GLuint fixed_types[4] = {
PIPE_FORMAT_R32_FIXED,
PIPE_FORMAT_R32G32_FIXED,
*/
enum pipe_format
st_pipe_vertex_format(GLenum type, GLuint size, GLenum format,
- GLboolean normalized)
+ GLboolean normalized, GLboolean integer)
{
assert((type >= GL_BYTE && type <= GL_DOUBLE) ||
type == GL_FIXED || type == GL_HALF_FLOAT ||
if (type == GL_INT_2_10_10_10_REV ||
type == GL_UNSIGNED_INT_2_10_10_10_REV) {
assert(size == 4);
+ assert(!integer);
if (format == GL_BGRA) {
if (type == GL_INT_2_10_10_10_REV) {
return PIPE_FORMAT_B8G8R8A8_UNORM;
}
- if (normalized) {
+ if (integer) {
+ switch (type) {
+ case GL_INT: return int_types_int[size-1];
+ case GL_SHORT: return short_types_int[size-1];
+ case GL_BYTE: return byte_types_int[size-1];
+ case GL_UNSIGNED_INT: return uint_types_int[size-1];
+ case GL_UNSIGNED_SHORT: return ushort_types_int[size-1];
+ case GL_UNSIGNED_BYTE: return ubyte_types_int[size-1];
+ default: assert(0); return 0;
+ }
+ }
+ else if (normalized) {
switch (type) {
case GL_DOUBLE: return double_types[size-1];
case GL_FLOAT: return float_types[size-1];
if (abs(array->Ptr - firstPtr) > firstStride)
return GL_FALSE; /* arrays start too far apart */
- if ((!bufObj || !_mesa_is_bufferobj(bufObj)) != userSpaceBuffer)
+ if ((!_mesa_is_bufferobj(bufObj)) != userSpaceBuffer)
return GL_FALSE; /* mix of VBO and user-space arrays */
}
}
const struct st_vp_variant *vpv,
const struct gl_client_array **arrays,
struct pipe_vertex_buffer *vbuffer,
- struct pipe_vertex_element velements[],
- unsigned max_index,
- unsigned num_instances)
+ struct pipe_vertex_element velements[])
{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
GLuint attr;
const GLubyte *low_addr = NULL;
GLboolean usingVBO; /* all arrays in a VBO? */
struct gl_buffer_object *bufobj;
- GLuint user_buffer_size = 0;
- GLuint vertex_size = 0; /* bytes per vertex, in bytes */
GLsizei stride;
/* Find the lowest address of the arrays we're drawing,
}
/* are the arrays in user space? */
- usingVBO = bufobj && _mesa_is_bufferobj(bufobj);
+ usingVBO = _mesa_is_bufferobj(bufobj);
for (attr = 0; attr < vpv->num_inputs; attr++) {
const GLuint mesaAttr = vp->index_to_input[attr];
velements[attr].src_format = st_pipe_vertex_format(array->Type,
array->Size,
array->Format,
- array->Normalized);
+ array->Normalized,
+ array->Integer);
assert(velements[attr].src_format);
-
- if (!usingVBO) {
- /* how many bytes referenced by this attribute array? */
- uint divisor = array->InstanceDivisor;
- uint last_index = divisor ? num_instances / divisor : max_index;
- uint bytes = src_offset + stride * last_index + element_size;
-
- user_buffer_size = MAX2(user_buffer_size, bytes);
-
- /* update vertex size */
- vertex_size = MAX2(vertex_size, src_offset + element_size);
- }
}
/*
if (vpv->num_inputs == 0) {
/* just defensive coding here */
vbuffer->buffer = NULL;
+ vbuffer->user_buffer = NULL;
vbuffer->buffer_offset = 0;
vbuffer->stride = 0;
- st->num_user_attribs = 0;
}
else if (usingVBO) {
/* all interleaved arrays in a VBO */
return GL_FALSE;
}
- vbuffer->buffer = NULL;
- pipe_resource_reference(&vbuffer->buffer, stobj->buffer);
+ vbuffer->buffer = stobj->buffer;
+ vbuffer->user_buffer = NULL;
vbuffer->buffer_offset = pointer_to_offset(low_addr);
vbuffer->stride = stride;
- st->num_user_attribs = 0;
}
else {
/* all interleaved arrays in user memory */
- vbuffer->buffer = pipe_user_buffer_create(pipe->screen,
- (void*) low_addr,
- user_buffer_size,
- PIPE_BIND_VERTEX_BUFFER);
+ vbuffer->buffer = NULL;
+ vbuffer->user_buffer = low_addr;
vbuffer->buffer_offset = 0;
vbuffer->stride = stride;
-
- /* Track user vertex buffers. */
- pipe_resource_reference(&st->user_attrib[0].buffer, vbuffer->buffer);
- st->user_attrib[0].element_size = vertex_size;
- st->user_attrib[0].stride = stride;
- st->num_user_attribs = 1;
}
return GL_TRUE;
const struct st_vp_variant *vpv,
const struct gl_client_array **arrays,
struct pipe_vertex_buffer vbuffer[],
- struct pipe_vertex_element velements[],
- unsigned max_index,
- unsigned num_instances)
+ struct pipe_vertex_element velements[])
{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
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;
- GLuint element_size = array->_ElementSize;
GLsizei stride = array->StrideB;
- assert(element_size == array->Size * _mesa_sizeof_type(array->Type));
+ assert(array->_ElementSize == array->Size * _mesa_sizeof_type(array->Type));
- if (bufobj && _mesa_is_bufferobj(bufobj)) {
+ 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.
return GL_FALSE;
}
- vbuffer[attr].buffer = NULL;
- pipe_resource_reference(&vbuffer[attr].buffer, stobj->buffer);
+ vbuffer[attr].buffer = stobj->buffer;
+ vbuffer[attr].user_buffer = NULL;
vbuffer[attr].buffer_offset = pointer_to_offset(array->Ptr);
}
else {
/* wrap user data */
- uint bytes;
void *ptr;
if (array->Ptr) {
- uint divisor = array->InstanceDivisor;
- uint last_index = divisor ? num_instances / divisor : max_index;
-
- bytes = stride * last_index + element_size;
-
ptr = (void *) array->Ptr;
}
else {
/* no array, use ctx->Current.Attrib[] value */
- bytes = element_size = sizeof(ctx->Current.Attrib[0]);
ptr = (void *) ctx->Current.Attrib[mesaAttr];
stride = 0;
}
assert(ptr);
- assert(bytes);
-
- vbuffer[attr].buffer =
- pipe_user_buffer_create(pipe->screen, ptr, bytes,
- PIPE_BIND_VERTEX_BUFFER);
+ vbuffer[attr].buffer = NULL;
+ vbuffer[attr].user_buffer = ptr;
vbuffer[attr].buffer_offset = 0;
-
- /* Track user vertex buffers. */
- pipe_resource_reference(&st->user_attrib[attr].buffer, vbuffer[attr].buffer);
- st->user_attrib[attr].element_size = element_size;
- st->user_attrib[attr].stride = stride;
- st->num_user_attribs = MAX2(st->num_user_attribs, attr + 1);
-
- if (!vbuffer[attr].buffer) {
- /* probably ran out of memory */
- return GL_FALSE;
- }
}
/* common-case setup */
velements[attr].src_format = st_pipe_vertex_format(array->Type,
array->Size,
array->Format,
- array->Normalized);
+ array->Normalized,
+ array->Integer);
assert(velements[attr].src_format);
}
static void
-setup_index_buffer(struct gl_context *ctx,
+setup_index_buffer(struct st_context *st,
const struct _mesa_index_buffer *ib,
struct pipe_index_buffer *ibuffer)
{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
+ struct gl_buffer_object *bufobj = ib->obj;
- memset(ibuffer, 0, sizeof(*ibuffer));
- if (ib) {
- struct gl_buffer_object *bufobj = ib->obj;
-
- switch (ib->type) {
- case GL_UNSIGNED_INT:
- ibuffer->index_size = 4;
- break;
- case GL_UNSIGNED_SHORT:
- ibuffer->index_size = 2;
- break;
- case GL_UNSIGNED_BYTE:
- ibuffer->index_size = 1;
- break;
- default:
- assert(0);
- return;
- }
+ ibuffer->index_size = vbo_sizeof_ib_type(ib->type);
- /* get/create the index buffer object */
- if (bufobj && _mesa_is_bufferobj(bufobj)) {
- /* elements/indexes are in a real VBO */
- struct st_buffer_object *stobj = st_buffer_object(bufobj);
- pipe_resource_reference(&ibuffer->buffer, stobj->buffer);
- ibuffer->offset = pointer_to_offset(ib->ptr);
- }
- else {
- /* element/indicies are in user space memory */
- ibuffer->buffer =
- pipe_user_buffer_create(pipe->screen, (void *) ib->ptr,
- ib->count * ibuffer->index_size,
- PIPE_BIND_INDEX_BUFFER);
- }
+ /* 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);
}
* sub-primitives.
*/
static void
-handle_fallback_primitive_restart(struct pipe_context *pipe,
+handle_fallback_primitive_restart(struct cso_context *cso,
+ struct pipe_context *pipe,
const struct _mesa_index_buffer *ib,
struct pipe_index_buffer *ibuffer,
struct pipe_draw_info *orig_info)
unsigned num_sub_prims;
assert(info.indexed);
- assert(ibuffer->buffer);
+ assert(ibuffer->buffer || ibuffer->user_buffer);
assert(ib);
- if (!ibuffer->buffer || !ib)
+ if (!ibuffer->buffer || !ibuffer->user_buffer || !ib)
return;
info.primitive_restart = FALSE;
info.instance_count = 1;
- if (ib->obj && _mesa_is_bufferobj(ib->obj)) {
+ if (_mesa_is_bufferobj(ib->obj)) {
ptr = pipe_buffer_map_range(pipe, ibuffer->buffer,
start * ibuffer->index_size, /* start */
count * ibuffer->index_size, /* length */
PIPE_TRANSFER_READ, &transfer);
+ if (!ptr)
+ return;
+
+ ptr = (uint8_t*)ptr + (ibuffer->offset - start * ibuffer->index_size);
}
else {
ptr = ib->ptr;
+ if (!ptr)
+ return;
}
- if (!ptr)
- return;
-
- ptr = ADD_POINTERS(ptr, ibuffer->offset);
-
sub_prims = find_sub_primitives(ptr, ibuffer->index_size,
0, count, orig_info->restart_index,
&num_sub_prims);
info.start = sub_prims[i].start;
info.count = sub_prims[i].count;
if (u_trim_pipe_prim(info.mode, &info.count)) {
- pipe->draw_vbo(pipe, &info);
+ cso_draw_vbo(cso, &info);
}
}
}
*/
static GLboolean
st_validate_varrays(struct gl_context *ctx,
- const struct gl_client_array **arrays,
- unsigned max_index,
- unsigned num_instances)
+ const struct gl_client_array **arrays)
{
struct st_context *st = st_context(ctx);
const struct st_vertex_program *vp;
struct pipe_vertex_buffer vbuffer[PIPE_MAX_SHADER_INPUTS];
struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS];
unsigned num_vbuffers, num_velements;
- GLuint attr;
- unsigned i;
/* must get these after state validation! */
vp = st->vp;
memset(velements, 0, sizeof(struct pipe_vertex_element) * vpv->num_inputs);
- /* Unreference any user vertex buffers. */
- for (i = 0; i < st->num_user_attribs; i++) {
- pipe_resource_reference(&st->user_attrib[i].buffer, NULL);
- }
- st->num_user_attribs = 0;
-
/*
* Setup the vbuffer[] and velements[] arrays.
*/
if (is_interleaved_arrays(vp, vpv, arrays)) {
- if (!setup_interleaved_attribs(ctx, vp, vpv, arrays, vbuffer, velements,
- max_index, num_instances)) {
+ if (!setup_interleaved_attribs(ctx, vp, vpv, arrays, vbuffer,
+ velements)) {
return GL_FALSE;
}
}
else {
if (!setup_non_interleaved_attribs(ctx, vp, vpv, arrays,
- vbuffer, velements, max_index,
- num_instances)) {
+ vbuffer, velements)) {
return GL_FALSE;
}
cso_set_vertex_buffers(st->cso_context, num_vbuffers, vbuffer);
cso_set_vertex_elements(st->cso_context, num_velements, velements);
- /* unreference buffers (frees wrapped user-space buffer objects)
- * This is OK, because the pipe driver should reference buffers by itself
- * in set_vertex_buffers. */
- for (attr = 0; attr < num_vbuffers; attr++) {
- pipe_resource_reference(&vbuffer[attr].buffer, NULL);
- assert(!vbuffer[attr].buffer);
- }
-
return GL_TRUE;
}
*/
void
st_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)
+ GLuint max_index,
+ struct gl_transform_feedback_object *tfb_vertcount)
{
struct st_context *st = st_context(ctx);
struct pipe_context *pipe = st->pipe;
- struct pipe_index_buffer ibuffer;
+ struct pipe_index_buffer ibuffer = {0};
struct pipe_draw_info info;
- unsigned i, num_instances = 1;
- GLboolean new_array =
- st->dirty.st &&
- (st->dirty.mesa & (_NEW_ARRAY | _NEW_PROGRAM | _NEW_BUFFER_OBJECT)) != 0;
+ const struct gl_client_array **arrays = ctx->Array._DrawArrays;
+ unsigned i;
+ GLboolean new_array;
/* Mesa core state should have been validated already */
assert(ctx->NewState == 0x0);
- if (ib) {
- /* Gallium probably doesn't want this in some cases. */
- if (!index_bounds_valid)
- if (!all_varyings_in_vbos(arrays))
- vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index);
+ /* Get Mesa driver state. */
+ st->dirty.st |= ctx->NewDriverState;
+ ctx->NewDriverState = 0;
- for (i = 0; i < nr_prims; i++) {
- num_instances = MAX2(num_instances, prims[i].num_instances);
- }
- }
- else {
- /* Get min/max index for non-indexed drawing. */
- min_index = ~0;
- max_index = 0;
-
- for (i = 0; i < nr_prims; i++) {
- min_index = MIN2(min_index, prims[i].start);
- max_index = MAX2(max_index, prims[i].start + prims[i].count - 1);
- num_instances = MAX2(num_instances, prims[i].num_instances);
- }
- }
+ new_array =
+ (st->dirty.st & (ST_NEW_VERTEX_ARRAYS | ST_NEW_VERTEX_PROGRAM)) ||
+ (st->dirty.mesa & (_NEW_PROGRAM | _NEW_BUFFER_OBJECT)) != 0;
/* Validate state. */
if (st->dirty.st) {
GLboolean vertDataEdgeFlags;
- /* sanity check for pointer arithmetic below */
- assert(sizeof(arrays[0]->Ptr[0]) == 1);
-
vertDataEdgeFlags = arrays[VERT_ATTRIB_EDGEFLAG]->BufferObj &&
arrays[VERT_ATTRIB_EDGEFLAG]->BufferObj->Name;
if (vertDataEdgeFlags != st->vertdata_edgeflags) {
st_validate_state(st);
if (new_array) {
- if (!st_validate_varrays(ctx, arrays, max_index, num_instances)) {
+ if (!st_validate_varrays(ctx, arrays)) {
/* probably out of memory, no-op the draw call */
return;
}
#endif
}
- /* Notify the driver that the content of user buffers may have been
- * changed. */
- assert(max_index >= min_index);
- if (!new_array && st->num_user_attribs) {
- for (i = 0; i < st->num_user_attribs; i++) {
- if (st->user_attrib[i].buffer) {
- unsigned element_size = st->user_attrib[i].element_size;
- unsigned stride = st->user_attrib[i].stride;
- unsigned min_offset = min_index * stride;
- unsigned max_offset = max_index * stride + element_size;
-
- assert(max_offset > min_offset);
-
- pipe->redefine_user_buffer(pipe, st->user_attrib[i].buffer,
- min_offset,
- max_offset - min_offset);
- }
- }
- }
-
- setup_index_buffer(ctx, ib, &ibuffer);
- pipe->set_index_buffer(pipe, &ibuffer);
-
util_draw_init_info(&info);
if (ib) {
+ /* Get index bounds for user buffers. */
+ if (!index_bounds_valid)
+ if (!all_varyings_in_vbos(arrays))
+ vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index,
+ nr_prims);
+
+ setup_index_buffer(st, ib, &ibuffer);
+
info.indexed = TRUE;
if (min_index != ~0 && max_index != ~0) {
info.min_index = min_index;
info.primitive_restart = ctx->Array.PrimitiveRestart;
info.restart_index = ctx->Array.RestartIndex;
}
+ else {
+ /* Transform feedback drawing is always non-indexed. */
+ /* Set info.count_from_stream_output. */
+ if (tfb_vertcount) {
+ st_transform_feedback_draw_init(tfb_vertcount, &info);
+ }
+ }
/* do actual drawing */
for (i = 0; i < nr_prims; i++) {
info.max_index = info.start + info.count - 1;
}
- if (info.primitive_restart) {
+ if (info.count_from_stream_output) {
+ cso_draw_vbo(st->cso_context, &info);
+ }
+ else if (info.primitive_restart) {
if (st->sw_primitive_restart) {
/* Handle primitive restart for drivers that doesn't support it */
- handle_fallback_primitive_restart(pipe, ib, &ibuffer, &info);
+ handle_fallback_primitive_restart(st->cso_context, pipe, ib,
+ &ibuffer, &info);
}
else {
/* don't trim, restarts might be inside index list */
- pipe->draw_vbo(pipe, &info);
+ cso_draw_vbo(st->cso_context, &info);
}
}
else if (u_trim_pipe_prim(info.mode, &info.count))
- pipe->draw_vbo(pipe, &info);
+ cso_draw_vbo(st->cso_context, &info);
}
- pipe_resource_reference(&ibuffer.buffer, NULL);
+ if (ib && st->indexbuf_uploader && !_mesa_is_bufferobj(ib->obj)) {
+ pipe_resource_reference(&ibuffer.buffer, NULL);
+ }
}