Hwc2TestBuffer.cpp revision 4cab6aac0dca13a79701e86ac6ff3cbb1584a8ab
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 31#include "Hwc2TestBuffer.h" 32#include "Hwc2TestLayers.h" 33 34using namespace android; 35using android::hardware::graphics::common::V1_0::BufferUsage; 36 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 334/* 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 352Hwc2TestBuffer::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{ 399 /* Create new graphic buffer with correct dimensions */ 400 mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height, 401 mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | 402 BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer"); 403 404 int ret = mGraphicBuffer->initCheck(); 405 if (ret) { 406 return ret; 407 } 408 if (!mGraphicBuffer->handle) { 409 return -EINVAL; 410 } 411 412 /* Locks the buffer for writing */ 413 uint8_t* img; 414 mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN), 415 (void**)(&img)); 416 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 459 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) 473{ 474 /* Create new graphic buffer with correct dimensions */ 475 mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height, 476 mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | 477 BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer"); 478 479 int ret = mGraphicBuffer->initCheck(); 480 if (ret) { 481 return ret; 482 } 483 if (!mGraphicBuffer->handle) { 484 return -EINVAL; 485 } 486 487 uint8_t* img; 488 mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN), 489 (void**)(&img)); 490 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; 579 xPos = yPos * dfW / dfH; 580 yPos = -tmp * dfH / dfW; 581 } 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; 701} 702