}
VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
- const sp<IGraphicBufferProducer>& sink, const String8& name)
-: ConsumerBase(new BufferQueue(true)),
+ const sp<IGraphicBufferProducer>& sink,
+ const sp<BufferQueue>& bq,
+ const String8& name)
+: ConsumerBase(bq),
mHwc(hwc),
mDisplayId(dispId),
mDisplayName(name),
mDbgLastCompositionType(COMPOSITION_UNKNOWN)
{
mSource[SOURCE_SINK] = sink;
- mSource[SOURCE_SCRATCH] = mBufferQueue;
+ mSource[SOURCE_SCRATCH] = bq;
resetPerFrameState();
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);
+ mConsumer->setConsumerName(ConsumerBase::mName);
+ mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
+ mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight);
+ mConsumer->setDefaultMaxBufferCount(2);
}
VirtualDisplaySurface::~VirtualDisplaySurface() {
}
-sp<IGraphicBufferProducer> VirtualDisplaySurface::getIGraphicBufferProducer() const {
- 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::beginFrame() {
+ if (mDisplayId < 0)
+ return NO_ERROR;
+
+ VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE,
+ "Unexpected beginFrame() in %s state", dbgStateStr());
+ mDbgState = DBG_STATE_BEGUN;
+
+ uint32_t transformHint, numPendingBuffers;
+ mQueueBufferOutput.deflate(&mSinkBufferWidth, &mSinkBufferHeight,
+ &transformHint, &numPendingBuffers);
+
+ return refreshOutputBuffer();
}
status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) {
if (mDisplayId < 0)
return NO_ERROR;
- VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE,
+ VDS_LOGW_IF(mDbgState != DBG_STATE_BEGUN,
"Unexpected prepareFrame() in %s state", dbgStateStr());
mDbgState = DBG_STATE_PREPARED;
}
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
+ // Use the output buffer for the FB as well, though conceptually the
+ // FB is unused on this frame.
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.
+ mFbFence = mOutputFence;
}
if (mFbProducerSlot < 0 || mOutputProducerSlot < 0) {
mFbProducerSlot, fbBuffer.get(),
mOutputProducerSlot, outBuffer.get());
- result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
- if (result == NO_ERROR) {
- result = mHwc.setOutputBuffer(mDisplayId, outFence, outBuffer);
- }
-
- return result;
+ return mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
}
void VirtualDisplaySurface::onFrameCommitted() {
sp<Fence> outFence = mHwc.getLastRetireFence(mDisplayId);
VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot);
status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot,
- QueueBufferInput(systemTime(),
+ QueueBufferInput(
+ systemTime(), false /* isAutoTimestamp */,
Rect(mSinkBufferWidth, mSinkBufferHeight),
- NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, outFence),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */,
+ true /* async*/,
+ outFence),
&qbo);
if (result == NO_ERROR) {
updateQueueBufferOutput(qbo);
status_t VirtualDisplaySurface::dequeueBuffer(Source source,
uint32_t format, int* sslot, sp<Fence>* fence) {
- status_t result = mSource[source]->dequeueBuffer(sslot, fence,
+ // Don't let a slow consumer block us
+ bool async = (source == SOURCE_SINK);
+
+ status_t result = mSource[source]->dequeueBuffer(sslot, fence, async,
mSinkBufferWidth, mSinkBufferHeight, format, mProducerUsage);
if (result < 0)
return result;
return result;
}
-status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence,
+status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, bool async,
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_LOGW_IF(!async, "EGL called dequeueBuffer with !async despite eglSwapInterval(0)");
VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage);
+ status_t result = NO_ERROR;
mProducerUsage = usage | GRALLOC_USAGE_HW_COMPOSER;
Source source = fbSourceForCompositionType(mCompositionType);
+
if (source == SOURCE_SINK) {
- mSinkBufferWidth = w;
- mSinkBufferHeight = h;
+ // We already dequeued the output buffer. If the GLES driver wants
+ // something incompatible, we have to cancel and get a new one. This
+ // will mean that HWC will see a different output buffer between
+ // prepare and set, but since we're in GLES-only mode already it
+ // shouldn't matter.
+
+ const sp<GraphicBuffer>& buf = mProducerBuffers[mOutputProducerSlot];
+ if ((mProducerUsage & ~buf->getUsage()) != 0 ||
+ (format != 0 && format != (uint32_t)buf->getPixelFormat()) ||
+ (w != 0 && w != mSinkBufferWidth) ||
+ (h != 0 && h != mSinkBufferHeight)) {
+ VDS_LOGV("dequeueBuffer: output buffer doesn't satisfy GLES "
+ "request, getting a new buffer");
+ result = refreshOutputBuffer();
+ if (result < 0)
+ return result;
+ }
}
- int sslot;
- status_t result = dequeueBuffer(source, format, &sslot, fence);
- if (result >= 0) {
- *pslot = mapSource2ProducerSlot(source, sslot);
+ if (source == SOURCE_SINK) {
+ *pslot = mOutputProducerSlot;
+ *fence = mOutputFence;
+ } else {
+ int sslot;
+ result = dequeueBuffer(source, format, &sslot, fence);
+ if (result >= 0) {
+ *pslot = mapSource2ProducerSlot(source, sslot);
+ }
}
return result;
}
// Queue the buffer back into the scratch pool
QueueBufferOutput scratchQBO;
int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, pslot);
- result = mBufferQueue->queueBuffer(sslot, input, &scratchQBO);
+ result = mSource[SOURCE_SCRATCH]->queueBuffer(sslot, input, &scratchQBO);
if (result != NO_ERROR)
return result;
// slot and fence as we just queued.
Mutex::Autolock lock(mMutex);
BufferQueue::BufferItem item;
- result = acquireBufferLocked(&item);
+ result = acquireBufferLocked(&item, 0);
if (result != NO_ERROR)
return result;
VDS_LOGW_IF(item.mBuf != sslot,
// Extract the GLES release fence for HWC to acquire
int64_t timestamp;
+ bool isAutoTimestamp;
Rect crop;
int scalingMode;
uint32_t transform;
- input.deflate(×tamp, &crop, &scalingMode, &transform,
- &mFbFence);
+ bool async;
+ input.deflate(×tamp, &isAutoTimestamp, &crop, &scalingMode,
+ &transform, &async, &mFbFence);
mFbProducerSlot = pslot;
+ mOutputFence = mFbFence;
}
*output = mQueueBufferOutput;
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) {
+status_t VirtualDisplaySurface::connect(const sp<IBinder>& token,
+ int api, bool producerControlledByApp,
+ QueueBufferOutput* output) {
QueueBufferOutput qbo;
- status_t result = mSource[SOURCE_SINK]->connect(api, &qbo);
+ status_t result = mSource[SOURCE_SINK]->connect(token, api, producerControlledByApp, &qbo);
if (result == NO_ERROR) {
updateQueueBufferOutput(qbo);
*output = mQueueBufferOutput;
mSinkBufferWidth = 0;
mSinkBufferHeight = 0;
mFbFence = Fence::NO_FENCE;
+ mOutputFence = Fence::NO_FENCE;
mFbProducerSlot = -1;
mOutputProducerSlot = -1;
}
+status_t VirtualDisplaySurface::refreshOutputBuffer() {
+ if (mOutputProducerSlot >= 0) {
+ mSource[SOURCE_SINK]->cancelBuffer(
+ mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot),
+ mOutputFence);
+ }
+
+ int sslot;
+ status_t result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &mOutputFence);
+ if (result < 0)
+ return result;
+ mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot);
+
+ result = mHwc.setOutputBuffer(mDisplayId, mOutputFence,
+ mProducerBuffers[mOutputProducerSlot]);
+
+ return result;
+}
+
// 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.