Path: blob/21.2-virgl/src/panfrost/midgard/midgard_derivatives.c
4564 views
/*1* Copyright (C) 2019 Collabora, Ltd.2* Copyright (C) 2019-2020 Collabora, Ltd.3*4* Permission is hereby granted, free of charge, to any person obtaining a5* copy of this software and associated documentation files (the "Software"),6* to deal in the Software without restriction, including without limitation7* the rights to use, copy, modify, merge, publish, distribute, sublicense,8* and/or sell copies of the Software, and to permit persons to whom the9* Software is furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice (including the next12* paragraph) shall be included in all copies or substantial portions of the13* Software.14*15* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL18* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER19* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,20* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE21* SOFTWARE.22*23* Authors (Collabora):24* Alyssa Rosenzweig <[email protected]>25*/2627#include "compiler.h"2829/* Derivatives in Midgard are implemented on the texture pipe, rather than the30* ALU pipe as suggested by NIR. The rationale is that normal texture31* instructions require (implicit) derivatives to be calculated anyway, so it32* makes sense to reuse the derivative logic. Thus, in addition to the usual33* texturing ops that calculate derivatives, there are two explicit texture ops34* dFdx/dFdy that perform differencing across helper invocations in either35* horizontal or vertical directions.36*37* One major caveat is that derivatives can only be calculated on up to a vec238* at a time. This restriction presumably is to save some silicon, as 99% of39* derivatives will be vec2 (autocalculating mip levels of 2D texture40* coordinates). Admittedly I'm not sure why 3D textures can have their levels41* calculated automatically, umm... Pressing on.42*43* This caveat is handled in two steps. During the first pass (code44* generation), we generate texture ops 1:1 to the incoming NIR derivatives.45* This works for float/vec2 but not for vec3/vec4. A later lowering pass will46* scan for vec3/vec4 derivatives and lower (split) to multiple instructions.47* This pass is separated as we'll have to rewrite th e destination into a48* register (rather than SSA) and we'd rather do this after we have the whole49* IR in front of us to do it at once.50*/5152static unsigned53mir_derivative_mode(nir_op op)54{55switch (op) {56case nir_op_fddx:57case nir_op_fddx_fine:58case nir_op_fddx_coarse:59return TEXTURE_DFDX;6061case nir_op_fddy:62case nir_op_fddy_fine:63case nir_op_fddy_coarse:64return TEXTURE_DFDY;6566default:67unreachable("Invalid derivative op");68}69}7071/* Returns true if a texturing op computes derivatives either explicitly or72* implicitly */7374bool75mir_op_computes_derivatives(gl_shader_stage stage, unsigned op)76{77/* Only fragment shaders may compute derivatives, but the sense of78* "normal" changes in vertex shaders on certain GPUs */7980if (op == midgard_tex_op_normal && stage != MESA_SHADER_FRAGMENT)81return false;8283switch (op) {84case midgard_tex_op_normal:85case midgard_tex_op_derivative:86assert(stage == MESA_SHADER_FRAGMENT);87return true;88default:89return false;90}91}9293void94midgard_emit_derivatives(compiler_context *ctx, nir_alu_instr *instr)95{96/* Create texture instructions */9798unsigned nr_components = nir_dest_num_components(instr->dest.dest);99100midgard_instruction ins = {101.type = TAG_TEXTURE_4,102.mask = mask_of(nr_components),103.dest = nir_dest_index(&instr->dest.dest),104.dest_type = nir_type_float32,105.src = { ~0, nir_src_index(ctx, &instr->src[0].src), ~0, ~0 },106.swizzle = SWIZZLE_IDENTITY_4,107.src_types = { nir_type_float32, nir_type_float32 },108.op = midgard_tex_op_derivative,109.texture = {110.mode = mir_derivative_mode(instr->op),111.format = 2,112.in_reg_full = 1,113.out_full = 1,114.sampler_type = MALI_SAMPLER_FLOAT,115}116};117118if (!instr->dest.dest.is_ssa)119ins.mask &= instr->dest.write_mask;120121emit_mir_instruction(ctx, ins);122}123124void125midgard_lower_derivatives(compiler_context *ctx, midgard_block *block)126{127mir_foreach_instr_in_block_safe(block, ins) {128if (ins->type != TAG_TEXTURE_4) continue;129if (ins->op != midgard_tex_op_derivative) continue;130131/* Check if we need to split */132133bool upper = ins->mask & 0b1100;134bool lower = ins->mask & 0b0011;135136if (!(upper && lower)) continue;137138/* Duplicate for dedicated upper instruction */139140midgard_instruction dup;141memcpy(&dup, ins, sizeof(dup));142143/* Fixup masks. Make original just lower and dupe just upper */144145ins->mask &= 0b0011;146dup.mask &= 0b1100;147148/* Fixup swizzles */149dup.swizzle[0][0] = dup.swizzle[0][1] = dup.swizzle[0][2] = COMPONENT_X;150dup.swizzle[0][3] = COMPONENT_Y;151152dup.swizzle[1][0] = COMPONENT_Z;153dup.swizzle[1][1] = dup.swizzle[1][2] = dup.swizzle[1][3] = COMPONENT_W;154155/* Insert the new instruction */156mir_insert_instruction_before(ctx, mir_next_op(ins), dup);157158/* We'll need both instructions to write to the same index, so159* rewrite to use a register */160161unsigned new = make_compiler_temp_reg(ctx);162mir_rewrite_index(ctx, ins->dest, new);163}164}165166167