/* * 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_VIRTUAL_DISPLAY_SURFACE_H #define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H #include #include #include #include #include #include #include #include "DisplayIdentification.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class HWComposer; class IProducerListener; /* This DisplaySurface implementation supports virtual displays, where GPU * 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 GPU 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: GPU-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 GPU-only composition, the GPU driver is given a buffer from the sink to * render into. When the GPU 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 GPU * 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 compositionengine::DisplaySurface, public BnGraphicBufferProducer, private ConsumerBase { public: VirtualDisplaySurface(HWComposer&, VirtualDisplayId, const sp& sink, const sp& bqProducer, const sp& bqConsumer, const std::string& name); // // DisplaySurface interface // virtual status_t beginFrame(bool mustRecompose); virtual status_t prepareFrame(CompositionType); virtual status_t advanceFrame(); virtual void onFrameCommitted(); virtual void dumpAsString(String8& result) const; virtual void resizeBuffers(const ui::Size&) override; virtual const sp& getClientTargetAcquireFence() const override; private: enum Source {SOURCE_SINK = 0, SOURCE_SCRATCH = 1}; virtual ~VirtualDisplaySurface(); // // IGraphicBufferProducer interface, used by the GPU driver. // virtual status_t requestBuffer(int pslot, sp* outBuf); virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); virtual status_t setAsyncMode(bool async); virtual status_t dequeueBuffer(int* pslot, sp*, uint32_t w, uint32_t h, PixelFormat, uint64_t usage, uint64_t* outBufferAge, FrameEventHistoryDelta* outTimestamps); virtual status_t detachBuffer(int slot); virtual status_t detachNextBuffer(sp* outBuffer, sp* outFence); virtual status_t attachBuffer(int* slot, const sp&); virtual status_t queueBuffer(int pslot, const QueueBufferInput&, QueueBufferOutput*); virtual status_t cancelBuffer(int pslot, const sp&); virtual int query(int what, int* value); virtual status_t connect(const sp&, int api, bool producerControlledByApp, QueueBufferOutput*); virtual status_t disconnect(int api, DisconnectMode); virtual status_t setSidebandStream(const sp& stream); virtual void allocateBuffers(uint32_t width, uint32_t height, PixelFormat, uint64_t usage); virtual status_t allowAllocation(bool allow); virtual status_t setGenerationNumber(uint32_t); virtual String8 getConsumerName() const override; virtual status_t setSharedBufferMode(bool sharedBufferMode) override; virtual status_t setAutoRefresh(bool autoRefresh) override; virtual status_t setDequeueTimeout(nsecs_t timeout) override; virtual status_t getLastQueuedBuffer(sp* outBuffer, sp* outFence, float outTransformMatrix[16]) override; virtual status_t getUniqueId(uint64_t* outId) const override; virtual status_t getConsumerUsage(uint64_t* outUsage) const override; // // Utility methods // static Source fbSourceForCompositionType(CompositionType); status_t dequeueBuffer(Source, PixelFormat, uint64_t usage, int* sslot, sp*); void updateQueueBufferOutput(QueueBufferOutput&&); void resetPerFrameState(); status_t refreshOutputBuffer(); // 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 graphics 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, int sslot); static int mapProducer2SourceSlot(Source, int pslot); // // Immutable after construction // HWComposer& mHwc; const VirtualDisplayId mDisplayId; const std::string mDisplayName; sp mSource[2]; // indexed by SOURCE_* uint32_t mDefaultOutputFormat; // // Inter-frame state // // To avoid buffer reallocations, we track the buffer usage and format // we used on the previous frame and use it again on the new frame. If // the composition type changes or the GPU driver starts requesting // different usage/format, we'll get a new buffer. uint32_t mOutputFormat; uint64_t mOutputUsage; // Since we present a single producer interface to the GPU 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 mProducerSlotSource corresponds to a producer // slot. Both mProducerSlotSource and mProducerBuffers are indexed by a // "producer slot"; see the mapSlot*() functions. uint64_t mProducerSlotSource; sp mProducerBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS]; // Need to propagate reallocation to VDS consumer. // Each bit corresponds to a producer slot. uint64_t mProducerSlotNeedReallocation; // The QueueBufferOutput with the latest info from the sink, and with the // transform hint cleared. Since we defer queueBuffer from the GPU driver // to the sink, we have to return the previous version. // Moves instead of copies are performed to avoid duplicate // FrameEventHistoryDeltas. QueueBufferOutput mQueueBufferOutput; // 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; // // Intra-frame state // // Composition type and graphics buffer source for the current frame. // Valid after prepareFrame(), cleared in onFrameCommitted. CompositionType mCompositionType; // mFbFence is the fence HWC should wait for before reading the framebuffer // target buffer. sp mFbFence; // mOutputFence is the fence HWC should wait for before writing to the // output buffer. sp mOutputFence; // 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 | beginFrame || BEGUN | // | BEGUN | prepareFrame || PREPARED | // | PREPARED | dequeueBuffer [1] || GPU | // | PREPARED | advanceFrame [2] || HWC | // | GPU | queueBuffer || GPU_DONE | // | GPU_DONE | advanceFrame || HWC | // | HWC | onFrameCommitted || IDLE | // +-----------+-------------------++------------+ // [1] COMPOSITION_GPU and COMPOSITION_MIXED frames. // [2] COMPOSITION_HWC frames. // enum DbgState { // no buffer dequeued, don't know anything about the next frame DBG_STATE_IDLE, // output buffer dequeued, framebuffer source not yet known DBG_STATE_BEGUN, // output buffer dequeued, framebuffer source known but not provided // to GPU yet. DBG_STATE_PREPARED, // GPU driver has a buffer dequeued DBG_STATE_GPU, // GPU driver has queued the buffer, we haven't sent it to HWC yet DBG_STATE_GPU_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); bool mMustRecompose; compositionengine::impl::HwcBufferCache mHwcBufferCache; bool mForceHwcCopy; }; // --------------------------------------------------------------------------- } // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H