/** * Draw vertex arrays, with optional indexing, optional instancing. * All the other drawing functions are implemented in terms of this function. * Basically, map the vertex buffers (and drawing surfaces), then hand off * the drawing to the 'draw' module. */ static void llvmpipe_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) { struct llvmpipe_context *lp = llvmpipe_context(pipe); struct draw_context *draw = lp->draw; const void *mapped_indices = NULL; unsigned i; if (!llvmpipe_check_render_cond(lp)) return; if (lp->dirty) llvmpipe_update_derived( lp ); /* * Map vertex buffers */ for (i = 0; i < lp->num_vertex_buffers; i++) { const void *buf = lp->vertex_buffer[i].user_buffer; if (!buf) buf = llvmpipe_resource_data(lp->vertex_buffer[i].buffer); draw_set_mapped_vertex_buffer(draw, i, buf); } /* Map index buffer, if present */ if (info->indexed) { mapped_indices = lp->index_buffer.user_buffer; if (!mapped_indices) mapped_indices = llvmpipe_resource_data(lp->index_buffer.buffer); draw_set_indexes(draw, (ubyte *) mapped_indices + lp->index_buffer.offset, lp->index_buffer.index_size); } llvmpipe_prepare_vertex_sampling(lp, lp->num_sampler_views[PIPE_SHADER_VERTEX], lp->sampler_views[PIPE_SHADER_VERTEX]); /* draw! */ draw_vbo(draw, info); /* * unmap vertex/index buffers */ for (i = 0; i < lp->num_vertex_buffers; i++) { draw_set_mapped_vertex_buffer(draw, i, NULL); } if (mapped_indices) { draw_set_indexes(draw, NULL, 0); } llvmpipe_cleanup_vertex_sampling(lp); /* * TODO: Flush only when a user vertex/index buffer is present * (or even better, modify draw module to do this * internally when this condition is seen?) */ draw_flush(draw); }
static void i915_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) { struct i915_context *i915 = i915_context(pipe); struct draw_context *draw = i915->draw; const void *mapped_indices = NULL; /* * Ack vs contants here, helps ipers a lot. */ i915->dirty &= ~I915_NEW_VS_CONSTANTS; if (i915->dirty) i915_update_derived(i915); /* * Map index buffer, if present */ if (info->indexed) { mapped_indices = i915->index_buffer.user_buffer; if (!mapped_indices) mapped_indices = i915_buffer(i915->index_buffer.buffer)->data; draw_set_indexes(draw, (ubyte *) mapped_indices + i915->index_buffer.offset, i915->index_buffer.index_size); } if (i915->constants[PIPE_SHADER_VERTEX]) draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0, i915_buffer(i915->constants[PIPE_SHADER_VERTEX])->data, (i915->current.num_user_constants[PIPE_SHADER_VERTEX] * 4 * sizeof(float))); else draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0, NULL, 0); if (i915->num_vertex_sampler_views > 0) i915_prepare_vertex_sampling(i915); /* * Do the drawing */ draw_vbo(i915->draw, info); if (mapped_indices) draw_set_indexes(draw, NULL, 0); if (i915->num_vertex_sampler_views > 0) i915_cleanup_vertex_sampling(i915); /* * Instead of flushing on every state change, we flush once here * when we fire the vbo. */ draw_flush(i915->draw); }
enum pipe_error svga_swtnl_draw_vbo(struct svga_context *svga, const struct pipe_draw_info *info) { struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS]; struct pipe_transfer *ib_transfer = NULL; struct pipe_transfer *cb_transfer = NULL; struct draw_context *draw = svga->swtnl.draw; unsigned i; const void *map; enum pipe_error ret; assert(!svga->dirty); assert(svga->state.sw.need_swtnl); assert(draw); /* Make sure that the need_swtnl flag does not go away */ svga->state.sw.in_swtnl_draw = TRUE; ret = svga_update_state(svga, SVGA_STATE_SWTNL_DRAW); if (ret != PIPE_OK) { svga_context_flush(svga, NULL); ret = svga_update_state(svga, SVGA_STATE_SWTNL_DRAW); svga->swtnl.new_vbuf = TRUE; assert(ret == PIPE_OK); } /* * Map vertex buffers */ for (i = 0; i < svga->curr.num_vertex_buffers; i++) { if (svga->curr.vb[i].buffer) { map = pipe_buffer_map(&svga->pipe, svga->curr.vb[i].buffer, PIPE_TRANSFER_READ, &vb_transfer[i]); draw_set_mapped_vertex_buffer(draw, i, map); } } /* Map index buffer, if present */ map = NULL; if (info->indexed && svga->curr.ib.buffer) { map = pipe_buffer_map(&svga->pipe, svga->curr.ib.buffer, PIPE_TRANSFER_READ, &ib_transfer); draw_set_indexes(draw, (const ubyte *) map + svga->curr.ib.offset, svga->curr.ib.index_size); } if (svga->curr.cb[PIPE_SHADER_VERTEX]) { map = pipe_buffer_map(&svga->pipe, svga->curr.cb[PIPE_SHADER_VERTEX], PIPE_TRANSFER_READ, &cb_transfer); assert(map); draw_set_mapped_constant_buffer( draw, PIPE_SHADER_VERTEX, 0, map, svga->curr.cb[PIPE_SHADER_VERTEX]->width0); } draw_vbo(draw, info); draw_flush(svga->swtnl.draw); /* Ensure the draw module didn't touch this */ assert(i == svga->curr.num_vertex_buffers); /* * unmap vertex/index buffers */ for (i = 0; i < svga->curr.num_vertex_buffers; i++) { if (svga->curr.vb[i].buffer) { pipe_buffer_unmap(&svga->pipe, vb_transfer[i]); draw_set_mapped_vertex_buffer(draw, i, NULL); } } if (ib_transfer) { pipe_buffer_unmap(&svga->pipe, ib_transfer); draw_set_indexes(draw, NULL, 0); } if (svga->curr.cb[PIPE_SHADER_VERTEX]) { pipe_buffer_unmap(&svga->pipe, cb_transfer); } /* Now safe to remove the need_swtnl flag in any update_state call */ svga->state.sw.in_swtnl_draw = FALSE; svga->dirty |= SVGA_NEW_NEED_PIPELINE | SVGA_NEW_NEED_SWVFETCH; return ret; }
/** * Draw vertex arrays, with optional indexing, optional instancing. * All the other drawing functions are implemented in terms of this function. * Basically, map the vertex buffers (and drawing surfaces), then hand off * the drawing to the 'draw' module. */ static void llvmpipe_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) { struct llvmpipe_context *lp = llvmpipe_context(pipe); struct draw_context *draw = lp->draw; const void *mapped_indices = NULL; unsigned i; if (!llvmpipe_check_render_cond(lp)) return; if (info->indirect) { util_draw_indirect(pipe, info); return; } if (lp->dirty) llvmpipe_update_derived( lp ); /* * Map vertex buffers */ for (i = 0; i < lp->num_vertex_buffers; i++) { const void *buf = lp->vertex_buffer[i].is_user_buffer ? lp->vertex_buffer[i].buffer.user : NULL; size_t size = ~0; if (!buf) { if (!lp->vertex_buffer[i].buffer.resource) { continue; } buf = llvmpipe_resource_data(lp->vertex_buffer[i].buffer.resource); size = lp->vertex_buffer[i].buffer.resource->width0; } draw_set_mapped_vertex_buffer(draw, i, buf, size); } /* Map index buffer, if present */ if (info->index_size) { unsigned available_space = ~0; mapped_indices = info->has_user_indices ? info->index.user : NULL; if (!mapped_indices) { mapped_indices = llvmpipe_resource_data(info->index.resource); available_space = info->index.resource->width0; } draw_set_indexes(draw, (ubyte *) mapped_indices, info->index_size, available_space); } for (i = 0; i < lp->num_so_targets; i++) { void *buf = 0; if (lp->so_targets[i]) { buf = llvmpipe_resource(lp->so_targets[i]->target.buffer)->data; lp->so_targets[i]->mapping = buf; } } draw_set_mapped_so_targets(draw, lp->num_so_targets, lp->so_targets); llvmpipe_prepare_vertex_sampling(lp, lp->num_sampler_views[PIPE_SHADER_VERTEX], lp->sampler_views[PIPE_SHADER_VERTEX]); llvmpipe_prepare_geometry_sampling(lp, lp->num_sampler_views[PIPE_SHADER_GEOMETRY], lp->sampler_views[PIPE_SHADER_GEOMETRY]); if (lp->gs && lp->gs->no_tokens) { /* we have an empty geometry shader with stream output, so attach the stream output info to the current vertex shader */ if (lp->vs) { draw_vs_attach_so(lp->vs, &lp->gs->stream_output); } } draw_collect_pipeline_statistics(draw, lp->active_statistics_queries > 0); /* draw! */ draw_vbo(draw, info); /* * unmap vertex/index buffers */ for (i = 0; i < lp->num_vertex_buffers; i++) { draw_set_mapped_vertex_buffer(draw, i, NULL, 0); } if (mapped_indices) { draw_set_indexes(draw, NULL, 0, 0); } draw_set_mapped_so_targets(draw, 0, NULL); if (lp->gs && lp->gs->no_tokens) { /* we have attached stream output to the vs for rendering, now lets reset it */ if (lp->vs) { draw_vs_reset_so(lp->vs); } } /* * TODO: Flush only when a user vertex/index buffer is present * (or even better, modify draw module to do this * internally when this condition is seen?) */ draw_flush(draw); }
void nv30_render_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) { struct nv30_context *nv30 = nv30_context(pipe); struct draw_context *draw = nv30->draw; struct pipe_transfer *transfer[PIPE_MAX_ATTRIBS] = {NULL}; struct pipe_transfer *transferi = NULL; int i; nv30_render_validate(nv30); if (nv30->draw_dirty & NV30_NEW_VIEWPORT) draw_set_viewport_states(draw, 0, 1, &nv30->viewport); if (nv30->draw_dirty & NV30_NEW_RASTERIZER) draw_set_rasterizer_state(draw, &nv30->rast->pipe, NULL); if (nv30->draw_dirty & NV30_NEW_CLIP) draw_set_clip_state(draw, &nv30->clip); if (nv30->draw_dirty & NV30_NEW_ARRAYS) { draw_set_vertex_buffers(draw, 0, nv30->num_vtxbufs, nv30->vtxbuf); draw_set_vertex_elements(draw, nv30->vertex->num_elements, nv30->vertex->pipe); } if (nv30->draw_dirty & NV30_NEW_FRAGPROG) { struct nv30_fragprog *fp = nv30->fragprog.program; if (!fp->draw) fp->draw = draw_create_fragment_shader(draw, &fp->pipe); draw_bind_fragment_shader(draw, fp->draw); } if (nv30->draw_dirty & NV30_NEW_VERTPROG) { struct nv30_vertprog *vp = nv30->vertprog.program; if (!vp->draw) vp->draw = draw_create_vertex_shader(draw, &vp->pipe); draw_bind_vertex_shader(draw, vp->draw); } if (nv30->draw_dirty & NV30_NEW_VERTCONST) { if (nv30->vertprog.constbuf) { void *map = nv04_resource(nv30->vertprog.constbuf)->data; draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0, map, nv30->vertprog.constbuf_nr * 16); } else { draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0, NULL, 0); } } for (i = 0; i < nv30->num_vtxbufs; i++) { const void *map = nv30->vtxbuf[i].user_buffer; if (!map) { if (nv30->vtxbuf[i].buffer) map = pipe_buffer_map(pipe, nv30->vtxbuf[i].buffer, PIPE_TRANSFER_UNSYNCHRONIZED | PIPE_TRANSFER_READ, &transfer[i]); } draw_set_mapped_vertex_buffer(draw, i, map, ~0); } if (info->indexed) { const void *map = nv30->idxbuf.user_buffer; if (!map) map = pipe_buffer_map(pipe, nv30->idxbuf.buffer, PIPE_TRANSFER_UNSYNCHRONIZED | PIPE_TRANSFER_READ, &transferi); draw_set_indexes(draw, (ubyte *) map + nv30->idxbuf.offset, nv30->idxbuf.index_size, ~0); } else { draw_set_indexes(draw, NULL, 0, 0); } draw_vbo(draw, info); draw_flush(draw); if (info->indexed && transferi) pipe_buffer_unmap(pipe, transferi); for (i = 0; i < nv30->num_vtxbufs; i++) if (transfer[i]) pipe_buffer_unmap(pipe, transfer[i]); nv30->draw_dirty = 0; nv30_state_release(nv30); }
/** * 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 _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] = {NULL}; struct pipe_transfer *ib_transfer = NULL; const struct gl_client_array **arrays = ctx->Array._DrawArrays; 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; vbuffers[attr].user_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; /* 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); } else { vbuffers[attr].buffer = NULL; vbuffers[attr].user_buffer = arrays[mesaAttr]->Ptr; vbuffers[attr].buffer_offset = 0; velements[attr].src_offset = 0; draw_set_mapped_vertex_buffer(draw, attr, vbuffers[attr].user_buffer); } /* 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 } 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_indexes(draw, (ubyte *) mapped_indices + ibuffer.offset, ibuffer.index_size); } /* 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_indexes(draw, NULL, 0); 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++) { if (vb_transfer[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); }