[Mesa-dev] [PATCH v2 12/16] glsl: Add a lowering pass to handle advanced blending modes.
Kenneth Graunke
kenneth at whitecape.org
Tue Aug 23 08:12:01 UTC 2016
On Monday, August 22, 2016 5:50:49 PM PDT Francisco Jerez wrote:
> Kenneth Graunke <kenneth at whitecape.org> writes:
>
> > Many GPUs cannot handle GL_KHR_blend_equation_advanced natively, and
> > need to emulate it in the pixel shader. This lowering pass implements
> > all the necessary math for advanced blending. It fetches the existing
> > framebuffer value using the MESA_shader_framebuffer_fetch built-in
> > variables, and the previous commit's state var uniform to select
> > which equation to use.
> >
> > This is done at the GLSL IR level to make it easy for all drivers to
> > implement the GL_KHR_blend_equation_advanced extension and share code.
> >
> > Drivers need to hook up MESA_shader_framebuffer_fetch functionality:
> > 1. Hook up the fb_fetch_output variable
> > 2. Implement BlendBarrier()
> >
> > Then to get KHR_blend_equation_advanced, they simply need to:
> > 3. Disable hardware blending based on ctx->Color._AdvancedBlendEnabled
> > 4. Call this lowering pass.
> >
> > Very little driver specific code should be required.
> >
> > v2: Handle multiple output variables per render target (which may exist
> > due to ARB_enhanced_layouts), and array variables (even with one
> > render target, we might have out vec4 color[1]), and non-vec4
> > variables (it's easier than finding spec text to justify not
> > handling it). Thanks to Francisco Jerez for the feedback.
> >
> > Signed-off-by: Kenneth Graunke <kenneth at whitecape.org>
> > ---
> > src/compiler/Makefile.sources | 1 +
> > src/compiler/glsl/ir_optimization.h | 1 +
> > .../glsl/lower_blend_equation_advanced.cpp | 557 +++++++++++++++++++++
> > 3 files changed, 559 insertions(+)
> > create mode 100644 src/compiler/glsl/lower_blend_equation_advanced.cpp
> >
> > diff --git a/src/compiler/Makefile.sources b/src/compiler/Makefile.sources
> > index 0ff9b23..fe26132 100644
> > --- a/src/compiler/Makefile.sources
> > +++ b/src/compiler/Makefile.sources
> > @@ -77,6 +77,7 @@ LIBGLSL_FILES = \
> > glsl/loop_analysis.h \
> > glsl/loop_controls.cpp \
> > glsl/loop_unroll.cpp \
> > + glsl/lower_blend_equation_advanced.cpp \
> > glsl/lower_buffer_access.cpp \
> > glsl/lower_buffer_access.h \
> > glsl/lower_const_arrays_to_uniforms.cpp \
> > diff --git a/src/compiler/glsl/ir_optimization.h b/src/compiler/glsl/ir_optimization.h
> > index c29260a..3bd6928 100644
> > --- a/src/compiler/glsl/ir_optimization.h
> > +++ b/src/compiler/glsl/ir_optimization.h
> > @@ -151,6 +151,7 @@ void optimize_dead_builtin_variables(exec_list *instructions,
> > bool lower_tess_level(gl_linked_shader *shader);
> >
> > bool lower_vertex_id(gl_linked_shader *shader);
> > +bool lower_blend_equation_advanced(gl_linked_shader *shader);
> >
> > bool lower_subroutine(exec_list *instructions, struct _mesa_glsl_parse_state *state);
> > void propagate_invariance(exec_list *instructions);
> > diff --git a/src/compiler/glsl/lower_blend_equation_advanced.cpp b/src/compiler/glsl/lower_blend_equation_advanced.cpp
> > new file mode 100644
> > index 0000000..5632865
> > --- /dev/null
> > +++ b/src/compiler/glsl/lower_blend_equation_advanced.cpp
> > @@ -0,0 +1,557 @@
> > +/*
> > + * Copyright © 2016 Intel Corporation
> > + *
> > + * 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 "ir.h"
> > +#include "ir_builder.h"
> > +#include "ir_optimization.h"
> > +#include "ir_hierarchical_visitor.h"
> > +#include "program/prog_instruction.h"
> > +#include "program/prog_statevars.h"
> > +#include "util/bitscan.h"
> > +
> > +using namespace ir_builder;
> > +
> > +#define imm1(x) new(mem_ctx) ir_constant((float) x, 1)
> > +#define imm3(x) new(mem_ctx) ir_constant((float) x, 3)
> > +
>
> The x argument should probably be between parentheses to avoid surprises
> in the future -- Or even better, make them static inline functions
> instead of macros.
Good call, I'll add parenthesis. I made them macros rather than static
inlines so you can do imm3(0.5) rather than imm3(mem_ctx, 0.5)...it's
shorter (which is the main point).
[snip]
> > + blend_comps[0], blend_comps[1],
> > + blend_comps[2], blend_comps[3]);
> > + }
> > +
> > + ir_function_signature *main = get_main(sh);
> > + ir_factory f(&main->body, mem_ctx);
> > +
> > + ir_variable *result_dest =
> > + calc_blend_result(f, mode, fb, blend_source, sh->info.BlendSupport);
> > +
> > + /* Copy the result back to the original values. It would be simpler
> > + * to demote the program's output variables, and create a new vec4
> > + * output for our result, but this pass runs before we create the
> > + * ARB_program_interface_query resource list. So we have to leave
> > + * the original outputs in place and use them.
> > + */
> > + for (int i = 0; i < 4; i++) {
> > + if (!outputs[i])
> > + continue;
> > +
> > + f.emit(assign(deref_output(outputs[i]), swizzle(result_dest, i, 1),
> > + 1 << i));
> > + }
> > +
>
> It looks like this relies on the main function having a single exit
> point, which AFAICT may not be the case if there are multiple return
> statements and the lowering pass is called before do_lower_jumps() (as
> is the case in your i965 code). Several options occur to me:
>
> - Rename the shader's main function and generate a new main function
> that calls into the original and implements the advanced blending
> epilogue. This has the advantage that it wouldn't force drivers to
> lower returns if they can support them natively, and is likely to
> result in better code generation than the next option.
>
> - Make the lowering pass re-emit the blending epilogue for each exit
> point of the main function.
>
> - Call do_lower_jumps(lower_main_return=true) manually at the top of
> lower_blend_equation_advanced() if support for any advanced blending
> modes was requested in order to make sure the function has the right
> form. This seems a bit of a hack but I guess it would be the easiest
> solution.
Ugh. Good point.
Option #2 seems unfortunate - I'd hate to emit this multiple times.
In a world where all functions are inlined, options #1 and #3 seem
basically equivalent - function inlining lowers early returns. So
the renamed main would have early returns lowered anyway.
I think I'll take option #3 and change the function to:
bool
lower_blend_equation_advanced(struct gl_linked_shader *sh)
{
if (sh->info.BlendSupport == 0)
return false;
/* Lower early returns in main() so there's a single exit point
* where we can insert our lowering code.
*/
do_lower_jumps(sh->ir, false, false, true, false, false);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: This is a digitally signed message part.
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20160823/8cdda158/attachment.sig>
More information about the mesa-dev
mailing list