summaryrefslogtreecommitdiff
path: root/stream-servers/tests/GLSnapshotTesting.h
blob: 2b1492b3d4b119da2d75e19f3f701272e6a24b3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
// Copyright (C) 2018 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include "base/PathUtils.h"
#include "base/System.h"
#include "base/testing/TestSystem.h"

#include "OpenGLTestContext.h"

#include <gtest/gtest.h>

#include <memory>
#include <vector>

namespace emugl {

struct GlValues {
    std::vector<GLint> ints;
    std::vector<GLfloat> floats;
};

struct GlBufferData {
    GLsizeiptr size;
    GLvoid* bytes;
    GLenum usage;
};

// Capabilities which, according to the GLES2 spec, start disabled.
static const GLenum kGLES2CanBeEnabled[] = {GL_BLEND,
                                            GL_CULL_FACE,
                                            GL_DEPTH_TEST,
                                            GL_POLYGON_OFFSET_FILL,
                                            GL_SAMPLE_ALPHA_TO_COVERAGE,
                                            GL_SAMPLE_COVERAGE,
                                            GL_SCISSOR_TEST,
                                            GL_STENCIL_TEST};

// Capabilities which, according to the GLES2 spec, start enabled.
static const GLenum kGLES2CanBeDisabled[] = {GL_DITHER};

// Modes for CullFace
static const GLenum kGLES2CullFaceModes[] = {GL_BACK, GL_FRONT,
                                             GL_FRONT_AND_BACK};

// Modes for FrontFace
static const GLenum kGLES2FrontFaceModes[] = {GL_CCW, GL_CW};

// Valid Stencil test functions
static const GLenum kGLES2StencilFuncs[] = {GL_NEVER,   GL_ALWAYS,  GL_LESS,
                                            GL_LEQUAL,  GL_EQUAL,   GL_GEQUAL,
                                            GL_GREATER, GL_NOTEQUAL};
// Valid Stencil test result operations
static const GLenum kGLES2StencilOps[] = {GL_KEEP,      GL_ZERO,     GL_REPLACE,
                                          GL_INCR,      GL_DECR,     GL_INVERT,
                                          GL_INCR_WRAP, GL_DECR_WRAP};

// Modes for the BlendEquation
static const GLenum kGLES2BlendEquations[] = {GL_FUNC_ADD, GL_FUNC_SUBTRACT,
                                              GL_FUNC_REVERSE_SUBTRACT};

// Valid Blend functions
static const GLenum kGLES2BlendFuncs[] = {GL_ZERO,
                                          GL_ONE,
                                          GL_SRC_COLOR,
                                          GL_ONE_MINUS_SRC_COLOR,
                                          GL_DST_COLOR,
                                          GL_ONE_MINUS_DST_COLOR,
                                          GL_SRC_ALPHA,
                                          GL_ONE_MINUS_SRC_ALPHA,
                                          GL_CONSTANT_COLOR,
                                          GL_ONE_MINUS_CONSTANT_COLOR,
                                          GL_CONSTANT_ALPHA,
                                          GL_ONE_MINUS_CONSTANT_ALPHA,
                                          GL_SRC_ALPHA_SATURATE};

// Valid GENERATE_MIPMAP_HINT values
static const GLenum kGLES2GenerateMipmapHints[] = {GL_DONT_CARE, GL_FASTEST,
                                                   GL_NICEST};

// Returns a string useful for failure messages describing |enumValue|.
std::string describeGlEnum(GLenum enumValue);

// For building other compare functions which return AssertionResult.
// Compares an |actual| against an |expected| value. Returns a failure values
// do not match; provide |description| to attach details to the failure message.
template <class T>
testing::AssertionResult compareValue(T expected,
                                      T actual,
                                      const std::string& description = "");

// Compares a global GL value, known by |name| and retrieved as a boolean,
// against an |expected| value.
testing::AssertionResult compareGlobalGlBoolean(const GLESv2Dispatch* gl,
                                                GLenum name,
                                                GLboolean expected);

// Compares a global GL value, known by |name| and retrieved as an integer,
// against an |expected| value.
testing::AssertionResult compareGlobalGlInt(const GLESv2Dispatch* gl,
                                            GLenum name,
                                            GLint expected);

testing::AssertionResult compareGlobalGlInt_i(const GLESv2Dispatch* gl,
                                              GLenum name,
                                              GLuint index,
                                              GLint expected);
// Compares a global GL value, known by |name| and retrieved as a float, against
// an |expected| value.
testing::AssertionResult compareGlobalGlFloat(const GLESv2Dispatch* gl,
                                              GLenum name,
                                              GLfloat expected);

// For building other compare functions which return AssertionResult.
// Compare the values at each index of a vector |actual| against an |expected|.
// Returns a failure if any values are mismatched; provide |description| to
// attach details to the failure message.
// |actual| is allowed to contain more elements than |expected|.
template <class T>
testing::AssertionResult compareVector(
        const std::vector<T>& expected,
        const std::vector<T>& actual,
        const std::string& description = "vector");

// Compares a vector of global GL values, known by |name| and retrieved as a
// boolean array, against |expected| values.
// Specify |size| if more space is needed than the size of |expected|.
testing::AssertionResult compareGlobalGlBooleanv(
        const GLESv2Dispatch* gl,
        GLenum name,
        const std::vector<GLboolean>& expected,
        GLuint size = 0);

testing::AssertionResult compareGlobalGlBooleanv_i(
        const GLESv2Dispatch* gl,
        GLenum name,
        GLuint index,
        const std::vector<GLboolean>& expected,
        GLuint size = 0);


// Compares a vector of global GL values, known by |name| and retrieved as an
// integer array, against |expected| values.
// Specify |size| if more space is needed than the size of |expected|.
testing::AssertionResult compareGlobalGlIntv(const GLESv2Dispatch* gl,
                                             GLenum name,
                                             const std::vector<GLint>& expected,
                                             GLuint size = 0);

testing::AssertionResult compareGlobalGlIntv_i(const GLESv2Dispatch* gl,
                                               GLenum name,
                                               GLuint index,
                                               const std::vector<GLint>& expected,
                                               GLuint size = 0);

// Compares a vector of global GL values, known by |name| and retrieved as a
// float array, against |expected| values.
// Specify |size| if more space is needed than the size of |expected|.
testing::AssertionResult compareGlobalGlFloatv(
        const GLESv2Dispatch* gl,
        GLenum name,
        const std::vector<GLfloat>& expected,
        GLuint size = 0);

// SnapshotTest - A helper class for performing a test related to saving or
// loading GL translator snapshots. As a test fixture, its setup will prepare a
// fresh GL state and paths for temporary snapshot files.
//
// doSnapshot saves a snapshot, clears the GL state, then loads the snapshot.
// saveSnapshot and loadSnapshot can be used to perform saves and loads
// independently.
//
// Usage example:
//     TEST_F(SnapshotTest, PreserveFooBar) {
//         // clean GL state is ready
//         EXPECT_TRUE(fooBarState());
//         modifyGlStateFooBar();
//         EXPECT_FALSE(fooBarState());  // GL state has been changed
//         doSnapshot(); // saves, resets, and reloads the state
//         EXPECT_FALSE(fooBarState());  // Snapshot preserved the state change
//     }
//
class SnapshotTest : public emugl::GLTest {
public:
    SnapshotTest() = default;

