TextureRecorded.cpp (7090B)
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 "TextureRecorded.h" 8 #include "mozilla/gfx/DrawTargetRecording.h" 9 #include "mozilla/layers/CompositableForwarder.h" 10 11 #include "RecordedCanvasEventImpl.h" 12 13 namespace mozilla { 14 namespace layers { 15 16 RecordedTextureData::RecordedTextureData( 17 already_AddRefed<CanvasChild> aCanvasChild, gfx::IntSize aSize, 18 gfx::SurfaceFormat aFormat, TextureType aTextureType, 19 TextureType aWebglTextureType) 20 : mRemoteTextureOwnerId(RemoteTextureOwnerId::GetNext()), 21 mCanvasChild(aCanvasChild), 22 mSize(aSize), 23 mFormat(aFormat) {} 24 25 RecordedTextureData::~RecordedTextureData() { 26 // We need the translator to drop its reference for the DrawTarget first, 27 // because the TextureData might need to destroy its DrawTarget within a lock. 28 mSnapshot = nullptr; 29 DetachSnapshotWrapper(); 30 if (mDT) { 31 mDT->DetachTextureData(this); 32 mDT = nullptr; 33 } 34 mCanvasChild->RecordEvent(RecordedTextureDestruction( 35 mRemoteTextureOwnerId, ToRemoteTextureTxnType(mFwdTransactionTracker), 36 ToRemoteTextureTxnId(mFwdTransactionTracker))); 37 } 38 39 void RecordedTextureData::FillInfo(TextureData::Info& aInfo) const { 40 aInfo.size = mSize; 41 aInfo.format = mFormat; 42 aInfo.supportsMoz2D = true; 43 aInfo.hasSynchronization = true; 44 } 45 46 void RecordedTextureData::InvalidateContents() { mInvalidContents = true; } 47 48 bool RecordedTextureData::Lock(OpenMode aMode) { 49 if (!mCanvasChild->EnsureBeginTransaction()) { 50 return false; 51 } 52 53 if (!mDT && mInited) { 54 return false; 55 } 56 57 // If modifying the texture, then allocate a new remote texture id. 58 if (aMode & OpenMode::OPEN_WRITE) { 59 mUsedRemoteTexture = false; 60 } 61 62 bool wasInvalidContents = mInvalidContents; 63 mInvalidContents = false; 64 65 if (!mDT && !mInited) { 66 mInited = true; 67 mDT = mCanvasChild->CreateDrawTarget(mRemoteTextureOwnerId, mSize, mFormat); 68 if (!mDT) { 69 return false; 70 } 71 72 mDT->AttachTextureData(this); 73 74 // We lock the TextureData when we create it to get the remote DrawTarget. 75 mLockedMode = aMode; 76 return true; 77 } 78 79 mCanvasChild->RecordEvent( 80 RecordedTextureLock(mRemoteTextureOwnerId, aMode, wasInvalidContents)); 81 mLockedMode = aMode; 82 return true; 83 } 84 85 void RecordedTextureData::DetachSnapshotWrapper(bool aInvalidate, 86 bool aRelease) { 87 if (mSnapshotWrapper) { 88 // If the snapshot only has one ref, then we don't need to worry about 89 // copying before invalidation since it is about to be deleted. Otherwise, 90 // we need to ensure any internal data is appropriately copied before 91 // shmems are potentially overwritten if there are still existing users. 92 mCanvasChild->DetachSurface(mSnapshotWrapper, 93 aInvalidate && !mSnapshotWrapper->hasOneRef()); 94 if (aRelease) { 95 mSnapshotWrapper = nullptr; 96 } 97 } 98 } 99 100 void RecordedTextureData::Unlock() { 101 if ((mLockedMode == OpenMode::OPEN_READ_WRITE) && 102 mCanvasChild->ShouldCacheDataSurface()) { 103 DetachSnapshotWrapper(); 104 mSnapshot = mDT->Snapshot(); 105 mDT->DetachAllSnapshots(); 106 mCanvasChild->RecordEvent(RecordedCacheDataSurface(mSnapshot.get())); 107 } 108 109 mCanvasChild->RecordEvent(RecordedTextureUnlock(mRemoteTextureOwnerId)); 110 111 mLockedMode = OpenMode::OPEN_NONE; 112 } 113 114 already_AddRefed<gfx::DrawTarget> RecordedTextureData::BorrowDrawTarget() { 115 if (mLockedMode & OpenMode::OPEN_WRITE) { 116 // The snapshot will be invalidated. 117 mSnapshot = nullptr; 118 DetachSnapshotWrapper(true); 119 } 120 return do_AddRef(mDT); 121 } 122 123 void RecordedTextureData::EndDraw() { 124 MOZ_ASSERT(mDT->hasOneRef()); 125 MOZ_ASSERT(mLockedMode == OpenMode::OPEN_READ_WRITE); 126 127 if (mCanvasChild->ShouldCacheDataSurface()) { 128 DetachSnapshotWrapper(); 129 mSnapshot = mDT->Snapshot(); 130 mCanvasChild->RecordEvent(RecordedCacheDataSurface(mSnapshot.get())); 131 } 132 } 133 134 void RecordedTextureData::DrawTargetWillChange() { 135 // The DrawTargetRecording will be modified, so ensure that possibly the last 136 // reference to a snapshot is discarded so that it does not inadvertently 137 // force a copy. 138 mSnapshot = nullptr; 139 DetachSnapshotWrapper(true); 140 } 141 142 already_AddRefed<gfx::SourceSurface> RecordedTextureData::BorrowSnapshot() { 143 if (mSnapshotWrapper) { 144 // The DT is unmodified since the last time snapshot was borrowed, so it 145 // is safe to reattach the snapshot for shmem readbacks. 146 mCanvasChild->AttachSurface(mSnapshotWrapper); 147 return do_AddRef(mSnapshotWrapper); 148 } 149 150 // There are some failure scenarios where we have no DrawTarget and 151 // BorrowSnapshot is called in an attempt to copy to a new texture. 152 if (!mDT) { 153 return nullptr; 154 } 155 156 RefPtr<gfx::SourceSurface> wrapper = mCanvasChild->WrapSurface( 157 mSnapshot ? mSnapshot : mDT->Snapshot(), mRemoteTextureOwnerId); 158 mSnapshotWrapper = wrapper; 159 return wrapper.forget(); 160 } 161 162 void RecordedTextureData::ReturnDrawTarget( 163 already_AddRefed<gfx::DrawTarget> aDT) { 164 RefPtr<gfx::DrawTarget> dt(aDT); 165 } 166 167 void RecordedTextureData::ReturnSnapshot( 168 already_AddRefed<gfx::SourceSurface> aSnapshot) { 169 RefPtr<gfx::SourceSurface> snapshot = aSnapshot; 170 // The snapshot needs to be marked detached but we keep the wrapper around 171 // so that it can be reused without repeatedly creating it and accidentally 172 // reading back data for each new instantiation. 173 DetachSnapshotWrapper(false, false); 174 } 175 176 void RecordedTextureData::Deallocate(LayersIPCChannel* aAllocator) {} 177 178 bool RecordedTextureData::Serialize(SurfaceDescriptor& aDescriptor) { 179 // If something is querying the id, assume it is going to be composited. 180 if (!mUsedRemoteTexture) { 181 mLastRemoteTextureId = RemoteTextureId::GetNext(); 182 mCanvasChild->RecordEvent( 183 RecordedPresentTexture(mRemoteTextureOwnerId, mLastRemoteTextureId)); 184 mUsedRemoteTexture = true; 185 } 186 187 aDescriptor = SurfaceDescriptorRemoteTexture(mLastRemoteTextureId, 188 mRemoteTextureOwnerId); 189 return true; 190 } 191 192 already_AddRefed<FwdTransactionTracker> 193 RecordedTextureData::UseCompositableForwarder( 194 CompositableForwarder* aForwarder) { 195 return FwdTransactionTracker::GetOrCreate(mFwdTransactionTracker); 196 } 197 198 void RecordedTextureData::OnForwardedToHost() { 199 // Compositing with RecordedTextureData requires RemoteTextureMap. 200 MOZ_CRASH("OnForwardedToHost not supported!"); 201 } 202 203 TextureFlags RecordedTextureData::GetTextureFlags() const { 204 // With WebRender, resource open happens asynchronously on RenderThread. 205 // Use WAIT_HOST_USAGE_END to keep TextureClient alive during host side usage. 206 return TextureFlags::WAIT_HOST_USAGE_END; 207 } 208 209 bool RecordedTextureData::RequiresRefresh() const { 210 return mCanvasChild->RequiresRefresh(mRemoteTextureOwnerId); 211 } 212 213 } // namespace layers 214 } // namespace mozilla