Home | History | Annotate | Download | only in DisplayHardware
      1 /*
      2  * Copyright 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 // #define LOG_NDEBUG 0
     18 #include "VirtualDisplaySurface.h"
     19 #include "HWComposer.h"
     20 
     21 // ---------------------------------------------------------------------------
     22 namespace android {
     23 // ---------------------------------------------------------------------------
     24 
     25 #if defined(FORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS)
     26 static const bool sForceHwcCopy = true;
     27 #else
     28 static const bool sForceHwcCopy = false;
     29 #endif
     30 
     31 #define VDS_LOGE(msg, ...) ALOGE("[%s] " msg, \
     32         mDisplayName.string(), ##__VA_ARGS__)
     33 #define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] " msg, \
     34         mDisplayName.string(), ##__VA_ARGS__)
     35 #define VDS_LOGV(msg, ...) ALOGV("[%s] " msg, \
     36         mDisplayName.string(), ##__VA_ARGS__)
     37 
     38 static const char* dbgCompositionTypeStr(DisplaySurface::CompositionType type) {
     39     switch (type) {
     40         case DisplaySurface::COMPOSITION_UNKNOWN: return "UNKNOWN";
     41         case DisplaySurface::COMPOSITION_GLES:    return "GLES";
     42         case DisplaySurface::COMPOSITION_HWC:     return "HWC";
     43         case DisplaySurface::COMPOSITION_MIXED:   return "MIXED";
     44         default:                                  return "<INVALID>";
     45     }
     46 }
     47 
     48 VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
     49         const sp<IGraphicBufferProducer>& sink,
     50         const sp<IGraphicBufferProducer>& bqProducer,
     51         const sp<IGraphicBufferConsumer>& bqConsumer,
     52         const String8& name)
     53 :   ConsumerBase(bqConsumer),
     54     mHwc(hwc),
     55     mDisplayId(dispId),
     56     mDisplayName(name),
     57     mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
     58     mProducerSlotSource(0),
     59     mDbgState(DBG_STATE_IDLE),
     60     mDbgLastCompositionType(COMPOSITION_UNKNOWN),
     61     mMustRecompose(false)
     62 {
     63     mSource[SOURCE_SINK] = sink;
     64     mSource[SOURCE_SCRATCH] = bqProducer;
     65 
     66     resetPerFrameState();
     67 
     68     int sinkWidth, sinkHeight;
     69     sink->query(NATIVE_WINDOW_WIDTH, &sinkWidth);
     70     sink->query(NATIVE_WINDOW_HEIGHT, &sinkHeight);
     71     mSinkBufferWidth = sinkWidth;
     72     mSinkBufferHeight = sinkHeight;
     73 
     74     // Pick the buffer format to request from the sink when not rendering to it
     75     // with GLES. If the consumer needs CPU access, use the default format
     76     // set by the consumer. Otherwise allow gralloc to decide the format based
     77     // on usage bits.
     78     int sinkUsage;
     79     sink->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &sinkUsage);
     80     if (sinkUsage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) {
     81         int sinkFormat;
     82         sink->query(NATIVE_WINDOW_FORMAT, &sinkFormat);
     83         mDefaultOutputFormat = sinkFormat;
     84     } else {
     85         mDefaultOutputFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
     86     }
     87     mOutputFormat = mDefaultOutputFormat;
     88 
     89     ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.string());
     90     mConsumer->setConsumerName(ConsumerBase::mName);
     91     mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
     92     mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight);
     93     mConsumer->setDefaultMaxBufferCount(2);
     94 }
     95 
     96 VirtualDisplaySurface::~VirtualDisplaySurface() {
     97 }
     98 
     99 status_t VirtualDisplaySurface::beginFrame(bool mustRecompose) {
    100     if (mDisplayId < 0)
    101         return NO_ERROR;
    102 
    103     mMustRecompose = mustRecompose;
    104 
    105     VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE,
    106             "Unexpected beginFrame() in %s state", dbgStateStr());
    107     mDbgState = DBG_STATE_BEGUN;
    108 
    109     return refreshOutputBuffer();
    110 }
    111 
    112 status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) {
    113     if (mDisplayId < 0)
    114         return NO_ERROR;
    115 
    116     VDS_LOGW_IF(mDbgState != DBG_STATE_BEGUN,
    117             "Unexpected prepareFrame() in %s state", dbgStateStr());
    118     mDbgState = DBG_STATE_PREPARED;
    119 
    120     mCompositionType = compositionType;
    121     if (sForceHwcCopy && mCompositionType == COMPOSITION_GLES) {
    122         // Some hardware can do RGB->YUV conversion more efficiently in hardware
    123         // controlled by HWC than in hardware controlled by the video encoder.
    124         // Forcing GLES-composed frames to go through an extra copy by the HWC
    125         // allows the format conversion to happen there, rather than passing RGB
    126         // directly to the consumer.
    127         //
    128         // On the other hand, when the consumer prefers RGB or can consume RGB
    129         // inexpensively, this forces an unnecessary copy.
    130         mCompositionType = COMPOSITION_MIXED;
    131     }
    132 
    133     if (mCompositionType != mDbgLastCompositionType) {
    134         VDS_LOGV("prepareFrame: composition type changed to %s",
    135                 dbgCompositionTypeStr(mCompositionType));
    136         mDbgLastCompositionType = mCompositionType;
    137     }
    138 
    139     if (mCompositionType != COMPOSITION_GLES &&
    140             (mOutputFormat != mDefaultOutputFormat ||
    141              mOutputUsage != GRALLOC_USAGE_HW_COMPOSER)) {
    142         // We must have just switched from GLES-only to MIXED or HWC
    143         // composition. Stop using the format and usage requested by the GLES
    144         // driver; they may be suboptimal when HWC is writing to the output
    145         // buffer. For example, if the output is going to a video encoder, and
    146         // HWC can write directly to YUV, some hardware can skip a
    147         // memory-to-memory RGB-to-YUV conversion step.
    148         //
    149         // If we just switched *to* GLES-only mode, we'll change the
    150         // format/usage and get a new buffer when the GLES driver calls
    151         // dequeueBuffer().
    152         mOutputFormat = mDefaultOutputFormat;
    153         mOutputUsage = GRALLOC_USAGE_HW_COMPOSER;
    154         refreshOutputBuffer();
    155     }
    156 
    157     return NO_ERROR;
    158 }
    159 
    160 status_t VirtualDisplaySurface::compositionComplete() {
    161     return NO_ERROR;
    162 }
    163 
    164 status_t VirtualDisplaySurface::advanceFrame() {
    165     if (mDisplayId < 0)
    166         return NO_ERROR;
    167 
    168     if (mCompositionType == COMPOSITION_HWC) {
    169         VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
    170                 "Unexpected advanceFrame() in %s state on HWC frame",
    171                 dbgStateStr());
    172     } else {
    173         VDS_LOGW_IF(mDbgState != DBG_STATE_GLES_DONE,
    174                 "Unexpected advanceFrame() in %s state on GLES/MIXED frame",
    175                 dbgStateStr());
    176     }
    177     mDbgState = DBG_STATE_HWC;
    178 
    179     if (mOutputProducerSlot < 0 ||
    180             (mCompositionType != COMPOSITION_HWC && mFbProducerSlot < 0)) {
    181         // Last chance bailout if something bad happened earlier. For example,
    182         // in a GLES configuration, if the sink disappears then dequeueBuffer
    183         // will fail, the GLES driver won't queue a buffer, but SurfaceFlinger
    184         // will soldier on. So we end up here without a buffer. There should
    185         // be lots of scary messages in the log just before this.
    186         VDS_LOGE("advanceFrame: no buffer, bailing out");
    187         return NO_MEMORY;
    188     }
    189 
    190     sp<GraphicBuffer> fbBuffer = mFbProducerSlot >= 0 ?
    191             mProducerBuffers[mFbProducerSlot] : sp<GraphicBuffer>(NULL);
    192     sp<GraphicBuffer> outBuffer = mProducerBuffers[mOutputProducerSlot];
    193     VDS_LOGV("advanceFrame: fb=%d(%p) out=%d(%p)",
    194             mFbProducerSlot, fbBuffer.get(),
    195             mOutputProducerSlot, outBuffer.get());
    196 
    197     // At this point we know the output buffer acquire fence,
    198     // so update HWC state with it.
    199     mHwc.setOutputBuffer(mDisplayId, mOutputFence, outBuffer);
    200 
    201     status_t result = NO_ERROR;
    202     if (fbBuffer != NULL) {
    203         result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
    204     }
    205 
    206     return result;
    207 }
    208 
    209 void VirtualDisplaySurface::onFrameCommitted() {
    210     if (mDisplayId < 0)
    211         return;
    212 
    213     VDS_LOGW_IF(mDbgState != DBG_STATE_HWC,
    214             "Unexpected onFrameCommitted() in %s state", dbgStateStr());
    215     mDbgState = DBG_STATE_IDLE;
    216 
    217     sp<Fence> fbFence = mHwc.getAndResetReleaseFence(mDisplayId);
    218     if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) {
    219         // release the scratch buffer back to the pool
    220         Mutex::Autolock lock(mMutex);
    221         int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot);
    222         VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot);
    223         addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], fbFence);
    224         releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot],
    225                 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
    226     }
    227 
    228     if (mOutputProducerSlot >= 0) {
    229         int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot);
    230         QueueBufferOutput qbo;
    231         sp<Fence> outFence = mHwc.getLastRetireFence(mDisplayId);
    232         VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot);
    233         if (mMustRecompose) {
    234             status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot,
    235                     QueueBufferInput(
    236                         systemTime(), false /* isAutoTimestamp */,
    237                         Rect(mSinkBufferWidth, mSinkBufferHeight),
    238                         NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */,
    239                         true /* async*/,
    240                         outFence),
    241                     &qbo);
    242             if (result == NO_ERROR) {
    243                 updateQueueBufferOutput(qbo);
    244             }
    245         } else {
    246             // If the surface hadn't actually been updated, then we only went
    247             // through the motions of updating the display to keep our state
    248             // machine happy. We cancel the buffer to avoid triggering another
    249             // re-composition and causing an infinite loop.
    250             mSource[SOURCE_SINK]->cancelBuffer(sslot, outFence);
    251         }
    252     }
    253 
    254     resetPerFrameState();
    255 }
    256 
    257 void VirtualDisplaySurface::dump(String8& /* result */) const {
    258 }
    259 
    260 void VirtualDisplaySurface::resizeBuffers(const uint32_t w, const uint32_t h) {
    261     uint32_t tmpW, tmpH, transformHint, numPendingBuffers;
    262     mQueueBufferOutput.deflate(&tmpW, &tmpH, &transformHint, &numPendingBuffers);
    263     mQueueBufferOutput.inflate(w, h, transformHint, numPendingBuffers);
    264 
    265     mSinkBufferWidth = w;
    266     mSinkBufferHeight = h;
    267 }
    268 
    269 status_t VirtualDisplaySurface::requestBuffer(int pslot,
    270         sp<GraphicBuffer>* outBuf) {
    271     if (mDisplayId < 0)
    272         return mSource[SOURCE_SINK]->requestBuffer(pslot, outBuf);
    273 
    274     VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
    275             "Unexpected requestBuffer pslot=%d in %s state",
    276             pslot, dbgStateStr());
    277 
    278     *outBuf = mProducerBuffers[pslot];
    279     return NO_ERROR;
    280 }
    281 
    282 status_t VirtualDisplaySurface::setBufferCount(int bufferCount) {
    283     return mSource[SOURCE_SINK]->setBufferCount(bufferCount);
    284 }
    285 
    286 status_t VirtualDisplaySurface::dequeueBuffer(Source source,
    287         uint32_t format, uint32_t usage, int* sslot, sp<Fence>* fence) {
    288     LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId);
    289     // Don't let a slow consumer block us
    290     bool async = (source == SOURCE_SINK);
    291 
    292     status_t result = mSource[source]->dequeueBuffer(sslot, fence, async,
    293             mSinkBufferWidth, mSinkBufferHeight, format, usage);
    294     if (result < 0)
    295         return result;
    296     int pslot = mapSource2ProducerSlot(source, *sslot);
    297     VDS_LOGV("dequeueBuffer(%s): sslot=%d pslot=%d result=%d",
    298             dbgSourceStr(source), *sslot, pslot, result);
    299     uint64_t sourceBit = static_cast<uint64_t>(source) << pslot;
    300 
    301     if ((mProducerSlotSource & (1ULL << pslot)) != sourceBit) {
    302         // This slot was previously dequeued from the other source; must
    303         // re-request the buffer.
    304         result |= BUFFER_NEEDS_REALLOCATION;
    305         mProducerSlotSource &= ~(1ULL << pslot);
    306         mProducerSlotSource |= sourceBit;
    307     }
    308 
    309     if (result & RELEASE_ALL_BUFFERS) {
    310         for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
    311             if ((mProducerSlotSource & (1ULL << i)) == sourceBit)
    312                 mProducerBuffers[i].clear();
    313         }
    314     }
    315     if (result & BUFFER_NEEDS_REALLOCATION) {
    316         result = mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]);
    317         if (result < 0) {
    318             mProducerBuffers[pslot].clear();
    319             mSource[source]->cancelBuffer(*sslot, *fence);
    320             return result;
    321         }
    322         VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#x",
    323                 dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(),
    324                 mProducerBuffers[pslot]->getPixelFormat(),
    325                 mProducerBuffers[pslot]->getUsage());
    326     }
    327 
    328     return result;
    329 }
    330 
    331 status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, bool async,
    332         uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
    333     if (mDisplayId < 0)
    334         return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, async, w, h, format, usage);
    335 
    336     VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
    337             "Unexpected dequeueBuffer() in %s state", dbgStateStr());
    338     mDbgState = DBG_STATE_GLES;
    339 
    340     VDS_LOGW_IF(!async, "EGL called dequeueBuffer with !async despite eglSwapInterval(0)");
    341     VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage);
    342 
    343     status_t result = NO_ERROR;
    344     Source source = fbSourceForCompositionType(mCompositionType);
    345 
    346     if (source == SOURCE_SINK) {
    347 
    348         if (mOutputProducerSlot < 0) {
    349             // Last chance bailout if something bad happened earlier. For example,
    350             // in a GLES configuration, if the sink disappears then dequeueBuffer
    351             // will fail, the GLES driver won't queue a buffer, but SurfaceFlinger
    352             // will soldier on. So we end up here without a buffer. There should
    353             // be lots of scary messages in the log just before this.
    354             VDS_LOGE("dequeueBuffer: no buffer, bailing out");
    355             return NO_MEMORY;
    356         }
    357 
    358         // We already dequeued the output buffer. If the GLES driver wants
    359         // something incompatible, we have to cancel and get a new one. This
    360         // will mean that HWC will see a different output buffer between
    361         // prepare and set, but since we're in GLES-only mode already it
    362         // shouldn't matter.
    363 
    364         usage |= GRALLOC_USAGE_HW_COMPOSER;
    365         const sp<GraphicBuffer>& buf = mProducerBuffers[mOutputProducerSlot];
    366         if ((usage & ~buf->getUsage()) != 0 ||
    367                 (format != 0 && format != (uint32_t)buf->getPixelFormat()) ||
    368                 (w != 0 && w != mSinkBufferWidth) ||
    369                 (h != 0 && h != mSinkBufferHeight)) {
    370             VDS_LOGV("dequeueBuffer: dequeueing new output buffer: "
    371                     "want %dx%d fmt=%d use=%#x, "
    372                     "have %dx%d fmt=%d use=%#x",
    373                     w, h, format, usage,
    374                     mSinkBufferWidth, mSinkBufferHeight,
    375                     buf->getPixelFormat(), buf->getUsage());
    376             mOutputFormat = format;
    377             mOutputUsage = usage;
    378             result = refreshOutputBuffer();
    379             if (result < 0)
    380                 return result;
    381         }
    382     }
    383 
    384     if (source == SOURCE_SINK) {
    385         *pslot = mOutputProducerSlot;
    386         *fence = mOutputFence;
    387     } else {
    388         int sslot;
    389         result = dequeueBuffer(source, format, usage, &sslot, fence);
    390         if (result >= 0) {
    391             *pslot = mapSource2ProducerSlot(source, sslot);
    392         }
    393     }
    394     return result;
    395 }
    396 
    397 status_t VirtualDisplaySurface::detachBuffer(int /* slot */) {
    398     VDS_LOGE("detachBuffer is not available for VirtualDisplaySurface");
    399     return INVALID_OPERATION;
    400 }
    401 
    402 status_t VirtualDisplaySurface::detachNextBuffer(
    403         sp<GraphicBuffer>* /* outBuffer */, sp<Fence>* /* outFence */) {
    404     VDS_LOGE("detachNextBuffer is not available for VirtualDisplaySurface");
    405     return INVALID_OPERATION;
    406 }
    407 
    408 status_t VirtualDisplaySurface::attachBuffer(int* /* outSlot */,
    409         const sp<GraphicBuffer>& /* buffer */) {
    410     VDS_LOGE("attachBuffer is not available for VirtualDisplaySurface");
    411     return INVALID_OPERATION;
    412 }
    413 
    414 status_t VirtualDisplaySurface::queueBuffer(int pslot,
    415         const QueueBufferInput& input, QueueBufferOutput* output) {
    416     if (mDisplayId < 0)
    417         return mSource[SOURCE_SINK]->queueBuffer(pslot, input, output);
    418 
    419     VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
    420             "Unexpected queueBuffer(pslot=%d) in %s state", pslot,
    421             dbgStateStr());
    422     mDbgState = DBG_STATE_GLES_DONE;
    423 
    424     VDS_LOGV("queueBuffer pslot=%d", pslot);
    425 
    426     status_t result;
    427     if (mCompositionType == COMPOSITION_MIXED) {
    428         // Queue the buffer back into the scratch pool
    429         QueueBufferOutput scratchQBO;
    430         int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, pslot);
    431         result = mSource[SOURCE_SCRATCH]->queueBuffer(sslot, input, &scratchQBO);
    432         if (result != NO_ERROR)
    433             return result;
    434 
    435         // Now acquire the buffer from the scratch pool -- should be the same
    436         // slot and fence as we just queued.
    437         Mutex::Autolock lock(mMutex);
    438         BufferQueue::BufferItem item;
    439         result = acquireBufferLocked(&item, 0);
    440         if (result != NO_ERROR)
    441             return result;
    442         VDS_LOGW_IF(item.mBuf != sslot,
    443                 "queueBuffer: acquired sslot %d from SCRATCH after queueing sslot %d",
    444                 item.mBuf, sslot);
    445         mFbProducerSlot = mapSource2ProducerSlot(SOURCE_SCRATCH, item.mBuf);
    446         mFbFence = mSlots[item.mBuf].mFence;
    447 
    448     } else {
    449         LOG_FATAL_IF(mCompositionType != COMPOSITION_GLES,
    450                 "Unexpected queueBuffer in state %s for compositionType %s",
    451                 dbgStateStr(), dbgCompositionTypeStr(mCompositionType));
    452 
    453         // Extract the GLES release fence for HWC to acquire
    454         int64_t timestamp;
    455         bool isAutoTimestamp;
    456         Rect crop;
    457         int scalingMode;
    458         uint32_t transform;
    459         bool async;
    460         input.deflate(&timestamp, &isAutoTimestamp, &crop, &scalingMode,
    461                 &transform, &async, &mFbFence);
    462 
    463         mFbProducerSlot = pslot;
    464         mOutputFence = mFbFence;
    465     }
    466 
    467     *output = mQueueBufferOutput;
    468     return NO_ERROR;
    469 }
    470 
    471 void VirtualDisplaySurface::cancelBuffer(int pslot, const sp<Fence>& fence) {
    472     if (mDisplayId < 0)
    473         return mSource[SOURCE_SINK]->cancelBuffer(mapProducer2SourceSlot(SOURCE_SINK, pslot), fence);
    474 
    475     VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
    476             "Unexpected cancelBuffer(pslot=%d) in %s state", pslot,
    477             dbgStateStr());
    478     VDS_LOGV("cancelBuffer pslot=%d", pslot);
    479     Source source = fbSourceForCompositionType(mCompositionType);
    480     return mSource[source]->cancelBuffer(
    481             mapProducer2SourceSlot(source, pslot), fence);
    482 }
    483 
    484 int VirtualDisplaySurface::query(int what, int* value) {
    485     switch (what) {
    486         case NATIVE_WINDOW_WIDTH:
    487             *value = mSinkBufferWidth;
    488             break;
    489         case NATIVE_WINDOW_HEIGHT:
    490             *value = mSinkBufferHeight;
    491             break;
    492         default:
    493             return mSource[SOURCE_SINK]->query(what, value);
    494     }
    495     return NO_ERROR;
    496 }
    497 
    498 status_t VirtualDisplaySurface::connect(const sp<IProducerListener>& listener,
    499         int api, bool producerControlledByApp,
    500         QueueBufferOutput* output) {
    501     QueueBufferOutput qbo;
    502     status_t result = mSource[SOURCE_SINK]->connect(listener, api,
    503             producerControlledByApp, &qbo);
    504     if (result == NO_ERROR) {
    505         updateQueueBufferOutput(qbo);
    506         *output = mQueueBufferOutput;
    507     }
    508     return result;
    509 }
    510 
    511 status_t VirtualDisplaySurface::disconnect(int api) {
    512     return mSource[SOURCE_SINK]->disconnect(api);
    513 }
    514 
    515 status_t VirtualDisplaySurface::setSidebandStream(const sp<NativeHandle>& /*stream*/) {
    516     return INVALID_OPERATION;
    517 }
    518 
    519 void VirtualDisplaySurface::allocateBuffers(bool /* async */,
    520         uint32_t /* width */, uint32_t /* height */, uint32_t /* format */,
    521         uint32_t /* usage */) {
    522     // TODO: Should we actually allocate buffers for a virtual display?
    523 }
    524 
    525 void VirtualDisplaySurface::updateQueueBufferOutput(
    526         const QueueBufferOutput& qbo) {
    527     uint32_t w, h, transformHint, numPendingBuffers;
    528     qbo.deflate(&w, &h, &transformHint, &numPendingBuffers);
    529     mQueueBufferOutput.inflate(w, h, 0, numPendingBuffers);
    530 }
    531 
    532 void VirtualDisplaySurface::resetPerFrameState() {
    533     mCompositionType = COMPOSITION_UNKNOWN;
    534     mFbFence = Fence::NO_FENCE;
    535     mOutputFence = Fence::NO_FENCE;
    536     mOutputProducerSlot = -1;
    537     mFbProducerSlot = -1;
    538 }
    539 
    540 status_t VirtualDisplaySurface::refreshOutputBuffer() {
    541     if (mOutputProducerSlot >= 0) {
    542         mSource[SOURCE_SINK]->cancelBuffer(
    543                 mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot),
    544                 mOutputFence);
    545     }
    546 
    547     int sslot;
    548     status_t result = dequeueBuffer(SOURCE_SINK, mOutputFormat, mOutputUsage,
    549             &sslot, &mOutputFence);
    550     if (result < 0)
    551         return result;
    552     mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot);
    553 
    554     // On GLES-only frames, we don't have the right output buffer acquire fence
    555     // until after GLES calls queueBuffer(). So here we just set the buffer
    556     // (for use in HWC prepare) but not the fence; we'll call this again with
    557     // the proper fence once we have it.
    558     result = mHwc.setOutputBuffer(mDisplayId, Fence::NO_FENCE,
    559             mProducerBuffers[mOutputProducerSlot]);
    560 
    561     return result;
    562 }
    563 
    564 // This slot mapping function is its own inverse, so two copies are unnecessary.
    565 // Both are kept to make the intent clear where the function is called, and for
    566 // the (unlikely) chance that we switch to a different mapping function.
    567 int VirtualDisplaySurface::mapSource2ProducerSlot(Source source, int sslot) {
    568     if (source == SOURCE_SCRATCH) {
    569         return BufferQueue::NUM_BUFFER_SLOTS - sslot - 1;
    570     } else {
    571         return sslot;
    572     }
    573 }
    574 int VirtualDisplaySurface::mapProducer2SourceSlot(Source source, int pslot) {
    575     return mapSource2ProducerSlot(source, pslot);
    576 }
    577 
    578 VirtualDisplaySurface::Source
    579 VirtualDisplaySurface::fbSourceForCompositionType(CompositionType type) {
    580     return type == COMPOSITION_MIXED ? SOURCE_SCRATCH : SOURCE_SINK;
    581 }
    582 
    583 const char* VirtualDisplaySurface::dbgStateStr() const {
    584     switch (mDbgState) {
    585         case DBG_STATE_IDLE:      return "IDLE";
    586         case DBG_STATE_PREPARED:  return "PREPARED";
    587         case DBG_STATE_GLES:      return "GLES";
    588         case DBG_STATE_GLES_DONE: return "GLES_DONE";
    589         case DBG_STATE_HWC:       return "HWC";
    590         default:                  return "INVALID";
    591     }
    592 }
    593 
    594 const char* VirtualDisplaySurface::dbgSourceStr(Source s) {
    595     switch (s) {
    596         case SOURCE_SINK:    return "SINK";
    597         case SOURCE_SCRATCH: return "SCRATCH";
    598         default:             return "INVALID";
    599     }
    600 }
    601 
    602 // ---------------------------------------------------------------------------
    603 } // namespace android
    604 // ---------------------------------------------------------------------------
    605