[Mesa-dev] [PATCH V2 2/2] meta: Use gl_FragColor to output color values to all the draw buffers
Anuj Phogat
anuj.phogat at gmail.com
Tue May 20 14:56:39 PDT 2014
On Tue, May 20, 2014 at 2:36 PM, Kenneth Graunke <kenneth at whitecape.org> wrote:
> On 05/20/2014 10:49 AM, Pohjolainen, Topi wrote:
>> On Tue, May 20, 2014 at 10:31:05AM -0700, Anuj Phogat wrote:
>>> _mesa_meta_setup_blit_shader() currently generates a fragment shader
>>> which, irrespective of the number of draw buffers, writes the color
>>> to only one 'out' variable. Current shader rely on an undefined
>>> behavior and possibly works by chance.
>>>
>>> From OpenGL 4.0 spec, page 256:
>>> "If a fragment shader writes to gl_FragColor, DrawBuffers specifies a
>>> set of draw buffers into which the single fragment color defined by
>>> gl_FragColor is written. If a fragment shader writes to gl_FragData,
>>> or a user-defined varying out variable, DrawBuffers specifies a set
>>> of draw buffers into which each of the multiple output colors defined
>>> by these variables are separately written. If a fragment shader writes
>>> to none of gl_FragColor, gl_FragData, nor any user defined varying out
>>> variables, the values of the fragment colors following shader execution
>>> are undefined, and may differ for each fragment color."
>>>
>>> OpenGL 4.4 spec, page 463, added an additional line in this section:
>>> "If some, but not all user-defined output variables are written, the
>>> values of fragment colors corresponding to unwritten variables are
>>> similarly undefined."
>>>
>>> V2: Write color output to gl_FragColor instead of writing to multiple
>>> 'out' variables. This'll avoid recompiling the shader every time
>>> draw buffers count is updated.
>>>
>>> Cc: <mesa-stable at lists.freedesktop.org>
>>> Signed-off-by: Anuj Phogat <anuj.phogat at gmail.com>
>>> Reviewed-by: Matt Turner <mattst88 at gmail.com> (V1)
>>
>> Fixes gles3 cts tests:
>>
>> framebuffer_blit_functionality_color_and_depth_blit.test
>> framebuffer_blit_functionality_nearest_filter_color_blit.test
>> framebuffer_blit_functionality_linear_filter_color_blit.test
>> framebuffer_blit_functionality_color_and_stencil_blit.test
>>
>>> ---
>>> src/mesa/drivers/common/meta.c | 15 ++++-----------
>>> 1 file changed, 4 insertions(+), 11 deletions(-)
>>>
>>> diff --git a/src/mesa/drivers/common/meta.c b/src/mesa/drivers/common/meta.c
>>> index fab9106..337be1b 100644
>>> --- a/src/mesa/drivers/common/meta.c
>>> +++ b/src/mesa/drivers/common/meta.c
>>> @@ -246,7 +246,6 @@ _mesa_meta_setup_blit_shader(struct gl_context *ctx,
>>> void *const mem_ctx = ralloc_context(NULL);
>>> struct blit_shader *shader = choose_blit_shader(target, table);
>>> const char *vs_input, *vs_output, *fs_input, *vs_preprocess, *fs_preprocess;
>>> - const char *fs_output_var, *fs_output_var_decl;
>>>
>>> if (ctx->Const.GLSLVersion < 130) {
>>> vs_preprocess = "";
>>> @@ -254,16 +253,12 @@ _mesa_meta_setup_blit_shader(struct gl_context *ctx,
>>> vs_output = "varying";
>>> fs_preprocess = "#extension GL_EXT_texture_array : enable";
>>> fs_input = "varying";
>>> - fs_output_var_decl = "";
>>> - fs_output_var = "gl_FragColor";
>>> } else {
>>> vs_preprocess = "#version 130";
>>> vs_input = "in";
>>> vs_output = "out";
>>> fs_preprocess = "#version 130";
>>> fs_input = "in";
>>> - fs_output_var_decl = "out vec4 out_color;";
>>> - fs_output_var = "out_color";
>>> shader->func = "texture";
>>> }
>>>
>>> @@ -291,15 +286,13 @@ _mesa_meta_setup_blit_shader(struct gl_context *ctx,
>>> "#extension GL_ARB_texture_cube_map_array: enable\n"
>>> "uniform %s texSampler;\n"
>>> "%s vec4 texCoords;\n"
>>> - "%s\n"
>>> "void main()\n"
>>> "{\n"
>>> - " vec4 color = %s(texSampler, %s);\n"
>>> - " %s = color;\n"
>>> - " gl_FragDepth = color.x;\n"
>>> + " gl_FragColor = %s(texSampler, %s);\n"
>>> + " gl_FragDepth = gl_FragColor.x;\n"
>>> "}\n",
>>> - fs_preprocess, shader->type, fs_input, fs_output_decl,
>>> - shader->func, shader->texcoords, fs_output);
>>> + fs_preprocess, shader->type, fs_input,
>>> + shader->func, shader->texcoords);
>
> Assuming you fix this line (as Topi pointed out), both patches are:
Fixed.
> Reviewed-by: Kenneth Graunke <kenneth at whitecape.org>
>
> Thanks for fixing this, Anuj.
>
>>>
>>> _mesa_meta_compile_and_link_program(ctx, vs_source, fs_source,
>>> ralloc_asprintf(mem_ctx, "%s blit",
>
> Topi and I spent a while analyzing why we saw failures with this code on
> Broadwell, but not on earlier platforms.
>
> Using gl_FragColor causes OutputsWritten to include FRAG_RESULT_COLOR,
> while using "out vec4 out_color" causes it to include only
> FRAG_RESULT_DATA0 (and not 1/2/3 for the other targets).
>
> If a program binds color buffer 1, but not color buffer 0, this means
> that brw_color_buffer_write_enabled() will return FALSE. Buffer 0 is
> NULL, and buffer 1 supposedly isn't written by the program.
>
> On most platforms, this happens to work out due to several subtle
> interactions:
>
> 1. Since the shader also happens to write gl_FragDepth, the following
> code in gen7_wm_state.c will still enable pixel shader dispatch:
>
> if (brw_color_buffer_write_enabled(brw) || writes_depth ||
> dw1 & GEN7_WM_KILL_ENABLE) {
> dw1 |= GEN7_WM_DISPATCH_ENABLE;
>
> So, the only reason we get color buffer writes to work at all is that we
> happened to write gl_FragDepth. Otherwise, we'd get no PS threads
> dispatched.
>
> 2. The fragment shader happens to write the right colors to the RTs.
>
> Our FS backend writes render targets in order. Since out_color
> corresponds to RT 0, it happens first. We put the color in the MRFs,
> and issue our first FB write.
>
> The later targets aren't technically written, but we happen to issue FB
> writes for them anyway, for some reason. We don't assign any particular
I'm not sure if it's a bug to write to all the draw buffers even if fragment
shader writes to only one. Spec says color values of unwritten draw
buffers will be undefined. But, I think it's better to leave them unchanged.
NVIDIA's driver doesn't modify the color values of unwritten draw buffers.
> color to the MRFs, so they retain their existing value...which happens
> to be the color for RT 0...which happens to be what we wanted.
>
> Nasty stuff.
>
> On Broadwell, things break because we use brw_color_buffer_write_enabled
> in the 3DSTATE_PS_BLEND packet to set the GEN8_PS_BLEND_HAS_WRITEABLE_RT
> bit. Since it returns FALSE, we've told the hardware that no writable
> render target exists. Apparently, this makes the hardware not write
> things depending on $PHASE_OF_MOON.
>
> Changing it to gl_FragColor makes brw_color_buffer_write_enabled return
> true when RTs (!= 0) exist, which makes us set this bit correctly, and
> then things start working.
>
I had these questions in my mind why existing code ever worked. Thanks
for explaining it Ken. Now I can sleep peacefully :).
> --Ken
>
More information about the mesa-dev
mailing list