Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include "TiledContentHost.h" |
michael@0 | 7 | #include "ThebesLayerComposite.h" // for ThebesLayerComposite |
michael@0 | 8 | #include "mozilla/gfx/BaseSize.h" // for BaseSize |
michael@0 | 9 | #include "mozilla/gfx/Matrix.h" // for Matrix4x4 |
michael@0 | 10 | #include "mozilla/layers/Compositor.h" // for Compositor |
michael@0 | 11 | #include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc |
michael@0 | 12 | #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL |
michael@0 | 13 | #include "nsAString.h" |
michael@0 | 14 | #include "nsDebug.h" // for NS_WARNING |
michael@0 | 15 | #include "nsPoint.h" // for nsIntPoint |
michael@0 | 16 | #include "nsPrintfCString.h" // for nsPrintfCString |
michael@0 | 17 | #include "nsRect.h" // for nsIntRect |
michael@0 | 18 | #include "nsSize.h" // for nsIntSize |
michael@0 | 19 | #include "mozilla/layers/TiledContentClient.h" |
michael@0 | 20 | |
michael@0 | 21 | class gfxReusableSurfaceWrapper; |
michael@0 | 22 | |
michael@0 | 23 | namespace mozilla { |
michael@0 | 24 | using namespace gfx; |
michael@0 | 25 | namespace layers { |
michael@0 | 26 | |
michael@0 | 27 | class Layer; |
michael@0 | 28 | |
michael@0 | 29 | TiledLayerBufferComposite::TiledLayerBufferComposite() |
michael@0 | 30 | : mFrameResolution(1.0) |
michael@0 | 31 | , mHasDoubleBufferedTiles(false) |
michael@0 | 32 | , mUninitialized(true) |
michael@0 | 33 | {} |
michael@0 | 34 | |
michael@0 | 35 | /* static */ void |
michael@0 | 36 | TiledLayerBufferComposite::RecycleCallback(TextureHost* textureHost, void* aClosure) |
michael@0 | 37 | { |
michael@0 | 38 | textureHost->CompositorRecycle(); |
michael@0 | 39 | } |
michael@0 | 40 | |
michael@0 | 41 | TiledLayerBufferComposite::TiledLayerBufferComposite(ISurfaceAllocator* aAllocator, |
michael@0 | 42 | const SurfaceDescriptorTiles& aDescriptor, |
michael@0 | 43 | const nsIntRegion& aOldPaintedRegion) |
michael@0 | 44 | { |
michael@0 | 45 | mUninitialized = false; |
michael@0 | 46 | mHasDoubleBufferedTiles = false; |
michael@0 | 47 | mValidRegion = aDescriptor.validRegion(); |
michael@0 | 48 | mPaintedRegion = aDescriptor.paintedRegion(); |
michael@0 | 49 | mRetainedWidth = aDescriptor.retainedWidth(); |
michael@0 | 50 | mRetainedHeight = aDescriptor.retainedHeight(); |
michael@0 | 51 | mResolution = aDescriptor.resolution(); |
michael@0 | 52 | mFrameResolution = CSSToParentLayerScale(aDescriptor.frameResolution()); |
michael@0 | 53 | |
michael@0 | 54 | // Combine any valid content that wasn't already uploaded |
michael@0 | 55 | nsIntRegion oldPaintedRegion(aOldPaintedRegion); |
michael@0 | 56 | oldPaintedRegion.And(oldPaintedRegion, mValidRegion); |
michael@0 | 57 | mPaintedRegion.Or(mPaintedRegion, oldPaintedRegion); |
michael@0 | 58 | |
michael@0 | 59 | const InfallibleTArray<TileDescriptor>& tiles = aDescriptor.tiles(); |
michael@0 | 60 | for(size_t i = 0; i < tiles.Length(); i++) { |
michael@0 | 61 | RefPtr<TextureHost> texture; |
michael@0 | 62 | const TileDescriptor& tileDesc = tiles[i]; |
michael@0 | 63 | switch (tileDesc.type()) { |
michael@0 | 64 | case TileDescriptor::TTexturedTileDescriptor : { |
michael@0 | 65 | texture = TextureHost::AsTextureHost(tileDesc.get_TexturedTileDescriptor().textureParent()); |
michael@0 | 66 | #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 |
michael@0 | 67 | if (!gfxPrefs::LayersUseSimpleTiles()) { |
michael@0 | 68 | texture->SetRecycleCallback(RecycleCallback, nullptr); |
michael@0 | 69 | } |
michael@0 | 70 | #endif |
michael@0 | 71 | const TileLock& ipcLock = tileDesc.get_TexturedTileDescriptor().sharedLock(); |
michael@0 | 72 | nsRefPtr<gfxSharedReadLock> sharedLock; |
michael@0 | 73 | if (ipcLock.type() == TileLock::TShmemSection) { |
michael@0 | 74 | sharedLock = gfxShmSharedReadLock::Open(aAllocator, ipcLock.get_ShmemSection()); |
michael@0 | 75 | } else { |
michael@0 | 76 | sharedLock = reinterpret_cast<gfxMemorySharedReadLock*>(ipcLock.get_uintptr_t()); |
michael@0 | 77 | if (sharedLock) { |
michael@0 | 78 | // The corresponding AddRef is in TiledClient::GetTileDescriptor |
michael@0 | 79 | sharedLock->Release(); |
michael@0 | 80 | } |
michael@0 | 81 | } |
michael@0 | 82 | |
michael@0 | 83 | mRetainedTiles.AppendElement(TileHost(sharedLock, texture)); |
michael@0 | 84 | break; |
michael@0 | 85 | } |
michael@0 | 86 | default: |
michael@0 | 87 | NS_WARNING("Unrecognised tile descriptor type"); |
michael@0 | 88 | // Fall through |
michael@0 | 89 | case TileDescriptor::TPlaceholderTileDescriptor : |
michael@0 | 90 | mRetainedTiles.AppendElement(GetPlaceholderTile()); |
michael@0 | 91 | break; |
michael@0 | 92 | } |
michael@0 | 93 | if (texture && !texture->HasInternalBuffer()) { |
michael@0 | 94 | mHasDoubleBufferedTiles = true; |
michael@0 | 95 | } |
michael@0 | 96 | } |
michael@0 | 97 | } |
michael@0 | 98 | |
michael@0 | 99 | void |
michael@0 | 100 | TiledLayerBufferComposite::ReadUnlock() |
michael@0 | 101 | { |
michael@0 | 102 | if (!IsValid()) { |
michael@0 | 103 | return; |
michael@0 | 104 | } |
michael@0 | 105 | for (size_t i = 0; i < mRetainedTiles.Length(); i++) { |
michael@0 | 106 | mRetainedTiles[i].ReadUnlock(); |
michael@0 | 107 | } |
michael@0 | 108 | } |
michael@0 | 109 | |
michael@0 | 110 | void |
michael@0 | 111 | TiledLayerBufferComposite::ReleaseTextureHosts() |
michael@0 | 112 | { |
michael@0 | 113 | if (!IsValid()) { |
michael@0 | 114 | return; |
michael@0 | 115 | } |
michael@0 | 116 | for (size_t i = 0; i < mRetainedTiles.Length(); i++) { |
michael@0 | 117 | mRetainedTiles[i].mTextureHost = nullptr; |
michael@0 | 118 | } |
michael@0 | 119 | } |
michael@0 | 120 | |
michael@0 | 121 | void |
michael@0 | 122 | TiledLayerBufferComposite::Upload() |
michael@0 | 123 | { |
michael@0 | 124 | if(!IsValid()) { |
michael@0 | 125 | return; |
michael@0 | 126 | } |
michael@0 | 127 | // The TextureClients were created with the TEXTURE_IMMEDIATE_UPLOAD flag, |
michael@0 | 128 | // so calling Update on all the texture hosts will perform the texture upload. |
michael@0 | 129 | Update(mValidRegion, mPaintedRegion); |
michael@0 | 130 | ClearPaintedRegion(); |
michael@0 | 131 | } |
michael@0 | 132 | |
michael@0 | 133 | TileHost |
michael@0 | 134 | TiledLayerBufferComposite::ValidateTile(TileHost aTile, |
michael@0 | 135 | const nsIntPoint& aTileOrigin, |
michael@0 | 136 | const nsIntRegion& aDirtyRect) |
michael@0 | 137 | { |
michael@0 | 138 | if (aTile.IsPlaceholderTile()) { |
michael@0 | 139 | NS_WARNING("Placeholder tile encountered in painted region"); |
michael@0 | 140 | return aTile; |
michael@0 | 141 | } |
michael@0 | 142 | |
michael@0 | 143 | #ifdef GFX_TILEDLAYER_PREF_WARNINGS |
michael@0 | 144 | printf_stderr("Upload tile %i, %i\n", aTileOrigin.x, aTileOrigin.y); |
michael@0 | 145 | long start = PR_IntervalNow(); |
michael@0 | 146 | #endif |
michael@0 | 147 | |
michael@0 | 148 | MOZ_ASSERT(aTile.mTextureHost->GetFlags() & TEXTURE_IMMEDIATE_UPLOAD); |
michael@0 | 149 | // We possibly upload the entire texture contents here. This is a purposeful |
michael@0 | 150 | // decision, as sub-image upload can often be slow and/or unreliable, but |
michael@0 | 151 | // we may want to reevaluate this in the future. |
michael@0 | 152 | // For !HasInternalBuffer() textures, this is likely a no-op. |
michael@0 | 153 | aTile.mTextureHost->Updated(nullptr); |
michael@0 | 154 | |
michael@0 | 155 | #ifdef GFX_TILEDLAYER_PREF_WARNINGS |
michael@0 | 156 | if (PR_IntervalNow() - start > 1) { |
michael@0 | 157 | printf_stderr("Tile Time to upload %i\n", PR_IntervalNow() - start); |
michael@0 | 158 | } |
michael@0 | 159 | #endif |
michael@0 | 160 | return aTile; |
michael@0 | 161 | } |
michael@0 | 162 | |
michael@0 | 163 | void |
michael@0 | 164 | TiledLayerBufferComposite::SetCompositor(Compositor* aCompositor) |
michael@0 | 165 | { |
michael@0 | 166 | if (!IsValid()) { |
michael@0 | 167 | return; |
michael@0 | 168 | } |
michael@0 | 169 | for (size_t i = 0; i < mRetainedTiles.Length(); i++) { |
michael@0 | 170 | if (mRetainedTiles[i].IsPlaceholderTile()) continue; |
michael@0 | 171 | mRetainedTiles[i].mTextureHost->SetCompositor(aCompositor); |
michael@0 | 172 | } |
michael@0 | 173 | } |
michael@0 | 174 | |
michael@0 | 175 | #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 |
michael@0 | 176 | void |
michael@0 | 177 | TiledLayerBufferComposite::SetReleaseFence(const android::sp<android::Fence>& aReleaseFence) |
michael@0 | 178 | { |
michael@0 | 179 | for (size_t i = 0; i < mRetainedTiles.Length(); i++) { |
michael@0 | 180 | if (!mRetainedTiles[i].mTextureHost) { |
michael@0 | 181 | continue; |
michael@0 | 182 | } |
michael@0 | 183 | TextureHostOGL* texture = mRetainedTiles[i].mTextureHost->AsHostOGL(); |
michael@0 | 184 | if (!texture) { |
michael@0 | 185 | continue; |
michael@0 | 186 | } |
michael@0 | 187 | texture->SetReleaseFence(new android::Fence(aReleaseFence->dup())); |
michael@0 | 188 | } |
michael@0 | 189 | } |
michael@0 | 190 | #endif |
michael@0 | 191 | |
michael@0 | 192 | TiledContentHost::TiledContentHost(const TextureInfo& aTextureInfo) |
michael@0 | 193 | : ContentHost(aTextureInfo) |
michael@0 | 194 | , mTiledBuffer(TiledLayerBufferComposite()) |
michael@0 | 195 | , mLowPrecisionTiledBuffer(TiledLayerBufferComposite()) |
michael@0 | 196 | , mOldTiledBuffer(TiledLayerBufferComposite()) |
michael@0 | 197 | , mOldLowPrecisionTiledBuffer(TiledLayerBufferComposite()) |
michael@0 | 198 | , mPendingUpload(false) |
michael@0 | 199 | , mPendingLowPrecisionUpload(false) |
michael@0 | 200 | { |
michael@0 | 201 | MOZ_COUNT_CTOR(TiledContentHost); |
michael@0 | 202 | } |
michael@0 | 203 | |
michael@0 | 204 | TiledContentHost::~TiledContentHost() |
michael@0 | 205 | { |
michael@0 | 206 | MOZ_COUNT_DTOR(TiledContentHost); |
michael@0 | 207 | |
michael@0 | 208 | // Unlock any buffers that may still be locked. If we have a pending upload, |
michael@0 | 209 | // we will need to unlock the buffer that was about to be uploaded. |
michael@0 | 210 | // If a buffer that was being composited had double-buffered tiles, we will |
michael@0 | 211 | // need to unlock that buffer too. |
michael@0 | 212 | if (mPendingUpload) { |
michael@0 | 213 | mTiledBuffer.ReadUnlock(); |
michael@0 | 214 | if (mOldTiledBuffer.HasDoubleBufferedTiles()) { |
michael@0 | 215 | mOldTiledBuffer.ReadUnlock(); |
michael@0 | 216 | } |
michael@0 | 217 | } else if (mTiledBuffer.HasDoubleBufferedTiles()) { |
michael@0 | 218 | mTiledBuffer.ReadUnlock(); |
michael@0 | 219 | } |
michael@0 | 220 | |
michael@0 | 221 | if (mPendingLowPrecisionUpload) { |
michael@0 | 222 | mLowPrecisionTiledBuffer.ReadUnlock(); |
michael@0 | 223 | if (mOldLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) { |
michael@0 | 224 | mOldLowPrecisionTiledBuffer.ReadUnlock(); |
michael@0 | 225 | } |
michael@0 | 226 | } else if (mLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) { |
michael@0 | 227 | mLowPrecisionTiledBuffer.ReadUnlock(); |
michael@0 | 228 | } |
michael@0 | 229 | } |
michael@0 | 230 | |
michael@0 | 231 | void |
michael@0 | 232 | TiledContentHost::Attach(Layer* aLayer, |
michael@0 | 233 | Compositor* aCompositor, |
michael@0 | 234 | AttachFlags aFlags /* = NO_FLAGS */) |
michael@0 | 235 | { |
michael@0 | 236 | CompositableHost::Attach(aLayer, aCompositor, aFlags); |
michael@0 | 237 | static_cast<ThebesLayerComposite*>(aLayer)->EnsureTiled(); |
michael@0 | 238 | } |
michael@0 | 239 | |
michael@0 | 240 | void |
michael@0 | 241 | TiledContentHost::UseTiledLayerBuffer(ISurfaceAllocator* aAllocator, |
michael@0 | 242 | const SurfaceDescriptorTiles& aTiledDescriptor) |
michael@0 | 243 | { |
michael@0 | 244 | if (aTiledDescriptor.resolution() < 1) { |
michael@0 | 245 | if (mPendingLowPrecisionUpload) { |
michael@0 | 246 | mLowPrecisionTiledBuffer.ReadUnlock(); |
michael@0 | 247 | } else { |
michael@0 | 248 | mPendingLowPrecisionUpload = true; |
michael@0 | 249 | // If the old buffer has double-buffered tiles, hang onto it so we can |
michael@0 | 250 | // unlock it after we've composited the new buffer. |
michael@0 | 251 | // We only need to hang onto the locks, but not the textures. |
michael@0 | 252 | // Releasing the textures here can help prevent a memory spike in the |
michael@0 | 253 | // situation that the client starts rendering new content before we get |
michael@0 | 254 | // to composite the new buffer. |
michael@0 | 255 | if (mLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) { |
michael@0 | 256 | mOldLowPrecisionTiledBuffer = mLowPrecisionTiledBuffer; |
michael@0 | 257 | mOldLowPrecisionTiledBuffer.ReleaseTextureHosts(); |
michael@0 | 258 | } |
michael@0 | 259 | } |
michael@0 | 260 | mLowPrecisionTiledBuffer = |
michael@0 | 261 | TiledLayerBufferComposite(aAllocator, aTiledDescriptor, |
michael@0 | 262 | mLowPrecisionTiledBuffer.GetPaintedRegion()); |
michael@0 | 263 | } else { |
michael@0 | 264 | if (mPendingUpload) { |
michael@0 | 265 | mTiledBuffer.ReadUnlock(); |
michael@0 | 266 | } else { |
michael@0 | 267 | mPendingUpload = true; |
michael@0 | 268 | if (mTiledBuffer.HasDoubleBufferedTiles()) { |
michael@0 | 269 | mOldTiledBuffer = mTiledBuffer; |
michael@0 | 270 | mOldTiledBuffer.ReleaseTextureHosts(); |
michael@0 | 271 | } |
michael@0 | 272 | } |
michael@0 | 273 | mTiledBuffer = TiledLayerBufferComposite(aAllocator, aTiledDescriptor, |
michael@0 | 274 | mTiledBuffer.GetPaintedRegion()); |
michael@0 | 275 | } |
michael@0 | 276 | } |
michael@0 | 277 | |
michael@0 | 278 | void |
michael@0 | 279 | TiledContentHost::Composite(EffectChain& aEffectChain, |
michael@0 | 280 | float aOpacity, |
michael@0 | 281 | const gfx::Matrix4x4& aTransform, |
michael@0 | 282 | const gfx::Filter& aFilter, |
michael@0 | 283 | const gfx::Rect& aClipRect, |
michael@0 | 284 | const nsIntRegion* aVisibleRegion /* = nullptr */, |
michael@0 | 285 | TiledLayerProperties* aLayerProperties /* = nullptr */) |
michael@0 | 286 | { |
michael@0 | 287 | MOZ_ASSERT(aLayerProperties, "aLayerProperties required for TiledContentHost"); |
michael@0 | 288 | |
michael@0 | 289 | if (mPendingUpload) { |
michael@0 | 290 | mTiledBuffer.SetCompositor(mCompositor); |
michael@0 | 291 | mTiledBuffer.Upload(); |
michael@0 | 292 | |
michael@0 | 293 | // For a single-buffered tiled buffer, Upload will upload the shared memory |
michael@0 | 294 | // surface to texture memory and we no longer need to read from them. |
michael@0 | 295 | if (!mTiledBuffer.HasDoubleBufferedTiles()) { |
michael@0 | 296 | mTiledBuffer.ReadUnlock(); |
michael@0 | 297 | } |
michael@0 | 298 | } |
michael@0 | 299 | if (mPendingLowPrecisionUpload) { |
michael@0 | 300 | mLowPrecisionTiledBuffer.SetCompositor(mCompositor); |
michael@0 | 301 | mLowPrecisionTiledBuffer.Upload(); |
michael@0 | 302 | |
michael@0 | 303 | if (!mLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) { |
michael@0 | 304 | mLowPrecisionTiledBuffer.ReadUnlock(); |
michael@0 | 305 | } |
michael@0 | 306 | } |
michael@0 | 307 | |
michael@0 | 308 | RenderLayerBuffer(mLowPrecisionTiledBuffer, aEffectChain, aOpacity, aFilter, |
michael@0 | 309 | aClipRect, aLayerProperties->mVisibleRegion, aTransform); |
michael@0 | 310 | RenderLayerBuffer(mTiledBuffer, aEffectChain, aOpacity, aFilter, |
michael@0 | 311 | aClipRect, aLayerProperties->mVisibleRegion, aTransform); |
michael@0 | 312 | |
michael@0 | 313 | // Now release the old buffer if it had double-buffered tiles, as we can |
michael@0 | 314 | // guarantee that they're no longer on the screen (and so any locks that may |
michael@0 | 315 | // have been held have been released). |
michael@0 | 316 | if (mPendingUpload && mOldTiledBuffer.HasDoubleBufferedTiles()) { |
michael@0 | 317 | mOldTiledBuffer.ReadUnlock(); |
michael@0 | 318 | mOldTiledBuffer = TiledLayerBufferComposite(); |
michael@0 | 319 | } |
michael@0 | 320 | if (mPendingLowPrecisionUpload && mOldLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) { |
michael@0 | 321 | mOldLowPrecisionTiledBuffer.ReadUnlock(); |
michael@0 | 322 | mOldLowPrecisionTiledBuffer = TiledLayerBufferComposite(); |
michael@0 | 323 | } |
michael@0 | 324 | mPendingUpload = mPendingLowPrecisionUpload = false; |
michael@0 | 325 | } |
michael@0 | 326 | |
michael@0 | 327 | |
michael@0 | 328 | void |
michael@0 | 329 | TiledContentHost::RenderTile(const TileHost& aTile, |
michael@0 | 330 | EffectChain& aEffectChain, |
michael@0 | 331 | float aOpacity, |
michael@0 | 332 | const gfx::Matrix4x4& aTransform, |
michael@0 | 333 | const gfx::Filter& aFilter, |
michael@0 | 334 | const gfx::Rect& aClipRect, |
michael@0 | 335 | const nsIntRegion& aScreenRegion, |
michael@0 | 336 | const nsIntPoint& aTextureOffset, |
michael@0 | 337 | const nsIntSize& aTextureBounds) |
michael@0 | 338 | { |
michael@0 | 339 | if (aTile.IsPlaceholderTile()) { |
michael@0 | 340 | // This shouldn't ever happen, but let's fail semi-gracefully. No need |
michael@0 | 341 | // to warn, the texture update would have already caught this. |
michael@0 | 342 | return; |
michael@0 | 343 | } |
michael@0 | 344 | |
michael@0 | 345 | nsIntRect screenBounds = aScreenRegion.GetBounds(); |
michael@0 | 346 | Rect quad(screenBounds.x, screenBounds.y, screenBounds.width, screenBounds.height); |
michael@0 | 347 | quad = aTransform.TransformBounds(quad); |
michael@0 | 348 | |
michael@0 | 349 | if (!quad.Intersects(mCompositor->ClipRectInLayersCoordinates(aClipRect))) { |
michael@0 | 350 | return; |
michael@0 | 351 | } |
michael@0 | 352 | |
michael@0 | 353 | AutoLockTextureHost autoLock(aTile.mTextureHost); |
michael@0 | 354 | if (autoLock.Failed()) { |
michael@0 | 355 | NS_WARNING("Failed to lock tile"); |
michael@0 | 356 | return; |
michael@0 | 357 | } |
michael@0 | 358 | RefPtr<NewTextureSource> source = aTile.mTextureHost->GetTextureSources(); |
michael@0 | 359 | if (!source) { |
michael@0 | 360 | return; |
michael@0 | 361 | } |
michael@0 | 362 | |
michael@0 | 363 | RefPtr<TexturedEffect> effect = |
michael@0 | 364 | CreateTexturedEffect(aTile.mTextureHost->GetFormat(), source, aFilter); |
michael@0 | 365 | if (!effect) { |
michael@0 | 366 | return; |
michael@0 | 367 | } |
michael@0 | 368 | |
michael@0 | 369 | aEffectChain.mPrimaryEffect = effect; |
michael@0 | 370 | |
michael@0 | 371 | nsIntRegionRectIterator it(aScreenRegion); |
michael@0 | 372 | for (const nsIntRect* rect = it.Next(); rect != nullptr; rect = it.Next()) { |
michael@0 | 373 | Rect graphicsRect(rect->x, rect->y, rect->width, rect->height); |
michael@0 | 374 | Rect textureRect(rect->x - aTextureOffset.x, rect->y - aTextureOffset.y, |
michael@0 | 375 | rect->width, rect->height); |
michael@0 | 376 | |
michael@0 | 377 | effect->mTextureCoords = Rect(textureRect.x / aTextureBounds.width, |
michael@0 | 378 | textureRect.y / aTextureBounds.height, |
michael@0 | 379 | textureRect.width / aTextureBounds.width, |
michael@0 | 380 | textureRect.height / aTextureBounds.height); |
michael@0 | 381 | mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, aOpacity, aTransform); |
michael@0 | 382 | } |
michael@0 | 383 | mCompositor->DrawDiagnostics(DIAGNOSTIC_CONTENT|DIAGNOSTIC_TILE, |
michael@0 | 384 | aScreenRegion, aClipRect, aTransform, mFlashCounter); |
michael@0 | 385 | } |
michael@0 | 386 | |
michael@0 | 387 | void |
michael@0 | 388 | TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer, |
michael@0 | 389 | EffectChain& aEffectChain, |
michael@0 | 390 | float aOpacity, |
michael@0 | 391 | const gfx::Filter& aFilter, |
michael@0 | 392 | const gfx::Rect& aClipRect, |
michael@0 | 393 | nsIntRegion aVisibleRegion, |
michael@0 | 394 | gfx::Matrix4x4 aTransform) |
michael@0 | 395 | { |
michael@0 | 396 | if (!mCompositor) { |
michael@0 | 397 | NS_WARNING("Can't render tiled content host - no compositor"); |
michael@0 | 398 | return; |
michael@0 | 399 | } |
michael@0 | 400 | float resolution = aLayerBuffer.GetResolution(); |
michael@0 | 401 | gfx::Size layerScale(1, 1); |
michael@0 | 402 | |
michael@0 | 403 | // We assume that the current frame resolution is the one used in our high |
michael@0 | 404 | // precision layer buffer. Compensate for a changing frame resolution when |
michael@0 | 405 | // rendering the low precision buffer. |
michael@0 | 406 | if (aLayerBuffer.GetFrameResolution() != mTiledBuffer.GetFrameResolution()) { |
michael@0 | 407 | const CSSToParentLayerScale& layerResolution = aLayerBuffer.GetFrameResolution(); |
michael@0 | 408 | const CSSToParentLayerScale& localResolution = mTiledBuffer.GetFrameResolution(); |
michael@0 | 409 | layerScale.width = layerScale.height = layerResolution.scale / localResolution.scale; |
michael@0 | 410 | aVisibleRegion.ScaleRoundOut(layerScale.width, layerScale.height); |
michael@0 | 411 | } |
michael@0 | 412 | |
michael@0 | 413 | // If we're drawing the low precision buffer, make sure the high precision |
michael@0 | 414 | // buffer is masked out to avoid overdraw and rendering artifacts with |
michael@0 | 415 | // non-opaque layers. |
michael@0 | 416 | nsIntRegion maskRegion; |
michael@0 | 417 | if (resolution != mTiledBuffer.GetResolution()) { |
michael@0 | 418 | maskRegion = mTiledBuffer.GetValidRegion(); |
michael@0 | 419 | // XXX This should be ScaleRoundIn, but there is no such function on |
michael@0 | 420 | // nsIntRegion. |
michael@0 | 421 | maskRegion.ScaleRoundOut(layerScale.width, layerScale.height); |
michael@0 | 422 | } |
michael@0 | 423 | |
michael@0 | 424 | // Make sure the resolution and difference in frame resolution are accounted |
michael@0 | 425 | // for in the layer transform. |
michael@0 | 426 | aTransform.Scale(1/(resolution * layerScale.width), |
michael@0 | 427 | 1/(resolution * layerScale.height), 1); |
michael@0 | 428 | |
michael@0 | 429 | uint32_t rowCount = 0; |
michael@0 | 430 | uint32_t tileX = 0; |
michael@0 | 431 | nsIntRect visibleRect = aVisibleRegion.GetBounds(); |
michael@0 | 432 | gfx::IntSize scaledTileSize = aLayerBuffer.GetScaledTileSize(); |
michael@0 | 433 | for (int32_t x = visibleRect.x; x < visibleRect.x + visibleRect.width;) { |
michael@0 | 434 | rowCount++; |
michael@0 | 435 | int32_t tileStartX = aLayerBuffer.GetTileStart(x, scaledTileSize.width); |
michael@0 | 436 | int32_t w = scaledTileSize.width - tileStartX; |
michael@0 | 437 | if (x + w > visibleRect.x + visibleRect.width) { |
michael@0 | 438 | w = visibleRect.x + visibleRect.width - x; |
michael@0 | 439 | } |
michael@0 | 440 | int tileY = 0; |
michael@0 | 441 | for (int32_t y = visibleRect.y; y < visibleRect.y + visibleRect.height;) { |
michael@0 | 442 | int32_t tileStartY = aLayerBuffer.GetTileStart(y, scaledTileSize.height); |
michael@0 | 443 | int32_t h = scaledTileSize.height - tileStartY; |
michael@0 | 444 | if (y + h > visibleRect.y + visibleRect.height) { |
michael@0 | 445 | h = visibleRect.y + visibleRect.height - y; |
michael@0 | 446 | } |
michael@0 | 447 | |
michael@0 | 448 | TileHost tileTexture = aLayerBuffer. |
michael@0 | 449 | GetTile(nsIntPoint(aLayerBuffer.RoundDownToTileEdge(x, scaledTileSize.width), |
michael@0 | 450 | aLayerBuffer.RoundDownToTileEdge(y, scaledTileSize.height))); |
michael@0 | 451 | if (tileTexture != aLayerBuffer.GetPlaceholderTile()) { |
michael@0 | 452 | nsIntRegion tileDrawRegion; |
michael@0 | 453 | tileDrawRegion.And(nsIntRect(x, y, w, h), aLayerBuffer.GetValidRegion()); |
michael@0 | 454 | tileDrawRegion.And(tileDrawRegion, aVisibleRegion); |
michael@0 | 455 | tileDrawRegion.Sub(tileDrawRegion, maskRegion); |
michael@0 | 456 | |
michael@0 | 457 | if (!tileDrawRegion.IsEmpty()) { |
michael@0 | 458 | tileDrawRegion.ScaleRoundOut(resolution, resolution); |
michael@0 | 459 | nsIntPoint tileOffset((x - tileStartX) * resolution, |
michael@0 | 460 | (y - tileStartY) * resolution); |
michael@0 | 461 | gfx::IntSize tileSize = aLayerBuffer.GetTileSize(); |
michael@0 | 462 | RenderTile(tileTexture, aEffectChain, aOpacity, aTransform, aFilter, aClipRect, tileDrawRegion, |
michael@0 | 463 | tileOffset, nsIntSize(tileSize.width, tileSize.height)); |
michael@0 | 464 | } |
michael@0 | 465 | } |
michael@0 | 466 | tileY++; |
michael@0 | 467 | y += h; |
michael@0 | 468 | } |
michael@0 | 469 | tileX++; |
michael@0 | 470 | x += w; |
michael@0 | 471 | } |
michael@0 | 472 | gfx::Rect rect(visibleRect.x, visibleRect.y, |
michael@0 | 473 | visibleRect.width, visibleRect.height); |
michael@0 | 474 | GetCompositor()->DrawDiagnostics(DIAGNOSTIC_CONTENT, |
michael@0 | 475 | rect, aClipRect, aTransform, mFlashCounter); |
michael@0 | 476 | } |
michael@0 | 477 | |
michael@0 | 478 | void |
michael@0 | 479 | TiledContentHost::PrintInfo(nsACString& aTo, const char* aPrefix) |
michael@0 | 480 | { |
michael@0 | 481 | aTo += aPrefix; |
michael@0 | 482 | aTo += nsPrintfCString("TiledContentHost (0x%p)", this); |
michael@0 | 483 | |
michael@0 | 484 | } |
michael@0 | 485 | |
michael@0 | 486 | #ifdef MOZ_DUMP_PAINTING |
michael@0 | 487 | void |
michael@0 | 488 | TiledContentHost::Dump(FILE* aFile, |
michael@0 | 489 | const char* aPrefix, |
michael@0 | 490 | bool aDumpHtml) |
michael@0 | 491 | { |
michael@0 | 492 | if (!aFile) { |
michael@0 | 493 | aFile = stderr; |
michael@0 | 494 | } |
michael@0 | 495 | |
michael@0 | 496 | TiledLayerBufferComposite::Iterator it = mTiledBuffer.TilesBegin(); |
michael@0 | 497 | TiledLayerBufferComposite::Iterator stop = mTiledBuffer.TilesEnd(); |
michael@0 | 498 | if (aDumpHtml) { |
michael@0 | 499 | fprintf_stderr(aFile, "<ul>"); |
michael@0 | 500 | } |
michael@0 | 501 | for (;it != stop; ++it) { |
michael@0 | 502 | fprintf_stderr(aFile, "%s", aPrefix); |
michael@0 | 503 | fprintf_stderr(aFile, aDumpHtml ? "<li> <a href=" : "Tile "); |
michael@0 | 504 | if (it->IsPlaceholderTile()) { |
michael@0 | 505 | fprintf_stderr(aFile, "empty tile"); |
michael@0 | 506 | } else { |
michael@0 | 507 | DumpTextureHost(aFile, it->mTextureHost); |
michael@0 | 508 | } |
michael@0 | 509 | fprintf_stderr(aFile, aDumpHtml ? " >Tile</a></li>" : " "); |
michael@0 | 510 | } |
michael@0 | 511 | if (aDumpHtml) { |
michael@0 | 512 | fprintf_stderr(aFile, "</ul>"); |
michael@0 | 513 | } |
michael@0 | 514 | } |
michael@0 | 515 | #endif |
michael@0 | 516 | |
michael@0 | 517 | } // namespace |
michael@0 | 518 | } // namespace |