ImageClient.cpp (9917B)
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 "ImageClient.h" 8 9 #include <stdint.h> // for uint32_t 10 11 #include "ImageContainer.h" // for Image, PlanarYCbCrImage, etc 12 #include "ImageTypes.h" // for ImageFormat::PLANAR_YCBCR, etc 13 #include "GLImages.h" // for SurfaceTextureImage::Data, etc 14 #include "gfx2DGlue.h" // for ImageFormatToSurfaceFormat 15 #include "gfxPlatform.h" // for gfxPlatform 16 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc 17 #include "mozilla/RefPtr.h" // for RefPtr, already_AddRefed 18 #include "mozilla/gfx/2D.h" 19 #include "mozilla/gfx/BaseSize.h" // for BaseSize 20 #include "mozilla/gfx/Point.h" // for IntSize 21 #include "mozilla/gfx/Types.h" // for SurfaceFormat, etc 22 #include "mozilla/layers/CompositableClient.h" // for CompositableClient 23 #include "mozilla/layers/CompositableForwarder.h" 24 #include "mozilla/layers/CompositorTypes.h" // for CompositableType, etc 25 #include "mozilla/layers/ISurfaceAllocator.h" 26 #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc 27 #include "mozilla/layers/TextureForwarder.h" 28 #include "mozilla/layers/TextureClient.h" // for TextureClient, etc 29 #include "mozilla/layers/TextureClientOGL.h" // for SurfaceTextureClient 30 #include "mozilla/mozalloc.h" // for operator delete, etc 31 #include "nsCOMPtr.h" // for already_AddRefed 32 #include "nsDebug.h" // for NS_WARNING, NS_ASSERTION 33 #include "nsISupportsImpl.h" // for Image::Release, etc 34 #include "nsRect.h" // for mozilla::gfx::IntRect 35 36 namespace mozilla { 37 namespace layers { 38 39 using namespace mozilla::gfx; 40 41 /* static */ 42 already_AddRefed<ImageClient> ImageClient::CreateImageClient( 43 CompositableType aCompositableHostType, ImageUsageType aUsageType, 44 CompositableForwarder* aForwarder, TextureFlags aFlags) { 45 RefPtr<ImageClient> result = nullptr; 46 switch (aCompositableHostType) { 47 case CompositableType::IMAGE: 48 result = new ImageClientSingle(aForwarder, aFlags, 49 CompositableType::IMAGE, aUsageType); 50 break; 51 case CompositableType::UNKNOWN: 52 result = nullptr; 53 break; 54 default: 55 MOZ_CRASH("GFX: unhandled program type image"); 56 } 57 58 NS_ASSERTION(result, "Failed to create ImageClient"); 59 60 return result.forget(); 61 } 62 63 void ImageClient::RemoveTexture(TextureClient* aTexture) { 64 GetForwarder()->RemoveTextureFromCompositable(this, aTexture); 65 } 66 67 ImageClientSingle::ImageClientSingle(CompositableForwarder* aFwd, 68 TextureFlags aFlags, 69 CompositableType aType, 70 ImageUsageType aUsageType) 71 : ImageClient(aFwd, aFlags, aType, aUsageType) {} 72 73 TextureInfo ImageClientSingle::GetTextureInfo() const { 74 return TextureInfo(CompositableType::IMAGE, mUsageType, 75 TextureFlags::DEFAULT); 76 } 77 78 void ImageClientSingle::ClearImagesInHost(ClearImagesType aType) { 79 GetForwarder()->ClearImagesFromCompositable(this, aType); 80 mBuffers.Clear(); 81 } 82 83 /* static */ 84 already_AddRefed<TextureClient> ImageClient::CreateTextureClientForImage( 85 Image* aImage, KnowsCompositor* aKnowsCompositor) { 86 RefPtr<TextureClient> texture; 87 if (aImage->GetFormat() == ImageFormat::PLANAR_YCBCR) { 88 PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(aImage); 89 const PlanarYCbCrData* data = ycbcr->GetData(); 90 if (!data) { 91 return nullptr; 92 } 93 texture = TextureClient::CreateForYCbCr( 94 aKnowsCompositor, data->mPictureRect, data->YDataSize(), data->mYStride, 95 data->CbCrDataSize(), data->mCbCrStride, data->mStereoMode, 96 data->mColorDepth, data->mYUVColorSpace, data->mColorRange, 97 data->mChromaSubsampling, TextureFlags::DEFAULT); 98 if (!texture) { 99 return nullptr; 100 } 101 102 TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY); 103 if (!autoLock.Succeeded()) { 104 return nullptr; 105 } 106 107 bool status = UpdateYCbCrTextureClient(texture, *data); 108 MOZ_ASSERT(status); 109 if (!status) { 110 return nullptr; 111 } 112 #ifdef MOZ_WIDGET_ANDROID 113 } else if (aImage->GetFormat() == ImageFormat::SURFACE_TEXTURE) { 114 gfx::IntSize size = aImage->GetSize(); 115 SurfaceTextureImage* typedImage = aImage->AsSurfaceTextureImage(); 116 texture = AndroidSurfaceTextureData::CreateTextureClient( 117 typedImage->GetHandle(), size, typedImage->GetContinuous(), 118 typedImage->GetOriginPos(), typedImage->GetHasAlpha(), 119 typedImage->GetForceBT709ColorSpace(), 120 typedImage->GetTransformOverride(), 121 aKnowsCompositor->GetTextureForwarder(), TextureFlags::DEFAULT); 122 #endif 123 } else { 124 RefPtr<gfx::SourceSurface> surface = aImage->GetAsSourceSurface(); 125 MOZ_ASSERT(surface); 126 texture = TextureClient::CreateForDrawing( 127 aKnowsCompositor, surface->GetFormat(), aImage->GetSize(), 128 BackendSelector::Content, TextureFlags::DEFAULT); 129 if (!texture) { 130 return nullptr; 131 } 132 133 MOZ_ASSERT(texture->CanExposeDrawTarget()); 134 135 if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) { 136 return nullptr; 137 } 138 139 { 140 // We must not keep a reference to the DrawTarget after it has been 141 // unlocked. 142 DrawTarget* dt = texture->BorrowDrawTarget(); 143 if (!dt) { 144 gfxWarning() 145 << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget"; 146 texture->Unlock(); 147 return nullptr; 148 } 149 MOZ_ASSERT(surface.get()); 150 dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), 151 IntPoint()); 152 } 153 154 texture->Unlock(); 155 } 156 return texture.forget(); 157 } 158 159 bool ImageClientSingle::UpdateImage(ImageContainer* aContainer) { 160 AutoTArray<ImageContainer::OwningImage, 4> images; 161 uint32_t generationCounter; 162 aContainer->GetCurrentImages(&images, &generationCounter); 163 164 if (mLastUpdateGenerationCounter == generationCounter) { 165 return true; 166 } 167 mLastUpdateGenerationCounter = generationCounter; 168 169 // Don't try to update to invalid images. 170 images.RemoveElementsBy( 171 [](const auto& image) { return !image.mImage->IsValid(); }); 172 if (images.IsEmpty()) { 173 // This can happen if a ClearAllImages raced with SetCurrentImages from 174 // another thread and ClearImagesFromImageBridge ran after the 175 // SetCurrentImages call but before UpdateImageClientNow. 176 // This can also happen if all images in the list are invalid. 177 // We return true because the caller would attempt to recreate the 178 // ImageClient otherwise, and that isn't going to help. 179 for (auto& b : mBuffers) { 180 RemoveTexture(b.mTextureClient); 181 } 182 mBuffers.Clear(); 183 return true; 184 } 185 186 nsTArray<Buffer> newBuffers; 187 AutoTArray<CompositableForwarder::TimedTextureClient, 4> textures; 188 189 for (auto& img : images) { 190 Image* image = img.mImage; 191 192 RefPtr<TextureClient> texture = image->GetTextureClient(GetForwarder()); 193 const bool hasTextureClient = !!texture; 194 195 for (int32_t i = mBuffers.Length() - 1; i >= 0; --i) { 196 if (mBuffers[i].mImageSerial == image->GetSerial()) { 197 if (hasTextureClient) { 198 MOZ_ASSERT(image->GetTextureClient(GetForwarder()) == 199 mBuffers[i].mTextureClient); 200 } else { 201 texture = mBuffers[i].mTextureClient; 202 } 203 // Remove this element from mBuffers so mBuffers only contains 204 // images that aren't present in 'images' 205 mBuffers.RemoveElementAt(i); 206 } 207 } 208 209 if (!texture) { 210 // Slow path, we should not be hitting it very often and if we do it means 211 // we are using an Image class that is not backed by textureClient and we 212 // should fix it. 213 texture = CreateTextureClientForImage(image, GetForwarder()); 214 } 215 216 if (!texture) { 217 return false; 218 } 219 220 // We check if the texture's allocator is still open, since in between media 221 // decoding a frame and adding it to the compositable, we could have 222 // restarted the GPU process. 223 if (!texture->GetAllocator()->IPCOpen()) { 224 continue; 225 } 226 if (!AddTextureClient(texture)) { 227 return false; 228 } 229 230 CompositableForwarder::TimedTextureClient* t = textures.AppendElement(); 231 t->mTextureClient = texture; 232 t->mTimeStamp = img.mTimeStamp; 233 t->mPictureRect = image->GetPictureRect(); 234 t->mFrameID = img.mFrameID; 235 t->mProducerID = img.mProducerID; 236 237 Buffer* newBuf = newBuffers.AppendElement(); 238 newBuf->mImageSerial = image->GetSerial(); 239 newBuf->mTextureClient = texture; 240 241 texture->SyncWithObject(GetForwarder()->GetSyncObject()); 242 } 243 244 GetForwarder()->UseTextures(this, textures); 245 246 for (auto& b : mBuffers) { 247 RemoveTexture(b.mTextureClient); 248 } 249 mBuffers = std::move(newBuffers); 250 251 return true; 252 } 253 254 RefPtr<TextureClient> ImageClientSingle::GetForwardedTexture() { 255 if (mBuffers.Length() == 0) { 256 return nullptr; 257 } 258 return mBuffers[0].mTextureClient; 259 } 260 261 bool ImageClientSingle::AddTextureClient(TextureClient* aTexture) { 262 MOZ_ASSERT((mTextureFlags & aTexture->GetFlags()) == mTextureFlags); 263 return CompositableClient::AddTextureClient(aTexture); 264 } 265 266 void ImageClientSingle::OnDetach() { mBuffers.Clear(); } 267 268 ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags, 269 CompositableType aType, ImageUsageType aUsageType) 270 : CompositableClient(aFwd, aFlags), 271 mType(aType), 272 mUsageType(aUsageType), 273 mLastUpdateGenerationCounter(0) {} 274 275 } // namespace layers 276 } // namespace mozilla