ShareableCanvasRenderer.cpp (6411B)
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 "ShareableCanvasRenderer.h" 8 9 #include "mozilla/dom/WebGLTypes.h" 10 #include "mozilla/gfx/2D.h" 11 #include "mozilla/layers/TextureClientSharedSurface.h" 12 #include "mozilla/layers/CompositableForwarder.h" 13 #include "mozilla/layers/TextureForwarder.h" 14 15 #include "ClientWebGLContext.h" 16 #include "gfxUtils.h" 17 #include "GLScreenBuffer.h" 18 #include "nsICanvasRenderingContextInternal.h" 19 #include "SharedSurfaceGL.h" 20 21 using namespace mozilla::gfx; 22 23 namespace mozilla { 24 namespace layers { 25 26 ShareableCanvasRenderer::ShareableCanvasRenderer() { 27 MOZ_COUNT_CTOR(ShareableCanvasRenderer); 28 } 29 30 ShareableCanvasRenderer::~ShareableCanvasRenderer() { 31 MOZ_COUNT_DTOR(ShareableCanvasRenderer); 32 33 mFrontBufferFromDesc = nullptr; 34 DisconnectClient(); 35 } 36 37 void ShareableCanvasRenderer::Initialize(const CanvasRendererData& aData) { 38 CanvasRenderer::Initialize(aData); 39 mCanvasClient = nullptr; 40 } 41 42 void ShareableCanvasRenderer::ClearCachedResources() { 43 CanvasRenderer::ClearCachedResources(); 44 45 if (mCanvasClient) { 46 mCanvasClient->Clear(); 47 } 48 } 49 50 void ShareableCanvasRenderer::DisconnectClient() { 51 if (mCanvasClient) { 52 mCanvasClient->OnDetach(); 53 mCanvasClient = nullptr; 54 } 55 } 56 57 RefPtr<layers::TextureClient> ShareableCanvasRenderer::GetFrontBufferFromDesc( 58 const layers::SurfaceDescriptor& desc, TextureFlags flags) { 59 if (mFrontBufferFromDesc && mFrontBufferDesc == desc) 60 return mFrontBufferFromDesc; 61 mFrontBufferFromDesc = nullptr; 62 63 // Test the validity of aAllocator 64 const auto& compositableForwarder = GetForwarder(); 65 if (!compositableForwarder) { 66 return nullptr; 67 } 68 const auto& textureForwarder = compositableForwarder->GetTextureForwarder(); 69 70 auto format = gfx::SurfaceFormat::R8G8B8X8; 71 if (!mData.mIsOpaque) { 72 format = gfx::SurfaceFormat::R8G8B8A8; 73 74 if (!mData.mIsAlphaPremult) { 75 flags |= TextureFlags::NON_PREMULTIPLIED; 76 } 77 } 78 79 mFrontBufferFromDesc = SharedSurfaceTextureData::CreateTextureClient( 80 desc, format, mData.mSize, flags, textureForwarder); 81 mFrontBufferDesc = desc; 82 return mFrontBufferFromDesc; 83 } 84 85 void ShareableCanvasRenderer::UpdateCompositableClient() { 86 if (!CreateCompositable()) { 87 return; 88 } 89 90 if (!IsDirty()) { 91 const auto context = mData.GetContext(); 92 if (!context) { 93 return; 94 } 95 const auto& forwarder = GetForwarder(); 96 RefPtr<FwdTransactionTracker> tracker = 97 context->UseCompositableForwarder(forwarder); 98 if (forwarder && tracker) { 99 forwarder->TrackFwdTransaction(tracker); 100 } 101 return; 102 } 103 ResetDirty(); 104 105 const auto context = mData.GetContext(); 106 if (!context) return; 107 const auto& provider = context->GetBufferProvider(); 108 const auto& forwarder = GetForwarder(); 109 110 // - 111 112 auto flags = TextureFlags::IMMUTABLE; 113 if (!YIsDown()) { 114 flags |= TextureFlags::ORIGIN_BOTTOM_LEFT; 115 } 116 if (IsOpaque()) { 117 flags |= TextureFlags::IS_OPAQUE; 118 } 119 if (provider) { 120 flags |= TextureFlags::ALLOC_BY_BUFFER_PROVIDER; 121 } 122 123 // - 124 125 const auto fnGetExistingTc = 126 [&](const Maybe<SurfaceDescriptor>& aDesc, 127 bool& aOutLostFrontTexture) -> RefPtr<TextureClient> { 128 if (aDesc) { 129 return GetFrontBufferFromDesc(*aDesc, flags); 130 } 131 if (provider) { 132 if (!provider->SetKnowsCompositor(forwarder, aOutLostFrontTexture)) { 133 gfxCriticalNote << "BufferProvider::SetForwarder failed"; 134 return nullptr; 135 } 136 if (aOutLostFrontTexture) { 137 return nullptr; 138 } 139 140 return provider->GetTextureClient(); 141 } 142 return nullptr; 143 }; 144 145 // - 146 147 const auto fnMakeTcFromSnapshot = [&]() -> RefPtr<TextureClient> { 148 const auto& size = mData.mSize; 149 150 auto contentType = gfxContentType::COLOR; 151 if (!mData.mIsOpaque) { 152 contentType = gfxContentType::COLOR_ALPHA; 153 } 154 const auto surfaceFormat = 155 gfxPlatform::GetPlatform()->Optimal2DFormatForContent(contentType); 156 157 const auto tc = 158 mCanvasClient->CreateTextureClientForCanvas(surfaceFormat, size, flags); 159 if (!tc) { 160 return nullptr; 161 } 162 163 { 164 TextureClientAutoLock tcLock(tc, OpenMode::OPEN_WRITE_ONLY); 165 if (!tcLock.Succeeded()) { 166 return nullptr; 167 } 168 169 const RefPtr<DrawTarget> dt = tc->BorrowDrawTarget(); 170 171 const bool requireAlphaPremult = false; 172 auto borrowed = BorrowSnapshot(requireAlphaPremult); 173 if (!borrowed) { 174 return nullptr; 175 } 176 dt->CopySurface(borrowed->mSurf, borrowed->mSurf->GetRect(), {0, 0}); 177 } 178 179 return tc; 180 }; 181 182 // - 183 184 { 185 FirePreTransactionCallback(); 186 187 const auto desc = context->GetFrontBuffer(nullptr); 188 if (desc && 189 desc->type() == SurfaceDescriptor::TSurfaceDescriptorRemoteTexture) { 190 const auto& forwarder = GetForwarder(); 191 const auto& textureDesc = desc->get_SurfaceDescriptorRemoteTexture(); 192 if (!mData.mIsAlphaPremult) { 193 flags |= TextureFlags::NON_PREMULTIPLIED; 194 } 195 EnsurePipeline(); 196 RefPtr<FwdTransactionTracker> tracker = 197 context->UseCompositableForwarder(forwarder); 198 if (tracker) { 199 flags |= TextureFlags::WAIT_FOR_REMOTE_TEXTURE_OWNER; 200 } 201 forwarder->UseRemoteTexture(mCanvasClient, textureDesc.textureId(), 202 textureDesc.ownerId(), mData.mSize, flags, 203 tracker); 204 FireDidTransactionCallback(); 205 return; 206 } 207 208 EnsurePipeline(); 209 210 // Let's see if we can get a no-copy TextureClient from the canvas. 211 bool lostFrontTexture = false; 212 auto tc = fnGetExistingTc(desc, lostFrontTexture); 213 if (lostFrontTexture) { 214 // Device reset could cause this. 215 return; 216 } 217 if (!tc) { 218 // Otherwise, snapshot the surface and copy into a TexClient. 219 tc = fnMakeTcFromSnapshot(); 220 } 221 if (tc != mFrontBufferFromDesc) { 222 mFrontBufferFromDesc = nullptr; 223 } 224 225 if (!tc) { 226 NS_WARNING("Couldn't make TextureClient for CanvasRenderer."); 227 return; 228 } 229 230 mCanvasClient->UseTexture(tc); 231 232 FireDidTransactionCallback(); 233 } 234 } 235 236 } // namespace layers 237 } // namespace mozilla