replicant-frameworks_native/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
Jesse Hall 028dc8f2d7 Provide HWC prepare with a valid output buffer
We weren't dequeing and setting the output buffer until just before
set(). This didn't allow HWC to make decisions in prepare() based on
the output buffer format, dimensions, etc.

Now we dequeue the output buffer at the beginning of the composition
loop and provide it to HWC in prepare. In GLES-only rendering, we may
have to cancel the buffer and acquire a new one if GLES requests a
buffer with properties different than the one we already dequeued.

Bug: 10365313
Change-Id: I96b4b0a851920e4334ef05080d58097d46467ab8
2013-08-20 16:35:32 -07:00

229 lines
9.5 KiB
C++

/*
* 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();
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 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(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,
int* sslot, sp<Fence>* fence, bool async);
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_*
//
// Inter-frame state
//
// To avoid buffer reallocations, we track the buffer usage requested by
// the GLES driver in dequeueBuffer so we can use the same flags on
// HWC-only frames.
uint32_t mProducerUsage;
// 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);
};
// ---------------------------------------------------------------------------
} // namespace android
// ---------------------------------------------------------------------------
#endif // ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H