TextureHostOGL.cpp (38777B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "TextureHostOGL.h" 8 9 #include "GLContextEGL.h" // for GLContext, etc 10 #include "GLLibraryEGL.h" // for GLLibraryEGL 11 #include "GLUploadHelpers.h" 12 #include "GLReadTexImageHelper.h" 13 #include "gfx2DGlue.h" // for ContentForFormat, etc 14 #include "mozilla/gfx/2D.h" // for DataSourceSurface 15 #include "mozilla/gfx/BaseSize.h" // for BaseSize 16 #include "mozilla/gfx/gfxVars.h" 17 #include "mozilla/gfx/Logging.h" // for gfxCriticalError 18 #include "mozilla/layers/Fence.h" 19 #include "mozilla/layers/ISurfaceAllocator.h" 20 #include "mozilla/webrender/RenderEGLImageTextureHost.h" 21 #include "mozilla/webrender/WebRenderAPI.h" 22 #include "nsRegion.h" // for nsIntRegion 23 #include "GfxTexturesReporter.h" // for GfxTexturesReporter 24 #include "GeckoProfiler.h" 25 26 #ifdef XP_MACOSX 27 # include "mozilla/layers/MacIOSurfaceTextureHostOGL.h" 28 #endif 29 30 #ifdef MOZ_WIDGET_ANDROID 31 # include "mozilla/layers/AndroidHardwareBuffer.h" 32 # include "mozilla/webrender/RenderAndroidHardwareBufferTextureHost.h" 33 # include "mozilla/webrender/RenderAndroidSurfaceTextureHost.h" 34 #endif 35 36 #ifdef MOZ_WIDGET_GTK 37 # include "mozilla/layers/DMABUFTextureHostOGL.h" 38 #endif 39 40 using namespace mozilla::gl; 41 using namespace mozilla::gfx; 42 43 namespace mozilla { 44 namespace layers { 45 46 class Compositor; 47 48 void ApplySamplingFilterToBoundTexture(gl::GLContext* aGL, 49 gfx::SamplingFilter aSamplingFilter, 50 GLuint aTarget) { 51 GLenum filter = 52 (aSamplingFilter == gfx::SamplingFilter::POINT ? LOCAL_GL_NEAREST 53 : LOCAL_GL_LINEAR); 54 55 aGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MIN_FILTER, filter); 56 aGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MAG_FILTER, filter); 57 } 58 59 already_AddRefed<TextureHost> CreateTextureHostOGL( 60 const SurfaceDescriptor& aDesc, ISurfaceAllocator* aDeallocator, 61 LayersBackend aBackend, TextureFlags aFlags) { 62 RefPtr<TextureHost> result; 63 switch (aDesc.type()) { 64 #ifdef MOZ_WIDGET_ANDROID 65 case SurfaceDescriptor::TSurfaceTextureDescriptor: { 66 const SurfaceTextureDescriptor& desc = 67 aDesc.get_SurfaceTextureDescriptor(); 68 java::GeckoSurfaceTexture::LocalRef surfaceTexture = 69 java::GeckoSurfaceTexture::Lookup(desc.handle()); 70 71 result = new SurfaceTextureHost( 72 aFlags, surfaceTexture, desc.size(), desc.format(), desc.continuous(), 73 desc.forceBT709ColorSpace(), desc.transformOverride()); 74 break; 75 } 76 case SurfaceDescriptor::TSurfaceDescriptorAndroidHardwareBuffer: { 77 const SurfaceDescriptorAndroidHardwareBuffer& desc = 78 aDesc.get_SurfaceDescriptorAndroidHardwareBuffer(); 79 result = AndroidHardwareBufferTextureHost::Create(aFlags, desc); 80 break; 81 } 82 #endif 83 84 case SurfaceDescriptor::TEGLImageDescriptor: { 85 const EGLImageDescriptor& desc = aDesc.get_EGLImageDescriptor(); 86 result = new EGLImageTextureHost(aFlags, (EGLImage)desc.image(), 87 (EGLSync)desc.fence(), desc.size(), 88 desc.hasAlpha()); 89 break; 90 } 91 92 #ifdef MOZ_WIDGET_GTK 93 case SurfaceDescriptor::TSurfaceDescriptorDMABuf: { 94 result = new DMABUFTextureHostOGL(aFlags, aDesc); 95 if (!result->IsValid()) { 96 gfxCriticalError() << "DMABuf surface import failed!"; 97 result = nullptr; 98 } 99 break; 100 } 101 #endif 102 103 #ifdef XP_MACOSX 104 case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: { 105 const SurfaceDescriptorMacIOSurface& desc = 106 aDesc.get_SurfaceDescriptorMacIOSurface(); 107 result = new MacIOSurfaceTextureHostOGL(aFlags, desc); 108 break; 109 } 110 #endif 111 112 case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture: { 113 const auto& desc = aDesc.get_SurfaceDescriptorSharedGLTexture(); 114 result = 115 new GLTextureHost(aFlags, desc.texture(), desc.target(), 116 (GLsync)desc.fence(), desc.size(), desc.hasAlpha()); 117 break; 118 } 119 default: { 120 MOZ_ASSERT_UNREACHABLE("Unsupported SurfaceDescriptor type"); 121 break; 122 } 123 } 124 return result.forget(); 125 } 126 127 static gl::TextureImage::Flags FlagsToGLFlags(TextureFlags aFlags) { 128 uint32_t result = TextureImage::NoFlags; 129 130 if (aFlags & TextureFlags::USE_NEAREST_FILTER) 131 result |= TextureImage::UseNearestFilter; 132 if (aFlags & TextureFlags::ORIGIN_BOTTOM_LEFT) 133 result |= TextureImage::OriginBottomLeft; 134 if (aFlags & TextureFlags::DISALLOW_BIGIMAGE) 135 result |= TextureImage::DisallowBigImage; 136 137 return static_cast<gl::TextureImage::Flags>(result); 138 } 139 140 TextureImageTextureSourceOGL::TextureImageTextureSourceOGL( 141 CompositorOGL* aCompositor, TextureFlags aFlags) 142 : mGL(aCompositor->gl()), 143 mCompositor(aCompositor), 144 mFlags(aFlags), 145 mIterating(false) { 146 if (mCompositor) { 147 mCompositor->RegisterTextureSource(this); 148 } 149 } 150 151 TextureImageTextureSourceOGL::~TextureImageTextureSourceOGL() { 152 DeallocateDeviceData(); 153 } 154 155 void TextureImageTextureSourceOGL::DeallocateDeviceData() { 156 mTexImage = nullptr; 157 mGL = nullptr; 158 if (mCompositor) { 159 mCompositor->UnregisterTextureSource(this); 160 } 161 SetUpdateSerial(0); 162 } 163 164 bool TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface, 165 nsIntRegion* aDestRegion, 166 gfx::IntPoint* aSrcOffset, 167 gfx::IntPoint* aDstOffset) { 168 GLContext* gl = mGL; 169 MOZ_ASSERT(gl); 170 if (!gl || !gl->MakeCurrent()) { 171 NS_WARNING( 172 "trying to update TextureImageTextureSourceOGL without a GLContext"); 173 return false; 174 } 175 if (!aSurface) { 176 gfxCriticalError() << "Invalid surface for OGL update"; 177 return false; 178 } 179 MOZ_ASSERT(aSurface); 180 181 IntSize size = aSurface->GetSize(); 182 if (!mTexImage || (mTexImage->GetSize() != size && !aSrcOffset) || 183 mTexImage->GetContentType() != 184 gfx::ContentForFormat(aSurface->GetFormat())) { 185 if (mFlags & TextureFlags::DISALLOW_BIGIMAGE) { 186 GLint maxTextureSize; 187 gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxTextureSize); 188 if (size.width > maxTextureSize || size.height > maxTextureSize) { 189 NS_WARNING("Texture exceeds maximum texture size, refusing upload"); 190 return false; 191 } 192 // Explicitly use CreateBasicTextureImage instead of CreateTextureImage, 193 // because CreateTextureImage might still choose to create a tiled 194 // texture image. 195 mTexImage = CreateBasicTextureImage( 196 gl, size, gfx::ContentForFormat(aSurface->GetFormat()), 197 LOCAL_GL_CLAMP_TO_EDGE, FlagsToGLFlags(mFlags)); 198 } else { 199 // XXX - clarify which size we want to use. IncrementalContentHost will 200 // require the size of the destination surface to be different from 201 // the size of aSurface. 202 // See bug 893300 (tracks the implementation of ContentHost for new 203 // textures). 204 mTexImage = CreateTextureImage( 205 gl, size, gfx::ContentForFormat(aSurface->GetFormat()), 206 LOCAL_GL_CLAMP_TO_EDGE, FlagsToGLFlags(mFlags), 207 SurfaceFormatToImageFormat(aSurface->GetFormat())); 208 } 209 ClearCachedFilter(); 210 211 if (aDestRegion && !aSrcOffset && 212 !aDestRegion->IsEqual(gfx::IntRect(0, 0, size.width, size.height))) { 213 // UpdateFromDataSource will ignore our specified aDestRegion since the 214 // texture hasn't been allocated with glTexImage2D yet. Call Resize() to 215 // force the allocation (full size, but no upload), and then we'll only 216 // upload the pixels we care about below. 217 mTexImage->Resize(size); 218 } 219 } 220 221 return mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset, 222 aDstOffset); 223 } 224 225 void TextureImageTextureSourceOGL::EnsureBuffer(const IntSize& aSize, 226 gfxContentType aContentType) { 227 if (!mTexImage || mTexImage->GetSize() != aSize || 228 mTexImage->GetContentType() != aContentType) { 229 mTexImage = 230 CreateTextureImage(mGL, aSize, aContentType, LOCAL_GL_CLAMP_TO_EDGE, 231 FlagsToGLFlags(mFlags)); 232 } 233 mTexImage->Resize(aSize); 234 } 235 236 gfx::IntSize TextureImageTextureSourceOGL::GetSize() const { 237 if (mTexImage) { 238 if (mIterating) { 239 return mTexImage->GetTileRect().Size(); 240 } 241 return mTexImage->GetSize(); 242 } 243 NS_WARNING("Trying to query the size of an empty TextureSource."); 244 return gfx::IntSize(0, 0); 245 } 246 247 gfx::SurfaceFormat TextureImageTextureSourceOGL::GetFormat() const { 248 if (mTexImage) { 249 return mTexImage->GetTextureFormat(); 250 } 251 NS_WARNING("Trying to query the format of an empty TextureSource."); 252 return gfx::SurfaceFormat::UNKNOWN; 253 } 254 255 gfx::IntRect TextureImageTextureSourceOGL::GetTileRect() { 256 return mTexImage->GetTileRect(); 257 } 258 259 void TextureImageTextureSourceOGL::BindTexture( 260 GLenum aTextureUnit, gfx::SamplingFilter aSamplingFilter) { 261 MOZ_ASSERT(mTexImage, 262 "Trying to bind a TextureSource that does not have an underlying " 263 "GL texture."); 264 mTexImage->BindTexture(aTextureUnit); 265 SetSamplingFilter(mGL, aSamplingFilter); 266 } 267 268 //////////////////////////////////////////////////////////////////////// 269 // GLTextureSource 270 271 GLTextureSource::GLTextureSource(TextureSourceProvider* aProvider, 272 GLuint aTextureHandle, GLenum aTarget, 273 gfx::IntSize aSize, gfx::SurfaceFormat aFormat) 274 : GLTextureSource(aProvider->GetGLContext(), aTextureHandle, aTarget, aSize, 275 aFormat) {} 276 277 GLTextureSource::GLTextureSource(GLContext* aGL, GLuint aTextureHandle, 278 GLenum aTarget, gfx::IntSize aSize, 279 gfx::SurfaceFormat aFormat) 280 : mGL(aGL), 281 mTextureHandle(aTextureHandle), 282 mTextureTarget(aTarget), 283 mSize(aSize), 284 mFormat(aFormat) { 285 MOZ_COUNT_CTOR(GLTextureSource); 286 } 287 288 GLTextureSource::~GLTextureSource() { 289 MOZ_COUNT_DTOR(GLTextureSource); 290 DeleteTextureHandle(); 291 } 292 293 void GLTextureSource::DeallocateDeviceData() { DeleteTextureHandle(); } 294 295 void GLTextureSource::DeleteTextureHandle() { 296 GLContext* gl = this->gl(); 297 if (mTextureHandle != 0 && gl && gl->MakeCurrent()) { 298 gl->fDeleteTextures(1, &mTextureHandle); 299 } 300 mTextureHandle = 0; 301 } 302 303 void GLTextureSource::BindTexture(GLenum aTextureUnit, 304 gfx::SamplingFilter aSamplingFilter) { 305 MOZ_ASSERT(mTextureHandle != 0); 306 GLContext* gl = this->gl(); 307 if (!gl || !gl->MakeCurrent()) { 308 return; 309 } 310 gl->fActiveTexture(aTextureUnit); 311 gl->fBindTexture(mTextureTarget, mTextureHandle); 312 ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, mTextureTarget); 313 } 314 315 bool GLTextureSource::IsValid() const { return !!gl() && mTextureHandle != 0; } 316 317 //////////////////////////////////////////////////////////////////////// 318 // DirectMapTextureSource 319 320 DirectMapTextureSource::DirectMapTextureSource(gl::GLContext* aContext, 321 gfx::DataSourceSurface* aSurface) 322 : GLTextureSource(aContext, 0, LOCAL_GL_TEXTURE_RECTANGLE_ARB, 323 aSurface->GetSize(), aSurface->GetFormat()), 324 mSync(0) { 325 MOZ_ASSERT(aSurface); 326 327 UpdateInternal(aSurface, nullptr, nullptr, true); 328 } 329 330 DirectMapTextureSource::DirectMapTextureSource(TextureSourceProvider* aProvider, 331 gfx::DataSourceSurface* aSurface) 332 : DirectMapTextureSource(aProvider->GetGLContext(), aSurface) {} 333 334 DirectMapTextureSource::~DirectMapTextureSource() { 335 if (!mSync || !gl() || !gl()->MakeCurrent() || gl()->IsDestroyed()) { 336 return; 337 } 338 339 gl()->fDeleteSync(mSync); 340 mSync = 0; 341 } 342 343 bool DirectMapTextureSource::Update(gfx::DataSourceSurface* aSurface, 344 nsIntRegion* aDestRegion, 345 gfx::IntPoint* aSrcOffset, 346 gfx::IntPoint* aDstOffset) { 347 MOZ_RELEASE_ASSERT(aDstOffset == nullptr); 348 if (!aSurface) { 349 return false; 350 } 351 352 return UpdateInternal(aSurface, aDestRegion, aSrcOffset, false); 353 } 354 355 void DirectMapTextureSource::MaybeFenceTexture() { 356 if (!gl() || !gl()->MakeCurrent() || gl()->IsDestroyed()) { 357 return; 358 } 359 360 if (mSync) { 361 gl()->fDeleteSync(mSync); 362 } 363 mSync = gl()->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0); 364 } 365 366 bool DirectMapTextureSource::Sync(bool aBlocking) { 367 if (!gl() || !gl()->MakeCurrent() || gl()->IsDestroyed()) { 368 // We use this function to decide whether we can unlock the texture 369 // and clean it up. If we return false here and for whatever reason 370 // the context is absent or invalid, the compositor will keep a 371 // reference to this texture forever. 372 return true; 373 } 374 375 if (!mSync) { 376 return false; 377 } 378 379 GLenum waitResult = 380 gl()->fClientWaitSync(mSync, LOCAL_GL_SYNC_FLUSH_COMMANDS_BIT, 381 aBlocking ? LOCAL_GL_TIMEOUT_IGNORED : 0); 382 return waitResult == LOCAL_GL_ALREADY_SIGNALED || 383 waitResult == LOCAL_GL_CONDITION_SATISFIED; 384 } 385 386 bool DirectMapTextureSource::UpdateInternal(gfx::DataSourceSurface* aSurface, 387 nsIntRegion* aDestRegion, 388 gfx::IntPoint* aSrcOffset, 389 bool aInit) { 390 if (!gl() || !gl()->MakeCurrent()) { 391 return false; 392 } 393 394 if (aInit) { 395 gl()->fGenTextures(1, &mTextureHandle); 396 gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, mTextureHandle); 397 398 gl()->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 399 LOCAL_GL_TEXTURE_STORAGE_HINT_APPLE, 400 LOCAL_GL_STORAGE_CACHED_APPLE); 401 gl()->fTextureRangeAPPLE(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 402 aSurface->Stride() * aSurface->GetSize().height, 403 aSurface->GetData()); 404 405 gl()->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 406 LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); 407 gl()->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 408 LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); 409 } 410 411 MOZ_ASSERT(mTextureHandle); 412 413 // APPLE_client_storage 414 gl()->fPixelStorei(LOCAL_GL_UNPACK_CLIENT_STORAGE_APPLE, LOCAL_GL_TRUE); 415 416 nsIntRegion destRegion = aDestRegion 417 ? *aDestRegion 418 : IntRect(0, 0, aSurface->GetSize().width, 419 aSurface->GetSize().height); 420 gfx::IntPoint srcPoint = aSrcOffset ? *aSrcOffset : gfx::IntPoint(0, 0); 421 mFormat = gl::UploadSurfaceToTexture( 422 gl(), aSurface, destRegion, mTextureHandle, aSurface->GetSize(), nullptr, 423 aInit, srcPoint, gfx::IntPoint(0, 0), LOCAL_GL_TEXTURE0, 424 LOCAL_GL_TEXTURE_RECTANGLE_ARB); 425 426 if (mSync) { 427 gl()->fDeleteSync(mSync); 428 mSync = 0; 429 } 430 431 gl()->fPixelStorei(LOCAL_GL_UNPACK_CLIENT_STORAGE_APPLE, LOCAL_GL_FALSE); 432 return true; 433 } 434 435 //////////////////////////////////////////////////////////////////////// 436 //////////////////////////////////////////////////////////////////////// 437 // SurfaceTextureHost 438 439 #ifdef MOZ_WIDGET_ANDROID 440 441 SurfaceTextureSource::SurfaceTextureSource( 442 TextureSourceProvider* aProvider, 443 mozilla::java::GeckoSurfaceTexture::Ref& aSurfTex, 444 gfx::SurfaceFormat aFormat, GLenum aTarget, GLenum aWrapMode, 445 gfx::IntSize aSize, Maybe<gfx::Matrix4x4> aTransformOverride) 446 : mGL(aProvider->GetGLContext()), 447 mSurfTex(aSurfTex), 448 mFormat(aFormat), 449 mTextureTarget(aTarget), 450 mWrapMode(aWrapMode), 451 mSize(aSize), 452 mTransformOverride(aTransformOverride) {} 453 454 void SurfaceTextureSource::BindTexture(GLenum aTextureUnit, 455 gfx::SamplingFilter aSamplingFilter) { 456 MOZ_ASSERT(mSurfTex); 457 GLContext* gl = this->gl(); 458 if (!gl || !gl->MakeCurrent()) { 459 NS_WARNING("Trying to bind a texture without a GLContext"); 460 return; 461 } 462 463 gl->fActiveTexture(aTextureUnit); 464 gl->fBindTexture(mTextureTarget, mSurfTex->GetTexName()); 465 466 ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, mTextureTarget); 467 } 468 469 bool SurfaceTextureSource::IsValid() const { return !!gl(); } 470 471 gfx::Matrix4x4 SurfaceTextureSource::GetTextureTransform() { 472 MOZ_ASSERT(mSurfTex); 473 474 gfx::Matrix4x4 ret; 475 476 // GetTransformMatrix() returns the transform set by the producer side of the 477 // SurfaceTexture that must be applied to texture coordinates when 478 // sampling. In some cases we may have set an override value, such as in 479 // AndroidNativeWindowTextureData where we own the producer side, or for 480 // MediaCodec output on devices where where we know the value is incorrect. 481 if (mTransformOverride) { 482 ret = *mTransformOverride; 483 } else { 484 const auto& surf = java::sdk::SurfaceTexture::LocalRef( 485 java::sdk::SurfaceTexture::Ref::From(mSurfTex)); 486 AndroidSurfaceTexture::GetTransformMatrix(surf, &ret); 487 } 488 489 return ret; 490 } 491 492 void SurfaceTextureSource::DeallocateDeviceData() { mSurfTex = nullptr; } 493 494 //////////////////////////////////////////////////////////////////////// 495 496 SurfaceTextureHost::SurfaceTextureHost( 497 TextureFlags aFlags, mozilla::java::GeckoSurfaceTexture::Ref& aSurfTex, 498 gfx::IntSize aSize, gfx::SurfaceFormat aFormat, bool aContinuousUpdate, 499 bool aForceBT709ColorSpace, Maybe<Matrix4x4> aTransformOverride) 500 : TextureHost(TextureHostType::AndroidSurfaceTexture, aFlags), 501 mSurfTex(aSurfTex), 502 mSize(aSize), 503 mFormat(aFormat), 504 mContinuousUpdate(aContinuousUpdate), 505 mForceBT709ColorSpace(aForceBT709ColorSpace), 506 mTransformOverride(aTransformOverride) { 507 if (!mSurfTex) { 508 return; 509 } 510 511 // Continuous update makes no sense with single buffer mode 512 MOZ_ASSERT(!mSurfTex->IsSingleBuffer() || !mContinuousUpdate); 513 514 mSurfTex->IncrementUse(); 515 } 516 517 SurfaceTextureHost::~SurfaceTextureHost() { 518 if (mSurfTex) { 519 mSurfTex->DecrementUse(); 520 mSurfTex = nullptr; 521 } 522 } 523 524 gl::GLContext* SurfaceTextureHost::gl() const { return nullptr; } 525 526 gfx::SurfaceFormat SurfaceTextureHost::GetFormat() const { return mFormat; } 527 528 void SurfaceTextureHost::DeallocateDeviceData() { 529 if (mTextureSource) { 530 mTextureSource->DeallocateDeviceData(); 531 } 532 533 if (mSurfTex) { 534 mSurfTex->DecrementUse(); 535 mSurfTex = nullptr; 536 } 537 } 538 539 void SurfaceTextureHost::CreateRenderTexture( 540 const wr::ExternalImageId& aExternalImageId) { 541 MOZ_ASSERT(mExternalImageId.isSome()); 542 543 bool isRemoteTexture = !!(mFlags & TextureFlags::REMOTE_TEXTURE); 544 RefPtr<wr::RenderTextureHost> texture = 545 new wr::RenderAndroidSurfaceTextureHost( 546 mSurfTex, mSize, mFormat, mContinuousUpdate, mTransformOverride, 547 isRemoteTexture); 548 wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId, 549 texture.forget()); 550 } 551 552 uint32_t SurfaceTextureHost::NumSubTextures() { return mSurfTex ? 1 : 0; } 553 554 void SurfaceTextureHost::PushResourceUpdates( 555 wr::TransactionBuilder& aResources, ResourceUpdateOp aOp, 556 const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) { 557 auto method = aOp == TextureHost::ADD_IMAGE 558 ? &wr::TransactionBuilder::AddExternalImage 559 : &wr::TransactionBuilder::UpdateExternalImage; 560 561 // Prefer TextureExternal unless the backend requires TextureRect. 562 TextureHost::NativeTexturePolicy policy = 563 TextureHost::BackendNativeTexturePolicy(aResources.GetBackendType(), 564 GetSize()); 565 auto imageType = wr::ExternalImageType::TextureHandle( 566 wr::ImageBufferKind::TextureExternal); 567 if (policy == TextureHost::NativeTexturePolicy::REQUIRE) { 568 imageType = 569 wr::ExternalImageType::TextureHandle(wr::ImageBufferKind::TextureRect); 570 } else if (mForceBT709ColorSpace) { 571 imageType = wr::ExternalImageType::TextureHandle( 572 wr::ImageBufferKind::TextureExternalBT709); 573 } 574 575 // Hardware webrender directly renders from the SurfaceTexture therefore we 576 // must provide it the (transformed) normalized UVs. For software webrender we 577 // first read from the SurfaceTexture in to a CPU buffer, which we sample from 578 // using unnormalized UVs. The readback code handles the texture transform. 579 // See RenderAndroidSurfaceTextureHost::Lock() and 580 // RenderAndroidSurfaceTextureHost::ReadTexImage(), respectively. 581 const bool normalizedUvs = 582 aResources.GetBackendType() == WebRenderBackend::HARDWARE; 583 584 switch (GetFormat()) { 585 case gfx::SurfaceFormat::R8G8B8X8: 586 case gfx::SurfaceFormat::R8G8B8A8: { 587 MOZ_ASSERT(aImageKeys.length() == 1); 588 589 // XXX Add RGBA handling. Temporary hack to avoid crash 590 // With BGRA format setting, rendering works without problem. 591 auto format = GetFormat() == gfx::SurfaceFormat::R8G8B8A8 592 ? gfx::SurfaceFormat::B8G8R8A8 593 : gfx::SurfaceFormat::B8G8R8X8; 594 wr::ImageDescriptor descriptor(GetSize(), format); 595 (aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0, 596 normalizedUvs); 597 break; 598 } 599 default: { 600 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 601 } 602 } 603 } 604 605 void SurfaceTextureHost::PushDisplayItems(wr::DisplayListBuilder& aBuilder, 606 const wr::LayoutRect& aBounds, 607 const wr::LayoutRect& aClip, 608 wr::ImageRendering aFilter, 609 const Range<wr::ImageKey>& aImageKeys, 610 PushDisplayItemFlagSet aFlags) { 611 bool preferCompositorSurface = 612 aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE); 613 bool supportsExternalCompositing = 614 SupportsExternalCompositing(aBuilder.GetBackendType()); 615 616 switch (GetFormat()) { 617 case gfx::SurfaceFormat::R8G8B8X8: 618 case gfx::SurfaceFormat::R8G8B8A8: 619 case gfx::SurfaceFormat::B8G8R8A8: 620 case gfx::SurfaceFormat::B8G8R8X8: { 621 MOZ_ASSERT(aImageKeys.length() == 1); 622 aBuilder.PushImage(aBounds, aClip, true, false, aFilter, aImageKeys[0], 623 !(mFlags & TextureFlags::NON_PREMULTIPLIED), 624 wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f}, 625 preferCompositorSurface, supportsExternalCompositing); 626 break; 627 } 628 default: { 629 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 630 } 631 } 632 } 633 634 bool SurfaceTextureHost::SupportsExternalCompositing( 635 WebRenderBackend aBackend) { 636 return aBackend == WebRenderBackend::SOFTWARE; 637 } 638 639 //////////////////////////////////////////////////////////////////////// 640 // AndroidHardwareBufferTextureSource 641 642 AndroidHardwareBufferTextureSource::AndroidHardwareBufferTextureSource( 643 TextureSourceProvider* aProvider, 644 AndroidHardwareBuffer* aAndroidHardwareBuffer, gfx::SurfaceFormat aFormat, 645 GLenum aTarget, GLenum aWrapMode, gfx::IntSize aSize) 646 : mGL(aProvider->GetGLContext()), 647 mAndroidHardwareBuffer(aAndroidHardwareBuffer), 648 mFormat(aFormat), 649 mTextureTarget(aTarget), 650 mWrapMode(aWrapMode), 651 mSize(aSize), 652 mEGLImage(EGL_NO_IMAGE), 653 mTextureHandle(0) {} 654 655 AndroidHardwareBufferTextureSource::~AndroidHardwareBufferTextureSource() { 656 DeleteTextureHandle(); 657 DestroyEGLImage(); 658 } 659 660 bool AndroidHardwareBufferTextureSource::EnsureEGLImage() { 661 if (!mAndroidHardwareBuffer) { 662 return false; 663 } 664 665 auto fenceFd = mAndroidHardwareBuffer->GetAndResetAcquireFence(); 666 if (fenceFd) { 667 const auto& gle = gl::GLContextEGL::Cast(mGL); 668 const auto& egl = gle->mEgl; 669 670 const EGLint attribs[] = {LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID, 671 fenceFd.get(), LOCAL_EGL_NONE}; 672 673 EGLSync sync = 674 egl->fCreateSync(LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); 675 if (sync) { 676 // Release fd here, since it is owned by EGLSync 677 (void)fenceFd.release(); 678 679 if (egl->IsExtensionSupported(gl::EGLExtension::KHR_wait_sync)) { 680 egl->fWaitSync(sync, 0); 681 } else { 682 egl->fClientWaitSync(sync, 0, LOCAL_EGL_FOREVER); 683 } 684 egl->fDestroySync(sync); 685 } else { 686 gfxCriticalNote << "Failed to create EGLSync from acquire fence fd"; 687 } 688 } 689 690 if (mTextureHandle) { 691 return true; 692 } 693 694 if (!mEGLImage) { 695 // XXX add crop handling for video 696 // Should only happen the first time. 697 const auto& gle = gl::GLContextEGL::Cast(mGL); 698 const auto& egl = gle->mEgl; 699 700 const EGLint attrs[] = { 701 LOCAL_EGL_IMAGE_PRESERVED, 702 LOCAL_EGL_TRUE, 703 LOCAL_EGL_NONE, 704 LOCAL_EGL_NONE, 705 }; 706 707 EGLClientBuffer clientBuffer = egl->mLib->fGetNativeClientBufferANDROID( 708 mAndroidHardwareBuffer->GetNativeBuffer()); 709 mEGLImage = egl->fCreateImage( 710 EGL_NO_CONTEXT, LOCAL_EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs); 711 } 712 MOZ_ASSERT(mEGLImage); 713 714 mGL->fGenTextures(1, &mTextureHandle); 715 mGL->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, mTextureHandle); 716 mGL->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL, LOCAL_GL_TEXTURE_WRAP_T, 717 LOCAL_GL_CLAMP_TO_EDGE); 718 mGL->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL, LOCAL_GL_TEXTURE_WRAP_S, 719 LOCAL_GL_CLAMP_TO_EDGE); 720 mGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_EXTERNAL, mEGLImage); 721 722 return true; 723 } 724 725 void AndroidHardwareBufferTextureSource::DeleteTextureHandle() { 726 if (!mTextureHandle) { 727 return; 728 } 729 MOZ_ASSERT(mGL); 730 mGL->fDeleteTextures(1, &mTextureHandle); 731 mTextureHandle = 0; 732 } 733 734 void AndroidHardwareBufferTextureSource::DestroyEGLImage() { 735 if (!mEGLImage) { 736 return; 737 } 738 MOZ_ASSERT(mGL); 739 const auto& gle = gl::GLContextEGL::Cast(mGL); 740 const auto& egl = gle->mEgl; 741 egl->fDestroyImage(mEGLImage); 742 mEGLImage = EGL_NO_IMAGE; 743 } 744 745 void AndroidHardwareBufferTextureSource::BindTexture( 746 GLenum aTextureUnit, gfx::SamplingFilter aSamplingFilter) { 747 MOZ_ASSERT(mAndroidHardwareBuffer); 748 GLContext* gl = this->gl(); 749 if (!gl || !gl->MakeCurrent()) { 750 NS_WARNING("Trying to bind a texture without a GLContext"); 751 return; 752 } 753 754 if (!EnsureEGLImage()) { 755 return; 756 } 757 758 gl->fActiveTexture(aTextureUnit); 759 gl->fBindTexture(mTextureTarget, mTextureHandle); 760 761 ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, mTextureTarget); 762 } 763 764 bool AndroidHardwareBufferTextureSource::IsValid() const { return !!gl(); } 765 766 void AndroidHardwareBufferTextureSource::DeallocateDeviceData() { 767 DestroyEGLImage(); 768 DeleteTextureHandle(); 769 mAndroidHardwareBuffer = nullptr; 770 } 771 772 //////////////////////////////////////////////////////////////////////// 773 // AndroidHardwareBufferTextureHost 774 775 /* static */ 776 already_AddRefed<AndroidHardwareBufferTextureHost> 777 AndroidHardwareBufferTextureHost::Create( 778 TextureFlags aFlags, const SurfaceDescriptorAndroidHardwareBuffer& aDesc) { 779 RefPtr<AndroidHardwareBuffer> buffer = 780 AndroidHardwareBufferManager::Get()->GetBuffer(aDesc.bufferId()); 781 if (!buffer) { 782 return nullptr; 783 } 784 RefPtr<AndroidHardwareBufferTextureHost> host = 785 new AndroidHardwareBufferTextureHost(aFlags, buffer); 786 return host.forget(); 787 } 788 789 AndroidHardwareBufferTextureHost::AndroidHardwareBufferTextureHost( 790 TextureFlags aFlags, AndroidHardwareBuffer* aAndroidHardwareBuffer) 791 : TextureHost(TextureHostType::AndroidHardwareBuffer, aFlags), 792 mAndroidHardwareBuffer(aAndroidHardwareBuffer) { 793 MOZ_ASSERT(mAndroidHardwareBuffer); 794 } 795 796 AndroidHardwareBufferTextureHost::~AndroidHardwareBufferTextureHost() {} 797 798 gl::GLContext* AndroidHardwareBufferTextureHost::gl() const { return nullptr; } 799 800 void AndroidHardwareBufferTextureHost::NotifyNotUsed() { 801 TextureHost::NotifyNotUsed(); 802 } 803 804 gfx::SurfaceFormat AndroidHardwareBufferTextureHost::GetFormat() const { 805 if (mAndroidHardwareBuffer) { 806 return mAndroidHardwareBuffer->mFormat; 807 } 808 return gfx::SurfaceFormat::UNKNOWN; 809 } 810 811 gfx::IntSize AndroidHardwareBufferTextureHost::GetSize() const { 812 if (mAndroidHardwareBuffer) { 813 return mAndroidHardwareBuffer->mSize; 814 } 815 return gfx::IntSize(); 816 } 817 818 void AndroidHardwareBufferTextureHost::DeallocateDeviceData() { 819 mAndroidHardwareBuffer = nullptr; 820 } 821 822 void AndroidHardwareBufferTextureHost::SetReadFence(Fence* aReadFence) { 823 MOZ_ASSERT(aReadFence); 824 MOZ_ASSERT(aReadFence->AsFenceFileHandle()); 825 MOZ_ASSERT(mAndroidHardwareBuffer); 826 827 if (!aReadFence || !aReadFence->AsFenceFileHandle() || 828 !mAndroidHardwareBuffer) { 829 return; 830 } 831 832 UniqueFileHandle handle = 833 aReadFence->AsFenceFileHandle()->DuplicateFileHandle(); 834 mAndroidHardwareBuffer->SetReleaseFence(std::move(handle)); 835 } 836 837 void AndroidHardwareBufferTextureHost::CreateRenderTexture( 838 const wr::ExternalImageId& aExternalImageId) { 839 MOZ_ASSERT(mExternalImageId.isSome()); 840 841 RefPtr<wr::RenderTextureHost> texture = 842 new wr::RenderAndroidHardwareBufferTextureHost(mAndroidHardwareBuffer); 843 wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId, 844 texture.forget()); 845 } 846 847 uint32_t AndroidHardwareBufferTextureHost::NumSubTextures() { 848 return mAndroidHardwareBuffer ? 1 : 0; 849 } 850 851 void AndroidHardwareBufferTextureHost::PushResourceUpdates( 852 wr::TransactionBuilder& aResources, ResourceUpdateOp aOp, 853 const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) { 854 auto method = aOp == TextureHost::ADD_IMAGE 855 ? &wr::TransactionBuilder::AddExternalImage 856 : &wr::TransactionBuilder::UpdateExternalImage; 857 858 // Prefer TextureExternal unless the backend requires TextureRect. 859 TextureHost::NativeTexturePolicy policy = 860 TextureHost::BackendNativeTexturePolicy(aResources.GetBackendType(), 861 GetSize()); 862 auto imageType = policy == TextureHost::NativeTexturePolicy::REQUIRE 863 ? wr::ExternalImageType::TextureHandle( 864 wr::ImageBufferKind::TextureRect) 865 : wr::ExternalImageType::TextureHandle( 866 wr::ImageBufferKind::TextureExternal); 867 868 switch (GetFormat()) { 869 case gfx::SurfaceFormat::R8G8B8X8: 870 case gfx::SurfaceFormat::R8G8B8A8: { 871 MOZ_ASSERT(aImageKeys.length() == 1); 872 873 // XXX Add RGBA handling. Temporary hack to avoid crash 874 // With BGRA format setting, rendering works without problem. 875 auto format = GetFormat() == gfx::SurfaceFormat::R8G8B8A8 876 ? gfx::SurfaceFormat::B8G8R8A8 877 : gfx::SurfaceFormat::B8G8R8X8; 878 wr::ImageDescriptor descriptor(GetSize(), format); 879 (aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0, 880 /* aNormalizedUvs */ false); 881 break; 882 } 883 default: { 884 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 885 } 886 } 887 } 888 889 void AndroidHardwareBufferTextureHost::PushDisplayItems( 890 wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds, 891 const wr::LayoutRect& aClip, wr::ImageRendering aFilter, 892 const Range<wr::ImageKey>& aImageKeys, PushDisplayItemFlagSet aFlags) { 893 bool preferCompositorSurface = 894 aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE); 895 bool supportsExternalCompositing = 896 SupportsExternalCompositing(aBuilder.GetBackendType()); 897 898 switch (GetFormat()) { 899 case gfx::SurfaceFormat::R8G8B8X8: 900 case gfx::SurfaceFormat::R8G8B8A8: 901 case gfx::SurfaceFormat::B8G8R8A8: 902 case gfx::SurfaceFormat::B8G8R8X8: { 903 MOZ_ASSERT(aImageKeys.length() == 1); 904 aBuilder.PushImage(aBounds, aClip, true, false, aFilter, aImageKeys[0], 905 !(mFlags & TextureFlags::NON_PREMULTIPLIED), 906 wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f}, 907 preferCompositorSurface, supportsExternalCompositing); 908 break; 909 } 910 default: { 911 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 912 } 913 } 914 } 915 916 bool AndroidHardwareBufferTextureHost::SupportsExternalCompositing( 917 WebRenderBackend aBackend) { 918 return aBackend == WebRenderBackend::SOFTWARE; 919 } 920 921 #endif // MOZ_WIDGET_ANDROID 922 923 //////////////////////////////////////////////////////////////////////// 924 //////////////////////////////////////////////////////////////////////// 925 // EGLImage 926 927 EGLImageTextureSource::EGLImageTextureSource(TextureSourceProvider* aProvider, 928 EGLImage aImage, 929 gfx::SurfaceFormat aFormat, 930 GLenum aTarget, GLenum aWrapMode, 931 gfx::IntSize aSize) 932 : mGL(aProvider->GetGLContext()), 933 mCompositor(aProvider->AsCompositorOGL()), 934 mImage(aImage), 935 mFormat(aFormat), 936 mTextureTarget(aTarget), 937 mWrapMode(aWrapMode), 938 mSize(aSize) { 939 MOZ_ASSERT(mTextureTarget == LOCAL_GL_TEXTURE_2D || 940 mTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL); 941 } 942 943 void EGLImageTextureSource::BindTexture(GLenum aTextureUnit, 944 gfx::SamplingFilter aSamplingFilter) { 945 GLContext* gl = this->gl(); 946 if (!gl || !gl->MakeCurrent()) { 947 NS_WARNING("Trying to bind a texture without a GLContext"); 948 return; 949 } 950 951 #ifdef DEBUG 952 const bool supportsEglImage = [&]() { 953 const auto& gle = GLContextEGL::Cast(gl); 954 const auto& egl = gle->mEgl; 955 956 return egl->HasKHRImageBase() && 957 egl->IsExtensionSupported(EGLExtension::KHR_gl_texture_2D_image) && 958 gl->IsExtensionSupported(GLContext::OES_EGL_image); 959 }(); 960 MOZ_ASSERT(supportsEglImage, "EGLImage not supported or disabled in runtime"); 961 #endif 962 963 GLuint tex = mCompositor->GetTemporaryTexture(mTextureTarget, aTextureUnit); 964 965 gl->fActiveTexture(aTextureUnit); 966 gl->fBindTexture(mTextureTarget, tex); 967 968 gl->fEGLImageTargetTexture2D(mTextureTarget, mImage); 969 970 ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, mTextureTarget); 971 } 972 973 bool EGLImageTextureSource::IsValid() const { return !!gl(); } 974 975 gfx::Matrix4x4 EGLImageTextureSource::GetTextureTransform() { 976 gfx::Matrix4x4 ret; 977 return ret; 978 } 979 980 //////////////////////////////////////////////////////////////////////// 981 982 EGLImageTextureHost::EGLImageTextureHost(TextureFlags aFlags, EGLImage aImage, 983 EGLSync aSync, gfx::IntSize aSize, 984 bool hasAlpha) 985 : TextureHost(TextureHostType::EGLImage, aFlags), 986 mImage(aImage), 987 mSync(aSync), 988 mSize(aSize), 989 mHasAlpha(hasAlpha) {} 990 991 EGLImageTextureHost::~EGLImageTextureHost() = default; 992 993 gl::GLContext* EGLImageTextureHost::gl() const { return nullptr; } 994 995 gfx::SurfaceFormat EGLImageTextureHost::GetFormat() const { 996 return mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8 997 : gfx::SurfaceFormat::R8G8B8X8; 998 } 999 1000 void EGLImageTextureHost::CreateRenderTexture( 1001 const wr::ExternalImageId& aExternalImageId) { 1002 MOZ_ASSERT(mExternalImageId.isSome()); 1003 1004 RefPtr<wr::RenderTextureHost> texture = 1005 new wr::RenderEGLImageTextureHost(mImage, mSync, mSize, GetFormat()); 1006 wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId, 1007 texture.forget()); 1008 } 1009 1010 void EGLImageTextureHost::PushResourceUpdates( 1011 wr::TransactionBuilder& aResources, ResourceUpdateOp aOp, 1012 const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) { 1013 auto method = aOp == TextureHost::ADD_IMAGE 1014 ? &wr::TransactionBuilder::AddExternalImage 1015 : &wr::TransactionBuilder::UpdateExternalImage; 1016 1017 // Prefer TextureExternal unless the backend requires TextureRect. 1018 TextureHost::NativeTexturePolicy policy = 1019 TextureHost::BackendNativeTexturePolicy(aResources.GetBackendType(), 1020 GetSize()); 1021 auto imageType = policy == TextureHost::NativeTexturePolicy::REQUIRE 1022 ? wr::ExternalImageType::TextureHandle( 1023 wr::ImageBufferKind::TextureRect) 1024 : wr::ExternalImageType::TextureHandle( 1025 wr::ImageBufferKind::TextureExternal); 1026 1027 gfx::SurfaceFormat format = GetFormat(); 1028 1029 MOZ_ASSERT(aImageKeys.length() == 1); 1030 // XXX Add RGBA handling. Temporary hack to avoid crash 1031 // With BGRA format setting, rendering works without problem. 1032 auto formatTmp = format == gfx::SurfaceFormat::R8G8B8A8 1033 ? gfx::SurfaceFormat::B8G8R8A8 1034 : gfx::SurfaceFormat::B8G8R8X8; 1035 wr::ImageDescriptor descriptor(GetSize(), formatTmp); 1036 (aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0, 1037 /* aNormalizedUvs */ false); 1038 } 1039 1040 void EGLImageTextureHost::PushDisplayItems( 1041 wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds, 1042 const wr::LayoutRect& aClip, wr::ImageRendering aFilter, 1043 const Range<wr::ImageKey>& aImageKeys, PushDisplayItemFlagSet aFlags) { 1044 bool preferCompositorSurface = 1045 aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE); 1046 bool supportsExternalCompositing = 1047 SupportsExternalCompositing(aBuilder.GetBackendType()); 1048 1049 MOZ_ASSERT(aImageKeys.length() == 1); 1050 aBuilder.PushImage(aBounds, aClip, true, false, aFilter, aImageKeys[0], 1051 !(mFlags & TextureFlags::NON_PREMULTIPLIED), 1052 wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f}, 1053 preferCompositorSurface, supportsExternalCompositing); 1054 } 1055 1056 bool EGLImageTextureHost::SupportsExternalCompositing( 1057 WebRenderBackend aBackend) { 1058 return aBackend == WebRenderBackend::SOFTWARE; 1059 } 1060 1061 // 1062 1063 GLTextureHost::GLTextureHost(TextureFlags aFlags, GLuint aTextureHandle, 1064 GLenum aTarget, GLsync aSync, gfx::IntSize aSize, 1065 bool aHasAlpha) 1066 : TextureHost(TextureHostType::GLTexture, aFlags), 1067 mTexture(aTextureHandle), 1068 mTarget(aTarget), 1069 mSync(aSync), 1070 mSize(aSize), 1071 mHasAlpha(aHasAlpha) {} 1072 1073 GLTextureHost::~GLTextureHost() = default; 1074 1075 gl::GLContext* GLTextureHost::gl() const { return nullptr; } 1076 1077 gfx::SurfaceFormat GLTextureHost::GetFormat() const { 1078 MOZ_ASSERT(mTextureSource); 1079 return mTextureSource ? mTextureSource->GetFormat() 1080 : gfx::SurfaceFormat::UNKNOWN; 1081 } 1082 1083 } // namespace layers 1084 } // namespace mozilla