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:
BufferListener(sp<IGraphicBufferConsumer> consumer,FenceCallback callback,void * callbackArgs)53         BufferListener(sp<IGraphicBufferConsumer> consumer,
54                 FenceCallback callback, void* callbackArgs)
55             : mConsumer(consumer),
56               mCallback(callback),
57               mCallbackArgs(callbackArgs) { }
58 
onFrameAvailable(const BufferItem &)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. */
initialize(const Area & bufferArea,android_pixel_format_t format,FenceCallback callback,void * callbackArgs)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. */
getSurface() const98     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:
Hwc2TestEglManager()118     Hwc2TestEglManager()
119         : mEglDisplay(EGL_NO_DISPLAY),
120           mEglSurface(EGL_NO_SURFACE),
121           mEglContext(EGL_NO_CONTEXT) { }
122 
~Hwc2TestEglManager()123     ~Hwc2TestEglManager()
124     {
125         cleanup();
126     }
127 
initialize(sp<Surface> surface)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 
makeCurrent() const202     void makeCurrent() const
203     {
204         eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
205     }
206 
present() const207     void present() const
208     {
209         eglSwapBuffers(mEglDisplay, mEglSurface);
210     }
211 
212 private:
cleanup()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 
Hwc2TestFenceGenerator()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 
~Hwc2TestFenceGenerator()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 */
get()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 */
set(int32_t 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 
setFence(int32_t fence,void * fenceGenerator)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 */
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)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 
Hwc2TestBuffer()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 */
updateBufferArea(const Area & bufferArea)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. */
get(buffer_handle_t * outHandle,int32_t * outFence)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 */
generateBuffer()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 
Hwc2TestClientTargetBuffer()461 Hwc2TestClientTargetBuffer::Hwc2TestClientTargetBuffer()
462     : mFenceGenerator(new Hwc2TestFenceGenerator()) { }
463 
~Hwc2TestClientTargetBuffer()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. */
compositeBufferFromLayers(const android::sp<android::GraphicBuffer> & graphicBuffer,android_pixel_format_t format,const Area & bufferArea,const Hwc2TestLayers * testLayers,const std::set<hwc2_layer_t> * layersToDraw,const std::set<hwc2_layer_t> * clearLayers)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. */
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)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 
updateBufferArea(const Area & bufferArea)718 void Hwc2TestVirtualBuffer::updateBufferArea(const Area& bufferArea)
719 {
720     mBufferArea.width = bufferArea.width;
721     mBufferArea.height = bufferArea.height;
722 }
723 
writeBufferToFile(std::string path)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 */
generateExpectedBuffer(const Hwc2TestLayers * testLayers,const std::vector<hwc2_layer_t> * allLayers,const std::set<hwc2_layer_t> * clearLayers)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 
getOutputBuffer(buffer_handle_t * outHandle,int32_t * outFence)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