| // |
| // 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 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; |
| })"; |
| |
| // 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 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; |
| })"; |
| |
| 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; |
| } |
| |
| enum WhichExtension |
| { |
| COHERENT, |
| NON_COHERENT, |
| }; |
| void setWhichExtension(WhichExtension whichExtension) |
| { |
| mCoherentExtension = (whichExtension == COHERENT) ? true : false; |
| } |
| |
| enum WhichFragmentShader |
| { |
| GLSL100, |
| GLSL310_NO_FETCH_1ATTACHMENT, |
| GLSL310_1ATTACHMENT, |
| GLSL310_1ATTACHMENT_WITH_STORAGE_BUFFER, |
| GLSL310_4ATTACHMENT, |
| GLSL310_4ATTACHMENT_ARRAY, |
| GLSL310_4ATTACHMENT_DIFFERENT1, |
| GLSL310_4ATTACHMENT_DIFFERENT2, |
| }; |
| const char *getFragmentShader(WhichFragmentShader whichFragmentShader) |
| { |
| 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 GLSL310_4ATTACHMENT: |
| return k310Coherent4AttachmentFS; |
| case GLSL310_4ATTACHMENT_ARRAY: |
| return k310Coherent4AttachmentArrayFS; |
| case GLSL310_4ATTACHMENT_DIFFERENT1: |
| return k310CoherentDifferent4AttachmentFS1; |
| case GLSL310_4ATTACHMENT_DIFFERENT2: |
| return k310CoherentDifferent4AttachmentFS2; |
| 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 GLSL310_4ATTACHMENT: |
| return k310NonCoherent4AttachmentFS; |
| case GLSL310_4ATTACHMENT_ARRAY: |
| return k310NonCoherent4AttachmentArrayFS; |
| case GLSL310_4ATTACHMENT_DIFFERENT1: |
| return k310NonCoherentDifferent4AttachmentFS1; |
| case GLSL310_4ATTACHMENT_DIFFERENT2: |
| return k310NonCoherentDifferent4AttachmentFS2; |
| 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) |
| { |
| 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 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}; |
| 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, color1.data()); |
| glBindTexture(GL_TEXTURE_2D, colorBufferTex1[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, |
| colorBufferTex1[i], 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 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; |
| }; |
| |
| // 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 |
| 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); |
| } |
| |
| // 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); |
| } |
| |
| // 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); |
| } |
| |
| // 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); |
| } |
| |
| // 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 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)); |
| } |
| |
| // TODO: http://anglebug.com/5792 |
| TEST_P(FramebufferFetchES31, DISABLED_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(); |
| |
| 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 * 2); |
| 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 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); |
| } |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FramebufferFetchES31); |
| ANGLE_INSTANTIATE_TEST_ES31(FramebufferFetchES31); |
| } // namespace angle |