diff options
| author | 2019-01-02 22:34:27 +0000 | |
|---|---|---|
| committer | 2019-01-02 22:34:27 +0000 | |
| commit | 7b2e64b9e4a7b143f7b29bc5a8c0334f3741bbd9 (patch) | |
| tree | d1dd9cae62ec5e7861ed0598ed6458dbed30ae60 | |
| parent | a5341ec91f30d16efa9ae66a97645b96331a0300 (diff) | |
| parent | 713b63f3e6f397cd688c982ee5c2bb5e26fa9446 (diff) | |
Merge "blast: Queue transactions by applying client"
| -rw-r--r-- | libs/gui/ISurfaceComposer.cpp | 12 | ||||
| -rw-r--r-- | libs/gui/SurfaceComposerClient.cpp | 4 | ||||
| -rw-r--r-- | libs/gui/include/gui/ISurfaceComposer.h | 3 | ||||
| -rw-r--r-- | libs/gui/tests/Surface_test.cpp | 4 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 75 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 24 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/Android.bp | 1 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/BufferGenerator.cpp | 381 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/BufferGenerator.h | 58 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/BufferGeneratorShader.h | 355 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/Transaction_test.cpp | 323 |
11 files changed, 1136 insertions, 104 deletions
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 2d6be26903..799151ae87 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -73,11 +73,9 @@ public: return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder()); } - virtual void setTransactionState( - const Vector<ComposerState>& state, - const Vector<DisplayState>& displays, - uint32_t flags) - { + virtual void setTransactionState(const Vector<ComposerState>& state, + const Vector<DisplayState>& displays, uint32_t flags, + const sp<IBinder>& applyToken) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -92,6 +90,7 @@ public: } data.writeUint32(flags); + data.writeStrongBinder(applyToken); remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply); } @@ -750,7 +749,8 @@ status_t BnSurfaceComposer::onTransact( } uint32_t stateFlags = data.readUint32(); - setTransactionState(state, displays, stateFlags); + sp<IBinder> applyToken = data.readStrongBinder(); + setTransactionState(state, displays, stateFlags, applyToken); return NO_ERROR; } case BOOT_FINISHED: { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 95862199eb..5b004e2805 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -264,7 +264,9 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { mAnimation = false; mEarlyWakeup = false; - sf->setTransactionState(composerStates, displayStates, flags); + sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); + + sf->setTransactionState(composerStates, displayStates, flags, applyToken); mStatus = NO_ERROR; return NO_ERROR; } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 3052c0b312..8cb40e78ad 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -124,7 +124,8 @@ public: /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */ virtual void setTransactionState(const Vector<ComposerState>& state, - const Vector<DisplayState>& displays, uint32_t flags) = 0; + const Vector<DisplayState>& displays, uint32_t flags, + const sp<IBinder>& applyToken) = 0; /* signal that we're done booting. * Requires ACCESS_SURFACE_FLINGER permission diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 67afbd6a52..c56304fdd4 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -558,8 +558,8 @@ public: void destroyDisplay(const sp<IBinder>& /*display */) override {} sp<IBinder> getBuiltInDisplay(int32_t /*id*/) override { return nullptr; } void setTransactionState(const Vector<ComposerState>& /*state*/, - const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/) - override {} + const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/, + const sp<IBinder>& /*applyToken*/) override {} void bootFinished() override {} bool authenticateSurfaceTexture( const sp<IGraphicBufferProducer>& /*surface*/) const override { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4a93be6fb4..02cd9d9f61 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1568,11 +1568,23 @@ void SurfaceFlinger::onMessageReceived(int32_t what) { bool SurfaceFlinger::handleMessageTransaction() { uint32_t transactionFlags = peekTransactionFlags(); + + // Apply any ready transactions in the queues if there are still transactions that have not been + // applied, wake up during the next vsync period and check again + bool transactionNeeded = false; + if (!flushTransactionQueues()) { + transactionNeeded = true; + } + if (transactionFlags) { handleTransaction(transactionFlags); - return true; } - return false; + + if (transactionNeeded) { + setTransactionFlags(eTransactionNeeded); + } + + return transactionFlags; } void SurfaceFlinger::handleMessageRefresh() { @@ -3314,6 +3326,26 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, return old; } +bool SurfaceFlinger::flushTransactionQueues() { + Mutex::Autolock _l(mStateLock); + auto it = mTransactionQueues.begin(); + while (it != mTransactionQueues.end()) { + auto& [applyToken, transactionQueue] = *it; + + while (!transactionQueue.empty()) { + const auto& [states, displays, flags] = transactionQueue.front(); + if (composerStateContainsUnsignaledFences(states)) { + break; + } + applyTransactionState(states, displays, flags); + transactionQueue.pop(); + } + + it = (transactionQueue.empty()) ? mTransactionQueues.erase(it) : std::next(it, 1); + } + return mTransactionQueues.empty(); +} + bool SurfaceFlinger::containsAnyInvalidClientState(const Vector<ComposerState>& states) { for (const ComposerState& state : states) { // Here we need to check that the interface we're given is indeed @@ -3336,19 +3368,44 @@ bool SurfaceFlinger::containsAnyInvalidClientState(const Vector<ComposerState>& return false; } -void SurfaceFlinger::setTransactionState( - const Vector<ComposerState>& states, - const Vector<DisplayState>& displays, - uint32_t flags) -{ +bool SurfaceFlinger::composerStateContainsUnsignaledFences(const Vector<ComposerState>& states) { + for (const ComposerState& state : states) { + const layer_state_t& s = state.state; + if (!(s.what & layer_state_t::eAcquireFenceChanged)) { + continue; + } + if (s.acquireFence && s.acquireFence->getStatus() == Fence::Status::Unsignaled) { + return true; + } + } + return false; +} + +void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& states, + const Vector<DisplayState>& displays, uint32_t flags, + const sp<IBinder>& applyToken) { ATRACE_CALL(); Mutex::Autolock _l(mStateLock); - uint32_t transactionFlags = 0; if (containsAnyInvalidClientState(states)) { return; } + // If its TransactionQueue already has a pending TransactionState or if it is pending + if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() || + composerStateContainsUnsignaledFences(states)) { + mTransactionQueues[applyToken].emplace(states, displays, flags); + setTransactionFlags(eTransactionNeeded); + return; + } + + applyTransactionState(states, displays, flags); +} + +void SurfaceFlinger::applyTransactionState(const Vector<ComposerState>& states, + const Vector<DisplayState>& displays, uint32_t flags) { + uint32_t transactionFlags = 0; + if (flags & eAnimation) { // For window updates that are part of an animation we must wait for // previous animation "frames" to be handled. @@ -3938,7 +3995,7 @@ void SurfaceFlinger::onInitializeDisplays() { d.width = 0; d.height = 0; displays.add(d); - setTransactionState(state, displays, 0); + setTransactionState(state, displays, 0, nullptr); const auto display = getDisplayDevice(displayToken); if (!display) return; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b1bfb3a08d..822bb18f99 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -442,7 +442,8 @@ private: virtual void destroyDisplay(const sp<IBinder>& displayToken); virtual sp<IBinder> getBuiltInDisplay(int32_t id); virtual void setTransactionState(const Vector<ComposerState>& state, - const Vector<DisplayState>& displays, uint32_t flags); + const Vector<DisplayState>& displays, uint32_t flags, + const sp<IBinder>& applyToken); virtual void bootFinished(); virtual bool authenticateSurfaceTexture( const sp<IGraphicBufferProducer>& bufferProducer) const; @@ -553,6 +554,10 @@ private: /* ------------------------------------------------------------------------ * Transactions */ + void applyTransactionState(const Vector<ComposerState>& state, + const Vector<DisplayState>& displays, uint32_t flags) + REQUIRES(mStateLock); + bool flushTransactionQueues(); uint32_t getTransactionFlags(uint32_t flags); uint32_t peekTransactionFlags(); // Can only be called from the main thread or with mStateLock held @@ -561,6 +566,7 @@ private: void latchAndReleaseBuffer(const sp<Layer>& layer); void commitTransaction(); bool containsAnyInvalidClientState(const Vector<ComposerState>& states); + bool composerStateContainsUnsignaledFences(const Vector<ComposerState>& states); uint32_t setClientStateLocked(const ComposerState& composerState); uint32_t setDisplayStateLocked(const DisplayState& s); void setDestroyStateLocked(const ComposerState& composerState); @@ -965,6 +971,22 @@ private: uint32_t mTexturePoolSize = 0; std::vector<uint32_t> mTexturePool; + struct IBinderHash { + std::size_t operator()(const sp<IBinder>& strongPointer) const { + return std::hash<IBinder*>{}(strongPointer.get()); + } + }; + struct TransactionState { + TransactionState(const Vector<ComposerState>& composerStates, + const Vector<DisplayState>& displayStates, uint32_t transactionFlags) + : states(composerStates), displays(displayStates), flags(transactionFlags) {} + + Vector<ComposerState> states; + Vector<DisplayState> displays; + uint32_t flags; + }; + std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IBinderHash> mTransactionQueues; + /* ------------------------------------------------------------------------ * Feature prototyping */ diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index 604aa7df56..f121a952d8 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -17,6 +17,7 @@ cc_test { defaults: ["surfaceflinger_defaults"], test_suites: ["device-tests"], srcs: [ + "BufferGenerator.cpp", "Credentials_test.cpp", "Stress_test.cpp", "SurfaceInterceptor_test.cpp", diff --git a/services/surfaceflinger/tests/BufferGenerator.cpp b/services/surfaceflinger/tests/BufferGenerator.cpp new file mode 100644 index 0000000000..8ddda60cd2 --- /dev/null +++ b/services/surfaceflinger/tests/BufferGenerator.cpp @@ -0,0 +1,381 @@ +/* + * Copyright 2018 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. + */ + +#include <gui/BufferItemConsumer.h> +#include <gui/Surface.h> + +#include <GLES3/gl3.h> +#include <math/vec2.h> +#include <math/vec3.h> +#include <math/vec4.h> + +#include "BufferGenerator.h" +#include "BufferGeneratorShader.h" + +namespace android { + +/* Used to receive the surfaces and fences from egl. The egl buffers are thrown + * away. The fences are sent to the requester via a callback */ +class SurfaceManager { +public: + /* Returns a fence from egl */ + using BufferCallback = std::function<void(const sp<GraphicBuffer>& buffer, int32_t fence)>; + + /* Listens for a new frame, detaches the buffer and returns the fence + * through saved callback. */ + class BufferListener : public ConsumerBase::FrameAvailableListener { + public: + BufferListener(sp<IGraphicBufferConsumer> consumer, BufferCallback callback) + : mConsumer(consumer), mCallback(callback) {} + + void onFrameAvailable(const BufferItem& /*item*/) { + BufferItem item; + + if (mConsumer->acquireBuffer(&item, 0)) return; + if (mConsumer->detachBuffer(item.mSlot)) return; + + mCallback(item.mGraphicBuffer, item.mFence->dup()); + } + + private: + sp<IGraphicBufferConsumer> mConsumer; + BufferCallback mCallback; + }; + + /* Creates a buffer listener that waits on a new frame from the buffer + * queue. */ + void initialize(uint32_t width, uint32_t height, android_pixel_format_t format, + BufferCallback callback) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + consumer->setDefaultBufferSize(width, height); + consumer->setDefaultBufferFormat(format); + + mBufferItemConsumer = new BufferItemConsumer(consumer, 0); + + mListener = new BufferListener(consumer, callback); + mBufferItemConsumer->setFrameAvailableListener(mListener); + + mSurface = new Surface(producer, true); + } + + /* Used by Egl manager. The surface is never displayed. */ + sp<Surface> getSurface() const { return mSurface; } + +private: + sp<BufferItemConsumer> mBufferItemConsumer; + sp<BufferListener> mListener; + /* Used by Egl manager. The surface is never displayed */ + sp<Surface> mSurface; +}; + +/* Used to generate valid fences. It is not possible to create a dummy sync + * fence for testing. Egl can generate buffers along with a valid fence. + * The buffer cannot be guaranteed to be the same format across all devices so + * a CPU filled buffer is used instead. The Egl fence is used along with the + * CPU filled buffer. */ +class EglManager { +public: + EglManager() + : mEglDisplay(EGL_NO_DISPLAY), mEglSurface(EGL_NO_SURFACE), mEglContext(EGL_NO_CONTEXT) {} + + ~EglManager() { cleanup(); } + + int initialize(sp<Surface> surface) { + mSurface = surface; + + mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (mEglDisplay == EGL_NO_DISPLAY) return false; + + EGLint major; + EGLint minor; + if (!eglInitialize(mEglDisplay, &major, &minor)) { + ALOGW("Could not initialize EGL"); + return false; + } + + /* We're going to use a 1x1 pbuffer surface later on + * The configuration distance doesn't really matter for what we're + * trying to do */ + EGLint configAttrs[] = {EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_ALPHA_SIZE, + 0, + EGL_DEPTH_SIZE, + 24, + EGL_STENCIL_SIZE, + 0, + EGL_NONE}; + + EGLConfig configs[1]; + EGLint configCnt; + if (!eglChooseConfig(mEglDisplay, configAttrs, configs, 1, &configCnt)) { + ALOGW("Could not select EGL configuration"); + eglReleaseThread(); + eglTerminate(mEglDisplay); + return false; + } + + if (configCnt <= 0) { + ALOGW("Could not find EGL configuration"); + eglReleaseThread(); + eglTerminate(mEglDisplay); + return false; + } + + /* These objects are initialized below but the default "null" values are + * used to cleanup properly at any point in the initialization sequence */ + EGLint attrs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE}; + mEglContext = eglCreateContext(mEglDisplay, configs[0], EGL_NO_CONTEXT, attrs); + if (mEglContext == EGL_NO_CONTEXT) { + ALOGW("Could not create EGL context"); + cleanup(); + return false; + } + + EGLint majorVersion; + if (!eglQueryContext(mEglDisplay, mEglContext, EGL_CONTEXT_CLIENT_VERSION, &majorVersion)) { + ALOGW("Could not query EGL version"); + cleanup(); + return false; + } + + if (majorVersion != 3) { + ALOGW("Unsupported EGL version"); + cleanup(); + return false; + } + + EGLint surfaceAttrs[] = {EGL_NONE}; + mEglSurface = eglCreateWindowSurface(mEglDisplay, configs[0], mSurface.get(), surfaceAttrs); + if (mEglSurface == EGL_NO_SURFACE) { + ALOGW("Could not create EGL surface"); + cleanup(); + return false; + } + + if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { + ALOGW("Could not change current EGL context"); + cleanup(); + return false; + } + + return true; + } + + void makeCurrent() const { eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext); } + + void present() const { eglSwapBuffers(mEglDisplay, mEglSurface); } + +private: + void cleanup() { + if (mEglDisplay == EGL_NO_DISPLAY) return; + if (mEglSurface != EGL_NO_SURFACE) eglDestroySurface(mEglDisplay, mEglSurface); + if (mEglContext != EGL_NO_CONTEXT) eglDestroyContext(mEglDisplay, mEglContext); + + eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglReleaseThread(); + eglTerminate(mEglDisplay); + } + + sp<Surface> mSurface; + EGLDisplay mEglDisplay; + EGLSurface mEglSurface; + EGLContext mEglContext; +}; + +class Program { +public: + ~Program() { + if (mInitialized) { + glDetachShader(mProgram, mVertexShader); + glDetachShader(mProgram, mFragmentShader); + + glDeleteShader(mVertexShader); + glDeleteShader(mFragmentShader); + + glDeleteProgram(mProgram); + } + } + + bool initialize(const char* vertex, const char* fragment) { + mVertexShader = buildShader(vertex, GL_VERTEX_SHADER); + if (!mVertexShader) { + return false; + } + + mFragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER); + if (!mFragmentShader) { + return false; + } + + mProgram = glCreateProgram(); + glAttachShader(mProgram, mVertexShader); + glAttachShader(mProgram, mFragmentShader); + + glLinkProgram(mProgram); + + GLint status; + glGetProgramiv(mProgram, GL_LINK_STATUS, &status); + if (status != GL_TRUE) { + GLint length = 0; + glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &length); + if (length > 1) { + GLchar log[length]; + glGetProgramInfoLog(mProgram, length, nullptr, &log[0]); + ALOGE("%s", log); + } + ALOGE("Error while linking shaders"); + return false; + } + mInitialized = true; + return true; + } + + void use() const { glUseProgram(mProgram); } + + void bindVec4(GLint location, vec4 v) const { glUniform4f(location, v.x, v.y, v.z, v.w); } + + void bindVec3(GLint location, const vec3* v, uint32_t count) const { + glUniform3fv(location, count, &(v->x)); + } + + void bindFloat(GLint location, float v) { glUniform1f(location, v); } + +private: + GLuint buildShader(const char* source, GLenum type) const { + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &source, nullptr); + glCompileShader(shader); + + GLint status; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (status != GL_TRUE) { + ALOGE("Error while compiling shader of type 0x%x:\n===\n%s\n===", type, source); + // Some drivers return wrong values for GL_INFO_LOG_LENGTH + // use a fixed size instead + GLchar log[512]; + glGetShaderInfoLog(shader, sizeof(log), nullptr, &log[0]); + ALOGE("Shader info log: %s", log); + return 0; + } + + return shader; + } + + GLuint mProgram = 0; + GLuint mVertexShader = 0; + GLuint mFragmentShader = 0; + bool mInitialized = false; +}; + +BufferGenerator::BufferGenerator() + : mSurfaceManager(new SurfaceManager), mEglManager(new EglManager), mProgram(new Program) { + const float width = 1000.0; + const float height = 1000.0; + + auto setBufferWithContext = + std::bind(setBuffer, std::placeholders::_1, std::placeholders::_2, this); + mSurfaceManager->initialize(width, height, HAL_PIXEL_FORMAT_RGBA_8888, setBufferWithContext); + + if (!mEglManager->initialize(mSurfaceManager->getSurface())) return; + + mEglManager->makeCurrent(); + + if (!mProgram->initialize(VERTEX_SHADER, FRAGMENT_SHADER)) return; + mProgram->use(); + mProgram->bindVec4(0, vec4{width, height, 1.0f / width, 1.0f / height}); + mProgram->bindVec3(2, &SPHERICAL_HARMONICS[0], 4); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, &TRIANGLE[0]); + + mInitialized = true; +} + +BufferGenerator::~BufferGenerator() { + mEglManager->makeCurrent(); +} + +status_t BufferGenerator::get(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) { + // mMutex is used to protect get() from getting called by multiple threads at the same time + static std::mutex mMutex; + std::lock_guard lock(mMutex); + + if (!mInitialized) { + if (outBuffer) { + *outBuffer = nullptr; + } + if (*outFence) { + *outFence = nullptr; + } + return -EINVAL; + } + + // Generate a buffer and fence. They will be returned through the setBuffer callback + mEglManager->makeCurrent(); + + glClear(GL_COLOR_BUFFER_BIT); + + const std::chrono::duration<float> time = std::chrono::steady_clock::now() - mEpoch; + mProgram->bindFloat(1, time.count()); + + glDrawArrays(GL_TRIANGLES, 0, 3); + + mPending = true; + mEglManager->present(); + + // Wait for the setBuffer callback + if (!mConditionVariable.wait_for(mMutex, std::chrono::seconds(2), + [this] { return !mPending; })) { + ALOGE("failed to set buffer and fence"); + return -ETIME; + } + + // Return buffer and fence + if (outBuffer) { + *outBuffer = mGraphicBuffer; + } + if (outFence) { + *outFence = new Fence(mFence); + } else { + close(mFence); + } + mGraphicBuffer = nullptr; + mFence = -1; + + return NO_ERROR; +} + +// static +void BufferGenerator::setBuffer(const sp<GraphicBuffer>& buffer, int32_t fence, + void* bufferGenerator) { + BufferGenerator* generator = static_cast<BufferGenerator*>(bufferGenerator); + generator->mGraphicBuffer = buffer; + generator->mFence = fence; + generator->mPending = false; + generator->mConditionVariable.notify_all(); +} + +} // namespace android diff --git a/services/surfaceflinger/tests/BufferGenerator.h b/services/surfaceflinger/tests/BufferGenerator.h new file mode 100644 index 0000000000..a3ffe86572 --- /dev/null +++ b/services/surfaceflinger/tests/BufferGenerator.h @@ -0,0 +1,58 @@ +/* + * Copyright 2018 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. + */ + +#pragma once + +#include <condition_variable> +#include <mutex> + +#include <ui/GraphicBuffer.h> + +namespace android { + +class SurfaceManager; +class EglManager; +class Program; + +class BufferGenerator { +public: + BufferGenerator(); + ~BufferGenerator(); + + /* Get a new fence */ + status_t get(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence); + + /* Static callback that sets the fence on a particular instance */ + static void setBuffer(const sp<GraphicBuffer>& buffer, int32_t fence, void* fenceGenerator); + +private: + bool mInitialized = false; + + std::unique_ptr<SurfaceManager> mSurfaceManager; + std::unique_ptr<EglManager> mEglManager; + std::unique_ptr<Program> mProgram; + + std::condition_variable_any mConditionVariable; + + sp<GraphicBuffer> mGraphicBuffer; + int32_t mFence = -1; + bool mPending = false; + + using Epoch = std::chrono::time_point<std::chrono::steady_clock>; + Epoch mEpoch = std::chrono::steady_clock::now(); +}; + +} // namespace android diff --git a/services/surfaceflinger/tests/BufferGeneratorShader.h b/services/surfaceflinger/tests/BufferGeneratorShader.h new file mode 100644 index 0000000000..564cda3ccc --- /dev/null +++ b/services/surfaceflinger/tests/BufferGeneratorShader.h @@ -0,0 +1,355 @@ +/* + * Copyright 2018 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. + */ + +#pragma once + +#include <GLES3/gl3.h> +#include <math/vec2.h> +#include <math/vec3.h> +#include <math/vec4.h> + +static const char* VERTEX_SHADER = R"SHADER__(#version 300 es +precision highp float; + +layout(location = 0) in vec4 mesh_position; + +void main() { + gl_Position = mesh_position; +} +)SHADER__"; + +static const char* FRAGMENT_SHADER = R"SHADER__(#version 300 es +precision highp float; + +layout(location = 0) uniform vec4 resolution; +layout(location = 1) uniform float time; +layout(location = 2) uniform vec3[4] SPHERICAL_HARMONICS; + +layout(location = 0) out vec4 fragColor; + +#define saturate(x) clamp(x, 0.0, 1.0) +#define PI 3.14159265359 + +//------------------------------------------------------------------------------ +// Distance field functions +//------------------------------------------------------------------------------ + +float sdPlane(in vec3 p) { + return p.y; +} + +float sdSphere(in vec3 p, float s) { + return length(p) - s; +} + +float sdTorus(in vec3 p, in vec2 t) { + return length(vec2(length(p.xz) - t.x, p.y)) - t.y; +} + +vec2 opUnion(vec2 d1, vec2 d2) { + return d1.x < d2.x ? d1 : d2; +} + +vec2 scene(in vec3 position) { + vec2 scene = opUnion( + vec2(sdPlane(position), 1.0), + vec2(sdSphere(position - vec3(0.0, 0.4, 0.0), 0.4), 12.0) + ); + return scene; +} + +//------------------------------------------------------------------------------ +// Ray casting +//------------------------------------------------------------------------------ + +float shadow(in vec3 origin, in vec3 direction, in float tmin, in float tmax) { + float hit = 1.0; + + for (float t = tmin; t < tmax; ) { + float h = scene(origin + direction * t).x; + if (h < 0.001) return 0.0; + t += h; + hit = min(hit, 10.0 * h / t); + } + + return clamp(hit, 0.0, 1.0); +} + +vec2 traceRay(in vec3 origin, in vec3 direction) { + float tmin = 0.02; + float tmax = 20.0; + + float material = -1.0; + float t = tmin; + + for ( ; t < tmax; ) { + vec2 hit = scene(origin + direction * t); + if (hit.x < 0.002 || t > tmax) break; + t += hit.x; + material = hit.y; + } + + if (t > tmax) { + material = -1.0; + } + + return vec2(t, material); +} + +vec3 normal(in vec3 position) { + vec3 epsilon = vec3(0.001, 0.0, 0.0); + vec3 n = vec3( + scene(position + epsilon.xyy).x - scene(position - epsilon.xyy).x, + scene(position + epsilon.yxy).x - scene(position - epsilon.yxy).x, + scene(position + epsilon.yyx).x - scene(position - epsilon.yyx).x); + return normalize(n); +} + +//------------------------------------------------------------------------------ +// BRDF +//------------------------------------------------------------------------------ + +float pow5(float x) { + float x2 = x * x; + return x2 * x2 * x; +} + +float D_GGX(float linearRoughness, float NoH, const vec3 h) { + // Walter et al. 2007, "Microfacet Models for Refraction through Rough Surfaces" + float oneMinusNoHSquared = 1.0 - NoH * NoH; + float a = NoH * linearRoughness; + float k = linearRoughness / (oneMinusNoHSquared + a * a); + float d = k * k * (1.0 / PI); + return d; +} + +float V_SmithGGXCorrelated(float linearRoughness, float NoV, float NoL) { + // Heitz 2014, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs" + float a2 = linearRoughness * linearRoughness; + float GGXV = NoL * sqrt((NoV - a2 * NoV) * NoV + a2); + float GGXL = NoV * sqrt((NoL - a2 * NoL) * NoL + a2); + return 0.5 / (GGXV + GGXL); +} + +vec3 F_Schlick(const vec3 f0, float VoH) { + // Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering" + return f0 + (vec3(1.0) - f0) * pow5(1.0 - VoH); +} + +float F_Schlick(float f0, float f90, float VoH) { + return f0 + (f90 - f0) * pow5(1.0 - VoH); +} + +float Fd_Burley(float linearRoughness, float NoV, float NoL, float LoH) { + // Burley 2012, "Physically-Based Shading at Disney" + float f90 = 0.5 + 2.0 * linearRoughness * LoH * LoH; + float lightScatter = F_Schlick(1.0, f90, NoL); + float viewScatter = F_Schlick(1.0, f90, NoV); + return lightScatter * viewScatter * (1.0 / PI); +} + +float Fd_Lambert() { + return 1.0 / PI; +} + +//------------------------------------------------------------------------------ +// Indirect lighting +//------------------------------------------------------------------------------ + +vec3 Irradiance_SphericalHarmonics(const vec3 n) { + return max( + SPHERICAL_HARMONICS[0] + + SPHERICAL_HARMONICS[1] * (n.y) + + SPHERICAL_HARMONICS[2] * (n.z) + + SPHERICAL_HARMONICS[3] * (n.x) + , 0.0); +} + +vec2 PrefilteredDFG_Karis(float roughness, float NoV) { + // Karis 2014, "Physically Based Material on Mobile" + const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); + const vec4 c1 = vec4( 1.0, 0.0425, 1.040, -0.040); + + vec4 r = roughness * c0 + c1; + float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y; + + return vec2(-1.04, 1.04) * a004 + r.zw; +} + +//------------------------------------------------------------------------------ +// Tone mapping and transfer functions +//------------------------------------------------------------------------------ + +vec3 Tonemap_ACES(const vec3 x) { + // Narkowicz 2015, "ACES Filmic Tone Mapping Curve" + const float a = 2.51; + const float b = 0.03; + const float c = 2.43; + const float d = 0.59; + const float e = 0.14; + return (x * (a * x + b)) / (x * (c * x + d) + e); +} + +vec3 OECF_sRGBFast(const vec3 linear) { + return pow(linear, vec3(1.0 / 2.2)); +} + +//------------------------------------------------------------------------------ +// Rendering +//------------------------------------------------------------------------------ + +vec3 render(in vec3 origin, in vec3 direction, out float distance) { + // Sky gradient + vec3 color = vec3(0.65, 0.85, 1.0) + direction.y * 0.72; + + // (distance, material) + vec2 hit = traceRay(origin, direction); + distance = hit.x; + float material = hit.y; + + // We've hit something in the scene + if (material > 0.0) { + vec3 position = origin + distance * direction; + + vec3 v = normalize(-direction); + vec3 n = normal(position); + vec3 l = normalize(vec3(0.6, 0.7, -0.7)); + vec3 h = normalize(v + l); + vec3 r = normalize(reflect(direction, n)); + + float NoV = abs(dot(n, v)) + 1e-5; + float NoL = saturate(dot(n, l)); + float NoH = saturate(dot(n, h)); + float LoH = saturate(dot(l, h)); + + vec3 baseColor = vec3(0.0); + float roughness = 0.0; + float metallic = 0.0; + + float intensity = 2.0; + float indirectIntensity = 0.64; + + if (material < 4.0) { + // Checkerboard floor + float f = mod(floor(6.0 * position.z) + floor(6.0 * position.x), 2.0); + baseColor = 0.4 + f * vec3(0.6); + roughness = 0.1; + } else if (material < 16.0) { + // Metallic objects + baseColor = vec3(0.3, 0.0, 0.0); + roughness = 0.2; + } + + float linearRoughness = roughness * roughness; + vec3 diffuseColor = (1.0 - metallic) * baseColor.rgb; + vec3 f0 = 0.04 * (1.0 - metallic) + baseColor.rgb * metallic; + + float attenuation = shadow(position, l, 0.02, 2.5); + + // specular BRDF + float D = D_GGX(linearRoughness, NoH, h); + float V = V_SmithGGXCorrelated(linearRoughness, NoV, NoL); + vec3 F = F_Schlick(f0, LoH); + vec3 Fr = (D * V) * F; + + // diffuse BRDF + vec3 Fd = diffuseColor * Fd_Burley(linearRoughness, NoV, NoL, LoH); + + color = Fd + Fr; + color *= (intensity * attenuation * NoL) * vec3(0.98, 0.92, 0.89); + + // diffuse indirect + vec3 indirectDiffuse = Irradiance_SphericalHarmonics(n) * Fd_Lambert(); + + vec2 indirectHit = traceRay(position, r); + vec3 indirectSpecular = vec3(0.65, 0.85, 1.0) + r.y * 0.72; + if (indirectHit.y > 0.0) { + if (indirectHit.y < 4.0) { + vec3 indirectPosition = position + indirectHit.x * r; + // Checkerboard floor + float f = mod(floor(6.0 * indirectPosition.z) + floor(6.0 * indirectPosition.x), 2.0); + indirectSpecular = 0.4 + f * vec3(0.6); + } else if (indirectHit.y < 16.0) { + // Metallic objects + indirectSpecular = vec3(0.3, 0.0, 0.0); + } + } + + // indirect contribution + vec2 dfg = PrefilteredDFG_Karis(roughness, NoV); + vec3 specularColor = f0 * dfg.x + dfg.y; + vec3 ibl = diffuseColor * indirectDiffuse + indirectSpecular * specularColor; + + color += ibl * indirectIntensity; + } + + return color; +} + +//------------------------------------------------------------------------------ +// Setup and execution +//------------------------------------------------------------------------------ + +mat3 setCamera(in vec3 origin, in vec3 target, float rotation) { + vec3 forward = normalize(target - origin); + vec3 orientation = vec3(sin(rotation), cos(rotation), 0.0); + vec3 left = normalize(cross(forward, orientation)); + vec3 up = normalize(cross(left, forward)); + return mat3(left, up, forward); +} + +void main() { + // Normalized coordinates + vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy; + // Aspect ratio + p.x *= resolution.x / resolution.y; + + // Camera position and "look at" + vec3 origin = vec3(0.0, 1.0, 0.0); + vec3 target = vec3(0.0); + + origin.x += 2.0 * cos(time * 0.2); + origin.z += 2.0 * sin(time * 0.2); + + mat3 toWorld = setCamera(origin, target, 0.0); + vec3 direction = toWorld * normalize(vec3(p.xy, 2.0)); + + // Render scene + float distance; + vec3 color = render(origin, direction, distance); + + // Tone mapping + color = Tonemap_ACES(color); + + // Exponential distance fog + color = mix(color, 0.8 * vec3(0.7, 0.8, 1.0), 1.0 - exp2(-0.011 * distance * distance)); + + // Gamma compression + color = OECF_sRGBFast(color); + + fragColor = vec4(color, 1.0); +} +)SHADER__"; + +static const android::vec3 SPHERICAL_HARMONICS[4] = + {{0.754554516862612, 0.748542953903366, 0.790921515418539}, + {-0.083856548007422, 0.092533500963210, 0.322764661032516}, + {0.308152705331738, 0.366796330467391, 0.466698181299906}, + {-0.188884931542396, -0.277402551592231, -0.377844212327557}}; + +static const android::vec4 TRIANGLE[3] = {{-1.0f, -1.0f, 1.0f, 1.0f}, + {3.0f, -1.0f, 1.0f, 1.0f}, + {-1.0f, 3.0f, 1.0f, 1.0f}}; diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index 037d32faff..d118ad6402 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -28,7 +28,6 @@ #include <gui/ISurfaceComposer.h> #include <gui/LayerState.h> - #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> #include <private/gui/ComposerService.h> @@ -41,6 +40,8 @@ #include <math.h> #include <math/vec3.h> +#include "BufferGenerator.h" + namespace android { namespace { @@ -478,6 +479,11 @@ protected: return screenshot; } + static status_t getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) { + static BufferGenerator bufferGenerator; + return bufferGenerator.get(outBuffer, outFence); + } + sp<SurfaceComposerClient> mClient; sp<IBinder> mDisplay; @@ -2164,6 +2170,36 @@ TEST_F(LayerTransactionTest, SetTransformToDisplayInverse_BufferState) { TEST_F(LayerTransactionTest, SetFenceBasic_BufferState) { sp<SurfaceControl> layer; + Transaction transaction; + ASSERT_NO_FATAL_FAILURE( + layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); + + sp<GraphicBuffer> buffer = + new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY, + "test"); + fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); + + sp<Fence> fence; + if (getBuffer(nullptr, &fence) != NO_ERROR) { + GTEST_SUCCEED() << "test not supported"; + return; + } + + Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply(); + + status_t status = fence->wait(1000); + ASSERT_NE(static_cast<status_t>(Fence::Status::Unsignaled), status); + std::this_thread::sleep_for(200ms); + + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); +} + +TEST_F(LayerTransactionTest, SetFenceNull_BufferState) { + sp<SurfaceControl> layer; ASSERT_NO_FATAL_FAILURE( layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); @@ -2514,7 +2550,7 @@ public: } void addSurface(ExpectedResult::Transaction transactionResult, const sp<SurfaceControl>& layer, - ExpectedResult::Buffer bufferResult = NOT_ACQUIRED, + ExpectedResult::Buffer bufferResult = ACQUIRED, ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) { mTransactionResult = transactionResult; mExpectedSurfaceResults.emplace(std::piecewise_construct, @@ -2524,7 +2560,7 @@ public: void addSurfaces(ExpectedResult::Transaction transactionResult, const std::vector<sp<SurfaceControl>>& layers, - ExpectedResult::Buffer bufferResult = NOT_ACQUIRED, + ExpectedResult::Buffer bufferResult = ACQUIRED, ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) { for (const auto& layer : layers) { addSurface(transactionResult, layer, bufferResult, previousBufferResult); @@ -2631,24 +2667,22 @@ public: return createLayer(mClient, "test", 0, 0, ISurfaceComposerClient::eFXSurfaceBufferState); } - static void fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper, - const sp<SurfaceControl>& layer = nullptr) { + static int fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper, + const sp<SurfaceControl>& layer = nullptr) { if (layer) { - sp<GraphicBuffer> buffer = - new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, - BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | - BufferUsage::COMPOSER_OVERLAY | - BufferUsage::GPU_TEXTURE, - "test"); - fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); - - sp<Fence> fence = new Fence(-1); + sp<GraphicBuffer> buffer; + sp<Fence> fence; + int err = getBuffer(&buffer, &fence); + if (err != NO_ERROR) { + return err; + } transaction.setBuffer(layer, buffer).setAcquireFence(layer, fence); } transaction.addTransactionCompletedCallback(callbackHelper->function, callbackHelper->getContext()); + return NO_ERROR; } static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult, @@ -2680,7 +2714,11 @@ TEST_F(LayerCallbackTest, Basic) { Transaction transaction; CallbackHelper callback; - fillTransaction(transaction, &callback, layer); + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction.apply(); @@ -2695,19 +2733,28 @@ TEST_F(LayerCallbackTest, NoBuffer) { Transaction transaction; CallbackHelper callback; - fillTransaction(transaction, &callback); + int err = fillTransaction(transaction, &callback); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); ExpectedResult expected; - expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer); + expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED); EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true)); } TEST_F(LayerCallbackTest, NoStateChange) { Transaction transaction; CallbackHelper callback; - fillTransaction(transaction, &callback); + int err = fillTransaction(transaction, &callback); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction.apply(); @@ -2721,7 +2768,11 @@ TEST_F(LayerCallbackTest, OffScreen) { Transaction transaction; CallbackHelper callback; - fillTransaction(transaction, &callback, layer); + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction.setFrame(layer, Rect(-100, -100, 100, 100)).apply(); @@ -2737,8 +2788,16 @@ TEST_F(LayerCallbackTest, Merge) { Transaction transaction1, transaction2; CallbackHelper callback1, callback2; - fillTransaction(transaction1, &callback1, layer1); - fillTransaction(transaction2, &callback2, layer2); + int err = fillTransaction(transaction1, &callback1, layer1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2, layer2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); @@ -2756,8 +2815,16 @@ TEST_F(LayerCallbackTest, Merge_SameCallback) { Transaction transaction1, transaction2; CallbackHelper callback; - fillTransaction(transaction1, &callback, layer1); - fillTransaction(transaction2, &callback, layer2); + int err = fillTransaction(transaction1, &callback, layer1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback, layer2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction2.merge(std::move(transaction1)).apply(); @@ -2773,8 +2840,16 @@ TEST_F(LayerCallbackTest, Merge_SameLayer) { Transaction transaction1, transaction2; CallbackHelper callback1, callback2; - fillTransaction(transaction1, &callback1, layer); - fillTransaction(transaction2, &callback2, layer); + int err = fillTransaction(transaction1, &callback1, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction2.merge(std::move(transaction1)).apply(); @@ -2784,25 +2859,6 @@ TEST_F(LayerCallbackTest, Merge_SameLayer) { EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true)); } -TEST_F(LayerCallbackTest, Merge_SingleBuffer) { - sp<SurfaceControl> layer1, layer2; - ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer()); - ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer()); - - Transaction transaction1, transaction2; - CallbackHelper callback1, callback2; - fillTransaction(transaction1, &callback1, layer1); - fillTransaction(transaction2, &callback2); - - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); - - ExpectedResult expected; - expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); - EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true)); - EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true)); -} - TEST_F(LayerCallbackTest, Merge_DifferentClients) { sp<SurfaceComposerClient> client1(new SurfaceComposerClient), client2(new SurfaceComposerClient); @@ -2818,8 +2874,16 @@ TEST_F(LayerCallbackTest, Merge_DifferentClients) { Transaction transaction1, transaction2; CallbackHelper callback1, callback2; - fillTransaction(transaction1, &callback1, layer1); - fillTransaction(transaction2, &callback2, layer2); + int err = fillTransaction(transaction1, &callback1, layer1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2, layer2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); @@ -2837,13 +2901,17 @@ TEST_F(LayerCallbackTest, MultipleTransactions) { Transaction transaction; CallbackHelper callback; for (size_t i = 0; i < 10; i++) { - fillTransaction(transaction, &callback, layer); + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction.apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, - ExpectedResult::Buffer::NOT_ACQUIRED, + ExpectedResult::Buffer::ACQUIRED, (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED : ExpectedResult::PreviousBuffer::RELEASED); EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected)); @@ -2861,10 +2929,18 @@ TEST_F(LayerCallbackTest, MultipleTransactions_NoStateChange) { ExpectedResult expected; if (i == 0) { - fillTransaction(transaction, &callback, layer); + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); } else { - fillTransaction(transaction, &callback); + int err = fillTransaction(transaction, &callback); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } } transaction.apply(); @@ -2882,9 +2958,17 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) { CallbackHelper callback; for (size_t i = 0; i < 10; i++) { if (i == 0) { - fillTransaction(transaction, &callback, layer); + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } } else { - fillTransaction(transaction, &callback); + int err = fillTransaction(transaction, &callback); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } } transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); @@ -2892,7 +2976,9 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) { ExpectedResult expected; expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED : ExpectedResult::Transaction::NOT_PRESENTED, - layer); + layer, + (i == 0) ? ExpectedResult::Buffer::ACQUIRED + : ExpectedResult::Buffer::NOT_ACQUIRED); EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, i == 0)); } ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState()); @@ -2906,15 +2992,23 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge) { Transaction transaction1, transaction2; CallbackHelper callback1, callback2; for (size_t i = 0; i < 10; i++) { - fillTransaction(transaction1, &callback1, layer1); - fillTransaction(transaction2, &callback2, layer2); + int err = fillTransaction(transaction1, &callback1, layer1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2, layer2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}, - ExpectedResult::Buffer::NOT_ACQUIRED, + ExpectedResult::Buffer::ACQUIRED, (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED : ExpectedResult::PreviousBuffer::RELEASED); EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected)); @@ -2939,15 +3033,23 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) { Transaction transaction1, transaction2; CallbackHelper callback1, callback2; for (size_t i = 0; i < 10; i++) { - fillTransaction(transaction1, &callback1, layer1); - fillTransaction(transaction2, &callback2, layer2); + int err = fillTransaction(transaction1, &callback1, layer1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2, layer2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}, - ExpectedResult::Buffer::NOT_ACQUIRED, + ExpectedResult::Buffer::ACQUIRED, (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED : ExpectedResult::PreviousBuffer::RELEASED); EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected)); @@ -2973,8 +3075,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateCha CallbackHelper callback1, callback2; // Normal call to set up test - fillTransaction(transaction1, &callback1, layer1); - fillTransaction(transaction2, &callback2, layer2); + int err = fillTransaction(transaction1, &callback1, layer1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2, layer2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); @@ -2986,8 +3096,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateCha expected.reset(); // Test - fillTransaction(transaction1, &callback1); - fillTransaction(transaction2, &callback2); + err = fillTransaction(transaction1, &callback1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction2.merge(std::move(transaction1)).apply(); @@ -3012,8 +3130,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateC CallbackHelper callback1, callback2; // Normal call to set up test - fillTransaction(transaction1, &callback1, layer1); - fillTransaction(transaction2, &callback2, layer2); + int err = fillTransaction(transaction1, &callback1, layer1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2, layer2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); @@ -3025,12 +3151,21 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateC expected.reset(); // Test - fillTransaction(transaction1, &callback1); - fillTransaction(transaction2, &callback2); + err = fillTransaction(transaction1, &callback1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); - expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2); + expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2, + ExpectedResult::Buffer::NOT_ACQUIRED); EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true)); EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true)); } @@ -3047,13 +3182,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame) { for (auto& expected : expectedResults) { expected.reset(); expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, - ExpectedResult::Buffer::NOT_ACQUIRED, previousBufferResult); + ExpectedResult::Buffer::ACQUIRED, previousBufferResult); previousBufferResult = ExpectedResult::PreviousBuffer::RELEASED; - fillTransaction(transaction, &callback, layer); + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction.apply(); - std::this_thread::sleep_for(200ms); } EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true)); } @@ -3062,23 +3200,33 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_NoStateChange) { sp<SurfaceControl> layer; ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + // Normal call to set up test Transaction transaction; CallbackHelper callback; + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + + transaction.apply(); + + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); + EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true)); + + // Test std::vector<ExpectedResult> expectedResults(50); - bool first = true; for (auto& expected : expectedResults) { expected.reset(); - if (first) { - fillTransaction(transaction, &callback, layer); - expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); - first = false; - } else { - fillTransaction(transaction, &callback); + err = fillTransaction(transaction, &callback); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; } transaction.apply(); - std::this_thread::sleep_for(200ms); } EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true)); } @@ -3090,7 +3238,11 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) { // Normal call to set up test Transaction transaction; CallbackHelper callback; - fillTransaction(transaction, &callback, layer); + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); @@ -3102,13 +3254,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) { std::vector<ExpectedResult> expectedResults(50); for (auto& expected : expectedResults) { expected.reset(); - expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer); + expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED); - fillTransaction(transaction, &callback); + err = fillTransaction(transaction, &callback); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); - - std::this_thread::sleep_for(200ms); } EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true)); } |