Path: blob/21.2-virgl/src/gallium/drivers/iris/iris_draw.c
4565 views
/*1* Copyright © 2017 Intel Corporation2*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 shall be included11* in all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS14* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER17* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING18* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER19* DEALINGS IN THE SOFTWARE.20*/2122/**23* @file iris_draw.c24*25* The main driver hooks for drawing and launching compute shaders.26*/2728#include <stdio.h>29#include <errno.h>30#include "pipe/p_defines.h"31#include "pipe/p_state.h"32#include "pipe/p_context.h"33#include "pipe/p_screen.h"34#include "util/u_draw.h"35#include "util/u_inlines.h"36#include "util/u_transfer.h"37#include "util/u_upload_mgr.h"38#include "intel/compiler/brw_compiler.h"39#include "intel/compiler/brw_eu_defines.h"40#include "iris_context.h"41#include "iris_defines.h"4243static bool44prim_is_points_or_lines(const struct pipe_draw_info *draw)45{46/* We don't need to worry about adjacency - it can only be used with47* geometry shaders, and we don't care about this info when GS is on.48*/49return draw->mode == PIPE_PRIM_POINTS ||50draw->mode == PIPE_PRIM_LINES ||51draw->mode == PIPE_PRIM_LINE_LOOP ||52draw->mode == PIPE_PRIM_LINE_STRIP;53}5455/**56* Record the current primitive mode and restart information, flagging57* related packets as dirty if necessary.58*59* This must be called before updating compiled shaders, because the patch60* information informs the TCS key.61*/62static void63iris_update_draw_info(struct iris_context *ice,64const struct pipe_draw_info *info)65{66struct iris_screen *screen = (struct iris_screen *)ice->ctx.screen;67const struct brw_compiler *compiler = screen->compiler;6869if (ice->state.prim_mode != info->mode) {70ice->state.prim_mode = info->mode;71ice->state.dirty |= IRIS_DIRTY_VF_TOPOLOGY;727374/* For XY Clip enables */75bool points_or_lines = prim_is_points_or_lines(info);76if (points_or_lines != ice->state.prim_is_points_or_lines) {77ice->state.prim_is_points_or_lines = points_or_lines;78ice->state.dirty |= IRIS_DIRTY_CLIP;79}80}8182if (info->mode == PIPE_PRIM_PATCHES &&83ice->state.vertices_per_patch != info->vertices_per_patch) {84ice->state.vertices_per_patch = info->vertices_per_patch;85ice->state.dirty |= IRIS_DIRTY_VF_TOPOLOGY;8687/* 8_PATCH TCS needs this for key->input_vertices */88if (compiler->use_tcs_8_patch)89ice->state.stage_dirty |= IRIS_STAGE_DIRTY_UNCOMPILED_TCS;9091/* Flag constants dirty for gl_PatchVerticesIn if needed. */92const struct shader_info *tcs_info =93iris_get_shader_info(ice, MESA_SHADER_TESS_CTRL);94if (tcs_info &&95BITSET_TEST(tcs_info->system_values_read, SYSTEM_VALUE_VERTICES_IN)) {96ice->state.stage_dirty |= IRIS_STAGE_DIRTY_CONSTANTS_TCS;97ice->state.shaders[MESA_SHADER_TESS_CTRL].sysvals_need_upload = true;98}99}100101/* Track restart_index changes only if primitive_restart is true */102const unsigned cut_index = info->primitive_restart ? info->restart_index :103ice->state.cut_index;104if (ice->state.primitive_restart != info->primitive_restart ||105ice->state.cut_index != cut_index) {106ice->state.dirty |= IRIS_DIRTY_VF;107ice->state.primitive_restart = info->primitive_restart;108ice->state.cut_index = cut_index;109}110}111112/**113* Update shader draw parameters, flagging VF packets as dirty if necessary.114*/115static void116iris_update_draw_parameters(struct iris_context *ice,117const struct pipe_draw_info *info,118unsigned drawid_offset,119const struct pipe_draw_indirect_info *indirect,120const struct pipe_draw_start_count_bias *draw)121{122bool changed = false;123124if (ice->state.vs_uses_draw_params) {125struct iris_state_ref *draw_params = &ice->draw.draw_params;126127if (indirect && indirect->buffer) {128pipe_resource_reference(&draw_params->res, indirect->buffer);129draw_params->offset =130indirect->offset + (info->index_size ? 12 : 8);131132changed = true;133ice->draw.params_valid = false;134} else {135int firstvertex = info->index_size ? draw->index_bias : draw->start;136137if (!ice->draw.params_valid ||138ice->draw.params.firstvertex != firstvertex ||139ice->draw.params.baseinstance != info->start_instance) {140141changed = true;142ice->draw.params.firstvertex = firstvertex;143ice->draw.params.baseinstance = info->start_instance;144ice->draw.params_valid = true;145146u_upload_data(ice->ctx.const_uploader, 0,147sizeof(ice->draw.params), 4, &ice->draw.params,148&draw_params->offset, &draw_params->res);149}150}151}152153if (ice->state.vs_uses_derived_draw_params) {154struct iris_state_ref *derived_params = &ice->draw.derived_draw_params;155int is_indexed_draw = info->index_size ? -1 : 0;156157if (ice->draw.derived_params.drawid != drawid_offset ||158ice->draw.derived_params.is_indexed_draw != is_indexed_draw) {159160changed = true;161ice->draw.derived_params.drawid = drawid_offset;162ice->draw.derived_params.is_indexed_draw = is_indexed_draw;163164u_upload_data(ice->ctx.const_uploader, 0,165sizeof(ice->draw.derived_params), 4,166&ice->draw.derived_params,167&derived_params->offset, &derived_params->res);168}169}170171if (changed) {172ice->state.dirty |= IRIS_DIRTY_VERTEX_BUFFERS |173IRIS_DIRTY_VERTEX_ELEMENTS |174IRIS_DIRTY_VF_SGVS;175}176}177178static void179iris_indirect_draw_vbo(struct iris_context *ice,180const struct pipe_draw_info *dinfo,181unsigned drawid_offset,182const struct pipe_draw_indirect_info *dindirect,183const struct pipe_draw_start_count_bias *draw)184{185struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER];186struct pipe_draw_info info = *dinfo;187struct pipe_draw_indirect_info indirect = *dindirect;188189if (indirect.indirect_draw_count &&190ice->state.predicate == IRIS_PREDICATE_STATE_USE_BIT) {191/* Upload MI_PREDICATE_RESULT to GPR15.*/192batch->screen->vtbl.load_register_reg64(batch, CS_GPR(15), MI_PREDICATE_RESULT);193}194195const uint64_t orig_dirty = ice->state.dirty;196const uint64_t orig_stage_dirty = ice->state.stage_dirty;197198for (int i = 0; i < indirect.draw_count; i++) {199iris_batch_maybe_flush(batch, 1500);200201iris_update_draw_parameters(ice, &info, drawid_offset + i, &indirect, draw);202203batch->screen->vtbl.upload_render_state(ice, batch, &info, drawid_offset + i, &indirect, draw);204205ice->state.dirty &= ~IRIS_ALL_DIRTY_FOR_RENDER;206ice->state.stage_dirty &= ~IRIS_ALL_STAGE_DIRTY_FOR_RENDER;207208indirect.offset += indirect.stride;209}210211if (indirect.indirect_draw_count &&212ice->state.predicate == IRIS_PREDICATE_STATE_USE_BIT) {213/* Restore MI_PREDICATE_RESULT. */214batch->screen->vtbl.load_register_reg64(batch, MI_PREDICATE_RESULT, CS_GPR(15));215}216217/* Put this back for post-draw resolves, we'll clear it again after. */218ice->state.dirty = orig_dirty;219ice->state.stage_dirty = orig_stage_dirty;220}221222static void223iris_simple_draw_vbo(struct iris_context *ice,224const struct pipe_draw_info *draw,225unsigned drawid_offset,226const struct pipe_draw_indirect_info *indirect,227const struct pipe_draw_start_count_bias *sc)228{229struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER];230231iris_batch_maybe_flush(batch, 1500);232233iris_update_draw_parameters(ice, draw, drawid_offset, indirect, sc);234235batch->screen->vtbl.upload_render_state(ice, batch, draw, drawid_offset, indirect, sc);236}237238/**239* The pipe->draw_vbo() driver hook. Performs a draw on the GPU.240*/241void242iris_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info,243unsigned drawid_offset,244const struct pipe_draw_indirect_info *indirect,245const struct pipe_draw_start_count_bias *draws,246unsigned num_draws)247{248if (num_draws > 1) {249util_draw_multi(ctx, info, drawid_offset, indirect, draws, num_draws);250return;251}252253if (!indirect && (!draws[0].count || !info->instance_count))254return;255256struct iris_context *ice = (struct iris_context *) ctx;257struct iris_screen *screen = (struct iris_screen*)ice->ctx.screen;258const struct intel_device_info *devinfo = &screen->devinfo;259struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER];260261if (ice->state.predicate == IRIS_PREDICATE_STATE_DONT_RENDER)262return;263264if (INTEL_DEBUG & DEBUG_REEMIT) {265ice->state.dirty |= IRIS_ALL_DIRTY_FOR_RENDER;266ice->state.stage_dirty |= IRIS_ALL_STAGE_DIRTY_FOR_RENDER;267}268269iris_update_draw_info(ice, info);270271if (devinfo->ver == 9)272gfx9_toggle_preemption(ice, batch, info);273274iris_update_compiled_shaders(ice);275276if (ice->state.dirty & IRIS_DIRTY_RENDER_RESOLVES_AND_FLUSHES) {277bool draw_aux_buffer_disabled[BRW_MAX_DRAW_BUFFERS] = { };278for (gl_shader_stage stage = 0; stage < MESA_SHADER_COMPUTE; stage++) {279if (ice->shaders.prog[stage])280iris_predraw_resolve_inputs(ice, batch, draw_aux_buffer_disabled,281stage, true);282}283iris_predraw_resolve_framebuffer(ice, batch, draw_aux_buffer_disabled);284}285286iris_binder_reserve_3d(ice);287288batch->screen->vtbl.update_surface_base_address(batch, &ice->state.binder);289290iris_handle_always_flush_cache(batch);291292if (indirect && indirect->buffer)293iris_indirect_draw_vbo(ice, info, drawid_offset, indirect, &draws[0]);294else295iris_simple_draw_vbo(ice, info, drawid_offset, indirect, &draws[0]);296297iris_handle_always_flush_cache(batch);298299iris_postdraw_update_resolve_tracking(ice, batch);300301ice->state.dirty &= ~IRIS_ALL_DIRTY_FOR_RENDER;302ice->state.stage_dirty &= ~IRIS_ALL_STAGE_DIRTY_FOR_RENDER;303}304305static void306iris_update_grid_size_resource(struct iris_context *ice,307const struct pipe_grid_info *grid)308{309const struct iris_screen *screen = (void *) ice->ctx.screen;310const struct isl_device *isl_dev = &screen->isl_dev;311struct iris_state_ref *grid_ref = &ice->state.grid_size;312struct iris_state_ref *state_ref = &ice->state.grid_surf_state;313314const struct iris_compiled_shader *shader = ice->shaders.prog[MESA_SHADER_COMPUTE];315bool grid_needs_surface = shader->bt.used_mask[IRIS_SURFACE_GROUP_CS_WORK_GROUPS];316bool grid_updated = false;317318if (grid->indirect) {319pipe_resource_reference(&grid_ref->res, grid->indirect);320grid_ref->offset = grid->indirect_offset;321322/* Zero out the grid size so that the next non-indirect grid launch will323* re-upload it properly.324*/325memset(ice->state.last_grid, 0, sizeof(ice->state.last_grid));326grid_updated = true;327} else if (memcmp(ice->state.last_grid, grid->grid, sizeof(grid->grid)) != 0) {328memcpy(ice->state.last_grid, grid->grid, sizeof(grid->grid));329u_upload_data(ice->state.dynamic_uploader, 0, sizeof(grid->grid), 4,330grid->grid, &grid_ref->offset, &grid_ref->res);331grid_updated = true;332}333334/* If we changed the grid, the old surface state is invalid. */335if (grid_updated)336pipe_resource_reference(&state_ref->res, NULL);337338/* Skip surface upload if we don't need it or we already have one */339if (!grid_needs_surface || state_ref->res)340return;341342struct iris_bo *grid_bo = iris_resource_bo(grid_ref->res);343344void *surf_map = NULL;345u_upload_alloc(ice->state.surface_uploader, 0, isl_dev->ss.size,346isl_dev->ss.align, &state_ref->offset, &state_ref->res,347&surf_map);348state_ref->offset +=349iris_bo_offset_from_base_address(iris_resource_bo(state_ref->res));350isl_buffer_fill_state(&screen->isl_dev, surf_map,351.address = grid_ref->offset + grid_bo->gtt_offset,352.size_B = sizeof(grid->grid),353.format = ISL_FORMAT_RAW,354.stride_B = 1,355.mocs = iris_mocs(grid_bo, isl_dev,356ISL_SURF_USAGE_CONSTANT_BUFFER_BIT));357358ice->state.stage_dirty |= IRIS_STAGE_DIRTY_BINDINGS_CS;359}360361void362iris_launch_grid(struct pipe_context *ctx, const struct pipe_grid_info *grid)363{364struct iris_context *ice = (struct iris_context *) ctx;365struct iris_batch *batch = &ice->batches[IRIS_BATCH_COMPUTE];366367if (ice->state.predicate == IRIS_PREDICATE_STATE_DONT_RENDER)368return;369370if (INTEL_DEBUG & DEBUG_REEMIT) {371ice->state.dirty |= IRIS_ALL_DIRTY_FOR_COMPUTE;372ice->state.stage_dirty |= IRIS_ALL_STAGE_DIRTY_FOR_COMPUTE;373}374375if (ice->state.dirty & IRIS_DIRTY_COMPUTE_RESOLVES_AND_FLUSHES)376iris_predraw_resolve_inputs(ice, batch, NULL, MESA_SHADER_COMPUTE, false);377378iris_batch_maybe_flush(batch, 1500);379380iris_update_compiled_compute_shader(ice);381382if (memcmp(ice->state.last_block, grid->block, sizeof(grid->block)) != 0) {383memcpy(ice->state.last_block, grid->block, sizeof(grid->block));384ice->state.stage_dirty |= IRIS_STAGE_DIRTY_CONSTANTS_CS;385ice->state.shaders[MESA_SHADER_COMPUTE].sysvals_need_upload = true;386}387388iris_update_grid_size_resource(ice, grid);389390iris_binder_reserve_compute(ice);391batch->screen->vtbl.update_surface_base_address(batch, &ice->state.binder);392393if (ice->state.compute_predicate) {394batch->screen->vtbl.load_register_mem64(batch, MI_PREDICATE_RESULT,395ice->state.compute_predicate, 0);396ice->state.compute_predicate = NULL;397}398399iris_handle_always_flush_cache(batch);400401batch->screen->vtbl.upload_compute_state(ice, batch, grid);402403iris_handle_always_flush_cache(batch);404405ice->state.dirty &= ~IRIS_ALL_DIRTY_FOR_COMPUTE;406ice->state.stage_dirty &= ~IRIS_ALL_STAGE_DIRTY_FOR_COMPUTE;407408/* Note: since compute shaders can't access the framebuffer, there's409* no need to call iris_postdraw_update_resolve_tracking.410*/411}412413414