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