From a99c360a463019a4aca9b551bd79c9c84f297468 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 26 Apr 2019 10:05:08 -0700 Subject: [PATCH] nir: add pass to lower fb reads Signed-off-by: Rob Clark Reviewed-by: Kristian H. Kristensen --- src/compiler/nir/meson.build | 1 + src/compiler/nir/nir.h | 7 +- src/compiler/nir/nir_lower_fb_read.c | 121 +++++++++++++++++++++++++++++++++++ src/compiler/nir/nir_print.c | 15 +++-- src/compiler/spirv/spirv_to_nir.c | 3 + 5 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 src/compiler/nir/nir_lower_fb_read.c diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build index 625f150..f79752d 100644 --- a/src/compiler/nir/meson.build +++ b/src/compiler/nir/meson.build @@ -123,6 +123,7 @@ files_libnir = files( 'nir_lower_constant_initializers.c', 'nir_lower_double_ops.c', 'nir_lower_drawpixels.c', + 'nir_lower_fb_read.c', 'nir_lower_fragcoord_wtrans.c', 'nir_lower_frexp.c', 'nir_lower_global_vars_to_local.c', diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index 3fc01b7..3083adb 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -1444,7 +1444,8 @@ typedef enum { nir_texop_txl, /**< Texture look-up with explicit LOD */ nir_texop_txd, /**< Texture look-up with partial derivatives */ nir_texop_txf, /**< Texel fetch with explicit LOD */ - nir_texop_txf_ms, /**< Multisample texture fetch */ + nir_texop_txf_ms, /**< Multisample texture fetch */ + nir_texop_txf_ms_fb, /**< Multisample texture fetch from framebuffer */ nir_texop_txf_ms_mcs, /**< Multisample compression value fetch */ nir_texop_txs, /**< Texture size */ nir_texop_lod, /**< Texture lod query */ @@ -1579,6 +1580,7 @@ nir_tex_instr_is_query(const nir_tex_instr *instr) case nir_texop_txd: case nir_texop_txf: case nir_texop_txf_ms: + case nir_texop_txf_ms_fb: case nir_texop_tg4: return false; default: @@ -1618,6 +1620,7 @@ nir_tex_instr_src_type(const nir_tex_instr *instr, unsigned src) switch (instr->op) { case nir_texop_txf: case nir_texop_txf_ms: + case nir_texop_txf_ms_fb: case nir_texop_txf_ms_mcs: case nir_texop_samples_identical: return nir_type_int; @@ -3394,6 +3397,8 @@ bool nir_lower_wpos_ytransform(nir_shader *shader, const nir_lower_wpos_ytransform_options *options); bool nir_lower_wpos_center(nir_shader *shader, const bool for_sample_shading); +bool nir_lower_fb_read(nir_shader *shader); + typedef struct nir_lower_drawpixels_options { gl_state_index16 texcoord_state_tokens[STATE_LENGTH]; gl_state_index16 scale_state_tokens[STATE_LENGTH]; diff --git a/src/compiler/nir/nir_lower_fb_read.c b/src/compiler/nir/nir_lower_fb_read.c new file mode 100644 index 0000000..07bff1a --- /dev/null +++ b/src/compiler/nir/nir_lower_fb_read.c @@ -0,0 +1,121 @@ +/* + * Copyright © 2019 Google, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "nir.h" +#include "nir_builder.h" + +/* Lowing for fragment shader load_output. + * + * This pass supports the blend_equation_advanced, where a fragment + * shader loads the output (fragcolor) to read the current framebuffer. + * It does this by lowering the output read to a txf_ms_fb instruction. + * This instruction works similarly to a normal txf_ms except without + * taking a texture source argument. (The driver backend is expected + * to wire this up to a free texture slot which is configured to read + * from the framebuffer.) + * + * This should be run after lower_wpos_ytransform, because the tex + * coordinates should be the physical fragcoord, not the logical + * y-flipped coord. + * + * Note that this pass explicitly does *not* add a sampler uniform + * (as txf_ms_fb does not reference a texture). The driver backend + * is going to want nif->info.num_textures to include the count of + * number of textures *not* including the one it inserts to sample + * from the framebuffer, so it more easily knows where to insert the + * hidden texture to read from the fb. + */ + +static void +lower_fb_read(nir_builder *b, nir_intrinsic_instr *intr) +{ + b->cursor = nir_before_instr(&intr->instr); + + nir_ssa_def *fragcoord = nir_load_frag_coord(b); + nir_ssa_def *sampid = nir_load_sample_id(b); + + fragcoord = nir_f2i32(b, fragcoord); + + nir_tex_instr *tex = nir_tex_instr_create(b->shader, 2); + tex->op = nir_texop_txf_ms_fb; + tex->sampler_dim = GLSL_SAMPLER_DIM_2D; + tex->coord_components = 2; + tex->dest_type = nir_type_float; + tex->src[0].src_type = nir_tex_src_coord; + tex->src[0].src = nir_src_for_ssa(nir_channels(b, fragcoord, 0x3)); + tex->src[1].src_type = nir_tex_src_ms_index; + tex->src[1].src = nir_src_for_ssa(sampid); + + nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, NULL); + nir_builder_instr_insert(b, &tex->instr); + + nir_ssa_def_rewrite_uses(&intr->dest.ssa, nir_src_for_ssa(&tex->dest.ssa)); +} + +bool +nir_lower_fb_read(nir_shader *shader) +{ + bool progress = false; + + assert(shader->info.stage == MESA_SHADER_FRAGMENT); + + nir_foreach_function(function, shader) { + nir_function_impl *impl = function->impl; + + if (!impl) + continue; + + nir_foreach_block(block, impl) { + nir_foreach_instr_safe(instr, block) { + if (instr->type != nir_instr_type_intrinsic) + continue; + + nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); + if (intr->intrinsic != nir_intrinsic_load_output) + continue; + + /* TODO KHR_blend_equation_advanced is limited to non-MRT + * scenarios.. but possible there are other extensions + * where this pass would be useful that do support MRT? + * + * I guess for now I'll leave that as an exercise for the + * reader. + */ + if (nir_intrinsic_base(intr) != 0 || + nir_src_as_uint(intr->src[0]) != 0) + continue; + + nir_builder b; + nir_builder_init(&b, impl); + lower_fb_read(&b, intr); + progress = true; + } + } + + nir_metadata_preserve(impl, nir_metadata_block_index | + nir_metadata_dominance); + + } + + return progress; +} diff --git a/src/compiler/nir/nir_print.c b/src/compiler/nir/nir_print.c index be36469..4699576 100644 --- a/src/compiler/nir/nir_print.c +++ b/src/compiler/nir/nir_print.c @@ -883,6 +883,9 @@ print_tex_instr(nir_tex_instr *instr, print_state *state) case nir_texop_txf_ms: fprintf(fp, "txf_ms "); break; + case nir_texop_txf_ms_fb: + fprintf(fp, "txf_ms_fb "); + break; case nir_texop_txf_ms_mcs: fprintf(fp, "txf_ms_mcs "); break; @@ -995,12 +998,14 @@ print_tex_instr(nir_tex_instr *instr, print_state *state) fprintf(fp, " } (offsets)"); } - if (!has_texture_deref) { - fprintf(fp, ", %u (texture)", instr->texture_index); - } + if (instr->op != nir_texop_txf_ms_fb) { + if (!has_texture_deref) { + fprintf(fp, ", %u (texture)", instr->texture_index); + } - if (!has_sampler_deref) { - fprintf(fp, ", %u (sampler)", instr->sampler_index); + if (!has_sampler_deref) { + fprintf(fp, ", %u (sampler)", instr->sampler_index); + } } } diff --git a/src/compiler/spirv/spirv_to_nir.c b/src/compiler/spirv/spirv_to_nir.c index 66097e4..751cedd 100644 --- a/src/compiler/spirv/spirv_to_nir.c +++ b/src/compiler/spirv/spirv_to_nir.c @@ -2200,6 +2200,9 @@ vtn_handle_texture(struct vtn_builder *b, SpvOp opcode, case nir_texop_samples_identical: /* These don't */ break; + case nir_texop_txf_ms_fb: + vtn_fail("unexpected nir_texop_txf_ms_fb"); + break; case nir_texop_txf_ms_mcs: vtn_fail("unexpected nir_texop_txf_ms_mcs"); } -- 2.7.4