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: 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. 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 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); 174 producerThread->run("ProducerThread"); 175 } 176 177 sp<ProducerThread> mProducerThread; 178 sp<FrameCondition> mFC; 179 }; 180 181 } // namespace android 182 183 #endif 184