1#include "ANGLETest.h"
2
3class DrawBuffersTest : public ANGLETest
4{
5  protected:
6    DrawBuffersTest(int clientVersion)
7    {
8        setWindowWidth(128);
9        setWindowHeight(128);
10        setConfigRedBits(8);
11        setConfigGreenBits(8);
12        setConfigBlueBits(8);
13        setConfigAlphaBits(8);
14        setConfigDepthBits(24);
15        setClientVersion(clientVersion);
16    }
17
18    virtual void SetUp()
19    {
20        ANGLETest::SetUp();
21
22        glGenFramebuffers(1, &mFBO);
23        glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
24
25        glGenTextures(4, mTextures);
26
27        for (size_t texIndex = 0; texIndex < ArraySize(mTextures); texIndex++)
28        {
29            glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);
30            glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight());
31        }
32
33        GLfloat data[] =
34        {
35            -1.0f, 1.0f,
36            -1.0f, -2.0f,
37            2.0f, 1.0f
38        };
39
40        glGenBuffers(1, &mBuffer);
41        glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
42        glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6, data, GL_STATIC_DRAW);
43
44        GLint maxDrawBuffers;
45        glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
46        ASSERT_EQ(maxDrawBuffers, 8);
47
48        ASSERT_GL_NO_ERROR();
49    }
50
51    virtual void TearDown()
52    {
53        glDeleteFramebuffers(1, &mFBO);
54        glDeleteTextures(4, mTextures);
55        glDeleteBuffers(1, &mBuffer);
56
57        ANGLETest::TearDown();
58    }
59
60    void setupMRTProgramESSL3(bool bufferEnabled[8], GLuint *programOut)
61    {
62        const std::string vertexShaderSource =
63            "#version 300 es\n"
64            "in vec4 position;\n"
65            "void main() {\n"
66            "    gl_Position = position;\n"
67            "}\n";
68
69        std::stringstream strstr;
70
71        strstr << "#version 300 es\n"
72                  "precision highp float;\n";
73
74        for (unsigned int index = 0; index < 8; index++)
75        {
76            if (bufferEnabled[index])
77            {
78                strstr << "layout(location = " << index << ") "
79                          "out vec4 value" << index << ";\n";
80            }
81        }
82
83        strstr << "void main()\n"
84                  "{\n";
85
86        for (unsigned int index = 0; index < 8; index++)
87        {
88            if (bufferEnabled[index])
89            {
90                unsigned int r = (index + 1) & 1;
91                unsigned int g = (index + 1) & 2;
92                unsigned int b = (index + 1) & 4;
93
94                strstr << "    value" << index << " = vec4("
95                       << r << ".0, " << g << ".0, "
96                       << b << ".0, 1.0);\n";
97            }
98        }
99
100        strstr << "}\n";
101
102        *programOut = CompileProgram(vertexShaderSource, strstr.str());
103        if (*programOut == 0)
104        {
105            FAIL() << "shader compilation failed.";
106        }
107
108        glUseProgram(*programOut);
109
110        GLint location = glGetAttribLocation(*programOut, "position");
111        ASSERT_NE(location, -1);
112        glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
113        glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 8, NULL);
114        glEnableVertexAttribArray(location);
115    }
116
117    void setupMRTProgramESSL1(bool bufferEnabled[8], GLuint *programOut)
118    {
119        const std::string vertexShaderSource =
120            "attribute vec4 position;\n"
121            "void main() {\n"
122            "    gl_Position = position;\n"
123            "}\n";
124
125        std::stringstream strstr;
126
127        strstr << "#extension GL_EXT_draw_buffers : enable\n"
128                  "precision highp float;\n"
129                  "void main()\n"
130                  "{\n";
131
132        for (unsigned int index = 0; index < 8; index++)
133        {
134            if (bufferEnabled[index])
135            {
136                unsigned int r = (index + 1) & 1;
137                unsigned int g = (index + 1) & 2;
138                unsigned int b = (index + 1) & 4;
139
140                strstr << "    gl_FragData[" << index << "] = vec4("
141                    << r << ".0, " << g << ".0, "
142                    << b << ".0, 1.0);\n";
143            }
144        }
145
146        strstr << "}\n";
147
148        *programOut = CompileProgram(vertexShaderSource, strstr.str());
149        if (*programOut == 0)
150        {
151            FAIL() << "shader compilation failed.";
152        }
153
154        glUseProgram(*programOut);
155
156        GLint location = glGetAttribLocation(*programOut, "position");
157        ASSERT_NE(location, -1);
158        glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
159        glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 8, NULL);
160        glEnableVertexAttribArray(location);
161    }
162
163    void setupMRTProgram(bool bufferEnabled[8], GLuint *programOut)
164    {
165        if (getClientVersion() == 3)
166        {
167            setupMRTProgramESSL3(bufferEnabled, programOut);
168        }
169        else
170        {
171            ASSERT_EQ(getClientVersion(), 2);
172            setupMRTProgramESSL1(bufferEnabled, programOut);
173        }
174    }
175
176    void verifyAttachment(unsigned int index, GLuint textureName)
177    {
178        for (unsigned int colorAttachment = 0; colorAttachment < 8; colorAttachment++)
179        {
180            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorAttachment, GL_TEXTURE_2D, 0, 0);
181        }
182
183        glBindTexture(GL_TEXTURE_2D, textureName);
184        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0);
185
186        unsigned int r = (((index + 1) & 1) > 0) ? 255 : 0;
187        unsigned int g = (((index + 1) & 2) > 0) ? 255 : 0;
188        unsigned int b = (((index + 1) & 4) > 0) ? 255 : 0;
189
190        EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, r, g, b, 255);
191    }
192
193    void gapsTest()
194    {
195        glBindTexture(GL_TEXTURE_2D, mTextures[0]);
196        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[0], 0);
197
198        bool flags[8] = { false, true };
199
200        GLuint program;
201        setupMRTProgram(flags, &program);
202
203        const GLenum bufs[] =
204        {
205            GL_NONE,
206            GL_COLOR_ATTACHMENT1
207        };
208        glUseProgram(program);
209        glDrawBuffersEXT(2, bufs);
210        glDrawArrays(GL_TRIANGLES, 0, 3);
211
212        verifyAttachment(1, mTextures[0]);
213
214        glDeleteProgram(program);
215    }
216
217    void firstAndLastTest()
218    {
219        glBindTexture(GL_TEXTURE_2D, mTextures[0]);
220        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
221
222        glBindTexture(GL_TEXTURE_2D, mTextures[1]);
223        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, mTextures[1], 0);
224
225        bool flags[8] = { true, false, false, true };
226
227        GLuint program;
228        setupMRTProgram(flags, &program);
229
230        const GLenum bufs[] =
231        {
232            GL_COLOR_ATTACHMENT0,
233            GL_NONE,
234            GL_NONE,
235            GL_COLOR_ATTACHMENT3
236        };
237
238        glUseProgram(program);
239        glDrawBuffersEXT(4, bufs);
240        glDrawArrays(GL_TRIANGLES, 0, 3);
241
242        verifyAttachment(0, mTextures[0]);
243        verifyAttachment(3, mTextures[1]);
244
245        EXPECT_GL_NO_ERROR();
246
247        glDeleteProgram(program);
248    }
249
250    void firstHalfNULLTest()
251    {
252        bool flags[8] = { false };
253        GLenum bufs[8] = { GL_NONE };
254
255        for (unsigned int texIndex = 0; texIndex < 4; texIndex++)
256        {
257            glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);
258            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4 + texIndex, GL_TEXTURE_2D, mTextures[texIndex], 0);
259            flags[texIndex + 4] = true;
260            bufs[texIndex + 4] = GL_COLOR_ATTACHMENT4 + texIndex;
261        }
262
263        GLuint program;
264        setupMRTProgram(flags, &program);
265
266        glUseProgram(program);
267        glDrawBuffersEXT(8, bufs);
268        glDrawArrays(GL_TRIANGLES, 0, 3);
269
270        for (unsigned int texIndex = 0; texIndex < 4; texIndex++)
271        {
272            verifyAttachment(texIndex + 4, mTextures[texIndex]);
273        }
274
275        EXPECT_GL_NO_ERROR();
276
277        glDeleteProgram(program);
278    }
279
280    GLuint mFBO;
281    GLuint mTextures[4];
282    GLuint mBuffer;
283};
284
285class DrawBuffersTestESSL3 : public DrawBuffersTest
286{
287  protected:
288    DrawBuffersTestESSL3()
289        : DrawBuffersTest(3)
290    {}
291};
292
293class DrawBuffersTestESSL1 : public DrawBuffersTest
294{
295  protected:
296    DrawBuffersTestESSL1()
297        : DrawBuffersTest(2)
298    {}
299};
300
301TEST_F(DrawBuffersTestESSL3, Gaps)
302{
303    gapsTest();
304}
305
306TEST_F(DrawBuffersTestESSL1, Gaps)
307{
308    gapsTest();
309}
310
311TEST_F(DrawBuffersTestESSL3, FirstAndLast)
312{
313    firstAndLastTest();
314}
315
316TEST_F(DrawBuffersTestESSL1, FirstAndLast)
317{
318    firstAndLastTest();
319}
320
321TEST_F(DrawBuffersTestESSL3, FirstHalfNULL)
322{
323    firstHalfNULLTest();
324}
325
326TEST_F(DrawBuffersTestESSL1, FirstHalfNULL)
327{
328    firstHalfNULLTest();
329}
330