blob: 2ce20eb2b15edbd44bca6b51878dc997f7943036 [file] [log] [blame]
Dan Stozacb1fcde2013-12-03 12:37:36 -08001/*
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
22namespace 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 */
53class SurfaceTextureGLThreadToGLTest : public SurfaceTextureGLToGLTest {
54protected:
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:
60 virtual ~ProducerThread() {
61 }
62
63 void setEglObjects(EGLDisplay producerEglDisplay,
64 EGLSurface producerEglSurface,
65 EGLContext producerEglContext) {
66 mProducerEglDisplay = producerEglDisplay;
67 mProducerEglSurface = producerEglSurface;
68 mProducerEglContext = producerEglContext;
69 }
70
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
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:
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.
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.
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.
Dan Stoza8dc55392014-11-04 11:37:46 -0800133 virtual void onFrameAvailable(const BufferItem& /* item */) {
Dan Stozacb1fcde2013-12-03 12:37:36 -0800134 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
154 virtual void SetUp() {
155 SurfaceTextureGLToGLTest::SetUp();
156 mFC = new FrameCondition();
157 mST->setFrameAvailableListener(mFC);
158 }
159
160 virtual void TearDown() {
161 if (mProducerThread != NULL) {
162 mProducerThread->requestExitAndWait();
163 }
164 mProducerThread.clear();
165 mFC.clear();
166 SurfaceTextureGLToGLTest::TearDown();
167 }
168
169 void runProducerThread(const sp<ProducerThread> producerThread) {
170 ASSERT_TRUE(mProducerThread == NULL);
171 mProducerThread = producerThread;
172 producerThread->setEglObjects(mEglDisplay, mProducerEglSurface,
173 mProducerEglContext);
Brian Carlstrom83b1e682016-03-12 16:07:59 -0800174 producerThread->run("ProducerThread");
Dan Stozacb1fcde2013-12-03 12:37:36 -0800175 }
176
177 sp<ProducerThread> mProducerThread;
178 sp<FrameCondition> mFC;
179};
180
181} // namespace android
182
183#endif