Hwc2TestBuffer.cpp revision 3f05602a8c33a4b66a47dc077eaba95f9f1e3977
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
35using namespace android;
36using android::hardware::graphics::common::V1_0::BufferUsage;
37
38/* Returns a fence from egl */
39typedef void (*FenceCallback)(int32_t fence, void* callbackArgs);
40
41/* Returns fence to fence generator */
42static 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 */
47class Hwc2TestSurfaceManager {
48public:
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
103private:
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. */
116class Hwc2TestEglManager {
117public:
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
212private:
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
235static 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
242class Hwc2TestFenceGenerator {
243public:
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
316private:
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
329static 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 */
337static 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
353Hwc2TestBuffer::Hwc2TestBuffer()
354    : mFenceGenerator(new Hwc2TestFenceGenerator()) { }
355
356Hwc2TestBuffer::~Hwc2TestBuffer() = default;
357
358/* When the buffer changes sizes, save the new size and invalidate the current
359 * buffer */
360void 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. */
375int 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 */
398int 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
461Hwc2TestClientTargetBuffer::Hwc2TestClientTargetBuffer()
462    : mFenceGenerator(new Hwc2TestFenceGenerator()) { }
463
464Hwc2TestClientTargetBuffer::~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. */
469static 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. */
691int 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
718void Hwc2TestVirtualBuffer::updateBufferArea(const Area& bufferArea)
719{
720    mBufferArea.width = bufferArea.width;
721    mBufferArea.height = bufferArea.height;
722}
723
724bool 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 */
745int 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
770int 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