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