Rewrite VirtualDisplaySurface

The previous implementation assumed that the HWC could read and write
the same buffer on frames that involved both GLES and HWC composition.
It turns out some hardware can't do this. The new implementation
maintains a scratch buffer pool to use on these mixed frames, but on
GLES-only or HWC-only frames still does composition directly into the
output buffer.

Bug: 8384764
Change-Id: I7a3addb34fad9bfcbdabbb8b635083e10223df69
This commit is contained in:
Jesse Hall 2013-04-06 23:12:29 -07:00
parent 5cd46aa339
commit 38efe86d94
9 changed files with 591 additions and 21 deletions

View File

@ -188,6 +188,25 @@ void DisplayDevice::flip(const Region& dirty) const
mPageFlipCount++;
}
status_t DisplayDevice::prepareFrame(const HWComposer& hwc) const {
DisplaySurface::CompositionType compositionType;
bool haveGles = hwc.hasGlesComposition(mHwcDisplayId);
bool haveHwc = hwc.hasHwcComposition(mHwcDisplayId);
if (haveGles && haveHwc) {
compositionType = DisplaySurface::COMPOSITION_MIXED;
} else if (haveGles) {
compositionType = DisplaySurface::COMPOSITION_GLES;
} else if (haveHwc) {
compositionType = DisplaySurface::COMPOSITION_HWC;
} else {
// Nothing to do -- when turning the screen off we get a frame like
// this. Call it a HWC frame since we won't be doing any GLES work but
// will do a prepare/set cycle.
compositionType = DisplaySurface::COMPOSITION_HWC;
}
return mDisplaySurface->prepareFrame(compositionType);
}
void DisplayDevice::swapBuffers(HWComposer& hwc) const {
// We need to call eglSwapBuffers() unless:
// (a) there was no GLES composition this frame, or

View File

@ -119,6 +119,8 @@ public:
int32_t getHwcDisplayId() const { return mHwcDisplayId; }
const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
status_t prepareFrame(const HWComposer& hwc) const;
void swapBuffers(HWComposer& hwc) const;
status_t compositionComplete() const;

View File

@ -32,6 +32,18 @@ class DisplaySurface : public virtual RefBase {
public:
virtual sp<IGraphicBufferProducer> getIGraphicBufferProducer() const = 0;
// prepareFrame is called after the composition configuration is known but
// before composition takes place. The DisplaySurface can use the
// composition type to decide how to manage the flow of buffers between
// GLES and HWC for this frame.
enum CompositionType {
COMPOSITION_UNKNOWN = 0,
COMPOSITION_GLES = 1,
COMPOSITION_HWC = 2,
COMPOSITION_MIXED = COMPOSITION_GLES | COMPOSITION_HWC
};
virtual status_t prepareFrame(CompositionType compositionType) = 0;
// Should be called when composition rendering is complete for a frame (but
// eglSwapBuffers hasn't necessarily been called). Required by certain
// older drivers for synchronization.

View File

@ -72,6 +72,10 @@ sp<IGraphicBufferProducer> FramebufferSurface::getIGraphicBufferProducer() const
return getBufferQueue();
}
status_t FramebufferSurface::prepareFrame(CompositionType compositionType) {
return NO_ERROR;
}
status_t FramebufferSurface::advanceFrame() {
// Once we remove FB HAL support, we can call nextBuffer() from here
// instead of using onFrameAvailable(). No real benefit, except it'll be

View File

@ -41,6 +41,7 @@ public:
virtual sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
virtual status_t prepareFrame(CompositionType compositionType);
virtual status_t compositionComplete();
virtual status_t advanceFrame();
virtual void onFrameCommitted();

View File

@ -16,9 +16,6 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
// Uncomment this to remove support for HWC_DEVICE_API_VERSION_0_3 and older
#define HWC_REMOVE_DEPRECATED_VERSIONS 1
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@ -50,9 +47,9 @@
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)
#ifndef HWC_DEVICE_API_VERSION_1_3
#define HWC_DEVICE_API_VERSION_1_3 HARDWARE_DEVICE_API_VERSION_2(1, 3, HWC_HEADER_VERSION)
#endif
#define MIN_HWC_HEADER_VERSION HWC_HEADER_VERSION
@ -156,8 +153,8 @@ HWComposer::HWComposer(
// the number of displays we actually have depends on the
// hw composer version
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_EXP)) {
// 1.?? adds support for virtual displays
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
// 1.3 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
@ -582,7 +579,7 @@ status_t HWComposer::prepare() {
}
mLists[i] = disp.list;
if (mLists[i]) {
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_EXP)) {
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
mLists[i]->outbuf = NULL;
mLists[i]->outbufAcquireFenceFd = -1;
} else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {

View File

@ -14,27 +14,89 @@
* limitations under the License.
*/
// #define LOG_NDEBUG 0
#include "VirtualDisplaySurface.h"
#include <cutils/log.h>
#include <gui/IGraphicBufferProducer.h>
#include "HWComposer.h"
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
#define VDS_LOGE(msg, ...) ALOGE("[%s] "msg, \
mDisplayName.string(), ##__VA_ARGS__)
#define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] "msg, \
mDisplayName.string(), ##__VA_ARGS__)
#define VDS_LOGV(msg, ...) ALOGV("[%s] "msg, \
mDisplayName.string(), ##__VA_ARGS__)
static const char* dbgCompositionTypeStr(DisplaySurface::CompositionType type) {
switch (type) {
case DisplaySurface::COMPOSITION_UNKNOWN: return "UNKNOWN";
case DisplaySurface::COMPOSITION_GLES: return "GLES";
case DisplaySurface::COMPOSITION_HWC: return "HWC";
case DisplaySurface::COMPOSITION_MIXED: return "MIXED";
default: return "<INVALID>";
}
}
VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
const sp<IGraphicBufferProducer>& sink, const String8& name)
: mSink(sink)
: ConsumerBase(new BufferQueue(true)),
mHwc(hwc),
mDisplayId(dispId),
mDisplayName(name),
mProducerUsage(GRALLOC_USAGE_HW_COMPOSER),
mProducerSlotSource(0),
mDbgState(DBG_STATE_IDLE),
mDbgLastCompositionType(COMPOSITION_UNKNOWN)
{
LOG_ALWAYS_FATAL_IF(dispId >= 0);
mSource[SOURCE_SINK] = sink;
mSource[SOURCE_SCRATCH] = mBufferQueue;
resetPerFrameState();
int sinkWidth, sinkHeight;
mSource[SOURCE_SINK]->query(NATIVE_WINDOW_WIDTH, &sinkWidth);
mSource[SOURCE_SINK]->query(NATIVE_WINDOW_HEIGHT, &sinkHeight);
ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.string());
mBufferQueue->setConsumerName(ConsumerBase::mName);
mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
mBufferQueue->setDefaultBufferSize(sinkWidth, sinkHeight);
mBufferQueue->setDefaultMaxBufferCount(2);
}
VirtualDisplaySurface::~VirtualDisplaySurface() {
}
sp<IGraphicBufferProducer> VirtualDisplaySurface::getIGraphicBufferProducer() const {
return mSink;
if (mDisplayId >= 0) {
return static_cast<IGraphicBufferProducer*>(
const_cast<VirtualDisplaySurface*>(this));
} else {
// There won't be any interaction with HWC for this virtual display,
// so the GLES driver can pass buffers directly to the sink.
return mSource[SOURCE_SINK];
}
}
status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) {
if (mDisplayId < 0)
return NO_ERROR;
VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE,
"Unexpected prepareFrame() in %s state", dbgStateStr());
mDbgState = DBG_STATE_PREPARED;
mCompositionType = compositionType;
if (mCompositionType != mDbgLastCompositionType) {
VDS_LOGV("prepareFrame: composition type changed to %s",
dbgCompositionTypeStr(mCompositionType));
mDbgLastCompositionType = mCompositionType;
}
return NO_ERROR;
}
status_t VirtualDisplaySurface::compositionComplete() {
@ -42,15 +104,319 @@ status_t VirtualDisplaySurface::compositionComplete() {
}
status_t VirtualDisplaySurface::advanceFrame() {
return NO_ERROR;
if (mDisplayId < 0)
return NO_ERROR;
if (mCompositionType == COMPOSITION_HWC) {
VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
"Unexpected advanceFrame() in %s state on HWC frame",
dbgStateStr());
} else {
VDS_LOGW_IF(mDbgState != DBG_STATE_GLES_DONE,
"Unexpected advanceFrame() in %s state on GLES/MIXED frame",
dbgStateStr());
}
mDbgState = DBG_STATE_HWC;
status_t result;
sp<Fence> outFence;
if (mCompositionType != COMPOSITION_GLES) {
// Dequeue an output buffer from the sink
uint32_t transformHint, numPendingBuffers;
mQueueBufferOutput.deflate(&mSinkBufferWidth, &mSinkBufferHeight,
&transformHint, &numPendingBuffers);
int sslot;
result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &outFence);
if (result < 0)
return result;
mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot);
}
if (mCompositionType == COMPOSITION_HWC) {
// We just dequeued the output buffer, use it for FB as well
mFbProducerSlot = mOutputProducerSlot;
mFbFence = outFence;
} else if (mCompositionType == COMPOSITION_GLES) {
mOutputProducerSlot = mFbProducerSlot;
outFence = mFbFence;
} else {
// mFbFence and mFbProducerSlot were set in queueBuffer,
// and mOutputProducerSlot and outFence were set above when dequeueing
// the sink buffer.
}
if (mFbProducerSlot < 0 || mOutputProducerSlot < 0) {
// Last chance bailout if something bad happened earlier. For example,
// in a GLES configuration, if the sink disappears then dequeueBuffer
// will fail, the GLES driver won't queue a buffer, but SurfaceFlinger
// will soldier on. So we end up here without a buffer. There should
// be lots of scary messages in the log just before this.
VDS_LOGE("advanceFrame: no buffer, bailing out");
return NO_MEMORY;
}
sp<GraphicBuffer> fbBuffer = mProducerBuffers[mFbProducerSlot];
sp<GraphicBuffer> outBuffer = mProducerBuffers[mOutputProducerSlot];
VDS_LOGV("advanceFrame: fb=%d(%p) out=%d(%p)",
mFbProducerSlot, fbBuffer.get(),
mOutputProducerSlot, outBuffer.get());
result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
if (result == NO_ERROR) {
result = mHwc.setOutputBuffer(mDisplayId, outFence, outBuffer);
}
return result;
}
void VirtualDisplaySurface::onFrameCommitted() {
if (mDisplayId < 0)
return;
VDS_LOGW_IF(mDbgState != DBG_STATE_HWC,
"Unexpected onFrameCommitted() in %s state", dbgStateStr());
mDbgState = DBG_STATE_IDLE;
sp<Fence> fbFence = mHwc.getAndResetReleaseFence(mDisplayId);
if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) {
// release the scratch buffer back to the pool
Mutex::Autolock lock(mMutex);
int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot);
VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot);
addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], fbFence);
releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot],
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
}
if (mOutputProducerSlot >= 0) {
int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot);
QueueBufferOutput qbo;
sp<Fence> outFence = mHwc.getLastRetireFence(mDisplayId);
VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot);
status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot,
QueueBufferInput(systemTime(),
Rect(mSinkBufferWidth, mSinkBufferHeight),
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, outFence),
&qbo);
if (result == NO_ERROR) {
updateQueueBufferOutput(qbo);
}
}
resetPerFrameState();
}
void VirtualDisplaySurface::dump(String8& result) const {
}
status_t VirtualDisplaySurface::requestBuffer(int pslot,
sp<GraphicBuffer>* outBuf) {
VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
"Unexpected requestBuffer pslot=%d in %s state",
pslot, dbgStateStr());
*outBuf = mProducerBuffers[pslot];
return NO_ERROR;
}
status_t VirtualDisplaySurface::setBufferCount(int bufferCount) {
return mSource[SOURCE_SINK]->setBufferCount(bufferCount);
}
status_t VirtualDisplaySurface::dequeueBuffer(Source source,
uint32_t format, int* sslot, sp<Fence>* fence) {
status_t result = mSource[source]->dequeueBuffer(sslot, fence,
mSinkBufferWidth, mSinkBufferHeight, format, mProducerUsage);
if (result < 0)
return result;
int pslot = mapSource2ProducerSlot(source, *sslot);
VDS_LOGV("dequeueBuffer(%s): sslot=%d pslot=%d result=%d",
dbgSourceStr(source), *sslot, pslot, result);
uint32_t sourceBit = static_cast<uint32_t>(source) << pslot;
if ((mProducerSlotSource & (1u << pslot)) != sourceBit) {
// This slot was previously dequeued from the other source; must
// re-request the buffer.
result |= BUFFER_NEEDS_REALLOCATION;
mProducerSlotSource &= ~(1u << pslot);
mProducerSlotSource |= sourceBit;
}
if (result & RELEASE_ALL_BUFFERS) {
for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
if ((mProducerSlotSource & (1u << i)) == sourceBit)
mProducerBuffers[i].clear();
}
}
if (result & BUFFER_NEEDS_REALLOCATION) {
mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]);
VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p",
dbgSourceStr(source), pslot, mProducerBuffers[pslot].get());
}
return result;
}
status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
"Unexpected dequeueBuffer() in %s state", dbgStateStr());
mDbgState = DBG_STATE_GLES;
VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage);
mProducerUsage = usage | GRALLOC_USAGE_HW_COMPOSER;
Source source = fbSourceForCompositionType(mCompositionType);
if (source == SOURCE_SINK) {
mSinkBufferWidth = w;
mSinkBufferHeight = h;
}
int sslot;
status_t result = dequeueBuffer(source, format, &sslot, fence);
if (result >= 0) {
*pslot = mapSource2ProducerSlot(source, sslot);
}
return result;
}
status_t VirtualDisplaySurface::queueBuffer(int pslot,
const QueueBufferInput& input, QueueBufferOutput* output) {
VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
"Unexpected queueBuffer(pslot=%d) in %s state", pslot,
dbgStateStr());
mDbgState = DBG_STATE_GLES_DONE;
VDS_LOGV("queueBuffer pslot=%d", pslot);
status_t result;
if (mCompositionType == COMPOSITION_MIXED) {
// Queue the buffer back into the scratch pool
QueueBufferOutput scratchQBO;
int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, pslot);
result = mBufferQueue->queueBuffer(sslot, input, &scratchQBO);
if (result != NO_ERROR)
return result;
// Now acquire the buffer from the scratch pool -- should be the same
// slot and fence as we just queued.
Mutex::Autolock lock(mMutex);
BufferQueue::BufferItem item;
result = acquireBufferLocked(&item);
if (result != NO_ERROR)
return result;
VDS_LOGW_IF(item.mBuf != sslot,
"queueBuffer: acquired sslot %d from SCRATCH after queueing sslot %d",
item.mBuf, sslot);
mFbProducerSlot = mapSource2ProducerSlot(SOURCE_SCRATCH, item.mBuf);
mFbFence = mSlots[item.mBuf].mFence;
} else {
LOG_FATAL_IF(mCompositionType != COMPOSITION_GLES,
"Unexpected queueBuffer in state %s for compositionType %s",
dbgStateStr(), dbgCompositionTypeStr(mCompositionType));
// Extract the GLES release fence for HWC to acquire
int64_t timestamp;
Rect crop;
int scalingMode;
uint32_t transform;
input.deflate(&timestamp, &crop, &scalingMode, &transform,
&mFbFence);
mFbProducerSlot = pslot;
}
*output = mQueueBufferOutput;
return NO_ERROR;
}
void VirtualDisplaySurface::cancelBuffer(int pslot, const sp<Fence>& fence) {
VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
"Unexpected cancelBuffer(pslot=%d) in %s state", pslot,
dbgStateStr());
VDS_LOGV("cancelBuffer pslot=%d", pslot);
Source source = fbSourceForCompositionType(mCompositionType);
return mSource[source]->cancelBuffer(
mapProducer2SourceSlot(source, pslot), fence);
}
int VirtualDisplaySurface::query(int what, int* value) {
return mSource[SOURCE_SINK]->query(what, value);
}
status_t VirtualDisplaySurface::setSynchronousMode(bool enabled) {
return mSource[SOURCE_SINK]->setSynchronousMode(enabled);
}
status_t VirtualDisplaySurface::connect(int api, QueueBufferOutput* output) {
QueueBufferOutput qbo;
status_t result = mSource[SOURCE_SINK]->connect(api, &qbo);
if (result == NO_ERROR) {
updateQueueBufferOutput(qbo);
*output = mQueueBufferOutput;
}
return result;
}
status_t VirtualDisplaySurface::disconnect(int api) {
return mSource[SOURCE_SINK]->disconnect(api);
}
void VirtualDisplaySurface::updateQueueBufferOutput(
const QueueBufferOutput& qbo) {
uint32_t w, h, transformHint, numPendingBuffers;
qbo.deflate(&w, &h, &transformHint, &numPendingBuffers);
mQueueBufferOutput.inflate(w, h, 0, numPendingBuffers);
}
void VirtualDisplaySurface::resetPerFrameState() {
mCompositionType = COMPOSITION_UNKNOWN;
mSinkBufferWidth = 0;
mSinkBufferHeight = 0;
mFbFence = Fence::NO_FENCE;
mFbProducerSlot = -1;
mOutputProducerSlot = -1;
}
// This slot mapping function is its own inverse, so two copies are unnecessary.
// Both are kept to make the intent clear where the function is called, and for
// the (unlikely) chance that we switch to a different mapping function.
int VirtualDisplaySurface::mapSource2ProducerSlot(Source source, int sslot) {
if (source == SOURCE_SCRATCH) {
return BufferQueue::NUM_BUFFER_SLOTS - sslot - 1;
} else {
return sslot;
}
}
int VirtualDisplaySurface::mapProducer2SourceSlot(Source source, int pslot) {
return mapSource2ProducerSlot(source, pslot);
}
VirtualDisplaySurface::Source
VirtualDisplaySurface::fbSourceForCompositionType(CompositionType type) {
return type == COMPOSITION_MIXED ? SOURCE_SCRATCH : SOURCE_SINK;
}
const char* VirtualDisplaySurface::dbgStateStr() const {
switch (mDbgState) {
case DBG_STATE_IDLE: return "IDLE";
case DBG_STATE_PREPARED: return "PREPARED";
case DBG_STATE_GLES: return "GLES";
case DBG_STATE_GLES_DONE: return "GLES_DONE";
case DBG_STATE_HWC: return "HWC";
default: return "INVALID";
}
}
const char* VirtualDisplaySurface::dbgSourceStr(Source s) {
switch (s) {
case SOURCE_SINK: return "SINK";
case SOURCE_SCRATCH: return "SCRATCH";
default: return "INVALID";
}
}
// ---------------------------------------------------------------------------
} // namespace android
// ---------------------------------------------------------------------------

