summaryrefslogtreecommitdiff
path: root/src/mesa/state_tracker/st_draw.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/state_tracker/st_draw.c')
-rw-r--r--src/mesa/state_tracker/st_draw.c283
1 files changed, 235 insertions, 48 deletions
diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c
index e1bc108eae..bdf8648ef7 100644
--- a/src/mesa/state_tracker/st_draw.c
+++ b/src/mesa/state_tracker/st_draw.c
@@ -32,6 +32,7 @@
#include "main/imports.h"
#include "main/image.h"
+#include "main/macros.h"
#include "vbo/vbo.h"
@@ -228,7 +229,7 @@ setup_edgeflags(GLcontext *ctx, GLenum primMode, GLint start, GLint count,
if (!vec)
return NULL;
- map = pipe_buffer_map(pipe, stobj->buffer, PIPE_BUFFER_USAGE_CPU_READ);
+ map = pipe_buffer_map(pipe->screen, stobj->buffer, PIPE_BUFFER_USAGE_CPU_READ);
map = ADD_POINTERS(map, array->Ptr);
for (i = 0; i < count; i++) {
@@ -238,7 +239,7 @@ setup_edgeflags(GLcontext *ctx, GLenum primMode, GLint start, GLint count,
map += array->StrideB;
}
- pipe_buffer_unmap(pipe, stobj->buffer);
+ pipe_buffer_unmap(pipe->screen, stobj->buffer);
pipe->set_edgeflags(pipe, vec);
@@ -252,40 +253,170 @@ setup_edgeflags(GLcontext *ctx, GLenum primMode, GLint start, GLint count,
}
+/**
+ * Examine the active arrays to determine if we have interleaved
+ * vertex arrays all living in one VBO, or all living in user space.
+ * \param userSpace returns whether the arrays are in user space.
+ */
+static GLboolean
+is_interleaved_arrays(const struct st_vertex_program *vp,
+ const struct gl_client_array **arrays,
+ GLboolean *userSpace)
+{
+ GLuint attr;
+ const struct gl_buffer_object *firstBufObj = NULL;
+ GLint firstStride = -1;
+ GLuint num_client_arrays = 0;
+ const GLubyte *client_addr = NULL;
+
+ for (attr = 0; attr < vp->num_inputs; attr++) {
+ const GLuint mesaAttr = vp->index_to_input[attr];
+ const struct gl_buffer_object *bufObj = arrays[mesaAttr]->BufferObj;
+ const GLsizei stride = arrays[mesaAttr]->StrideB; /* in bytes */
+
+ if (firstStride < 0) {
+ firstStride = stride;
+ }
+ else if (firstStride != stride) {
+ return GL_FALSE;
+ }
+
+ if (!bufObj || !bufObj->Name) {
+ num_client_arrays++;
+ /* Try to detect if the client-space arrays are
+ * "close" to each other.
+ */
+ if (!client_addr) {
+ client_addr = arrays[mesaAttr]->Ptr;
+ }
+ else if (abs(arrays[mesaAttr]->Ptr - client_addr) > firstStride) {
+ /* arrays start too far apart */
+ return GL_FALSE;
+ }
+ }
+ else if (!firstBufObj) {
+ firstBufObj = bufObj;
+ }
+ else if (bufObj != firstBufObj) {
+ return GL_FALSE;
+ }
+ }
+
+ *userSpace = (num_client_arrays == vp->num_inputs);
+ /*printf("user space: %d\n", (int) *userSpace);*/
+
+ return GL_TRUE;
+}
+
/**
- * This function gets plugged into the VBO module and is called when
- * we have something to render.
- * Basically, translate the information into the format expected by pipe.
+ * Once we know all the arrays are in user space, this function
+ * computes the memory range occupied by the arrays.
*/
-void
-st_draw_vbo(GLcontext *ctx,
- const struct gl_client_array **arrays,
- const struct _mesa_prim *prims,
- GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
- GLuint min_index,
- GLuint max_index)
+static void
+get_user_arrays_bounds(const struct st_vertex_program *vp,
+ const struct gl_client_array **arrays,
+ GLuint max_index,
+ const GLubyte **low, const GLubyte **high)
+{
+ const GLubyte *low_addr = NULL;
+ GLuint attr;
+ GLint stride;
+
+ for (attr = 0; attr < vp->num_inputs; attr++) {
+ const GLuint mesaAttr = vp->index_to_input[attr];
+ const GLubyte *start = arrays[mesaAttr]->Ptr;
+ stride = arrays[mesaAttr]->StrideB;
+ if (attr == 0) {
+ low_addr = start;
+ }
+ else {
+ low_addr = MIN2(low_addr, start);
+ }
+ }
+
+ *low = low_addr;
+ *high = low_addr + (max_index + 1) * stride;
+}
+
+
+/**
+ * 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 void
+setup_interleaved_attribs(GLcontext *ctx,
+ const struct st_vertex_program *vp,
+ const struct gl_client_array **arrays,
+ GLuint max_index,
+ GLboolean userSpace,
+ struct pipe_vertex_buffer *vbuffer,
+ struct pipe_vertex_element velements[])
{
struct pipe_context *pipe = ctx->st->pipe;
- const struct st_vertex_program *vp;
- const struct pipe_shader_state *vs;
- struct pipe_vertex_buffer vbuffer[PIPE_MAX_SHADER_INPUTS];
GLuint attr;
- struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS];
+ const GLubyte *offset0;
- /* sanity check for pointer arithmetic below */
- assert(sizeof(arrays[0]->Ptr[0]) == 1);
+ for (attr = 0; attr < vp->num_inputs; attr++) {
+ const GLuint mesaAttr = vp->index_to_input[attr];
+ struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj;
+ struct st_buffer_object *stobj = st_buffer_object(bufobj);
+ GLsizei stride = arrays[mesaAttr]->StrideB;
- st_validate_state(ctx->st);
+ /*printf("stobj %u = %p\n", attr, (void*)stobj);*/
+
+ if (attr == 0) {
+ if (userSpace) {
+ const GLubyte *low, *high;
+ get_user_arrays_bounds(vp, arrays, max_index, &low, &high);
+ /*printf("user buffer range: %p %p %d\n", low, high, high-low);*/
+ vbuffer->buffer =
+ pipe_user_buffer_create(pipe->screen, (void *) low, high - low);
+ vbuffer->buffer_offset = 0;
+ offset0 = low;
+ }
+ else {
+ vbuffer->buffer = NULL;
+ pipe_buffer_reference(pipe->screen, &vbuffer->buffer, stobj->buffer);
+ vbuffer->buffer_offset = (unsigned) arrays[mesaAttr]->Ptr;
+ offset0 = arrays[mesaAttr]->Ptr;
+ }
+ vbuffer->pitch = stride; /* in bytes */
+ vbuffer->max_index = max_index;
+ }
- /* must get these after state validation! */
- vp = ctx->st->vp;
- vs = &ctx->st->vp->state;
+ velements[attr].src_offset =
+ (unsigned) (arrays[mesaAttr]->Ptr - offset0);
+ velements[attr].vertex_buffer_index = 0;
+ velements[attr].nr_components = arrays[mesaAttr]->Size;
+ velements[attr].src_format =
+ pipe_vertex_format(arrays[mesaAttr]->Type,
+ arrays[mesaAttr]->Size,
+ arrays[mesaAttr]->Normalized);
+ assert(velements[attr].src_format);
+ }
+}
+
+
+/**
+ * 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 void
+setup_non_interleaved_attribs(GLcontext *ctx,
+ const struct st_vertex_program *vp,
+ const struct gl_client_array **arrays,
+ GLuint max_index,
+ struct pipe_vertex_buffer vbuffer[],
+ struct pipe_vertex_element velements[])
+{
+ struct pipe_context *pipe = ctx->st->pipe;
+ GLuint attr;
- /* 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;
@@ -298,15 +429,17 @@ st_draw_vbo(GLcontext *ctx,
*/
struct st_buffer_object *stobj = st_buffer_object(bufobj);
assert(stobj->buffer);
+ /*printf("stobj %u = %p\n", attr, (void*) stobj);*/
vbuffer[attr].buffer = NULL;
- pipe_reference_buffer(pipe, &vbuffer[attr].buffer, stobj->buffer);
+ pipe_buffer_reference(pipe->screen, &vbuffer[attr].buffer, stobj->buffer);
vbuffer[attr].buffer_offset = (unsigned) arrays[mesaAttr]->Ptr;
velements[attr].src_offset = 0;
}
else {
/* attribute data is in user-space memory, not a VBO */
uint bytes;
+ /*printf("user-space array %d stride %d\n", attr, stride);*/
/* wrap user data */
if (arrays[mesaAttr]->Ptr) {
@@ -318,13 +451,13 @@ st_draw_vbo(GLcontext *ctx,
bytes = arrays[mesaAttr]->Size
* _mesa_sizeof_type(arrays[mesaAttr]->Type);
}
- vbuffer[attr].buffer = pipe_user_buffer_create(pipe,
+ vbuffer[attr].buffer = pipe_user_buffer_create(pipe->screen,
(void *) arrays[mesaAttr]->Ptr, bytes);
}
else {
/* no array, use ctx->Current.Attrib[] value */
bytes = sizeof(ctx->Current.Attrib[0]);
- vbuffer[attr].buffer = pipe_user_buffer_create(pipe,
+ vbuffer[attr].buffer = pipe_user_buffer_create(pipe->screen,
(void *) ctx->Current.Attrib[mesaAttr], bytes);
stride = 0;
}
@@ -346,27 +479,81 @@ st_draw_vbo(GLcontext *ctx,
arrays[mesaAttr]->Normalized);
assert(velements[attr].src_format);
}
+}
+
+
+
+
+/**
+ * This function gets plugged into the VBO module and is called when
+ * we have something to render.
+ * Basically, translate the information into the format expected by gallium.
+ */
+void
+st_draw_vbo(GLcontext *ctx,
+ const struct gl_client_array **arrays,
+ const struct _mesa_prim *prims,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ GLuint min_index,
+ GLuint max_index)
+{
+ struct pipe_context *pipe = ctx->st->pipe;
+ const struct st_vertex_program *vp;
+ const struct pipe_shader_state *vs;
+ struct pipe_vertex_buffer vbuffer[PIPE_MAX_SHADER_INPUTS];
+ GLuint attr;
+ struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS];
+ unsigned num_vbuffers, num_velements;
+ GLboolean userSpace;
+
+ /* sanity check for pointer arithmetic below */
+ assert(sizeof(arrays[0]->Ptr[0]) == 1);
+
+ st_validate_state(ctx->st);
+
+ /* must get these after state validation! */
+ vp = ctx->st->vp;
+ vs = &ctx->st->vp->state;
+
+ /*
+ * Setup the vbuffer[] and velements[] arrays.
+ */
+ if (is_interleaved_arrays(vp, arrays, &userSpace)) {
+ /*printf("Draw interleaved\n");*/
+ setup_interleaved_attribs(ctx, vp, arrays, max_index, userSpace,
+ vbuffer, velements);
+ num_vbuffers = 1;
+ num_velements = vp->num_inputs;
+ }
+ else {
+ /*printf("Draw non-interleaved\n");*/
+ setup_non_interleaved_attribs(ctx, vp, arrays, max_index,
+ vbuffer, velements);
+ num_vbuffers = vp->num_inputs;
+ num_velements = vp->num_inputs;
+ }
#if 0
{
GLuint i;
- for (i = 0; i < vp->num_inputs; i++) {
+ for (i = 0; i < num_vbuffers; i++) {
printf("buffers[%d].pitch = %u\n", i, vbuffer[i].pitch);
printf("buffers[%d].max_index = %u\n", i, vbuffer[i].max_index);
printf("buffers[%d].buffer_offset = %u\n", i, vbuffer[i].buffer_offset);
printf("buffers[%d].buffer = %p\n", i, (void*) vbuffer[i].buffer);
}
- for (i = 0; i < vp->num_inputs; i++) {
- printf("vlements[%d].src_offset = %u\n", i, velements[i].src_offset);
+ for (i = 0; i < num_velements; i++) {
printf("vlements[%d].vbuffer_index = %u\n", i, velements[i].vertex_buffer_index);
+ printf("vlements[%d].src_offset = %u\n", i, velements[i].src_offset);
printf("vlements[%d].nr_comps = %u\n", i, velements[i].nr_components);
printf("vlements[%d].format = %s\n", i, pf_name(velements[i].src_format));
}
}
#endif
- pipe->set_vertex_buffers(pipe, vp->num_inputs, vbuffer);
- pipe->set_vertex_elements(pipe, vp->num_inputs, velements);
+ pipe->set_vertex_buffers(pipe, num_vbuffers, vbuffer);
+ pipe->set_vertex_elements(pipe, num_velements, velements);
/* do actual drawing */
if (ib) {
@@ -394,12 +581,12 @@ st_draw_vbo(GLcontext *ctx,
if (bufobj && bufobj->Name) {
/* elements/indexes are in a real VBO */
struct st_buffer_object *stobj = st_buffer_object(bufobj);
- pipe_reference_buffer(pipe, &indexBuf, stobj->buffer);
+ pipe_buffer_reference(pipe->screen, &indexBuf, stobj->buffer);
indexOffset = (unsigned) ib->ptr / indexSize;
}
else {
/* element/indicies are in user space memory */
- indexBuf = pipe_user_buffer_create(pipe, (void *) ib->ptr,
+ indexBuf = pipe_user_buffer_create(pipe->screen, (void *) ib->ptr,
ib->count * indexSize);
indexOffset = 0;
}
@@ -434,7 +621,7 @@ st_draw_vbo(GLcontext *ctx,
}
}
- pipe_reference_buffer(pipe, &indexBuf, NULL);
+ pipe_buffer_reference(pipe->screen, &indexBuf, NULL);
}
else {
/* non-indexed */
@@ -449,8 +636,8 @@ st_draw_vbo(GLcontext *ctx,
}
/* unreference buffers (frees wrapped user-space buffer objects) */
- for (attr = 0; attr < vp->num_inputs; attr++) {
- pipe_reference_buffer(pipe, &vbuffer[attr].buffer, NULL);
+ for (attr = 0; attr < num_vbuffers; attr++) {
+ pipe_buffer_reference(pipe->screen, &vbuffer[attr].buffer, NULL);
assert(!vbuffer[attr].buffer);
}
pipe->set_vertex_buffers(pipe, vp->num_inputs, vbuffer);
@@ -563,7 +750,7 @@ st_feedback_draw_vbo(GLcontext *ctx,
assert(stobj->buffer);
vbuffers[attr].buffer = NULL;
- pipe_reference_buffer(pipe, &vbuffers[attr].buffer, stobj->buffer);
+ pipe_buffer_reference(pipe->screen, &vbuffers[attr].buffer, stobj->buffer);
vbuffers[attr].buffer_offset = (unsigned) arrays[0]->Ptr;/* in bytes */
velements[attr].src_offset = arrays[mesaAttr]->Ptr - arrays[0]->Ptr;
}
@@ -575,7 +762,7 @@ st_feedback_draw_vbo(GLcontext *ctx,
/* wrap user data */
vbuffers[attr].buffer
- = pipe_user_buffer_create(pipe, (void *) arrays[mesaAttr]->Ptr,
+ = pipe_user_buffer_create(pipe->screen, (void *) arrays[mesaAttr]->Ptr,
bytes);
vbuffers[attr].buffer_offset = 0;
velements[attr].src_offset = 0;
@@ -597,7 +784,7 @@ st_feedback_draw_vbo(GLcontext *ctx,
#endif
/* map the attrib buffer */
- map = pipe_buffer_map(pipe, vbuffers[attr].buffer,
+ map = pipe_buffer_map(pipe->screen, vbuffers[attr].buffer,
PIPE_BUFFER_USAGE_CPU_READ);
draw_set_mapped_vertex_buffer(draw, attr, map);
}
@@ -625,7 +812,7 @@ st_feedback_draw_vbo(GLcontext *ctx,
return;
}
- map = pipe_buffer_map(pipe, index_buffer_handle,
+ map = pipe_buffer_map(pipe->screen, index_buffer_handle,
PIPE_BUFFER_USAGE_CPU_READ);
draw_set_mapped_element_buffer(draw, indexSize, map);
}
@@ -636,7 +823,7 @@ st_feedback_draw_vbo(GLcontext *ctx,
/* map constant buffers */
- mapped_constants = pipe_buffer_map(pipe,
+ 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,
@@ -650,20 +837,20 @@ st_feedback_draw_vbo(GLcontext *ctx,
/* unmap constant buffers */
- pipe_buffer_unmap(pipe, st->state.constants[PIPE_SHADER_VERTEX].buffer);
+ 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, draw->pt.vertex_buffer[i].buffer);
- pipe_reference_buffer(pipe, &draw->pt.vertex_buffer[i].buffer, NULL);
+ pipe_buffer_unmap(pipe->screen, draw->pt.vertex_buffer[i].buffer);
+ pipe_buffer_reference(pipe->screen, &draw->pt.vertex_buffer[i].buffer, NULL);
draw_set_mapped_vertex_buffer(draw, i, NULL);
}
}
if (ib) {
- pipe_buffer_unmap(pipe, index_buffer_handle);
+ pipe_buffer_unmap(pipe->screen, index_buffer_handle);
draw_set_mapped_element_buffer(draw, 0, NULL);
}
}