Bug 1739448 - Implement a prototype WebGL-backed Canvas2D. r=gfx-reviewers,nical,jrmuizel
This mainly provides DrawTargetWebgl, which implements the subset of the DrawTarget API necessary for integration with CanvasRenderingContext2D. It translates them to suitable commands for its internal ClientWebGLContext, which then manages remoting WebGL requests to the parent/GPU process. Currently two shaders are used for drawing Canvas2D primitives, but can be expanded in the future. These are an image shader and a solid color shader. The core of this implementation revolves around TexturePacker and TextureHandle, which cope with the necessity of frequently uploading SourceSurfaces for use with WebGL. TexturePacker implements a bin-packing algorithm for packing these uploads into texture pages, which can either be SharedTextures if they are reasonably small, or StandaloneTextures if they are too big to pack in a SharedTexture. Each upload is assigned a TextureHandle which is used to manage it in a move-to-front cache, so that we can easily eject TextureHandles from the back of the cache if we have too many. These TextureHandles are associated with the SourceSurface that spawned them to more easily manage their lifetimes. There are further dependent caches for dealing with blurred shadows and with text. Shadows are cached in an uploaded texture bound to the SourceSurface that generated them. Text is handled by caching entire runs in the GlyphCache (keyed by both their rendering parameters and their glyphs). The text is first rasterized to a surface and then uploaded to a texture in the GlyphCache which can be reused should the text be encountered again. To deal with commands we can't accelerate, a separate internal DrawTargetSkia is also maintained. The content of the WebGL framebuffer is copied into it so that drawing can then proceed in software from there. It remains in this fallover state until the next frame, when it resets back to using the WebGL framebuffer again. This acceleration is disabled by default. To enable it, you must toggle the pref "gfx.canvas.accelerated" to true. This should be suitably different from the naming of the previous SkiaGL prefs to not alias with them. There are a few dependent prefs that follow from the previous SkiaGL prefs for setting the size limitations for acceleration and also limitations for the internal texture cache. Differential Revision: https://phabricator.services.mozilla.com/D130388
This commit is contained in:
@@ -61,6 +61,7 @@
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsStyleUtil.h"
|
||||
#include "CanvasImageCache.h"
|
||||
#include "DrawTargetWebgl.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -1312,7 +1313,8 @@ bool CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect,
|
||||
RefPtr<DrawTarget> newTarget;
|
||||
RefPtr<PersistentBufferProvider> newProvider;
|
||||
|
||||
if (!TrySharedTarget(newTarget, newProvider) &&
|
||||
if (!TryAcceleratedTarget(newTarget, newProvider) &&
|
||||
!TrySharedTarget(newTarget, newProvider) &&
|
||||
!TryBasicTarget(newTarget, newProvider)) {
|
||||
gfxCriticalError(
|
||||
CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(GetSize())))
|
||||
@@ -1423,6 +1425,18 @@ static WindowRenderer* WindowRendererFromCanvasElement(
|
||||
return nsContentUtils::WindowRendererForDocument(aCanvasElement->OwnerDoc());
|
||||
}
|
||||
|
||||
bool CanvasRenderingContext2D::TryAcceleratedTarget(
|
||||
RefPtr<gfx::DrawTarget>& aOutDT,
|
||||
RefPtr<layers::PersistentBufferProvider>& aOutProvider) {
|
||||
aOutDT = DrawTargetWebgl::Create(GetSize(), GetSurfaceFormat());
|
||||
if (!aOutDT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aOutProvider = new PersistentBufferProviderAccelerated(aOutDT);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CanvasRenderingContext2D::TrySharedTarget(
|
||||
RefPtr<gfx::DrawTarget>& aOutDT,
|
||||
RefPtr<layers::PersistentBufferProvider>& aOutProvider) {
|
||||
@@ -1433,9 +1447,7 @@ bool CanvasRenderingContext2D::TrySharedTarget(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mBufferProvider &&
|
||||
(mBufferProvider->GetType() == LayersBackend::LAYERS_CLIENT ||
|
||||
mBufferProvider->GetType() == LayersBackend::LAYERS_WR)) {
|
||||
if (mBufferProvider && mBufferProvider->IsShared()) {
|
||||
// we are already using a shared buffer provider, we are allocating a new
|
||||
// one because the current one failed so let's just fall back to the basic
|
||||
// provider.
|
||||
@@ -1485,6 +1497,13 @@ bool CanvasRenderingContext2D::TryBasicTarget(
|
||||
return true;
|
||||
}
|
||||
|
||||
ClientWebGLContext* CanvasRenderingContext2D::AsWebgl() {
|
||||
if (mBufferProvider) {
|
||||
return mBufferProvider->AsWebgl();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PresShell* CanvasRenderingContext2D::GetPresShell() {
|
||||
if (mCanvasElement) {
|
||||
return mCanvasElement->OwnerDoc()->GetPresShell();
|
||||
@@ -4912,9 +4931,7 @@ void CanvasRenderingContext2D::DrawWindow(nsGlobalWindowInner& aWindow,
|
||||
}
|
||||
}
|
||||
if (op == CompositionOp::OP_OVER &&
|
||||
(!mBufferProvider ||
|
||||
(mBufferProvider->GetType() != LayersBackend::LAYERS_CLIENT &&
|
||||
mBufferProvider->GetType() != LayersBackend::LAYERS_WR))) {
|
||||
(!mBufferProvider || !mBufferProvider->IsShared())) {
|
||||
thebes = gfxContext::CreateOrNull(mTarget);
|
||||
MOZ_ASSERT(thebes); // already checked the draw target above
|
||||
// (in SupportsAzureContentForDrawTarget)
|
||||
|
||||
@@ -611,12 +611,18 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
|
||||
|
||||
void RestoreClipsAndTransformToTarget();
|
||||
|
||||
bool TryAcceleratedTarget(
|
||||
RefPtr<gfx::DrawTarget>& aOutDT,
|
||||
RefPtr<layers::PersistentBufferProvider>& aOutProvider);
|
||||
|
||||
bool TrySharedTarget(RefPtr<gfx::DrawTarget>& aOutDT,
|
||||
RefPtr<layers::PersistentBufferProvider>& aOutProvider);
|
||||
|
||||
bool TryBasicTarget(RefPtr<gfx::DrawTarget>& aOutDT,
|
||||
RefPtr<layers::PersistentBufferProvider>& aOutProvider);
|
||||
|
||||
ClientWebGLContext* AsWebgl() override;
|
||||
|
||||
void RegisterAllocation();
|
||||
|
||||
void SetInitialState();
|
||||
|
||||
@@ -3172,6 +3172,14 @@ void ClientWebGLContext::BufferData(GLenum target,
|
||||
Run<RPROC(BufferData)>(target, RawBuffer<>(range), usage);
|
||||
}
|
||||
|
||||
void ClientWebGLContext::RawBufferData(GLenum target,
|
||||
const Range<const uint8_t>& srcData,
|
||||
GLenum usage) {
|
||||
const FuncScope funcScope(*this, "bufferData");
|
||||
|
||||
Run<RPROC(BufferData)>(target, RawBuffer<>(srcData), usage);
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
void ClientWebGLContext::BufferSubData(GLenum target,
|
||||
@@ -4085,6 +4093,14 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
|
||||
scopedArr.Reset(); // (For the hazard analysis) Done with the data.
|
||||
}
|
||||
|
||||
void ClientWebGLContext::RawTexImage(
|
||||
uint32_t level, GLenum respecFormat, uvec3 offset,
|
||||
const webgl::PackingInfo& pi, const webgl::TexUnpackBlobDesc& desc) const {
|
||||
const FuncScope funcScope(*this, "tex(Sub)Image[23]D");
|
||||
if (IsContextLost()) return;
|
||||
Run<RPROC(TexImage)>(level, respecFormat, offset, pi, desc);
|
||||
}
|
||||
|
||||
void ClientWebGLContext::CompressedTexImage(bool sub, uint8_t funcDims,
|
||||
GLenum imageTarget, GLint level,
|
||||
GLenum format, const ivec3& offset,
|
||||
|
||||
@@ -37,6 +37,10 @@ namespace dom {
|
||||
class WebGLChild;
|
||||
}
|
||||
|
||||
namespace gfx {
|
||||
class DrawTargetWebgl;
|
||||
}
|
||||
|
||||
namespace webgl {
|
||||
class AvailabilityRunnable;
|
||||
class TexUnpackBlob;
|
||||
@@ -693,6 +697,7 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
|
||||
friend class webgl::ObjectJS;
|
||||
friend class webgl::ProgramKeepAlive;
|
||||
friend class webgl::ShaderKeepAlive;
|
||||
friend class gfx::DrawTargetWebgl;
|
||||
|
||||
// ----------------------------- Lifetime and DOM ---------------------------
|
||||
public:
|
||||
@@ -921,6 +926,12 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
|
||||
}
|
||||
|
||||
void OnMemoryPressure() override;
|
||||
void SetContextOptions(const WebGLContextOptions& aOptions) {
|
||||
mInitialOptions.emplace(aOptions);
|
||||
}
|
||||
const WebGLContextOptions& GetContextOptions() const {
|
||||
return mInitialOptions.ref();
|
||||
}
|
||||
NS_IMETHOD
|
||||
SetContextOptions(JSContext* cx, JS::Handle<JS::Value> options,
|
||||
ErrorResult& aRvForDictionaryInit) override;
|
||||
@@ -1385,6 +1396,8 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
|
||||
void BufferData(GLenum target, const dom::ArrayBufferView& srcData,
|
||||
GLenum usage, GLuint srcElemOffset = 0,
|
||||
GLuint srcElemCountOverride = 0);
|
||||
void RawBufferData(GLenum target, const Range<const uint8_t>& srcData,
|
||||
GLenum usage);
|
||||
|
||||
void BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset,
|
||||
const dom::ArrayBufferView& src, GLuint srcElemOffset = 0,
|
||||
@@ -1503,6 +1516,9 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
|
||||
GLenum internalFormat, const ivec3& size) const;
|
||||
|
||||
// Primitive tex upload functions
|
||||
void RawTexImage(uint32_t level, GLenum respecFormat, uvec3 offset,
|
||||
const webgl::PackingInfo& pi,
|
||||
const webgl::TexUnpackBlobDesc&) const;
|
||||
void TexImage(uint8_t funcDims, GLenum target, GLint level,
|
||||
GLenum respecFormat, const ivec3& offset, const ivec3& size,
|
||||
GLint border, const webgl::PackingInfo& pi,
|
||||
|
||||
1770
dom/canvas/DrawTargetWebgl.cpp
Normal file
1770
dom/canvas/DrawTargetWebgl.cpp
Normal file
File diff suppressed because it is too large
Load Diff
252
dom/canvas/DrawTargetWebgl.h
Normal file
252
dom/canvas/DrawTargetWebgl.h
Normal file
@@ -0,0 +1,252 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef _MOZILLA_GFX_DRAWTARGETWEBGL_H
|
||||
#define _MOZILLA_GFX_DRAWTARGETWEBGL_H
|
||||
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include <vector>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ClientWebGLContext;
|
||||
class WebGLBufferJS;
|
||||
class WebGLProgramJS;
|
||||
class WebGLTextureJS;
|
||||
class WebGLUniformLocationJS;
|
||||
class WebGLVertexArrayJS;
|
||||
|
||||
namespace gfx {
|
||||
|
||||
class DataSourceSurface;
|
||||
class DrawTargetSkia;
|
||||
class DrawTargetWebgl;
|
||||
class SourceSurfaceSkia;
|
||||
|
||||
class TextureHandle;
|
||||
class SharedTexture;
|
||||
class SharedTextureHandle;
|
||||
class StandaloneTexture;
|
||||
class GlyphCacheEntry;
|
||||
class GlyphCache;
|
||||
|
||||
// DrawTargetWebgl implements a subset of the DrawTarget API suitable for use
|
||||
// by CanvasRenderingContext2D. It maps these to a client WebGL context so that
|
||||
// they can be accelerated where possible by WebGL. It manages both routing to
|
||||
// appropriate shaders and texture allocation/caching for surfaces. For commands
|
||||
// that are not feasible to accelerate with WebGL, it mirrors state to a backup
|
||||
// DrawTargetSkia that can be used as a fallback software renderer.
|
||||
class DrawTargetWebgl : public DrawTarget {
|
||||
friend class SharedTextureHandle;
|
||||
friend class StandaloneTexture;
|
||||
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetWebgl, override)
|
||||
|
||||
private:
|
||||
IntSize mSize;
|
||||
RefPtr<ClientWebGLContext> mWebgl;
|
||||
RefPtr<DrawTargetSkia> mSkia;
|
||||
// The currently cached snapshot of the WebGL context
|
||||
RefPtr<DataSourceSurface> mSnapshot;
|
||||
// Whether or not the Skia target has valid contents and is being drawn to
|
||||
bool mSkiaValid = false;
|
||||
// Whether or not the WebGL context has valid contents and is being drawn to
|
||||
bool mWebglValid = false;
|
||||
|
||||
// WebGL shader resources
|
||||
RefPtr<WebGLBufferJS> mVertexBuffer;
|
||||
RefPtr<WebGLVertexArrayJS> mVertexArray;
|
||||
RefPtr<WebGLProgramJS> mSolidProgram;
|
||||
RefPtr<WebGLUniformLocationJS> mSolidProgramTransform;
|
||||
RefPtr<WebGLUniformLocationJS> mSolidProgramColor;
|
||||
RefPtr<WebGLProgramJS> mImageProgram;
|
||||
RefPtr<WebGLUniformLocationJS> mImageProgramTransform;
|
||||
RefPtr<WebGLUniformLocationJS> mImageProgramTexMatrix;
|
||||
RefPtr<WebGLUniformLocationJS> mImageProgramTexBounds;
|
||||
RefPtr<WebGLUniformLocationJS> mImageProgramColor;
|
||||
RefPtr<WebGLUniformLocationJS> mImageProgramSwizzle;
|
||||
RefPtr<WebGLUniformLocationJS> mImageProgramSampler;
|
||||
// A most-recently-used list of allocated texture handles.
|
||||
LinkedList<RefPtr<TextureHandle>> mTextureHandles;
|
||||
size_t mNumTextureHandles = 0;
|
||||
// User data key linking a SourceSurface with its TextureHandle.
|
||||
UserDataKey mTextureHandleKey = {0};
|
||||
// User data key linking a SourceSurface with its shadow blur TextureHandle.
|
||||
UserDataKey mShadowTextureKey = {0};
|
||||
// User data key linking a ScaledFont with its GlyphCache.
|
||||
UserDataKey mGlyphCacheKey = {0};
|
||||
// List of all GlyphCaches currently allocated to fonts.
|
||||
LinkedList<GlyphCache> mGlyphCaches;
|
||||
// Collection of allocated shared texture pages that may be shared amongst
|
||||
// many handles.
|
||||
std::vector<RefPtr<SharedTexture>> mSharedTextures;
|
||||
// Collection of allocated standalone textures that have a single assigned
|
||||
// handle.
|
||||
std::vector<RefPtr<StandaloneTexture>> mStandaloneTextures;
|
||||
size_t mUsedTextureMemory = 0;
|
||||
size_t mTotalTextureMemory = 0;
|
||||
RefPtr<TextureHandle> mSnapshotTexture;
|
||||
CompositionOp mLastCompositionOp = CompositionOp::OP_SOURCE;
|
||||
|
||||
public:
|
||||
DrawTargetWebgl();
|
||||
~DrawTargetWebgl();
|
||||
|
||||
static already_AddRefed<DrawTargetWebgl> Create(const IntSize& aSize,
|
||||
SurfaceFormat aFormat);
|
||||
|
||||
bool Init(const IntSize& aSize, SurfaceFormat aFormat);
|
||||
|
||||
DrawTargetType GetType() const override {
|
||||
return DrawTargetType::HARDWARE_RASTER;
|
||||
}
|
||||
BackendType GetBackendType() const override { return BackendType::WEBGL; }
|
||||
IntSize GetSize() const override { return mSize; }
|
||||
|
||||
already_AddRefed<SourceSurface> Snapshot() override;
|
||||
already_AddRefed<SourceSurface> GetBackingSurface() override;
|
||||
void DetachAllSnapshots() override { MarkChanged(); }
|
||||
|
||||
bool LockBits(uint8_t** aData, IntSize* aSize, int32_t* aStride,
|
||||
SurfaceFormat* aFormat, IntPoint* aOrigin = nullptr) override;
|
||||
void ReleaseBits(uint8_t* aData) override;
|
||||
|
||||
void Flush() override;
|
||||
void DrawSurface(
|
||||
SourceSurface* aSurface, const Rect& aDest, const Rect& aSource,
|
||||
const DrawSurfaceOptions& aSurfOptions = DrawSurfaceOptions(),
|
||||
const DrawOptions& aOptions = DrawOptions()) override;
|
||||
void DrawFilter(FilterNode* aNode, const Rect& aSourceRect,
|
||||
const Point& aDestPoint,
|
||||
const DrawOptions& aOptions = DrawOptions()) override;
|
||||
void DrawSurfaceWithShadow(SourceSurface* aSurface, const Point& aDest,
|
||||
const DeviceColor& aColor, const Point& aOffset,
|
||||
Float aSigma, CompositionOp aOperator) override;
|
||||
void ClearRect(const Rect& aRect) override;
|
||||
void CopySurface(SourceSurface* aSurface, const IntRect& aSourceRect,
|
||||
const IntPoint& aDestination) override;
|
||||
void FillRect(const Rect& aRect, const Pattern& aPattern,
|
||||
const DrawOptions& aOptions = DrawOptions()) override;
|
||||
void StrokeRect(const Rect& aRect, const Pattern& aPattern,
|
||||
const StrokeOptions& aStrokeOptions = StrokeOptions(),
|
||||
const DrawOptions& aOptions = DrawOptions()) override;
|
||||
void StrokeLine(const Point& aStart, const Point& aEnd,
|
||||
const Pattern& aPattern,
|
||||
const StrokeOptions& aStrokeOptions = StrokeOptions(),
|
||||
const DrawOptions& aOptions = DrawOptions()) override;
|
||||
void Stroke(const Path* aPath, const Pattern& aPattern,
|
||||
const StrokeOptions& aStrokeOptions = StrokeOptions(),
|
||||
const DrawOptions& aOptions = DrawOptions()) override;
|
||||
void Fill(const Path* aPath, const Pattern& aPattern,
|
||||
const DrawOptions& aOptions = DrawOptions()) override;
|
||||
|
||||
void SetPermitSubpixelAA(bool aPermitSubpixelAA) override;
|
||||
void FillGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
|
||||
const Pattern& aPattern,
|
||||
const DrawOptions& aOptions = DrawOptions()) override;
|
||||
void StrokeGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
|
||||
const Pattern& aPattern,
|
||||
const StrokeOptions& aStrokeOptions = StrokeOptions(),
|
||||
const DrawOptions& aOptions = DrawOptions()) override;
|
||||
void Mask(const Pattern& aSource, const Pattern& aMask,
|
||||
const DrawOptions& aOptions = DrawOptions()) override;
|
||||
void MaskSurface(const Pattern& aSource, SourceSurface* aMask, Point aOffset,
|
||||
const DrawOptions& aOptions = DrawOptions()) override;
|
||||
bool Draw3DTransformedSurface(SourceSurface* aSurface,
|
||||
const Matrix4x4& aMatrix) override;
|
||||
void PushClip(const Path* aPath) override;
|
||||
void PushClipRect(const Rect& aRect) override;
|
||||
void PushDeviceSpaceClipRects(const IntRect* aRects,
|
||||
uint32_t aCount) override;
|
||||
void PopClip() override;
|
||||
void PushLayer(bool aOpaque, Float aOpacity, SourceSurface* aMask,
|
||||
const Matrix& aMaskTransform,
|
||||
const IntRect& aBounds = IntRect(),
|
||||
bool aCopyBackground = false) override {
|
||||
MOZ_ASSERT(false);
|
||||
}
|
||||
void PushLayerWithBlend(
|
||||
bool aOpaque, Float aOpacity, SourceSurface* aMask,
|
||||
const Matrix& aMaskTransform, const IntRect& aBounds = IntRect(),
|
||||
bool aCopyBackground = false,
|
||||
CompositionOp aCompositionOp = CompositionOp::OP_OVER) override {
|
||||
MOZ_ASSERT(false);
|
||||
}
|
||||
void PopLayer() override { MOZ_ASSERT(false); }
|
||||
already_AddRefed<SourceSurface> CreateSourceSurfaceFromData(
|
||||
unsigned char* aData, const IntSize& aSize, int32_t aStride,
|
||||
SurfaceFormat aFormat) const override;
|
||||
already_AddRefed<SourceSurface> OptimizeSourceSurface(
|
||||
SourceSurface* aSurface) const override;
|
||||
already_AddRefed<SourceSurface> OptimizeSourceSurfaceForUnknownAlpha(
|
||||
SourceSurface* aSurface) const override;
|
||||
already_AddRefed<SourceSurface> CreateSourceSurfaceFromNativeSurface(
|
||||
const NativeSurface& aSurface) const override;
|
||||
already_AddRefed<DrawTarget> CreateSimilarDrawTarget(
|
||||
const IntSize& aSize, SurfaceFormat aFormat) const override;
|
||||
bool CanCreateSimilarDrawTarget(const IntSize& aSize,
|
||||
SurfaceFormat aFormat) const override;
|
||||
RefPtr<DrawTarget> CreateClippedDrawTarget(const Rect& aBounds,
|
||||
SurfaceFormat aFormat) override;
|
||||
|
||||
already_AddRefed<PathBuilder> CreatePathBuilder(
|
||||
FillRule aFillRule = FillRule::FILL_WINDING) const override;
|
||||
already_AddRefed<GradientStops> CreateGradientStops(
|
||||
GradientStop* aStops, uint32_t aNumStops,
|
||||
ExtendMode aExtendMode = ExtendMode::CLAMP) const override;
|
||||
already_AddRefed<FilterNode> CreateFilter(FilterType aType) override;
|
||||
void SetTransform(const Matrix& aTransform) override;
|
||||
void* GetNativeSurface(NativeSurfaceType aType) override;
|
||||
|
||||
operator std::string() const {
|
||||
std::stringstream stream;
|
||||
stream << "DrawTargetWebgl(" << this << ")";
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
private:
|
||||
bool SupportsPattern(const Pattern& aPattern);
|
||||
|
||||
bool DrawRect(const Rect& aRect, const Pattern& aPattern,
|
||||
const DrawOptions& aOptions,
|
||||
Maybe<DeviceColor> aMaskColor = Nothing(),
|
||||
RefPtr<TextureHandle>* aHandle = nullptr,
|
||||
bool aTransformed = true, bool aClipped = true,
|
||||
bool aAccelOnly = false, bool aForceUpdate = false);
|
||||
|
||||
void MarkChanged();
|
||||
|
||||
void ReadIntoSkia();
|
||||
bool FlushFromSkia();
|
||||
|
||||
void MarkSkiaChanged() {
|
||||
if (!mSkiaValid) {
|
||||
ReadIntoSkia();
|
||||
}
|
||||
mWebglValid = false;
|
||||
}
|
||||
|
||||
bool ReadInto(uint8_t* aDstData, int32_t aDstStride);
|
||||
|
||||
bool CreateShaders();
|
||||
|
||||
bool RemoveSharedTexture(const RefPtr<SharedTexture>& aTexture);
|
||||
bool RemoveStandaloneTexture(const RefPtr<StandaloneTexture>& aTexture);
|
||||
|
||||
void PruneTextureHandle(RefPtr<TextureHandle> aHandle);
|
||||
bool PruneTextureMemory(size_t aMargin = 0, bool aPruneUnused = true);
|
||||
|
||||
void UnlinkSurfaceTextures();
|
||||
void UnlinkSurfaceTexture(const RefPtr<TextureHandle>& aHandle);
|
||||
void UnlinkGlyphCaches();
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // _MOZILLA_GFX_DRAWTARGETWEBGL_H
|
||||
298
dom/canvas/DrawTargetWebglInternal.h
Normal file
298
dom/canvas/DrawTargetWebglInternal.h
Normal file
@@ -0,0 +1,298 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef _MOZILLA_GFX_DRAWTARGETWEBGL_INTERNAL_H
|
||||
#define _MOZILLA_GFX_DRAWTARGETWEBGL_INTERNAL_H
|
||||
|
||||
#include "DrawTargetWebgl.h"
|
||||
|
||||
#include "mozilla/HashFunctions.h"
|
||||
|
||||
namespace mozilla::gfx {
|
||||
|
||||
// TexturePacker implements a bin-packing algorithm for 2D rectangles. It uses
|
||||
// a binary tree that partitions the space of a node at a given split. This
|
||||
// produces two children, one on either side of the split. This subdivision
|
||||
// proceeds recursively as necessary.
|
||||
class TexturePacker {
|
||||
public:
|
||||
explicit TexturePacker(const IntRect& aBounds, bool aAvailable = true)
|
||||
: mBounds(aBounds),
|
||||
mAvailable(aAvailable ? std::min(aBounds.width, aBounds.height) : 0) {}
|
||||
|
||||
Maybe<IntPoint> Insert(const IntSize& aSize);
|
||||
|
||||
bool Remove(const IntRect& aBounds);
|
||||
|
||||
const IntRect& GetBounds() const { return mBounds; }
|
||||
|
||||
private:
|
||||
bool IsLeaf() const { return !mChildren[0]; }
|
||||
bool IsFullyAvailable() const { return IsLeaf() && mAvailable > 0; }
|
||||
|
||||
void DiscardChildren() {
|
||||
mChildren[0] = nullptr;
|
||||
mChildren[1] = nullptr;
|
||||
}
|
||||
|
||||
// If applicable, the two children produced by picking a single axis split
|
||||
// within the node's bounds and subdividing the bounds there.
|
||||
UniquePtr<TexturePacker> mChildren[2];
|
||||
// The bounds enclosing this node and any children within it.
|
||||
IntRect mBounds;
|
||||
// For a leaf node, specifies the size of the smallest dimension available to
|
||||
// allocate. For a branch node, specifies largest potential available size of
|
||||
// all children. This can be used during the allocation process to rapidly
|
||||
// reject certain sub-trees without having to search all the way to a leaf
|
||||
// node if we know that largest available size within the sub-tree wouldn't
|
||||
// fit the requested size.
|
||||
int mAvailable = 0;
|
||||
};
|
||||
|
||||
class GlyphCacheEntry;
|
||||
|
||||
// TextureHandle is an abstract base class for supplying textures to drawing
|
||||
// commands that may be backed by different resource types (such as a shared
|
||||
// or standalone texture). It may be further linked to use-specific metadata
|
||||
// such as for shadow drawing or for cached entries in the glyph cache.
|
||||
class TextureHandle : public RefCounted<TextureHandle>,
|
||||
public LinkedListElement<RefPtr<TextureHandle>> {
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(TextureHandle)
|
||||
|
||||
enum Type { SHARED, STANDALONE };
|
||||
|
||||
virtual Type GetType() const = 0;
|
||||
virtual const RefPtr<WebGLTextureJS>& GetWebGLTexture() const = 0;
|
||||
virtual IntRect GetBounds() const = 0;
|
||||
IntSize GetSize() const { return GetBounds().Size(); }
|
||||
virtual IntSize GetBackingSize() const = 0;
|
||||
virtual SurfaceFormat GetFormat() const = 0;
|
||||
virtual size_t UsedBytes() const = 0;
|
||||
|
||||
static inline size_t UsedBytes(SurfaceFormat aFormat, const IntSize& aSize) {
|
||||
return size_t(BytesPerPixel(aFormat)) * size_t(aSize.width) *
|
||||
size_t(aSize.height);
|
||||
}
|
||||
|
||||
virtual void UpdateSize(const IntSize& aSize) {}
|
||||
|
||||
virtual void Cleanup(DrawTargetWebgl& aDT) {}
|
||||
|
||||
virtual ~TextureHandle() {}
|
||||
|
||||
bool IsValid() const { return mValid; }
|
||||
void Invalidate() { mValid = false; }
|
||||
|
||||
void SetSurface(SourceSurface* aSurface) { mSurface = aSurface; }
|
||||
SourceSurface* GetSurface() const { return mSurface; }
|
||||
|
||||
float GetSigma() const { return mSigma; }
|
||||
void SetSigma(float aSigma) { mSigma = aSigma; }
|
||||
bool IsShadow() const { return mSigma >= 0.0f; }
|
||||
|
||||
void SetSamplingOffset(const IntPoint& aSamplingOffset) {
|
||||
mSamplingOffset = aSamplingOffset;
|
||||
}
|
||||
const IntPoint& GetSamplingOffset() const { return mSamplingOffset; }
|
||||
IntRect GetSamplingRect() const {
|
||||
return IntRect(GetSamplingOffset(), GetSize());
|
||||
}
|
||||
|
||||
const RefPtr<GlyphCacheEntry>& GetGlyphCacheEntry() const {
|
||||
return mGlyphCacheEntry;
|
||||
}
|
||||
void SetGlyphCacheEntry(const RefPtr<GlyphCacheEntry>& aEntry) {
|
||||
mGlyphCacheEntry = aEntry;
|
||||
}
|
||||
|
||||
// Note as used if there is corresponding surface or cache entry.
|
||||
bool IsUsed() const { return mSurface || mGlyphCacheEntry; }
|
||||
|
||||
private:
|
||||
bool mValid = true;
|
||||
// If applicable, weak pointer to the SourceSurface that is linked to this
|
||||
// TextureHandle.
|
||||
SourceSurface* mSurface = nullptr;
|
||||
// If this TextureHandle stores a cached shadow, then we need to remember the
|
||||
// blur sigma used to produce the shadow.
|
||||
float mSigma = -1.0f;
|
||||
// If the originating surface requested a sampling rect, then we need to know
|
||||
// the offset of the subrect within the surface for texture coordinates.
|
||||
IntPoint mSamplingOffset;
|
||||
// If applicable, the GlyphCacheEntry that is linked to this TextureHandle.
|
||||
RefPtr<GlyphCacheEntry> mGlyphCacheEntry;
|
||||
};
|
||||
|
||||
class SharedTextureHandle;
|
||||
|
||||
// SharedTexture is a large slab texture that is subdivided (by using a
|
||||
// TexturePacker) to hold many small SharedTextureHandles. This avoids needing
|
||||
// to allocate many WebGL textures for every single small Canvas 2D texture.
|
||||
class SharedTexture : public RefCounted<SharedTexture> {
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(SharedTexture)
|
||||
|
||||
SharedTexture(const IntSize& aSize, SurfaceFormat aFormat,
|
||||
const RefPtr<WebGLTextureJS>& aTexture);
|
||||
|
||||
already_AddRefed<SharedTextureHandle> Allocate(const IntSize& aSize);
|
||||
bool Free(const SharedTextureHandle& aHandle);
|
||||
|
||||
SurfaceFormat GetFormat() const { return mFormat; }
|
||||
IntSize GetSize() const { return mPacker.GetBounds().Size(); }
|
||||
|
||||
size_t UsedBytes() const {
|
||||
return TextureHandle::UsedBytes(GetFormat(), GetSize());
|
||||
}
|
||||
|
||||
bool HasAllocatedHandles() const { return mAllocatedHandles > 0; }
|
||||
|
||||
const RefPtr<WebGLTextureJS>& GetWebGLTexture() const { return mTexture; }
|
||||
|
||||
private:
|
||||
TexturePacker mPacker;
|
||||
SurfaceFormat mFormat;
|
||||
RefPtr<WebGLTextureJS> mTexture;
|
||||
size_t mAllocatedHandles = 0;
|
||||
};
|
||||
|
||||
// SharedTextureHandle is an allocated region within a large SharedTexture page
|
||||
// that owns it.
|
||||
class SharedTextureHandle : public TextureHandle {
|
||||
friend class SharedTexture;
|
||||
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SharedTextureHandle, override)
|
||||
|
||||
SharedTextureHandle(const IntRect& aBounds, SharedTexture* aTexture);
|
||||
|
||||
Type GetType() const override { return Type::SHARED; }
|
||||
|
||||
const RefPtr<WebGLTextureJS>& GetWebGLTexture() const override {
|
||||
return mTexture->GetWebGLTexture();
|
||||
}
|
||||
|
||||
IntRect GetBounds() const override { return mBounds; }
|
||||
IntSize GetBackingSize() const override { return mTexture->GetSize(); }
|
||||
|
||||
SurfaceFormat GetFormat() const override { return mTexture->GetFormat(); }
|
||||
|
||||
size_t UsedBytes() const override {
|
||||
return TextureHandle::UsedBytes(GetFormat(), mBounds.Size());
|
||||
}
|
||||
|
||||
void Cleanup(DrawTargetWebgl& aDT) override;
|
||||
|
||||
const RefPtr<SharedTexture>& GetOwner() const { return mTexture; }
|
||||
|
||||
private:
|
||||
IntRect mBounds;
|
||||
RefPtr<SharedTexture> mTexture;
|
||||
};
|
||||
|
||||
// StandaloneTexture is a texture that can not be effectively shared within
|
||||
// a SharedTexture page, such that it is better to assign it its own WebGL
|
||||
// texture.
|
||||
class StandaloneTexture : public TextureHandle {
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(StandaloneTexture, override)
|
||||
|
||||
StandaloneTexture(const IntSize& aSize, SurfaceFormat aFormat,
|
||||
const RefPtr<WebGLTextureJS>& aTexture);
|
||||
|
||||
Type GetType() const override { return Type::STANDALONE; }
|
||||
|
||||
SurfaceFormat GetFormat() const override { return mFormat; }
|
||||
|
||||
const RefPtr<WebGLTextureJS>& GetWebGLTexture() const override {
|
||||
return mTexture;
|
||||
}
|
||||
|
||||
IntRect GetBounds() const override { return IntRect(IntPoint(0, 0), mSize); }
|
||||
IntSize GetBackingSize() const override { return mSize; }
|
||||
|
||||
size_t UsedBytes() const override {
|
||||
return TextureHandle::UsedBytes(mFormat, mSize);
|
||||
}
|
||||
|
||||
void UpdateSize(const IntSize& aSize) override { mSize = aSize; }
|
||||
|
||||
void Cleanup(DrawTargetWebgl& aDT) override;
|
||||
|
||||
private:
|
||||
IntSize mSize;
|
||||
SurfaceFormat mFormat;
|
||||
RefPtr<WebGLTextureJS> mTexture;
|
||||
};
|
||||
|
||||
// GlyphCacheEntry stores rendering metadata for a rendered text run, as well
|
||||
// the handle to the texture it was rendered into, so that it can be located
|
||||
// for reuse under similar rendering circumstances.
|
||||
class GlyphCacheEntry : public RefCounted<GlyphCacheEntry>,
|
||||
public LinkedListElement<RefPtr<GlyphCacheEntry>> {
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(GlyphCacheEntry)
|
||||
|
||||
GlyphCacheEntry(const GlyphBuffer& aBuffer, const DeviceColor& aColor,
|
||||
const Matrix& aTransform, const IntRect& aBounds,
|
||||
HashNumber aHash = 0);
|
||||
|
||||
bool MatchesGlyphs(const GlyphBuffer& aBuffer, const DeviceColor& aColor,
|
||||
const Matrix& aTransform, const IntRect& aBounds,
|
||||
HashNumber aHash);
|
||||
|
||||
static HashNumber HashGlyphs(const GlyphBuffer& aBuffer,
|
||||
const Matrix& aTransform);
|
||||
|
||||
void Link(const RefPtr<TextureHandle>& aHandle);
|
||||
void Unlink();
|
||||
|
||||
const RefPtr<TextureHandle>& GetHandle() const { return mHandle; }
|
||||
|
||||
private:
|
||||
// The handle of the rendered text run.
|
||||
RefPtr<TextureHandle> mHandle;
|
||||
// The glyph keys used to render the text run.
|
||||
GlyphBuffer mBuffer = {nullptr, 0};
|
||||
// The color of the text run.
|
||||
DeviceColor mColor;
|
||||
// The transform that was used to render the text run. This is necessary as
|
||||
// subpixel anti-aliasing is only correctly rendered in device space after
|
||||
// the transform is applied, so in general we can't cache untransformed text
|
||||
// runs.
|
||||
Matrix mTransform;
|
||||
// The device space bounds of the rendered text run.
|
||||
IntRect mBounds;
|
||||
// A hash of the glyph keys that may be used for quickly rejecting entries.
|
||||
HashNumber mHash;
|
||||
};
|
||||
|
||||
// GlyphCache maintains a list of GlyphCacheEntry's representing previously
|
||||
// rendered text runs. The cache is searched to see if a given incoming text
|
||||
// run has already been rendered to a texture, and if so, just reuses it.
|
||||
// Otherwise, the text run will be rendered to a new texture handle and
|
||||
// inserted into a new GlyphCacheEntry to represent it.
|
||||
class GlyphCache : public LinkedListElement<GlyphCache> {
|
||||
public:
|
||||
explicit GlyphCache(ScaledFont* aFont);
|
||||
~GlyphCache();
|
||||
|
||||
ScaledFont* GetFont() const { return mFont; }
|
||||
|
||||
already_AddRefed<GlyphCacheEntry> FindOrInsertEntry(
|
||||
const GlyphBuffer& aBuffer, const DeviceColor& aColor,
|
||||
const Matrix& aTransform, const IntRect& aBounds, HashNumber aHash = 0);
|
||||
|
||||
private:
|
||||
// Weak pointer to the owning font
|
||||
ScaledFont* mFont;
|
||||
LinkedList<RefPtr<GlyphCacheEntry>> mEntries;
|
||||
};
|
||||
|
||||
} // namespace mozilla::gfx
|
||||
|
||||
#endif // _MOZILLA_GFX_DRAWTARGETWEBGL_INTERNAL_H
|
||||
@@ -71,6 +71,10 @@ EXPORTS.mozilla.dom += [
|
||||
]
|
||||
# XRWebGLLayer.h must be exported for use by the generated WebXRBinding.h
|
||||
|
||||
EXPORTS.mozilla.gfx += [
|
||||
"DrawTargetWebgl.h",
|
||||
]
|
||||
|
||||
# Canvas 2D and common sources
|
||||
UNIFIED_SOURCES += [
|
||||
"CanvasGradient.cpp",
|
||||
@@ -88,6 +92,7 @@ UNIFIED_SOURCES += [
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
"DrawTargetWebgl.cpp", # Isolate Skia
|
||||
"ImageUtils.cpp",
|
||||
]
|
||||
|
||||
|
||||
@@ -1281,6 +1281,67 @@ void DrawTargetSkia::DrawGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<Rect> DrawTargetSkia::GetGlyphLocalBounds(
|
||||
ScaledFont* aFont, const GlyphBuffer& aBuffer, const Pattern& aPattern,
|
||||
const StrokeOptions* aStrokeOptions, const DrawOptions& aOptions) {
|
||||
if (!CanDrawFont(aFont)) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
ScaledFontBase* skiaFont = static_cast<ScaledFontBase*>(aFont);
|
||||
SkTypeface* typeface = skiaFont->GetSkTypeface();
|
||||
if (!typeface) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
AutoPaintSetup paint(mCanvas, aOptions, aPattern);
|
||||
if (aStrokeOptions && !StrokeOptionsToPaint(paint.mPaint, *aStrokeOptions)) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
AntialiasMode aaMode = aFont->GetDefaultAAMode();
|
||||
if (aOptions.mAntialiasMode != AntialiasMode::DEFAULT) {
|
||||
aaMode = aOptions.mAntialiasMode;
|
||||
}
|
||||
bool aaEnabled = aaMode != AntialiasMode::NONE;
|
||||
paint.mPaint.setAntiAlias(aaEnabled);
|
||||
|
||||
SkFont font(sk_ref_sp(typeface), SkFloatToScalar(skiaFont->mSize));
|
||||
|
||||
bool useSubpixelAA =
|
||||
GetPermitSubpixelAA() &&
|
||||
(aaMode == AntialiasMode::DEFAULT || aaMode == AntialiasMode::SUBPIXEL);
|
||||
font.setEdging(useSubpixelAA ? SkFont::Edging::kSubpixelAntiAlias
|
||||
: (aaEnabled ? SkFont::Edging::kAntiAlias
|
||||
: SkFont::Edging::kAlias));
|
||||
|
||||
skiaFont->SetupSkFontDrawOptions(font);
|
||||
|
||||
// Limit the amount of internal batch allocations Skia does.
|
||||
const uint32_t kMaxGlyphBatchSize = 8192;
|
||||
|
||||
Rect bounds;
|
||||
for (uint32_t offset = 0; offset < aBuffer.mNumGlyphs;) {
|
||||
uint32_t batchSize =
|
||||
std::min(aBuffer.mNumGlyphs - offset, kMaxGlyphBatchSize);
|
||||
SkTextBlobBuilder builder;
|
||||
auto runBuffer = builder.allocRunPos(font, batchSize);
|
||||
for (uint32_t i = 0; i < batchSize; i++, offset++) {
|
||||
runBuffer.glyphs[i] = aBuffer.mGlyphs[offset].mIndex;
|
||||
runBuffer.points()[i] = PointToSkPoint(aBuffer.mGlyphs[offset].mPosition);
|
||||
}
|
||||
|
||||
sk_sp<SkTextBlob> text = builder.make();
|
||||
bounds = bounds.Union(SkRectToRect(text->bounds()));
|
||||
}
|
||||
|
||||
if (bounds.IsEmpty()) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
return Some(bounds);
|
||||
}
|
||||
|
||||
void DrawTargetSkia::FillGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
|
||||
const Pattern& aPattern,
|
||||
const DrawOptions& aOptions) {
|
||||
@@ -1778,6 +1839,19 @@ void DrawTargetSkia::PopClip() {
|
||||
SetTransform(GetTransform());
|
||||
}
|
||||
|
||||
Maybe<Rect> DrawTargetSkia::GetDeviceClipRect() const {
|
||||
if (mCanvas->isClipEmpty()) {
|
||||
return Some(Rect());
|
||||
}
|
||||
if (mCanvas->isClipRect()) {
|
||||
SkIRect deviceBounds;
|
||||
if (mCanvas->getDeviceClipBounds(&deviceBounds)) {
|
||||
return Some(Rect(SkIRectToIntRect(deviceBounds)));
|
||||
}
|
||||
}
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
void DrawTargetSkia::PushLayer(bool aOpaque, Float aOpacity,
|
||||
SourceSurface* aMask,
|
||||
const Matrix& aMaskTransform,
|
||||
|
||||
@@ -151,6 +151,13 @@ class DrawTargetSkia : public DrawTarget {
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
Maybe<Rect> GetDeviceClipRect() const;
|
||||
|
||||
Maybe<Rect> GetGlyphLocalBounds(ScaledFont* aFont, const GlyphBuffer& aBuffer,
|
||||
const Pattern& aPattern,
|
||||
const StrokeOptions* aStrokeOptions,
|
||||
const DrawOptions& aOptions);
|
||||
|
||||
private:
|
||||
friend class SourceSurfaceSkia;
|
||||
|
||||
|
||||
@@ -478,6 +478,7 @@ bool Factory::DoesBackendSupportDataDrawtarget(BackendType aType) {
|
||||
case BackendType::NONE:
|
||||
case BackendType::BACKEND_LAST:
|
||||
case BackendType::WEBRENDER_TEXT:
|
||||
case BackendType::WEBGL:
|
||||
return false;
|
||||
case BackendType::CAIRO:
|
||||
case BackendType::SKIA:
|
||||
|
||||
@@ -550,6 +550,7 @@ enum class BackendType : int8_t {
|
||||
RECORDING,
|
||||
DIRECT2D1_1,
|
||||
WEBRENDER_TEXT,
|
||||
WEBGL,
|
||||
|
||||
// Add new entries above this line.
|
||||
BACKEND_LAST
|
||||
@@ -569,7 +570,8 @@ enum class NativeSurfaceType : int8_t {
|
||||
CAIRO_CONTEXT,
|
||||
CGCONTEXT,
|
||||
CGCONTEXT_ACCELERATED,
|
||||
OPENGL_TEXTURE
|
||||
OPENGL_TEXTURE,
|
||||
WEBGL_CONTEXT
|
||||
};
|
||||
|
||||
enum class FontStyle : int8_t { NORMAL, ITALIC, BOLD, BOLD_ITALIC };
|
||||
|
||||
@@ -26,6 +26,7 @@ EXPORTS.mozilla.gfx += [
|
||||
"DrawEventRecorder.h",
|
||||
"DrawTargetOffset.h",
|
||||
"DrawTargetRecording.h",
|
||||
"DrawTargetSkia.h",
|
||||
"Filters.h",
|
||||
"FontVariation.h",
|
||||
"Helpers.h",
|
||||
@@ -38,6 +39,7 @@ EXPORTS.mozilla.gfx += [
|
||||
"MatrixFwd.h",
|
||||
"NumericTools.h",
|
||||
"PathHelpers.h",
|
||||
"PathSkia.h",
|
||||
"PatternHelpers.h",
|
||||
"Point.h",
|
||||
"Polygon.h",
|
||||
|
||||
@@ -96,6 +96,21 @@ PersistentBufferProviderBasic::Create(gfx::IntSize aSize,
|
||||
return provider.forget();
|
||||
}
|
||||
|
||||
PersistentBufferProviderAccelerated::PersistentBufferProviderAccelerated(
|
||||
DrawTarget* aDt)
|
||||
: PersistentBufferProviderBasic(aDt) {
|
||||
MOZ_COUNT_CTOR(PersistentBufferProviderAccelerated);
|
||||
}
|
||||
|
||||
PersistentBufferProviderAccelerated::~PersistentBufferProviderAccelerated() {
|
||||
MOZ_COUNT_DTOR(PersistentBufferProviderAccelerated);
|
||||
}
|
||||
|
||||
ClientWebGLContext* PersistentBufferProviderAccelerated::AsWebgl() {
|
||||
return (ClientWebGLContext*)mDrawTarget->GetNativeSurface(
|
||||
NativeSurfaceType::WEBGL_CONTEXT);
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<PersistentBufferProviderShared>
|
||||
PersistentBufferProviderShared::Create(gfx::IntSize aSize,
|
||||
@@ -184,15 +199,6 @@ PersistentBufferProviderShared::~PersistentBufferProviderShared() {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
LayersBackend PersistentBufferProviderShared::GetType() {
|
||||
if (mKnowsCompositor->GetCompositorBackendType() ==
|
||||
LayersBackend::LAYERS_WR) {
|
||||
return LayersBackend::LAYERS_WR;
|
||||
} else {
|
||||
return LayersBackend::LAYERS_CLIENT;
|
||||
}
|
||||
}
|
||||
|
||||
bool PersistentBufferProviderShared::SetKnowsCompositor(
|
||||
KnowsCompositor* aKnowsCompositor) {
|
||||
MOZ_ASSERT(aKnowsCompositor);
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ClientWebGLContext;
|
||||
|
||||
namespace gfx {
|
||||
class SourceSurface;
|
||||
class DrawTarget;
|
||||
@@ -41,7 +43,8 @@ class PersistentBufferProvider : public RefCounted<PersistentBufferProvider>,
|
||||
|
||||
virtual ~PersistentBufferProvider() = default;
|
||||
|
||||
virtual LayersBackend GetType() { return LayersBackend::LAYERS_NONE; }
|
||||
virtual bool IsShared() const { return false; }
|
||||
virtual bool IsAccelerated() const { return false; }
|
||||
|
||||
/**
|
||||
* Get a DrawTarget from the PersistentBufferProvider.
|
||||
@@ -67,6 +70,8 @@ class PersistentBufferProvider : public RefCounted<PersistentBufferProvider>,
|
||||
|
||||
virtual TextureClient* GetTextureClient() { return nullptr; }
|
||||
|
||||
virtual ClientWebGLContext* AsWebgl() { return nullptr; }
|
||||
|
||||
virtual void OnShutdown() {}
|
||||
|
||||
virtual bool SetKnowsCompositor(KnowsCompositor* aKnowsCompositor) {
|
||||
@@ -96,8 +101,6 @@ class PersistentBufferProviderBasic : public PersistentBufferProvider {
|
||||
|
||||
explicit PersistentBufferProviderBasic(gfx::DrawTarget* aTarget);
|
||||
|
||||
LayersBackend GetType() override { return LayersBackend::LAYERS_BASIC; }
|
||||
|
||||
already_AddRefed<gfx::DrawTarget> BorrowDrawTarget(
|
||||
const gfx::IntRect& aPersistedRect) override;
|
||||
|
||||
@@ -114,13 +117,28 @@ class PersistentBufferProviderBasic : public PersistentBufferProvider {
|
||||
protected:
|
||||
void Destroy();
|
||||
|
||||
private:
|
||||
virtual ~PersistentBufferProviderBasic();
|
||||
~PersistentBufferProviderBasic() override;
|
||||
|
||||
RefPtr<gfx::DrawTarget> mDrawTarget;
|
||||
RefPtr<gfx::SourceSurface> mSnapshot;
|
||||
};
|
||||
|
||||
class PersistentBufferProviderAccelerated
|
||||
: public PersistentBufferProviderBasic {
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PersistentBufferProviderAccelerated,
|
||||
override)
|
||||
|
||||
explicit PersistentBufferProviderAccelerated(gfx::DrawTarget* aTarget);
|
||||
|
||||
bool IsAccelerated() const override { return true; }
|
||||
|
||||
ClientWebGLContext* AsWebgl() override;
|
||||
|
||||
protected:
|
||||
~PersistentBufferProviderAccelerated() override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides access to a buffer which can be sent to the compositor without
|
||||
* requiring a copy.
|
||||
@@ -135,7 +153,7 @@ class PersistentBufferProviderShared : public PersistentBufferProvider,
|
||||
gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
KnowsCompositor* aKnowsCompositor);
|
||||
|
||||
LayersBackend GetType() override;
|
||||
bool IsShared() const override { return true; }
|
||||
|
||||
already_AddRefed<gfx::DrawTarget> BorrowDrawTarget(
|
||||
const gfx::IntRect& aPersistedRect) override;
|
||||
|
||||
@@ -134,6 +134,11 @@ void ShareableCanvasRenderer::UpdateCompositableClient() {
|
||||
// -
|
||||
|
||||
const auto fnGetExistingTc = [&]() -> RefPtr<TextureClient> {
|
||||
if (webgl) {
|
||||
const auto desc = webgl->GetFrontBuffer(nullptr);
|
||||
if (!desc) return nullptr;
|
||||
return GetFrontBufferFromDesc(*desc, flags);
|
||||
}
|
||||
if (provider) {
|
||||
if (!provider->SetKnowsCompositor(forwarder)) {
|
||||
gfxCriticalNote << "BufferProvider::SetForwarder failed";
|
||||
@@ -142,12 +147,7 @@ void ShareableCanvasRenderer::UpdateCompositableClient() {
|
||||
|
||||
return provider->GetTextureClient();
|
||||
}
|
||||
|
||||
if (!webgl) return nullptr;
|
||||
|
||||
const auto desc = webgl->GetFrontBuffer(nullptr);
|
||||
if (!desc) return nullptr;
|
||||
return GetFrontBufferFromDesc(*desc, flags);
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
@@ -873,7 +873,7 @@ void gfxPlatform::Init() {
|
||||
// Prefs that don't fit into any of the other sections
|
||||
forcedPrefs.AppendPrintf("-T%d%d%d) ",
|
||||
StaticPrefs::gfx_android_rgb16_force_AtStartup(),
|
||||
0, // SkiaGL canvas no longer supported
|
||||
StaticPrefs::gfx_canvas_accelerated(),
|
||||
StaticPrefs::layers_force_shmem_tiles_AtStartup());
|
||||
ScopedGfxFeatureReporter::AppNote(forcedPrefs);
|
||||
}
|
||||
|
||||
@@ -138,6 +138,8 @@ inline const char* GetBackendName(mozilla::gfx::BackendType aBackend) {
|
||||
return "webrender text";
|
||||
case mozilla::gfx::BackendType::NONE:
|
||||
return "none";
|
||||
case mozilla::gfx::BackendType::WEBGL:
|
||||
return "webgl";
|
||||
case mozilla::gfx::BackendType::BACKEND_LAST:
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ void swgl_drawSpanR8() {
|
||||
float scale = -dot(local_step, (normal)); \
|
||||
if (scale >= 0.0) { \
|
||||
if (dist > opaque_start * scale) { \
|
||||
start_corner = info; \
|
||||
SET_CORNER(start_corner, info); \
|
||||
start_plane = vec4(offset, normal); \
|
||||
float inv_scale = recip(max(scale, 1.0e-6)); \
|
||||
opaque_start = dist * inv_scale; \
|
||||
@@ -327,7 +327,7 @@ void swgl_drawSpanR8() {
|
||||
aa_start = opaque_start - apex * inv_scale; \
|
||||
} \
|
||||
} else if (dist > opaque_end * scale) { \
|
||||
end_corner = info; \
|
||||
SET_CORNER(end_corner, info); \
|
||||
end_plane = vec4(offset, normal); \
|
||||
float inv_scale = recip(min(scale, -1.0e-6)); \
|
||||
opaque_end = dist * inv_scale; \
|
||||
@@ -353,14 +353,13 @@ void swgl_drawSpanR8() {
|
||||
vec2 n_br = vClipParams.zz;
|
||||
vec2 n_bl = vec2(-vClipParams.z, vClipParams.z);
|
||||
|
||||
bool start_corner = false;
|
||||
bool end_corner = false;
|
||||
#define SET_CORNER(corner, info)
|
||||
|
||||
// Clip against the corner half-spaces.
|
||||
CLIP_CORNER(corner_tl, n_tl, true);
|
||||
CLIP_CORNER(corner_tr, n_tr, true);
|
||||
CLIP_CORNER(corner_br, n_br, true);
|
||||
CLIP_CORNER(corner_bl, n_bl, true);
|
||||
CLIP_CORNER(corner_tl, n_tl, );
|
||||
CLIP_CORNER(corner_tr, n_tr, );
|
||||
CLIP_CORNER(corner_br, n_br, );
|
||||
CLIP_CORNER(corner_bl, n_bl, );
|
||||
|
||||
// Later we need to calculate distance AA for both corners and the
|
||||
// outer bounding rect. For the fast-path, this is all done inside
|
||||
@@ -376,6 +375,8 @@ void swgl_drawSpanR8() {
|
||||
vec4 start_corner = vec4(vec2(1.0e6), vec2(1.0));
|
||||
vec4 end_corner = vec4(vec2(1.0e6), vec2(1.0));
|
||||
|
||||
#define SET_CORNER(corner, info) corner = info
|
||||
|
||||
// Clip against the corner half-spaces. We have already computed the
|
||||
// corner half-spaces in the vertex shader.
|
||||
CLIP_CORNER(vClipCorner_TL.xy, vClipCorner_TL.zw, vClipCenter_Radius_TL);
|
||||
|
||||
@@ -4839,6 +4839,41 @@
|
||||
value: 0
|
||||
mirror: once
|
||||
|
||||
- name: gfx.canvas.accelerated
|
||||
type: RelaxedAtomicBool
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
- name: gfx.canvas.accelerated.cache-items
|
||||
type: RelaxedAtomicUint32
|
||||
value: 1024
|
||||
mirror: always
|
||||
|
||||
- name: gfx.canvas.accelerated.cache-size
|
||||
type: RelaxedAtomicUint32
|
||||
value: 128
|
||||
mirror: always
|
||||
|
||||
- name: gfx.canvas.accelerated.max-size
|
||||
type: RelaxedAtomicInt32
|
||||
value: 0
|
||||
mirror: always
|
||||
|
||||
- name: gfx.canvas.accelerated.min-size
|
||||
type: RelaxedAtomicInt32
|
||||
value: 128
|
||||
mirror: always
|
||||
|
||||
- name: gfx.canvas.accelerated.max-surface-size
|
||||
type: RelaxedAtomicUint32
|
||||
value: 5280
|
||||
mirror: always
|
||||
|
||||
- name: gfx.canvas.accelerated.shared-page-size
|
||||
type: RelaxedAtomicUint32
|
||||
value: 1024
|
||||
mirror: always
|
||||
|
||||
# 0x7fff is the maximum supported xlib surface size and is more than enough for canvases.
|
||||
- name: gfx.canvas.max-size
|
||||
type: RelaxedAtomicInt32
|
||||
|
||||
Reference in New Issue
Block a user