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