blob: cb90c5bb63f1060a78bcda39b680fd28d7b1d305 [file] [log] [blame]
Mingyu Hu2d0e5b52019-08-27 13:49:07 -07001//
2// Copyright 2019 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// MultisampledRenderToTextureTest: Tests of EXT_multisampled_render_to_texture extension
8
9#include "test_utils/ANGLETest.h"
10#include "test_utils/gl_raii.h"
11
12using namespace angle;
13
14namespace
15{
16constexpr char kBasicVertexShader[] =
17 R"(attribute vec3 position;
18void main()
19{
20 gl_Position = vec4(position, 1);
21})";
22
23constexpr char kGreenFragmentShader[] =
24 R"(void main()
25{
26 gl_FragColor = vec4(0, 1, 0, 1);
27})";
28
29constexpr char kRedFragmentShader[] =
30 R"(void main()
31{
32 gl_FragColor = vec4(1, 0, 0, 1);
33})";
34
35constexpr char kVS[] =
36 "precision highp float;\n"
37 "attribute vec4 position;\n"
38 "varying vec2 texcoord;\n"
39 "\n"
40 "void main()\n"
41 "{\n"
42 " gl_Position = position;\n"
43 " texcoord = (position.xy * 0.5) + 0.5;\n"
44 "}\n";
45
46constexpr char kFS[] =
47 "precision highp float;\n"
48 "uniform sampler2D tex;\n"
49 "varying vec2 texcoord;\n"
50 "\n"
51 "void main()\n"
52 "{\n"
53 " gl_FragColor = texture2D(tex, texcoord);\n"
54 "}\n";
55
56class MultisampledRenderToTextureTest : public ANGLETest
57{
58 protected:
59 MultisampledRenderToTextureTest()
60 {
61 setWindowWidth(64);
62 setWindowHeight(64);
63 setConfigRedBits(8);
64 setConfigGreenBits(8);
65 setConfigBlueBits(8);
66 setConfigAlphaBits(8);
67 }
68
69 void testSetUp() override {}
70
71 void testTearDown() override {}
72
73 void setupCopyTexProgram()
74 {
75 mCopyTextureProgram.makeRaster(kVS, kFS);
76 ASSERT_GL_TRUE(mCopyTextureProgram.valid());
77
78 mCopyTextureUniformLocation = glGetUniformLocation(mCopyTextureProgram, "tex");
79
80 ASSERT_GL_NO_ERROR();
81 }
82
83 void verifyResults(GLuint texture,
84 GLubyte data[4],
85 GLint fboSize,
86 GLint xs,
87 GLint ys,
88 GLint xe,
89 GLint ye)
90 {
91 glViewport(0, 0, fboSize, fboSize);
92
93 glBindFramebuffer(GL_FRAMEBUFFER, 0);
94
95 // Draw a quad with the target texture
96 glUseProgram(mCopyTextureProgram);
97 glBindTexture(GL_TEXTURE_2D, texture);
98 glUniform1i(mCopyTextureUniformLocation, 0);
99
100 drawQuad(mCopyTextureProgram, "position", 0.5f);
101
102 // Expect that the rendered quad has the same color as the source texture
103 EXPECT_PIXEL_NEAR(xs, ys, data[0], data[1], data[2], data[3], 1.0);
104 EXPECT_PIXEL_NEAR(xs, ye - 1, data[0], data[1], data[2], data[3], 1.0);
105 EXPECT_PIXEL_NEAR(xe - 1, ys, data[0], data[1], data[2], data[3], 1.0);
106 EXPECT_PIXEL_NEAR(xe - 1, ye - 1, data[0], data[1], data[2], data[3], 1.0);
107 EXPECT_PIXEL_NEAR((xs + xe) / 2, (ys + ye) / 2, data[0], data[1], data[2], data[3], 1.0);
108 }
109
110 void clearAndDrawQuad(GLuint program, GLsizei viewportWidth, GLsizei viewportHeight)
111 {
112 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
113 glClear(GL_COLOR_BUFFER_BIT);
114 glViewport(0, 0, viewportWidth, viewportHeight);
115 ASSERT_GL_NO_ERROR();
116
117 drawQuad(program, "position", 0.0f);
118 }
119
120 GLProgram mCopyTextureProgram;
121 GLint mCopyTextureUniformLocation = -1;
122};
123
124class MultisampledRenderToTextureES3Test : public MultisampledRenderToTextureTest
125{};
126
127// Checking against invalid parameters for RenderbufferStorageMultisampleEXT.
128TEST_P(MultisampledRenderToTextureTest, RenderbufferParameterCheck)
129{
130 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
131
132 GLRenderbuffer renderbuffer;
133 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
134
135 // Positive test case
136 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, 64, 64);
137 ASSERT_GL_NO_ERROR();
138
139 GLint samples;
140 glGetIntegerv(GL_MAX_SAMPLES_EXT, &samples);
141 ASSERT_GL_NO_ERROR();
142 EXPECT_GE(samples, 1);
143
144 // Samples too large
145 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples + 1, GL_DEPTH_COMPONENT16, 64, 64);
146 ASSERT_GL_ERROR(GL_INVALID_VALUE);
147
148 // Renderbuffer size too large
149 GLint maxSize;
150 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxSize);
151 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 2, GL_DEPTH_COMPONENT16, maxSize + 1,
152 maxSize);
153 ASSERT_GL_ERROR(GL_INVALID_VALUE);
154 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 2, GL_DEPTH_COMPONENT16, maxSize,
155 maxSize + 1);
156 ASSERT_GL_ERROR(GL_INVALID_VALUE);
157
158 // Retrieving samples
159 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, 64, 64);
160 GLint param = 0;
161 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES_EXT, &param);
162 // GE because samples may vary base on implementation. Spec says "the resulting value for
163 // RENDERBUFFER_SAMPLES_EXT is guaranteed to be greater than or equal to samples and no more
164 // than the next larger sample count supported by the implementation"
165 EXPECT_GE(param, 4);
166}
167
168// Checking against invalid parameters for FramebufferTexture2DMultisampleEXT.
169TEST_P(MultisampledRenderToTextureTest, Texture2DParameterCheck)
170{
171 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
172
173 GLTexture texture;
174 glBindTexture(GL_TEXTURE_2D, texture);
175 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
176 ASSERT_GL_NO_ERROR();
177
178 GLFramebuffer fbo;
179 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
180 // Positive test case
181 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
182 texture, 0, 4);
183 ASSERT_GL_NO_ERROR();
184
185 // Attachment not COLOR_ATTACHMENT0
186 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D,
187 texture, 0, 4);
188 ASSERT_GL_ERROR(GL_INVALID_ENUM);
189
190 // Target not framebuffer
191 glFramebufferTexture2DMultisampleEXT(GL_RENDERBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
192 texture, 0, 4);
193 ASSERT_GL_ERROR(GL_INVALID_ENUM);
194
195 GLint samples;
196 glGetIntegerv(GL_MAX_SAMPLES_EXT, &samples);
197 ASSERT_GL_NO_ERROR();
198 EXPECT_GE(samples, 1);
199
200 // Samples too large
201 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
202 texture, 0, samples + 1);
203 ASSERT_GL_ERROR(GL_INVALID_VALUE);
204
205 // Retrieving samples
206 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
207 texture, 0, 4);
208 GLint param = 0;
209 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
210 GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT, &param);
211 // GE because samples may vary base on implementation. Spec says "the resulting value for
212 // TEXTURE_SAMPLES_EXT is guaranteed to be greater than or equal to samples and no more than the
213 // next larger sample count supported by the implementation"
214 EXPECT_GE(param, 4);
215}
216
217// Checking against invalid parameters for FramebufferTexture2DMultisampleEXT (cubemap).
218TEST_P(MultisampledRenderToTextureTest, TextureCubeMapParameterCheck)
219{
220 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
221
222 GLTexture texture;
223 glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
224 for (GLenum face = 0; face < 6; face++)
225 {
226 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGBA, 64, 64, 0, GL_RGBA,
227 GL_UNSIGNED_BYTE, nullptr);
228 ASSERT_GL_NO_ERROR();
229 }
230
231 GLint samples;
232 glGetIntegerv(GL_MAX_SAMPLES_EXT, &samples);
233 ASSERT_GL_NO_ERROR();
234 EXPECT_GE(samples, 1);
235
236 GLFramebuffer FBO;
237 glBindFramebuffer(GL_FRAMEBUFFER, FBO);
238 for (GLenum face = 0; face < 6; face++)
239 {
240 // Positive test case
241 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
242 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture, 0, 4);
243 ASSERT_GL_NO_ERROR();
244
245 // Attachment not COLOR_ATTACHMENT0
246 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
247 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture, 0, 4);
248 ASSERT_GL_ERROR(GL_INVALID_ENUM);
249
250 // Target not framebuffer
251 glFramebufferTexture2DMultisampleEXT(GL_RENDERBUFFER, GL_COLOR_ATTACHMENT0,
252 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture, 0, 4);
253 ASSERT_GL_ERROR(GL_INVALID_ENUM);
254
255 // Samples too large
256 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
257 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture, 0,
258 samples + 1);
259 ASSERT_GL_ERROR(GL_INVALID_VALUE);
260
261 // Retrieving samples
262 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
263 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture, 0, 4);
264 GLint param = 0;
265 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
266 GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT,
267 &param);
268 // GE because samples may vary base on implementation. Spec says "the resulting value for
269 // TEXTURE_SAMPLES_EXT is guaranteed to be greater than or equal to samples and no more than
270 // the next larger sample count supported by the implementation"
271 EXPECT_GE(param, 4);
272 }
273}
274
275// Checking for framebuffer completeness using extension methods.
276TEST_P(MultisampledRenderToTextureTest, FramebufferCompleteness)
277{
278 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
279
280 // Checking that Renderbuffer and texture2d having different number of samples results
281 // in a FRAMEBUFFER_INCOMPLETE_MULTISAMPLE
282 GLTexture texture;
283 glBindTexture(GL_TEXTURE_2D, texture);
284 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
285 ASSERT_GL_NO_ERROR();
286
287 GLFramebuffer FBO;
288 glBindFramebuffer(GL_FRAMEBUFFER, FBO);
289 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
290 texture, 0, 4);
291 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
292
293 GLRenderbuffer renderbuffer;
294 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
295 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 8, GL_DEPTH_COMPONENT16, 64, 64);
296 ASSERT_GL_NO_ERROR();
297 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
298 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
299 glCheckFramebufferStatus(GL_FRAMEBUFFER));
300}
301
302// Draw test with color attachment only.
303TEST_P(MultisampledRenderToTextureTest, 2DColorAttachmentMultisampleDrawTest)
304{
305 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
306 // Set up texture and bind to FBO
307 GLsizei size = 6;
308 GLTexture texture;
309 glBindTexture(GL_TEXTURE_2D, texture);
310 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
311 ASSERT_GL_NO_ERROR();
312
313 GLFramebuffer FBO;
314 glBindFramebuffer(GL_FRAMEBUFFER, FBO);
315 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
316 texture, 0, 4);
317 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
318
319 // Set viewport and clear to black
320 glViewport(0, 0, size, size);
321 glClearColor(0.0, 0.0, 0.0, 1.0);
322 glClear(GL_COLOR_BUFFER_BIT);
323
324 // Set up Green square program
325 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
326 glUseProgram(program);
327 GLint positionLocation = glGetAttribLocation(program, "position");
328 ASSERT_NE(-1, positionLocation);
329
330 setupQuadVertexBuffer(0.5f, 0.5f);
331 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
332 glEnableVertexAttribArray(positionLocation);
333
334 // Draw green square
335 glDrawArrays(GL_TRIANGLES, 0, 6);
336 ASSERT_GL_NO_ERROR();
337
338 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
339 EXPECT_PIXEL_COLOR_EQ(size / 2, size / 2, GLColor::green);
340
341 // Set up Red square program
342 ANGLE_GL_PROGRAM(program2, kBasicVertexShader, kRedFragmentShader);
343 glUseProgram(program2);
344 GLint positionLocation2 = glGetAttribLocation(program2, "position");
345 ASSERT_NE(-1, positionLocation2);
346
347 setupQuadVertexBuffer(0.5f, 0.75f);
348 glVertexAttribPointer(positionLocation2, 3, GL_FLOAT, GL_FALSE, 0, 0);
349
350 // Draw red square
351 glDrawArrays(GL_TRIANGLES, 0, 6);
352 ASSERT_GL_NO_ERROR();
353
354 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
355 EXPECT_PIXEL_COLOR_EQ(size / 2, size / 2, GLColor::red);
356
357 glDisableVertexAttribArray(0);
358 glBindBuffer(GL_ARRAY_BUFFER, 0);
359}
360
361// Draw test using both color and depth attachments.
362TEST_P(MultisampledRenderToTextureTest, 2DColorDepthMultisampleDrawTest)
363{
364 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
365 GLsizei size = 6;
366 // create complete framebuffer with depth buffer
367 GLTexture texture;
368 glBindTexture(GL_TEXTURE_2D, texture);
369 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
370 ASSERT_GL_NO_ERROR();
371
372 GLFramebuffer FBO;
373 glBindFramebuffer(GL_FRAMEBUFFER, FBO);
374 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
375 texture, 0, 4);
376
377 GLRenderbuffer renderbuffer;
378 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
379 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, size, size);
380 ASSERT_GL_NO_ERROR();
381 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
382 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
383
384 // Set viewport and clear framebuffer
385 glViewport(0, 0, size, size);
386 glClearColor(0.0, 0.0, 0.0, 1.0);
387 glClearDepthf(0.5f);
388 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
389
390 // Draw first green square
391 ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
392 glEnable(GL_DEPTH_TEST);
393 glDepthFunc(GL_GREATER);
394 glUseProgram(program);
395 GLint positionLocation = glGetAttribLocation(program, "position");
396 ASSERT_NE(-1, positionLocation);
397
398 setupQuadVertexBuffer(0.8f, 0.5f);
399 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
400 glEnableVertexAttribArray(positionLocation);
401
402 // Tests that TRIANGLES works.
403 glDrawArrays(GL_TRIANGLES, 0, 6);
404 ASSERT_GL_NO_ERROR();
405
406 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
407 EXPECT_PIXEL_COLOR_EQ(size / 2, size / 2, GLColor::green);
408
409 // Draw red square behind green square
410 ANGLE_GL_PROGRAM(program2, kBasicVertexShader, kRedFragmentShader);
411 glUseProgram(program2);
412 GLint positionLocation2 = glGetAttribLocation(program2, "position");
413 ASSERT_NE(-1, positionLocation2);
414
415 setupQuadVertexBuffer(0.7f, 1.0f);
416 glVertexAttribPointer(positionLocation2, 3, GL_FLOAT, GL_FALSE, 0, 0);
417
418 glDrawArrays(GL_TRIANGLES, 0, 6);
419 ASSERT_GL_NO_ERROR();
420 glDisable(GL_DEPTH_TEST);
421
422 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
423 EXPECT_PIXEL_COLOR_EQ(size / 2, size / 2, GLColor::green);
424
425 glDisableVertexAttribArray(0);
426 glBindBuffer(GL_ARRAY_BUFFER, 0);
427}
428
429// Read pixels with pack buffer. ES3+.
430TEST_P(MultisampledRenderToTextureES3Test, MultisampleReadPixelsTest)
431{
432 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
433
434 // PBO only available ES3 and above
435 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
436 GLsizei size = 6;
437 GLTexture texture;
438 glBindTexture(GL_TEXTURE_2D, texture);
439 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, size, size);
440 ASSERT_GL_NO_ERROR();
441
442 GLFramebuffer FBO;
443 glBindFramebuffer(GL_FRAMEBUFFER, FBO);
444 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
445 texture, 0, 4);
446 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
447
448 // Set viewport and clear to red
449 glViewport(0, 0, size, size);
450 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
451 glClear(GL_COLOR_BUFFER_BIT);
452 ASSERT_GL_NO_ERROR();
453
454 // Bind Pack Pixel Buffer and read to it
455 GLBuffer PBO;
456 glBindBuffer(GL_PIXEL_PACK_BUFFER, PBO);
457 glBufferData(GL_PIXEL_PACK_BUFFER, 4 * size * size, nullptr, GL_STATIC_DRAW);
458 glReadPixels(0, 0, size, size, GL_RGBA, GL_UNSIGNED_BYTE, 0);
459 ASSERT_GL_NO_ERROR();
460
461 // Retrieving pixel color
462 void *mappedPtr = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, 32, GL_MAP_READ_BIT);
463 GLColor *dataColor = static_cast<GLColor *>(mappedPtr);
464 EXPECT_GL_NO_ERROR();
465
466 EXPECT_EQ(GLColor::red, dataColor[0]);
467
468 glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
469 EXPECT_GL_NO_ERROR();
470}
471
472// CopyTexImage from a multisampled texture functionality test.
473TEST_P(MultisampledRenderToTextureTest, MultisampleCopyTexImageTest)
474{
475 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
476 GLsizei size = 16;
477
478 setupCopyTexProgram();
479 GLTexture texture;
480 glBindTexture(GL_TEXTURE_2D, texture);
481 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
482
483 // Disable mipmapping
484 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
485 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
486
487 GLFramebuffer FBO;
488 glBindFramebuffer(GL_FRAMEBUFFER, FBO);
489 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
490 texture, 0, 4);
491
492 // Set color for framebuffer
493 glClearColor(0.25f, 1.0f, 0.75f, 0.5f);
494 glClear(GL_COLOR_BUFFER_BIT);
495 ASSERT_GL_NO_ERROR();
496
497 GLTexture copyToTex;
498 glBindTexture(GL_TEXTURE_2D, copyToTex);
499
500 // Disable mipmapping
501 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
502 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
503
504 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, size, size, 0);
505 ASSERT_GL_NO_ERROR();
506
507 GLubyte expected[4] = {64, 255, 191, 255};
508 verifyResults(copyToTex, expected, size, 0, 0, size, size);
509}
510
511// CopyTexSubImage from a multisampled texture functionality test.
512TEST_P(MultisampledRenderToTextureTest, MultisampleCopyTexSubImageTest)
513{
514 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
515 GLsizei size = 16;
516
517 setupCopyTexProgram();
518
519 GLTexture texture;
520 // Create texture in copyFBO0 with color (.25, 1, .75, .5)
521 glBindTexture(GL_TEXTURE_2D, texture);
522 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
523
524 // Disable mipmapping
525 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
526 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
527
528 GLFramebuffer copyFBO0;
529 glBindFramebuffer(GL_FRAMEBUFFER, copyFBO0);
530 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
531 texture, 0, 4);
532
533 // Set color for
534 glClearColor(0.25f, 1.0f, 0.75f, 0.5f);
535 glClear(GL_COLOR_BUFFER_BIT);
536 ASSERT_GL_NO_ERROR();
537
538 // Create texture in copyFBO[1] with color (1, .75, .5, .25)
539 GLTexture texture1;
540 glBindTexture(GL_TEXTURE_2D, texture1);
541 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
542
543 // Disable mipmapping
544 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
545 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
546
547 GLFramebuffer copyFBO1;
548 glBindFramebuffer(GL_FRAMEBUFFER, copyFBO1);
549 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
550 texture1, 0, 4);
551
552 // Set color for
553 glClearColor(1.0f, 0.75f, 0.5f, 0.25f);
554 glClear(GL_COLOR_BUFFER_BIT);
555 ASSERT_GL_NO_ERROR();
556
557 GLTexture copyToTex;
558 glBindTexture(GL_TEXTURE_2D, copyToTex);
559
560 // Disable mipmapping
561 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
562 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
563
564 // copyFBO0 -> copyToTex
565 // copyToTex should hold what was originally in copyFBO0 : (.25, 1, .75, .5)
566 glBindFramebuffer(GL_FRAMEBUFFER, copyFBO0);
567 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, size, size, 0);
568 ASSERT_GL_NO_ERROR();
569
570 GLubyte expected0[4] = {64, 255, 191, 255};
571 verifyResults(copyToTex, expected0, size, 0, 0, size, size);
572
573 // copyFBO[1] - copySubImage -> copyToTex
574 // copyToTex should have subportion what was in copyFBO[1] : (1, .75, .5, .25)
575 // The rest should still be untouched: (.25, 1, .75, .5)
576 GLint half = size / 2;
577 glBindFramebuffer(GL_FRAMEBUFFER, copyFBO1);
578 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, half, half, half, half, half, half);
579 ASSERT_GL_NO_ERROR();
580
581 GLubyte expected1[4] = {255, 191, 127, 255};
582 verifyResults(copyToTex, expected1, size, half, half, size, size);
583
584 // Verify rest is untouched
585 verifyResults(copyToTex, expected0, size, 0, 0, half, half);
586 verifyResults(copyToTex, expected0, size, 0, half, half, size);
587 verifyResults(copyToTex, expected0, size, half, 0, size, half);
588}
589
590// BlitFramebuffer functionality test. ES3+.
591TEST_P(MultisampledRenderToTextureES3Test, MultisampleBlitFramebufferTest)
592{
593 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
594 // blitFramebuffer only available ES3 and above
595 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
596
597 GLsizei size = 16;
598
599 // Create multisampled framebuffer to use as source.
600 GLRenderbuffer depthMS;
601 glBindRenderbuffer(GL_RENDERBUFFER, depthMS.get());
602 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT24, size, size);
603
604 GLTexture colorMS;
605 glBindTexture(GL_TEXTURE_2D, colorMS);
606 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
607
608 GLFramebuffer fboMS;
609 glBindFramebuffer(GL_FRAMEBUFFER, fboMS);
610 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthMS.get());
611 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
612 colorMS, 0, 4);
613 ASSERT_GL_NO_ERROR();
614
615 // Clear depth to 0.5 and color to green.
616 glClearDepthf(0.5f);
617 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
618 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
619 glFlush();
620 ASSERT_GL_NO_ERROR();
621
622 // Draw red into the multisampled color buffer.
623 ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
624 glEnable(GL_DEPTH_TEST);
625 glDepthFunc(GL_EQUAL);
626 drawQuad(drawRed.get(), essl1_shaders::PositionAttrib(), 0.0f);
627 ASSERT_GL_NO_ERROR();
628
629 // Create single sampled framebuffer to use as dest.
630 GLFramebuffer fboSS;
631 glBindFramebuffer(GL_FRAMEBUFFER, fboSS);
632 GLTexture colorSS;
633 glBindTexture(GL_TEXTURE_2D, colorSS);
634 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
635 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorSS, 0);
636 ASSERT_GL_NO_ERROR();
637
638 // Bind MS to READ as SS is already bound to DRAW.
639 glBindFramebuffer(GL_READ_FRAMEBUFFER, fboMS.get());
640 glBlitFramebuffer(0, 0, size, size, 0, 0, size, size, GL_COLOR_BUFFER_BIT, GL_NEAREST);
641 ASSERT_GL_NO_ERROR();
642
643 // Bind SS to READ so we can readPixels from it
644 glBindFramebuffer(GL_FRAMEBUFFER, fboSS.get());
645
646 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
647 EXPECT_PIXEL_COLOR_EQ(size - 1, 0, GLColor::red);
648 EXPECT_PIXEL_COLOR_EQ(0, size - 1, GLColor::red);
649 EXPECT_PIXEL_COLOR_EQ(size - 1, size - 1, GLColor::red);
650 EXPECT_PIXEL_COLOR_EQ(size / 2, size / 2, GLColor::red);
651 ASSERT_GL_NO_ERROR();
652}
653
654// GenerateMipmap functionality test
655TEST_P(MultisampledRenderToTextureTest, MultisampleGenerateMipmapTest)
656{
657 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
658 GLsizei size = 64;
659 // Vertex Shader source
660 constexpr char kVS[] = R"(attribute vec4 position;
661varying vec2 vTexCoord;
662
663void main()
664{
665 gl_Position = position;
666 vTexCoord = (position.xy * 0.5) + 0.5;
667})";
668
669 // Fragment Shader source
670 constexpr char kFS[] = R"(precision mediump float;
671uniform sampler2D uTexture;
672varying vec2 vTexCoord;
673
674void main()
675{
676 gl_FragColor = texture2D(uTexture, vTexCoord);
677})";
678
679 GLProgram m2DProgram;
680 m2DProgram.makeRaster(kVS, kFS);
681 ASSERT_GL_TRUE(m2DProgram.valid());
682
683 ASSERT_GL_NO_ERROR();
684
685 // Initialize texture with blue
686 GLTexture texture;
687 glBindTexture(GL_TEXTURE_2D, texture);
688 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
689 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
690 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
691
692 GLFramebuffer FBO;
693 glBindFramebuffer(GL_FRAMEBUFFER, FBO);
694 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
695 texture, 0, 4);
696 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
697 glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
698 glClear(GL_COLOR_BUFFER_BIT);
699 glViewport(0, 0, size, size);
700 glBindFramebuffer(GL_FRAMEBUFFER, 0);
701 ASSERT_GL_NO_ERROR();
702
703 // Generate mipmap
704 glGenerateMipmap(GL_TEXTURE_2D);
705 ASSERT_GL_NO_ERROR();
706
707 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
708
709 // Now draw the texture to various different sized areas.
710 clearAndDrawQuad(m2DProgram, size, size);
711 EXPECT_PIXEL_COLOR_EQ(size / 2, size / 2, GLColor::blue);
712
713 // Use mip level 1
714 clearAndDrawQuad(m2DProgram, size / 2, size / 2);
715 EXPECT_PIXEL_COLOR_EQ(size / 4, size / 4, GLColor::blue);
716
717 // Use mip level 2
718 clearAndDrawQuad(m2DProgram, size / 4, size / 4);
719 EXPECT_PIXEL_COLOR_EQ(size / 8, size / 8, GLColor::blue);
720
721 ASSERT_GL_NO_ERROR();
722}
723ANGLE_INSTANTIATE_TEST(MultisampledRenderToTextureTest,
724 ES2_D3D9(),
725 ES2_D3D11(),
726 ES3_D3D11(),
727 ES2_OPENGL(),
728 ES3_OPENGL(),
729 ES2_OPENGLES(),
730 ES3_OPENGLES(),
731 ES2_VULKAN(),
732 ES3_VULKAN());
733ANGLE_INSTANTIATE_TEST(MultisampledRenderToTextureES3Test,
734 ES3_D3D11(),
735 ES3_OPENGL(),
736 ES3_OPENGLES(),
737 ES3_VULKAN());
738} // namespace