Path: blob/21.2-virgl/src/gallium/auxiliary/indices/u_primconvert.c
4565 views
/*1* Copyright (C) 2013 Rob Clark <[email protected]>2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,19* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20* SOFTWARE.21*22* Authors:23* Rob Clark <[email protected]>24*/2526/**27* This module converts provides a more convenient front-end to u_indices,28* etc, utils to convert primitive types supported not supported by the29* hardware. It handles binding new index buffer state, and restoring30* previous state after. To use, put something like this at the front of31* drivers pipe->draw_vbo():32*33* // emulate unsupported primitives:34* if (info->mode needs emulating) {35* util_primconvert_save_rasterizer_state(ctx->primconvert, ctx->rasterizer);36* util_primconvert_draw_vbo(ctx->primconvert, info);37* return;38* }39*40*/4142#include "pipe/p_state.h"43#include "util/u_draw.h"44#include "util/u_inlines.h"45#include "util/u_memory.h"46#include "util/u_prim.h"47#include "util/u_prim_restart.h"48#include "util/u_upload_mgr.h"4950#include "indices/u_indices.h"51#include "indices/u_primconvert.h"5253struct primconvert_context54{55struct pipe_context *pipe;56struct primconvert_config cfg;57unsigned api_pv;58};596061struct primconvert_context *62util_primconvert_create_config(struct pipe_context *pipe,63struct primconvert_config *cfg)64{65struct primconvert_context *pc = CALLOC_STRUCT(primconvert_context);66if (!pc)67return NULL;68pc->pipe = pipe;69pc->cfg = *cfg;70return pc;71}7273struct primconvert_context *74util_primconvert_create(struct pipe_context *pipe, uint32_t primtypes_mask)75{76struct primconvert_config cfg = { .primtypes_mask = primtypes_mask, .restart_primtypes_mask = primtypes_mask };77return util_primconvert_create_config(pipe, &cfg);78}7980void81util_primconvert_destroy(struct primconvert_context *pc)82{83FREE(pc);84}8586void87util_primconvert_save_rasterizer_state(struct primconvert_context *pc,88const struct pipe_rasterizer_state89*rast)90{91util_primconvert_save_flatshade_first(pc, rast->flatshade_first);92}9394void95util_primconvert_save_flatshade_first(struct primconvert_context *pc, bool flatshade_first)96{97/* if we actually translated the provoking vertex for the buffer,98* we would actually need to save/restore rasterizer state. As99* it is, we just need to make note of the pv.100*/101pc->api_pv = flatshade_first ? PV_FIRST : PV_LAST;102}103104void105util_primconvert_draw_vbo(struct primconvert_context *pc,106const struct pipe_draw_info *info,107unsigned drawid_offset,108const struct pipe_draw_indirect_info *indirect,109const struct pipe_draw_start_count_bias *draws,110unsigned num_draws)111{112struct pipe_draw_info new_info;113struct pipe_draw_start_count_bias new_draw;114struct pipe_draw_start_count_bias *direct_draws = NULL;115unsigned num_direct_draws = 0;116struct pipe_transfer *src_transfer = NULL;117u_translate_func trans_func, direct_draw_func;118u_generate_func gen_func;119const void *src = NULL;120void *dst;121unsigned ib_offset;122unsigned total_index_count = draws->count;123void *rewrite_buffer = NULL;124125if (indirect && indirect->buffer) {126/* this is stupid, but we're already doing a readback,127* so this thing may as well get the rest of the job done128*/129unsigned draw_count = 0;130struct u_indirect_params *new_draws = util_draw_indirect_read(pc->pipe, info, indirect, &draw_count);131if (!new_draws)132return;133134for (unsigned i = 0; i < draw_count; i++)135util_primconvert_draw_vbo(pc, &new_draws[i].info, drawid_offset + i, NULL, &new_draws[i].draw, 1);136free(new_draws);137return;138}139140if (num_draws > 1) {141unsigned drawid = drawid_offset;142for (unsigned i = 0; i < num_draws; i++) {143if (draws[i].count && info->instance_count)144util_primconvert_draw_vbo(pc, info, drawid, NULL, &draws[i], 1);145if (info->increment_draw_id)146drawid++;147}148return;149}150151const struct pipe_draw_start_count_bias *draw = &draws[0];152153/* Filter out degenerate primitives, u_upload_alloc() will assert154* on size==0 so just bail:155*/156if (!info->primitive_restart &&157!u_trim_pipe_prim(info->mode, (unsigned*)&draw->count))158return;159160util_draw_init_info(&new_info);161new_info.index_bounds_valid = info->index_bounds_valid;162new_info.min_index = info->min_index;163new_info.max_index = info->max_index;164new_info.start_instance = info->start_instance;165new_info.instance_count = info->instance_count;166new_info.primitive_restart = info->primitive_restart;167new_info.restart_index = info->restart_index;168if (info->index_size) {169enum pipe_prim_type mode = new_info.mode = u_index_prim_type_convert(pc->cfg.primtypes_mask, info->mode, true);170unsigned index_size = info->index_size;171new_info.index_size = u_index_size_convert(info->index_size);172173src = info->has_user_indices ? info->index.user : NULL;174if (!src) {175src = pipe_buffer_map(pc->pipe, info->index.resource,176PIPE_MAP_READ, &src_transfer);177}178src = (const uint8_t *)src;179180/* if the resulting primitive type is not supported by the driver for primitive restart,181* the draw needs to be rewritten to not use primitive restart182*/183if (info->primitive_restart &&184!(pc->cfg.restart_primtypes_mask & BITFIELD_BIT(mode))) {185/* step 1: rewrite draw to not use primitive primitive restart;186* this pre-filters degenerate primitives187*/188direct_draws = util_prim_restart_convert_to_direct(src, info, draw, &num_direct_draws,189&new_info.min_index, &new_info.max_index, &total_index_count);190new_info.primitive_restart = false;191/* step 2: get a translator function which does nothing but handle any index size conversions192* which may or may not occur (8bit -> 16bit)193*/194u_index_translator(0xffff,195info->mode, index_size, total_index_count,196pc->api_pv, pc->api_pv,197PR_DISABLE,198&mode, &index_size, &new_draw.count,199&direct_draw_func);200/* this should always be a direct translation */201assert(new_draw.count == total_index_count);202/* step 3: allocate a temp buffer for an intermediate rewrite step */203rewrite_buffer = malloc(index_size * total_index_count);204if (!rewrite_buffer) {205if (src_transfer)206pipe_buffer_unmap(pc->pipe, src_transfer);207return;208}209}210/* (step 4: get the actual primitive conversion translator function) */211u_index_translator(pc->cfg.primtypes_mask,212info->mode, index_size, total_index_count,213pc->api_pv, pc->api_pv,214new_info.primitive_restart ? PR_ENABLE : PR_DISABLE,215&mode, &index_size, &new_draw.count,216&trans_func);217assert(new_info.mode == mode);218assert(new_info.index_size == index_size);219}220else {221enum pipe_prim_type mode = 0;222unsigned index_size;223224u_index_generator(pc->cfg.primtypes_mask,225info->mode, draw->start, draw->count,226pc->api_pv, pc->api_pv,227&mode, &index_size, &new_draw.count,228&gen_func);229new_info.mode = mode;230new_info.index_size = index_size;231}232233/* (step 5: allocate gpu memory sized for the FINAL index count) */234u_upload_alloc(pc->pipe->stream_uploader, 0, new_info.index_size * new_draw.count, 4,235&ib_offset, &new_info.index.resource, &dst);236new_draw.start = ib_offset / new_info.index_size;237new_draw.index_bias = info->index_size ? draw->index_bias : 0;238239if (info->index_size) {240if (num_direct_draws) {241uint8_t *ptr = rewrite_buffer;242uint8_t *dst_ptr = dst;243/* step 6: if rewriting a prim-restart draw to direct draws,244* loop over all the direct draws in order to rewrite them into a single index buffer245* and draw in order to match the original call246*/247for (unsigned i = 0; i < num_direct_draws; i++) {248/* step 6a: get the index count for this draw, once converted */249unsigned tmp_count = u_index_count_converted_indices(pc->cfg.primtypes_mask, true, info->mode, direct_draws[i].count);250/* step 6b: handle index size conversion using the temp buffer; no change in index count251* TODO: this step can be optimized out if the index size is known to not change252*/253direct_draw_func(src, direct_draws[i].start, direct_draws[i].count, direct_draws[i].count, info->restart_index, ptr);254/* step 6c: handle the primitive type conversion rewriting to the converted index count */255trans_func(ptr, 0, direct_draws[i].count, tmp_count, info->restart_index, dst_ptr);256/* step 6d: increment the temp buffer and mapped final index buffer pointers */257ptr += new_info.index_size * direct_draws[i].count;258dst_ptr += new_info.index_size * tmp_count;259}260/* step 7: set the final index count, which is the converted total index count from the original draw rewrite */261new_draw.count = u_index_count_converted_indices(pc->cfg.primtypes_mask, true, info->mode, total_index_count);262} else263trans_func(src, draw->start, draw->count, new_draw.count, info->restart_index, dst);264265if (pc->cfg.fixed_prim_restart && new_info.primitive_restart) {266new_info.restart_index = (1ull << (new_info.index_size * 8)) - 1;267if (info->restart_index != new_info.restart_index)268util_translate_prim_restart_data(new_info.index_size, dst, dst,269new_draw.count,270info->restart_index);271}272}273else {274gen_func(draw->start, new_draw.count, dst);275}276277if (src_transfer)278pipe_buffer_unmap(pc->pipe, src_transfer);279280u_upload_unmap(pc->pipe->stream_uploader);281282/* to the translated draw: */283pc->pipe->draw_vbo(pc->pipe, &new_info, drawid_offset, NULL, &new_draw, 1);284free(direct_draws);285free(rewrite_buffer);286287pipe_resource_reference(&new_info.index.resource, NULL);288}289290291