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