blob: fcd0d31078ef1a57b294edcf7630d919e061eaef [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
Ady Abrahamb0dbdaa2020-01-06 16:19:42 -080017// TODO(b/129481165): remove the #pragma below and fix conversion issues
18#pragma clang diagnostic push
19#pragma clang diagnostic ignored "-Wconversion"
20
Marissa Wall5a240aa2016-12-15 12:34:06 -080021#include <mutex>
22#include <array>
23#include <sstream>
24#include <algorithm>
25
26#include <gui/Surface.h>
27#include <gui/BufferItemConsumer.h>
Marissa Wall5a240aa2016-12-15 12:34:06 -080028
29#include <ui/GraphicBuffer.h>
David Hanna Jr4cab6aa2017-08-15 13:49:24 -070030#include <android/hardware/graphics/common/1.0/types.h>
Marissa Walldde19442017-03-14 13:06:04 -070031#include <math/vec4.h>
Marissa Wall5a240aa2016-12-15 12:34:06 -080032
33#include <GLES3/gl3.h>
David Hanna Jr3f056022017-07-27 19:19:15 -070034#include <SkImageEncoder.h>
35#include <SkStream.h>
Marissa Wall5a240aa2016-12-15 12:34:06 -080036#include "Hwc2TestBuffer.h"
37#include "Hwc2TestLayers.h"
38
39using namespace android;
David Hanna Jr4cab6aa2017-08-15 13:49:24 -070040using android::hardware::graphics::common::V1_0::BufferUsage;
Marissa Wall5a240aa2016-12-15 12:34:06 -080041
42/* Returns a fence from egl */
43typedef void (*FenceCallback)(int32_t fence, void* callbackArgs);
44
45/* Returns fence to fence generator */
46static void setFence(int32_t fence, void* fenceGenerator);
47
48
49/* Used to receive the surfaces and fences from egl. The egl buffers are thrown
50 * away. The fences are sent to the requester via a callback */
51class Hwc2TestSurfaceManager {
52public:
53 /* Listens for a new frame, detaches the buffer and returns the fence
54 * through saved callback. */
55 class BufferListener : public ConsumerBase::FrameAvailableListener {
56 public:
57 BufferListener(sp<IGraphicBufferConsumer> consumer,
58 FenceCallback callback, void* callbackArgs)
59 : mConsumer(consumer),
60 mCallback(callback),
61 mCallbackArgs(callbackArgs) { }
62
63 void onFrameAvailable(const BufferItem& /*item*/)
64 {
65 BufferItem item;
66
67 if (mConsumer->acquireBuffer(&item, 0))
68 return;
69 if (mConsumer->detachBuffer(item.mSlot))
70 return;
71
72 mCallback(item.mFence->dup(), mCallbackArgs);
73 }
74
75 private:
76 sp<IGraphicBufferConsumer> mConsumer;
77 FenceCallback mCallback;
78 void* mCallbackArgs;
79 };
80
81 /* Creates a buffer listener that waits on a new frame from the buffer
82 * queue. */
83 void initialize(const Area& bufferArea, android_pixel_format_t format,
84 FenceCallback callback, void* callbackArgs)
85 {
86 sp<IGraphicBufferProducer> producer;
87 sp<IGraphicBufferConsumer> consumer;
88 BufferQueue::createBufferQueue(&producer, &consumer);
89
90 consumer->setDefaultBufferSize(bufferArea.width, bufferArea.height);
91 consumer->setDefaultBufferFormat(format);
92
93 mBufferItemConsumer = new BufferItemConsumer(consumer, 0);
94
95 mListener = new BufferListener(consumer, callback, callbackArgs);
96 mBufferItemConsumer->setFrameAvailableListener(mListener);
97
98 mSurface = new Surface(producer, true);
99 }
100
101 /* Used by Egl manager. The surface is never displayed. */
102 sp<Surface> getSurface() const
103 {
104 return mSurface;
105 }
106
107private:
108 sp<BufferItemConsumer> mBufferItemConsumer;
109 sp<BufferListener> mListener;
110 /* Used by Egl manager. The surface is never displayed */
111 sp<Surface> mSurface;
112};
113
114
115/* Used to generate valid fences. It is not possible to create a dummy sync
116 * fence for testing. Egl can generate buffers along with a valid fence.
117 * The buffer cannot be guaranteed to be the same format across all devices so
118 * a CPU filled buffer is used instead. The Egl fence is used along with the
119 * CPU filled buffer. */
120class Hwc2TestEglManager {
121public:
122 Hwc2TestEglManager()
123 : mEglDisplay(EGL_NO_DISPLAY),
124 mEglSurface(EGL_NO_SURFACE),
125 mEglContext(EGL_NO_CONTEXT) { }
126
127 ~Hwc2TestEglManager()
128 {
129 cleanup();
130 }
131
132 int initialize(sp<Surface> surface)
133 {
134 mSurface = surface;
135
136 mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
137 if (mEglDisplay == EGL_NO_DISPLAY) return false;
138
139 EGLint major;
140 EGLint minor;
141 if (!eglInitialize(mEglDisplay, &major, &minor)) {
142 ALOGW("Could not initialize EGL");
143 return false;
144 }
145
146 /* We're going to use a 1x1 pbuffer surface later on
147 * The configuration distance doesn't really matter for what we're
148 * trying to do */
149 EGLint configAttrs[] = {
150 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
151 EGL_RED_SIZE, 8,
152 EGL_GREEN_SIZE, 8,
153 EGL_BLUE_SIZE, 8,
154 EGL_ALPHA_SIZE, 0,
155 EGL_DEPTH_SIZE, 24,
156 EGL_STENCIL_SIZE, 0,
157 EGL_NONE
158 };
159
160 EGLConfig configs[1];
161 EGLint configCnt;
162 if (!eglChooseConfig(mEglDisplay, configAttrs, configs, 1,
163 &configCnt)) {
164 ALOGW("Could not select EGL configuration");
165 eglReleaseThread();
166 eglTerminate(mEglDisplay);
167 return false;
168 }
169
170 if (configCnt <= 0) {
171 ALOGW("Could not find EGL configuration");
172 eglReleaseThread();
173 eglTerminate(mEglDisplay);
174 return false;
175 }
176
177 /* These objects are initialized below but the default "null" values are
178 * used to cleanup properly at any point in the initialization sequence */
179 EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
180 mEglContext = eglCreateContext(mEglDisplay, configs[0], EGL_NO_CONTEXT,
181 attrs);
182 if (mEglContext == EGL_NO_CONTEXT) {
183 ALOGW("Could not create EGL context");
184 cleanup();
185 return false;
186 }
187
188 EGLint surfaceAttrs[] = { EGL_NONE };
189 mEglSurface = eglCreateWindowSurface(mEglDisplay, configs[0],
190 mSurface.get(), surfaceAttrs);
191 if (mEglSurface == EGL_NO_SURFACE) {
192 ALOGW("Could not create EGL surface");
193 cleanup();
194 return false;
195 }
196
197 if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
198 ALOGW("Could not change current EGL context");
199 cleanup();
200 return false;
201 }
202
203 return true;
204 }
205
206 void makeCurrent() const
207 {
208 eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
209 }
210
211 void present() const
212 {
213 eglSwapBuffers(mEglDisplay, mEglSurface);
214 }
215
216private:
217 void cleanup()
218 {
219 if (mEglDisplay == EGL_NO_DISPLAY)
220 return;
221 if (mEglSurface != EGL_NO_SURFACE)
222 eglDestroySurface(mEglDisplay, mEglSurface);
223 if (mEglContext != EGL_NO_CONTEXT)
224 eglDestroyContext(mEglDisplay, mEglContext);
225
226 eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
227 EGL_NO_CONTEXT);
228 eglReleaseThread();
229 eglTerminate(mEglDisplay);
230 }
231
232 sp<Surface> mSurface;
233 EGLDisplay mEglDisplay;
234 EGLSurface mEglSurface;
235 EGLContext mEglContext;
236};
237
238
239static const std::array<vec2, 4> triangles = {{
240 { 1.0f, 1.0f },
241 { -1.0f, 1.0f },
242 { 1.0f, -1.0f },
243 { -1.0f, -1.0f },
244}};
245
246class Hwc2TestFenceGenerator {
247public:
248
249 Hwc2TestFenceGenerator()
250 {
251 mSurfaceManager.initialize({1, 1}, HAL_PIXEL_FORMAT_RGBA_8888,
252 setFence, this);
253
254 if (!mEglManager.initialize(mSurfaceManager.getSurface()))
255 return;
256
257 mEglManager.makeCurrent();
258
259 glClearColor(0.0, 0.0, 0.0, 1.0);
260 glEnableVertexAttribArray(0);
261 }
262
263 ~Hwc2TestFenceGenerator()
264 {
265 if (mFence >= 0)
266 close(mFence);
267 mFence = -1;
268
269 mEglManager.makeCurrent();
270 }
271
272 /* It is not possible to simply generate a fence. The easiest way is to
273 * generate a buffer using egl and use the associated fence. The buffer
274 * cannot be guaranteed to be a certain format across all devices using this
275 * method. Instead the buffer is generated using the CPU */
276 int32_t get()
277 {
278 if (mFence >= 0) {
279 return dup(mFence);
280 }
281
282 std::unique_lock<std::mutex> lock(mMutex);
283
284 /* If the pending is still set to false and times out, we cannot recover.
285 * Set an error and return */
286 while (mPending != false) {
287 if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout)
288 return -ETIME;
289 }
290
291 /* Generate a fence. The fence will be returned through the setFence
292 * callback */
293 mEglManager.makeCurrent();
294
295 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, triangles.data());
296 glClear(GL_COLOR_BUFFER_BIT);
297
298 mEglManager.present();
299
300 /* Wait for the setFence callback */
301 while (mPending != true) {
302 if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout)
303 return -ETIME;
304 }
305
306 mPending = false;
307
308 return dup(mFence);
309 }
310
311 /* Callback that sets the fence */
312 void set(int32_t fence)
313 {
314 mFence = fence;
315 mPending = true;
316
317 mCv.notify_all();
318 }
319
320private:
321
322 Hwc2TestSurfaceManager mSurfaceManager;
323 Hwc2TestEglManager mEglManager;
324
325 std::mutex mMutex;
326 std::condition_variable mCv;
327
328 int32_t mFence = -1;
329 bool mPending = false;
330};
331
332
333static void setFence(int32_t fence, void* fenceGenerator)
334{
335 static_cast<Hwc2TestFenceGenerator*>(fenceGenerator)->set(fence);
336}
337
338
Marissa Wallf18cfb02017-02-21 14:01:05 -0800339/* Sets the pixel of a buffer given the location, format, stride and color.
340 * Currently only supports RGBA_8888 */
341static void setColor(int32_t x, int32_t y,
342 android_pixel_format_t format, uint32_t stride, uint8_t* img, uint8_t r,
343 uint8_t g, uint8_t b, uint8_t a)
344{
345 switch (format) {
346 case HAL_PIXEL_FORMAT_RGBA_8888:
347 img[(y * stride + x) * 4 + 0] = r;
348 img[(y * stride + x) * 4 + 1] = g;
349 img[(y * stride + x) * 4 + 2] = b;
350 img[(y * stride + x) * 4 + 3] = a;
351 break;
352 default:
353 break;
354 }
355}
356
Marissa Wall5a240aa2016-12-15 12:34:06 -0800357Hwc2TestBuffer::Hwc2TestBuffer()
358 : mFenceGenerator(new Hwc2TestFenceGenerator()) { }
359
360Hwc2TestBuffer::~Hwc2TestBuffer() = default;
361
362/* When the buffer changes sizes, save the new size and invalidate the current
363 * buffer */
364void Hwc2TestBuffer::updateBufferArea(const Area& bufferArea)
365{
366 if (mBufferArea.width == bufferArea.width
367 && mBufferArea.height == bufferArea.height)
368 return;
369
370 mBufferArea.width = bufferArea.width;
371 mBufferArea.height = bufferArea.height;
372
373 mValidBuffer = false;
374}
375
376/* Returns a valid buffer handle and fence. The handle is filled using the CPU
377 * to ensure the correct format across all devices. The fence is created using
378 * egl. */
379int Hwc2TestBuffer::get(buffer_handle_t* outHandle, int32_t* outFence)
380{
381 if (mBufferArea.width == -1 || mBufferArea.height == -1)
382 return -EINVAL;
383
384 /* If the current buffer is valid, the previous buffer can be reused.
385 * Otherwise, create new buffer */
386 if (!mValidBuffer) {
387 int ret = generateBuffer();
388 if (ret)
389 return ret;
390 }
391
392 *outFence = mFenceGenerator->get();
393 *outHandle = mHandle;
394
395 mValidBuffer = true;
396
397 return 0;
398}
399
400/* CPU fills a buffer to guarantee the correct buffer format across all
401 * devices */
402int Hwc2TestBuffer::generateBuffer()
403{
Marissa Wall5a240aa2016-12-15 12:34:06 -0800404 /* Create new graphic buffer with correct dimensions */
Marissa Wall0fa86762017-03-14 12:30:35 -0700405 mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
David Hanna Jr4cab6aa2017-08-15 13:49:24 -0700406 mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
407 BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer");
408
Marissa Wall0fa86762017-03-14 12:30:35 -0700409 int ret = mGraphicBuffer->initCheck();
410 if (ret) {
Marissa Wall5a240aa2016-12-15 12:34:06 -0800411 return ret;
Marissa Wall0fa86762017-03-14 12:30:35 -0700412 }
413 if (!mGraphicBuffer->handle) {
414 return -EINVAL;
415 }
Marissa Wall5a240aa2016-12-15 12:34:06 -0800416
417 /* Locks the buffer for writing */
418 uint8_t* img;
David Hanna Jr4cab6aa2017-08-15 13:49:24 -0700419 mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
420 (void**)(&img));
Marissa Wall5a240aa2016-12-15 12:34:06 -0800421
422 uint32_t stride = mGraphicBuffer->getStride();
423
424 /* Iterate from the top row of the buffer to the bottom row */
425 for (int32_t y = 0; y < mBufferArea.height; y++) {
426
427 /* Will be used as R, G and B values for pixel colors */
428 uint8_t max = 255;
429 uint8_t min = 0;
430
431 /* Divide the rows into 3 sections. The first section will contain
432 * the lighest colors. The last section will contain the darkest
433 * colors. */
434 if (y < mBufferArea.height * 1.0 / 3.0) {
435 min = 255 / 2;
436 } else if (y >= mBufferArea.height * 2.0 / 3.0) {
437 max = 255 / 2;
438 }
439
440 /* Divide the columns into 3 sections. The first section is red,
441 * the second is green and the third is blue */
442 int32_t x = 0;
443 for (; x < mBufferArea.width / 3; x++) {
444 setColor(x, y, mFormat, stride, img, max, min, min, 255);
445 }
446
447 for (; x < mBufferArea.width * 2 / 3; x++) {
448 setColor(x, y, mFormat, stride, img, min, max, min, 255);
449 }
450
451 for (; x < mBufferArea.width; x++) {
452 setColor(x, y, mFormat, stride, img, min, min, max, 255);
453 }
454 }
455
456 /* Unlock the buffer for reading */
457 mGraphicBuffer->unlock();
458
459 mHandle = mGraphicBuffer->handle;
460
461 return 0;
462}
463
Marissa Wallf18cfb02017-02-21 14:01:05 -0800464
465Hwc2TestClientTargetBuffer::Hwc2TestClientTargetBuffer()
466 : mFenceGenerator(new Hwc2TestFenceGenerator()) { }
467
468Hwc2TestClientTargetBuffer::~Hwc2TestClientTargetBuffer() { }
469
David Hanna Jr3f056022017-07-27 19:19:15 -0700470/* Generates a buffer from layersToDraw.
471 * Takes into account the individual layer properties such as
Marissa Wallf18cfb02017-02-21 14:01:05 -0800472 * transform, blend mode, source crop, etc. */
David Hanna Jr3f056022017-07-27 19:19:15 -0700473static void compositeBufferFromLayers(
474 const android::sp<android::GraphicBuffer>& graphicBuffer,
475 android_pixel_format_t format, const Area& bufferArea,
Marissa Wallf18cfb02017-02-21 14:01:05 -0800476 const Hwc2TestLayers* testLayers,
David Hanna Jr3f056022017-07-27 19:19:15 -0700477 const std::set<hwc2_layer_t>* layersToDraw,
Marissa Wallf18cfb02017-02-21 14:01:05 -0800478 const std::set<hwc2_layer_t>* clearLayers)
Marissa Wall5a240aa2016-12-15 12:34:06 -0800479{
David Hanna Jr3f056022017-07-27 19:19:15 -0700480 /* Locks the buffer for writing */
Marissa Wallf18cfb02017-02-21 14:01:05 -0800481 uint8_t* img;
David Hanna Jr3f056022017-07-27 19:19:15 -0700482 graphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
David Hanna Jr4cab6aa2017-08-15 13:49:24 -0700483 (void**)(&img));
Marissa Wallf18cfb02017-02-21 14:01:05 -0800484
David Hanna Jr3f056022017-07-27 19:19:15 -0700485 uint32_t stride = graphicBuffer->getStride();
Marissa Wallf18cfb02017-02-21 14:01:05 -0800486
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
David Hanna Jr3f056022017-07-27 19:19:15 -0700500 /* Cycle through each layer from back to front and
Marissa Wallf18cfb02017-02-21 14:01:05 -0800501 * update the pixel color. */
David Hanna Jr3f056022017-07-27 19:19:15 -0700502 for (auto layer = layersToDraw->rbegin();
503 layer != layersToDraw->rend(); ++layer) {
Marissa Wallf18cfb02017-02-21 14:01:05 -0800504
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;
David Hanna Jr1d8d4122017-08-15 19:53:57 -0700573 xPos = yPos * dfW / dfH;
574 yPos = -tmp * dfH / dfW;
Marissa Wallf18cfb02017-02-21 14:01:05 -0800575 }
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 */
David Hanna Jr3f056022017-07-27 19:19:15 -0700685 setColor(x, y, format, stride, img, r, g, b, a * 255);
Marissa Wallf18cfb02017-02-21 14:01:05 -0800686 }
687 }
688
David Hanna Jr3f056022017-07-27 19:19:15 -0700689 graphicBuffer->unlock();
690}
691
692/* Generates a client target buffer using the layers assigned for client
693 * composition. Takes into account the individual layer properties such as
694 * transform, blend mode, source crop, etc. */
695int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle,
696 int32_t* outFence, const Area& bufferArea,
697 const Hwc2TestLayers* testLayers,
698 const std::set<hwc2_layer_t>* clientLayers,
699 const std::set<hwc2_layer_t>* clearLayers)
700{
701 /* Create new graphic buffer with correct dimensions */
702 mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height,
703 mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
704 BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer");
705
706 int ret = mGraphicBuffer->initCheck();
707 if (ret)
708 return ret;
709
710 if (!mGraphicBuffer->handle)
711 return -EINVAL;
712
713 compositeBufferFromLayers(mGraphicBuffer, mFormat, bufferArea, testLayers,
714 clientLayers, clearLayers);
Marissa Wallf18cfb02017-02-21 14:01:05 -0800715
716 *outFence = mFenceGenerator->get();
717 *outHandle = mGraphicBuffer->handle;
718
719 return 0;
Marissa Wall5a240aa2016-12-15 12:34:06 -0800720}
David Hanna Jr3f056022017-07-27 19:19:15 -0700721
722void Hwc2TestVirtualBuffer::updateBufferArea(const Area& bufferArea)
723{
724 mBufferArea.width = bufferArea.width;
725 mBufferArea.height = bufferArea.height;
726}
727
728bool Hwc2TestVirtualBuffer::writeBufferToFile(std::string path)
729{
730 SkFILEWStream file(path.c_str());
731 const SkImageInfo info = SkImageInfo::Make(mBufferArea.width,
732 mBufferArea.height, SkColorType::kRGBA_8888_SkColorType,
733 SkAlphaType::kPremul_SkAlphaType);
734
735 uint8_t* img;
736 mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
737 (void**)(&img));
738
739 SkPixmap pixmap(info, img, mGraphicBuffer->getStride());
740 bool result = file.isValid() && SkEncodeImage(&file, pixmap,
741 SkEncodedImageFormat::kPNG, 100);
742
743 mGraphicBuffer->unlock();
744 return result;
745}
746
747/* Generates a buffer that holds the expected result of compositing all of our
748 * layers */
749int Hwc2TestExpectedBuffer::generateExpectedBuffer(
750 const Hwc2TestLayers* testLayers,
751 const std::vector<hwc2_layer_t>* allLayers,
752 const std::set<hwc2_layer_t>* clearLayers)
753{
754 mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
755 mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
756 "hwc2_test_buffer");
757
758 int ret = mGraphicBuffer->initCheck();
759 if (ret)
760 return ret;
761
762 if (!mGraphicBuffer->handle)
763 return -EINVAL;
764
765 const std::set<hwc2_layer_t> allLayerSet(allLayers->begin(),
766 allLayers->end());
767
768 compositeBufferFromLayers(mGraphicBuffer, mFormat, mBufferArea, testLayers,
769 &allLayerSet, clearLayers);
770
771 return 0;
772}
773
774int Hwc2TestOutputBuffer::getOutputBuffer(buffer_handle_t* outHandle,
775 int32_t* outFence)
776{
777 if (mBufferArea.width == -1 || mBufferArea.height == -1)
778 return -EINVAL;
779
780 mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
781 mFormat, BufferUsage::CPU_READ_OFTEN |
782 BufferUsage::GPU_RENDER_TARGET, "hwc2_test_buffer");
783
784 int ret = mGraphicBuffer->initCheck();
785 if (ret)
786 return ret;
787
788 if (!mGraphicBuffer->handle)
789 return -EINVAL;
790
791 *outFence = -1;
792 *outHandle = mGraphicBuffer->handle;
793
794 return 0;
795}
Ady Abrahamb0dbdaa2020-01-06 16:19:42 -0800796
797// TODO(b/129481165): remove the #pragma below and fix conversion issues
798#pragma clang diagnostic pop // ignored "-Wconversion"