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 #ifndef ANDROID_SURFACE_TEXTURE_GL_THREAD_TO_GL_H
18 #define ANDROID_SURFACE_TEXTURE_GL_THREAD_TO_GL_H
19 
20 #include "SurfaceTextureGLToGL.h"
21 
22 namespace android {
23 
24 /*
25  * This test fixture is for testing GL -> GL texture streaming from one thread
26  * to another.  It contains functionality to create a producer thread that will
27  * perform GL rendering to an ANativeWindow that feeds frames to a
28  * GLConsumer.  Additionally it supports interlocking the producer and
29  * consumer threads so that a specific sequence of calls can be
30  * deterministically created by the test.
31  *
32  * The intended usage is as follows:
33  *
34  * TEST_F(...) {
35  *     class PT : public ProducerThread {
36  *         virtual void render() {
37  *             ...
38  *             swapBuffers();
39  *         }
40  *     };
41  *
42  *     runProducerThread(new PT());
43  *
44  *     // The order of these calls will vary from test to test and may include
45  *     // multiple frames and additional operations (e.g. GL rendering from the
46  *     // texture).
47  *     fc->waitForFrame();
48  *     mST->updateTexImage();
49  *     fc->finishFrame();
50  * }
51  *
52  */
53 class SurfaceTextureGLThreadToGLTest : public SurfaceTextureGLToGLTest {
54 protected:
55 
56     // ProducerThread is an abstract base class to simplify the creation of
57     // OpenGL ES frame producer threads.
58     class ProducerThread : public Thread {
59     public:
~ProducerThread()60         virtual ~ProducerThread() {
61         }
62 
setEglObjects(EGLDisplay producerEglDisplay,EGLSurface producerEglSurface,EGLContext producerEglContext)63         void setEglObjects(EGLDisplay producerEglDisplay,
64                 EGLSurface producerEglSurface,
65                 EGLContext producerEglContext) {
66             mProducerEglDisplay = producerEglDisplay;
67             mProducerEglSurface = producerEglSurface;
68             mProducerEglContext = producerEglContext;
69         }
70 
threadLoop()71         virtual bool threadLoop() {
72             eglMakeCurrent(mProducerEglDisplay, mProducerEglSurface,
73                     mProducerEglSurface, mProducerEglContext);
74             render();
75             eglMakeCurrent(mProducerEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
76                     EGL_NO_CONTEXT);
77             return false;
78         }
79 
80     protected:
81         virtual void render() = 0;
82 
swapBuffers()83         void swapBuffers() {
84             eglSwapBuffers(mProducerEglDisplay, mProducerEglSurface);
85         }
86 
87         EGLDisplay mProducerEglDisplay;
88         EGLSurface mProducerEglSurface;
89         EGLContext mProducerEglContext;
90     };
91 
92     // FrameCondition is a utility class for interlocking between the producer
93     // and consumer threads.  The FrameCondition object should be created and
94     // destroyed in the consumer thread only.  The consumer thread should set
95     // the FrameCondition as the FrameAvailableListener of the GLConsumer,
96     // and should call both waitForFrame and finishFrame once for each expected
97     // frame.
98     //
99     // This interlocking relies on the fact that onFrameAvailable gets called
100     // synchronously from GLConsumer::queueBuffer.
101     class FrameCondition : public GLConsumer::FrameAvailableListener {
102     public:
FrameCondition()103         FrameCondition():
104                 mFrameAvailable(false),
105                 mFrameFinished(false) {
106         }
107 
108         // waitForFrame waits for the next frame to arrive.  This should be
109         // called from the consumer thread once for every frame expected by the
110         // test.
waitForFrame()111         void waitForFrame() {
112             Mutex::Autolock lock(mMutex);
113             ALOGV("+waitForFrame");
114             while (!mFrameAvailable) {
115                 mFrameAvailableCondition.wait(mMutex);
116             }
117             mFrameAvailable = false;
118             ALOGV("-waitForFrame");
119         }
120 
121         // Allow the producer to return from its swapBuffers call and continue
122         // on to produce the next frame.  This should be called by the consumer
123         // thread once for every frame expected by the test.
finishFrame()124         void finishFrame() {
125             Mutex::Autolock lock(mMutex);
126             ALOGV("+finishFrame");
127             mFrameFinished = true;
128             mFrameFinishCondition.signal();
129             ALOGV("-finishFrame");
130         }
131 
132         // This should be called by GLConsumer on the producer thread.
onFrameAvailable(const BufferItem &)133         virtual void onFrameAvailable(const BufferItem& /* item */) {
134             Mutex::Autolock lock(mMutex);
135             ALOGV("+onFrameAvailable");
136             mFrameAvailable = true;
137             mFrameAvailableCondition.signal();
138             while (!mFrameFinished) {
139                 mFrameFinishCondition.wait(mMutex);
140             }
141             mFrameFinished = false;
142             ALOGV("-onFrameAvailable");
143         }
144 
145     protected:
146         bool mFrameAvailable;
147         bool mFrameFinished;
148 
149         Mutex mMutex;
150         Condition mFrameAvailableCondition;
151         Condition mFrameFinishCondition;
152     };
153 
SetUp()154     virtual void SetUp() {
155         SurfaceTextureGLToGLTest::SetUp();
156         mFC = new FrameCondition();
157         mST->setFrameAvailableListener(mFC);
158     }
159 
TearDown()160     virtual void TearDown() {
161         if (mProducerThread != nullptr) {
162             mProducerThread->requestExitAndWait();
163         }
164         mProducerThread.clear();
165         mFC.clear();
166         SurfaceTextureGLToGLTest::TearDown();
167     }
168 
runProducerThread(const sp<ProducerThread> producerThread)169     void runProducerThread(const sp<ProducerThread> producerThread) {
170         ASSERT_TRUE(mProducerThread == nullptr);
171         mProducerThread = producerThread;
172         producerThread->setEglObjects(mEglDisplay, mProducerEglSurface,
173                 mProducerEglContext);
174         producerThread->run("ProducerThread");
175     }
176 
177     sp<ProducerThread> mProducerThread;
178     sp<FrameCondition> mFC;
179 };
180 
181 } // namespace android
182 
183 #endif
184