Home | History | Annotate | Download | only in tests
      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