diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index f36e1bfb5..ec296d333 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -14,7 +14,6 @@ LOCAL_SRC_FILES:= \ SurfaceFlingerConsumer.cpp \ SurfaceTextureLayer.cpp \ Transform.cpp \ - DisplayHardware/BufferQueueInterposer.cpp \ DisplayHardware/FramebufferSurface.cpp \ DisplayHardware/HWComposer.cpp \ DisplayHardware/PowerHAL.cpp \ diff --git a/services/surfaceflinger/DisplayHardware/BufferQueueInterposer.cpp b/services/surfaceflinger/DisplayHardware/BufferQueueInterposer.cpp deleted file mode 100644 index 91f9aeabd..000000000 --- a/services/surfaceflinger/DisplayHardware/BufferQueueInterposer.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - * 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. - */ - -#undef LOG_TAG -#define LOG_TAG "BQInterposer" -//#define LOG_NDEBUG 0 - -#include "BufferQueueInterposer.h" - -// --------------------------------------------------------------------------- -namespace android { -// --------------------------------------------------------------------------- - -#define BQI_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) -#define BQI_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) -#define BQI_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) -#define BQI_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) -#define BQI_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) - -// Get an ID that's unique within this process. -static int32_t createProcessUniqueId() { - static volatile int32_t globalCounter = 0; - return android_atomic_inc(&globalCounter); -} - -BufferQueueInterposer::BufferQueueInterposer( - const sp& sink, const String8& name) -: mSink(sink), - mName(name), - mAcquired(false) -{ - BQI_LOGV("BufferQueueInterposer sink=%p", sink.get()); -} - -BufferQueueInterposer::~BufferQueueInterposer() { - Mutex::Autolock lock(mMutex); - flushQueuedBuffersLocked(); - BQI_LOGV("~BufferQueueInterposer"); -} - -status_t BufferQueueInterposer::requestBuffer(int slot, - sp* outBuf) { - BQI_LOGV("requestBuffer slot=%d", slot); - Mutex::Autolock lock(mMutex); - - if (size_t(slot) >= mBuffers.size()) { - size_t size = mBuffers.size(); - mBuffers.insertAt(size, size - slot + 1); - } - sp& buf = mBuffers.editItemAt(slot); - - status_t result = mSink->requestBuffer(slot, &buf); - *outBuf = buf; - return result; -} - -status_t BufferQueueInterposer::setBufferCount(int bufferCount) { - BQI_LOGV("setBufferCount count=%d", bufferCount); - Mutex::Autolock lock(mMutex); - - bufferCount += 1; - - status_t result = flushQueuedBuffersLocked(); - if (result != NO_ERROR) - return result; - - result = mSink->setBufferCount(bufferCount); - if (result != NO_ERROR) - return result; - - for (size_t i = 0; i < mBuffers.size(); i++) - mBuffers.editItemAt(i).clear(); - ssize_t n = mBuffers.resize(bufferCount); - result = (n < 0) ? n : result; - - return result; -} - -status_t BufferQueueInterposer::dequeueBuffer(int* slot, sp* fence, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { - BQI_LOGV("dequeueBuffer %ux%u fmt=%u usage=%#x", w, h, format, usage); - return mSink->dequeueBuffer(slot, fence, w, h, format, usage); -} - -status_t BufferQueueInterposer::queueBuffer(int slot, - const QueueBufferInput& input, QueueBufferOutput* output) { - BQI_LOGV("queueBuffer slot=%d", slot); - Mutex::Autolock lock(mMutex); - mQueue.push(QueuedBuffer(slot, input)); - *output = mQueueBufferOutput; - return NO_ERROR; -} - -void BufferQueueInterposer::cancelBuffer(int slot, const sp& fence) { - BQI_LOGV("cancelBuffer slot=%d", slot); - mSink->cancelBuffer(slot, fence); -} - -int BufferQueueInterposer::query(int what, int* value) { - BQI_LOGV("query what=%d", what); - return mSink->query(what, value); -} - -status_t BufferQueueInterposer::setSynchronousMode(bool enabled) { - BQI_LOGV("setSynchronousMode %s", enabled ? "true" : "false"); - return mSink->setSynchronousMode(enabled); -} - -status_t BufferQueueInterposer::connect(int api, QueueBufferOutput* output) { - BQI_LOGV("connect api=%d", api); - Mutex::Autolock lock(mMutex); - status_t result = mSink->connect(api, &mQueueBufferOutput); - if (result == NO_ERROR) { - *output = mQueueBufferOutput; - } - return result; -} - -status_t BufferQueueInterposer::disconnect(int api) { - BQI_LOGV("disconnect: api=%d", api); - Mutex::Autolock lock(mMutex); - flushQueuedBuffersLocked(); - return mSink->disconnect(api); -} - -status_t BufferQueueInterposer::pullEmptyBuffer() { - status_t result; - - int slot; - sp fence; - result = dequeueBuffer(&slot, &fence, 0, 0, 0, 0); - if (result == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) { - sp buffer; - result = requestBuffer(slot, &buffer); - } else if (result != NO_ERROR) { - return result; - } - - uint32_t w, h, transformHint, numPendingBuffers; - mQueueBufferOutput.deflate(&w, &h, &transformHint, &numPendingBuffers); - - IGraphicBufferProducer::QueueBufferInput qbi(0, Rect(w, h), - NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, fence); - IGraphicBufferProducer::QueueBufferOutput qbo; - result = queueBuffer(slot, qbi, &qbo); - if (result != NO_ERROR) - return result; - - return NO_ERROR; -} - -status_t BufferQueueInterposer::acquireBuffer(sp* buf, - sp* fence) { - Mutex::Autolock lock(mMutex); - if (mQueue.empty()) { - BQI_LOGV("acquireBuffer: no buffers available"); - return NO_BUFFER_AVAILABLE; - } - if (mAcquired) { - BQI_LOGE("acquireBuffer: buffer already acquired"); - return BUFFER_ALREADY_ACQUIRED; - } - BQI_LOGV("acquireBuffer: acquiring slot %d", mQueue[0].slot); - - *buf = mBuffers[mQueue[0].slot]; - *fence = mQueue[0].fence; - mAcquired = true; - return NO_ERROR; -} - -status_t BufferQueueInterposer::releaseBuffer(const sp& fence) { - Mutex::Autolock lock(mMutex); - if (!mAcquired) { - BQI_LOGE("releaseBuffer: releasing a non-acquired buffer"); - return BUFFER_NOT_ACQUIRED; - } - BQI_LOGV("releaseBuffer: releasing slot %d to sink", mQueue[0].slot); - - const QueuedBuffer& b = mQueue[0]; - status_t result = mSink->queueBuffer(b.slot, - QueueBufferInput(b.timestamp, b.crop, b.scalingMode, - b.transform, b.fence), - &mQueueBufferOutput); - mQueue.removeAt(0); - mAcquired = false; - - return result; -} - -status_t BufferQueueInterposer::flushQueuedBuffersLocked() { - if (mAcquired) { - BQI_LOGE("flushQueuedBuffersLocked: buffer acquired, can't flush"); - return INVALID_OPERATION; - } - - status_t result = NO_ERROR; - for (size_t i = 0; i < mQueue.size(); i++) { - const QueuedBuffer& b = mQueue[i]; - BQI_LOGV("flushing queued slot %d to sink", b.slot); - status_t err = mSink->queueBuffer(b.slot, - QueueBufferInput(b.timestamp, b.crop, b.scalingMode, - b.transform, b.fence), - &mQueueBufferOutput); - if (err != NO_ERROR && result == NO_ERROR) // latch first error - result = err; - } - mQueue.clear(); - return result; -} - -// --------------------------------------------------------------------------- -} // namespace android -// --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/DisplayHardware/BufferQueueInterposer.h b/services/surfaceflinger/DisplayHardware/BufferQueueInterposer.h deleted file mode 100644 index 7e84e973d..000000000 --- a/services/surfaceflinger/DisplayHardware/BufferQueueInterposer.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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_SF_BUFFERQUEUEINTERPOSER_H -#define ANDROID_SF_BUFFERQUEUEINTERPOSER_H - -#include -#include -#include - -// --------------------------------------------------------------------------- -namespace android { -// --------------------------------------------------------------------------- - -// BufferQueueInterposers introduce an extra stage between a buffer producer -// (the source) and a buffer consumer (the sink), which communicate via the -// IGraphicBufferProducer interface. It is designed to be as transparent as -// possible to both endpoints, so that they can work the same whether an -// interposer is present or not. -// -// When the interpose is present, the source queues buffers to the -// IGraphicBufferProducer implemented by BufferQueueInterposer. A client of -// the BufferQueueInterposer can acquire each buffer in turn and read or -// modify it, releasing the buffer when finished. When the buffer is released, -// the BufferQueueInterposer queues it to the original IGraphicBufferProducer -// interface representing the sink. -// -// A BufferQueueInterposer can be used to do additional rendering to a buffer -// before it is consumed -- essentially pipelining two producers. As an -// example, SurfaceFlinger uses this to implement mixed GLES and HWC -// compositing to the same buffer for virtual displays. If it used two separate -// buffer queues, then in GLES-only or mixed GLES+HWC compositing, the HWC -// would have to copy the GLES output buffer to the HWC output buffer, using -// more bandwidth than having HWC do additional composition "in place" on the -// GLES output buffer. -// -// The goal for this class is to be usable in a variety of situations and be -// part of libgui. But both the interface and implementation need some -// iteration before then, so for now it should only be used by -// VirtualDisplaySurface, which is why it's currently in SurfaceFlinger. -// -// Some of the problems that still need to be solved are: -// -// - Refactor the interposer interface along with BufferQueue and ConsumerBase, -// so that there is a common interface for the consumer end of a queue. The -// existing interfaces have some problems when the implementation isn't the -// final consumer. -// -// - The client of the interposer may need one or more buffers in addition to -// those used by the source and sink. IGraphicBufferProducer will probably -// need to change to allow the producer to specify how many buffers it needs -// to dequeue at a time, and then the interposer can add its requirements to -// those of the source. -// -// - Abandoning, disconnecting, and connecting need to pass through somehow. -// There needs to be a way to tell the interposer client to release its -// buffer immediately so it can be queued/released, e.g. when the source -// calls disconnect(). -// -// - Right now the source->BQI queue is synchronous even if the BQI->sink queue -// is asynchronous. Need to figure out how asynchronous should behave and -// implement that. - -class BufferQueueInterposer : public BnGraphicBufferProducer { -public: - BufferQueueInterposer(const sp& sink, - const String8& name); - - // - // IGraphicBufferProducer interface - // - virtual status_t requestBuffer(int slot, sp* outBuf); - virtual status_t setBufferCount(int bufferCount); - virtual status_t dequeueBuffer(int* slot, sp* fence, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage); - virtual status_t queueBuffer(int slot, - const QueueBufferInput& input, QueueBufferOutput* output); - virtual void cancelBuffer(int slot, const sp& fence); - virtual int query(int what, int* value); - virtual status_t setSynchronousMode(bool enabled); - virtual status_t connect(int api, QueueBufferOutput* output); - virtual status_t disconnect(int api); - - // - // Interposer interface - // - - enum { - NO_BUFFER_AVAILABLE = 2, // matches BufferQueue - BUFFER_NOT_ACQUIRED, - BUFFER_ALREADY_ACQUIRED, - }; - - // Acquire the oldest queued buffer. If no buffers are pending, returns - // NO_BUFFER_AVAILABLE. If a buffer is currently acquired, returns - // BUFFER_ALREADY_ACQUIRED. - status_t acquireBuffer(sp* buf, sp* fence); - - // Release the currently acquired buffer, queueing it to the sink. If the - // current buffer hasn't been acquired, returns BUFFER_NOT_ACQUIRED. - status_t releaseBuffer(const sp& fence); - - // pullEmptyBuffer dequeues a buffer from the sink, then immediately - // queues it to the interposer. This makes a buffer available for the - // client to acquire even if the source hasn't queued one. - status_t pullEmptyBuffer(); - -private: - struct QueuedBuffer { - QueuedBuffer(): slot(-1) {} - QueuedBuffer(int slot, const QueueBufferInput& qbi): slot(slot) { - qbi.deflate(×tamp, &crop, &scalingMode, &transform, &fence); - } - int slot; - int64_t timestamp; - Rect crop; - int scalingMode; - uint32_t transform; - sp fence; - }; - - virtual ~BufferQueueInterposer(); - status_t flushQueuedBuffersLocked(); - - const sp mSink; - String8 mName; - - Mutex mMutex; - Vector > mBuffers; - Vector mQueue; - bool mAcquired; - QueueBufferOutput mQueueBufferOutput; -}; - -// --------------------------------------------------------------------------- -} // namespace android -// --------------------------------------------------------------------------- - -#endif // ANDROID_SF_BUFFERQUEUEINTERPOSER_H diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 6bdccb931..4e6dde531 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -50,6 +50,10 @@ namespace android { +// This is not a real HWC version. It's used for in-development features that +// haven't been committed to a specific real HWC version. +#define HWC_DEVICE_API_VERSION_1_EXP HARDWARE_DEVICE_API_VERSION_2(1, 0xFF, HWC_HEADER_VERSION) + #define MIN_HWC_HEADER_VERSION HWC_HEADER_VERSION #define NUM_PHYSICAL_DISPLAYS HWC_NUM_DISPLAY_TYPES @@ -152,8 +156,8 @@ HWComposer::HWComposer( // the number of displays we actually have depends on the // hw composer version - if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) { - // 1.2 adds support for virtual displays + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_EXP)) { + // 1.?? adds support for virtual displays mNumDisplays = MAX_DISPLAYS; } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { // 1.1 adds support for multiple displays @@ -578,7 +582,7 @@ status_t HWComposer::prepare() { } mLists[i] = disp.list; if (mLists[i]) { - if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) { + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_EXP)) { mLists[i]->outbuf = NULL; mLists[i]->outbufAcquireFenceFd = -1; } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 7e14d955a..2838b2303 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -15,7 +15,9 @@ */ #include "VirtualDisplaySurface.h" -#include "HWComposer.h" + +#include +#include // --------------------------------------------------------------------------- namespace android { @@ -23,28 +25,16 @@ namespace android { VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, const sp& sink, const String8& name) -: mHwc(hwc), - mDisplayId(dispId), - mName(name) +: mSink(sink) { - if (mDisplayId >= 0) { - mInterposer = new BufferQueueInterposer(sink, name); - mSourceProducer = mInterposer; - } else { - mSourceProducer = sink; - } + LOG_ALWAYS_FATAL_IF(dispId >= 0); } VirtualDisplaySurface::~VirtualDisplaySurface() { - if (mAcquiredBuffer != NULL) { - status_t result = mInterposer->releaseBuffer(Fence::NO_FENCE); - ALOGE_IF(result != NO_ERROR, "VirtualDisplaySurface \"%s\": " - "failed to release buffer: %d", mName.string(), result); - } } sp VirtualDisplaySurface::getIGraphicBufferProducer() const { - return mSourceProducer; + return mSink; } status_t VirtualDisplaySurface::compositionComplete() { @@ -52,60 +42,10 @@ status_t VirtualDisplaySurface::compositionComplete() { } status_t VirtualDisplaySurface::advanceFrame() { - if (mInterposer == NULL) - return NO_ERROR; - - Mutex::Autolock lock(mMutex); - status_t result = NO_ERROR; - - if (mAcquiredBuffer != NULL) { - ALOGE("VirtualDisplaySurface \"%s\": " - "advanceFrame called twice without onFrameCommitted", - mName.string()); - return INVALID_OPERATION; - } - - sp fence; - result = mInterposer->acquireBuffer(&mAcquiredBuffer, &fence); - if (result == BufferQueueInterposer::NO_BUFFER_AVAILABLE) { - result = mInterposer->pullEmptyBuffer(); - if (result != NO_ERROR) - return result; - result = mInterposer->acquireBuffer(&mAcquiredBuffer, &fence); - } - if (result != NO_ERROR) - return result; - - result = mHwc.fbPost(mDisplayId, fence, mAcquiredBuffer); - if (result == NO_ERROR) { - result = mHwc.setOutputBuffer(mDisplayId, fence, mAcquiredBuffer); - } - return result; + return NO_ERROR; } void VirtualDisplaySurface::onFrameCommitted() { - if (mInterposer == NULL) - return; - - Mutex::Autolock lock(mMutex); - if (mAcquiredBuffer != NULL) { - // fbFence signals when reads from the framebuffer are finished - // outFence signals when writes to the output buffer are finished - // It's unlikely that there will be an implementation where fbFence - // signals after outFence (in fact they'll typically be the same - // sync_pt), but just to be pedantic we merge them so the sink will - // be sure to wait until both are complete. - sp fbFence = mHwc.getAndResetReleaseFence(mDisplayId); - sp outFence = mHwc.getLastRetireFence(mDisplayId); - sp fence = Fence::merge( - String8::format("HWC done: %.21s", mName.string()), - fbFence, outFence); - - status_t result = mInterposer->releaseBuffer(fence); - ALOGE_IF(result != NO_ERROR, "VirtualDisplaySurface \"%s\": " - "failed to release buffer: %d", mName.string(), result); - mAcquiredBuffer.clear(); - } } void VirtualDisplaySurface::dump(String8& result) const { diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 0706e7566..f32179576 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -17,7 +17,6 @@ #ifndef ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H #define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H -#include "BufferQueueInterposer.h" #include "DisplaySurface.h" // --------------------------------------------------------------------------- @@ -26,33 +25,8 @@ namespace android { class HWComposer; -/* This DisplaySurface implementation uses a BufferQueueInterposer to pass - * partially- or fully-composited buffers from the OpenGL ES driver to - * HWComposer to use as the output buffer for virtual displays. Allowing HWC - * to compose into the same buffer that contains GLES results saves bandwidth - * compared to having two separate BufferQueues for frames with at least some - * GLES composition. - * - * The alternative would be to have two complete BufferQueues, one from GLES - * to HWC and one from HWC to the virtual display sink (e.g. video encoder). - * For GLES-only frames, the same bandwidth saving could be achieved if buffers - * could be acquired from the GLES->HWC queue and inserted into the HWC->sink - * queue. That would be complicated and doesn't help the mixed GLES+HWC case. - * - * On frames with no GLES composition, the VirtualDisplaySurface dequeues a - * buffer directly from the sink IGraphicBufferProducer and passes it to HWC, - * bypassing the GLES driver. This is only guaranteed to work if - * eglSwapBuffers doesn't immediately dequeue a buffer for the next frame, - * since we can't rely on being able to dequeue more than one buffer at a time. - * - * This class also has a passthrough mode, where it doesn't use a - * BufferQueueInterposer and never sends buffers to HWC. Instead, OpenGL ES - * output buffers are queued directly to the virtual display sink; this class - * is inactive after construction. This mode is used when the HWC doesn't - * support compositing for virtual displays. - * - * TODO(jessehall): Add a libgui test that ensures that EGL/GLES do lazy - * dequeBuffers; we've wanted to require that for other reasons anyway. +/* This DisplaySurface implementation is a stub used for developing HWC + * virtual display support. It is currently just a passthrough. */ class VirtualDisplaySurface : public DisplaySurface { public: @@ -70,19 +44,7 @@ public: private: virtual ~VirtualDisplaySurface(); - // immutable after construction - HWComposer& mHwc; - int32_t mDisplayId; - String8 mName; - - // with HWC support, both of these point to the same object. - // otherwise, mInterposer is NULL and mSourceProducer is the sink. - sp mInterposer; - sp mSourceProducer; - - // mutable, must be synchronized with mMutex - Mutex mMutex; - sp mAcquiredBuffer; + sp mSink; }; // ---------------------------------------------------------------------------