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 <math/vec4.h> 27 28 #include <GLES3/gl3.h> 29 30 #include "Hwc2TestBuffer.h" 31 #include "Hwc2TestLayers.h" 32 33 using namespace android; 34 35 /* Returns a fence from egl */ 36 typedef void (*FenceCallback)(int32_t fence, void* callbackArgs); 37 38 /* Returns fence to fence generator */ 39 static void setFence(int32_t fence, void* fenceGenerator); 40 41 42 /* Used to receive the surfaces and fences from egl. The egl buffers are thrown 43 * away. The fences are sent to the requester via a callback */ 44 class Hwc2TestSurfaceManager { 45 public: 46 /* Listens for a new frame, detaches the buffer and returns the fence 47 * through saved callback. */ 48 class BufferListener : public ConsumerBase::FrameAvailableListener { 49 public: 50 BufferListener(sp<IGraphicBufferConsumer> consumer, 51 FenceCallback callback, void* callbackArgs) 52 : mConsumer(consumer), 53 mCallback(callback), 54 mCallbackArgs(callbackArgs) { } 55 56 void onFrameAvailable(const BufferItem& /*item*/) 57 { 58 BufferItem item; 59 60 if (mConsumer->acquireBuffer(&item, 0)) 61 return; 62 if (mConsumer->detachBuffer(item.mSlot)) 63 return; 64 65 mCallback(item.mFence->dup(), mCallbackArgs); 66 } 67 68 private: 69 sp<IGraphicBufferConsumer> mConsumer; 70 FenceCallback mCallback; 71 void* mCallbackArgs; 72 }; 73 74 /* Creates a buffer listener that waits on a new frame from the buffer 75 * queue. */ 76 void initialize(const Area& bufferArea, android_pixel_format_t format, 77 FenceCallback callback, void* callbackArgs) 78 { 79 sp<IGraphicBufferProducer> producer; 80 sp<IGraphicBufferConsumer> consumer; 81 BufferQueue::createBufferQueue(&producer, &consumer); 82 83 consumer->setDefaultBufferSize(bufferArea.width, bufferArea.height); 84 consumer->setDefaultBufferFormat(format); 85 86 mBufferItemConsumer = new BufferItemConsumer(consumer, 0); 87 88 mListener = new BufferListener(consumer, callback, callbackArgs); 89 mBufferItemConsumer->setFrameAvailableListener(mListener); 90 91 mSurface = new Surface(producer, true); 92 } 93 94 /* Used by Egl manager. The surface is never displayed. */ 95 sp<Surface> getSurface() const 96 { 97 return mSurface; 98 } 99 100 private: 101 sp<BufferItemConsumer> mBufferItemConsumer; 102 sp<BufferListener> mListener; 103 /* Used by Egl manager. The surface is never displayed */ 104 sp<Surface> mSurface; 105 }; 106 107 108 /* Used to generate valid fences. It is not possible to create a dummy sync 109 * fence for testing. Egl can generate buffers along with a valid fence. 110 * The buffer cannot be guaranteed to be the same format across all devices so 111 * a CPU filled buffer is used instead. The Egl fence is used along with the 112 * CPU filled buffer. */ 113 class Hwc2TestEglManager { 114 public: 115 Hwc2TestEglManager() 116 : mEglDisplay(EGL_NO_DISPLAY), 117 mEglSurface(EGL_NO_SURFACE), 118 mEglContext(EGL_NO_CONTEXT) { } 119 120 ~Hwc2TestEglManager() 121 { 122 cleanup(); 123 } 124 125 int initialize(sp<Surface> surface) 126 { 127 mSurface = surface; 128 129 mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); 130 if (mEglDisplay == EGL_NO_DISPLAY) return false; 131 132 EGLint major; 133 EGLint minor; 134 if (!eglInitialize(mEglDisplay, &major, &minor)) { 135 ALOGW("Could not initialize EGL"); 136 return false; 137 } 138 139 /* We're going to use a 1x1 pbuffer surface later on 140 * The configuration distance doesn't really matter for what we're 141 * trying to do */ 142 EGLint configAttrs[] = { 143 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 144 EGL_RED_SIZE, 8, 145 EGL_GREEN_SIZE, 8, 146 EGL_BLUE_SIZE, 8, 147 EGL_ALPHA_SIZE, 0, 148 EGL_DEPTH_SIZE, 24, 149 EGL_STENCIL_SIZE, 0, 150 EGL_NONE 151 }; 152 153 EGLConfig configs[1]; 154 EGLint configCnt; 155 if (!eglChooseConfig(mEglDisplay, configAttrs, configs, 1, 156 &configCnt)) { 157 ALOGW("Could not select EGL configuration"); 158 eglReleaseThread(); 159 eglTerminate(mEglDisplay); 160 return false; 161 } 162 163 if (configCnt <= 0) { 164 ALOGW("Could not find EGL configuration"); 165 eglReleaseThread(); 166 eglTerminate(mEglDisplay); 167 return false; 168 } 169 170 /* These objects are initialized below but the default "null" values are 171 * used to cleanup properly at any point in the initialization sequence */ 172 EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; 173 mEglContext = eglCreateContext(mEglDisplay, configs[0], EGL_NO_CONTEXT, 174 attrs); 175 if (mEglContext == EGL_NO_CONTEXT) { 176 ALOGW("Could not create EGL context"); 177 cleanup(); 178 return false; 179 } 180 181 EGLint surfaceAttrs[] = { EGL_NONE }; 182 mEglSurface = eglCreateWindowSurface(mEglDisplay, configs[0], 183 mSurface.get(), surfaceAttrs); 184 if (mEglSurface == EGL_NO_SURFACE) { 185 ALOGW("Could not create EGL surface"); 186 cleanup(); 187 return false; 188 } 189 190 if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 191 ALOGW("Could not change current EGL context"); 192 cleanup(); 193 return false; 194 } 195 196 return true; 197 } 198 199 void makeCurrent() const 200 { 201 eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext); 202 } 203 204 void present() const 205 { 206 eglSwapBuffers(mEglDisplay, mEglSurface); 207 } 208 209 private: 210 void cleanup() 211 { 212 if (mEglDisplay == EGL_NO_DISPLAY) 213 return; 214 if (mEglSurface != EGL_NO_SURFACE) 215 eglDestroySurface(mEglDisplay, mEglSurface); 216 if (mEglContext != EGL_NO_CONTEXT) 217 eglDestroyContext(mEglDisplay, mEglContext); 218 219 eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, 220 EGL_NO_CONTEXT); 221 eglReleaseThread(); 222 eglTerminate(mEglDisplay); 223 } 224 225 sp<Surface> mSurface; 226 EGLDisplay mEglDisplay; 227 EGLSurface mEglSurface; 228 EGLContext mEglContext; 229 }; 230 231 232 static const std::array<vec2, 4> triangles = {{ 233 { 1.0f, 1.0f }, 234 { -1.0f, 1.0f }, 235 { 1.0f, -1.0f }, 236 { -1.0f, -1.0f }, 237 }}; 238 239 class Hwc2TestFenceGenerator { 240 public: 241 242 Hwc2TestFenceGenerator() 243 { 244 mSurfaceManager.initialize({1, 1}, HAL_PIXEL_FORMAT_RGBA_8888, 245 setFence, this); 246 247 if (!mEglManager.initialize(mSurfaceManager.getSurface())) 248 return; 249 250 mEglManager.makeCurrent(); 251 252 glClearColor(0.0, 0.0, 0.0, 1.0); 253 glEnableVertexAttribArray(0); 254 } 255 256 ~Hwc2TestFenceGenerator() 257 { 258 if (mFence >= 0) 259 close(mFence); 260 mFence = -1; 261 262 mEglManager.makeCurrent(); 263 } 264 265 /* It is not possible to simply generate a fence. The easiest way is to 266 * generate a buffer using egl and use the associated fence. The buffer 267 * cannot be guaranteed to be a certain format across all devices using this 268 * method. Instead the buffer is generated using the CPU */ 269 int32_t get() 270 { 271 if (mFence >= 0) { 272 return dup(mFence); 273 } 274 275 std::unique_lock<std::mutex> lock(mMutex); 276 277 /* If the pending is still set to false and times out, we cannot recover. 278 * Set an error and return */ 279 while (mPending != false) { 280 if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout) 281 return -ETIME; 282 } 283 284 /* Generate a fence. The fence will be returned through the setFence 285 * callback */ 286 mEglManager.makeCurrent(); 287 288 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, triangles.data()); 289 glClear(GL_COLOR_BUFFER_BIT); 290 291 mEglManager.present(); 292 293 /* Wait for the setFence callback */ 294 while (mPending != true) { 295 if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout) 296 return -ETIME; 297 } 298 299 mPending = false; 300 301 return dup(mFence); 302 } 303 304 /* Callback that sets the fence */ 305 void set(int32_t fence) 306 { 307 mFence = fence; 308 mPending = true; 309 310 mCv.notify_all(); 311 } 312 313 private: 314 315 Hwc2TestSurfaceManager mSurfaceManager; 316 Hwc2TestEglManager mEglManager; 317 318 std::mutex mMutex; 319 std::condition_variable mCv; 320 321 int32_t mFence = -1; 322 bool mPending = false; 323 }; 324 325 326 static void setFence(int32_t fence, void* fenceGenerator) 327 { 328 static_cast<Hwc2TestFenceGenerator*>(fenceGenerator)->set(fence); 329 } 330 331 332 /* Sets the pixel of a buffer given the location, format, stride and color. 333 * Currently only supports RGBA_8888 */ 334 static void setColor(int32_t x, int32_t y, 335 android_pixel_format_t format, uint32_t stride, uint8_t* img, uint8_t r, 336 uint8_t g, uint8_t b, uint8_t a) 337 { 338 switch (format) { 339 case HAL_PIXEL_FORMAT_RGBA_8888: 340 img[(y * stride + x) * 4 + 0] = r; 341 img[(y * stride + x) * 4 + 1] = g; 342 img[(y * stride + x) * 4 + 2] = b; 343 img[(y * stride + x) * 4 + 3] = a; 344 break; 345 default: 346 break; 347 } 348 } 349 350 Hwc2TestBuffer::Hwc2TestBuffer() 351 : mFenceGenerator(new Hwc2TestFenceGenerator()) { } 352 353 Hwc2TestBuffer::~Hwc2TestBuffer() = default; 354 355 /* When the buffer changes sizes, save the new size and invalidate the current 356 * buffer */ 357 void Hwc2TestBuffer::updateBufferArea(const Area& bufferArea) 358 { 359 if (mBufferArea.width == bufferArea.width 360 && mBufferArea.height == bufferArea.height) 361 return; 362 363 mBufferArea.width = bufferArea.width; 364 mBufferArea.height = bufferArea.height; 365 366 mValidBuffer = false; 367 } 368 369 /* Returns a valid buffer handle and fence. The handle is filled using the CPU 370 * to ensure the correct format across all devices. The fence is created using 371 * egl. */ 372 int Hwc2TestBuffer::get(buffer_handle_t* outHandle, int32_t* outFence) 373 { 374 if (mBufferArea.width == -1 || mBufferArea.height == -1) 375 return -EINVAL; 376 377 /* If the current buffer is valid, the previous buffer can be reused. 378 * Otherwise, create new buffer */ 379 if (!mValidBuffer) { 380 int ret = generateBuffer(); 381 if (ret) 382 return ret; 383 } 384 385 *outFence = mFenceGenerator->get(); 386 *outHandle = mHandle; 387 388 mValidBuffer = true; 389 390 return 0; 391 } 392 393 /* CPU fills a buffer to guarantee the correct buffer format across all 394 * devices */ 395 int Hwc2TestBuffer::generateBuffer() 396 { 397 /* Create new graphic buffer with correct dimensions */ 398 mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height, 399 mFormat, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER, 400 "hwc2_test_buffer"); 401 int ret = mGraphicBuffer->initCheck(); 402 if (ret) { 403 return ret; 404 } 405 if (!mGraphicBuffer->handle) { 406 return -EINVAL; 407 } 408 409 /* Locks the buffer for writing */ 410 uint8_t* img; 411 mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); 412 413 uint32_t stride = mGraphicBuffer->getStride(); 414 415 /* Iterate from the top row of the buffer to the bottom row */ 416 for (int32_t y = 0; y < mBufferArea.height; y++) { 417 418 /* Will be used as R, G and B values for pixel colors */ 419 uint8_t max = 255; 420 uint8_t min = 0; 421 422 /* Divide the rows into 3 sections. The first section will contain 423 * the lighest colors. The last section will contain the darkest 424 * colors. */ 425 if (y < mBufferArea.height * 1.0 / 3.0) { 426 min = 255 / 2; 427 } else if (y >= mBufferArea.height * 2.0 / 3.0) { 428 max = 255 / 2; 429 } 430 431 /* Divide the columns into 3 sections. The first section is red, 432 * the second is green and the third is blue */ 433 int32_t x = 0; 434 for (; x < mBufferArea.width / 3; x++) { 435 setColor(x, y, mFormat, stride, img, max, min, min, 255); 436 } 437 438 for (; x < mBufferArea.width * 2 / 3; x++) { 439 setColor(x, y, mFormat, stride, img, min, max, min, 255); 440 } 441 442 for (; x < mBufferArea.width; x++) { 443 setColor(x, y, mFormat, stride, img, min, min, max, 255); 444 } 445 } 446 447 /* Unlock the buffer for reading */ 448 mGraphicBuffer->unlock(); 449 450 mHandle = mGraphicBuffer->handle; 451 452 return 0; 453 } 454 455 456 Hwc2TestClientTargetBuffer::Hwc2TestClientTargetBuffer() 457 : mFenceGenerator(new Hwc2TestFenceGenerator()) { } 458 459 Hwc2TestClientTargetBuffer::~Hwc2TestClientTargetBuffer() { } 460 461 /* Generates a client target buffer using the layers assigned for client 462 * composition. Takes into account the individual layer properties such as 463 * transform, blend mode, source crop, etc. */ 464 int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle, 465 int32_t* outFence, const Area& bufferArea, 466 const Hwc2TestLayers* testLayers, 467 const std::set<hwc2_layer_t>* clientLayers, 468 const std::set<hwc2_layer_t>* clearLayers) 469 { 470 /* Create new graphic buffer with correct dimensions */ 471 mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height, 472 mFormat, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER, 473 "hwc2_test_buffer"); 474 int ret = mGraphicBuffer->initCheck(); 475 if (ret) { 476 return ret; 477 } 478 if (!mGraphicBuffer->handle) { 479 return -EINVAL; 480 } 481 482 uint8_t* img; 483 mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); 484 485 uint32_t stride = mGraphicBuffer->getStride(); 486 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 500 /* Cycle through each client layer from back to front and 501 * update the pixel color. */ 502 for (auto layer = clientLayers->rbegin(); 503 layer != clientLayers->rend(); ++layer) { 504 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; 573 xPos = -yPos * dfW / dfH; 574 yPos = tmp * dfH / dfW; 575 } 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 */ 685 setColor(x, y, mFormat, stride, img, r, g, b, a * 255); 686 } 687 } 688 689 mGraphicBuffer->unlock(); 690 691 *outFence = mFenceGenerator->get(); 692 *outHandle = mGraphicBuffer->handle; 693 694 return 0; 695 } 696