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:
BufferListener(sp<IGraphicBufferConsumer> consumer,FenceCallback callback,void * callbackArgs)50         BufferListener(sp<IGraphicBufferConsumer> consumer,
51                 FenceCallback callback, void* callbackArgs)
52             : mConsumer(consumer),
53               mCallback(callback),
54               mCallbackArgs(callbackArgs) { }
55 
onFrameAvailable(const BufferItem &)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. */
initialize(const Area & bufferArea,android_pixel_format_t format,FenceCallback callback,void * callbackArgs)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. */
getSurface() const95     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:
Hwc2TestEglManager()115     Hwc2TestEglManager()
116         : mEglDisplay(EGL_NO_DISPLAY),
117           mEglSurface(EGL_NO_SURFACE),
118           mEglContext(EGL_NO_CONTEXT) { }
119 
~Hwc2TestEglManager()120     ~Hwc2TestEglManager()
121     {
122         cleanup();
123     }
124 
initialize(sp<Surface> surface)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 
makeCurrent() const199     void makeCurrent() const
200     {
201         eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
202     }
203 
present() const204     void present() const
205     {
206         eglSwapBuffers(mEglDisplay, mEglSurface);
207     }
208 
209 private:
cleanup()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 
Hwc2TestFenceGenerator()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 
~Hwc2TestFenceGenerator()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 */
get()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 */
set(int32_t 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 
setFence(int32_t fence,void * fenceGenerator)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 */
setColor(int32_t x,int32_t y,android_pixel_format_t format,uint32_t stride,uint8_t * img,uint8_t r,uint8_t g,uint8_t b,uint8_t a)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 
Hwc2TestBuffer()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 */
updateBufferArea(const Area & bufferArea)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. */
get(buffer_handle_t * outHandle,int32_t * outFence)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 */
generateBuffer()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 
Hwc2TestClientTargetBuffer()456 Hwc2TestClientTargetBuffer::Hwc2TestClientTargetBuffer()
457     : mFenceGenerator(new Hwc2TestFenceGenerator()) { }
458 
~Hwc2TestClientTargetBuffer()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. */
get(buffer_handle_t * outHandle,int32_t * outFence,const Area & bufferArea,const Hwc2TestLayers * testLayers,const std::set<hwc2_layer_t> * clientLayers,const std::set<hwc2_layer_t> * clearLayers)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