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, ¶m);
282 EXPECT_GL_ERROR(GL_INVALID_ENUM);
283
284 glGetTexParameteriv(GL_TEXTURE_2D, GL_IMPLEMENTATION_COLOR_READ_TYPE, ¶m);
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, ¶m);
298 EXPECT_GL_ERROR(GL_INVALID_ENUM);
299
300 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_IMPLEMENTATION_COLOR_READ_TYPE, ¶m);
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