1 /*
2 // Copyright (c) 2014 Intel Corporation
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 #include <HwcTrace.h>
17 #include <Hwcomposer.h>
18 #include <DisplayPlaneManager.h>
19 #include <DisplayQuery.h>
20 #include <VirtualDevice.h>
21 #include <SoftVsyncObserver.h>
22
23 #include <binder/IServiceManager.h>
24 #include <binder/ProcessState.h>
25
26 #include <hal_public.h>
27 #include <libsync/sw_sync.h>
28 #include <sync/sync.h>
29
30 #include <va/va_android.h>
31 #include <va/va_vpp.h>
32 #include <va/va_tpi.h>
33
34 #include <cutils/properties.h>
35
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39
40 #define NUM_CSC_BUFFERS 6
41 #define NUM_SCALING_BUFFERS 3
42
43 #define QCIF_WIDTH 176
44 #define QCIF_HEIGHT 144
45
46 namespace android {
47 namespace intel {
48
align_width(uint32_t val)49 static inline uint32_t align_width(uint32_t val)
50 {
51 return align_to(val, 64);
52 }
53
align_height(uint32_t val)54 static inline uint32_t align_height(uint32_t val)
55 {
56 return align_to(val, 16);
57 }
58
my_close_fence(const char * func,const char * fenceName,int & fenceFd)59 static void my_close_fence(const char* func, const char* fenceName, int& fenceFd)
60 {
61 if (fenceFd != -1) {
62 ALOGV("%s: closing fence %s (fd=%d)", func, fenceName, fenceFd);
63 int err = close(fenceFd);
64 if (err < 0) {
65 ALOGE("%s: fence %s close error %d: %s", func, fenceName, err, strerror(errno));
66 }
67 fenceFd = -1;
68 }
69 }
70
my_sync_wait_and_close(const char * func,const char * fenceName,int & fenceFd)71 static void my_sync_wait_and_close(const char* func, const char* fenceName, int& fenceFd)
72 {
73 if (fenceFd != -1) {
74 ALOGV("%s: waiting on fence %s (fd=%d)", func, fenceName, fenceFd);
75 int err = sync_wait(fenceFd, 300);
76 if (err < 0) {
77 ALOGE("%s: fence %s sync_wait error %d: %s", func, fenceName, err, strerror(errno));
78 }
79 my_close_fence(func, fenceName, fenceFd);
80 }
81 }
82
my_timeline_inc(const char * func,const char * timelineName,int & syncTimelineFd)83 static void my_timeline_inc(const char* func, const char* timelineName, int& syncTimelineFd)
84 {
85 if (syncTimelineFd != -1) {
86 ALOGV("%s: incrementing timeline %s (fd=%d)", func, timelineName, syncTimelineFd);
87 int err = sw_sync_timeline_inc(syncTimelineFd, 1);
88 if (err < 0)
89 ALOGE("%s sync timeline %s increment error %d: %s", func, timelineName, errno, strerror(errno));
90 syncTimelineFd = -1;
91 }
92 }
93
94 #define CLOSE_FENCE(fenceName) my_close_fence(__func__, #fenceName, fenceName)
95 #define SYNC_WAIT_AND_CLOSE(fenceName) my_sync_wait_and_close(__func__, #fenceName, fenceName)
96 #define TIMELINE_INC(timelineName) my_timeline_inc(__func__, #timelineName, timelineName)
97
98 class MappedSurface {
99 public:
MappedSurface(VADisplay dpy,VASurfaceID surf)100 MappedSurface(VADisplay dpy, VASurfaceID surf)
101 : va_dpy(dpy),
102 ptr(NULL)
103 {
104 VAStatus va_status;
105 va_status = vaDeriveImage(va_dpy, surf, &image);
106 if (va_status != VA_STATUS_SUCCESS) {
107 ETRACE("vaDeriveImage returns %08x", va_status);
108 return;
109 }
110 va_status = vaMapBuffer(va_dpy, image.buf, (void**)&ptr);
111 if (va_status != VA_STATUS_SUCCESS) {
112 ETRACE("vaMapBuffer returns %08x", va_status);
113 vaDestroyImage(va_dpy, image.image_id);
114 return;
115 }
116 }
~MappedSurface()117 ~MappedSurface() {
118 if (ptr == NULL)
119 return;
120
121 VAStatus va_status;
122
123 va_status = vaUnmapBuffer(va_dpy, image.buf);
124 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaUnmapBuffer returns %08x", va_status);
125
126 va_status = vaDestroyImage(va_dpy, image.image_id);
127 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaDestroyImage returns %08x", va_status);
128 }
valid()129 bool valid() { return ptr != NULL; }
getPtr()130 uint8_t* getPtr() { return ptr; }
131 private:
132 VADisplay va_dpy;
133 VAImage image;
134 uint8_t* ptr;
135 };
136
137 class VirtualDevice::VAMappedHandle {
138 public:
VAMappedHandle(VADisplay dpy,buffer_handle_t handle,uint32_t stride,uint32_t height,unsigned int pixel_format)139 VAMappedHandle(VADisplay dpy, buffer_handle_t handle, uint32_t stride, uint32_t height, unsigned int pixel_format)
140 : va_dpy(dpy),
141 surface(0)
142 {
143 VTRACE("Map gralloc %p size=%ux%u", handle, stride, height);
144
145 unsigned int format;
146 unsigned long buffer = reinterpret_cast<unsigned long>(handle);
147 VASurfaceAttribExternalBuffers buf;
148 buf.pixel_format = pixel_format;
149 buf.width = stride;
150 buf.height = height;
151 buf.buffers = &buffer;
152 buf.num_buffers = 1;
153 buf.flags = 0;
154 buf.private_data = NULL;
155
156 if (pixel_format == VA_FOURCC_RGBA || pixel_format == VA_FOURCC_BGRA) {
157 format = VA_RT_FORMAT_RGB32;
158 buf.data_size = stride * height * 4;
159 buf.num_planes = 3;
160 buf.pitches[0] = stride;
161 buf.pitches[1] = stride;
162 buf.pitches[2] = stride;
163 buf.pitches[3] = 0;
164 buf.offsets[0] = 0;
165 buf.offsets[1] = 0;
166 buf.offsets[2] = 0;
167 buf.offsets[3] = 0;
168 }
169 else {
170 format = VA_RT_FORMAT_YUV420;
171 buf.data_size = stride * height * 3/2;
172 buf.num_planes = 2;
173 buf.pitches[0] = stride;
174 buf.pitches[1] = stride;
175 buf.pitches[2] = 0;
176 buf.pitches[3] = 0;
177 buf.offsets[0] = 0;
178 buf.offsets[1] = stride * height;
179 }
180
181 VASurfaceAttrib attrib_list[3];
182 attrib_list[0].type = (VASurfaceAttribType)VASurfaceAttribMemoryType;
183 attrib_list[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
184 attrib_list[0].value.type = VAGenericValueTypeInteger;
185 attrib_list[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_ANDROID_GRALLOC;
186 attrib_list[1].type = (VASurfaceAttribType)VASurfaceAttribExternalBufferDescriptor;
187 attrib_list[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
188 attrib_list[1].value.type = VAGenericValueTypePointer;
189 attrib_list[1].value.value.p = (void *)&buf;
190 attrib_list[2].type = (VASurfaceAttribType)VASurfaceAttribPixelFormat;
191 attrib_list[2].flags = VA_SURFACE_ATTRIB_SETTABLE;
192 attrib_list[2].value.type = VAGenericValueTypeInteger;
193 attrib_list[2].value.value.i = pixel_format;
194
195 VAStatus va_status;
196 va_status = vaCreateSurfaces(va_dpy,
197 format,
198 stride,
199 height,
200 &surface,
201 1,
202 attrib_list,
203 3);
204 if (va_status != VA_STATUS_SUCCESS) {
205 ETRACE("vaCreateSurfaces returns %08x, surface = %x", va_status, surface);
206 surface = 0;
207 }
208 }
VAMappedHandle(VADisplay dpy,buffer_handle_t khandle,uint32_t stride,uint32_t height,bool tiled)209 VAMappedHandle(VADisplay dpy, buffer_handle_t khandle, uint32_t stride, uint32_t height, bool tiled)
210 : va_dpy(dpy),
211 surface(0)
212 {
213 int format;
214 VASurfaceAttributeTPI attribTpi;
215 memset(&attribTpi, 0, sizeof(attribTpi));
216 VTRACE("Map khandle 0x%x size=%ux%u", khandle, stride, height);
217 attribTpi.type = VAExternalMemoryKernelDRMBufffer;
218 attribTpi.width = stride;
219 attribTpi.height = height;
220 attribTpi.size = stride*height*3/2;
221 attribTpi.pixel_format = VA_FOURCC_NV12;
222 attribTpi.tiling = tiled;
223 attribTpi.luma_stride = stride;
224 attribTpi.chroma_u_stride = stride;
225 attribTpi.chroma_v_stride = stride;
226 attribTpi.luma_offset = 0;
227 attribTpi.chroma_u_offset = stride*height;
228 attribTpi.chroma_v_offset = stride*height+1;
229 format = VA_RT_FORMAT_YUV420;
230 attribTpi.count = 1;
231 attribTpi.buffers = (long unsigned int*) &khandle;
232
233 VAStatus va_status;
234 va_status = vaCreateSurfacesWithAttribute(va_dpy,
235 stride,
236 height,
237 format,
238 1,
239 &surface,
240 &attribTpi);
241 if (va_status != VA_STATUS_SUCCESS) {
242 ETRACE("vaCreateSurfacesWithAttribute returns %08x", va_status);
243 surface = 0;
244 }
245 }
~VAMappedHandle()246 ~VAMappedHandle()
247 {
248 if (surface == 0)
249 return;
250 VAStatus va_status;
251 va_status = vaDestroySurfaces(va_dpy, &surface, 1);
252 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaDestroySurfaces returns %08x", va_status);
253 }
254 private:
255 VADisplay va_dpy;
256 public:
257 VASurfaceID surface;
258 };
259
260 // refcounted version of VAMappedHandle, to make caching easier
261 class VirtualDevice::VAMappedHandleObject : public RefBase, public VAMappedHandle {
262 public:
VAMappedHandleObject(VADisplay dpy,buffer_handle_t handle,uint32_t stride,uint32_t height,unsigned int pixel_format)263 VAMappedHandleObject(VADisplay dpy, buffer_handle_t handle, uint32_t stride, uint32_t height, unsigned int pixel_format)
264 : VAMappedHandle(dpy, handle, stride, height, pixel_format) { }
VAMappedHandleObject(VADisplay dpy,buffer_handle_t khandle,uint32_t stride,uint32_t height,bool tiled)265 VAMappedHandleObject(VADisplay dpy, buffer_handle_t khandle, uint32_t stride, uint32_t height, bool tiled)
266 : VAMappedHandle(dpy, khandle, stride, height, tiled) { }
267 protected:
~VAMappedHandleObject()268 ~VAMappedHandleObject() {}
269 };
270
CachedBuffer(BufferManager * mgr,buffer_handle_t handle)271 VirtualDevice::CachedBuffer::CachedBuffer(BufferManager *mgr, buffer_handle_t handle)
272 : manager(mgr),
273 mapper(NULL),
274 vaMappedHandle(NULL),
275 cachedKhandle(0)
276 {
277 DataBuffer *buffer = manager->lockDataBuffer((buffer_handle_t)handle);
278 mapper = manager->map(*buffer);
279 manager->unlockDataBuffer(buffer);
280 }
281
~CachedBuffer()282 VirtualDevice::CachedBuffer::~CachedBuffer()
283 {
284 if (vaMappedHandle != NULL)
285 delete vaMappedHandle;
286 manager->unmap(mapper);
287 }
288
HeldDecoderBuffer(const sp<VirtualDevice> & vd,const android::sp<CachedBuffer> & cachedBuffer)289 VirtualDevice::HeldDecoderBuffer::HeldDecoderBuffer(const sp<VirtualDevice>& vd, const android::sp<CachedBuffer>& cachedBuffer)
290 : vd(vd),
291 cachedBuffer(cachedBuffer)
292 {
293 if (!vd->mPayloadManager->setRenderStatus(cachedBuffer->mapper, true)) {
294 ETRACE("Failed to set render status");
295 }
296 }
297
~HeldDecoderBuffer()298 VirtualDevice::HeldDecoderBuffer::~HeldDecoderBuffer()
299 {
300 if (!vd->mPayloadManager->setRenderStatus(cachedBuffer->mapper, false)) {
301 ETRACE("Failed to set render status");
302 }
303 }
304
305 struct VirtualDevice::Task : public RefBase {
306 virtual void run(VirtualDevice& vd) = 0;
~Taskandroid::intel::VirtualDevice::Task307 virtual ~Task() {}
308 };
309
310 struct VirtualDevice::RenderTask : public VirtualDevice::Task {
RenderTaskandroid::intel::VirtualDevice::RenderTask311 RenderTask() : successful(false) { }
312 virtual void run(VirtualDevice& vd) = 0;
313 bool successful;
314 };
315
316 struct VirtualDevice::ComposeTask : public VirtualDevice::RenderTask {
ComposeTaskandroid::intel::VirtualDevice::ComposeTask317 ComposeTask()
318 : videoKhandle(0),
319 rgbHandle(NULL),
320 mappedRgbIn(NULL),
321 outputHandle(NULL),
322 yuvAcquireFenceFd(-1),
323 rgbAcquireFenceFd(-1),
324 outbufAcquireFenceFd(-1),
325 syncTimelineFd(-1) { }
326
~ComposeTaskandroid::intel::VirtualDevice::ComposeTask327 virtual ~ComposeTask() {
328 // If queueCompose() creates this object and sets up fences,
329 // but aborts before enqueuing the task, or if the task runs
330 // but errors out, make sure our acquire fences get closed
331 // and any release fences get signaled.
332 CLOSE_FENCE(yuvAcquireFenceFd);
333 CLOSE_FENCE(rgbAcquireFenceFd);
334 CLOSE_FENCE(outbufAcquireFenceFd);
335 TIMELINE_INC(syncTimelineFd);
336 }
337
runandroid::intel::VirtualDevice::ComposeTask338 virtual void run(VirtualDevice& vd) {
339 bool dump = false;
340 if (vd.mDebugVspDump && ++vd.mDebugCounter > 200) {
341 dump = true;
342 vd.mDebugCounter = 0;
343 }
344
345 SYNC_WAIT_AND_CLOSE(yuvAcquireFenceFd);
346
347 VASurfaceID videoInSurface;
348 if (videoKhandle == 0) {
349 videoInSurface = vd.va_blank_yuv_in;
350 } else {
351 if (videoCachedBuffer->cachedKhandle != videoKhandle || videoCachedBuffer->vaMappedHandle == NULL) {
352 if (videoCachedBuffer->vaMappedHandle != NULL)
353 delete videoCachedBuffer->vaMappedHandle;
354 videoCachedBuffer->vaMappedHandle = new VAMappedHandle(vd.va_dpy, videoKhandle, videoStride, videoBufHeight, videoTiled);
355 videoCachedBuffer->cachedKhandle = videoKhandle;
356 }
357 videoInSurface = videoCachedBuffer->vaMappedHandle->surface;
358 }
359
360 if (videoInSurface == 0) {
361 ETRACE("Couldn't map video");
362 return;
363 }
364 SYNC_WAIT_AND_CLOSE(rgbAcquireFenceFd);
365 SYNC_WAIT_AND_CLOSE(outbufAcquireFenceFd);
366
367 VAMappedHandle mappedVideoOut(vd.va_dpy, outputHandle, align_width(outWidth), align_height(outHeight), (unsigned int)VA_FOURCC_NV12);
368 if (mappedVideoOut.surface == 0) {
369 ETRACE("Unable to map outbuf");
370 return;
371 }
372
373 if (dump)
374 dumpSurface(vd.va_dpy, "/data/misc/vsp_in.yuv", videoInSurface, videoStride*videoBufHeight*3/2);
375
376 if (mappedRgbIn != NULL) {
377 if (dump)
378 dumpSurface(vd.va_dpy, "/data/misc/vsp_in.rgb", mappedRgbIn->surface, align_width(outWidth)*align_height(outHeight)*4);
379 vd.vspCompose(videoInSurface, mappedRgbIn->surface, mappedVideoOut.surface, &surface_region, &output_region);
380 }
381 else if (rgbHandle != NULL) {
382 VAMappedHandle localMappedRgbIn(vd.va_dpy, rgbHandle, align_width(outWidth), align_height(outHeight), (unsigned int)VA_FOURCC_BGRA);
383 vd.vspCompose(videoInSurface, localMappedRgbIn.surface, mappedVideoOut.surface, &surface_region, &output_region);
384 }
385 else {
386 // No RGBA, so compose with 100% transparent RGBA frame.
387 if (dump)
388 dumpSurface(vd.va_dpy, "/data/misc/vsp_in.rgb", vd.va_blank_rgb_in, align_width(outWidth)*align_height(outHeight)*4);
389 vd.vspCompose(videoInSurface, vd.va_blank_rgb_in, mappedVideoOut.surface, &surface_region, &output_region);
390 }
391 if (dump)
392 dumpSurface(vd.va_dpy, "/data/misc/vsp_out.yuv", mappedVideoOut.surface, align_width(outWidth)*align_height(outHeight)*3/2);
393 TIMELINE_INC(syncTimelineFd);
394 successful = true;
395 }
dumpSurfaceandroid::intel::VirtualDevice::ComposeTask396 void dumpSurface(VADisplay va_dpy, const char* filename, VASurfaceID surf, int size) {
397 MappedSurface dumpSurface(va_dpy, surf);
398 if (dumpSurface.valid()) {
399 int fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
400 if (fd > 0) {
401 write(fd, dumpSurface.getPtr(), size);
402 close(fd);
403 ALOGI("Output dumped");
404 }
405 else
406 ALOGE("Error %d opening output file: %s", errno, strerror(errno));
407 }
408 else
409 ALOGE("Failed to map output for dump");
410 }
411 buffer_handle_t videoKhandle;
412 uint32_t videoStride;
413 uint32_t videoBufHeight;
414 bool videoTiled;
415 buffer_handle_t rgbHandle;
416 sp<RefBase> heldRgbHandle;
417 sp<VAMappedHandleObject> mappedRgbIn;
418 buffer_handle_t outputHandle;
419 VARectangle surface_region;
420 VARectangle output_region;
421 uint32_t outWidth;
422 uint32_t outHeight;
423 sp<CachedBuffer> videoCachedBuffer;
424 sp<RefBase> heldVideoBuffer;
425 int yuvAcquireFenceFd;
426 int rgbAcquireFenceFd;
427 int outbufAcquireFenceFd;
428 int syncTimelineFd;
429 };
430
431 struct VirtualDevice::EnableVspTask : public VirtualDevice::Task {
runandroid::intel::VirtualDevice::EnableVspTask432 virtual void run(VirtualDevice& vd) {
433 vd.vspEnable(width, height);
434 }
435 uint32_t width;
436 uint32_t height;
437 };
438
439 struct VirtualDevice::DisableVspTask : public VirtualDevice::Task {
runandroid::intel::VirtualDevice::DisableVspTask440 virtual void run(VirtualDevice& vd) {
441 vd.vspDisable();
442 }
443 };
444
445 struct VirtualDevice::BlitTask : public VirtualDevice::RenderTask {
BlitTaskandroid::intel::VirtualDevice::BlitTask446 BlitTask()
447 : srcAcquireFenceFd(-1),
448 destAcquireFenceFd(-1),
449 syncTimelineFd(-1) { }
450
~BlitTaskandroid::intel::VirtualDevice::BlitTask451 virtual ~BlitTask()
452 {
453 // If queueColorConvert() creates this object and sets up fences,
454 // but aborts before enqueuing the task, or if the task runs
455 // but errors out, make sure our acquire fences get closed
456 // and any release fences get signaled.
457 CLOSE_FENCE(srcAcquireFenceFd);
458 CLOSE_FENCE(destAcquireFenceFd);
459 TIMELINE_INC(syncTimelineFd);
460 }
461
runandroid::intel::VirtualDevice::BlitTask462 virtual void run(VirtualDevice& vd) {
463 SYNC_WAIT_AND_CLOSE(srcAcquireFenceFd);
464 SYNC_WAIT_AND_CLOSE(destAcquireFenceFd);
465 BufferManager* mgr = vd.mHwc.getBufferManager();
466 if (!(mgr->blit(srcHandle, destHandle, destRect, false, false))) {
467 ETRACE("color space conversion from RGB to NV12 failed");
468 }
469 else
470 successful = true;
471 TIMELINE_INC(syncTimelineFd);
472 }
473 buffer_handle_t srcHandle;
474 buffer_handle_t destHandle;
475 int srcAcquireFenceFd;
476 int destAcquireFenceFd;
477 int syncTimelineFd;
478 crop_t destRect;
479 };
480
481 struct VirtualDevice::FrameTypeChangedTask : public VirtualDevice::Task {
runandroid::intel::VirtualDevice::FrameTypeChangedTask482 virtual void run(VirtualDevice& vd) {
483 #ifdef INTEL_WIDI
484 typeChangeListener->frameTypeChanged(inputFrameInfo);
485 ITRACE("Notify frameTypeChanged: %dx%d in %dx%d @ %d fps",
486 inputFrameInfo.contentWidth, inputFrameInfo.contentHeight,
487 inputFrameInfo.bufferWidth, inputFrameInfo.bufferHeight,
488 inputFrameInfo.contentFrameRateN);
489 #endif
490 }
491 #ifdef INTEL_WIDI
492 sp<IFrameTypeChangeListener> typeChangeListener;
493 FrameInfo inputFrameInfo;
494 #endif
495 };
496
497 struct VirtualDevice::BufferInfoChangedTask : public VirtualDevice::Task {
runandroid::intel::VirtualDevice::BufferInfoChangedTask498 virtual void run(VirtualDevice& vd) {
499 #ifdef INTEL_WIDI
500 typeChangeListener->bufferInfoChanged(outputFrameInfo);
501 ITRACE("Notify bufferInfoChanged: %dx%d in %dx%d @ %d fps",
502 outputFrameInfo.contentWidth, outputFrameInfo.contentHeight,
503 outputFrameInfo.bufferWidth, outputFrameInfo.bufferHeight,
504 outputFrameInfo.contentFrameRateN);
505 #endif
506 }
507 #ifdef INTEL_WIDI
508 sp<IFrameTypeChangeListener> typeChangeListener;
509 FrameInfo outputFrameInfo;
510 #endif
511 };
512
513 struct VirtualDevice::OnFrameReadyTask : public VirtualDevice::Task {
runandroid::intel::VirtualDevice::OnFrameReadyTask514 virtual void run(VirtualDevice& vd) {
515 if (renderTask != NULL && !renderTask->successful)
516 return;
517
518 {
519 Mutex::Autolock _l(vd.mHeldBuffersLock);
520 //Add the heldbuffer to the vector before calling onFrameReady, so that the buffer will be removed
521 //from the vector properly even if the notifyBufferReturned call acquires mHeldBuffersLock first.
522 vd.mHeldBuffers.add(handle, heldBuffer);
523 }
524 #ifdef INTEL_WIDI
525 // FIXME: we could remove this casting once onFrameReady receives
526 // a buffer_handle_t handle
527 status_t result = frameListener->onFrameReady((uint32_t)handle, handleType, renderTimestamp, mediaTimestamp);
528 if (result != OK) {
529 Mutex::Autolock _l(vd.mHeldBuffersLock);
530 vd.mHeldBuffers.removeItem(handle);
531 }
532 #else
533 Mutex::Autolock _l(vd.mHeldBuffersLock);
534 vd.mHeldBuffers.removeItem(handle);
535 #endif
536 }
537 sp<RenderTask> renderTask;
538 sp<RefBase> heldBuffer;
539 buffer_handle_t handle;
540 #ifdef INTEL_WIDI
541 sp<IFrameListener> frameListener;
542 HWCBufferHandleType handleType;
543 #endif
544 int64_t renderTimestamp;
545 int64_t mediaTimestamp;
546 };
547
548 struct VirtualDevice::BufferList::HeldBuffer : public RefBase {
HeldBufferandroid::intel::VirtualDevice::BufferList::HeldBuffer549 HeldBuffer(BufferList& list, buffer_handle_t handle, uint32_t w, uint32_t h)
550 : mList(list),
551 mHandle(handle),
552 mWidth(w),
553 mHeight(h) { }
~HeldBufferandroid::intel::VirtualDevice::BufferList::HeldBuffer554 virtual ~HeldBuffer()
555 {
556 Mutex::Autolock _l(mList.mVd.mTaskLock);
557 if (mWidth == mList.mWidth && mHeight == mList.mHeight) {
558 VTRACE("Returning %s buffer %p (%ux%u) to list", mList.mName, mHandle, mWidth, mHeight);
559 mList.mAvailableBuffers.push_back(mHandle);
560 } else {
561 VTRACE("Deleting %s buffer %p (%ux%u)", mList.mName, mHandle, mWidth, mHeight);
562 BufferManager* mgr = mList.mVd.mHwc.getBufferManager();
563 mgr->freeGrallocBuffer((mHandle));
564 if (mList.mBuffersToCreate < mList.mLimit)
565 mList.mBuffersToCreate++;
566 }
567 }
568
569 BufferList& mList;
570 buffer_handle_t mHandle;
571 uint32_t mWidth;
572 uint32_t mHeight;
573 };
574
BufferList(VirtualDevice & vd,const char * name,uint32_t limit,uint32_t format,uint32_t usage)575 VirtualDevice::BufferList::BufferList(VirtualDevice& vd, const char* name,
576 uint32_t limit, uint32_t format, uint32_t usage)
577 : mVd(vd),
578 mName(name),
579 mLimit(limit),
580 mFormat(format),
581 mUsage(usage),
582 mBuffersToCreate(0),
583 mWidth(0),
584 mHeight(0)
585 {
586 }
587
get(uint32_t width,uint32_t height,sp<RefBase> * heldBuffer)588 buffer_handle_t VirtualDevice::BufferList::get(uint32_t width, uint32_t height, sp<RefBase>* heldBuffer)
589 {
590 width = align_width(width);
591 height = align_height(height);
592 if (mWidth != width || mHeight != height) {
593 ITRACE("%s buffers changing from %dx%d to %dx%d",
594 mName, mWidth, mHeight, width, height);
595 clear();
596 mWidth = width;
597 mHeight = height;
598 mBuffersToCreate = mLimit;
599 }
600
601 buffer_handle_t handle;
602 if (mAvailableBuffers.empty()) {
603 if (mBuffersToCreate <= 0)
604 return NULL;
605 BufferManager* mgr = mVd.mHwc.getBufferManager();
606 handle = reinterpret_cast<buffer_handle_t>(
607 mgr->allocGrallocBuffer(width, height, mFormat, mUsage));
608 if (handle == NULL){
609 ETRACE("failed to allocate %s buffer", mName);
610 return NULL;
611 }
612 mBuffersToCreate--;
613 }
614 else {
615 handle = *mAvailableBuffers.begin();
616 mAvailableBuffers.erase(mAvailableBuffers.begin());
617 }
618 *heldBuffer = new HeldBuffer(*this, handle, width, height);
619 return handle;
620 }
621
clear()622 void VirtualDevice::BufferList::clear()
623 {
624 if (mWidth != 0 || mHeight != 0)
625 ITRACE("Releasing %s buffers (%ux%u)", mName, mWidth, mHeight);
626 if (!mAvailableBuffers.empty()) {
627 // iterate the list and call freeGraphicBuffer
628 for (List<buffer_handle_t>::iterator i = mAvailableBuffers.begin(); i != mAvailableBuffers.end(); ++i) {
629 VTRACE("Deleting the gralloc buffer associated with handle (%p)", (*i));
630 mVd.mHwc.getBufferManager()->freeGrallocBuffer((*i));
631 }
632 mAvailableBuffers.clear();
633 }
634 mWidth = 0;
635 mHeight = 0;
636 }
637
VirtualDevice(Hwcomposer & hwc)638 VirtualDevice::VirtualDevice(Hwcomposer& hwc)
639 : mProtectedMode(false),
640 mCscBuffers(*this, "CSC",
641 NUM_CSC_BUFFERS, DisplayQuery::queryNV12Format(),
642 GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_PRIVATE_1),
643 mRgbUpscaleBuffers(*this, "RGB upscale",
644 NUM_SCALING_BUFFERS, HAL_PIXEL_FORMAT_BGRA_8888,
645 GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER),
646 mInitialized(false),
647 mHwc(hwc),
648 mPayloadManager(NULL),
649 mVsyncObserver(NULL),
650 mOrigContentWidth(0),
651 mOrigContentHeight(0),
652 mFirstVideoFrame(true),
653 mLastConnectionStatus(false),
654 mCachedBufferCapcity(16),
655 mDecWidth(0),
656 mDecHeight(0),
657 mFpsDivider(1)
658 {
659 CTRACE();
660 #ifdef INTEL_WIDI
661 mNextConfig.frameServerActive = false;
662 #endif
663 }
664
~VirtualDevice()665 VirtualDevice::~VirtualDevice()
666 {
667 WARN_IF_NOT_DEINIT();
668 }
669
getMappedBuffer(buffer_handle_t handle)670 sp<VirtualDevice::CachedBuffer> VirtualDevice::getMappedBuffer(buffer_handle_t handle)
671 {
672 ssize_t index = mMappedBufferCache.indexOfKey(handle);
673 sp<CachedBuffer> cachedBuffer;
674 if (index == NAME_NOT_FOUND) {
675 if (mMappedBufferCache.size() > mCachedBufferCapcity)
676 mMappedBufferCache.clear();
677
678 cachedBuffer = new CachedBuffer(mHwc.getBufferManager(), handle);
679 mMappedBufferCache.add(handle, cachedBuffer);
680 } else {
681 cachedBuffer = mMappedBufferCache[index];
682 }
683
684 return cachedBuffer;
685 }
686
threadLoop()687 bool VirtualDevice::threadLoop()
688 {
689 sp<Task> task;
690 {
691 Mutex::Autolock _l(mTaskLock);
692 while (mTasks.empty()) {
693 mRequestQueued.wait(mTaskLock);
694 }
695 task = *mTasks.begin();
696 mTasks.erase(mTasks.begin());
697 }
698 if (task != NULL) {
699 task->run(*this);
700 task = NULL;
701 }
702 mRequestDequeued.signal();
703
704 return true;
705 }
706 #ifdef INTEL_WIDI
start(sp<IFrameTypeChangeListener> typeChangeListener)707 status_t VirtualDevice::start(sp<IFrameTypeChangeListener> typeChangeListener)
708 {
709 ITRACE();
710 Mutex::Autolock _l(mConfigLock);
711 mNextConfig.typeChangeListener = typeChangeListener;
712 mNextConfig.frameListener = NULL;
713 mNextConfig.policy.scaledWidth = 0;
714 mNextConfig.policy.scaledHeight = 0;
715 mNextConfig.policy.xdpi = 96;
716 mNextConfig.policy.ydpi = 96;
717 mNextConfig.policy.refresh = 60;
718 mNextConfig.extendedModeEnabled =
719 Hwcomposer::getInstance().getDisplayAnalyzer()->isVideoExtModeEnabled();
720 mVideoFramerate = 0;
721 mFirstVideoFrame = true;
722 mNextConfig.frameServerActive = true;
723 mNextConfig.forceNotifyFrameType = true;
724 mNextConfig.forceNotifyBufferInfo = true;
725
726 return NO_ERROR;
727 }
728
stop(bool isConnected)729 status_t VirtualDevice::stop(bool isConnected)
730 {
731 ITRACE();
732 Mutex::Autolock _l(mConfigLock);
733 mNextConfig.typeChangeListener = NULL;
734 mNextConfig.frameListener = NULL;
735 mNextConfig.policy.scaledWidth = 0;
736 mNextConfig.policy.scaledHeight = 0;
737 mNextConfig.policy.xdpi = 96;
738 mNextConfig.policy.ydpi = 96;
739 mNextConfig.policy.refresh = 60;
740 mNextConfig.frameServerActive = false;
741 mNextConfig.extendedModeEnabled = false;
742 mNextConfig.forceNotifyFrameType = false;
743 mNextConfig.forceNotifyBufferInfo = false;
744 {
745 Mutex::Autolock _l(mTaskLock);
746 mCscBuffers.clear();
747 }
748 return NO_ERROR;
749 }
750 #endif
751
isFrameServerActive() const752 bool VirtualDevice::isFrameServerActive() const
753 {
754 #ifdef INTEL_WIDI
755 return mCurrentConfig.frameServerActive;
756 #endif
757 return false;
758 }
759
760 #ifdef INTEL_WIDI
761 /* TODO: 64-bit - this handle of size 32-bit is a problem for 64-bit */
notifyBufferReturned(int handle)762 status_t VirtualDevice::notifyBufferReturned(int handle)
763 {
764 CTRACE();
765 Mutex::Autolock _l(mHeldBuffersLock);
766 ssize_t index = mHeldBuffers.indexOfKey((buffer_handle_t)handle);
767 if (index == NAME_NOT_FOUND) {
768 ETRACE("Couldn't find returned khandle %p", handle);
769 } else {
770 VTRACE("Removing heldBuffer associated with handle (%p)", handle);
771 mHeldBuffers.removeItemsAt(index, 1);
772 }
773 return NO_ERROR;
774 }
775
setResolution(const FrameProcessingPolicy & policy,sp<IFrameListener> listener)776 status_t VirtualDevice::setResolution(const FrameProcessingPolicy& policy, sp<IFrameListener> listener)
777 {
778 ITRACE();
779 Mutex::Autolock _l(mConfigLock);
780 mNextConfig.frameListener = listener;
781 mNextConfig.policy = policy;
782 return NO_ERROR;
783 }
784 #endif
canUseDirectly(const hwc_display_contents_1_t * display,size_t n)785 static bool canUseDirectly(const hwc_display_contents_1_t *display, size_t n)
786 {
787 const hwc_layer_1_t& fbTarget = display->hwLayers[display->numHwLayers-1];
788 const hwc_layer_1_t& layer = display->hwLayers[n];
789 const IMG_native_handle_t* nativeHandle = reinterpret_cast<const IMG_native_handle_t*>(layer.handle);
790 return !(layer.flags & HWC_SKIP_LAYER) && layer.transform == 0 &&
791 layer.blending == HWC_BLENDING_PREMULT &&
792 layer.sourceCropf.left == 0 && layer.sourceCropf.top == 0 &&
793 layer.displayFrame.left == 0 && layer.displayFrame.top == 0 &&
794 layer.sourceCropf.right == fbTarget.sourceCropf.right &&
795 layer.sourceCropf.bottom == fbTarget.sourceCropf.bottom &&
796 layer.displayFrame.right == fbTarget.displayFrame.right &&
797 layer.displayFrame.bottom == fbTarget.displayFrame.bottom &&
798 layer.planeAlpha == 255 && layer.handle != NULL &&
799 (nativeHandle->iFormat == HAL_PIXEL_FORMAT_RGBA_8888 ||
800 nativeHandle->iFormat == HAL_PIXEL_FORMAT_BGRA_8888);
801 }
802
prePrepare(hwc_display_contents_1_t * display)803 bool VirtualDevice::prePrepare(hwc_display_contents_1_t *display)
804 {
805 RETURN_FALSE_IF_NOT_INIT();
806 return true;
807 }
808
prepare(hwc_display_contents_1_t * display)809 bool VirtualDevice::prepare(hwc_display_contents_1_t *display)
810 {
811 RETURN_FALSE_IF_NOT_INIT();
812
813 mRenderTimestamp = systemTime();
814 mVspInUse = false;
815 mExpectAcquireFences = false;
816 mIsForceCloneMode = false;
817 #ifdef INTEL_WIDI
818 {
819 Mutex::Autolock _l(mConfigLock);
820 mCurrentConfig = mNextConfig;
821 }
822 #endif
823
824 bool shouldBeConnected = (display != NULL);
825 if (shouldBeConnected != mLastConnectionStatus) {
826 // calling this will reload the property 'hwc.video.extmode.enable'
827 Hwcomposer::getInstance().getDisplayAnalyzer()->isVideoExtModeEnabled();
828 char propertyVal[PROPERTY_VALUE_MAX];
829 if (property_get("widi.compose.rgb_upscale", propertyVal, NULL) > 0)
830 mVspUpscale = atoi(propertyVal);
831 if (property_get("widi.compose.all_video", propertyVal, NULL) > 0)
832 mDebugVspClear = atoi(propertyVal);
833 if (property_get("widi.compose.dump", propertyVal, NULL) > 0)
834 mDebugVspDump = atoi(propertyVal);
835
836 Hwcomposer::getInstance().getMultiDisplayObserver()->notifyWidiConnectionStatus(shouldBeConnected);
837 mLastConnectionStatus = shouldBeConnected;
838 }
839
840 if (!display) {
841 // No image. We're done with any mappings and CSC buffers.
842 mMappedBufferCache.clear();
843 Mutex::Autolock _l(mTaskLock);
844 mCscBuffers.clear();
845 return true;
846 }
847
848 #ifdef INTEL_WIDI
849 if (!mCurrentConfig.frameServerActive) {
850 // We're done with CSC buffers, since we blit to outbuf in this mode.
851 // We want to keep mappings cached, so we don't clear mMappedBufferCache.
852 Mutex::Autolock _l(mTaskLock);
853 mCscBuffers.clear();
854 }
855 #else
856 Mutex::Autolock _l(mTaskLock);
857 mCscBuffers.clear();
858 #endif
859
860 // by default send the FRAMEBUFFER_TARGET layer (composited image)
861 const ssize_t fbTarget = display->numHwLayers-1;
862 mRgbLayer = fbTarget;
863 mYuvLayer = -1;
864
865 DisplayAnalyzer *analyzer = mHwc.getDisplayAnalyzer();
866
867 mProtectedMode = false;
868 #ifdef INTEL_WIDI
869 if (mCurrentConfig.typeChangeListener != NULL &&
870 !analyzer->isOverlayAllowed() &&
871 analyzer->getVideoInstances() <= 1) {
872 if (mCurrentConfig.typeChangeListener->shutdownVideo() != OK) {
873 ITRACE("Waiting for prior encoder session to shut down...");
874 }
875 /* Setting following flag to true will enable us to call bufferInfoChanged() in clone mode. */
876 mNextConfig.forceNotifyBufferInfo = true;
877 mYuvLayer = -1;
878 mRgbLayer = -1;
879 // Skipping frames.
880 // Fences aren't set in prepare, and we don't need them here, but they'll
881 // be set later and we have to close them. Don't log a warning in this case.
882 mExpectAcquireFences = true;
883 for (ssize_t i = 0; i < fbTarget; i++)
884 display->hwLayers[i].compositionType = HWC_OVERLAY;
885 return true;
886 }
887
888 for (ssize_t i = 0; i < fbTarget; i++) {
889 hwc_layer_1_t& layer = display->hwLayers[i];
890 if (analyzer->isVideoLayer(layer) && (mCurrentConfig.extendedModeEnabled || mDebugVspClear || analyzer->isProtectedLayer(layer))) {
891 if (mCurrentConfig.frameServerActive && mCurrentConfig.extendedModeEnabled) {
892 // If composed in surface flinger, then stream fbtarget.
893 if ((layer.flags & HWC_SKIP_LAYER) && !analyzer->ignoreVideoSkipFlag()) {
894 continue;
895 }
896
897 /* If the resolution of the video layer is less than QCIF, then we are going to play it in clone mode only.*/
898 uint32_t vidContentWidth = layer.sourceCropf.right - layer.sourceCropf.left;
899 uint32_t vidContentHeight = layer.sourceCropf.bottom - layer.sourceCropf.top;
900 if (vidContentWidth < QCIF_WIDTH || vidContentHeight < QCIF_HEIGHT) {
901 VTRACE("Ingoring layer %d which is too small for extended mode", i);
902 continue;
903 }
904 }
905 mYuvLayer = i;
906 mProtectedMode = analyzer->isProtectedLayer(layer);
907 break;
908 }
909 }
910 #endif
911
912 if (mYuvLayer == -1) {
913 mFirstVideoFrame = true;
914 mDecWidth = 0;
915 mDecHeight = 0;
916 }
917 #ifdef INTEL_WIDI
918 if (mCurrentConfig.frameServerActive && mCurrentConfig.extendedModeEnabled && mYuvLayer != -1) {
919 if (handleExtendedMode(display)) {
920 mYuvLayer = -1;
921 mRgbLayer = -1;
922 // Extended mode is successful.
923 // Fences aren't set in prepare, and we don't need them here, but they'll
924 // be set later and we have to close them. Don't log a warning in this case.
925 mExpectAcquireFences = true;
926 for (ssize_t i = 0; i < fbTarget; i++)
927 display->hwLayers[i].compositionType = HWC_OVERLAY;
928 return true;
929 }
930 // if error in playback file , switch to clone mode
931 WTRACE("Error, falling back to clone mode");
932 mIsForceCloneMode = true;
933 mYuvLayer = -1;
934 }
935 #endif
936 if (mYuvLayer == 0 && fbTarget == 1) {
937 // No RGB layer, so tell queueCompose to use blank RGB in fbtarget.
938 mRgbLayer = -1;
939 }
940 else if (mYuvLayer == 0 && fbTarget == 2) {
941 if (canUseDirectly(display, 1))
942 mRgbLayer = 1;
943 }
944 else if (mYuvLayer == -1 && fbTarget == 1) {
945 if (canUseDirectly(display, 0))
946 mRgbLayer = 0;
947 }
948
949 for (ssize_t i = 0; i < fbTarget; i++) {
950 hwc_layer_1_t& layer = display->hwLayers[i];
951 if (i == mYuvLayer || i == mRgbLayer || mRgbLayer != fbTarget)
952 layer.compositionType = HWC_OVERLAY;
953 else
954 layer.compositionType = HWC_FRAMEBUFFER;
955 }
956 if (mYuvLayer != -1 && mRgbLayer == fbTarget)
957 // This tells SurfaceFlinger to render this layer by writing transparent pixels
958 // to this layer's target region within the framebuffer. This effectively punches
959 // a hole through any content that is supposed to show below the video, and the
960 // video can be seen through this hole when we composite the YUV and RGBA layers
961 // together. Content above will draw on top of this hole and can cover the video.
962 // This has no effect when the video is the bottommost layer.
963 display->hwLayers[mYuvLayer].hints |= HWC_HINT_CLEAR_FB;
964
965 #ifdef INTEL_WIDI
966 // we're streaming fbtarget, so send onFramePrepare and wait for composition to happen
967 if (mCurrentConfig.frameListener != NULL)
968 mCurrentConfig.frameListener->onFramePrepare(mRenderTimestamp, -1);
969 #endif
970 return true;
971 }
972
commit(hwc_display_contents_1_t * display,IDisplayContext * context)973 bool VirtualDevice::commit(hwc_display_contents_1_t *display, IDisplayContext *context)
974 {
975 RETURN_FALSE_IF_NOT_INIT();
976
977 if (display != NULL && (mRgbLayer != -1 || mYuvLayer != -1))
978 sendToWidi(display);
979
980 if (mVspEnabled && !mVspInUse) {
981 mVaMapCache.clear();
982 sp<DisableVspTask> disableVsp = new DisableVspTask();
983 mMappedBufferCache.clear();
984 Mutex::Autolock _l(mTaskLock);
985 mRgbUpscaleBuffers.clear();
986 mTasks.push(disableVsp);
987 mRequestQueued.signal();
988 mVspEnabled = false;
989 }
990
991 if (display != NULL) {
992 // All acquire fences should be copied somewhere else or closed by now
993 // and set to -1 in these structs except in the case of extended mode.
994 // Make sure the fences are closed and log a warning if not in extended mode.
995 if (display->outbufAcquireFenceFd != -1) {
996 if (!mExpectAcquireFences)
997 WTRACE("outbuf acquire fence (fd=%d) not yet saved or closed", display->outbufAcquireFenceFd);
998 CLOSE_FENCE(display->outbufAcquireFenceFd);
999 }
1000 for (size_t i = 0; i < display->numHwLayers; i++) {
1001 hwc_layer_1_t& layer = display->hwLayers[i];
1002 if (layer.acquireFenceFd != -1) {
1003 if (!mExpectAcquireFences && (i < display->numHwLayers-1 || i == (size_t) mRgbLayer))
1004 WTRACE("layer %zd acquire fence (fd=%zd) not yet saved or closed", i, layer.acquireFenceFd);
1005 CLOSE_FENCE(layer.acquireFenceFd);
1006 }
1007 }
1008 }
1009
1010 return true;
1011 }
1012
sendToWidi(hwc_display_contents_1_t * display)1013 bool VirtualDevice::sendToWidi(hwc_display_contents_1_t *display)
1014 {
1015 VTRACE("RGB=%d, YUV=%d", mRgbLayer, mYuvLayer);
1016
1017 if (mYuvLayer == -1 && mRgbLayer == -1)
1018 return true;
1019
1020 if (mYuvLayer != -1) {
1021 mVspInUse = true;
1022 if (queueCompose(display))
1023 return true;
1024 }
1025
1026 return queueColorConvert(display);
1027 }
1028
queueCompose(hwc_display_contents_1_t * display)1029 bool VirtualDevice::queueCompose(hwc_display_contents_1_t *display)
1030 {
1031 hwc_layer_1_t& yuvLayer = display->hwLayers[mYuvLayer];
1032 if (yuvLayer.handle == NULL) {
1033 ETRACE("No video handle");
1034 return false;
1035 }
1036 #ifdef INTEL_WIDI
1037 if (!mCurrentConfig.frameServerActive && display->outbuf == NULL) {
1038 #else
1039 if (display->outbuf == NULL) {
1040 #endif
1041 ETRACE("No outbuf");
1042 return true; // fallback would be pointless
1043 }
1044
1045 sp<ComposeTask> composeTask = new ComposeTask();
1046
1047 sp<RefBase> heldBuffer;
1048 sp<OnFrameReadyTask> frameReadyTask;
1049 Mutex::Autolock _l(mTaskLock);
1050
1051 float upscale_x = 1.0;
1052 float upscale_y = 1.0;
1053 hwc_layer_1_t& fbTarget = display->hwLayers[display->numHwLayers-1];
1054 composeTask->outWidth = fbTarget.sourceCropf.right - fbTarget.sourceCropf.left;
1055 composeTask->outHeight = fbTarget.sourceCropf.bottom - fbTarget.sourceCropf.top;
1056
1057 bool scaleRgb = false;
1058 #ifdef INTEL_WIDI
1059 if (mCurrentConfig.frameServerActive) {
1060 if (mVspUpscale) {
1061 composeTask->outWidth = mCurrentConfig.policy.scaledWidth;
1062 composeTask->outHeight = mCurrentConfig.policy.scaledHeight;
1063 upscale_x = mCurrentConfig.policy.scaledWidth/(fbTarget.sourceCropf.right - fbTarget.sourceCropf.left);
1064 upscale_y = mCurrentConfig.policy.scaledHeight/(fbTarget.sourceCropf.bottom - fbTarget.sourceCropf.top);
1065 scaleRgb = composeTask->outWidth != fbTarget.sourceCropf.right - fbTarget.sourceCropf.left ||
1066 composeTask->outHeight != fbTarget.sourceCropf.bottom - fbTarget.sourceCropf.top;
1067 }
1068
1069 composeTask->outputHandle = mCscBuffers.get(composeTask->outWidth, composeTask->outHeight, &heldBuffer);
1070 if (composeTask->outputHandle == NULL) {
1071 WTRACE("Out of CSC buffers, dropping frame");
1072 return true;
1073 }
1074 } else {
1075 composeTask->outputHandle = display->outbuf;
1076 }
1077 #else
1078 composeTask->outputHandle = display->outbuf;
1079 #endif
1080
1081 vspPrepare(composeTask->outWidth, composeTask->outHeight);
1082
1083 composeTask->videoCachedBuffer = getMappedBuffer(yuvLayer.handle);
1084 if (composeTask->videoCachedBuffer == NULL) {
1085 ETRACE("Couldn't map video handle %p", yuvLayer.handle);
1086 return false;
1087 }
1088 if (composeTask->videoCachedBuffer->mapper == NULL) {
1089 ETRACE("Src mapper gone");
1090 return false;
1091 }
1092 composeTask->heldVideoBuffer = new HeldDecoderBuffer(this, composeTask->videoCachedBuffer);
1093 IVideoPayloadManager::MetaData videoMetadata;
1094 if (!mPayloadManager->getMetaData(composeTask->videoCachedBuffer->mapper, &videoMetadata)) {
1095 ETRACE("Failed to map video payload info");
1096 return false;
1097 }
1098 if (videoMetadata.normalBuffer.width == 0 || videoMetadata.normalBuffer.height == 0) {
1099 ETRACE("Bad video metadata for handle %p", yuvLayer.handle);
1100 return false;
1101 }
1102 if (videoMetadata.normalBuffer.khandle == 0) {
1103 ETRACE("Bad khandle");
1104 return false;
1105 }
1106
1107 VARectangle& output_region = composeTask->output_region;
1108 output_region.x = static_cast<uint32_t>(yuvLayer.displayFrame.left*upscale_x) & ~1;
1109 output_region.y = static_cast<uint32_t>(yuvLayer.displayFrame.top*upscale_y) & ~1;
1110 output_region.width = (static_cast<uint32_t>(yuvLayer.displayFrame.right*upscale_y+1) & ~1) - output_region.x;
1111 output_region.height = (static_cast<uint32_t>(yuvLayer.displayFrame.bottom*upscale_y+1) & ~1) - output_region.y;
1112
1113 uint32_t videoWidth;
1114 uint32_t videoHeight;
1115 if (videoMetadata.transform == 0 || videoMetadata.transform == HAL_TRANSFORM_ROT_180) {
1116 videoWidth = videoMetadata.normalBuffer.width;
1117 videoHeight = videoMetadata.normalBuffer.height;
1118 } else {
1119 videoWidth = videoMetadata.normalBuffer.height;
1120 videoHeight = videoMetadata.normalBuffer.width;
1121 }
1122
1123 // Layer source crop info is based on an unrotated, unscaled buffer.
1124 // Rotate the rectangle to get the source crop we'd use for a rotated, unscaled buffer.
1125 hwc_frect_t rotatedCrop;
1126 switch (videoMetadata.transform) {
1127 default:
1128 rotatedCrop = yuvLayer.sourceCropf;
1129 break;
1130 case HAL_TRANSFORM_ROT_90:
1131 rotatedCrop.left = yuvLayer.sourceCropf.top;
1132 rotatedCrop.top = videoHeight - yuvLayer.sourceCropf.right;
1133 rotatedCrop.right = yuvLayer.sourceCropf.bottom;
1134 rotatedCrop.bottom = videoHeight - yuvLayer.sourceCropf.left;
1135 break;
1136 case HAL_TRANSFORM_ROT_180:
1137 rotatedCrop.left = videoWidth - yuvLayer.sourceCropf.right;
1138 rotatedCrop.top = videoHeight - yuvLayer.sourceCropf.bottom;
1139 rotatedCrop.right = videoWidth - yuvLayer.sourceCropf.left;
1140 rotatedCrop.bottom = videoHeight - yuvLayer.sourceCropf.top;
1141 break;
1142 case HAL_TRANSFORM_ROT_270:
1143 rotatedCrop.left = videoWidth - yuvLayer.sourceCropf.bottom;
1144 rotatedCrop.top = yuvLayer.sourceCropf.left;
1145 rotatedCrop.right = videoWidth - yuvLayer.sourceCropf.top;
1146 rotatedCrop.bottom = yuvLayer.sourceCropf.right;
1147 break;
1148 }
1149
1150 float factor_x = output_region.width / (rotatedCrop.right - rotatedCrop.left);
1151 float factor_y = output_region.height / (rotatedCrop.bottom - rotatedCrop.top);
1152
1153 uint32_t scaleWidth = videoWidth * factor_x;
1154 uint32_t scaleHeight = videoHeight * factor_y;
1155
1156 scaleWidth &= ~1;
1157 scaleHeight &= ~1;
1158
1159 IVideoPayloadManager::Buffer info;
1160 if (!getFrameOfSize(scaleWidth, scaleHeight, videoMetadata, info)) {
1161 //Returning true as else we fall into the queueColorConvert
1162 //resulting into scrambled frames for protected content.
1163 ITRACE("scaled frame not yet available.");
1164 return true;
1165 }
1166
1167 composeTask->videoKhandle = info.khandle;
1168 composeTask->videoStride = info.lumaStride;
1169 composeTask->videoBufHeight = info.bufHeight;
1170 composeTask->videoTiled = info.tiled;
1171
1172 // rotatedCrop accounts for rotation. Now account for any scaling along each dimension.
1173 hwc_frect_t scaledCrop = rotatedCrop;
1174 if (info.width < videoWidth) {
1175 float factor = static_cast<float>(info.width) / videoWidth;
1176 scaledCrop.left *= factor;
1177 scaledCrop.right *= factor;
1178 }
1179 if (info.height < videoHeight) {
1180 float factor = static_cast<float>(info.height) / videoHeight;
1181 scaledCrop.top *= factor;
1182 scaledCrop.bottom *= factor;
1183 }
1184
1185 VARectangle& surface_region = composeTask->surface_region;
1186 surface_region.x = static_cast<int>(scaledCrop.left) + info.offsetX;
1187 surface_region.y = static_cast<int>(scaledCrop.top) + info.offsetY;
1188 surface_region.width = static_cast<int>(scaledCrop.right - scaledCrop.left);
1189 surface_region.height = static_cast<int>(scaledCrop.bottom - scaledCrop.top);
1190
1191 VTRACE("Want to take (%d,%d)-(%d,%d) region from %dx%d video (in %dx%d buffer) and output to (%d,%d)-(%d,%d)",
1192 surface_region.x, surface_region.y,
1193 surface_region.x + surface_region.width, surface_region.y + surface_region.height,
1194 info.width, info.height,
1195 info.bufWidth, info.bufHeight,
1196 output_region.x, output_region.y,
1197 output_region.x + output_region.width, output_region.y + output_region.height);
1198
1199 if (surface_region.x + surface_region.width > static_cast<int>(info.width + info.offsetX) ||
1200 surface_region.y + surface_region.height > static_cast<int>(info.height + info.offsetY))
1201 {
1202 ETRACE("Source crop exceeds video dimensions: (%d,%d)-(%d,%d) > %ux%u",
1203 surface_region.x, surface_region.y,
1204 surface_region.x + surface_region.width, surface_region.y + surface_region.height,
1205 info.width, info.height);
1206 return false;
1207 }
1208
1209 if (surface_region.width > output_region.width || surface_region.height > output_region.height) {
1210 // VSP can upscale but can't downscale video, so use blank video
1211 // until we start getting downscaled frames.
1212 surface_region.x = 0;
1213 surface_region.y = 0;
1214 surface_region.width = composeTask->outWidth;
1215 surface_region.height = composeTask->outHeight;
1216 output_region = surface_region;
1217 composeTask->videoKhandle = 0;
1218 composeTask->videoStride = composeTask->outWidth;
1219 composeTask->videoBufHeight = composeTask->outHeight;
1220 composeTask->videoTiled = false;
1221 }
1222
1223 composeTask->yuvAcquireFenceFd = yuvLayer.acquireFenceFd;
1224 yuvLayer.acquireFenceFd = -1;
1225
1226 composeTask->outbufAcquireFenceFd = display->outbufAcquireFenceFd;
1227 display->outbufAcquireFenceFd = -1;
1228
1229 int retireFd = sw_sync_fence_create(mSyncTimelineFd, "widi_compose_retire", mNextSyncPoint);
1230 yuvLayer.releaseFenceFd = retireFd;
1231
1232 if (mRgbLayer == -1) {
1233 CLOSE_FENCE(fbTarget.acquireFenceFd);
1234 } else {
1235 hwc_layer_1_t& rgbLayer = display->hwLayers[mRgbLayer];
1236 composeTask->rgbAcquireFenceFd = rgbLayer.acquireFenceFd;
1237 rgbLayer.acquireFenceFd = -1;
1238 rgbLayer.releaseFenceFd = dup(retireFd);
1239 }
1240
1241 mNextSyncPoint++;
1242 composeTask->syncTimelineFd = mSyncTimelineFd;
1243
1244 if (mRgbLayer != -1)
1245 {
1246 hwc_layer_1_t& rgbLayer = display->hwLayers[mRgbLayer];
1247 if (rgbLayer.handle == NULL) {
1248 ETRACE("No RGB handle");
1249 return false;
1250 }
1251
1252 if (scaleRgb) {
1253 buffer_handle_t scalingBuffer;
1254 sp<RefBase> heldUpscaleBuffer;
1255 while ((scalingBuffer = mRgbUpscaleBuffers.get(composeTask->outWidth, composeTask->outHeight, &heldUpscaleBuffer)) == NULL &&
1256 !mTasks.empty()) {
1257 VTRACE("Waiting for free RGB upscale buffer...");
1258 mRequestDequeued.wait(mTaskLock);
1259 }
1260 if (scalingBuffer == NULL) {
1261 ETRACE("Couldn't get scaling buffer");
1262 return false;
1263 }
1264 BufferManager* mgr = mHwc.getBufferManager();
1265 crop_t destRect;
1266 destRect.x = 0;
1267 destRect.y = 0;
1268 destRect.w = composeTask->outWidth;
1269 destRect.h = composeTask->outHeight;
1270 if (!mgr->blit(rgbLayer.handle, scalingBuffer, destRect, true, true))
1271 return true;
1272 composeTask->rgbHandle = scalingBuffer;
1273 composeTask->heldRgbHandle = heldUpscaleBuffer;
1274 }
1275 else {
1276 unsigned int pixel_format = VA_FOURCC_BGRA;
1277 const IMG_native_handle_t* nativeHandle = reinterpret_cast<const IMG_native_handle_t*>(rgbLayer.handle);
1278 if (nativeHandle->iFormat == HAL_PIXEL_FORMAT_RGBA_8888)
1279 pixel_format = VA_FOURCC_RGBA;
1280 mRgbUpscaleBuffers.clear();
1281 ssize_t index = mVaMapCache.indexOfKey(rgbLayer.handle);
1282 if (index == NAME_NOT_FOUND) {
1283 composeTask->mappedRgbIn = new VAMappedHandleObject(va_dpy, rgbLayer.handle, composeTask->outWidth, composeTask->outHeight, pixel_format);
1284 mVaMapCache.add(rgbLayer.handle, composeTask->mappedRgbIn);
1285 }
1286 else
1287 composeTask->mappedRgbIn = mVaMapCache[index];
1288 if (composeTask->mappedRgbIn->surface == 0) {
1289 ETRACE("Unable to map RGB surface");
1290 return false;
1291 }
1292 }
1293 }
1294 else
1295 composeTask->mappedRgbIn = NULL;
1296
1297 mTasks.push_back(composeTask);
1298 mRequestQueued.signal();
1299 #ifdef INTEL_WIDI
1300 if (mCurrentConfig.frameServerActive) {
1301
1302 FrameInfo inputFrameInfo;
1303 memset(&inputFrameInfo, 0, sizeof(inputFrameInfo));
1304 inputFrameInfo.isProtected = mProtectedMode;
1305 inputFrameInfo.frameType = HWC_FRAMETYPE_FRAME_BUFFER;
1306 if (mVspUpscale) {
1307 float upscale_x = (rotatedCrop.right - rotatedCrop.left) /
1308 (yuvLayer.displayFrame.right - yuvLayer.displayFrame.left);
1309 float upscale_y = (rotatedCrop.bottom - rotatedCrop.top) /
1310 (yuvLayer.displayFrame.bottom - yuvLayer.displayFrame.top);
1311 float upscale = upscale_x > upscale_y ? upscale_x : upscale_y;
1312 if (upscale <= 1.0)
1313 upscale = 1.0;
1314 inputFrameInfo.contentWidth = (fbTarget.sourceCropf.right - fbTarget.sourceCropf.left)*upscale;
1315 inputFrameInfo.contentHeight = (fbTarget.sourceCropf.bottom - fbTarget.sourceCropf.top)*upscale;
1316 }
1317 else {
1318 inputFrameInfo.contentWidth = composeTask->outWidth;
1319 inputFrameInfo.contentHeight = composeTask->outHeight;
1320 }
1321 inputFrameInfo.contentFrameRateN = 0;
1322 inputFrameInfo.contentFrameRateD = 0;
1323 FrameInfo outputFrameInfo = inputFrameInfo;
1324
1325 BufferManager* mgr = mHwc.getBufferManager();
1326 DataBuffer* dataBuf = mgr->lockDataBuffer(composeTask->outputHandle);
1327 outputFrameInfo.contentWidth = composeTask->outWidth;
1328 outputFrameInfo.contentHeight = composeTask->outHeight;
1329 outputFrameInfo.bufferWidth = dataBuf->getWidth();
1330 outputFrameInfo.bufferHeight = dataBuf->getHeight();
1331 outputFrameInfo.lumaUStride = dataBuf->getWidth();
1332 outputFrameInfo.chromaUStride = dataBuf->getWidth();
1333 outputFrameInfo.chromaVStride = dataBuf->getWidth();
1334 mgr->unlockDataBuffer(dataBuf);
1335
1336 queueFrameTypeInfo(inputFrameInfo);
1337 if (mCurrentConfig.policy.scaledWidth == 0 || mCurrentConfig.policy.scaledHeight == 0)
1338 return true; // This isn't a failure, WiDi just doesn't want frames right now.
1339 queueBufferInfo(outputFrameInfo);
1340
1341 if (mCurrentConfig.frameListener != NULL) {
1342 frameReadyTask = new OnFrameReadyTask();
1343 frameReadyTask->renderTask = composeTask;
1344 frameReadyTask->heldBuffer = heldBuffer;
1345 frameReadyTask->frameListener = mCurrentConfig.frameListener;
1346 frameReadyTask->handle = composeTask->outputHandle;
1347 frameReadyTask->handleType = HWC_HANDLE_TYPE_GRALLOC;
1348 frameReadyTask->renderTimestamp = mRenderTimestamp;
1349 frameReadyTask->mediaTimestamp = -1;
1350 mTasks.push_back(frameReadyTask);
1351 }
1352 }
1353 else {
1354 display->retireFenceFd = dup(retireFd);
1355 }
1356 #else
1357 display->retireFenceFd = dup(retireFd);
1358 #endif
1359
1360 return true;
1361 }
1362
1363 bool VirtualDevice::queueColorConvert(hwc_display_contents_1_t *display)
1364 {
1365 if (mRgbLayer == -1) {
1366 ETRACE("RGB layer not set");
1367 return false;
1368 }
1369 hwc_layer_1_t& layer = display->hwLayers[mRgbLayer];
1370 if (layer.handle == NULL) {
1371 ETRACE("RGB layer has no handle set");
1372 return false;
1373 }
1374 if (display->outbuf == NULL) {
1375 ETRACE("outbuf is not set");
1376 return false;
1377 }
1378
1379 {
1380 const IMG_native_handle_t* nativeSrcHandle = reinterpret_cast<const IMG_native_handle_t*>(layer.handle);
1381 const IMG_native_handle_t* nativeDestHandle = reinterpret_cast<const IMG_native_handle_t*>(display->outbuf);
1382
1383 if ((nativeSrcHandle->iFormat == HAL_PIXEL_FORMAT_RGBA_8888 &&
1384 nativeDestHandle->iFormat == HAL_PIXEL_FORMAT_BGRA_8888) ||
1385 (nativeSrcHandle->iFormat == HAL_PIXEL_FORMAT_BGRA_8888 &&
1386 nativeDestHandle->iFormat == HAL_PIXEL_FORMAT_RGBA_8888))
1387 {
1388 SYNC_WAIT_AND_CLOSE(layer.acquireFenceFd);
1389 SYNC_WAIT_AND_CLOSE(display->outbufAcquireFenceFd);
1390 display->retireFenceFd = -1;
1391
1392 // synchronous in this case
1393 colorSwap(layer.handle, display->outbuf, ((nativeSrcHandle->iWidth+31)&~31)*nativeSrcHandle->iHeight);
1394 // Workaround: Don't keep cached buffers. If the VirtualDisplaySurface gets destroyed,
1395 // these would be unmapped on the next frame, after the buffers are destroyed,
1396 // which is causing heap corruption, probably due to a double-free somewhere.
1397 mMappedBufferCache.clear();
1398 return true;
1399 }
1400 }
1401
1402 sp<BlitTask> blitTask = new BlitTask();
1403 sp<OnFrameReadyTask> frameReadyTask;
1404 blitTask->destRect.x = 0;
1405 blitTask->destRect.y = 0;
1406 blitTask->destRect.w = layer.sourceCropf.right - layer.sourceCropf.left;
1407 blitTask->destRect.h = layer.sourceCropf.bottom - layer.sourceCropf.top;
1408 blitTask->srcHandle = layer.handle;
1409
1410 sp<RefBase> heldBuffer;
1411 Mutex::Autolock _l(mTaskLock);
1412
1413 blitTask->srcAcquireFenceFd = layer.acquireFenceFd;
1414 layer.acquireFenceFd = -1;
1415
1416 blitTask->syncTimelineFd = mSyncTimelineFd;
1417 // Framebuffer after BlitTask::run() calls sw_sync_timeline_inc().
1418 layer.releaseFenceFd = sw_sync_fence_create(mSyncTimelineFd, "widi_blit_retire", mNextSyncPoint);
1419 mNextSyncPoint++;
1420 #ifdef INTEL_WIDI
1421 if (mCurrentConfig.frameServerActive) {
1422 blitTask->destHandle = mCscBuffers.get(blitTask->destRect.w, blitTask->destRect.h, &heldBuffer);
1423 blitTask->destAcquireFenceFd = -1;
1424
1425 // we do not use retire fence in frameServerActive path.
1426 CLOSE_FENCE(display->retireFenceFd);
1427
1428 // we use our own buffer, so just close this fence without a wait
1429 CLOSE_FENCE(display->outbufAcquireFenceFd);
1430 }
1431 else {
1432 blitTask->destHandle = display->outbuf;
1433 blitTask->destAcquireFenceFd = display->outbufAcquireFenceFd;
1434 // don't let TngDisplayContext::commitEnd() close this
1435 display->outbufAcquireFenceFd = -1;
1436 display->retireFenceFd = dup(layer.releaseFenceFd);
1437 }
1438 #else
1439 blitTask->destHandle = display->outbuf;
1440 blitTask->destAcquireFenceFd = display->outbufAcquireFenceFd;
1441 // don't let TngDisplayContext::commitEnd() close this
1442 display->outbufAcquireFenceFd = -1;
1443 display->retireFenceFd = dup(layer.releaseFenceFd);
1444 #endif
1445 if (blitTask->destHandle == NULL) {
1446 WTRACE("Out of CSC buffers, dropping frame");
1447 return false;
1448 }
1449
1450 mTasks.push_back(blitTask);
1451 mRequestQueued.signal();
1452 #ifdef INTEL_WIDI
1453 if (mCurrentConfig.frameServerActive) {
1454 FrameInfo inputFrameInfo;
1455 memset(&inputFrameInfo, 0, sizeof(inputFrameInfo));
1456 inputFrameInfo.isProtected = mProtectedMode;
1457 FrameInfo outputFrameInfo;
1458
1459 inputFrameInfo.frameType = HWC_FRAMETYPE_FRAME_BUFFER;
1460 inputFrameInfo.contentWidth = blitTask->destRect.w;
1461 inputFrameInfo.contentHeight = blitTask->destRect.h;
1462 inputFrameInfo.contentFrameRateN = 0;
1463 inputFrameInfo.contentFrameRateD = 0;
1464 outputFrameInfo = inputFrameInfo;
1465
1466 BufferManager* mgr = mHwc.getBufferManager();
1467 DataBuffer* dataBuf = mgr->lockDataBuffer(blitTask->destHandle);
1468 outputFrameInfo.bufferWidth = dataBuf->getWidth();
1469 outputFrameInfo.bufferHeight = dataBuf->getHeight();
1470 outputFrameInfo.lumaUStride = dataBuf->getWidth();
1471 outputFrameInfo.chromaUStride = dataBuf->getWidth();
1472 outputFrameInfo.chromaVStride = dataBuf->getWidth();
1473 mgr->unlockDataBuffer(dataBuf);
1474
1475 if (!mIsForceCloneMode)
1476 queueFrameTypeInfo(inputFrameInfo);
1477
1478 if (mCurrentConfig.policy.scaledWidth == 0 || mCurrentConfig.policy.scaledHeight == 0)
1479 return true; // This isn't a failure, WiDi just doesn't want frames right now.
1480 queueBufferInfo(outputFrameInfo);
1481
1482 if (mCurrentConfig.frameListener != NULL) {
1483 frameReadyTask = new OnFrameReadyTask();
1484 frameReadyTask->renderTask = blitTask;
1485 frameReadyTask->heldBuffer = heldBuffer;
1486 frameReadyTask->frameListener = mCurrentConfig.frameListener;
1487 frameReadyTask->handle = blitTask->destHandle;
1488 frameReadyTask->handleType = HWC_HANDLE_TYPE_GRALLOC;
1489 frameReadyTask->renderTimestamp = mRenderTimestamp;
1490 frameReadyTask->mediaTimestamp = -1;
1491 mTasks.push_back(frameReadyTask);
1492 }
1493 }
1494 #endif
1495 return true;
1496 }
1497 #ifdef INTEL_WIDI
1498 bool VirtualDevice::handleExtendedMode(hwc_display_contents_1_t *display)
1499 {
1500 FrameInfo inputFrameInfo;
1501 memset(&inputFrameInfo, 0, sizeof(inputFrameInfo));
1502 inputFrameInfo.isProtected = mProtectedMode;
1503
1504 hwc_layer_1_t& layer = display->hwLayers[mYuvLayer];
1505 if (layer.handle == NULL) {
1506 ETRACE("video layer has no handle set");
1507 return false;
1508 }
1509 sp<CachedBuffer> cachedBuffer;
1510 if ((cachedBuffer = getMappedBuffer(layer.handle)) == NULL) {
1511 ETRACE("Failed to map display buffer");
1512 return false;
1513 }
1514
1515 inputFrameInfo.frameType = HWC_FRAMETYPE_VIDEO;
1516 // for video mode let 30 fps be the default value.
1517 inputFrameInfo.contentFrameRateN = 30;
1518 inputFrameInfo.contentFrameRateD = 1;
1519
1520 IVideoPayloadManager::MetaData metadata;
1521 if (!mPayloadManager->getMetaData(cachedBuffer->mapper, &metadata)) {
1522 ETRACE("Failed to get metadata");
1523 return false;
1524 }
1525
1526 if (metadata.transform == 0 || metadata.transform == HAL_TRANSFORM_ROT_180) {
1527 inputFrameInfo.contentWidth = metadata.normalBuffer.width;
1528 inputFrameInfo.contentHeight = metadata.normalBuffer.height;
1529 } else {
1530 inputFrameInfo.contentWidth = metadata.normalBuffer.height;
1531 inputFrameInfo.contentHeight = metadata.normalBuffer.width;
1532 // 90 and 270 have some issues that appear to be decoder bugs
1533 ITRACE("Skipping extended mode due to rotation of 90 or 270");
1534 return false;
1535 }
1536 // Use the crop size if something changed derive it again..
1537 // Only get video source info if frame rate has not been initialized.
1538 // getVideoSourceInfo() is a fairly expensive operation. This optimization
1539 // will save us a few milliseconds per frame
1540 if (mFirstVideoFrame || (mOrigContentWidth != metadata.normalBuffer.width) ||
1541 (mOrigContentHeight != metadata.normalBuffer.height)) {
1542 mVideoFramerate = inputFrameInfo.contentFrameRateN;
1543 VTRACE("VideoWidth = %d, VideoHeight = %d", metadata.normalBuffer.width, metadata.normalBuffer.height);
1544 mOrigContentWidth = metadata.normalBuffer.width;
1545 mOrigContentHeight = metadata.normalBuffer.height;
1546
1547 // For the first video session by default
1548 int sessionID = Hwcomposer::getInstance().getDisplayAnalyzer()->getFirstVideoInstanceSessionID();
1549 if (sessionID >= 0) {
1550 ITRACE("Session id = %d", sessionID);
1551 VideoSourceInfo videoInfo;
1552 memset(&videoInfo, 0, sizeof(videoInfo));
1553 status_t ret = mHwc.getMultiDisplayObserver()->getVideoSourceInfo(sessionID, &videoInfo);
1554 if (ret == NO_ERROR) {
1555 ITRACE("width = %d, height = %d, fps = %d", videoInfo.width, videoInfo.height,
1556 videoInfo.frameRate);
1557 if (videoInfo.frameRate > 0) {
1558 mVideoFramerate = videoInfo.frameRate;
1559 }
1560 }
1561 }
1562 mFirstVideoFrame = false;
1563 }
1564 inputFrameInfo.contentFrameRateN = mVideoFramerate;
1565 inputFrameInfo.contentFrameRateD = 1;
1566
1567 sp<ComposeTask> composeTask;
1568 sp<RefBase> heldBuffer;
1569 Mutex::Autolock _l(mTaskLock);
1570
1571 if (mCurrentConfig.policy.scaledWidth == 0 || mCurrentConfig.policy.scaledHeight == 0) {
1572 queueFrameTypeInfo(inputFrameInfo);
1573 return true; // This isn't a failure, WiDi just doesn't want frames right now.
1574 }
1575
1576 IVideoPayloadManager::Buffer info;
1577 if (!getFrameOfSize(mCurrentConfig.policy.scaledWidth, mCurrentConfig.policy.scaledHeight, metadata, info)) {
1578 ITRACE("Extended mode waiting for scaled frame");
1579 return false;
1580 }
1581
1582 queueFrameTypeInfo(inputFrameInfo);
1583
1584 heldBuffer = new HeldDecoderBuffer(this, cachedBuffer);
1585 int64_t mediaTimestamp = metadata.timestamp;
1586
1587 VARectangle surface_region;
1588 surface_region.x = info.offsetX;
1589 surface_region.y = info.offsetY;
1590 surface_region.width = info.width;
1591 surface_region.height = info.height;
1592 FrameInfo outputFrameInfo = inputFrameInfo;
1593 outputFrameInfo.bufferFormat = metadata.format;
1594
1595 outputFrameInfo.contentWidth = info.width;
1596 outputFrameInfo.contentHeight = info.height;
1597 outputFrameInfo.bufferWidth = info.bufWidth;
1598 outputFrameInfo.bufferHeight = info.bufHeight;
1599 outputFrameInfo.lumaUStride = info.lumaStride;
1600 outputFrameInfo.chromaUStride = info.chromaUStride;
1601 outputFrameInfo.chromaVStride = info.chromaVStride;
1602
1603 if (outputFrameInfo.bufferFormat == 0 ||
1604 outputFrameInfo.bufferWidth < outputFrameInfo.contentWidth ||
1605 outputFrameInfo.bufferHeight < outputFrameInfo.contentHeight ||
1606 outputFrameInfo.contentWidth <= 0 || outputFrameInfo.contentHeight <= 0 ||
1607 outputFrameInfo.lumaUStride <= 0 ||
1608 outputFrameInfo.chromaUStride <= 0 || outputFrameInfo.chromaVStride <= 0) {
1609 ITRACE("Payload cleared or inconsistent info, not sending frame");
1610 ITRACE("outputFrameInfo.bufferFormat = %d ", outputFrameInfo.bufferFormat);
1611 ITRACE("outputFrameInfo.bufferWidth = %d ", outputFrameInfo.bufferWidth);
1612 ITRACE("outputFrameInfo.contentWidth = %d ", outputFrameInfo.contentWidth);
1613 ITRACE("outputFrameInfo.bufferHeight = %d ", outputFrameInfo.bufferHeight);
1614 ITRACE("outputFrameInfo.contentHeight = %d ", outputFrameInfo.contentHeight);
1615 ITRACE("outputFrameInfo.lumaUStride = %d ", outputFrameInfo.lumaUStride);
1616 ITRACE("outputFrameInfo.chromaUStride = %d ", outputFrameInfo.chromaUStride);
1617 ITRACE("outputFrameInfo.chromaVStride = %d ", outputFrameInfo.chromaVStride);
1618 return false;
1619 }
1620
1621 if (mCurrentConfig.policy.scaledWidth == 0 || mCurrentConfig.policy.scaledHeight == 0)
1622 return true; // This isn't a failure, WiDi just doesn't want frames right now.
1623
1624 if (info.khandle == mExtLastKhandle && mediaTimestamp == mExtLastTimestamp) {
1625 // Same frame again. We don't send a frame, but we return true because
1626 // this isn't an error.
1627 if (metadata.transform != 0)
1628 mVspInUse = true; // Don't shut down VSP just to start it again really quick.
1629 return true;
1630 }
1631 mExtLastKhandle = info.khandle;
1632 mExtLastTimestamp = mediaTimestamp;
1633
1634 HWCBufferHandleType handleType = HWC_HANDLE_TYPE_KBUF;
1635
1636 buffer_handle_t handle = info.khandle;
1637
1638 // Ideally we'd check if there's an offset (info.offsetX > 0 || info.offsetY > 0),
1639 // so we use VSP only when cropping is needed. But using the khandle directly when
1640 // both rotation and scaling are involved can encode the frame with the wrong
1641 // tiling status, so use VSP to normalize if any rotation is involved.
1642 if (metadata.transform != 0) {
1643 // Cropping (or above workaround) needed, so use VSP to do it.
1644 mVspInUse = true;
1645 vspPrepare(info.width, info.height);
1646
1647 composeTask = new ComposeTask();
1648 composeTask->heldVideoBuffer = heldBuffer;
1649 heldBuffer = NULL;
1650 composeTask->outWidth = info.width;
1651 composeTask->outHeight = info.height;
1652 composeTask->outputHandle = mCscBuffers.get(composeTask->outWidth, composeTask->outHeight, &heldBuffer);
1653 if (composeTask->outputHandle == NULL) {
1654 ITRACE("Out of CSC buffers, dropping frame");
1655 return true;
1656 }
1657
1658 composeTask->surface_region = surface_region;
1659 composeTask->videoCachedBuffer = cachedBuffer;
1660 VARectangle& output_region = composeTask->output_region;
1661 output_region.x = 0;
1662 output_region.y = 0;
1663 output_region.width = info.width;
1664 output_region.height = info.height;
1665
1666 composeTask->videoKhandle = info.khandle;
1667 composeTask->videoStride = info.lumaStride;
1668 composeTask->videoBufHeight = info.bufHeight;
1669 composeTask->videoTiled = info.tiled;
1670
1671 BufferManager* mgr = mHwc.getBufferManager();
1672 DataBuffer* dataBuf = mgr->lockDataBuffer(composeTask->outputHandle);
1673 outputFrameInfo.contentWidth = composeTask->outWidth;
1674 outputFrameInfo.contentHeight = composeTask->outHeight;
1675 outputFrameInfo.bufferWidth = dataBuf->getWidth();
1676 outputFrameInfo.bufferHeight = dataBuf->getHeight();
1677 outputFrameInfo.lumaUStride = dataBuf->getWidth();
1678 outputFrameInfo.chromaUStride = dataBuf->getWidth();
1679 outputFrameInfo.chromaVStride = dataBuf->getWidth();
1680 mgr->unlockDataBuffer(dataBuf);
1681
1682 handle = composeTask->outputHandle;
1683 handleType = HWC_HANDLE_TYPE_GRALLOC;
1684
1685 mTasks.push_back(composeTask);
1686 mRequestQueued.signal();
1687 }
1688
1689 queueBufferInfo(outputFrameInfo);
1690
1691 if (mCurrentConfig.frameListener != NULL) {
1692 sp<OnFrameReadyTask> frameReadyTask = new OnFrameReadyTask();
1693 frameReadyTask->renderTask = composeTask;
1694 frameReadyTask->heldBuffer = heldBuffer;
1695 frameReadyTask->frameListener = mCurrentConfig.frameListener;
1696 frameReadyTask->handle = handle;
1697 frameReadyTask->handleType = handleType;
1698 frameReadyTask->renderTimestamp = mRenderTimestamp;
1699 frameReadyTask->mediaTimestamp = mediaTimestamp;
1700
1701 mTasks.push_back(frameReadyTask);
1702 mRequestQueued.signal();
1703 }
1704
1705 return true;
1706 }
1707
1708 void VirtualDevice::queueFrameTypeInfo(const FrameInfo& inputFrameInfo)
1709 {
1710 if (mCurrentConfig.forceNotifyFrameType ||
1711 memcmp(&inputFrameInfo, &mLastInputFrameInfo, sizeof(inputFrameInfo)) != 0) {
1712 // something changed, notify type change listener
1713 mNextConfig.forceNotifyFrameType = false;
1714 mLastInputFrameInfo = inputFrameInfo;
1715
1716 sp<FrameTypeChangedTask> notifyTask = new FrameTypeChangedTask;
1717 notifyTask->typeChangeListener = mCurrentConfig.typeChangeListener;
1718 notifyTask->inputFrameInfo = inputFrameInfo;
1719 mTasks.push_back(notifyTask);
1720 }
1721 }
1722
1723 void VirtualDevice::queueBufferInfo(const FrameInfo& outputFrameInfo)
1724 {
1725 if (mCurrentConfig.forceNotifyBufferInfo ||
1726 memcmp(&outputFrameInfo, &mLastOutputFrameInfo, sizeof(outputFrameInfo)) != 0) {
1727 mNextConfig.forceNotifyBufferInfo = false;
1728 mLastOutputFrameInfo = outputFrameInfo;
1729
1730 sp<BufferInfoChangedTask> notifyTask = new BufferInfoChangedTask;
1731 notifyTask->typeChangeListener = mCurrentConfig.typeChangeListener;
1732 notifyTask->outputFrameInfo = outputFrameInfo;
1733
1734 //if (handleType == HWC_HANDLE_TYPE_GRALLOC)
1735 // mMappedBufferCache.clear(); // !
1736 mTasks.push_back(notifyTask);
1737 }
1738 }
1739 #endif
1740
1741 void VirtualDevice::colorSwap(buffer_handle_t src, buffer_handle_t dest, uint32_t pixelCount)
1742 {
1743 sp<CachedBuffer> srcCachedBuffer;
1744 sp<CachedBuffer> destCachedBuffer;
1745
1746 {
1747 srcCachedBuffer = getMappedBuffer(src);
1748 if (srcCachedBuffer == NULL || srcCachedBuffer->mapper == NULL)
1749 return;
1750 destCachedBuffer = getMappedBuffer(dest);
1751 if (destCachedBuffer == NULL || destCachedBuffer->mapper == NULL)
1752 return;
1753 }
1754
1755 uint8_t* srcPtr = static_cast<uint8_t*>(srcCachedBuffer->mapper->getCpuAddress(0));
1756 uint8_t* destPtr = static_cast<uint8_t*>(destCachedBuffer->mapper->getCpuAddress(0));
1757 if (srcPtr == NULL || destPtr == NULL)
1758 return;
1759 while (pixelCount > 0) {
1760 destPtr[0] = srcPtr[2];
1761 destPtr[1] = srcPtr[1];
1762 destPtr[2] = srcPtr[0];
1763 destPtr[3] = srcPtr[3];
1764 srcPtr += 4;
1765 destPtr += 4;
1766 pixelCount--;
1767 }
1768 }
1769
1770 void VirtualDevice::vspPrepare(uint32_t width, uint32_t height)
1771 {
1772 if (mVspEnabled && width == mVspWidth && height == mVspHeight)
1773 return;
1774
1775 if (mVspEnabled)
1776 {
1777 ITRACE("Going to switch VSP from %ux%u to %ux%u", mVspWidth, mVspHeight, width, height);
1778 mMappedBufferCache.clear();
1779 mVaMapCache.clear();
1780 sp<DisableVspTask> disableVsp = new DisableVspTask();
1781 mTasks.push_back(disableVsp);
1782 }
1783 mVspWidth = width;
1784 mVspHeight = height;
1785
1786 sp<EnableVspTask> enableTask = new EnableVspTask();
1787 enableTask->width = width;
1788 enableTask->height = height;
1789 mTasks.push_back(enableTask);
1790 mRequestQueued.signal();
1791 // to map a buffer from this thread, we need this task to complete on the other thread
1792 while (enableTask->getStrongCount() > 1) {
1793 VTRACE("Waiting for WidiBlit thread to enable VSP...");
1794 mRequestDequeued.wait(mTaskLock);
1795 }
1796 mVspEnabled = true;
1797 }
1798
1799 void VirtualDevice::vspEnable(uint32_t width, uint32_t height)
1800 {
1801 width = align_width(width);
1802 height = align_height(height);
1803 ITRACE("Start VSP at %ux%u", width, height);
1804 VAStatus va_status;
1805
1806 int display = 0;
1807 int major_ver, minor_ver;
1808 va_dpy = vaGetDisplay(&display);
1809 va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
1810 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaInitialize returns %08x", va_status);
1811
1812 VAConfigAttrib va_attr;
1813 va_attr.type = VAConfigAttribRTFormat;
1814 va_status = vaGetConfigAttributes(va_dpy,
1815 VAProfileNone,
1816 VAEntrypointVideoProc,
1817 &va_attr,
1818 1);
1819 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaGetConfigAttributes returns %08x", va_status);
1820
1821 va_status = vaCreateConfig(
1822 va_dpy,
1823 VAProfileNone,
1824 VAEntrypointVideoProc,
1825 &(va_attr),
1826 1,
1827 &va_config
1828 );
1829 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaCreateConfig returns %08x", va_status);
1830
1831 VADisplayAttribute attr;
1832 attr.type = VADisplayAttribRenderMode;
1833 attr.value = VA_RENDER_MODE_LOCAL_OVERLAY;
1834 va_status = vaSetDisplayAttributes(va_dpy, &attr, 1);
1835 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaSetDisplayAttributes returns %08x", va_status);
1836
1837
1838 va_status = vaCreateSurfaces(
1839 va_dpy,
1840 VA_RT_FORMAT_YUV420,
1841 width,
1842 height,
1843 &va_blank_yuv_in,
1844 1,
1845 NULL,
1846 0);
1847 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaCreateSurfaces (video in) returns %08x", va_status);
1848
1849 unsigned long buffer;
1850 VASurfaceAttribExternalBuffers buf;
1851 int stride = align_width(width);
1852 int bufHeight = align_height(height);
1853 buf.pixel_format = VA_FOURCC_RGBA;
1854 buf.width = width;
1855 buf.height = height;
1856 buf.data_size = stride * bufHeight * 4;
1857 buf.num_planes = 3;
1858 buf.pitches[0] = stride;
1859 buf.pitches[1] = stride;
1860 buf.pitches[2] = stride;
1861 buf.pitches[3] = 0;
1862 buf.offsets[0] = 0;
1863 buf.offsets[1] = stride * bufHeight;
1864 buf.offsets[2] = buf.offsets[1];
1865 buf.offsets[3] = 0;
1866 buf.buffers = &buffer;
1867 buf.num_buffers = 1;
1868 buf.flags = 0;
1869 buf.private_data = NULL;
1870
1871 VASurfaceAttrib attrib_list[2];
1872 attrib_list[0].type = (VASurfaceAttribType)VASurfaceAttribMemoryType;
1873 attrib_list[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
1874 attrib_list[0].value.type = VAGenericValueTypeInteger;
1875 attrib_list[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA;
1876 attrib_list[1].type = (VASurfaceAttribType)VASurfaceAttribExternalBufferDescriptor;
1877 attrib_list[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
1878 attrib_list[1].value.type = VAGenericValueTypePointer;
1879 attrib_list[1].value.value.p = (void *)&buf;
1880
1881 va_status = vaCreateSurfaces(
1882 va_dpy,
1883 VA_RT_FORMAT_RGB32,
1884 stride,
1885 bufHeight,
1886 &va_blank_rgb_in,
1887 1,
1888 attrib_list,
1889 2);
1890 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaCreateSurfaces (blank rgba in) returns %08x", va_status);
1891
1892 va_status = vaCreateContext(
1893 va_dpy,
1894 va_config,
1895 stride,
1896 bufHeight,
1897 0,
1898 &va_blank_yuv_in /* not used by VSP, but libva checks for it */,
1899 1,
1900 &va_context);
1901 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaCreateContext returns %08x", va_status);
1902
1903 VASurfaceID tmp_yuv;
1904 va_status = vaCreateSurfaces(
1905 va_dpy,
1906 VA_RT_FORMAT_YUV420,
1907 stride,
1908 bufHeight,
1909 &tmp_yuv,
1910 1,
1911 NULL,
1912 0);
1913 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaCreateSurfaces (temp yuv) returns %08x", va_status);
1914 {
1915 MappedSurface mappedVideoIn(va_dpy, tmp_yuv);
1916 if (mappedVideoIn.valid()) {
1917 // Value doesn't matter, as RGBA will be opaque,
1918 // but I don't want random data in here.
1919 memset(mappedVideoIn.getPtr(), 0x0, width*height*3/2);
1920 }
1921 else
1922 ETRACE("Unable to map tmp black surface");
1923 }
1924
1925 {
1926 MappedSurface mappedBlankIn(va_dpy, va_blank_rgb_in);
1927 if (mappedBlankIn.valid()) {
1928 // Fill RGBA with opaque black temporarily, in order to generate an
1929 // encrypted black buffer in va_blank_yuv_in to use in place of the
1930 // real frame data during the short interval where we're waiting for
1931 // downscaling to kick in.
1932 uint32_t* pixels = reinterpret_cast<uint32_t*>(mappedBlankIn.getPtr());
1933 for (size_t i = 0; i < stride*height; i++)
1934 pixels[i] = 0xff000000;
1935 }
1936 else
1937 ETRACE("Unable to map blank rgba in");
1938 }
1939
1940 // Compose opaque black with temp yuv to produce encrypted black yuv.
1941 VARectangle region;
1942 region.x = 0;
1943 region.y = 0;
1944 region.width = width;
1945 region.height = height;
1946 vspCompose(tmp_yuv, va_blank_rgb_in, va_blank_yuv_in, ®ion, ®ion);
1947
1948 va_status = vaDestroySurfaces(va_dpy, &tmp_yuv, 1);
1949 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaDestroySurfaces (temp yuv) returns %08x", va_status);
1950
1951 {
1952 // Fill RGBA with transparent black now, to be used when there is no
1953 // UI to compose on top of the video.
1954 MappedSurface mappedBlankIn(va_dpy, va_blank_rgb_in);
1955 if (mappedBlankIn.valid())
1956 memset(mappedBlankIn.getPtr(), 0, stride*height*4);
1957 else
1958 ETRACE("Unable to map blank rgba in");
1959 }
1960 }
1961
1962 void VirtualDevice::vspDisable()
1963 {
1964 ITRACE("Shut down VSP");
1965
1966 if (va_context == 0 && va_blank_yuv_in == 0) {
1967 ITRACE("Already shut down");
1968 return;
1969 }
1970
1971 VABufferID pipeline_param_id;
1972 VAStatus va_status;
1973 va_status = vaCreateBuffer(va_dpy,
1974 va_context,
1975 VAProcPipelineParameterBufferType,
1976 sizeof(VAProcPipelineParameterBuffer),
1977 1,
1978 NULL,
1979 &pipeline_param_id);
1980 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaCreateBuffer returns %08x", va_status);
1981
1982 VABlendState blend_state;
1983 VAProcPipelineParameterBuffer *pipeline_param;
1984 va_status = vaMapBuffer(va_dpy,
1985 pipeline_param_id,
1986 (void **)&pipeline_param);
1987 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaMapBuffer returns %08x", va_status);
1988
1989 memset(pipeline_param, 0, sizeof(VAProcPipelineParameterBuffer));
1990 pipeline_param->pipeline_flags = VA_PIPELINE_FLAG_END;
1991 pipeline_param->num_filters = 0;
1992 pipeline_param->blend_state = &blend_state;
1993
1994 va_status = vaUnmapBuffer(va_dpy, pipeline_param_id);
1995 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaUnmapBuffer returns %08x", va_status);
1996
1997 va_status = vaBeginPicture(va_dpy, va_context, va_blank_yuv_in /* just need some valid surface */);
1998 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaBeginPicture returns %08x", va_status);
1999
2000 va_status = vaRenderPicture(va_dpy, va_context, &pipeline_param_id, 1);
2001 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaRenderPicture returns %08x", va_status);
2002
2003 va_status = vaEndPicture(va_dpy, va_context);
2004 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaEndPicture returns %08x", va_status);
2005
2006 va_status = vaDestroyContext(va_dpy, va_context);
2007 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaDestroyContext returns %08x", va_status);
2008 va_context = 0;
2009
2010 va_status = vaDestroySurfaces(va_dpy, &va_blank_yuv_in, 1);
2011 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaDestroySurfaces (video in) returns %08x", va_status);
2012 va_blank_yuv_in = 0;
2013
2014 va_status = vaDestroySurfaces(va_dpy, &va_blank_rgb_in, 1);
2015 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaDestroySurfaces (blank rgba in) returns %08x", va_status);
2016
2017 if (va_config) {
2018 vaDestroyConfig(va_dpy, va_config);
2019 va_config = 0;
2020 }
2021 if (va_dpy) {
2022 vaTerminate(va_dpy);
2023 va_dpy = NULL;
2024 }
2025 }
2026
2027 void VirtualDevice::vspCompose(VASurfaceID videoIn, VASurfaceID rgbIn, VASurfaceID videoOut,
2028 const VARectangle* surface_region, const VARectangle* output_region)
2029 {
2030 VAStatus va_status;
2031
2032 VABufferID pipeline_param_id;
2033 va_status = vaCreateBuffer(va_dpy,
2034 va_context,
2035 VAProcPipelineParameterBufferType,
2036 sizeof(VAProcPipelineParameterBuffer),
2037 1,
2038 NULL,
2039 &pipeline_param_id);
2040 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaCreateBuffer returns %08x", va_status);
2041
2042 VABlendState blend_state;
2043
2044 VAProcPipelineParameterBuffer *pipeline_param;
2045 va_status = vaMapBuffer(va_dpy,
2046 pipeline_param_id,
2047 (void **)&pipeline_param);
2048 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaMapBuffer returns %08x", va_status);
2049
2050 memset(pipeline_param, 0, sizeof(VAProcPipelineParameterBuffer));
2051 pipeline_param->surface = videoIn;
2052 pipeline_param->surface_region = surface_region;
2053 pipeline_param->output_region = output_region;
2054
2055 pipeline_param->pipeline_flags = 0;
2056 pipeline_param->num_filters = 0;
2057 pipeline_param->blend_state = &blend_state;
2058 pipeline_param->num_additional_outputs = 1;
2059 pipeline_param->additional_outputs = &rgbIn;
2060
2061 va_status = vaUnmapBuffer(va_dpy, pipeline_param_id);
2062 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaUnmapBuffer returns %08x", va_status);
2063
2064 va_status = vaBeginPicture(va_dpy, va_context, videoOut);
2065 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaBeginPicture returns %08x", va_status);
2066
2067 va_status = vaRenderPicture(va_dpy, va_context, &pipeline_param_id, 1);
2068 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaRenderPicture returns %08x", va_status);
2069
2070 va_status = vaEndPicture(va_dpy, va_context);
2071 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaEndPicture returns %08x", va_status);
2072
2073 va_status = vaSyncSurface(va_dpy, videoOut);
2074 if (va_status != VA_STATUS_SUCCESS) ETRACE("vaSyncSurface returns %08x", va_status);
2075 }
2076
2077 static uint32_t min(uint32_t a, uint32_t b)
2078 {
2079 return (a < b) ? a : b;
2080 }
2081
2082 bool VirtualDevice::getFrameOfSize(uint32_t width, uint32_t height, const IVideoPayloadManager::MetaData& metadata, IVideoPayloadManager::Buffer& info)
2083 {
2084 if (metadata.transform == 0 || metadata.transform == HAL_TRANSFORM_ROT_180)
2085 setMaxDecodeResolution(min(width, metadata.normalBuffer.width), min(height, metadata.normalBuffer.height));
2086 else
2087 setMaxDecodeResolution(min(height, metadata.normalBuffer.width), min(width, metadata.normalBuffer.height));
2088
2089 if (metadata.transform == 0) {
2090 if (metadata.normalBuffer.khandle != 0 && metadata.normalBuffer.width <= width && metadata.normalBuffer.height <= height) {
2091 info = metadata.normalBuffer;
2092 return true;
2093 }
2094
2095 if (metadata.scalingBuffer.khandle != 0 && metadata.scalingBuffer.width <= width && metadata.scalingBuffer.height <= height) {
2096 info = metadata.scalingBuffer;
2097 return true;
2098 }
2099 } else {
2100 if (metadata.rotationBuffer.khandle != 0 && metadata.rotationBuffer.width <= width && metadata.rotationBuffer.height <= height) {
2101 info = metadata.rotationBuffer;
2102 return true;
2103 }
2104 }
2105
2106 return false;
2107 }
2108
2109 void VirtualDevice::setMaxDecodeResolution(uint32_t width, uint32_t height)
2110 {
2111 if (mDecWidth == width && mDecHeight == height)
2112 return;
2113
2114 int sessionID = mHwc.getDisplayAnalyzer()->getFirstVideoInstanceSessionID();
2115 if (sessionID < 0) {
2116 ETRACE("Session id is less than 0");
2117 return;
2118 }
2119
2120 MultiDisplayObserver* mds = mHwc.getMultiDisplayObserver();
2121 status_t ret = mds->setDecoderOutputResolution(sessionID, width, height, 0, 0, width, height);
2122 if (ret != NO_ERROR) {
2123 ETRACE("Failed to set scaling to %ux%u: %x", width, height, ret);
2124 return;
2125 }
2126
2127 mDecWidth = width;
2128 mDecHeight = height;
2129 ITRACE("Set scaling to %ux%u",mDecWidth, mDecHeight);
2130 }
2131
2132 bool VirtualDevice::vsyncControl(bool enabled)
2133 {
2134 RETURN_FALSE_IF_NOT_INIT();
2135 return mVsyncObserver->control(enabled);
2136 }
2137
2138 bool VirtualDevice::blank(bool blank)
2139 {
2140 RETURN_FALSE_IF_NOT_INIT();
2141 return true;
2142 }
2143
2144 bool VirtualDevice::getDisplaySize(int *width, int *height)
2145 {
2146 RETURN_FALSE_IF_NOT_INIT();
2147 if (!width || !height) {
2148 ETRACE("invalid parameters");
2149 return false;
2150 }
2151
2152 // TODO: make this platform specifc
2153 *width = 1280;
2154 *height = 720;
2155 return true;
2156 }
2157
2158 bool VirtualDevice::getDisplayConfigs(uint32_t *configs,
2159 size_t *numConfigs)
2160 {
2161 RETURN_FALSE_IF_NOT_INIT();
2162 if (!configs || !numConfigs) {
2163 ETRACE("invalid parameters");
2164 return false;
2165 }
2166
2167 *configs = 0;
2168 *numConfigs = 1;
2169
2170 return true;
2171 }
2172
2173 bool VirtualDevice::getDisplayAttributes(uint32_t configs,
2174 const uint32_t *attributes,
2175 int32_t *values)
2176 {
2177 RETURN_FALSE_IF_NOT_INIT();
2178
2179 if (!attributes || !values) {
2180 ETRACE("invalid parameters");
2181 return false;
2182 }
2183
2184 int i = 0;
2185 while (attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE) {
2186 switch (attributes[i]) {
2187 case HWC_DISPLAY_VSYNC_PERIOD:
2188 values[i] = 1e9 / 60;
2189 break;
2190 case HWC_DISPLAY_WIDTH:
2191 values[i] = 1280;
2192 break;
2193 case HWC_DISPLAY_HEIGHT:
2194 values[i] = 720;
2195 break;
2196 case HWC_DISPLAY_DPI_X:
2197 values[i] = 0;
2198 break;
2199 case HWC_DISPLAY_DPI_Y:
2200 values[i] = 0;
2201 break;
2202 default:
2203 ETRACE("unknown attribute %d", attributes[i]);
2204 break;
2205 }
2206 i++;
2207 }
2208
2209 return true;
2210 }
2211
2212 bool VirtualDevice::compositionComplete()
2213 {
2214 RETURN_FALSE_IF_NOT_INIT();
2215 return true;
2216 }
2217
2218 bool VirtualDevice::initialize()
2219 {
2220 mRgbLayer = -1;
2221 mYuvLayer = -1;
2222 char prop[PROPERTY_VALUE_MAX];
2223 char *retptr;
2224
2225 if (property_get("hwc.fps_divider", prop, "1") > 0) {
2226 uint32_t divider = strtoul(prop, &retptr, 10);
2227 if (*retptr == '\0' && divider > 1 && divider < 60) {
2228 mFpsDivider = divider;
2229 ALOGI("Virtual display, setting HWC FPS divider to %d", mFpsDivider);
2230 }
2231 }
2232
2233 #ifdef INTEL_WIDI
2234 // Add initialization codes here. If init fails, invoke DEINIT_AND_RETURN_FALSE();
2235 mNextConfig.typeChangeListener = NULL;
2236 mNextConfig.policy.scaledWidth = 0;
2237 mNextConfig.policy.scaledHeight = 0;
2238 mNextConfig.policy.xdpi = 96;
2239 mNextConfig.policy.ydpi = 96;
2240 mNextConfig.policy.refresh = 60;
2241 mNextConfig.extendedModeEnabled = false;
2242 mNextConfig.forceNotifyFrameType = false;
2243 mNextConfig.forceNotifyBufferInfo = false;
2244 mCurrentConfig = mNextConfig;
2245
2246 memset(&mLastInputFrameInfo, 0, sizeof(mLastInputFrameInfo));
2247 memset(&mLastOutputFrameInfo, 0, sizeof(mLastOutputFrameInfo));
2248 #endif
2249 mPayloadManager = mHwc.getPlatFactory()->createVideoPayloadManager();
2250
2251 if (!mPayloadManager) {
2252 DEINIT_AND_RETURN_FALSE("Failed to create payload manager");
2253 }
2254
2255 mVsyncObserver = new SoftVsyncObserver(*this);
2256 if (!mVsyncObserver || !mVsyncObserver->initialize()) {
2257 DEINIT_AND_RETURN_FALSE("Failed to create Soft Vsync Observer");
2258 }
2259
2260 mSyncTimelineFd = sw_sync_timeline_create();
2261 mNextSyncPoint = 1;
2262 mExpectAcquireFences = false;
2263
2264 mThread = new WidiBlitThread(this);
2265 mThread->run("WidiBlit", PRIORITY_URGENT_DISPLAY);
2266
2267 #ifdef INTEL_WIDI
2268 // Publish frame server service with service manager
2269 status_t ret = defaultServiceManager()->addService(String16("hwc.widi"), this);
2270 if (ret == NO_ERROR) {
2271 ProcessState::self()->startThreadPool();
2272 mInitialized = true;
2273 } else {
2274 ETRACE("Could not register hwc.widi with service manager, error = %d", ret);
2275 deinitialize();
2276 }
2277 #else
2278 mInitialized = true;
2279 #endif
2280 mVspEnabled = false;
2281 mVspInUse = false;
2282 mVspWidth = 0;
2283 mVspHeight = 0;
2284 va_dpy = NULL;
2285 va_config = 0;
2286 va_context = 0;
2287 va_blank_yuv_in = 0;
2288 va_blank_rgb_in = 0;
2289 mVspUpscale = false;
2290 mDebugVspClear = false;
2291 mDebugVspDump = false;
2292 mDebugCounter = 0;
2293
2294 ITRACE("Init done.");
2295
2296 return mInitialized;
2297 }
2298
2299 bool VirtualDevice::isConnected() const
2300 {
2301 return true;
2302 }
2303
2304 const char* VirtualDevice::getName() const
2305 {
2306 return "Virtual";
2307 }
2308
2309 int VirtualDevice::getType() const
2310 {
2311 return DEVICE_VIRTUAL;
2312 }
2313
2314 void VirtualDevice::onVsync(int64_t timestamp)
2315 {
2316 mHwc.vsync(DEVICE_VIRTUAL, timestamp);
2317 }
2318
2319 void VirtualDevice::dump(Dump& d)
2320 {
2321 }
2322
2323 uint32_t VirtualDevice::getFpsDivider()
2324 {
2325 return mFpsDivider;
2326 }
2327
2328 void VirtualDevice::deinitialize()
2329 {
2330 VAStatus va_status;
2331
2332 if (mPayloadManager) {
2333 delete mPayloadManager;
2334 mPayloadManager = NULL;
2335 }
2336 DEINIT_AND_DELETE_OBJ(mVsyncObserver);
2337 mInitialized = false;
2338 }
2339
2340 bool VirtualDevice::setPowerMode(int /*mode*/)
2341 {
2342 return true;
2343 }
2344
2345 int VirtualDevice::getActiveConfig()
2346 {
2347 return 0;
2348 }
2349
2350 bool VirtualDevice::setActiveConfig(int /*index*/)
2351 {
2352 return false;
2353 }
2354
2355 } // namespace intel
2356 } // namespace android
2357