mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1857447 - Avoid redundant UniformData calls in DrawTargetWebgl. r=lsalzman
Calling ClientWebGLContext::UniformData() many times causes the command buffer to fill up and we spend a fair amount of time flushing the old buffer and allocating a new one, as well as serializing the values. The uniforms themselves are very small but they add up over a large number of calls. We already have some code to track whether the uniform values are dirty to avoid some redundancy, but a) this doesn't cover every uniform, and b) we invalidate them all when switching program. This patch makes us track the value of every uniform that gets set dynamically, and tracks the values separately for each program used. It then uses these to avoid calling UniformData redundantly. Differential Revision: https://phabricator.services.mozilla.com/D190269
This commit is contained in:
parent
9b40b3e022
commit
836b0d935c
@ -490,7 +490,6 @@ void DrawTargetWebgl::SharedContext::SetBlendState(
|
||||
// alpha that is blended separately from AA coverage. This would require two
|
||||
// stage blending which can incur a substantial performance penalty, so to
|
||||
// work around this currently we just disable AA for those ops.
|
||||
mDirtyAA = true;
|
||||
|
||||
// Map the composition op to a WebGL blend mode, if possible.
|
||||
bool enabled = true;
|
||||
@ -556,8 +555,6 @@ bool DrawTargetWebgl::SharedContext::SetTarget(DrawTargetWebgl* aDT) {
|
||||
mWebgl->BindFramebuffer(LOCAL_GL_FRAMEBUFFER, aDT->mFramebuffer);
|
||||
mViewportSize = aDT->GetSize();
|
||||
mWebgl->Viewport(0, 0, mViewportSize.width, mViewportSize.height);
|
||||
// Force the viewport to be reset.
|
||||
mDirtyViewport = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -570,8 +567,6 @@ void DrawTargetWebgl::SharedContext::SetClipRect(const Rect& aClipRect) {
|
||||
mClipAARect = aClipRect;
|
||||
// Store the integer-aligned bounds.
|
||||
mClipRect = RoundedOut(aClipRect);
|
||||
// Notify the shader uniform it needs to update.
|
||||
mDirtyClip = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2018,6 +2013,19 @@ static inline Maybe<IntRect> IsAlignedRect(bool aTransformed,
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
template <class T, size_t N>
|
||||
void DrawTargetWebgl::SharedContext::MaybeUniformData(
|
||||
GLenum aFuncElemType, const WebGLUniformLocationJS* const aLoc,
|
||||
const Array<T, N>& aData, Maybe<Array<T, N>>& aCached) {
|
||||
if (aCached.isNothing() || !(*aCached == aData)) {
|
||||
aCached = Some(aData);
|
||||
Span<const uint8_t> bytes = AsBytes(Span(aData));
|
||||
// We currently always pass false for transpose. If in the future we need
|
||||
// support for transpose then caching needs to take that in to account.
|
||||
mWebgl->UniformData(aFuncElemType, aLoc, false, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// Common rectangle and pattern drawing function shared by many DrawTarget
|
||||
// commands. If aMaskColor is specified, the provided surface pattern will be
|
||||
// treated as a mask. If aHandle is specified, then the surface pattern's
|
||||
@ -2145,47 +2153,38 @@ bool DrawTargetWebgl::SharedContext::DrawRectAccel(
|
||||
if (mLastProgram != mSolidProgram) {
|
||||
mWebgl->UseProgram(mSolidProgram);
|
||||
mLastProgram = mSolidProgram;
|
||||
// Ensure uniform state is current.
|
||||
mDirtyViewport = true;
|
||||
mDirtyAA = true;
|
||||
mDirtyClip = true;
|
||||
}
|
||||
if (mDirtyViewport) {
|
||||
float viewportData[2] = {float(mViewportSize.width),
|
||||
float(mViewportSize.height)};
|
||||
mWebgl->UniformData(
|
||||
LOCAL_GL_FLOAT_VEC2, mSolidProgramViewport, false,
|
||||
{(const uint8_t*)viewportData, sizeof(viewportData)});
|
||||
mDirtyViewport = false;
|
||||
}
|
||||
if (mDirtyAA || aVertexRange) {
|
||||
// Generated paths provide their own AA as vertex alpha.
|
||||
float aaData = aVertexRange ? 0.0f : 1.0f;
|
||||
mWebgl->UniformData(LOCAL_GL_FLOAT, mSolidProgramAA, false,
|
||||
{(const uint8_t*)&aaData, sizeof(aaData)});
|
||||
mDirtyAA = aaData == 0.0f;
|
||||
}
|
||||
if (mDirtyClip) {
|
||||
// Offset the clip AA bounds by 0.5 to ensure AA falls to 0 at pixel
|
||||
// boundary.
|
||||
float clipData[4] = {mClipAARect.x - 0.5f, mClipAARect.y - 0.5f,
|
||||
mClipAARect.XMost() + 0.5f,
|
||||
mClipAARect.YMost() + 0.5f};
|
||||
mWebgl->UniformData(LOCAL_GL_FLOAT_VEC4, mSolidProgramClipBounds, false,
|
||||
{(const uint8_t*)clipData, sizeof(clipData)});
|
||||
mDirtyClip = false;
|
||||
}
|
||||
float colorData[4] = {color.b, color.g, color.r, color.a};
|
||||
Array<float, 2> viewportData = {float(mViewportSize.width),
|
||||
float(mViewportSize.height)};
|
||||
MaybeUniformData(LOCAL_GL_FLOAT_VEC2, mSolidProgramViewport, viewportData,
|
||||
mSolidProgramUniformState.mViewport);
|
||||
|
||||
// Generated paths provide their own AA as vertex alpha.
|
||||
Array<float, 1> aaData = {aVertexRange ? 0.0f : 1.0f};
|
||||
MaybeUniformData(LOCAL_GL_FLOAT, mSolidProgramAA, aaData,
|
||||
mSolidProgramUniformState.mAA);
|
||||
|
||||
// Offset the clip AA bounds by 0.5 to ensure AA falls to 0 at pixel
|
||||
// boundary.
|
||||
Array<float, 4> clipData = {mClipAARect.x - 0.5f, mClipAARect.y - 0.5f,
|
||||
mClipAARect.XMost() + 0.5f,
|
||||
mClipAARect.YMost() + 0.5f};
|
||||
MaybeUniformData(LOCAL_GL_FLOAT_VEC4, mSolidProgramClipBounds, clipData,
|
||||
mSolidProgramUniformState.mClipBounds);
|
||||
|
||||
Array<float, 4> colorData = {color.b, color.g, color.r, color.a};
|
||||
Matrix xform(aRect.width, 0.0f, 0.0f, aRect.height, aRect.x, aRect.y);
|
||||
if (aTransformed) {
|
||||
xform *= currentTransform;
|
||||
}
|
||||
float xformData[6] = {xform._11, xform._12, xform._21,
|
||||
xform._22, xform._31, xform._32};
|
||||
mWebgl->UniformData(LOCAL_GL_FLOAT_VEC2, mSolidProgramTransform, false,
|
||||
{(const uint8_t*)xformData, sizeof(xformData)});
|
||||
mWebgl->UniformData(LOCAL_GL_FLOAT_VEC4, mSolidProgramColor, false,
|
||||
{(const uint8_t*)colorData, sizeof(colorData)});
|
||||
Array<float, 6> xformData = {xform._11, xform._12, xform._21,
|
||||
xform._22, xform._31, xform._32};
|
||||
MaybeUniformData(LOCAL_GL_FLOAT_VEC2, mSolidProgramTransform, xformData,
|
||||
mSolidProgramUniformState.mTransform);
|
||||
|
||||
MaybeUniformData(LOCAL_GL_FLOAT_VEC4, mSolidProgramColor, colorData,
|
||||
mSolidProgramUniformState.mColor);
|
||||
|
||||
// Finally draw the colored rectangle.
|
||||
if (aVertexRange) {
|
||||
// If there's a vertex range, then we need to draw triangles within from
|
||||
@ -2309,41 +2308,30 @@ bool DrawTargetWebgl::SharedContext::DrawRectAccel(
|
||||
if (mLastProgram != mImageProgram) {
|
||||
mWebgl->UseProgram(mImageProgram);
|
||||
mLastProgram = mImageProgram;
|
||||
// Ensure uniform state is current.
|
||||
mDirtyViewport = true;
|
||||
mDirtyAA = true;
|
||||
mDirtyClip = true;
|
||||
}
|
||||
if (mDirtyViewport) {
|
||||
float viewportData[2] = {float(mViewportSize.width),
|
||||
float(mViewportSize.height)};
|
||||
mWebgl->UniformData(
|
||||
LOCAL_GL_FLOAT_VEC2, mImageProgramViewport, false,
|
||||
{(const uint8_t*)viewportData, sizeof(viewportData)});
|
||||
mDirtyViewport = false;
|
||||
}
|
||||
if (mDirtyAA || aVertexRange) {
|
||||
// AA is not supported for OP_SOURCE. Generated paths provide their own
|
||||
// AA as vertex alpha.
|
||||
|
||||
float aaData =
|
||||
mLastCompositionOp == CompositionOp::OP_SOURCE || aVertexRange
|
||||
? 0.0f
|
||||
: 1.0f;
|
||||
mWebgl->UniformData(LOCAL_GL_FLOAT, mImageProgramAA, false,
|
||||
{(const uint8_t*)&aaData, sizeof(aaData)});
|
||||
mDirtyAA = aaData == 0.0f;
|
||||
}
|
||||
if (mDirtyClip) {
|
||||
// Offset the clip AA bounds by 0.5 to ensure AA falls to 0 at pixel
|
||||
// boundary.
|
||||
float clipData[4] = {mClipAARect.x - 0.5f, mClipAARect.y - 0.5f,
|
||||
mClipAARect.XMost() + 0.5f,
|
||||
mClipAARect.YMost() + 0.5f};
|
||||
mWebgl->UniformData(LOCAL_GL_FLOAT_VEC4, mImageProgramClipBounds, false,
|
||||
{(const uint8_t*)clipData, sizeof(clipData)});
|
||||
mDirtyClip = false;
|
||||
}
|
||||
Array<float, 2> viewportData = {float(mViewportSize.width),
|
||||
float(mViewportSize.height)};
|
||||
MaybeUniformData(LOCAL_GL_FLOAT_VEC2, mImageProgramViewport, viewportData,
|
||||
mImageProgramUniformState.mViewport);
|
||||
|
||||
// AA is not supported for OP_SOURCE. Generated paths provide their own
|
||||
// AA as vertex alpha.
|
||||
Array<float, 1> aaData = {
|
||||
mLastCompositionOp == CompositionOp::OP_SOURCE || aVertexRange
|
||||
? 0.0f
|
||||
: 1.0f};
|
||||
MaybeUniformData(LOCAL_GL_FLOAT, mImageProgramAA, aaData,
|
||||
mImageProgramUniformState.mAA);
|
||||
|
||||
// Offset the clip AA bounds by 0.5 to ensure AA falls to 0 at pixel
|
||||
// boundary.
|
||||
Array<float, 4> clipData = {mClipAARect.x - 0.5f, mClipAARect.y - 0.5f,
|
||||
mClipAARect.XMost() + 0.5f,
|
||||
mClipAARect.YMost() + 0.5f};
|
||||
MaybeUniformData(LOCAL_GL_FLOAT_VEC4, mImageProgramClipBounds, clipData,
|
||||
mImageProgramUniformState.mClipBounds);
|
||||
|
||||
DeviceColor color =
|
||||
mLastCompositionOp == CompositionOp::OP_CLEAR
|
||||
? DeviceColor(1, 1, 1, 1)
|
||||
@ -2352,20 +2340,22 @@ bool DrawTargetWebgl::SharedContext::DrawRectAccel(
|
||||
? DeviceColor::Mask(1.0f, aMaskColor->a)
|
||||
: aMaskColor.valueOr(DeviceColor(1, 1, 1, 1)),
|
||||
aOptions.mAlpha);
|
||||
float colorData[4] = {color.b, color.g, color.r, color.a};
|
||||
float swizzleData = format == SurfaceFormat::A8 ? 1.0f : 0.0f;
|
||||
Array<float, 4> colorData = {color.b, color.g, color.r, color.a};
|
||||
Array<float, 1> swizzleData = {format == SurfaceFormat::A8 ? 1.0f : 0.0f};
|
||||
Matrix xform(aRect.width, 0.0f, 0.0f, aRect.height, aRect.x, aRect.y);
|
||||
if (aTransformed) {
|
||||
xform *= currentTransform;
|
||||
}
|
||||
float xformData[6] = {xform._11, xform._12, xform._21,
|
||||
xform._22, xform._31, xform._32};
|
||||
mWebgl->UniformData(LOCAL_GL_FLOAT_VEC2, mImageProgramTransform, false,
|
||||
{(const uint8_t*)xformData, sizeof(xformData)});
|
||||
mWebgl->UniformData(LOCAL_GL_FLOAT_VEC4, mImageProgramColor, false,
|
||||
{(const uint8_t*)colorData, sizeof(colorData)});
|
||||
mWebgl->UniformData(LOCAL_GL_FLOAT, mImageProgramSwizzle, false,
|
||||
{(const uint8_t*)&swizzleData, sizeof(swizzleData)});
|
||||
Array<float, 6> xformData = {xform._11, xform._12, xform._21,
|
||||
xform._22, xform._31, xform._32};
|
||||
MaybeUniformData(LOCAL_GL_FLOAT_VEC2, mImageProgramTransform, xformData,
|
||||
mImageProgramUniformState.mTransform);
|
||||
|
||||
MaybeUniformData(LOCAL_GL_FLOAT_VEC4, mImageProgramColor, colorData,
|
||||
mImageProgramUniformState.mColor);
|
||||
|
||||
MaybeUniformData(LOCAL_GL_FLOAT, mImageProgramSwizzle, swizzleData,
|
||||
mImageProgramUniformState.mSwizzle);
|
||||
|
||||
// Start binding the WebGL state for the texture.
|
||||
BackingTexture* backing = nullptr;
|
||||
@ -2415,20 +2405,20 @@ bool DrawTargetWebgl::SharedContext::DrawRectAccel(
|
||||
1.0f / backingSizeF.height,
|
||||
float(bounds.x - offset.x) / backingSizeF.width,
|
||||
float(bounds.y - offset.y) / backingSizeF.height);
|
||||
float uvData[6] = {uvMatrix._11, uvMatrix._12, uvMatrix._21,
|
||||
uvMatrix._22, uvMatrix._31, uvMatrix._32};
|
||||
mWebgl->UniformData(LOCAL_GL_FLOAT_VEC2, mImageProgramTexMatrix, false,
|
||||
{(const uint8_t*)uvData, sizeof(uvData)});
|
||||
Array<float, 6> uvData = {uvMatrix._11, uvMatrix._12, uvMatrix._21,
|
||||
uvMatrix._22, uvMatrix._31, uvMatrix._32};
|
||||
MaybeUniformData(LOCAL_GL_FLOAT_VEC2, mImageProgramTexMatrix, uvData,
|
||||
mImageProgramUniformState.mTexMatrix);
|
||||
|
||||
// Clamp sampling to within the bounds of the backing texture subrect.
|
||||
float texBounds[4] = {
|
||||
Array<float, 4> texBounds = {
|
||||
(bounds.x + 0.5f) / backingSizeF.width,
|
||||
(bounds.y + 0.5f) / backingSizeF.height,
|
||||
(bounds.XMost() - 0.5f) / backingSizeF.width,
|
||||
(bounds.YMost() - 0.5f) / backingSizeF.height,
|
||||
};
|
||||
mWebgl->UniformData(LOCAL_GL_FLOAT_VEC4, mImageProgramTexBounds, false,
|
||||
{(const uint8_t*)texBounds, sizeof(texBounds)});
|
||||
MaybeUniformData(LOCAL_GL_FLOAT_VEC4, mImageProgramTexBounds, texBounds,
|
||||
mImageProgramUniformState.mTexBounds);
|
||||
|
||||
// Ensure we use nearest filtering when no antialiasing is requested.
|
||||
if (UseNearestFilter(surfacePattern)) {
|
||||
@ -3109,22 +3099,23 @@ already_AddRefed<TextureHandle> DrawTargetWebgl::SharedContext::DrawStrokeMask(
|
||||
mWebgl->UseProgram(mSolidProgram);
|
||||
mLastProgram = mSolidProgram;
|
||||
}
|
||||
float viewportData[2] = {float(texBounds.width), float(texBounds.height)};
|
||||
mWebgl->UniformData(LOCAL_GL_FLOAT_VEC2, mSolidProgramViewport, false,
|
||||
{(const uint8_t*)viewportData, sizeof(viewportData)});
|
||||
float aaData = 0.0f;
|
||||
mWebgl->UniformData(LOCAL_GL_FLOAT, mSolidProgramAA, false,
|
||||
{(const uint8_t*)&aaData, sizeof(aaData)});
|
||||
float clipData[4] = {-0.5f, -0.5f, float(texBounds.width) + 0.5f,
|
||||
float(texBounds.height) + 0.5f};
|
||||
mWebgl->UniformData(LOCAL_GL_FLOAT_VEC4, mSolidProgramClipBounds, false,
|
||||
{(const uint8_t*)clipData, sizeof(clipData)});
|
||||
float colorData[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
mWebgl->UniformData(LOCAL_GL_FLOAT_VEC4, mSolidProgramColor, false,
|
||||
{(const uint8_t*)colorData, sizeof(colorData)});
|
||||
float xformData[6] = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f};
|
||||
mWebgl->UniformData(LOCAL_GL_FLOAT_VEC2, mSolidProgramTransform, false,
|
||||
{(const uint8_t*)xformData, sizeof(xformData)});
|
||||
Array<float, 2> viewportData = {float(texBounds.width),
|
||||
float(texBounds.height)};
|
||||
MaybeUniformData(LOCAL_GL_FLOAT_VEC2, mSolidProgramViewport, viewportData,
|
||||
mSolidProgramUniformState.mViewport);
|
||||
Array<float, 1> aaData = {0.0f};
|
||||
MaybeUniformData(LOCAL_GL_FLOAT, mSolidProgramAA, aaData,
|
||||
mSolidProgramUniformState.mAA);
|
||||
Array<float, 4> clipData = {-0.5f, -0.5f, float(texBounds.width) + 0.5f,
|
||||
float(texBounds.height) + 0.5f};
|
||||
MaybeUniformData(LOCAL_GL_FLOAT_VEC4, mSolidProgramClipBounds, clipData,
|
||||
mSolidProgramUniformState.mClipBounds);
|
||||
Array<float, 4> colorData = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
MaybeUniformData(LOCAL_GL_FLOAT_VEC4, mSolidProgramColor, colorData,
|
||||
mSolidProgramUniformState.mColor);
|
||||
Array<float, 6> xformData = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f};
|
||||
MaybeUniformData(LOCAL_GL_FLOAT_VEC2, mSolidProgramTransform, xformData,
|
||||
mSolidProgramUniformState.mTransform);
|
||||
|
||||
// Ensure the current clip mask is ignored.
|
||||
RefPtr<WebGLTextureJS> prevClipMask = mLastClipMask;
|
||||
@ -3137,9 +3128,6 @@ already_AddRefed<TextureHandle> DrawTargetWebgl::SharedContext::DrawStrokeMask(
|
||||
// Restore the previous framebuffer state.
|
||||
mWebgl->BindFramebuffer(LOCAL_GL_FRAMEBUFFER, mCurrentTarget->mFramebuffer);
|
||||
mWebgl->Viewport(0, 0, mViewportSize.width, mViewportSize.height);
|
||||
mDirtyViewport = true;
|
||||
mDirtyAA = true;
|
||||
mDirtyClip = true;
|
||||
if (prevClipMask) {
|
||||
SetClipMask(prevClipMask);
|
||||
}
|
||||
|
@ -7,6 +7,8 @@
|
||||
#ifndef _MOZILLA_GFX_DRAWTARGETWEBGL_H
|
||||
#define _MOZILLA_GFX_DRAWTARGETWEBGL_H
|
||||
|
||||
#include "GLTypes.h"
|
||||
#include "mozilla/Array.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/PathSkia.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
@ -180,12 +182,6 @@ class DrawTargetWebgl : public DrawTarget, public SupportsWeakPtr {
|
||||
RefPtr<WebGLProgramJS> mLastProgram;
|
||||
RefPtr<WebGLTextureJS> mLastTexture;
|
||||
RefPtr<WebGLTextureJS> mLastClipMask;
|
||||
// Whether the shader viewport state requires updating.
|
||||
bool mDirtyViewport = true;
|
||||
// Whether the shader anti-aliasing state requires updating.
|
||||
bool mDirtyAA = true;
|
||||
// Whether the shader clip AA bounds require updating.
|
||||
bool mDirtyClip = true;
|
||||
|
||||
// WebGL shader resources
|
||||
RefPtr<WebGLBufferJS> mPathVertexBuffer;
|
||||
@ -221,6 +217,25 @@ class DrawTargetWebgl : public DrawTarget, public SupportsWeakPtr {
|
||||
RefPtr<WebGLUniformLocationJS> mImageProgramClipMask;
|
||||
RefPtr<WebGLUniformLocationJS> mImageProgramClipBounds;
|
||||
|
||||
struct SolidProgramUniformState {
|
||||
Maybe<Array<float, 2>> mViewport;
|
||||
Maybe<Array<float, 1>> mAA;
|
||||
Maybe<Array<float, 6>> mTransform;
|
||||
Maybe<Array<float, 4>> mColor;
|
||||
Maybe<Array<float, 4>> mClipBounds;
|
||||
} mSolidProgramUniformState;
|
||||
|
||||
struct ImageProgramUniformState {
|
||||
Maybe<Array<float, 2>> mViewport;
|
||||
Maybe<Array<float, 1>> mAA;
|
||||
Maybe<Array<float, 6>> mTransform;
|
||||
Maybe<Array<float, 6>> mTexMatrix;
|
||||
Maybe<Array<float, 4>> mTexBounds;
|
||||
Maybe<Array<float, 4>> mColor;
|
||||
Maybe<Array<float, 1>> mSwizzle;
|
||||
Maybe<Array<float, 4>> mClipBounds;
|
||||
} mImageProgramUniformState;
|
||||
|
||||
// Scratch framebuffer used to wrap textures for miscellaneous utility ops.
|
||||
RefPtr<WebGLFramebufferJS> mScratchFramebuffer;
|
||||
// Buffer filled with zero data for initializing textures.
|
||||
@ -293,6 +308,13 @@ class DrawTargetWebgl : public DrawTarget, public SupportsWeakPtr {
|
||||
return mLastClipMask && mLastClipMask != mNoClipMask;
|
||||
}
|
||||
|
||||
// Avoids redundant UniformData calls by caching the previously set value.
|
||||
template <class T, size_t N>
|
||||
void MaybeUniformData(GLenum aFuncElemType,
|
||||
const WebGLUniformLocationJS* const aLoc,
|
||||
const Array<T, N>& aData,
|
||||
Maybe<Array<T, N>>& aCached);
|
||||
|
||||
bool IsCurrentTarget(DrawTargetWebgl* aDT) const {
|
||||
return aDT == mCurrentTarget;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user