blob: 90bfce7b349b1f85e2d1be4187104c0f5f02fb1e [file] [log] [blame]
Jesse Hall99c7dbb2013-03-14 14:29:29 -07001/*
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
Jesse Hall38efe862013-04-06 23:12:29 -070017// #define LOG_NDEBUG 0
Jesse Hall99c7dbb2013-03-14 14:29:29 -070018#include "VirtualDisplaySurface.h"
Jesse Hall38efe862013-04-06 23:12:29 -070019#include "HWComposer.h"
Jesse Hall99c7dbb2013-03-14 14:29:29 -070020
21// ---------------------------------------------------------------------------
22namespace android {
23// ---------------------------------------------------------------------------
24
Jesse Hall38efe862013-04-06 23:12:29 -070025#define VDS_LOGE(msg, ...) ALOGE("[%s] "msg, \
26 mDisplayName.string(), ##__VA_ARGS__)
27#define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] "msg, \
28 mDisplayName.string(), ##__VA_ARGS__)
29#define VDS_LOGV(msg, ...) ALOGV("[%s] "msg, \
30 mDisplayName.string(), ##__VA_ARGS__)
31
32static const char* dbgCompositionTypeStr(DisplaySurface::CompositionType type) {
33 switch (type) {
34 case DisplaySurface::COMPOSITION_UNKNOWN: return "UNKNOWN";
35 case DisplaySurface::COMPOSITION_GLES: return "GLES";
36 case DisplaySurface::COMPOSITION_HWC: return "HWC";
37 case DisplaySurface::COMPOSITION_MIXED: return "MIXED";
38 default: return "<INVALID>";
39 }
40}
41
Jesse Hallffe1f192013-03-22 15:13:48 -070042VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
Jesse Hall99c7dbb2013-03-14 14:29:29 -070043 const sp<IGraphicBufferProducer>& sink, const String8& name)
Jesse Hall38efe862013-04-06 23:12:29 -070044: ConsumerBase(new BufferQueue(true)),
45 mHwc(hwc),
46 mDisplayId(dispId),
47 mDisplayName(name),
48 mProducerUsage(GRALLOC_USAGE_HW_COMPOSER),
49 mProducerSlotSource(0),
50 mDbgState(DBG_STATE_IDLE),
51 mDbgLastCompositionType(COMPOSITION_UNKNOWN)
Jesse Hallffe1f192013-03-22 15:13:48 -070052{
Jesse Hall38efe862013-04-06 23:12:29 -070053 mSource[SOURCE_SINK] = sink;
54 mSource[SOURCE_SCRATCH] = mBufferQueue;
55
56 resetPerFrameState();
57
58 int sinkWidth, sinkHeight;
59 mSource[SOURCE_SINK]->query(NATIVE_WINDOW_WIDTH, &sinkWidth);
60 mSource[SOURCE_SINK]->query(NATIVE_WINDOW_HEIGHT, &sinkHeight);
61
62 ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.string());
63 mBufferQueue->setConsumerName(ConsumerBase::mName);
64 mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
65 mBufferQueue->setDefaultBufferSize(sinkWidth, sinkHeight);
66 mBufferQueue->setDefaultMaxBufferCount(2);
Jesse Hallffe1f192013-03-22 15:13:48 -070067}
Jesse Hall99c7dbb2013-03-14 14:29:29 -070068
69VirtualDisplaySurface::~VirtualDisplaySurface() {
70}
71
72sp<IGraphicBufferProducer> VirtualDisplaySurface::getIGraphicBufferProducer() const {
Jesse Hall38efe862013-04-06 23:12:29 -070073 if (mDisplayId >= 0) {
74 return static_cast<IGraphicBufferProducer*>(
75 const_cast<VirtualDisplaySurface*>(this));
76 } else {
77 // There won't be any interaction with HWC for this virtual display,
78 // so the GLES driver can pass buffers directly to the sink.
79 return mSource[SOURCE_SINK];
80 }
81}
82
83status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) {
84 if (mDisplayId < 0)
85 return NO_ERROR;
86
87 VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE,
88 "Unexpected prepareFrame() in %s state", dbgStateStr());
89 mDbgState = DBG_STATE_PREPARED;
90
91 mCompositionType = compositionType;
92
93 if (mCompositionType != mDbgLastCompositionType) {
94 VDS_LOGV("prepareFrame: composition type changed to %s",
95 dbgCompositionTypeStr(mCompositionType));
96 mDbgLastCompositionType = mCompositionType;
97 }
98
99 return NO_ERROR;
Jesse Hall99c7dbb2013-03-14 14:29:29 -0700100}
101
102status_t VirtualDisplaySurface::compositionComplete() {
103 return NO_ERROR;
104}
105
106status_t VirtualDisplaySurface::advanceFrame() {
Jesse Hall38efe862013-04-06 23:12:29 -0700107 if (mDisplayId < 0)
108 return NO_ERROR;
109
110 if (mCompositionType == COMPOSITION_HWC) {
111 VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
112 "Unexpected advanceFrame() in %s state on HWC frame",
113 dbgStateStr());
114 } else {
115 VDS_LOGW_IF(mDbgState != DBG_STATE_GLES_DONE,
116 "Unexpected advanceFrame() in %s state on GLES/MIXED frame",
117 dbgStateStr());
118 }
119 mDbgState = DBG_STATE_HWC;
120
121 status_t result;
122 sp<Fence> outFence;
123 if (mCompositionType != COMPOSITION_GLES) {
124 // Dequeue an output buffer from the sink
125 uint32_t transformHint, numPendingBuffers;
126 mQueueBufferOutput.deflate(&mSinkBufferWidth, &mSinkBufferHeight,
127 &transformHint, &numPendingBuffers);
128 int sslot;
129 result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &outFence);
130 if (result < 0)
131 return result;
132 mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot);
133 }
134
135 if (mCompositionType == COMPOSITION_HWC) {
136 // We just dequeued the output buffer, use it for FB as well
137 mFbProducerSlot = mOutputProducerSlot;
138 mFbFence = outFence;
139 } else if (mCompositionType == COMPOSITION_GLES) {
140 mOutputProducerSlot = mFbProducerSlot;
141 outFence = mFbFence;
142 } else {
143 // mFbFence and mFbProducerSlot were set in queueBuffer,
144 // and mOutputProducerSlot and outFence were set above when dequeueing
145 // the sink buffer.
146 }
147
148 if (mFbProducerSlot < 0 || mOutputProducerSlot < 0) {
149 // Last chance bailout if something bad happened earlier. For example,
150 // in a GLES configuration, if the sink disappears then dequeueBuffer
151 // will fail, the GLES driver won't queue a buffer, but SurfaceFlinger
152 // will soldier on. So we end up here without a buffer. There should
153 // be lots of scary messages in the log just before this.
154 VDS_LOGE("advanceFrame: no buffer, bailing out");
155 return NO_MEMORY;
156 }
157
158 sp<GraphicBuffer> fbBuffer = mProducerBuffers[mFbProducerSlot];
159 sp<GraphicBuffer> outBuffer = mProducerBuffers[mOutputProducerSlot];
160 VDS_LOGV("advanceFrame: fb=%d(%p) out=%d(%p)",
161 mFbProducerSlot, fbBuffer.get(),
162 mOutputProducerSlot, outBuffer.get());
163
164 result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
165 if (result == NO_ERROR) {
166 result = mHwc.setOutputBuffer(mDisplayId, outFence, outBuffer);
167 }
168
169 return result;
Jesse Hall99c7dbb2013-03-14 14:29:29 -0700170}
171
Jesse Hall851cfe82013-03-20 13:44:00 -0700172void VirtualDisplaySurface::onFrameCommitted() {
Jesse Hall38efe862013-04-06 23:12:29 -0700173 if (mDisplayId < 0)
174 return;
175
176 VDS_LOGW_IF(mDbgState != DBG_STATE_HWC,
177 "Unexpected onFrameCommitted() in %s state", dbgStateStr());
178 mDbgState = DBG_STATE_IDLE;
179
180 sp<Fence> fbFence = mHwc.getAndResetReleaseFence(mDisplayId);
181 if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) {
182 // release the scratch buffer back to the pool
183 Mutex::Autolock lock(mMutex);
184 int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot);
185 VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot);
186 addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], fbFence);
187 releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot],
188 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
189 }
190
191 if (mOutputProducerSlot >= 0) {
192 int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot);
193 QueueBufferOutput qbo;
194 sp<Fence> outFence = mHwc.getLastRetireFence(mDisplayId);
195 VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot);
196 status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot,
197 QueueBufferInput(systemTime(),
198 Rect(mSinkBufferWidth, mSinkBufferHeight),
199 NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, outFence),
200 &qbo);
201 if (result == NO_ERROR) {
202 updateQueueBufferOutput(qbo);
203 }
204 }
205
206 resetPerFrameState();
Jesse Hall99c7dbb2013-03-14 14:29:29 -0700207}
208
209void VirtualDisplaySurface::dump(String8& result) const {
210}
211
Jesse Hall38efe862013-04-06 23:12:29 -0700212status_t VirtualDisplaySurface::requestBuffer(int pslot,
213 sp<GraphicBuffer>* outBuf) {
214 VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
215 "Unexpected requestBuffer pslot=%d in %s state",
216 pslot, dbgStateStr());
217
218 *outBuf = mProducerBuffers[pslot];
219 return NO_ERROR;
220}
221
222status_t VirtualDisplaySurface::setBufferCount(int bufferCount) {
223 return mSource[SOURCE_SINK]->setBufferCount(bufferCount);
224}
225
226status_t VirtualDisplaySurface::dequeueBuffer(Source source,
227 uint32_t format, int* sslot, sp<Fence>* fence) {
228 status_t result = mSource[source]->dequeueBuffer(sslot, fence,
229 mSinkBufferWidth, mSinkBufferHeight, format, mProducerUsage);
230 if (result < 0)
231 return result;
232 int pslot = mapSource2ProducerSlot(source, *sslot);
233 VDS_LOGV("dequeueBuffer(%s): sslot=%d pslot=%d result=%d",
234 dbgSourceStr(source), *sslot, pslot, result);
235 uint32_t sourceBit = static_cast<uint32_t>(source) << pslot;
236
237 if ((mProducerSlotSource & (1u << pslot)) != sourceBit) {
238 // This slot was previously dequeued from the other source; must
239 // re-request the buffer.
240 result |= BUFFER_NEEDS_REALLOCATION;
241 mProducerSlotSource &= ~(1u << pslot);
242 mProducerSlotSource |= sourceBit;
243 }
244
245 if (result & RELEASE_ALL_BUFFERS) {
246 for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
247 if ((mProducerSlotSource & (1u << i)) == sourceBit)
248 mProducerBuffers[i].clear();
249 }
250 }
251 if (result & BUFFER_NEEDS_REALLOCATION) {
252 mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]);
253 VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p",
254 dbgSourceStr(source), pslot, mProducerBuffers[pslot].get());
255 }
256
257 return result;
258}
259
260status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence,
261 uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
262 VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
263 "Unexpected dequeueBuffer() in %s state", dbgStateStr());
264 mDbgState = DBG_STATE_GLES;
265
266 VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage);
267
268 mProducerUsage = usage | GRALLOC_USAGE_HW_COMPOSER;
269 Source source = fbSourceForCompositionType(mCompositionType);
270 if (source == SOURCE_SINK) {
271 mSinkBufferWidth = w;
272 mSinkBufferHeight = h;
273 }
274
275 int sslot;
276 status_t result = dequeueBuffer(source, format, &sslot, fence);
277 if (result >= 0) {
278 *pslot = mapSource2ProducerSlot(source, sslot);
279 }
280 return result;
281}
282
283status_t VirtualDisplaySurface::queueBuffer(int pslot,
284 const QueueBufferInput& input, QueueBufferOutput* output) {
285 VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
286 "Unexpected queueBuffer(pslot=%d) in %s state", pslot,
287 dbgStateStr());
288 mDbgState = DBG_STATE_GLES_DONE;
289
290 VDS_LOGV("queueBuffer pslot=%d", pslot);
291
292 status_t result;
293 if (mCompositionType == COMPOSITION_MIXED) {
294 // Queue the buffer back into the scratch pool
295 QueueBufferOutput scratchQBO;
296 int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, pslot);
297 result = mBufferQueue->queueBuffer(sslot, input, &scratchQBO);
298 if (result != NO_ERROR)
299 return result;
300
301 // Now acquire the buffer from the scratch pool -- should be the same
302 // slot and fence as we just queued.
303 Mutex::Autolock lock(mMutex);
304 BufferQueue::BufferItem item;
305 result = acquireBufferLocked(&item);
306 if (result != NO_ERROR)
307 return result;
308 VDS_LOGW_IF(item.mBuf != sslot,
309 "queueBuffer: acquired sslot %d from SCRATCH after queueing sslot %d",
310 item.mBuf, sslot);
311 mFbProducerSlot = mapSource2ProducerSlot(SOURCE_SCRATCH, item.mBuf);
312 mFbFence = mSlots[item.mBuf].mFence;
313
314 } else {
315 LOG_FATAL_IF(mCompositionType != COMPOSITION_GLES,
316 "Unexpected queueBuffer in state %s for compositionType %s",
317 dbgStateStr(), dbgCompositionTypeStr(mCompositionType));
318
319 // Extract the GLES release fence for HWC to acquire
320 int64_t timestamp;
321 Rect crop;
322 int scalingMode;
323 uint32_t transform;
324 input.deflate(&timestamp, &crop, &scalingMode, &transform,
325 &mFbFence);
326
327 mFbProducerSlot = pslot;
328 }
329
330 *output = mQueueBufferOutput;
331 return NO_ERROR;
332}
333
334void VirtualDisplaySurface::cancelBuffer(int pslot, const sp<Fence>& fence) {
335 VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
336 "Unexpected cancelBuffer(pslot=%d) in %s state", pslot,
337 dbgStateStr());
338 VDS_LOGV("cancelBuffer pslot=%d", pslot);
339 Source source = fbSourceForCompositionType(mCompositionType);
340 return mSource[source]->cancelBuffer(
341 mapProducer2SourceSlot(source, pslot), fence);
342}
343
344int VirtualDisplaySurface::query(int what, int* value) {
345 return mSource[SOURCE_SINK]->query(what, value);
346}
347
348status_t VirtualDisplaySurface::setSynchronousMode(bool enabled) {
349 return mSource[SOURCE_SINK]->setSynchronousMode(enabled);
350}
351
352status_t VirtualDisplaySurface::connect(int api, QueueBufferOutput* output) {
353 QueueBufferOutput qbo;
354 status_t result = mSource[SOURCE_SINK]->connect(api, &qbo);
355 if (result == NO_ERROR) {
356 updateQueueBufferOutput(qbo);
357 *output = mQueueBufferOutput;
358 }
359 return result;
360}
361
362status_t VirtualDisplaySurface::disconnect(int api) {
363 return mSource[SOURCE_SINK]->disconnect(api);
364}
365
366void VirtualDisplaySurface::updateQueueBufferOutput(
367 const QueueBufferOutput& qbo) {
368 uint32_t w, h, transformHint, numPendingBuffers;
369 qbo.deflate(&w, &h, &transformHint, &numPendingBuffers);
370 mQueueBufferOutput.inflate(w, h, 0, numPendingBuffers);
371}
372
373void VirtualDisplaySurface::resetPerFrameState() {
374 mCompositionType = COMPOSITION_UNKNOWN;
375 mSinkBufferWidth = 0;
376 mSinkBufferHeight = 0;
377 mFbFence = Fence::NO_FENCE;
378 mFbProducerSlot = -1;
379 mOutputProducerSlot = -1;
380}
381
382// This slot mapping function is its own inverse, so two copies are unnecessary.
383// Both are kept to make the intent clear where the function is called, and for
384// the (unlikely) chance that we switch to a different mapping function.
385int VirtualDisplaySurface::mapSource2ProducerSlot(Source source, int sslot) {
386 if (source == SOURCE_SCRATCH) {
387 return BufferQueue::NUM_BUFFER_SLOTS - sslot - 1;
388 } else {
389 return sslot;
390 }
391}
392int VirtualDisplaySurface::mapProducer2SourceSlot(Source source, int pslot) {
393 return mapSource2ProducerSlot(source, pslot);
394}
395
396VirtualDisplaySurface::Source
397VirtualDisplaySurface::fbSourceForCompositionType(CompositionType type) {
398 return type == COMPOSITION_MIXED ? SOURCE_SCRATCH : SOURCE_SINK;
399}
400
401const char* VirtualDisplaySurface::dbgStateStr() const {
402 switch (mDbgState) {
403 case DBG_STATE_IDLE: return "IDLE";
404 case DBG_STATE_PREPARED: return "PREPARED";
405 case DBG_STATE_GLES: return "GLES";
406 case DBG_STATE_GLES_DONE: return "GLES_DONE";
407 case DBG_STATE_HWC: return "HWC";
408 default: return "INVALID";
409 }
410}
411
412const char* VirtualDisplaySurface::dbgSourceStr(Source s) {
413 switch (s) {
414 case SOURCE_SINK: return "SINK";
415 case SOURCE_SCRATCH: return "SCRATCH";
416 default: return "INVALID";
417 }
418}
419
Jesse Hall99c7dbb2013-03-14 14:29:29 -0700420// ---------------------------------------------------------------------------
421} // namespace android
422// ---------------------------------------------------------------------------