13464ebd5Sriastradh/************************************************************************** 23464ebd5Sriastradh * 33464ebd5Sriastradh * Copyright 2011 VMware, Inc. 43464ebd5Sriastradh * All Rights Reserved. 53464ebd5Sriastradh * 63464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a 73464ebd5Sriastradh * copy of this software and associated documentation files (the 83464ebd5Sriastradh * "Software"), to deal in the Software without restriction, including 93464ebd5Sriastradh * without limitation the rights to use, copy, modify, merge, publish, 103464ebd5Sriastradh * distribute, sub license, and/or sell copies of the Software, and to 113464ebd5Sriastradh * permit persons to whom the Software is furnished to do so, subject to 123464ebd5Sriastradh * the following conditions: 133464ebd5Sriastradh * 143464ebd5Sriastradh * The above copyright notice and this permission notice (including the 153464ebd5Sriastradh * next paragraph) shall be included in all copies or substantial portions 163464ebd5Sriastradh * of the Software. 173464ebd5Sriastradh * 183464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 193464ebd5Sriastradh * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 203464ebd5Sriastradh * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 213464ebd5Sriastradh * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 223464ebd5Sriastradh * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 233464ebd5Sriastradh * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 243464ebd5Sriastradh * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 253464ebd5Sriastradh * 263464ebd5Sriastradh **************************************************************************/ 273464ebd5Sriastradh 283464ebd5Sriastradh 293464ebd5Sriastradh#include "util/u_debug.h" 30af69d88dSmrg#include "util/u_inlines.h" 313464ebd5Sriastradh#include "util/u_math.h" 327ec681f3Smrg#include "util/format/u_format.h" 333464ebd5Sriastradh#include "util/u_draw.h" 343464ebd5Sriastradh 353464ebd5Sriastradh 363464ebd5Sriastradh/** 37af69d88dSmrg * Returns the largest legal index value plus one for the current set 38af69d88dSmrg * of bound vertex buffers. Regardless of any other consideration, 39af69d88dSmrg * all vertex lookups need to be clamped to 0..max_index-1 to prevent 40af69d88dSmrg * an out-of-bound access. 41af69d88dSmrg * 42af69d88dSmrg * Note that if zero is returned it means that one or more buffers is 43af69d88dSmrg * too small to contain any valid vertex data. 443464ebd5Sriastradh */ 453464ebd5Sriastradhunsigned 463464ebd5Sriastradhutil_draw_max_index( 473464ebd5Sriastradh const struct pipe_vertex_buffer *vertex_buffers, 483464ebd5Sriastradh const struct pipe_vertex_element *vertex_elements, 493464ebd5Sriastradh unsigned nr_vertex_elements, 503464ebd5Sriastradh const struct pipe_draw_info *info) 513464ebd5Sriastradh{ 523464ebd5Sriastradh unsigned max_index; 533464ebd5Sriastradh unsigned i; 543464ebd5Sriastradh 55af69d88dSmrg max_index = ~0U - 1; 563464ebd5Sriastradh for (i = 0; i < nr_vertex_elements; i++) { 573464ebd5Sriastradh const struct pipe_vertex_element *element = 583464ebd5Sriastradh &vertex_elements[i]; 593464ebd5Sriastradh const struct pipe_vertex_buffer *buffer = 603464ebd5Sriastradh &vertex_buffers[element->vertex_buffer_index]; 613464ebd5Sriastradh unsigned buffer_size; 623464ebd5Sriastradh const struct util_format_description *format_desc; 633464ebd5Sriastradh unsigned format_size; 643464ebd5Sriastradh 6501e04c3fSmrg if (buffer->is_user_buffer || !buffer->buffer.resource) { 66af69d88dSmrg continue; 67af69d88dSmrg } 68af69d88dSmrg 6901e04c3fSmrg assert(buffer->buffer.resource->height0 == 1); 7001e04c3fSmrg assert(buffer->buffer.resource->depth0 == 1); 7101e04c3fSmrg buffer_size = buffer->buffer.resource->width0; 723464ebd5Sriastradh 733464ebd5Sriastradh format_desc = util_format_description(element->src_format); 743464ebd5Sriastradh assert(format_desc->block.width == 1); 753464ebd5Sriastradh assert(format_desc->block.height == 1); 763464ebd5Sriastradh assert(format_desc->block.bits % 8 == 0); 773464ebd5Sriastradh format_size = format_desc->block.bits/8; 783464ebd5Sriastradh 79af69d88dSmrg if (buffer->buffer_offset >= buffer_size) { 80af69d88dSmrg /* buffer is too small */ 81af69d88dSmrg return 0; 82af69d88dSmrg } 83af69d88dSmrg 843464ebd5Sriastradh buffer_size -= buffer->buffer_offset; 853464ebd5Sriastradh 86af69d88dSmrg if (element->src_offset >= buffer_size) { 87af69d88dSmrg /* buffer is too small */ 88af69d88dSmrg return 0; 89af69d88dSmrg } 90af69d88dSmrg 913464ebd5Sriastradh buffer_size -= element->src_offset; 923464ebd5Sriastradh 93af69d88dSmrg if (format_size > buffer_size) { 94af69d88dSmrg /* buffer is too small */ 95af69d88dSmrg return 0; 96af69d88dSmrg } 97af69d88dSmrg 983464ebd5Sriastradh buffer_size -= format_size; 993464ebd5Sriastradh 1003464ebd5Sriastradh if (buffer->stride != 0) { 1013464ebd5Sriastradh unsigned buffer_max_index; 1023464ebd5Sriastradh 1033464ebd5Sriastradh buffer_max_index = buffer_size / buffer->stride; 1043464ebd5Sriastradh 1053464ebd5Sriastradh if (element->instance_divisor == 0) { 1063464ebd5Sriastradh /* Per-vertex data */ 1073464ebd5Sriastradh max_index = MIN2(max_index, buffer_max_index); 1083464ebd5Sriastradh } 1093464ebd5Sriastradh else { 1107ec681f3Smrg /* Per-instance data. Simply make sure gallium frontends didn't 1113464ebd5Sriastradh * request more instances than those that fit in the buffer */ 112af69d88dSmrg if ((info->start_instance + info->instance_count)/element->instance_divisor 113af69d88dSmrg > (buffer_max_index + 1)) { 114af69d88dSmrg /* FIXME: We really should stop thinking in terms of maximum 115af69d88dSmrg * indices/instances and simply start clamping against buffer 116af69d88dSmrg * size. */ 117af69d88dSmrg debug_printf("%s: too many instances for vertex buffer\n", 118af69d88dSmrg __FUNCTION__); 119af69d88dSmrg return 0; 120af69d88dSmrg } 1213464ebd5Sriastradh } 1223464ebd5Sriastradh } 1233464ebd5Sriastradh } 1243464ebd5Sriastradh 125af69d88dSmrg return max_index + 1; 126af69d88dSmrg} 127af69d88dSmrg 1287ec681f3Smrgstruct u_indirect_params * 1297ec681f3Smrgutil_draw_indirect_read(struct pipe_context *pipe, 1307ec681f3Smrg const struct pipe_draw_info *info_in, 1317ec681f3Smrg const struct pipe_draw_indirect_info *indirect, 1327ec681f3Smrg unsigned *num_draws) 1337ec681f3Smrg{ 1347ec681f3Smrg struct pipe_transfer *transfer; 1357ec681f3Smrg uint32_t *params; 1367ec681f3Smrg struct u_indirect_params *draws; 1377ec681f3Smrg unsigned num_params = info_in->index_size ? 5 : 4; 1387ec681f3Smrg 1397ec681f3Smrg assert(indirect); 1407ec681f3Smrg assert(!indirect->count_from_stream_output); 1417ec681f3Smrg 1427ec681f3Smrg uint32_t draw_count = indirect->draw_count; 1437ec681f3Smrg if (indirect->indirect_draw_count) { 1447ec681f3Smrg struct pipe_transfer *dc_transfer; 1457ec681f3Smrg uint32_t *dc_param = pipe_buffer_map_range(pipe, 1467ec681f3Smrg indirect->indirect_draw_count, 1477ec681f3Smrg indirect->indirect_draw_count_offset, 1487ec681f3Smrg 4, PIPE_MAP_READ, &dc_transfer); 1497ec681f3Smrg if (!dc_transfer) { 1507ec681f3Smrg debug_printf("%s: failed to map indirect draw count buffer\n", __FUNCTION__); 1517ec681f3Smrg return NULL; 1527ec681f3Smrg } 1537ec681f3Smrg if (dc_param[0] < draw_count) 1547ec681f3Smrg draw_count = dc_param[0]; 1557ec681f3Smrg pipe_buffer_unmap(pipe, dc_transfer); 1567ec681f3Smrg } 1577ec681f3Smrg draws = malloc(sizeof(struct u_indirect_params) * draw_count); 1587ec681f3Smrg if (!draws) 1597ec681f3Smrg return NULL; 1607ec681f3Smrg 1617ec681f3Smrg if (indirect->stride) 1627ec681f3Smrg num_params = MIN2(indirect->stride / 4, num_params); 1637ec681f3Smrg params = pipe_buffer_map_range(pipe, 1647ec681f3Smrg indirect->buffer, 1657ec681f3Smrg indirect->offset, 1667ec681f3Smrg (num_params * indirect->draw_count) * sizeof(uint32_t), 1677ec681f3Smrg PIPE_MAP_READ, 1687ec681f3Smrg &transfer); 1697ec681f3Smrg if (!transfer) { 1707ec681f3Smrg debug_printf("%s: failed to map indirect buffer\n", __FUNCTION__); 1717ec681f3Smrg free(draws); 1727ec681f3Smrg return NULL; 1737ec681f3Smrg } 1747ec681f3Smrg 1757ec681f3Smrg for (unsigned i = 0; i < draw_count; i++) { 1767ec681f3Smrg memcpy(&draws[i].info, info_in, sizeof(struct pipe_draw_info)); 1777ec681f3Smrg draws[i].draw.count = params[0]; 1787ec681f3Smrg draws[i].info.instance_count = params[1]; 1797ec681f3Smrg draws[i].draw.start = params[2]; 1807ec681f3Smrg draws[i].draw.index_bias = info_in->index_size ? params[3] : 0; 1817ec681f3Smrg draws[i].info.start_instance = info_in->index_size ? params[4] : params[3]; 1827ec681f3Smrg params += indirect->stride / 4; 1837ec681f3Smrg } 1847ec681f3Smrg pipe_buffer_unmap(pipe, transfer); 1857ec681f3Smrg *num_draws = draw_count; 1867ec681f3Smrg return draws; 1877ec681f3Smrg} 188af69d88dSmrg 1897ec681f3Smrg/* This extracts the draw arguments from the indirect resource, 190af69d88dSmrg * puts them into a new instance of pipe_draw_info, and calls draw_vbo on it. 191af69d88dSmrg */ 192af69d88dSmrgvoid 193af69d88dSmrgutil_draw_indirect(struct pipe_context *pipe, 1947ec681f3Smrg const struct pipe_draw_info *info_in, 1957ec681f3Smrg const struct pipe_draw_indirect_info *indirect) 196af69d88dSmrg{ 197af69d88dSmrg struct pipe_draw_info info; 198af69d88dSmrg struct pipe_transfer *transfer; 199af69d88dSmrg uint32_t *params; 2007ec681f3Smrg unsigned num_params = info_in->index_size ? 5 : 4; 201af69d88dSmrg 2027ec681f3Smrg assert(indirect); 2037ec681f3Smrg assert(!indirect->count_from_stream_output); 204af69d88dSmrg 205af69d88dSmrg memcpy(&info, info_in, sizeof(info)); 206af69d88dSmrg 2077ec681f3Smrg uint32_t draw_count = indirect->draw_count; 2087ec681f3Smrg 2097ec681f3Smrg if (indirect->indirect_draw_count) { 2107ec681f3Smrg struct pipe_transfer *dc_transfer; 2117ec681f3Smrg uint32_t *dc_param = pipe_buffer_map_range(pipe, 2127ec681f3Smrg indirect->indirect_draw_count, 2137ec681f3Smrg indirect->indirect_draw_count_offset, 2147ec681f3Smrg 4, PIPE_MAP_READ, &dc_transfer); 2157ec681f3Smrg if (!dc_transfer) { 2167ec681f3Smrg debug_printf("%s: failed to map indirect draw count buffer\n", __FUNCTION__); 2177ec681f3Smrg return; 2187ec681f3Smrg } 2197ec681f3Smrg if (dc_param[0] < draw_count) 2207ec681f3Smrg draw_count = dc_param[0]; 2217ec681f3Smrg pipe_buffer_unmap(pipe, dc_transfer); 2227ec681f3Smrg } 2237ec681f3Smrg 2247ec681f3Smrg if (indirect->stride) 2257ec681f3Smrg num_params = MIN2(indirect->stride / 4, num_params); 226af69d88dSmrg params = (uint32_t *) 227af69d88dSmrg pipe_buffer_map_range(pipe, 2287ec681f3Smrg indirect->buffer, 2297ec681f3Smrg indirect->offset, 2307ec681f3Smrg (num_params * indirect->draw_count) * sizeof(uint32_t), 2317ec681f3Smrg PIPE_MAP_READ, 232af69d88dSmrg &transfer); 233af69d88dSmrg if (!transfer) { 234af69d88dSmrg debug_printf("%s: failed to map indirect buffer\n", __FUNCTION__); 235af69d88dSmrg return; 236af69d88dSmrg } 237af69d88dSmrg 2387ec681f3Smrg for (unsigned i = 0; i < draw_count; i++) { 2397ec681f3Smrg struct pipe_draw_start_count_bias draw; 2407ec681f3Smrg 2417ec681f3Smrg draw.count = params[0]; 2427ec681f3Smrg info.instance_count = params[1]; 2437ec681f3Smrg draw.start = params[2]; 2447ec681f3Smrg draw.index_bias = info_in->index_size ? params[3] : 0; 2457ec681f3Smrg info.start_instance = info_in->index_size ? params[4] : params[3]; 2467ec681f3Smrg 2477ec681f3Smrg pipe->draw_vbo(pipe, &info, i, NULL, &draw, 1); 248af69d88dSmrg 2497ec681f3Smrg params += indirect->stride / 4; 2507ec681f3Smrg } 251af69d88dSmrg pipe_buffer_unmap(pipe, transfer); 2527ec681f3Smrg} 253af69d88dSmrg 2547ec681f3Smrgvoid 2557ec681f3Smrgutil_draw_multi(struct pipe_context *pctx, const struct pipe_draw_info *info, 2567ec681f3Smrg unsigned drawid_offset, 2577ec681f3Smrg const struct pipe_draw_indirect_info *indirect, 2587ec681f3Smrg const struct pipe_draw_start_count_bias *draws, 2597ec681f3Smrg unsigned num_draws) 2607ec681f3Smrg{ 2617ec681f3Smrg struct pipe_draw_info tmp_info = *info; 2627ec681f3Smrg unsigned drawid = drawid_offset; 2637ec681f3Smrg 2647ec681f3Smrg /* If you call this with num_draws==1, that is probably going to be 2657ec681f3Smrg * an infinite loop 2667ec681f3Smrg */ 2677ec681f3Smrg assert(num_draws > 1); 2687ec681f3Smrg 2697ec681f3Smrg for (unsigned i = 0; i < num_draws; i++) { 2707ec681f3Smrg if (indirect || (draws[i].count && info->instance_count)) 2717ec681f3Smrg pctx->draw_vbo(pctx, &tmp_info, drawid, indirect, &draws[i], 1); 2727ec681f3Smrg if (tmp_info.increment_draw_id) 2737ec681f3Smrg drawid++; 2747ec681f3Smrg } 2753464ebd5Sriastradh} 276