summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/tests/gl_tests/FenceSyncTests.cpp
blob: 1568509f669d1f7cab02a8cea84de274be736894 (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
//
// Copyright 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

#include "test_utils/ANGLETest.h"

using namespace angle;

class FenceNVTest : public ANGLETest
{
  protected:
    FenceNVTest()
    {
        setWindowWidth(128);
        setWindowHeight(128);
        setConfigRedBits(8);
        setConfigGreenBits(8);
        setConfigBlueBits(8);
        setConfigAlphaBits(8);
        setConfigDepthBits(24);
    }
};

class FenceSyncTest : public ANGLETest
{
  protected:
    FenceSyncTest()
    {
        setWindowWidth(128);
        setWindowHeight(128);
        setConfigRedBits(8);
        setConfigGreenBits(8);
        setConfigBlueBits(8);
        setConfigAlphaBits(8);
        setConfigDepthBits(24);
    }
};

// FenceNV objects should respond false to glIsFenceNV until they've been set
TEST_P(FenceNVTest, IsFence)
{
    if (!extensionEnabled("GL_NV_fence"))
    {
        std::cout << "Test skipped due to missing GL_NV_fence extension." << std::endl;
        return;
    }

    GLuint fence = 0;
    glGenFencesNV(1, &fence);
    EXPECT_GL_NO_ERROR();

    EXPECT_EQ(GL_FALSE, glIsFenceNV(fence));
    EXPECT_GL_NO_ERROR();

    glSetFenceNV(fence, GL_ALL_COMPLETED_NV);
    EXPECT_GL_NO_ERROR();

    EXPECT_EQ(GL_TRUE, glIsFenceNV(fence));
    EXPECT_GL_NO_ERROR();
}

// Test error cases for all FenceNV functions
TEST_P(FenceNVTest, Errors)
{
    if (!extensionEnabled("GL_NV_fence"))
    {
        std::cout << "Test skipped due to missing GL_NV_fence extension." << std::endl;
        return;
    }

    // glTestFenceNV should still return TRUE for an invalid fence and generate an INVALID_OPERATION
    EXPECT_EQ(GL_TRUE, glTestFenceNV(10));
    EXPECT_GL_ERROR(GL_INVALID_OPERATION);

    GLuint fence = 20;

    // glGenFencesNV should generate INVALID_VALUE for a negative n and not write anything to the fences pointer
    glGenFencesNV(-1, &fence);
    EXPECT_GL_ERROR(GL_INVALID_VALUE);
    EXPECT_EQ(20u, fence);

    // Generate a real fence
    glGenFencesNV(1, &fence);
    EXPECT_GL_NO_ERROR();

    // glTestFenceNV should still return TRUE for a fence that is not started and generate an INVALID_OPERATION
    EXPECT_EQ(GL_TRUE, glTestFenceNV(fence));
    EXPECT_GL_ERROR(GL_INVALID_OPERATION);

    // glGetFenceivNV should generate an INVALID_OPERATION for an invalid or unstarted fence and not modify the params
    GLint result = 30;
    glGetFenceivNV(10, GL_FENCE_STATUS_NV, &result);
    EXPECT_GL_ERROR(GL_INVALID_OPERATION);
    EXPECT_EQ(30, result);

    glGetFenceivNV(fence, GL_FENCE_STATUS_NV, &result);
    EXPECT_GL_ERROR(GL_INVALID_OPERATION);
    EXPECT_EQ(30, result);

    // glSetFenceNV should generate an error for any condition that is not ALL_COMPLETED_NV
    glSetFenceNV(fence, 0);
    EXPECT_GL_ERROR(GL_INVALID_ENUM);

    // glSetFenceNV should generate INVALID_OPERATION for an invalid fence
    glSetFenceNV(10, GL_ALL_COMPLETED_NV);
    EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}

// Test that basic usage works and doesn't generate errors or crash
TEST_P(FenceNVTest, BasicOperations)
{
    if (!extensionEnabled("GL_NV_fence"))
    {
        std::cout << "Test skipped due to missing GL_NV_fence extension." << std::endl;
        return;
    }

    glClearColor(1.0f, 0.0f, 1.0f, 1.0f);

    GLuint fences[20] = { 0 };
    glGenFencesNV(static_cast<GLsizei>(ArraySize(fences)), fences);
    EXPECT_GL_NO_ERROR();

    for (GLuint fence : fences)
    {
        glSetFenceNV(fence, GL_ALL_COMPLETED_NV);

        glClear(GL_COLOR_BUFFER_BIT);
    }

    glFinish();

    for (GLuint fence : fences)
    {
        GLint status = 0;
        glGetFenceivNV(fence, GL_FENCE_STATUS_NV, &status);
        EXPECT_GL_NO_ERROR();

        // Fence should be complete now that Finish has been called
        EXPECT_EQ(GL_TRUE, status);
    }

    EXPECT_PIXEL_EQ(0, 0, 255, 0, 255, 255);
}

// FenceSync objects should respond true to IsSync after they are created with glFenceSync
TEST_P(FenceSyncTest, IsSync)
{
    GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
    EXPECT_GL_NO_ERROR();

    EXPECT_EQ(GL_TRUE, glIsSync(sync));
    EXPECT_EQ(GL_FALSE, glIsSync(reinterpret_cast<GLsync>(40)));
}

// Test error cases for all FenceSync function
TEST_P(FenceSyncTest, Errors)
{
    GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);

    // DeleteSync generates INVALID_VALUE when the sync is not valid
    glDeleteSync(reinterpret_cast<GLsync>(20));
    EXPECT_GL_ERROR(GL_INVALID_VALUE);

    // glFenceSync generates GL_INVALID_ENUM if the condition is not GL_SYNC_GPU_COMMANDS_COMPLETE
    EXPECT_EQ(0, glFenceSync(0, 0));
    EXPECT_GL_ERROR(GL_INVALID_ENUM);

    // glFenceSync generates GL_INVALID_ENUM if the flags is not 0
    EXPECT_EQ(0, glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 10));
    EXPECT_GL_ERROR(GL_INVALID_VALUE);

    // glClientWaitSync generates GL_INVALID_VALUE and returns GL_WAIT_FAILED if flags contains more than just GL_SYNC_FLUSH_COMMANDS_BIT
    EXPECT_GLENUM_EQ(GL_WAIT_FAILED, glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT | 0x2, 0));
    EXPECT_GL_ERROR(GL_INVALID_VALUE);

    // glClientWaitSync generates GL_INVALID_VALUE and returns GL_WAIT_FAILED if the sync object is not valid
    EXPECT_GLENUM_EQ(GL_WAIT_FAILED, glClientWaitSync(reinterpret_cast<GLsync>(30), GL_SYNC_FLUSH_COMMANDS_BIT, 0));
    EXPECT_GL_ERROR(GL_INVALID_VALUE);

    // glWaitSync generates GL_INVALID_VALUE if flags is non-zero
    glWaitSync(sync, 1, GL_TIMEOUT_IGNORED);
    EXPECT_GL_ERROR(GL_INVALID_VALUE);

    // glWaitSync generates GL_INVALID_VALUE if GLuint64 is not GL_TIMEOUT_IGNORED
    glWaitSync(sync, 0, 0);
    EXPECT_GL_ERROR(GL_INVALID_VALUE);

    // glWaitSync generates GL_INVALID_VALUE if the sync object is not valid
    glWaitSync(reinterpret_cast<GLsync>(30), 0, GL_TIMEOUT_IGNORED);
    EXPECT_GL_ERROR(GL_INVALID_VALUE);

    // glGetSynciv generates GL_INVALID_VALUE if bufSize is less than zero, results should be untouched
    GLsizei length = 20;
    GLint value = 30;
    glGetSynciv(sync, GL_OBJECT_TYPE, -1, &length, &value);
    EXPECT_GL_ERROR(GL_INVALID_VALUE);
    EXPECT_EQ(20, length);
    EXPECT_EQ(30, value);

    // glGetSynciv generates GL_INVALID_VALUE if the sync object tis not valid, results should be untouched
    glGetSynciv(reinterpret_cast<GLsync>(30), GL_OBJECT_TYPE, 1, &length, &value);
    EXPECT_GL_ERROR(GL_INVALID_VALUE);
    EXPECT_EQ(20, length);
    EXPECT_EQ(30, value);
}