View File

@ -17,6 +17,9 @@
#ifndef ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
#define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
#include <gui/ConsumerBase.h>
#include <gui/IGraphicBufferProducer.h>
#include "DisplaySurface.h"
// ---------------------------------------------------------------------------
@ -25,26 +28,187 @@ namespace android {
class HWComposer;
/* This DisplaySurface implementation is a stub used for developing HWC
* virtual display support. It is currently just a passthrough.
/* This DisplaySurface implementation supports virtual displays, where GLES
* and/or HWC compose into a buffer that is then passed to an arbitrary
* consumer (the sink) running in another process.
*
* The simplest case is when the virtual display will never use the h/w
* composer -- either the h/w composer doesn't support writing to buffers, or
* there are more virtual displays than it supports simultaneously. In this
* case, the GLES driver works directly with the output buffer queue, and
* calls to the VirtualDisplay from SurfaceFlinger and DisplayHardware do
* nothing.
*
* If h/w composer might be used, then each frame will fall into one of three
* configurations: GLES-only, HWC-only, and MIXED composition. In all of these,
* we must provide a FB target buffer and output buffer for the HWC set() call.
*
* In GLES-only composition, the GLES driver is given a buffer from the sink to
* render into. When the GLES driver queues the buffer to the
* VirtualDisplaySurface, the VirtualDisplaySurface holds onto it instead of
* immediately queueing it to the sink. The buffer is used as both the FB
* target and output buffer for HWC, though on these frames the HWC doesn't
* do any work for this display and doesn't write to the output buffer. After
* composition is complete, the buffer is queued to the sink.
*
* In HWC-only composition, the VirtualDisplaySurface dequeues a buffer from
* the sink and passes it to HWC as both the FB target buffer and output
* buffer. The HWC doesn't need to read from the FB target buffer, but does
* write to the output buffer. After composition is complete, the buffer is
* queued to the sink.
*
* On MIXED frames, things become more complicated, since some h/w composer
* implementations can't read from and write to the same buffer. This class has
* an internal BufferQueue that it uses as a scratch buffer pool. The GLES
* driver is given a scratch buffer to render into. When it finishes rendering,
* the buffer is queued and then immediately acquired by the
* VirtualDisplaySurface. The scratch buffer is then used as the FB target
* buffer for HWC, and a separate buffer is dequeued from the sink and used as
* the HWC output buffer. When HWC composition is complete, the scratch buffer
* is released and the output buffer is queued to the sink.
*/
class VirtualDisplaySurface : public DisplaySurface {
class VirtualDisplaySurface : public DisplaySurface,
private BnGraphicBufferProducer,
private ConsumerBase {
public:
VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
const sp<IGraphicBufferProducer>& sink,
const String8& name);
//
// DisplaySurface interface
//
virtual sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
virtual status_t prepareFrame(CompositionType compositionType);
virtual status_t compositionComplete();
virtual status_t advanceFrame();
virtual void onFrameCommitted();
virtual void dump(String8& result) const;
private:
enum Source {SOURCE_SINK = 0, SOURCE_SCRATCH = 1};
virtual ~VirtualDisplaySurface();
sp<IGraphicBufferProducer> mSink;
//
// IGraphicBufferProducer interface, used by the GLES driver.
//
virtual status_t requestBuffer(int pslot, sp<GraphicBuffer>* outBuf);
virtual status_t setBufferCount(int bufferCount);
virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
virtual status_t queueBuffer(int pslot,
const QueueBufferInput& input, QueueBufferOutput* output);
virtual void cancelBuffer(int pslot, const sp<Fence>& 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);
//
// Utility methods
//
static Source fbSourceForCompositionType(CompositionType type);
status_t dequeueBuffer(Source source, uint32_t format,
int* sslot, sp<Fence>* fence);
void updateQueueBufferOutput(const QueueBufferOutput& qbo);
void resetPerFrameState();
// Both the sink and scratch buffer pools have their own set of slots
// ("source slots", or "sslot"). We have to merge these into the single
// set of slots used by the GLES producer ("producer slots" or "pslot") and
// internally in the VirtualDisplaySurface. To minimize the number of times
// a producer slot switches which source it comes from, we map source slot
// numbers to producer slot numbers differently for each source.
static int mapSource2ProducerSlot(Source source, int sslot);
static int mapProducer2SourceSlot(Source source, int pslot);
//
// Immutable after construction
//
HWComposer& mHwc;
const int32_t mDisplayId;
const String8 mDisplayName;
sp<IGraphicBufferProducer> mSource[2]; // indexed by SOURCE_*
//
// Inter-frame state
//
// To avoid buffer reallocations, we track the buffer usage requested by
// the GLES driver in dequeueBuffer so we can use the same flags on
// HWC-only frames.
uint32_t mProducerUsage;
// Since we present a single producer interface to the GLES driver, but
// are internally muxing between the sink and scratch producers, we have
// to keep track of which source last returned each producer slot from
// dequeueBuffer. Each bit in mLastSlotSource corresponds to a producer
// slot. Both mProducerSlotSource and mProducerBuffers are indexed by a
// "producer slot"; see the mapSlot*() functions.
uint32_t mProducerSlotSource;
sp<GraphicBuffer> mProducerBuffers[BufferQueue::NUM_BUFFER_SLOTS];
// The QueueBufferOutput with the latest info from the sink, and with the
// transform hint cleared. Since we defer queueBuffer from the GLES driver
// to the sink, we have to return the previous version.
QueueBufferOutput mQueueBufferOutput;
//
// Intra-frame state
//
// Composition type and GLES buffer source for the current frame.
// Valid after prepareFrame(), cleared in onFrameCommitted.
CompositionType mCompositionType;
// Details of the current sink buffer. These become valid when a buffer is
// dequeued from the sink, and are used when queueing the buffer.
uint32_t mSinkBufferWidth, mSinkBufferHeight;
// mFbFence is the fence HWC should wait for before reading the framebuffer
// target buffer.
sp<Fence> mFbFence;
// Producer slot numbers for the buffers to use for HWC framebuffer target
// and output.
int mFbProducerSlot;
int mOutputProducerSlot;
// Debug only -- track the sequence of events in each frame so we can make
// sure they happen in the order we expect. This class implicitly models
// a state machine; this enum/variable makes it explicit.
//
// +-----------+-------------------+-------------+
// | State | Event || Next State |
// +-----------+-------------------+-------------+
// | IDLE | prepareFrame || PREPARED |
// | PREPARED | dequeueBuffer [1] || GLES |
// | PREPARED | advanceFrame [2] || HWC |
// | GLES | queueBuffer || GLES_DONE |
// | GLES_DONE | advanceFrame || HWC |
// | HWC | onFrameCommitted || IDLE |
// +-----------+-------------------++------------+
// [1] COMPOSITION_GLES and COMPOSITION_MIXED frames.
// [2] COMPOSITION_HWC frames.
//
enum DbgState {
// no buffer dequeued, don't know anything about the next frame
DBG_STATE_IDLE,
// no buffer dequeued, but we know the buffer source for the frame
DBG_STATE_PREPARED,
// GLES driver has a buffer dequeued
DBG_STATE_GLES,
// GLES driver has queued the buffer, we haven't sent it to HWC yet
DBG_STATE_GLES_DONE,
// HWC has the buffer for this frame
DBG_STATE_HWC,
};
DbgState mDbgState;
CompositionType mDbgLastCompositionType;
const char* dbgStateStr() const;
static const char* dbgSourceStr(Source s);
};
// ---------------------------------------------------------------------------

View File

@ -895,6 +895,11 @@ void SurfaceFlinger::setUpHWComposer() {
status_t err = hwc.prepare();
ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
hw->prepareFrame(hwc);
}
}
}