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