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 // TODO(b/129481165): remove the #pragma below and fix conversion issues
18 #pragma clang diagnostic push
19 #pragma clang diagnostic ignored "-Wconversion"
20 
21 // #define LOG_NDEBUG 0
22 
23 #include <cinttypes>
24 
25 #include <ftl/enum.h>
26 #include <ftl/flags.h>
27 #include <gui/BufferItem.h>
28 #include <gui/BufferQueue.h>
29 #include <gui/IProducerListener.h>
30 #include <system/window.h>
31 
32 #include "HWComposer.h"
33 #include "SurfaceFlinger.h"
34 #include "VirtualDisplaySurface.h"
35 
36 #define VDS_LOGE(msg, ...) ALOGE("[%s] " msg, \
37         mDisplayName.c_str(), ##__VA_ARGS__)
38 #define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] " msg, \
39         mDisplayName.c_str(), ##__VA_ARGS__)
40 #define VDS_LOGV(msg, ...) ALOGV("[%s] " msg, \
41         mDisplayName.c_str(), ##__VA_ARGS__)
42 
43 #define UNSUPPORTED()                                               \
44     VDS_LOGE("%s: Invalid operation on virtual display", __func__); \
45     return INVALID_OPERATION
46 
47 namespace android {
48 
VirtualDisplaySurface(HWComposer & hwc,VirtualDisplayId displayId,const sp<IGraphicBufferProducer> & sink,const sp<IGraphicBufferProducer> & bqProducer,const sp<IGraphicBufferConsumer> & bqConsumer,const std::string & name)49 VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, VirtualDisplayId displayId,
50                                              const sp<IGraphicBufferProducer>& sink,
51                                              const sp<IGraphicBufferProducer>& bqProducer,
52                                              const sp<IGraphicBufferConsumer>& bqConsumer,
53                                              const std::string& name)
54       : ConsumerBase(bqConsumer),
55         mHwc(hwc),
56         mDisplayId(displayId),
57         mDisplayName(name),
58         mSource{},
59         mDefaultOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
60         mOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
61         mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
62         mProducerSlotSource(0),
63         mProducerBuffers(),
64         mProducerSlotNeedReallocation(0),
65         mQueueBufferOutput(),
66         mSinkBufferWidth(0),
67         mSinkBufferHeight(0),
68         mFbFence(Fence::NO_FENCE),
69         mOutputFence(Fence::NO_FENCE),
70         mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
71         mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
72         mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv) {
73     mSource[SOURCE_SINK] = sink;
74     mSource[SOURCE_SCRATCH] = bqProducer;
75 
76     resetPerFrameState();
77 
78     int sinkWidth, sinkHeight;
79     sink->query(NATIVE_WINDOW_WIDTH, &sinkWidth);
80     sink->query(NATIVE_WINDOW_HEIGHT, &sinkHeight);
81     mSinkBufferWidth = sinkWidth;
82     mSinkBufferHeight = sinkHeight;
83 
84     // Pick the buffer format to request from the sink when not rendering to it
85     // with GPU. If the consumer needs CPU access, use the default format
86     // set by the consumer. Otherwise allow gralloc to decide the format based
87     // on usage bits.
88     int sinkUsage;
89     sink->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &sinkUsage);
90     if (sinkUsage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) {
91         int sinkFormat;
92         sink->query(NATIVE_WINDOW_FORMAT, &sinkFormat);
93         mDefaultOutputFormat = sinkFormat;
94     } else {
95         mDefaultOutputFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
96     }
97     mOutputFormat = mDefaultOutputFormat;
98 
99     ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.c_str());
100     mConsumer->setConsumerName(ConsumerBase::mName);
101     mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
102     mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight);
103     sink->setAsyncMode(true);
104     IGraphicBufferProducer::QueueBufferOutput output;
105     mSource[SOURCE_SCRATCH]->connect(nullptr, NATIVE_WINDOW_API_EGL, false, &output);
106 
107     for (size_t i = 0; i < sizeof(mHwcBufferIds) / sizeof(mHwcBufferIds[0]); ++i) {
108         mHwcBufferIds[i] = UINT64_MAX;
109     }
110 }
111 
~VirtualDisplaySurface()112 VirtualDisplaySurface::~VirtualDisplaySurface() {
113     mSource[SOURCE_SCRATCH]->disconnect(NATIVE_WINDOW_API_EGL);
114 }
115 
beginFrame(bool mustRecompose)116 status_t VirtualDisplaySurface::beginFrame(bool mustRecompose) {
117     if (GpuVirtualDisplayId::tryCast(mDisplayId)) {
118         return NO_ERROR;
119     }
120 
121     mMustRecompose = mustRecompose;
122 
123     VDS_LOGW_IF(mDebugState != DebugState::Idle, "Unexpected %s in %s state", __func__,
124                 ftl::enum_string(mDebugState).c_str());
125     mDebugState = DebugState::Begun;
126 
127     return refreshOutputBuffer();
128 }
129 
prepareFrame(CompositionType compositionType)130 status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) {
131     if (GpuVirtualDisplayId::tryCast(mDisplayId)) {
132         return NO_ERROR;
133     }
134 
135     VDS_LOGW_IF(mDebugState != DebugState::Begun, "Unexpected %s in %s state", __func__,
136                 ftl::enum_string(mDebugState).c_str());
137     mDebugState = DebugState::Prepared;
138 
139     mCompositionType = compositionType;
140     if (mForceHwcCopy && mCompositionType == CompositionType::Gpu) {
141         // Some hardware can do RGB->YUV conversion more efficiently in hardware
142         // controlled by HWC than in hardware controlled by the video encoder.
143         // Forcing GPU-composed frames to go through an extra copy by the HWC
144         // allows the format conversion to happen there, rather than passing RGB
145         // directly to the consumer.
146         //
147         // On the other hand, when the consumer prefers RGB or can consume RGB
148         // inexpensively, this forces an unnecessary copy.
149         mCompositionType = CompositionType::Mixed;
150     }
151 
152     if (mCompositionType != mDebugLastCompositionType) {
153         VDS_LOGV("%s: composition type changed to %s", __func__,
154                  toString(mCompositionType).c_str());
155         mDebugLastCompositionType = mCompositionType;
156     }
157 
158     if (mCompositionType != CompositionType::Gpu &&
159         (mOutputFormat != mDefaultOutputFormat || mOutputUsage != GRALLOC_USAGE_HW_COMPOSER)) {
160         // We must have just switched from GPU-only to MIXED or HWC
161         // composition. Stop using the format and usage requested by the GPU
162         // driver; they may be suboptimal when HWC is writing to the output
163         // buffer. For example, if the output is going to a video encoder, and
164         // HWC can write directly to YUV, some hardware can skip a
165         // memory-to-memory RGB-to-YUV conversion step.
166         //
167         // If we just switched *to* GPU-only mode, we'll change the
168         // format/usage and get a new buffer when the GPU driver calls
169         // dequeueBuffer().
170         mOutputFormat = mDefaultOutputFormat;
171         mOutputUsage = GRALLOC_USAGE_HW_COMPOSER;
172         refreshOutputBuffer();
173     }
174 
175     return NO_ERROR;
176 }
177 
advanceFrame(float hdrSdrRatio)178 status_t VirtualDisplaySurface::advanceFrame(float hdrSdrRatio) {
179     if (GpuVirtualDisplayId::tryCast(mDisplayId)) {
180         return NO_ERROR;
181     }
182 
183     if (mCompositionType == CompositionType::Hwc) {
184         VDS_LOGW_IF(mDebugState != DebugState::Prepared, "Unexpected %s in %s state on HWC frame",
185                     __func__, ftl::enum_string(mDebugState).c_str());
186     } else {
187         VDS_LOGW_IF(mDebugState != DebugState::GpuDone,
188                     "Unexpected %s in %s state on GPU/MIXED frame", __func__,
189                     ftl::enum_string(mDebugState).c_str());
190     }
191     mDebugState = DebugState::Hwc;
192 
193     if (mOutputProducerSlot < 0 ||
194         (mCompositionType != CompositionType::Hwc && mFbProducerSlot < 0)) {
195         // Last chance bailout if something bad happened earlier. For example,
196         // in a graphics API configuration, if the sink disappears then dequeueBuffer
197         // will fail, the GPU driver won't queue a buffer, but SurfaceFlinger
198         // will soldier on. So we end up here without a buffer. There should
199         // be lots of scary messages in the log just before this.
200         VDS_LOGE("%s: no buffer, bailing out", __func__);
201         return NO_MEMORY;
202     }
203 
204     sp<GraphicBuffer> const& fbBuffer =
205             mFbProducerSlot >= 0 ? mProducerBuffers[mFbProducerSlot] : sp<GraphicBuffer>(nullptr);
206     sp<GraphicBuffer> const& outBuffer = mProducerBuffers[mOutputProducerSlot];
207     VDS_LOGV("%s: fb=%d(%p) out=%d(%p)", __func__, mFbProducerSlot, fbBuffer.get(),
208              mOutputProducerSlot, outBuffer.get());
209 
210     const auto halDisplayId = HalVirtualDisplayId::tryCast(mDisplayId);
211     LOG_FATAL_IF(!halDisplayId);
212     // At this point we know the output buffer acquire fence,
213     // so update HWC state with it.
214     mHwc.setOutputBuffer(*halDisplayId, mOutputFence, outBuffer);
215 
216     status_t result = NO_ERROR;
217     if (fbBuffer != nullptr) {
218         // assume that HWC has previously seen the buffer in this slot
219         sp<GraphicBuffer> hwcBuffer = sp<GraphicBuffer>(nullptr);
220         if (fbBuffer->getId() != mHwcBufferIds[mFbProducerSlot]) {
221             mHwcBufferIds[mFbProducerSlot] = fbBuffer->getId();
222             hwcBuffer = fbBuffer; // HWC hasn't previously seen this buffer in this slot
223         }
224         // TODO: Correctly propagate the dataspace from GL composition
225         result = mHwc.setClientTarget(*halDisplayId, mFbProducerSlot, mFbFence, hwcBuffer,
226                                       ui::Dataspace::UNKNOWN, hdrSdrRatio);
227     }
228 
229     return result;
230 }
231 
onFrameCommitted()232 void VirtualDisplaySurface::onFrameCommitted() {
233     const auto halDisplayId = HalVirtualDisplayId::tryCast(mDisplayId);
234     if (!halDisplayId) {
235         return;
236     }
237 
238     VDS_LOGW_IF(mDebugState != DebugState::Hwc, "Unexpected %s in %s state", __func__,
239                 ftl::enum_string(mDebugState).c_str());
240     mDebugState = DebugState::Idle;
241 
242     sp<Fence> retireFence = mHwc.getPresentFence(*halDisplayId);
243     if (mCompositionType == CompositionType::Mixed && mFbProducerSlot >= 0) {
244         // release the scratch buffer back to the pool
245         Mutex::Autolock lock(mMutex);
246         int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot);
247         VDS_LOGV("%s: release scratch sslot=%d", __func__, sslot);
248         addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot],
249                 retireFence);
250         releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot]);
251     }
252 
253     if (mOutputProducerSlot >= 0) {
254         int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot);
255         QueueBufferOutput qbo;
256         VDS_LOGV("%s: queue sink sslot=%d", __func__, sslot);
257         if (mMustRecompose) {
258             status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot,
259                     QueueBufferInput(
260                         systemTime(), false /* isAutoTimestamp */,
261                         HAL_DATASPACE_UNKNOWN,
262                         Rect(mSinkBufferWidth, mSinkBufferHeight),
263                         NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */,
264                         retireFence),
265                     &qbo);
266             if (result == NO_ERROR) {
267                 updateQueueBufferOutput(std::move(qbo));
268             }
269         } else {
270             // If the surface hadn't actually been updated, then we only went
271             // through the motions of updating the display to keep our state
272             // machine happy. We cancel the buffer to avoid triggering another
273             // re-composition and causing an infinite loop.
274             mSource[SOURCE_SINK]->cancelBuffer(sslot, retireFence);
275         }
276     }
277 
278     resetPerFrameState();
279 }
280 
dumpAsString(String8 &) const281 void VirtualDisplaySurface::dumpAsString(String8& /* result */) const {
282 }
283 
resizeBuffers(const ui::Size & newSize)284 void VirtualDisplaySurface::resizeBuffers(const ui::Size& newSize) {
285     mQueueBufferOutput.width = newSize.width;
286     mQueueBufferOutput.height = newSize.height;
287     mSinkBufferWidth = newSize.width;
288     mSinkBufferHeight = newSize.height;
289 }
290 
getClientTargetAcquireFence() const291 const sp<Fence>& VirtualDisplaySurface::getClientTargetAcquireFence() const {
292     return mFbFence;
293 }
294 
requestBuffer(int pslot,sp<GraphicBuffer> * outBuf)295 status_t VirtualDisplaySurface::requestBuffer(int pslot,
296         sp<GraphicBuffer>* outBuf) {
297     if (GpuVirtualDisplayId::tryCast(mDisplayId)) {
298         return mSource[SOURCE_SINK]->requestBuffer(pslot, outBuf);
299     }
300 
301     VDS_LOGW_IF(mDebugState != DebugState::Gpu, "Unexpected %s pslot=%d in %s state", __func__,
302                 pslot, ftl::enum_string(mDebugState).c_str());
303 
304     *outBuf = mProducerBuffers[pslot];
305     return NO_ERROR;
306 }
307 
setMaxDequeuedBufferCount(int maxDequeuedBuffers)308 status_t VirtualDisplaySurface::setMaxDequeuedBufferCount(
309         int maxDequeuedBuffers) {
310     return mSource[SOURCE_SINK]->setMaxDequeuedBufferCount(maxDequeuedBuffers);
311 }
312 
setAsyncMode(bool async)313 status_t VirtualDisplaySurface::setAsyncMode(bool async) {
314     return mSource[SOURCE_SINK]->setAsyncMode(async);
315 }
316 
dequeueBuffer(Source source,PixelFormat format,uint64_t usage,int * sslot,sp<Fence> * fence)317 status_t VirtualDisplaySurface::dequeueBuffer(Source source,
318         PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence) {
319     LOG_ALWAYS_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId).has_value());
320 
321     status_t result =
322             mSource[source]->dequeueBuffer(sslot, fence, mSinkBufferWidth, mSinkBufferHeight,
323                                            format, usage, nullptr, nullptr);
324     if (result < 0)
325         return result;
326     int pslot = mapSource2ProducerSlot(source, *sslot);
327     VDS_LOGV("%s(%s): sslot=%d pslot=%d result=%d", __func__, ftl::enum_string(source).c_str(),
328              *sslot, pslot, result);
329     uint64_t sourceBit = static_cast<uint64_t>(source) << pslot;
330 
331     // reset producer slot reallocation flag
332     mProducerSlotNeedReallocation &= ~(1ULL << pslot);
333 
334     if ((mProducerSlotSource & (1ULL << pslot)) != sourceBit) {
335         // This slot was previously dequeued from the other source; must
336         // re-request the buffer.
337         mProducerSlotNeedReallocation |= 1ULL << pslot;
338 
339         mProducerSlotSource &= ~(1ULL << pslot);
340         mProducerSlotSource |= sourceBit;
341     }
342 
343     if (result & RELEASE_ALL_BUFFERS) {
344         for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
345             if ((mProducerSlotSource & (1ULL << i)) == sourceBit)
346                 mProducerBuffers[i].clear();
347         }
348     }
349     if (result & BUFFER_NEEDS_REALLOCATION) {
350         result = mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]);
351         if (result < 0) {
352             mProducerBuffers[pslot].clear();
353             mSource[source]->cancelBuffer(*sslot, *fence);
354             return result;
355         }
356         VDS_LOGV("%s(%s): buffers[%d]=%p fmt=%d usage=%#" PRIx64, __func__,
357                  ftl::enum_string(source).c_str(), pslot, mProducerBuffers[pslot].get(),
358                  mProducerBuffers[pslot]->getPixelFormat(), mProducerBuffers[pslot]->getUsage());
359 
360         // propagate reallocation to VDS consumer
361         mProducerSlotNeedReallocation |= 1ULL << pslot;
362     }
363 
364     return result;
365 }
366 
dequeueBuffer(int * pslot,sp<Fence> * fence,uint32_t w,uint32_t h,PixelFormat format,uint64_t usage,uint64_t * outBufferAge,FrameEventHistoryDelta * outTimestamps)367 status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w, uint32_t h,
368                                               PixelFormat format, uint64_t usage,
369                                               uint64_t* outBufferAge,
370                                               FrameEventHistoryDelta* outTimestamps) {
371     if (GpuVirtualDisplayId::tryCast(mDisplayId)) {
372         return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, w, h, format, usage, outBufferAge,
373                                                    outTimestamps);
374     }
375 
376     VDS_LOGW_IF(mDebugState != DebugState::Prepared, "Unexpected %s in %s state", __func__,
377                 ftl::enum_string(mDebugState).c_str());
378     mDebugState = DebugState::Gpu;
379 
380     VDS_LOGV("%s %dx%d fmt=%d usage=%#" PRIx64, __func__, w, h, format, usage);
381 
382     status_t result = NO_ERROR;
383     Source source = fbSourceForCompositionType(mCompositionType);
384 
385     if (source == SOURCE_SINK) {
386 
387         if (mOutputProducerSlot < 0) {
388             // Last chance bailout if something bad happened earlier. For example,
389             // in a graphics API configuration, if the sink disappears then dequeueBuffer
390             // will fail, the GPU driver won't queue a buffer, but SurfaceFlinger
391             // will soldier on. So we end up here without a buffer. There should
392             // be lots of scary messages in the log just before this.
393             VDS_LOGE("%s: no buffer, bailing out", __func__);
394             return NO_MEMORY;
395         }
396 
397         // We already dequeued the output buffer. If the GPU driver wants
398         // something incompatible, we have to cancel and get a new one. This
399         // will mean that HWC will see a different output buffer between
400         // prepare and set, but since we're in GPU-only mode already it
401         // shouldn't matter.
402 
403         usage |= GRALLOC_USAGE_HW_COMPOSER;
404         const sp<GraphicBuffer>& buf = mProducerBuffers[mOutputProducerSlot];
405         if ((usage & ~buf->getUsage()) != 0 ||
406                 (format != 0 && format != buf->getPixelFormat()) ||
407                 (w != 0 && w != mSinkBufferWidth) ||
408                 (h != 0 && h != mSinkBufferHeight)) {
409             VDS_LOGV("%s: dequeueing new output buffer: "
410                      "want %dx%d fmt=%d use=%#" PRIx64 ", "
411                      "have %dx%d fmt=%d use=%#" PRIx64,
412                      __func__, w, h, format, usage, mSinkBufferWidth, mSinkBufferHeight,
413                      buf->getPixelFormat(), buf->getUsage());
414             mOutputFormat = format;
415             mOutputUsage = usage;
416             result = refreshOutputBuffer();
417             if (result < 0)
418                 return result;
419         }
420     }
421 
422     if (source == SOURCE_SINK) {
423         *pslot = mOutputProducerSlot;
424         *fence = mOutputFence;
425     } else {
426         int sslot;
427         result = dequeueBuffer(source, format, usage, &sslot, fence);
428         if (result >= 0) {
429             *pslot = mapSource2ProducerSlot(source, sslot);
430         }
431     }
432     if (outBufferAge) {
433         *outBufferAge = 0;
434     }
435 
436     if ((mProducerSlotNeedReallocation & (1ULL << *pslot)) != 0) {
437         result |= BUFFER_NEEDS_REALLOCATION;
438     }
439 
440     return result;
441 }
442 
detachBuffer(int)443 status_t VirtualDisplaySurface::detachBuffer(int) {
444     UNSUPPORTED();
445 }
446 
detachNextBuffer(sp<GraphicBuffer> *,sp<Fence> *)447 status_t VirtualDisplaySurface::detachNextBuffer(sp<GraphicBuffer>*, sp<Fence>*) {
448     UNSUPPORTED();
449 }
450 
attachBuffer(int *,const sp<GraphicBuffer> &)451 status_t VirtualDisplaySurface::attachBuffer(int*, const sp<GraphicBuffer>&) {
452     UNSUPPORTED();
453 }
454 
queueBuffer(int pslot,const QueueBufferInput & input,QueueBufferOutput * output)455 status_t VirtualDisplaySurface::queueBuffer(int pslot,
456         const QueueBufferInput& input, QueueBufferOutput* output) {
457     if (GpuVirtualDisplayId::tryCast(mDisplayId)) {
458         return mSource[SOURCE_SINK]->queueBuffer(pslot, input, output);
459     }
460 
461     VDS_LOGW_IF(mDebugState != DebugState::Gpu, "Unexpected %s(pslot=%d) in %s state", __func__,
462                 pslot, ftl::enum_string(mDebugState).c_str());
463     mDebugState = DebugState::GpuDone;
464 
465     VDS_LOGV("%s pslot=%d", __func__, pslot);
466 
467     status_t result;
468     if (mCompositionType == CompositionType::Mixed) {
469         // Queue the buffer back into the scratch pool
470         QueueBufferOutput scratchQBO;
471         int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, pslot);
472         result = mSource[SOURCE_SCRATCH]->queueBuffer(sslot, input, &scratchQBO);
473         if (result != NO_ERROR)
474             return result;
475 
476         // Now acquire the buffer from the scratch pool -- should be the same
477         // slot and fence as we just queued.
478         Mutex::Autolock lock(mMutex);
479         BufferItem item;
480         result = acquireBufferLocked(&item, 0);
481         if (result != NO_ERROR)
482             return result;
483         VDS_LOGW_IF(item.mSlot != sslot,
484                     "%s: acquired sslot %d from SCRATCH after queueing sslot %d", __func__,
485                     item.mSlot, sslot);
486         mFbProducerSlot = mapSource2ProducerSlot(SOURCE_SCRATCH, item.mSlot);
487         mFbFence = mSlots[item.mSlot].mFence;
488 
489     } else {
490         LOG_FATAL_IF(mCompositionType != CompositionType::Gpu,
491                      "Unexpected %s in state %s for composition type %s", __func__,
492                      ftl::enum_string(mDebugState).c_str(), toString(mCompositionType).c_str());
493 
494         // Extract the GPU release fence for HWC to acquire
495         int64_t timestamp;
496         bool isAutoTimestamp;
497         android_dataspace dataSpace;
498         Rect crop;
499         int scalingMode;
500         uint32_t transform;
501         input.deflate(&timestamp, &isAutoTimestamp, &dataSpace, &crop,
502                 &scalingMode, &transform, &mFbFence);
503 
504         mFbProducerSlot = pslot;
505         mOutputFence = mFbFence;
506     }
507 
508     // This moves the frame timestamps and keeps a copy of all other fields.
509     *output = std::move(mQueueBufferOutput);
510     return NO_ERROR;
511 }
512 
cancelBuffer(int pslot,const sp<Fence> & fence)513 status_t VirtualDisplaySurface::cancelBuffer(int pslot,
514         const sp<Fence>& fence) {
515     if (GpuVirtualDisplayId::tryCast(mDisplayId)) {
516         return mSource[SOURCE_SINK]->cancelBuffer(mapProducer2SourceSlot(SOURCE_SINK, pslot), fence);
517     }
518 
519     VDS_LOGW_IF(mDebugState != DebugState::Gpu, "Unexpected %s(pslot=%d) in %s state", __func__,
520                 pslot, ftl::enum_string(mDebugState).c_str());
521     VDS_LOGV("%s pslot=%d", __func__, pslot);
522     Source source = fbSourceForCompositionType(mCompositionType);
523     return mSource[source]->cancelBuffer(
524             mapProducer2SourceSlot(source, pslot), fence);
525 }
526 
query(int what,int * value)527 int VirtualDisplaySurface::query(int what, int* value) {
528     switch (what) {
529         case NATIVE_WINDOW_WIDTH:
530             *value = mSinkBufferWidth;
531             break;
532         case NATIVE_WINDOW_HEIGHT:
533             *value = mSinkBufferHeight;
534             break;
535         default:
536             return mSource[SOURCE_SINK]->query(what, value);
537     }
538     return NO_ERROR;
539 }
540 
connect(const sp<IProducerListener> & listener,int api,bool producerControlledByApp,QueueBufferOutput * output)541 status_t VirtualDisplaySurface::connect(const sp<IProducerListener>& listener,
542         int api, bool producerControlledByApp,
543         QueueBufferOutput* output) {
544     QueueBufferOutput qbo;
545     status_t result = mSource[SOURCE_SINK]->connect(listener, api,
546             producerControlledByApp, &qbo);
547     if (result == NO_ERROR) {
548         updateQueueBufferOutput(std::move(qbo));
549         // This moves the frame timestamps and keeps a copy of all other fields.
550         *output = std::move(mQueueBufferOutput);
551     }
552     return result;
553 }
554 
disconnect(int api,DisconnectMode mode)555 status_t VirtualDisplaySurface::disconnect(int api, DisconnectMode mode) {
556     return mSource[SOURCE_SINK]->disconnect(api, mode);
557 }
558 
setSidebandStream(const sp<NativeHandle> &)559 status_t VirtualDisplaySurface::setSidebandStream(const sp<NativeHandle>&) {
560     UNSUPPORTED();
561 }
562 
allocateBuffers(uint32_t,uint32_t,PixelFormat,uint64_t)563 void VirtualDisplaySurface::allocateBuffers(uint32_t /* width */,
564         uint32_t /* height */, PixelFormat /* format */, uint64_t /* usage */) {
565     // TODO: Should we actually allocate buffers for a virtual display?
566 }
567 
allowAllocation(bool)568 status_t VirtualDisplaySurface::allowAllocation(bool /* allow */) {
569     return INVALID_OPERATION;
570 }
571 
setGenerationNumber(uint32_t)572 status_t VirtualDisplaySurface::setGenerationNumber(uint32_t) {
573     UNSUPPORTED();
574 }
575 
getConsumerName() const576 String8 VirtualDisplaySurface::getConsumerName() const {
577     return String8("VirtualDisplaySurface");
578 }
579 
setSharedBufferMode(bool)580 status_t VirtualDisplaySurface::setSharedBufferMode(bool) {
581     UNSUPPORTED();
582 }
583 
setAutoRefresh(bool)584 status_t VirtualDisplaySurface::setAutoRefresh(bool) {
585     UNSUPPORTED();
586 }
587 
setDequeueTimeout(nsecs_t)588 status_t VirtualDisplaySurface::setDequeueTimeout(nsecs_t) {
589     UNSUPPORTED();
590 }
591 
getLastQueuedBuffer(sp<GraphicBuffer> *,sp<Fence> *,float[16])592 status_t VirtualDisplaySurface::getLastQueuedBuffer(sp<GraphicBuffer>*, sp<Fence>*, float[16]) {
593     UNSUPPORTED();
594 }
595 
getUniqueId(uint64_t *) const596 status_t VirtualDisplaySurface::getUniqueId(uint64_t*) const {
597     UNSUPPORTED();
598 }
599 
getConsumerUsage(uint64_t * outUsage) const600 status_t VirtualDisplaySurface::getConsumerUsage(uint64_t* outUsage) const {
601     return mSource[SOURCE_SINK]->getConsumerUsage(outUsage);
602 }
603 
updateQueueBufferOutput(QueueBufferOutput && qbo)604 void VirtualDisplaySurface::updateQueueBufferOutput(
605         QueueBufferOutput&& qbo) {
606     mQueueBufferOutput = std::move(qbo);
607     mQueueBufferOutput.transformHint = 0;
608 }
609 
resetPerFrameState()610 void VirtualDisplaySurface::resetPerFrameState() {
611     mCompositionType = CompositionType::Unknown;
612     mFbFence = Fence::NO_FENCE;
613     mOutputFence = Fence::NO_FENCE;
614     mOutputProducerSlot = -1;
615     mFbProducerSlot = -1;
616 }
617 
refreshOutputBuffer()618 status_t VirtualDisplaySurface::refreshOutputBuffer() {
619     LOG_ALWAYS_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId).has_value());
620 
621     if (mOutputProducerSlot >= 0) {
622         mSource[SOURCE_SINK]->cancelBuffer(
623                 mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot),
624                 mOutputFence);
625     }
626 
627     int sslot;
628     status_t result = dequeueBuffer(SOURCE_SINK, mOutputFormat, mOutputUsage,
629             &sslot, &mOutputFence);
630     if (result < 0)
631         return result;
632     mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot);
633 
634     // On GPU-only frames, we don't have the right output buffer acquire fence
635     // until after GPU calls queueBuffer(). So here we just set the buffer
636     // (for use in HWC prepare) but not the fence; we'll call this again with
637     // the proper fence once we have it.
638     const auto halDisplayId = HalVirtualDisplayId::tryCast(mDisplayId);
639     LOG_FATAL_IF(!halDisplayId);
640     result = mHwc.setOutputBuffer(*halDisplayId, Fence::NO_FENCE,
641                                   mProducerBuffers[mOutputProducerSlot]);
642 
643     return result;
644 }
645 
646 // This slot mapping function is its own inverse, so two copies are unnecessary.
647 // Both are kept to make the intent clear where the function is called, and for
648 // the (unlikely) chance that we switch to a different mapping function.
mapSource2ProducerSlot(Source source,int sslot)649 int VirtualDisplaySurface::mapSource2ProducerSlot(Source source, int sslot) {
650     if (source == SOURCE_SCRATCH) {
651         return BufferQueue::NUM_BUFFER_SLOTS - sslot - 1;
652     } else {
653         return sslot;
654     }
655 }
mapProducer2SourceSlot(Source source,int pslot)656 int VirtualDisplaySurface::mapProducer2SourceSlot(Source source, int pslot) {
657     return mapSource2ProducerSlot(source, pslot);
658 }
659 
fbSourceForCompositionType(CompositionType type)660 auto VirtualDisplaySurface::fbSourceForCompositionType(CompositionType type) -> Source {
661     return type == CompositionType::Mixed ? SOURCE_SCRATCH : SOURCE_SINK;
662 }
663 
toString(CompositionType type)664 std::string VirtualDisplaySurface::toString(CompositionType type) {
665     using namespace std::literals;
666     return type == CompositionType::Unknown ? "Unknown"s : ftl::Flags(type).string();
667 }
668 
669 } // namespace android
670 
671 // TODO(b/129481165): remove the #pragma below and fix conversion issues
672 #pragma clang diagnostic pop // ignored "-Wconversion"
673