    void SetUp() override;

    // Mimics FrameBuffer.onSave, with fewer objects to manage.
    // |streamFile| is a filename into which the snapshot will be saved.
    // |textureFile| is a filename into which the textures will be saved.
    void saveSnapshot(const std::string streamFile,
                      const std::string textureFile);

    // Mimics FrameBuffer.onLoad, with fewer objects to manage.
    // Assumes that a valid display is present.
    // |streamFile| is a filename from which the snapshot will be loaded.
    // |textureFile| is a filename from which the textures will be loaded.
    void loadSnapshot(const std::string streamFile,
                      const std::string textureFile);

    // Performs a teardown and reset of graphics objects in preparation for
    // a snapshot load.
    void preloadReset();

    // Mimics saving and then loading a graphics snapshot.
    // To verify that state has been reset to some default before the load,
    // assertions can be performed in |preloadCheck|.
    void doSnapshot(std::function<void()> preloadCheck);

protected:
    android::base::TestSystem mTestSystem;
    std::string mSnapshotPath = {};
};

// SnapshotPreserveTest - A helper class building on SnapshotTest for granular
// testing of the GL snapshot. This is specifically for the common case where a
// piece of GL state has a known default, and our test aims to verify that the
// snapshot preserves this piece of state when it has been changed from the
// default.
//
// This acts as an abstract class; implementations should override the state
// check state change functions to perform the assertions and operations
// relevant to the part of GL state that they are testing.
// doCheckedSnapshot can be but does not need to be overwritten. It performs the
// following:
//      - check for default state
//      - make state changes, check that the state changes are in effect
//      - save a snapshot, reset the GL state, then check for default state
//      - load the snapshot, check that the state changes are in effect again
//
// Usage example with a subclass:
//     class SnapshotEnableFooTest : public SnapshotPreserveTest {
//         void defaultStateCheck() override { EXPECT_FALSE(isFooEnabled()); }
//         void changedStateCheck() override { EXPECT_TRUE(isFooEnabled());  }
//         void stateChange() override { enableFoo(); }
//     };
//     TEST_F(SnapshotEnableFooTest, PreserveFooEnable) {
//         doCheckedSnapshot();
//     }
//
class SnapshotPreserveTest : public SnapshotTest {
public:
    // Asserts that we are working from a clean starting state.
    virtual void defaultStateCheck() {
        ADD_FAILURE() << "Snapshot test needs a default state check function.";
    }

