Home | History | Annotate | Download | only in hwc2
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <mutex>
     18 #include <array>
     19 #include <sstream>
     20 #include <algorithm>
     21 
     22 #include <gui/Surface.h>
     23 #include <gui/BufferItemConsumer.h>
     24 
     25 #include <ui/GraphicBuffer.h>
     26 #include <android/hardware/graphics/common/1.0/types.h>
     27 #include <math/vec4.h>
     28 
     29 #include <GLES3/gl3.h>
     30 #include <SkImageEncoder.h>
     31 #include <SkStream.h>
     32 #include "Hwc2TestBuffer.h"
     33 #include "Hwc2TestLayers.h"
     34 
     35 using namespace android;
     36 using android::hardware::graphics::common::V1_0::BufferUsage;
     37 
     38 /* Returns a fence from egl */
     39 typedef void (*FenceCallback)(int32_t fence, void* callbackArgs);
     40 
     41 /* Returns fence to fence generator */
     42 static void setFence(int32_t fence, void* fenceGenerator);
     43 
     44 
     45 /* Used to receive the surfaces and fences from egl. The egl buffers are thrown
     46  * away. The fences are sent to the requester via a callback */
     47 class Hwc2TestSurfaceManager {
     48 public:
     49     /* Listens for a new frame, detaches the buffer and returns the fence
     50      * through saved callback. */
     51     class BufferListener : public ConsumerBase::FrameAvailableListener {
     52     public:
     53         BufferListener(sp<IGraphicBufferConsumer> consumer,
     54                 FenceCallback callback, void* callbackArgs)
     55             : mConsumer(consumer),
     56               mCallback(callback),
     57               mCallbackArgs(callbackArgs) { }
     58 
     59         void onFrameAvailable(const BufferItem& /*item*/)
     60         {
     61             BufferItem item;
     62 
     63             if (mConsumer->acquireBuffer(&item, 0))
     64                 return;
     65             if (mConsumer->detachBuffer(item.mSlot))
     66                 return;
     67 
     68             mCallback(item.mFence->dup(), mCallbackArgs);
     69         }
     70 
     71     private:
     72         sp<IGraphicBufferConsumer> mConsumer;
     73         FenceCallback mCallback;
     74         void* mCallbackArgs;
     75     };
     76 
     77     /* Creates a buffer listener that waits on a new frame from the buffer
     78      * queue. */
     79     void initialize(const Area& bufferArea, android_pixel_format_t format,
     80             FenceCallback callback, void* callbackArgs)
     81     {
     82         sp<IGraphicBufferProducer> producer;
     83         sp<IGraphicBufferConsumer> consumer;
     84         BufferQueue::createBufferQueue(&producer, &consumer);
     85 
     86         consumer->setDefaultBufferSize(bufferArea.width, bufferArea.height);
     87         consumer->setDefaultBufferFormat(format);
     88 
     89         mBufferItemConsumer = new BufferItemConsumer(consumer, 0);
     90 
     91         mListener = new BufferListener(consumer, callback, callbackArgs);
     92         mBufferItemConsumer->setFrameAvailableListener(mListener);
     93 
     94         mSurface = new Surface(producer, true);
     95     }
     96 
     97     /* Used by Egl manager. The surface is never displayed. */
     98     sp<Surface> getSurface() const
     99     {
    100         return mSurface;
    101     }
    102 
    103 private:
    104     sp<BufferItemConsumer> mBufferItemConsumer;
    105     sp<BufferListener> mListener;
    106     /* Used by Egl manager. The surface is never displayed */
    107     sp<Surface> mSurface;
    108 };
    109 
    110 
    111 /* Used to generate valid fences. It is not possible to create a dummy sync
    112  * fence for testing. Egl can generate buffers along with a valid fence.
    113  * The buffer cannot be guaranteed to be the same format across all devices so
    114  * a CPU filled buffer is used instead. The Egl fence is used along with the
    115  * CPU filled buffer. */
    116 class Hwc2TestEglManager {
    117 public:
    118     Hwc2TestEglManager()
    119         : mEglDisplay(EGL_NO_DISPLAY),
    120           mEglSurface(EGL_NO_SURFACE),
    121           mEglContext(EGL_NO_CONTEXT) { }
    122 
    123     ~Hwc2TestEglManager()
    124     {
    125         cleanup();
    126     }
    127 
    128     int initialize(sp<Surface> surface)
    129     {
    130         mSurface = surface;
    131 
    132         mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    133         if (mEglDisplay == EGL_NO_DISPLAY) return false;
    134 
    135         EGLint major;
    136         EGLint minor;
    137         if (!eglInitialize(mEglDisplay, &major, &minor)) {
    138             ALOGW("Could not initialize EGL");
    139             return false;
    140         }
    141 
    142         /* We're going to use a 1x1 pbuffer surface later on
    143          * The configuration distance doesn't really matter for what we're
    144          * trying to do */
    145         EGLint configAttrs[] = {
    146                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
    147                 EGL_RED_SIZE, 8,
    148                 EGL_GREEN_SIZE, 8,
    149                 EGL_BLUE_SIZE, 8,
    150                 EGL_ALPHA_SIZE, 0,
    151                 EGL_DEPTH_SIZE, 24,
    152                 EGL_STENCIL_SIZE, 0,
    153                 EGL_NONE
    154         };
    155 
    156         EGLConfig configs[1];
    157         EGLint configCnt;
    158         if (!eglChooseConfig(mEglDisplay, configAttrs, configs, 1,
    159                 &configCnt)) {
    160             ALOGW("Could not select EGL configuration");
    161             eglReleaseThread();
    162             eglTerminate(mEglDisplay);
    163             return false;
    164         }
    165 
    166         if (configCnt <= 0) {
    167             ALOGW("Could not find EGL configuration");
    168             eglReleaseThread();
    169             eglTerminate(mEglDisplay);
    170             return false;
    171         }
    172 
    173         /* These objects are initialized below but the default "null" values are
    174          * used to cleanup properly at any point in the initialization sequence */
    175         EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
    176         mEglContext = eglCreateContext(mEglDisplay, configs[0], EGL_NO_CONTEXT,
    177                 attrs);
    178         if (mEglContext == EGL_NO_CONTEXT) {
    179             ALOGW("Could not create EGL context");
    180             cleanup();
    181             return false;
    182         }
    183 
    184         EGLint surfaceAttrs[] = { EGL_NONE };
    185         mEglSurface = eglCreateWindowSurface(mEglDisplay, configs[0],
    186                 mSurface.get(), surfaceAttrs);
    187         if (mEglSurface == EGL_NO_SURFACE) {
    188             ALOGW("Could not create EGL surface");
    189             cleanup();
    190             return false;
    191         }
    192 
    193         if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
    194             ALOGW("Could not change current EGL context");
    195             cleanup();
    196             return false;
    197         }
    198 
    199         return true;
    200     }
    201 
    202     void makeCurrent() const
    203     {
    204         eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
    205     }
    206 
    207     void present() const
    208     {
    209         eglSwapBuffers(mEglDisplay, mEglSurface);
    210     }
    211 
    212 private:
    213     void cleanup()
    214     {
    215         if (mEglDisplay == EGL_NO_DISPLAY)
    216             return;
    217         if (mEglSurface != EGL_NO_SURFACE)
    218             eglDestroySurface(mEglDisplay, mEglSurface);
    219         if (mEglContext != EGL_NO_CONTEXT)
    220             eglDestroyContext(mEglDisplay, mEglContext);
    221 
    222         eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
    223                 EGL_NO_CONTEXT);
    224         eglReleaseThread();
    225         eglTerminate(mEglDisplay);
    226     }
    227 
    228     sp<Surface> mSurface;
    229     EGLDisplay mEglDisplay;
    230     EGLSurface mEglSurface;
    231     EGLContext mEglContext;
    232 };
    233 
    234 
    235 static const std::array<vec2, 4> triangles = {{
    236     {  1.0f,  1.0f },
    237     { -1.0f,  1.0f },
    238     {  1.0f, -1.0f },
    239     { -1.0f, -1.0f },
    240 }};
    241 
    242 class Hwc2TestFenceGenerator {
    243 public:
    244 
    245     Hwc2TestFenceGenerator()
    246     {
    247         mSurfaceManager.initialize({1, 1}, HAL_PIXEL_FORMAT_RGBA_8888,
    248                 setFence, this);
    249 
    250         if (!mEglManager.initialize(mSurfaceManager.getSurface()))
    251             return;
    252 
    253         mEglManager.makeCurrent();
    254 
    255         glClearColor(0.0, 0.0, 0.0, 1.0);
    256         glEnableVertexAttribArray(0);
    257     }
    258 
    259     ~Hwc2TestFenceGenerator()
    260     {
    261         if (mFence >= 0)
    262             close(mFence);
    263         mFence = -1;
    264 
    265         mEglManager.makeCurrent();
    266     }
    267 
    268     /* It is not possible to simply generate a fence. The easiest way is to
    269      * generate a buffer using egl and use the associated fence. The buffer
    270      * cannot be guaranteed to be a certain format across all devices using this
    271      * method. Instead the buffer is generated using the CPU */
    272     int32_t get()
    273     {
    274         if (mFence >= 0) {
    275             return dup(mFence);
    276         }
    277 
    278         std::unique_lock<std::mutex> lock(mMutex);
    279 
    280         /* If the pending is still set to false and times out, we cannot recover.
    281          * Set an error and return */
    282         while (mPending != false) {
    283             if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout)
    284                 return -ETIME;
    285         }
    286 
    287         /* Generate a fence. The fence will be returned through the setFence
    288          * callback */
    289         mEglManager.makeCurrent();
    290 
    291         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, triangles.data());
    292         glClear(GL_COLOR_BUFFER_BIT);
    293 
    294         mEglManager.present();
    295 
    296         /* Wait for the setFence callback */
    297         while (mPending != true) {
    298             if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout)
    299                 return -ETIME;
    300         }
    301 
    302         mPending = false;
    303 
    304         return dup(mFence);
    305     }
    306 
    307     /* Callback that sets the fence */
    308     void set(int32_t fence)
    309     {
    310         mFence = fence;
    311         mPending = true;
    312 
    313         mCv.notify_all();
    314     }
    315 
    316 private:
    317 
    318     Hwc2TestSurfaceManager mSurfaceManager;
    319     Hwc2TestEglManager mEglManager;
    320 
    321     std::mutex mMutex;
    322     std::condition_variable mCv;
    323 
    324     int32_t mFence = -1;
    325     bool mPending = false;
    326 };
    327 
    328 
    329 static void setFence(int32_t fence, void* fenceGenerator)
    330 {
    331     static_cast<Hwc2TestFenceGenerator*>(fenceGenerator)->set(fence);
    332 }
    333 
    334 
    335 /* Sets the pixel of a buffer given the location, format, stride and color.
    336  * Currently only supports RGBA_8888 */
    337 static void setColor(int32_t x, int32_t y,
    338         android_pixel_format_t format, uint32_t stride, uint8_t* img, uint8_t r,
    339         uint8_t g, uint8_t b, uint8_t a)
    340 {
    341        switch (format) {
    342        case HAL_PIXEL_FORMAT_RGBA_8888:
    343            img[(y * stride + x) * 4 + 0] = r;
    344            img[(y * stride + x) * 4 + 1] = g;
    345            img[(y * stride + x) * 4 + 2] = b;
    346            img[(y * stride + x) * 4 + 3] = a;
    347            break;
    348        default:
    349            break;
    350        }
    351 }
    352 
    353 Hwc2TestBuffer::Hwc2TestBuffer()
    354     : mFenceGenerator(new Hwc2TestFenceGenerator()) { }
    355 
    356 Hwc2TestBuffer::~Hwc2TestBuffer() = default;
    357 
    358 /* When the buffer changes sizes, save the new size and invalidate the current
    359  * buffer */
    360 void Hwc2TestBuffer::updateBufferArea(const Area& bufferArea)
    361 {
    362     if (mBufferArea.width == bufferArea.width
    363             && mBufferArea.height == bufferArea.height)
    364         return;
    365 
    366     mBufferArea.width = bufferArea.width;
    367     mBufferArea.height = bufferArea.height;
    368 
    369     mValidBuffer = false;
    370 }
    371 
    372 /* Returns a valid buffer handle and fence. The handle is filled using the CPU
    373  * to ensure the correct format across all devices. The fence is created using
    374  * egl. */
    375 int Hwc2TestBuffer::get(buffer_handle_t* outHandle, int32_t* outFence)
    376 {
    377     if (mBufferArea.width == -1 || mBufferArea.height == -1)
    378         return -EINVAL;
    379 
    380     /* If the current buffer is valid, the previous buffer can be reused.
    381      * Otherwise, create new buffer */
    382     if (!mValidBuffer) {
    383         int ret = generateBuffer();
    384         if (ret)
    385             return ret;
    386     }
    387 
    388     *outFence = mFenceGenerator->get();
    389     *outHandle = mHandle;
    390 
    391     mValidBuffer = true;
    392 
    393     return 0;
    394 }
    395 
    396 /* CPU fills a buffer to guarantee the correct buffer format across all
    397  * devices */
    398 int Hwc2TestBuffer::generateBuffer()
    399 {
    400     /* Create new graphic buffer with correct dimensions */
    401     mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
    402             mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
    403             BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer");
    404 
    405     int ret = mGraphicBuffer->initCheck();
    406     if (ret) {
    407         return ret;
    408     }
    409     if (!mGraphicBuffer->handle) {
    410         return -EINVAL;
    411     }
    412 
    413     /* Locks the buffer for writing */
    414     uint8_t* img;
    415     mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
    416             (void**)(&img));
    417 
    418     uint32_t stride = mGraphicBuffer->getStride();
    419 
    420     /* Iterate from the top row of the buffer to the bottom row */
    421     for (int32_t y = 0; y < mBufferArea.height; y++) {
    422 
    423         /* Will be used as R, G and B values for pixel colors */
    424         uint8_t max = 255;
    425         uint8_t min = 0;
    426 
    427         /* Divide the rows into 3 sections. The first section will contain
    428          * the lighest colors. The last section will contain the darkest
    429          * colors. */
    430         if (y < mBufferArea.height * 1.0 / 3.0) {
    431             min = 255 / 2;
    432         } else if (y >= mBufferArea.height * 2.0 / 3.0) {
    433             max = 255 / 2;
    434         }
    435 
    436         /* Divide the columns into 3 sections. The first section is red,
    437          * the second is green and the third is blue */
    438         int32_t x = 0;
    439         for (; x < mBufferArea.width / 3; x++) {
    440             setColor(x, y, mFormat, stride, img, max, min, min, 255);
    441         }
    442 
    443         for (; x < mBufferArea.width * 2 / 3; x++) {
    444             setColor(x, y, mFormat, stride, img, min, max, min, 255);
    445         }
    446 
    447         for (; x < mBufferArea.width; x++) {
    448             setColor(x, y, mFormat, stride, img, min, min, max, 255);
    449         }
    450     }
    451 
    452     /* Unlock the buffer for reading */
    453     mGraphicBuffer->unlock();
    454 
    455     mHandle = mGraphicBuffer->handle;
    456 
    457     return 0;
    458 }
    459 
    460 
    461 Hwc2TestClientTargetBuffer::Hwc2TestClientTargetBuffer()
    462     : mFenceGenerator(new Hwc2TestFenceGenerator()) { }
    463 
    464 Hwc2TestClientTargetBuffer::~Hwc2TestClientTargetBuffer() { }
    465 
    466 /* Generates a buffer from layersToDraw.
    467  * Takes into account the individual layer properties such as
    468  * transform, blend mode, source crop, etc. */
    469 static void compositeBufferFromLayers(
    470         const android::sp<android::GraphicBuffer>& graphicBuffer,
    471         android_pixel_format_t format, const Area& bufferArea,
    472         const Hwc2TestLayers* testLayers,
    473         const std::set<hwc2_layer_t>* layersToDraw,
    474         const std::set<hwc2_layer_t>* clearLayers)
    475 {
    476     /* Locks the buffer for writing */
    477     uint8_t* img;
    478     graphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
    479             (void**)(&img));
    480 
    481     uint32_t stride = graphicBuffer->getStride();
    482 
    483     float bWDiv3 = bufferArea.width / 3;
    484     float bW2Div3 = bufferArea.width * 2 / 3;
    485     float bHDiv3 = bufferArea.height / 3;
    486     float bH2Div3 = bufferArea.height * 2 / 3;
    487 
    488     /* Cycle through every pixel in the buffer and determine what color it
    489      * should be. */
    490     for (int32_t y = 0; y < bufferArea.height; y++) {
    491         for (int32_t x = 0; x < bufferArea.width; x++) {
    492 
    493             uint8_t r = 0, g = 0, b = 0;
    494             float a = 0.0f;
    495 
    496             /* Cycle through each layer from back to front and
    497              * update the pixel color. */
    498             for (auto layer = layersToDraw->rbegin();
    499                     layer != layersToDraw->rend(); ++layer) {
    500 
    501                 const hwc_rect_t df = testLayers->getDisplayFrame(*layer);
    502 
    503                 float dfL = df.left;
    504                 float dfT = df.top;
    505                 float dfR = df.right;
    506                 float dfB = df.bottom;
    507 
    508                 /* If the pixel location falls outside of the layer display
    509                  * frame, skip the layer. */
    510                 if (x < dfL || x >= dfR || y < dfT || y >= dfB)
    511                     continue;
    512 
    513                 /* If the device has requested the layer be clear, clear
    514                  * the pixel and continue. */
    515                 if (clearLayers->count(*layer) != 0) {
    516                     r = 0;
    517                     g = 0;
    518                     b = 0;
    519                     a = 0.0f;
    520                     continue;
    521                 }
    522 
    523                 float planeAlpha = testLayers->getPlaneAlpha(*layer);
    524 
    525                 /* If the layer is a solid color, fill the color and
    526                  * continue. */
    527                 if (testLayers->getComposition(*layer)
    528                         == HWC2_COMPOSITION_SOLID_COLOR) {
    529                     const auto color = testLayers->getColor(*layer);
    530                     r = color.r;
    531                     g = color.g;
    532                     b = color.b;
    533                     a = color.a * planeAlpha;
    534                     continue;
    535                 }
    536 
    537                 float xPos = x;
    538                 float yPos = y;
    539 
    540                 hwc_transform_t transform = testLayers->getTransform(*layer);
    541 
    542                 float dfW = dfR - dfL;
    543                 float dfH = dfB - dfT;
    544 
    545                 /* If a layer has a transform, find which location on the
    546                  * layer will end up in the current pixel location. We
    547                  * can calculate the color of the current pixel using that
    548                  * location. */
    549                 if (transform > 0) {
    550                     /* Change origin to be the center of the layer. */
    551                     xPos = xPos - dfL - dfW / 2.0;
    552                     yPos = yPos - dfT - dfH / 2.0;
    553 
    554                     /* Flip Horizontal by reflecting across the y axis. */
    555                     if (transform & HWC_TRANSFORM_FLIP_H)
    556                         xPos = -xPos;
    557 
    558                     /* Flip vertical by reflecting across the x axis. */
    559                     if (transform & HWC_TRANSFORM_FLIP_V)
    560                         yPos = -yPos;
    561 
    562                     /* Rotate 90 by using a basic linear algebra rotation
    563                      * and scaling the result so the display frame remains
    564                      * the same. For example, a buffer of size 100x50 should
    565                      * rotate 90 degress but remain the same dimension
    566                      * (100x50) at the end of the transformation. */
    567                     if (transform & HWC_TRANSFORM_ROT_90) {
    568                         float tmp = xPos;
    569                         xPos = yPos * dfW / dfH;
    570                         yPos = -tmp * dfH / dfW;
    571                     }
    572 
    573                     /* Change origin back to the top left corner of the
    574                      * layer. */
    575                     xPos = xPos + dfL + dfW / 2.0;
    576                     yPos = yPos + dfT + dfH / 2.0;
    577                 }
    578 
    579                 hwc_frect_t sc = testLayers->getSourceCrop(*layer);
    580                 float scL = sc.left, scT = sc.top;
    581 
    582                 float dfWDivScW = dfW / (sc.right - scL);
    583                 float dfHDivScH = dfH / (sc.bottom - scT);
    584 
    585                 float max = 255, min = 0;
    586 
    587                 /* Choose the pixel color. Similar to generateBuffer,
    588                  * each layer will be divided into 3x3 colors. Because
    589                  * both the source crop and display frame must be taken into
    590                  * account, the formulas are more complicated.
    591                  *
    592                  * If the source crop and display frame were not taken into
    593                  * account, we would simply divide the buffer into three
    594                  * sections by height. Each section would get one color.
    595                  * For example the formula for the first section would be:
    596                  *
    597                  * if (yPos < bufferArea.height / 3)
    598                  *        //Select first section color
    599                  *
    600                  * However the pixel color is chosen based on the source
    601                  * crop and displayed based on the display frame.
    602                  *
    603                  * If the display frame top was 0 and the source crop height
    604                  * and display frame height were the same. The only factor
    605                  * would be the source crop top. To calculate the new
    606                  * section boundary, the section boundary would be moved up
    607                  * by the height of the source crop top. The formula would
    608                  * be:
    609                  * if (yPos < (bufferArea.height / 3 - sourceCrop.top)
    610                  *        //Select first section color
    611                  *
    612                  * If the display frame top could also vary but source crop
    613                  * and display frame heights were the same, the formula
    614                  * would be:
    615                  * if (yPos < (bufferArea.height / 3 - sourceCrop.top
    616                  *              + displayFrameTop)
    617                  *        //Select first section color
    618                  *
    619                  * If the heights were not the same, the conversion between
    620                  * the source crop and display frame dimensions must be
    621                  * taken into account. The formula would be:
    622                  * if (yPos < ((bufferArea.height / 3) - sourceCrop.top)
    623                  *              * displayFrameHeight / sourceCropHeight
    624                  *              + displayFrameTop)
    625                  *        //Select first section color
    626                  */
    627                 if (yPos < ((bHDiv3) - scT) * dfHDivScH + dfT) {
    628                     min = 255 / 2;
    629                 } else if (yPos >= ((bH2Div3) - scT) * dfHDivScH + dfT) {
    630                     max = 255 / 2;
    631                 }
    632 
    633                 uint8_t rCur = min, gCur = min, bCur = min;
    634                 float aCur = 1.0f;
    635 
    636                 /* This further divides the color sections from 3 to 3x3.
    637                  * The math behind it follows the same logic as the previous
    638                  * comment */
    639                 if (xPos < ((bWDiv3) - scL) * (dfWDivScW) + dfL) {
    640                     rCur = max;
    641                 } else if (xPos < ((bW2Div3) - scL) * (dfWDivScW) + dfL) {
    642                     gCur = max;
    643                 } else {
    644                     bCur = max;
    645                 }
    646 
    647 
    648                 /* Blend the pixel color with the previous layers' pixel
    649                  * colors using the plane alpha and blend mode. The final
    650                  * pixel color is chosen using the plane alpha and blend
    651                  * mode formulas found in hwcomposer2.h */
    652                 hwc2_blend_mode_t blendMode = testLayers->getBlendMode(*layer);
    653 
    654                 if (blendMode == HWC2_BLEND_MODE_PREMULTIPLIED) {
    655                     rCur *= planeAlpha;
    656                     gCur *= planeAlpha;
    657                     bCur *= planeAlpha;
    658                 }
    659 
    660                 aCur *= planeAlpha;
    661 
    662                 if (blendMode == HWC2_BLEND_MODE_PREMULTIPLIED) {
    663                     r = rCur + r * (1.0 - aCur);
    664                     g = gCur + g * (1.0 - aCur);
    665                     b = bCur + b * (1.0 - aCur);
    666                     a = aCur + a * (1.0 - aCur);
    667                 } else if (blendMode == HWC2_BLEND_MODE_COVERAGE) {
    668                     r = rCur * aCur + r * (1.0 - aCur);
    669                     g = gCur * aCur + g * (1.0 - aCur);
    670                     b = bCur * aCur + b * (1.0 - aCur);
    671                     a = aCur * aCur + a * (1.0 - aCur);
    672                 } else {
    673                     r = rCur;
    674                     g = gCur;
    675                     b = bCur;
    676                     a = aCur;
    677                 }
    678             }
    679 
    680             /* Set the pixel color */
    681             setColor(x, y, format, stride, img, r, g, b, a * 255);
    682         }
    683     }
    684 
    685     graphicBuffer->unlock();
    686 }
    687 
    688 /* Generates a client target buffer using the layers assigned for client
    689  * composition. Takes into account the individual layer properties such as
    690  * transform, blend mode, source crop, etc. */
    691 int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle,
    692         int32_t* outFence, const Area& bufferArea,
    693         const Hwc2TestLayers* testLayers,
    694         const std::set<hwc2_layer_t>* clientLayers,
    695         const std::set<hwc2_layer_t>* clearLayers)
    696 {
    697     /* Create new graphic buffer with correct dimensions */
    698     mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height,
    699             mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
    700             BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer");
    701 
    702     int ret = mGraphicBuffer->initCheck();
    703     if (ret)
    704         return ret;
    705 
    706     if (!mGraphicBuffer->handle)
    707         return -EINVAL;
    708 
    709     compositeBufferFromLayers(mGraphicBuffer, mFormat, bufferArea, testLayers,
    710             clientLayers, clearLayers);
    711 
    712     *outFence = mFenceGenerator->get();
    713     *outHandle = mGraphicBuffer->handle;
    714 
    715     return 0;
    716 }
    717 
    718 void Hwc2TestVirtualBuffer::updateBufferArea(const Area& bufferArea)
    719 {
    720     mBufferArea.width = bufferArea.width;
    721     mBufferArea.height = bufferArea.height;
    722 }
    723 
    724 bool Hwc2TestVirtualBuffer::writeBufferToFile(std::string path)
    725 {
    726     SkFILEWStream file(path.c_str());
    727     const SkImageInfo info = SkImageInfo::Make(mBufferArea.width,
    728             mBufferArea.height, SkColorType::kRGBA_8888_SkColorType,
    729             SkAlphaType::kPremul_SkAlphaType);
    730 
    731     uint8_t* img;
    732     mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
    733             (void**)(&img));
    734 
    735     SkPixmap pixmap(info, img, mGraphicBuffer->getStride());
    736     bool result = file.isValid() && SkEncodeImage(&file, pixmap,
    737             SkEncodedImageFormat::kPNG, 100);
    738 
    739     mGraphicBuffer->unlock();
    740     return result;
    741 }
    742 
    743 /* Generates a buffer that holds the expected result of compositing all of our
    744  * layers */
    745 int Hwc2TestExpectedBuffer::generateExpectedBuffer(
    746         const Hwc2TestLayers* testLayers,
    747         const std::vector<hwc2_layer_t>* allLayers,
    748         const std::set<hwc2_layer_t>* clearLayers)
    749 {
    750     mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
    751             mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
    752             "hwc2_test_buffer");
    753 
    754     int ret = mGraphicBuffer->initCheck();
    755     if (ret)
    756         return ret;
    757 
    758     if (!mGraphicBuffer->handle)
    759         return -EINVAL;
    760 
    761     const std::set<hwc2_layer_t> allLayerSet(allLayers->begin(),
    762             allLayers->end());
    763 
    764     compositeBufferFromLayers(mGraphicBuffer, mFormat, mBufferArea, testLayers,
    765             &allLayerSet, clearLayers);
    766 
    767     return 0;
    768 }
    769 
    770 int Hwc2TestOutputBuffer::getOutputBuffer(buffer_handle_t* outHandle,
    771         int32_t* outFence)
    772 {
    773     if (mBufferArea.width == -1 || mBufferArea.height == -1)
    774         return -EINVAL;
    775 
    776     mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
    777             mFormat, BufferUsage::CPU_READ_OFTEN |
    778             BufferUsage::GPU_RENDER_TARGET, "hwc2_test_buffer");
    779 
    780     int ret = mGraphicBuffer->initCheck();
    781     if (ret)
    782         return ret;
    783 
    784     if (!mGraphicBuffer->handle)
    785         return -EINVAL;
    786 
    787     *outFence = -1;
    788     *outHandle = mGraphicBuffer->handle;
    789 
    790     return 0;
    791 }
    792