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