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