Path: blob/21.2-virgl/src/panfrost/midgard/midgard_opt_perspective.c
4564 views
/*1* Copyright (C) 2019 Collabora, Ltd.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*/2223/* Midgard has some accelerated support for perspective projection on the24* load/store pipes. So the first perspective projection pass looks for25* lowered/open-coded perspective projection of the form "fmul (A.xyz,26* frcp(A.w))" or "fmul (A.xy, frcp(A.z))" and rewrite with a native27* perspective division opcode (on the load/store pipe). Caveats apply: the28* frcp should be used only once to make this optimization worthwhile. And the29* source of the frcp ought to be a varying to make it worthwhile...30*31* The second pass in this file is a step #2 of sorts: fusing that load/store32* projection into a varying load instruction (they can be done together33* implicitly). This depends on the combination pass. Again caveat: the vary34* should only be used once to make this worthwhile.35*/3637#include "compiler.h"3839static bool40is_swizzle_0(unsigned *swizzle)41{42for (unsigned c = 0; c < MIR_VEC_COMPONENTS; ++c)43if (swizzle[c])44return false;4546return true;47}4849bool50midgard_opt_combine_projection(compiler_context *ctx, midgard_block *block)51{52bool progress = false;5354mir_foreach_instr_in_block_safe(block, ins) {55/* First search for fmul */56if (ins->type != TAG_ALU_4) continue;57if (ins->op != midgard_alu_op_fmul) continue;5859/* TODO: Flip */6061/* Check the swizzles */6263if (!mir_is_simple_swizzle(ins->swizzle[0], ins->mask)) continue;64if (!is_swizzle_0(ins->swizzle[1])) continue;6566/* Awesome, we're the right form. Now check where src2 is from */67unsigned frcp = ins->src[1];68unsigned to = ins->dest;6970if (frcp & PAN_IS_REG) continue;71if (to & PAN_IS_REG) continue;7273bool frcp_found = false;74unsigned frcp_component = 0;75unsigned frcp_from = 0;7677mir_foreach_instr_in_block_safe(block, sub) {78if (sub->dest != frcp) continue;7980frcp_component = sub->swizzle[0][0];81frcp_from = sub->src[0];8283frcp_found =84(sub->type == TAG_ALU_4) &&85(sub->op == midgard_alu_op_frcp);86break;87}8889if (!frcp_found) continue;90if (frcp_from != ins->src[0]) continue;91if (frcp_component != COMPONENT_W && frcp_component != COMPONENT_Z) continue;92if (!mir_single_use(ctx, frcp)) continue;9394/* Heuristic: check if the frcp is from a single-use varying */9596bool ok = false;9798/* One for frcp and one for fmul */99if (mir_use_count(ctx, frcp_from) > 2) continue;100101mir_foreach_instr_in_block_safe(block, v) {102if (v->dest != frcp_from) continue;103if (v->type != TAG_LOAD_STORE_4) break;104if (!OP_IS_LOAD_VARY_F(v->op)) break;105106ok = true;107break;108}109110if (!ok)111continue;112113/* Nice, we got the form spot on. Let's convert! */114115midgard_instruction accel = {116.type = TAG_LOAD_STORE_4,117.mask = ins->mask,118.dest = to,119.dest_type = nir_type_float32,120.src = { frcp_from, ~0, ~0, ~0 },121.src_types = { nir_type_float32 },122.swizzle = SWIZZLE_IDENTITY_4,123.op = frcp_component == COMPONENT_W ?124midgard_op_ldst_perspective_div_w :125midgard_op_ldst_perspective_div_z,126.load_store = {127.bitsize_toggle = true,128}129};130131mir_insert_instruction_before(ctx, ins, accel);132mir_remove_instruction(ins);133134progress |= true;135}136137return progress;138}139140bool141midgard_opt_varying_projection(compiler_context *ctx, midgard_block *block)142{143bool progress = false;144145mir_foreach_instr_in_block_safe(block, ins) {146/* Search for a projection */147if (ins->type != TAG_LOAD_STORE_4) continue;148if (!OP_IS_PROJECTION(ins->op)) continue;149150unsigned vary = ins->src[0];151unsigned to = ins->dest;152153if (vary & PAN_IS_REG) continue;154if (to & PAN_IS_REG) continue;155if (!mir_single_use(ctx, vary)) continue;156157/* Check for a varying source. If we find it, we rewrite */158159bool rewritten = false;160161mir_foreach_instr_in_block_safe(block, v) {162if (v->dest != vary) continue;163if (v->type != TAG_LOAD_STORE_4) break;164if (!OP_IS_LOAD_VARY_F(v->op)) break;165166/* We found it, so rewrite it to project. Grab the167* modifier */168169midgard_varying_params p =170midgard_unpack_varying_params(v->load_store);171172if (p.modifier != midgard_varying_mod_none)173break;174175bool projects_w =176ins->op == midgard_op_ldst_perspective_div_w;177178p.modifier = projects_w ?179midgard_varying_mod_perspective_w :180midgard_varying_mod_perspective_z;181182midgard_pack_varying_params(&v->load_store, p);183184/* Use the new destination */185v->dest = to;186187rewritten = true;188break;189}190191if (rewritten)192mir_remove_instruction(ins);193194progress |= rewritten;195}196197return progress;198}199200201