// Test usage of glGetSynciv
TEST_P(FenceSyncTest, BasicQueries)
{
    GLsizei length = 0;
    GLint value = 0;
    GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);

    glGetSynciv(sync, GL_SYNC_CONDITION, 1, &length, &value);
    EXPECT_GL_NO_ERROR();
    EXPECT_EQ(GL_SYNC_GPU_COMMANDS_COMPLETE, value);

    glGetSynciv(sync, GL_OBJECT_TYPE, 1, &length, &value);
    EXPECT_GL_NO_ERROR();
    EXPECT_EQ(GL_SYNC_FENCE, value);

    glGetSynciv(sync, GL_SYNC_FLAGS, 1, &length, &value);
    EXPECT_GL_NO_ERROR();
    EXPECT_EQ(0, value);
}

// Test that basic usage works and doesn't generate errors or crash
TEST_P(FenceSyncTest, BasicOperations)
{
    // TODO(geofflang): Figure out why this is broken on Intel OpenGL
    if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
    {
        std::cout << "Test skipped on Intel OpenGL." << std::endl;
        return;
    }

    glClearColor(1.0f, 0.0f, 1.0f, 1.0f);

    GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);

    glClear(GL_COLOR_BUFFER_BIT);
    glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
    EXPECT_GL_NO_ERROR();

    GLsizei length = 0;
    GLint value = 0;
    unsigned int loopCount = 0;

    glFlush();

    // Use 'loopCount' to make sure the test doesn't get stuck in an infinite loop
    while (value != GL_SIGNALED && loopCount <= 1000000)
    {
        loopCount++;

        glGetSynciv(sync, GL_SYNC_STATUS, 1, &length, &value);
        ASSERT_GL_NO_ERROR();
    }

    ASSERT_GLENUM_EQ(GL_SIGNALED, value);

    for (size_t i = 0; i < 20; i++)
    {
        glClear(GL_COLOR_BUFFER_BIT);
        glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
        EXPECT_GL_NO_ERROR();
    }
}

// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(FenceNVTest,
                       ES2_D3D9(),
                       ES2_D3D11(),
                       ES3_D3D11(),
                       ES2_OPENGL(),
                       ES3_OPENGL(),
                       ES2_OPENGLES(),
                       ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(FenceSyncTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());