• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "GLSnapshotTestStateUtils.h"
16 #include "GLSnapshotTesting.h"
17 #include "apigen-codec-common/glUtils.h"
18 
19 #include <gtest/gtest.h>
20 
21 namespace emugl {
22 
23 struct GlTextureUnitState {
24     GLuint binding2D;
25     GLuint bindingCubeMap;
26 };
27 
28 struct GlTextureImageState {
29     GLenum format;
30     GLenum type;
31     GLsizei width;
32     GLsizei height;
33 
34     GLboolean isCompressed;
35     GLsizei compressedSize;
36 
37     std::vector<GLubyte> bytes;
38 };
39 
40 using GlMipmapArray = std::vector<GlTextureImageState>;
41 
42 struct GlTextureObjectState {
43     GLenum minFilter;
44     GLenum magFilter;
45     GLenum wrapS;
46     GLenum wrapT;
47 
48     GLenum target;
49     GlMipmapArray images2D;
50     std::vector<GlMipmapArray> imagesCubeMap;
51 };
52 
53 static const GLenum kGLES2TextureCubeMapSides[] = {
54         GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
55         GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
56         GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
57 };
58 
59 static const GlMipmapArray kGLES2TestTexture2D = {{GL_RGBA,
60                                                    GL_UNSIGNED_BYTE,
61                                                    4,
62                                                    4,
63                                                    false,
64                                                    0,
65                                                    {
66                                                            0x11,
67                                                            0x22,
68                                                            0x33,
69                                                            0x44,
70                                                            0x55,
71                                                            0x66,
72                                                            0x77,
73                                                            0x88,
74                                                            0x99,
75                                                            0xaa,
76                                                            0xbb,
77                                                            0xcc,
78                                                            0xdd,
79                                                            0xee,
80                                                            0xff,
81                                                            0x00,
82                                                    }},
83                                                   {GL_RGBA,
84                                                    GL_UNSIGNED_SHORT_4_4_4_4,
85                                                    2,
86                                                    2,
87                                                    false,
88                                                    0,
89                                                    {
90                                                            0x51,
91                                                            0x52,
92                                                            0x53,
93                                                            0x54,
94                                                    }},
95                                                   {GL_RGBA,
96                                                    GL_UNSIGNED_SHORT_5_5_5_1,
97                                                    1,
98                                                    1,
99                                                    false,
100                                                    0,
101                                                    {
102                                                            0xab,
103                                                    }}};
104 
105 static const std::vector<GlMipmapArray> kGLES2TestTextureCubeMap = {
106         {{GL_RGBA,
107           GL_UNSIGNED_BYTE,
108           2,
109           2,
110           false,
111           0,
112           {
113                   0x11,
114                   0x12,
115                   0x13,
116                   0x14,
117           }}},
118         {{GL_RGBA,
119           GL_UNSIGNED_BYTE,
120           2,
121           2,
122           false,
123           0,
124           {
125                   0x21,
126                   0x22,
127                   0x23,
128                   0x24,
129           }}},
130         {{GL_RGBA,
131           GL_UNSIGNED_BYTE,
132           2,
133           2,
134           false,
135           0,
136           {
137                   0x31,
138                   0x32,
139                   0x33,
140                   0x34,
141           }}},
142         {{GL_RGBA,
143           GL_UNSIGNED_BYTE,
144           2,
145           2,
146           false,
147           0,
148           {
149                   0x41,
150                   0x42,
151                   0x43,
152                   0x44,
153           }}},
154         {{GL_RGBA,
155           GL_UNSIGNED_BYTE,
156           2,
157           2,
158           false,
159           0,
160           {
161                   0x51,
162                   0x52,
163                   0x53,
164                   0x54,
165           }}},
166         {{GL_RGBA,
167           GL_UNSIGNED_BYTE,
168           2,
169           2,
170           false,
171           0,
172           {
173                   0x61,
174                   0x62,
175                   0x63,
176                   0x64,
177           }}},
178 };
179 
180 class SnapshotGlTextureUnitActiveTest : public SnapshotPreserveTest {
181 public:
defaultStateCheck()182     void defaultStateCheck() override {
183         EXPECT_TRUE(compareGlobalGlInt(gl, GL_ACTIVE_TEXTURE, GL_TEXTURE0));
184     }
185 
changedStateCheck()186     void changedStateCheck() override {
187         EXPECT_TRUE(compareGlobalGlInt(gl, GL_ACTIVE_TEXTURE,
188                                        GL_TEXTURE0 + m_active_texture_unit));
189     }
190 
stateChange()191     void stateChange() override {
192         gl->glActiveTexture(GL_TEXTURE0 + m_active_texture_unit);
193     }
194 
useTextureUnit(GLuint unit)195     void useTextureUnit(GLuint unit) {
196         GLint maxTextureUnits;
197         gl->glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
198                           &maxTextureUnits);
199         EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
200 
201         if (unit < maxTextureUnits) {
202             m_active_texture_unit = unit;
203         } else {
204             fprintf(stderr,
205                     "Tried to use texture unit %d when max unit was %d."
206                     " Defaulting to unit 0.\n",
207                     unit, maxTextureUnits);
208             m_active_texture_unit = 0;
209         }
210     }
211 
212 protected:
213     GLuint m_active_texture_unit;
214 };
215 
TEST_F(SnapshotGlTextureUnitActiveTest,ActiveTextureUnit)216 TEST_F(SnapshotGlTextureUnitActiveTest, ActiveTextureUnit) {
217     useTextureUnit(1);
218     doCheckedSnapshot();
219 }
220 
221 class SnapshotGlTextureUnitBindingsTest : public SnapshotPreserveTest {
222 public:
defaultStateCheck()223     void defaultStateCheck() override {
224         GLint maxTextureUnits;
225         gl->glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
226                           &maxTextureUnits);
227         for (int i = 0; i < maxTextureUnits; i++) {
228             gl->glActiveTexture(GL_TEXTURE0 + i);
229             EXPECT_TRUE(compareGlobalGlInt(gl, GL_TEXTURE_BINDING_2D, 0));
230             EXPECT_TRUE(compareGlobalGlInt(gl, GL_TEXTURE_BINDING_CUBE_MAP, 0));
231         }
232     }
233 
changedStateCheck()234     void changedStateCheck() override {
235         GLint maxTextureUnits;
236         gl->glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
237                           &maxTextureUnits);
238         EXPECT_EQ(m_unit_states.size(), maxTextureUnits);
239 
240         for (int i = 0; i < maxTextureUnits; i++) {
241             gl->glActiveTexture(GL_TEXTURE0 + i);
242             EXPECT_TRUE(compareGlobalGlInt(gl, GL_TEXTURE_BINDING_2D,
243                                            m_unit_states[i].binding2D));
244             EXPECT_TRUE(compareGlobalGlInt(gl, GL_TEXTURE_BINDING_CUBE_MAP,
245                                            m_unit_states[i].bindingCubeMap));
246         }
247     }
248 
stateChange()249     void stateChange() override {
250         GLint maxTextureUnits;
251         gl->glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
252                           &maxTextureUnits);
253         m_unit_states.resize(maxTextureUnits);
254 
255         m_state_changer();
256     }
257 
setStateChanger(std::function<void ()> changer)258     void setStateChanger(std::function<void()> changer) {
259         m_state_changer = changer;
260     }
261 
262 protected:
263     // Create a texture object, bind to texture unit |unit| at binding point
264     // |bindPoint|, and record that we've done so.
createAndBindTexture(GLuint unit,GLenum bindPoint)265     GLuint createAndBindTexture(GLuint unit, GLenum bindPoint) {
266         GLint maxTextureUnits;
267         gl->glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
268                           &maxTextureUnits);
269         if (unit >= maxTextureUnits) {
270             fprintf(stderr,
271                     "Cannot bind to unit %d: max units is %d. Binding to %d "
272                     "instead.\n",
273                     unit, maxTextureUnits, maxTextureUnits - 1);
274             unit = maxTextureUnits - 1;
275         }
276 
277         GLuint testTexture;
278         gl->glGenTextures(1, &testTexture);
279         gl->glActiveTexture(GL_TEXTURE0 + unit);
280         gl->glBindTexture(bindPoint, testTexture);
281         EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
282         switch (bindPoint) {
283             case GL_TEXTURE_2D:
284                 m_unit_states[unit].binding2D = testTexture;
285                 break;
286             case GL_TEXTURE_CUBE_MAP:
287                 m_unit_states[unit].bindingCubeMap = testTexture;
288                 break;
289             default:
290                 ADD_FAILURE() << "Unsupported texture unit bind point " +
291                                          describeGlEnum(bindPoint);
292         }
293         return testTexture;
294     }
295 
296     std::vector<GlTextureUnitState> m_unit_states;
__anonc94a75350102null297     std::function<void()> m_state_changer = [] {};
298 };
299 
TEST_F(SnapshotGlTextureUnitBindingsTest,BindTextures)300 TEST_F(SnapshotGlTextureUnitBindingsTest, BindTextures) {
301     setStateChanger([this] {
302         createAndBindTexture(1, GL_TEXTURE_2D);
303         createAndBindTexture(8, GL_TEXTURE_CUBE_MAP);
304         createAndBindTexture(16, GL_TEXTURE_2D);
305         createAndBindTexture(32, GL_TEXTURE_CUBE_MAP);
306     });
307     doCheckedSnapshot();
308 }
309 
310 class SnapshotGlTextureObjectTest : public SnapshotPreserveTest {
311 public:
defaultStateCheck()312     void defaultStateCheck() override {
313         EXPECT_EQ(GL_FALSE, gl->glIsTexture(m_object_name));
314     }
315 
changedStateCheck()316     void changedStateCheck() override {
317         SCOPED_TRACE("Texture object " + std::to_string(m_object_name) +
318                      ", target " + describeGlEnum(m_state.target));
319         EXPECT_EQ(GL_TRUE, gl->glIsTexture(m_object_name));
320 
321         EXPECT_TRUE(compareGlobalGlInt(gl, GL_ACTIVE_TEXTURE, GL_TEXTURE0));
322         EXPECT_TRUE(compareGlobalGlInt(gl, getTargetBindingName(m_state.target),
323                                        m_object_name));
324 
325         EXPECT_TRUE(compareParameter(GL_TEXTURE_MIN_FILTER, m_state.minFilter));
326         EXPECT_TRUE(compareParameter(GL_TEXTURE_MAG_FILTER, m_state.magFilter));
327         EXPECT_TRUE(compareParameter(GL_TEXTURE_WRAP_S, m_state.wrapS));
328         EXPECT_TRUE(compareParameter(GL_TEXTURE_WRAP_T, m_state.wrapT));
329 
330         auto compareImageFunc = [this](GLenum imageTarget,
331                                        GlMipmapArray& levels) {
332             for (int i = 0; i < levels.size(); i++) {
333                 EXPECT_TRUE(compareVector<GLubyte>(
334                         levels[i].bytes,
335                         getTextureImageData(gl, m_object_name, imageTarget, i,
336                                             levels[i].width, levels[i].height,
337                                             levels[i].format, levels[i].type),
338                         "mipmap level " + std::to_string(i)));
339                 EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
340             }
341         };
342 
343         switch (m_state.target) {
344             case GL_TEXTURE_2D: {
345                 compareImageFunc(m_state.target, m_state.images2D);
346             } break;
347             case GL_TEXTURE_CUBE_MAP: {
348                 if (m_state.imagesCubeMap.size() > 6) {
349                     ADD_FAILURE() << "Test texture cube map had "
350                                   << m_state.imagesCubeMap.size()
351                                   << " 'sides' of data.";
352                     break;
353                 }
354                 for (int j = 0; j < m_state.imagesCubeMap.size(); j++) {
355                     compareImageFunc(kGLES2TextureCubeMapSides[j],
356                                      m_state.imagesCubeMap[j]);
357                 }
358             } break;
359             default:
360                 ADD_FAILURE()
361                         << "Unsupported texture target " << m_state.target;
362                 break;
363         }
364     }
365 
stateChange()366     void stateChange() override {
367         gl->glGenTextures(1, &m_object_name);
368 
369         // Bind to texture unit TEXTURE0 for test simplicity
370         gl->glActiveTexture(GL_TEXTURE0);
371         gl->glBindTexture(m_state.target, m_object_name);
372 
373         // Set texture sample parameters
374         gl->glTexParameteri(m_state.target, GL_TEXTURE_MIN_FILTER,
375                             m_state.minFilter);
376         gl->glTexParameteri(m_state.target, GL_TEXTURE_MAG_FILTER,
377                             m_state.magFilter);
378         gl->glTexParameteri(m_state.target, GL_TEXTURE_WRAP_S, m_state.wrapS);
379         gl->glTexParameteri(m_state.target, GL_TEXTURE_WRAP_T, m_state.wrapT);
380 
381         auto initImageFunc = [this](GLenum imageTarget, GlMipmapArray& levels) {
382             for (int i = 0; i < levels.size(); i++) {
383                 levels[i].bytes.resize(
384                         levels[i].width * levels[i].height *
385                         glUtilsPixelBitSize(
386                                 levels[i].format,
387                                 GL_UNSIGNED_BYTE /* levels[i].type */) / 8);
388                 gl->glTexImage2D(imageTarget, i, levels[i].format,
389                                  levels[i].width, levels[i].height, 0,
390                                  levels[i].format,
391                                  GL_UNSIGNED_BYTE /* levels[i].type */,
392                                  levels[i].bytes.data());
393             }
394         };
395 
396         switch (m_state.target) {
397             case GL_TEXTURE_2D: {
398                 initImageFunc(m_state.target, m_state.images2D);
399             } break;
400             case GL_TEXTURE_CUBE_MAP: {
401                 if (m_state.imagesCubeMap.size() > 6) {
402                     ADD_FAILURE() << "Test texture cube map had "
403                                   << m_state.imagesCubeMap.size()
404                                   << " 'sides' of data.";
405                     break;
406                 }
407                 for (int j = 0; j < m_state.imagesCubeMap.size(); j++) {
408                     GLenum side = kGLES2TextureCubeMapSides[j];
409                     initImageFunc(side, m_state.imagesCubeMap[j]);
410                 }
411             } break;
412             default:
413                 ADD_FAILURE()
414                         << "Unsupported texture target " << m_state.target;
415                 break;
416         }
417     }
418 
419 protected:
420     // Compares a symbolic constant value |expected| against the parameter named
421     // |paramName| of the texture object which is bound in unit TEXTURE0.
compareParameter(GLenum paramName,GLenum expected)422     testing::AssertionResult compareParameter(GLenum paramName,
423                                               GLenum expected) {
424         GLint actual;
425         gl->glGetTexParameteriv(m_state.target, paramName, &actual);
426         return compareValue<GLint>(
427                 expected, actual,
428                 "GL texture object " + std::to_string(m_object_name) +
429                         " mismatch for param " + describeGlEnum(paramName) +
430                         " on target " + describeGlEnum(m_state.target));
431     }
432 
getTargetBindingName(GLenum target)433     GLenum getTargetBindingName(GLenum target) {
434         switch (target) {
435             case GL_TEXTURE_2D:
436                 return GL_TEXTURE_BINDING_2D;
437             case GL_TEXTURE_CUBE_MAP:
438                 return GL_TEXTURE_BINDING_CUBE_MAP;
439             default:
440                 ADD_FAILURE() << "Unsupported texture target " << target;
441                 return 0;
442         }
443     }
444 
445     GLuint m_object_name;
446     GlTextureObjectState m_state = {};
447 };
448 
TEST_F(SnapshotGlTextureObjectTest,SetObjectParameters)449 TEST_F(SnapshotGlTextureObjectTest, SetObjectParameters) {
450     m_state = {
451             .minFilter = GL_LINEAR,
452             .magFilter = GL_NEAREST,
453             .wrapS = GL_MIRRORED_REPEAT,
454             .wrapT = GL_CLAMP_TO_EDGE,
455             .target = GL_TEXTURE_2D,
456     };
457     doCheckedSnapshot();
458 }
459 
TEST_F(SnapshotGlTextureObjectTest,Create2DMipmap)460 TEST_F(SnapshotGlTextureObjectTest, Create2DMipmap) {
461     m_state = {.minFilter = GL_LINEAR,
462                .magFilter = GL_NEAREST,
463                .wrapS = GL_MIRRORED_REPEAT,
464                .wrapT = GL_CLAMP_TO_EDGE,
465                .target = GL_TEXTURE_2D,
466                .images2D = kGLES2TestTexture2D};
467     doCheckedSnapshot();
468 }
469 
TEST_F(SnapshotGlTextureObjectTest,CreateCubeMap)470 TEST_F(SnapshotGlTextureObjectTest, CreateCubeMap) {
471     m_state = {.minFilter = GL_LINEAR,
472                .magFilter = GL_NEAREST,
473                .wrapS = GL_MIRRORED_REPEAT,
474                .wrapT = GL_CLAMP_TO_EDGE,
475                .target = GL_TEXTURE_CUBE_MAP,
476                .images2D = {}, // mingw compiler cannot deal with gaps
477                .imagesCubeMap = kGLES2TestTextureCubeMap};
478     doCheckedSnapshot();
479 }
480 
481 }  // namespace emugl
482