summaryrefslogtreecommitdiffstats
path: root/dom/canvas/SourceSurfaceWebgl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/SourceSurfaceWebgl.cpp')
-rw-r--r--dom/canvas/SourceSurfaceWebgl.cpp172
1 files changed, 172 insertions, 0 deletions
diff --git a/dom/canvas/SourceSurfaceWebgl.cpp b/dom/canvas/SourceSurfaceWebgl.cpp
new file mode 100644
index 0000000000..b7793e3173
--- /dev/null
+++ b/dom/canvas/SourceSurfaceWebgl.cpp
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "DrawTargetWebglInternal.h"
+#include "SourceSurfaceWebgl.h"
+
+namespace mozilla::gfx {
+
+SourceSurfaceWebgl::SourceSurfaceWebgl(DrawTargetWebgl* aDT)
+ : mFormat(aDT->GetFormat()),
+ mSize(aDT->GetSize()),
+ mDT(aDT),
+ mSharedContext(aDT->mSharedContext) {}
+
+SourceSurfaceWebgl::SourceSurfaceWebgl(
+ const RefPtr<TextureHandle>& aHandle,
+ const RefPtr<DrawTargetWebgl::SharedContext>& aSharedContext)
+ : mFormat(aHandle->GetFormat()),
+ mSize(aHandle->GetSize()),
+ mSharedContext(aSharedContext),
+ mHandle(aHandle) {
+ mHandle->SetSurface(this);
+}
+
+SourceSurfaceWebgl::~SourceSurfaceWebgl() {
+ if (mHandle) {
+ // Signal that the texture handle is not being used now.
+ mHandle->SetSurface(nullptr);
+ }
+}
+
+// Read back the contents of the target or texture handle for data use.
+inline bool SourceSurfaceWebgl::EnsureData() {
+ if (mData) {
+ return true;
+ }
+ if (!mDT) {
+ // Assume that the target changed, so there should be a texture handle
+ // holding a copy. Try to read data from the copy since we can't read
+ // from the target.
+ if (!mHandle || !mSharedContext) {
+ return false;
+ }
+ mData = mSharedContext->ReadSnapshot(mHandle);
+ } else {
+ mData = mDT->ReadSnapshot();
+ }
+ return !!mData;
+}
+
+uint8_t* SourceSurfaceWebgl::GetData() {
+ if (!EnsureData()) {
+ return nullptr;
+ }
+ return mData->GetData();
+}
+
+int32_t SourceSurfaceWebgl::Stride() {
+ if (!EnsureData()) {
+ return 0;
+ }
+ return mData->Stride();
+}
+
+bool SourceSurfaceWebgl::Map(MapType aType, MappedSurface* aMappedSurface) {
+ if (!EnsureData()) {
+ return false;
+ }
+ return mData->Map(aType, aMappedSurface);
+}
+
+void SourceSurfaceWebgl::Unmap() {
+ if (mData) {
+ mData->Unmap();
+ }
+}
+
+// Handler for when the owner DrawTargetWebgl is about to modify its internal
+// framebuffer, and so this snapshot must be copied into a new texture, if
+// possible, or read back into data, if necessary, to preserve this particular
+// version of the framebuffer.
+void SourceSurfaceWebgl::DrawTargetWillChange(bool aNeedHandle) {
+ MOZ_ASSERT(mDT);
+ // Only try to copy into a new texture handle if we don't already have data.
+ // However, we still might need to immediately draw this snapshot to a WebGL
+ // target, which would require a subsequent upload, so also copy into a new
+ // handle even if we already have data in that case since it is faster than
+ // uploading.
+ if ((!mData || aNeedHandle) && !mHandle) {
+ // Prefer copying the framebuffer to a texture if possible.
+ mHandle = mDT->CopySnapshot();
+ if (mHandle) {
+ // Link this surface to the handle.
+ mHandle->SetSurface(this);
+ } else {
+ // If that fails, then try to just read the data to a surface.
+ EnsureData();
+ }
+ }
+ mDT = nullptr;
+}
+
+// Handler for when the owner DrawTargetWebgl is itself being destroyed and
+// needs to transfer ownership of its internal backing texture to the snapshot.
+void SourceSurfaceWebgl::GiveTexture(RefPtr<TextureHandle> aHandle) {
+ // If we get here, then the target still points to this surface as its
+ // snapshot and needs to hand off its backing texture before it is destroyed.
+ MOZ_ASSERT(mDT);
+ MOZ_ASSERT(!mHandle);
+ mHandle = aHandle.forget();
+ mHandle->SetSurface(this);
+ mDT = nullptr;
+}
+
+// Handler for when the owner DrawTargetWebgl is destroying the cached texture
+// handle that has been allocated for this snapshot.
+void SourceSurfaceWebgl::OnUnlinkTexture(
+ DrawTargetWebgl::SharedContext* aContext) {
+ // If we get here, then we must have copied a snapshot, which only happens
+ // if the target changed.
+ MOZ_ASSERT(!mDT);
+ // If the snapshot was mapped before the target changed, we may have read
+ // data instead of holding a copied texture handle. If subsequently we then
+ // try to draw with this snapshot, we might have allocated an external texture
+ // handle in the texture cache that still links to this snapshot and can cause
+ // us to end up here inside OnUnlinkTexture.
+ MOZ_ASSERT(mHandle || mData);
+ if (!mData) {
+ mData = aContext->ReadSnapshot(mHandle);
+ }
+ mHandle = nullptr;
+}
+
+already_AddRefed<SourceSurface> SourceSurfaceWebgl::ExtractSubrect(
+ const IntRect& aRect) {
+ // Ensure we have a texture source available to extract from.
+ if (!(mDT || (mHandle && mSharedContext)) || aRect.IsEmpty() ||
+ !GetRect().Contains(aRect)) {
+ return nullptr;
+ }
+ RefPtr<TextureHandle> subHandle;
+ RefPtr<DrawTargetWebgl::SharedContext> sharedContext;
+ if (mDT) {
+ // If this is still a snapshot linked to a target, then copy from the
+ // target.
+ subHandle = mDT->CopySnapshot(aRect);
+ if (!subHandle) {
+ return nullptr;
+ }
+ sharedContext = mDT->mSharedContext;
+ } else {
+ // Otherwise, we have a handle, but we need to verify it is still linked to
+ // a valid context.
+ sharedContext = mSharedContext;
+ if (!sharedContext) {
+ return nullptr;
+ }
+ // Try to copy directly from the handle using the context.
+ subHandle = sharedContext->CopySnapshot(aRect, mHandle);
+ if (!subHandle) {
+ return nullptr;
+ }
+ }
+ RefPtr<SourceSurface> surface =
+ new SourceSurfaceWebgl(subHandle, sharedContext);
+ return surface.forget();
+}
+
+} // namespace mozilla::gfx