1 //
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 // GetImageTest:
7 //   Tests for the ANGLE_get_image extension.
8 //
9 
10 #include "test_utils/ANGLETest.h"
11 #include "test_utils/gl_raii.h"
12 
13 using namespace angle;
14 
15 namespace
16 {
17 constexpr uint32_t kSize        = 32;
18 constexpr char kExtensionName[] = "GL_ANGLE_get_image";
19 constexpr uint32_t kSmallSize   = 2;
20 constexpr uint8_t kUNormZero    = 0x00;
21 constexpr uint8_t kUNormHalf    = 0x7F;
22 constexpr uint8_t kUNormFull    = 0xFF;
23 
24 class GetImageTest : public ANGLETest
25 {
26   public:
GetImageTest()27     GetImageTest()
28     {
29         setWindowWidth(kSize);
30         setWindowHeight(kSize);
31         setConfigRedBits(8);
32         setConfigGreenBits(8);
33         setConfigBlueBits(8);
34         setConfigAlphaBits(8);
35     }
36 };
37 
38 class GetImageTestNoExtensions : public ANGLETest
39 {
40   public:
GetImageTestNoExtensions()41     GetImageTestNoExtensions() { setExtensionsEnabled(false); }
42 };
43 
InitTextureWithFormatAndSize(GLenum format,uint32_t size,void * pixelData)44 GLTexture InitTextureWithFormatAndSize(GLenum format, uint32_t size, void *pixelData)
45 {
46     GLTexture tex;
47     glBindTexture(GL_TEXTURE_2D, tex);
48     glTexImage2D(GL_TEXTURE_2D, 0, format, size, size, 0, format, GL_UNSIGNED_BYTE, pixelData);
49     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
50     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
51     return tex;
52 }
53 
InitTextureWithSize(uint32_t size,void * pixelData)54 GLTexture InitTextureWithSize(uint32_t size, void *pixelData)
55 {
56     // Create a simple texture.
57     GLTexture tex;
58     glBindTexture(GL_TEXTURE_2D, tex);
59     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelData);
60     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
61     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
62     return tex;
63 }
64 
InitSimpleTexture()65 GLTexture InitSimpleTexture()
66 {
67     std::vector<GLColor> pixelData(kSize * kSize, GLColor::red);
68     return InitTextureWithSize(kSize, pixelData.data());
69 }
70 
InitRenderbufferWithSize(uint32_t size)71 GLRenderbuffer InitRenderbufferWithSize(uint32_t size)
72 {
73     // Create a simple renderbuffer.
74     GLRenderbuffer renderbuf;
75     glBindRenderbuffer(GL_RENDERBUFFER, renderbuf);
76     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, size, size);
77     return renderbuf;
78 }
79 
InitSimpleRenderbuffer()80 GLRenderbuffer InitSimpleRenderbuffer()
81 {
82     return InitRenderbufferWithSize(kSize);
83 }
84 
85 // Test validation for the extension functions.
TEST_P(GetImageTest,NegativeAPI)86 TEST_P(GetImageTest, NegativeAPI)
87 {
88     // Verify the extension is enabled.
89     ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
90 
91     // Draw once with simple texture.
92     GLTexture tex = InitSimpleTexture();
93     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
94     drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
95     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
96     ASSERT_GL_NO_ERROR();
97 
98     // Pack pixels tightly.
99     glPixelStorei(GL_PACK_ALIGNMENT, 1);
100 
101     // Verify GetTexImage can work with correct parameters.
102     std::vector<GLColor> buffer(kSize * kSize);
103     glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
104     EXPECT_GL_NO_ERROR();
105 
106     // Test invalid texture target.
107     glGetTexImageANGLE(GL_TEXTURE_CUBE_MAP, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
108     EXPECT_GL_ERROR(GL_INVALID_ENUM);
109 
110     // Test invalid texture level.
111     glGetTexImageANGLE(GL_TEXTURE_2D, -1, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
112     EXPECT_GL_ERROR(GL_INVALID_VALUE);
113     glGetTexImageANGLE(GL_TEXTURE_2D, 2000, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
114     EXPECT_GL_ERROR(GL_INVALID_VALUE);
115 
116     // Test invalid format and type.
117     glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_NONE, GL_UNSIGNED_BYTE, buffer.data());
118     EXPECT_GL_ERROR(GL_INVALID_ENUM);
119     glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_NONE, buffer.data());
120     EXPECT_GL_ERROR(GL_INVALID_ENUM);
121 
122     // Create a simple renderbuffer.
123     GLRenderbuffer renderbuf = InitSimpleRenderbuffer();
124     ASSERT_GL_NO_ERROR();
125 
126     // Verify GetRenderbufferImage can work with correct parameters.
127     glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
128     EXPECT_GL_NO_ERROR();
129 
130     // Test invalid renderbuffer target.
131     glGetRenderbufferImageANGLE(GL_TEXTURE_2D, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
132     EXPECT_GL_ERROR(GL_INVALID_ENUM);
133 
134     // Test invalid renderbuffer format/type.
135     glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_NONE, GL_UNSIGNED_BYTE, buffer.data());
136     EXPECT_GL_ERROR(GL_INVALID_ENUM);
137     glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_NONE, buffer.data());
138     EXPECT_GL_ERROR(GL_INVALID_ENUM);
139 
140     // Pack buffer tests. Requires ES 3+ or extension.
141     if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_NV_pixel_buffer_object"))
142     {
143         // Test valid pack buffer.
144         GLBuffer packBuffer;
145         glBindBuffer(GL_PIXEL_PACK_BUFFER, packBuffer);
146         glBufferData(GL_PIXEL_PACK_BUFFER, kSize * kSize * sizeof(GLColor), nullptr,
147                      GL_STATIC_DRAW);
148         glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
149         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
150         glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
151         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
152 
153         // Test too small pack buffer.
154         glBufferData(GL_PIXEL_PACK_BUFFER, kSize, nullptr, GL_STATIC_DRAW);
155         glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
156         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
157         glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
158         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
159     }
160 }
161 
162 // Simple test for GetTexImage
TEST_P(GetImageTest,GetTexImage)163 TEST_P(GetImageTest, GetTexImage)
164 {
165     // Verify the extension is enabled.
166     ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
167 
168     constexpr uint32_t kSmallSize     = 2;
169     std::vector<GLColor> expectedData = {GLColor::red, GLColor::blue, GLColor::green,
170                                          GLColor::yellow};
171 
172     glViewport(0, 0, kSmallSize, kSmallSize);
173 
174     // Draw once with simple texture.
175     GLTexture tex = InitTextureWithSize(kSmallSize, expectedData.data());
176     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
177     drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
178     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
179     ASSERT_GL_NO_ERROR();
180 
181     // Pack pixels tightly.
182     glPixelStorei(GL_PACK_ALIGNMENT, 1);
183 
184     // Verify GetImage.
185     std::vector<GLColor> actualData(kSmallSize * kSmallSize);
186     glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, actualData.data());
187     EXPECT_GL_NO_ERROR();
188     EXPECT_EQ(expectedData, actualData);
189 }
190 
191 // Simple cube map test for GetTexImage
TEST_P(GetImageTest,CubeMap)192 TEST_P(GetImageTest, CubeMap)
193 {
194     // Verify the extension is enabled.
195     ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
196 
197     const std::array<std::array<GLColor, kSmallSize * kSmallSize>, kCubeFaces.size()> expectedData =
198         {{
199             {GLColor::red, GLColor::red, GLColor::red, GLColor::red},
200             {GLColor::green, GLColor::green, GLColor::green, GLColor::green},
201             {GLColor::blue, GLColor::blue, GLColor::blue, GLColor::blue},
202             {GLColor::yellow, GLColor::yellow, GLColor::yellow, GLColor::yellow},
203             {GLColor::cyan, GLColor::cyan, GLColor::cyan, GLColor::cyan},
204             {GLColor::magenta, GLColor::magenta, GLColor::magenta, GLColor::magenta},
205         }};
206 
207     GLTexture texture;
208     glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
209 
210     for (size_t faceIndex = 0; faceIndex < kCubeFaces.size(); ++faceIndex)
211     {
212         glTexImage2D(kCubeFaces[faceIndex], 0, GL_RGBA, kSmallSize, kSmallSize, 0, GL_RGBA,
213                      GL_UNSIGNED_BYTE, expectedData[faceIndex].data());
214     }
215     glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
216     glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
217 
218     // Pack pixels tightly.
219     glPixelStorei(GL_PACK_ALIGNMENT, 1);
220 
221     // Verify GetImage.
222     std::array<GLColor, kSmallSize *kSmallSize> actualData = {};
223     for (size_t faceIndex = 0; faceIndex < kCubeFaces.size(); ++faceIndex)
224     {
225         glGetTexImageANGLE(kCubeFaces[faceIndex], 0, GL_RGBA, GL_UNSIGNED_BYTE, actualData.data());
226         EXPECT_GL_NO_ERROR();
227         EXPECT_EQ(expectedData[faceIndex], actualData);
228     }
229 }
230 
231 // Simple test for GetRenderbufferImage
TEST_P(GetImageTest,GetRenderbufferImage)232 TEST_P(GetImageTest, GetRenderbufferImage)
233 {
234     // Verify the extension is enabled.
235     ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
236 
237     std::vector<GLColor> expectedData = {GLColor::red, GLColor::blue, GLColor::green,
238                                          GLColor::yellow};
239 
240     glViewport(0, 0, kSmallSize, kSmallSize);
241 
242     // Set up a simple Framebuffer with a Renderbuffer.
243     GLRenderbuffer renderbuffer = InitRenderbufferWithSize(kSmallSize);
244     GLFramebuffer framebuffer;
245     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
246     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
247     ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
248 
249     // Draw once with simple texture.
250     GLTexture tex = InitTextureWithSize(kSmallSize, expectedData.data());
251     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
252     drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
253     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
254     ASSERT_GL_NO_ERROR();
255 
256     // Pack pixels tightly.
257     glPixelStorei(GL_PACK_ALIGNMENT, 1);
258 
259     // Verify GetImage.
260     std::vector<GLColor> actualData(kSmallSize * kSmallSize);
261     glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_UNSIGNED_BYTE, actualData.data());
262     EXPECT_GL_NO_ERROR();
263     EXPECT_EQ(expectedData, actualData);
264 }
265 
266 // Verifies that the extension enums and entry points are invalid when the extension is disabled.
TEST_P(GetImageTestNoExtensions,EntryPointsInactive)267 TEST_P(GetImageTestNoExtensions, EntryPointsInactive)
268 {
269     // Verify the extension is not enabled.
270     ASSERT_FALSE(IsGLExtensionEnabled(kExtensionName));
271 
272     // Draw once with simple texture.
273     GLTexture tex = InitSimpleTexture();
274     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
275     drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
276     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
277     ASSERT_GL_NO_ERROR();
278 
279     // Query implementation format and type. Should give invalid enum.
280     GLint param;
281     glGetTexParameteriv(GL_TEXTURE_2D, GL_IMPLEMENTATION_COLOR_READ_FORMAT, &param);
282     EXPECT_GL_ERROR(GL_INVALID_ENUM);
283 
284     glGetTexParameteriv(GL_TEXTURE_2D, GL_IMPLEMENTATION_COLOR_READ_TYPE, &param);
285     EXPECT_GL_ERROR(GL_INVALID_ENUM);
286 
287     // Verify calling GetTexImage produces an error.
288     std::vector<GLColor> buffer(kSize * kSize, 0);
289     glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
290     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
291 
292     // Create a simple renderbuffer.
293     GLRenderbuffer renderbuf = InitSimpleRenderbuffer();
294     ASSERT_GL_NO_ERROR();
295 
296     // Query implementation format and type. Should give invalid enum.
297     glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_IMPLEMENTATION_COLOR_READ_FORMAT, &param);
298     EXPECT_GL_ERROR(GL_INVALID_ENUM);
299 
300     glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_IMPLEMENTATION_COLOR_READ_TYPE, &param);
301     EXPECT_GL_ERROR(GL_INVALID_ENUM);
302 
303     // Verify calling GetRenderbufferImage produces an error.
304     glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
305     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
306 }
307 
308 // Test LUMINANCE_ALPHA (non-renderable) format with GetTexImage
TEST_P(GetImageTest,GetTexImageLuminanceAlpha)309 TEST_P(GetImageTest, GetTexImageLuminanceAlpha)
310 {
311     // Verify the extension is enabled.
312     ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
313 
314     constexpr GLColorRG kMediumLumAlpha = GLColorRG(kUNormHalf, kUNormHalf);
315     std::vector<GLColorRG> expectedData = {kMediumLumAlpha, kMediumLumAlpha, kMediumLumAlpha,
316                                            kMediumLumAlpha};
317 
318     glViewport(0, 0, kSmallSize, kSmallSize);
319 
320     // Set up a simple LUMINANCE_ALPHA texture
321     GLTexture tex =
322         InitTextureWithFormatAndSize(GL_LUMINANCE_ALPHA, kSmallSize, expectedData.data());
323 
324     // Draw once with simple texture.
325     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
326     drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
327     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(kUNormHalf, kUNormHalf, kUNormHalf, kUNormHalf));
328     ASSERT_GL_NO_ERROR();
329 
330     // Pack pixels tightly.
331     glPixelStorei(GL_PACK_ALIGNMENT, 1);
332 
333     // Verify GetImage.
334     std::vector<GLColorRG> actualData(kSmallSize * kSmallSize);
335     glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, actualData.data());
336     EXPECT_GL_NO_ERROR();
337     for (uint32_t i = 0; i < kSmallSize * kSmallSize; ++i)
338     {
339         EXPECT_EQ(expectedData[i].R, actualData[i].R);
340         EXPECT_EQ(expectedData[i].G, actualData[i].G);
341     }
342 }
343 
344 // Test LUMINANCE (non-renderable) format with GetTexImage
TEST_P(GetImageTest,GetTexImageLuminance)345 TEST_P(GetImageTest, GetTexImageLuminance)
346 {
347     // Verify the extension is enabled.
348     ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
349 
350     constexpr GLColorR kMediumLuminance = GLColorR(kUNormHalf);
351     std::vector<GLColorR> expectedData  = {kMediumLuminance, kMediumLuminance, kMediumLuminance,
352                                           kMediumLuminance};
353 
354     glViewport(0, 0, kSmallSize, kSmallSize);
355 
356     // Set up a simple LUMINANCE texture
357     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
358     GLTexture tex = InitTextureWithFormatAndSize(GL_LUMINANCE, kSmallSize, expectedData.data());
359 
360     // Draw once with simple texture.
361     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
362     drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
363     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(kUNormHalf, kUNormHalf, kUNormHalf, kUNormFull));
364     ASSERT_GL_NO_ERROR();
365 
366     // Pack pixels tightly.
367     glPixelStorei(GL_PACK_ALIGNMENT, 1);
368 
369     // Verify GetImage.
370     std::vector<GLColorR> actualData(kSmallSize * kSmallSize);
371     glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, actualData.data());
372     EXPECT_GL_NO_ERROR();
373     for (uint32_t i = 0; i < kSmallSize * kSmallSize; ++i)
374     {
375         EXPECT_EQ(expectedData[i].R, actualData[i].R);
376     }
377 }
378 
379 // Test ALPHA (non-renderable) format with GetTexImage
TEST_P(GetImageTest,GetTexImageAlpha)380 TEST_P(GetImageTest, GetTexImageAlpha)
381 {
382     // Verify the extension is enabled.
383     ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
384 
385     constexpr GLColorR kMediumAlpha    = GLColorR(kUNormHalf);
386     std::vector<GLColorR> expectedData = {kMediumAlpha, kMediumAlpha, kMediumAlpha, kMediumAlpha};
387 
388     glViewport(0, 0, kSmallSize, kSmallSize);
389 
390     // Set up a simple ALPHA texture
391     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
392     GLTexture tex = InitTextureWithFormatAndSize(GL_ALPHA, kSmallSize, expectedData.data());
393 
394     // Draw once with simple texture
395     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
396     drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
397     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(kUNormZero, kUNormZero, kUNormZero, kUNormHalf));
398     ASSERT_GL_NO_ERROR();
399 
400     // Pack pixels tightly.
401     glPixelStorei(GL_PACK_ALIGNMENT, 1);
402 
403     // Verify we get back the correct pixels from GetTexImage
404     std::vector<GLColorR> actualData(kSmallSize * kSmallSize);
405     glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_ALPHA, GL_UNSIGNED_BYTE, actualData.data());
406     EXPECT_GL_NO_ERROR();
407     for (uint32_t i = 0; i < kSmallSize * kSmallSize; ++i)
408     {
409         EXPECT_EQ(expectedData[i].R, actualData[i].R);
410     }
411 }
412 
413 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GetImageTest);
414 ANGLE_INSTANTIATE_TEST(GetImageTest, ES2_VULKAN(), ES3_VULKAN());
415 
416 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GetImageTestNoExtensions);
417 ANGLE_INSTANTIATE_TEST(GetImageTestNoExtensions, ES2_VULKAN(), ES3_VULKAN());
418 
419 }  // namespace