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