1/*
2 * Copyright 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "SurfaceTextureMultiContextGL_test"
18//#define LOG_NDEBUG 0
19
20#include "SurfaceTextureMultiContextGL.h"
21
22#include "FillBuffer.h"
23
24#include <GLES/glext.h>
25
26namespace android {
27
28TEST_F(SurfaceTextureMultiContextGLTest, UpdateFromMultipleContextsFails) {
29    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
30
31    // Latch the texture contents on the primary context.
32    mFW->waitForFrame();
33    ASSERT_EQ(OK, mST->updateTexImage());
34
35    // Attempt to latch the texture on the secondary context.
36    ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
37            mSecondEglContext));
38    ASSERT_EQ(EGL_SUCCESS, eglGetError());
39    ASSERT_EQ(INVALID_OPERATION, mST->updateTexImage());
40}
41
42TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextSucceeds) {
43    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
44
45    // Latch the texture contents on the primary context.
46    mFW->waitForFrame();
47    ASSERT_EQ(OK, mST->updateTexImage());
48
49    // Detach from the primary context.
50    ASSERT_EQ(OK, mST->detachFromContext());
51
52    // Check that the GL texture was deleted.
53    EXPECT_EQ(GL_FALSE, glIsTexture(TEX_ID));
54}
55
56TEST_F(SurfaceTextureMultiContextGLTest,
57        DetachFromContextSucceedsAfterProducerDisconnect) {
58    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
59
60    // Latch the texture contents on the primary context.
61    mFW->waitForFrame();
62    ASSERT_EQ(OK, mST->updateTexImage());
63
64    // Detach from the primary context.
65    native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU);
66    ASSERT_EQ(OK, mST->detachFromContext());
67
68    // Check that the GL texture was deleted.
69    EXPECT_EQ(GL_FALSE, glIsTexture(TEX_ID));
70}
71
72TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWhenAbandoned) {
73    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
74
75    // Latch the texture contents on the primary context.
76    mFW->waitForFrame();
77    ASSERT_EQ(OK, mST->updateTexImage());
78
79    // Attempt to detach from the primary context.
80    mST->abandon();
81    ASSERT_EQ(NO_INIT, mST->detachFromContext());
82}
83
84TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWhenDetached) {
85    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
86
87    // Latch the texture contents on the primary context.
88    mFW->waitForFrame();
89    ASSERT_EQ(OK, mST->updateTexImage());
90
91    // Detach from the primary context.
92    ASSERT_EQ(OK, mST->detachFromContext());
93
94    // Attempt to detach from the primary context again.
95    ASSERT_EQ(INVALID_OPERATION, mST->detachFromContext());
96}
97
98TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWithNoDisplay) {
99    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
100
101    // Latch the texture contents on the primary context.
102    mFW->waitForFrame();
103    ASSERT_EQ(OK, mST->updateTexImage());
104
105    // Make there be no current display.
106    ASSERT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
107            EGL_NO_CONTEXT));
108    ASSERT_EQ(EGL_SUCCESS, eglGetError());
109
110    // Attempt to detach from the primary context.
111    ASSERT_EQ(INVALID_OPERATION, mST->detachFromContext());
112}
113
114TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWithNoContext) {
115    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
116
117    // Latch the texture contents on the primary context.
118    mFW->waitForFrame();
119    ASSERT_EQ(OK, mST->updateTexImage());
120
121    // Make current context be incorrect.
122    ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
123            mSecondEglContext));
124    ASSERT_EQ(EGL_SUCCESS, eglGetError());
125
126    // Attempt to detach from the primary context.
127    ASSERT_EQ(INVALID_OPERATION, mST->detachFromContext());
128}
129
130TEST_F(SurfaceTextureMultiContextGLTest, UpdateTexImageFailsWhenDetached) {
131    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
132
133    // Detach from the primary context.
134    ASSERT_EQ(OK, mST->detachFromContext());
135
136    // Attempt to latch the texture contents on the primary context.
137    mFW->waitForFrame();
138    ASSERT_EQ(INVALID_OPERATION, mST->updateTexImage());
139}
140
141TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceeds) {
142    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
143
144    // Latch the texture contents on the primary context.
145    mFW->waitForFrame();
146    ASSERT_EQ(OK, mST->updateTexImage());
147
148    // Detach from the primary context.
149    ASSERT_EQ(OK, mST->detachFromContext());
150
151    // Attach to the secondary context.
152    ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
153            mSecondEglContext));
154    ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID));
155
156    // Verify that the texture object was created and bound.
157    GLint texBinding = -1;
158    glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding);
159    EXPECT_EQ(SECOND_TEX_ID, texBinding);
160
161    // Try to use the texture from the secondary context.
162    glClearColor(0.2, 0.2, 0.2, 0.2);
163    glClear(GL_COLOR_BUFFER_BIT);
164    glViewport(0, 0, 1, 1);
165    mSecondTextureRenderer->drawTexture();
166    ASSERT_TRUE(checkPixel( 0,  0,  35,  35,  35,  35));
167    ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
168}
169
170TEST_F(SurfaceTextureMultiContextGLTest,
171        AttachToContextSucceedsAfterProducerDisconnect) {
172    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
173
174    // Latch the texture contents on the primary context.
175    mFW->waitForFrame();
176    ASSERT_EQ(OK, mST->updateTexImage());
177
178    // Detach from the primary context.
179    native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU);
180    ASSERT_EQ(OK, mST->detachFromContext());
181
182    // Attach to the secondary context.
183    ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
184            mSecondEglContext));
185    ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID));
186
187    // Verify that the texture object was created and bound.
188    GLint texBinding = -1;
189    glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding);
190    EXPECT_EQ(SECOND_TEX_ID, texBinding);
191
192    // Try to use the texture from the secondary context.
193    glClearColor(0.2, 0.2, 0.2, 0.2);
194    glClear(GL_COLOR_BUFFER_BIT);
195    glViewport(0, 0, 1, 1);
196    mSecondTextureRenderer->drawTexture();
197    ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
198    ASSERT_TRUE(checkPixel( 0,  0,  35,  35,  35,  35));
199}
200
201TEST_F(SurfaceTextureMultiContextGLTest,
202        AttachToContextSucceedsBeforeUpdateTexImage) {
203    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
204
205    // Detach from the primary context.
206    native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU);
207    ASSERT_EQ(OK, mST->detachFromContext());
208
209    // Attach to the secondary context.
210    ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
211            mSecondEglContext));
212    ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID));
213
214    // Verify that the texture object was created and bound.
215    GLint texBinding = -1;
216    glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding);
217    EXPECT_EQ(SECOND_TEX_ID, texBinding);
218
219    // Latch the texture contents on the primary context.
220    mFW->waitForFrame();
221    ASSERT_EQ(OK, mST->updateTexImage());
222
223    // Try to use the texture from the secondary context.
224    glClearColor(0.2, 0.2, 0.2, 0.2);
225    glClear(GL_COLOR_BUFFER_BIT);
226    glViewport(0, 0, 1, 1);
227    mSecondTextureRenderer->drawTexture();
228    ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
229    ASSERT_TRUE(checkPixel( 0,  0,  35,  35,  35,  35));
230}
231
232TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWhenAbandoned) {
233    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
234
235    // Latch the texture contents on the primary context.
236    mFW->waitForFrame();
237    ASSERT_EQ(OK, mST->updateTexImage());
238
239    // Detach from the primary context.
240    ASSERT_EQ(OK, mST->detachFromContext());
241
242    // Attempt to attach to the secondary context.
243    mST->abandon();
244
245    // Attempt to attach to the primary context.
246    ASSERT_EQ(NO_INIT, mST->attachToContext(SECOND_TEX_ID));
247}
248
249TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWhenAttached) {
250    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
251
252    // Latch the texture contents on the primary context.
253    mFW->waitForFrame();
254    ASSERT_EQ(OK, mST->updateTexImage());
255
256    // Attempt to attach to the primary context.
257    ASSERT_EQ(INVALID_OPERATION, mST->attachToContext(SECOND_TEX_ID));
258}
259
260TEST_F(SurfaceTextureMultiContextGLTest,
261        AttachToContextFailsWhenAttachedBeforeUpdateTexImage) {
262    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
263
264    // Attempt to attach to the primary context.
265    ASSERT_EQ(INVALID_OPERATION, mST->attachToContext(SECOND_TEX_ID));
266}
267
268TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWithNoDisplay) {
269    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
270
271    // Latch the texture contents on the primary context.
272    mFW->waitForFrame();
273    ASSERT_EQ(OK, mST->updateTexImage());
274
275    // Detach from the primary context.
276    ASSERT_EQ(OK, mST->detachFromContext());
277
278    // Make there be no current display.
279    ASSERT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
280            EGL_NO_CONTEXT));
281    ASSERT_EQ(EGL_SUCCESS, eglGetError());
282
283    // Attempt to attach with no context current.
284    ASSERT_EQ(INVALID_OPERATION, mST->attachToContext(SECOND_TEX_ID));
285}
286
287TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceedsTwice) {
288    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
289
290    // Latch the texture contents on the primary context.
291    mFW->waitForFrame();
292    ASSERT_EQ(OK, mST->updateTexImage());
293
294    // Detach from the primary context.
295    ASSERT_EQ(OK, mST->detachFromContext());
296
297    // Attach to the secondary context.
298    ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
299            mSecondEglContext));
300    ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID));
301
302    // Detach from the secondary context.
303    ASSERT_EQ(OK, mST->detachFromContext());
304
305    // Attach to the tertiary context.
306    ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
307            mThirdEglContext));
308    ASSERT_EQ(OK, mST->attachToContext(THIRD_TEX_ID));
309
310    // Verify that the texture object was created and bound.
311    GLint texBinding = -1;
312    glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding);
313    EXPECT_EQ(THIRD_TEX_ID, texBinding);
314
315    // Try to use the texture from the tertiary context.
316    glClearColor(0.2, 0.2, 0.2, 0.2);
317    glClear(GL_COLOR_BUFFER_BIT);
318    glViewport(0, 0, 1, 1);
319    mThirdTextureRenderer->drawTexture();
320    ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
321    ASSERT_TRUE(checkPixel( 0,  0,  35,  35,  35,  35));
322}
323
324TEST_F(SurfaceTextureMultiContextGLTest,
325        AttachToContextSucceedsTwiceBeforeUpdateTexImage) {
326    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
327
328    // Detach from the primary context.
329    ASSERT_EQ(OK, mST->detachFromContext());
330
331    // Attach to the secondary context.
332    ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
333            mSecondEglContext));
334    ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID));
335
336    // Detach from the secondary context.
337    ASSERT_EQ(OK, mST->detachFromContext());
338
339    // Attach to the tertiary context.
340    ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
341            mThirdEglContext));
342    ASSERT_EQ(OK, mST->attachToContext(THIRD_TEX_ID));
343
344    // Verify that the texture object was created and bound.
345    GLint texBinding = -1;
346    glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding);
347    EXPECT_EQ(THIRD_TEX_ID, texBinding);
348
349    // Latch the texture contents on the tertiary context.
350    mFW->waitForFrame();
351    ASSERT_EQ(OK, mST->updateTexImage());
352
353    // Try to use the texture from the tertiary context.
354    glClearColor(0.2, 0.2, 0.2, 0.2);
355    glClear(GL_COLOR_BUFFER_BIT);
356    glViewport(0, 0, 1, 1);
357    mThirdTextureRenderer->drawTexture();
358    ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
359    ASSERT_TRUE(checkPixel( 0,  0,  35,  35,  35,  35));
360}
361
362TEST_F(SurfaceTextureMultiContextGLTest,
363        UpdateTexImageSucceedsForBufferConsumedBeforeDetach) {
364    ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
365
366    // produce two frames and consume them both on the primary context
367    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
368    mFW->waitForFrame();
369    ASSERT_EQ(OK, mST->updateTexImage());
370
371    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
372    mFW->waitForFrame();
373    ASSERT_EQ(OK, mST->updateTexImage());
374
375    // produce one more frame
376    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
377
378    // Detach from the primary context and attach to the secondary context
379    ASSERT_EQ(OK, mST->detachFromContext());
380    ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
381            mSecondEglContext));
382    ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID));
383
384    // Consume final frame on secondary context
385    mFW->waitForFrame();
386    ASSERT_EQ(OK, mST->updateTexImage());
387}
388
389TEST_F(SurfaceTextureMultiContextGLTest,
390       AttachAfterDisplayTerminatedSucceeds) {
391    ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
392
393    // produce two frames and consume them both on the primary context
394    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
395    mFW->waitForFrame();
396    ASSERT_EQ(OK, mST->updateTexImage());
397
398    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
399    mFW->waitForFrame();
400    ASSERT_EQ(OK, mST->updateTexImage());
401
402    // produce one more frame
403    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
404
405    // Detach from the primary context.
406    ASSERT_EQ(OK, mST->releaseTexImage());
407    ASSERT_EQ(OK, mST->detachFromContext());
408
409    // Terminate and then initialize the display. All contexts, surfaces
410    // and images are invalid at this point.
411    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
412    ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
413    EGLint majorVersion = 0;
414    EGLint minorVersion = 0;
415    EXPECT_TRUE(eglTerminate(display));
416    EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
417    ASSERT_EQ(EGL_SUCCESS, eglGetError());
418
419    // The surface is invalid so create it again.
420    EGLint pbufferAttribs[] = {
421        EGL_WIDTH, 64,
422        EGL_HEIGHT, 64,
423        EGL_NONE };
424    mEglSurface = eglCreatePbufferSurface(mEglDisplay, mGlConfig,
425            pbufferAttribs);
426
427    // The second context is invalid so create it again.
428    mSecondEglContext = eglCreateContext(mEglDisplay, mGlConfig,
429            EGL_NO_CONTEXT, getContextAttribs());
430    ASSERT_EQ(EGL_SUCCESS, eglGetError());
431    ASSERT_NE(EGL_NO_CONTEXT, mSecondEglContext);
432
433    ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
434            mSecondEglContext));
435    ASSERT_EQ(EGL_SUCCESS, eglGetError());
436
437    // Now attach to and consume final frame on secondary context.
438    ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID));
439    mFW->waitForFrame();
440    ASSERT_EQ(OK, mST->updateTexImage());
441}
442
443
444} // namespace android
445