gfx/layers/d3d9/ThebesLayerD3D9.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 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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 "mozilla/layers/PLayerTransaction.h"
michael@0 7
michael@0 8 // This must occur *after* layers/PLayerTransaction.h to avoid
michael@0 9 // typedefs conflicts.
michael@0 10 #include "mozilla/ArrayUtils.h"
michael@0 11
michael@0 12 #include "ThebesLayerD3D9.h"
michael@0 13 #include "gfxPlatform.h"
michael@0 14
michael@0 15 #include "gfxWindowsPlatform.h"
michael@0 16 #include "gfxTeeSurface.h"
michael@0 17 #include "gfxUtils.h"
michael@0 18 #include "ReadbackProcessor.h"
michael@0 19 #include "ReadbackLayer.h"
michael@0 20 #include "mozilla/gfx/2D.h"
michael@0 21
michael@0 22 namespace mozilla {
michael@0 23 namespace layers {
michael@0 24
michael@0 25 using namespace gfx;
michael@0 26
michael@0 27 ThebesLayerD3D9::ThebesLayerD3D9(LayerManagerD3D9 *aManager)
michael@0 28 : ThebesLayer(aManager, nullptr)
michael@0 29 , LayerD3D9(aManager)
michael@0 30 {
michael@0 31 mImplData = static_cast<LayerD3D9*>(this);
michael@0 32 aManager->deviceManager()->mLayersWithResources.AppendElement(this);
michael@0 33 }
michael@0 34
michael@0 35 ThebesLayerD3D9::~ThebesLayerD3D9()
michael@0 36 {
michael@0 37 if (mD3DManager) {
michael@0 38 mD3DManager->deviceManager()->mLayersWithResources.RemoveElement(this);
michael@0 39 }
michael@0 40 }
michael@0 41
michael@0 42 /**
michael@0 43 * Retention threshold - amount of pixels intersection required to enable
michael@0 44 * layer content retention. This is a guesstimate. Profiling could be done to
michael@0 45 * figure out the optimal threshold.
michael@0 46 */
michael@0 47 #define RETENTION_THRESHOLD 16384
michael@0 48
michael@0 49 void
michael@0 50 ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion)
michael@0 51 {
michael@0 52 mInvalidRegion.Or(mInvalidRegion, aRegion);
michael@0 53 mInvalidRegion.SimplifyOutward(20);
michael@0 54 mValidRegion.Sub(mValidRegion, mInvalidRegion);
michael@0 55 }
michael@0 56
michael@0 57 void
michael@0 58 ThebesLayerD3D9::CopyRegion(IDirect3DTexture9* aSrc, const nsIntPoint &aSrcOffset,
michael@0 59 IDirect3DTexture9* aDest, const nsIntPoint &aDestOffset,
michael@0 60 const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion)
michael@0 61 {
michael@0 62 nsRefPtr<IDirect3DSurface9> srcSurface, dstSurface;
michael@0 63 aSrc->GetSurfaceLevel(0, getter_AddRefs(srcSurface));
michael@0 64 aDest->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
michael@0 65
michael@0 66 nsIntRegion retainedRegion;
michael@0 67 nsIntRegionRectIterator iter(aCopyRegion);
michael@0 68 const nsIntRect *r;
michael@0 69 while ((r = iter.Next())) {
michael@0 70 if (r->width * r->height > RETENTION_THRESHOLD) {
michael@0 71 RECT oldRect, newRect;
michael@0 72
michael@0 73 // Calculate the retained rectangle's position on the old and the new
michael@0 74 // surface.
michael@0 75 oldRect.left = r->x - aSrcOffset.x;
michael@0 76 oldRect.top = r->y - aSrcOffset.y;
michael@0 77 oldRect.right = oldRect.left + r->width;
michael@0 78 oldRect.bottom = oldRect.top + r->height;
michael@0 79
michael@0 80 newRect.left = r->x - aDestOffset.x;
michael@0 81 newRect.top = r->y - aDestOffset.y;
michael@0 82 newRect.right = newRect.left + r->width;
michael@0 83 newRect.bottom = newRect.top + r->height;
michael@0 84
michael@0 85 // Copy data from our old texture to the new one
michael@0 86 HRESULT hr = device()->
michael@0 87 StretchRect(srcSurface, &oldRect, dstSurface, &newRect, D3DTEXF_NONE);
michael@0 88
michael@0 89 if (SUCCEEDED(hr)) {
michael@0 90 retainedRegion.Or(retainedRegion, *r);
michael@0 91 }
michael@0 92 }
michael@0 93 }
michael@0 94
michael@0 95 // Areas which were valid and were retained are still valid
michael@0 96 aValidRegion->And(*aValidRegion, retainedRegion);
michael@0 97 }
michael@0 98
michael@0 99 static uint64_t RectArea(const nsIntRect& aRect)
michael@0 100 {
michael@0 101 return aRect.width*uint64_t(aRect.height);
michael@0 102 }
michael@0 103
michael@0 104 void
michael@0 105 ThebesLayerD3D9::UpdateTextures(SurfaceMode aMode)
michael@0 106 {
michael@0 107 nsIntRect visibleRect = mVisibleRegion.GetBounds();
michael@0 108
michael@0 109 if (HaveTextures(aMode)) {
michael@0 110 if (!mTextureRect.IsEqualInterior(visibleRect)) {
michael@0 111 nsRefPtr<IDirect3DTexture9> oldTexture = mTexture;
michael@0 112 nsRefPtr<IDirect3DTexture9> oldTextureOnWhite = mTextureOnWhite;
michael@0 113
michael@0 114 NS_ASSERTION(mTextureRect.Contains(mValidRegion.GetBounds()),
michael@0 115 "How can we have valid data outside the texture?");
michael@0 116 nsIntRegion retainRegion;
michael@0 117 // The region we want to retain is the valid data that is inside
michael@0 118 // the new visible region
michael@0 119 retainRegion.And(mValidRegion, mVisibleRegion);
michael@0 120
michael@0 121 CreateNewTextures(gfx::IntSize(visibleRect.width, visibleRect.height), aMode);
michael@0 122
michael@0 123 // If our texture creation failed this can mean a device reset is pending and we
michael@0 124 // should silently ignore the failure. In the future when device failures
michael@0 125 // are properly handled we should test for the type of failure and gracefully
michael@0 126 // handle different failures. See bug 569081.
michael@0 127 if (!HaveTextures(aMode)) {
michael@0 128 mValidRegion.SetEmpty();
michael@0 129 } else {
michael@0 130 CopyRegion(oldTexture, mTextureRect.TopLeft(), mTexture, visibleRect.TopLeft(),
michael@0 131 retainRegion, &mValidRegion);
michael@0 132 if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
michael@0 133 CopyRegion(oldTextureOnWhite, mTextureRect.TopLeft(), mTextureOnWhite, visibleRect.TopLeft(),
michael@0 134 retainRegion, &mValidRegion);
michael@0 135 }
michael@0 136 }
michael@0 137
michael@0 138 mTextureRect = visibleRect;
michael@0 139 }
michael@0 140 } else {
michael@0 141 CreateNewTextures(gfx::IntSize(visibleRect.width, visibleRect.height), aMode);
michael@0 142 mTextureRect = visibleRect;
michael@0 143
michael@0 144 NS_ASSERTION(mValidRegion.IsEmpty(), "Someone forgot to empty the region");
michael@0 145 }
michael@0 146 }
michael@0 147
michael@0 148 void
michael@0 149 ThebesLayerD3D9::RenderRegion(const nsIntRegion& aRegion)
michael@0 150 {
michael@0 151 nsIntRegionRectIterator iter(aRegion);
michael@0 152
michael@0 153 const nsIntRect *iterRect;
michael@0 154 while ((iterRect = iter.Next())) {
michael@0 155 device()->SetVertexShaderConstantF(CBvLayerQuad,
michael@0 156 ShaderConstantRect(iterRect->x,
michael@0 157 iterRect->y,
michael@0 158 iterRect->width,
michael@0 159 iterRect->height),
michael@0 160 1);
michael@0 161
michael@0 162 device()->SetVertexShaderConstantF(CBvTextureCoords,
michael@0 163 ShaderConstantRect(
michael@0 164 (float)(iterRect->x - mTextureRect.x) / (float)mTextureRect.width,
michael@0 165 (float)(iterRect->y - mTextureRect.y) / (float)mTextureRect.height,
michael@0 166 (float)iterRect->width / (float)mTextureRect.width,
michael@0 167 (float)iterRect->height / (float)mTextureRect.height), 1);
michael@0 168
michael@0 169 device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
michael@0 170 }
michael@0 171 }
michael@0 172
michael@0 173 void
michael@0 174 ThebesLayerD3D9::RenderThebesLayer(ReadbackProcessor* aReadback)
michael@0 175 {
michael@0 176 if (mVisibleRegion.IsEmpty()) {
michael@0 177 return;
michael@0 178 }
michael@0 179
michael@0 180 nsIntRect newTextureRect = mVisibleRegion.GetBounds();
michael@0 181
michael@0 182 SurfaceMode mode = GetSurfaceMode();
michael@0 183 if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA &&
michael@0 184 (!mParent || !mParent->SupportsComponentAlphaChildren())) {
michael@0 185 mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
michael@0 186 }
michael@0 187 // If we have a transform that requires resampling of our texture, then
michael@0 188 // we need to make sure we don't sample pixels that haven't been drawn.
michael@0 189 // We clamp sample coordinates to the texture rect, but when the visible region
michael@0 190 // doesn't fill the entire texture rect we need to make sure we draw all the
michael@0 191 // pixels in the texture rect anyway in case they get sampled.
michael@0 192 nsIntRegion neededRegion = mVisibleRegion;
michael@0 193 if (!neededRegion.GetBounds().IsEqualInterior(newTextureRect) ||
michael@0 194 neededRegion.GetNumRects() > 1) {
michael@0 195 if (MayResample()) {
michael@0 196 neededRegion = newTextureRect;
michael@0 197 if (mode == SurfaceMode::SURFACE_OPAQUE) {
michael@0 198 // We're going to paint outside the visible region, but layout hasn't
michael@0 199 // promised that it will paint opaquely there, so we'll have to
michael@0 200 // treat this layer as transparent.
michael@0 201 mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
michael@0 202 }
michael@0 203 }
michael@0 204 }
michael@0 205
michael@0 206 VerifyContentType(mode);
michael@0 207 UpdateTextures(mode);
michael@0 208 if (!HaveTextures(mode)) {
michael@0 209 NS_WARNING("Texture creation failed");
michael@0 210 return;
michael@0 211 }
michael@0 212
michael@0 213 nsTArray<ReadbackProcessor::Update> readbackUpdates;
michael@0 214 nsIntRegion readbackRegion;
michael@0 215 if (aReadback && UsedForReadback()) {
michael@0 216 aReadback->GetThebesLayerUpdates(this, &readbackUpdates, &readbackRegion);
michael@0 217 }
michael@0 218
michael@0 219 // Because updates to D3D9 ThebesLayers are rendered with the CPU, we don't
michael@0 220 // have to do readback from D3D9 surfaces. Instead we make sure that any area
michael@0 221 // needed for readback is included in the drawRegion we ask layout to render.
michael@0 222 // Then the readback areas we need can be copied out of the temporary
michael@0 223 // destinationSurface in DrawRegion.
michael@0 224 nsIntRegion drawRegion;
michael@0 225 drawRegion.Sub(neededRegion, mValidRegion);
michael@0 226 drawRegion.Or(drawRegion, readbackRegion);
michael@0 227 // NS_ASSERTION(mVisibleRegion.Contains(region), "Bad readback region!");
michael@0 228
michael@0 229 if (!drawRegion.IsEmpty()) {
michael@0 230 LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
michael@0 231 if (!cbInfo.Callback) {
michael@0 232 NS_ERROR("D3D9 should never need to update ThebesLayers in an empty transaction");
michael@0 233 return;
michael@0 234 }
michael@0 235
michael@0 236 DrawRegion(drawRegion, mode, readbackUpdates);
michael@0 237
michael@0 238 mValidRegion = neededRegion;
michael@0 239 }
michael@0 240
michael@0 241 if (mD3DManager->CompositingDisabled()) {
michael@0 242 return;
michael@0 243 }
michael@0 244
michael@0 245 SetShaderTransformAndOpacity();
michael@0 246
michael@0 247 if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
michael@0 248 mD3DManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS1,
michael@0 249 GetMaskLayer());
michael@0 250 device()->SetTexture(0, mTexture);
michael@0 251 device()->SetTexture(1, mTextureOnWhite);
michael@0 252 device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
michael@0 253 device()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR);
michael@0 254 RenderRegion(neededRegion);
michael@0 255
michael@0 256 mD3DManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS2,
michael@0 257 GetMaskLayer());
michael@0 258 device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
michael@0 259 device()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
michael@0 260 RenderRegion(neededRegion);
michael@0 261
michael@0 262 // Restore defaults
michael@0 263 device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
michael@0 264 device()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
michael@0 265 device()->SetTexture(1, nullptr);
michael@0 266 } else {
michael@0 267 mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER,
michael@0 268 GetMaskLayer());
michael@0 269 device()->SetTexture(0, mTexture);
michael@0 270 RenderRegion(neededRegion);
michael@0 271 }
michael@0 272
michael@0 273 // Set back to default.
michael@0 274 device()->SetVertexShaderConstantF(CBvTextureCoords,
michael@0 275 ShaderConstantRect(0, 0, 1.0f, 1.0f),
michael@0 276 1);
michael@0 277 }
michael@0 278
michael@0 279 void
michael@0 280 ThebesLayerD3D9::CleanResources()
michael@0 281 {
michael@0 282 mTexture = nullptr;
michael@0 283 mTextureOnWhite = nullptr;
michael@0 284 mValidRegion.SetEmpty();
michael@0 285 }
michael@0 286
michael@0 287 void
michael@0 288 ThebesLayerD3D9::LayerManagerDestroyed()
michael@0 289 {
michael@0 290 mD3DManager->deviceManager()->mLayersWithResources.RemoveElement(this);
michael@0 291 mD3DManager = nullptr;
michael@0 292 }
michael@0 293
michael@0 294 Layer*
michael@0 295 ThebesLayerD3D9::GetLayer()
michael@0 296 {
michael@0 297 return this;
michael@0 298 }
michael@0 299
michael@0 300 bool
michael@0 301 ThebesLayerD3D9::IsEmpty()
michael@0 302 {
michael@0 303 return !mTexture;
michael@0 304 }
michael@0 305
michael@0 306 void
michael@0 307 ThebesLayerD3D9::VerifyContentType(SurfaceMode aMode)
michael@0 308 {
michael@0 309 if (!mTexture)
michael@0 310 return;
michael@0 311
michael@0 312 D3DSURFACE_DESC desc;
michael@0 313 mTexture->GetLevelDesc(0, &desc);
michael@0 314
michael@0 315 switch (aMode) {
michael@0 316 case SurfaceMode::SURFACE_OPAQUE:
michael@0 317 if (desc.Format == D3DFMT_X8R8G8B8 && !mTextureOnWhite)
michael@0 318 return;
michael@0 319 break;
michael@0 320
michael@0 321 case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA:
michael@0 322 if (desc.Format == D3DFMT_A8R8G8B8 && !mTextureOnWhite)
michael@0 323 return;
michael@0 324 break;
michael@0 325
michael@0 326 case SurfaceMode::SURFACE_COMPONENT_ALPHA:
michael@0 327 if (mTextureOnWhite) {
michael@0 328 NS_ASSERTION(desc.Format == D3DFMT_X8R8G8B8, "Wrong format for component alpha texture");
michael@0 329 return;
michael@0 330 }
michael@0 331 break;
michael@0 332 }
michael@0 333
michael@0 334 // The new format isn't compatible with the old texture(s), toss out the old
michael@0 335 // texture(s).
michael@0 336 mTexture = nullptr;
michael@0 337 mTextureOnWhite = nullptr;
michael@0 338 mValidRegion.SetEmpty();
michael@0 339 }
michael@0 340
michael@0 341 class OpaqueRenderer {
michael@0 342 public:
michael@0 343 OpaqueRenderer(const nsIntRegion& aUpdateRegion) :
michael@0 344 mUpdateRegion(aUpdateRegion) {}
michael@0 345 ~OpaqueRenderer() { End(); }
michael@0 346 already_AddRefed<gfxWindowsSurface> Begin(LayerD3D9* aLayer);
michael@0 347 void End();
michael@0 348 IDirect3DTexture9* GetTexture() { return mTmpTexture; }
michael@0 349
michael@0 350 private:
michael@0 351 const nsIntRegion& mUpdateRegion;
michael@0 352 nsRefPtr<IDirect3DTexture9> mTmpTexture;
michael@0 353 nsRefPtr<IDirect3DSurface9> mSurface;
michael@0 354 nsRefPtr<gfxWindowsSurface> mD3D9ThebesSurface;
michael@0 355 };
michael@0 356
michael@0 357 already_AddRefed<gfxWindowsSurface>
michael@0 358 OpaqueRenderer::Begin(LayerD3D9* aLayer)
michael@0 359 {
michael@0 360 nsIntRect bounds = mUpdateRegion.GetBounds();
michael@0 361
michael@0 362 HRESULT hr = aLayer->device()->
michael@0 363 CreateTexture(bounds.width, bounds.height, 1, 0, D3DFMT_X8R8G8B8,
michael@0 364 D3DPOOL_SYSTEMMEM, getter_AddRefs(mTmpTexture), nullptr);
michael@0 365
michael@0 366 if (FAILED(hr)) {
michael@0 367 aLayer->ReportFailure(NS_LITERAL_CSTRING("Failed to create temporary texture in system memory."), hr);
michael@0 368 return nullptr;
michael@0 369 }
michael@0 370
michael@0 371 hr = mTmpTexture->GetSurfaceLevel(0, getter_AddRefs(mSurface));
michael@0 372
michael@0 373 if (FAILED(hr)) {
michael@0 374 // Uh-oh, bail.
michael@0 375 NS_WARNING("Failed to get texture surface level.");
michael@0 376 return nullptr;
michael@0 377 }
michael@0 378
michael@0 379 nsRefPtr<gfxWindowsSurface> result = new gfxWindowsSurface(mSurface);
michael@0 380 if (!result || result->CairoStatus()) {
michael@0 381 NS_WARNING("Failed to d3d9 cairo surface.");
michael@0 382 return nullptr;
michael@0 383 }
michael@0 384 mD3D9ThebesSurface = result;
michael@0 385
michael@0 386 return result.forget();
michael@0 387 }
michael@0 388
michael@0 389 void
michael@0 390 OpaqueRenderer::End()
michael@0 391 {
michael@0 392 mSurface = nullptr;
michael@0 393 // gfxWindowsSurface returned from ::Begin() should be released before the
michael@0 394 // texture is used. This will assert that this is the case
michael@0 395 #if 1
michael@0 396 if (mD3D9ThebesSurface) {
michael@0 397 mD3D9ThebesSurface->AddRef();
michael@0 398 nsrefcnt c = mD3D9ThebesSurface->Release();
michael@0 399 if (c != 1)
michael@0 400 NS_RUNTIMEABORT("Reference mD3D9ThebesSurface must be released by caller of Begin() before calling End()");
michael@0 401 }
michael@0 402 #endif
michael@0 403 mD3D9ThebesSurface = nullptr;
michael@0 404
michael@0 405 }
michael@0 406
michael@0 407 static void
michael@0 408 FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion,
michael@0 409 const nsIntPoint& aOffset, const gfxRGBA& aColor)
michael@0 410 {
michael@0 411 nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
michael@0 412 ctx->Translate(-gfxPoint(aOffset.x, aOffset.y));
michael@0 413 gfxUtils::ClipToRegion(ctx, aRegion);
michael@0 414 ctx->SetColor(aColor);
michael@0 415 ctx->Paint();
michael@0 416 }
michael@0 417
michael@0 418 void
michael@0 419 ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
michael@0 420 const nsTArray<ReadbackProcessor::Update>& aReadbackUpdates)
michael@0 421 {
michael@0 422 HRESULT hr;
michael@0 423 nsIntRect visibleRect = mVisibleRegion.GetBounds();
michael@0 424
michael@0 425 nsRefPtr<gfxASurface> destinationSurface;
michael@0 426 nsIntRect bounds = aRegion.GetBounds();
michael@0 427 nsRefPtr<IDirect3DTexture9> tmpTexture;
michael@0 428 OpaqueRenderer opaqueRenderer(aRegion);
michael@0 429 OpaqueRenderer opaqueRendererOnWhite(aRegion);
michael@0 430
michael@0 431 switch (aMode)
michael@0 432 {
michael@0 433 case SurfaceMode::SURFACE_OPAQUE:
michael@0 434 destinationSurface = opaqueRenderer.Begin(this);
michael@0 435 break;
michael@0 436
michael@0 437 case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: {
michael@0 438 hr = device()->CreateTexture(bounds.width, bounds.height, 1,
michael@0 439 0, D3DFMT_A8R8G8B8,
michael@0 440 D3DPOOL_SYSTEMMEM, getter_AddRefs(tmpTexture), nullptr);
michael@0 441
michael@0 442 if (FAILED(hr)) {
michael@0 443 ReportFailure(NS_LITERAL_CSTRING("Failed to create temporary texture in system memory."), hr);
michael@0 444 return;
michael@0 445 }
michael@0 446
michael@0 447 // XXX - We may consider retaining a SYSTEMMEM texture texture the size
michael@0 448 // of our DEFAULT texture and then use UpdateTexture and add dirty rects
michael@0 449 // to update in a single call.
michael@0 450 nsRefPtr<gfxWindowsSurface> dest = new gfxWindowsSurface(
michael@0 451 gfxIntSize(bounds.width, bounds.height), gfxImageFormat::ARGB32);
michael@0 452 // If the contents of this layer don't require component alpha in the
michael@0 453 // end of rendering, it's safe to enable Cleartype since all the Cleartype
michael@0 454 // glyphs must be over (or under) opaque pixels.
michael@0 455 dest->SetSubpixelAntialiasingEnabled(!(mContentFlags & CONTENT_COMPONENT_ALPHA));
michael@0 456 destinationSurface = dest.forget();
michael@0 457 break;
michael@0 458 }
michael@0 459
michael@0 460 case SurfaceMode::SURFACE_COMPONENT_ALPHA: {
michael@0 461 nsRefPtr<gfxWindowsSurface> onBlack = opaqueRenderer.Begin(this);
michael@0 462 nsRefPtr<gfxWindowsSurface> onWhite = opaqueRendererOnWhite.Begin(this);
michael@0 463 if (onBlack && onWhite) {
michael@0 464 FillSurface(onBlack, aRegion, bounds.TopLeft(), gfxRGBA(0.0, 0.0, 0.0, 1.0));
michael@0 465 FillSurface(onWhite, aRegion, bounds.TopLeft(), gfxRGBA(1.0, 1.0, 1.0, 1.0));
michael@0 466 gfxASurface* surfaces[2] = { onBlack.get(), onWhite.get() };
michael@0 467 destinationSurface = new gfxTeeSurface(surfaces, ArrayLength(surfaces));
michael@0 468 // Using this surface as a source will likely go horribly wrong, since
michael@0 469 // only the onBlack surface will really be used, so alpha information will
michael@0 470 // be incorrect.
michael@0 471 destinationSurface->SetAllowUseAsSource(false);
michael@0 472 }
michael@0 473 break;
michael@0 474 }
michael@0 475 }
michael@0 476
michael@0 477 if (!destinationSurface)
michael@0 478 return;
michael@0 479
michael@0 480 nsRefPtr<gfxContext> context;
michael@0 481 if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(BackendType::CAIRO)) {
michael@0 482 RefPtr<DrawTarget> dt =
michael@0 483 gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(destinationSurface,
michael@0 484 IntSize(destinationSurface->GetSize().width,
michael@0 485 destinationSurface->GetSize().height));
michael@0 486
michael@0 487 context = new gfxContext(dt);
michael@0 488 } else {
michael@0 489 context = new gfxContext(destinationSurface);
michael@0 490 }
michael@0 491
michael@0 492 context->Translate(gfxPoint(-bounds.x, -bounds.y));
michael@0 493 LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
michael@0 494 cbInfo.Callback(this, context, aRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), cbInfo.CallbackData);
michael@0 495
michael@0 496 for (uint32_t i = 0; i < aReadbackUpdates.Length(); ++i) {
michael@0 497 NS_ASSERTION(aMode == SurfaceMode::SURFACE_OPAQUE,
michael@0 498 "Transparent surfaces should not be used for readback");
michael@0 499 const ReadbackProcessor::Update& update = aReadbackUpdates[i];
michael@0 500 nsIntPoint offset = update.mLayer->GetBackgroundLayerOffset();
michael@0 501 nsRefPtr<gfxContext> ctx =
michael@0 502 update.mLayer->GetSink()->BeginUpdate(update.mUpdateRect + offset,
michael@0 503 update.mSequenceCounter);
michael@0 504 if (ctx) {
michael@0 505 ctx->Translate(gfxPoint(offset.x, offset.y));
michael@0 506 ctx->SetSource(destinationSurface, gfxPoint(bounds.x, bounds.y));
michael@0 507 ctx->Paint();
michael@0 508 update.mLayer->GetSink()->EndUpdate(ctx, update.mUpdateRect + offset);
michael@0 509 }
michael@0 510 }
michael@0 511
michael@0 512 // Release the cairo d3d9 surface before we try to composite it
michael@0 513 context = nullptr;
michael@0 514
michael@0 515 nsAutoTArray<IDirect3DTexture9*,2> srcTextures;
michael@0 516 nsAutoTArray<IDirect3DTexture9*,2> destTextures;
michael@0 517 switch (aMode)
michael@0 518 {
michael@0 519 case SurfaceMode::SURFACE_OPAQUE:
michael@0 520 // Must release reference to dest surface before ending drawing
michael@0 521 destinationSurface = nullptr;
michael@0 522 opaqueRenderer.End();
michael@0 523 srcTextures.AppendElement(opaqueRenderer.GetTexture());
michael@0 524 destTextures.AppendElement(mTexture);
michael@0 525 break;
michael@0 526
michael@0 527 case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: {
michael@0 528 LockTextureRectD3D9 textureLock(tmpTexture);
michael@0 529 if (!textureLock.HasLock()) {
michael@0 530 NS_WARNING("Failed to lock ThebesLayer tmpTexture texture.");
michael@0 531 return;
michael@0 532 }
michael@0 533
michael@0 534 D3DLOCKED_RECT r = textureLock.GetLockRect();
michael@0 535
michael@0 536 nsRefPtr<gfxImageSurface> imgSurface =
michael@0 537 new gfxImageSurface((unsigned char *)r.pBits,
michael@0 538 bounds.Size(),
michael@0 539 r.Pitch,
michael@0 540 gfxImageFormat::ARGB32);
michael@0 541
michael@0 542 if (destinationSurface) {
michael@0 543 nsRefPtr<gfxContext> context = new gfxContext(imgSurface);
michael@0 544 context->SetSource(destinationSurface);
michael@0 545 context->SetOperator(gfxContext::OPERATOR_SOURCE);
michael@0 546 context->Paint();
michael@0 547 }
michael@0 548
michael@0 549 // Must release reference to dest surface before ending drawing
michael@0 550 destinationSurface = nullptr;
michael@0 551 imgSurface = nullptr;
michael@0 552
michael@0 553 srcTextures.AppendElement(tmpTexture);
michael@0 554 destTextures.AppendElement(mTexture);
michael@0 555 break;
michael@0 556 }
michael@0 557
michael@0 558 case SurfaceMode::SURFACE_COMPONENT_ALPHA: {
michael@0 559 // Must release reference to dest surface before ending drawing
michael@0 560 destinationSurface = nullptr;
michael@0 561 opaqueRenderer.End();
michael@0 562 opaqueRendererOnWhite.End();
michael@0 563 srcTextures.AppendElement(opaqueRenderer.GetTexture());
michael@0 564 destTextures.AppendElement(mTexture);
michael@0 565 srcTextures.AppendElement(opaqueRendererOnWhite.GetTexture());
michael@0 566 destTextures.AppendElement(mTextureOnWhite);
michael@0 567 break;
michael@0 568 }
michael@0 569 }
michael@0 570 NS_ASSERTION(srcTextures.Length() == destTextures.Length(), "Mismatched lengths");
michael@0 571
michael@0 572
michael@0 573 // Copy to the texture.
michael@0 574 for (uint32_t i = 0; i < srcTextures.Length(); ++i) {
michael@0 575 nsRefPtr<IDirect3DSurface9> srcSurface;
michael@0 576 nsRefPtr<IDirect3DSurface9> dstSurface;
michael@0 577
michael@0 578 destTextures[i]->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
michael@0 579 srcTextures[i]->GetSurfaceLevel(0, getter_AddRefs(srcSurface));
michael@0 580
michael@0 581 nsIntRegionRectIterator iter(aRegion);
michael@0 582 const nsIntRect *iterRect;
michael@0 583 while ((iterRect = iter.Next())) {
michael@0 584 RECT rect;
michael@0 585 rect.left = iterRect->x - bounds.x;
michael@0 586 rect.top = iterRect->y - bounds.y;
michael@0 587 rect.right = iterRect->XMost() - bounds.x;
michael@0 588 rect.bottom = iterRect->YMost() - bounds.y;
michael@0 589
michael@0 590 POINT point;
michael@0 591 point.x = iterRect->x - visibleRect.x;
michael@0 592 point.y = iterRect->y - visibleRect.y;
michael@0 593 device()->UpdateSurface(srcSurface, &rect, dstSurface, &point);
michael@0 594 }
michael@0 595 }
michael@0 596 }
michael@0 597
michael@0 598 void
michael@0 599 ThebesLayerD3D9::CreateNewTextures(const gfx::IntSize &aSize,
michael@0 600 SurfaceMode aMode)
michael@0 601 {
michael@0 602 if (aSize.width == 0 || aSize.height == 0) {
michael@0 603 // Nothing to do.
michael@0 604 return;
michael@0 605 }
michael@0 606
michael@0 607 mTexture = nullptr;
michael@0 608 mTextureOnWhite = nullptr;
michael@0 609 HRESULT hr = device()->CreateTexture(aSize.width, aSize.height, 1,
michael@0 610 D3DUSAGE_RENDERTARGET,
michael@0 611 aMode != SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8,
michael@0 612 D3DPOOL_DEFAULT, getter_AddRefs(mTexture), nullptr);
michael@0 613 if (FAILED(hr)) {
michael@0 614 ReportFailure(NS_LITERAL_CSTRING("ThebesLayerD3D9::CreateNewTextures(): Failed to create texture"),
michael@0 615 hr);
michael@0 616 return;
michael@0 617 }
michael@0 618
michael@0 619 if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
michael@0 620 hr = device()->CreateTexture(aSize.width, aSize.height, 1,
michael@0 621 D3DUSAGE_RENDERTARGET,
michael@0 622 D3DFMT_X8R8G8B8,
michael@0 623 D3DPOOL_DEFAULT, getter_AddRefs(mTextureOnWhite), nullptr);
michael@0 624 if (FAILED(hr)) {
michael@0 625 ReportFailure(NS_LITERAL_CSTRING("ThebesLayerD3D9::CreateNewTextures(): Failed to create texture (2)"),
michael@0 626 hr);
michael@0 627 return;
michael@0 628 }
michael@0 629 }
michael@0 630 }
michael@0 631
michael@0 632 } /* namespace layers */
michael@0 633 } /* namespace mozilla */

mercurial