    // Asserts that any expected changes to state have occurred.
    virtual void changedStateCheck() {
        ADD_FAILURE()
                << "Snapshot test needs a post-change state check function.";
    }

    // Modifies the state.
    virtual void stateChange() {
        ADD_FAILURE() << "Snapshot test needs a state-changer function.";
    }

    // Sets up a non-default state and asserts that a snapshot preserves it.
    virtual void doCheckedSnapshot();
};

// SnapshotSetValueTest - A helper class for testing preservation of pieces of
// GL state where default and changed state checks are comparisons against the
// same type of expected reference value.
//
// The expected |m_default_value| and |m_changed_value| should be set before
// a checked snapshot is attempted.
//
// Usage example with a subclass:
//     class SnapshotSetFooTest : public SnapshotSetValueTest<Foo> {
//         void stateCheck(Foo expected) { EXPECT_EQ(expected, getFoo()); }
//         void stateChange() override { setFoo(*m_changed_value); }
//     };
//     TEST_F(SnapshotSetFooTest, SetFooValue) {
//         setExpectedValues(kFooDefaultValue, kFooTestValue);
//         doCheckedSnapshot();
//     }
//
template <class T>
class SnapshotSetValueTest : public SnapshotPreserveTest {
public:
    // Configures the test to assert against values which it should consider
    // default and values which it should expect after changes.
    void setExpectedValues(T defaultValue, T changedValue) {
        m_default_value = std::unique_ptr<T>(new T(defaultValue));
        m_changed_value = std::unique_ptr<T>(new T(changedValue));
    }

    // Checks part of state against an expected value.
    virtual void stateCheck(T expected) {
        ADD_FAILURE() << "Snapshot test needs a state-check function.";
    };

    void defaultStateCheck() override { stateCheck(*m_default_value); }
    void changedStateCheck() override { stateCheck(*m_changed_value); }

    void doCheckedSnapshot() override {
        if (m_default_value == nullptr || m_changed_value == nullptr) {
            FAIL() << "Snapshot test not provided expected values.";
        }
        SnapshotPreserveTest::doCheckedSnapshot();
    }

protected:
    std::unique_ptr<T> m_default_value;
    std::unique_ptr<T> m_changed_value;
};

}  // namespace emugl