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