* commit '5bc0c358a80f3c0e762b489e8bfb5888444159a6': Provide HWC prepare with a valid output buffer
This commit is contained in:
commit
68df058934
@ -198,6 +198,10 @@ void DisplayDevice::flip(const Region& dirty) const
|
|||||||
mPageFlipCount++;
|
mPageFlipCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_t DisplayDevice::beginFrame() const {
|
||||||
|
return mDisplaySurface->beginFrame();
|
||||||
|
}
|
||||||
|
|
||||||
status_t DisplayDevice::prepareFrame(const HWComposer& hwc) const {
|
status_t DisplayDevice::prepareFrame(const HWComposer& hwc) const {
|
||||||
DisplaySurface::CompositionType compositionType;
|
DisplaySurface::CompositionType compositionType;
|
||||||
bool haveGles = hwc.hasGlesComposition(mHwcDisplayId);
|
bool haveGles = hwc.hasGlesComposition(mHwcDisplayId);
|
||||||
|
@ -122,6 +122,7 @@ public:
|
|||||||
int32_t getHwcDisplayId() const { return mHwcDisplayId; }
|
int32_t getHwcDisplayId() const { return mHwcDisplayId; }
|
||||||
const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
|
const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
|
||||||
|
|
||||||
|
status_t beginFrame() const;
|
||||||
status_t prepareFrame(const HWComposer& hwc) const;
|
status_t prepareFrame(const HWComposer& hwc) const;
|
||||||
|
|
||||||
void swapBuffers(HWComposer& hwc) const;
|
void swapBuffers(HWComposer& hwc) const;
|
||||||
|
@ -30,6 +30,11 @@ class String8;
|
|||||||
|
|
||||||
class DisplaySurface : public virtual RefBase {
|
class DisplaySurface : public virtual RefBase {
|
||||||
public:
|
public:
|
||||||
|
// beginFrame is called at the beginning of the composition loop, before
|
||||||
|
// the configuration is known. The DisplaySurface should do anything it
|
||||||
|
// needs to do to enable HWComposer to decide how to compose the frame.
|
||||||
|
virtual status_t beginFrame() = 0;
|
||||||
|
|
||||||
// prepareFrame is called after the composition configuration is known but
|
// prepareFrame is called after the composition configuration is known but
|
||||||
// before composition takes place. The DisplaySurface can use the
|
// before composition takes place. The DisplaySurface can use the
|
||||||
// composition type to decide how to manage the flow of buffers between
|
// composition type to decide how to manage the flow of buffers between
|
||||||
|
@ -68,6 +68,10 @@ FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp,
|
|||||||
mConsumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS);
|
mConsumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_t FramebufferSurface::beginFrame() {
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
status_t FramebufferSurface::prepareFrame(CompositionType compositionType) {
|
status_t FramebufferSurface::prepareFrame(CompositionType compositionType) {
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ class FramebufferSurface : public ConsumerBase,
|
|||||||
public:
|
public:
|
||||||
FramebufferSurface(HWComposer& hwc, int disp, const sp<IGraphicBufferConsumer>& consumer);
|
FramebufferSurface(HWComposer& hwc, int disp, const sp<IGraphicBufferConsumer>& consumer);
|
||||||
|
|
||||||
|
virtual status_t beginFrame();
|
||||||
virtual status_t prepareFrame(CompositionType compositionType);
|
virtual status_t prepareFrame(CompositionType compositionType);
|
||||||
virtual status_t compositionComplete();
|
virtual status_t compositionComplete();
|
||||||
virtual status_t advanceFrame();
|
virtual status_t advanceFrame();
|
||||||
|
@ -71,11 +71,26 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
|
|||||||
VirtualDisplaySurface::~VirtualDisplaySurface() {
|
VirtualDisplaySurface::~VirtualDisplaySurface() {
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) {
|
status_t VirtualDisplaySurface::beginFrame() {
|
||||||
if (mDisplayId < 0)
|
if (mDisplayId < 0)
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
|
|
||||||
VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE,
|
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_BEGUN,
|
||||||
"Unexpected prepareFrame() in %s state", dbgStateStr());
|
"Unexpected prepareFrame() in %s state", dbgStateStr());
|
||||||
mDbgState = DBG_STATE_PREPARED;
|
mDbgState = DBG_STATE_PREPARED;
|
||||||
|
|
||||||
@ -109,31 +124,11 @@ status_t VirtualDisplaySurface::advanceFrame() {
|
|||||||
}
|
}
|
||||||
mDbgState = DBG_STATE_HWC;
|
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, false);
|
|
||||||
if (result < 0)
|
|
||||||
return result;
|
|
||||||
mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mCompositionType == COMPOSITION_HWC) {
|
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;
|
mFbProducerSlot = mOutputProducerSlot;
|
||||||
mFbFence = outFence;
|
mFbFence = mOutputFence;
|
||||||
} 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) {
|
if (mFbProducerSlot < 0 || mOutputProducerSlot < 0) {
|
||||||
@ -152,12 +147,7 @@ status_t VirtualDisplaySurface::advanceFrame() {
|
|||||||
mFbProducerSlot, fbBuffer.get(),
|
mFbProducerSlot, fbBuffer.get(),
|
||||||
mOutputProducerSlot, outBuffer.get());
|
mOutputProducerSlot, outBuffer.get());
|
||||||
|
|
||||||
result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
|
return mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
|
||||||
if (result == NO_ERROR) {
|
|
||||||
result = mHwc.setOutputBuffer(mDisplayId, outFence, outBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualDisplaySurface::onFrameCommitted() {
|
void VirtualDisplaySurface::onFrameCommitted() {
|
||||||
@ -256,17 +246,39 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, bool
|
|||||||
|
|
||||||
VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage);
|
VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage);
|
||||||
|
|
||||||
|
status_t result = NO_ERROR;
|
||||||
mProducerUsage = usage | GRALLOC_USAGE_HW_COMPOSER;
|
mProducerUsage = usage | GRALLOC_USAGE_HW_COMPOSER;
|
||||||
Source source = fbSourceForCompositionType(mCompositionType);
|
Source source = fbSourceForCompositionType(mCompositionType);
|
||||||
|
|
||||||
if (source == SOURCE_SINK) {
|
if (source == SOURCE_SINK) {
|
||||||
mSinkBufferWidth = w;
|
// We already dequeued the output buffer. If the GLES driver wants
|
||||||
mSinkBufferHeight = h;
|
// 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;
|
if (source == SOURCE_SINK) {
|
||||||
status_t result = dequeueBuffer(source, format, &sslot, fence, async);
|
*pslot = mOutputProducerSlot;
|
||||||
if (result >= 0) {
|
*fence = mOutputFence;
|
||||||
*pslot = mapSource2ProducerSlot(source, sslot);
|
} else {
|
||||||
|
int sslot;
|
||||||
|
result = dequeueBuffer(source, format, &sslot, fence, async);
|
||||||
|
if (result >= 0) {
|
||||||
|
*pslot = mapSource2ProducerSlot(source, sslot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -318,6 +330,7 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot,
|
|||||||
&transform, &async, &mFbFence);
|
&transform, &async, &mFbFence);
|
||||||
|
|
||||||
mFbProducerSlot = pslot;
|
mFbProducerSlot = pslot;
|
||||||
|
mOutputFence = mFbFence;
|
||||||
}
|
}
|
||||||
|
|
||||||
*output = mQueueBufferOutput;
|
*output = mQueueBufferOutput;
|
||||||
@ -365,10 +378,30 @@ void VirtualDisplaySurface::resetPerFrameState() {
|
|||||||
mSinkBufferWidth = 0;
|
mSinkBufferWidth = 0;
|
||||||
mSinkBufferHeight = 0;
|
mSinkBufferHeight = 0;
|
||||||
mFbFence = Fence::NO_FENCE;
|
mFbFence = Fence::NO_FENCE;
|
||||||
|
mOutputFence = Fence::NO_FENCE;
|
||||||
mFbProducerSlot = -1;
|
mFbProducerSlot = -1;
|
||||||
mOutputProducerSlot = -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, false);
|
||||||
|
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.
|
// 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
|
// 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.
|
// the (unlikely) chance that we switch to a different mapping function.
|
||||||
|
@ -79,6 +79,7 @@ public:
|
|||||||
//
|
//
|
||||||
// DisplaySurface interface
|
// DisplaySurface interface
|
||||||
//
|
//
|
||||||
|
virtual status_t beginFrame();
|
||||||
virtual status_t prepareFrame(CompositionType compositionType);
|
virtual status_t prepareFrame(CompositionType compositionType);
|
||||||
virtual status_t compositionComplete();
|
virtual status_t compositionComplete();
|
||||||
virtual status_t advanceFrame();
|
virtual status_t advanceFrame();
|
||||||
@ -112,6 +113,7 @@ private:
|
|||||||
int* sslot, sp<Fence>* fence, bool async);
|
int* sslot, sp<Fence>* fence, bool async);
|
||||||
void updateQueueBufferOutput(const QueueBufferOutput& qbo);
|
void updateQueueBufferOutput(const QueueBufferOutput& qbo);
|
||||||
void resetPerFrameState();
|
void resetPerFrameState();
|
||||||
|
status_t refreshOutputBuffer();
|
||||||
|
|
||||||
// Both the sink and scratch buffer pools have their own set of slots
|
// 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
|
// ("source slots", or "sslot"). We have to merge these into the single
|
||||||
@ -169,6 +171,10 @@ private:
|
|||||||
// target buffer.
|
// target buffer.
|
||||||
sp<Fence> mFbFence;
|
sp<Fence> mFbFence;
|
||||||
|
|
||||||
|
// mOutputFence is the fence HWC should wait for before writing to the
|
||||||
|
// output buffer.
|
||||||
|
sp<Fence> mOutputFence;
|
||||||
|
|
||||||
// Producer slot numbers for the buffers to use for HWC framebuffer target
|
// Producer slot numbers for the buffers to use for HWC framebuffer target
|
||||||
// and output.
|
// and output.
|
||||||
int mFbProducerSlot;
|
int mFbProducerSlot;
|
||||||
@ -181,7 +187,8 @@ private:
|
|||||||
// +-----------+-------------------+-------------+
|
// +-----------+-------------------+-------------+
|
||||||
// | State | Event || Next State |
|
// | State | Event || Next State |
|
||||||
// +-----------+-------------------+-------------+
|
// +-----------+-------------------+-------------+
|
||||||
// | IDLE | prepareFrame || PREPARED |
|
// | IDLE | beginFrame || BEGUN |
|
||||||
|
// | BEGUN | prepareFrame || PREPARED |
|
||||||
// | PREPARED | dequeueBuffer [1] || GLES |
|
// | PREPARED | dequeueBuffer [1] || GLES |
|
||||||
// | PREPARED | advanceFrame [2] || HWC |
|
// | PREPARED | advanceFrame [2] || HWC |
|
||||||
// | GLES | queueBuffer || GLES_DONE |
|
// | GLES | queueBuffer || GLES_DONE |
|
||||||
@ -194,7 +201,10 @@ private:
|
|||||||
enum DbgState {
|
enum DbgState {
|
||||||
// no buffer dequeued, don't know anything about the next frame
|
// no buffer dequeued, don't know anything about the next frame
|
||||||
DBG_STATE_IDLE,
|
DBG_STATE_IDLE,
|
||||||
// no buffer dequeued, but we know the buffer source for the frame
|
// output buffer dequeued, framebuffer source not yet known
|
||||||
|
DBG_STATE_BEGUN,
|
||||||
|
// output buffer dequeued, framebuffer source known but not provided
|
||||||
|
// to GLES yet.
|
||||||
DBG_STATE_PREPARED,
|
DBG_STATE_PREPARED,
|
||||||
// GLES driver has a buffer dequeued
|
// GLES driver has a buffer dequeued
|
||||||
DBG_STATE_GLES,
|
DBG_STATE_GLES,
|
||||||
|
@ -850,6 +850,10 @@ void SurfaceFlinger::rebuildLayerStacks() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SurfaceFlinger::setUpHWComposer() {
|
void SurfaceFlinger::setUpHWComposer() {
|
||||||
|
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
|
||||||
|
mDisplays[dpy]->beginFrame();
|
||||||
|
}
|
||||||
|
|
||||||
HWComposer& hwc(getHwComposer());
|
HWComposer& hwc(getHwComposer());
|
||||||
if (hwc.initCheck() == NO_ERROR) {
|
if (hwc.initCheck() == NO_ERROR) {
|
||||||
// build the h/w work list
|
// build the h/w work list
|
||||||
|
Loading…
Reference in New Issue
Block a user