Path: blob/21.2-virgl/src/gallium/auxiliary/util/u_draw.c
4561 views
/**************************************************************************1*2* Copyright 2011 VMware, Inc.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/262728#include "util/u_debug.h"29#include "util/u_inlines.h"30#include "util/u_math.h"31#include "util/format/u_format.h"32#include "util/u_draw.h"333435/**36* Returns the largest legal index value plus one for the current set37* of bound vertex buffers. Regardless of any other consideration,38* all vertex lookups need to be clamped to 0..max_index-1 to prevent39* an out-of-bound access.40*41* Note that if zero is returned it means that one or more buffers is42* too small to contain any valid vertex data.43*/44unsigned45util_draw_max_index(46const struct pipe_vertex_buffer *vertex_buffers,47const struct pipe_vertex_element *vertex_elements,48unsigned nr_vertex_elements,49const struct pipe_draw_info *info)50{51unsigned max_index;52unsigned i;5354max_index = ~0U - 1;55for (i = 0; i < nr_vertex_elements; i++) {56const struct pipe_vertex_element *element =57&vertex_elements[i];58const struct pipe_vertex_buffer *buffer =59&vertex_buffers[element->vertex_buffer_index];60unsigned buffer_size;61const struct util_format_description *format_desc;62unsigned format_size;6364if (buffer->is_user_buffer || !buffer->buffer.resource) {65continue;66}6768assert(buffer->buffer.resource->height0 == 1);69assert(buffer->buffer.resource->depth0 == 1);70buffer_size = buffer->buffer.resource->width0;7172format_desc = util_format_description(element->src_format);73assert(format_desc->block.width == 1);74assert(format_desc->block.height == 1);75assert(format_desc->block.bits % 8 == 0);76format_size = format_desc->block.bits/8;7778if (buffer->buffer_offset >= buffer_size) {79/* buffer is too small */80return 0;81}8283buffer_size -= buffer->buffer_offset;8485if (element->src_offset >= buffer_size) {86/* buffer is too small */87return 0;88}8990buffer_size -= element->src_offset;9192if (format_size > buffer_size) {93/* buffer is too small */94return 0;95}9697buffer_size -= format_size;9899if (buffer->stride != 0) {100unsigned buffer_max_index;101102buffer_max_index = buffer_size / buffer->stride;103104if (element->instance_divisor == 0) {105/* Per-vertex data */106max_index = MIN2(max_index, buffer_max_index);107}108else {109/* Per-instance data. Simply make sure gallium frontends didn't110* request more instances than those that fit in the buffer */111if ((info->start_instance + info->instance_count)/element->instance_divisor112> (buffer_max_index + 1)) {113/* FIXME: We really should stop thinking in terms of maximum114* indices/instances and simply start clamping against buffer115* size. */116debug_printf("%s: too many instances for vertex buffer\n",117__FUNCTION__);118return 0;119}120}121}122}123124return max_index + 1;125}126127struct u_indirect_params *128util_draw_indirect_read(struct pipe_context *pipe,129const struct pipe_draw_info *info_in,130const struct pipe_draw_indirect_info *indirect,131unsigned *num_draws)132{133struct pipe_transfer *transfer;134uint32_t *params;135struct u_indirect_params *draws;136unsigned num_params = info_in->index_size ? 5 : 4;137138assert(indirect);139assert(!indirect->count_from_stream_output);140141uint32_t draw_count = indirect->draw_count;142if (indirect->indirect_draw_count) {143struct pipe_transfer *dc_transfer;144uint32_t *dc_param = pipe_buffer_map_range(pipe,145indirect->indirect_draw_count,146indirect->indirect_draw_count_offset,1474, PIPE_MAP_READ, &dc_transfer);148if (!dc_transfer) {149debug_printf("%s: failed to map indirect draw count buffer\n", __FUNCTION__);150return NULL;151}152if (dc_param[0] < draw_count)153draw_count = dc_param[0];154pipe_buffer_unmap(pipe, dc_transfer);155}156draws = malloc(sizeof(struct u_indirect_params) * draw_count);157if (!draws)158return NULL;159160if (indirect->stride)161num_params = MIN2(indirect->stride / 4, num_params);162params = pipe_buffer_map_range(pipe,163indirect->buffer,164indirect->offset,165(num_params * indirect->draw_count) * sizeof(uint32_t),166PIPE_MAP_READ,167&transfer);168if (!transfer) {169debug_printf("%s: failed to map indirect buffer\n", __FUNCTION__);170free(draws);171return NULL;172}173174for (unsigned i = 0; i < draw_count; i++) {175memcpy(&draws[i].info, info_in, sizeof(struct pipe_draw_info));176draws[i].draw.count = params[0];177draws[i].info.instance_count = params[1];178draws[i].draw.start = params[2];179draws[i].draw.index_bias = info_in->index_size ? params[3] : 0;180draws[i].info.start_instance = info_in->index_size ? params[4] : params[3];181params += indirect->stride / 4;182}183pipe_buffer_unmap(pipe, transfer);184*num_draws = draw_count;185return draws;186}187188/* This extracts the draw arguments from the indirect resource,189* puts them into a new instance of pipe_draw_info, and calls draw_vbo on it.190*/191void192util_draw_indirect(struct pipe_context *pipe,193const struct pipe_draw_info *info_in,194const struct pipe_draw_indirect_info *indirect)195{196struct pipe_draw_info info;197struct pipe_transfer *transfer;198uint32_t *params;199unsigned num_params = info_in->index_size ? 5 : 4;200201assert(indirect);202assert(!indirect->count_from_stream_output);203204memcpy(&info, info_in, sizeof(info));205206uint32_t draw_count = indirect->draw_count;207208if (indirect->indirect_draw_count) {209struct pipe_transfer *dc_transfer;210uint32_t *dc_param = pipe_buffer_map_range(pipe,211indirect->indirect_draw_count,212indirect->indirect_draw_count_offset,2134, PIPE_MAP_READ, &dc_transfer);214if (!dc_transfer) {215debug_printf("%s: failed to map indirect draw count buffer\n", __FUNCTION__);216return;217}218if (dc_param[0] < draw_count)219draw_count = dc_param[0];220pipe_buffer_unmap(pipe, dc_transfer);221}222223if (indirect->stride)224num_params = MIN2(indirect->stride / 4, num_params);225params = (uint32_t *)226pipe_buffer_map_range(pipe,227indirect->buffer,228indirect->offset,229(num_params * indirect->draw_count) * sizeof(uint32_t),230PIPE_MAP_READ,231&transfer);232if (!transfer) {233debug_printf("%s: failed to map indirect buffer\n", __FUNCTION__);234return;235}236237for (unsigned i = 0; i < draw_count; i++) {238struct pipe_draw_start_count_bias draw;239240draw.count = params[0];241info.instance_count = params[1];242draw.start = params[2];243draw.index_bias = info_in->index_size ? params[3] : 0;244info.start_instance = info_in->index_size ? params[4] : params[3];245246pipe->draw_vbo(pipe, &info, i, NULL, &draw, 1);247248params += indirect->stride / 4;249}250pipe_buffer_unmap(pipe, transfer);251}252253void254util_draw_multi(struct pipe_context *pctx, const struct pipe_draw_info *info,255unsigned drawid_offset,256const struct pipe_draw_indirect_info *indirect,257const struct pipe_draw_start_count_bias *draws,258unsigned num_draws)259{260struct pipe_draw_info tmp_info = *info;261unsigned drawid = drawid_offset;262263/* If you call this with num_draws==1, that is probably going to be264* an infinite loop265*/266assert(num_draws > 1);267268for (unsigned i = 0; i < num_draws; i++) {269if (indirect || (draws[i].count && info->instance_count))270pctx->draw_vbo(pctx, &tmp_info, drawid, indirect, &draws[i], 1);271if (tmp_info.increment_draw_id)272drawid++;273}274}275276277