widget/gonk/HwcComposer2D.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /*
michael@0 2 * Copyright (c) 2012, 2013 The Linux Foundation. All rights reserved.
michael@0 3 *
michael@0 4 * Licensed under the Apache License, Version 2.0 (the "License");
michael@0 5 * you may not use this file except in compliance with the License.
michael@0 6 * You may obtain a copy of the License at
michael@0 7 *
michael@0 8 * http://www.apache.org/licenses/LICENSE-2.0
michael@0 9 *
michael@0 10 * Unless required by applicable law or agreed to in writing, software
michael@0 11 * distributed under the License is distributed on an "AS IS" BASIS,
michael@0 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
michael@0 13 * See the License for the specific language governing permissions and
michael@0 14 * limitations under the License.
michael@0 15 */
michael@0 16
michael@0 17 #include <android/log.h>
michael@0 18 #include <string.h>
michael@0 19
michael@0 20 #include "libdisplay/GonkDisplay.h"
michael@0 21 #include "Framebuffer.h"
michael@0 22 #include "GLContext.h" // for GLContext
michael@0 23 #include "HwcUtils.h"
michael@0 24 #include "HwcComposer2D.h"
michael@0 25 #include "mozilla/layers/LayerManagerComposite.h"
michael@0 26 #include "mozilla/layers/PLayerTransaction.h"
michael@0 27 #include "mozilla/layers/ShadowLayerUtilsGralloc.h"
michael@0 28 #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
michael@0 29 #include "mozilla/StaticPtr.h"
michael@0 30 #include "cutils/properties.h"
michael@0 31 #include "gfx2DGlue.h"
michael@0 32
michael@0 33 #if ANDROID_VERSION >= 17
michael@0 34 #include "libdisplay/FramebufferSurface.h"
michael@0 35 #ifndef HWC_BLIT
michael@0 36 #define HWC_BLIT (HWC_FRAMEBUFFER_TARGET + 1)
michael@0 37 #endif
michael@0 38 #endif
michael@0 39
michael@0 40 #ifdef LOG_TAG
michael@0 41 #undef LOG_TAG
michael@0 42 #endif
michael@0 43 #define LOG_TAG "HWComposer"
michael@0 44
michael@0 45 /*
michael@0 46 * By default the debug message of hwcomposer (LOG_DEBUG level) are undefined,
michael@0 47 * but can be enabled by uncommenting HWC_DEBUG below.
michael@0 48 */
michael@0 49 //#define HWC_DEBUG
michael@0 50
michael@0 51 #ifdef HWC_DEBUG
michael@0 52 #define LOGD(args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, ## args)
michael@0 53 #else
michael@0 54 #define LOGD(args...) ((void)0)
michael@0 55 #endif
michael@0 56
michael@0 57 #define LOGI(args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, ## args)
michael@0 58 #define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, ## args)
michael@0 59
michael@0 60 #define LAYER_COUNT_INCREMENTS 5
michael@0 61
michael@0 62 using namespace android;
michael@0 63 using namespace mozilla::layers;
michael@0 64
michael@0 65 namespace mozilla {
michael@0 66
michael@0 67 static StaticRefPtr<HwcComposer2D> sInstance;
michael@0 68
michael@0 69 HwcComposer2D::HwcComposer2D()
michael@0 70 : mHwc(nullptr)
michael@0 71 , mList(nullptr)
michael@0 72 , mMaxLayerCount(0)
michael@0 73 , mColorFill(false)
michael@0 74 , mRBSwapSupport(false)
michael@0 75 #if ANDROID_VERSION >= 17
michael@0 76 , mPrevRetireFence(Fence::NO_FENCE)
michael@0 77 , mPrevDisplayFence(Fence::NO_FENCE)
michael@0 78 #endif
michael@0 79 , mPrepared(false)
michael@0 80 {
michael@0 81 }
michael@0 82
michael@0 83 HwcComposer2D::~HwcComposer2D() {
michael@0 84 free(mList);
michael@0 85 }
michael@0 86
michael@0 87 int
michael@0 88 HwcComposer2D::Init(hwc_display_t dpy, hwc_surface_t sur)
michael@0 89 {
michael@0 90 MOZ_ASSERT(!Initialized());
michael@0 91
michael@0 92 mHwc = (HwcDevice*)GetGonkDisplay()->GetHWCDevice();
michael@0 93 if (!mHwc) {
michael@0 94 LOGE("Failed to initialize hwc");
michael@0 95 return -1;
michael@0 96 }
michael@0 97
michael@0 98 nsIntSize screenSize;
michael@0 99
michael@0 100 mozilla::Framebuffer::GetSize(&screenSize);
michael@0 101 mScreenRect = nsIntRect(nsIntPoint(0, 0), screenSize);
michael@0 102
michael@0 103 #if ANDROID_VERSION >= 17
michael@0 104 int supported = 0;
michael@0 105
michael@0 106 if (mHwc->query) {
michael@0 107 if (mHwc->query(mHwc, HwcUtils::HWC_COLOR_FILL, &supported) == NO_ERROR) {
michael@0 108 mColorFill = !!supported;
michael@0 109 }
michael@0 110 if (mHwc->query(mHwc, HwcUtils::HWC_FORMAT_RB_SWAP, &supported) == NO_ERROR) {
michael@0 111 mRBSwapSupport = !!supported;
michael@0 112 }
michael@0 113 } else {
michael@0 114 mColorFill = false;
michael@0 115 mRBSwapSupport = false;
michael@0 116 }
michael@0 117 #else
michael@0 118 char propValue[PROPERTY_VALUE_MAX];
michael@0 119 property_get("ro.display.colorfill", propValue, "0");
michael@0 120 mColorFill = (atoi(propValue) == 1) ? true : false;
michael@0 121 mRBSwapSupport = true;
michael@0 122 #endif
michael@0 123
michael@0 124 mDpy = dpy;
michael@0 125 mSur = sur;
michael@0 126
michael@0 127 return 0;
michael@0 128 }
michael@0 129
michael@0 130 HwcComposer2D*
michael@0 131 HwcComposer2D::GetInstance()
michael@0 132 {
michael@0 133 if (!sInstance) {
michael@0 134 LOGI("Creating new instance");
michael@0 135 sInstance = new HwcComposer2D();
michael@0 136 }
michael@0 137 return sInstance;
michael@0 138 }
michael@0 139
michael@0 140 bool
michael@0 141 HwcComposer2D::ReallocLayerList()
michael@0 142 {
michael@0 143 int size = sizeof(HwcList) +
michael@0 144 ((mMaxLayerCount + LAYER_COUNT_INCREMENTS) * sizeof(HwcLayer));
michael@0 145
michael@0 146 HwcList* listrealloc = (HwcList*)realloc(mList, size);
michael@0 147
michael@0 148 if (!listrealloc) {
michael@0 149 return false;
michael@0 150 }
michael@0 151
michael@0 152 if (!mList) {
michael@0 153 //first alloc, initialize
michael@0 154 listrealloc->numHwLayers = 0;
michael@0 155 listrealloc->flags = 0;
michael@0 156 }
michael@0 157
michael@0 158 mList = listrealloc;
michael@0 159 mMaxLayerCount += LAYER_COUNT_INCREMENTS;
michael@0 160 return true;
michael@0 161 }
michael@0 162
michael@0 163 void
michael@0 164 HwcComposer2D::setCrop(HwcLayer* layer, hwc_rect_t srcCrop)
michael@0 165 {
michael@0 166 #if ANDROID_VERSION >= 19
michael@0 167 if (mHwc->common.version >= HWC_DEVICE_API_VERSION_1_3) {
michael@0 168 layer->sourceCropf.left = srcCrop.left;
michael@0 169 layer->sourceCropf.top = srcCrop.top;
michael@0 170 layer->sourceCropf.right = srcCrop.right;
michael@0 171 layer->sourceCropf.bottom = srcCrop.bottom;
michael@0 172 } else {
michael@0 173 layer->sourceCrop = srcCrop;
michael@0 174 }
michael@0 175 #else
michael@0 176 layer->sourceCrop = srcCrop;
michael@0 177 #endif
michael@0 178 }
michael@0 179
michael@0 180 void
michael@0 181 HwcComposer2D::setHwcGeometry(bool aGeometryChanged)
michael@0 182 {
michael@0 183 #if ANDROID_VERSION >= 19
michael@0 184 mList->flags = aGeometryChanged ? HWC_GEOMETRY_CHANGED : 0;
michael@0 185 #else
michael@0 186 mList->flags = HWC_GEOMETRY_CHANGED;
michael@0 187 #endif
michael@0 188 }
michael@0 189
michael@0 190 bool
michael@0 191 HwcComposer2D::PrepareLayerList(Layer* aLayer,
michael@0 192 const nsIntRect& aClip,
michael@0 193 const gfxMatrix& aParentTransform,
michael@0 194 const gfxMatrix& aGLWorldTransform)
michael@0 195 {
michael@0 196 // NB: we fall off this path whenever there are container layers
michael@0 197 // that require intermediate surfaces. That means all the
michael@0 198 // GetEffective*() coordinates are relative to the framebuffer.
michael@0 199
michael@0 200 bool fillColor = false;
michael@0 201
michael@0 202 const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
michael@0 203 if (visibleRegion.IsEmpty()) {
michael@0 204 return true;
michael@0 205 }
michael@0 206
michael@0 207 uint8_t opacity = std::min(0xFF, (int)(aLayer->GetEffectiveOpacity() * 256.0));
michael@0 208 #if ANDROID_VERSION < 18
michael@0 209 if (opacity < 0xFF) {
michael@0 210 LOGD("%s Layer has planar semitransparency which is unsupported", aLayer->Name());
michael@0 211 return false;
michael@0 212 }
michael@0 213 #endif
michael@0 214
michael@0 215 nsIntRect clip;
michael@0 216 if (!HwcUtils::CalculateClipRect(aParentTransform * aGLWorldTransform,
michael@0 217 aLayer->GetEffectiveClipRect(),
michael@0 218 aClip,
michael@0 219 &clip))
michael@0 220 {
michael@0 221 LOGD("%s Clip rect is empty. Skip layer", aLayer->Name());
michael@0 222 return true;
michael@0 223 }
michael@0 224
michael@0 225 // HWC supports only the following 2D transformations:
michael@0 226 //
michael@0 227 // Scaling via the sourceCrop and displayFrame in HwcLayer
michael@0 228 // Translation via the sourceCrop and displayFrame in HwcLayer
michael@0 229 // Rotation (in square angles only) via the HWC_TRANSFORM_ROT_* flags
michael@0 230 // Reflection (horizontal and vertical) via the HWC_TRANSFORM_FLIP_* flags
michael@0 231 //
michael@0 232 // A 2D transform with PreservesAxisAlignedRectangles() has all the attributes
michael@0 233 // above
michael@0 234 gfxMatrix transform;
michael@0 235 gfx3DMatrix transform3D;
michael@0 236 gfx::To3DMatrix(aLayer->GetEffectiveTransform(), transform3D);
michael@0 237
michael@0 238 if (!transform3D.Is2D(&transform) || !transform.PreservesAxisAlignedRectangles()) {
michael@0 239 LOGD("Layer has a 3D transform or a non-square angle rotation");
michael@0 240 return false;
michael@0 241 }
michael@0 242
michael@0 243
michael@0 244 if (ContainerLayer* container = aLayer->AsContainerLayer()) {
michael@0 245 nsAutoTArray<Layer*, 12> children;
michael@0 246 container->SortChildrenBy3DZOrder(children);
michael@0 247
michael@0 248 for (uint32_t i = 0; i < children.Length(); i++) {
michael@0 249 if (!PrepareLayerList(children[i], clip, transform, aGLWorldTransform)) {
michael@0 250 return false;
michael@0 251 }
michael@0 252 }
michael@0 253 return true;
michael@0 254 }
michael@0 255
michael@0 256 LayerRenderState state = aLayer->GetRenderState();
michael@0 257 nsIntSize surfaceSize;
michael@0 258
michael@0 259 if (state.mSurface.get()) {
michael@0 260 surfaceSize = state.mSize;
michael@0 261 } else {
michael@0 262 if (aLayer->AsColorLayer() && mColorFill) {
michael@0 263 fillColor = true;
michael@0 264 } else {
michael@0 265 LOGD("%s Layer doesn't have a gralloc buffer", aLayer->Name());
michael@0 266 return false;
michael@0 267 }
michael@0 268 }
michael@0 269 // Buffer rotation is not to be confused with the angled rotation done by a transform matrix
michael@0 270 // It's a fancy ThebesLayer feature used for scrolling
michael@0 271 if (state.BufferRotated()) {
michael@0 272 LOGD("%s Layer has a rotated buffer", aLayer->Name());
michael@0 273 return false;
michael@0 274 }
michael@0 275
michael@0 276 nsIntRect visibleRect = visibleRegion.GetBounds();
michael@0 277
michael@0 278 nsIntRect bufferRect;
michael@0 279 if (fillColor) {
michael@0 280 bufferRect = nsIntRect(visibleRect);
michael@0 281 } else {
michael@0 282 if(state.mHasOwnOffset) {
michael@0 283 bufferRect = nsIntRect(state.mOffset.x, state.mOffset.y,
michael@0 284 state.mSize.width, state.mSize.height);
michael@0 285 } else {
michael@0 286 //Since the buffer doesn't have its own offset, assign the whole
michael@0 287 //surface size as its buffer bounds
michael@0 288 bufferRect = nsIntRect(0, 0, state.mSize.width, state.mSize.height);
michael@0 289 }
michael@0 290 }
michael@0 291
michael@0 292 hwc_rect_t sourceCrop, displayFrame;
michael@0 293 if(!HwcUtils::PrepareLayerRects(visibleRect,
michael@0 294 transform * aGLWorldTransform,
michael@0 295 clip,
michael@0 296 bufferRect,
michael@0 297 state.YFlipped(),
michael@0 298 &(sourceCrop),
michael@0 299 &(displayFrame)))
michael@0 300 {
michael@0 301 return true;
michael@0 302 }
michael@0 303
michael@0 304 // OK! We can compose this layer with hwc.
michael@0 305 int current = mList ? mList->numHwLayers : 0;
michael@0 306
michael@0 307 // Do not compose any layer below full-screen Opaque layer
michael@0 308 // Note: It can be generalized to non-fullscreen Opaque layers.
michael@0 309 bool isOpaque = (opacity == 0xFF) && (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE);
michael@0 310 if (current && isOpaque) {
michael@0 311 nsIntRect displayRect = nsIntRect(displayFrame.left, displayFrame.top,
michael@0 312 displayFrame.right - displayFrame.left, displayFrame.bottom - displayFrame.top);
michael@0 313 if (displayRect.Contains(mScreenRect)) {
michael@0 314 // In z-order, all previous layers are below
michael@0 315 // the current layer. We can ignore them now.
michael@0 316 mList->numHwLayers = current = 0;
michael@0 317 mHwcLayerMap.Clear();
michael@0 318 }
michael@0 319 }
michael@0 320
michael@0 321 if (!mList || current >= mMaxLayerCount) {
michael@0 322 if (!ReallocLayerList() || current >= mMaxLayerCount) {
michael@0 323 LOGE("PrepareLayerList failed! Could not increase the maximum layer count");
michael@0 324 return false;
michael@0 325 }
michael@0 326 }
michael@0 327
michael@0 328 HwcLayer& hwcLayer = mList->hwLayers[current];
michael@0 329 hwcLayer.flags = 0;
michael@0 330
michael@0 331 if (ContainerLayer* parent = aLayer->GetParent()) {
michael@0 332 if (parent->UseIntermediateSurface()) {
michael@0 333 LOGD("Parent container needs intermediate surface");
michael@0 334 hwcLayer.flags = HWC_SKIP_LAYER;
michael@0 335 #if ANDROID_VERSION < 18
michael@0 336 // No partial HWC Composition on older versions
michael@0 337 return false;
michael@0 338 #endif
michael@0 339 }
michael@0 340 }
michael@0 341
michael@0 342 hwcLayer.displayFrame = displayFrame;
michael@0 343 setCrop(&hwcLayer, sourceCrop);
michael@0 344 buffer_handle_t handle = fillColor ? nullptr : state.mSurface->getNativeBuffer()->handle;
michael@0 345 hwcLayer.handle = handle;
michael@0 346
michael@0 347 hwcLayer.hints = 0;
michael@0 348 hwcLayer.blending = isOpaque ? HWC_BLENDING_NONE : HWC_BLENDING_PREMULT;
michael@0 349 #if ANDROID_VERSION >= 17
michael@0 350 hwcLayer.compositionType = HWC_FRAMEBUFFER;
michael@0 351
michael@0 352 hwcLayer.acquireFenceFd = -1;
michael@0 353 hwcLayer.releaseFenceFd = -1;
michael@0 354 #if ANDROID_VERSION >= 18
michael@0 355 hwcLayer.planeAlpha = opacity;
michael@0 356 #endif
michael@0 357 #else
michael@0 358 hwcLayer.compositionType = HwcUtils::HWC_USE_COPYBIT;
michael@0 359 #endif
michael@0 360
michael@0 361 if (!fillColor) {
michael@0 362 if (state.FormatRBSwapped()) {
michael@0 363 if (!mRBSwapSupport) {
michael@0 364 LOGD("No R/B swap support in H/W Composer");
michael@0 365 return false;
michael@0 366 }
michael@0 367 hwcLayer.flags |= HwcUtils::HWC_FORMAT_RB_SWAP;
michael@0 368 }
michael@0 369
michael@0 370 // Translation and scaling have been addressed in PrepareLayerRects().
michael@0 371 // Given the above and that we checked for PreservesAxisAlignedRectangles()
michael@0 372 // the only possible transformations left to address are
michael@0 373 // square angle rotation and horizontal/vertical reflection.
michael@0 374 //
michael@0 375 // The rotation and reflection permutations total 16 but can be
michael@0 376 // reduced to 8 transformations after eliminating redundancies.
michael@0 377 //
michael@0 378 // All matrices represented here are in the form
michael@0 379 //
michael@0 380 // | xx xy |
michael@0 381 // | yx yy |
michael@0 382 //
michael@0 383 // And ignore scaling.
michael@0 384 //
michael@0 385 // Reflection is applied before rotation
michael@0 386 gfxMatrix rotation = transform * aGLWorldTransform;
michael@0 387 // Compute fuzzy zero like PreservesAxisAlignedRectangles()
michael@0 388 if (fabs(rotation.xx) < 1e-6) {
michael@0 389 if (rotation.xy < 0) {
michael@0 390 if (rotation.yx > 0) {
michael@0 391 // 90 degree rotation
michael@0 392 //
michael@0 393 // | 0 -1 |
michael@0 394 // | 1 0 |
michael@0 395 //
michael@0 396 hwcLayer.transform = HWC_TRANSFORM_ROT_90;
michael@0 397 LOGD("Layer rotated 90 degrees");
michael@0 398 }
michael@0 399 else {
michael@0 400 // Horizontal reflection then 90 degree rotation
michael@0 401 //
michael@0 402 // | 0 -1 | | -1 0 | = | 0 -1 |
michael@0 403 // | 1 0 | | 0 1 | | -1 0 |
michael@0 404 //
michael@0 405 // same as vertical reflection then 270 degree rotation
michael@0 406 //
michael@0 407 // | 0 1 | | 1 0 | = | 0 -1 |
michael@0 408 // | -1 0 | | 0 -1 | | -1 0 |
michael@0 409 //
michael@0 410 hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_H;
michael@0 411 LOGD("Layer vertically reflected then rotated 270 degrees");
michael@0 412 }
michael@0 413 } else {
michael@0 414 if (rotation.yx < 0) {
michael@0 415 // 270 degree rotation
michael@0 416 //
michael@0 417 // | 0 1 |
michael@0 418 // | -1 0 |
michael@0 419 //
michael@0 420 hwcLayer.transform = HWC_TRANSFORM_ROT_270;
michael@0 421 LOGD("Layer rotated 270 degrees");
michael@0 422 }
michael@0 423 else {
michael@0 424 // Vertical reflection then 90 degree rotation
michael@0 425 //
michael@0 426 // | 0 1 | | -1 0 | = | 0 1 |
michael@0 427 // | -1 0 | | 0 1 | | 1 0 |
michael@0 428 //
michael@0 429 // Same as horizontal reflection then 270 degree rotation
michael@0 430 //
michael@0 431 // | 0 -1 | | 1 0 | = | 0 1 |
michael@0 432 // | 1 0 | | 0 -1 | | 1 0 |
michael@0 433 //
michael@0 434 hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_V;
michael@0 435 LOGD("Layer horizontally reflected then rotated 270 degrees");
michael@0 436 }
michael@0 437 }
michael@0 438 } else if (rotation.xx < 0) {
michael@0 439 if (rotation.yy > 0) {
michael@0 440 // Horizontal reflection
michael@0 441 //
michael@0 442 // | -1 0 |
michael@0 443 // | 0 1 |
michael@0 444 //
michael@0 445 hwcLayer.transform = HWC_TRANSFORM_FLIP_H;
michael@0 446 LOGD("Layer rotated 180 degrees");
michael@0 447 }
michael@0 448 else {
michael@0 449 // 180 degree rotation
michael@0 450 //
michael@0 451 // | -1 0 |
michael@0 452 // | 0 -1 |
michael@0 453 //
michael@0 454 // Same as horizontal and vertical reflection
michael@0 455 //
michael@0 456 // | -1 0 | | 1 0 | = | -1 0 |
michael@0 457 // | 0 1 | | 0 -1 | | 0 -1 |
michael@0 458 //
michael@0 459 hwcLayer.transform = HWC_TRANSFORM_ROT_180;
michael@0 460 LOGD("Layer rotated 180 degrees");
michael@0 461 }
michael@0 462 } else {
michael@0 463 if (rotation.yy < 0) {
michael@0 464 // Vertical reflection
michael@0 465 //
michael@0 466 // | 1 0 |
michael@0 467 // | 0 -1 |
michael@0 468 //
michael@0 469 hwcLayer.transform = HWC_TRANSFORM_FLIP_V;
michael@0 470 LOGD("Layer rotated 180 degrees");
michael@0 471 }
michael@0 472 else {
michael@0 473 // No rotation or reflection
michael@0 474 //
michael@0 475 // | 1 0 |
michael@0 476 // | 0 1 |
michael@0 477 //
michael@0 478 hwcLayer.transform = 0;
michael@0 479 }
michael@0 480 }
michael@0 481
michael@0 482 if (state.YFlipped()) {
michael@0 483 // Invert vertical reflection flag if it was already set
michael@0 484 hwcLayer.transform ^= HWC_TRANSFORM_FLIP_V;
michael@0 485 }
michael@0 486 hwc_region_t region;
michael@0 487 if (visibleRegion.GetNumRects() > 1) {
michael@0 488 mVisibleRegions.push_back(HwcUtils::RectVector());
michael@0 489 HwcUtils::RectVector* visibleRects = &(mVisibleRegions.back());
michael@0 490 if(!HwcUtils::PrepareVisibleRegion(visibleRegion,
michael@0 491 transform * aGLWorldTransform,
michael@0 492 clip,
michael@0 493 bufferRect,
michael@0 494 visibleRects)) {
michael@0 495 return true;
michael@0 496 }
michael@0 497 region.numRects = visibleRects->size();
michael@0 498 region.rects = &((*visibleRects)[0]);
michael@0 499 } else {
michael@0 500 region.numRects = 1;
michael@0 501 region.rects = &(hwcLayer.displayFrame);
michael@0 502 }
michael@0 503 hwcLayer.visibleRegionScreen = region;
michael@0 504 } else {
michael@0 505 hwcLayer.flags |= HwcUtils::HWC_COLOR_FILL;
michael@0 506 ColorLayer* colorLayer = aLayer->AsColorLayer();
michael@0 507 if (colorLayer->GetColor().a < 1.0) {
michael@0 508 LOGD("Color layer has semitransparency which is unsupported");
michael@0 509 return false;
michael@0 510 }
michael@0 511 hwcLayer.transform = colorLayer->GetColor().Packed();
michael@0 512 }
michael@0 513
michael@0 514 mHwcLayerMap.AppendElement(static_cast<LayerComposite*>(aLayer->ImplData()));
michael@0 515 mList->numHwLayers++;
michael@0 516 return true;
michael@0 517 }
michael@0 518
michael@0 519
michael@0 520 #if ANDROID_VERSION >= 17
michael@0 521 bool
michael@0 522 HwcComposer2D::TryHwComposition()
michael@0 523 {
michael@0 524 FramebufferSurface* fbsurface = (FramebufferSurface*)(GetGonkDisplay()->GetFBSurface());
michael@0 525
michael@0 526 if (!(fbsurface && fbsurface->lastHandle)) {
michael@0 527 LOGD("H/W Composition failed. FBSurface not initialized.");
michael@0 528 return false;
michael@0 529 }
michael@0 530
michael@0 531 // Add FB layer
michael@0 532 int idx = mList->numHwLayers++;
michael@0 533 if (idx >= mMaxLayerCount) {
michael@0 534 if (!ReallocLayerList() || idx >= mMaxLayerCount) {
michael@0 535 LOGE("TryHwComposition failed! Could not add FB layer");
michael@0 536 return false;
michael@0 537 }
michael@0 538 }
michael@0 539
michael@0 540 Prepare(fbsurface->lastHandle, -1);
michael@0 541
michael@0 542 /* Possible composition paths, after hwc prepare:
michael@0 543 1. GPU Composition
michael@0 544 2. BLIT Composition
michael@0 545 3. Full OVERLAY Composition
michael@0 546 4. Partial OVERLAY Composition (GPU + OVERLAY) */
michael@0 547
michael@0 548 bool gpuComposite = false;
michael@0 549 bool blitComposite = false;
michael@0 550 bool overlayComposite = true;
michael@0 551
michael@0 552 for (int j=0; j < idx; j++) {
michael@0 553 if (mList->hwLayers[j].compositionType == HWC_FRAMEBUFFER ||
michael@0 554 mList->hwLayers[j].compositionType == HWC_BLIT) {
michael@0 555 // Full OVERLAY composition is not possible on this frame
michael@0 556 // It is either GPU / BLIT / partial OVERLAY composition.
michael@0 557 overlayComposite = false;
michael@0 558 break;
michael@0 559 }
michael@0 560 }
michael@0 561
michael@0 562 if (!overlayComposite) {
michael@0 563 for (int k=0; k < idx; k++) {
michael@0 564 switch (mList->hwLayers[k].compositionType) {
michael@0 565 case HWC_FRAMEBUFFER:
michael@0 566 gpuComposite = true;
michael@0 567 break;
michael@0 568 case HWC_BLIT:
michael@0 569 blitComposite = true;
michael@0 570 break;
michael@0 571 case HWC_OVERLAY:
michael@0 572 // HWC will compose HWC_OVERLAY layers in partial
michael@0 573 // Overlay Composition, set layer composition flag
michael@0 574 // on mapped LayerComposite to skip GPU composition
michael@0 575 mHwcLayerMap[k]->SetLayerComposited(true);
michael@0 576 if ((mList->hwLayers[k].hints & HWC_HINT_CLEAR_FB) &&
michael@0 577 (mList->hwLayers[k].blending == HWC_BLENDING_NONE)) {
michael@0 578 // Clear visible rect on FB with transparent pixels.
michael@0 579 hwc_rect_t r = mList->hwLayers[k].displayFrame;
michael@0 580 mHwcLayerMap[k]->SetClearRect(nsIntRect(r.left, r.top,
michael@0 581 r.right - r.left,
michael@0 582 r.bottom - r.top));
michael@0 583 }
michael@0 584 break;
michael@0 585 default:
michael@0 586 break;
michael@0 587 }
michael@0 588 }
michael@0 589
michael@0 590 if (gpuComposite) {
michael@0 591 // GPU or partial OVERLAY Composition
michael@0 592 return false;
michael@0 593 } else if (blitComposite) {
michael@0 594 // BLIT Composition, flip FB target
michael@0 595 GetGonkDisplay()->UpdateFBSurface(mDpy, mSur);
michael@0 596 FramebufferSurface* fbsurface = (FramebufferSurface*)(GetGonkDisplay()->GetFBSurface());
michael@0 597 if (!fbsurface) {
michael@0 598 LOGE("H/W Composition failed. NULL FBSurface.");
michael@0 599 return false;
michael@0 600 }
michael@0 601 mList->hwLayers[idx].handle = fbsurface->lastHandle;
michael@0 602 mList->hwLayers[idx].acquireFenceFd = fbsurface->GetPrevFBAcquireFd();
michael@0 603 }
michael@0 604 }
michael@0 605
michael@0 606 // BLIT or full OVERLAY Composition
michael@0 607 Commit();
michael@0 608
michael@0 609 GetGonkDisplay()->SetFBReleaseFd(mList->hwLayers[idx].releaseFenceFd);
michael@0 610 return true;
michael@0 611 }
michael@0 612
michael@0 613 bool
michael@0 614 HwcComposer2D::Render(EGLDisplay dpy, EGLSurface sur)
michael@0 615 {
michael@0 616 if (!mList) {
michael@0 617 // After boot, HWC list hasn't been created yet
michael@0 618 return GetGonkDisplay()->SwapBuffers(dpy, sur);
michael@0 619 }
michael@0 620
michael@0 621 GetGonkDisplay()->UpdateFBSurface(dpy, sur);
michael@0 622
michael@0 623 FramebufferSurface* fbsurface = (FramebufferSurface*)(GetGonkDisplay()->GetFBSurface());
michael@0 624 if (!fbsurface) {
michael@0 625 LOGE("H/W Composition failed. FBSurface not initialized.");
michael@0 626 return false;
michael@0 627 }
michael@0 628
michael@0 629 if (mPrepared) {
michael@0 630 // No mHwc prepare, if already prepared in current draw cycle
michael@0 631 mList->hwLayers[mList->numHwLayers - 1].handle = fbsurface->lastHandle;
michael@0 632 mList->hwLayers[mList->numHwLayers - 1].acquireFenceFd = fbsurface->GetPrevFBAcquireFd();
michael@0 633 } else {
michael@0 634 mList->flags = HWC_GEOMETRY_CHANGED;
michael@0 635 mList->numHwLayers = 2;
michael@0 636 mList->hwLayers[0].hints = 0;
michael@0 637 mList->hwLayers[0].compositionType = HWC_FRAMEBUFFER;
michael@0 638 mList->hwLayers[0].flags = HWC_SKIP_LAYER;
michael@0 639 mList->hwLayers[0].backgroundColor = {0};
michael@0 640 mList->hwLayers[0].acquireFenceFd = -1;
michael@0 641 mList->hwLayers[0].releaseFenceFd = -1;
michael@0 642 mList->hwLayers[0].displayFrame = {0, 0, mScreenRect.width, mScreenRect.height};
michael@0 643 Prepare(fbsurface->lastHandle, fbsurface->GetPrevFBAcquireFd());
michael@0 644 }
michael@0 645
michael@0 646 // GPU or partial HWC Composition
michael@0 647 Commit();
michael@0 648
michael@0 649 GetGonkDisplay()->SetFBReleaseFd(mList->hwLayers[mList->numHwLayers - 1].releaseFenceFd);
michael@0 650 return true;
michael@0 651 }
michael@0 652
michael@0 653 void
michael@0 654 HwcComposer2D::Prepare(buffer_handle_t fbHandle, int fence)
michael@0 655 {
michael@0 656 int idx = mList->numHwLayers - 1;
michael@0 657 const hwc_rect_t r = {0, 0, mScreenRect.width, mScreenRect.height};
michael@0 658 hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = { nullptr };
michael@0 659
michael@0 660 displays[HWC_DISPLAY_PRIMARY] = mList;
michael@0 661 mList->outbufAcquireFenceFd = -1;
michael@0 662 mList->outbuf = nullptr;
michael@0 663 mList->retireFenceFd = -1;
michael@0 664
michael@0 665 mList->hwLayers[idx].hints = 0;
michael@0 666 mList->hwLayers[idx].flags = 0;
michael@0 667 mList->hwLayers[idx].transform = 0;
michael@0 668 mList->hwLayers[idx].handle = fbHandle;
michael@0 669 mList->hwLayers[idx].blending = HWC_BLENDING_PREMULT;
michael@0 670 mList->hwLayers[idx].compositionType = HWC_FRAMEBUFFER_TARGET;
michael@0 671 setCrop(&mList->hwLayers[idx], r);
michael@0 672 mList->hwLayers[idx].displayFrame = r;
michael@0 673 mList->hwLayers[idx].visibleRegionScreen.numRects = 1;
michael@0 674 mList->hwLayers[idx].visibleRegionScreen.rects = &mList->hwLayers[idx].displayFrame;
michael@0 675 mList->hwLayers[idx].acquireFenceFd = fence;
michael@0 676 mList->hwLayers[idx].releaseFenceFd = -1;
michael@0 677 #if ANDROID_VERSION >= 18
michael@0 678 mList->hwLayers[idx].planeAlpha = 0xFF;
michael@0 679 #endif
michael@0 680 if (mPrepared) {
michael@0 681 LOGE("Multiple hwc prepare calls!");
michael@0 682 }
michael@0 683 mHwc->prepare(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
michael@0 684 mPrepared = true;
michael@0 685 }
michael@0 686
michael@0 687 bool
michael@0 688 HwcComposer2D::Commit()
michael@0 689 {
michael@0 690 hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = { nullptr };
michael@0 691 displays[HWC_DISPLAY_PRIMARY] = mList;
michael@0 692
michael@0 693 int err = mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
michael@0 694
michael@0 695 mPrevDisplayFence = mPrevRetireFence;
michael@0 696 mPrevRetireFence = Fence::NO_FENCE;
michael@0 697
michael@0 698 for (uint32_t j=0; j < (mList->numHwLayers - 1); j++) {
michael@0 699 if (mList->hwLayers[j].releaseFenceFd >= 0) {
michael@0 700 int fd = mList->hwLayers[j].releaseFenceFd;
michael@0 701 mList->hwLayers[j].releaseFenceFd = -1;
michael@0 702 sp<Fence> fence = new Fence(fd);
michael@0 703
michael@0 704 LayerRenderState state = mHwcLayerMap[j]->GetLayer()->GetRenderState();
michael@0 705 if (!state.mTexture) {
michael@0 706 continue;
michael@0 707 }
michael@0 708 TextureHostOGL* texture = state.mTexture->AsHostOGL();
michael@0 709 if (!texture) {
michael@0 710 continue;
michael@0 711 }
michael@0 712 texture->SetReleaseFence(fence);
michael@0 713 }
michael@0 714 }
michael@0 715
michael@0 716 if (mList->retireFenceFd >= 0) {
michael@0 717 mPrevRetireFence = new Fence(mList->retireFenceFd);
michael@0 718 }
michael@0 719
michael@0 720 mPrepared = false;
michael@0 721 return !err;
michael@0 722 }
michael@0 723
michael@0 724 void
michael@0 725 HwcComposer2D::Reset()
michael@0 726 {
michael@0 727 LOGD("hwcomposer is already prepared, reset with null set");
michael@0 728 hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = { nullptr };
michael@0 729 displays[HWC_DISPLAY_PRIMARY] = nullptr;
michael@0 730 mHwc->set(mHwc, HWC_DISPLAY_PRIMARY, displays);
michael@0 731 mPrepared = false;
michael@0 732 }
michael@0 733 #else
michael@0 734 bool
michael@0 735 HwcComposer2D::TryHwComposition()
michael@0 736 {
michael@0 737 return !mHwc->set(mHwc, mDpy, mSur, mList);
michael@0 738 }
michael@0 739
michael@0 740 bool
michael@0 741 HwcComposer2D::Render(EGLDisplay dpy, EGLSurface sur)
michael@0 742 {
michael@0 743 return GetGonkDisplay()->SwapBuffers(dpy, sur);
michael@0 744 }
michael@0 745
michael@0 746 void
michael@0 747 HwcComposer2D::Reset()
michael@0 748 {
michael@0 749 mPrepared = false;
michael@0 750 }
michael@0 751 #endif
michael@0 752
michael@0 753 bool
michael@0 754 HwcComposer2D::TryRender(Layer* aRoot,
michael@0 755 const gfx::Matrix& GLWorldTransform,
michael@0 756 bool aGeometryChanged)
michael@0 757 {
michael@0 758 gfxMatrix aGLWorldTransform = ThebesMatrix(GLWorldTransform);
michael@0 759 if (!aGLWorldTransform.PreservesAxisAlignedRectangles()) {
michael@0 760 LOGD("Render aborted. World transform has non-square angle rotation");
michael@0 761 return false;
michael@0 762 }
michael@0 763
michael@0 764 MOZ_ASSERT(Initialized());
michael@0 765 if (mList) {
michael@0 766 setHwcGeometry(aGeometryChanged);
michael@0 767 mList->numHwLayers = 0;
michael@0 768 mHwcLayerMap.Clear();
michael@0 769 }
michael@0 770
michael@0 771 if (mPrepared) {
michael@0 772 Reset();
michael@0 773 }
michael@0 774
michael@0 775 // XXX: The clear() below means all rect vectors will be have to be
michael@0 776 // reallocated. We may want to avoid this if possible
michael@0 777 mVisibleRegions.clear();
michael@0 778
michael@0 779 MOZ_ASSERT(mHwcLayerMap.IsEmpty());
michael@0 780 if (!PrepareLayerList(aRoot,
michael@0 781 mScreenRect,
michael@0 782 gfxMatrix(),
michael@0 783 aGLWorldTransform))
michael@0 784 {
michael@0 785 LOGD("Render aborted. Nothing was drawn to the screen");
michael@0 786 return false;
michael@0 787 }
michael@0 788
michael@0 789 if (!TryHwComposition()) {
michael@0 790 LOGD("H/W Composition failed");
michael@0 791 return false;
michael@0 792 }
michael@0 793
michael@0 794 LOGD("Frame rendered");
michael@0 795 return true;
michael@0 796 }
michael@0 797
michael@0 798 } // namespace mozilla

mercurial