1af69d88dSmrg/* 2af69d88dSmrg * Copyright (C) 2013 Rob Clark <robclark@freedesktop.org> 3af69d88dSmrg * 4af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 5af69d88dSmrg * copy of this software and associated documentation files (the "Software"), 6af69d88dSmrg * to deal in the Software without restriction, including without limitation 7af69d88dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8af69d88dSmrg * and/or sell copies of the Software, and to permit persons to whom the 9af69d88dSmrg * Software is furnished to do so, subject to the following conditions: 10af69d88dSmrg * 11af69d88dSmrg * The above copyright notice and this permission notice (including the next 12af69d88dSmrg * paragraph) shall be included in all copies or substantial portions of the 13af69d88dSmrg * Software. 14af69d88dSmrg * 15af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16af69d88dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17af69d88dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19af69d88dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20af69d88dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21af69d88dSmrg * SOFTWARE. 22af69d88dSmrg * 23af69d88dSmrg * Authors: 24af69d88dSmrg * Rob Clark <robclark@freedesktop.org> 25af69d88dSmrg */ 26af69d88dSmrg 27af69d88dSmrg/** 28af69d88dSmrg * This module converts provides a more convenient front-end to u_indices, 29af69d88dSmrg * etc, utils to convert primitive types supported not supported by the 30af69d88dSmrg * hardware. It handles binding new index buffer state, and restoring 31af69d88dSmrg * previous state after. To use, put something like this at the front of 32af69d88dSmrg * drivers pipe->draw_vbo(): 33af69d88dSmrg * 34af69d88dSmrg * // emulate unsupported primitives: 35af69d88dSmrg * if (info->mode needs emulating) { 36af69d88dSmrg * util_primconvert_save_rasterizer_state(ctx->primconvert, ctx->rasterizer); 37af69d88dSmrg * util_primconvert_draw_vbo(ctx->primconvert, info); 38af69d88dSmrg * return; 39af69d88dSmrg * } 40af69d88dSmrg * 41af69d88dSmrg */ 42af69d88dSmrg 43af69d88dSmrg#include "pipe/p_state.h" 44af69d88dSmrg#include "util/u_draw.h" 45af69d88dSmrg#include "util/u_inlines.h" 46af69d88dSmrg#include "util/u_memory.h" 477ec681f3Smrg#include "util/u_prim.h" 487ec681f3Smrg#include "util/u_prim_restart.h" 4901e04c3fSmrg#include "util/u_upload_mgr.h" 50af69d88dSmrg 51af69d88dSmrg#include "indices/u_indices.h" 52af69d88dSmrg#include "indices/u_primconvert.h" 53af69d88dSmrg 54af69d88dSmrgstruct primconvert_context 55af69d88dSmrg{ 56af69d88dSmrg struct pipe_context *pipe; 577ec681f3Smrg struct primconvert_config cfg; 58af69d88dSmrg unsigned api_pv; 59af69d88dSmrg}; 60af69d88dSmrg 61af69d88dSmrg 62af69d88dSmrgstruct primconvert_context * 637ec681f3Smrgutil_primconvert_create_config(struct pipe_context *pipe, 647ec681f3Smrg struct primconvert_config *cfg) 65af69d88dSmrg{ 66af69d88dSmrg struct primconvert_context *pc = CALLOC_STRUCT(primconvert_context); 67af69d88dSmrg if (!pc) 68af69d88dSmrg return NULL; 69af69d88dSmrg pc->pipe = pipe; 707ec681f3Smrg pc->cfg = *cfg; 71af69d88dSmrg return pc; 72af69d88dSmrg} 73af69d88dSmrg 747ec681f3Smrgstruct primconvert_context * 757ec681f3Smrgutil_primconvert_create(struct pipe_context *pipe, uint32_t primtypes_mask) 767ec681f3Smrg{ 777ec681f3Smrg struct primconvert_config cfg = { .primtypes_mask = primtypes_mask, .restart_primtypes_mask = primtypes_mask }; 787ec681f3Smrg return util_primconvert_create_config(pipe, &cfg); 797ec681f3Smrg} 807ec681f3Smrg 81af69d88dSmrgvoid 82af69d88dSmrgutil_primconvert_destroy(struct primconvert_context *pc) 83af69d88dSmrg{ 84af69d88dSmrg FREE(pc); 85af69d88dSmrg} 86af69d88dSmrg 87af69d88dSmrgvoid 88af69d88dSmrgutil_primconvert_save_rasterizer_state(struct primconvert_context *pc, 89af69d88dSmrg const struct pipe_rasterizer_state 90af69d88dSmrg *rast) 917ec681f3Smrg{ 927ec681f3Smrg util_primconvert_save_flatshade_first(pc, rast->flatshade_first); 937ec681f3Smrg} 947ec681f3Smrg 957ec681f3Smrgvoid 967ec681f3Smrgutil_primconvert_save_flatshade_first(struct primconvert_context *pc, bool flatshade_first) 97af69d88dSmrg{ 98af69d88dSmrg /* if we actually translated the provoking vertex for the buffer, 99af69d88dSmrg * we would actually need to save/restore rasterizer state. As 100af69d88dSmrg * it is, we just need to make note of the pv. 101af69d88dSmrg */ 1027ec681f3Smrg pc->api_pv = flatshade_first ? PV_FIRST : PV_LAST; 103af69d88dSmrg} 104af69d88dSmrg 105af69d88dSmrgvoid 106af69d88dSmrgutil_primconvert_draw_vbo(struct primconvert_context *pc, 1077ec681f3Smrg const struct pipe_draw_info *info, 1087ec681f3Smrg unsigned drawid_offset, 1097ec681f3Smrg const struct pipe_draw_indirect_info *indirect, 1107ec681f3Smrg const struct pipe_draw_start_count_bias *draws, 1117ec681f3Smrg unsigned num_draws) 112af69d88dSmrg{ 113af69d88dSmrg struct pipe_draw_info new_info; 1147ec681f3Smrg struct pipe_draw_start_count_bias new_draw; 1157ec681f3Smrg struct pipe_draw_start_count_bias *direct_draws = NULL; 1167ec681f3Smrg unsigned num_direct_draws = 0; 11701e04c3fSmrg struct pipe_transfer *src_transfer = NULL; 1187ec681f3Smrg u_translate_func trans_func, direct_draw_func; 119af69d88dSmrg u_generate_func gen_func; 12001e04c3fSmrg const void *src = NULL; 121af69d88dSmrg void *dst; 12201e04c3fSmrg unsigned ib_offset; 1237ec681f3Smrg unsigned total_index_count = draws->count; 1247ec681f3Smrg void *rewrite_buffer = NULL; 1257ec681f3Smrg 1267ec681f3Smrg if (indirect && indirect->buffer) { 1277ec681f3Smrg /* this is stupid, but we're already doing a readback, 1287ec681f3Smrg * so this thing may as well get the rest of the job done 1297ec681f3Smrg */ 1307ec681f3Smrg unsigned draw_count = 0; 1317ec681f3Smrg struct u_indirect_params *new_draws = util_draw_indirect_read(pc->pipe, info, indirect, &draw_count); 1327ec681f3Smrg if (!new_draws) 1337ec681f3Smrg return; 1347ec681f3Smrg 1357ec681f3Smrg for (unsigned i = 0; i < draw_count; i++) 1367ec681f3Smrg util_primconvert_draw_vbo(pc, &new_draws[i].info, drawid_offset + i, NULL, &new_draws[i].draw, 1); 1377ec681f3Smrg free(new_draws); 1387ec681f3Smrg return; 1397ec681f3Smrg } 1407ec681f3Smrg 1417ec681f3Smrg if (num_draws > 1) { 1427ec681f3Smrg unsigned drawid = drawid_offset; 1437ec681f3Smrg for (unsigned i = 0; i < num_draws; i++) { 1447ec681f3Smrg if (draws[i].count && info->instance_count) 1457ec681f3Smrg util_primconvert_draw_vbo(pc, info, drawid, NULL, &draws[i], 1); 1467ec681f3Smrg if (info->increment_draw_id) 1477ec681f3Smrg drawid++; 1487ec681f3Smrg } 1497ec681f3Smrg return; 1507ec681f3Smrg } 1517ec681f3Smrg 1527ec681f3Smrg const struct pipe_draw_start_count_bias *draw = &draws[0]; 1537ec681f3Smrg 1547ec681f3Smrg /* Filter out degenerate primitives, u_upload_alloc() will assert 1557ec681f3Smrg * on size==0 so just bail: 1567ec681f3Smrg */ 1577ec681f3Smrg if (!info->primitive_restart && 1587ec681f3Smrg !u_trim_pipe_prim(info->mode, (unsigned*)&draw->count)) 1597ec681f3Smrg return; 160af69d88dSmrg 161af69d88dSmrg util_draw_init_info(&new_info); 1627ec681f3Smrg new_info.index_bounds_valid = info->index_bounds_valid; 163af69d88dSmrg new_info.min_index = info->min_index; 164af69d88dSmrg new_info.max_index = info->max_index; 16501e04c3fSmrg new_info.start_instance = info->start_instance; 16601e04c3fSmrg new_info.instance_count = info->instance_count; 16701e04c3fSmrg new_info.primitive_restart = info->primitive_restart; 16801e04c3fSmrg new_info.restart_index = info->restart_index; 16901e04c3fSmrg if (info->index_size) { 1707ec681f3Smrg enum pipe_prim_type mode = new_info.mode = u_index_prim_type_convert(pc->cfg.primtypes_mask, info->mode, true); 1717ec681f3Smrg unsigned index_size = info->index_size; 1727ec681f3Smrg new_info.index_size = u_index_size_convert(info->index_size); 173af69d88dSmrg 17401e04c3fSmrg src = info->has_user_indices ? info->index.user : NULL; 175af69d88dSmrg if (!src) { 17601e04c3fSmrg src = pipe_buffer_map(pc->pipe, info->index.resource, 1777ec681f3Smrg PIPE_MAP_READ, &src_transfer); 178af69d88dSmrg } 17901e04c3fSmrg src = (const uint8_t *)src; 1807ec681f3Smrg 1817ec681f3Smrg /* if the resulting primitive type is not supported by the driver for primitive restart, 1827ec681f3Smrg * or if the original primitive type was not supported by the driver, 1837ec681f3Smrg * the draw needs to be rewritten to not use primitive restart 1847ec681f3Smrg */ 1857ec681f3Smrg if (info->primitive_restart && 1867ec681f3Smrg (!(pc->cfg.restart_primtypes_mask & BITFIELD_BIT(mode)) || 1877ec681f3Smrg !(pc->cfg.primtypes_mask & BITFIELD_BIT(info->mode)))) { 1887ec681f3Smrg /* step 1: rewrite draw to not use primitive primitive restart; 1897ec681f3Smrg * this pre-filters degenerate primitives 1907ec681f3Smrg */ 1917ec681f3Smrg direct_draws = util_prim_restart_convert_to_direct(src, info, draw, &num_direct_draws, 1927ec681f3Smrg &new_info.min_index, &new_info.max_index, &total_index_count); 1937ec681f3Smrg new_info.primitive_restart = false; 1947ec681f3Smrg /* step 2: get a translator function which does nothing but handle any index size conversions 1957ec681f3Smrg * which may or may not occur (8bit -> 16bit) 1967ec681f3Smrg */ 1977ec681f3Smrg u_index_translator(0xffff, 1987ec681f3Smrg info->mode, index_size, total_index_count, 1997ec681f3Smrg pc->api_pv, pc->api_pv, 2007ec681f3Smrg PR_DISABLE, 2017ec681f3Smrg &mode, &index_size, &new_draw.count, 2027ec681f3Smrg &direct_draw_func); 2037ec681f3Smrg /* this should always be a direct translation */ 2047ec681f3Smrg assert(new_draw.count == total_index_count); 2057ec681f3Smrg /* step 3: allocate a temp buffer for an intermediate rewrite step 2067ec681f3Smrg * if no indices were found, this was a single incomplete restart and can be discarded 2077ec681f3Smrg */ 2087ec681f3Smrg if (total_index_count) 2097ec681f3Smrg rewrite_buffer = malloc(index_size * total_index_count); 2107ec681f3Smrg if (!rewrite_buffer) { 2117ec681f3Smrg if (src_transfer) 2127ec681f3Smrg pipe_buffer_unmap(pc->pipe, src_transfer); 2137ec681f3Smrg return; 2147ec681f3Smrg } 2157ec681f3Smrg } 2167ec681f3Smrg /* (step 4: get the actual primitive conversion translator function) */ 2177ec681f3Smrg u_index_translator(pc->cfg.primtypes_mask, 2187ec681f3Smrg info->mode, index_size, total_index_count, 2197ec681f3Smrg pc->api_pv, pc->api_pv, 2207ec681f3Smrg new_info.primitive_restart ? PR_ENABLE : PR_DISABLE, 2217ec681f3Smrg &mode, &index_size, &new_draw.count, 2227ec681f3Smrg &trans_func); 2237ec681f3Smrg assert(new_info.mode == mode); 2247ec681f3Smrg assert(new_info.index_size == index_size); 225af69d88dSmrg } 226af69d88dSmrg else { 22701e04c3fSmrg enum pipe_prim_type mode = 0; 22801e04c3fSmrg unsigned index_size; 22901e04c3fSmrg 2307ec681f3Smrg u_index_generator(pc->cfg.primtypes_mask, 2317ec681f3Smrg info->mode, draw->start, draw->count, 232af69d88dSmrg pc->api_pv, pc->api_pv, 2337ec681f3Smrg &mode, &index_size, &new_draw.count, 234af69d88dSmrg &gen_func); 23501e04c3fSmrg new_info.mode = mode; 23601e04c3fSmrg new_info.index_size = index_size; 237af69d88dSmrg } 238af69d88dSmrg 2397ec681f3Smrg /* (step 5: allocate gpu memory sized for the FINAL index count) */ 2407ec681f3Smrg u_upload_alloc(pc->pipe->stream_uploader, 0, new_info.index_size * new_draw.count, 4, 24101e04c3fSmrg &ib_offset, &new_info.index.resource, &dst); 2427ec681f3Smrg new_draw.start = ib_offset / new_info.index_size; 2437ec681f3Smrg new_draw.index_bias = info->index_size ? draw->index_bias : 0; 244af69d88dSmrg 24501e04c3fSmrg if (info->index_size) { 2467ec681f3Smrg if (num_direct_draws) { 2477ec681f3Smrg uint8_t *ptr = rewrite_buffer; 2487ec681f3Smrg uint8_t *dst_ptr = dst; 2497ec681f3Smrg /* step 6: if rewriting a prim-restart draw to direct draws, 2507ec681f3Smrg * loop over all the direct draws in order to rewrite them into a single index buffer 2517ec681f3Smrg * and draw in order to match the original call 2527ec681f3Smrg */ 2537ec681f3Smrg for (unsigned i = 0; i < num_direct_draws; i++) { 2547ec681f3Smrg /* step 6a: get the index count for this draw, once converted */ 2557ec681f3Smrg unsigned tmp_count = u_index_count_converted_indices(pc->cfg.primtypes_mask, true, info->mode, direct_draws[i].count); 2567ec681f3Smrg /* step 6b: handle index size conversion using the temp buffer; no change in index count 2577ec681f3Smrg * TODO: this step can be optimized out if the index size is known to not change 2587ec681f3Smrg */ 2597ec681f3Smrg direct_draw_func(src, direct_draws[i].start, direct_draws[i].count, direct_draws[i].count, info->restart_index, ptr); 2607ec681f3Smrg /* step 6c: handle the primitive type conversion rewriting to the converted index count */ 2617ec681f3Smrg trans_func(ptr, 0, direct_draws[i].count, tmp_count, info->restart_index, dst_ptr); 2627ec681f3Smrg /* step 6d: increment the temp buffer and mapped final index buffer pointers */ 2637ec681f3Smrg ptr += new_info.index_size * direct_draws[i].count; 2647ec681f3Smrg dst_ptr += new_info.index_size * tmp_count; 2657ec681f3Smrg } 2667ec681f3Smrg /* step 7: set the final index count, which is the converted total index count from the original draw rewrite */ 2677ec681f3Smrg new_draw.count = u_index_count_converted_indices(pc->cfg.primtypes_mask, true, info->mode, total_index_count); 2687ec681f3Smrg } else 2697ec681f3Smrg trans_func(src, draw->start, draw->count, new_draw.count, info->restart_index, dst); 2707ec681f3Smrg 2717ec681f3Smrg if (pc->cfg.fixed_prim_restart && new_info.primitive_restart) { 2727ec681f3Smrg new_info.restart_index = (1ull << (new_info.index_size * 8)) - 1; 2737ec681f3Smrg if (info->restart_index != new_info.restart_index) 2747ec681f3Smrg util_translate_prim_restart_data(new_info.index_size, dst, dst, 2757ec681f3Smrg new_draw.count, 2767ec681f3Smrg info->restart_index); 2777ec681f3Smrg } 278af69d88dSmrg } 279af69d88dSmrg else { 2807ec681f3Smrg gen_func(draw->start, new_draw.count, dst); 281af69d88dSmrg } 282af69d88dSmrg 283af69d88dSmrg if (src_transfer) 284af69d88dSmrg pipe_buffer_unmap(pc->pipe, src_transfer); 285af69d88dSmrg 28601e04c3fSmrg u_upload_unmap(pc->pipe->stream_uploader); 287af69d88dSmrg 288af69d88dSmrg /* to the translated draw: */ 2897ec681f3Smrg pc->pipe->draw_vbo(pc->pipe, &new_info, drawid_offset, NULL, &new_draw, 1); 2907ec681f3Smrg free(direct_draws); 2917ec681f3Smrg free(rewrite_buffer); 292af69d88dSmrg 29301e04c3fSmrg pipe_resource_reference(&new_info.index.resource, NULL); 294af69d88dSmrg} 295