blob: 2f211917ca4aeccffe3ef0f38bbe214f5f6dd8b8 [file] [log] [blame]
//
// Copyright 2021 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// FramebufferFetchTest:
// Tests the correctness of the EXT_shader_framebuffer_fetch and the
// EXT_shader_framebuffer_fetch_non_coherent extensions.
//
#include "common/debug.h"
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
#include "util/EGLWindow.h"
namespace angle
{
//
// Shared Vertex Shaders for the tests below
//
// A 1.0 GLSL vertex shader
static constexpr char k100VS[] = R"(#version 100
attribute vec4 a_position;
void main (void)
{
gl_Position = a_position;
})";
// A 3.1 GLSL vertex shader
static constexpr char k310VS[] = R"(#version 310 es
in highp vec4 a_position;
void main (void)
{
gl_Position = a_position;
})";
// Shared simple (i.e. no framebuffer fetch) Fragment Shaders for the tests below
//
// Simple (i.e. no framebuffer fetch) 3.1 GLSL fragment shader that writes to 1 attachment
static constexpr char k310NoFetch1AttachmentFS[] = R"(#version 310 es
layout(location = 0) out highp vec4 o_color;
uniform highp vec4 u_color;
void main (void)
{
o_color = u_color;
})";
// Shared Coherent Fragment Shaders for the tests below
//
// Coherent version of a 1.0 GLSL fragment shader that uses gl_LastFragData
static constexpr char k100CoherentFS[] = R"(#version 100
#extension GL_EXT_shader_framebuffer_fetch : require
mediump vec4 gl_LastFragData[gl_MaxDrawBuffers];
uniform highp vec4 u_color;
void main (void)
{
gl_FragColor = u_color + gl_LastFragData[0];
})";
// Coherent version of a 3.1 GLSL fragment shader that writes to 1 attachment
static constexpr char k310Coherent1AttachmentFS[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch : require
layout(location = 0) inout highp vec4 o_color;
uniform highp vec4 u_color;
void main (void)
{
o_color += u_color;
})";
// Coherent version of a 3.1 GLSL fragment shader that writes the output to a storage buffer.
static constexpr char k310CoherentStorageBuffer[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch : require
layout(location = 0) inout highp vec4 o_color;
layout(std140, binding = 0) buffer outBlock {
highp vec4 data[256];
};
uniform highp vec4 u_color;
void main (void)
{
uint index = uint(gl_FragCoord.y) * 16u + uint(gl_FragCoord.x);
data[index] = o_color;
o_color += u_color;
})";
// Coherent version of a 1.0 GLSL fragment shader that writes to 4 attachments with constant indices
static constexpr char k100Coherent4AttachmentFS[] = R"(#version 100
#extension GL_EXT_shader_framebuffer_fetch : require
#extension GL_EXT_draw_buffers : require
uniform highp vec4 u_color;
void main (void)
{
gl_FragData[0] = gl_LastFragData[0] + u_color;
gl_FragData[1] = gl_LastFragData[1] + u_color;
gl_FragData[2] = gl_LastFragData[2] + u_color;
gl_FragData[3] = gl_LastFragData[3] + u_color;
})";
// Coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments
static constexpr char k310Coherent4AttachmentFS[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch : require
layout(location = 0) inout highp vec4 o_color0;
layout(location = 1) inout highp vec4 o_color1;
layout(location = 2) inout highp vec4 o_color2;
layout(location = 3) inout highp vec4 o_color3;
uniform highp vec4 u_color;
void main (void)
{
o_color0 += u_color;
o_color1 += u_color;
o_color2 += u_color;
o_color3 += u_color;
})";
// Coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments via an inout
// array
static constexpr char k310Coherent4AttachmentArrayFS[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch : require
inout highp vec4 o_color[4];
uniform highp vec4 u_color;
void main (void)
{
o_color[0] += u_color;
o_color[1] += u_color;
o_color[2] += u_color;
o_color[3] += u_color;
})";
// Coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments with the order of
// non-fetch program and fetch program with different attachments (version 1)
static constexpr char k310CoherentDifferent4AttachmentFS1[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch : require
layout(location = 0) inout highp vec4 o_color0;
layout(location = 1) out highp vec4 o_color1;
layout(location = 2) inout highp vec4 o_color2;
layout(location = 3) out highp vec4 o_color3;
uniform highp vec4 u_color;
void main (void)
{
o_color0 += u_color;
o_color1 = u_color;
o_color2 += u_color;
o_color3 = u_color;
})";
// Coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments with the order
// of non-fetch program and fetch program with different attachments (version 2)
static constexpr char k310CoherentDifferent4AttachmentFS2[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch : require
layout(location = 0) inout highp vec4 o_color0;
layout(location = 1) out highp vec4 o_color1;
layout(location = 2) out highp vec4 o_color2;
layout(location = 3) inout highp vec4 o_color3;
uniform highp vec4 u_color;
void main (void)
{
o_color0 += u_color;
o_color1 = u_color;
o_color2 = u_color;
o_color3 += u_color;
})";
// Coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments, fetching from
// different indices (version 3)
static constexpr char k310CoherentDifferent4AttachmentFS3[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch : require
layout(location = 0) out highp vec4 o_color0;
layout(location = 1) inout highp vec4 o_color1;
layout(location = 2) inout highp vec4 o_color2;
layout(location = 3) out highp vec4 o_color3;
uniform highp vec4 u_color;
void main (void)
{
o_color0 = u_color;
o_color1 += u_color;
o_color2 += u_color;
o_color3 = u_color;
})";
// Coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments, fetching from
// different indices (version 4)
static constexpr char k310CoherentDifferent4AttachmentFS4[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch : require
layout(location = 0) out highp vec4 o_color0;
layout(location = 1) out highp vec4 o_color1;
layout(location = 2) inout highp vec4 o_color2;
layout(location = 3) inout highp vec4 o_color3;
uniform highp vec4 u_color;
void main (void)
{
o_color0 = u_color;
o_color1 = u_color;
o_color2 += u_color;
o_color3 += u_color;
})";
// Coherent version of a 1.0 GLSL fragment shader with complex interactions
static constexpr char k100CoherentComplexFS[] = R"(#version 100
#extension GL_EXT_shader_framebuffer_fetch : require
#extension GL_EXT_draw_buffers : require
precision highp float;
uniform vec4 u_color;
vec4 addColor(vec4 lastFragData, vec4 color)
{
return lastFragData + color;
}
void addLastFragData(inout vec4 outVar, vec4 lastFragData)
{
outVar += lastFragData;
}
void main (void)
{
// Leave gl_LastFragData[0] unused, as well as gl_LastFragData[2]
gl_FragData[0] = u_color;
gl_FragData[1] = addColor(gl_LastFragData[1], u_color);
gl_FragData[2] = u_color;
gl_FragData[3] = addColor(gl_LastFragData[3], u_color);
// Make sure gl_LastFragData is not clobbered by a write to gl_FragData.
gl_FragData[1] -= gl_LastFragData[1];
gl_FragData[3] -= gl_LastFragData[3];
// Test passing to inout variables.
addLastFragData(gl_FragData[1], gl_LastFragData[1]);
addLastFragData(gl_FragData[3], gl_LastFragData[3]);
})";
// Coherent version of a 3.1 GLSL fragment shader with complex interactions
static constexpr char k310CoherentComplexFS[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch : require
precision highp float;
layout(location = 0) inout highp vec4 o_color0;
layout(location = 1) inout highp vec4 o_color1;
layout(location = 2) inout highp vec4 o_color2[2];
uniform vec4 u_color;
vec4 addColor(vec4 lastValue, vec4 color)
{
return lastValue + color;
}
vec4 getColor2_1()
{
return o_color2[1];
}
void addUniform(inout vec4 outVar)
{
outVar += u_color;
}
void main (void)
{
// o_color0 and o_color2[0] don't use the input value.
o_color0 = u_color;
o_color2[0] = u_color;
addUniform(o_color1);
addUniform(o_color2[1]);
// Make sure reading back from the output variables returns the latest value and not the
// original input value.
vec4 temp1 = o_color1;
vec4 temp3 = getColor2_1();
o_color1 = temp1;
o_color2[1] = temp3;
})";
// Shared Non-Coherent Fragment Shaders for the tests below
//
// Non-coherent version of a 1.0 GLSL fragment shader that uses gl_LastFragData
static constexpr char k100NonCoherentFS[] = R"(#version 100
#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
layout(noncoherent) mediump vec4 gl_LastFragData[gl_MaxDrawBuffers];
uniform highp vec4 u_color;
void main (void)
{
gl_FragColor = u_color + gl_LastFragData[0];
})";
// Non-coherent version of a 3.1 GLSL fragment shader that writes to 1 attachment
static constexpr char k310NonCoherent1AttachmentFS[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
layout(noncoherent, location = 0) inout highp vec4 o_color;
uniform highp vec4 u_color;
void main (void)
{
o_color += u_color;
})";
// Non-coherent version of a 3.1 GLSL fragment shader that writes the output to a storage buffer.
static constexpr char k310NonCoherentStorageBuffer[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
layout(noncoherent) inout highp vec4 o_color;
layout(std140, binding = 0) buffer outBlock {
highp vec4 data[256];
};
uniform highp vec4 u_color;
void main (void)
{
uint index = uint(gl_FragCoord.y) * 16u + uint(gl_FragCoord.x);
data[index] = o_color;
o_color += u_color;
})";
// Non-coherent version of a 1.0 GLSL fragment shader that writes to 4 attachments with constant
// indices
static constexpr char k100NonCoherent4AttachmentFS[] = R"(#version 100
#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
#extension GL_EXT_draw_buffers : require
layout(noncoherent) mediump vec4 gl_LastFragData[gl_MaxDrawBuffers];
uniform highp vec4 u_color;
void main (void)
{
gl_FragData[0] = gl_LastFragData[0] + u_color;
gl_FragData[1] = gl_LastFragData[1] + u_color;
gl_FragData[2] = gl_LastFragData[2] + u_color;
gl_FragData[3] = gl_LastFragData[3] + u_color;
})";
// Non-coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments
static constexpr char k310NonCoherent4AttachmentFS[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
layout(noncoherent, location = 0) inout highp vec4 o_color0;
layout(noncoherent, location = 1) inout highp vec4 o_color1;
layout(noncoherent, location = 2) inout highp vec4 o_color2;
layout(noncoherent, location = 3) inout highp vec4 o_color3;
uniform highp vec4 u_color;
void main (void)
{
o_color0 += u_color;
o_color1 += u_color;
o_color2 += u_color;
o_color3 += u_color;
})";
// Non-coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments via an inout
// array
static constexpr char k310NonCoherent4AttachmentArrayFS[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
layout(noncoherent, location = 0) inout highp vec4 o_color[4];
uniform highp vec4 u_color;
void main (void)
{
o_color[0] += u_color;
o_color[1] += u_color;
o_color[2] += u_color;
o_color[3] += u_color;
})";
// Non-coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments with the order
// of non-fetch program and fetch program with different attachments (version 1)
static constexpr char k310NonCoherentDifferent4AttachmentFS1[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
layout(noncoherent, location = 0) inout highp vec4 o_color0;
layout(location = 1) out highp vec4 o_color1;
layout(noncoherent, location = 2) inout highp vec4 o_color2;
layout(location = 3) out highp vec4 o_color3;
uniform highp vec4 u_color;
void main (void)
{
o_color0 += u_color;
o_color1 = u_color;
o_color2 += u_color;
o_color3 = u_color;
})";
// Non-coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments with the order
// of non-fetch program and fetch program with different attachments (version 2)
static constexpr char k310NonCoherentDifferent4AttachmentFS2[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
layout(noncoherent, location = 0) inout highp vec4 o_color0;
layout(location = 1) out highp vec4 o_color1;
layout(location = 2) out highp vec4 o_color2;
layout(noncoherent, location = 3) inout highp vec4 o_color3;
uniform highp vec4 u_color;
void main (void)
{
o_color0 += u_color;
o_color1 = u_color;
o_color2 = u_color;
o_color3 += u_color;
})";
// Non-coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments, fetching from
// different indices (version 3)
static constexpr char k310NonCoherentDifferent4AttachmentFS3[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
layout(location = 0) out highp vec4 o_color0;
layout(noncoherent, location = 1) inout highp vec4 o_color1;
layout(noncoherent, location = 2) inout highp vec4 o_color2;
layout(location = 3) out highp vec4 o_color3;
uniform highp vec4 u_color;
void main (void)
{
o_color0 = u_color;
o_color1 += u_color;
o_color2 += u_color;
o_color3 = u_color;
})";
// Non-coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments, fetching from
// different indices (version 4)
static constexpr char k310NonCoherentDifferent4AttachmentFS4[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
layout(location = 0) out highp vec4 o_color0;
layout(location = 1) out highp vec4 o_color1;
layout(noncoherent, location = 2) inout highp vec4 o_color2;
layout(noncoherent, location = 3) inout highp vec4 o_color3;
uniform highp vec4 u_color;
void main (void)
{
o_color0 = u_color;
o_color1 = u_color;
o_color2 += u_color;
o_color3 += u_color;
})";
// Non-coherent version of a 1.0 GLSL fragment shader with complex interactions
static constexpr char k100NonCoherentComplexFS[] = R"(#version 100
#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
#extension GL_EXT_draw_buffers : require
precision highp float;
layout(noncoherent) mediump vec4 gl_LastFragData[gl_MaxDrawBuffers];
uniform vec4 u_color;
vec4 addColor(vec4 lastFragData, vec4 color)
{
return lastFragData + color;
}
void addLastFragData(inout vec4 outVar, vec4 lastFragData)
{
outVar += lastFragData;
}
void main (void)
{
// Leave gl_LastFragData[0] unused, as well as gl_LastFragData[2]
gl_FragData[0] = u_color;
gl_FragData[1] = addColor(gl_LastFragData[1], u_color);
gl_FragData[2] = u_color;
gl_FragData[3] = addColor(gl_LastFragData[3], u_color);
// Make sure gl_LastFragData is not clobbered by a write to gl_FragData.
gl_FragData[1] -= gl_LastFragData[1];
gl_FragData[3] -= gl_LastFragData[3];
// Test passing to inout variables.
addLastFragData(gl_FragData[1], gl_LastFragData[1]);
addLastFragData(gl_FragData[3], gl_LastFragData[3]);
})";
// Non-coherent version of a 3.1 GLSL fragment shader with complex interactions
static constexpr char k310NonCoherentComplexFS[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
precision highp float;
layout(location = 0) out highp vec4 o_color0;
layout(noncoherent, location = 1) inout highp vec4 o_color1;
layout(noncoherent, location = 2) inout highp vec4 o_color2[2];
uniform vec4 u_color;
vec4 addColor(vec4 lastValue, vec4 color)
{
return lastValue + color;
}
vec4 getColor2_1()
{
return o_color2[1];
}
void addUniform(inout vec4 outVar)
{
outVar += u_color;
}
void main (void)
{
// o_color0 and o_color2[0] don't use the input value.
o_color0 = u_color;
o_color2[0] = u_color;
addUniform(o_color1);
addUniform(o_color2[1]);
// Make sure reading back from the output variables returns the latest value and not the
// original input value.
vec4 temp1 = o_color1;
vec4 temp3 = getColor2_1();
o_color1 = temp1;
o_color2[1] = temp3;
})";
// Shared Coherent Fragment Shaders for the tests below
//
// Coherent version of a 1.0 GLSL fragment shader that uses gl_LastFragColorARM
static constexpr char k100ARMFS[] = R"(#version 100
#extension GL_ARM_shader_framebuffer_fetch : require
mediump vec4 gl_LastFragColorARM;
uniform highp vec4 u_color;
void main (void)
{
gl_FragColor = u_color + gl_LastFragColorARM;
})";
// ARM version of a 3.1 GLSL fragment shader that writes to 1 attachment
static constexpr char k310ARM1AttachmentFS[] = R"(#version 310 es
#extension GL_ARM_shader_framebuffer_fetch : require
layout(location = 0) out highp vec4 o_color;
uniform highp vec4 u_color;
void main (void)
{
o_color = u_color + gl_LastFragColorARM;
})";
// ARM version of a 3.1 GLSL fragment shader that writes the output to a storage buffer.
static constexpr char k310ARMStorageBuffer[] = R"(#version 310 es
#extension GL_ARM_shader_framebuffer_fetch : require
layout(location = 0) out highp vec4 o_color;
layout(std140, binding = 0) buffer outBlock {
highp vec4 data[256];
};
uniform highp vec4 u_color;
void main (void)
{
uint index = uint(gl_FragCoord.y) * 16u + uint(gl_FragCoord.x);
data[index] = gl_LastFragColorARM;
o_color = u_color + gl_LastFragColorARM;
})";
// Variants that use both EXT and ARM simultaneously. At least one app has been observed to do
// this.
static constexpr char k100BothFS[] = R"(#version 100
#extension GL_EXT_shader_framebuffer_fetch : require
#extension GL_ARM_shader_framebuffer_fetch : require
uniform highp vec4 u_color;
void main (void)
{
gl_FragColor = u_color + (gl_LastFragColorARM + gl_LastFragData[0]) / 2.;
})";
static constexpr char k310Both1AttachmentFS[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch : require
#extension GL_ARM_shader_framebuffer_fetch : require
inout highp vec4 o_color;
uniform highp vec4 u_color;
void main (void)
{
o_color = u_color + (o_color + gl_LastFragColorARM) / 2.;
})";
static constexpr char k100Both4AttachmentFS[] = R"(#version 100
#extension GL_EXT_shader_framebuffer_fetch : require
#extension GL_ARM_shader_framebuffer_fetch : require
#extension GL_EXT_draw_buffers : require
uniform highp vec4 u_color;
void main (void)
{
gl_FragData[0] = (gl_LastFragData[0] + gl_LastFragColorARM) / 2. + u_color;
gl_FragData[1] = gl_LastFragData[1] + u_color;
gl_FragData[2] = gl_LastFragData[2] + u_color;
gl_FragData[3] = gl_LastFragData[3] + u_color;
})";
static constexpr char k100BothComplexFS[] = R"(#version 100
#extension GL_EXT_shader_framebuffer_fetch : require
#extension GL_ARM_shader_framebuffer_fetch : require
#extension GL_EXT_draw_buffers : require
precision highp float;
uniform vec4 u_color;
vec4 addColor(vec4 lastFragData, vec4 color)
{
return lastFragData + color;
}
void addLastFragData(inout vec4 outVar, vec4 lastFragData)
{
outVar += lastFragData;
}
void main (void)
{
// Leave gl_LastFragData[1] unused, as well as gl_LastFragData[3]
gl_FragData[0] = addColor((gl_LastFragData[0] + gl_LastFragColorARM) / 2., u_color);
gl_FragData[1] = u_color;
gl_FragData[2] = addColor(gl_LastFragData[2], u_color);
gl_FragData[3] = u_color;
// Make sure gl_LastFragData is not clobbered by a write to gl_FragData.
gl_FragData[0] -= gl_LastFragColorARM;
gl_FragData[2] -= gl_LastFragData[2];
// Test passing to inout variables.
addLastFragData(gl_FragData[0], gl_LastFragData[0]);
addLastFragData(gl_FragData[2], gl_LastFragData[2]);
})";
static constexpr char k310BothComplexFS[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch : require
#extension GL_ARM_shader_framebuffer_fetch : require
precision highp float;
layout(location = 0) inout highp vec4 o_color0;
layout(location = 1) inout highp vec4 o_color1;
layout(location = 2) inout highp vec4 o_color2[2];
uniform vec4 u_color;
vec4 addColor(vec4 lastValue, vec4 color)
{
return lastValue + color;
}
vec4 getColor2_0()
{
return o_color2[0];
}
void addUniform(inout vec4 outVar)
{
outVar += u_color;
}
void main (void)
{
// o_color1 and o_color2[1] don't use the input value.
o_color1 = u_color;
o_color2[1] = u_color;
o_color0 = gl_LastFragColorARM + u_color;
addUniform(o_color2[0]);
// Make sure reading back from the output variables returns the latest value and not the
// original input value.
vec4 temp0 = o_color0;
vec4 temp2 = getColor2_0();
o_color0 = temp0;
o_color2[0] = temp2;
// Make sure gl_LastFragColorARM is not clobberred by the write to o_color0
if (gl_LastFragColorARM == o_color0)
o_color0 = vec4(0);
})";
class FramebufferFetchES31 : public ANGLETest<>
{
protected:
static constexpr GLuint kMaxColorBuffer = 4u;
static constexpr GLuint kViewportWidth = 16u;
static constexpr GLuint kViewportHeight = 16u;
FramebufferFetchES31()
{
setWindowWidth(16);
setWindowHeight(16);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
setConfigDepthBits(24);
mCoherentExtension = false;
mARMExtension = false;
mBothExtensions = false;
}
enum WhichExtension
{
COHERENT,
NON_COHERENT,
ARM,
BOTH,
};
void setWhichExtension(WhichExtension whichExtension)
{
mCoherentExtension = whichExtension != NON_COHERENT;
mARMExtension = whichExtension == ARM;
mBothExtensions = whichExtension == BOTH;
}
enum WhichFragmentShader
{
GLSL100,
GLSL310_NO_FETCH_1ATTACHMENT,
GLSL310_1ATTACHMENT,
GLSL310_1ATTACHMENT_WITH_STORAGE_BUFFER,
GLSL100_4ATTACHMENT,
GLSL100_COMPLEX,
GLSL310_4ATTACHMENT,
GLSL310_4ATTACHMENT_ARRAY,
GLSL310_4ATTACHMENT_DIFFERENT1,
GLSL310_4ATTACHMENT_DIFFERENT2,
GLSL310_4ATTACHMENT_DIFFERENT3,
GLSL310_4ATTACHMENT_DIFFERENT4,
GLSL310_COMPLEX,
};
const char *getFragmentShader(WhichFragmentShader whichFragmentShader)
{
if (mBothExtensions)
{
switch (whichFragmentShader)
{
case GLSL100:
return k100BothFS;
case GLSL310_NO_FETCH_1ATTACHMENT:
return k310NoFetch1AttachmentFS;
case GLSL310_1ATTACHMENT:
return k310Both1AttachmentFS;
case GLSL100_4ATTACHMENT:
return k100Both4AttachmentFS;
case GLSL100_COMPLEX:
return k100BothComplexFS;
case GLSL310_COMPLEX:
return k310BothComplexFS;
default:
UNREACHABLE();
return nullptr;
}
}
else if (mARMExtension)
{
// gl_LastFragColorARM cannot support multiple attachments
switch (whichFragmentShader)
{
case GLSL100:
return k100ARMFS;
case GLSL310_NO_FETCH_1ATTACHMENT:
return k310NoFetch1AttachmentFS;
case GLSL310_1ATTACHMENT:
return k310ARM1AttachmentFS;
case GLSL310_1ATTACHMENT_WITH_STORAGE_BUFFER:
return k310ARMStorageBuffer;
default:
UNREACHABLE();
return nullptr;
}
}
else if (mCoherentExtension)
{
switch (whichFragmentShader)
{
case GLSL100:
return k100CoherentFS;
case GLSL310_NO_FETCH_1ATTACHMENT:
return k310NoFetch1AttachmentFS;
case GLSL310_1ATTACHMENT:
return k310Coherent1AttachmentFS;
case GLSL310_1ATTACHMENT_WITH_STORAGE_BUFFER:
return k310CoherentStorageBuffer;
case GLSL100_4ATTACHMENT:
return k100Coherent4AttachmentFS;
case GLSL310_4ATTACHMENT:
return k310Coherent4AttachmentFS;
case GLSL310_4ATTACHMENT_ARRAY:
return k310Coherent4AttachmentArrayFS;
case GLSL310_4ATTACHMENT_DIFFERENT1:
return k310CoherentDifferent4AttachmentFS1;
case GLSL310_4ATTACHMENT_DIFFERENT2:
return k310CoherentDifferent4AttachmentFS2;
case GLSL310_4ATTACHMENT_DIFFERENT3:
return k310CoherentDifferent4AttachmentFS3;
case GLSL310_4ATTACHMENT_DIFFERENT4:
return k310CoherentDifferent4AttachmentFS4;
case GLSL100_COMPLEX:
return k100CoherentComplexFS;
case GLSL310_COMPLEX:
return k310CoherentComplexFS;
default:
UNREACHABLE();
return nullptr;
}
}
else
{
switch (whichFragmentShader)
{
case GLSL100:
return k100NonCoherentFS;
case GLSL310_NO_FETCH_1ATTACHMENT:
return k310NoFetch1AttachmentFS;
case GLSL310_1ATTACHMENT:
return k310NonCoherent1AttachmentFS;
case GLSL310_1ATTACHMENT_WITH_STORAGE_BUFFER:
return k310NonCoherentStorageBuffer;
case GLSL100_4ATTACHMENT:
return k100NonCoherent4AttachmentFS;
case GLSL310_4ATTACHMENT:
return k310NonCoherent4AttachmentFS;
case GLSL310_4ATTACHMENT_ARRAY:
return k310NonCoherent4AttachmentArrayFS;
case GLSL310_4ATTACHMENT_DIFFERENT1:
return k310NonCoherentDifferent4AttachmentFS1;
case GLSL310_4ATTACHMENT_DIFFERENT2:
return k310NonCoherentDifferent4AttachmentFS2;
case GLSL310_4ATTACHMENT_DIFFERENT3:
return k310NonCoherentDifferent4AttachmentFS3;
case GLSL310_4ATTACHMENT_DIFFERENT4:
return k310NonCoherentDifferent4AttachmentFS4;
case GLSL100_COMPLEX:
return k100NonCoherentComplexFS;
case GLSL310_COMPLEX:
return k310NonCoherentComplexFS;
default:
UNREACHABLE();
return nullptr;
}
}
}
void render(GLuint coordLoc, GLboolean needsFramebufferFetchBarrier)
{
const GLfloat coords[] = {
-1.0f, -1.0f, +1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f,
};
const GLushort indices[] = {
0, 1, 2, 2, 3, 0,
};
glViewport(0, 0, kViewportWidth, kViewportHeight);
GLBuffer coordinatesBuffer;
GLBuffer elementsBuffer;
glBindBuffer(GL_ARRAY_BUFFER, coordinatesBuffer);
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)sizeof(coords), coords, GL_STATIC_DRAW);
glEnableVertexAttribArray(coordLoc);
glVertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementsBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)sizeof(indices), &indices[0],
GL_STATIC_DRAW);
if (needsFramebufferFetchBarrier)
{
glFramebufferFetchBarrierEXT();
}
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
ASSERT_GL_NO_ERROR();
}
void BasicTest(GLProgram &program)
{
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
std::vector<GLColor> greenColor(kViewportWidth * kViewportHeight, GLColor::green);
GLTexture colorBufferTex;
glBindTexture(GL_TEXTURE_2D, colorBufferTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, greenColor.data());
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTex,
0);
ASSERT_GL_NO_ERROR();
float color[4] = {1.0f, 0.0f, 0.0f, 1.0f};
GLint colorLocation = glGetUniformLocation(program, "u_color");
glUniform4fv(colorLocation, 1, color);
GLint positionLocation = glGetAttribLocation(program, "a_position");
render(positionLocation, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void MultipleRenderTargetTest(GLProgram &program, WhichFragmentShader whichFragmentShader)
{
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
std::vector<GLColor> color0(kViewportWidth * kViewportHeight, GLColor::cyan);
std::vector<GLColor> color1(kViewportWidth * kViewportHeight, GLColor::green);
std::vector<GLColor> color2(kViewportWidth * kViewportHeight, GLColor::blue);
std::vector<GLColor> color3(kViewportWidth * kViewportHeight, GLColor::black);
GLTexture colorBufferTex[kMaxColorBuffer];
GLenum colorAttachments[kMaxColorBuffer] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
glBindTexture(GL_TEXTURE_2D, colorBufferTex[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color0.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color1.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color2.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex[3]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color3.data());
glBindTexture(GL_TEXTURE_2D, 0);
for (unsigned int i = 0; i < kMaxColorBuffer; i++)
{
glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[i], GL_TEXTURE_2D,
colorBufferTex[i], 0);
}
glDrawBuffers(kMaxColorBuffer, &colorAttachments[0]);
ASSERT_GL_NO_ERROR();
float color[4] = {1.0f, 0.0f, 0.0f, 1.0f};
GLint colorLocation = glGetUniformLocation(program, "u_color");
glUniform4fv(colorLocation, 1, color);
GLint positionLocation = glGetAttribLocation(program, "a_position");
render(positionLocation, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
// All fragment shaders add the input color with the uniform. Except the COMPLEX shaders
// which initialize attachments 0 and 2, or 1 and 3 with the uniform only (and don't use
// input attachments for these indices).
GLColor expect0 = GLColor::white;
GLColor expect1 = GLColor::yellow;
GLColor expect2 = GLColor::magenta;
GLColor expect3 = GLColor::red;
switch (whichFragmentShader)
{
case GLSL100_COMPLEX:
case GLSL310_COMPLEX:
if (mBothExtensions)
{
expect1 = GLColor::red;
expect3 = GLColor::red;
}
else
{
expect0 = GLColor::red;
expect2 = GLColor::red;
}
break;
default:
break;
}
glReadBuffer(colorAttachments[0]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, expect0);
glReadBuffer(colorAttachments[1]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, expect1);
glReadBuffer(colorAttachments[2]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, expect2);
glReadBuffer(colorAttachments[3]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, expect3);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void MultipleRenderTargetArrayTest(GLProgram &program)
{
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
std::vector<GLColor> color0(kViewportWidth * kViewportHeight, GLColor::black);
std::vector<GLColor> color1(kViewportWidth * kViewportHeight, GLColor::green);
std::vector<GLColor> color2(kViewportWidth * kViewportHeight, GLColor::blue);
std::vector<GLColor> color3(kViewportWidth * kViewportHeight, GLColor::cyan);
GLTexture colorBufferTex[kMaxColorBuffer];
GLenum colorAttachments[kMaxColorBuffer] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
glBindTexture(GL_TEXTURE_2D, colorBufferTex[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color0.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color1.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color2.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex[3]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color3.data());
glBindTexture(GL_TEXTURE_2D, 0);
for (unsigned int i = 0; i < kMaxColorBuffer; i++)
{
glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[i], GL_TEXTURE_2D,
colorBufferTex[i], 0);
}
glDrawBuffers(kMaxColorBuffer, &colorAttachments[0]);
ASSERT_GL_NO_ERROR();
float color[4] = {1.0f, 0.0f, 0.0f, 1.0f};
GLint colorLocation = glGetUniformLocation(program, "u_color");
glUniform4fv(colorLocation, 1, color);
GLint positionLocation = glGetAttribLocation(program, "a_position");
render(positionLocation, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
glReadBuffer(colorAttachments[0]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
glReadBuffer(colorAttachments[1]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
glReadBuffer(colorAttachments[2]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
glReadBuffer(colorAttachments[3]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::white);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void MultipleDrawTest(GLProgram &program)
{
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
std::vector<GLColor> greenColor(kViewportWidth * kViewportHeight, GLColor::green);
GLTexture colorBufferTex;
glBindTexture(GL_TEXTURE_2D, colorBufferTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, greenColor.data());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTex,
0);
ASSERT_GL_NO_ERROR();
float color1[4] = {1.0f, 0.0f, 0.0f, 1.0f};
GLint colorLocation = glGetUniformLocation(program, "u_color");
glUniform4fv(colorLocation, 1, color1);
GLint positionLocation = glGetAttribLocation(program, "a_position");
render(positionLocation, !mCoherentExtension);
float color2[4] = {0.0f, 0.0f, 1.0f, 1.0f};
glUniform4fv(colorLocation, 1, color2);
render(positionLocation, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::white);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void DrawNonFetchDrawFetchTest(GLProgram &programNonFetch, GLProgram &programFetch)
{
glUseProgram(programNonFetch);
ASSERT_GL_NO_ERROR();
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
std::vector<GLColor> greenColor(kViewportWidth * kViewportHeight, GLColor::green);
GLTexture colorBufferTex;
glBindTexture(GL_TEXTURE_2D, colorBufferTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, greenColor.data());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTex,
0);
ASSERT_GL_NO_ERROR();
float colorRed[4] = {1.0f, 0.0f, 0.0f, 1.0f};
GLint colorLocationNonFetch = glGetUniformLocation(programNonFetch, "u_color");
glUniform4fv(colorLocationNonFetch, 1, colorRed);
GLint positionLocationNonFetch = glGetAttribLocation(programNonFetch, "a_position");
// Render without regard to glFramebufferFetchBarrierEXT()
render(positionLocationNonFetch, GL_FALSE);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
glUseProgram(programFetch);
float colorGreen[4] = {0.0f, 1.0f, 0.0f, 1.0f};
GLint colorLocationFetch = glGetUniformLocation(programFetch, "u_color");
glUniform4fv(colorLocationFetch, 1, colorGreen);
GLint positionLocationFetch = glGetAttribLocation(programFetch, "a_position");
// Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
// extension being used
render(positionLocationFetch, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
glUseProgram(programNonFetch);
glUniform4fv(colorLocationNonFetch, 1, colorRed);
// Render without regard to glFramebufferFetchBarrierEXT()
render(positionLocationNonFetch, GL_FALSE);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
glUseProgram(programFetch);
glUniform4fv(colorLocationFetch, 1, colorGreen);
// Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
// extension being used
render(positionLocationFetch, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void DrawFetchDrawNonFetchTest(GLProgram &programNonFetch, GLProgram &programFetch)
{
glUseProgram(programFetch);
ASSERT_GL_NO_ERROR();
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
std::vector<GLColor> greenColor(kViewportWidth * kViewportHeight, GLColor::green);
GLTexture colorBufferTex;
glBindTexture(GL_TEXTURE_2D, colorBufferTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, greenColor.data());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTex,
0);
ASSERT_GL_NO_ERROR();
float colorRed[4] = {1.0f, 0.0f, 0.0f, 1.0f};
GLint colorLocationFetch = glGetUniformLocation(programFetch, "u_color");
glUniform4fv(colorLocationFetch, 1, colorRed);
GLint positionLocationFetch = glGetAttribLocation(programFetch, "a_position");
// Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
// extension being used
render(positionLocationFetch, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
glUseProgram(programNonFetch);
GLint colorLocationNonFetch = glGetUniformLocation(programNonFetch, "u_color");
glUniform4fv(colorLocationNonFetch, 1, colorRed);
GLint positionLocationNonFetch = glGetAttribLocation(programNonFetch, "a_position");
// Render without regard to glFramebufferFetchBarrierEXT()
render(positionLocationNonFetch, GL_FALSE);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
float colorGreen[4] = {0.0f, 1.0f, 0.0f, 1.0f};
glUseProgram(programFetch);
glUniform4fv(colorLocationFetch, 1, colorGreen);
// Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
// extension being used
render(positionLocationFetch, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
glUseProgram(programNonFetch);
glUniform4fv(colorLocationNonFetch, 1, colorRed);
// Render without regard to glFramebufferFetchBarrierEXT()
render(positionLocationNonFetch, GL_FALSE);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
enum class StorageBufferTestPostFetchAction
{
Nothing,
Clear,
};
void DrawNonFetchDrawFetchInStorageBufferTest(GLProgram &programNonFetch,
GLProgram &programFetch,
StorageBufferTestPostFetchAction postFetchAction)
{
// Create output buffer
constexpr GLsizei kBufferSize = kViewportWidth * kViewportHeight * sizeof(float[4]);
GLBuffer buffer;
glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kBufferSize, nullptr, GL_STATIC_DRAW);
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, buffer, 0, kBufferSize);
// Zero-initialize it
void *bufferData = glMapBufferRange(
GL_SHADER_STORAGE_BUFFER, 0, kBufferSize,
GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
memset(bufferData, 0, kBufferSize);
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
glUseProgram(programNonFetch);
ASSERT_GL_NO_ERROR();
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
std::vector<GLColor> initColor(kViewportWidth * kViewportHeight, GLColor{10, 20, 30, 40});
GLTexture colorBufferTex;
glBindTexture(GL_TEXTURE_2D, colorBufferTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, initColor.data());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTex,
0);
ASSERT_GL_NO_ERROR();
float colorRed[4] = {1.0f, 0.0f, 0.0f, 1.0f};
GLint colorLocationNonFetch = glGetUniformLocation(programNonFetch, "u_color");
glUniform4fv(colorLocationNonFetch, 1, colorRed);
GLint positionLocationNonFetch = glGetAttribLocation(programNonFetch, "a_position");
// Mask color output. The no-fetch draw call should be a no-op, and the fetch draw-call
// should only output to the storage buffer, but not the color attachment.
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
// Render without regard to glFramebufferFetchBarrierEXT()
render(positionLocationNonFetch, GL_FALSE);
ASSERT_GL_NO_ERROR();
glUseProgram(programFetch);
float colorBlue[4] = {0.0f, 0.0f, 1.0f, 1.0f};
GLint colorLocationFetch = glGetUniformLocation(programFetch, "u_color");
glUniform4fv(colorLocationFetch, 1, colorBlue);
GLint positionLocationFetch = glGetAttribLocation(programFetch, "a_position");
// Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
// extension being used
render(positionLocationFetch, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
// Enable the color mask and clear the alpha channel. This shouldn't be reordered with the
// fetch draw.
GLColor expect = initColor[0];
if (postFetchAction == StorageBufferTestPostFetchAction::Clear)
{
expect.A = 200;
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
glClearColor(0.5, 0.6, 0.7, expect.A / 255.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
// Since color is completely masked out, the texture should retain its original green color.
EXPECT_PIXEL_COLOR_NEAR(kViewportWidth / 2, kViewportHeight / 2, expect, 1);
// Read back the storage buffer and make sure framebuffer fetch worked as intended despite
// masked color.
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
const float *colorData = static_cast<const float *>(
glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kBufferSize, GL_MAP_READ_BIT));
for (uint32_t y = 0; y < kViewportHeight; ++y)
{
for (uint32_t x = 0; x < kViewportWidth; ++x)
{
uint32_t ssboIndex = (y * kViewportWidth + x) * 4;
EXPECT_NEAR(colorData[ssboIndex + 0], initColor[0].R / 255.0, 0.05);
EXPECT_NEAR(colorData[ssboIndex + 1], initColor[0].G / 255.0, 0.05);
EXPECT_NEAR(colorData[ssboIndex + 2], initColor[0].B / 255.0, 0.05);
EXPECT_NEAR(colorData[ssboIndex + 3], initColor[0].A / 255.0, 0.05);
}
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void DrawNonFetchDrawFetchWithDifferentAttachmentsTest(GLProgram &programNonFetch,
GLProgram &programFetch)
{
glUseProgram(programNonFetch);
ASSERT_GL_NO_ERROR();
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
std::vector<GLColor> greenColor(kViewportWidth * kViewportHeight, GLColor::green);
GLTexture colorTex;
glBindTexture(GL_TEXTURE_2D, colorTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, greenColor.data());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0);
ASSERT_GL_NO_ERROR();
float colorRed[4] = {1.0f, 0.0f, 0.0f, 1.0f};
GLint colorLocationNonFetch = glGetUniformLocation(programNonFetch, "u_color");
glUniform4fv(colorLocationNonFetch, 1, colorRed);
GLint positionLocationNonFetch = glGetAttribLocation(programNonFetch, "a_position");
// Render without regard to glFramebufferFetchBarrierEXT()
render(positionLocationNonFetch, GL_FALSE);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
glUseProgram(programFetch);
ASSERT_GL_NO_ERROR();
GLFramebuffer framebufferMRT1;
glBindFramebuffer(GL_FRAMEBUFFER, framebufferMRT1);
std::vector<GLColor> color1(kViewportWidth * kViewportHeight, GLColor::green);
std::vector<GLColor> color2(kViewportWidth * kViewportHeight, GLColor::blue);
GLTexture colorBufferTex1[kMaxColorBuffer];
GLenum colorAttachments[kMaxColorBuffer] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
glBindTexture(GL_TEXTURE_2D, colorBufferTex1[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color1.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex1[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color1.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex1[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color2.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex1[3]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color2.data());
glBindTexture(GL_TEXTURE_2D, 0);
for (unsigned int i = 0; i < kMaxColorBuffer; i++)
{
glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[i], GL_TEXTURE_2D,
colorBufferTex1[i], 0);
}
glDrawBuffers(kMaxColorBuffer, &colorAttachments[0]);
ASSERT_GL_NO_ERROR();
GLint colorLocation = glGetUniformLocation(programFetch, "u_color");
glUniform4fv(colorLocation, 1, colorRed);
GLint positionLocation = glGetAttribLocation(programFetch, "a_position");
// Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
// extension being used
render(positionLocation, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
glReadBuffer(colorAttachments[0]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
glReadBuffer(colorAttachments[1]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
glReadBuffer(colorAttachments[2]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
glReadBuffer(colorAttachments[3]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
GLFramebuffer framebufferMRT2;
glBindFramebuffer(GL_FRAMEBUFFER, framebufferMRT2);
GLTexture colorBufferTex2[kMaxColorBuffer];
glBindTexture(GL_TEXTURE_2D, colorBufferTex2[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color2.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex2[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color2.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex2[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color1.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex2[3]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color1.data());
glBindTexture(GL_TEXTURE_2D, 0);
for (unsigned int i = 0; i < kMaxColorBuffer; i++)
{
glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[i], GL_TEXTURE_2D,
colorBufferTex2[i], 0);
}
glDrawBuffers(kMaxColorBuffer, &colorAttachments[0]);
ASSERT_GL_NO_ERROR();
glUniform4fv(colorLocation, 1, colorRed);
// Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
// extension being used
render(positionLocation, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
glReadBuffer(colorAttachments[0]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
glReadBuffer(colorAttachments[1]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
glReadBuffer(colorAttachments[2]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
glReadBuffer(colorAttachments[3]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void DrawNonFetchDrawFetchWithDifferentProgramsTest(GLProgram &programNonFetch,
GLProgram &programFetch1,
GLProgram &programFetch2)
{
glUseProgram(programNonFetch);
ASSERT_GL_NO_ERROR();
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
std::vector<GLColor> greenColor(kViewportWidth * kViewportHeight, GLColor::green);
GLTexture colorTex;
glBindTexture(GL_TEXTURE_2D, colorTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, greenColor.data());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0);
ASSERT_GL_NO_ERROR();
float colorRed[4] = {1.0f, 0.0f, 0.0f, 1.0f};
GLint colorLocationNonFetch = glGetUniformLocation(programNonFetch, "u_color");
glUniform4fv(colorLocationNonFetch, 1, colorRed);
GLint positionLocationNonFetch = glGetAttribLocation(programNonFetch, "a_position");
// Render without regard to glFramebufferFetchBarrierEXT()
render(positionLocationNonFetch, GL_FALSE);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
glUseProgram(programFetch1);
ASSERT_GL_NO_ERROR();
GLFramebuffer framebufferMRT1;
glBindFramebuffer(GL_FRAMEBUFFER, framebufferMRT1);
std::vector<GLColor> color1(kViewportWidth * kViewportHeight, GLColor::green);
GLTexture colorBufferTex1[kMaxColorBuffer];
GLenum colorAttachments[kMaxColorBuffer] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
for (unsigned int i = 0; i < kMaxColorBuffer; i++)
{
glBindTexture(GL_TEXTURE_2D, colorBufferTex1[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color1.data());
glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[i], GL_TEXTURE_2D,
colorBufferTex1[i], 0);
}
glBindTexture(GL_TEXTURE_2D, 0);
glDrawBuffers(kMaxColorBuffer, &colorAttachments[0]);
ASSERT_GL_NO_ERROR();
GLint colorLocation = glGetUniformLocation(programFetch1, "u_color");
glUniform4fv(colorLocation, 1, colorRed);
GLint positionLocation = glGetAttribLocation(programFetch1, "a_position");
// Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
// extension being used
render(positionLocation, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
glReadBuffer(colorAttachments[0]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
glReadBuffer(colorAttachments[1]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
glReadBuffer(colorAttachments[2]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
glReadBuffer(colorAttachments[3]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
glUseProgram(programFetch2);
ASSERT_GL_NO_ERROR();
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLint colorLocation1 = glGetUniformLocation(programFetch2, "u_color");
glUniform4fv(colorLocation1, 1, colorRed);
GLint positionLocation1 = glGetAttribLocation(programFetch2, "a_position");
// Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
// extension being used
render(positionLocation1, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
glReadBuffer(colorAttachments[0]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
glReadBuffer(colorAttachments[1]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
glReadBuffer(colorAttachments[2]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
glReadBuffer(colorAttachments[3]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void DrawFetchWithDifferentIndicesInSameRenderPassTest(GLProgram &programFetch1,
GLProgram &programFetch2)
{
GLFramebuffer framebufferMRT1;
glBindFramebuffer(GL_FRAMEBUFFER, framebufferMRT1);
std::vector<GLColor> color1(kViewportWidth * kViewportHeight, GLColor::green);
GLTexture colorBufferTex1[kMaxColorBuffer];
GLenum colorAttachments[kMaxColorBuffer] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
for (unsigned int i = 0; i < kMaxColorBuffer; i++)
{
glBindTexture(GL_TEXTURE_2D, colorBufferTex1[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color1.data());
glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[i], GL_TEXTURE_2D,
colorBufferTex1[i], 0);
}
glBindTexture(GL_TEXTURE_2D, 0);
glDrawBuffers(kMaxColorBuffer, &colorAttachments[0]);
ASSERT_GL_NO_ERROR();
glUseProgram(programFetch1);
ASSERT_GL_NO_ERROR();
GLint colorLocation = glGetUniformLocation(programFetch1, "u_color");
const float colorRed[4] = {1.0f, 0.0f, 0.0f, 1.0f};
glUniform4fv(colorLocation, 1, colorRed);
GLint positionLocation = glGetAttribLocation(programFetch1, "a_position");
// Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
// extension being used
//
// Attachments are red, yellow, yellow, red
render(positionLocation, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
glUseProgram(programFetch2);
ASSERT_GL_NO_ERROR();
GLint colorLocation1 = glGetUniformLocation(programFetch2, "u_color");
const float colorBlue[4] = {0.0f, 0.0f, 1.0f, 1.0f};
glUniform4fv(colorLocation1, 1, colorBlue);
GLint positionLocation1 = glGetAttribLocation(programFetch2, "a_position");
// Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
// extension being used
//
// Attachments are blue, blue, white, magenta
render(positionLocation1, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
glReadBuffer(colorAttachments[0]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::blue);
glReadBuffer(colorAttachments[1]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::blue);
glReadBuffer(colorAttachments[2]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::white);
glReadBuffer(colorAttachments[3]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void DrawFetchBlitDrawFetchTest(GLProgram &programNonFetch, GLProgram &programFetch)
{
glUseProgram(programFetch);
ASSERT_GL_NO_ERROR();
GLFramebuffer framebufferMRT1;
glBindFramebuffer(GL_FRAMEBUFFER, framebufferMRT1);
std::vector<GLColor> color1(kViewportWidth * kViewportHeight, GLColor::green);
std::vector<GLColor> color2(kViewportWidth * kViewportHeight, GLColor::blue);
GLTexture colorBufferTex1[kMaxColorBuffer];
GLenum colorAttachments[kMaxColorBuffer] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
glBindTexture(GL_TEXTURE_2D, colorBufferTex1[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color1.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex1[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color1.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex1[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color2.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex1[3]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color2.data());
glBindTexture(GL_TEXTURE_2D, 0);
for (unsigned int i = 0; i < kMaxColorBuffer; i++)
{
glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[i], GL_TEXTURE_2D,
colorBufferTex1[i], 0);
}
glDrawBuffers(kMaxColorBuffer, &colorAttachments[0]);
ASSERT_GL_NO_ERROR();
float colorRed[4] = {1.0f, 0.0f, 0.0f, 1.0f};
GLint colorLocation = glGetUniformLocation(programFetch, "u_color");
glUniform4fv(colorLocation, 1, colorRed);
GLint positionLocation = glGetAttribLocation(programFetch, "a_position");
// Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
// extension being used
render(positionLocation, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
glReadBuffer(colorAttachments[0]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
glReadBuffer(colorAttachments[1]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
glReadBuffer(colorAttachments[2]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
glReadBuffer(colorAttachments[3]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
GLFramebuffer framebufferColor;
glBindFramebuffer(GL_FRAMEBUFFER, framebufferColor);
GLTexture colorTex;
glBindTexture(GL_TEXTURE_2D, colorTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color2.data());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, framebufferColor);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, framebufferMRT1);
glBlitFramebuffer(0, 0, kViewportWidth, kViewportHeight, 0, 0, kViewportWidth,
kViewportHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
ASSERT_GL_NO_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, framebufferMRT1);
glReadBuffer(colorAttachments[0]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::blue);
glReadBuffer(colorAttachments[1]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::blue);
glReadBuffer(colorAttachments[2]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::blue);
glReadBuffer(colorAttachments[3]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::blue);
float colorGreen[4] = {0.0f, 1.0f, 0.0f, 1.0f};
glUniform4fv(colorLocation, 1, colorGreen);
// Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
// extension being used
render(positionLocation, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
glReadBuffer(colorAttachments[0]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::cyan);
glReadBuffer(colorAttachments[1]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::green);
glReadBuffer(colorAttachments[2]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::cyan);
glReadBuffer(colorAttachments[3]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::green);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void ProgramPipelineTest(const char *kVS, const char *kFS1, const char *kFS2)
{
GLProgram programVert, programNonFetch, programFetch;
const char *sourceArray[3] = {kVS, kFS1, kFS2};
GLShader vertShader(GL_VERTEX_SHADER);
glShaderSource(vertShader, 1, &sourceArray[0], nullptr);
glCompileShader(vertShader);
glProgramParameteri(programVert, GL_PROGRAM_SEPARABLE, GL_TRUE);
glAttachShader(programVert, vertShader);
glLinkProgram(programVert);
ASSERT_GL_NO_ERROR();
GLShader fragShader1(GL_FRAGMENT_SHADER);
glShaderSource(fragShader1, 1, &sourceArray[1], nullptr);
glCompileShader(fragShader1);
glProgramParameteri(programNonFetch, GL_PROGRAM_SEPARABLE, GL_TRUE);
glAttachShader(programNonFetch, fragShader1);
glLinkProgram(programNonFetch);
ASSERT_GL_NO_ERROR();
GLShader fragShader2(GL_FRAGMENT_SHADER);
glShaderSource(fragShader2, 1, &sourceArray[2], nullptr);
glCompileShader(fragShader2);
glProgramParameteri(programFetch, GL_PROGRAM_SEPARABLE, GL_TRUE);
glAttachShader(programFetch, fragShader2);
glLinkProgram(programFetch);
ASSERT_GL_NO_ERROR();
GLProgramPipeline pipeline1, pipeline2, pipeline3, pipeline4;
glUseProgramStages(pipeline1, GL_VERTEX_SHADER_BIT, programVert);
glUseProgramStages(pipeline1, GL_FRAGMENT_SHADER_BIT, programNonFetch);
glBindProgramPipeline(pipeline1);
ASSERT_GL_NO_ERROR();
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
std::vector<GLColor> greenColor(kViewportWidth * kViewportHeight, GLColor::green);
GLTexture colorBufferTex;
glBindTexture(GL_TEXTURE_2D, colorBufferTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, greenColor.data());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTex,
0);
ASSERT_GL_NO_ERROR();
glActiveShaderProgram(pipeline1, programNonFetch);
float colorRed[4] = {1.0f, 0.0f, 0.0f, 1.0f};
GLint colorLocationNonFetch = glGetUniformLocation(programNonFetch, "u_color");
glUniform4fv(colorLocationNonFetch, 1, colorRed);
ASSERT_GL_NO_ERROR();
glActiveShaderProgram(pipeline1, programVert);
GLint positionLocation = glGetAttribLocation(programVert, "a_position");
// Render without regard to glFramebufferFetchBarrierEXT()
render(positionLocation, GL_FALSE);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
glUseProgramStages(pipeline2, GL_VERTEX_SHADER_BIT, programVert);
glUseProgramStages(pipeline2, GL_FRAGMENT_SHADER_BIT, programFetch);
glBindProgramPipeline(pipeline2);
ASSERT_GL_NO_ERROR();
glActiveShaderProgram(pipeline2, programFetch);
float colorGreen[4] = {0.0f, 1.0f, 0.0f, 1.0f};
GLint colorLocationFetch = glGetUniformLocation(programFetch, "u_color");
glUniform4fv(colorLocationFetch, 1, colorGreen);
// Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
// extension being used
render(positionLocation, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
glUseProgramStages(pipeline3, GL_VERTEX_SHADER_BIT, programVert);
glUseProgramStages(pipeline3, GL_FRAGMENT_SHADER_BIT, programNonFetch);
glBindProgramPipeline(pipeline3);
ASSERT_GL_NO_ERROR();
glActiveShaderProgram(pipeline3, programNonFetch);
colorLocationNonFetch = glGetUniformLocation(programNonFetch, "u_color");
glUniform4fv(colorLocationNonFetch, 1, colorRed);
ASSERT_GL_NO_ERROR();
// Render without regard to glFramebufferFetchBarrierEXT()
render(positionLocation, GL_FALSE);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
glUseProgramStages(pipeline4, GL_VERTEX_SHADER_BIT, programVert);
glUseProgramStages(pipeline4, GL_FRAGMENT_SHADER_BIT, programFetch);
glBindProgramPipeline(pipeline4);
ASSERT_GL_NO_ERROR();
glActiveShaderProgram(pipeline4, programFetch);
colorLocationFetch = glGetUniformLocation(programFetch, "u_color");
glUniform4fv(colorLocationFetch, 1, colorGreen);
// Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
// extension being used
render(positionLocation, !mCoherentExtension);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
bool mCoherentExtension;
bool mARMExtension;
bool mBothExtensions;
};
// Test coherent extension with inout qualifier
TEST_P(FramebufferFetchES31, BasicInout_Coherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(COHERENT);
GLProgram program;
program.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
BasicTest(program);
}
// Test non-coherent extension with inout qualifier
TEST_P(FramebufferFetchES31, BasicInout_NonCoherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
setWhichExtension(NON_COHERENT);
GLProgram program;
program.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
BasicTest(program);
}
// Test coherent extension with gl_LastFragData
TEST_P(FramebufferFetchES31, BasicLastFragData_Coherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(COHERENT);
GLProgram program;
program.makeRaster(k100VS, getFragmentShader(GLSL100));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
BasicTest(program);
}
// Test non-coherent extension with gl_LastFragData
TEST_P(FramebufferFetchES31, BasicLastFragData_NonCoherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
setWhichExtension(NON_COHERENT);
GLProgram program;
program.makeRaster(k100VS, getFragmentShader(GLSL100));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
BasicTest(program);
}
// Testing coherent extension with multiple render target, using gl_FragData with constant indices
TEST_P(FramebufferFetchES31, MultipleRenderTarget_Coherent_FragData)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_draw_buffers"));
setWhichExtension(COHERENT);
GLProgram program;
program.makeRaster(k100VS, getFragmentShader(GLSL100_4ATTACHMENT));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
MultipleRenderTargetTest(program, GLSL100_4ATTACHMENT);
}
// Testing coherent extension with multiple render target, using gl_FragData with complex
// expressions
TEST_P(FramebufferFetchES31, MultipleRenderTarget_Coherent_FragData_Complex)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_draw_buffers"));
setWhichExtension(COHERENT);
GLProgram program;
program.makeRaster(k100VS, getFragmentShader(GLSL100_COMPLEX));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
MultipleRenderTargetTest(program, GLSL100_COMPLEX);
}
// Testing coherent extension with multiple render target, using inouts with complex expressions
TEST_P(FramebufferFetchES31, MultipleRenderTarget_Coherent_Complex)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(COHERENT);
GLProgram program;
program.makeRaster(k310VS, getFragmentShader(GLSL310_COMPLEX));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
MultipleRenderTargetTest(program, GLSL310_COMPLEX);
}
// Testing coherent extension with multiple render target
TEST_P(FramebufferFetchES31, MultipleRenderTarget_Coherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(COHERENT);
GLProgram program;
program.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
MultipleRenderTargetTest(program, GLSL310_4ATTACHMENT);
}
// Testing non-coherent extension with multiple render target, using gl_FragData with constant
// indices
TEST_P(FramebufferFetchES31, MultipleRenderTarget_NonCoherent_FragData)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_draw_buffers"));
setWhichExtension(NON_COHERENT);
GLProgram program;
program.makeRaster(k100VS, getFragmentShader(GLSL100_4ATTACHMENT));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
MultipleRenderTargetTest(program, GLSL100_4ATTACHMENT);
}
// Testing non-coherent extension with multiple render target, using gl_FragData with complex
// expressions
TEST_P(FramebufferFetchES31, MultipleRenderTarget_NonCoherent_FragData_Complex)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_draw_buffers"));
setWhichExtension(NON_COHERENT);
GLProgram program;
program.makeRaster(k100VS, getFragmentShader(GLSL100_COMPLEX));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
MultipleRenderTargetTest(program, GLSL100_COMPLEX);
}
// Testing non-coherent extension with multiple render target, using inouts with complex expressions
TEST_P(FramebufferFetchES31, MultipleRenderTarget_NonCoherent_Complex)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
setWhichExtension(NON_COHERENT);
GLProgram program;
program.makeRaster(k310VS, getFragmentShader(GLSL310_COMPLEX));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
MultipleRenderTargetTest(program, GLSL310_COMPLEX);
}
// Testing non-coherent extension with multiple render target
TEST_P(FramebufferFetchES31, MultipleRenderTarget_NonCoherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
setWhichExtension(NON_COHERENT);
GLProgram program;
program.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
MultipleRenderTargetTest(program, GLSL310_4ATTACHMENT);
}
// Testing non-coherent extension with multiple render target using inout array
TEST_P(FramebufferFetchES31, MultipleRenderTargetWithInoutArray_NonCoherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
setWhichExtension(NON_COHERENT);
GLProgram program;
program.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
MultipleRenderTargetTest(program, GLSL310_4ATTACHMENT);
}
// Testing coherent extension with multiple render target using inout array
TEST_P(FramebufferFetchES31, MultipleRenderTargetWithInoutArray_Coherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(COHERENT);
GLProgram program;
program.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
MultipleRenderTargetTest(program, GLSL310_4ATTACHMENT);
}
// Test coherent extension with multiple draw
TEST_P(FramebufferFetchES31, MultipleDraw_Coherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(COHERENT);
GLProgram program;
program.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
MultipleDrawTest(program);
}
// Test non-coherent extension with multiple draw
TEST_P(FramebufferFetchES31, MultipleDraw_NonCoherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
setWhichExtension(NON_COHERENT);
GLProgram program;
program.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
MultipleDrawTest(program);
}
// Testing coherent extension with the order of non-fetch program and fetch program
TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetch_Coherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(COHERENT);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
ASSERT_GL_NO_ERROR();
DrawNonFetchDrawFetchTest(programNonFetch, programFetch);
}
// Testing non-coherent extension with the order of non-fetch program and fetch program
TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetch_NonCoherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
setWhichExtension(NON_COHERENT);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
ASSERT_GL_NO_ERROR();
DrawNonFetchDrawFetchTest(programNonFetch, programFetch);
}
// Testing coherent extension with the order of fetch program and non-fetch program
TEST_P(FramebufferFetchES31, DrawFetchDrawNonFetch_Coherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(COHERENT);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
ASSERT_GL_NO_ERROR();
DrawFetchDrawNonFetchTest(programNonFetch, programFetch);
}
// Testing non-coherent extension with the order of fetch program and non-fetch program
TEST_P(FramebufferFetchES31, DrawFetchDrawNonFetch_NonCoherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
setWhichExtension(NON_COHERENT);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
ASSERT_GL_NO_ERROR();
DrawFetchDrawNonFetchTest(programNonFetch, programFetch);
}
// Testing coherent extension with framebuffer fetch read in combination with color attachment mask
TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetchInStorageBuffer_Coherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(COHERENT);
GLint maxFragmentShaderStorageBlocks = 0;
glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &maxFragmentShaderStorageBlocks);
ANGLE_SKIP_TEST_IF(maxFragmentShaderStorageBlocks == 0);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT_WITH_STORAGE_BUFFER));
ASSERT_GL_NO_ERROR();
DrawNonFetchDrawFetchInStorageBufferTest(programNonFetch, programFetch,
StorageBufferTestPostFetchAction::Nothing);
}
// Testing non-coherent extension with framebuffer fetch read in combination with color attachment
// mask
TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetchInStorageBuffer_NonCoherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
setWhichExtension(NON_COHERENT);
GLint maxFragmentShaderStorageBlocks = 0;
glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &maxFragmentShaderStorageBlocks);
ANGLE_SKIP_TEST_IF(maxFragmentShaderStorageBlocks == 0);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT_WITH_STORAGE_BUFFER));
ASSERT_GL_NO_ERROR();
DrawNonFetchDrawFetchInStorageBufferTest(programNonFetch, programFetch,
StorageBufferTestPostFetchAction::Nothing);
}
// Testing coherent extension with the order of non-fetch program and fetch program with
// different attachments
TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetchWithDifferentAttachments_Coherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(COHERENT);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT1));
ASSERT_GL_NO_ERROR();
DrawNonFetchDrawFetchWithDifferentAttachmentsTest(programNonFetch, programFetch);
}
// Testing coherent extension with framebuffer fetch read in combination with color attachment mask
// and clear
TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetchInStorageBufferThenClear_Coherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(COHERENT);
GLint maxFragmentShaderStorageBlocks = 0;
glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &maxFragmentShaderStorageBlocks);
ANGLE_SKIP_TEST_IF(maxFragmentShaderStorageBlocks == 0);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT_WITH_STORAGE_BUFFER));
ASSERT_GL_NO_ERROR();
DrawNonFetchDrawFetchInStorageBufferTest(programNonFetch, programFetch,
StorageBufferTestPostFetchAction::Clear);
}
// Testing non-coherent extension with framebuffer fetch read in combination with color attachment
// mask and clear
TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetchInStorageBufferThenClear_NonCoherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
setWhichExtension(NON_COHERENT);
GLint maxFragmentShaderStorageBlocks = 0;
glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &maxFragmentShaderStorageBlocks);
ANGLE_SKIP_TEST_IF(maxFragmentShaderStorageBlocks == 0);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT_WITH_STORAGE_BUFFER));
ASSERT_GL_NO_ERROR();
DrawNonFetchDrawFetchInStorageBufferTest(programNonFetch, programFetch,
StorageBufferTestPostFetchAction::Clear);
}
// Testing non-coherent extension with the order of non-fetch program and fetch program with
// different attachments
TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetchWithDifferentAttachments_NonCoherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
setWhichExtension(NON_COHERENT);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT1));
ASSERT_GL_NO_ERROR();
DrawNonFetchDrawFetchWithDifferentAttachmentsTest(programNonFetch, programFetch);
}
// Testing coherent extension with the order of non-fetch program and fetch with different
// programs
TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetchWithDifferentPrograms_Coherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(COHERENT);
GLProgram programNonFetch, programFetch1, programFetch2;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch1.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT1));
programFetch2.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT2));
ASSERT_GL_NO_ERROR();
DrawNonFetchDrawFetchWithDifferentProgramsTest(programNonFetch, programFetch1, programFetch2);
}
// Testing non-coherent extension with the order of non-fetch program and fetch with different
// programs
TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetchWithDifferentPrograms_NonCoherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
setWhichExtension(NON_COHERENT);
GLProgram programNonFetch, programFetch1, programFetch2;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch1.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT1));
programFetch2.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT2));
ASSERT_GL_NO_ERROR();
DrawNonFetchDrawFetchWithDifferentProgramsTest(programNonFetch, programFetch1, programFetch2);
}
// Testing coherent extension with two fetch programs using different attachments. The different
// sets of attachments start at different non-zero indices.
TEST_P(FramebufferFetchES31, DrawFetchWithDifferentIndicesInSameRenderPass_Coherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(COHERENT);
GLProgram programFetch1, programFetch2;
programFetch1.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT3));
programFetch2.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT4));
ASSERT_GL_NO_ERROR();
DrawFetchWithDifferentIndicesInSameRenderPassTest(programFetch1, programFetch2);
}
// Testing non-coherent extension with two fetch programs using different attachments. The
// different sets of attachments start at different non-zero indices.
TEST_P(FramebufferFetchES31, DrawFetchWithDifferentIndicesInSameRenderPass_NonCoherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
setWhichExtension(NON_COHERENT);
GLProgram programFetch1, programFetch2;
programFetch1.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT3));
programFetch2.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT4));
ASSERT_GL_NO_ERROR();
DrawFetchWithDifferentIndicesInSameRenderPassTest(programFetch1, programFetch2);
}
// Testing coherent extension with the order of draw fetch, blit and draw fetch
TEST_P(FramebufferFetchES31, DrawFetchBlitDrawFetch_Coherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(COHERENT);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT1));
ASSERT_GL_NO_ERROR();
DrawFetchBlitDrawFetchTest(programNonFetch, programFetch);
}
// Testing non-coherent extension with the order of draw fetch, blit and draw fetch
TEST_P(FramebufferFetchES31, DrawFetchBlitDrawFetch_NonCoherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
setWhichExtension(NON_COHERENT);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT1));
ASSERT_GL_NO_ERROR();
DrawFetchBlitDrawFetchTest(programNonFetch, programFetch);
}
// Testing coherent extension with program pipeline
TEST_P(FramebufferFetchES31, ProgramPipeline_Coherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(COHERENT);
ProgramPipelineTest(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT),
getFragmentShader(GLSL310_1ATTACHMENT));
}
// Testing non-coherent extension with program pipeline
TEST_P(FramebufferFetchES31, ProgramPipeline_NonCoherent)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
setWhichExtension(NON_COHERENT);
ProgramPipelineTest(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT),
getFragmentShader(GLSL310_1ATTACHMENT));
}
// Test combination of inout and samplers.
TEST_P(FramebufferFetchES31, UniformUsageCombinations)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
constexpr char kVS[] = R"(#version 310 es
in highp vec4 a_position;
out highp vec2 texCoord;
void main()
{
gl_Position = a_position;
texCoord = (a_position.xy * 0.5) + 0.5;
})";
constexpr char kFS[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
layout(binding=0, offset=0) uniform atomic_uint atDiff;
uniform sampler2D tex;
layout(noncoherent, location = 0) inout highp vec4 o_color[4];
in highp vec2 texCoord;
void main()
{
highp vec4 texColor = texture(tex, texCoord);
if (texColor != o_color[0])
{
atomicCounterIncrement(atDiff);
o_color[0] = texColor;
}
else
{
if (atomicCounter(atDiff) > 0u)
{
atomicCounterDecrement(atDiff);
}
}
if (texColor != o_color[1])
{
atomicCounterIncrement(atDiff);
o_color[1] = texColor;
}
else
{
if (atomicCounter(atDiff) > 0u)
{
atomicCounterDecrement(atDiff);
}
}
if (texColor != o_color[2])
{
atomicCounterIncrement(atDiff);
o_color[2] = texColor;
}
else
{
if (atomicCounter(atDiff) > 0u)
{
atomicCounterDecrement(atDiff);
}
}
if (texColor != o_color[3])
{
atomicCounterIncrement(atDiff);
o_color[3] = texColor;
}
else
{
if (atomicCounter(atDiff) > 0u)
{
atomicCounterDecrement(atDiff);
}
}
})";
GLProgram program;
program.makeRaster(kVS, kFS);
glUseProgram(program);
ASSERT_GL_NO_ERROR();
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
std::vector<GLColor> color0(kViewportWidth * kViewportHeight, GLColor::cyan);
std::vector<GLColor> color1(kViewportWidth * kViewportHeight, GLColor::green);
std::vector<GLColor> color2(kViewportWidth * kViewportHeight, GLColor::blue);
std::vector<GLColor> color3(kViewportWidth * kViewportHeight, GLColor::black);
GLTexture colorBufferTex[kMaxColorBuffer];
GLenum colorAttachments[kMaxColorBuffer] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
glBindTexture(GL_TEXTURE_2D, colorBufferTex[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color0.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color1.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color2.data());
glBindTexture(GL_TEXTURE_2D, colorBufferTex[3]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, color3.data());
glBindTexture(GL_TEXTURE_2D, 0);
for (unsigned int i = 0; i < kMaxColorBuffer; i++)
{
glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[i], GL_TEXTURE_2D,
colorBufferTex[i], 0);
}
glDrawBuffers(kMaxColorBuffer, &colorAttachments[0]);
ASSERT_GL_NO_ERROR();
GLBuffer atomicBuffer;
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicBuffer);
glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
// Reset atomic counter buffer
GLuint *userCounters;
userCounters = static_cast<GLuint *>(glMapBufferRange(
GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint),
GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT));
memset(userCounters, 0, sizeof(GLuint));
glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicBuffer);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
float color[4] = {1.0f, 0.0f, 0.0f, 1.0f};
GLint colorLocation = glGetUniformLocation(program, "u_color");
glUniform4fv(colorLocation, 1, color);
GLint positionLocation = glGetAttribLocation(program, "a_position");
render(positionLocation, GL_TRUE);
ASSERT_GL_NO_ERROR();
// Because no texture is bound, the shader samples black, increments the counter for every pixel
// and sets all attachments to black.
for (unsigned int i = 0; i < kMaxColorBuffer; i++)
{
glReadBuffer(colorAttachments[i]);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::black);
}
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicBuffer);
userCounters = static_cast<GLuint *>(
glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT));
EXPECT_EQ(*userCounters, kViewportWidth * kViewportHeight * 4);
glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
// Testing that binding the location value using GLES API is conflicted to the location value of the
// fragment inout.
TEST_P(FramebufferFetchES31, FixedUniformLocation)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
constexpr char kVS[] = R"(#version 310 es
in highp vec4 a_position;
void main (void)
{
gl_Position = a_position;
})";
constexpr char kFS[] = R"(#version 310 es
#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
layout(noncoherent, location = 0) inout highp vec4 o_color;
layout(location = 0) uniform highp vec4 u_color;
void main (void)
{
o_color += u_color;
})";
GLProgram program;
program.makeRaster(kVS, kFS);
glUseProgram(program);
ASSERT_GL_NO_ERROR();
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
std::vector<GLColor> greenColor(kViewportWidth * kViewportHeight, GLColor::green);
GLTexture colorBufferTex;
glBindTexture(GL_TEXTURE_2D, colorBufferTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, greenColor.data());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTex, 0);
ASSERT_GL_NO_ERROR();
float color[4] = {1.0f, 0.0f, 0.0f, 1.0f};
GLint colorLocation = glGetUniformLocation(program, "u_color");
glUniform4fv(colorLocation, 1, color);
GLint positionLocation = glGetAttribLocation(program, "a_position");
render(positionLocation, GL_TRUE);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
// Verify we can use inout with the default framebuffer
// http://anglebug.com/6893
TEST_P(FramebufferFetchES31, DefaultFramebufferTest)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
constexpr char kVS[] = R"(#version 300 es
in highp vec4 a_position;
void main (void)
{
gl_Position = a_position;
})";
constexpr char kFS[] = R"(#version 300 es
#extension GL_EXT_shader_framebuffer_fetch : require
layout(location = 0) inout highp vec4 o_color;
uniform highp vec4 u_color;
void main (void)
{
o_color += u_color;
})";
GLProgram program;
program.makeRaster(kVS, kFS);
glUseProgram(program);
ASSERT_GL_NO_ERROR();
// Ensure that we're rendering to the default framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Start with a clear buffer
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLint positionLocation = glGetAttribLocation(program, "a_position");
GLint colorLocation = glGetUniformLocation(program, "u_color");
// Draw once with red
glUniform4fv(colorLocation, 1, GLColor::red.toNormalizedVector().data());
render(positionLocation, GL_FALSE);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
ASSERT_GL_NO_ERROR();
// Draw again with blue, adding it to the existing red, ending up with magenta
glUniform4fv(colorLocation, 1, GLColor::blue.toNormalizedVector().data());
render(positionLocation, GL_FALSE);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
ASSERT_GL_NO_ERROR();
}
// Verify we can render to the default framebuffer without fetch, then switch to a program
// that does fetch.
// http://anglebug.com/6893
TEST_P(FramebufferFetchES31, DefaultFramebufferMixedProgramsTest)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
constexpr char kVS[] = R"(#version 300 es
in highp vec4 a_position;
void main (void)
{
gl_Position = a_position;
})";
constexpr char kFS[] = R"(#version 300 es
layout(location = 0) out highp vec4 o_color;
uniform highp vec4 u_color;
void main (void)
{
o_color = u_color;
})";
constexpr char kFetchFS[] = R"(#version 300 es
#extension GL_EXT_shader_framebuffer_fetch : require
layout(location = 0) inout highp vec4 o_color;
uniform highp vec4 u_color;
void main (void)
{
o_color += u_color;
})";
// Create a program that simply writes out a color, no fetching
GLProgram program;
program.makeRaster(kVS, kFS);
glUseProgram(program);
ASSERT_GL_NO_ERROR();
// Ensure that we're rendering to the default framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Start with a clear buffer
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLint positionLocation = glGetAttribLocation(program, "a_position");
GLint colorLocation = glGetUniformLocation(program, "u_color");
// Draw once with red
glUniform4fv(colorLocation, 1, GLColor::red.toNormalizedVector().data());
render(positionLocation, false);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
ASSERT_GL_NO_ERROR();
// Create another program that DOES fetch from the framebuffer
GLProgram program2;
program2.makeRaster(kVS, kFetchFS);
glUseProgram(program2);
GLint positionLocation2 = glGetAttribLocation(program2, "a_position");
GLint colorLocation2 = glGetUniformLocation(program2, "u_color");
// Draw again with blue, fetching red from the framebuffer, adding it together
glUniform4fv(colorLocation2, 1, GLColor::blue.toNormalizedVector().data());
render(positionLocation2, false);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
ASSERT_GL_NO_ERROR();
// Switch back to the non-fetched framebuffer, and render green
glUseProgram(program);
glUniform4fv(colorLocation, 1, GLColor::green.toNormalizedVector().data());
render(positionLocation, false);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::green);
ASSERT_GL_NO_ERROR();
}
// Verify we can render to a framebuffer with fetch, then switch to another framebuffer (without
// changing programs) http://anglebug.com/6893
TEST_P(FramebufferFetchES31, FramebufferMixedFetchTest)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
constexpr char kVS[] = R"(#version 300 es
in highp vec4 a_position;
void main (void)
{
gl_Position = a_position;
})";
constexpr char kFS[] = R"(#version 300 es
layout(location = 0) out highp vec4 o_color;
uniform highp vec4 u_color;
void main (void)
{
o_color = u_color;
})";
constexpr char kFetchFS[] = R"(#version 300 es
#extension GL_EXT_shader_framebuffer_fetch : require
layout(location = 0) inout highp vec4 o_color;
uniform highp vec4 u_color;
void main (void)
{
o_color += u_color;
})";
// Create a program that simply writes out a color, no fetching
GLProgram program;
program.makeRaster(kVS, kFS);
GLint positionLocation = glGetAttribLocation(program, "a_position");
GLint colorLocation = glGetUniformLocation(program, "u_color");
ASSERT_GL_NO_ERROR();
// Create a program that DOES fetch from the framebuffer
GLProgram fetchProgram;
fetchProgram.makeRaster(kVS, kFetchFS);
GLint fetchPositionLocation = glGetAttribLocation(fetchProgram, "a_position");
GLint fetchColorLocation = glGetUniformLocation(fetchProgram, "u_color");
ASSERT_GL_NO_ERROR();
// Create an empty framebuffer to use without fetch
GLFramebuffer framebuffer1;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
std::vector<GLColor> clearColor(kViewportWidth * kViewportHeight, GLColor::transparentBlack);
GLTexture colorBufferTex1;
glBindTexture(GL_TEXTURE_2D, colorBufferTex1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, clearColor.data());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTex1, 0);
ASSERT_GL_NO_ERROR();
// Draw to it with green, without using fetch, overwriting any contents
glUseProgram(program);
glUniform4fv(colorLocation, 1, GLColor::green.toNormalizedVector().data());
render(positionLocation, false);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::green);
ASSERT_GL_NO_ERROR();
// Create another framebuffer to use WITH fetch, and initialize it with blue
GLFramebuffer framebuffer2;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
std::vector<GLColor> blueColor(kViewportWidth * kViewportHeight, GLColor::blue);
GLTexture colorBufferTex2;
glBindTexture(GL_TEXTURE_2D, colorBufferTex2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, blueColor.data());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTex2, 0);
ASSERT_GL_NO_ERROR();
// Draw once with red, fetching blue from the framebuffer, adding it together
glUseProgram(fetchProgram);
glUniform4fv(fetchColorLocation, 1, GLColor::red.toNormalizedVector().data());
render(fetchPositionLocation, false);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
ASSERT_GL_NO_ERROR();
// Now use the same program (WITH fetch) and render to the other framebuffer that was NOT used
// with fetch. This verifies the framebuffer state is appropriately updated to match the
// program.
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
render(fetchPositionLocation, false);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
ASSERT_GL_NO_ERROR();
}
// Verify that switching between single sampled framebuffer fetch and multi sampled framebuffer
// fetch works fine
TEST_P(FramebufferFetchES31, SingleSampledMultiSampledMixedTest)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(COHERENT);
// Create a program that fetches from the framebuffer
GLProgram fetchProgram;
fetchProgram.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
GLint positionLocation = glGetAttribLocation(fetchProgram, "a_position");
GLint colorLocation = glGetUniformLocation(fetchProgram, "u_color");
ASSERT_GL_NO_ERROR();
// Create two single sampled framebuffer
GLRenderbuffer singleSampledRenderbuffer1;
glBindRenderbuffer(GL_RENDERBUFFER, singleSampledRenderbuffer1);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kViewportWidth, kViewportHeight);
GLFramebuffer singleSampledFramebuffer1;
glBindFramebuffer(GL_FRAMEBUFFER, singleSampledFramebuffer1);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
singleSampledRenderbuffer1);
GLRenderbuffer singleSampledRenderbuffer2;
glBindRenderbuffer(GL_RENDERBUFFER, singleSampledRenderbuffer2);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kViewportWidth, kViewportHeight);
GLFramebuffer singleSampledFramebuffer2;
glBindFramebuffer(GL_FRAMEBUFFER, singleSampledFramebuffer2);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
singleSampledRenderbuffer2);
// Create one multi sampled framebuffer
GLRenderbuffer multiSampledRenderbuffer;
glBindRenderbuffer(GL_RENDERBUFFER, multiSampledRenderbuffer);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, kViewportWidth, kViewportHeight);
GLFramebuffer multiSampledFramebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, multiSampledFramebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
multiSampledRenderbuffer);
// Create a singlesampled render buffer for blit and read
GLRenderbuffer resolvedRbo;
glBindRenderbuffer(GL_RENDERBUFFER, resolvedRbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kViewportWidth, kViewportHeight);
GLFramebuffer resolvedFbo;
glBindFramebuffer(GL_FRAMEBUFFER, resolvedFbo);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, resolvedRbo);
// Clear three Framebuffers with different colors
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glBindFramebuffer(GL_FRAMEBUFFER, singleSampledFramebuffer1);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::black);
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glBindFramebuffer(GL_FRAMEBUFFER, singleSampledFramebuffer2);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::blue);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glBindFramebuffer(GL_FRAMEBUFFER, multiSampledFramebuffer);
glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolvedFbo);
glBlitFramebuffer(0, 0, kViewportWidth, kViewportHeight, 0, 0, kViewportWidth, kViewportHeight,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolvedFbo);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::green);
// Bind first single sampled framebuffer, draw once with red, fetching black from the
// framebuffer
glUseProgram(fetchProgram);
glUniform4fv(colorLocation, 1, GLColor::red.toNormalizedVector().data());
glBindFramebuffer(GL_FRAMEBUFFER, singleSampledFramebuffer1);
render(positionLocation, false);
ASSERT_GL_NO_ERROR();
// Bind the multi sampled framebuffer, draw once with red, fetching green from the framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, multiSampledFramebuffer);
render(positionLocation, false);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolvedFbo);
glBlitFramebuffer(0, 0, kViewportWidth, kViewportHeight, 0, 0, kViewportWidth, kViewportHeight,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolvedFbo);
ASSERT_GL_NO_ERROR();
// Bind the single sampled framebuffer, draw once with red, fetching blue from the framebuffer
glUniform4fv(colorLocation, 1, GLColor::red.toNormalizedVector().data());
glBindFramebuffer(GL_FRAMEBUFFER, singleSampledFramebuffer2);
render(positionLocation, false);
ASSERT_GL_NO_ERROR();
// Verify the rendering result on all three framebuffers
// Verify the last framebuffer being drawn: singleSampledFramebuffer2
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
// Verify the second last framebuffer being drawn: multisampledFramebuffer
glBindFramebuffer(GL_READ_FRAMEBUFFER, multiSampledFramebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolvedFbo);
glBlitFramebuffer(0, 0, kViewportWidth, kViewportHeight, 0, 0, kViewportWidth, kViewportHeight,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolvedFbo);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
// Verify the first framebuffer being drawn: singleSampledFramebuffer1
glBindFramebuffer(GL_FRAMEBUFFER, singleSampledFramebuffer1);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
}
// Verify that calling glFramebufferFetchBarrierEXT without an open render pass is ok.
TEST_P(FramebufferFetchES31, BarrierBeforeDraw)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch") ||
!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
glFramebufferFetchBarrierEXT();
drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Test ARM extension with gl_LastFragColorARM
TEST_P(FramebufferFetchES31, BasicLastFragData_ARM)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
setWhichExtension(ARM);
GLProgram program;
program.makeRaster(k100VS, getFragmentShader(GLSL100));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
BasicTest(program);
}
// Test ARM extension with multiple draw
TEST_P(FramebufferFetchES31, MultipleDraw_ARM)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
setWhichExtension(ARM);
GLProgram program;
program.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
MultipleDrawTest(program);
}
// Testing ARM extension with the order of non-fetch program and fetch program
TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetch_ARM)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
setWhichExtension(ARM);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
ASSERT_GL_NO_ERROR();
DrawNonFetchDrawFetchTest(programNonFetch, programFetch);
}
// Testing ARM extension with the order of fetch program and non-fetch program
TEST_P(FramebufferFetchES31, DrawFetchDrawNonFetch_ARM)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
setWhichExtension(ARM);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
ASSERT_GL_NO_ERROR();
DrawFetchDrawNonFetchTest(programNonFetch, programFetch);
}
// Testing ARM extension with framebuffer fetch read in combination with color attachment mask
TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetchInStorageBuffer_ARM)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
setWhichExtension(ARM);
GLint maxFragmentShaderStorageBlocks = 0;
glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &maxFragmentShaderStorageBlocks);
ANGLE_SKIP_TEST_IF(maxFragmentShaderStorageBlocks == 0);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT_WITH_STORAGE_BUFFER));
ASSERT_GL_NO_ERROR();
DrawNonFetchDrawFetchInStorageBufferTest(programNonFetch, programFetch,
StorageBufferTestPostFetchAction::Nothing);
}
// Testing ARM extension with framebuffer fetch read in combination with color attachment mask
// and clear
TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetchInStorageBufferThenClear_ARM)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
setWhichExtension(ARM);
GLint maxFragmentShaderStorageBlocks = 0;
glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &maxFragmentShaderStorageBlocks);
ANGLE_SKIP_TEST_IF(maxFragmentShaderStorageBlocks == 0);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT_WITH_STORAGE_BUFFER));
ASSERT_GL_NO_ERROR();
DrawNonFetchDrawFetchInStorageBufferTest(programNonFetch, programFetch,
StorageBufferTestPostFetchAction::Clear);
}
// Testing ARM extension with program pipeline
TEST_P(FramebufferFetchES31, ProgramPipeline_ARM)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
setWhichExtension(ARM);
ProgramPipelineTest(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT),
getFragmentShader(GLSL310_1ATTACHMENT));
}
// Verify we can use the default framebuffer
// http://anglebug.com/6893
TEST_P(FramebufferFetchES31, DefaultFramebufferTest_ARM)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
constexpr char kVS[] = R"(#version 300 es
in highp vec4 a_position;
void main (void)
{
gl_Position = a_position;
})";
constexpr char kFS[] = R"(#version 300 es
#extension GL_ARM_shader_framebuffer_fetch : require
layout(location = 0) out highp vec4 o_color;
uniform highp vec4 u_color;
void main (void)
{
o_color = u_color + gl_LastFragColorARM;
})";
GLProgram program;
program.makeRaster(kVS, kFS);
glUseProgram(program);
ASSERT_GL_NO_ERROR();
// Ensure that we're rendering to the default framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Start with a clear buffer
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLint positionLocation = glGetAttribLocation(program, "a_position");
GLint colorLocation = glGetUniformLocation(program, "u_color");
// Draw once with red
glUniform4fv(colorLocation, 1, GLColor::red.toNormalizedVector().data());
render(positionLocation, GL_FALSE);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
ASSERT_GL_NO_ERROR();
// Draw again with blue, adding it to the existing red, ending up with magenta
glUniform4fv(colorLocation, 1, GLColor::blue.toNormalizedVector().data());
render(positionLocation, GL_FALSE);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
ASSERT_GL_NO_ERROR();
}
// Verify we can redeclare gl_LastFragColorARM with a new precision
// http://anglebug.com/6893
TEST_P(FramebufferFetchES31, NondefaultPrecisionTest_ARM)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
constexpr char kVS[] = R"(#version 300 es
in highp vec4 a_position;
void main (void)
{
gl_Position = a_position;
})";
constexpr char kFS[] = R"(#version 300 es
#extension GL_ARM_shader_framebuffer_fetch : require
highp vec4 gl_LastFragColorARM;
layout(location = 0) out highp vec4 o_color;
uniform highp vec4 u_color;
void main (void)
{
o_color = u_color + gl_LastFragColorARM;
})";
GLProgram program;
program.makeRaster(kVS, kFS);
glUseProgram(program);
ASSERT_GL_NO_ERROR();
// Ensure that we're rendering to the default framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Start with a clear buffer
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLint positionLocation = glGetAttribLocation(program, "a_position");
GLint colorLocation = glGetUniformLocation(program, "u_color");
// Draw once with red
glUniform4fv(colorLocation, 1, GLColor::red.toNormalizedVector().data());
render(positionLocation, GL_FALSE);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
ASSERT_GL_NO_ERROR();
// Draw again with blue, adding it to the existing red, ending up with magenta
glUniform4fv(colorLocation, 1, GLColor::blue.toNormalizedVector().data());
render(positionLocation, GL_FALSE);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
ASSERT_GL_NO_ERROR();
}
// Verify we can render to the default framebuffer without fetch, then switch to a program
// that does fetch.
// http://anglebug.com/6893
TEST_P(FramebufferFetchES31, DefaultFramebufferMixedProgramsTest_ARM)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
constexpr char kVS[] = R"(#version 300 es
in highp vec4 a_position;
void main (void)
{
gl_Position = a_position;
})";
constexpr char kFS[] = R"(#version 300 es
layout(location = 0) out highp vec4 o_color;
uniform highp vec4 u_color;
void main (void)
{
o_color = u_color;
})";
constexpr char kFetchFS[] = R"(#version 300 es
#extension GL_ARM_shader_framebuffer_fetch : require
layout(location = 0) out highp vec4 o_color;
uniform highp vec4 u_color;
void main (void)
{
o_color = u_color + gl_LastFragColorARM;
})";
// Create a program that simply writes out a color, no fetching
GLProgram program;
program.makeRaster(kVS, kFS);
glUseProgram(program);
ASSERT_GL_NO_ERROR();
// Ensure that we're rendering to the default framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Start with a clear buffer
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLint positionLocation = glGetAttribLocation(program, "a_position");
GLint colorLocation = glGetUniformLocation(program, "u_color");
// Draw once with red
glUniform4fv(colorLocation, 1, GLColor::red.toNormalizedVector().data());
render(positionLocation, false);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
ASSERT_GL_NO_ERROR();
// Create another program that DOES fetch from the framebuffer
GLProgram program2;
program2.makeRaster(kVS, kFetchFS);
glUseProgram(program2);
GLint positionLocation2 = glGetAttribLocation(program2, "a_position");
GLint colorLocation2 = glGetUniformLocation(program2, "u_color");
// Draw again with blue, fetching red from the framebuffer, adding it together
glUniform4fv(colorLocation2, 1, GLColor::blue.toNormalizedVector().data());
render(positionLocation2, false);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
ASSERT_GL_NO_ERROR();
// Switch back to the non-fetched framebuffer, and render green
glUseProgram(program);
glUniform4fv(colorLocation, 1, GLColor::green.toNormalizedVector().data());
render(positionLocation, false);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::green);
ASSERT_GL_NO_ERROR();
}
// Verify we can render to a framebuffer with fetch, then switch to another framebuffer (without
// changing programs) http://anglebug.com/6893
TEST_P(FramebufferFetchES31, FramebufferMixedFetchTest_ARM)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
constexpr char kVS[] = R"(#version 300 es
in highp vec4 a_position;
void main (void)
{
gl_Position = a_position;
})";
constexpr char kFS[] = R"(#version 300 es
layout(location = 0) out highp vec4 o_color;
uniform highp vec4 u_color;
void main (void)
{
o_color = u_color;
})";
constexpr char kFetchFS[] = R"(#version 300 es
#extension GL_ARM_shader_framebuffer_fetch : require
layout(location = 0) out highp vec4 o_color;
uniform highp vec4 u_color;
void main (void)
{
o_color = u_color + gl_LastFragColorARM;
})";
// Create a program that simply writes out a color, no fetching
GLProgram program;
program.makeRaster(kVS, kFS);
GLint positionLocation = glGetAttribLocation(program, "a_position");
GLint colorLocation = glGetUniformLocation(program, "u_color");
ASSERT_GL_NO_ERROR();
// Create a program that DOES fetch from the framebuffer
GLProgram fetchProgram;
fetchProgram.makeRaster(kVS, kFetchFS);
GLint fetchPositionLocation = glGetAttribLocation(fetchProgram, "a_position");
GLint fetchColorLocation = glGetUniformLocation(fetchProgram, "u_color");
ASSERT_GL_NO_ERROR();
// Create an empty framebuffer to use without fetch
GLFramebuffer framebuffer1;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
std::vector<GLColor> clearColor(kViewportWidth * kViewportHeight, GLColor::transparentBlack);
GLTexture colorBufferTex1;
glBindTexture(GL_TEXTURE_2D, colorBufferTex1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, clearColor.data());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTex1, 0);
ASSERT_GL_NO_ERROR();
// Draw to it with green, without using fetch, overwriting any contents
glUseProgram(program);
glUniform4fv(colorLocation, 1, GLColor::green.toNormalizedVector().data());
render(positionLocation, false);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::green);
ASSERT_GL_NO_ERROR();
// Create another framebuffer to use WITH fetch, and initialize it with blue
GLFramebuffer framebuffer2;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
std::vector<GLColor> blueColor(kViewportWidth * kViewportHeight, GLColor::blue);
GLTexture colorBufferTex2;
glBindTexture(GL_TEXTURE_2D, colorBufferTex2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, blueColor.data());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTex2, 0);
ASSERT_GL_NO_ERROR();
// Draw once with red, fetching blue from the framebuffer, adding it together
glUseProgram(fetchProgram);
glUniform4fv(fetchColorLocation, 1, GLColor::red.toNormalizedVector().data());
render(fetchPositionLocation, false);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
ASSERT_GL_NO_ERROR();
// Now use the same program (WITH fetch) and render to the other framebuffer that was NOT used
// with fetch. This verifies the framebuffer state is appropriately updated to match the
// program.
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
render(fetchPositionLocation, false);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
ASSERT_GL_NO_ERROR();
}
// Verify that switching between single sampled framebuffer fetch and multi sampled framebuffer
// fetch works fine
TEST_P(FramebufferFetchES31, SingleSampledMultiSampledMixedTest_ARM)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
setWhichExtension(ARM);
// Create a program that fetches from the framebuffer
GLProgram fetchProgram;
fetchProgram.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
GLint positionLocation = glGetAttribLocation(fetchProgram, "a_position");
GLint colorLocation = glGetUniformLocation(fetchProgram, "u_color");
ASSERT_GL_NO_ERROR();
// Create two single sampled framebuffer
GLRenderbuffer singleSampledRenderbuffer1;
glBindRenderbuffer(GL_RENDERBUFFER, singleSampledRenderbuffer1);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kViewportWidth, kViewportHeight);
GLFramebuffer singleSampledFramebuffer1;
glBindFramebuffer(GL_FRAMEBUFFER, singleSampledFramebuffer1);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
singleSampledRenderbuffer1);
GLRenderbuffer singleSampledRenderbuffer2;
glBindRenderbuffer(GL_RENDERBUFFER, singleSampledRenderbuffer2);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kViewportWidth, kViewportHeight);
GLFramebuffer singleSampledFramebuffer2;
glBindFramebuffer(GL_FRAMEBUFFER, singleSampledFramebuffer2);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
singleSampledRenderbuffer2);
// Create one multi sampled framebuffer
GLRenderbuffer multiSampledRenderbuffer;
glBindRenderbuffer(GL_RENDERBUFFER, multiSampledRenderbuffer);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, kViewportWidth, kViewportHeight);
GLFramebuffer multiSampledFramebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, multiSampledFramebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
multiSampledRenderbuffer);
// Create a singlesampled render buffer for blit and read
GLRenderbuffer resolvedRbo;
glBindRenderbuffer(GL_RENDERBUFFER, resolvedRbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kViewportWidth, kViewportHeight);
GLFramebuffer resolvedFbo;
glBindFramebuffer(GL_FRAMEBUFFER, resolvedFbo);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, resolvedRbo);
// Clear three Framebuffers with different colors
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glBindFramebuffer(GL_FRAMEBUFFER, singleSampledFramebuffer1);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::black);
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glBindFramebuffer(GL_FRAMEBUFFER, singleSampledFramebuffer2);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::blue);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glBindFramebuffer(GL_FRAMEBUFFER, multiSampledFramebuffer);
glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolvedFbo);
glBlitFramebuffer(0, 0, kViewportWidth, kViewportHeight, 0, 0, kViewportWidth, kViewportHeight,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolvedFbo);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::green);
// Bind first single sampled framebuffer, draw once with red, fetching black from the
// framebuffer
glUseProgram(fetchProgram);
glUniform4fv(colorLocation, 1, GLColor::red.toNormalizedVector().data());
glBindFramebuffer(GL_FRAMEBUFFER, singleSampledFramebuffer1);
render(positionLocation, false);
ASSERT_GL_NO_ERROR();
// Bind the multi sampled framebuffer, draw once with red, fetching green from the framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, multiSampledFramebuffer);
render(positionLocation, false);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolvedFbo);
glBlitFramebuffer(0, 0, kViewportWidth, kViewportHeight, 0, 0, kViewportWidth, kViewportHeight,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolvedFbo);
ASSERT_GL_NO_ERROR();
// Bind the single sampled framebuffer, draw once with red, fetching blue from the framebuffer
glUniform4fv(colorLocation, 1, GLColor::red.toNormalizedVector().data());
glBindFramebuffer(GL_FRAMEBUFFER, singleSampledFramebuffer2);
render(positionLocation, false);
ASSERT_GL_NO_ERROR();
// Verify the rendering result on all three framebuffers
// Verify the last framebuffer being drawn: singleSampledFramebuffer2
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
// Verify the second last framebuffer being drawn: multisampledFramebuffer
glBindFramebuffer(GL_READ_FRAMEBUFFER, multiSampledFramebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolvedFbo);
glBlitFramebuffer(0, 0, kViewportWidth, kViewportHeight, 0, 0, kViewportWidth, kViewportHeight,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolvedFbo);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
// Verify the first framebuffer being drawn: singleSampledFramebuffer1
glBindFramebuffer(GL_FRAMEBUFFER, singleSampledFramebuffer1);
EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
}
// Test ARM extension with new tokens
TEST_P(FramebufferFetchES31, BasicTokenUsage_ARM)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
// GL_FETCH_PER_SAMPLE_ARM can be set and queried
GLboolean isFetchPerSampleEnabledBool = false;
GLint isFetchPerSampleEnabledInt = -1;
GLfloat isFetchPerSampleEnabledFloat = -1.0f;
// Set GL_FETCH_PER_SAMPLE_ARM true
glEnable(GL_FETCH_PER_SAMPLE_ARM);
EXPECT_GL_TRUE(glIsEnabled(GL_FETCH_PER_SAMPLE_ARM));
// Ensure it returns true
glGetBooleanv(GL_FETCH_PER_SAMPLE_ARM, &isFetchPerSampleEnabledBool);
EXPECT_GL_TRUE(isFetchPerSampleEnabledBool);
glGetIntegerv(GL_FETCH_PER_SAMPLE_ARM, &isFetchPerSampleEnabledInt);
ASSERT_EQ(isFetchPerSampleEnabledInt, 1);
glGetFloatv(GL_FETCH_PER_SAMPLE_ARM, &isFetchPerSampleEnabledFloat);
ASSERT_EQ(isFetchPerSampleEnabledFloat, 1.0);
// Set GL_FETCH_PER_SAMPLE_ARM false
glDisable(GL_FETCH_PER_SAMPLE_ARM);
EXPECT_GL_FALSE(glIsEnabled(GL_FETCH_PER_SAMPLE_ARM));
// Ensure it returns false
glGetBooleanv(GL_FETCH_PER_SAMPLE_ARM, &isFetchPerSampleEnabledBool);
EXPECT_GL_FALSE(isFetchPerSampleEnabledBool);
glGetIntegerv(GL_FETCH_PER_SAMPLE_ARM, &isFetchPerSampleEnabledInt);
ASSERT_EQ(isFetchPerSampleEnabledInt, 0);
glGetFloatv(GL_FETCH_PER_SAMPLE_ARM, &isFetchPerSampleEnabledFloat);
ASSERT_EQ(isFetchPerSampleEnabledFloat, 0.0);
ASSERT_GL_NO_ERROR();
// GL_FRAGMENT_SHADER_FRAMEBUFFER_FETCH_MRT_ARM can only be queried
GLboolean isFragmentShaderFramebufferFetchMrtBool = false;
GLint isFragmentShaderFramebufferFetchMrtInt = -1;
GLfloat isFragmentShaderFramebufferFetchMrtFloat = -1.0f;
// Try to set it, ensure we can't
glEnable(GL_FRAGMENT_SHADER_FRAMEBUFFER_FETCH_MRT_ARM);
EXPECT_GL_ERROR(GL_INVALID_ENUM);
glDisable(GL_FRAGMENT_SHADER_FRAMEBUFFER_FETCH_MRT_ARM);
EXPECT_GL_ERROR(GL_INVALID_ENUM);
// Ensure we can't query its state with isEnabled
// Commented out due to http://anglebug.com/8025
// glIsEnabled(GL_FRAGMENT_SHADER_FRAMEBUFFER_FETCH_MRT_ARM);
// EXPECT_GL_ERROR(GL_INVALID_ENUM);
// Ensure GL_FRAGMENT_SHADER_FRAMEBUFFER_FETCH_MRT_ARM returns false
glGetBooleanv(GL_FRAGMENT_SHADER_FRAMEBUFFER_FETCH_MRT_ARM,
&isFragmentShaderFramebufferFetchMrtBool);
EXPECT_GL_FALSE(isFragmentShaderFramebufferFetchMrtBool);
glGetIntegerv(GL_FRAGMENT_SHADER_FRAMEBUFFER_FETCH_MRT_ARM,
&isFragmentShaderFramebufferFetchMrtInt);
ASSERT_EQ(isFragmentShaderFramebufferFetchMrtInt, 0);
glGetFloatv(GL_FRAGMENT_SHADER_FRAMEBUFFER_FETCH_MRT_ARM,
&isFragmentShaderFramebufferFetchMrtFloat);
ASSERT_EQ(isFragmentShaderFramebufferFetchMrtFloat, 0.0);
ASSERT_GL_NO_ERROR();
}
// Test using both extensions simultaneously with gl_LastFragData and gl_LastFragColorARM
TEST_P(FramebufferFetchES31, BasicLastFragData_Both)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(BOTH);
GLProgram program;
program.makeRaster(k100VS, getFragmentShader(GLSL100));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
BasicTest(program);
}
// Test using both extentions simultaneously with multiple draw
TEST_P(FramebufferFetchES31, MultipleDraw_Both)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(BOTH);
GLProgram program;
program.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
MultipleDrawTest(program);
}
// Testing using both extentions simultaneously with the order of non-fetch program and fetch
// program
TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetch_Both)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(BOTH);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
ASSERT_GL_NO_ERROR();
DrawNonFetchDrawFetchTest(programNonFetch, programFetch);
}
// Testing using both extentions simultaneously with the order of fetch program and non-fetch
// program
TEST_P(FramebufferFetchES31, DrawFetchDrawNonFetch_Both)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(BOTH);
GLProgram programNonFetch, programFetch;
programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
ASSERT_GL_NO_ERROR();
DrawFetchDrawNonFetchTest(programNonFetch, programFetch);
}
// Testing using both extentions simultaneously with multiple render target, using gl_FragData with
// constant indices
TEST_P(FramebufferFetchES31, MultipleRenderTarget_Both_FragData)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_draw_buffers"));
setWhichExtension(BOTH);
GLProgram program;
program.makeRaster(k100VS, getFragmentShader(GLSL100_4ATTACHMENT));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
MultipleRenderTargetTest(program, GLSL100_4ATTACHMENT);
}
// Testing using both extentions simultaneously with multiple render target, using gl_FragData with
// complex expressions
TEST_P(FramebufferFetchES31, MultipleRenderTarget_Both_FragData_Complex)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_draw_buffers"));
setWhichExtension(BOTH);
GLProgram program;
program.makeRaster(k100VS, getFragmentShader(GLSL100_COMPLEX));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
MultipleRenderTargetTest(program, GLSL100_COMPLEX);
}
// Testing using both extentions simultaneously with multiple render target, using inouts with
// complex expressions
TEST_P(FramebufferFetchES31, MultipleRenderTarget_Both_Complex)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_shader_framebuffer_fetch"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
setWhichExtension(BOTH);
GLProgram program;
program.makeRaster(k310VS, getFragmentShader(GLSL310_COMPLEX));
glUseProgram(program);
ASSERT_GL_NO_ERROR();
MultipleRenderTargetTest(program, GLSL310_COMPLEX);
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FramebufferFetchES31);
ANGLE_INSTANTIATE_TEST_ES31(FramebufferFetchES31);
} // namespace angle