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