1bf215546Sopenharmony_ci/************************************************************************** 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright 2011 VMware, Inc. 4bf215546Sopenharmony_ci * All Rights Reserved. 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 12bf215546Sopenharmony_ci * the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 16bf215546Sopenharmony_ci * of the Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci **************************************************************************/ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include "util/u_debug.h" 30bf215546Sopenharmony_ci#include "util/u_inlines.h" 31bf215546Sopenharmony_ci#include "util/u_math.h" 32bf215546Sopenharmony_ci#include "util/format/u_format.h" 33bf215546Sopenharmony_ci#include "util/u_draw.h" 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_ci/** 37bf215546Sopenharmony_ci * Returns the largest legal index value plus one for the current set 38bf215546Sopenharmony_ci * of bound vertex buffers. Regardless of any other consideration, 39bf215546Sopenharmony_ci * all vertex lookups need to be clamped to 0..max_index-1 to prevent 40bf215546Sopenharmony_ci * an out-of-bound access. 41bf215546Sopenharmony_ci * 42bf215546Sopenharmony_ci * Note that if zero is returned it means that one or more buffers is 43bf215546Sopenharmony_ci * too small to contain any valid vertex data. 44bf215546Sopenharmony_ci */ 45bf215546Sopenharmony_ciunsigned 46bf215546Sopenharmony_ciutil_draw_max_index( 47bf215546Sopenharmony_ci const struct pipe_vertex_buffer *vertex_buffers, 48bf215546Sopenharmony_ci const struct pipe_vertex_element *vertex_elements, 49bf215546Sopenharmony_ci unsigned nr_vertex_elements, 50bf215546Sopenharmony_ci const struct pipe_draw_info *info) 51bf215546Sopenharmony_ci{ 52bf215546Sopenharmony_ci unsigned max_index; 53bf215546Sopenharmony_ci unsigned i; 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci max_index = ~0U - 1; 56bf215546Sopenharmony_ci for (i = 0; i < nr_vertex_elements; i++) { 57bf215546Sopenharmony_ci const struct pipe_vertex_element *element = 58bf215546Sopenharmony_ci &vertex_elements[i]; 59bf215546Sopenharmony_ci const struct pipe_vertex_buffer *buffer = 60bf215546Sopenharmony_ci &vertex_buffers[element->vertex_buffer_index]; 61bf215546Sopenharmony_ci unsigned buffer_size; 62bf215546Sopenharmony_ci const struct util_format_description *format_desc; 63bf215546Sopenharmony_ci unsigned format_size; 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_ci if (buffer->is_user_buffer || !buffer->buffer.resource) { 66bf215546Sopenharmony_ci continue; 67bf215546Sopenharmony_ci } 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci assert(buffer->buffer.resource->height0 == 1); 70bf215546Sopenharmony_ci assert(buffer->buffer.resource->depth0 == 1); 71bf215546Sopenharmony_ci buffer_size = buffer->buffer.resource->width0; 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci format_desc = util_format_description(element->src_format); 74bf215546Sopenharmony_ci assert(format_desc->block.width == 1); 75bf215546Sopenharmony_ci assert(format_desc->block.height == 1); 76bf215546Sopenharmony_ci assert(format_desc->block.bits % 8 == 0); 77bf215546Sopenharmony_ci format_size = format_desc->block.bits/8; 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci if (buffer->buffer_offset >= buffer_size) { 80bf215546Sopenharmony_ci /* buffer is too small */ 81bf215546Sopenharmony_ci return 0; 82bf215546Sopenharmony_ci } 83bf215546Sopenharmony_ci 84bf215546Sopenharmony_ci buffer_size -= buffer->buffer_offset; 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_ci if (element->src_offset >= buffer_size) { 87bf215546Sopenharmony_ci /* buffer is too small */ 88bf215546Sopenharmony_ci return 0; 89bf215546Sopenharmony_ci } 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_ci buffer_size -= element->src_offset; 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci if (format_size > buffer_size) { 94bf215546Sopenharmony_ci /* buffer is too small */ 95bf215546Sopenharmony_ci return 0; 96bf215546Sopenharmony_ci } 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci buffer_size -= format_size; 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_ci if (buffer->stride != 0) { 101bf215546Sopenharmony_ci unsigned buffer_max_index; 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_ci buffer_max_index = buffer_size / buffer->stride; 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci if (element->instance_divisor == 0) { 106bf215546Sopenharmony_ci /* Per-vertex data */ 107bf215546Sopenharmony_ci max_index = MIN2(max_index, buffer_max_index); 108bf215546Sopenharmony_ci } 109bf215546Sopenharmony_ci else { 110bf215546Sopenharmony_ci /* Per-instance data. Simply make sure gallium frontends didn't 111bf215546Sopenharmony_ci * request more instances than those that fit in the buffer */ 112bf215546Sopenharmony_ci if ((info->start_instance + info->instance_count)/element->instance_divisor 113bf215546Sopenharmony_ci > (buffer_max_index + 1)) { 114bf215546Sopenharmony_ci /* FIXME: We really should stop thinking in terms of maximum 115bf215546Sopenharmony_ci * indices/instances and simply start clamping against buffer 116bf215546Sopenharmony_ci * size. */ 117bf215546Sopenharmony_ci debug_printf("%s: too many instances for vertex buffer\n", 118bf215546Sopenharmony_ci __FUNCTION__); 119bf215546Sopenharmony_ci return 0; 120bf215546Sopenharmony_ci } 121bf215546Sopenharmony_ci } 122bf215546Sopenharmony_ci } 123bf215546Sopenharmony_ci } 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_ci return max_index + 1; 126bf215546Sopenharmony_ci} 127bf215546Sopenharmony_ci 128bf215546Sopenharmony_cistruct u_indirect_params * 129bf215546Sopenharmony_ciutil_draw_indirect_read(struct pipe_context *pipe, 130bf215546Sopenharmony_ci const struct pipe_draw_info *info_in, 131bf215546Sopenharmony_ci const struct pipe_draw_indirect_info *indirect, 132bf215546Sopenharmony_ci unsigned *num_draws) 133bf215546Sopenharmony_ci{ 134bf215546Sopenharmony_ci struct pipe_transfer *transfer; 135bf215546Sopenharmony_ci uint32_t *params; 136bf215546Sopenharmony_ci struct u_indirect_params *draws; 137bf215546Sopenharmony_ci unsigned num_params = info_in->index_size ? 5 : 4; 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_ci assert(indirect); 140bf215546Sopenharmony_ci assert(!indirect->count_from_stream_output); 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_ci uint32_t draw_count = indirect->draw_count; 143bf215546Sopenharmony_ci if (indirect->indirect_draw_count) { 144bf215546Sopenharmony_ci struct pipe_transfer *dc_transfer; 145bf215546Sopenharmony_ci uint32_t *dc_param = pipe_buffer_map_range(pipe, 146bf215546Sopenharmony_ci indirect->indirect_draw_count, 147bf215546Sopenharmony_ci indirect->indirect_draw_count_offset, 148bf215546Sopenharmony_ci 4, PIPE_MAP_READ, &dc_transfer); 149bf215546Sopenharmony_ci if (!dc_transfer) { 150bf215546Sopenharmony_ci debug_printf("%s: failed to map indirect draw count buffer\n", __FUNCTION__); 151bf215546Sopenharmony_ci return NULL; 152bf215546Sopenharmony_ci } 153bf215546Sopenharmony_ci draw_count = dc_param[0]; 154bf215546Sopenharmony_ci pipe_buffer_unmap(pipe, dc_transfer); 155bf215546Sopenharmony_ci } 156bf215546Sopenharmony_ci if (!draw_count) { 157bf215546Sopenharmony_ci *num_draws = draw_count; 158bf215546Sopenharmony_ci return NULL; 159bf215546Sopenharmony_ci } 160bf215546Sopenharmony_ci draws = malloc(sizeof(struct u_indirect_params) * draw_count); 161bf215546Sopenharmony_ci if (!draws) 162bf215546Sopenharmony_ci return NULL; 163bf215546Sopenharmony_ci 164bf215546Sopenharmony_ci unsigned map_size = (draw_count - 1) * indirect->stride + (num_params * sizeof(uint32_t)); 165bf215546Sopenharmony_ci params = pipe_buffer_map_range(pipe, 166bf215546Sopenharmony_ci indirect->buffer, 167bf215546Sopenharmony_ci indirect->offset, 168bf215546Sopenharmony_ci map_size, 169bf215546Sopenharmony_ci PIPE_MAP_READ, 170bf215546Sopenharmony_ci &transfer); 171bf215546Sopenharmony_ci if (!transfer) { 172bf215546Sopenharmony_ci debug_printf("%s: failed to map indirect buffer\n", __FUNCTION__); 173bf215546Sopenharmony_ci free(draws); 174bf215546Sopenharmony_ci return NULL; 175bf215546Sopenharmony_ci } 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_ci for (unsigned i = 0; i < draw_count; i++) { 178bf215546Sopenharmony_ci memcpy(&draws[i].info, info_in, sizeof(struct pipe_draw_info)); 179bf215546Sopenharmony_ci draws[i].draw.count = params[0]; 180bf215546Sopenharmony_ci draws[i].info.instance_count = params[1]; 181bf215546Sopenharmony_ci draws[i].draw.start = params[2]; 182bf215546Sopenharmony_ci draws[i].draw.index_bias = info_in->index_size ? params[3] : 0; 183bf215546Sopenharmony_ci draws[i].info.start_instance = info_in->index_size ? params[4] : params[3]; 184bf215546Sopenharmony_ci params += indirect->stride / 4; 185bf215546Sopenharmony_ci } 186bf215546Sopenharmony_ci pipe_buffer_unmap(pipe, transfer); 187bf215546Sopenharmony_ci *num_draws = draw_count; 188bf215546Sopenharmony_ci return draws; 189bf215546Sopenharmony_ci} 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci/* This extracts the draw arguments from the indirect resource, 192bf215546Sopenharmony_ci * puts them into a new instance of pipe_draw_info, and calls draw_vbo on it. 193bf215546Sopenharmony_ci */ 194bf215546Sopenharmony_civoid 195bf215546Sopenharmony_ciutil_draw_indirect(struct pipe_context *pipe, 196bf215546Sopenharmony_ci const struct pipe_draw_info *info_in, 197bf215546Sopenharmony_ci const struct pipe_draw_indirect_info *indirect) 198bf215546Sopenharmony_ci{ 199bf215546Sopenharmony_ci struct pipe_draw_info info; 200bf215546Sopenharmony_ci struct pipe_transfer *transfer; 201bf215546Sopenharmony_ci uint32_t *params; 202bf215546Sopenharmony_ci unsigned num_params = info_in->index_size ? 5 : 4; 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_ci assert(indirect); 205bf215546Sopenharmony_ci assert(!indirect->count_from_stream_output); 206bf215546Sopenharmony_ci 207bf215546Sopenharmony_ci memcpy(&info, info_in, sizeof(info)); 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci uint32_t draw_count = indirect->draw_count; 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci if (indirect->indirect_draw_count) { 212bf215546Sopenharmony_ci struct pipe_transfer *dc_transfer; 213bf215546Sopenharmony_ci uint32_t *dc_param = pipe_buffer_map_range(pipe, 214bf215546Sopenharmony_ci indirect->indirect_draw_count, 215bf215546Sopenharmony_ci indirect->indirect_draw_count_offset, 216bf215546Sopenharmony_ci 4, PIPE_MAP_READ, &dc_transfer); 217bf215546Sopenharmony_ci if (!dc_transfer) { 218bf215546Sopenharmony_ci debug_printf("%s: failed to map indirect draw count buffer\n", __FUNCTION__); 219bf215546Sopenharmony_ci return; 220bf215546Sopenharmony_ci } 221bf215546Sopenharmony_ci if (dc_param[0] < draw_count) 222bf215546Sopenharmony_ci draw_count = dc_param[0]; 223bf215546Sopenharmony_ci pipe_buffer_unmap(pipe, dc_transfer); 224bf215546Sopenharmony_ci } 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci if (indirect->stride) 227bf215546Sopenharmony_ci num_params = MIN2(indirect->stride / 4, num_params); 228bf215546Sopenharmony_ci params = (uint32_t *) 229bf215546Sopenharmony_ci pipe_buffer_map_range(pipe, 230bf215546Sopenharmony_ci indirect->buffer, 231bf215546Sopenharmony_ci indirect->offset, 232bf215546Sopenharmony_ci (num_params * indirect->draw_count) * sizeof(uint32_t), 233bf215546Sopenharmony_ci PIPE_MAP_READ, 234bf215546Sopenharmony_ci &transfer); 235bf215546Sopenharmony_ci if (!transfer) { 236bf215546Sopenharmony_ci debug_printf("%s: failed to map indirect buffer\n", __FUNCTION__); 237bf215546Sopenharmony_ci return; 238bf215546Sopenharmony_ci } 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci for (unsigned i = 0; i < draw_count; i++) { 241bf215546Sopenharmony_ci struct pipe_draw_start_count_bias draw; 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci draw.count = params[0]; 244bf215546Sopenharmony_ci info.instance_count = params[1]; 245bf215546Sopenharmony_ci draw.start = params[2]; 246bf215546Sopenharmony_ci draw.index_bias = info_in->index_size ? params[3] : 0; 247bf215546Sopenharmony_ci info.start_instance = info_in->index_size ? params[4] : params[3]; 248bf215546Sopenharmony_ci 249bf215546Sopenharmony_ci pipe->draw_vbo(pipe, &info, i, NULL, &draw, 1); 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci params += indirect->stride / 4; 252bf215546Sopenharmony_ci } 253bf215546Sopenharmony_ci pipe_buffer_unmap(pipe, transfer); 254bf215546Sopenharmony_ci} 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_civoid 257bf215546Sopenharmony_ciutil_draw_multi(struct pipe_context *pctx, const struct pipe_draw_info *info, 258bf215546Sopenharmony_ci unsigned drawid_offset, 259bf215546Sopenharmony_ci const struct pipe_draw_indirect_info *indirect, 260bf215546Sopenharmony_ci const struct pipe_draw_start_count_bias *draws, 261bf215546Sopenharmony_ci unsigned num_draws) 262bf215546Sopenharmony_ci{ 263bf215546Sopenharmony_ci struct pipe_draw_info tmp_info = *info; 264bf215546Sopenharmony_ci unsigned drawid = drawid_offset; 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci /* If you call this with num_draws==1, that is probably going to be 267bf215546Sopenharmony_ci * an infinite loop 268bf215546Sopenharmony_ci */ 269bf215546Sopenharmony_ci assert(num_draws > 1); 270bf215546Sopenharmony_ci 271bf215546Sopenharmony_ci for (unsigned i = 0; i < num_draws; i++) { 272bf215546Sopenharmony_ci if (indirect || (draws[i].count && info->instance_count)) 273bf215546Sopenharmony_ci pctx->draw_vbo(pctx, &tmp_info, drawid, indirect, &draws[i], 1); 274bf215546Sopenharmony_ci if (tmp_info.increment_draw_id) 275bf215546Sopenharmony_ci drawid++; 276bf215546Sopenharmony_ci } 277bf215546Sopenharmony_ci} 278