| /* |
| * 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 <gui/ConsumerBase.h> |
| #include <gui/IGraphicBufferProducer.h> |
| |
| #include "DisplaySurface.h" |
| |
| // --------------------------------------------------------------------------- |
| namespace android { |
| // --------------------------------------------------------------------------- |
| |
| class HWComposer; |
| |
| /* 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, |
| public BnGraphicBufferProducer, |
| private ConsumerBase { |
| public: |
| VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, |
| const sp<IGraphicBufferProducer>& sink, |
| const sp<BufferQueue>& bq, |
| const String8& name); |
| |
| // |
| // DisplaySurface interface |
| // |
| virtual status_t beginFrame(bool mustRecompose); |
| 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(); |
| |
| // |
| // 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, bool async, |
| uint32_t w, uint32_t h, uint32_t format, uint32_t usage); |
| virtual status_t detachBuffer(int slot); |
| virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer); |
| 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 connect(const sp<IBinder>& token, |
| int api, bool producerControlledByApp, QueueBufferOutput* output); |
| virtual status_t disconnect(int api); |
| |
| // |
| // Utility methods |
| // |
| static Source fbSourceForCompositionType(CompositionType type); |
| status_t dequeueBuffer(Source source, uint32_t format, uint32_t usage, |
| int* sslot, sp<Fence>* fence); |
| void updateQueueBufferOutput(const QueueBufferOutput& qbo); |
| 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 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_* |
| 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 GLES driver starts requesting |
| // different usage/format, we'll get a new buffer. |
| uint32_t mOutputFormat; |
| uint32_t mOutputUsage; |
| |
| // 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; |
| |
| // 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 |
| // 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] || 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, |
| // 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, |
| // 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); |
| |
| bool mMustRecompose; |
| }; |
| |
| // --------------------------------------------------------------------------- |
| } // namespace android |
| // --------------------------------------------------------------------------- |
| |
| #endif // ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H |
| |