diff options
Diffstat (limited to 'gfx')
237 files changed, 4826 insertions, 2080 deletions
diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h index 024723868b..e6b94f86ea 100644 --- a/gfx/2d/2D.h +++ b/gfx/2d/2D.h @@ -1987,7 +1987,7 @@ class DrawTarget : public external::AtomicRefCounted<DrawTarget> { SurfaceFormat mFormat; }; -class DrawEventRecorder : public RefCounted<DrawEventRecorder> { +class DrawEventRecorder : public external::AtomicRefCounted<DrawEventRecorder> { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorder) virtual RecorderType GetRecorderType() const { return RecorderType::UNKNOWN; } @@ -2160,6 +2160,9 @@ class GFX2D_API Factory { SurfaceFormat aFormat, SourceSurfaceDeallocator aDeallocator = nullptr, void* aClosure = nullptr); + static already_AddRefed<DataSourceSurface> CopyDataSourceSurface( + DataSourceSurface* aSource); + static void CopyDataSourceSurface(DataSourceSurface* aSource, DataSourceSurface* aDest); diff --git a/gfx/2d/DrawEventRecorder.cpp b/gfx/2d/DrawEventRecorder.cpp index 967c02f8a0..51f8b836ec 100644 --- a/gfx/2d/DrawEventRecorder.cpp +++ b/gfx/2d/DrawEventRecorder.cpp @@ -16,9 +16,7 @@ namespace gfx { DrawEventRecorderPrivate::DrawEventRecorderPrivate() : mExternalFonts(false) {} -DrawEventRecorderPrivate::~DrawEventRecorderPrivate() { - NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate); -} +DrawEventRecorderPrivate::~DrawEventRecorderPrivate() = default; void DrawEventRecorderPrivate::SetDrawTarget(ReferencePtr aDT) { NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate); diff --git a/gfx/2d/DrawEventRecorder.h b/gfx/2d/DrawEventRecorder.h index 13380b014a..d62f098784 100644 --- a/gfx/2d/DrawEventRecorder.h +++ b/gfx/2d/DrawEventRecorder.h @@ -41,7 +41,7 @@ class DrawEventRecorderPrivate : public DrawEventRecorder { return true; } virtual void FlushItem(IntRect) {} - void DetachResources() { + virtual void DetachResources() { NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate); nsTHashSet<ScaledFont*> fonts = std::move(mStoredFonts); @@ -116,7 +116,7 @@ class DrawEventRecorderPrivate : public DrawEventRecorder { return mStoredObjects.EnsureInserted(aObject); } - void AddPendingDeletion(std::function<void()>&& aPendingDeletion) { + virtual void AddPendingDeletion(std::function<void()>&& aPendingDeletion) { auto lockedPendingDeletions = mPendingDeletions.Lock(); lockedPendingDeletions->emplace_back(std::move(aPendingDeletion)); } diff --git a/gfx/2d/DrawTargetSkia.cpp b/gfx/2d/DrawTargetSkia.cpp index 098ff81117..508dac3f62 100644 --- a/gfx/2d/DrawTargetSkia.cpp +++ b/gfx/2d/DrawTargetSkia.cpp @@ -1398,7 +1398,7 @@ void DrawTargetSkia::Mask(const Pattern& aSource, const Pattern& aMask, SkPaint maskPaint; SetPaintPattern(maskPaint, aMask, lock); - sk_sp<SkShader> maskShader(maskPaint.getShader()); + sk_sp<SkShader> maskShader(maskPaint.refShader()); if (!maskShader && maskPaint.getAlpha() != 0xFF) { if (maskPaint.getAlpha() == 0) { return; diff --git a/gfx/2d/Factory.cpp b/gfx/2d/Factory.cpp index abf7a8669b..1bdf597142 100644 --- a/gfx/2d/Factory.cpp +++ b/gfx/2d/Factory.cpp @@ -1106,6 +1106,40 @@ already_AddRefed<DataSourceSurface> Factory::CreateDataSourceSurfaceWithStride( return nullptr; } +already_AddRefed<DataSourceSurface> Factory::CopyDataSourceSurface( + DataSourceSurface* aSource) { + // Don't worry too much about speed. + MOZ_ASSERT(aSource->GetFormat() == SurfaceFormat::R8G8B8A8 || + aSource->GetFormat() == SurfaceFormat::R8G8B8X8 || + aSource->GetFormat() == SurfaceFormat::B8G8R8A8 || + aSource->GetFormat() == SurfaceFormat::B8G8R8X8); + + DataSourceSurface::ScopedMap srcMap(aSource, DataSourceSurface::READ); + if (NS_WARN_IF(!srcMap.IsMapped())) { + MOZ_ASSERT_UNREACHABLE("CopyDataSourceSurface: Failed to map surface."); + return nullptr; + } + + IntSize size = aSource->GetSize(); + SurfaceFormat format = aSource->GetFormat(); + + RefPtr<DataSourceSurface> dst = CreateDataSourceSurfaceWithStride( + size, format, srcMap.GetStride(), /* aZero */ false); + if (NS_WARN_IF(!dst)) { + return nullptr; + } + + DataSourceSurface::ScopedMap dstMap(dst, DataSourceSurface::WRITE); + if (NS_WARN_IF(!dstMap.IsMapped())) { + MOZ_ASSERT_UNREACHABLE("CopyDataSourceSurface: Failed to map surface."); + return nullptr; + } + + SwizzleData(srcMap.GetData(), srcMap.GetStride(), format, dstMap.GetData(), + dstMap.GetStride(), format, size); + return dst.forget(); +} + void Factory::CopyDataSourceSurface(DataSourceSurface* aSource, DataSourceSurface* aDest) { // Don't worry too much about speed. diff --git a/gfx/2d/MacIOSurface.cpp b/gfx/2d/MacIOSurface.cpp index 8c1c24bc10..1701731d61 100644 --- a/gfx/2d/MacIOSurface.cpp +++ b/gfx/2d/MacIOSurface.cpp @@ -5,11 +5,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "MacIOSurface.h" -#include <OpenGL/gl.h> -#include <OpenGL/CGLIOSurface.h> +#ifdef XP_MACOSX +# include <OpenGL/gl.h> +# include <OpenGL/CGLIOSurface.h> +#endif #include <QuartzCore/QuartzCore.h> #include "GLConsts.h" -#include "GLContextCGL.h" +#ifdef XP_MACOSX +# include "GLContextCGL.h" +#else +# include "GLContextEAGL.h" +#endif #include "gfxMacUtils.h" #include "nsPrintfCString.h" #include "mozilla/Assertions.h" @@ -223,6 +229,7 @@ already_AddRefed<MacIOSurface> MacIOSurface::CreateNV12OrP010Surface( surfaceRef.get(), CFSTR("IOSurfaceTransferFunction"), gfxMacUtils::CFStringForTransferFunction(aTransferFunction)); +#ifdef XP_MACOSX // Override the color space to be the same as the main display, so that // CoreAnimation won't try to do any color correction (from the IOSurface // space, to the display). In the future we may want to try specifying this @@ -234,6 +241,7 @@ already_AddRefed<MacIOSurface> MacIOSurface::CreateNV12OrP010Surface( CGColorSpaceCopyICCData(colorSpace.get())); IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"), colorData.get()); +#endif RefPtr<MacIOSurface> ioSurface = new MacIOSurface(std::move(surfaceRef), false, aColorSpace); @@ -285,6 +293,8 @@ already_AddRefed<MacIOSurface> MacIOSurface::CreateYUV422Surface( IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"), CFSTR("ITU_R_709_2")); } + +#ifdef XP_MACOSX // Override the color space to be the same as the main display, so that // CoreAnimation won't try to do any color correction (from the IOSurface // space, to the display). In the future we may want to try specifying this @@ -296,6 +306,7 @@ already_AddRefed<MacIOSurface> MacIOSurface::CreateYUV422Surface( CGColorSpaceCopyICCData(colorSpace.get())); IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"), colorData.get()); +#endif RefPtr<MacIOSurface> ioSurface = new MacIOSurface(std::move(surfaceRef), false, aColorSpace); @@ -482,19 +493,10 @@ ColorDepth MacIOSurface::GetColorDepth() const { } } -CGLError MacIOSurface::CGLTexImageIOSurface2D(CGLContextObj ctx, GLenum target, - GLenum internalFormat, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - GLuint plane) const { - return ::CGLTexImageIOSurface2D(ctx, target, internalFormat, width, height, - format, type, mIOSurfaceRef.get(), plane); -} - -CGLError MacIOSurface::CGLTexImageIOSurface2D( - mozilla::gl::GLContext* aGL, CGLContextObj ctx, size_t plane, - mozilla::gfx::SurfaceFormat* aOutReadFormat) { - MOZ_ASSERT(plane >= 0); +bool MacIOSurface::BindTexImage(mozilla::gl::GLContext* aGL, size_t aPlane, + mozilla::gfx::SurfaceFormat* aOutReadFormat) { +#ifdef XP_MACOSX + MOZ_ASSERT(aPlane >= 0); bool isCompatibilityProfile = aGL->IsCompatibilityProfile(); OSType pixelFormat = GetPixelFormat(); @@ -504,12 +506,12 @@ CGLError MacIOSurface::CGLTexImageIOSurface2D( if (pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange || pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) { MOZ_ASSERT(GetPlaneCount() == 2); - MOZ_ASSERT(plane < 2); + MOZ_ASSERT(aPlane < 2); // The LOCAL_GL_LUMINANCE and LOCAL_GL_LUMINANCE_ALPHA are the deprecated // format. So, use LOCAL_GL_RED and LOCAL_GL_RB if we use core profile. // https://www.khronos.org/opengl/wiki/Image_Format#Legacy_Image_Formats - if (plane == 0) { + if (aPlane == 0) { internalFormat = format = (isCompatibilityProfile) ? (LOCAL_GL_LUMINANCE) : (LOCAL_GL_RED); } else { @@ -523,12 +525,12 @@ CGLError MacIOSurface::CGLTexImageIOSurface2D( } else if (pixelFormat == kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange || pixelFormat == kCVPixelFormatType_420YpCbCr10BiPlanarFullRange) { MOZ_ASSERT(GetPlaneCount() == 2); - MOZ_ASSERT(plane < 2); + MOZ_ASSERT(aPlane < 2); // The LOCAL_GL_LUMINANCE and LOCAL_GL_LUMINANCE_ALPHA are the deprecated // format. So, use LOCAL_GL_RED and LOCAL_GL_RB if we use core profile. // https://www.khronos.org/opengl/wiki/Image_Format#Legacy_Image_Formats - if (plane == 0) { + if (aPlane == 0) { internalFormat = format = (isCompatibilityProfile) ? (LOCAL_GL_LUMINANCE) : (LOCAL_GL_RED); } else { @@ -541,7 +543,7 @@ CGLError MacIOSurface::CGLTexImageIOSurface2D( } } else if (pixelFormat == kCVPixelFormatType_422YpCbCr8_yuvs || pixelFormat == kCVPixelFormatType_422YpCbCr8FullRange) { - MOZ_ASSERT(plane == 0); + MOZ_ASSERT(aPlane == 0); // The YCBCR_422_APPLE ext is only available in compatibility profile. So, // we should use RGB_422_APPLE for core profile. The difference between // YCBCR_422_APPLE and RGB_422_APPLE is that the YCBCR_422_APPLE converts @@ -565,7 +567,7 @@ CGLError MacIOSurface::CGLTexImageIOSurface2D( internalFormat = LOCAL_GL_RGB; type = LOCAL_GL_UNSIGNED_SHORT_8_8_REV_APPLE; } else { - MOZ_ASSERT(plane == 0); + MOZ_ASSERT(aPlane == 0); internalFormat = HasAlpha() ? LOCAL_GL_RGBA : LOCAL_GL_RGB; format = LOCAL_GL_BGRA; @@ -576,10 +578,13 @@ CGLError MacIOSurface::CGLTexImageIOSurface2D( } } - auto err = - CGLTexImageIOSurface2D(ctx, LOCAL_GL_TEXTURE_RECTANGLE_ARB, - internalFormat, GetDevicePixelWidth(plane), - GetDevicePixelHeight(plane), format, type, plane); + size_t width = GetDevicePixelWidth(aPlane); + size_t height = GetDevicePixelHeight(aPlane); + + auto err = ::CGLTexImageIOSurface2D( + gl::GLContextCGL::Cast(aGL)->GetCGLContext(), + LOCAL_GL_TEXTURE_RECTANGLE_ARB, internalFormat, width, height, format, + type, mIOSurfaceRef.get(), aPlane); if (err) { const auto formatChars = (const char*)&pixelFormat; const char formatStr[] = {formatChars[3], formatChars[2], formatChars[1], @@ -587,13 +592,15 @@ CGLError MacIOSurface::CGLTexImageIOSurface2D( const nsPrintfCString errStr( "CGLTexImageIOSurface2D(context, target, 0x%04x," " %u, %u, 0x%04x, 0x%04x, iosurfPtr, %u) -> %i", - internalFormat, uint32_t(GetDevicePixelWidth(plane)), - uint32_t(GetDevicePixelHeight(plane)), format, type, - (unsigned int)plane, err); + internalFormat, uint32_t(width), uint32_t(height), format, type, + (unsigned int)aPlane, err); gfxCriticalError() << errStr.get() << " (iosurf format: " << formatStr << ")"; } - return err; + return !err; +#else + MOZ_CRASH("unimplemented"); +#endif } void MacIOSurface::SetColorSpace(const mozilla::gfx::ColorSpace2 cs) const { diff --git a/gfx/2d/MacIOSurface.h b/gfx/2d/MacIOSurface.h index ef176430d1..d0ee3baeef 100644 --- a/gfx/2d/MacIOSurface.h +++ b/gfx/2d/MacIOSurface.h @@ -8,7 +8,7 @@ #define MacIOSurface_h__ #ifdef XP_DARWIN # include <CoreVideo/CoreVideo.h> -# include <IOSurface/IOSurface.h> +# include <IOSurface/IOSurfaceRef.h> # include <QuartzCore/QuartzCore.h> # include <dlfcn.h> @@ -21,20 +21,19 @@ class GLContext; } } // namespace mozilla +# ifdef XP_MACOSX struct _CGLContextObject; typedef _CGLContextObject* CGLContextObj; -typedef uint32_t IOSurfaceID; - -# ifdef XP_IOS -typedef kern_return_t IOReturn; -typedef int CGLError; # endif +typedef uint32_t IOSurfaceID; # ifdef XP_MACOSX # import <OpenGL/OpenGL.h> # else -# import <OpenGLES/ES2/gl.h> +# include "GLTypes.h" +typedef realGLboolean GLboolean; +# include <OpenGLES/ES2/gl.h> # endif # include "2D.h" @@ -123,15 +122,15 @@ class MacIOSurface final return mozilla::gfx::ColorRange::LIMITED; } - // We would like to forward declare NSOpenGLContext, but it is an @interface - // and this file is also used from c++, so we use a void *. - CGLError CGLTexImageIOSurface2D( - mozilla::gl::GLContext* aGL, CGLContextObj ctxt, size_t plane, - mozilla::gfx::SurfaceFormat* aOutReadFormat = nullptr); - CGLError CGLTexImageIOSurface2D(CGLContextObj ctxt, GLenum target, - GLenum internalFormat, GLsizei width, - GLsizei height, GLenum format, GLenum type, - GLuint plane) const; + // Bind this IOSurface to a texture using the most efficient mechanism + // available on the current platform. + // + // Note that on iOS simulator, due to incomplete support for + // texImageIOSurface, this will only use texImage2D to upload, and cannot be + // used to read-back the GL texture to an IOSurface. + bool BindTexImage(mozilla::gl::GLContext* aGL, size_t aPlane, + mozilla::gfx::SurfaceFormat* aOutReadFormat = nullptr); + already_AddRefed<SourceSurface> GetAsSurface(); // Creates a DrawTarget that wraps the data in the IOSurface. Rendering to diff --git a/gfx/2d/ScaledFontMac.cpp b/gfx/2d/ScaledFontMac.cpp index 9528b3527e..7ac1cfc9c9 100644 --- a/gfx/2d/ScaledFontMac.cpp +++ b/gfx/2d/ScaledFontMac.cpp @@ -7,7 +7,9 @@ #include "ScaledFontMac.h" #include "UnscaledFontMac.h" #include "mozilla/webrender/WebRenderTypes.h" -#include "nsCocoaFeatures.h" +#ifdef MOZ_WIDGET_COCOA +# include "nsCocoaFeatures.h" +#endif #include "PathSkia.h" #include "skia/include/core/SkPaint.h" #include "skia/include/core/SkPath.h" @@ -73,6 +75,7 @@ class AutoRelease final { CTFontRef CreateCTFontFromCGFontWithVariations(CGFontRef aCGFont, CGFloat aSize, bool aInstalledFont, CTFontDescriptorRef aFontDesc) { +#ifdef MOZ_WIDGET_COCOA // New implementation (see bug 1856035) for macOS 13+. if (nsCocoaFeatures::OnVenturaOrLater()) { // Create CTFont, applying any descriptor that was passed (used by @@ -96,6 +99,7 @@ CTFontRef CreateCTFontFromCGFontWithVariations(CGFontRef aCGFont, CGFloat aSize, // No variations to set, just return the default CTFont. return ctFont.forget(); } +#endif // Older implementation used up to macOS 12. CTFontRef ctFont; diff --git a/gfx/2d/moz.build b/gfx/2d/moz.build index c04530c72b..d1408b9dc9 100644 --- a/gfx/2d/moz.build +++ b/gfx/2d/moz.build @@ -69,6 +69,7 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] in ("cocoa", "uikit"): "UnscaledFontMac.h", ] UNIFIED_SOURCES += [ + "MacIOSurface.cpp", "NativeFontResourceMac.cpp", "ScaledFontMac.cpp", ] @@ -188,11 +189,6 @@ SOURCES += [ "InlineTranslator.cpp", ] -if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa": - SOURCES += [ - "MacIOSurface.cpp", - ] - if CONFIG["TARGET_CPU"] == "aarch64" or CONFIG["BUILD_ARM_NEON"]: SOURCES += [ "BlurNEON.cpp", diff --git a/gfx/angle/moz.build b/gfx/angle/moz.build index ea4be831bd..ee870a088e 100644 --- a/gfx/angle/moz.build +++ b/gfx/angle/moz.build @@ -4,7 +4,10 @@ # 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/. -DIRS += ["targets/translator"] +DIRS += [ + "targets/angle_common", + "targets/translator", +] # Only build libEGL/libGLESv2 on Windows if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows": diff --git a/gfx/angle/targets/angle_gpu_info_util/moz.build b/gfx/angle/targets/angle_gpu_info_util/moz.build index f2fe1dd3d4..7278d2bfcd 100644 --- a/gfx/angle/targets/angle_gpu_info_util/moz.build +++ b/gfx/angle/targets/angle_gpu_info_util/moz.build @@ -170,10 +170,6 @@ USE_LIBS += [ "angle_common", ] -DIRS += [ - "../angle_common", -] - OS_LIBS += [ "dxgi", "setupapi", diff --git a/gfx/angle/targets/angle_image_util/moz.build b/gfx/angle/targets/angle_image_util/moz.build index 8a17982e17..38871adc6e 100644 --- a/gfx/angle/targets/angle_image_util/moz.build +++ b/gfx/angle/targets/angle_image_util/moz.build @@ -150,10 +150,6 @@ USE_LIBS += [ "angle_common", ] -DIRS += [ - "../angle_common", -] - # LDFLAGS += [ # "--color-diagnostics", # "/call-graph-profile-sort:no", diff --git a/gfx/angle/targets/libEGL/moz.build b/gfx/angle/targets/libEGL/moz.build index 9327db4c23..eb8c049493 100644 --- a/gfx/angle/targets/libEGL/moz.build +++ b/gfx/angle/targets/libEGL/moz.build @@ -157,11 +157,6 @@ USE_LIBS += [ "libGLESv2", ] -DIRS += [ - "../angle_common", - "../libGLESv2", -] - OS_LIBS += [ "advapi32", "comdlg32", diff --git a/gfx/angle/targets/libGLESv2/moz.build b/gfx/angle/targets/libGLESv2/moz.build index dfcf0df719..18d296d084 100644 --- a/gfx/angle/targets/libGLESv2/moz.build +++ b/gfx/angle/targets/libGLESv2/moz.build @@ -366,11 +366,9 @@ USE_LIBS += [ ] DIRS += [ - "../angle_common", "../angle_gpu_info_util", "../angle_image_util", "../compression_utils_portable", - "../translator", ] OS_LIBS += [ diff --git a/gfx/angle/targets/preprocessor/moz.build b/gfx/angle/targets/preprocessor/moz.build index 3fbce2e0c4..c790132062 100644 --- a/gfx/angle/targets/preprocessor/moz.build +++ b/gfx/angle/targets/preprocessor/moz.build @@ -156,10 +156,6 @@ USE_LIBS += [ "angle_common", ] -DIRS += [ - "../angle_common", -] - # LDFLAGS += [ # "--color-diagnostics", # "/call-graph-profile-sort:no", diff --git a/gfx/angle/targets/translator/moz.build b/gfx/angle/targets/translator/moz.build index 38dbb74f79..4b59b82403 100644 --- a/gfx/angle/targets/translator/moz.build +++ b/gfx/angle/targets/translator/moz.build @@ -298,7 +298,6 @@ USE_LIBS += [ ] DIRS += [ - "../angle_common", "../preprocessor", ] diff --git a/gfx/angle/update-angle.py b/gfx/angle/update-angle.py index 348a1cf745..99d65f84f6 100755 --- a/gfx/angle/update-angle.py +++ b/gfx/angle/update-angle.py @@ -5,7 +5,7 @@ assert __name__ == "__main__" -""" +r""" To update ANGLE in Gecko, use Windows with git-bash, and setup depot_tools, python2, and python3. Because depot_tools expects `python` to be `python2` (shame!), python2 must come before python3 in your path. @@ -502,8 +502,18 @@ def export_target(target_full_name) -> Set[str]: dep_dirs = set(dep_libs) dep_dirs.discard("zlib") + # Those directories are added by gfx/angle/moz.build. + already_added_dirs = [ + "angle_common", + "translator", + "libEGL", + "libGLESv2", + ] + append_arr(lines, "USE_LIBS", dep_libs) - append_arr(lines, "DIRS", ["../" + x for x in dep_dirs]) + append_arr( + lines, "DIRS", ["../" + x for x in dep_dirs if x not in already_added_dirs] + ) append_arr(lines, "OS_LIBS", os_libs) append_arr_commented(lines, "LDFLAGS", ldflags) diff --git a/gfx/config/gfxVars.h b/gfx/config/gfxVars.h index d520ec7716..d74255b5db 100644 --- a/gfx/config/gfxVars.h +++ b/gfx/config/gfxVars.h @@ -99,7 +99,9 @@ class gfxVarReceiver; _(WebglOopAsyncPresentForceSync, bool, true) \ _(UseAcceleratedCanvas2D, bool, false) \ _(AllowSoftwareWebRenderOGL, bool, false) \ - _(WebglUseHardware, bool, true) + _(WebglUseHardware, bool, true) \ + _(WebRenderOverlayVpAutoHDR, bool, false) \ + _(WebRenderOverlayVpSuperResolution, bool, false) /* Add new entries above this line. */ diff --git a/gfx/gl/GLBlitHelper.cpp b/gfx/gl/GLBlitHelper.cpp index dd9fa00235..c5c8995dab 100644 --- a/gfx/gl/GLBlitHelper.cpp +++ b/gfx/gl/GLBlitHelper.cpp @@ -1176,8 +1176,6 @@ bool GLBlitHelper::BlitImage(MacIOSurface* const iosurf, MOZ_ASSERT(false); return false; } - const auto glCGL = static_cast<GLContextCGL*>(mGL); - const auto cglContext = glCGL->GetCGLContext(); const auto& srcOrigin = OriginPos::BottomLeft; @@ -1268,8 +1266,7 @@ bool GLBlitHelper::BlitImage(MacIOSurface* const iosurf, mGL->fBindTexture(texTarget, texs[p]); mGL->TexParams_SetClampNoMips(texTarget); - auto err = iosurf->CGLTexImageIOSurface2D(mGL, cglContext, p); - if (err) { + if (!iosurf->BindTexImage(mGL, p)) { return false; } diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 9036653af8..5eba6c58aa 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -2049,17 +2049,24 @@ static void ReportArrayContents( nsTArray<GLContext::NamedResource> copy(aArray.Clone()); copy.Sort(); + // Accumulate the output in a buffer to avoid interleaved output. + nsCString line; + GLContext* lastContext = nullptr; for (uint32_t i = 0; i < copy.Length(); ++i) { if (lastContext != copy[i].origin) { - if (lastContext) printf_stderr("\n"); - printf_stderr(" [%p - %s] ", copy[i].origin, - copy[i].originDeleted ? "deleted" : "live"); + if (lastContext) { + printf_stderr("%s\n", line.BeginReading()); + line.Assign(""); + } + line.Append(nsPrintfCString(" [%p - %s] ", copy[i].origin, + copy[i].originDeleted ? "deleted" : "live")); lastContext = copy[i].origin; } - printf_stderr("%d ", copy[i].name); + line.AppendInt(copy[i].name); + line.Append(' '); } - printf_stderr("\n"); + printf_stderr("%s\n", line.BeginReading()); } void GLContext::ReportOutstandingNames() { diff --git a/gfx/gl/GLContextEAGL.h b/gfx/gl/GLContextEAGL.h index 6e137e7b70..2b062d1a0f 100644 --- a/gfx/gl/GLContextEAGL.h +++ b/gfx/gl/GLContextEAGL.h @@ -10,7 +10,11 @@ #include "GLContext.h" #include <CoreGraphics/CoreGraphics.h> -#include <OpenGLES/EAGL.h> +#ifdef __OBJC__ +# include <OpenGLES/EAGL.h> +#else +typedef void EAGLContext; +#endif namespace mozilla { namespace gl { @@ -23,7 +27,7 @@ class GLContextEAGL : public GLContext { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextEAGL, override) GLContextEAGL(const GLContextDesc&, EAGLContext* context, - GLContext* sharedContext, ContextProfile profile); + GLContext* sharedContext); ~GLContextEAGL(); @@ -36,8 +40,6 @@ class GLContextEAGL : public GLContext { return static_cast<GLContextEAGL*>(gl); } - bool AttachToWindow(nsIWidget* aWidget); - EAGLContext* GetEAGLContext() const { return mContext; } virtual bool MakeCurrentImpl() const override; @@ -54,18 +56,9 @@ class GLContextEAGL : public GLContext { virtual GLuint GetDefaultFramebuffer() override { return mBackbufferFB; } - virtual bool RenewSurface(widget::CompositorWidget*) override { - // FIXME: should use the passed widget instead of the existing one. - return RecreateRB(); - } - private: GLuint mBackbufferRB = 0; GLuint mBackbufferFB = 0; - - void* mLayer = nullptr; - - bool RecreateRB(); }; } // namespace gl diff --git a/gfx/gl/GLContextProvider.h b/gfx/gl/GLContextProvider.h index c63f1ada0b..277b76efa8 100644 --- a/gfx/gl/GLContextProvider.h +++ b/gfx/gl/GLContextProvider.h @@ -60,10 +60,6 @@ namespace gl { # define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderLinux #endif -#ifndef GL_CONTEXT_PROVIDER_DEFAULT -# define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderEGL -#endif - #if defined(MOZ_WIDGET_UIKIT) # define GL_CONTEXT_PROVIDER_NAME GLContextProviderEAGL # include "GLContextProviderImpl.h" @@ -73,6 +69,10 @@ namespace gl { # endif #endif +#ifndef GL_CONTEXT_PROVIDER_DEFAULT +# define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderEGL +#endif + #ifdef MOZ_GL_PROVIDER # define GL_CONTEXT_PROVIDER_NAME MOZ_GL_PROVIDER # include "GLContextProviderImpl.h" diff --git a/gfx/gl/GLContextProviderEAGL.mm b/gfx/gl/GLContextProviderEAGL.mm index 6e27498028..648d6642d4 100644 --- a/gfx/gl/GLContextProviderEAGL.mm +++ b/gfx/gl/GLContextProviderEAGL.mm @@ -5,6 +5,7 @@ #include "GLContextProvider.h" #include "GLContextEAGL.h" +#include "GLLibraryLoader.h" #include "nsDebug.h" #include "nsIWidget.h" #include "gfxFailure.h" @@ -38,58 +39,12 @@ GLContextEAGL::~GLContextEAGL() { MarkDestroyed(); - if (mLayer) { - mLayer = nil; - } - if (mContext) { [EAGLContext setCurrentContext:nil]; [mContext release]; } } -bool GLContextEAGL::AttachToWindow(nsIWidget* aWidget) { - // This should only be called once - MOZ_ASSERT(!mBackbufferFB && !mBackbufferRB); - - UIView* view = - reinterpret_cast<UIView*>(aWidget->GetNativeData(NS_NATIVE_WIDGET)); - - if (!view) { - MOZ_CRASH("no view!"); - } - - mLayer = [view layer]; - - fGenFramebuffers(1, &mBackbufferFB); - return RecreateRB(); -} - -bool GLContextEAGL::RecreateRB() { - MakeCurrent(); - - CAEAGLLayer* layer = (CAEAGLLayer*)mLayer; - - if (mBackbufferRB) { - // It doesn't seem to be enough to just call renderbufferStorage: below, - // we apparently have to recreate the RB. - fDeleteRenderbuffers(1, &mBackbufferRB); - mBackbufferRB = 0; - } - - fGenRenderbuffers(1, &mBackbufferRB); - fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mBackbufferRB); - - [mContext renderbufferStorage:LOCAL_GL_RENDERBUFFER fromDrawable:layer]; - - fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackbufferFB); - fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, - LOCAL_GL_RENDERBUFFER, mBackbufferRB); - - return LOCAL_GL_FRAMEBUFFER_COMPLETE == - fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); -} - bool GLContextEAGL::MakeCurrentImpl() const { if (mContext) { GLContext::ResetTLSCurrentContext(); @@ -107,7 +62,7 @@ bool GLContextEAGL::IsCurrentImpl() const { static PRFuncPtr GLAPIENTRY GetLoadedProcAddress(const char* const name) { PRLibrary* lib = nullptr; - const auto& ret = PR_FindFunctionSymbolAndLibrary(name, &leakedLibRef); + const auto& ret = PR_FindFunctionSymbolAndLibrary(name, &lib); if (lib) { PR_UnloadLibrary(lib); } @@ -173,29 +128,17 @@ static RefPtr<GLContext> CreateEAGLContext(const GLContextDesc& desc, already_AddRefed<GLContext> GLContextProviderEAGL::CreateForCompositorWidget( CompositorWidget* aCompositorWidget, bool aHardwareWebRender, bool aForceAccelerated) { - if (!aCompositorWidget) { - MOZ_ASSERT(false); - return nullptr; + CreateContextFlags flags = CreateContextFlags::ALLOW_OFFLINE_RENDERER; + if (aForceAccelerated) { + flags |= CreateContextFlags::FORBID_SOFTWARE; } - - const GLContextDesc desc = {}; - auto glContext = CreateEAGLContext(desc, GetGlobalContextEAGL()); - if (!glContext) { - return nullptr; - } - - if (!GLContextEAGL::Cast(glContext)->AttachToWindow( - aCompositorWidget->RealWidget())) { - return nullptr; - } - - return glContext.forget(); + nsCString failureUnused; + return CreateHeadless({flags}, &failureUnused); } already_AddRefed<GLContext> GLContextProviderEAGL::CreateHeadless( const GLContextCreateDesc& createDesc, nsACString* const out_failureId) { auto desc = GLContextDesc{createDesc}; - desc.isOffcreen = true; return CreateEAGLContext(desc, GetGlobalContextEAGL()).forget(); } @@ -208,7 +151,8 @@ GLContext* GLContextProviderEAGL::GetGlobalContext() { MOZ_RELEASE_ASSERT(!gGlobalContext, "GFX: Global GL context already initialized."); - RefPtr<GLContext> temp = CreateHeadless(CreateContextFlags::NONE); + nsCString discardFailureId; + RefPtr<GLContext> temp = CreateHeadless({}, &discardFailureId); gGlobalContext = temp; if (!gGlobalContext) { diff --git a/gfx/gl/GLTypes.h b/gfx/gl/GLTypes.h index f5b317b4b7..6caa1cc623 100644 --- a/gfx/gl/GLTypes.h +++ b/gfx/gl/GLTypes.h @@ -55,6 +55,13 @@ typedef signed long int GLsizeiptr; #endif /* #if !defined(__gltypes_h_) && !defined(__gl_h_) */ +#ifdef XP_IOS +# ifndef GLdouble_defined +typedef double GLdouble; +# endif +typedef double GLclampd; +#endif + #include <stdint.h> // ARB_sync diff --git a/gfx/gl/SharedSurface.cpp b/gfx/gl/SharedSurface.cpp index 2fbfd3f625..0465926521 100644 --- a/gfx/gl/SharedSurface.cpp +++ b/gfx/gl/SharedSurface.cpp @@ -89,13 +89,13 @@ UniquePtr<SurfaceFactory> SurfaceFactory::Create( return SurfaceFactory_D3D11Interop::Create(gl); } #endif - return nullptr; + break; case layers::TextureType::MacIOSurface: #ifdef XP_MACOSX return MakeUnique<SurfaceFactory_IOSurface>(gl); #else - return nullptr; + break; #endif case layers::TextureType::DMABUF: @@ -105,13 +105,13 @@ UniquePtr<SurfaceFactory> SurfaceFactory::Create( return SurfaceFactory_DMABUF::Create(gl); } #endif - return nullptr; + break; case layers::TextureType::AndroidNativeWindow: #ifdef MOZ_WIDGET_ANDROID return MakeUnique<SurfaceFactory_SurfaceTexture>(gl); #else - return nullptr; + break; #endif case layers::TextureType::AndroidHardwareBuffer: @@ -121,7 +121,7 @@ UniquePtr<SurfaceFactory> SurfaceFactory::Create( return SurfaceFactory_AndroidHardwareBuffer::Create(gl); } #endif - return nullptr; + break; case layers::TextureType::EGLImage: #ifdef MOZ_WIDGET_ANDROID @@ -129,17 +129,15 @@ UniquePtr<SurfaceFactory> SurfaceFactory::Create( return SurfaceFactory_EGLImage::Create(gl); } #endif - return nullptr; + break; case layers::TextureType::Unknown: case layers::TextureType::Last: break; } -#ifdef MOZ_X11 // Silence a warning. Unused << gl; -#endif return nullptr; } diff --git a/gfx/gl/SharedSurfaceIO.cpp b/gfx/gl/SharedSurfaceIO.cpp index 1fd0f22d31..459faa64b3 100644 --- a/gfx/gl/SharedSurfaceIO.cpp +++ b/gfx/gl/SharedSurfaceIO.cpp @@ -28,7 +28,7 @@ SurfaceFactory_IOSurface::SurfaceFactory_IOSurface(GLContext& gl) // - // Surface -static void BackTextureWithIOSurf(GLContext* const gl, const GLuint tex, +static bool BackTextureWithIOSurf(GLContext* const gl, const GLuint tex, MacIOSurface* const ioSurf) { MOZ_ASSERT(gl->IsCurrent()); @@ -43,10 +43,7 @@ static void BackTextureWithIOSurf(GLContext* const gl, const GLuint tex, gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); - CGLContextObj cgl = GLContextCGL::Cast(gl)->GetCGLContext(); - MOZ_ASSERT(cgl); - - ioSurf->CGLTexImageIOSurface2D(gl, cgl, 0); + return ioSurf->BindTexImage(gl, 0); } /*static*/ @@ -65,7 +62,9 @@ UniquePtr<SharedSurface_IOSurface> SharedSurface_IOSurface::Create( // - auto tex = MakeUnique<Texture>(*desc.gl); - BackTextureWithIOSurf(desc.gl, tex->name, ioSurf); + if (!BackTextureWithIOSurf(desc.gl, tex->name, ioSurf)) { + return nullptr; + } const GLenum target = LOCAL_GL_TEXTURE_RECTANGLE; auto fb = MozFramebuffer::CreateForBacking(desc.gl, desc.size, 0, false, diff --git a/gfx/gl/moz.build b/gfx/gl/moz.build index f45e85b8f4..965b0add48 100644 --- a/gfx/gl/moz.build +++ b/gfx/gl/moz.build @@ -12,6 +12,7 @@ elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa": gl_provider = "CGL" elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "uikit": gl_provider = "EAGL" + DEFINES["GLES_SILENCE_DEPRECATION"] = 1 elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk": gl_provider = "Linux" elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "android": diff --git a/gfx/ipc/CanvasManagerChild.cpp b/gfx/ipc/CanvasManagerChild.cpp index eca803bc4b..dee232b6b1 100644 --- a/gfx/ipc/CanvasManagerChild.cpp +++ b/gfx/ipc/CanvasManagerChild.cpp @@ -10,6 +10,7 @@ #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/dom/WorkerRef.h" #include "mozilla/gfx/2D.h" +#include "mozilla/gfx/CanvasShutdownManager.h" #include "mozilla/gfx/Swizzle.h" #include "mozilla/ipc/Endpoint.h" #include "mozilla/layers/ActiveResource.h" @@ -30,7 +31,10 @@ MOZ_THREAD_LOCAL(CanvasManagerChild*) CanvasManagerChild::sLocalManager; Atomic<uint32_t> CanvasManagerChild::sNextId(1); -CanvasManagerChild::CanvasManagerChild(uint32_t aId) : mId(aId) {} +CanvasManagerChild::CanvasManagerChild(ThreadSafeWorkerRef* aWorkerRef, + uint32_t aId) + : mWorkerRef(aWorkerRef), mId(aId) {} + CanvasManagerChild::~CanvasManagerChild() = default; void CanvasManagerChild::ActorDestroy(ActorDestroyReason aReason) { @@ -42,11 +46,6 @@ void CanvasManagerChild::ActorDestroy(ActorDestroyReason aReason) { } void CanvasManagerChild::DestroyInternal() { - std::set<CanvasRenderingContext2D*> activeCanvas = std::move(mActiveCanvas); - for (const auto& i : activeCanvas) { - i->OnShutdown(); - } - if (mActiveResourceTracker) { mActiveResourceTracker->AgeAllGenerations(); mActiveResourceTracker.reset(); @@ -56,6 +55,10 @@ void CanvasManagerChild::DestroyInternal() { mCanvasChild->Destroy(); mCanvasChild = nullptr; } + + if (auto* shutdownManager = CanvasShutdownManager::Get()) { + shutdownManager->OnRemoteCanvasLost(); + } } void CanvasManagerChild::Destroy() { @@ -67,12 +70,6 @@ void CanvasManagerChild::Destroy() { } /* static */ void CanvasManagerChild::Shutdown() { - MOZ_ASSERT(NS_IsMainThread()); - - // The worker threads should destroy their own CanvasManagerChild instances - // during their shutdown sequence. We just need to take care of the main - // thread. We need to init here because we may have never created a - // CanvasManagerChild for the main thread in the first place. if (sLocalManager.init()) { RefPtr<CanvasManagerChild> manager = sLocalManager.get(); if (manager) { @@ -103,6 +100,11 @@ void CanvasManagerChild::Destroy() { return managerWeak; } + auto* shutdownManager = CanvasShutdownManager::Get(); + if (NS_WARN_IF(!shutdownManager)) { + return nullptr; + } + // We are only used on the main thread, or on worker threads. WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT_IF(!worker, NS_IsMainThread()); @@ -121,29 +123,8 @@ void CanvasManagerChild::Destroy() { return nullptr; } - auto manager = MakeRefPtr<CanvasManagerChild>(sNextId++); - - if (worker) { - // The ThreadSafeWorkerRef will let us know when the worker is shutting - // down. This will let us clear our threadlocal reference and close the - // actor. We rely upon an explicit shutdown for the main thread. - RefPtr<StrongWorkerRef> workerRef = StrongWorkerRef::Create( - worker, "CanvasManager", [manager]() { manager->Destroy(); }); - if (NS_WARN_IF(!workerRef)) { - return nullptr; - } - - manager->mWorkerRef = new ThreadSafeWorkerRef(workerRef); - } else if (NS_IsMainThread()) { - if (NS_WARN_IF( - AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed))) { - return nullptr; - } - } else { - MOZ_ASSERT_UNREACHABLE("Can only be used on main or DOM worker threads!"); - return nullptr; - } - + auto manager = MakeRefPtr<CanvasManagerChild>(shutdownManager->GetWorkerRef(), + sNextId++); if (NS_WARN_IF(!childEndpoint.Bind(manager))) { return nullptr; } @@ -163,6 +144,7 @@ void CanvasManagerChild::Destroy() { } manager->SendInitialize(manager->Id()); + shutdownManager->OnRemoteCanvasRestored(); sLocalManager.set(manager); return manager; } @@ -175,16 +157,6 @@ void CanvasManagerChild::Destroy() { return sLocalManager.get(); } -void CanvasManagerChild::AddShutdownObserver( - dom::CanvasRenderingContext2D* aCanvas) { - mActiveCanvas.insert(aCanvas); -} - -void CanvasManagerChild::RemoveShutdownObserver( - dom::CanvasRenderingContext2D* aCanvas) { - mActiveCanvas.erase(aCanvas); -} - void CanvasManagerChild::EndCanvasTransaction() { if (!mCanvasChild) { return; @@ -224,8 +196,9 @@ RefPtr<layers::CanvasChild> CanvasManagerChild::GetCanvasChild() { } if (!mCanvasChild) { - mCanvasChild = MakeAndAddRef<layers::CanvasChild>(); + mCanvasChild = MakeAndAddRef<layers::CanvasChild>(mWorkerRef); if (!SendPCanvasConstructor(mCanvasChild)) { + mCanvasChild->Destroy(); mCanvasChild = nullptr; } } diff --git a/gfx/ipc/CanvasManagerChild.h b/gfx/ipc/CanvasManagerChild.h index 6369d87ada..c59ba7c502 100644 --- a/gfx/ipc/CanvasManagerChild.h +++ b/gfx/ipc/CanvasManagerChild.h @@ -10,7 +10,6 @@ #include "mozilla/gfx/PCanvasManagerChild.h" #include "mozilla/gfx/Types.h" #include "mozilla/ThreadLocal.h" -#include <set> namespace mozilla { namespace dom { @@ -35,7 +34,8 @@ class CanvasManagerChild final : public PCanvasManagerChild { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CanvasManagerChild, override); - explicit CanvasManagerChild(uint32_t aId); + explicit CanvasManagerChild(dom::ThreadSafeWorkerRef* aWorkerRef, + uint32_t aId); uint32_t Id() const { return mId; } already_AddRefed<DataSourceSurface> GetSnapshot( uint32_t aManagerId, int32_t aProtocolId, @@ -49,9 +49,6 @@ class CanvasManagerChild final : public PCanvasManagerChild { static bool CreateParent( mozilla::ipc::Endpoint<PCanvasManagerParent>&& aEndpoint); - void AddShutdownObserver(dom::CanvasRenderingContext2D* aCanvas); - void RemoveShutdownObserver(dom::CanvasRenderingContext2D* aCanvas); - bool IsCanvasActive() { return mActive; } void EndCanvasTransaction(); void ClearCachedResources(); @@ -73,7 +70,6 @@ class CanvasManagerChild final : public PCanvasManagerChild { RefPtr<layers::CanvasChild> mCanvasChild; RefPtr<webgpu::WebGPUChild> mWebGPUChild; UniquePtr<layers::ActiveResourceTracker> mActiveResourceTracker; - std::set<dom::CanvasRenderingContext2D*> mActiveCanvas; const uint32_t mId; bool mActive = true; bool mBlocked = false; diff --git a/gfx/ipc/CanvasShutdownManager.cpp b/gfx/ipc/CanvasShutdownManager.cpp new file mode 100644 index 0000000000..d7fc96d255 --- /dev/null +++ b/gfx/ipc/CanvasShutdownManager.cpp @@ -0,0 +1,179 @@ +/* -*- 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 "CanvasShutdownManager.h" +#include "mozilla/AppShutdown.h" +#include "mozilla/dom/CanvasRenderingContext2D.h" +#include "mozilla/dom/WorkerPrivate.h" +#include "mozilla/dom/WorkerRef.h" +#include "mozilla/dom/WorkerRunnable.h" +#include "mozilla/gfx/CanvasManagerChild.h" + +using namespace mozilla::dom; + +namespace mozilla::gfx { + +StaticMutex CanvasShutdownManager::sManagersMutex; +std::set<CanvasShutdownManager*> CanvasShutdownManager::sManagers; + +// The owning thread will tell us to close when it is shutdown, either via +// CanvasShutdownManager::Shutdown for the main thread, or via a shutdown +// callback from ThreadSafeWorkerRef for worker threads. +MOZ_THREAD_LOCAL(CanvasShutdownManager*) CanvasShutdownManager::sLocalManager; + +CanvasShutdownManager::CanvasShutdownManager(StrongWorkerRef* aWorkerRef) + : mWorkerRef(new ThreadSafeWorkerRef(aWorkerRef)) {} + +CanvasShutdownManager::CanvasShutdownManager() = default; +CanvasShutdownManager::~CanvasShutdownManager() = default; + +void CanvasShutdownManager::Destroy() { + std::set<CanvasRenderingContext2D*> activeCanvas = std::move(mActiveCanvas); + for (const auto& i : activeCanvas) { + i->OnShutdown(); + } + + CanvasManagerChild::Shutdown(); + mWorkerRef = nullptr; +} + +/* static */ void CanvasShutdownManager::Shutdown() { + auto* manager = MaybeGet(); + if (!manager) { + return; + } + + { + StaticMutexAutoLock lock(sManagersMutex); + sManagers.erase(manager); + } + + sLocalManager.set(nullptr); + manager->Destroy(); + delete manager; +} + +/* static */ CanvasShutdownManager* CanvasShutdownManager::MaybeGet() { + if (NS_WARN_IF(!sLocalManager.init())) { + return nullptr; + } + + return sLocalManager.get(); +} + +/* static */ CanvasShutdownManager* CanvasShutdownManager::Get() { + if (NS_WARN_IF(!sLocalManager.init())) { + return nullptr; + } + + CanvasShutdownManager* managerWeak = sLocalManager.get(); + if (managerWeak) { + return managerWeak; + } + + if (WorkerPrivate* worker = GetCurrentThreadWorkerPrivate()) { + // The ThreadSafeWorkerRef will let us know when the worker is shutting + // down. This will let us clear our threadlocal reference and close the + // actor. We rely upon an explicit shutdown for the main thread. + RefPtr<StrongWorkerRef> workerRef = StrongWorkerRef::Create( + worker, "CanvasShutdownManager", []() { Shutdown(); }); + if (NS_WARN_IF(!workerRef)) { + return nullptr; + } + + CanvasShutdownManager* manager = new CanvasShutdownManager(workerRef); + sLocalManager.set(manager); + + StaticMutexAutoLock lock(sManagersMutex); + sManagers.insert(manager); + return manager; + } + + if (NS_IsMainThread()) { + if (NS_WARN_IF( + AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed))) { + return nullptr; + } + + CanvasShutdownManager* manager = new CanvasShutdownManager(); + sLocalManager.set(manager); + + StaticMutexAutoLock lock(sManagersMutex); + sManagers.insert(manager); + return manager; + } + + MOZ_ASSERT_UNREACHABLE("Can only be used on main or DOM worker threads!"); + return nullptr; +} + +void CanvasShutdownManager::AddShutdownObserver( + dom::CanvasRenderingContext2D* aCanvas) { + mActiveCanvas.insert(aCanvas); +} + +void CanvasShutdownManager::RemoveShutdownObserver( + dom::CanvasRenderingContext2D* aCanvas) { + mActiveCanvas.erase(aCanvas); +} + +void CanvasShutdownManager::OnRemoteCanvasLost() { + // Note that the canvas cannot do anything that mutates our state. It will + // dispatch for anything that risks re-entrancy. + for (const auto& canvas : mActiveCanvas) { + canvas->OnRemoteCanvasLost(); + } +} + +void CanvasShutdownManager::OnRemoteCanvasRestored() { + // Note that the canvas cannot do anything that mutates our state. It will + // dispatch for anything that risks re-entrancy. + for (const auto& canvas : mActiveCanvas) { + canvas->OnRemoteCanvasRestored(); + } +} + +/* static */ void CanvasShutdownManager::MaybeRestoreRemoteCanvas() { + // Calling Get will recreate the CanvasManagerChild, which in turn will + // cause us to call OnRemoteCanvasRestore upon success. + if (CanvasShutdownManager* manager = MaybeGet()) { + if (!manager->mActiveCanvas.empty()) { + CanvasManagerChild::Get(); + } + } +} + +/* static */ void CanvasShutdownManager::OnCompositorManagerRestored() { + MOZ_ASSERT(NS_IsMainThread()); + + class RestoreRunnable final : public WorkerRunnable { + public: + explicit RestoreRunnable(WorkerPrivate* aWorkerPrivate) + : WorkerRunnable(aWorkerPrivate, + "CanvasShutdownManager::RestoreRunnable") {} + + bool WorkerRun(JSContext*, WorkerPrivate*) override { + MaybeRestoreRemoteCanvas(); + return true; + } + }; + + // We can restore the main thread canvases immediately. + MaybeRestoreRemoteCanvas(); + + // And dispatch to restore any DOM worker canvases. This is safe because we + // remove the manager from sManagers before clearing mWorkerRef during DOM + // worker shutdown. + StaticMutexAutoLock lock(sManagersMutex); + for (const auto& manager : sManagers) { + if (manager->mWorkerRef) { + auto task = MakeRefPtr<RestoreRunnable>(manager->mWorkerRef->Private()); + task->Dispatch(); + } + } +} + +} // namespace mozilla::gfx diff --git a/gfx/ipc/CanvasShutdownManager.h b/gfx/ipc/CanvasShutdownManager.h new file mode 100644 index 0000000000..803d6a1eb8 --- /dev/null +++ b/gfx/ipc/CanvasShutdownManager.h @@ -0,0 +1,57 @@ +/* -*- 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 _include_gfx_ipc_CanvasShutdownManager_h__ +#define _include_gfx_ipc_CanvasShutdownManager_h__ + +#include "mozilla/RefPtr.h" +#include "mozilla/StaticMutex.h" +#include "mozilla/ThreadLocal.h" +#include <set> + +namespace mozilla { +namespace dom { +class CanvasRenderingContext2D; +class StrongWorkerRef; +class ThreadSafeWorkerRef; +} // namespace dom + +namespace gfx { + +class CanvasShutdownManager final { + public: + static CanvasShutdownManager* Get(); + static CanvasShutdownManager* MaybeGet(); + static void Shutdown(); + + dom::ThreadSafeWorkerRef* GetWorkerRef() const { return mWorkerRef; } + void AddShutdownObserver(dom::CanvasRenderingContext2D* aCanvas); + void RemoveShutdownObserver(dom::CanvasRenderingContext2D* aCanvas); + + static void OnCompositorManagerRestored(); + + void OnRemoteCanvasLost(); + void OnRemoteCanvasRestored(); + + private: + explicit CanvasShutdownManager(dom::StrongWorkerRef* aWorkerRef); + CanvasShutdownManager(); + ~CanvasShutdownManager(); + void Destroy(); + + static void MaybeRestoreRemoteCanvas(); + + RefPtr<dom::ThreadSafeWorkerRef> mWorkerRef; + std::set<dom::CanvasRenderingContext2D*> mActiveCanvas; + static MOZ_THREAD_LOCAL(CanvasShutdownManager*) sLocalManager; + + static StaticMutex sManagersMutex; + static std::set<CanvasShutdownManager*> sManagers; +}; + +} // namespace gfx +} // namespace mozilla + +#endif // _include_gfx_ipc_CanvasShutdownManager_h__ diff --git a/gfx/ipc/GPUParent.cpp b/gfx/ipc/GPUParent.cpp index 283fb87ee9..f4240a5d97 100644 --- a/gfx/ipc/GPUParent.cpp +++ b/gfx/ipc/GPUParent.cpp @@ -571,6 +571,19 @@ mozilla::ipc::IPCResult GPUParent::RecvPreferenceUpdate(const Pref& aPref) { return IPC_OK(); } +mozilla::ipc::IPCResult GPUParent::RecvScreenInformationChanged() { +#if defined(XP_WIN) + DeviceManagerDx::Get()->PostUpdateMonitorInfo(); +#endif + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvNotifyBatteryInfo( + const BatteryInformation& aBatteryInfo) { + wr::RenderThread::Get()->SetBatteryInfo(aBatteryInfo); + return IPC_OK(); +} + static void CopyFeatureChange(Feature aFeature, Maybe<FeatureFailure>* aOut) { FeatureState& feature = gfxConfig::GetFeature(aFeature); if (feature.DisabledByDefault() || feature.IsEnabled()) { diff --git a/gfx/ipc/GPUParent.h b/gfx/ipc/GPUParent.h index 434c9eab79..4c01761e77 100644 --- a/gfx/ipc/GPUParent.h +++ b/gfx/ipc/GPUParent.h @@ -74,6 +74,9 @@ class GPUParent final : public PGPUParent { Endpoint<PProfilerChild>&& aEndpoint); mozilla::ipc::IPCResult RecvUpdateVar(const GfxVarUpdate& pref); mozilla::ipc::IPCResult RecvPreferenceUpdate(const Pref& pref); + mozilla::ipc::IPCResult RecvScreenInformationChanged(); + mozilla::ipc::IPCResult RecvNotifyBatteryInfo( + const BatteryInformation& aBatteryInfo); mozilla::ipc::IPCResult RecvNewContentCompositorManager( Endpoint<PCompositorManagerParent>&& aEndpoint, const ContentParentId& aChildId, uint32_t aNamespace); diff --git a/gfx/ipc/GPUProcessManager.cpp b/gfx/ipc/GPUProcessManager.cpp index babc523e3a..97f4d47111 100644 --- a/gfx/ipc/GPUProcessManager.cpp +++ b/gfx/ipc/GPUProcessManager.cpp @@ -136,10 +136,28 @@ GPUProcessManager::Observer::Observe(nsISupports* aSubject, const char* aTopic, } } else if (!strcmp(aTopic, "application-background")) { mManager->mAppInForeground = false; + } else if (!strcmp(aTopic, "screen-information-changed")) { + mManager->ScreenInformationChanged(); } return NS_OK; } +GPUProcessManager::BatteryObserver::BatteryObserver(GPUProcessManager* aManager) + : mManager(aManager) { + hal::RegisterBatteryObserver(this); +} + +void GPUProcessManager::BatteryObserver::Notify( + const hal::BatteryInformation& aBatteryInfo) { + mManager->NotifyBatteryInfo(aBatteryInfo); +} + +void GPUProcessManager::BatteryObserver::ShutDown() { + hal::UnregisterBatteryObserver(this); +} + +GPUProcessManager::BatteryObserver::~BatteryObserver() {} + void GPUProcessManager::OnXPCOMShutdown() { if (mObserver) { nsContentUtils::UnregisterShutdownObserver(mObserver); @@ -148,6 +166,7 @@ void GPUProcessManager::OnXPCOMShutdown() { if (obsServ) { obsServ->RemoveObserver(mObserver, "application-foreground"); obsServ->RemoveObserver(mObserver, "application-background"); + obsServ->RemoveObserver(mObserver, "screen-information-changed"); } mObserver = nullptr; } @@ -172,6 +191,21 @@ void GPUProcessManager::OnPreferenceChange(const char16_t* aData) { } } +void GPUProcessManager::ScreenInformationChanged() { +#if defined(XP_WIN) + if (!!mGPUChild) { + mGPUChild->SendScreenInformationChanged(); + } +#endif +} + +void GPUProcessManager::NotifyBatteryInfo( + const hal::BatteryInformation& aBatteryInfo) { + if (mGPUChild) { + mGPUChild->SendNotifyBatteryInfo(aBatteryInfo); + } +} + void GPUProcessManager::ResetProcessStable() { mTotalProcessAttempts++; mProcessStable = false; @@ -207,6 +241,7 @@ bool GPUProcessManager::LaunchGPUProcess() { if (obsServ) { obsServ->AddObserver(mObserver, "application-foreground", false); obsServ->AddObserver(mObserver, "application-background", false); + obsServ->AddObserver(mObserver, "screen-information-changed", false); } } @@ -566,6 +601,9 @@ void GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost) { std::move(vsyncChild)); mGPUChild->SendInitVsyncBridge(std::move(vsyncParent)); + MOZ_ASSERT(!mBatteryObserver); + mBatteryObserver = new BatteryObserver(this); + // Flush any pref updates that happened during launch and weren't // included in the blobs set up in LaunchGPUProcess. for (const mozilla::dom::Pref& pref : mQueuedPrefs) { @@ -573,12 +611,11 @@ void GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost) { } mQueuedPrefs.Clear(); - CrashReporter::AnnotateCrashReport( - CrashReporter::Annotation::GPUProcessStatus, "Running"_ns); + CrashReporter::RecordAnnotationCString( + CrashReporter::Annotation::GPUProcessStatus, "Running"); - CrashReporter::AnnotateCrashReport( - CrashReporter::Annotation::GPUProcessLaunchCount, - static_cast<int>(mTotalProcessAttempts)); + CrashReporter::RecordAnnotationU32( + CrashReporter::Annotation::GPUProcessLaunchCount, mTotalProcessAttempts); ReinitializeRendering(); } @@ -754,8 +791,9 @@ void GPUProcessManager::NotifyWebRenderError(wr::WebRenderError aError) { Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON, uint32_t(aReason)); } - CrashReporter::AnnotateCrashReport( - CrashReporter::Annotation::DeviceResetReason, int(aReason)); + CrashReporter::RecordAnnotationU32( + CrashReporter::Annotation::DeviceResetReason, + static_cast<uint32_t>(aReason)); } bool GPUProcessManager::OnDeviceReset(bool aTrackThreshold) { @@ -1062,9 +1100,13 @@ void GPUProcessManager::DestroyProcess(bool aUnexpectedShutdown) { mVsyncBridge->Close(); mVsyncBridge = nullptr; } + if (mBatteryObserver) { + mBatteryObserver->ShutDown(); + mBatteryObserver = nullptr; + } - CrashReporter::AnnotateCrashReport( - CrashReporter::Annotation::GPUProcessStatus, "Destroyed"_ns); + CrashReporter::RecordAnnotationCString( + CrashReporter::Annotation::GPUProcessStatus, "Destroyed"); } already_AddRefed<CompositorSession> GPUProcessManager::CreateTopLevelCompositor( diff --git a/gfx/ipc/GPUProcessManager.h b/gfx/ipc/GPUProcessManager.h index bf5b7e6587..8b58d15b54 100644 --- a/gfx/ipc/GPUProcessManager.h +++ b/gfx/ipc/GPUProcessManager.h @@ -14,6 +14,7 @@ #include "mozilla/gfx/GPUProcessHost.h" #include "mozilla/gfx/PGPUChild.h" #include "mozilla/gfx/Point.h" +#include "mozilla/Hal.h" #include "mozilla/ipc/ProtocolUtils.h" #include "mozilla/ipc/TaskFactory.h" #include "mozilla/layers/LayersTypes.h" @@ -214,6 +215,7 @@ class GPUProcessManager final : public GPUProcessHost::Listener { // Called from our xpcom-shutdown observer. void OnXPCOMShutdown(); void OnPreferenceChange(const char16_t* aData); + void ScreenInformationChanged(); bool CreateContentCompositorManager( base::ProcessId aOtherProcess, dom::ContentParentId aChildId, @@ -309,6 +311,8 @@ class GPUProcessManager final : public GPUProcessHost::Listener { DISALLOW_COPY_AND_ASSIGN(GPUProcessManager); + void NotifyBatteryInfo(const hal::BatteryInformation& aBatteryInfo); + class Observer final : public nsIObserver { public: NS_DECL_ISUPPORTS @@ -322,10 +326,25 @@ class GPUProcessManager final : public GPUProcessHost::Listener { }; friend class Observer; + class BatteryObserver final : public hal::BatteryObserver { + public: + NS_INLINE_DECL_REFCOUNTING(BatteryObserver) + explicit BatteryObserver(GPUProcessManager* aManager); + + void Notify(const hal::BatteryInformation& aBatteryInfo) override; + void ShutDown(); + + protected: + virtual ~BatteryObserver(); + + GPUProcessManager* mManager; + }; + private: bool mDecodeVideoOnGpuProcess = true; RefPtr<Observer> mObserver; + RefPtr<BatteryObserver> mBatteryObserver; mozilla::ipc::TaskFactory<GPUProcessManager> mTaskFactory; RefPtr<VsyncIOThreadHolder> mVsyncIOThread; uint32_t mNextNamespace; diff --git a/gfx/ipc/PGPU.ipdl b/gfx/ipc/PGPU.ipdl index b6e84bf142..aabb81dc43 100644 --- a/gfx/ipc/PGPU.ipdl +++ b/gfx/ipc/PGPU.ipdl @@ -41,6 +41,7 @@ using mozilla::layers::OverlayInfo from "mozilla/layers/OverlayInfo.h"; using mozilla::layers::SwapChainInfo from "mozilla/layers/OverlayInfo.h"; using mozilla::media::MediaCodecsSupported from "MediaCodecsSupport.h"; using mozilla::layers::VideoBridgeSource from "mozilla/layers/VideoBridgeUtils.h"; +using mozilla::hal::BatteryInformation from "mozilla/hal_sandbox/PHal.h"; namespace mozilla { namespace gfx { @@ -79,6 +80,8 @@ parent: async UpdateVar(GfxVarUpdate var); async PreferenceUpdate(Pref pref); + async ScreenInformationChanged(); + async NotifyBatteryInfo(BatteryInformation aBatteryInfo); // Create a new content-process compositor bridge. async NewContentCompositorManager(Endpoint<PCompositorManagerParent> endpoint, ContentParentId childId, uint32_t aNamespace); diff --git a/gfx/ipc/moz.build b/gfx/ipc/moz.build index b8a52079e4..cc007a8193 100644 --- a/gfx/ipc/moz.build +++ b/gfx/ipc/moz.build @@ -13,6 +13,7 @@ EXPORTS.mozilla.gfx += [ "CanvasManagerChild.h", "CanvasManagerParent.h", "CanvasRenderThread.h", + "CanvasShutdownManager.h", "CrossProcessPaint.h", "FileHandleWrapper.h", "GPUChild.h", @@ -42,6 +43,7 @@ UNIFIED_SOURCES += [ "CanvasManagerChild.cpp", "CanvasManagerParent.cpp", "CanvasRenderThread.cpp", + "CanvasShutdownManager.cpp", "CompositorSession.cpp", "CompositorWidgetVsyncObserver.cpp", "CrossProcessPaint.cpp", diff --git a/gfx/layers/BuildConstants.h b/gfx/layers/BuildConstants.h index 6db150d136..cebdd35371 100644 --- a/gfx/layers/BuildConstants.h +++ b/gfx/layers/BuildConstants.h @@ -52,6 +52,13 @@ constexpr bool kIsAndroid = false; #endif +constexpr bool kIsDmd = +#ifdef MOZ_DMD + true; +#else + false; +#endif + } // namespace mozilla #endif // BUILD_CONSTANTS_H_ diff --git a/gfx/layers/CanvasDrawEventRecorder.cpp b/gfx/layers/CanvasDrawEventRecorder.cpp index 1bf928b816..af143bf5cb 100644 --- a/gfx/layers/CanvasDrawEventRecorder.cpp +++ b/gfx/layers/CanvasDrawEventRecorder.cpp @@ -8,6 +8,11 @@ #include <string.h> +#include "mozilla/dom/WorkerCommon.h" +#include "mozilla/dom/WorkerPrivate.h" +#include "mozilla/dom/WorkerRef.h" +#include "mozilla/dom/WorkerRunnable.h" +#include "mozilla/layers/TextureRecorded.h" #include "mozilla/layers/SharedSurfacesChild.h" #include "mozilla/StaticPrefs_gfx.h" #include "RecordedCanvasEventImpl.h" @@ -34,7 +39,9 @@ static Maybe<ShmemAndHandle> CreateAndMapShmem(size_t aSize) { return Some(ShmemAndHandle{shmem.forget(), std::move(shmemHandle)}); } -CanvasDrawEventRecorder::CanvasDrawEventRecorder() { +CanvasDrawEventRecorder::CanvasDrawEventRecorder( + dom::ThreadSafeWorkerRef* aWorkerRef) + : mWorkerRef(aWorkerRef), mIsOnWorker(!!aWorkerRef) { mDefaultBufferSize = ipc::SharedMemory::PageAlignedSize( StaticPrefs::gfx_canvas_remote_default_buffer_size()); mMaxDefaultBuffers = StaticPrefs::gfx_canvas_remote_max_default_buffers(); @@ -43,7 +50,10 @@ CanvasDrawEventRecorder::CanvasDrawEventRecorder() { mDropBufferOnZero = mDropBufferLimit; } +CanvasDrawEventRecorder::~CanvasDrawEventRecorder() { MOZ_ASSERT(!mWorkerRef); } + bool CanvasDrawEventRecorder::Init(TextureType aTextureType, + TextureType aWebglTextureType, gfx::BackendType aBackendType, UniquePtr<Helpers> aHelpers) { NS_ASSERT_OWNINGTHREAD(CanvasDrawEventRecorder); @@ -95,7 +105,7 @@ bool CanvasDrawEventRecorder::Init(TextureType aTextureType, return false; } - if (!mHelpers->InitTranslator(aTextureType, aBackendType, + if (!mHelpers->InitTranslator(aTextureType, aWebglTextureType, aBackendType, std::move(header->handle), std::move(bufferHandles), mDefaultBufferSize, std::move(readerSem), std::move(writerSem))) { @@ -317,6 +327,106 @@ void CanvasDrawEventRecorder::CheckAndSignalReader() { } while (true); } +void CanvasDrawEventRecorder::DetachResources() { + NS_ASSERT_OWNINGTHREAD(CanvasDrawEventRecorder); + + DrawEventRecorderPrivate::DetachResources(); + + { + auto lockedPendingDeletions = mPendingDeletions.Lock(); + mWorkerRef = nullptr; + } +} + +void CanvasDrawEventRecorder::QueueProcessPendingDeletionsLocked( + RefPtr<CanvasDrawEventRecorder>&& aRecorder) { + if (!mWorkerRef) { + MOZ_RELEASE_ASSERT( + !mIsOnWorker, + "QueueProcessPendingDeletionsLocked called after worker shutdown!"); + + NS_DispatchToMainThread(NS_NewRunnableFunction( + "CanvasDrawEventRecorder::QueueProcessPendingDeletionsLocked", + [self = std::move(aRecorder)]() { self->ProcessPendingDeletions(); })); + return; + } + + if (!NS_IsMainThread()) { + NS_DispatchToMainThread(NS_NewRunnableFunction( + "CanvasDrawEventRecorder::QueueProcessPendingDeletionsLocked", + [self = std::move(aRecorder)]() mutable { + self->QueueProcessPendingDeletions(std::move(self)); + })); + return; + } + + class ProcessPendingRunnable final : public dom::WorkerRunnable { + public: + ProcessPendingRunnable(dom::WorkerPrivate* aWorkerPrivate, + RefPtr<CanvasDrawEventRecorder>&& aRecorder) + : dom::WorkerRunnable(aWorkerPrivate), + mRecorder(std::move(aRecorder)) {} + + bool WorkerRun(JSContext*, dom::WorkerPrivate*) override { + RefPtr<CanvasDrawEventRecorder> recorder = std::move(mRecorder); + recorder->ProcessPendingDeletions(); + return true; + } + + private: + RefPtr<CanvasDrawEventRecorder> mRecorder; + }; + + auto task = MakeRefPtr<ProcessPendingRunnable>(mWorkerRef->Private(), + std::move(aRecorder)); + if (NS_WARN_IF(!task->Dispatch())) { + MOZ_CRASH("ProcessPendingRunnable leaked!"); + } +} + +void CanvasDrawEventRecorder::QueueProcessPendingDeletions( + RefPtr<CanvasDrawEventRecorder>&& aRecorder) { + auto lockedPendingDeletions = mPendingDeletions.Lock(); + if (lockedPendingDeletions->empty()) { + // We raced to handle the deletions, and something got there first. + return; + } + + QueueProcessPendingDeletionsLocked(std::move(aRecorder)); +} + +void CanvasDrawEventRecorder::AddPendingDeletion( + std::function<void()>&& aPendingDeletion) { + PendingDeletionsVector pendingDeletions; + + { + auto lockedPendingDeletions = mPendingDeletions.Lock(); + bool wasEmpty = lockedPendingDeletions->empty(); + lockedPendingDeletions->emplace_back(std::move(aPendingDeletion)); + + MOZ_RELEASE_ASSERT(!mIsOnWorker || mWorkerRef, + "AddPendingDeletion called after worker shutdown!"); + + // If we are not on the owning thread, we must queue an event to run the + // deletions, if we transitioned from empty to non-empty. + if ((mWorkerRef && !mWorkerRef->Private()->IsOnCurrentThread()) || + (!mWorkerRef && !NS_IsMainThread())) { + if (wasEmpty) { + RefPtr<CanvasDrawEventRecorder> self(this); + QueueProcessPendingDeletionsLocked(std::move(self)); + } + return; + } + + // Otherwise, we can just run all of them right now. + pendingDeletions.swap(*lockedPendingDeletions); + } + + for (const auto& pendingDeletion : pendingDeletions) { + pendingDeletion(); + } +} + void CanvasDrawEventRecorder::StoreSourceSurfaceRecording( gfx::SourceSurface* aSurface, const char* aReason) { NS_ASSERT_OWNINGTHREAD(CanvasDrawEventRecorder); diff --git a/gfx/layers/CanvasDrawEventRecorder.h b/gfx/layers/CanvasDrawEventRecorder.h index a4b1261cfb..c9eacf27ac 100644 --- a/gfx/layers/CanvasDrawEventRecorder.h +++ b/gfx/layers/CanvasDrawEventRecorder.h @@ -21,6 +21,10 @@ namespace mozilla { using EventType = gfx::RecordedEvent::EventType; +namespace dom { +class ThreadSafeWorkerRef; +} + namespace layers { typedef mozilla::ipc::SharedMemoryBasic::Handle Handle; @@ -31,7 +35,8 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate, public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(CanvasDrawEventRecorder, final) - CanvasDrawEventRecorder(); + explicit CanvasDrawEventRecorder(dom::ThreadSafeWorkerRef* aWorkerRef); + ~CanvasDrawEventRecorder() override; enum class State : uint32_t { Processing, @@ -68,6 +73,7 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate, virtual ~Helpers() = default; virtual bool InitTranslator(TextureType aTextureType, + TextureType aWebglTextureType, gfx::BackendType aBackendType, Handle&& aReadHandle, nsTArray<Handle>&& aBufferHandles, @@ -89,8 +95,8 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate, virtual bool RestartReader() = 0; }; - bool Init(TextureType aTextureType, gfx::BackendType aBackendType, - UniquePtr<Helpers> aHelpers); + bool Init(TextureType aTextureType, TextureType aWebglTextureType, + gfx::BackendType aBackendType, UniquePtr<Helpers> aHelpers); /** * Record an event for processing by the CanvasParent's CanvasTranslator. @@ -98,6 +104,10 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate, */ void RecordEvent(const gfx::RecordedEvent& aEvent) final; + void DetachResources() final; + + void AddPendingDeletion(std::function<void()>&& aPendingDeletion) override; + void StoreSourceSurfaceRecording(gfx::SourceSurface* aSurface, const char* aReason) final; @@ -134,6 +144,11 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate, void CheckAndSignalReader(); + void QueueProcessPendingDeletions( + RefPtr<CanvasDrawEventRecorder>&& aRecorder); + void QueueProcessPendingDeletionsLocked( + RefPtr<CanvasDrawEventRecorder>&& aRecorder); + size_t mDefaultBufferSize; size_t mMaxDefaultBuffers; uint32_t mMaxSpinCount; @@ -173,6 +188,9 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate, UniquePtr<CrossProcessSemaphore> mWriterSemaphore; UniquePtr<CrossProcessSemaphore> mReaderSemaphore; + + RefPtr<dom::ThreadSafeWorkerRef> mWorkerRef; + bool mIsOnWorker = false; }; } // namespace layers diff --git a/gfx/layers/FrameMetrics.cpp b/gfx/layers/FrameMetrics.cpp index 5d82b7f295..86fdd5ffd6 100644 --- a/gfx/layers/FrameMetrics.cpp +++ b/gfx/layers/FrameMetrics.cpp @@ -147,12 +147,10 @@ CSSSize FrameMetrics::CalculateCompositedSizeInCssPixels( return aCompositionBounds.Size() / aZoom; } -std::pair<bool, CSSPoint> FrameMetrics::ApplyAbsoluteScrollUpdateFrom( - const ScrollPositionUpdate& aUpdate) { - CSSPoint oldVisualOffset = GetVisualScrollOffset(); +bool FrameMetrics::ApplyScrollUpdateFrom(const ScrollPositionUpdate& aUpdate) { // In applying a main-thread scroll update, try to preserve the relative // offset between the visual and layout viewports. - CSSPoint relativeOffset = oldVisualOffset - GetLayoutScrollOffset(); + CSSPoint relativeOffset = GetVisualScrollOffset() - GetLayoutScrollOffset(); MOZ_ASSERT(IsRootContent() || relativeOffset == CSSPoint()); // We need to set the two offsets together, otherwise a subsequent // RecalculateLayoutViewportOffset() could see divergent layout and @@ -160,7 +158,7 @@ std::pair<bool, CSSPoint> FrameMetrics::ApplyAbsoluteScrollUpdateFrom( bool offsetChanged = SetLayoutScrollOffset(aUpdate.GetDestination()); offsetChanged |= ClampAndSetVisualScrollOffset(aUpdate.GetDestination() + relativeOffset); - return {offsetChanged, GetVisualScrollOffset() - oldVisualOffset}; + return offsetChanged; } CSSPoint FrameMetrics::ApplyRelativeScrollUpdateFrom( @@ -168,7 +166,7 @@ CSSPoint FrameMetrics::ApplyRelativeScrollUpdateFrom( MOZ_ASSERT(aUpdate.GetType() == ScrollUpdateType::Relative); CSSPoint origin = GetVisualScrollOffset(); CSSPoint delta = (aUpdate.GetDestination() - aUpdate.GetSource()); - ClampAndSetVisualScrollOffset(origin + delta); + SetVisualScrollOffset(origin + delta); return GetVisualScrollOffset() - origin; } diff --git a/gfx/layers/FrameMetrics.h b/gfx/layers/FrameMetrics.h index 6b7a41bf25..5d13d36703 100644 --- a/gfx/layers/FrameMetrics.h +++ b/gfx/layers/FrameMetrics.h @@ -243,11 +243,9 @@ struct FrameMetrics { } /* - * Returns true if the layout scroll offset or visual scroll offset changed - * and returns the visual scroll offset change delta. + * Returns true if the layout scroll offset or visual scroll offset changed. */ - std::pair<bool, CSSPoint> ApplyAbsoluteScrollUpdateFrom( - const ScrollPositionUpdate& aUpdate); + bool ApplyScrollUpdateFrom(const ScrollPositionUpdate& aUpdate); /** * Applies the relative scroll offset update contained in aOther to the @@ -893,6 +891,12 @@ struct ScrollMetadata { mScrollUpdates.AppendElements(std::move(aUpdates)); } + void PrependUpdates(const nsTArray<ScrollPositionUpdate>& aUpdates) { + MOZ_ASSERT(!aUpdates.IsEmpty()); + + mScrollUpdates.InsertElementsAt(0, aUpdates); + } + private: FrameMetrics mMetrics; diff --git a/gfx/layers/ImageContainer.cpp b/gfx/layers/ImageContainer.cpp index 8a4c03f5a2..bdedccf56d 100644 --- a/gfx/layers/ImageContainer.cpp +++ b/gfx/layers/ImageContainer.cpp @@ -34,7 +34,7 @@ #include "nsProxyRelease.h" #include "nsISupportsUtils.h" // for NS_IF_ADDREF -#ifdef XP_MACOSX +#ifdef XP_DARWIN # include "MacIOSurfaceImage.h" #endif @@ -563,7 +563,7 @@ ImageContainer::GetD3D11YCbCrRecycleAllocator( } #endif -#ifdef XP_MACOSX +#ifdef XP_DARWIN already_AddRefed<MacIOSurfaceRecycleAllocator> ImageContainer::GetMacIOSurfaceRecycleAllocator() { RecursiveMutexAutoLock lock(mRecursiveMutex); diff --git a/gfx/layers/ImageContainer.h b/gfx/layers/ImageContainer.h index 253ba417eb..6fa12cf195 100644 --- a/gfx/layers/ImageContainer.h +++ b/gfx/layers/ImageContainer.h @@ -63,7 +63,7 @@ class MemoryOrShmem; class D3D11RecycleAllocator; class D3D11YCbCrRecycleAllocator; #endif -#ifdef XP_MACOSX +#ifdef XP_DARWIN class MacIOSurfaceRecycleAllocator; #endif class SurfaceDescriptorBuffer; @@ -80,7 +80,7 @@ class GLImage; class SharedRGBImage; #ifdef MOZ_WIDGET_ANDROID class SurfaceTextureImage; -#elif defined(XP_MACOSX) +#elif defined(XP_DARWIN) class MacIOSurfaceImage; #elif MOZ_WIDGET_GTK class DMABUFSurfaceImage; @@ -159,7 +159,7 @@ class Image { #ifdef MOZ_WIDGET_ANDROID virtual SurfaceTextureImage* AsSurfaceTextureImage() { return nullptr; } #endif -#ifdef XP_MACOSX +#ifdef XP_DARWIN virtual MacIOSurfaceImage* AsMacIOSurfaceImage() { return nullptr; } #endif virtual PlanarYCbCrImage* AsPlanarYCbCrImage() { return nullptr; } @@ -191,8 +191,8 @@ class Image { virtual ~Image() = default; mozilla::EnumeratedArray<mozilla::layers::LayersBackend, - mozilla::layers::LayersBackend::LAYERS_LAST, - UniquePtr<ImageBackendData>> + UniquePtr<ImageBackendData>, + size_t(mozilla::layers::LayersBackend::LAYERS_LAST)> mBackendData; void* mImplData; @@ -530,7 +530,7 @@ class ImageContainer final : public SupportsThreadSafeWeakPtr<ImageContainer> { KnowsCompositor* aKnowsCompositor); #endif -#ifdef XP_MACOSX +#ifdef XP_DARWIN already_AddRefed<MacIOSurfaceRecycleAllocator> GetMacIOSurfaceRecycleAllocator(); #endif @@ -618,7 +618,7 @@ class ImageContainer final : public SupportsThreadSafeWeakPtr<ImageContainer> { RefPtr<D3D11YCbCrRecycleAllocator> mD3D11YCbCrRecycleAllocator MOZ_GUARDED_BY(mRecursiveMutex); #endif -#ifdef XP_MACOSX +#ifdef XP_DARWIN RefPtr<MacIOSurfaceRecycleAllocator> mMacIOSurfaceRecycleAllocator MOZ_GUARDED_BY(mRecursiveMutex); #endif diff --git a/gfx/layers/NativeLayerCA.h b/gfx/layers/NativeLayerCA.h index 1424c1251f..b41ac36c23 100644 --- a/gfx/layers/NativeLayerCA.h +++ b/gfx/layers/NativeLayerCA.h @@ -6,7 +6,7 @@ #ifndef mozilla_layers_NativeLayerCA_h #define mozilla_layers_NativeLayerCA_h -#include <IOSurface/IOSurface.h> +#include <IOSurface/IOSurfaceRef.h> #include <deque> #include <unordered_map> @@ -39,7 +39,9 @@ class RenderMacIOSurfaceTextureHost; namespace layers { +#ifdef XP_MACOSX class NativeLayerRootSnapshotterCA; +#endif class SurfacePoolHandleCA; enum class VideoLowPowerType { @@ -102,8 +104,10 @@ class NativeLayerRootCA : public NativeLayerRoot { bool CommitToScreen() override; void CommitOffscreen(); +#ifdef XP_MACOSX void OnNativeLayerRootSnapshotterDestroyed( NativeLayerRootSnapshotterCA* aNativeLayerRootSnapshotter); +#endif // Enters a mode during which CommitToScreen(), when called on a non-main // thread, will not apply any updates to the CALayer tree. @@ -139,7 +143,7 @@ class NativeLayerRootCA : public NativeLayerRoot { void SetWindowIsFullscreen(bool aFullscreen); - VideoLowPowerType CheckVideoLowPower(const MutexAutoLock& aProofOfLock); + VideoLowPowerType CheckVideoLowPower(); protected: explicit NativeLayerRootCA(CALayer* aLayer); @@ -149,7 +153,8 @@ class NativeLayerRootCA : public NativeLayerRoot { explicit Representation(CALayer* aRootCALayer); ~Representation(); void Commit(WhichRepresentation aRepresentation, - const nsTArray<RefPtr<NativeLayerCA>>& aSublayers); + const nsTArray<RefPtr<NativeLayerCA>>& aSublayers, + bool aWindowIsFullscreen); CALayer* mRootCALayer = nullptr; // strong bool mMutatedLayerStructure = false; }; @@ -160,7 +165,9 @@ class NativeLayerRootCA : public NativeLayerRoot { Mutex mMutex MOZ_UNANNOTATED; // protects all other fields Representation mOnscreenRepresentation; Representation mOffscreenRepresentation; +#ifdef XP_MACOSX NativeLayerRootSnapshotterCA* mWeakSnapshotter = nullptr; +#endif nsTArray<RefPtr<NativeLayerCA>> mSublayers; // in z-order float mBackingScale = 1.0f; bool mMutated = false; @@ -188,6 +195,7 @@ class NativeLayerRootCA : public NativeLayerRoot { class RenderSourceNLRS; +#ifdef XP_MACOSX class NativeLayerRootSnapshotterCA final : public NativeLayerRootSnapshotter { public: static UniquePtr<NativeLayerRootSnapshotterCA> Create( @@ -217,6 +225,7 @@ class NativeLayerRootSnapshotterCA final : public NativeLayerRootSnapshotter { RefPtr<RenderSourceNLRS> mSnapshot; CARenderer* mRenderer = nullptr; // strong }; +#endif // NativeLayerCA wraps a CALayer and lets you draw to it. It ensures that only // fully-drawn frames make their way to the screen, by maintaining a swap chain @@ -260,6 +269,8 @@ class NativeLayerCA : public NativeLayer { void AttachExternalImage(wr::RenderTextureHost* aExternalImage) override; + void SetRootWindowIsFullscreen(bool aFullscreen); + protected: friend class NativeLayerRootCA; @@ -324,7 +335,8 @@ class NativeLayerCA : public NativeLayer { Maybe<SurfaceWithInvalidRegion> GetUnusedSurfaceAndCleanUp( const MutexAutoLock& aProofOfLock); - bool IsVideo(const MutexAutoLock& aProofOfLock); + bool IsVideo(); + bool IsVideoAndLocked(const MutexAutoLock& aProofOfLock); bool ShouldSpecializeVideo(const MutexAutoLock& aProofOfLock); bool HasExtent() const { return mHasExtent; } void SetHasExtent(bool aHasExtent) { mHasExtent = aHasExtent; } @@ -468,10 +480,10 @@ class NativeLayerCA : public NativeLayer { bool mSurfaceIsFlipped = false; CFTypeRefPtr<CGColorRef> mColor; const bool mIsOpaque = false; + bool mRootWindowIsFullscreen = false; bool mSpecializeVideo = false; bool mHasExtent = false; bool mIsDRM = false; - bool mIsTextureHostVideo = false; #ifdef NIGHTLY_BUILD // Track the consistency of our caller's API usage. Layers that are drawn diff --git a/gfx/layers/NativeLayerCA.mm b/gfx/layers/NativeLayerCA.mm index bd0b50e91b..42a889184e 100644 --- a/gfx/layers/NativeLayerCA.mm +++ b/gfx/layers/NativeLayerCA.mm @@ -5,10 +5,12 @@ #include "mozilla/layers/NativeLayerCA.h" -#import <AppKit/NSAnimationContext.h> -#import <AppKit/NSColor.h> +#ifdef XP_MACOSX +# import <AppKit/NSAnimationContext.h> +# import <AppKit/NSColor.h> +# import <OpenGL/gl.h> +#endif #import <AVFoundation/AVFoundation.h> -#import <OpenGL/gl.h> #import <QuartzCore/QuartzCore.h> #include <algorithm> @@ -19,7 +21,11 @@ #include "gfxUtils.h" #include "GLBlitHelper.h" -#include "GLContextCGL.h" +#ifdef XP_MACOSX +# include "GLContextCGL.h" +#else +# include "GLContextEAGL.h" +#endif #include "GLContextProvider.h" #include "MozFramebuffer.h" #include "mozilla/gfx/Swizzle.h" @@ -45,7 +51,9 @@ using gfx::IntSize; using gfx::Matrix4x4; using gfx::SurfaceFormat; using gl::GLContext; +#ifdef XP_MACOSX using gl::GLContextCGL; +#endif static Maybe<Telemetry::LABELS_GFX_MACOS_VIDEO_LOW_POWER> VideoLowPowerTypeToTelemetryType(VideoLowPowerType aVideoLowPower) { @@ -150,13 +158,23 @@ class AsyncReadbackBufferNLRS // protection, see bug 1585523. struct MOZ_STACK_CLASS AutoCATransaction final { AutoCATransaction() { +#ifdef XP_MACOSX [NSAnimationContext beginGrouping]; +#else + [CATransaction begin]; +#endif // By default, mutating a CALayer property triggers an animation which // smoothly transitions the property to the new value. We don't need these // animations, and this call turns them off: [CATransaction setDisableActions:YES]; } - ~AutoCATransaction() { [NSAnimationContext endGrouping]; } + ~AutoCATransaction() { +#ifdef XP_MACOSX + [NSAnimationContext endGrouping]; +#else + [CATransaction commit]; +#endif + } }; /* static */ already_AddRefed<NativeLayerRootCA> @@ -178,9 +196,9 @@ static CALayer* MakeOffscreenRootCALayer() { // down). AutoCATransaction transaction; CALayer* layer = [CALayer layer]; - layer.position = NSZeroPoint; - layer.bounds = NSZeroRect; - layer.anchorPoint = NSZeroPoint; + layer.position = CGPointZero; + layer.bounds = CGRectZero; + layer.anchorPoint = CGPointZero; layer.contentsGravity = kCAGravityTopLeft; layer.masksToBounds = YES; layer.geometryFlipped = YES; @@ -226,6 +244,7 @@ void NativeLayerRootCA::AppendLayer(NativeLayer* aLayer) { mSublayers.AppendElement(layerCA); layerCA->SetBackingScale(mBackingScale); + layerCA->SetRootWindowIsFullscreen(mWindowIsFullscreen); ForAllRepresentations( [&](Representation& r) { r.mMutatedLayerStructure = true; }); } @@ -257,6 +276,7 @@ void NativeLayerRootCA::SetLayers( RefPtr<NativeLayerCA> layerCA = layer->AsNativeLayerCA(); MOZ_RELEASE_ASSERT(layerCA); layerCA->SetBackingScale(mBackingScale); + layerCA->SetRootWindowIsFullscreen(mWindowIsFullscreen); layersCA.AppendElement(std::move(layerCA)); } @@ -306,47 +326,48 @@ bool NativeLayerRootCA::CommitToScreen() { return false; } - mOnscreenRepresentation.Commit(WhichRepresentation::ONSCREEN, mSublayers); + mOnscreenRepresentation.Commit(WhichRepresentation::ONSCREEN, mSublayers, + mWindowIsFullscreen); mCommitPending = false; + } - if (StaticPrefs::gfx_webrender_debug_dump_native_layer_tree_to_file()) { - static uint32_t sFrameID = 0; - uint32_t frameID = sFrameID++; - - NSString* dirPath = - [NSString stringWithFormat:@"%@/Desktop/nativelayerdumps-%d", - NSHomeDirectory(), getpid()]; - if ([NSFileManager.defaultManager createDirectoryAtPath:dirPath - withIntermediateDirectories:YES - attributes:nil - error:nullptr]) { - NSString* filename = - [NSString stringWithFormat:@"frame-%d.html", frameID]; - NSString* filePath = [dirPath stringByAppendingPathComponent:filename]; - DumpLayerTreeToFile([filePath UTF8String]); - } else { - NSLog(@"Failed to create directory %@", dirPath); - } + if (StaticPrefs::gfx_webrender_debug_dump_native_layer_tree_to_file()) { + static uint32_t sFrameID = 0; + uint32_t frameID = sFrameID++; + + NSString* dirPath = + [NSString stringWithFormat:@"%@/Desktop/nativelayerdumps-%d", + NSHomeDirectory(), getpid()]; + if ([NSFileManager.defaultManager createDirectoryAtPath:dirPath + withIntermediateDirectories:YES + attributes:nil + error:nullptr]) { + NSString* filename = + [NSString stringWithFormat:@"frame-%d.html", frameID]; + NSString* filePath = [dirPath stringByAppendingPathComponent:filename]; + DumpLayerTreeToFile([filePath UTF8String]); + } else { + NSLog(@"Failed to create directory %@", dirPath); } + } - // Decide if we are going to emit telemetry about video low power on this - // commit. - static const int32_t TELEMETRY_COMMIT_PERIOD = - StaticPrefs::gfx_core_animation_low_power_telemetry_frames_AtStartup(); - mTelemetryCommitCount = - (mTelemetryCommitCount + 1) % TELEMETRY_COMMIT_PERIOD; - if (mTelemetryCommitCount == 0) { - // Figure out if we are hitting video low power mode. - VideoLowPowerType videoLowPower = CheckVideoLowPower(lock); - EmitTelemetryForVideoLowPower(videoLowPower); - } + // Decide if we are going to emit telemetry about video low power on this + // commit. + static const int32_t TELEMETRY_COMMIT_PERIOD = + StaticPrefs::gfx_core_animation_low_power_telemetry_frames_AtStartup(); + mTelemetryCommitCount = (mTelemetryCommitCount + 1) % TELEMETRY_COMMIT_PERIOD; + if (mTelemetryCommitCount == 0) { + // Figure out if we are hitting video low power mode. + VideoLowPowerType videoLowPower = CheckVideoLowPower(); + EmitTelemetryForVideoLowPower(videoLowPower); } return true; } UniquePtr<NativeLayerRootSnapshotter> NativeLayerRootCA::CreateSnapshotter() { +#ifdef XP_MACOSX MutexAutoLock lock(mMutex); MOZ_RELEASE_ASSERT(!mWeakSnapshotter, "No NativeLayerRootSnapshotter for this NativeLayerRoot " @@ -358,18 +379,24 @@ UniquePtr<NativeLayerRootSnapshotter> NativeLayerRootCA::CreateSnapshotter() { mWeakSnapshotter = cr.get(); } return cr; +#else + return nullptr; +#endif } +#ifdef XP_MACOSX void NativeLayerRootCA::OnNativeLayerRootSnapshotterDestroyed( NativeLayerRootSnapshotterCA* aNativeLayerRootSnapshotter) { MutexAutoLock lock(mMutex); MOZ_RELEASE_ASSERT(mWeakSnapshotter == aNativeLayerRootSnapshotter); mWeakSnapshotter = nullptr; } +#endif void NativeLayerRootCA::CommitOffscreen() { MutexAutoLock lock(mMutex); - mOffscreenRepresentation.Commit(WhichRepresentation::OFFSCREEN, mSublayers); + mOffscreenRepresentation.Commit(WhichRepresentation::OFFSCREEN, mSublayers, + mWindowIsFullscreen); } template <typename F> @@ -394,7 +421,8 @@ NativeLayerRootCA::Representation::~Representation() { void NativeLayerRootCA::Representation::Commit( WhichRepresentation aRepresentation, - const nsTArray<RefPtr<NativeLayerCA>>& aSublayers) { + const nsTArray<RefPtr<NativeLayerCA>>& aSublayers, + bool aWindowIsFullscreen) { bool mustRebuild = mMutatedLayerStructure; if (!mustRebuild) { // Check which type of update we need to do, if any. @@ -439,7 +467,7 @@ void NativeLayerRootCA::Representation::Commit( mustRebuild |= layer->WillUpdateAffectLayers(aRepresentation); layer->ApplyChanges(aRepresentation, NativeLayerCA::UpdateType::All); CALayer* caLayer = layer->UnderlyingCALayer(aRepresentation); - if (!caLayer.masksToBounds || !NSIsEmptyRect(caLayer.bounds)) { + if (!caLayer.masksToBounds || !CGRectIsEmpty(caLayer.bounds)) { // This layer has an extent. If it didn't before, we need to rebuild. mustRebuild |= !layer->HasExtent(); layer->SetHasExtent(true); @@ -472,6 +500,7 @@ void NativeLayerRootCA::Representation::Commit( mMutatedLayerStructure = false; } +#ifdef XP_MACOSX /* static */ UniquePtr<NativeLayerRootSnapshotterCA> NativeLayerRootSnapshotterCA::Create(NativeLayerRootCA* aLayerRoot, CALayer* aRootCALayer) { @@ -498,6 +527,7 @@ NativeLayerRootSnapshotterCA::Create(NativeLayerRootCA* aLayerRoot, new NativeLayerRootSnapshotterCA(aLayerRoot, std::move(gl), aRootCALayer)); } +#endif void NativeLayerRootCA::DumpLayerTreeToFile(const char* aPath) { MutexAutoLock lock(mMutex); @@ -519,7 +549,15 @@ void NativeLayerRootCA::DumpLayerTreeToFile(const char* aPath) { } void NativeLayerRootCA::SetWindowIsFullscreen(bool aFullscreen) { - mWindowIsFullscreen = aFullscreen; + MutexAutoLock lock(mMutex); + + if (mWindowIsFullscreen != aFullscreen) { + mWindowIsFullscreen = aFullscreen; + + for (auto layer : mSublayers) { + layer->SetRootWindowIsFullscreen(mWindowIsFullscreen); + } + } } /* static */ bool IsCGColorOpaqueBlack(CGColorRef aColor) { @@ -541,8 +579,7 @@ void NativeLayerRootCA::SetWindowIsFullscreen(bool aFullscreen) { return components[componentCount - 1] >= 1.0f; } -VideoLowPowerType NativeLayerRootCA::CheckVideoLowPower( - const MutexAutoLock& aProofOfLock) { +VideoLowPowerType NativeLayerRootCA::CheckVideoLowPower() { // This deteremines whether the current layer contents qualify for the // macOS Core Animation video low power mode. Those requirements are // summarized at @@ -572,7 +609,7 @@ VideoLowPowerType NativeLayerRootCA::CheckVideoLowPower( secondCALayer = topCALayer; topCALayer = topLayer->UnderlyingCALayer(WhichRepresentation::ONSCREEN); - topLayerIsVideo = topLayer->IsVideo(aProofOfLock); + topLayerIsVideo = topLayer->IsVideo(); if (topLayerIsVideo) { ++videoLayerCount; } @@ -641,6 +678,7 @@ VideoLowPowerType NativeLayerRootCA::CheckVideoLowPower( return VideoLowPowerType::LowPower; } +#ifdef XP_MACOSX NativeLayerRootSnapshotterCA::NativeLayerRootSnapshotterCA( NativeLayerRootCA* aLayerRoot, RefPtr<GLContext>&& aGL, CALayer* aRootCALayer) @@ -779,6 +817,7 @@ NativeLayerRootSnapshotterCA::CreateAsyncReadbackBuffer(const IntSize& aSize) { LOCAL_GL_STREAM_READ); return MakeAndAddRef<AsyncReadbackBufferNLRS>(mGL, aSize, bufferHandle); } +#endif NativeLayerCA::NativeLayerCA(const IntSize& aSize, bool aIsOpaque, SurfacePoolHandleCA* aSurfacePoolHandle) @@ -796,8 +835,9 @@ NativeLayerCA::NativeLayerCA(bool aIsOpaque) mIsOpaque(aIsOpaque) { #ifdef NIGHTLY_BUILD if (StaticPrefs::gfx_core_animation_specialize_video_log()) { - NSLog(@"VIDEO_LOG: NativeLayerCA: %p is being created to host an external " - @"image, which may force a video layer rebuild.", + NSLog(@"VIDEO_LOG: NativeLayerCA: %p is being created to host video, which " + @"will force a video " + @"layer rebuild.", this); } #endif @@ -824,7 +864,7 @@ NativeLayerCA::~NativeLayerCA() { if (mHasEverAttachExternalImage && StaticPrefs::gfx_core_animation_specialize_video_log()) { NSLog(@"VIDEO_LOG: ~NativeLayerCA: %p is being destroyed after hosting " - @"an external image.", + @"video.", this); } #endif @@ -862,9 +902,6 @@ void NativeLayerCA::AttachExternalImage(wr::RenderTextureHost* aExternalImage) { return; } - // Determine if TextureHost is a video surface. - mIsTextureHostVideo = gfx::Info(mTextureHost->GetFormat())->isYuv; - gfx::IntSize oldSize = mSize; mSize = texture->GetSize(0); bool changedSizeAndDisplayRect = (mSize != oldSize); @@ -896,15 +933,18 @@ void NativeLayerCA::AttachExternalImage(wr::RenderTextureHost* aExternalImage) { }); } -bool NativeLayerCA::IsVideo(const MutexAutoLock& aProofOfLock) { - // If we have a texture host, we've checked to see if it's providing video. - // And if we don't have a texture host, it isn't video, so we just check - // the value we've computed. - return mIsTextureHostVideo; +bool NativeLayerCA::IsVideo() { + // Anything with a texture host is considered a video source. + return mTextureHost; +} + +bool NativeLayerCA::IsVideoAndLocked(const MutexAutoLock& aProofOfLock) { + // Anything with a texture host is considered a video source. + return mTextureHost; } bool NativeLayerCA::ShouldSpecializeVideo(const MutexAutoLock& aProofOfLock) { - if (!IsVideo(aProofOfLock)) { + if (!IsVideoAndLocked(aProofOfLock)) { // Only videos are eligible. return false; } @@ -934,7 +974,49 @@ bool NativeLayerCA::ShouldSpecializeVideo(const MutexAutoLock& aProofOfLock) { return true; } - return StaticPrefs::gfx_core_animation_specialize_video(); + // Beyond this point, we return true if-and-only-if we think we can achieve + // the power-saving "detached mode" of the macOS compositor. + + if (!StaticPrefs::gfx_core_animation_specialize_video()) { + // Pref must be set. + return false; + } + + if (pixelFormat != kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange && + pixelFormat != kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) { + // The video is not in one of the formats that qualifies for detachment. + return false; + } + + // It will only detach if we're fullscreen. + return mRootWindowIsFullscreen; +} + +void NativeLayerCA::SetRootWindowIsFullscreen(bool aFullscreen) { + if (mRootWindowIsFullscreen == aFullscreen) { + return; + } + + MutexAutoLock lock(mMutex); + + mRootWindowIsFullscreen = aFullscreen; + + bool oldSpecializeVideo = mSpecializeVideo; + mSpecializeVideo = ShouldSpecializeVideo(lock); + bool changedSpecializeVideo = (mSpecializeVideo != oldSpecializeVideo); + + if (changedSpecializeVideo) { +#ifdef NIGHTLY_BUILD + if (StaticPrefs::gfx_core_animation_specialize_video_log()) { + NSLog(@"VIDEO_LOG: SetRootWindowIsFullscreen: %p is forcing a video " + @"layer rebuild.", + this); + } +#endif + + ForAllRepresentations( + [&](Representation& r) { r.mMutatedSpecializeVideo = true; }); + } } void NativeLayerCA::SetSurfaceIsFlipped(bool aIsFlipped) { @@ -1328,8 +1410,6 @@ void NativeLayerCA::NotifySurfaceReady() { mInProgressSurface, "NotifySurfaceReady called without preceding call to NextSurface"); - mIsTextureHostVideo = false; - if (mInProgressLockedIOSurface) { mInProgressLockedIOSurface->Unlock(false); mInProgressLockedIOSurface = nullptr; @@ -1385,7 +1465,7 @@ void NativeLayerCA::ForAllRepresentations(F aFn) { NativeLayerCA::UpdateType NativeLayerCA::HasUpdate( WhichRepresentation aRepresentation) { MutexAutoLock lock(mMutex); - return GetRepresentation(aRepresentation).HasUpdate(IsVideo(lock)); + return GetRepresentation(aRepresentation).HasUpdate(IsVideoAndLocked(lock)); } /* static */ @@ -1430,7 +1510,7 @@ bool NativeLayerCA::ApplyChanges(WhichRepresentation aRepresentation, .ApplyChanges(aUpdate, mSize, mIsOpaque, mPosition, mTransform, mDisplayRect, mClipRect, mBackingScale, mSurfaceIsFlipped, mSamplingFilter, mSpecializeVideo, surface, mColor, mIsDRM, - IsVideo(lock)); + IsVideo()); } CALayer* NativeLayerCA::UnderlyingCALayer(WhichRepresentation aRepresentation) { @@ -1457,8 +1537,10 @@ static NSString* NSStringForOSType(OSType type) { CFRelease(surfaceValues); if (aBuffer) { +#ifdef XP_MACOSX CGColorSpaceRef colorSpace = CVImageBufferGetColorSpace(aBuffer); NSLog(@"ColorSpace is %@.\n", colorSpace); +#endif CFDictionaryRef bufferAttachments = CVBufferGetAttachments(aBuffer, kCVAttachmentMode_ShouldPropagate); @@ -1512,7 +1594,7 @@ bool NativeLayerCA::Representation::EnqueueSurface(IOSurfaceRef aSurfaceRef) { return false; } -#ifdef NIGHTLY_BUILD +#if defined(NIGHTLY_BUILD) && defined(XP_MACOSX) if (StaticPrefs::gfx_core_animation_specialize_video_check_color_space()) { // Ensure the resulting pixel buffer has a color space. If it doesn't, then // modify the surface and create the buffer again. @@ -1764,10 +1846,10 @@ bool NativeLayerCA::Representation::ApplyChanges( mOpaquenessTintLayer.contentsGravity = kCAGravityTopLeft; if (aIsOpaque) { mOpaquenessTintLayer.backgroundColor = - [[[NSColor greenColor] colorWithAlphaComponent:0.5] CGColor]; + CGColorCreateGenericRGB(0, 1, 0, 0.5); } else { mOpaquenessTintLayer.backgroundColor = - [[[NSColor redColor] colorWithAlphaComponent:0.5] CGColor]; + CGColorCreateGenericRGB(1, 0, 0, 0.5); } [mWrappingCALayer addSublayer:mOpaquenessTintLayer]; } else if (!shouldTintOpaqueness && mOpaquenessTintLayer) { diff --git a/gfx/layers/PersistentBufferProvider.cpp b/gfx/layers/PersistentBufferProvider.cpp index 0e02501a4a..d79c8cdca1 100644 --- a/gfx/layers/PersistentBufferProvider.cpp +++ b/gfx/layers/PersistentBufferProvider.cpp @@ -663,14 +663,15 @@ PersistentBufferProviderShared::BorrowSnapshot(gfx::DrawTarget* aTarget) { if (mDrawTarget) { auto back = GetTexture(mBack); - MOZ_ASSERT(back && back->IsLocked()); + if (NS_WARN_IF(!back) || NS_WARN_IF(!back->IsLocked())) { + return nullptr; + } mSnapshot = back->BorrowSnapshot(); return do_AddRef(mSnapshot); } auto front = GetTexture(mFront); - if (!front || front->IsLocked()) { - MOZ_ASSERT(false); + if (NS_WARN_IF(!front) || NS_WARN_IF(front->IsLocked())) { return nullptr; } diff --git a/gfx/layers/RemoteTextureMap.cpp b/gfx/layers/RemoteTextureMap.cpp index fa0cfd33f5..3fe3b13deb 100644 --- a/gfx/layers/RemoteTextureMap.cpp +++ b/gfx/layers/RemoteTextureMap.cpp @@ -369,7 +369,11 @@ void RemoteTextureMap::PushTexture( aTextureId, aTextureHost, std::move(aTextureData), std::move(aResourceWrapper)); - MOZ_ASSERT(owner->mLatestTextureId < aTextureId); + MOZ_ASSERT(owner->mLatestPushedTextureId < aTextureId); + if (owner->mLatestPushedTextureId < aTextureId) { + owner->mLatestPushedTextureId = aTextureId; + } + MOZ_ASSERT(owner->mLatestUsingTextureId < aTextureId); owner->mWaitingTextureDataHolders.push_back(std::move(textureData)); @@ -898,9 +902,9 @@ void RemoteTextureMap::UpdateTexture(const MonitorAutoLock& aProofOfLock, const RemoteTextureId aTextureId) { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); MOZ_ASSERT(aOwner); - MOZ_ASSERT(aTextureId >= aOwner->mLatestTextureId); + MOZ_ASSERT(aTextureId >= aOwner->mLatestUsingTextureId); - if (aTextureId == aOwner->mLatestTextureId) { + if (aTextureId == aOwner->mLatestUsingTextureId) { // No need to update texture. return; } @@ -913,7 +917,7 @@ void RemoteTextureMap::UpdateTexture(const MonitorAutoLock& aProofOfLock, } MOZ_RELEASE_ASSERT(front->mTextureHost); aOwner->mLatestTextureHost = front->mTextureHost; - aOwner->mLatestTextureId = front->mTextureId; + aOwner->mLatestUsingTextureId = front->mTextureId; UniquePtr<TextureDataHolder> holder = std::move(front); aOwner->mWaitingTextureDataHolders.pop_front(); @@ -962,10 +966,42 @@ void RemoteTextureMap::GetAllRenderingReadyCallbacks( MOZ_ASSERT(aOwner->mRenderingReadyCallbackHolders.empty()); } +bool RemoteTextureMap::WaitForRemoteTextureOwner( + RemoteTextureHostWrapper* aTextureHostWrapper) { + MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); + MOZ_ASSERT(aTextureHostWrapper); + + const auto& ownerId = aTextureHostWrapper->mOwnerId; + const auto& forPid = aTextureHostWrapper->mForPid; + + MonitorAutoLock lock(mMonitor); + + auto* owner = GetTextureOwner(lock, ownerId, forPid); + // If there is no texture owner yet, then we might need to wait for one to + // be created, if allowed. If so, we must also wait for an initial texture + // host to be created so we can use it. + if (!owner || (!owner->mLatestTextureHost && + owner->mWaitingTextureDataHolders.empty())) { + const TimeDuration timeout = TimeDuration::FromMilliseconds(10000); + while (!owner || (!owner->mLatestTextureHost && + owner->mWaitingTextureDataHolders.empty())) { + if (owner && (owner->mIsContextLost || owner->mDeferUnregister)) { + // If the context was lost, no further updates are expected. + return false; + } + CVStatus status = mMonitor.Wait(timeout); + if (status == CVStatus::Timeout) { + return false; + } + owner = GetTextureOwner(lock, ownerId, forPid); + } + } + return true; +} + bool RemoteTextureMap::GetRemoteTexture( RemoteTextureHostWrapper* aTextureHostWrapper, - std::function<void(const RemoteTextureInfo&)>&& aReadyCallback, - bool aWaitForRemoteTextureOwner) { + std::function<void(const RemoteTextureInfo&)>&& aReadyCallback) { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); MOZ_ASSERT(aTextureHostWrapper); @@ -983,27 +1019,8 @@ bool RemoteTextureMap::GetRemoteTexture( MonitorAutoLock lock(mMonitor); auto* owner = GetTextureOwner(lock, ownerId, forPid); - // If there is no texture owner yet, then we might need to wait for one to - // be created, if allowed. If so, we must also wait for an initial texture - // host to be created so we can use it. - if (!owner || (aWaitForRemoteTextureOwner && !owner->mLatestTextureHost && - owner->mWaitingTextureDataHolders.empty())) { - if (!aWaitForRemoteTextureOwner) { - return false; - } - const TimeDuration timeout = TimeDuration::FromMilliseconds(10000); - while (!owner || (!owner->mLatestTextureHost && - owner->mWaitingTextureDataHolders.empty())) { - if (owner && (owner->mIsContextLost || owner->mDeferUnregister)) { - // If the context was lost, no further updates are expected. - return false; - } - CVStatus status = mMonitor.Wait(timeout); - if (status == CVStatus::Timeout) { - return false; - } - owner = GetTextureOwner(lock, ownerId, forPid); - } + if (!owner) { + return false; } UpdateTexture(lock, owner, textureId); @@ -1014,7 +1031,7 @@ bool RemoteTextureMap::GetRemoteTexture( return false; } - if (textureId == owner->mLatestTextureId) { + if (textureId == owner->mLatestUsingTextureId) { MOZ_ASSERT(owner->mLatestTextureHost); MOZ_ASSERT(owner->mLatestTextureHost->GetSize() == size); if (owner->mLatestTextureHost->GetSize() != size) { @@ -1034,7 +1051,7 @@ bool RemoteTextureMap::GetRemoteTexture( } // Update mRemoteTextureHost - if (textureId == owner->mLatestTextureId) { + if (textureId == owner->mLatestUsingTextureId) { const auto key = std::pair(forPid, textureId); auto it = mRemoteTextureHostWrapperHolders.find(key); if (it != mRemoteTextureHostWrapperHolders.end() && @@ -1195,16 +1212,9 @@ bool RemoteTextureMap::CheckRemoteTextureReady( return true; } - if (it->second->mRemoteTextureHost) { + if (owner->mLatestPushedTextureId >= aInfo.mTextureId) { return true; } - MOZ_ASSERT(!it->second->mRemoteTextureHost); - - // Check if RemoteTextureId is as expected. - if (!owner->mRenderingReadyCallbackHolders.empty()) { - auto& front = owner->mRenderingReadyCallbackHolders.front(); - MOZ_RELEASE_ASSERT(aInfo.mTextureId >= front->mTextureId); - } auto callbackHolder = MakeUnique<RenderingReadyCallbackHolder>( aInfo.mTextureId, std::move(aCallback)); @@ -1234,9 +1244,8 @@ bool RemoteTextureMap::WaitRemoteTextureReady(const RemoteTextureInfo& aInfo) { } const TimeDuration timeout = TimeDuration::FromMilliseconds(1000); - TextureHost* remoteTexture = it->second->mRemoteTextureHost; - while (!remoteTexture) { + while (owner->mLatestPushedTextureId < aInfo.mTextureId) { CVStatus status = mMonitor.Wait(timeout); if (status == CVStatus::Timeout) { MOZ_ASSERT_UNREACHABLE("unexpected to be called"); @@ -1251,14 +1260,11 @@ bool RemoteTextureMap::WaitRemoteTextureReady(const RemoteTextureInfo& aInfo) { return false; } - remoteTexture = it->second->mRemoteTextureHost; - if (!remoteTexture) { - auto* owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid); - // When owner is alreay unregistered, remote texture will not be pushed. - if (!owner || owner->mIsContextLost) { - // This could happen with IPC abnormal shutdown - return false; - } + auto* owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid); + // When owner is alreay unregistered, remote texture will not be pushed. + if (!owner || owner->mIsContextLost) { + // This could happen with IPC abnormal shutdown + return false; } } diff --git a/gfx/layers/RemoteTextureMap.h b/gfx/layers/RemoteTextureMap.h index a60bfd4c3c..8aee1c6f7d 100644 --- a/gfx/layers/RemoteTextureMap.h +++ b/gfx/layers/RemoteTextureMap.h @@ -304,13 +304,14 @@ class RemoteTextureMap { void NotifyContextRestored(const RemoteTextureOwnerIdSet& aOwnerIds, const base::ProcessId aForPid); + bool WaitForRemoteTextureOwner(RemoteTextureHostWrapper* aTextureHostWrapper); + // Get remote texture's TextureHost for RemoteTextureHostWrapper. // // return true when aReadyCallback will be called. bool GetRemoteTexture( RemoteTextureHostWrapper* aTextureHostWrapper, - std::function<void(const RemoteTextureInfo&)>&& aReadyCallback, - bool aWaitForRemoteTextureOwner = false); + std::function<void(const RemoteTextureInfo&)>&& aReadyCallback); bool WaitForTxn(const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, RemoteTextureTxnType aTxnType, @@ -403,7 +404,8 @@ class RemoteTextureMap { std::deque<UniquePtr<RenderingReadyCallbackHolder>> mRenderingReadyCallbackHolders; - RemoteTextureId mLatestTextureId = {0}; + RemoteTextureId mLatestPushedTextureId = {0}; + RemoteTextureId mLatestUsingTextureId = {0}; CompositableTextureHostRef mLatestTextureHost; CompositableTextureHostRef mLatestRenderedTextureHost; // Holds compositable refs to TextureHosts of RenderTextureHosts that are diff --git a/gfx/layers/SurfacePool.h b/gfx/layers/SurfacePool.h index eecb398d85..6be3718af5 100644 --- a/gfx/layers/SurfacePool.h +++ b/gfx/layers/SurfacePool.h @@ -31,7 +31,7 @@ class SurfacePool { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SurfacePool); -#if defined(XP_MACOSX) || defined(MOZ_WAYLAND) +#if defined(XP_DARWIN) || defined(MOZ_WAYLAND) static RefPtr<SurfacePool> Create(size_t aPoolSizeLimit); #endif diff --git a/gfx/layers/SurfacePoolCA.h b/gfx/layers/SurfacePoolCA.h index 97344f7d06..265782df9e 100644 --- a/gfx/layers/SurfacePoolCA.h +++ b/gfx/layers/SurfacePoolCA.h @@ -6,7 +6,7 @@ #ifndef mozilla_layers_SurfacePoolCA_h #define mozilla_layers_SurfacePoolCA_h -#include <IOSurface/IOSurface.h> +#include <IOSurface/IOSurfaceRef.h> #include <deque> #include <unordered_map> diff --git a/gfx/layers/SurfacePoolCA.mm b/gfx/layers/SurfacePoolCA.mm index 47b2663ed7..4e012350f0 100644 --- a/gfx/layers/SurfacePoolCA.mm +++ b/gfx/layers/SurfacePoolCA.mm @@ -6,6 +6,7 @@ #include "mozilla/layers/SurfacePoolCA.h" #import <CoreVideo/CVPixelBuffer.h> +#include <IOSurface/IOSurfaceTypes.h> #include <algorithm> #include <unordered_set> @@ -16,7 +17,12 @@ #include "mozilla/StaticMutex.h" #include "mozilla/StaticPrefs_gfx.h" -#include "GLContextCGL.h" +#ifdef XP_MACOSX +# include "GLContextCGL.h" +#else +# include "GLContextEAGL.h" +#endif + #include "MozFramebuffer.h" #include "ScopedGLHelpers.h" @@ -28,7 +34,11 @@ using gfx::IntRect; using gfx::IntRegion; using gfx::IntSize; using gl::GLContext; +#ifdef XP_MACOSX using gl::GLContextCGL; +#else +using gl::GLContextEAGL; +#endif /* static */ RefPtr<SurfacePool> SurfacePool::Create(size_t aPoolSizeLimit) { return new SurfacePoolCA(aPoolSizeLimit); @@ -306,8 +316,13 @@ Maybe<GLuint> SurfacePoolCA::LockedPool::GetFramebufferForSurface( "Framebuffer creation", GRAPHICS_TileAllocation, nsPrintfCString("%dx%d", entry.mSize.width, entry.mSize.height)); +#ifdef XP_MACOSX RefPtr<GLContextCGL> cgl = GLContextCGL::Cast(aGL); MOZ_RELEASE_ASSERT(cgl, "Unexpected GLContext type"); +#else + RefPtr<GLContextEAGL> eagl = GLContextEAGL::Cast(aGL); + MOZ_RELEASE_ASSERT(eagl, "Unexpected GLContext type"); +#endif if (!aGL->MakeCurrent()) { // Context may have been destroyed. @@ -318,10 +333,14 @@ Maybe<GLuint> SurfacePoolCA::LockedPool::GetFramebufferForSurface( { const gl::ScopedBindTexture bindTex(aGL, tex, LOCAL_GL_TEXTURE_RECTANGLE_ARB); +#ifdef XP_MACOSX CGLTexImageIOSurface2D(cgl->GetCGLContext(), LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_RGBA, entry.mSize.width, entry.mSize.height, LOCAL_GL_BGRA, LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV, entry.mIOSurface.get(), 0); +#else + MOZ_CRASH("unimplemented"); +#endif } auto fb = diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp index d28392b716..ef3cde3596 100644 --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -62,6 +62,8 @@ mozilla::LazyLogModule mozilla::layers::APZCTreeManager::sLog("apz.manager"); #define APZCTM_LOG(...) \ MOZ_LOG(APZCTreeManager::sLog, LogLevel::Debug, (__VA_ARGS__)) +#define APZCTM_LOGV(...) \ + MOZ_LOG(APZCTreeManager::sLog, LogLevel::Verbose, (__VA_ARGS__)) static mozilla::LazyLogModule sApzKeyLog("apz.key"); #define APZ_KEY_LOG(...) MOZ_LOG(sApzKeyLog, LogLevel::Debug, (__VA_ARGS__)) @@ -83,10 +85,10 @@ typedef CompositorBridgeParent::LayerTreeState LayerTreeState; struct APZCTreeManager::TreeBuildingState { TreeBuildingState(LayersId aRootLayersId, bool aIsFirstPaint, LayersId aOriginatingLayersId, APZTestData* aTestData, - uint32_t aPaintSequence) + uint32_t aPaintSequence, bool aIsTestLoggingEnabled) : mIsFirstPaint(aIsFirstPaint), mOriginatingLayersId(aOriginatingLayersId), - mPaintLogger(aTestData, aPaintSequence) { + mPaintLogger(aTestData, aPaintSequence, aIsTestLoggingEnabled) { CompositorBridgeParent::CallWithIndirectShadowTree( aRootLayersId, [this](LayerTreeState& aState) -> void { mCompositorController = aState.GetCompositorController(); @@ -158,6 +160,9 @@ struct APZCTreeManager::TreeBuildingState { // cumulative EventRegionsOverride flags from the reflayers, and is used to // apply them to descendant layers. std::stack<EventRegionsOverride> mOverrideFlags; + + // Wether the APZC correspoinding to the originating LayersId was updated. + bool mOriginatingLayersIdUpdated = false; }; class APZCTreeManager::CheckerboardFlushObserver : public nsIObserver { @@ -391,8 +396,7 @@ void APZCTreeManager::SetAllowedTouchBehavior( uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aValues) { if (!APZThreadUtils::IsControllerThread()) { APZThreadUtils::RunOnControllerThread( - NewRunnableMethod<uint64_t, - StoreCopyPassByLRef<nsTArray<TouchBehaviorFlags>>>( + NewRunnableMethod<uint64_t, nsTArray<TouchBehaviorFlags>>( "layers::APZCTreeManager::SetAllowedTouchBehavior", this, &APZCTreeManager::SetAllowedTouchBehavior, aInputBlockId, aValues.Clone())); @@ -420,9 +424,11 @@ void APZCTreeManager::SetBrowserGestureResponse( mInputQueue->SetBrowserGestureResponse(aInputBlockId, aResponse); } -void APZCTreeManager::UpdateHitTestingTree( - const WebRenderScrollDataWrapper& aRoot, bool aIsFirstPaint, - LayersId aOriginatingLayersId, uint32_t aPaintSequenceNumber) { +APZCTreeManager::OriginatingLayersIdUpdated +APZCTreeManager::UpdateHitTestingTree(const WebRenderScrollDataWrapper& aRoot, + bool aIsFirstPaint, + LayersId aOriginatingLayersId, + uint32_t aPaintSequenceNumber) { AssertOnUpdaterThread(); RecursiveMutexAutoLock lock(mTreeLock); @@ -430,7 +436,8 @@ void APZCTreeManager::UpdateHitTestingTree( // For testing purposes, we log some data to the APZTestData associated with // the layers id that originated this update. APZTestData* testData = nullptr; - if (StaticPrefs::apz_test_logging_enabled()) { + const bool testLoggingEnabled = StaticPrefs::apz_test_logging_enabled(); + if (testLoggingEnabled) { MutexAutoLock lock(mTestDataLock); UniquePtr<APZTestData> ptr = MakeUnique<APZTestData>(); auto result = @@ -440,7 +447,7 @@ void APZCTreeManager::UpdateHitTestingTree( } TreeBuildingState state(mRootLayersId, aIsFirstPaint, aOriginatingLayersId, - testData, aPaintSequenceNumber); + testData, aPaintSequenceNumber, testLoggingEnabled); // We do this business with collecting the entire tree into an array because // otherwise it's very hard to determine which APZC instances need to be @@ -730,6 +737,8 @@ void APZCTreeManager::UpdateHitTestingTree( mRootNode->Dump(" "); } SendSubtreeTransformsToChromeMainThread(nullptr); + + return OriginatingLayersIdUpdated{state.mOriginatingLayersIdUpdated}; } void APZCTreeManager::UpdateFocusState(LayersId aRootLayerTreeId, @@ -763,7 +772,7 @@ void APZCTreeManager::SampleForWebRender(const Maybe<VsyncId>& aVsyncId, controller->ScheduleRenderOnCompositorThread( wr::RenderReasons::ANIMATED_PROPERTY); } - APZCTM_LOG( + APZCTM_LOGV( "APZCTreeManager(%p)::SampleForWebRender, want more composites: %d\n", this, (activeAnimations && controller)); @@ -1231,6 +1240,10 @@ HitTestingTreeNode* APZCTreeManager::PrepareNodeForLayer( "Found APZC %p for layer %p with identifiers %" PRIx64 " %" PRId64 "\n", apzc.get(), aLayer.GetLayer(), uint64_t(guid.mLayersId), guid.mScrollId); + if (aLayersId == aState.mOriginatingLayersId) { + aState.mOriginatingLayersIdUpdated = true; + } + // If we haven't encountered a layer already with the same metrics, then we // need to do the full reuse-or-make-an-APZC algorithm, which is contained // inside the block below. @@ -1522,6 +1535,11 @@ APZEventResult APZCTreeManager::ReceiveInputEvent( } case MOUSE_INPUT: { MouseInput& mouseInput = aEvent.AsMouseInput(); + MOZ_LOG(APZCTreeManager::sLog, + mouseInput.mType == MouseInput::MOUSE_MOVE ? LogLevel::Verbose + : LogLevel::Debug, + ("Received mouse input type %d at %s\n", (int)mouseInput.mType, + ToString(mouseInput.mOrigin).c_str())); mouseInput.mHandledByAPZ = true; SetCurrentMousePosition(mouseInput.mOrigin); @@ -1613,6 +1631,9 @@ APZEventResult APZCTreeManager::ReceiveInputEvent( // Do this before early return for Fission hit testing. ScrollWheelInput& wheelInput = aEvent.AsScrollWheelInput(); + APZCTM_LOG("Received wheel input at %s with delta (%f, %f)\n", + ToString(wheelInput.mOrigin).c_str(), wheelInput.mDeltaX, + wheelInput.mDeltaY); state.mHit = GetTargetAPZC(wheelInput.mOrigin); wheelInput.mHandledByAPZ = WillHandleInput(wheelInput); @@ -1674,6 +1695,9 @@ APZEventResult APZCTreeManager::ReceiveInputEvent( // Do this before early return for Fission hit testing. PanGestureInput& panInput = aEvent.AsPanGestureInput(); + APZCTM_LOG("Received pan gesture input type %d at %s with delta %s\n", + (int)panInput.mType, ToString(panInput.mPanStartPoint).c_str(), + ToString(panInput.mPanDisplacement).c_str()); state.mHit = GetTargetAPZC(panInput.mPanStartPoint); panInput.mHandledByAPZ = WillHandleInput(panInput); @@ -2021,6 +2045,18 @@ APZEventResult APZCTreeManager::InputHandlingState::Finish( void APZCTreeManager::ProcessTouchInput(InputHandlingState& aState, MultiTouchInput& aInput) { + APZCTM_LOG("Received touch input type %d with touch points [%s]\n", + (int)aInput.mType, + [&] { + nsCString result; + for (const auto& touch : aInput.mTouches) { + result.AppendPrintf("%s", + ToString(touch.mScreenPoint).c_str()); + } + return result; + }() + .get()); + aInput.mHandledByAPZ = true; nsTArray<TouchBehaviorFlags> touchBehaviors; HitTestingTreeNodeAutoLock hitScrollbarNode; diff --git a/gfx/layers/apz/src/APZCTreeManager.h b/gfx/layers/apz/src/APZCTreeManager.h index ff9bba51ca..71d35fd5a6 100644 --- a/gfx/layers/apz/src/APZCTreeManager.h +++ b/gfx/layers/apz/src/APZCTreeManager.h @@ -190,10 +190,13 @@ class APZCTreeManager : public IAPZCTreeManager, public APZInputBridge { * this layer update. Note that every child * process' layer subtree has its own sequence * numbers. + * @return OriginatingLayersIdUpdated whether the given + * |aOriginatingLayersId|'s data was processed. */ - void UpdateHitTestingTree(const WebRenderScrollDataWrapper& aRoot, - bool aIsFirstPaint, LayersId aOriginatingLayersId, - uint32_t aPaintSequenceNumber); + enum class OriginatingLayersIdUpdated : bool { No, Yes }; + OriginatingLayersIdUpdated UpdateHitTestingTree( + const WebRenderScrollDataWrapper& aRoot, bool aIsFirstPaint, + LayersId aOriginatingLayersId, uint32_t aPaintSequenceNumber); /** * Called when webrender is enabled, from the sampler thread. This function diff --git a/gfx/layers/apz/src/APZUpdater.cpp b/gfx/layers/apz/src/APZUpdater.cpp index 2bbad6e1a7..2f1b551f3a 100644 --- a/gfx/layers/apz/src/APZUpdater.cpp +++ b/gfx/layers/apz/src/APZUpdater.cpp @@ -191,14 +191,38 @@ void APZUpdater::UpdateScrollDataAndTreeState( auto isFirstPaint = aScrollData.IsFirstPaint(); auto paintSequenceNumber = aScrollData.GetPaintSequenceNumber(); + auto previous = self->mScrollData.find(aOriginatingLayersId); + // If there's the previous scroll data which hasn't yet been + // processed, we need to merge the previous scroll position updates + // into the latest one. + if (previous != self->mScrollData.end()) { + WebRenderScrollData& previousData = previous->second; + if (previousData.GetWasUpdateSkipped()) { + MOZ_ASSERT(previousData.IsFirstPaint()); + aScrollData.PrependUpdates(previousData); + } + } + self->mScrollData[aOriginatingLayersId] = std::move(aScrollData); auto root = self->mScrollData.find(aRootLayerTreeId); if (root == self->mScrollData.end()) { return; } - self->mApz->UpdateHitTestingTree( - WebRenderScrollDataWrapper(*self, &(root->second)), - isFirstPaint, aOriginatingLayersId, paintSequenceNumber); + if ((self->mApz->UpdateHitTestingTree( + WebRenderScrollDataWrapper(*self, &(root->second)), + isFirstPaint, aOriginatingLayersId, paintSequenceNumber) == + APZCTreeManager::OriginatingLayersIdUpdated::No) && + isFirstPaint) { + // If the given |aOriginatingLayersId| data wasn't used for + // updating, it's likly that the parent process hasn't yet + // received the LayersId as "ReferentId", thus we need to process + // it in a subsequent update where we got the "ReferentId". + // + // NOTE: We restrict the above previous scroll data prepending to + // the first paint case, otherwise the cumulative scroll data may + // be exploded if we have never received the "ReferenceId". + self->mScrollData[aOriginatingLayersId].SetWasUpdateSkipped(); + } })); } diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp index 342375c019..edbd2ecffa 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -106,6 +106,10 @@ static mozilla::LazyLogModule sApzCtlLog("apz.controller"); APZC_LOG("%p(%s scrollId=%" PRIu64 "): " fmt, (apzc), \ (apzc)->IsRootContent() ? "root" : "subframe", \ (apzc)->GetScrollId(), ##__VA_ARGS__) +#define APZC_LOGV_DETAIL(fmt, apzc, ...) \ + APZC_LOGV("%p(%s scrollId=%" PRIu64 "): " fmt, (apzc), \ + (apzc)->IsRootContent() ? "root" : "subframe", \ + (apzc)->GetScrollId(), ##__VA_ARGS__) #define APZC_LOG_FM_COMMON(fm, prefix, level, ...) \ if (MOZ_LOG_TEST(sApzCtlLog, level)) { \ @@ -2248,6 +2252,11 @@ CSSRect AsyncPanZoomController::GetCurrentScrollRangeInCssPixels() const { return Metrics().CalculateScrollRange(); } +bool AsyncPanZoomController::AllowOneTouchPinch() const { + return StaticPrefs::apz_one_touch_pinch_enabled() && + ZoomConstraintsAllowZoom(); +} + // Return whether or not the underlying layer can be scrolled on either axis. bool AsyncPanZoomController::CanScroll(const InputData& aEvent) const { ParentLayerPoint delta = GetDeltaForEvent(aEvent); @@ -4734,7 +4743,7 @@ bool AsyncPanZoomController::UpdateAnimation( // Even if there's no animation, if we have a scroll offset change pending due // to the frame delay, we need to keep compositing. if (mLastSampleTime == aSampleTime) { - APZC_LOG_DETAIL( + APZC_LOGV_DETAIL( "UpdateAnimation short-circuit, animation=%p, pending frame-delayed " "offset=%d\n", this, mAnimation.get(), HavePendingFrameDelayedOffset()); @@ -4754,8 +4763,8 @@ bool AsyncPanZoomController::UpdateAnimation( // so that e.g. a main-thread animation can stay in sync with user-driven // scrolling or a compositor animation. bool needComposite = SampleCompositedAsyncTransform(aProofOfLock); - APZC_LOG_DETAIL("UpdateAnimation needComposite=%d mAnimation=%p\n", this, - needComposite, mAnimation.get()); + APZC_LOGV_DETAIL("UpdateAnimation needComposite=%d mAnimation=%p\n", this, + needComposite, mAnimation.get()); TimeDuration sampleTimeDelta = aSampleTime - mLastSampleTime; mLastSampleTime = aSampleTime; @@ -5581,17 +5590,6 @@ void AsyncPanZoomController::NotifyLayersUpdated( aScrollMetadata.GetOverscrollBehavior()); } - if (needToReclampScroll) { - // Whenever scrollable rect or composition bounds has changed, we need to - // re-clamp the scroll offset since it may be out of bounds. Also note that - // we need to re-clamp before updating new scroll offsets from content since - // we will use the last scroll offset to reflect the new offsets. - ClampAndSetVisualScrollOffset(Metrics().GetVisualScrollOffset()); - for (auto& sampledState : mSampledState) { - sampledState.ClampVisualScrollOffset(Metrics()); - } - } - bool instantScrollMayTriggerTransform = false; bool scrollOffsetUpdated = false; bool smoothScrollRequested = false; @@ -5738,20 +5736,11 @@ void AsyncPanZoomController::NotifyLayersUpdated( relativeDelta = Some(Metrics().ApplyPureRelativeScrollUpdateFrom(scrollUpdate)); Metrics().RecalculateLayoutViewportOffset(); - } else if (scrollUpdate.GetType() == ScrollUpdateType::MergeableAbsolute) { - APZC_LOG("%p mergeable updating scroll offset from %s to %s\n", this, - ToString(Metrics().GetVisualScrollOffset()).c_str(), - ToString(scrollUpdate.GetDestination()).c_str()); - relativeDelta = - Some(Metrics().ApplyAbsoluteScrollUpdateFrom(scrollUpdate).second); - Metrics().RecalculateLayoutViewportOffset(); - scrollOffsetUpdated = true; } else { APZC_LOG("%p updating scroll offset from %s to %s\n", this, ToString(Metrics().GetVisualScrollOffset()).c_str(), ToString(scrollUpdate.GetDestination()).c_str()); - auto [offsetChanged, _] = - Metrics().ApplyAbsoluteScrollUpdateFrom(scrollUpdate); + bool offsetChanged = Metrics().ApplyScrollUpdateFrom(scrollUpdate); Metrics().RecalculateLayoutViewportOffset(); if (offsetChanged || scrollUpdate.GetMode() != ScrollMode::Instant || @@ -5788,6 +5777,15 @@ void AsyncPanZoomController::NotifyLayersUpdated( } } + if (aIsFirstPaint || needToReclampScroll) { + // The scrollable rect or composition bounds may have changed in a way that + // makes our local scroll offset out of bounds, so clamp it. + ClampAndSetVisualScrollOffset(Metrics().GetVisualScrollOffset()); + for (auto& sampledState : mSampledState) { + sampledState.ClampVisualScrollOffset(Metrics()); + } + } + if (scrollOffsetUpdated) { for (auto& sampledState : mSampledState) { if (!didCancelAnimation && cumulativeRelativeDelta.isSome()) { diff --git a/gfx/layers/apz/src/AsyncPanZoomController.h b/gfx/layers/apz/src/AsyncPanZoomController.h index fdc72b1971..d0c4537a66 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.h +++ b/gfx/layers/apz/src/AsyncPanZoomController.h @@ -1305,6 +1305,8 @@ class AsyncPanZoomController { */ CSSRect GetCurrentScrollRangeInCssPixels() const; + bool AllowOneTouchPinch() const; + private: /** * Advances to the next sample, if there is one, the list of sampled states diff --git a/gfx/layers/apz/src/AutoscrollAnimation.cpp b/gfx/layers/apz/src/AutoscrollAnimation.cpp index 8d4b8fca10..45063ef2b4 100644 --- a/gfx/layers/apz/src/AutoscrollAnimation.cpp +++ b/gfx/layers/apz/src/AutoscrollAnimation.cpp @@ -17,7 +17,7 @@ namespace mozilla { namespace layers { // Helper function for AutoscrollAnimation::DoSample(). -// Basically copied as-is from toolkit/actors/AutoScrollChild.jsm. +// Basically copied as-is from toolkit/actors/AutoScrollChild.sys.mjs. static float Accelerate(ScreenCoord curr, ScreenCoord start) { static const int speed = 12; float val = (curr - start) / speed; diff --git a/gfx/layers/apz/src/GenericScrollAnimation.cpp b/gfx/layers/apz/src/GenericScrollAnimation.cpp index 04ca8c4697..62f19fab35 100644 --- a/gfx/layers/apz/src/GenericScrollAnimation.cpp +++ b/gfx/layers/apz/src/GenericScrollAnimation.cpp @@ -15,6 +15,9 @@ #include "ScrollAnimationMSDPhysics.h" #include "mozilla/StaticPrefs_general.h" +static mozilla::LazyLogModule sApzScrollAnimLog("apz.scrollanimation"); +#define GSA_LOG(...) MOZ_LOG(sApzScrollAnimLog, LogLevel::Debug, (__VA_ARGS__)) + namespace mozilla { namespace layers { @@ -101,6 +104,12 @@ bool GenericScrollAnimation::DoSample(FrameMetrics& aFrameMetrics, // then end the animation early. Note that the initial displacement could be 0 // if the compositor ran very quickly (<1ms) after the animation was created. // When that happens we want to make sure the animation continues. + GSA_LOG( + "Sampling GenericScrollAnimation: time %f finished %d sampledDest %s " + "adjustedOffset %s overscroll %s\n", + (now - TimeStamp::ProcessCreation()).ToMilliseconds(), finished, + ToString(CSSPoint::FromAppUnits(sampledDest)).c_str(), + ToString(adjustedOffset).c_str(), ToString(overscroll).c_str()); if (!IsZero(displacement / zoom) && IsZero(adjustedOffset / zoom)) { // Nothing more to do - end the animation. return false; diff --git a/gfx/layers/apz/src/GestureEventListener.cpp b/gfx/layers/apz/src/GestureEventListener.cpp index b54674b593..4300e9ba41 100644 --- a/gfx/layers/apz/src/GestureEventListener.cpp +++ b/gfx/layers/apz/src/GestureEventListener.cpp @@ -5,13 +5,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "GestureEventListener.h" -#include <algorithm> // for max +#include <algorithm> // for max +#include <ostream> #include <math.h> // for fabsf #include <stddef.h> // for size_t #include "AsyncPanZoomController.h" // for AsyncPanZoomController #include "InputBlockState.h" // for TouchBlockState #include "base/task.h" // for CancelableTask, etc #include "InputBlockState.h" // for TouchBlockState +#include "mozilla/Assertions.h" +#include "mozilla/EventForwards.h" #include "mozilla/StaticPrefs_apz.h" #include "mozilla/StaticPrefs_ui.h" #include "nsDebug.h" // for NS_WARNING @@ -83,8 +86,8 @@ GestureEventListener::~GestureEventListener() = default; nsEventStatus GestureEventListener::HandleInputEvent( const MultiTouchInput& aEvent) { - GEL_LOG("Receiving event type %d with %zu touches in state %d\n", - aEvent.mType, aEvent.mTouches.Length(), mState); + GEL_LOG("Receiving event type %d with %zu touches in state %s\n", + aEvent.mType, aEvent.mTouches.Length(), ToString(mState).c_str()); nsEventStatus rv = nsEventStatus_eIgnore; @@ -175,16 +178,15 @@ nsEventStatus GestureEventListener::HandleInputTouchSingleStart() { EnterFirstSingleTouchDown(); break; case GESTURE_FIRST_SINGLE_TOUCH_UP: + // Bail out of any gesture that includes the first tap. + CancelLongTapTimeoutTask(); + CancelMaxTapTimeoutTask(); if (SecondTapIsFar()) { - // If the second tap goes down far away from the first, then bail out - // of any gesture that includes the first tap. - CancelLongTapTimeoutTask(); - CancelMaxTapTimeoutTask(); - mSingleTapSent = Nothing(); - - // But still allow the second tap to participate in a gesture + // If the second tap goes down far away from the first, + // allow the second tap to participate in a gesture // (e.g. lead to a single tap, or a double tap if an additional // tap occurs near the same location). + mSingleTapSent = Nothing(); EnterFirstSingleTouchDown(); } else { // Otherwise, reset the touch start position so that, if this turns into @@ -225,9 +227,10 @@ nsEventStatus GestureEventListener::HandleInputTouchMultiStart() { rv = nsEventStatus_eConsumeNoDefault; break; case GESTURE_FIRST_SINGLE_TOUCH_UP: - case GESTURE_SECOND_SINGLE_TOUCH_DOWN: // Cancel wait for double tap CancelMaxTapTimeoutTask(); + [[fallthrough]]; + case GESTURE_SECOND_SINGLE_TOUCH_DOWN: MOZ_ASSERT(mSingleTapSent.isSome()); if (!mSingleTapSent.value()) { TriggerSingleTapConfirmedEvent(); @@ -307,12 +310,8 @@ nsEventStatus GestureEventListener::HandleInputTouchMove() { // If touch has moved noticeably (within StaticPrefs::apz_max_tap_time()), // change state. if (MoveDistanceIsLarge()) { - CancelLongTapTimeoutTask(); - CancelMaxTapTimeoutTask(); mSingleTapSent = Nothing(); - if (!StaticPrefs::apz_one_touch_pinch_enabled()) { - // If the one-touch-pinch feature is disabled, bail out of the double- - // tap gesture instead. + if (!mAsyncPanZoomController->AllowOneTouchPinch()) { SetState(GESTURE_NONE); break; } @@ -451,7 +450,6 @@ nsEventStatus GestureEventListener::HandleInputTouchEnd() { } case GESTURE_SECOND_SINGLE_TOUCH_DOWN: { - CancelMaxTapTimeoutTask(); MOZ_ASSERT(mSingleTapSent.isSome()); mAsyncPanZoomController->HandleGestureEvent(CreateTapEvent( mLastTouchInput, mSingleTapSent.value() @@ -535,7 +533,9 @@ nsEventStatus GestureEventListener::HandleInputTouchCancel() { } void GestureEventListener::HandleInputTimeoutLongTap() { - GEL_LOG("Running long-tap timeout task in state %d\n", mState); + MOZ_ASSERT(mState != GESTURE_SECOND_SINGLE_TOUCH_DOWN); + GEL_LOG("Running long-tap timeout task in state %s\n", + ToString(mState).c_str()); mLongTapTimeoutTask = nullptr; @@ -559,14 +559,15 @@ void GestureEventListener::HandleInputTimeoutLongTap() { } void GestureEventListener::HandleInputTimeoutMaxTap(bool aDuringFastFling) { - GEL_LOG("Running max-tap timeout task in state %d\n", mState); + MOZ_ASSERT(mState != GESTURE_SECOND_SINGLE_TOUCH_DOWN); + GEL_LOG("Running max-tap timeout task in state %s\n", + ToString(mState).c_str()); mMaxTapTimeoutTask = nullptr; if (mState == GESTURE_FIRST_SINGLE_TOUCH_DOWN) { SetState(GESTURE_FIRST_SINGLE_TOUCH_MAX_TAP_DOWN); - } else if (mState == GESTURE_FIRST_SINGLE_TOUCH_UP || - mState == GESTURE_SECOND_SINGLE_TOUCH_DOWN) { + } else if (mState == GESTURE_FIRST_SINGLE_TOUCH_UP) { MOZ_ASSERT(mSingleTapSent.isSome()); if (!aDuringFastFling && !mSingleTapSent.value()) { TriggerSingleTapConfirmedEvent(); @@ -585,6 +586,8 @@ void GestureEventListener::TriggerSingleTapConfirmedEvent() { } void GestureEventListener::SetState(GestureState aState) { + GEL_LOG("State change from %s to %s", ToString(mState).c_str(), + ToString(aState).c_str()); mState = aState; if (mState == GESTURE_NONE) { @@ -598,10 +601,7 @@ void GestureEventListener::SetState(GestureState aState) { } void GestureEventListener::CancelLongTapTimeoutTask() { - if (mState == GESTURE_SECOND_SINGLE_TOUCH_DOWN) { - // being in this state means the task has been canceled already - return; - } + MOZ_ASSERT(mState != GESTURE_SECOND_SINGLE_TOUCH_DOWN); if (mLongTapTimeoutTask) { mLongTapTimeoutTask->Cancel(); @@ -628,6 +628,8 @@ void GestureEventListener::CreateLongTapTimeoutTask() { } void GestureEventListener::CancelMaxTapTimeoutTask() { + MOZ_ASSERT(mState != GESTURE_SECOND_SINGLE_TOUCH_DOWN); + if (mState == GESTURE_FIRST_SINGLE_TOUCH_MAX_TAP_DOWN) { // being in this state means the timer has just been triggered return; @@ -659,5 +661,40 @@ void GestureEventListener::CreateMaxTapTimeoutTask() { std::max(0L, remainingDelay)); } +std::ostream& operator<<(std::ostream& os, + GestureEventListener::GestureState aState) { + switch (aState) { + case GestureEventListener::GESTURE_NONE: + os << "GESTURE_NONE"; + break; + case GestureEventListener::GESTURE_FIRST_SINGLE_TOUCH_DOWN: + os << "GESTURE_FIRST_SINGLE_TOUCH_DOWN"; + break; + case GestureEventListener::GESTURE_FIRST_SINGLE_TOUCH_MAX_TAP_DOWN: + os << "GESTURE_FIRST_SINGLE_TOUCH_MAX_TAP_DOWN"; + break; + case GestureEventListener::GESTURE_FIRST_SINGLE_TOUCH_UP: + os << "GESTURE_FIRST_SINGLE_TOUCH_UP"; + break; + case GestureEventListener::GESTURE_SECOND_SINGLE_TOUCH_DOWN: + os << "GESTURE_SECOND_SINGLE_TOUCH_DOWN"; + break; + case GestureEventListener::GESTURE_LONG_TOUCH_DOWN: + os << "GESTURE_LONG_TOUCH_DOWN"; + break; + case GestureEventListener::GESTURE_MULTI_TOUCH_DOWN: + os << "GESTURE_MULTI_TOUCH_DOWN"; + break; + case GestureEventListener::GESTURE_PINCH: + os << "GESTURE_PINCH"; + break; + case GestureEventListener::GESTURE_ONE_TOUCH_PINCH: + os << "GESTURE_ONE_TOUCH_PINCH"; + break; + } + + return os; +} + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/apz/src/GestureEventListener.h b/gfx/layers/apz/src/GestureEventListener.h index aa51889fdd..bf50d4f40a 100644 --- a/gfx/layers/apz/src/GestureEventListener.h +++ b/gfx/layers/apz/src/GestureEventListener.h @@ -7,6 +7,7 @@ #ifndef mozilla_layers_GestureEventListener_h #define mozilla_layers_GestureEventListener_h +#include <iosfwd> #include "InputData.h" // for MultiTouchInput, etc #include "Units.h" #include "mozilla/EventForwards.h" // for nsEventStatus @@ -135,6 +136,8 @@ class GestureEventListener final { GESTURE_ONE_TOUCH_PINCH }; + friend std::ostream& operator<<(std::ostream& os, GestureState aState); + /** * These HandleInput* functions comprise input alphabet of the GEL * finite-state machine triggering state transitions. diff --git a/gfx/layers/apz/test/gtest/TestGestureDetector.cpp b/gfx/layers/apz/test/gtest/TestGestureDetector.cpp index f244ca4dc7..8256667d6b 100644 --- a/gfx/layers/apz/test/gtest/TestGestureDetector.cpp +++ b/gfx/layers/apz/test/gtest/TestGestureDetector.cpp @@ -21,12 +21,12 @@ class APZCGestureDetectorTester : public APZCBasicTester { : APZCBasicTester(AsyncPanZoomController::USE_GESTURE_DETECTOR) {} protected: - FrameMetrics GetPinchableFrameMetrics() { + FrameMetrics GetPinchableFrameMetrics(float aZoom = 2.0f) { FrameMetrics fm; fm.SetCompositionBounds(ParentLayerRect(200, 200, 100, 200)); fm.SetScrollableRect(CSSRect(0, 0, 980, 1000)); fm.SetVisualScrollOffset(CSSPoint(300, 300)); - fm.SetZoom(CSSToParentLayerScale(2.0)); + fm.SetZoom(CSSToParentLayerScale(aZoom)); // APZC only allows zooming on the root scrollable frame. fm.SetIsRootContent(true); // the visible area of the document in CSS pixels is x=300 y=300 w=50 h=100 @@ -843,3 +843,235 @@ TEST_F(APZCGestureDetectorTester, LongPressWithInputQueueDelay3) { mcc->AdvanceByMillis(1); check.Call("post long-tap dispatch"); } + +TEST_F(APZCGestureDetectorTester, OneTouchPinchGestureShort) { + // Take less than StaticPrefs::apz_max_tap_time() until second touch down, + // hold second touch down for a very short time, then move + // and expect a successful one touch pinch gesture + SCOPED_GFX_PREF_BOOL("apz.one_touch_pinch.enabled", true); + + MakeApzcZoomable(); + apzc->SetFrameMetrics(GetPinchableFrameMetrics()); + const auto oldZoom = apzc->GetFrameMetrics().GetZoom().scale; + + const auto tapResult = + Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(10)); + apzc->SetAllowedTouchBehavior(tapResult.mInputBlockId, + {kDefaultTouchBehavior}); + + mcc->AdvanceByMillis(10); + const auto touchResult = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time()); + apzc->SetAllowedTouchBehavior(touchResult.mInputBlockId, + {kDefaultTouchBehavior}); + + // We should be able to hold down the second touch as long as we like + // before beginning to move + mcc->AdvanceByMillis(10); + TouchMove(apzc, ScreenIntPoint(10, 50), mcc->Time()); + + mcc->AdvanceByMillis(10); + TouchMove(apzc, ScreenIntPoint(10, 150), mcc->Time()); + + mcc->AdvanceByMillis(10); + TouchUp(apzc, ScreenIntPoint(10, 150), mcc->Time()); + + const auto newZoom = apzc->GetFrameMetrics().GetZoom().scale; + EXPECT_NE(newZoom, oldZoom); +} + +TEST_F(APZCGestureDetectorTester, OneTouchPinchGestureLong) { + // Take less than StaticPrefs::apz_max_tap_time() until second touch down, + // hold second touch down for a long time, then move + // and expect a successful one touch pinch gesture + SCOPED_GFX_PREF_BOOL("apz.one_touch_pinch.enabled", true); + + MakeApzcZoomable(); + apzc->SetFrameMetrics(GetPinchableFrameMetrics()); + const auto oldZoom = apzc->GetFrameMetrics().GetZoom().scale; + + const auto tapResult = + Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(10)); + apzc->SetAllowedTouchBehavior(tapResult.mInputBlockId, + {kDefaultTouchBehavior}); + + mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time() - 20); + const auto touchResult = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time()); + apzc->SetAllowedTouchBehavior(touchResult.mInputBlockId, + {kDefaultTouchBehavior}); + + // We should be able to hold down the second touch as long as we like + // before beginning to move + mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time() + 100); + TouchMove(apzc, ScreenIntPoint(10, 50), mcc->Time()); + + mcc->AdvanceByMillis(10); + TouchMove(apzc, ScreenIntPoint(10, 150), mcc->Time()); + + mcc->AdvanceByMillis(10); + TouchUp(apzc, ScreenIntPoint(10, 150), mcc->Time()); + + const auto newZoom = apzc->GetFrameMetrics().GetZoom().scale; + EXPECT_NE(newZoom, oldZoom); +} + +TEST_F(APZCGestureDetectorTester, OneTouchPinchGestureNoMoveTriggersDoubleTap) { + // Take less than StaticPrefs::apz_max_tap_time() until second touch down, + // then wait longer than StaticPrefs::apz_max_tap_time(), lift finger up + // and expect a successful double tap. No zooming should be performed + // by the one-touch pinch codepath. + SCOPED_GFX_PREF_BOOL("apz.one_touch_pinch.enabled", true); + + apzc->SetFrameMetrics(GetPinchableFrameMetrics()); + const auto oldZoom = apzc->GetFrameMetrics().GetZoom().scale; + + MakeApzcZoomable(); + + EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, 0, apzc->GetGuid(), _, _)) + .Times(0); + EXPECT_CALL(*mcc, + HandleTap(TapType::eDoubleTap, _, 0, apzc->GetGuid(), _, _)); + + const auto tapResult = + Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(10)); + apzc->SetAllowedTouchBehavior(tapResult.mInputBlockId, + {kDefaultTouchBehavior}); + + mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time() - 20); + const auto touchResult = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time()); + apzc->SetAllowedTouchBehavior(touchResult.mInputBlockId, + {kDefaultTouchBehavior}); + + // We should be able to hold down the second touch as long as we like + // before lifting the finger + mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time() + 100); + TouchUp(apzc, ScreenIntPoint(10, 10), mcc->Time()); + + const auto newZoom = apzc->GetFrameMetrics().GetZoom().scale; + EXPECT_EQ(newZoom, oldZoom); +} + +TEST_F(APZCGestureDetectorTester, OneTouchPinchGestureNonZoomablePage) { + // Use a non-zoomable page. Perform a tap and a touch-drag + // which on a zoomable page trigger a one touch pinch gesture, + // and expect a single tap followed by a touch-scroll + SCOPED_GFX_PREF_BOOL("apz.one_touch_pinch.enabled", true); + + apzc->SetFrameMetrics(GetPinchableFrameMetrics(1.0f)); + const auto oldZoom = apzc->GetFrameMetrics().GetZoom().scale; + const auto oldScrollOffset = apzc->GetFrameMetrics().GetVisualScrollOffset(); + MakeApzcUnzoomable(); + + EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, 0, apzc->GetGuid(), _, _)) + .Times(1); + EXPECT_CALL(*mcc, HandleTap(TapType::eDoubleTap, _, 0, apzc->GetGuid(), _, _)) + .Times(0); + + const auto tapResult = + Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(10)); + apzc->SetAllowedTouchBehavior(tapResult.mInputBlockId, + {kDefaultTouchBehavior}); + + mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time() - 20); + const auto touchResult = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time()); + apzc->SetAllowedTouchBehavior(touchResult.mInputBlockId, + {kDefaultTouchBehavior}); + + // We should be able to hold down the second touch as long as we like + // before beginning to move + mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time() + 100); + TouchMove(apzc, ScreenIntPoint(10, 50), mcc->Time()); + + mcc->AdvanceByMillis(10); + TouchMove(apzc, ScreenIntPoint(10, 100), mcc->Time()); + + mcc->AdvanceByMillis(10); + TouchUp(apzc, ScreenIntPoint(10, 100), mcc->Time()); + + const auto newZoom = apzc->GetFrameMetrics().GetZoom().scale; + EXPECT_EQ(newZoom, oldZoom); + + const auto newScrollOffset = apzc->GetFrameMetrics().GetVisualScrollOffset(); + EXPECT_NE(newScrollOffset, oldScrollOffset); +} + +TEST_F(APZCGestureDetectorTester, OneTouchPinchGestureTimeout) { + // Take longer than StaticPrefs::apz_max_tap_time() until second touch down + // and expect no one touch pinch gesture being performed + SCOPED_GFX_PREF_BOOL("apz.one_touch_pinch.enabled", true); + + MakeApzcZoomable(); + apzc->SetFrameMetrics(GetPinchableFrameMetrics()); + const auto oldZoom = apzc->GetFrameMetrics().GetZoom().scale; + + EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, 0, apzc->GetGuid(), _, _)) + .Times(1); + + const auto tapResult = + Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(10)); + apzc->SetAllowedTouchBehavior(tapResult.mInputBlockId, + {kDefaultTouchBehavior}); + + mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time()); + const auto touchResult = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time()); + apzc->SetAllowedTouchBehavior(touchResult.mInputBlockId, + {kDefaultTouchBehavior}); + + mcc->AdvanceByMillis(10); + TouchMove(apzc, ScreenIntPoint(10, 50), mcc->Time()); + + mcc->AdvanceByMillis(10); + TouchMove(apzc, ScreenIntPoint(10, 150), mcc->Time()); + + mcc->AdvanceByMillis(10); + TouchUp(apzc, ScreenIntPoint(10, 150), mcc->Time()); + + const auto newZoom = apzc->GetFrameMetrics().GetZoom().scale; + EXPECT_EQ(newZoom, oldZoom); +} + +TEST_F(APZCGestureDetectorTester, OneTouchPinchGestureDisabled) { + // With apz.one_touch_pinch disabled, + // perform one touch pinch gesture within the time threshold, + // and expect no zooming. + SCOPED_GFX_PREF_BOOL("apz.one_touch_pinch.enabled", false); + + MakeApzcZoomable(); + apzc->SetFrameMetrics(GetPinchableFrameMetrics()); + const auto oldZoom = apzc->GetFrameMetrics().GetZoom().scale; + const auto oldScrollOffset = apzc->GetFrameMetrics().GetVisualScrollOffset(); + + // todo: enable following EXPECT_CALLs when fixing bug 1881794 + // EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, 0, apzc->GetGuid(), _, + // _)) + // .Times(1); + // EXPECT_CALL(*mcc, HandleTap(TapType::eDoubleTap, _, 0, apzc->GetGuid(), _, + // _)) + // .Times(0); + + const auto tapResult = + Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(10)); + apzc->SetAllowedTouchBehavior(tapResult.mInputBlockId, + {kDefaultTouchBehavior}); + + mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time() - 20); + const auto touchResult = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time()); + apzc->SetAllowedTouchBehavior(touchResult.mInputBlockId, + {kDefaultTouchBehavior}); + + // We should be able to hold down the second touch as long as we like + // before beginning to move + mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time() + 100); + TouchMove(apzc, ScreenIntPoint(10, 50), mcc->Time()); + + mcc->AdvanceByMillis(10); + TouchMove(apzc, ScreenIntPoint(10, 150), mcc->Time()); + + mcc->AdvanceByMillis(10); + TouchUp(apzc, ScreenIntPoint(10, 150), mcc->Time()); + + const auto newZoom = apzc->GetFrameMetrics().GetZoom().scale; + EXPECT_EQ(newZoom, oldZoom); + + const auto newScrollOffset = apzc->GetFrameMetrics().GetVisualScrollOffset(); + EXPECT_NE(newScrollOffset, oldScrollOffset); +} diff --git a/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js b/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js index c290965845..1642bc147a 100644 --- a/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js +++ b/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js @@ -498,7 +498,7 @@ async function promiseNativeTouchpadPanEventAndWaitForObserver( return new Promise(resolve => { var observer = { - observe(aSubject, aTopic, aData) { + observe(aSubject, aTopic) { if (aTopic == "touchpadpanevent") { resolve(); } @@ -557,7 +557,7 @@ function promiseNativePanGestureEventAndWaitForObserver( ) { return new Promise(resolve => { var observer = { - observe(aSubject, aTopic, aData) { + observe(aSubject, aTopic) { if (aTopic == "mousescrollevent") { resolve(); } @@ -588,7 +588,7 @@ function promiseNativeWheelAndWaitForObserver( ) { return new Promise(resolve => { var observer = { - observe(aSubject, aTopic, aData) { + observe(aSubject, aTopic) { if (aTopic == "mousescrollevent") { resolve(); } @@ -614,7 +614,7 @@ function promiseNativeWheelAndWaitForWheelEvent( var targetWindow = windowForTarget(aTarget); targetWindow.addEventListener( "wheel", - function (e) { + function () { setTimeout(resolve, 0); }, { once: true } @@ -1566,7 +1566,7 @@ function promiseScrollend(aTarget = window) { function promiseTouchEnd(element, count = 1) { return new Promise(resolve => { var eventCount = 0; - var counterFunction = function (e) { + var counterFunction = function () { eventCount++; if (eventCount == count) { element.removeEventListener("touchend", counterFunction, { @@ -1816,7 +1816,7 @@ async function panRightToLeftUpdate(aElement, aX, aY, aMultiplier) { ); } -async function panRightToLeftEnd(aElement, aX, aY, aMultiplier) { +async function panRightToLeftEnd(aElement, aX, aY) { await NativePanHandler.promiseNativePanEvent( aElement, aX, @@ -1869,7 +1869,7 @@ async function panLeftToRightUpdate(aElement, aX, aY, aMultiplier) { ); } -async function panLeftToRightEnd(aElement, aX, aY, aMultiplier) { +async function panLeftToRightEnd(aElement, aX, aY) { await NativePanHandler.promiseNativePanEvent( aElement, aX, diff --git a/gfx/layers/apz/test/mochitest/apz_test_utils.js b/gfx/layers/apz/test/mochitest/apz_test_utils.js index 821c66103d..cdae7824b2 100644 --- a/gfx/layers/apz/test/mochitest/apz_test_utils.js +++ b/gfx/layers/apz/test/mochitest/apz_test_utils.js @@ -309,7 +309,7 @@ function promiseAfterPaint() { // occurred by the the returned promise resolves. If you want to wait // for those repaints, consider using promiseApzFlushedRepaints instead. function promiseOnlyApzControllerFlushedWithoutSetTimeout(aWindow = window) { - return new Promise(function (resolve, reject) { + return new Promise(function (resolve) { var repaintDone = function () { dump("PromiseApzRepaintsFlushed: APZ flush done\n"); SpecialPowers.Services.obs.removeObserver( @@ -518,7 +518,7 @@ function runSubtestsSeriallyInFreshWindows(aSubtests) { if (test.onload) { w.addEventListener( "load", - function (e) { + function () { test.onload(w); }, { once: true } diff --git a/gfx/layers/apz/test/mochitest/browser.toml b/gfx/layers/apz/test/mochitest/browser.toml index 5432aa0ae1..67428eee23 100644 --- a/gfx/layers/apz/test/mochitest/browser.toml +++ b/gfx/layers/apz/test/mochitest/browser.toml @@ -19,7 +19,7 @@ support-files = ["helper_test_autoscrolling_in_oop_frame.html"] support-files = ["helper_background_tab_load_scroll.html"] ["browser_test_background_tab_scroll.js"] -skip-if = ["toolkit == 'android'"] # wheel events not supported on mobile +skip-if = ["os == 'android'"] # wheel events not supported on mobile support-files = ["helper_background_tab_scroll.html"] ["browser_test_content_response_timeout.js"] @@ -28,7 +28,7 @@ support-files = ["helper_content_response_timeout.html"] ["browser_test_group_fission.js"] skip-if = [ "win11_2009 && bits == 32", # intermittent failures on on win11/32 - "os == 'linux' && bits == 64", # Bug 1773830 + "os == 'linux' && os_version == '18.04' && bits == 64", # Bug 1773830 ] support-files = [ "FissionTestHelperParent.sys.mjs", @@ -49,7 +49,7 @@ support-files = ["helper_scroll_thumb_dragging.html"] ["browser_test_scrollbar_in_extension_popup_window.js"] skip-if = [ "verify", - "os == 'linux'" # Bug 1713052 + "os == 'linux' && os_version == '18.04'" # Bug 1713052 ] ["browser_test_scrolling_in_extension_popup_window.js"] @@ -70,7 +70,7 @@ skip-if = ["os == 'win'"] # bug 1495580 support-files = ["helper_test_select_zoom.html"] ["browser_test_tab_drag_event_counts.js"] -skip-if = ["os == 'linux'"] # No native key event support on Linux at this time (bug 1770143) +skip-if = ["os == 'linux' && os_version == '18.04'"] # No native key event support on Linux at this time (bug 1770143) support-files = [ "helper_test_tab_drag_event_counts.html" ] diff --git a/gfx/layers/apz/test/mochitest/browser_test_autoscrolling_in_oop_frame.js b/gfx/layers/apz/test/mochitest/browser_test_autoscrolling_in_oop_frame.js index 26d0ff6109..f7f83575f2 100644 --- a/gfx/layers/apz/test/mochitest/browser_test_autoscrolling_in_oop_frame.js +++ b/gfx/layers/apz/test/mochitest/browser_test_autoscrolling_in_oop_frame.js @@ -74,7 +74,7 @@ async function doTest() { return new Promise(resolve => { content.addEventListener( "scroll", - event => { + () => { dump("Got a scroll event in the iframe\n"); resolve(); }, diff --git a/gfx/layers/apz/test/mochitest/browser_test_content_response_timeout.js b/gfx/layers/apz/test/mochitest/browser_test_content_response_timeout.js index a80fd77c17..98f6ea6c29 100644 --- a/gfx/layers/apz/test/mochitest/browser_test_content_response_timeout.js +++ b/gfx/layers/apz/test/mochitest/browser_test_content_response_timeout.js @@ -60,6 +60,7 @@ add_task(async () => { ); await new Promise(resolve => { + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout setTimeout(resolve, 200); }); diff --git a/gfx/layers/apz/test/mochitest/browser_test_scrolling_in_extension_popup_window.js b/gfx/layers/apz/test/mochitest/browser_test_scrolling_in_extension_popup_window.js index 6da3f3311b..9896e628e3 100644 --- a/gfx/layers/apz/test/mochitest/browser_test_scrolling_in_extension_popup_window.js +++ b/gfx/layers/apz/test/mochitest/browser_test_scrolling_in_extension_popup_window.js @@ -98,7 +98,7 @@ add_task(async () => { return new Promise(resolve => { content.window.addEventListener( "scroll", - event => { + () => { dump("Got a scroll event in the popup content document\n"); resolve(); }, diff --git a/gfx/layers/apz/test/mochitest/helper_basic_scrollend.html b/gfx/layers/apz/test/mochitest/helper_basic_scrollend.html index 9d71fe6251..6c31859690 100644 --- a/gfx/layers/apz/test/mochitest/helper_basic_scrollend.html +++ b/gfx/layers/apz/test/mochitest/helper_basic_scrollend.html @@ -19,7 +19,7 @@ const searchParams = new URLSearchParams(location.search); async function test() { var scrollendCount = 0; - function onScrollend(e) { + function onScrollend() { scrollendCount += 1; } diff --git a/gfx/layers/apz/test/mochitest/helper_browser_test_utils.js b/gfx/layers/apz/test/mochitest/helper_browser_test_utils.js index ac68c9b1d4..22a072e48d 100644 --- a/gfx/layers/apz/test/mochitest/helper_browser_test_utils.js +++ b/gfx/layers/apz/test/mochitest/helper_browser_test_utils.js @@ -4,7 +4,7 @@ Services.scriptloader.loadSubScript( this ); -function openSelectPopup(selector = "select", win = window) { +function openSelectPopup(selector, win = window) { let popupShownPromise = BrowserTestUtils.waitForSelectPopupShown(win); EventUtils.synthesizeKey("KEY_ArrowDown", { altKey: true }, win); return popupShownPromise; diff --git a/gfx/layers/apz/test/mochitest/helper_bug1346632.html b/gfx/layers/apz/test/mochitest/helper_bug1346632.html index f91f8159b5..c7f92c3810 100644 --- a/gfx/layers/apz/test/mochitest/helper_bug1346632.html +++ b/gfx/layers/apz/test/mochitest/helper_bug1346632.html @@ -28,7 +28,7 @@ async function test() { var root = document.scrollingElement; var scrollPos = root.scrollTop; - var scrollPromise = new Promise((resolve, reject) => { + var scrollPromise = new Promise((resolve) => { document.addEventListener("scroll", () => { ok(root.scrollTop > scrollPos, "document scrolled after dragging scrollbar"); resolve(); diff --git a/gfx/layers/apz/test/mochitest/helper_bug1414336.html b/gfx/layers/apz/test/mochitest/helper_bug1414336.html index 636328b7e4..c0d35db401 100644 --- a/gfx/layers/apz/test/mochitest/helper_bug1414336.html +++ b/gfx/layers/apz/test/mochitest/helper_bug1414336.html @@ -62,14 +62,14 @@ waitUntilApzStable().then(async () => { let target0 = window.document.getElementById("target0"); let target0_events = ["pointerdown", "pointermove"]; - target0_events.forEach((elem, index, arr) => { + target0_events.forEach((elem) => { target0.addEventListener(elem, (event) => { is(event.type, target0_events[0], "receive " + event.type + " on target0"); target0_events.shift(); }, { once: true }); }); - target0.addEventListener("pointercancel", (event) => { + target0.addEventListener("pointercancel", () => { ok(false, "Shouldn't receive pointercancel when content prevents default on touchstart"); // Wait until the event is done processing before we end the subtest, // otherwise on Android the pointer events pref is flipped back to false @@ -81,7 +81,7 @@ waitUntilApzStable().then(async () => { event.preventDefault(); }, { once: true }); - target0.addEventListener("pointerup", (event) => { + target0.addEventListener("pointerup", () => { ok(!target0_events.length, " should receive " + target0_events + " on target0"); // Wait until the event is done processing before we end the subtest, // otherwise on Android the pointer events pref is flipped back to false diff --git a/gfx/layers/apz/test/mochitest/helper_bug1502010_unconsumed_pan.html b/gfx/layers/apz/test/mochitest/helper_bug1502010_unconsumed_pan.html index 73badf4bc7..8534e8886b 100644 --- a/gfx/layers/apz/test/mochitest/helper_bug1502010_unconsumed_pan.html +++ b/gfx/layers/apz/test/mochitest/helper_bug1502010_unconsumed_pan.html @@ -38,7 +38,7 @@ async function test() { var target = document.getElementById("carousel"); - target.addEventListener("pointercancel", (event) => { + target.addEventListener("pointercancel", () => { ok(false, "Received pointercancel, uh-oh!"); endEventReceived = true; setTimeout(checkForTestEnd, 0); diff --git a/gfx/layers/apz/test/mochitest/helper_bug1506497_touch_action_fixed_on_fixed.html b/gfx/layers/apz/test/mochitest/helper_bug1506497_touch_action_fixed_on_fixed.html index cc73fe99ea..b853bde04d 100644 --- a/gfx/layers/apz/test/mochitest/helper_bug1506497_touch_action_fixed_on_fixed.html +++ b/gfx/layers/apz/test/mochitest/helper_bug1506497_touch_action_fixed_on_fixed.html @@ -11,7 +11,7 @@ <script type="application/javascript"> async function test() { - document.getElementById("overlay").addEventListener("touchstart", function(e) { + document.getElementById("overlay").addEventListener("touchstart", function() { // no need to do anything here. Just having a non-passive touchstart // listener will force APZ to wait for the main thread to handle the // touch event. The bug is that the touch-action:none property on the @@ -34,7 +34,7 @@ async function test() { // This promise will resolve after the main thread has processed // all the synthesized touch events. let promiseTouchEnd = new Promise(resolve => { - var waitForTouchEnd = function(e) { + var waitForTouchEnd = function() { dump("touchend listener hit\n"); resolve(); }; diff --git a/gfx/layers/apz/test/mochitest/helper_bug1695598.html b/gfx/layers/apz/test/mochitest/helper_bug1695598.html index fb6102e33d..7961d7ced4 100644 --- a/gfx/layers/apz/test/mochitest/helper_bug1695598.html +++ b/gfx/layers/apz/test/mochitest/helper_bug1695598.html @@ -19,7 +19,7 @@ let utils = SpecialPowers.getDOMWindowUtils(window); let timeStamp = document.timeline.currentTime; - async function sendScrollEvent(aRafTimestamp) { + async function sendScrollEvent() { if (i < scrollEvents) { if (timeStamp == document.timeline.currentTime) { // If we are in a rAF callback at the same time stamp we've already diff --git a/gfx/layers/apz/test/mochitest/helper_content_response_timeout.html b/gfx/layers/apz/test/mochitest/helper_content_response_timeout.html index 41a0319699..c0481d01a4 100644 --- a/gfx/layers/apz/test/mochitest/helper_content_response_timeout.html +++ b/gfx/layers/apz/test/mochitest/helper_content_response_timeout.html @@ -11,7 +11,7 @@ div { height: 1000vh; } </style> <div id='target'></div> <script> -window.addEventListener('wheel', (e) => { +window.addEventListener('wheel', () => { const timeAtStart = window.performance.now(); while (window.performance.now() - timeAtStart < 200) { // Make a 200ms busy state. diff --git a/gfx/layers/apz/test/mochitest/helper_displayport_expiry.html b/gfx/layers/apz/test/mochitest/helper_displayport_expiry.html index 023786a270..b463e4f39c 100644 --- a/gfx/layers/apz/test/mochitest/helper_displayport_expiry.html +++ b/gfx/layers/apz/test/mochitest/helper_displayport_expiry.html @@ -53,7 +53,7 @@ async function test() { await promiseFrame(); let paintCount = 0; - function countPaints(e) { + function countPaints() { paintCount += 1; } diff --git a/gfx/layers/apz/test/mochitest/helper_fission_event_region_override.html b/gfx/layers/apz/test/mochitest/helper_fission_event_region_override.html index 82f529bebd..8ebfc492f2 100644 --- a/gfx/layers/apz/test/mochitest/helper_fission_event_region_override.html +++ b/gfx/layers/apz/test/mochitest/helper_fission_event_region_override.html @@ -29,7 +29,7 @@ let code_for_oopif_to_run = function() { let result = { x: e.clientX, y: e.clientY }; FissionTestHelper.fireEventInEmbedder("OOPIF:WheelData", result); }, { passive: true }); - document.addEventListener("scroll", function(e) { + document.addEventListener("scroll", function() { dump(`OOPIF got scroll to ${window.scrollX},${window.scrollY}\n`); let result = { x: window.scrollX, y: window.scrollY }; FissionTestHelper.fireEventInEmbedder("OOPIF:Scrolled", result); diff --git a/gfx/layers/apz/test/mochitest/helper_fission_scroll_oopif.html b/gfx/layers/apz/test/mochitest/helper_fission_scroll_oopif.html index 2911b1eaf0..5a192c9f9e 100644 --- a/gfx/layers/apz/test/mochitest/helper_fission_scroll_oopif.html +++ b/gfx/layers/apz/test/mochitest/helper_fission_scroll_oopif.html @@ -66,7 +66,7 @@ let make_oopif_scrollable = function() { FissionTestHelper.fireEventInEmbedder("OOPIF:Scrollable", result); }); // Also register a scroll listener for when it actually gets scrolled. - window.addEventListener("scroll", function(e) { + window.addEventListener("scroll", function() { dump(`OOPIF got scroll event, now at ${window.scrollY}\n`); let result = { y: window.scrollY }; FissionTestHelper.fireEventInEmbedder("OOPIF:Scrolled", result); diff --git a/gfx/layers/apz/test/mochitest/helper_fullscreen.html b/gfx/layers/apz/test/mochitest/helper_fullscreen.html index 32de4979f2..7ac443a1cc 100644 --- a/gfx/layers/apz/test/mochitest/helper_fullscreen.html +++ b/gfx/layers/apz/test/mochitest/helper_fullscreen.html @@ -27,7 +27,7 @@ }); } - async function test(testDriver) { + async function test() { target.requestFullscreen(); await waitForFullscreenChange(); diff --git a/gfx/layers/apz/test/mochitest/helper_hittest_deep_scene_stack.html b/gfx/layers/apz/test/mochitest/helper_hittest_deep_scene_stack.html index a04b1d3e83..30a9740d24 100644 --- a/gfx/layers/apz/test/mochitest/helper_hittest_deep_scene_stack.html +++ b/gfx/layers/apz/test/mochitest/helper_hittest_deep_scene_stack.html @@ -38,7 +38,7 @@ for (var i = 3; i < 1000; i++) { } document.body.appendChild(div); -async function test(testDriver) { +async function test() { var config = getHitTestConfig(); var utils = config.utils; diff --git a/gfx/layers/apz/test/mochitest/helper_hittest_fixed-2.html b/gfx/layers/apz/test/mochitest/helper_hittest_fixed-2.html index 0f20719d46..b83b864aa2 100644 --- a/gfx/layers/apz/test/mochitest/helper_hittest_fixed-2.html +++ b/gfx/layers/apz/test/mochitest/helper_hittest_fixed-2.html @@ -45,7 +45,7 @@ async function test() { e.stopPropagation(); // do not propagate event to |fixed| ancestor resolve(); }); - fixed.addEventListener("click", e => { + fixed.addEventListener("click", () => { // Since target's listener calls stopPropagation(), if we get here // then the coordinates of the click event did not correspond to // |target|, but somewhere else on |fixed|. diff --git a/gfx/layers/apz/test/mochitest/helper_hittest_fixed-3.html b/gfx/layers/apz/test/mochitest/helper_hittest_fixed-3.html index 2004ea9ae4..092c5b0dfa 100644 --- a/gfx/layers/apz/test/mochitest/helper_hittest_fixed-3.html +++ b/gfx/layers/apz/test/mochitest/helper_hittest_fixed-3.html @@ -72,7 +72,7 @@ async function test() { e.stopPropagation(); // do not propagate event to ancestors resolve(); }); - fixed.addEventListener("click", e => { + fixed.addEventListener("click", () => { // Since target's listener calls stopPropagation(), if we get here // then the coordinates of the click event did not correspond to // |target|, but somewhere else on |fixed|. @@ -82,7 +82,7 @@ async function test() { todo(false, "Fixed ancestor should not be hit"); resolve(); }); - window.addEventListener("click", e => { + window.addEventListener("click", () => { // Similarly, the root content document's window should not be hit. ok(false, "Root document should not be hit"); resolve(); diff --git a/gfx/layers/apz/test/mochitest/helper_hittest_fixed.html b/gfx/layers/apz/test/mochitest/helper_hittest_fixed.html index 530c53fd7a..3185d83bf5 100644 --- a/gfx/layers/apz/test/mochitest/helper_hittest_fixed.html +++ b/gfx/layers/apz/test/mochitest/helper_hittest_fixed.html @@ -53,7 +53,7 @@ async function test() { e.stopPropagation(); // do not propagate event to |fixed| ancestor resolve(); }); - fixed.addEventListener("click", e => { + fixed.addEventListener("click", () => { // Since target's listener calls stopPropagation(), if we get here // then the coordinates of the click event did not correspond to // |target|, but somewhere else on |fixed|. diff --git a/gfx/layers/apz/test/mochitest/helper_hittest_hidden_inactive_scrollframe.html b/gfx/layers/apz/test/mochitest/helper_hittest_hidden_inactive_scrollframe.html index 0abed82156..6d9ea7bc53 100644 --- a/gfx/layers/apz/test/mochitest/helper_hittest_hidden_inactive_scrollframe.html +++ b/gfx/layers/apz/test/mochitest/helper_hittest_hidden_inactive_scrollframe.html @@ -26,7 +26,7 @@ </body> <script type="application/javascript"> -function test(testDriver) { +function test() { var config = getHitTestConfig(); var utils = config.utils; diff --git a/gfx/layers/apz/test/mochitest/helper_hittest_iframe_perspective-2.html b/gfx/layers/apz/test/mochitest/helper_hittest_iframe_perspective-2.html index 9838a02aa9..b6128aaa87 100644 --- a/gfx/layers/apz/test/mochitest/helper_hittest_iframe_perspective-2.html +++ b/gfx/layers/apz/test/mochitest/helper_hittest_iframe_perspective-2.html @@ -44,7 +44,7 @@ async function test() { } }); - window.addEventListener("mousedown", event => { + window.addEventListener("mousedown", () => { ok(true, "Parent document should have received mouse-down"); resolve(); }); diff --git a/gfx/layers/apz/test/mochitest/helper_hittest_overscroll.html b/gfx/layers/apz/test/mochitest/helper_hittest_overscroll.html index c245258b68..c33dff3f28 100644 --- a/gfx/layers/apz/test/mochitest/helper_hittest_overscroll.html +++ b/gfx/layers/apz/test/mochitest/helper_hittest_overscroll.html @@ -63,7 +63,7 @@ function startListeningForClickEventsInChrome() { topWin = Services.wm.getMostRecentWindow("navigator:geckoview"); } let chromeReceivedClick = false; - function chromeListener(e) { + function chromeListener() { chromeReceivedClick = true; } topWin.addEventListener("click", chromeListener); diff --git a/gfx/layers/apz/test/mochitest/helper_hittest_overscroll_contextmenu.html b/gfx/layers/apz/test/mochitest/helper_hittest_overscroll_contextmenu.html index 8aff3103dd..0bb3972c8a 100644 --- a/gfx/layers/apz/test/mochitest/helper_hittest_overscroll_contextmenu.html +++ b/gfx/layers/apz/test/mochitest/helper_hittest_overscroll_contextmenu.html @@ -43,7 +43,7 @@ function startListeningForContextmenuEventsInChrome() { topWin = Services.wm.getMostRecentWindow("navigator:geckoview"); } let chromeReceivedContextmenu = false; - function chromeListener(e) { + function chromeListener() { chromeReceivedContextmenu = true; } topWin.addEventListener("contextmenu", chromeListener); @@ -95,7 +95,7 @@ async function test() { let midGutter = 4 / deviceScale; // gutter is 8 *screen* pixels startListeningForContextmenuEventsInChrome(); let contentReceivedContextmenu = false; - let contentListener = function(e) { + let contentListener = function() { contentReceivedContextmenu = true; }; document.addEventListener("contextmenu", contentListener); diff --git a/gfx/layers/apz/test/mochitest/helper_hittest_overscroll_subframe.html b/gfx/layers/apz/test/mochitest/helper_hittest_overscroll_subframe.html index 36918b3682..ff97c34bd5 100644 --- a/gfx/layers/apz/test/mochitest/helper_hittest_overscroll_subframe.html +++ b/gfx/layers/apz/test/mochitest/helper_hittest_overscroll_subframe.html @@ -84,7 +84,7 @@ async function test() { // This makes sure we catch the case where the overscroll transform causes // the event to incorrectly target the document. let receivedClick = false; - let listener = function(e) { + let listener = function() { receivedClick = true; }; document.addEventListener("click", listener); diff --git a/gfx/layers/apz/test/mochitest/helper_key_scroll.html b/gfx/layers/apz/test/mochitest/helper_key_scroll.html index 021e2803b7..4f574abd10 100644 --- a/gfx/layers/apz/test/mochitest/helper_key_scroll.html +++ b/gfx/layers/apz/test/mochitest/helper_key_scroll.html @@ -32,7 +32,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1383365 // page. This scroll is done synchronously because APZ doesn't have // current focus state at page load. let scrollBottomPromise = new Promise(resolve => { - let checkBottom = function(e) { + let checkBottom = function() { if (window.scrollY < window.scrollMaxY) { return; } @@ -63,7 +63,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1383365 // This scroll should be asynchronous now that the focus state is up to date. let scrollTopPromise = new Promise(resolve => { - let checkTop = function(e) { + let checkTop = function() { if (window.scrollY > 0) { return; } diff --git a/gfx/layers/apz/test/mochitest/helper_main_thread_smooth_scroll_scrollend.html b/gfx/layers/apz/test/mochitest/helper_main_thread_smooth_scroll_scrollend.html index 4f07db516e..c4a98ec7fa 100644 --- a/gfx/layers/apz/test/mochitest/helper_main_thread_smooth_scroll_scrollend.html +++ b/gfx/layers/apz/test/mochitest/helper_main_thread_smooth_scroll_scrollend.html @@ -25,7 +25,7 @@ async function test() { let scrollendCount = 0; - window.addEventListener("scrollend", e => { + window.addEventListener("scrollend", () => { scrollendCount += 1; }); diff --git a/gfx/layers/apz/test/mochitest/helper_minimum_scale_1_0.html b/gfx/layers/apz/test/mochitest/helper_minimum_scale_1_0.html index 17ccb3a54d..9c98ecf727 100644 --- a/gfx/layers/apz/test/mochitest/helper_minimum_scale_1_0.html +++ b/gfx/layers/apz/test/mochitest/helper_minimum_scale_1_0.html @@ -22,7 +22,7 @@ <script type="application/javascript"> const utils = SpecialPowers.getDOMWindowUtils(window); - async function test(testDriver) { + async function test() { utils.scrollToVisual(100, 0, utils.UPDATE_TYPE_MAIN_THREAD, utils.SCROLL_MODE_INSTANT); diff --git a/gfx/layers/apz/test/mochitest/helper_no_scalable_with_initial_scale.html b/gfx/layers/apz/test/mochitest/helper_no_scalable_with_initial_scale.html index 7280a26006..1c26fafdb7 100644 --- a/gfx/layers/apz/test/mochitest/helper_no_scalable_with_initial_scale.html +++ b/gfx/layers/apz/test/mochitest/helper_no_scalable_with_initial_scale.html @@ -22,7 +22,7 @@ <script type="application/javascript"> const utils = SpecialPowers.getDOMWindowUtils(window); - async function test(testDriver) { + async function test() { utils.scrollToVisual(100, 0, utils.UPDATE_TYPE_MAIN_THREAD, utils.SCROLL_MODE_INSTANT); diff --git a/gfx/layers/apz/test/mochitest/helper_programmatic_scroll_behavior.html b/gfx/layers/apz/test/mochitest/helper_programmatic_scroll_behavior.html index 721ce7e538..755c4115e2 100644 --- a/gfx/layers/apz/test/mochitest/helper_programmatic_scroll_behavior.html +++ b/gfx/layers/apz/test/mochitest/helper_programmatic_scroll_behavior.html @@ -35,7 +35,7 @@ async function test() { // trigger one scroll event, so a scroll event count of 1 indicates that a // instant scroll was conducted. let scrollCount = 0; - window.addEventListener("scroll", (e) => { + window.addEventListener("scroll", () => { scrollCount += 1; }); diff --git a/gfx/layers/apz/test/mochitest/helper_touch_action_regions.html b/gfx/layers/apz/test/mochitest/helper_touch_action_regions.html index 6a8a09e55a..14e800a561 100644 --- a/gfx/layers/apz/test/mochitest/helper_touch_action_regions.html +++ b/gfx/layers/apz/test/mochitest/helper_touch_action_regions.html @@ -293,7 +293,7 @@ function* test(testDriver) { // waitUntilApzStable().then(runContinuation(myTest)); function runContinuation(testFunction) { return function() { - return new Promise(function(resolve, reject) { + return new Promise(function(resolve) { var testContinuation = null; function driveTest() { diff --git a/gfx/layers/apz/test/mochitest/helper_zoomed_pan.html b/gfx/layers/apz/test/mochitest/helper_zoomed_pan.html index 98547fb73f..0692c2f588 100644 --- a/gfx/layers/apz/test/mochitest/helper_zoomed_pan.html +++ b/gfx/layers/apz/test/mochitest/helper_zoomed_pan.html @@ -42,7 +42,7 @@ x: 0, y: 0, dx: (width) => -computeDelta(width), - dy: (height) => 0, + dy: () => 0, expected: { x: [OFFSET_CSS_PX, "x-offset was adjusted"], y: [0, "y-offset was not affected"], @@ -51,7 +51,7 @@ { x: OFFSET_CSS_PX, y: 0, - dx: (width) => 0, + dx: () => 0, dy: (height) => -computeDelta(height), expected: { x: [OFFSET_CSS_PX, "x-offset was not affected"], diff --git a/gfx/layers/apz/test/mochitest/test_smoothness.html b/gfx/layers/apz/test/mochitest/test_smoothness.html index 64cb8bcefa..0f2ca3219e 100644 --- a/gfx/layers/apz/test/mochitest/test_smoothness.html +++ b/gfx/layers/apz/test/mochitest/test_smoothness.html @@ -23,7 +23,7 @@ SimpleTest.waitForExplicitFinish(); var utils = SpecialPowers.getDOMWindowUtils(window); - async function sendScrollEvent(aRafTimestamp) { + async function sendScrollEvent() { var scrollDiv = document.getElementById("content"); if (i < scrollEvents) { diff --git a/gfx/layers/apz/test/mochitest/test_touch_listeners_impacting_wheel.html b/gfx/layers/apz/test/mochitest/test_touch_listeners_impacting_wheel.html index 71147d5238..0598f1a201 100644 --- a/gfx/layers/apz/test/mochitest/test_touch_listeners_impacting_wheel.html +++ b/gfx/layers/apz/test/mochitest/test_touch_listeners_impacting_wheel.html @@ -27,7 +27,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1203140 const kResponseTimeoutMs = 2 * 60 * 1000; // 2 minutes -function takeSnapshots(e) { +function takeSnapshots() { // Grab some snapshots, and make sure some of them are different (i.e. check // the page is scrolling in the compositor, concurrently with this wheel // listener running). @@ -69,7 +69,7 @@ async function test() { // Ensure the div is layerized by scrolling it await promiseMoveMouseAndScrollWheelOver(box, 10, 10); - box.addEventListener("touchstart", function(e) { + box.addEventListener("touchstart", function() { ok(false, "This should never be run"); }); box.addEventListener("wheel", takeSnapshots, { capture: false, passive: true }); diff --git a/gfx/layers/apz/test/reftest/reftest.list b/gfx/layers/apz/test/reftest/reftest.list index 77bfff3e6e..9af67384a8 100644 --- a/gfx/layers/apz/test/reftest/reftest.list +++ b/gfx/layers/apz/test/reftest/reftest.list @@ -1,14 +1,14 @@ # The following tests test the async positioning of the scrollbars. # Basic root-frame scrollbar with async scrolling # First make sure that we are actually drawing scrollbars -skip-if(!asyncPan) pref(apz.allow_zooming,true) != async-scrollbar-1-v.html about:blank -skip-if(!asyncPan) pref(apz.allow_zooming,true) != async-scrollbar-1-v-ref.html about:blank -fuzzy-if(Android,0-5,0-6) fuzzy-if(gtkWidget,1-8,8-32) fuzzy-if(cocoaWidget,16-22,20-44) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-v.html async-scrollbar-1-v-ref.html -fuzzy-if(Android,0-13,0-10) fuzzy-if(gtkWidget,1-30,4-32) fuzzy-if(cocoaWidget,14-22,20-44) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-h.html async-scrollbar-1-h-ref.html -fuzzy-if(Android,0-13,0-21) fuzzy-if(gtkWidget,1-4,4-24) fuzzy-if(cocoaWidget,11-18,44-88) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-vh.html async-scrollbar-1-vh-ref.html -fuzzy-if(Android,0-5,0-6) fuzzy-if(gtkWidget,1-8,8-32) fuzzy-if(cocoaWidget,16-22,20-44) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-v-rtl.html async-scrollbar-1-v-rtl-ref.html -fuzzy-if(Android,0-14,0-10) fuzzy-if(gtkWidget,1-30,12-32) fuzzy-if(cocoaWidget,14-22,20-44) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-h-rtl.html async-scrollbar-1-h-rtl-ref.html -fuzzy-if(Android,0-43,0-26) fuzzy-if(gtkWidget,0-14,12-32) fuzzy-if(cocoaWidget,11-18,26-76) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-vh-rtl.html async-scrollbar-1-vh-rtl-ref.html +skip-if(useDrawSnapshot) pref(apz.allow_zooming,true) != async-scrollbar-1-v.html about:blank +skip-if(useDrawSnapshot) pref(apz.allow_zooming,true) != async-scrollbar-1-v-ref.html about:blank +fuzzy-if(Android,0-5,0-6) fuzzy-if(gtkWidget,1-8,8-32) fuzzy-if(cocoaWidget,16-22,20-44) skip-if(useDrawSnapshot) pref(apz.allow_zooming,true) == async-scrollbar-1-v.html async-scrollbar-1-v-ref.html +fuzzy-if(Android,0-13,0-10) fuzzy-if(gtkWidget,1-30,4-32) fuzzy-if(cocoaWidget,14-22,20-44) skip-if(useDrawSnapshot) pref(apz.allow_zooming,true) == async-scrollbar-1-h.html async-scrollbar-1-h-ref.html +fuzzy-if(Android,0-13,0-21) fuzzy-if(gtkWidget,1-4,4-24) fuzzy-if(cocoaWidget,11-18,44-88) skip-if(useDrawSnapshot) pref(apz.allow_zooming,true) == async-scrollbar-1-vh.html async-scrollbar-1-vh-ref.html +fuzzy-if(Android,0-5,0-6) fuzzy-if(gtkWidget,1-8,8-32) fuzzy-if(cocoaWidget,16-22,20-44) skip-if(useDrawSnapshot) pref(apz.allow_zooming,true) == async-scrollbar-1-v-rtl.html async-scrollbar-1-v-rtl-ref.html +fuzzy-if(Android,0-14,0-10) fuzzy-if(gtkWidget,1-30,12-32) fuzzy-if(cocoaWidget,14-22,20-44) skip-if(useDrawSnapshot) pref(apz.allow_zooming,true) == async-scrollbar-1-h-rtl.html async-scrollbar-1-h-rtl-ref.html +fuzzy-if(Android,0-43,0-26) fuzzy-if(gtkWidget,0-14,12-32) fuzzy-if(cocoaWidget,11-18,26-76) skip-if(useDrawSnapshot) pref(apz.allow_zooming,true) == async-scrollbar-1-vh-rtl.html async-scrollbar-1-vh-rtl-ref.html # Different async zoom levels. Since the scrollthumb gets async-scaled in the # compositor, the border-radius ends of the scrollthumb are going to be a little @@ -37,7 +37,7 @@ fuzzy-if(Android,0-28,0-23) fuzzy-if(!Android,0-107,0-34) pref(apz.allow_zooming # Meta-viewport tag support skip-if(!Android) pref(apz.allow_zooming,true) == initial-scale-1.html initial-scale-1-ref.html -skip-if(!asyncPan) == frame-reconstruction-scroll-clamping.html frame-reconstruction-scroll-clamping-ref.html +skip-if(useDrawSnapshot) == frame-reconstruction-scroll-clamping.html frame-reconstruction-scroll-clamping-ref.html # Test that position:fixed and position:sticky elements are attached to the # layout viewport. diff --git a/gfx/layers/apz/testutil/APZTestData.h b/gfx/layers/apz/testutil/APZTestData.h index e4a73c80cc..d180bbcf1d 100644 --- a/gfx/layers/apz/testutil/APZTestData.h +++ b/gfx/layers/apz/testutil/APZTestData.h @@ -144,10 +144,10 @@ class APZTestData { // A helper class for logging data for a paint. class APZPaintLogHelper { public: - APZPaintLogHelper(APZTestData* aTestData, SequenceNumber aPaintSequenceNumber) + APZPaintLogHelper(APZTestData* aTestData, SequenceNumber aPaintSequenceNumber, + bool aIsTestLoggingEnabled) : mTestData(aTestData), mPaintSequenceNumber(aPaintSequenceNumber) { - MOZ_ASSERT(!aTestData || StaticPrefs::apz_test_logging_enabled(), - "don't call me"); + MOZ_ASSERT(!aTestData || aIsTestLoggingEnabled, "don't call me"); } template <typename Value> diff --git a/gfx/layers/apz/util/APZCCallbackHelper.cpp b/gfx/layers/apz/util/APZCCallbackHelper.cpp index 9ad65ce981..508cd8e67f 100644 --- a/gfx/layers/apz/util/APZCCallbackHelper.cpp +++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp @@ -518,7 +518,8 @@ nsEventStatus APZCCallbackHelper::DispatchSynthesizedMouseEvent( WidgetMouseEvent::eNormal); event.mRefPoint = LayoutDeviceIntPoint::Truncate(aRefPoint.x, aRefPoint.y); event.mButton = MouseButton::ePrimary; - event.mButtons |= MouseButtonsFlag::ePrimaryFlag; + event.mButtons = aMsg == eMouseDown ? MouseButtonsFlag::ePrimaryFlag + : MouseButtonsFlag::eNoButtons; event.mInputSource = dom::MouseEvent_Binding::MOZ_SOURCE_TOUCH; if (aMsg == eMouseLongTap) { event.mFlags.mOnlyChromeDispatch = true; diff --git a/gfx/layers/apz/util/APZEventState.cpp b/gfx/layers/apz/util/APZEventState.cpp index 7384296f45..5db6a08429 100644 --- a/gfx/layers/apz/util/APZEventState.cpp +++ b/gfx/layers/apz/util/APZEventState.cpp @@ -240,7 +240,7 @@ void APZEventState::ProcessLongTap(PresShell* aPresShell, false; #elif defined(MOZ_WIDGET_ANDROID) // On Android, GeckoView calls preventDefault() in a JSActor - // (ContentDelegateChild.jsm) when opening context menu so that we can + // (ContentDelegateChild.sys.mjs) when opening context menu so that we can // tell whether contextmenu opens in response to the contextmenu event by // checking where preventDefault() got called. preventDefaultResult == PreventDefaultResult::ByChrome; diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index bfc20b9b08..4187e48955 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -27,6 +27,7 @@ #include "mozilla/gfx/gfxVars.h" #include "mozilla/ipc/CrossProcessSemaphore.h" #include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc +#include "mozilla/layers/CanvasRenderer.h" #include "mozilla/layers/CompositableForwarder.h" #include "mozilla/layers/ISurfaceAllocator.h" #include "mozilla/layers/ImageBridgeChild.h" @@ -375,7 +376,8 @@ TextureData* TextureData::Create(TextureForwarder* aAllocator, RefPtr<CanvasChild> canvasChild = aAllocator->GetCanvasChild(); if (canvasChild) { return new RecordedTextureData(canvasChild.forget(), aSize, aFormat, - textureType); + textureType, + layers::TexTypeForWebgl(aKnowsCompositor)); } // If we must be remote, but there is no canvas child, then falling back // is not possible. @@ -746,12 +748,10 @@ void TextureClient::ReadUnlock() { } bool TextureClient::Lock(OpenMode aMode) { - MOZ_ASSERT(IsValid()); - MOZ_ASSERT(!mIsLocked); - if (!IsValid()) { + if (NS_WARN_IF(!IsValid())) { return false; } - if (mIsLocked) { + if (NS_WARN_IF(mIsLocked)) { return mOpenMode == aMode; } diff --git a/gfx/layers/client/TextureRecorded.cpp b/gfx/layers/client/TextureRecorded.cpp index 7e7ee2da99..da4ca4f8f3 100644 --- a/gfx/layers/client/TextureRecorded.cpp +++ b/gfx/layers/client/TextureRecorded.cpp @@ -23,9 +23,10 @@ static int64_t sNextRecordedTextureId = 0; RecordedTextureData::RecordedTextureData( already_AddRefed<CanvasChild> aCanvasChild, gfx::IntSize aSize, - gfx::SurfaceFormat aFormat, TextureType aTextureType) + gfx::SurfaceFormat aFormat, TextureType aTextureType, + TextureType aWebglTextureType) : mCanvasChild(aCanvasChild), mSize(aSize), mFormat(aFormat) { - mCanvasChild->EnsureRecorder(aSize, aFormat, aTextureType); + mCanvasChild->EnsureRecorder(aSize, aFormat, aTextureType, aWebglTextureType); } RecordedTextureData::~RecordedTextureData() { diff --git a/gfx/layers/client/TextureRecorded.h b/gfx/layers/client/TextureRecorded.h index d846c1fac1..56e504fb54 100644 --- a/gfx/layers/client/TextureRecorded.h +++ b/gfx/layers/client/TextureRecorded.h @@ -18,7 +18,8 @@ class RecordedTextureData final : public TextureData { public: RecordedTextureData(already_AddRefed<CanvasChild> aCanvasChild, gfx::IntSize aSize, gfx::SurfaceFormat aFormat, - TextureType aTextureType); + TextureType aTextureType, + TextureType aWebglTextureType = TextureType::Unknown); void FillInfo(TextureData::Info& aInfo) const final; diff --git a/gfx/layers/ipc/CanvasChild.cpp b/gfx/layers/ipc/CanvasChild.cpp index 553217d82b..515463cd8e 100644 --- a/gfx/layers/ipc/CanvasChild.cpp +++ b/gfx/layers/ipc/CanvasChild.cpp @@ -7,6 +7,9 @@ #include "CanvasChild.h" #include "MainThreadUtils.h" +#include "mozilla/dom/WorkerPrivate.h" +#include "mozilla/dom/WorkerRef.h" +#include "mozilla/dom/WorkerRunnable.h" #include "mozilla/gfx/CanvasManagerChild.h" #include "mozilla/gfx/DrawTargetRecording.h" #include "mozilla/gfx/Tools.h" @@ -18,6 +21,7 @@ #include "mozilla/layers/ImageDataSerializer.h" #include "mozilla/layers/SourceSurfaceSharedData.h" #include "mozilla/Maybe.h" +#include "mozilla/Mutex.h" #include "nsIObserverService.h" #include "RecordedCanvasEventImpl.h" @@ -33,9 +37,9 @@ class RecorderHelpers final : public CanvasDrawEventRecorder::Helpers { ~RecorderHelpers() override = default; - bool InitTranslator(TextureType aTextureType, gfx::BackendType aBackendType, - Handle&& aReadHandle, nsTArray<Handle>&& aBufferHandles, - uint64_t aBufferSize, + bool InitTranslator(TextureType aTextureType, TextureType aWebglTextureType, + gfx::BackendType aBackendType, Handle&& aReadHandle, + nsTArray<Handle>&& aBufferHandles, uint64_t aBufferSize, CrossProcessSemaphoreHandle&& aReaderSem, CrossProcessSemaphoreHandle&& aWriterSem) override { NS_ASSERT_OWNINGTHREAD(RecorderHelpers); @@ -43,7 +47,7 @@ class RecorderHelpers final : public CanvasDrawEventRecorder::Helpers { return false; } return mCanvasChild->SendInitTranslator( - aTextureType, aBackendType, std::move(aReadHandle), + aTextureType, aWebglTextureType, aBackendType, std::move(aReadHandle), std::move(aBufferHandles), aBufferSize, std::move(aReaderSem), std::move(aWriterSem)); } @@ -165,9 +169,104 @@ class SourceSurfaceCanvasRecording final : public gfx::SourceSurface { bool mDetached = false; }; -CanvasChild::CanvasChild() = default; +class CanvasDataShmemHolder { + public: + CanvasDataShmemHolder(ipc::SharedMemoryBasic* aShmem, + CanvasChild* aCanvasChild) + : mMutex("CanvasChild::DataShmemHolder::mMutex"), + mShmem(aShmem), + mCanvasChild(aCanvasChild) {} + + bool Init(dom::ThreadSafeWorkerRef* aWorkerRef) { + if (!aWorkerRef) { + return true; + } -CanvasChild::~CanvasChild() = default; + RefPtr<dom::StrongWorkerRef> workerRef = dom::StrongWorkerRef::Create( + aWorkerRef->Private(), "CanvasChild::DataShmemHolder", + [this]() { DestroyWorker(); }); + if (NS_WARN_IF(!workerRef)) { + return false; + } + + MutexAutoLock lock(mMutex); + mWorkerRef = new dom::ThreadSafeWorkerRef(workerRef); + return true; + } + + void Destroy() { + class DestroyRunnable final : public dom::WorkerRunnable { + public: + DestroyRunnable(dom::WorkerPrivate* aWorkerPrivate, + CanvasDataShmemHolder* aShmemHolder) + : dom::WorkerRunnable(aWorkerPrivate, + "CanvasDataShmemHolder::Destroy", + dom::WorkerRunnable::WorkerThread), + mShmemHolder(aShmemHolder) {} + + bool WorkerRun(JSContext* aCx, + dom::WorkerPrivate* aWorkerPrivate) override { + mShmemHolder->Destroy(); + return true; + } + + void PostRun(JSContext* aCx, dom::WorkerPrivate* aWorkerPrivate, + bool aRunResult) override {} + + bool PreDispatch(dom::WorkerPrivate* aWorkerPrivate) override { + return true; + } + + void PostDispatch(dom::WorkerPrivate* aWorkerPrivate, + bool aDispatchResult) override {} + + private: + CanvasDataShmemHolder* mShmemHolder; + }; + + mMutex.Lock(); + + if (mCanvasChild) { + if (mWorkerRef) { + if (!mWorkerRef->Private()->IsOnCurrentThread()) { + auto task = MakeRefPtr<DestroyRunnable>(mWorkerRef->Private(), this); + mMutex.Unlock(); + task->Dispatch(); + return; + } + } else if (!NS_IsMainThread()) { + mMutex.Unlock(); + NS_DispatchToMainThread(NS_NewRunnableFunction( + "CanvasDataShmemHolder::Destroy", [this]() { Destroy(); })); + return; + } + + mCanvasChild->ReturnDataSurfaceShmem(mShmem.forget()); + mCanvasChild = nullptr; + mWorkerRef = nullptr; + } + + mMutex.Unlock(); + delete this; + } + + void DestroyWorker() { + MutexAutoLock lock(mMutex); + mCanvasChild = nullptr; + mWorkerRef = nullptr; + } + + private: + Mutex mMutex; + RefPtr<ipc::SharedMemoryBasic> mShmem; + RefPtr<CanvasChild> mCanvasChild MOZ_GUARDED_BY(mMutex); + RefPtr<dom::ThreadSafeWorkerRef> mWorkerRef MOZ_GUARDED_BY(mMutex); +}; + +CanvasChild::CanvasChild(dom::ThreadSafeWorkerRef* aWorkerRef) + : mWorkerRef(aWorkerRef) {} + +CanvasChild::~CanvasChild() { MOZ_ASSERT(!mWorkerRef); } static void NotifyCanvasDeviceReset() { nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); @@ -207,14 +306,15 @@ ipc::IPCResult CanvasChild::RecvBlockCanvas() { } void CanvasChild::EnsureRecorder(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, - TextureType aTextureType) { + TextureType aTextureType, + TextureType aWebglTextureType) { NS_ASSERT_OWNINGTHREAD(CanvasChild); if (!mRecorder) { gfx::BackendType backendType = gfxPlatform::GetPlatform()->GetPreferredCanvasBackend(); - auto recorder = MakeRefPtr<CanvasDrawEventRecorder>(); - if (!recorder->Init(aTextureType, backendType, + auto recorder = MakeRefPtr<CanvasDrawEventRecorder>(mWorkerRef); + if (!recorder->Init(aTextureType, aWebglTextureType, backendType, MakeUnique<RecorderHelpers>(this))) { return; } @@ -242,6 +342,8 @@ void CanvasChild::Destroy() { if (CanSend()) { Send__delete__(this); } + + mWorkerRef = nullptr; } bool CanvasChild::EnsureBeginTransaction() { @@ -397,6 +499,10 @@ already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface( return nullptr; } + gfx::IntSize ssSize = aSurface->GetSize(); + gfx::SurfaceFormat ssFormat = aSurface->GetFormat(); + auto stride = ImageDataSerializer::ComputeRGBStride(ssFormat, ssSize.width); + // Shmem is only valid if the surface is the latest snapshot (not detached). if (!aDetached) { // If there is a shmem associated with this snapshot id, then we want to try @@ -411,20 +517,22 @@ already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface( if (NS_WARN_IF(!mRecorder->WaitForCheckpoint(checkpoint))) { return nullptr; } - gfx::IntSize size = aSurface->GetSize(); - gfx::SurfaceFormat format = aSurface->GetFormat(); - auto stride = ImageDataSerializer::ComputeRGBStride(format, size.width); + auto* closure = + new CanvasDataShmemHolder(it->second.mSnapshotShmem, this); + if (NS_WARN_IF(!closure->Init(mWorkerRef))) { + delete closure; + return nullptr; + } RefPtr<gfx::DataSourceSurface> dataSurface = - gfx::Factory::CreateWrappingDataSourceSurface(shmemPtr, stride, size, - format); + gfx::Factory::CreateWrappingDataSourceSurface( + shmemPtr, stride, ssSize, ssFormat, ReleaseDataShmemHolder, + closure); return dataSurface.forget(); } } RecordEvent(RecordedPrepareDataForSurface(aSurface)); - gfx::IntSize ssSize = aSurface->GetSize(); - gfx::SurfaceFormat ssFormat = aSurface->GetFormat(); if (!EnsureDataSurfaceShmem(ssSize, ssFormat)) { return nullptr; } @@ -435,15 +543,15 @@ already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface( return nullptr; } + auto* closure = new CanvasDataShmemHolder(mDataSurfaceShmem, this); + if (NS_WARN_IF(!closure->Init(mWorkerRef))) { + delete closure; + return nullptr; + } + mDataSurfaceShmemAvailable = false; - struct DataShmemHolder { - RefPtr<ipc::SharedMemoryBasic> shmem; - RefPtr<CanvasChild> canvasChild; - }; auto* data = static_cast<uint8_t*>(mDataSurfaceShmem->memory()); - auto* closure = new DataShmemHolder{do_AddRef(mDataSurfaceShmem), this}; - auto stride = ImageDataSerializer::ComputeRGBStride(ssFormat, ssSize.width); RefPtr<gfx::DataSourceSurface> dataSurface = gfx::Factory::CreateWrappingDataSourceSurface( @@ -452,16 +560,8 @@ already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface( } /* static */ void CanvasChild::ReleaseDataShmemHolder(void* aClosure) { - if (!NS_IsMainThread()) { - NS_DispatchToMainThread(NS_NewRunnableFunction( - "CanvasChild::ReleaseDataShmemHolder", - [aClosure]() { ReleaseDataShmemHolder(aClosure); })); - return; - } - - auto* shmemHolder = static_cast<DataShmemHolder*>(aClosure); - shmemHolder->canvasChild->ReturnDataSurfaceShmem(shmemHolder->shmem.forget()); - delete shmemHolder; + auto* shmemHolder = static_cast<CanvasDataShmemHolder*>(aClosure); + shmemHolder->Destroy(); } already_AddRefed<gfx::SourceSurface> CanvasChild::WrapSurface( diff --git a/gfx/layers/ipc/CanvasChild.h b/gfx/layers/ipc/CanvasChild.h index c99fe50bfb..e22109f406 100644 --- a/gfx/layers/ipc/CanvasChild.h +++ b/gfx/layers/ipc/CanvasChild.h @@ -15,6 +15,10 @@ namespace mozilla { +namespace dom { +class ThreadSafeWorkerRef; +} + namespace gfx { class DrawTargetRecording; class SourceSurface; @@ -28,7 +32,7 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr { public: NS_INLINE_DECL_REFCOUNTING(CanvasChild) - CanvasChild(); + explicit CanvasChild(dom::ThreadSafeWorkerRef* aWorkerRef); /** * @returns true if remote canvas has been deactivated due to failure. @@ -58,7 +62,7 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr { * @params aTextureType the TextureType to create in the CanvasTranslator. */ void EnsureRecorder(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, - TextureType aTextureType); + TextureType aTextureType, TextureType aWebglTextureType); /** * Clean up IPDL actor. @@ -147,6 +151,9 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr { void CleanupTexture(int64_t aTextureId); + void ReturnDataSurfaceShmem( + already_AddRefed<ipc::SharedMemoryBasic> aDataSurfaceShmem); + protected: void ActorDestroy(ActorDestroyReason aWhy) final; @@ -157,14 +164,6 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr { bool EnsureDataSurfaceShmem(gfx::IntSize aSize, gfx::SurfaceFormat aFormat); - void ReturnDataSurfaceShmem( - already_AddRefed<ipc::SharedMemoryBasic> aDataSurfaceShmem); - - struct DataShmemHolder { - RefPtr<ipc::SharedMemoryBasic> shmem; - RefPtr<CanvasChild> canvasChild; - }; - static void ReleaseDataShmemHolder(void* aClosure); void DropFreeBuffersWhenDormant(); @@ -173,6 +172,7 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr { static bool mDeactivated; + RefPtr<dom::ThreadSafeWorkerRef> mWorkerRef; RefPtr<CanvasDrawEventRecorder> mRecorder; RefPtr<ipc::SharedMemoryBasic> mDataSurfaceShmem; diff --git a/gfx/layers/ipc/CanvasTranslator.cpp b/gfx/layers/ipc/CanvasTranslator.cpp index 08150d6952..4a184f48d8 100644 --- a/gfx/layers/ipc/CanvasTranslator.cpp +++ b/gfx/layers/ipc/CanvasTranslator.cpp @@ -13,6 +13,7 @@ #include "mozilla/gfx/DrawTargetWebgl.h" #include "mozilla/gfx/gfxVars.h" #include "mozilla/gfx/GPUParent.h" +#include "mozilla/gfx/GPUProcessManager.h" #include "mozilla/gfx/Logging.h" #include "mozilla/ipc/Endpoint.h" #include "mozilla/layers/BufferTexture.h" @@ -131,15 +132,17 @@ bool CanvasTranslator::EnsureSharedContextWebgl() { } mozilla::ipc::IPCResult CanvasTranslator::RecvInitTranslator( - TextureType aTextureType, gfx::BackendType aBackendType, - Handle&& aReadHandle, nsTArray<Handle>&& aBufferHandles, - uint64_t aBufferSize, CrossProcessSemaphoreHandle&& aReaderSem, + TextureType aTextureType, TextureType aWebglTextureType, + gfx::BackendType aBackendType, Handle&& aReadHandle, + nsTArray<Handle>&& aBufferHandles, uint64_t aBufferSize, + CrossProcessSemaphoreHandle&& aReaderSem, CrossProcessSemaphoreHandle&& aWriterSem) { if (mHeaderShmem) { return IPC_FAIL(this, "RecvInitTranslator called twice."); } mTextureType = aTextureType; + mWebglTextureType = aWebglTextureType; mBackendType = aBackendType; mOtherPid = OtherPid(); @@ -637,7 +640,11 @@ bool CanvasTranslator::HandleExtensionEvent(int32_t aType) { } } -void CanvasTranslator::BeginTransaction() { mIsInTransaction = true; } +void CanvasTranslator::BeginTransaction() { + PROFILER_MARKER_TEXT("CanvasTranslator", GRAPHICS, {}, + "CanvasTranslator::BeginTransaction"_ns); + mIsInTransaction = true; +} void CanvasTranslator::Flush() { #if defined(XP_WIN) @@ -728,9 +735,15 @@ bool CanvasTranslator::CheckForFreshCanvasDevice(int aLineNumber) { NotifyDeviceChanged(); } - RefPtr<Runnable> runnable = NS_NewRunnableFunction( - "CanvasTranslator NotifyDeviceReset", - []() { gfx::GPUParent::GetSingleton()->NotifyDeviceReset(); }); + RefPtr<Runnable> runnable = + NS_NewRunnableFunction("CanvasTranslator NotifyDeviceReset", []() { + if (XRE_IsGPUProcess()) { + gfx::GPUParent::GetSingleton()->NotifyDeviceReset(); + } else { + gfx::GPUProcessManager::Get()->OnInProcessDeviceReset( + /* aTrackThreshold */ false); + } + }); // It is safe to wait here because only the Compositor thread waits on us and // the main thread doesn't wait on the compositor thread in the GPU process. @@ -1025,6 +1038,8 @@ bool CanvasTranslator::UnlockTexture(int64_t aTextureId) { } bool CanvasTranslator::PresentTexture(int64_t aTextureId, RemoteTextureId aId) { + AUTO_PROFILER_MARKER_TEXT("CanvasTranslator", GRAPHICS, {}, + "CanvasTranslator::PresentTexture"_ns); auto result = mTextureInfo.find(aTextureId); if (result == mTextureInfo.end()) { return false; @@ -1033,7 +1048,8 @@ bool CanvasTranslator::PresentTexture(int64_t aTextureId, RemoteTextureId aId) { RemoteTextureOwnerId ownerId = info.mRemoteTextureOwnerId; if (gfx::DrawTargetWebgl* webgl = info.GetDrawTargetWebgl()) { EnsureRemoteTextureOwner(ownerId); - if (webgl->CopyToSwapChain(aId, ownerId, mRemoteTextureOwner)) { + if (webgl->CopyToSwapChain(mWebglTextureType, aId, ownerId, + mRemoteTextureOwner)) { return true; } if (mSharedContext && mSharedContext->IsContextLost()) { diff --git a/gfx/layers/ipc/CanvasTranslator.h b/gfx/layers/ipc/CanvasTranslator.h index cf87b7ab53..5258e0c529 100644 --- a/gfx/layers/ipc/CanvasTranslator.h +++ b/gfx/layers/ipc/CanvasTranslator.h @@ -69,6 +69,7 @@ class CanvasTranslator final : public gfx::InlineTranslator, * CanvasEventRingBuffer. * * @param aTextureType the TextureType the translator will create + * @param aWebglTextureType the TextureType of any WebGL buffers * @param aBackendType the BackendType for texture data * @param aHeaderHandle handle for the control header * @param aBufferHandles handles for the initial buffers for translation @@ -77,6 +78,7 @@ class CanvasTranslator final : public gfx::InlineTranslator, * @param aWriterSem writing blocked semaphore for the CanvasEventRingBuffer */ ipc::IPCResult RecvInitTranslator(TextureType aTextureType, + TextureType aWebglTextureType, gfx::BackendType aBackendType, Handle&& aReadHandle, nsTArray<Handle>&& aBufferHandles, @@ -358,6 +360,7 @@ class CanvasTranslator final : public gfx::InlineTranslator, UniquePtr<CrossProcessSemaphore> mWriterSemaphore; UniquePtr<CrossProcessSemaphore> mReaderSemaphore; TextureType mTextureType = TextureType::Unknown; + TextureType mWebglTextureType = TextureType::Unknown; UniquePtr<TextureData> mReferenceTextureData; dom::ContentParentId mContentId; uint32_t mManagerId; diff --git a/gfx/layers/ipc/CompositorManagerChild.cpp b/gfx/layers/ipc/CompositorManagerChild.cpp index 0e553745d3..8d89339373 100644 --- a/gfx/layers/ipc/CompositorManagerChild.cpp +++ b/gfx/layers/ipc/CompositorManagerChild.cpp @@ -10,6 +10,7 @@ #include "mozilla/layers/CompositorBridgeChild.h" #include "mozilla/layers/CompositorManagerParent.h" #include "mozilla/layers/CompositorThread.h" +#include "mozilla/gfx/CanvasShutdownManager.h" #include "mozilla/gfx/gfxVars.h" #include "mozilla/gfx/GPUProcessManager.h" #include "mozilla/dom/ContentChild.h" // for ContentChild @@ -67,7 +68,15 @@ bool CompositorManagerChild::Init(Endpoint<PCompositorManagerChild>&& aEndpoint, sInstance = new CompositorManagerChild(std::move(aEndpoint), aProcessToken, aNamespace); sOtherPid = sInstance->OtherPid(); - return sInstance->CanSend(); + if (!sInstance->CanSend()) { + return false; + } + + // If there are any canvases waiting on the recreation of the GPUProcess or + // CompositorManagerChild, then we need to notify them so that they can + // restore their contexts. + gfx::CanvasShutdownManager::OnCompositorManagerRestored(); + return true; } /* static */ diff --git a/gfx/layers/ipc/LayersMessageUtils.h b/gfx/layers/ipc/LayersMessageUtils.h index d869d4ed83..a4e9557ac3 100644 --- a/gfx/layers/ipc/LayersMessageUtils.h +++ b/gfx/layers/ipc/LayersMessageUtils.h @@ -520,7 +520,7 @@ template <> struct ParamTraits<mozilla::ScrollUpdateType> : public ContiguousEnumSerializerInclusive< mozilla::ScrollUpdateType, mozilla::ScrollUpdateType::Absolute, - mozilla::ScrollUpdateType::MergeableAbsolute> {}; + mozilla::ScrollUpdateType::PureRelative> {}; template <> struct ParamTraits<mozilla::ScrollMode> diff --git a/gfx/layers/ipc/PCanvas.ipdl b/gfx/layers/ipc/PCanvas.ipdl index 5187e61d23..59896b72cf 100644 --- a/gfx/layers/ipc/PCanvas.ipdl +++ b/gfx/layers/ipc/PCanvas.ipdl @@ -32,9 +32,9 @@ parent: * each aBufferHandles' memory and the default size. aReaderSem and aWriterSem * are handles for the semaphores to handle waiting on either side. */ - async InitTranslator(TextureType aTextureType, BackendType aBackendType, - Handle aHeaderHandle, Handle[] aBufferHandles, - uint64_t aBufferSize, + async InitTranslator(TextureType aTextureType, TextureType aWebglTextureType, + BackendType aBackendType, Handle aHeaderHandle, + Handle[] aBufferHandles, uint64_t aBufferSize, CrossProcessSemaphoreHandle aReaderSem, CrossProcessSemaphoreHandle aWriterSem); diff --git a/gfx/layers/ipc/VideoBridgeParent.cpp b/gfx/layers/ipc/VideoBridgeParent.cpp index 6413c27bc1..50f0549e50 100644 --- a/gfx/layers/ipc/VideoBridgeParent.cpp +++ b/gfx/layers/ipc/VideoBridgeParent.cpp @@ -17,9 +17,8 @@ namespace mozilla::layers { using namespace mozilla::ipc; using namespace mozilla::gfx; -using VideoBridgeTable = - EnumeratedArray<VideoBridgeSource, VideoBridgeSource::_Count, - VideoBridgeParent*>; +using VideoBridgeTable = EnumeratedArray<VideoBridgeSource, VideoBridgeParent*, + size_t(VideoBridgeSource::_Count)>; static StaticDataMutex<VideoBridgeTable> sVideoBridgeFromProcess( "VideoBridges"); diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index 1bf2e83804..384611b68b 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -260,7 +260,7 @@ if CONFIG["MOZ_WAYLAND"]: "SurfacePoolWayland.cpp", ] -if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa": +if CONFIG["MOZ_WIDGET_TOOLKIT"] in ("cocoa", "uikit"): EXPORTS.mozilla.layers += [ "NativeLayerCA.h", "SurfacePoolCA.h", @@ -458,7 +458,7 @@ DEFINES["GOOGLE_PROTOBUF_NO_RTTI"] = True DEFINES["GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER"] = True DEFINES["MOZ_APP_VERSION"] = CONFIG["MOZ_APP_VERSION"] -if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa": +if CONFIG["MOZ_WIDGET_TOOLKIT"] in ("cocoa", "uikit"): SOURCES += [ "opengl/MacIOSurfaceTextureClientOGL.cpp", "opengl/MacIOSurfaceTextureHostOGL.cpp", diff --git a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp index ee61045599..112ed7711c 100644 --- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp +++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp @@ -10,7 +10,6 @@ #include "mozilla/webrender/RenderMacIOSurfaceTextureHost.h" #include "mozilla/webrender/RenderThread.h" #include "mozilla/webrender/WebRenderAPI.h" -#include "GLContextCGL.h" namespace mozilla { namespace layers { diff --git a/gfx/layers/wr/AsyncImagePipelineManager.cpp b/gfx/layers/wr/AsyncImagePipelineManager.cpp index 464b8fb69f..8a49ffef69 100644 --- a/gfx/layers/wr/AsyncImagePipelineManager.cpp +++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp @@ -229,8 +229,7 @@ Maybe<TextureHost::ResourceUpdateOp> AsyncImagePipelineManager::UpdateImageKeys( auto* wrapper = aTexture ? aTexture->AsRemoteTextureHostWrapper() : nullptr; if (wrapper && !aPipeline->mImageHost->GetAsyncRef()) { std::function<void(const RemoteTextureInfo&)> function; - RemoteTextureMap::Get()->GetRemoteTexture( - wrapper, std::move(function), /* aWaitForRemoteTextureOwner */ false); + RemoteTextureMap::Get()->GetRemoteTexture(wrapper, std::move(function)); } if (!aTexture || aTexture->NumSubTextures() == 0) { diff --git a/gfx/layers/wr/WebRenderBridgeParent.cpp b/gfx/layers/wr/WebRenderBridgeParent.cpp index 789476cb6b..83139b6af6 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.cpp +++ b/gfx/layers/wr/WebRenderBridgeParent.cpp @@ -141,7 +141,7 @@ void gfx_wr_set_crash_annotation(mozilla::wr::CrashAnnotation aAnnotation, return; } - CrashReporter::AnnotateCrashReport(annotation, nsDependentCString(aValue)); + CrashReporter::RecordAnnotationCString(annotation, aValue); } void gfx_wr_clear_crash_annotation(mozilla::wr::CrashAnnotation aAnnotation) { @@ -150,7 +150,7 @@ void gfx_wr_clear_crash_annotation(mozilla::wr::CrashAnnotation aAnnotation) { return; } - CrashReporter::RemoveCrashReportAnnotation(annotation); + CrashReporter::UnrecordAnnotation(annotation); } } @@ -1188,7 +1188,8 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetDisplayList( IsRootWebRenderBridgeParent()); if (!IsRootWebRenderBridgeParent()) { - CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::URL, aTxnURL); + CrashReporter::RecordAnnotationNSCString(CrashReporter::Annotation::URL, + aTxnURL); } CompositorBridgeParent* cbp = GetRootCompositorBridgeParent(); @@ -1330,7 +1331,8 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEmptyTransaction( IsRootWebRenderBridgeParent()); if (!IsRootWebRenderBridgeParent()) { - CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::URL, aTxnURL); + CrashReporter::RecordAnnotationNSCString(CrashReporter::Annotation::URL, + aTxnURL); } AUTO_PROFILER_TRACING_MARKER("Paint", "EmptyTransaction", GRAPHICS); diff --git a/gfx/layers/wr/WebRenderImageHost.cpp b/gfx/layers/wr/WebRenderImageHost.cpp index e3bbd5d50f..5016bc30f8 100644 --- a/gfx/layers/wr/WebRenderImageHost.cpp +++ b/gfx/layers/wr/WebRenderImageHost.cpp @@ -198,8 +198,11 @@ void WebRenderImageHost::UseRemoteTexture() { while (!mPendingRemoteTextureWrappers.empty()) { auto* wrapper = mPendingRemoteTextureWrappers.front()->AsRemoteTextureHostWrapper(); - mWaitingReadyCallback = RemoteTextureMap::Get()->GetRemoteTexture( - wrapper, readyCallback, mWaitForRemoteTextureOwner); + if (mWaitForRemoteTextureOwner) { + RemoteTextureMap::Get()->WaitForRemoteTextureOwner(wrapper); + } + mWaitingReadyCallback = + RemoteTextureMap::Get()->GetRemoteTexture(wrapper, readyCallback); MOZ_ASSERT_IF(mWaitingReadyCallback, !wrapper->IsReadyForRendering()); if (!wrapper->IsReadyForRendering()) { break; @@ -213,9 +216,9 @@ void WebRenderImageHost::UseRemoteTexture() { mPendingRemoteTextureWrappers.pop_front(); MOZ_ASSERT(mPendingRemoteTextureWrappers.empty()); - std::function<void(const RemoteTextureInfo&)> function; - RemoteTextureMap::Get()->GetRemoteTexture(wrapper, std::move(function), - mWaitForRemoteTextureOwner); + if (mWaitForRemoteTextureOwner) { + RemoteTextureMap::Get()->WaitForRemoteTextureOwner(wrapper); + } mWaitForRemoteTextureOwner = false; } diff --git a/gfx/layers/wr/WebRenderScrollData.cpp b/gfx/layers/wr/WebRenderScrollData.cpp index 538df8bdef..905b7e1de0 100644 --- a/gfx/layers/wr/WebRenderScrollData.cpp +++ b/gfx/layers/wr/WebRenderScrollData.cpp @@ -370,6 +370,22 @@ void WebRenderScrollData::ApplyUpdates(ScrollUpdatesMap&& aUpdates, mPaintSequenceNumber = aPaintSequenceNumber; } +void WebRenderScrollData::PrependUpdates( + const WebRenderScrollData& aPreviousData) { + for (auto previousMetadata : aPreviousData.mScrollMetadatas) { + const nsTArray<ScrollPositionUpdate>& previousUpdates = + previousMetadata.GetScrollUpdates(); + if (previousUpdates.IsEmpty()) { + continue; + } + + if (Maybe<size_t> index = + HasMetadataFor(previousMetadata.GetMetrics().GetScrollId())) { + mScrollMetadatas[*index].PrependUpdates(previousUpdates); + } + } +} + void WebRenderScrollData::DumpSubtree(std::ostream& aOut, size_t aIndex, const std::string& aIndent) const { aOut << aIndent; diff --git a/gfx/layers/wr/WebRenderScrollData.h b/gfx/layers/wr/WebRenderScrollData.h index c575d4ca21..fd82ac93fc 100644 --- a/gfx/layers/wr/WebRenderScrollData.h +++ b/gfx/layers/wr/WebRenderScrollData.h @@ -276,6 +276,13 @@ class WebRenderScrollData { void ApplyUpdates(ScrollUpdatesMap&& aUpdates, uint32_t aPaintSequenceNumber); + // Prepend the scroll position updates in the previous data to this data so + // that we can handle all scroll position updates in the proper order. + void PrependUpdates(const WebRenderScrollData& aPreviousData); + + void SetWasUpdateSkipped() { mWasUpdateSkipped = true; } + bool GetWasUpdateSkipped() const { return mWasUpdateSkipped; } + friend struct IPC::ParamTraits<WebRenderScrollData>; friend std::ostream& operator<<(std::ostream& aOut, @@ -328,6 +335,12 @@ class WebRenderScrollData { bool mIsFirstPaint; uint32_t mPaintSequenceNumber; + + // Wether this data was skipped to updated because the parent process hasn't + // yet gotten the referent LayersId for this data. + // + // Note this variable is not copied over IPC. + bool mWasUpdateSkipped = false; }; } // namespace layers diff --git a/gfx/ots/src/ots.h b/gfx/ots/src/ots.h index 434e068d48..7e3625c737 100644 --- a/gfx/ots/src/ots.h +++ b/gfx/ots/src/ots.h @@ -87,8 +87,7 @@ class Buffer { if (n_bytes > 1024 * 1024 * 1024) { return OTS_FAILURE(); } - if ((offset_ + n_bytes > length_) || - (offset_ > length_ - n_bytes)) { + if (length_ < n_bytes || offset_ > length_ - n_bytes) { return OTS_FAILURE(); } if (buf) { @@ -99,7 +98,7 @@ class Buffer { } inline bool ReadU8(uint8_t *value) { - if (offset_ + 1 > length_) { + if (length_ < 1 || offset_ > length_ - 1) { return OTS_FAILURE(); } *value = buffer_[offset_]; @@ -108,7 +107,7 @@ class Buffer { } bool ReadU16(uint16_t *value) { - if (offset_ + 2 > length_) { + if (length_ < 2 || offset_ > length_ - 2) { return OTS_FAILURE(); } std::memcpy(value, buffer_ + offset_, sizeof(uint16_t)); @@ -122,7 +121,7 @@ class Buffer { } bool ReadU24(uint32_t *value) { - if (offset_ + 3 > length_) { + if (length_ < 3 || offset_ > length_ - 3) { return OTS_FAILURE(); } *value = static_cast<uint32_t>(buffer_[offset_]) << 16 | @@ -133,7 +132,7 @@ class Buffer { } bool ReadU32(uint32_t *value) { - if (offset_ + 4 > length_) { + if (length_ < 4 || offset_ > length_ - 4) { return OTS_FAILURE(); } std::memcpy(value, buffer_ + offset_, sizeof(uint32_t)); @@ -147,7 +146,7 @@ class Buffer { } bool ReadR64(uint64_t *value) { - if (offset_ + 8 > length_) { + if (length_ < 8 || offset_ > length_ - 8) { return OTS_FAILURE(); } std::memcpy(value, buffer_ + offset_, sizeof(uint64_t)); diff --git a/gfx/ots/src/stat.cc b/gfx/ots/src/stat.cc index f6f65fdf60..0eeaffb1c6 100644 --- a/gfx/ots/src/stat.cc +++ b/gfx/ots/src/stat.cc @@ -48,10 +48,6 @@ bool OpenTypeSTAT::Parse(const uint8_t* data, size_t length) { this->minorVersion = 2; } - if (this->designAxisSize < sizeof(AxisRecord)) { - return Drop("Invalid designAxisSize"); - } - size_t headerEnd = table.offset(); if (this->designAxisCount == 0) { @@ -60,9 +56,13 @@ bool OpenTypeSTAT::Parse(const uint8_t* data, size_t length) { this->designAxesOffset = 0; } } else { + if (this->designAxisSize < sizeof(AxisRecord)) { + return Drop("Invalid designAxisSize"); + } if (this->designAxesOffset < headerEnd || - size_t(this->designAxesOffset) + - size_t(this->designAxisCount) * size_t(this->designAxisSize) > length) { + size_t(this->designAxesOffset) > length || + size_t(this->designAxisCount) * size_t(this->designAxisSize) > + length - size_t(this->designAxesOffset)) { return Drop("Invalid designAxesOffset"); } } @@ -95,8 +95,9 @@ bool OpenTypeSTAT::Parse(const uint8_t* data, size_t length) { } } else { if (this->offsetToAxisValueOffsets < headerEnd || - size_t(this->offsetToAxisValueOffsets) + - size_t(this->axisValueCount) * sizeof(uint16_t) > length) { + size_t(this->offsetToAxisValueOffsets) > length || + size_t(this->axisValueCount) * sizeof(uint16_t) > + length - size_t(this->offsetToAxisValueOffsets)) { return Drop("Invalid offsetToAxisValueOffsets"); } } @@ -107,7 +108,9 @@ bool OpenTypeSTAT::Parse(const uint8_t* data, size_t length) { if (!table.ReadU16(&axisValueOffset)) { return Drop("Failed to read axis value offset"); } - if (this->offsetToAxisValueOffsets + axisValueOffset > length) { + // We already checked that offsetToAxisValueOffsets doesn't exceed length, + // so this subtraction will not underflow. + if (axisValueOffset > length - this->offsetToAxisValueOffsets) { return Drop("Invalid axis value offset"); } table.set_offset(this->offsetToAxisValueOffsets + axisValueOffset); diff --git a/gfx/qcms/Cargo.toml b/gfx/qcms/Cargo.toml index 094d1183d1..c6e0e76722 100644 --- a/gfx/qcms/Cargo.toml +++ b/gfx/qcms/Cargo.toml @@ -20,3 +20,6 @@ cmyk = [] [dependencies] libc = {version = "0.2", optional = true } + +[build-dependencies] +version_check = "0.9" diff --git a/gfx/qcms/build.rs b/gfx/qcms/build.rs new file mode 100644 index 0000000000..6810a8828e --- /dev/null +++ b/gfx/qcms/build.rs @@ -0,0 +1,7 @@ +extern crate version_check as rustc; + +fn main() { + if rustc::is_min_version("1.78.0").unwrap_or(false) { + println!("cargo:rustc-cfg=stdsimd_split"); + } +} diff --git a/gfx/qcms/src/iccread.rs b/gfx/qcms/src/iccread.rs index ad45a58d35..ba2b5a3257 100644 --- a/gfx/qcms/src/iccread.rs +++ b/gfx/qcms/src/iccread.rs @@ -61,9 +61,7 @@ pub struct Profile { pub(crate) mAB: Option<Box<lutmABType>>, pub(crate) mBA: Option<Box<lutmABType>>, pub(crate) chromaticAdaption: Option<Matrix>, - pub(crate) output_table_r: Option<Arc<PrecacheOuput>>, - pub(crate) output_table_g: Option<Arc<PrecacheOuput>>, - pub(crate) output_table_b: Option<Arc<PrecacheOuput>>, + pub(crate) precache_output: Option<Arc<PrecacheOuput>>, is_srgb: bool, } diff --git a/gfx/qcms/src/lib.rs b/gfx/qcms/src/lib.rs index c311964ee3..fc496816a8 100644 --- a/gfx/qcms/src/lib.rs +++ b/gfx/qcms/src/lib.rs @@ -7,9 +7,11 @@ #![allow(non_upper_case_globals)] // These are needed for the neon SIMD code and can be removed once the MSRV supports the // instrinsics we use -#![cfg_attr(feature = "neon", feature(stdsimd))] +#![cfg_attr(all(stdsimd_split, target_arch = "arm", feature = "neon"), feature(stdarch_arm_neon_intrinsics))] +#![cfg_attr(all(stdsimd_split, target_arch = "arm", feature = "neon"), feature(stdarch_arm_feature_detection))] +#![cfg_attr(all(not(stdsimd_split), target_arch = "arm", feature = "neon"), feature(stdsimd))] #![cfg_attr( - feature = "neon", + all(target_arch = "arm", feature = "neon"), feature(arm_target_feature, raw_ref_op) )] diff --git a/gfx/qcms/src/transform.rs b/gfx/qcms/src/transform.rs index b0c8b60b18..54f89864eb 100644 --- a/gfx/qcms/src/transform.rs +++ b/gfx/qcms/src/transform.rs @@ -73,13 +73,17 @@ pub struct PrecacheOuput { * improve startup performance and reduce memory usage. ColorSync on * 10.5 uses 4097 which is perhaps because they use a fixed point * representation where 1. is represented by 0x1000. */ - pub data: [u8; PRECACHE_OUTPUT_SIZE], + pub lut_r: [u8; PRECACHE_OUTPUT_SIZE], + pub lut_g: [u8; PRECACHE_OUTPUT_SIZE], + pub lut_b: [u8; PRECACHE_OUTPUT_SIZE], } impl Default for PrecacheOuput { fn default() -> PrecacheOuput { PrecacheOuput { - data: [0; PRECACHE_OUTPUT_SIZE], + lut_r: [0; PRECACHE_OUTPUT_SIZE], + lut_g: [0; PRECACHE_OUTPUT_SIZE], + lut_b: [0; PRECACHE_OUTPUT_SIZE], } } } @@ -113,9 +117,7 @@ pub struct qcms_transform { pub output_gamma_lut_g_length: usize, pub output_gamma_lut_b_length: usize, pub output_gamma_lut_gray_length: usize, - pub output_table_r: Option<Arc<PrecacheOuput>>, - pub output_table_g: Option<Arc<PrecacheOuput>>, - pub output_table_b: Option<Arc<PrecacheOuput>>, + pub precache_output: Option<Arc<PrecacheOuput>>, pub transform_fn: transform_fn_t, } @@ -414,15 +416,15 @@ unsafe extern "C" fn qcms_transform_data_gray_template_lut<I: GrayFormat, F: For let out_device_r: f32 = lut_interp_linear( linear as f64, - &(*transform).output_gamma_lut_r.as_ref().unwrap(), + &transform.output_gamma_lut_r.as_ref().unwrap(), ); let out_device_g: f32 = lut_interp_linear( linear as f64, - &(*transform).output_gamma_lut_g.as_ref().unwrap(), + &transform.output_gamma_lut_g.as_ref().unwrap(), ); let out_device_b: f32 = lut_interp_linear( linear as f64, - &(*transform).output_gamma_lut_b.as_ref().unwrap(), + &transform.output_gamma_lut_b.as_ref().unwrap(), ); *dest.add(F::kRIndex) = clamp_u8(out_device_r * 255f32); *dest.add(F::kGIndex) = clamp_u8(out_device_g * 255f32); @@ -475,17 +477,18 @@ unsafe fn qcms_transform_data_graya_bgra_out_lut( qcms_transform_data_gray_template_lut::<GrayAlpha, BGRA>(transform, src, dest, length); } unsafe fn qcms_transform_data_gray_template_precache<I: GrayFormat, F: Format>( - transform: *const qcms_transform, + transform: &qcms_transform, mut src: *const u8, mut dest: *mut u8, length: usize, ) { let components: u32 = if F::kAIndex == 0xff { 3 } else { 4 } as u32; - let output_table_r = ((*transform).output_table_r).as_deref().unwrap(); - let output_table_g = ((*transform).output_table_g).as_deref().unwrap(); - let output_table_b = ((*transform).output_table_b).as_deref().unwrap(); + let precache_output = transform.precache_output.as_deref().unwrap(); + let output_r = &precache_output.lut_r; + let output_g = &precache_output.lut_g; + let output_b = &precache_output.lut_b; - let input_gamma_table_gray = (*transform) + let input_gamma_table_gray = transform .input_gamma_table_gray .as_ref() .unwrap() @@ -506,9 +509,9 @@ unsafe fn qcms_transform_data_gray_template_precache<I: GrayFormat, F: Format>( let linear: f32 = *input_gamma_table_gray.offset(device as isize); /* we could round here... */ let gray: u16 = (linear * PRECACHE_OUTPUT_MAX as f32) as u16; - *dest.add(F::kRIndex) = (output_table_r).data[gray as usize]; - *dest.add(F::kGIndex) = (output_table_g).data[gray as usize]; - *dest.add(F::kBIndex) = (output_table_b).data[gray as usize]; + *dest.add(F::kRIndex) = output_r[gray as usize]; + *dest.add(F::kGIndex) = output_g[gray as usize]; + *dest.add(F::kBIndex) = output_b[gray as usize]; if F::kAIndex != 0xff { *dest.add(F::kAIndex) = alpha } @@ -563,12 +566,12 @@ unsafe fn qcms_transform_data_template_lut_precache<F: Format>( length: usize, ) { let components: u32 = if F::kAIndex == 0xff { 3 } else { 4 } as u32; - let output_table_r = ((*transform).output_table_r).as_deref().unwrap(); - let output_table_g = ((*transform).output_table_g).as_deref().unwrap(); - let output_table_b = ((*transform).output_table_b).as_deref().unwrap(); - let input_gamma_table_r = (*transform).input_gamma_table_r.as_ref().unwrap().as_ptr(); - let input_gamma_table_g = (*transform).input_gamma_table_g.as_ref().unwrap().as_ptr(); - let input_gamma_table_b = (*transform).input_gamma_table_b.as_ref().unwrap().as_ptr(); + let output_table_r = &transform.precache_output.as_deref().unwrap().lut_r; + let output_table_g = &transform.precache_output.as_deref().unwrap().lut_g; + let output_table_b = &transform.precache_output.as_deref().unwrap().lut_b; + let input_gamma_table_r = transform.input_gamma_table_r.as_ref().unwrap().as_ptr(); + let input_gamma_table_g = transform.input_gamma_table_g.as_ref().unwrap().as_ptr(); + let input_gamma_table_b = transform.input_gamma_table_b.as_ref().unwrap().as_ptr(); let mat = &transform.matrix; let mut i: u32 = 0; @@ -596,9 +599,9 @@ unsafe fn qcms_transform_data_template_lut_precache<F: Format>( let r: u16 = (out_linear_r * PRECACHE_OUTPUT_MAX as f32) as u16; let g: u16 = (out_linear_g * PRECACHE_OUTPUT_MAX as f32) as u16; let b: u16 = (out_linear_b * PRECACHE_OUTPUT_MAX as f32) as u16; - *dest.add(F::kRIndex) = (output_table_r).data[r as usize]; - *dest.add(F::kGIndex) = (output_table_g).data[g as usize]; - *dest.add(F::kBIndex) = (output_table_b).data[b as usize]; + *dest.add(F::kRIndex) = output_table_r[r as usize]; + *dest.add(F::kGIndex) = output_table_g[g as usize]; + *dest.add(F::kBIndex) = output_table_b[b as usize]; if F::kAIndex != 0xff { *dest.add(F::kAIndex) = alpha } @@ -695,7 +698,7 @@ fn int_div_ceil(value: i32, div: i32) -> i32 { } // Using lcms' tetra interpolation algorithm. unsafe extern "C" fn qcms_transform_data_tetra_clut_template<F: Format>( - transform: *const qcms_transform, + transform: &qcms_transform, mut src: *const u8, mut dest: *mut u8, length: usize, @@ -703,9 +706,9 @@ unsafe extern "C" fn qcms_transform_data_tetra_clut_template<F: Format>( let components: u32 = if F::kAIndex == 0xff { 3 } else { 4 } as u32; let xy_len: i32 = 1; - let x_len: i32 = (*transform).grid_size as i32; + let x_len: i32 = transform.grid_size as i32; let len: i32 = x_len * x_len; - let table = (*transform).clut.as_ref().unwrap().as_ptr(); + let table = transform.clut.as_ref().unwrap().as_ptr(); let r_table: *const f32 = table; let g_table: *const f32 = table.offset(1); let b_table: *const f32 = table.offset(2); @@ -735,15 +738,15 @@ unsafe extern "C" fn qcms_transform_data_tetra_clut_template<F: Format>( let linear_r: f32 = in_r as i32 as f32 / 255.0; let linear_g: f32 = in_g as i32 as f32 / 255.0; let linear_b: f32 = in_b as i32 as f32 / 255.0; - let x: i32 = in_r as i32 * ((*transform).grid_size as i32 - 1) / 255; - let y: i32 = in_g as i32 * ((*transform).grid_size as i32 - 1) / 255; - let z: i32 = in_b as i32 * ((*transform).grid_size as i32 - 1) / 255; - let x_n: i32 = int_div_ceil(in_r as i32 * ((*transform).grid_size as i32 - 1), 255); - let y_n: i32 = int_div_ceil(in_g as i32 * ((*transform).grid_size as i32 - 1), 255); - let z_n: i32 = int_div_ceil(in_b as i32 * ((*transform).grid_size as i32 - 1), 255); - let rx: f32 = linear_r * ((*transform).grid_size as i32 - 1) as f32 - x as f32; - let ry: f32 = linear_g * ((*transform).grid_size as i32 - 1) as f32 - y as f32; - let rz: f32 = linear_b * ((*transform).grid_size as i32 - 1) as f32 - z as f32; + let x: i32 = in_r as i32 * (transform.grid_size as i32 - 1) / 255; + let y: i32 = in_g as i32 * (transform.grid_size as i32 - 1) / 255; + let z: i32 = in_b as i32 * (transform.grid_size as i32 - 1) / 255; + let x_n: i32 = int_div_ceil(in_r as i32 * (transform.grid_size as i32 - 1), 255); + let y_n: i32 = int_div_ceil(in_g as i32 * (transform.grid_size as i32 - 1), 255); + let z_n: i32 = int_div_ceil(in_b as i32 * (transform.grid_size as i32 - 1), 255); + let rx: f32 = linear_r * (transform.grid_size as i32 - 1) as f32 - x as f32; + let ry: f32 = linear_g * (transform.grid_size as i32 - 1) as f32 - y as f32; + let rz: f32 = linear_b * (transform.grid_size as i32 - 1) as f32 - z as f32; let CLU = |table: *const f32, x, y, z| { *table.offset(((x * len + y * x_len + z * xy_len) * 3) as isize) }; @@ -848,17 +851,17 @@ unsafe fn tetra( let linear_g: f32 = in_g as i32 as f32 / 255.0; let linear_b: f32 = in_b as i32 as f32 / 255.0; let xy_len: i32 = 1; - let x_len: i32 = (*transform).grid_size as i32; + let x_len: i32 = transform.grid_size as i32; let len: i32 = x_len * x_len; - let x: i32 = in_r as i32 * ((*transform).grid_size as i32 - 1) / 255; - let y: i32 = in_g as i32 * ((*transform).grid_size as i32 - 1) / 255; - let z: i32 = in_b as i32 * ((*transform).grid_size as i32 - 1) / 255; - let x_n: i32 = int_div_ceil(in_r as i32 * ((*transform).grid_size as i32 - 1), 255); - let y_n: i32 = int_div_ceil(in_g as i32 * ((*transform).grid_size as i32 - 1), 255); - let z_n: i32 = int_div_ceil(in_b as i32 * ((*transform).grid_size as i32 - 1), 255); - let rx: f32 = linear_r * ((*transform).grid_size as i32 - 1) as f32 - x as f32; - let ry: f32 = linear_g * ((*transform).grid_size as i32 - 1) as f32 - y as f32; - let rz: f32 = linear_b * ((*transform).grid_size as i32 - 1) as f32 - z as f32; + let x: i32 = in_r as i32 * (transform.grid_size as i32 - 1) / 255; + let y: i32 = in_g as i32 * (transform.grid_size as i32 - 1) / 255; + let z: i32 = in_b as i32 * (transform.grid_size as i32 - 1) / 255; + let x_n: i32 = int_div_ceil(in_r as i32 * (transform.grid_size as i32 - 1), 255); + let y_n: i32 = int_div_ceil(in_g as i32 * (transform.grid_size as i32 - 1), 255); + let z_n: i32 = int_div_ceil(in_b as i32 * (transform.grid_size as i32 - 1), 255); + let rx: f32 = linear_r * (transform.grid_size as i32 - 1) as f32 - x as f32; + let ry: f32 = linear_g * (transform.grid_size as i32 - 1) as f32 - y as f32; + let rz: f32 = linear_b * (transform.grid_size as i32 - 1) as f32 - z as f32; let CLU = |table: *const f32, x, y, z| { *table.offset(((x * len + y * x_len + z * xy_len) * 3) as isize) }; @@ -966,9 +969,9 @@ unsafe fn qcms_transform_data_tetra_clut_cmyk( mut dest: *mut u8, length: usize, ) { - let table = (*transform).clut.as_ref().unwrap().as_ptr(); + let table = transform.clut.as_ref().unwrap().as_ptr(); assert!( - (*transform).clut.as_ref().unwrap().len() + transform.clut.as_ref().unwrap().len() >= ((transform.grid_size as i32).pow(4) * 3) as usize ); for _ in 0..length { @@ -978,10 +981,10 @@ unsafe fn qcms_transform_data_tetra_clut_cmyk( let k: u8 = *src.add(3); src = src.offset(4); let linear_k: f32 = k as i32 as f32 / 255.0; - let grid_size = (*transform).grid_size as i32; - let w: i32 = k as i32 * ((*transform).grid_size as i32 - 1) / 255; - let w_n: i32 = int_div_ceil(k as i32 * ((*transform).grid_size as i32 - 1), 255); - let t: f32 = linear_k * ((*transform).grid_size as i32 - 1) as f32 - w as f32; + let grid_size = transform.grid_size as i32; + let w: i32 = k as i32 * (transform.grid_size as i32 - 1) / 255; + let w_n: i32 = int_div_ceil(k as i32 * (transform.grid_size as i32 - 1), 255); + let t: f32 = linear_k * (transform.grid_size as i32 - 1) as f32 - w as f32; let table1 = table.offset((w * grid_size * grid_size * grid_size * 3) as isize); let table2 = table.offset((w_n * grid_size * grid_size * grid_size * 3) as isize); @@ -1032,9 +1035,9 @@ unsafe fn qcms_transform_data_template_lut<F: Format>( let mat = &transform.matrix; let mut i: u32 = 0; - let input_gamma_table_r = (*transform).input_gamma_table_r.as_ref().unwrap().as_ptr(); - let input_gamma_table_g = (*transform).input_gamma_table_g.as_ref().unwrap().as_ptr(); - let input_gamma_table_b = (*transform).input_gamma_table_b.as_ref().unwrap().as_ptr(); + let input_gamma_table_r = transform.input_gamma_table_r.as_ref().unwrap().as_ptr(); + let input_gamma_table_g = transform.input_gamma_table_g.as_ref().unwrap().as_ptr(); + let input_gamma_table_b = transform.input_gamma_table_b.as_ref().unwrap().as_ptr(); while (i as usize) < length { let device_r: u8 = *src.add(F::kRIndex); let device_g: u8 = *src.add(F::kGIndex); @@ -1057,15 +1060,15 @@ unsafe fn qcms_transform_data_template_lut<F: Format>( let out_device_r: f32 = lut_interp_linear( out_linear_r as f64, - &(*transform).output_gamma_lut_r.as_ref().unwrap(), + &transform.output_gamma_lut_r.as_ref().unwrap(), ); let out_device_g: f32 = lut_interp_linear( out_linear_g as f64, - (*transform).output_gamma_lut_g.as_ref().unwrap(), + transform.output_gamma_lut_g.as_ref().unwrap(), ); let out_device_b: f32 = lut_interp_linear( out_linear_b as f64, - (*transform).output_gamma_lut_b.as_ref().unwrap(), + transform.output_gamma_lut_b.as_ref().unwrap(), ); *dest.add(F::kRIndex) = clamp_u8(out_device_r * 255f32); *dest.add(F::kGIndex) = clamp_u8(out_device_g * 255f32); @@ -1172,33 +1175,22 @@ pub extern "C" fn qcms_profile_precache_output_transform(profile: &mut Profile) if profile.redTRC.is_none() || profile.greenTRC.is_none() || profile.blueTRC.is_none() { return; } - if profile.output_table_r.is_none() { - let mut output_table_r = precache_create(); - if compute_precache( + if profile.precache_output.is_none() { + let mut precache = precache_create(); + compute_precache( profile.redTRC.as_deref().unwrap(), - &mut Arc::get_mut(&mut output_table_r).unwrap().data, - ) { - profile.output_table_r = Some(output_table_r); - } - } - if profile.output_table_g.is_none() { - let mut output_table_g = precache_create(); - if compute_precache( + &mut Arc::get_mut(&mut precache).unwrap().lut_r, + ); + compute_precache( profile.greenTRC.as_deref().unwrap(), - &mut Arc::get_mut(&mut output_table_g).unwrap().data, - ) { - profile.output_table_g = Some(output_table_g); - } - } - if profile.output_table_b.is_none() { - let mut output_table_b = precache_create(); - if compute_precache( + &mut Arc::get_mut(&mut precache).unwrap().lut_g, + ); + compute_precache( profile.blueTRC.as_deref().unwrap(), - &mut Arc::get_mut(&mut output_table_b).unwrap().data, - ) { - profile.output_table_b = Some(output_table_b); - } - }; + &mut Arc::get_mut(&mut precache).unwrap().lut_b, + ); + profile.precache_output = Some(precache); + } } /* Replace the current transformation with a LUT transformation using a given number of sample points */ fn transform_precacheLUT_float( @@ -1225,16 +1217,16 @@ fn transform_precacheLUT_float( } let lut = chain_transform(input, output, src, dest, lutSize as usize); if let Some(lut) = lut { - (*transform).clut = Some(lut); - (*transform).grid_size = samples as u16; + transform.clut = Some(lut); + transform.grid_size = samples as u16; if in_type == RGBA8 { - (*transform).transform_fn = Some(qcms_transform_data_tetra_clut_rgba) + transform.transform_fn = Some(qcms_transform_data_tetra_clut_rgba) } else if in_type == BGRA8 { - (*transform).transform_fn = Some(qcms_transform_data_tetra_clut_bgra) + transform.transform_fn = Some(qcms_transform_data_tetra_clut_bgra) } else if in_type == RGB8 { - (*transform).transform_fn = Some(qcms_transform_data_tetra_clut_rgb) + transform.transform_fn = Some(qcms_transform_data_tetra_clut_rgb) } - debug_assert!((*transform).transform_fn.is_some()); + debug_assert!(transform.transform_fn.is_some()); } else { return None; } @@ -1303,10 +1295,7 @@ pub fn transform_create( } let mut transform: Box<qcms_transform> = Box::new(Default::default()); let mut precache: bool = false; - if output.output_table_r.is_some() - && output.output_table_g.is_some() - && output.output_table_b.is_some() - { + if output.precache_output.is_some() { precache = true } // This precache assumes RGB_SIGNATURE (fails on GRAY_SIGNATURE, for instance) @@ -1330,9 +1319,7 @@ pub fn transform_create( return result; } if precache { - transform.output_table_r = Some(Arc::clone(output.output_table_r.as_ref().unwrap())); - transform.output_table_g = Some(Arc::clone(output.output_table_g.as_ref().unwrap())); - transform.output_table_b = Some(Arc::clone(output.output_table_b.as_ref().unwrap())); + transform.precache_output = Some(Arc::clone(output.precache_output.as_ref().unwrap())); } else { if output.redTRC.is_none() || output.greenTRC.is_none() || output.blueTRC.is_none() { return None; diff --git a/gfx/qcms/src/transform_avx.rs b/gfx/qcms/src/transform_avx.rs index 3a000e56ba..04ca752a83 100644 --- a/gfx/qcms/src/transform_avx.rs +++ b/gfx/qcms/src/transform_avx.rs @@ -24,33 +24,33 @@ unsafe extern "C" fn qcms_transform_data_template_lut_avx<F: Format>( mut dest: *mut u8, mut length: usize, ) { - let mat: *const [f32; 4] = (*transform).matrix.as_ptr(); + let mat: *const [f32; 4] = transform.matrix.as_ptr(); let mut input: Output = std::mem::zeroed(); /* share input and output locations to save having to keep the * locations in separate registers */ let output: *const u32 = &mut input as *mut Output as *mut u32; /* deref *transform now to avoid it in loop */ - let igtbl_r: *const f32 = (*transform).input_gamma_table_r.as_ref().unwrap().as_ptr(); - let igtbl_g: *const f32 = (*transform).input_gamma_table_g.as_ref().unwrap().as_ptr(); - let igtbl_b: *const f32 = (*transform).input_gamma_table_b.as_ref().unwrap().as_ptr(); + let igtbl_r: *const f32 = transform.input_gamma_table_r.as_ref().unwrap().as_ptr(); + let igtbl_g: *const f32 = transform.input_gamma_table_g.as_ref().unwrap().as_ptr(); + let igtbl_b: *const f32 = transform.input_gamma_table_b.as_ref().unwrap().as_ptr(); /* deref *transform now to avoid it in loop */ - let otdata_r: *const u8 = (*transform) - .output_table_r + let otdata_r: *const u8 = transform + .precache_output .as_deref() .unwrap() - .data + .lut_r .as_ptr(); let otdata_g: *const u8 = (*transform) - .output_table_g + .precache_output .as_deref() .unwrap() - .data + .lut_g .as_ptr(); let otdata_b: *const u8 = (*transform) - .output_table_b + .precache_output .as_deref() .unwrap() - .data + .lut_b .as_ptr(); /* input matrix values never change */ let mat0: __m256 = _mm256_broadcast_ps(&*((*mat.offset(0isize)).as_ptr() as *const __m128)); diff --git a/gfx/qcms/src/transform_neon.rs b/gfx/qcms/src/transform_neon.rs index b14b67107d..121b52ff52 100644 --- a/gfx/qcms/src/transform_neon.rs +++ b/gfx/qcms/src/transform_neon.rs @@ -25,23 +25,23 @@ unsafe fn qcms_transform_data_template_lut_neon<F: Format>( let igtbl_g: *const f32 = (*transform).input_gamma_table_g.as_ref().unwrap().as_ptr(); let igtbl_b: *const f32 = (*transform).input_gamma_table_b.as_ref().unwrap().as_ptr(); /* deref *transform now to avoid it in loop */ - let otdata_r: *const u8 = (*transform) - .output_table_r + let otdata_r: *const u8 = transform + .precache_output .as_deref() .unwrap() - .data + .lut_r .as_ptr(); let otdata_g: *const u8 = (*transform) - .output_table_g + .precache_output .as_deref() .unwrap() - .data + .lut_g .as_ptr(); let otdata_b: *const u8 = (*transform) - .output_table_b + .precache_output .as_deref() .unwrap() - .data + .lut_b .as_ptr(); /* input matrix values never change */ let mat0: float32x4_t = vld1q_f32((*mat.offset(0isize)).as_ptr()); diff --git a/gfx/qcms/src/transform_sse2.rs b/gfx/qcms/src/transform_sse2.rs index f6bccaadc3..865a01be1c 100644 --- a/gfx/qcms/src/transform_sse2.rs +++ b/gfx/qcms/src/transform_sse2.rs @@ -30,22 +30,22 @@ unsafe extern "C" fn qcms_transform_data_template_lut_sse2<F: Format>( let igtbl_b: *const f32 = (*transform).input_gamma_table_b.as_ref().unwrap().as_ptr(); /* deref *transform now to avoid it in loop */ let otdata_r: *const u8 = (*transform) - .output_table_r + .precache_output .as_deref() .unwrap() - .data + .lut_r .as_ptr(); let otdata_g: *const u8 = (*transform) - .output_table_g + .precache_output .as_deref() .unwrap() - .data + .lut_g .as_ptr(); let otdata_b: *const u8 = (*transform) - .output_table_b + .precache_output .as_deref() .unwrap() - .data + .lut_b .as_ptr(); /* input matrix values never change */ let mat0: __m128 = _mm_load_ps((*mat.offset(0isize)).as_ptr()); diff --git a/gfx/qcms/src/transform_util.rs b/gfx/qcms/src/transform_util.rs index 75fd2ca0e2..f341ae7946 100644 --- a/gfx/qcms/src/transform_util.rs +++ b/gfx/qcms/src/transform_util.rs @@ -471,7 +471,7 @@ pub fn compute_precache_linear(output: &mut [u8; PRECACHE_OUTPUT_SIZE]) { output[v] = (v / (PRECACHE_OUTPUT_SIZE / 256)) as u8; } } -pub(crate) fn compute_precache(trc: &curveType, output: &mut [u8; PRECACHE_OUTPUT_SIZE]) -> bool { +pub(crate) fn compute_precache(trc: &curveType, output: &mut [u8; PRECACHE_OUTPUT_SIZE]) { match trc { curveType::Parametric(params) => { let mut gamma_table_uint: [u16; 256] = [0; 256]; @@ -512,7 +512,6 @@ pub(crate) fn compute_precache(trc: &curveType, output: &mut [u8; PRECACHE_OUTPU } } } - true } fn build_linear_table(length: usize) -> Vec<u16> { let mut output = Vec::with_capacity(length); diff --git a/gfx/skia/skia/src/ports/SkTypeface_mac_ct.cpp b/gfx/skia/skia/src/ports/SkTypeface_mac_ct.cpp index 362245ec45..ebeda314d8 100644 --- a/gfx/skia/skia/src/ports/SkTypeface_mac_ct.cpp +++ b/gfx/skia/skia/src/ports/SkTypeface_mac_ct.cpp @@ -64,7 +64,7 @@ #include <string.h> #include <memory> -#ifdef MOZ_SKIA +#if defined(MOZ_SKIA) && defined(XP_MACOSX) #include "nsCocoaFeatures.h" #endif @@ -290,7 +290,7 @@ SkUniqueCFRef<CTFontRef> SkCTFontCreateExactCopy(CTFontRef baseFont, CGFloat tex auto ctFont = SkUniqueCFRef<CTFontRef>( CTFontCreateWithGraphicsFont(baseCGFont.get(), textSize, nullptr, desc.get())); if (variations) { -#ifdef MOZ_SKIA +#if defined(MOZ_SKIA) && defined(XP_MACOSX) if (nsCocoaFeatures::OnVenturaOrLater()) { // On recent macOS versions, CTFontCreateWithGraphicsFont fails to apply // the variations from the descriptor, so to get the correct values we use diff --git a/gfx/src/DriverCrashGuard.cpp b/gfx/src/DriverCrashGuard.cpp index 9b68c07e55..c54a07b9ec 100644 --- a/gfx/src/DriverCrashGuard.cpp +++ b/gfx/src/DriverCrashGuard.cpp @@ -156,7 +156,7 @@ DriverCrashGuard::~DriverCrashGuard() { dom::ContentChild::GetSingleton()->SendEndDriverCrashGuard(uint32_t(mType)); } - CrashReporter::RemoveCrashReportAnnotation( + CrashReporter::UnrecordAnnotation( CrashReporter::Annotation::GraphicsStartupTest); } @@ -195,7 +195,7 @@ void DriverCrashGuard::ActivateGuard() { // attribute a random parent process crash to a graphics problem in a child // process. if (mMode != Mode::Proxy) { - CrashReporter::AnnotateCrashReport( + CrashReporter::RecordAnnotationBool( CrashReporter::Annotation::GraphicsStartupTest, true); } diff --git a/gfx/tests/browser/browser_native_font_cache_macos.js b/gfx/tests/browser/browser_native_font_cache_macos.js index 919a5c7a72..e71ccbf5a6 100644 --- a/gfx/tests/browser/browser_native_font_cache_macos.js +++ b/gfx/tests/browser/browser_native_font_cache_macos.js @@ -87,8 +87,9 @@ add_task(async () => { const nfrm_match = nfrm_line.exec(copiedText); if (nfrm_match) { const nfrm_mb = nfrm_match[1]; - ok( - nfrm_mb < MB_EXCLUSIVE_MAX, + Assert.less( + nfrm_mb, + MB_EXCLUSIVE_MAX, `native-font-resource-mac ${nfrm_mb} MB should be less than ${MB_EXCLUSIVE_MAX} MB.` ); } else { @@ -102,8 +103,9 @@ add_task(async () => { const gfx_match = gfx_line.exec(copiedText); if (gfx_match && gfx_match.index < om_match.index) { const gfx_mb = gfx_match[1]; - ok( - gfx_mb < MB_EXCLUSIVE_MAX, + Assert.less( + gfx_mb, + MB_EXCLUSIVE_MAX, `Explicit Allocations gfx ${gfx_mb} MB should be less than ${MB_EXCLUSIVE_MAX} MB.` ); } else { diff --git a/gfx/tests/browser/browser_windowless_troubleshoot_crash.js b/gfx/tests/browser/browser_windowless_troubleshoot_crash.js index 44fc50e2f8..2ccae78a6e 100644 --- a/gfx/tests/browser/browser_windowless_troubleshoot_crash.js +++ b/gfx/tests/browser/browser_windowless_troubleshoot_crash.js @@ -1,10 +1,10 @@ add_task(async function test_windowlessBrowserTroubleshootCrash() { let webNav = Services.appShell.createWindowlessBrowser(false); - let onLoaded = new Promise((resolve, reject) => { + let onLoaded = new Promise(resolve => { let docShell = webNav.docShell; let listener = { - observe(contentWindow, topic, data) { + observe(contentWindow) { let observedDocShell = contentWindow.docShell.sameTypeRootTreeItem.QueryInterface( Ci.nsIDocShell @@ -45,8 +45,9 @@ add_task(async function test_windowlessBrowserTroubleshootCrash() { ); var data = await Troubleshoot.snapshot(); - ok( - data.graphics.windowLayerManagerType !== "None", + Assert.notStrictEqual( + data.graphics.windowLayerManagerType, + "None", "windowless browser window should not set windowLayerManagerType to 'None'" ); diff --git a/gfx/tests/chrome/test_device_reset.html b/gfx/tests/chrome/test_device_reset.html index a081c26dc4..167dff1b7b 100644 --- a/gfx/tests/chrome/test_device_reset.html +++ b/gfx/tests/chrome/test_device_reset.html @@ -70,7 +70,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1274663 windowutils.triggerDeviceReset(); SimpleTest.waitForExplicitFinish(); - window.addEventListener("MozAfterPaint", function paintHandle(e) { + window.addEventListener("MozAfterPaint", function paintHandle() { // Add more latency before calling runCanvasTest() // runCanvasTest() needs to be called after gecko's device reset handling. // Since Bug 1757879 fix, the triggerDeviceReset() does the device reset diff --git a/gfx/tests/crashtests/1701975-1.html b/gfx/tests/crashtests/1701975-1.html deleted file mode 100644 index c7d54ca996..0000000000 --- a/gfx/tests/crashtests/1701975-1.html +++ /dev/null @@ -1,20 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <style> - #id_0 { - font-size: 10000% ! important - } - - * { - border-top-style: groove; - } - </style> - -</head> -<math> - <semantics style='border-inline: 1000000em outset !important'> - <mmultiscripts id='id_0'></mmultiscripts> - </semantics> -</math> -</html> diff --git a/gfx/tests/crashtests/306902-1.xml b/gfx/tests/crashtests/306902-1.xml deleted file mode 100644 index 24e8c068a0..0000000000 --- a/gfx/tests/crashtests/306902-1.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version='1.0'?> - -<html xmlns="http://www.w3.org/1999/xhtml"> - -<body> - -<math xmlns='http://www.w3.org/1998/Math/MathML' display='block'><msup> - -XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - -</msup></math> - -</body> -</html> diff --git a/gfx/tests/crashtests/385289-1.xhtml b/gfx/tests/crashtests/385289-1.xhtml deleted file mode 100644 index 666756c016..0000000000 --- a/gfx/tests/crashtests/385289-1.xhtml +++ /dev/null @@ -1,30 +0,0 @@ -<html xmlns="http://www.w3.org/1999/xhtml"> -<head> -<script> -function boom() -{ - var mss = document.getElementById("mss"); - - var j = document.createTextNode("j"); - var comb = document.createTextNode("\u0302"); - - mss.appendChild(j); - mss.appendChild(comb); -} -</script> -</head> - -<body onload="boom()"> - -<div> - <math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> - <msub id="mss"> - <mi>v</mi> - <mn>1</mn> - </msub> - </math> -</div> - -</body> - -</html> diff --git a/gfx/tests/crashtests/410728-1.xml b/gfx/tests/crashtests/410728-1.xml deleted file mode 100644 index deaeb8fc55..0000000000 --- a/gfx/tests/crashtests/410728-1.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE html PUBLIC - "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" - "http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd" -[ - <!ENTITY mathml "http://www.w3.org/1998/Math/MathML"> -]> -<math display="block" xmlns="&mathml;"> - <mi>f ̲</mi> - <mi>-</mi> - <mo>+</mo> - <mo> -</mo> - <mo>̲</mo> -</math> diff --git a/gfx/tests/crashtests/crashtests.list b/gfx/tests/crashtests/crashtests.list index d3c9efef11..44a2f61050 100644 --- a/gfx/tests/crashtests/crashtests.list +++ b/gfx/tests/crashtests/crashtests.list @@ -5,7 +5,6 @@ load 199379-1.html load 206561-1.html load 248518-1.html load 306649-1.xml -load 306902-1.xml load 333861-1.html load 334735-1.html load 345576-1.html @@ -24,7 +23,6 @@ load 383473-1.html load 383872-1.svg load 385228-1.svg skip load 385228-2.svg # bug 523255 / bug 385228 -load 385289-1.xhtml load 385417-1.html load 385417-2.html load 385423-1.html @@ -32,7 +30,7 @@ load 385423-2.html load 385719-1.html load 389326-1.html load 390476.html -skip-if(xulRuntime.OS=="WINNT"&&!xulRuntime.is64Bit) load 393746-1.xhtml # Bug 1727925 +skip-if(winWidget&&!is64Bit) load 393746-1.xhtml # Bug 1727925 load 393749-1.html load 393822-1.html load 394384-1.html @@ -53,7 +51,6 @@ load 405268-1.xhtml load 407761-1.html load 407842.html load 408754-1.html -load 410728-1.xml load 416637-1.html load 419095-1.html load 419255-1.html @@ -205,7 +202,6 @@ load 1694783-1.html load 1695782-1.html load 1699013.html load 1700232.html -load 1701975-1.html load 1704321-1.html load 1702638.html load 1730695.html diff --git a/gfx/tests/gtest/TestConfigManager.cpp b/gfx/tests/gtest/TestConfigManager.cpp index d76dcfd234..825a995e98 100644 --- a/gfx/tests/gtest/TestConfigManager.cpp +++ b/gfx/tests/gtest/TestConfigManager.cpp @@ -159,6 +159,12 @@ class MockGfxInfo final : public nsIGfxInfo { NS_IMETHOD GetUsingGPUProcess(bool* aOutValue) override { return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD GetUsingRemoteCanvas(bool* aOutValue) override { + return NS_ERROR_NOT_IMPLEMENTED; + } + NS_IMETHOD GetUsingAcceleratedCanvas(bool* aOutValue) override { + return NS_ERROR_NOT_IMPLEMENTED; + } NS_IMETHOD GetIsHeadless(bool* aIsHeadless) override { return NS_ERROR_NOT_IMPLEMENTED; } diff --git a/gfx/tests/reftest/reftest.list b/gfx/tests/reftest/reftest.list index bb081d5c06..dcdac53c67 100644 --- a/gfx/tests/reftest/reftest.list +++ b/gfx/tests/reftest/reftest.list @@ -2,7 +2,7 @@ == 468496-1.html 468496-1-ref.html fuzzy(0-175,0-443) == 611498-1.html 611498-ref.html skip-if(gtkWidget||Android||isDebugBuild) fuzzy-if(appleSilicon,0-1,0-9) == 709477-1.html 709477-1-ref.html #Bug 1620096 -skip-if(!asyncPan) == 1086723.html 1086723-ref.html +skip-if(useDrawSnapshot) == 1086723.html 1086723-ref.html == 853889-1.html 853889-1-ref.html skip-if(Android) fuzzy(0-1,0-587) == 1143303-1.svg pass.svg fuzzy(0-100,0-30) == 1149923.html 1149923-ref.html # use fuzzy due to few distorted pixels caused by border-radius @@ -18,13 +18,13 @@ fuzzy-if(!useDrawSnapshot,0-5,0-1060) fuzzy-if(useDrawSnapshot,32-32,26350-26350 fuzzy(0-11,0-4) fails-if(useDrawSnapshot) == 1474722.html 1474722-ref.html fails-if(useDrawSnapshot) == 1501195.html 1501195-ref.html == 1519754.html 1519754-ref.html -skip-if(!asyncPan) == 1524261.html 1524261-ref.html +skip-if(useDrawSnapshot) == 1524261.html 1524261-ref.html fuzzy-if(!useDrawSnapshot,14-14,44-95) == 1524353.html 1524353-ref.html == 1523776.html 1523776-ref.html == bug1523410-translate-scale-snap.html bug1523410-translate-scale-snap-ref.html == 1523080.html 1523080-ref.html == 1616444-same-color-different-paths.html 1616444-same-color-different-paths-ref.html -skip-if(!asyncPan||Android) fuzzy-if(winWidget,54-94,2713-3419) fuzzy-if(cocoaWidget,24-24,1190-1200) pref(apz.allow_zooming,true) == picture-caching-on-async-zoom.html picture-caching-on-async-zoom.html?ref +skip-if(useDrawSnapshot||Android) fuzzy-if(winWidget,54-94,2713-3419) fuzzy-if(cocoaWidget,24-24,1190-1200) pref(apz.allow_zooming,true) == picture-caching-on-async-zoom.html picture-caching-on-async-zoom.html?ref pref(apz.allow_zooming,true) fails-if(useDrawSnapshot) == 1662062-1-no-blurry.html 1662062-1-ref.html # Bug 1715676: nsBulletFrame has been removed and the new rendering does not use PushRoundedRect that this test is for: # == 1681610.html 1681610-ref.html @@ -32,7 +32,7 @@ skip-if(geckoview) fuzzy-if(!useDrawSnapshot,0-255,0-1050) fuzzy-if(useDrawSnaps fuzzy(64-99,506-645) == 1696439-1.html 1696439-1-ref.html random-if(gtkWidget) == 1722689-1.html 1722689-1-ref.html fuzzy-if(useDrawSnapshot,255-255,5-5) == 1724901-1.html 1724901-1-ref.html -pref(image.downscale-during-decode.enabled,true) skip-if(Android) fuzzy-if(useDrawSnapshot&&browserIsFission,203-203,193600-193600) HTTP == 1724901-2.html 1724901-2-ref.html +pref(image.downscale-during-decode.enabled,true) skip-if(Android) fuzzy-if(useDrawSnapshot&&fission,203-203,193600-193600) HTTP == 1724901-2.html 1724901-2-ref.html == 1760747-1.html 1760747-1-ref.html != 1761685-1.html 1761685-1-ref.html fuzzy(0-9,0-305) == 1761460.html 1761460-ref.html diff --git a/gfx/thebes/CoreTextFontList.cpp b/gfx/thebes/CoreTextFontList.cpp index 0c8c179e8e..e83435b638 100644 --- a/gfx/thebes/CoreTextFontList.cpp +++ b/gfx/thebes/CoreTextFontList.cpp @@ -35,6 +35,15 @@ using namespace mozilla; using namespace mozilla::gfx; +#ifdef MOZ_WIDGET_COCOA +// Building with newer macOS SDKs can cause a bunch of font-family names to be +// hidden from the Core Text API we use to enumerate available fonts. Because +// some content still benefits from having these names recognized, we forcibly +// include them in the list. Some day we might want to drop support for these. +# define USE_DEPRECATED_FONT_FAMILY_NAMES 1 +#endif + +#if USE_DEPRECATED_FONT_FAMILY_NAMES // List generated by diffing the arrays returned by // CTFontManagerCopyAvailableFontFamilyNames() when built with // MACOSX_DEPLOYMENT_TARGET=10.12 vs 11.0, to identify the font family names @@ -198,6 +207,7 @@ constexpr nsLiteralCString kDeprecatedFontFamilies[] = { "Superclarendon"_ns, "Times"_ns, }; +#endif // USE_DEPRECATED_FONT_FAMILY_NAMES static void GetStringForCFString(CFStringRef aSrc, nsAString& aDest) { auto len = CFStringGetLength(aSrc); @@ -497,7 +507,7 @@ CGFontRef CTFontEntry::CreateOrCopyFontRef() { return mFontRef; } - CrashReporter::AutoAnnotateCrashReport autoFontName( + CrashReporter::AutoRecordAnnotation autoFontName( CrashReporter::Annotation::FontName, mName); // Create a new CGFont; caller will own the only reference to it. @@ -666,7 +676,7 @@ bool CTFontEntry::SupportsOpenTypeFeature(Script aScript, return mHasAATSmallCaps; } - CrashReporter::AutoAnnotateCrashReport autoFontName( + CrashReporter::AutoRecordAnnotation autoFontName( CrashReporter::Annotation::FontName, FamilyName()); AutoCFRelease<CTFontRef> ctFont = @@ -907,6 +917,47 @@ void CTFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) { AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("CTFontFamily::FindStyleVariations", LAYOUT, mName); + if (mForSystemFont) { + MOZ_ASSERT(gfxPlatform::HasVariationFontSupport()); + + auto addToFamily = [&](CTFontRef aFont) MOZ_REQUIRES(mLock) { + AutoCFRelease<CFStringRef> psName = CTFontCopyPostScriptName(aFont); + nsAutoString nameUTF16; + nsAutoCString nameUTF8; + GetStringForCFString(psName, nameUTF16); + CopyUTF16toUTF8(nameUTF16, nameUTF8); + + auto* fe = + new CTFontEntry(nameUTF8, WeightRange(FontWeight::NORMAL), true, 0.0); + + // Set the appropriate style, assuming it may not have a variation range. + CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(aFont); + fe->mStyleRange = SlantStyleRange((traits & kCTFontTraitItalic) + ? FontSlantStyle::ITALIC + : FontSlantStyle::NORMAL); + + // Set up weight (and width, if present) ranges. + fe->SetupVariationRanges(); + AddFontEntryLocked(fe); + }; + + addToFamily(mForSystemFont); + + // See if there is a corresponding italic face, and add it to the family. + AutoCFRelease<CTFontRef> italicFont = CTFontCreateCopyWithSymbolicTraits( + mForSystemFont, 0.0, nullptr, kCTFontTraitItalic, kCTFontTraitItalic); + if (italicFont != mForSystemFont) { + addToFamily(italicFont); + } + + CFRelease(mForSystemFont); + mForSystemFont = nullptr; + + SetHasStyles(true); + + return; + } + struct Context { CTFontFamily* family; const void* prevValue = nullptr; @@ -1134,11 +1185,13 @@ nsresult CoreTextFontList::InitFontListForPlatform() { (CFStringRef)CFArrayGetValueAtIndex(familyNames, i); AddFamily(familyName); } +#if USE_DEPRECATED_FONT_FAMILY_NAMES for (const auto& name : kDeprecatedFontFamilies) { if (DeprecatedFamilyIsAvailable(name)) { AddFamily(name, GetVisibilityForFamily(name)); } } +#endif } else { // Content process: use font list passed from the chrome process via // the GetXPCOMProcessAttributes message, because it's much faster than @@ -1196,8 +1249,11 @@ void CoreTextFontList::InitSharedFontListForPlatform() { AutoCFRelease<CFArrayRef> familyNames = CTFontManagerCopyAvailableFontFamilyNames(); nsTArray<fontlist::Family::InitData> families; - families.SetCapacity(CFArrayGetCount(familyNames) + - ArrayLength(kDeprecatedFontFamilies)); + families.SetCapacity(CFArrayGetCount(familyNames) +#if USE_DEPRECATED_FONT_FAMILY_NAMES + + ArrayLength(kDeprecatedFontFamilies) +#endif + ); for (CFIndex i = 0; i < CFArrayGetCount(familyNames); ++i) { nsAutoString name16; CFStringRef familyName = @@ -1209,6 +1265,7 @@ void CoreTextFontList::InitSharedFontListForPlatform() { families.AppendElement(fontlist::Family::InitData( key, name, fontlist::Family::kNoIndex, GetVisibilityForFamily(name))); } +#if USE_DEPRECATED_FONT_FAMILY_NAMES for (const nsACString& name : kDeprecatedFontFamilies) { if (DeprecatedFamilyIsAvailable(name)) { nsAutoCString key; @@ -1218,6 +1275,7 @@ void CoreTextFontList::InitSharedFontListForPlatform() { GetVisibilityForFamily(name))); } } +#endif SharedFontList()->SetFamilyNames(families); InitAliasesForSingleFaceList(); GetPrefsAndStartLoader(); @@ -1367,7 +1425,7 @@ gfxFontEntry* CoreTextFontList::LookupLocalFont( AutoLock lock(mLock); - CrashReporter::AutoAnnotateCrashReport autoFontName( + CrashReporter::AutoRecordAnnotation autoFontName( CrashReporter::Annotation::FontName, aFontName); AutoCFRelease<CFStringRef> faceName = CreateCFStringForString(aFontName); @@ -1444,7 +1502,7 @@ gfxFontEntry* CoreTextFontList::MakePlatformFont(const nsACString& aFontName, return nullptr; } - CrashReporter::AutoAnnotateCrashReport autoFontName( + CrashReporter::AutoRecordAnnotation autoFontName( CrashReporter::Annotation::FontName, aFontName); AutoCFRelease<CGDataProviderRef> provider = @@ -1504,7 +1562,7 @@ class CTFontInfo final : public FontInfoData { }; void CTFontInfo::LoadFontFamilyData(const nsACString& aFamilyName) { - CrashReporter::AutoAnnotateCrashReport autoFontName( + CrashReporter::AutoRecordAnnotation autoFontName( CrashReporter::Annotation::FontName, aFamilyName); // Prevent this from running concurrently with CGFont operations on the main // thread, because the macOS font cache is fragile with concurrent access. @@ -1726,7 +1784,7 @@ void CoreTextFontList::GetFacesInitDataForFamily( const fontlist::Family* aFamily, nsTArray<fontlist::Face::InitData>& aFaces, bool aLoadCmaps) const { auto name = aFamily->Key().AsString(SharedFontList()); - CrashReporter::AutoAnnotateCrashReport autoFontName( + CrashReporter::AutoRecordAnnotation autoFontName( CrashReporter::Annotation::FontName, name); struct Context { @@ -1805,6 +1863,56 @@ void CoreTextFontList::ReadFaceNamesForFamily( } } +static CFStringRef CopyRealFamilyName(CTFontRef aFont) { + AutoCFRelease<CFStringRef> psName = CTFontCopyPostScriptName(aFont); + AutoCFRelease<CGFontRef> cgFont = + CGFontCreateWithFontName(CFStringRef(psName)); + if (!cgFont) { + return CTFontCopyFamilyName(aFont); + } + AutoCFRelease<CTFontRef> ctFont = + CTFontCreateWithGraphicsFont(cgFont, 0.0, nullptr, nullptr); + if (!ctFont) { + return CTFontCopyFamilyName(aFont); + } + return CTFontCopyFamilyName(ctFont); +} + +void CoreTextFontList::InitSystemFontNames() { + // text font family + AutoCFRelease<CTFontRef> font = CTFontCreateUIFontForLanguage( + kCTFontUIFontSystem, 0.0, nullptr); // TODO: language + AutoCFRelease<CFStringRef> name = CopyRealFamilyName(font); + + nsAutoString familyName; + GetStringForCFString(name, familyName); + CopyUTF16toUTF8(familyName, mSystemFontFamilyName); + + // We store an in-process gfxFontFamily for the system font even if using the + // shared fontlist to manage "normal" fonts, because the hidden system fonts + // may be excluded from the font list altogether. This family will be + // populated based on the given NSFont. + RefPtr<gfxFontFamily> fam = new CTFontFamily(mSystemFontFamilyName, font); + if (fam) { + nsAutoCString key; + GenerateFontListKey(mSystemFontFamilyName, key); + mFontFamilies.InsertOrUpdate(key, std::move(fam)); + } +} + +FontFamily CoreTextFontList::GetDefaultFontForPlatform( + nsPresContext* aPresContext, const gfxFontStyle* aStyle, + nsAtom* aLanguage) { + AutoCFRelease<CTFontRef> font = CTFontCreateUIFontForLanguage( + kCTFontUIFontUser, 0.0, nullptr); // TODO: language + AutoCFRelease<CFStringRef> name = CTFontCopyFamilyName(font); + + nsAutoString familyName; + GetStringForCFString(name, familyName); + + return FindFamily(aPresContext, NS_ConvertUTF16toUTF8(familyName)); +} + #ifdef MOZ_BUNDLED_FONTS void CoreTextFontList::ActivateBundledFonts() { nsCOMPtr<nsIFile> localDir; diff --git a/gfx/thebes/CoreTextFontList.h b/gfx/thebes/CoreTextFontList.h index 3aa7b75247..97052b36f6 100644 --- a/gfx/thebes/CoreTextFontList.h +++ b/gfx/thebes/CoreTextFontList.h @@ -118,6 +118,15 @@ class CTFontFamily : public gfxFontFamily { CTFontFamily(const nsACString& aName, FontVisibility aVisibility) : gfxFontFamily(aName, aVisibility) {} + CTFontFamily(const nsACString& aName, CTFontRef aSystemFont) + : gfxFontFamily(aName, FontVisibility::Unknown), + mForSystemFont(aSystemFont) { + // I don't think the system font instance is at much risk of being deleted, + // but to be on the safe side let's retain a reference until we're finished + // using it for lazy initialization. + CFRetain(mForSystemFont); + } + virtual ~CTFontFamily() = default; void LocalizedName(nsACString& aLocalizedName) override; @@ -127,6 +136,15 @@ class CTFontFamily : public gfxFontFamily { protected: void AddFace(CTFontDescriptorRef aFace) MOZ_REQUIRES(mLock); + + // If non-null, this is a family representing the system UI font, and should + // use the given CTFontRef as the basis for initialization as the normal + // font-manager APIs based on family name won't handle it. + CTFontRef mForSystemFont = nullptr; +}; + +class gfxMacFontFamily final : public CTFontFamily { + public: }; class CoreTextFontList : public gfxPlatformFontList { @@ -179,7 +197,13 @@ class CoreTextFontList : public gfxPlatformFontList { void PreloadNamesList() MOZ_REQUIRES(mLock); // initialize system fonts - virtual void InitSystemFontNames() = 0; + void InitSystemFontNames() MOZ_REQUIRES(mLock); + + // look up a default font to use as fallback + FontFamily GetDefaultFontForPlatform(nsPresContext* aPresContext, + const gfxFontStyle* aStyle, + nsAtom* aLanguage = nullptr) + MOZ_REQUIRES(mLock) override; // Hooks for the macOS-specific "single face family" hack (Osaka-mono). virtual void InitSingleFaceList() {} diff --git a/gfx/thebes/DeviceManagerDx.cpp b/gfx/thebes/DeviceManagerDx.cpp index 18c5cea7db..ba473e0d1e 100644 --- a/gfx/thebes/DeviceManagerDx.cpp +++ b/gfx/thebes/DeviceManagerDx.cpp @@ -206,6 +206,129 @@ bool DeviceManagerDx::GetOutputFromMonitor(HMONITOR monitor, return false; } +void DeviceManagerDx::PostUpdateMonitorInfo() { + MOZ_ASSERT(XRE_IsGPUProcess()); + MOZ_ASSERT(NS_IsMainThread()); + + MutexAutoLock lock(mDeviceLock); + // Reduce frequency of UpdateMonitorInfo() call. + if (mUpdateMonitorInfoRunnable) { + return; + } + + auto* holder = CompositorThreadHolder::GetSingleton(); + if (!holder) { + return; + } + + mUpdateMonitorInfoRunnable = NS_NewRunnableFunction( + "DeviceManagerDx::PostUpdateMonitorInfo::Runnable", []() -> void { + auto* dm = gfx::DeviceManagerDx::Get(); + if (dm) { + dm->UpdateMonitorInfo(); + } + }); + + const uint32_t kDelayMS = 100; + RefPtr<Runnable> runnable = mUpdateMonitorInfoRunnable; + holder->GetCompositorThread()->DelayedDispatch(runnable.forget(), kDelayMS); +} + +void DeviceManagerDx::UpdateMonitorInfo() { + bool systemHdrEnabled = false; + + for (const auto& desc : GetOutputDescs()) { + if (desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) { + systemHdrEnabled = true; + } + } + { + MutexAutoLock lock(mDeviceLock); + mSystemHdrEnabled = Some(systemHdrEnabled); + mUpdateMonitorInfoRunnable = nullptr; + } +} + +std::vector<DXGI_OUTPUT_DESC1> DeviceManagerDx::GetOutputDescs() { + std::vector<DXGI_OUTPUT_DESC1> outputDescs; + + nsModuleHandle dxgiModule(LoadLibrarySystem32(L"dxgi.dll")); + decltype(CreateDXGIFactory1)* createDXGIFactory1 = + (decltype(CreateDXGIFactory1)*)GetProcAddress(dxgiModule, + "CreateDXGIFactory1"); + if (!createDXGIFactory1) { + return outputDescs; + } + + RefPtr<IDXGIFactory1> dxgiFactory; + HRESULT hr = + createDXGIFactory1(__uuidof(IDXGIFactory1), getter_AddRefs(dxgiFactory)); + if (FAILED(hr)) { + gfxCriticalNoteOnce << "Failed to create DXGI factory: " << gfx::hexa(hr); + return outputDescs; + } + + for (UINT adapterIndex = 0;; adapterIndex++) { + RefPtr<IDXGIAdapter> adapter; + hr = dxgiFactory->EnumAdapters(adapterIndex, getter_AddRefs(adapter)); + if (hr == DXGI_ERROR_NOT_FOUND) { + break; + } + if (FAILED(hr)) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + gfxCriticalNoteOnce << "Failed to enumerate DXGI adapter: " + << gfx::hexa(hr); + break; + } + + for (UINT outputIndex = 0;; ++outputIndex) { + RefPtr<IDXGIOutput> output; + hr = adapter->EnumOutputs(outputIndex, getter_AddRefs(output)); + if (hr == DXGI_ERROR_NOT_FOUND) { + break; + } + if (FAILED(hr)) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + gfxCriticalNoteOnce << "Failed to enumulate DXGI output: " + << gfx::hexa(hr); + break; + } + + RefPtr<IDXGIOutput6> output6; + hr = output->QueryInterface(__uuidof(IDXGIOutput6), + getter_AddRefs(output6)); + if (FAILED(hr)) { + continue; + } + + DXGI_OUTPUT_DESC1 desc; + if (FAILED(output6->GetDesc1(&desc))) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + gfxCriticalNoteOnce << "Failed to get DXGI output descriptor"; + continue; + } + + outputDescs.push_back(std::move(desc)); + } + } + + return outputDescs; +} + +bool DeviceManagerDx::SystemHDREnabled() { + { + MutexAutoLock lock(mDeviceLock); + if (mSystemHdrEnabled.isSome()) { + return mSystemHdrEnabled.ref(); + } + } + + UpdateMonitorInfo(); + + MutexAutoLock lock(mDeviceLock); + return mSystemHdrEnabled.ref(); +} + void DeviceManagerDx::CheckHardwareStretchingSupport(HwStretchingSupport& aRv) { RefPtr<IDXGIAdapter> adapter = GetDXGIAdapter(); diff --git a/gfx/thebes/DeviceManagerDx.h b/gfx/thebes/DeviceManagerDx.h index 9d127af358..c6860c7ffa 100644 --- a/gfx/thebes/DeviceManagerDx.h +++ b/gfx/thebes/DeviceManagerDx.h @@ -6,6 +6,8 @@ #ifndef mozilla_gfx_thebes_DeviceManagerDx_h #define mozilla_gfx_thebes_DeviceManagerDx_h +#include <vector> + #include "gfxPlatform.h" #include "gfxTelemetry.h" #include "gfxTypes.h" @@ -88,6 +90,9 @@ class DeviceManagerDx final { // 'monitor'; returns false if not found or some error occurred. bool GetOutputFromMonitor(HMONITOR monitor, RefPtr<IDXGIOutput>* aOutOutput); + void PostUpdateMonitorInfo(); + bool SystemHDREnabled(); + // Check if the current adapter supports hardware stretching void CheckHardwareStretchingSupport(HwStretchingSupport& aRv); @@ -172,6 +177,9 @@ class DeviceManagerDx final { bool GetAnyDeviceRemovedReason(DeviceResetReason* aOutReason) MOZ_REQUIRES(mDeviceLock); + void UpdateMonitorInfo(); + std::vector<DXGI_OUTPUT_DESC1> GetOutputDescs(); + private: static StaticAutoPtr<DeviceManagerDx> sInstance; @@ -198,6 +206,8 @@ class DeviceManagerDx final { bool mCompositorDeviceSupportsVideo MOZ_GUARDED_BY(mDeviceLock); Maybe<D3D11DeviceStatus> mDeviceStatus MOZ_GUARDED_BY(mDeviceLock); Maybe<DeviceResetReason> mDeviceResetReason MOZ_GUARDED_BY(mDeviceLock); + RefPtr<Runnable> mUpdateMonitorInfoRunnable MOZ_GUARDED_BY(mDeviceLock); + Maybe<bool> mSystemHdrEnabled MOZ_GUARDED_BY(mDeviceLock); nsModuleHandle mDirectDrawDLL; RefPtr<IDirectDraw7> mDirectDraw; diff --git a/gfx/thebes/IOSPlatformFontList.h b/gfx/thebes/IOSPlatformFontList.h new file mode 100644 index 0000000000..733939b755 --- /dev/null +++ b/gfx/thebes/IOSPlatformFontList.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * 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 IOSPlatformFontList_H_ +#define IOSPlatformFontList_H_ + +#include <CoreFoundation/CoreFoundation.h> + +#include "CoreTextFontList.h" + +class IOSPlatformFontList final : public CoreTextFontList { + public: + static IOSPlatformFontList* PlatformFontList() { + return static_cast<IOSPlatformFontList*>( + gfxPlatformFontList::PlatformFontList()); + } + + static void LookupSystemFont(mozilla::LookAndFeel::FontID aSystemFontID, + nsACString& aSystemFontName, + gfxFontStyle& aFontStyle); + + protected: + nsTArray<std::pair<const char**, uint32_t>> GetFilteredPlatformFontLists() + override; + + private: + friend class gfxPlatformMac; + + // Only the friend class gfxPlatformMac constructs this. + IOSPlatformFontList(); + virtual ~IOSPlatformFontList(); +}; + +#endif /* IOSPlatformFontList_H_ */ diff --git a/gfx/thebes/IOSPlatformFontList.mm b/gfx/thebes/IOSPlatformFontList.mm new file mode 100644 index 0000000000..e42d209fa3 --- /dev/null +++ b/gfx/thebes/IOSPlatformFontList.mm @@ -0,0 +1,24 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * 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/. */ + +#import <UIKit/UIKit.h> +#include "IOSPlatformFontList.h" + +IOSPlatformFontList::IOSPlatformFontList() : CoreTextFontList() {} + +IOSPlatformFontList::~IOSPlatformFontList() {} + +void IOSPlatformFontList::LookupSystemFont( + mozilla::LookAndFeel::FontID aSystemFontID, nsACString& aSystemFontName, + gfxFontStyle& aFontStyle) { + MOZ_CRASH("UNIMPLEMENTED"); +} + +nsTArray<std::pair<const char**, uint32_t>> +IOSPlatformFontList::GetFilteredPlatformFontLists() { + nsTArray<std::pair<const char**, uint32_t>> fontLists; + + return fontLists; +} diff --git a/gfx/thebes/gencjkcisvs.py b/gfx/thebes/gencjkcisvs.py index 6a28e7d492..000b3f5711 100644 --- a/gfx/thebes/gencjkcisvs.py +++ b/gfx/thebes/gencjkcisvs.py @@ -9,7 +9,7 @@ import sys f = open(sys.argv[1] if len(sys.argv) > 1 else "StandardizedVariants.txt") line = f.readline() -m = re.compile("^# (StandardizedVariants(-\d+(\.\d+)*)?\.txt)").search(line) +m = re.compile(r"^# (StandardizedVariants(-\d+(\.\d+)*)?\.txt)").search(line) fileversion = m.group(1) vsdict = {} r = re.compile( diff --git a/gfx/thebes/gfxCoreTextShaper.h b/gfx/thebes/gfxCoreTextShaper.h index 53f24ba3ba..557b6ba247 100644 --- a/gfx/thebes/gfxCoreTextShaper.h +++ b/gfx/thebes/gfxCoreTextShaper.h @@ -8,7 +8,7 @@ #include "gfxFont.h" -#include <ApplicationServices/ApplicationServices.h> +#include <CoreText/CoreText.h> class gfxMacFont; diff --git a/gfx/thebes/gfxDWriteFontList.cpp b/gfx/thebes/gfxDWriteFontList.cpp index b77058b359..8595004d21 100644 --- a/gfx/thebes/gfxDWriteFontList.cpp +++ b/gfx/thebes/gfxDWriteFontList.cpp @@ -1159,6 +1159,17 @@ FontVisibility gfxDWriteFontList::GetVisibilityForFamily( return FontVisibility::User; } +nsTArray<std::pair<const char**, uint32_t>> +gfxDWriteFontList::GetFilteredPlatformFontLists() { + nsTArray<std::pair<const char**, uint32_t>> fontLists; + + fontLists.AppendElement(std::make_pair(kBaseFonts, ArrayLength(kBaseFonts))); + fontLists.AppendElement( + std::make_pair(kLangPackFonts, ArrayLength(kLangPackFonts))); + + return fontLists; +} + void gfxDWriteFontList::AppendFamiliesFromCollection( IDWriteFontCollection* aCollection, nsTArray<fontlist::Family::InitData>& aFamilies, diff --git a/gfx/thebes/gfxDWriteFontList.h b/gfx/thebes/gfxDWriteFontList.h index adf8fdfa5a..357336a12c 100644 --- a/gfx/thebes/gfxDWriteFontList.h +++ b/gfx/thebes/gfxDWriteFontList.h @@ -436,6 +436,9 @@ class gfxDWriteFontList final : public gfxPlatformFontList { FontFamily& aMatchedFamily) MOZ_REQUIRES(mLock) override; + nsTArray<std::pair<const char**, uint32_t>> GetFilteredPlatformFontLists() + override; + private: friend class gfxDWriteFontFamily; diff --git a/gfx/thebes/gfxFT2FontList.cpp b/gfx/thebes/gfxFT2FontList.cpp index 6ff9788dc1..66f7655282 100644 --- a/gfx/thebes/gfxFT2FontList.cpp +++ b/gfx/thebes/gfxFT2FontList.cpp @@ -1321,6 +1321,55 @@ FontVisibility gfxFT2FontList::GetVisibilityForFamily( return FontVisibility::User; } +nsTArray<std::pair<const char**, uint32_t>> +gfxFT2FontList::GetFilteredPlatformFontLists() { + static Device fontVisibilityDevice = Device::Unassigned; + if (fontVisibilityDevice == Device::Unassigned) { + nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service(); + Unused << gfxInfo->GetFontVisibilityDetermination(&fontVisibilityDevice); + } + + nsTArray<std::pair<const char**, uint32_t>> fontLists; + + if (fontVisibilityDevice == Device::Android_Unknown_Release_Version || + fontVisibilityDevice == Device::Android_Unknown_Peloton || + fontVisibilityDevice == Device::Android_Unknown_vbox || + fontVisibilityDevice == Device::Android_Unknown_mitv || + fontVisibilityDevice == Device::Android_Chromebook || + fontVisibilityDevice == Device::Android_Amazon) { + return fontLists; + } + + // Sanity Check + if (fontVisibilityDevice != Device::Android_sub_9 && + fontVisibilityDevice != Device::Android_9_11 && + fontVisibilityDevice != Device::Android_12_plus) { + return fontLists; + } + + fontLists.AppendElement( + std::make_pair(kBaseFonts_Android, ArrayLength(kBaseFonts_Android))); + + if (fontVisibilityDevice == Device::Android_sub_9) { + fontLists.AppendElement(std::make_pair(kBaseFonts_Android5_8, + ArrayLength(kBaseFonts_Android5_8))); + } else { + fontLists.AppendElement(std::make_pair( + kBaseFonts_Android9_Higher, ArrayLength(kBaseFonts_Android9_Higher))); + + if (fontVisibilityDevice == Device::Android_9_11) { + fontLists.AppendElement(std::make_pair( + kBaseFonts_Android9_11, ArrayLength(kBaseFonts_Android9_11))); + } else { + fontLists.AppendElement( + std::make_pair(kBaseFonts_Android12_Higher, + ArrayLength(kBaseFonts_Android12_Higher))); + } + } + + return fontLists; +} + static void GetName(hb_face_t* aFace, hb_ot_name_id_t aNameID, nsACString& aName) { unsigned int n = 0; diff --git a/gfx/thebes/gfxFT2FontList.h b/gfx/thebes/gfxFT2FontList.h index 895b1172d4..0e92d31944 100644 --- a/gfx/thebes/gfxFT2FontList.h +++ b/gfx/thebes/gfxFT2FontList.h @@ -210,6 +210,9 @@ class gfxFT2FontList final : public gfxPlatformFontList { void CollectInitData(const FontListEntry& aFLE, const nsCString& aPSName, const nsCString& aFullName, StandardFile aStdFile); + nsTArray<std::pair<const char**, uint32_t>> GetFilteredPlatformFontLists() + override; + /** * Callback passed to AppendFacesFromCachedFaceList to collect family/face * information in either the unshared or shared list we're building. diff --git a/gfx/thebes/gfxFcPlatformFontList.cpp b/gfx/thebes/gfxFcPlatformFontList.cpp index 60a8f9894e..30c202d6ee 100644 --- a/gfx/thebes/gfxFcPlatformFontList.cpp +++ b/gfx/thebes/gfxFcPlatformFontList.cpp @@ -2048,6 +2048,49 @@ FontVisibility gfxFcPlatformFontList::GetVisibilityForFamily( } } +nsTArray<std::pair<const char**, uint32_t>> +gfxFcPlatformFontList::GetFilteredPlatformFontLists() { + AssignFontVisibilityDevice(); + + nsTArray<std::pair<const char**, uint32_t>> fontLists; + + switch (sFontVisibilityDevice) { + case Device::Linux_Ubuntu_any: + case Device::Linux_Ubuntu_22: + fontLists.AppendElement(std::make_pair( + kBaseFonts_Ubuntu_22_04, ArrayLength(kBaseFonts_Ubuntu_22_04))); + fontLists.AppendElement(std::make_pair( + kLangFonts_Ubuntu_22_04, ArrayLength(kLangFonts_Ubuntu_22_04))); + // For Ubuntu_any, we fall through to also check the 20_04 lists. + [[fallthrough]]; + + case Device::Linux_Ubuntu_20: + fontLists.AppendElement(std::make_pair( + kBaseFonts_Ubuntu_20_04, ArrayLength(kBaseFonts_Ubuntu_20_04))); + fontLists.AppendElement(std::make_pair( + kLangFonts_Ubuntu_20_04, ArrayLength(kLangFonts_Ubuntu_20_04))); + break; + + case Device::Linux_Fedora_any: + case Device::Linux_Fedora_39: + fontLists.AppendElement(std::make_pair( + kBaseFonts_Fedora_39, ArrayLength(kBaseFonts_Fedora_39))); + // For Fedora_any, fall through to also check Fedora 38 list. + [[fallthrough]]; + + case Device::Linux_Fedora_38: + fontLists.AppendElement(std::make_pair( + kBaseFonts_Fedora_38, ArrayLength(kBaseFonts_Fedora_38))); + break; + + default: + // We don't know how to categorize fonts on this system + break; + } + + return fontLists; +} + gfxFontEntry* gfxFcPlatformFontList::CreateFontEntry( fontlist::Face* aFace, const fontlist::Family* aFamily) { nsAutoCString desc(aFace->mDescriptor.AsString(SharedFontList())); diff --git a/gfx/thebes/gfxFcPlatformFontList.h b/gfx/thebes/gfxFcPlatformFontList.h index 54070d1410..ebf57fbcaa 100644 --- a/gfx/thebes/gfxFcPlatformFontList.h +++ b/gfx/thebes/gfxFcPlatformFontList.h @@ -317,6 +317,9 @@ class gfxFcPlatformFontList final : public gfxPlatformFontList { protected: virtual ~gfxFcPlatformFontList(); + nsTArray<std::pair<const char**, uint32_t>> GetFilteredPlatformFontLists() + override; + #if defined(MOZ_SANDBOX) && defined(XP_LINUX) typedef mozilla::SandboxBroker::Policy SandboxPolicy; #else diff --git a/gfx/thebes/gfxFontUtils.cpp b/gfx/thebes/gfxFontUtils.cpp index 02543607cd..46f33f4696 100644 --- a/gfx/thebes/gfxFontUtils.cpp +++ b/gfx/thebes/gfxFontUtils.cpp @@ -28,7 +28,7 @@ #include "plbase64.h" #include "mozilla/Logging.h" -#ifdef XP_MACOSX +#ifdef XP_DARWIN # include <CoreFoundation/CoreFoundation.h> #endif @@ -1441,7 +1441,7 @@ bool gfxFontUtils::DecodeFontName(const char* aNameData, int32_t aByteLen, } if (encoding == X_USER_DEFINED_ENCODING) { -#ifdef XP_MACOSX +#ifdef XP_DARWIN // Special case for macOS only: support legacy Mac encodings // that aren't part of the Encoding Standard. if (aPlatformCode == PLATFORM_ID_MAC) { diff --git a/gfx/thebes/gfxGDIFontList.cpp b/gfx/thebes/gfxGDIFontList.cpp index 3c4c7bce07..4dca4506c0 100644 --- a/gfx/thebes/gfxGDIFontList.cpp +++ b/gfx/thebes/gfxGDIFontList.cpp @@ -853,6 +853,13 @@ bool gfxGDIFontList::FindAndAddFamiliesLocked( aDevToCssSize); } +nsTArray<std::pair<const char**, uint32_t>> +gfxGDIFontList::GetFilteredPlatformFontLists() { + nsTArray<std::pair<const char**, uint32_t>> fontLists; + + return fontLists; +} + FontFamily gfxGDIFontList::GetDefaultFontForPlatform( nsPresContext* aPresContext, const gfxFontStyle* aStyle, nsAtom* aLanguage) { diff --git a/gfx/thebes/gfxGDIFontList.h b/gfx/thebes/gfxGDIFontList.h index 708f7fc114..7fc7f7521b 100644 --- a/gfx/thebes/gfxGDIFontList.h +++ b/gfx/thebes/gfxGDIFontList.h @@ -332,6 +332,9 @@ class gfxGDIFontList final : public gfxPlatformFontList { nsAtom* aLanguage = nullptr) MOZ_REQUIRES(mLock) override; + nsTArray<std::pair<const char**, uint32_t>> GetFilteredPlatformFontLists() + override; + private: friend class gfxWindowsPlatform; diff --git a/gfx/thebes/gfxMacFont.h b/gfx/thebes/gfxMacFont.h index f33ad478ec..051c4ea675 100644 --- a/gfx/thebes/gfxMacFont.h +++ b/gfx/thebes/gfxMacFont.h @@ -8,7 +8,7 @@ #include "mozilla/MemoryReporting.h" #include "gfxFont.h" -#include <ApplicationServices/ApplicationServices.h> +#include <CoreText/CoreText.h> #include "mozilla/gfx/UnscaledFontMac.h" diff --git a/gfx/thebes/gfxMacPlatformFontList.h b/gfx/thebes/gfxMacPlatformFontList.h index ac0d8927fe..8bafa1b803 100644 --- a/gfx/thebes/gfxMacPlatformFontList.h +++ b/gfx/thebes/gfxMacPlatformFontList.h @@ -17,6 +17,9 @@ class gfxMacPlatformFontList final : public CoreTextFontList { gfxPlatformFontList::PlatformFontList()); } + nsTArray<std::pair<const char**, uint32_t>> GetFilteredPlatformFontLists() + override; + static void LookupSystemFont(mozilla::LookAndFeel::FontID aSystemFontID, nsACString& aSystemFontName, gfxFontStyle& aFontStyle); @@ -25,11 +28,6 @@ class gfxMacPlatformFontList final : public CoreTextFontList { bool DeprecatedFamilyIsAvailable(const nsACString& aName) override; FontVisibility GetVisibilityForFamily(const nsACString& aName) const override; - FontFamily GetDefaultFontForPlatform(nsPresContext* aPresContext, - const gfxFontStyle* aStyle, - nsAtom* aLanguage = nullptr) - MOZ_REQUIRES(mLock) override; - private: friend class gfxPlatformMac; @@ -40,9 +38,6 @@ class gfxMacPlatformFontList final : public CoreTextFontList { void InitSingleFaceList() MOZ_REQUIRES(mLock) override; void InitAliasesForSingleFaceList() MOZ_REQUIRES(mLock) override; - // initialize system fonts - void InitSystemFontNames() override MOZ_REQUIRES(mLock); - nsTArray<nsCString> mSingleFaceFonts; }; diff --git a/gfx/thebes/gfxMacPlatformFontList.mm b/gfx/thebes/gfxMacPlatformFontList.mm index e36c9c8a25..2b8d1fa16a 100644 --- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -72,80 +72,6 @@ static NSString* GetNSStringForString(const nsAString& aSrc) { #define LOG_CMAPDATA_ENABLED() \ MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_cmapdata), mozilla::LogLevel::Debug) -class gfxMacFontFamily final : public CTFontFamily { - public: - gfxMacFontFamily(const nsACString& aName, NSFont* aSystemFont) - : CTFontFamily(aName, FontVisibility::Unknown), - mForSystemFont(aSystemFont) { - // I don't think the system font instance is at much risk of being deleted, - // but to be on the safe side let's retain a reference until we're finished - // using it for lazy initialization. - [mForSystemFont retain]; - } - - void FindStyleVariationsLocked(FontInfoData* aFontInfoData = nullptr) - MOZ_REQUIRES(mLock) override; - - protected: - // If non-null, this is a family representing the system UI font, and should - // use the given NSFont as the basis for initialization as the normal - // font-manager APIs based on family name won't handle it. - NSFont* mForSystemFont = nullptr; -}; - -void gfxMacFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) { - if (mHasStyles) { - return; - } - - AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("gfxMacFontFamily::FindStyleVariations", - LAYOUT, mName); - - nsAutoreleasePool localPool; - - if (mForSystemFont) { - MOZ_ASSERT(gfxPlatform::HasVariationFontSupport()); - - auto addToFamily = [&](NSFont* aNSFont) MOZ_REQUIRES(mLock) { - NSString* psNameNS = aNSFont.fontDescriptor.postscriptName; - nsAutoString nameUTF16; - nsAutoCString psName; - nsCocoaUtils::GetStringForNSString(psNameNS, nameUTF16); - CopyUTF16toUTF8(nameUTF16, psName); - - auto* fe = - new CTFontEntry(psName, WeightRange(FontWeight::NORMAL), true, 0.0); - - // Set the appropriate style, assuming it may not have a variation range. - fe->mStyleRange = SlantStyleRange( - (aNSFont.fontDescriptor.symbolicTraits & NSFontItalicTrait) - ? FontSlantStyle::ITALIC - : FontSlantStyle::NORMAL); - - // Set up weight (and width, if present) ranges. - fe->SetupVariationRanges(); - AddFontEntryLocked(fe); - }; - - addToFamily(mForSystemFont); - - // See if there is a corresponding italic face, and add it to the family. - NSFont* italicFont = [sFontManager convertFont:mForSystemFont - toHaveTrait:NSItalicFontMask]; - if (italicFont != mForSystemFont) { - addToFamily(italicFont); - } - - [mForSystemFont release]; - mForSystemFont = nullptr; - SetHasStyles(true); - - return; - } - - CTFontFamily::FindStyleVariationsLocked(aFontInfoData); -} - /* gfxSingleFaceMacFontFamily */ class gfxSingleFaceMacFontFamily final : public gfxFontFamily { @@ -252,6 +178,15 @@ FontVisibility gfxMacPlatformFontList::GetVisibilityForFamily( return FontVisibility::User; } +nsTArray<std::pair<const char**, uint32_t>> +gfxMacPlatformFontList::GetFilteredPlatformFontLists() { + nsTArray<std::pair<const char**, uint32_t>> fontLists; + + fontLists.AppendElement(std::make_pair(kBaseFonts, ArrayLength(kBaseFonts))); + + return fontLists; +} + bool gfxMacPlatformFontList::DeprecatedFamilyIsAvailable( const nsACString& aName) { NSString* family = GetNSStringForString(NS_ConvertUTF8toUTF16(aName)); @@ -394,92 +329,6 @@ void gfxMacPlatformFontList::InitSingleFaceList() { } } -// System fonts under OSX may contain weird "meta" names but if we create -// a new font using just the Postscript name, the NSFont api returns an object -// with the actual real family name. For example, under OSX 10.11: -// -// [[NSFont menuFontOfSize:8.0] familyName] ==> .AppleSystemUIFont -// [[NSFont fontWithName:[[[NSFont menuFontOfSize:8.0] fontDescriptor] -// postscriptName] -// size:8.0] familyName] ==> .SF NS Text - -static NSString* GetRealFamilyName(NSFont* aFont) { - NSString* psName = [[aFont fontDescriptor] postscriptName]; - // With newer macOS versions and SDKs (e.g. when compiled against SDK 10.15), - // [NSFont fontWithName:] fails for hidden system fonts, because the - // underlying Core Text functions it uses reject such names and tell us to use - // the special CTFontCreateUIFontForLanguage API instead. To work around this, - // as we don't yet work directly with the CTFontUIFontType identifiers, we - // create a Core Graphics font (as it doesn't reject system font names), and - // use this to create a Core Text font that we can query for the family name. - // Eventually we should move to using CTFontUIFontType constants to identify - // system fonts, and eliminate the need to instantiate them (indirectly) from - // their postscript names. - AutoCFRelease<CGFontRef> cgFont = - CGFontCreateWithFontName(CFStringRef(psName)); - if (!cgFont) { - return [aFont familyName]; - } - - AutoCFRelease<CTFontRef> ctFont = - CTFontCreateWithGraphicsFont(cgFont, 0.0, nullptr, nullptr); - if (!ctFont) { - return [aFont familyName]; - } - NSString* familyName = (NSString*)CTFontCopyFamilyName(ctFont); - - return [familyName autorelease]; -} - -void gfxMacPlatformFontList::InitSystemFontNames() { - // text font family - NSFont* sys = [NSFont systemFontOfSize:0.0]; - NSString* textFamilyName = GetRealFamilyName(sys); - nsAutoString familyName; - nsCocoaUtils::GetStringForNSString(textFamilyName, familyName); - CopyUTF16toUTF8(familyName, mSystemFontFamilyName); - - // We store an in-process gfxFontFamily for the system font even if using the - // shared fontlist to manage "normal" fonts, because the hidden system fonts - // may be excluded from the font list altogether. This family will be - // populated based on the given NSFont. - RefPtr<gfxFontFamily> fam = new gfxMacFontFamily(mSystemFontFamilyName, sys); - if (fam) { - nsAutoCString key; - GenerateFontListKey(mSystemFontFamilyName, key); - mFontFamilies.InsertOrUpdate(key, std::move(fam)); - } - -#ifdef DEBUG - // different system font API's always map to the same family under OSX, so - // just assume that and emit a warning if that ever changes - NSString* sysFamily = GetRealFamilyName([NSFont systemFontOfSize:0.0]); - if ([sysFamily compare:GetRealFamilyName([NSFont - boldSystemFontOfSize:0.0])] != NSOrderedSame || - [sysFamily compare:GetRealFamilyName([NSFont - controlContentFontOfSize:0.0])] != NSOrderedSame || - [sysFamily compare:GetRealFamilyName([NSFont menuBarFontOfSize:0.0])] != - NSOrderedSame || - [sysFamily compare:GetRealFamilyName([NSFont toolTipsFontOfSize:0.0])] != - NSOrderedSame) { - NS_WARNING("system font types map to different font families" - " -- please log a bug!!"); - } -#endif -} - -FontFamily gfxMacPlatformFontList::GetDefaultFontForPlatform( - nsPresContext* aPresContext, const gfxFontStyle* aStyle, - nsAtom* aLanguage) { - nsAutoreleasePool localPool; - - NSString* defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName]; - nsAutoString familyName; - - GetStringForNSString(defaultFamily, familyName); - return FindFamily(aPresContext, NS_ConvertUTF16toUTF8(familyName)); -} - void gfxMacPlatformFontList::LookupSystemFont(LookAndFeel::FontID aSystemFontID, nsACString& aSystemFontName, gfxFontStyle& aFontStyle) { diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index ccc76def7e..c57564b054 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -21,8 +21,8 @@ #include "mozilla/gfx/gfxVars.h" #include "mozilla/gfx/GPUProcessManager.h" #include "mozilla/gfx/GraphicsMessages.h" -#include "mozilla/gfx/CanvasManagerChild.h" #include "mozilla/gfx/CanvasRenderThread.h" +#include "mozilla/gfx/CanvasShutdownManager.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/DebugOnly.h" #include "mozilla/EnumTypeTraits.h" @@ -79,7 +79,7 @@ #if defined(XP_WIN) # include "gfxWindowsPlatform.h" # include "mozilla/widget/WinWindowOcclusionTracker.h" -#elif defined(XP_MACOSX) +#elif defined(XP_DARWIN) # include "gfxPlatformMac.h" # include "gfxQuartzSurface.h" #elif defined(MOZ_WIDGET_GTK) @@ -289,9 +289,8 @@ void CrashStatsLogForwarder::UpdateCrashReport() { << " (t=" << std::get<2>(it) << ") "; } - nsCString reportString(message.str().c_str()); - nsresult annotated = - CrashReporter::AnnotateCrashReport(mCrashCriticalKey, reportString); + nsresult annotated = CrashReporter::RecordAnnotationCString( + mCrashCriticalKey, message.str().c_str()); if (annotated != NS_OK) { printf("Crash Annotation %s: %s", @@ -409,7 +408,7 @@ void CrashStatsLogForwarder::CrashAction(LogReason aReason) { #define GFX_PREF_WORD_CACHE_MAXENTRIES "gfx.font_rendering.wordcache.maxentries" #define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled" -#if defined(XP_MACOSX) +#if defined(XP_DARWIN) # define GFX_PREF_CORETEXT_SHAPING "gfx.font_rendering.coretext.enabled" #endif @@ -786,7 +785,7 @@ bool gfxPlatform::HasVariationFontSupport() { // as any thread will set it to the same value. #if defined(XP_WIN) sHasVariationFontSupport = gfxWindowsPlatform::CheckVariationFontSupport(); -#elif defined(XP_MACOSX) +#elif defined(XP_DARWIN) sHasVariationFontSupport = gfxPlatformMac::CheckVariationFontSupport(); #elif defined(MOZ_WIDGET_GTK) sHasVariationFontSupport = gfxPlatformGtk::CheckVariationFontSupport(); @@ -904,7 +903,7 @@ void gfxPlatform::Init() { #if defined(XP_WIN) gPlatform = new gfxWindowsPlatform; -#elif defined(XP_MACOSX) +#elif defined(XP_DARWIN) gPlatform = new gfxPlatformMac; #elif defined(MOZ_WIDGET_GTK) gPlatform = new gfxPlatformGtk; @@ -1069,6 +1068,15 @@ void gfxPlatform::ReportTelemetry() { nsString adapterDesc; gfxInfo->GetAdapterDescription(adapterDesc); + +// Android description is constructed in a way that makes it possible to exceed +// the metric's length limit. +#if defined(ANDROID) + if (!adapterDesc.IsEmpty()) { + adapterDesc.Truncate(99); + } +#endif + mozilla::glean::gfx_adapter_primary::description.Set( NS_ConvertUTF16toUTF8(adapterDesc)); @@ -1335,7 +1343,7 @@ void gfxPlatform::ShutdownLayersIPC() { if (XRE_IsContentProcess()) { gfx::VRManagerChild::ShutDown(); - gfx::CanvasManagerChild::Shutdown(); + gfx::CanvasShutdownManager::Shutdown(); // cf bug 1215265. if (StaticPrefs::layers_child_process_shutdown()) { layers::CompositorManagerChild::Shutdown(); @@ -1346,7 +1354,7 @@ void gfxPlatform::ShutdownLayersIPC() { VideoBridgeParent::Shutdown(); RDDProcessManager::RDDProcessShutdown(); gfx::VRManagerChild::ShutDown(); - gfx::CanvasManagerChild::Shutdown(); + gfx::CanvasShutdownManager::Shutdown(); layers::CompositorManagerChild::Shutdown(); layers::ImageBridgeChild::ShutDown(); // This could be running on either the Compositor thread, the Renderer @@ -2273,7 +2281,7 @@ void gfxPlatform::FontsPrefsChanged(const char* aPref) { !strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) { FlushFontAndWordCaches(); } else if ( -#if defined(XP_MACOSX) +#if defined(XP_DARWIN) !strcmp(GFX_PREF_CORETEXT_SHAPING, aPref) || #endif !strcmp("gfx.font_rendering.ahem_antialias_none", aPref)) { @@ -2693,7 +2701,7 @@ void gfxPlatform::InitWebRenderConfig() { StaticPrefs::GetPrefName_gfx_webrender_batched_upload_threshold())); if (WebRenderResourcePathOverride()) { - CrashReporter::AnnotateCrashReport( + CrashReporter::RecordAnnotationBool( CrashReporter::Annotation::IsWebRenderResourcePathOverridden, true); } @@ -2740,7 +2748,7 @@ void gfxPlatform::InitWebRenderConfig() { "FEATURE_FAILURE_WR_NO_GFX_INFO"_ns); useVideoHwOverlay = false; } else { - if (status != nsIGfxInfo::FEATURE_ALLOW_ALWAYS) { + if (status != nsIGfxInfo::FEATURE_STATUS_OK) { FeatureState& feature = gfxConfig::GetFeature(Feature::VIDEO_HARDWARE_OVERLAY); feature.DisableByDefault(FeatureStatus::Blocked, @@ -2897,6 +2905,49 @@ void gfxPlatform::InitWebRenderConfig() { } #endif + bool allowOverlayVpAutoHDR = false; + if (StaticPrefs::gfx_webrender_overlay_vp_auto_hdr_AtStartup()) { + allowOverlayVpAutoHDR = true; + + nsCString failureId; + int32_t status; + const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service(); + if (NS_FAILED(gfxInfo->GetFeatureStatus( + nsIGfxInfo::FEATURE_OVERLAY_VP_AUTO_HDR, failureId, &status))) { + allowOverlayVpAutoHDR = false; + } else { + if (status != nsIGfxInfo::FEATURE_STATUS_OK) { + allowOverlayVpAutoHDR = false; + } + } + } + + if (allowOverlayVpAutoHDR) { + gfxVars::SetWebRenderOverlayVpAutoHDR(true); + } + + bool allowOverlayVpSuperResolution = false; + if (StaticPrefs::gfx_webrender_overlay_vp_super_resolution_AtStartup()) { + allowOverlayVpSuperResolution = true; + + nsCString failureId; + int32_t status; + const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service(); + if (NS_FAILED(gfxInfo->GetFeatureStatus( + nsIGfxInfo::FEATURE_OVERLAY_VP_SUPER_RESOLUTION, failureId, + &status))) { + allowOverlayVpSuperResolution = false; + } else { + if (status != nsIGfxInfo::FEATURE_STATUS_OK) { + allowOverlayVpSuperResolution = false; + } + } + } + + if (allowOverlayVpSuperResolution) { + gfxVars::SetWebRenderOverlayVpSuperResolution(true); + } + if (gfxConfig::IsEnabled(Feature::WEBRENDER_COMPOSITOR)) { gfxVars::SetUseWebRenderCompositor(true); } diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp index 709a0f3c27..bc0e123f85 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -378,6 +378,40 @@ gfxPlatformFontList::~gfxPlatformFontList() { NS_RELEASE(gFontListPrefObserver); } +void gfxPlatformFontList::GetMissingFonts(nsCString& aMissingFonts) { + AutoLock lock(mLock); + + auto fontLists = GetFilteredPlatformFontLists(); + + if (!fontLists.Length()) { + aMissingFonts.Append("No font list available for this device."); + } + + for (unsigned int i = 0; i < fontLists.Length(); i++) { + for (unsigned int j = 0; j < fontLists[i].second; j++) { + nsCString key(fontLists[i].first[j]); + GenerateFontListKey(key); + + if (SharedFontList()) { + fontlist::Family* family = SharedFontList()->FindFamily(key); + if (!family) { + aMissingFonts.Append(fontLists[i].first[j]); + aMissingFonts.Append("|"); + } + } else { + gfxFontFamily* familyEntry = mFontFamilies.GetWeak(key); + if (!familyEntry) { + familyEntry = mOtherFamilyNames.GetWeak(key); + } + if (!familyEntry) { + aMissingFonts.Append(fontLists[i].first[j]); + aMissingFonts.Append("|"); + } + } + } + } +} + /* static */ void gfxPlatformFontList::FontWhitelistPrefChanged(const char* aPref, void* aClosure) { @@ -700,6 +734,10 @@ void gfxPlatformFontList::GenerateFontListKey(const nsACString& aKeyName, ToLowerCase(aResult); } +void gfxPlatformFontList::GenerateFontListKey(nsACString& aKeyName) { + ToLowerCase(aKeyName); +} + // Used if a stylo thread wants to trigger InitOtherFamilyNames in the main // process: we can't do IPC from the stylo thread so we post this to the main // thread instead. @@ -755,7 +793,7 @@ bool gfxPlatformFontList::InitOtherFamilyNames( // (This is used so we can reliably run reftests that depend on localized // font-family names being available.) if (aDeferOtherFamilyNamesLoading && - StaticPrefs::gfx_font_loader_delay_AtStartup() > 0) { + StaticPrefs::gfx_font_loader_delay() > 0) { if (!mPendingOtherFamilyNameTask) { RefPtr<mozilla::CancelableRunnable> task = new InitOtherFamilyNamesRunnable(); @@ -2648,7 +2686,7 @@ bool gfxPlatformFontList::LoadFontInfo() { // Limit the time spent reading fonts in one pass, unless the font-loader // delay was set to zero, in which case we run to completion even if it // causes some jank. - if (StaticPrefs::gfx_font_loader_delay_AtStartup() > 0) { + if (StaticPrefs::gfx_font_loader_delay() > 0) { TimeDuration elapsed = TimeStamp::Now() - start; if (elapsed.ToMilliseconds() > FONT_LOADER_MAX_TIMESLICE && i + 1 != endIndex) { @@ -2751,7 +2789,7 @@ void gfxPlatformFontList::GetPrefsAndStartLoader() { if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) { return; } - uint32_t delay = std::max(1u, StaticPrefs::gfx_font_loader_delay_AtStartup()); + uint32_t delay = std::max(1u, StaticPrefs::gfx_font_loader_delay()); if (NS_IsMainThread()) { StartLoader(delay); } else { diff --git a/gfx/thebes/gfxPlatformFontList.h b/gfx/thebes/gfxPlatformFontList.h index 4d5b9e4015..3ab74c5f74 100644 --- a/gfx/thebes/gfxPlatformFontList.h +++ b/gfx/thebes/gfxPlatformFontList.h @@ -245,6 +245,8 @@ class gfxPlatformFontList : public gfxFontInfoLoader { return sPlatformFontList; } + void GetMissingFonts(nsCString& aMissingFonts); + static bool Initialize(gfxPlatformFontList* aList); static void Shutdown() { @@ -658,6 +660,9 @@ class gfxPlatformFontList : public gfxFontInfoLoader { mutable mozilla::RecursiveMutex mLock; protected: + virtual nsTArray<std::pair<const char**, uint32_t>> + GetFilteredPlatformFontLists() = 0; + friend class mozilla::fontlist::FontList; friend class InitOtherFamilyNamesForStylo; @@ -867,7 +872,10 @@ class gfxPlatformFontList : public gfxFontInfoLoader { // load the bad underline blocklist from pref. void LoadBadUnderlineList(); + // This version of the function will not modify aKeyName void GenerateFontListKey(const nsACString& aKeyName, nsACString& aResult); + // This version of the function WILL modify aKeyName + void GenerateFontListKey(nsACString& aKeyName); virtual void GetFontFamilyNames(nsTArray<nsCString>& aFontFamilyNames) MOZ_REQUIRES(mLock); @@ -1010,13 +1018,14 @@ class gfxPlatformFontList : public gfxFontInfoLoader { // When system-wide font lookup fails for a character, cache it to skip future // searches. This is an array of bitsets, one for each FontVisibility level. - mozilla::EnumeratedArray<FontVisibility, FontVisibility::Count, - gfxSparseBitSet> + mozilla::EnumeratedArray<FontVisibility, gfxSparseBitSet, + size_t(FontVisibility::Count)> mCodepointsWithNoFonts MOZ_GUARDED_BY(mLock); // the family to use for U+FFFD fallback, to avoid expensive search every time // on pages with lots of problems - mozilla::EnumeratedArray<FontVisibility, FontVisibility::Count, FontFamily> + mozilla::EnumeratedArray<FontVisibility, FontFamily, + size_t(FontVisibility::Count)> mReplacementCharFallbackFamily MOZ_GUARDED_BY(mLock); // Sorted array of lowercased family names; use ContainsSorted to test diff --git a/gfx/thebes/gfxPlatformMac.cpp b/gfx/thebes/gfxPlatformMac.cpp index 02ec1a7b28..091b0dff28 100644 --- a/gfx/thebes/gfxPlatformMac.cpp +++ b/gfx/thebes/gfxPlatformMac.cpp @@ -9,7 +9,6 @@ #include "mozilla/DataMutex.h" #include "mozilla/gfx/2D.h" -#include "gfxMacPlatformFontList.h" #include "gfxMacFont.h" #include "gfxCoreTextShaper.h" #include "gfxTextRun.h" @@ -20,7 +19,9 @@ #include "nsTArray.h" #include "mozilla/Preferences.h" #include "mozilla/VsyncDispatcher.h" -#include "nsCocoaFeatures.h" +#ifdef MOZ_WIDGET_COCOA +# include "nsCocoaFeatures.h" +#endif #include "nsComponentManagerUtils.h" #include "nsIFile.h" #include "nsUnicodeProperties.h" @@ -48,6 +49,14 @@ using namespace mozilla::unicode; using mozilla::dom::SystemFontList; +#ifdef MOZ_WIDGET_COCOA +# include "gfxMacPlatformFontList.h" +using PlatformFontListClass = gfxMacPlatformFontList; +#else +# include "IOSPlatformFontList.h" +using PlatformFontListClass = IOSPlatformFontList; +#endif + // A bunch of fonts for "additional language support" are shipped in a // "Language Support" directory, and don't show up in the standard font // list returned by CTFontManagerCopyAvailableFontFamilyNames unless @@ -62,7 +71,7 @@ void gfxPlatformMac::FontRegistrationCallback(void* aUnused) { PR_SetCurrentThreadName("RegisterFonts"); for (const auto& dir : kLangFontsDirs) { - gfxMacPlatformFontList::ActivateFontsFromDir(dir); + PlatformFontListClass::ActivateFontsFromDir(dir); } } @@ -111,11 +120,11 @@ BackendPrefsData gfxPlatformMac::GetBackendPrefs() const { } bool gfxPlatformMac::CreatePlatformFontList() { - return gfxPlatformFontList::Initialize(new gfxMacPlatformFontList); + return gfxPlatformFontList::Initialize(new PlatformFontListClass); } void gfxPlatformMac::ReadSystemFontList(SystemFontList* aFontList) { - gfxMacPlatformFontList::PlatformFontList()->ReadSystemFontList(aFontList); + PlatformFontListClass::PlatformFontList()->ReadSystemFontList(aFontList); } already_AddRefed<gfxASurface> gfxPlatformMac::CreateOffscreenSurface( @@ -668,8 +677,8 @@ void gfxPlatformMac::GetCommonFallbackFonts(uint32_t aCh, Script aRunScript, void gfxPlatformMac::LookupSystemFont( mozilla::LookAndFeel::FontID aSystemFontID, nsACString& aSystemFontName, gfxFontStyle& aFontStyle) { - return gfxMacPlatformFontList::LookupSystemFont(aSystemFontID, - aSystemFontName, aFontStyle); + return PlatformFontListClass::LookupSystemFont(aSystemFontID, aSystemFontName, + aFontStyle); } uint32_t gfxPlatformMac::ReadAntiAliasingThreshold() { @@ -700,6 +709,7 @@ uint32_t gfxPlatformMac::ReadAntiAliasingThreshold() { bool gfxPlatformMac::AccelerateLayersByDefault() { return true; } +#ifdef MOZ_WIDGET_COCOA // This is the renderer output callback function, called on the vsync thread static CVReturn VsyncCallback(CVDisplayLinkRef aDisplayLink, const CVTimeStamp* aNow, @@ -934,9 +944,11 @@ static CVReturn VsyncCallback(CVDisplayLinkRef aDisplayLink, vsyncSource->NotifyVsync(previousVsync, outputTime); return kCVReturnSuccess; } +#endif already_AddRefed<mozilla::gfx::VsyncSource> gfxPlatformMac::CreateGlobalHardwareVsyncSource() { +#ifdef MOZ_WIDGET_COCOA RefPtr<VsyncSource> osxVsyncSource = new OSXVsyncSource(); osxVsyncSource->EnableVsync(); if (!osxVsyncSource->IsVsyncEnabled()) { @@ -947,6 +959,10 @@ gfxPlatformMac::CreateGlobalHardwareVsyncSource() { osxVsyncSource->DisableVsync(); return osxVsyncSource.forget(); +#else + // TODO: CADisplayLink + return GetSoftwareVsyncSource(); +#endif } bool gfxPlatformMac::SupportsHDR() { @@ -958,8 +974,10 @@ bool gfxPlatformMac::SupportsHDR() { return false; } +#ifdef MOZ_WIDGET_UIKIT + return false; +#elif defined(EARLY_BETA_OR_EARLIER) // Screen is capable. Is the OS capable? -#ifdef EARLY_BETA_OR_EARLIER // More-or-less supported in Catalina. return true; #else @@ -974,7 +992,10 @@ nsTArray<uint8_t> gfxPlatformMac::GetPlatformCMSOutputProfileData() { return prefProfileData; } - CGColorSpaceRef cspace = ::CGDisplayCopyColorSpace(::CGMainDisplayID()); + CGColorSpaceRef cspace = nil; +#ifdef MOZ_WIDGET_COCOA + cspace = ::CGDisplayCopyColorSpace(::CGMainDisplayID()); +#endif if (!cspace) { cspace = ::CGColorSpaceCreateDeviceRGB(); } diff --git a/gfx/thebes/gfxQuartzSurface.h b/gfx/thebes/gfxQuartzSurface.h index fbc081197b..cb5e54c80b 100644 --- a/gfx/thebes/gfxQuartzSurface.h +++ b/gfx/thebes/gfxQuartzSurface.h @@ -10,7 +10,11 @@ #include "nsSize.h" #include "gfxPoint.h" -#include <Carbon/Carbon.h> +#ifdef MOZ_WIDGET_COCOA +# include <Carbon/Carbon.h> +#else +# include <CoreGraphics/CoreGraphics.h> +#endif class gfxContext; class gfxImageSurface; diff --git a/gfx/thebes/gfxUserFontSet.cpp b/gfx/thebes/gfxUserFontSet.cpp index aeaf296200..e9a2f513b3 100644 --- a/gfx/thebes/gfxUserFontSet.cpp +++ b/gfx/thebes/gfxUserFontSet.cpp @@ -492,38 +492,54 @@ void gfxUserFontEntry::DoLoadNextSrc(bool aIsContinue) { else if (currSrc.mSourceType == gfxFontFaceSrc::eSourceType_URL) { if (gfxPlatform::GetPlatform()->IsFontFormatSupported( currSrc.mFormatHint, currSrc.mTechFlags)) { - if (ServoStyleSet* set = gfxFontUtils::CurrentServoStyleSet()) { - // Only support style worker threads synchronously getting - // entries from the font cache when it's not a data: URI - // @font-face that came from UA or user sheets, since we - // were not able to call IsFontLoadAllowed ahead of time - // for these entries. - if (currSrc.mUseOriginPrincipal && IgnorePrincipal(currSrc.mURI)) { - set->AppendTask(PostTraversalTask::LoadFontEntry(this)); - SetLoadState(STATUS_LOAD_PENDING); - return; + // TODO(emilio): Make UserFontCache thread-safe maybe? But we need to + // potentially do CSP checks so maybe not trivial. + const bool canCheckCache = [&] { + if (NS_IsMainThread()) { + return true; } - } + if (gfxFontUtils::CurrentServoStyleSet()) { + // Only support style worker threads synchronously getting entries + // from the font cache when it's not a data: URI @font-face that + // came from UA or user sheets, since we were not able to call + // IsFontLoadAllowed ahead of time for these entries. + return !currSrc.mUseOriginPrincipal || + !IgnorePrincipal(currSrc.mURI); + } + return false; + }(); // see if we have an existing entry for this source - gfxFontEntry* fe = - gfxUserFontSet::UserFontCache::GetFont(currSrc, *this); - if (fe) { - mPlatformFontEntry = fe; - SetLoadState(STATUS_LOADED); - LOG( - ("userfonts (%p) [src %d] " - "loaded uri from cache: (%s) for (%s)\n", - fontSet.get(), mCurrentSrcIndex, - currSrc.mURI->GetSpecOrDefault().get(), mFamilyName.get())); - return; + if (canCheckCache) { + gfxFontEntry* fe = + gfxUserFontSet::UserFontCache::GetFont(currSrc, *this); + if (fe) { + mPlatformFontEntry = fe; + SetLoadState(STATUS_LOADED); + LOG( + ("userfonts (%p) [src %d] " + "loaded uri from cache: (%s) for (%s)\n", + fontSet.get(), mCurrentSrcIndex, + currSrc.mURI->GetSpecOrDefault().get(), mFamilyName.get())); + return; + } } if (ServoStyleSet* set = gfxFontUtils::CurrentServoStyleSet()) { // If we need to start a font load and we're on a style // worker thread, we have to defer it. + SetLoadState(STATUS_LOAD_PENDING); set->AppendTask(PostTraversalTask::LoadFontEntry(this)); + return; + } + + if (dom::IsCurrentThreadRunningWorker()) { + // TODO: Maybe support loading the font entry in workers, at least for + // buffers or other sync sources? SetLoadState(STATUS_LOAD_PENDING); + NS_DispatchToMainThread( + NewRunnableMethod("gfxUserFontEntry::ContinueLoad", this, + &gfxUserFontEntry::ContinueLoad)); return; } @@ -551,9 +567,9 @@ void gfxUserFontEntry::DoLoadNextSrc(bool aIsContinue) { fontSet->LogMessage(this, mCurrentSrcIndex, "font load failed", nsIScriptError::errorFlag, rv); } else if (!aIsContinue) { - RefPtr<nsIRunnable> runnable = NS_NewRunnableFunction( - "gfxUserFontSet::AsyncContinueLoad", - [loader = RefPtr{this}] { loader->ContinueLoad(); }); + RefPtr<nsIRunnable> runnable = + NewRunnableMethod("gfxUserFontEntry::ContinueLoad", this, + &gfxUserFontEntry::ContinueLoad); SetLoadState(STATUS_LOAD_PENDING); // We don't want to trigger the channel open at random points in // time, because it can run privileged JS. @@ -817,13 +833,6 @@ void gfxUserFontEntry::Load() { if (mUserFontLoadState != STATUS_NOT_LOADED) { return; } - if (dom::IsCurrentThreadRunningWorker()) { - // TODO: Maybe support loading the font entry in workers, at least for - // buffers or other sync sources? - NS_DispatchToMainThread(NewRunnableMethod("gfxUserFontEntry::Load", this, - &gfxUserFontEntry::Load)); - return; - } LoadNextSrc(); } diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index e6994f8665..93de20f445 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -540,42 +540,38 @@ void gfxWindowsPlatform::UpdateSupportsHDR() { return; } - // Set mSupportsHDR to true if any of the DeviceManager outputs have both: - // 1) greater than 8-bit color - // 2) a colorspace that uses BT2020 + // Set mSupportsHDR to true if any of the DeviceManager outputs have a BT2020 + // colorspace with EOTF2084 gamma curve, this indicates the system is sending + // an HDR format to at least one monitor. The colorspace returned by DXGI is + // very vague - we only see DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 for HDR + // and DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 for SDR modes, even if the + // monitor is using something like YCbCr444 according to Settings + // (System -> Display Settings -> Advanced Display). To get more specific + // info we would need to query the DISPLAYCONFIG values in WinGDI. + // + // Note that the bit depth used to be checked here, but as of Windows 11 22H2, + // HDR is supported with 8bpc for lower bandwidth, where DWM converts to + // dithered RGB8 rather than RGB10, which doesn't really matter here. + // + // This only returns true if there is an HDR display connected at app start, + // if the user switches to HDR to watch a video, we won't know that here, and + // if no displays are connected we return false (e.g. if Windows Update + // restarted a laptop with its lid closed and no external displays, we will + // see zero outputs here when the app is restarted automatically). + // + // It would be better to track if HDR is ever used and report that telemetry + // so we know if HDR matters, not just when it is detected at app start. + // + // Further reading: + // https://learn.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range + // https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-displayconfig_sdr_white_level DeviceManagerDx* dx = DeviceManagerDx::Get(); nsTArray<DXGI_OUTPUT_DESC1> outputs = dx->EnumerateOutputs(); for (auto& output : outputs) { - if (output.BitsPerColor <= 8) { - continue; - } - - switch (output.ColorSpace) { - case DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020: - case DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020: - case DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020: - case DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020: - case DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020: - case DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020: - case DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_TOPLEFT_P2020: - case DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020: - case DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020: - case DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020: - case DXGI_COLOR_SPACE_YCBCR_FULL_GHLG_TOPLEFT_P2020: -#ifndef __MINGW32__ - // Windows MinGW has an older dxgicommon.h that doesn't define - // these enums. We'd like to define them ourselves in that case, - // but there's no compilable way to add new enums to an existing - // enum type. So instead we just don't check for these values. - case DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P2020: - case DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P2020: - case DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_TOPLEFT_P2020: -#endif - mSupportsHDR = true; - return; - default: - break; + if (output.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) { + mSupportsHDR = true; + return; } } diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index fd1fcf236d..3d99906827 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -96,16 +96,13 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "android": "gfxFT2Utils.cpp", "PrintTargetPDF.cpp", ] -elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa": +elif CONFIG["MOZ_WIDGET_TOOLKIT"] in ("cocoa", "uikit"): EXPORTS += [ "gfxMacUtils.h", "gfxPlatformMac.h", "gfxQuartzNativeDrawing.h", "gfxQuartzSurface.h", ] - EXPORTS.mozilla.gfx += [ - "PrintTargetCG.h", - ] SOURCES += [ "CoreTextFontList.cpp", "gfxCoreTextShaper.cpp", @@ -114,8 +111,14 @@ elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa": "gfxPlatformMac.cpp", "gfxQuartzNativeDrawing.cpp", "gfxQuartzSurface.cpp", - "PrintTargetCG.mm", ] + if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa": + EXPORTS.mozilla.gfx += [ + "PrintTargetCG.h", + ] + SOURCES += [ + "PrintTargetCG.mm", + ] elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk": EXPORTS += [ "gfxFT2FontBase.h", @@ -239,6 +242,10 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa": UNIFIED_SOURCES += [ "gfxMacPlatformFontList.mm", ] +elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "uikit": + UNIFIED_SOURCES += [ + "IOSPlatformFontList.mm", + ] elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows": UNIFIED_SOURCES += [ "D3D11Checks.cpp", diff --git a/gfx/vr/ipc/VRProcessManager.cpp b/gfx/vr/ipc/VRProcessManager.cpp index f3bc13bac0..440d50546c 100644 --- a/gfx/vr/ipc/VRProcessManager.cpp +++ b/gfx/vr/ipc/VRProcessManager.cpp @@ -87,8 +87,8 @@ void VRProcessManager::DestroyProcess() { mProcess = nullptr; mVRChild = nullptr; - CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::VRProcessStatus, - "Destroyed"_ns); + CrashReporter::RecordAnnotationCString( + CrashReporter::Annotation::VRProcessStatus, "Destroyed"); } bool VRProcessManager::EnsureVRReady() { @@ -134,8 +134,8 @@ void VRProcessManager::OnProcessLaunchComplete(VRProcessParent* aParent) { } mQueuedPrefs.Clear(); - CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::VRProcessStatus, - "Running"_ns); + CrashReporter::RecordAnnotationCString( + CrashReporter::Annotation::VRProcessStatus, "Running"); } void VRProcessManager::OnProcessUnexpectedShutdown(VRProcessParent* aParent) { diff --git a/gfx/webrender_bindings/Cargo.toml b/gfx/webrender_bindings/Cargo.toml index f6b3fd637f..0f0c069e87 100644 --- a/gfx/webrender_bindings/Cargo.toml +++ b/gfx/webrender_bindings/Cargo.toml @@ -33,7 +33,7 @@ features = ["capture", "serialize_program", "gecko", "sw_compositor"] dwrote = "0.11" winapi = "0.3" -[target.'cfg(target_os = "macos")'.dependencies] +[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] core-foundation = "0.9" core-graphics = "0.23" foreign-types = "0.5.0" diff --git a/gfx/webrender_bindings/DCLayerTree.cpp b/gfx/webrender_bindings/DCLayerTree.cpp index eee5601182..177979a466 100644 --- a/gfx/webrender_bindings/DCLayerTree.cpp +++ b/gfx/webrender_bindings/DCLayerTree.cpp @@ -1178,6 +1178,126 @@ void DCSurfaceVideo::AttachExternalImage(wr::ExternalImageId aExternalImage) { mRenderTextureHost = texture; } +static UINT GetVendorId(ID3D11VideoDevice* const aVideoDevice) { + RefPtr<IDXGIDevice> dxgiDevice; + RefPtr<IDXGIAdapter> adapter; + aVideoDevice->QueryInterface((IDXGIDevice**)getter_AddRefs(dxgiDevice)); + dxgiDevice->GetAdapter(getter_AddRefs(adapter)); + + DXGI_ADAPTER_DESC adapterDesc; + adapter->GetDesc(&adapterDesc); + + return adapterDesc.VendorId; +} + +static HRESULT SetNvidiaVpSuperResolution(ID3D11VideoContext* aVideoContext, + ID3D11VideoProcessor* aVideoProcessor, + bool aEnable) { + LOG("SetNvidiaVpSuperResolution() aEnable=%d", aEnable); + + // Undocumented NVIDIA driver constants + constexpr GUID nvGUID = {0xD43CE1B3, + 0x1F4B, + 0x48AC, + {0xBA, 0xEE, 0xC3, 0xC2, 0x53, 0x75, 0xE6, 0xF7}}; + + constexpr UINT nvExtensionVersion = 0x1; + constexpr UINT nvExtensionMethodSuperResolution = 0x2; + struct { + UINT version; + UINT method; + UINT enable; + } streamExtensionInfo = {nvExtensionVersion, nvExtensionMethodSuperResolution, + aEnable ? 1u : 0}; + + HRESULT hr; + hr = aVideoContext->VideoProcessorSetStreamExtension( + aVideoProcessor, 0, &nvGUID, sizeof(streamExtensionInfo), + &streamExtensionInfo); + return hr; +} + +static HRESULT SetVpSuperResolution(UINT aGpuVendorId, + ID3D11VideoContext* aVideoContext, + ID3D11VideoProcessor* aVideoProcessor, + bool aEnable) { + MOZ_ASSERT(aVideoContext); + MOZ_ASSERT(aVideoProcessor); + + if (aGpuVendorId == 0x10DE) { + return SetNvidiaVpSuperResolution(aVideoContext, aVideoProcessor, aEnable); + } + return E_NOTIMPL; +} + +static bool GetNvidiaRTXVideoTrueHDRSupported( + ID3D11VideoContext* aVideoContext, ID3D11VideoProcessor* aVideoProcessor) { + const GUID kNvidiaTrueHDRInterfaceGUID = { + 0xfdd62bb4, + 0x620b, + 0x4fd7, + {0x9a, 0xb3, 0x1e, 0x59, 0xd0, 0xd5, 0x44, 0xb3}}; + UINT available = 0; + HRESULT hr = aVideoContext->VideoProcessorGetStreamExtension( + aVideoProcessor, 0, &kNvidiaTrueHDRInterfaceGUID, sizeof(available), + &available); + if (FAILED(hr)) { + return false; + } + + bool driverSupportsTrueHdr = (available == 1); + return driverSupportsTrueHdr; +} + +static HRESULT SetNvidiaRTXVideoTrueHDR(ID3D11VideoContext* aVideoContext, + ID3D11VideoProcessor* aVideoProcessor, + bool aEnable) { + constexpr GUID kNvidiaTrueHDRInterfaceGUID = { + 0xfdd62bb4, + 0x620b, + 0x4fd7, + {0x9a, 0xb3, 0x1e, 0x59, 0xd0, 0xd5, 0x44, 0xb3}}; + constexpr UINT kStreamExtensionMethodTrueHDR = 0x3; + const UINT TrueHDRVersion4 = 4; + struct { + UINT version; + UINT method; + UINT enable : 1; + UINT reserved : 31; + } streamExtensionInfo = {TrueHDRVersion4, kStreamExtensionMethodTrueHDR, + aEnable ? 1u : 0u, 0u}; + HRESULT hr = aVideoContext->VideoProcessorSetStreamExtension( + aVideoProcessor, 0, &kNvidiaTrueHDRInterfaceGUID, + sizeof(streamExtensionInfo), &streamExtensionInfo); + return hr; +} + +static bool GetVpAutoHDRSupported(UINT aGpuVendorId, + ID3D11VideoContext* aVideoContext, + ID3D11VideoProcessor* aVideoProcessor) { + MOZ_ASSERT(aVideoContext); + MOZ_ASSERT(aVideoProcessor); + + if (aGpuVendorId == 0x10DE) { + return GetNvidiaRTXVideoTrueHDRSupported(aVideoContext, aVideoProcessor); + } + return false; +} + +static HRESULT SetVpAutoHDR(UINT aGpuVendorId, + ID3D11VideoContext* aVideoContext, + ID3D11VideoProcessor* aVideoProcessor, + bool aEnable) { + MOZ_ASSERT(aVideoContext); + MOZ_ASSERT(aVideoProcessor); + + if (aGpuVendorId == 0x10DE) { + return SetNvidiaRTXVideoTrueHDR(aVideoContext, aVideoProcessor, aEnable); + } + MOZ_ASSERT_UNREACHABLE("Unexpected to be called"); + return E_NOTIMPL; +} + bool DCSurfaceVideo::CalculateSwapChainSize(gfx::Matrix& aTransform) { if (!mRenderTextureHost) { MOZ_ASSERT_UNREACHABLE("unexpected to be called"); @@ -1225,18 +1345,39 @@ bool DCSurfaceVideo::CalculateSwapChainSize(gfx::Matrix& aTransform) { transform = gfx::Matrix::Translation(aTransform.GetTranslation()); } - if (!mVideoSwapChain || mSwapChainSize != swapChainSize || mIsDRM != isDRM) { + if (!mDCLayerTree->EnsureVideoProcessor(mVideoSize, swapChainSize)) { + gfxCriticalNote << "EnsureVideoProcessor Failed"; + return false; + } + + MOZ_ASSERT(mDCLayerTree->GetVideoContext()); + MOZ_ASSERT(mDCLayerTree->GetVideoProcessor()); + + const UINT vendorId = GetVendorId(mDCLayerTree->GetVideoDevice()); + const bool driverSupportsTrueHDR = + GetVpAutoHDRSupported(vendorId, mDCLayerTree->GetVideoContext(), + mDCLayerTree->GetVideoProcessor()); + const bool contentIsHDR = false; // XXX for now, only non-HDR is supported. + const bool monitorIsHDR = gfx::DeviceManagerDx::Get()->SystemHDREnabled(); + const bool powerIsCharging = RenderThread::Get()->GetPowerIsCharging(); + + bool useVpAutoHDR = gfx::gfxVars::WebRenderOverlayVpAutoHDR() && + !contentIsHDR && monitorIsHDR && driverSupportsTrueHDR && + powerIsCharging && !mVpAutoHDRFailed; + + if (!mVideoSwapChain || mSwapChainSize != swapChainSize || mIsDRM != isDRM || + mUseVpAutoHDR != useVpAutoHDR) { needsToPresent = true; ReleaseDecodeSwapChainResources(); // Update mSwapChainSize before creating SwapChain mSwapChainSize = swapChainSize; mIsDRM = isDRM; - auto swapChainFormat = GetSwapChainFormat(); + auto swapChainFormat = GetSwapChainFormat(useVpAutoHDR); bool useYUVSwapChain = IsYUVSwapChainFormat(swapChainFormat); if (useYUVSwapChain) { // Tries to create YUV SwapChain - CreateVideoSwapChain(); + CreateVideoSwapChain(swapChainFormat); if (!mVideoSwapChain) { mFailedYuvSwapChain = true; ReleaseDecodeSwapChainResources(); @@ -1246,11 +1387,21 @@ bool DCSurfaceVideo::CalculateSwapChainSize(gfx::Matrix& aTransform) { } // Tries to create RGB SwapChain if (!mVideoSwapChain) { - CreateVideoSwapChain(); + CreateVideoSwapChain(swapChainFormat); + } + if (!mVideoSwapChain && useVpAutoHDR) { + mVpAutoHDRFailed = true; + gfxCriticalNoteOnce << "Failed to create video SwapChain for VpAutoHDR"; + + // Disable VpAutoHDR + useVpAutoHDR = false; + swapChainFormat = GetSwapChainFormat(useVpAutoHDR); + CreateVideoSwapChain(swapChainFormat); } } aTransform = transform; + mUseVpAutoHDR = useVpAutoHDR; return needsToPresent; } @@ -1270,8 +1421,7 @@ void DCSurfaceVideo::PresentVideo() { mVisual->SetContent(mVideoSwapChain); if (!CallVideoProcessorBlt()) { - auto swapChainFormat = GetSwapChainFormat(); - bool useYUVSwapChain = IsYUVSwapChainFormat(swapChainFormat); + bool useYUVSwapChain = IsYUVSwapChainFormat(mSwapChainFormat); if (useYUVSwapChain) { mFailedYuvSwapChain = true; ReleaseDecodeSwapChainResources(); @@ -1392,14 +1542,17 @@ void DCSurfaceVideo::PresentVideo() { } } -DXGI_FORMAT DCSurfaceVideo::GetSwapChainFormat() { +DXGI_FORMAT DCSurfaceVideo::GetSwapChainFormat(bool aUseVpAutoHDR) { + if (aUseVpAutoHDR) { + return DXGI_FORMAT_R16G16B16A16_FLOAT; + } if (mFailedYuvSwapChain || !mDCLayerTree->SupportsHardwareOverlays()) { return DXGI_FORMAT_B8G8R8A8_UNORM; } return mDCLayerTree->GetOverlayFormatForSDR(); } -bool DCSurfaceVideo::CreateVideoSwapChain() { +bool DCSurfaceVideo::CreateVideoSwapChain(DXGI_FORMAT aSwapChainFormat) { MOZ_ASSERT(mRenderTextureHost); mFirstPresent = true; @@ -1423,12 +1576,10 @@ bool DCSurfaceVideo::CreateVideoSwapChain() { return false; } - auto swapChainFormat = GetSwapChainFormat(); - DXGI_SWAP_CHAIN_DESC1 desc = {}; desc.Width = mSwapChainSize.width; desc.Height = mSwapChainSize.height; - desc.Format = swapChainFormat; + desc.Format = aSwapChainFormat; desc.Stereo = FALSE; desc.SampleDesc.Count = 1; desc.BufferCount = mSwapChainBufferCount; @@ -1436,7 +1587,7 @@ bool DCSurfaceVideo::CreateVideoSwapChain() { desc.Scaling = DXGI_SCALING_STRETCH; desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; desc.Flags = DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO; - if (IsYUVSwapChainFormat(swapChainFormat)) { + if (IsYUVSwapChainFormat(aSwapChainFormat)) { desc.Flags |= DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO; } if (mIsDRM) { @@ -1455,7 +1606,7 @@ bool DCSurfaceVideo::CreateVideoSwapChain() { return false; } - mSwapChainFormat = swapChainFormat; + mSwapChainFormat = aSwapChainFormat; return true; } @@ -1494,50 +1645,6 @@ static Maybe<DXGI_COLOR_SPACE_TYPE> GetSourceDXGIColorSpace( return GetSourceDXGIColorSpace(info.space, info.range); } -static void SetNvidiaVideoSuperRes(ID3D11VideoContext* videoContext, - ID3D11VideoProcessor* videoProcessor, - bool enabled) { - LOG("SetNvidiaVideoSuperRes() enabled=%d", enabled); - - // Undocumented NVIDIA driver constants - constexpr GUID nvGUID = {0xD43CE1B3, - 0x1F4B, - 0x48AC, - {0xBA, 0xEE, 0xC3, 0xC2, 0x53, 0x75, 0xE6, 0xF7}}; - - constexpr UINT nvExtensionVersion = 0x1; - constexpr UINT nvExtensionMethodSuperResolution = 0x2; - struct { - UINT version; - UINT method; - UINT enable; - } streamExtensionInfo = {nvExtensionVersion, nvExtensionMethodSuperResolution, - enabled ? 1u : 0}; - - HRESULT hr; - hr = videoContext->VideoProcessorSetStreamExtension( - videoProcessor, 0, &nvGUID, sizeof(streamExtensionInfo), - &streamExtensionInfo); - - // Ignore errors as could be unsupported - if (FAILED(hr)) { - LOG("SetNvidiaVideoSuperRes() error: %lx", hr); - return; - } -} - -static UINT GetVendorId(ID3D11VideoDevice* const videoDevice) { - RefPtr<IDXGIDevice> dxgiDevice; - RefPtr<IDXGIAdapter> adapter; - videoDevice->QueryInterface((IDXGIDevice**)getter_AddRefs(dxgiDevice)); - dxgiDevice->GetAdapter(getter_AddRefs(adapter)); - - DXGI_ADAPTER_DESC adapterDesc; - adapter->GetDesc(&adapterDesc); - - return adapterDesc.VendorId; -} - bool DCSurfaceVideo::CallVideoProcessorBlt() { MOZ_ASSERT(mRenderTextureHost); @@ -1576,11 +1683,6 @@ bool DCSurfaceVideo::CallVideoProcessorBlt() { } } - if (!mDCLayerTree->EnsureVideoProcessor(mVideoSize, mSwapChainSize)) { - gfxCriticalNote << "EnsureVideoProcessor Failed"; - return false; - } - RefPtr<IDXGISwapChain3> swapChain3; mVideoSwapChain->QueryInterface( (IDXGISwapChain3**)getter_AddRefs(swapChain3)); @@ -1609,6 +1711,13 @@ bool DCSurfaceVideo::CallVideoProcessorBlt() { IsYUVSwapChainFormat(mSwapChainFormat) ? inputColorSpace : DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; + + if (mUseVpAutoHDR) { + outputColorSpace = mSwapChainFormat == DXGI_FORMAT_R16G16B16A16_FLOAT + ? DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709 + : DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; + } + hr = swapChain3->SetColorSpace1(outputColorSpace); if (FAILED(hr)) { gfxCriticalNoteOnce << "SetColorSpace1 failed: " << gfx::hexa(hr); @@ -1679,9 +1788,24 @@ bool DCSurfaceVideo::CallVideoProcessorBlt() { } const UINT vendorId = GetVendorId(videoDevice); - if (vendorId == 0x10DE && - StaticPrefs::gfx_webrender_super_resolution_nvidia_AtStartup()) { - SetNvidiaVideoSuperRes(videoContext, videoProcessor, true); + const auto powerIsCharging = RenderThread::Get()->GetPowerIsCharging(); + if (gfx::gfxVars::WebRenderOverlayVpSuperResolution() && + !mVpSuperResolutionFailed && powerIsCharging) { + hr = SetVpSuperResolution(vendorId, videoContext, videoProcessor, true); + if (FAILED(hr)) { + if (hr != E_NOTIMPL) { + gfxCriticalNoteOnce << "SetVpSuperResolution failed: " << gfx::hexa(hr); + } + mVpSuperResolutionFailed = true; + } + } + + if (mUseVpAutoHDR) { + hr = SetVpAutoHDR(vendorId, videoContext, videoProcessor, true); + if (FAILED(hr)) { + gfxCriticalNoteOnce << "SetVpAutoHDR failed: " << gfx::hexa(hr); + mVpAutoHDRFailed = true; + } } hr = videoContext->VideoProcessorBlt(videoProcessor, mOutputView, 0, 1, @@ -1703,6 +1827,7 @@ void DCSurfaceVideo::ReleaseDecodeSwapChainResources() { ::CloseHandle(mSwapChainSurfaceHandle); mSwapChainSurfaceHandle = 0; } + mUseVpAutoHDR = false; } DCSurfaceHandle::DCSurfaceHandle(bool aIsOpaque, DCLayerTree* aDCLayerTree) diff --git a/gfx/webrender_bindings/DCLayerTree.h b/gfx/webrender_bindings/DCLayerTree.h index babd1112fb..6d3a611802 100644 --- a/gfx/webrender_bindings/DCLayerTree.h +++ b/gfx/webrender_bindings/DCLayerTree.h @@ -389,8 +389,8 @@ class DCSurfaceVideo : public DCSurface { protected: virtual ~DCSurfaceVideo(); - DXGI_FORMAT GetSwapChainFormat(); - bool CreateVideoSwapChain(); + DXGI_FORMAT GetSwapChainFormat(bool aUseVpAutoHDR); + bool CreateVideoSwapChain(DXGI_FORMAT aFormat); bool CallVideoProcessorBlt(); void ReleaseDecodeSwapChainResources(); @@ -409,6 +409,9 @@ class DCSurfaceVideo : public DCSurface { int mSlowPresentCount = 0; bool mFirstPresent = true; const UINT mSwapChainBufferCount; + bool mUseVpAutoHDR = false; + bool mVpAutoHDRFailed = false; + bool mVpSuperResolutionFailed = false; }; /** diff --git a/gfx/webrender_bindings/RenderCompositor.cpp b/gfx/webrender_bindings/RenderCompositor.cpp index 8dd6e8ff00..1712eca855 100644 --- a/gfx/webrender_bindings/RenderCompositor.cpp +++ b/gfx/webrender_bindings/RenderCompositor.cpp @@ -31,7 +31,7 @@ # include "mozilla/webrender/RenderCompositorNative.h" #endif -#ifdef XP_MACOSX +#ifdef XP_DARWIN # include "mozilla/webrender/RenderCompositorNative.h" #endif @@ -168,7 +168,7 @@ void wr_partial_present_compositor_set_buffer_damage_region( UniquePtr<RenderCompositor> RenderCompositor::Create( const RefPtr<widget::CompositorWidget>& aWidget, nsACString& aError) { if (aWidget->GetCompositorOptions().UseSoftwareWebRender()) { -#ifdef XP_MACOSX +#ifdef XP_DARWIN // Mac uses NativeLayerCA if (!gfxPlatform::IsHeadless()) { return RenderCompositorNativeSWGL::Create(aWidget, aError); @@ -216,7 +216,7 @@ UniquePtr<RenderCompositor> RenderCompositor::Create( #if defined(MOZ_WIDGET_ANDROID) // RenderCompositorOGL is not used on android return nullptr; -#elif defined(XP_MACOSX) +#elif defined(XP_DARWIN) // Mac uses NativeLayerCA return RenderCompositorNativeOGL::Create(aWidget, aError); #else diff --git a/gfx/webrender_bindings/RenderCompositorNative.cpp b/gfx/webrender_bindings/RenderCompositorNative.cpp index 81cafd1fd6..3b5a29948e 100644 --- a/gfx/webrender_bindings/RenderCompositorNative.cpp +++ b/gfx/webrender_bindings/RenderCompositorNative.cpp @@ -31,7 +31,7 @@ RenderCompositorNative::RenderCompositorNative( mNativeLayerRoot(GetWidget()->GetNativeLayerRoot()) { LOG("RenderCompositorNative::RenderCompositorNative()"); -#if defined(XP_MACOSX) || defined(MOZ_WAYLAND) +#if defined(XP_DARWIN) || defined(MOZ_WAYLAND) auto pool = RenderThread::Get()->SharedSurfacePool(); if (pool) { mSurfacePoolHandle = pool->GetHandleForGL(aGL); @@ -103,7 +103,7 @@ bool RenderCompositorNative::Resume() { return true; } inline layers::WebRenderCompositor RenderCompositorNative::CompositorType() const { if (gfx::gfxVars::UseWebRenderCompositor()) { -#if defined(XP_MACOSX) +#if defined(XP_DARWIN) return layers::WebRenderCompositor::CORE_ANIMATION; #elif defined(MOZ_WAYLAND) return layers::WebRenderCompositor::WAYLAND; @@ -123,7 +123,7 @@ bool RenderCompositorNative::ShouldUseNativeCompositor() { void RenderCompositorNative::GetCompositorCapabilities( CompositorCapabilities* aCaps) { RenderCompositor::GetCompositorCapabilities(aCaps); -#if defined(XP_MACOSX) +#if defined(XP_DARWIN) aCaps->supports_surface_for_backdrop = !gfx::gfxVars::UseSoftwareWebRender(); #endif } @@ -509,7 +509,7 @@ void RenderCompositorNativeOGL::DoSwap() { void RenderCompositorNativeOGL::DoFlush() { mGL->fFlush(); } void RenderCompositorNativeOGL::InsertFrameDoneSync() { -#ifdef XP_MACOSX +#ifdef XP_DARWIN // Only do this on macOS. // On other platforms, SwapBuffers automatically applies back-pressure. if (mThisFrameDoneSync) { diff --git a/gfx/webrender_bindings/RenderMacIOSurfaceTextureHost.cpp b/gfx/webrender_bindings/RenderMacIOSurfaceTextureHost.cpp index bb0575949b..c1f93327e5 100644 --- a/gfx/webrender_bindings/RenderMacIOSurfaceTextureHost.cpp +++ b/gfx/webrender_bindings/RenderMacIOSurfaceTextureHost.cpp @@ -6,16 +6,20 @@ #include "RenderMacIOSurfaceTextureHost.h" -#include "GLContextCGL.h" +#ifdef XP_MACOSX +# include "GLContextCGL.h" +#else +# include "GLContextEAGL.h" +#endif + #include "mozilla/gfx/Logging.h" #include "ScopedGLHelpers.h" namespace mozilla { namespace wr { -static CGLError CreateTextureForPlane(uint8_t aPlaneID, gl::GLContext* aGL, - MacIOSurface* aSurface, - GLuint* aTexture) { +static bool CreateTextureForPlane(uint8_t aPlaneID, gl::GLContext* aGL, + MacIOSurface* aSurface, GLuint* aTexture) { MOZ_ASSERT(aGL && aSurface && aTexture); aGL->fGenTextures(1, aTexture); @@ -26,10 +30,8 @@ static CGLError CreateTextureForPlane(uint8_t aPlaneID, gl::GLContext* aGL, aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); - CGLError result = kCGLNoError; gfx::SurfaceFormat readFormat = gfx::SurfaceFormat::UNKNOWN; - result = aSurface->CGLTexImageIOSurface2D( - aGL, gl::GLContextCGL::Cast(aGL)->GetCGLContext(), aPlaneID, &readFormat); + bool result = aSurface->BindTexImage(aGL, aPlaneID, &readFormat); // If this is a yuv format, the Webrender only supports YUV422 interleaving // format. MOZ_ASSERT(aSurface->GetFormat() != gfx::SurfaceFormat::YUV422 || @@ -89,7 +91,11 @@ wr::WrExternalImage RenderMacIOSurfaceTextureHost::Lock(uint8_t aChannelIndex, } if (!mTextureHandles[0]) { +#ifdef XP_MACOSX MOZ_ASSERT(gl::GLContextCGL::Cast(mGL.get())->GetCGLContext()); +#else + MOZ_ASSERT(gl::GLContextEAGL::Cast(mGL.get())->GetEAGLContext()); +#endif // The result of GetPlaneCount() is 0 for single plane format, but it will // be 2 if the format has 2 planar data. diff --git a/gfx/webrender_bindings/RenderThread.cpp b/gfx/webrender_bindings/RenderThread.cpp index 89fc339c03..e1a41ee225 100644 --- a/gfx/webrender_bindings/RenderThread.cpp +++ b/gfx/webrender_bindings/RenderThread.cpp @@ -70,12 +70,15 @@ static mozilla::BackgroundHangMonitor* sBackgroundHangMonitor; #ifdef DEBUG static bool sRenderThreadEverStarted = false; #endif +size_t RenderThread::sRendererCount = 0; +size_t RenderThread::sActiveRendererCount = 0; RenderThread::RenderThread(RefPtr<nsIThread> aThread) : mThread(std::move(aThread)), mThreadPool(false), mThreadPoolLP(true), mSingletonGLIsForHardwareWebRender(true), + mBatteryInfo("RenderThread.mBatteryInfo"), mWindowInfos("RenderThread.mWindowInfos"), mRenderTextureMapLock("RenderThread.mRenderTextureMapLock"), mHasShutdown(false), @@ -149,6 +152,11 @@ void RenderThread::Start(uint32_t aNamespace) { } sRenderThread = new RenderThread(thread); + CrashReporter::RegisterAnnotationUSize( + CrashReporter::Annotation::GraphicsNumRenderers, &sRendererCount); + CrashReporter::RegisterAnnotationUSize( + CrashReporter::Annotation::GraphicsNumActiveRenderers, + &sActiveRendererCount); #ifdef XP_WIN widget::WinCompositorWindowThread::Start(); #endif @@ -291,6 +299,26 @@ RefPtr<MemoryReportPromise> RenderThread::AccumulateMemoryReport( return p; } +void RenderThread::SetBatteryInfo(const hal::BatteryInformation& aBatteryInfo) { + MOZ_ASSERT(XRE_IsGPUProcess()); + + auto batteryInfo = mBatteryInfo.Lock(); + batteryInfo.ref() = Some(aBatteryInfo); +} + +bool RenderThread::GetPowerIsCharging() { + MOZ_ASSERT(XRE_IsGPUProcess()); + + auto batteryInfo = mBatteryInfo.Lock(); + if (batteryInfo.ref().isSome()) { + return batteryInfo.ref().ref().charging(); + } + + gfxCriticalNoteOnce << "BatteryInfo is not set"; + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + return false; +} + void RenderThread::AddRenderer(wr::WindowId aWindowId, UniquePtr<RendererOGL> aRenderer) { MOZ_ASSERT(IsInRenderThread()); @@ -301,9 +329,7 @@ void RenderThread::AddRenderer(wr::WindowId aWindowId, } mRenderers[aWindowId] = std::move(aRenderer); - CrashReporter::AnnotateCrashReport( - CrashReporter::Annotation::GraphicsNumRenderers, - (unsigned int)mRenderers.size()); + sRendererCount = mRenderers.size(); auto windows = mWindowInfos.Lock(); windows->emplace(AsUint64(aWindowId), new WindowInfo()); @@ -321,9 +347,7 @@ void RenderThread::RemoveRenderer(wr::WindowId aWindowId) { } mRenderers.erase(aWindowId); - CrashReporter::AnnotateCrashReport( - CrashReporter::Annotation::GraphicsNumRenderers, - (unsigned int)mRenderers.size()); + sRendererCount = mRenderers.size(); if (mRenderers.empty()) { if (mHandlingDeviceReset) { @@ -370,7 +394,7 @@ size_t RenderThread::RendererCount() const { return mRenderers.size(); } -size_t RenderThread::ActiveRendererCount() const { +void RenderThread::UpdateActiveRendererCount() { MOZ_ASSERT(IsInRenderThread()); size_t num_active = 0; for (const auto& it : mRenderers) { @@ -378,7 +402,7 @@ size_t RenderThread::ActiveRendererCount() const { num_active++; } } - return num_active; + sActiveRendererCount = num_active; } void RenderThread::WrNotifierEvent_WakeUp(WrWindowId aWindowId, @@ -842,9 +866,7 @@ void RenderThread::Pause(wr::WindowId aWindowId) { auto& renderer = it->second; renderer->Pause(); - CrashReporter::AnnotateCrashReport( - CrashReporter::Annotation::GraphicsNumActiveRenderers, - (unsigned int)ActiveRendererCount()); + UpdateActiveRendererCount(); } bool RenderThread::Resume(wr::WindowId aWindowId) { @@ -861,9 +883,7 @@ bool RenderThread::Resume(wr::WindowId aWindowId) { auto& renderer = it->second; bool resumed = renderer->Resume(); - CrashReporter::AnnotateCrashReport( - CrashReporter::Annotation::GraphicsNumActiveRenderers, - (unsigned int)ActiveRendererCount()); + UpdateActiveRendererCount(); return resumed; } @@ -1378,7 +1398,7 @@ RenderThread::GetProgramsForCompositorOGL() { } RefPtr<layers::SurfacePool> RenderThread::SharedSurfacePool() { -#if defined(XP_MACOSX) || defined(MOZ_WAYLAND) +#if defined(XP_DARWIN) || defined(MOZ_WAYLAND) if (!mSurfacePool) { size_t poolSizeLimit = StaticPrefs::gfx_webrender_compositor_surface_pool_size_AtStartup(); @@ -1555,7 +1575,7 @@ static already_AddRefed<gl::GLContext> CreateGLContextEGL() { } #endif -#ifdef XP_MACOSX +#ifdef XP_DARWIN static already_AddRefed<gl::GLContext> CreateGLContextCGL() { nsCString failureUnused; return gl::GLContextProvider::CreateHeadless( @@ -1578,7 +1598,7 @@ static already_AddRefed<gl::GLContext> CreateGLContext(nsACString& aError) { if (gfx::gfxVars::UseEGL()) { gl = CreateGLContextEGL(); } -#elif XP_MACOSX +#elif XP_DARWIN gl = CreateGLContextCGL(); #endif diff --git a/gfx/webrender_bindings/RenderThread.h b/gfx/webrender_bindings/RenderThread.h index aa508e5581..f9ab1e742e 100644 --- a/gfx/webrender_bindings/RenderThread.h +++ b/gfx/webrender_bindings/RenderThread.h @@ -14,6 +14,7 @@ #include "GLTypes.h" // for GLenum #include "nsISupportsImpl.h" #include "mozilla/gfx/Point.h" +#include "mozilla/Hal.h" #include "mozilla/MozPromise.h" #include "mozilla/DataMutex.h" #include "mozilla/Maybe.h" @@ -292,7 +293,8 @@ class RenderThread final { bool SyncObjectNeeded(); size_t RendererCount() const; - size_t ActiveRendererCount() const; + size_t ActiveRendererCount() const { return sActiveRendererCount; }; + void UpdateActiveRendererCount(); void BeginRecordingForWindow(wr::WindowId aWindowId, const TimeStamp& aRecordingStart, @@ -302,7 +304,13 @@ class RenderThread final { static void MaybeEnableGLDebugMessage(gl::GLContext* aGLContext); + void SetBatteryInfo(const hal::BatteryInformation& aBatteryInfo); + bool GetPowerIsCharging(); + private: + static size_t sRendererCount; + static size_t sActiveRendererCount; + enum class RenderTextureOp { PrepareForUse, NotifyForUse, @@ -434,6 +442,8 @@ class RenderThread final { std::map<wr::WindowId, UniquePtr<RendererOGL>> mRenderers; + DataMutex<Maybe<hal::BatteryInformation>> mBatteryInfo; + struct PendingFrameInfo { TimeStamp mStartTime; VsyncId mStartId; diff --git a/gfx/webrender_bindings/moz.build b/gfx/webrender_bindings/moz.build index f17c77e4cb..6cca348acb 100644 --- a/gfx/webrender_bindings/moz.build +++ b/gfx/webrender_bindings/moz.build @@ -51,7 +51,7 @@ UNIFIED_SOURCES += [ "WebRenderTypes.cpp", ] -if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa": +if CONFIG["MOZ_WIDGET_TOOLKIT"] in ("cocoa", "uikit"): EXPORTS.mozilla.webrender += [ "RenderCompositorNative.h", "RenderMacIOSurfaceTextureHost.h", diff --git a/gfx/webrender_bindings/src/bindings.rs b/gfx/webrender_bindings/src/bindings.rs index 1f3bca644a..047791c76b 100644 --- a/gfx/webrender_bindings/src/bindings.rs +++ b/gfx/webrender_bindings/src/bindings.rs @@ -7,7 +7,7 @@ use gleam::gl; use std::cell::RefCell; -#[cfg(not(target_os = "macos"))] +#[cfg(not(any(target_os = "macos", target_os = "ios")))] use std::ffi::OsString; use std::ffi::{CStr, CString}; use std::io::Cursor; @@ -16,7 +16,7 @@ use std::ops::Range; #[cfg(target_os = "android")] use std::os::raw::c_int; use std::os::raw::{c_char, c_float, c_void}; -#[cfg(not(any(target_os = "macos", target_os = "windows")))] +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))] use std::os::unix::ffi::OsStringExt; #[cfg(target_os = "windows")] use std::os::windows::ffi::OsStringExt; @@ -2326,7 +2326,7 @@ fn read_font_descriptor(bytes: &mut WrVecU8, index: u32) -> NativeFontHandle { } } -#[cfg(target_os = "macos")] +#[cfg(any(target_os = "macos", target_os = "ios"))] fn read_font_descriptor(bytes: &mut WrVecU8, index: u32) -> NativeFontHandle { // On macOS, the descriptor string is a concatenation of the PostScript name // and the font file path (to disambiguate cases where there are multiple @@ -2340,7 +2340,7 @@ fn read_font_descriptor(bytes: &mut WrVecU8, index: u32) -> NativeFontHandle { } } -#[cfg(not(any(target_os = "macos", target_os = "windows")))] +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))] fn read_font_descriptor(bytes: &mut WrVecU8, index: u32) -> NativeFontHandle { let chars = bytes.flush_into_vec(); NativeFontHandle { diff --git a/gfx/webrender_bindings/src/lib.rs b/gfx/webrender_bindings/src/lib.rs index 9e94302e0f..b3c6e6ac56 100644 --- a/gfx/webrender_bindings/src/lib.rs +++ b/gfx/webrender_bindings/src/lib.rs @@ -28,11 +28,11 @@ extern crate dwrote; #[cfg(target_os = "windows")] extern crate winapi; -#[cfg(target_os = "macos")] +#[cfg(any(target_os = "macos", target_os = "ios"))] extern crate core_foundation; -#[cfg(target_os = "macos")] +#[cfg(any(target_os = "macos", target_os = "ios"))] extern crate core_graphics; -#[cfg(target_os = "macos")] +#[cfg(any(target_os = "macos", target_os = "ios"))] extern crate foreign_types; mod program_cache; diff --git a/gfx/webrender_bindings/src/moz2d_renderer.rs b/gfx/webrender_bindings/src/moz2d_renderer.rs index 4c7a32c912..ca1e76f96f 100644 --- a/gfx/webrender_bindings/src/moz2d_renderer.rs +++ b/gfx/webrender_bindings/src/moz2d_renderer.rs @@ -33,16 +33,16 @@ use std::sync::Arc; #[cfg(target_os = "windows")] use dwrote; -#[cfg(target_os = "macos")] +#[cfg(any(target_os = "macos", target_os = "ios"))] use core_foundation::string::CFString; -#[cfg(target_os = "macos")] +#[cfg(any(target_os = "macos", target_os = "ios"))] use core_graphics::font::CGFont; -#[cfg(target_os = "macos")] +#[cfg(any(target_os = "macos", target_os = "ios"))] use foreign_types::ForeignType; -#[cfg(not(any(target_os = "macos", target_os = "windows")))] +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))] use std::ffi::CString; -#[cfg(not(any(target_os = "macos", target_os = "windows")))] +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))] use std::os::unix::ffi::OsStrExt; /// Local print-debugging utility @@ -787,7 +787,7 @@ impl Moz2dBlobImageHandler { unsafe { AddNativeFontHandle(key, face.as_ptr() as *mut c_void, 0) }; } - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] fn process_native_font_handle(key: FontKey, handle: &NativeFontHandle) { let font = match CGFont::from_name(&CFString::new(&handle.name)) { Ok(font) => font, @@ -804,7 +804,7 @@ impl Moz2dBlobImageHandler { unsafe { AddNativeFontHandle(key, font.as_ptr() as *mut c_void, 0) }; } - #[cfg(not(any(target_os = "macos", target_os = "windows")))] + #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))] fn process_native_font_handle(key: FontKey, handle: &NativeFontHandle) { let cstr = CString::new(handle.path.as_os_str().as_bytes()).unwrap(); unsafe { AddNativeFontHandle(key, cstr.as_ptr() as *mut c_void, handle.index) }; diff --git a/gfx/wgpu_bindings/Cargo.toml b/gfx/wgpu_bindings/Cargo.toml index b24d09a955..21b4b8c7f7 100644 --- a/gfx/wgpu_bindings/Cargo.toml +++ b/gfx/wgpu_bindings/Cargo.toml @@ -17,7 +17,7 @@ default = [] [dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a" +rev = "6040820099bc72b827a6a5f53d66dda3e301f944" # TODO: remove the replay feature on the next update containing https://github.com/gfx-rs/wgpu/pull/5182 features = ["serde", "replay", "trace", "strict_asserts", "wgsl", "api_log_info"] @@ -26,37 +26,37 @@ features = ["serde", "replay", "trace", "strict_asserts", "wgsl", "api_log_info" [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a" +rev = "6040820099bc72b827a6a5f53d66dda3e301f944" features = ["metal"] # We want the wgpu-core Direct3D backends on Windows. [target.'cfg(windows)'.dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a" +rev = "6040820099bc72b827a6a5f53d66dda3e301f944" features = ["dx12"] # We want the wgpu-core Vulkan backend on Linux and Windows. [target.'cfg(any(windows, all(unix, not(any(target_os = "macos", target_os = "ios")))))'.dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a" +rev = "6040820099bc72b827a6a5f53d66dda3e301f944" features = ["vulkan"] [dependencies.wgt] package = "wgpu-types" git = "https://github.com/gfx-rs/wgpu" -rev = "07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a" +rev = "6040820099bc72b827a6a5f53d66dda3e301f944" [dependencies.wgh] package = "wgpu-hal" git = "https://github.com/gfx-rs/wgpu" -rev = "07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a" +rev = "6040820099bc72b827a6a5f53d66dda3e301f944" features = ["windows_rs"] [target.'cfg(windows)'.dependencies.d3d12] git = "https://github.com/gfx-rs/wgpu" -rev = "07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a" +rev = "6040820099bc72b827a6a5f53d66dda3e301f944" [target.'cfg(windows)'.dependencies] winapi = "0.3" @@ -68,3 +68,4 @@ parking_lot = "0.12" serde = "1" nsstring = { path = "../../xpcom/rust/nsstring" } static_prefs = { path = "../../modules/libpref/init/static_prefs" } +arrayvec = "0.7" diff --git a/gfx/wgpu_bindings/moz.yaml b/gfx/wgpu_bindings/moz.yaml index 1c4f19cbb7..ffa746cb46 100644 --- a/gfx/wgpu_bindings/moz.yaml +++ b/gfx/wgpu_bindings/moz.yaml @@ -20,11 +20,11 @@ origin: # Human-readable identifier for this version/release # Generally "version NNN", "tag SSS", "bookmark SSS" - release: commit 07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a + release: 6040820099bc72b827a6a5f53d66dda3e301f944 (2024-03-12T14:49:44Z). # Revision to pull in # Must be a long or short commit SHA (long preferred) - revision: 07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a + revision: 6040820099bc72b827a6a5f53d66dda3e301f944 license: ['MIT', 'Apache-2.0'] diff --git a/gfx/wgpu_bindings/src/client.rs b/gfx/wgpu_bindings/src/client.rs index bf53a8c871..c49dbea7a5 100644 --- a/gfx/wgpu_bindings/src/client.rs +++ b/gfx/wgpu_bindings/src/client.rs @@ -47,7 +47,7 @@ impl ProgrammableStageDescriptor { fn to_wgpu(&self) -> wgc::pipeline::ProgrammableStageDescriptor { wgc::pipeline::ProgrammableStageDescriptor { module: self.module, - entry_point: cow_label(&self.entry_point).unwrap(), + entry_point: cow_label(&self.entry_point), } } } @@ -177,6 +177,7 @@ pub enum RawBindingType { SampledTexture, ReadonlyStorageTexture, WriteonlyStorageTexture, + ReadWriteStorageTexture, } #[repr(C)] @@ -237,7 +238,7 @@ pub struct SamplerDescriptor<'a> { lod_min_clamp: f32, lod_max_clamp: f32, compare: Option<&'a wgt::CompareFunction>, - anisotropy_clamp: Option<&'a u16>, + max_anisotropy: u16, } #[repr(C)] @@ -614,7 +615,7 @@ pub extern "C" fn wgpu_client_create_sampler( lod_min_clamp: desc.lod_min_clamp, lod_max_clamp: desc.lod_max_clamp, compare: desc.compare.cloned(), - anisotropy_clamp: *desc.anisotropy_clamp.unwrap_or(&1), + anisotropy_clamp: desc.max_anisotropy, border_color: None, }; let action = DeviceAction::CreateSampler(id, wgpu_desc); @@ -769,9 +770,8 @@ pub struct ComputePassTimestampWrites<'a> { #[no_mangle] pub unsafe extern "C" fn wgpu_command_encoder_begin_compute_pass( - encoder_id: id::CommandEncoderId, desc: &ComputePassDescriptor, -) -> *mut wgc::command::ComputePass { +) -> *mut crate::command::RecordedComputePass { let &ComputePassDescriptor { label, timestamp_writes, @@ -795,27 +795,24 @@ pub unsafe extern "C" fn wgpu_command_encoder_begin_compute_pass( }); let timestamp_writes = timestamp_writes.as_ref(); - let pass = wgc::command::ComputePass::new( - encoder_id, - &wgc::command::ComputePassDescriptor { - label, - timestamp_writes, - }, - ); + let pass = crate::command::RecordedComputePass::new(&wgc::command::ComputePassDescriptor { + label, + timestamp_writes, + }); Box::into_raw(Box::new(pass)) } #[no_mangle] pub unsafe extern "C" fn wgpu_compute_pass_finish( - pass: *mut wgc::command::ComputePass, + pass: *mut crate::command::RecordedComputePass, output: &mut ByteBuf, ) { - let command = Box::from_raw(pass).into_command(); + let command = Box::from_raw(pass); *output = make_byte_buf(&command); } #[no_mangle] -pub unsafe extern "C" fn wgpu_compute_pass_destroy(pass: *mut wgc::command::ComputePass) { +pub unsafe extern "C" fn wgpu_compute_pass_destroy(pass: *mut crate::command::RecordedComputePass) { let _ = Box::from_raw(pass); } @@ -838,9 +835,8 @@ pub struct RenderPassTimestampWrites<'a> { #[no_mangle] pub unsafe extern "C" fn wgpu_command_encoder_begin_render_pass( - encoder_id: id::CommandEncoderId, desc: &RenderPassDescriptor, -) -> *mut wgc::command::RenderPass { +) -> *mut crate::command::RecordedRenderPass { let &RenderPassDescriptor { label, color_attachments, @@ -873,30 +869,27 @@ pub unsafe extern "C" fn wgpu_command_encoder_begin_render_pass( .iter() .map(|format| Some(format.clone())) .collect(); - let pass = wgc::command::RenderPass::new( - encoder_id, - &wgc::command::RenderPassDescriptor { - label, - color_attachments: Cow::Owned(color_attachments), - depth_stencil_attachment: depth_stencil_attachment.as_ref(), - timestamp_writes, - occlusion_query_set, - }, - ); + let pass = crate::command::RecordedRenderPass::new(&wgc::command::RenderPassDescriptor { + label, + color_attachments: Cow::Owned(color_attachments), + depth_stencil_attachment: depth_stencil_attachment.as_ref(), + timestamp_writes, + occlusion_query_set, + }); Box::into_raw(Box::new(pass)) } #[no_mangle] pub unsafe extern "C" fn wgpu_render_pass_finish( - pass: *mut wgc::command::RenderPass, + pass: *mut crate::command::RecordedRenderPass, output: &mut ByteBuf, ) { - let command = Box::from_raw(pass).into_command(); + let command = Box::from_raw(pass); *output = make_byte_buf(&command); } #[no_mangle] -pub unsafe extern "C" fn wgpu_render_pass_destroy(pass: *mut wgc::command::RenderPass) { +pub unsafe extern "C" fn wgpu_render_pass_destroy(pass: *mut crate::command::RecordedRenderPass) { let _ = Box::from_raw(pass); } @@ -974,6 +967,11 @@ pub unsafe extern "C" fn wgpu_client_create_bind_group_layout( view_dimension: *entry.view_dimension.unwrap(), format: *entry.storage_texture_format.unwrap(), }, + RawBindingType::ReadWriteStorageTexture => wgt::BindingType::StorageTexture { + access: wgt::StorageTextureAccess::ReadWrite, + view_dimension: *entry.view_dimension.unwrap(), + format: *entry.storage_texture_format.unwrap(), + }, }, }); } diff --git a/gfx/wgpu_bindings/src/command.rs b/gfx/wgpu_bindings/src/command.rs new file mode 100644 index 0000000000..acba975c13 --- /dev/null +++ b/gfx/wgpu_bindings/src/command.rs @@ -0,0 +1,1062 @@ +/* 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/. */ + +use crate::{id, RawString}; +use std::{borrow::Cow, ffi, slice}; +use wgc::{command::{compute_ffi, render_ffi, ComputePassDescriptor, ComputePassTimestampWrites, RenderPassColorAttachment, RenderPassDepthStencilAttachment, RenderPassDescriptor, RenderPassTimestampWrites}, id::CommandEncoderId}; +use wgt::{BufferAddress, BufferSize, Color, DynamicOffset, IndexFormat}; + +use serde::{Serialize, Deserialize}; +use arrayvec::ArrayVec; + +/// A stream of commands for a render pass or compute pass. +/// +/// This also contains side tables referred to by certain commands, +/// like dynamic offsets for [`SetBindGroup`] or string data for +/// [`InsertDebugMarker`]. +/// +/// Render passes use `BasePass<RenderCommand>`, whereas compute +/// passes use `BasePass<ComputeCommand>`. +/// +/// [`SetBindGroup`]: RenderCommand::SetBindGroup +/// [`InsertDebugMarker`]: RenderCommand::InsertDebugMarker +#[doc(hidden)] +#[derive(Debug)] +#[derive(serde::Serialize, serde::Deserialize)] +pub struct BasePass<C> { + pub label: Option<String>, + + /// The stream of commands. + pub commands: Vec<C>, + + /// Dynamic offsets consumed by [`SetBindGroup`] commands in `commands`. + /// + /// Each successive `SetBindGroup` consumes the next + /// [`num_dynamic_offsets`] values from this list. + pub dynamic_offsets: Vec<wgt::DynamicOffset>, + + /// Strings used by debug instructions. + /// + /// Each successive [`PushDebugGroup`] or [`InsertDebugMarker`] + /// instruction consumes the next `len` bytes from this vector. + pub string_data: Vec<u8>, +} + +#[derive(Deserialize, Serialize)] +pub struct RecordedRenderPass { + base: BasePass<RenderCommand>, + color_attachments: ArrayVec<Option<RenderPassColorAttachment>, { wgh::MAX_COLOR_ATTACHMENTS }>, + depth_stencil_attachment: Option<RenderPassDepthStencilAttachment>, + timestamp_writes: Option<RenderPassTimestampWrites>, + occlusion_query_set_id: Option<id::QuerySetId>, +} + +impl RecordedRenderPass { + pub fn new(desc: &RenderPassDescriptor) -> Self { + Self { + base: BasePass { + label: desc.label.as_ref().map(|cow| cow.to_string()), + commands: Vec::new(), + dynamic_offsets: Vec::new(), + string_data: Vec::new(), + }, + color_attachments: desc.color_attachments.iter().cloned().collect(), + depth_stencil_attachment: desc.depth_stencil_attachment.cloned(), + timestamp_writes: desc.timestamp_writes.cloned(), + occlusion_query_set_id: desc.occlusion_query_set, + } + } +} + +#[derive(serde::Deserialize, serde::Serialize)] +pub struct RecordedComputePass { + base: BasePass<ComputeCommand>, + timestamp_writes: Option<ComputePassTimestampWrites>, +} + +impl RecordedComputePass { + pub fn new(desc: &ComputePassDescriptor) -> Self { + Self { + base: BasePass { + label: desc.label.as_ref().map(|cow| cow.to_string()), + commands: Vec::new(), + dynamic_offsets: Vec::new(), + string_data: Vec::new(), + }, + timestamp_writes: desc.timestamp_writes.cloned(), + } + } +} + +#[doc(hidden)] +#[derive(Clone, Copy, Debug)] +#[derive(serde::Serialize, serde::Deserialize)] +pub enum RenderCommand { + SetBindGroup { + index: u32, + num_dynamic_offsets: usize, + bind_group_id: id::BindGroupId, + }, + SetPipeline(id::RenderPipelineId), + SetIndexBuffer { + buffer_id: id::BufferId, + index_format: wgt::IndexFormat, + offset: BufferAddress, + size: Option<BufferSize>, + }, + SetVertexBuffer { + slot: u32, + buffer_id: id::BufferId, + offset: BufferAddress, + size: Option<BufferSize>, + }, + SetBlendConstant(Color), + SetStencilReference(u32), + SetViewport { + x: f32, y: f32, w: f32, h: f32, + depth_min: f32, + depth_max: f32, + }, + SetScissor { x: u32, y: u32, w: u32, h: u32 }, + Draw { + vertex_count: u32, + instance_count: u32, + first_vertex: u32, + first_instance: u32, + }, + DrawIndexed { + index_count: u32, + instance_count: u32, + first_index: u32, + base_vertex: i32, + first_instance: u32, + }, + MultiDrawIndirect { + buffer_id: id::BufferId, + offset: BufferAddress, + /// Count of `None` represents a non-multi call. + count: Option<u32>, + indexed: bool, + }, + MultiDrawIndirectCount { + buffer_id: id::BufferId, + offset: BufferAddress, + count_buffer_id: id::BufferId, + count_buffer_offset: BufferAddress, + max_count: u32, + indexed: bool, + }, + PushDebugGroup { + color: u32, + len: usize, + }, + PopDebugGroup, + InsertDebugMarker { + color: u32, + len: usize, + }, + WriteTimestamp { + query_set_id: id::QuerySetId, + query_index: u32, + }, + BeginOcclusionQuery { + query_index: u32, + }, + EndOcclusionQuery, + BeginPipelineStatisticsQuery { + query_set_id: id::QuerySetId, + query_index: u32, + }, + EndPipelineStatisticsQuery, + ExecuteBundle(id::RenderBundleId), +} + +#[doc(hidden)] +#[derive(Clone, Copy, Debug)] +#[derive(serde::Serialize, serde::Deserialize)] +pub enum ComputeCommand { + SetBindGroup { + index: u32, + num_dynamic_offsets: usize, + bind_group_id: id::BindGroupId, + }, + SetPipeline(id::ComputePipelineId), + Dispatch([u32; 3]), + DispatchIndirect { + buffer_id: id::BufferId, + offset: wgt::BufferAddress, + }, + PushDebugGroup { + color: u32, + len: usize, + }, + PopDebugGroup, + InsertDebugMarker { + color: u32, + len: usize, + }, + WriteTimestamp { + query_set_id: id::QuerySetId, + query_index: u32, + }, + BeginPipelineStatisticsQuery { + query_set_id: id::QuerySetId, + query_index: u32, + }, + EndPipelineStatisticsQuery, +} + +/// # Safety +/// +/// This function is unsafe as there is no guarantee that the given pointer is +/// valid for `offset_length` elements. +#[no_mangle] +pub unsafe extern "C" fn wgpu_recorded_render_pass_set_bind_group( + pass: &mut RecordedRenderPass, + index: u32, + bind_group_id: id::BindGroupId, + offsets: *const DynamicOffset, + offset_length: usize, +) { + pass.base.dynamic_offsets + .extend_from_slice(unsafe { slice::from_raw_parts(offsets, offset_length) }); + + pass.base.commands.push(RenderCommand::SetBindGroup { + index, + num_dynamic_offsets: offset_length, + bind_group_id, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_set_pipeline( + pass: &mut RecordedRenderPass, + pipeline_id: id::RenderPipelineId, +) { + pass.base + .commands + .push(RenderCommand::SetPipeline(pipeline_id)); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_set_vertex_buffer( + pass: &mut RecordedRenderPass, + slot: u32, + buffer_id: id::BufferId, + offset: BufferAddress, + size: Option<BufferSize>, +) { + pass.base.commands.push(RenderCommand::SetVertexBuffer { + slot, + buffer_id, + offset, + size, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_set_index_buffer( + pass: &mut RecordedRenderPass, + buffer_id: id::BufferId, + index_format: IndexFormat, + offset: BufferAddress, + size: Option<BufferSize>, +) { + pass.base.commands.push(RenderCommand::SetIndexBuffer { + buffer_id, + index_format, + offset, + size, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_set_blend_constant(pass: &mut RecordedRenderPass, color: &Color) { + pass.base + .commands + .push(RenderCommand::SetBlendConstant(*color)); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_set_stencil_reference(pass: &mut RecordedRenderPass, value: u32) { + pass.base + .commands + .push(RenderCommand::SetStencilReference(value)); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_set_viewport( + pass: &mut RecordedRenderPass, + x: f32, + y: f32, + w: f32, + h: f32, + depth_min: f32, + depth_max: f32, +) { + pass.base.commands.push(RenderCommand::SetViewport { + x, y, w, h, + depth_min, + depth_max, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_set_scissor_rect( + pass: &mut RecordedRenderPass, + x: u32, + y: u32, + w: u32, + h: u32, +) { + pass.base + .commands + .push(RenderCommand::SetScissor { x, y, w, h }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_draw( + pass: &mut RecordedRenderPass, + vertex_count: u32, + instance_count: u32, + first_vertex: u32, + first_instance: u32, +) { + pass.base.commands.push(RenderCommand::Draw { + vertex_count, + instance_count, + first_vertex, + first_instance, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_draw_indexed( + pass: &mut RecordedRenderPass, + index_count: u32, + instance_count: u32, + first_index: u32, + base_vertex: i32, + first_instance: u32, +) { + pass.base.commands.push(RenderCommand::DrawIndexed { + index_count, + instance_count, + first_index, + base_vertex, + first_instance, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_draw_indirect( + pass: &mut RecordedRenderPass, + buffer_id: id::BufferId, + offset: BufferAddress, +) { + pass.base.commands.push(RenderCommand::MultiDrawIndirect { + buffer_id, + offset, + count: None, + indexed: false, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_draw_indexed_indirect( + pass: &mut RecordedRenderPass, + buffer_id: id::BufferId, + offset: BufferAddress, +) { + pass.base.commands.push(RenderCommand::MultiDrawIndirect { + buffer_id, + offset, + count: None, + indexed: true, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_multi_draw_indirect( + pass: &mut RecordedRenderPass, + buffer_id: id::BufferId, + offset: BufferAddress, + count: u32, +) { + pass.base.commands.push(RenderCommand::MultiDrawIndirect { + buffer_id, + offset, + count: Some(count), + indexed: false, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_multi_draw_indexed_indirect( + pass: &mut RecordedRenderPass, + buffer_id: id::BufferId, + offset: BufferAddress, + count: u32, +) { + pass.base.commands.push(RenderCommand::MultiDrawIndirect { + buffer_id, + offset, + count: Some(count), + indexed: true, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_multi_draw_indirect_count( + pass: &mut RecordedRenderPass, + buffer_id: id::BufferId, + offset: BufferAddress, + count_buffer_id: id::BufferId, + count_buffer_offset: BufferAddress, + max_count: u32, +) { + pass.base + .commands + .push(RenderCommand::MultiDrawIndirectCount { + buffer_id, + offset, + count_buffer_id, + count_buffer_offset, + max_count, + indexed: false, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_multi_draw_indexed_indirect_count( + pass: &mut RecordedRenderPass, + buffer_id: id::BufferId, + offset: BufferAddress, + count_buffer_id: id::BufferId, + count_buffer_offset: BufferAddress, + max_count: u32, +) { + pass.base + .commands + .push(RenderCommand::MultiDrawIndirectCount { + buffer_id, + offset, + count_buffer_id, + count_buffer_offset, + max_count, + indexed: true, + }); +} + +/// # Safety +/// +/// This function is unsafe as there is no guarantee that the given `label` +/// is a valid null-terminated string. +#[no_mangle] +pub unsafe extern "C" fn wgpu_recorded_render_pass_push_debug_group( + pass: &mut RecordedRenderPass, + label: RawString, + color: u32, +) { + let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes(); + pass.base.string_data.extend_from_slice(bytes); + + pass.base.commands.push(RenderCommand::PushDebugGroup { + color, + len: bytes.len(), + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_pop_debug_group(pass: &mut RecordedRenderPass) { + pass.base.commands.push(RenderCommand::PopDebugGroup); +} + +/// # Safety +/// +/// This function is unsafe as there is no guarantee that the given `label` +/// is a valid null-terminated string. +#[no_mangle] +pub unsafe extern "C" fn wgpu_recorded_render_pass_insert_debug_marker( + pass: &mut RecordedRenderPass, + label: RawString, + color: u32, +) { + let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes(); + pass.base.string_data.extend_from_slice(bytes); + + pass.base.commands.push(RenderCommand::InsertDebugMarker { + color, + len: bytes.len(), + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_write_timestamp( + pass: &mut RecordedRenderPass, + query_set_id: id::QuerySetId, + query_index: u32, +) { + pass.base.commands.push(RenderCommand::WriteTimestamp { + query_set_id, + query_index, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_begin_occlusion_query( + pass: &mut RecordedRenderPass, + query_index: u32, +) { + pass.base + .commands + .push(RenderCommand::BeginOcclusionQuery { query_index }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_end_occlusion_query(pass: &mut RecordedRenderPass) { + pass.base.commands.push(RenderCommand::EndOcclusionQuery); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_begin_pipeline_statistics_query( + pass: &mut RecordedRenderPass, + query_set_id: id::QuerySetId, + query_index: u32, +) { + pass.base + .commands + .push(RenderCommand::BeginPipelineStatisticsQuery { + query_set_id, + query_index, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_end_pipeline_statistics_query(pass: &mut RecordedRenderPass) { + pass.base + .commands + .push(RenderCommand::EndPipelineStatisticsQuery); +} + +/// # Safety +/// +/// This function is unsafe as there is no guarantee that the given pointer is +/// valid for `render_bundle_ids_length` elements. +#[no_mangle] +pub unsafe extern "C" fn wgpu_recorded_render_pass_execute_bundles( + pass: &mut RecordedRenderPass, + render_bundle_ids: *const id::RenderBundleId, + render_bundle_ids_length: usize, +) { + for &bundle_id in + unsafe { slice::from_raw_parts(render_bundle_ids, render_bundle_ids_length) } + { + pass.base + .commands + .push(RenderCommand::ExecuteBundle(bundle_id)); + } +} + +/// # Safety +/// +/// This function is unsafe as there is no guarantee that the given pointer is +/// valid for `offset_length` elements. +#[no_mangle] +pub unsafe extern "C" fn wgpu_recorded_compute_pass_set_bind_group( + pass: &mut RecordedComputePass, + index: u32, + bind_group_id: id::BindGroupId, + offsets: *const DynamicOffset, + offset_length: usize, +) { + pass.base.dynamic_offsets + .extend_from_slice(unsafe { slice::from_raw_parts(offsets, offset_length) }); + + pass.base.commands.push(ComputeCommand::SetBindGroup { + index, + num_dynamic_offsets: offset_length, + bind_group_id, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_compute_pass_set_pipeline( + pass: &mut RecordedComputePass, + pipeline_id: id::ComputePipelineId, +) { + pass.base + .commands + .push(ComputeCommand::SetPipeline(pipeline_id)); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_compute_pass_dispatch_workgroups( + pass: &mut RecordedComputePass, + groups_x: u32, + groups_y: u32, + groups_z: u32, +) { + pass.base + .commands + .push(ComputeCommand::Dispatch([groups_x, groups_y, groups_z])); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_compute_pass_dispatch_workgroups_indirect( + pass: &mut RecordedComputePass, + buffer_id: id::BufferId, + offset: BufferAddress, +) { + pass.base + .commands + .push(ComputeCommand::DispatchIndirect { buffer_id, offset }); +} + +/// # Safety +/// +/// This function is unsafe as there is no guarantee that the given `label` +/// is a valid null-terminated string. +#[no_mangle] +pub unsafe extern "C" fn wgpu_recorded_compute_pass_push_debug_group( + pass: &mut RecordedComputePass, + label: RawString, + color: u32, +) { + let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes(); + pass.base.string_data.extend_from_slice(bytes); + + pass.base.commands.push(ComputeCommand::PushDebugGroup { + color, + len: bytes.len(), + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_compute_pass_pop_debug_group(pass: &mut RecordedComputePass) { + pass.base.commands.push(ComputeCommand::PopDebugGroup); +} + +/// # Safety +/// +/// This function is unsafe as there is no guarantee that the given `label` +/// is a valid null-terminated string. +#[no_mangle] +pub unsafe extern "C" fn wgpu_recorded_compute_pass_insert_debug_marker( + pass: &mut RecordedComputePass, + label: RawString, + color: u32, +) { + let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes(); + pass.base.string_data.extend_from_slice(bytes); + + pass.base.commands.push(ComputeCommand::InsertDebugMarker { + color, + len: bytes.len(), + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_compute_pass_write_timestamp( + pass: &mut RecordedComputePass, + query_set_id: id::QuerySetId, + query_index: u32, +) { + pass.base.commands.push(ComputeCommand::WriteTimestamp { + query_set_id, + query_index, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_compute_pass_begin_pipeline_statistics_query( + pass: &mut RecordedComputePass, + query_set_id: id::QuerySetId, + query_index: u32, +) { + pass.base + .commands + .push(ComputeCommand::BeginPipelineStatisticsQuery { + query_set_id, + query_index, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_compute_pass_end_pipeline_statistics_query(pass: &mut RecordedComputePass) { + pass.base + .commands + .push(ComputeCommand::EndPipelineStatisticsQuery); +} + +pub fn replay_render_pass( + id: CommandEncoderId, + src_pass: &RecordedRenderPass +) -> wgc::command::RenderPass { + + let mut dst_pass = wgc::command::RenderPass::new( + id, + &wgc::command::RenderPassDescriptor { + label: src_pass.base.label.as_ref().map(|s| s.as_str().into()), + color_attachments: Cow::Borrowed(&src_pass.color_attachments), + depth_stencil_attachment: src_pass.depth_stencil_attachment.as_ref(), + timestamp_writes: src_pass.timestamp_writes.as_ref(), + occlusion_query_set: src_pass.occlusion_query_set_id, + }, + ); + + let mut dynamic_offsets = src_pass.base.dynamic_offsets.as_slice(); + let mut dynamic_offsets = |len| { + let offsets; + (offsets, dynamic_offsets) = dynamic_offsets.split_at(len); + offsets + }; + let mut strings = src_pass.base.string_data.as_slice(); + let mut strings = |len| { + let label; + (label, strings) = strings.split_at(len); + label + }; + for command in &src_pass.base.commands { + match *command { + RenderCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group_id, + } => { + let offsets = dynamic_offsets(num_dynamic_offsets); + unsafe { + render_ffi::wgpu_render_pass_set_bind_group( + &mut dst_pass, + index, + bind_group_id, + offsets.as_ptr(), + offsets.len(), + ); + } + } + RenderCommand::SetPipeline(pipeline_id) => { + render_ffi::wgpu_render_pass_set_pipeline(&mut dst_pass, pipeline_id); + } + RenderCommand::SetIndexBuffer { + buffer_id, + index_format, + offset, + size, + } => { + render_ffi::wgpu_render_pass_set_index_buffer( + &mut dst_pass, + buffer_id, + index_format, + offset, + size + ); + } + RenderCommand::SetVertexBuffer { + slot, + buffer_id, + offset, + size, + } => { + render_ffi::wgpu_render_pass_set_vertex_buffer( + &mut dst_pass, + slot, + buffer_id, + offset, + size + ) + } + RenderCommand::SetBlendConstant(ref color) => { + render_ffi::wgpu_render_pass_set_blend_constant(&mut dst_pass, color); + } + RenderCommand::SetStencilReference(value) => { + render_ffi::wgpu_render_pass_set_stencil_reference(&mut dst_pass, value); + } + RenderCommand::SetViewport { + x, y, w, h, + depth_min, + depth_max, + } => { + render_ffi::wgpu_render_pass_set_viewport( + &mut dst_pass, + x, y, w, h, + depth_min, + depth_max, + ); + } + RenderCommand::SetScissor { x, y, w, h } => { + render_ffi::wgpu_render_pass_set_scissor_rect( + &mut dst_pass, + x, y, w, h + ); + } + RenderCommand::Draw { + vertex_count, + instance_count, + first_vertex, + first_instance, + } => { + render_ffi::wgpu_render_pass_draw( + &mut dst_pass, + vertex_count, + instance_count, + first_vertex, + first_instance, + ); + } + RenderCommand::DrawIndexed { + index_count, + instance_count, + first_index, + base_vertex, + first_instance, + } => { + render_ffi::wgpu_render_pass_draw_indexed( + &mut dst_pass, + index_count, + instance_count, + first_index, + base_vertex, + first_instance, + ); + } + RenderCommand::MultiDrawIndirect { + buffer_id, + offset, + count, + indexed, + } => { + match (indexed, count) { + (false, Some(count)) => render_ffi::wgpu_render_pass_multi_draw_indirect( + &mut dst_pass, + buffer_id, + offset, + count, + ), + (false, None) => render_ffi::wgpu_render_pass_draw_indirect( + &mut dst_pass, + buffer_id, + offset, + ), + (true, Some(count)) => render_ffi::wgpu_render_pass_multi_draw_indexed_indirect( + &mut dst_pass, + buffer_id, + offset, + count, + ), + (true, None) => render_ffi::wgpu_render_pass_draw_indexed_indirect( + &mut dst_pass, + buffer_id, + offset, + ), + }; + } + RenderCommand::MultiDrawIndirectCount { + buffer_id, + offset, + count_buffer_id, + count_buffer_offset, + max_count, + indexed, + } => { + if indexed { + render_ffi::wgpu_render_pass_multi_draw_indexed_indirect_count( + &mut dst_pass, + buffer_id, + offset, + count_buffer_id, + count_buffer_offset, + max_count, + ); + } else { + render_ffi::wgpu_render_pass_multi_draw_indirect_count( + &mut dst_pass, + buffer_id, + offset, + count_buffer_id, + count_buffer_offset, + max_count, + ); + } + } + RenderCommand::PushDebugGroup { color, len } => { + let label = strings(len); + let label = std::ffi::CString::new(label).unwrap(); + unsafe { + render_ffi::wgpu_render_pass_push_debug_group( + &mut dst_pass, + label.as_ptr(), + color + ); + } + } + RenderCommand::PopDebugGroup => { + render_ffi::wgpu_render_pass_pop_debug_group(&mut dst_pass); + } + RenderCommand::InsertDebugMarker { color, len } => { + let label = strings(len); + let label = std::ffi::CString::new(label).unwrap(); + unsafe { + render_ffi::wgpu_render_pass_insert_debug_marker( + &mut dst_pass, + label.as_ptr(), + color, + ); + } + } + RenderCommand::WriteTimestamp { + query_set_id, + query_index, + } => { + render_ffi::wgpu_render_pass_write_timestamp( + &mut dst_pass, + query_set_id, + query_index, + ); + } + RenderCommand::BeginOcclusionQuery { query_index } => { + render_ffi::wgpu_render_pass_begin_occlusion_query( + &mut dst_pass, + query_index + ); + } + RenderCommand::EndOcclusionQuery => { + render_ffi::wgpu_render_pass_end_occlusion_query(&mut dst_pass); + } + RenderCommand::BeginPipelineStatisticsQuery { + query_set_id, + query_index, + } => { + render_ffi::wgpu_render_pass_begin_pipeline_statistics_query( + &mut dst_pass, + query_set_id, + query_index, + ); + } + RenderCommand::EndPipelineStatisticsQuery => { + render_ffi::wgpu_render_pass_end_pipeline_statistics_query(&mut dst_pass); + } + RenderCommand::ExecuteBundle(bundle_id) => { + unsafe { + render_ffi::wgpu_render_pass_execute_bundles( + &mut dst_pass, + &bundle_id, + 1, + ); + } + } + } + } + + dst_pass +} + +pub fn replay_compute_pass( + id: CommandEncoderId, + src_pass: &RecordedComputePass +) -> wgc::command::ComputePass { + let mut dst_pass = wgc::command::ComputePass::new( + id, + &wgc::command::ComputePassDescriptor { + label: src_pass.base.label.as_ref().map(|s| s.as_str().into()), + timestamp_writes: src_pass.timestamp_writes.as_ref(), + }, + ); + + let mut dynamic_offsets = src_pass.base.dynamic_offsets.as_slice(); + let mut dynamic_offsets = |len| { + let offsets; + (offsets, dynamic_offsets) = dynamic_offsets.split_at(len); + offsets + }; + let mut strings = src_pass.base.string_data.as_slice(); + let mut strings = |len| { + let label; + (label, strings) = strings.split_at(len); + label + }; + for command in &src_pass.base.commands { + match *command { + ComputeCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group_id, + } => { + let offsets = dynamic_offsets(num_dynamic_offsets); + unsafe { + compute_ffi::wgpu_compute_pass_set_bind_group( + &mut dst_pass, + index, + bind_group_id, + offsets.as_ptr(), + offsets.len() + ); + } + } + ComputeCommand::SetPipeline(pipeline_id) => { + compute_ffi::wgpu_compute_pass_set_pipeline(&mut dst_pass, pipeline_id) + } + ComputeCommand::Dispatch([x, y, z]) => { + compute_ffi::wgpu_compute_pass_dispatch_workgroups(&mut dst_pass, x, y, z); + } + ComputeCommand::DispatchIndirect { buffer_id, offset } => { + compute_ffi::wgpu_compute_pass_dispatch_workgroups_indirect( + &mut dst_pass, + buffer_id, + offset, + ); + } + ComputeCommand::PushDebugGroup { color, len } => { + let label = strings(len); + let label = std::ffi::CString::new(label).unwrap(); + unsafe { + compute_ffi::wgpu_compute_pass_push_debug_group( + &mut dst_pass, + label.as_ptr(), + color + ); + } + } + ComputeCommand::PopDebugGroup => { + compute_ffi::wgpu_compute_pass_pop_debug_group(&mut dst_pass); + } + ComputeCommand::InsertDebugMarker { color, len } => { + let label = strings(len); + let label = std::ffi::CString::new(label).unwrap(); + unsafe { + compute_ffi::wgpu_compute_pass_insert_debug_marker( + &mut dst_pass, + label.as_ptr(), + color, + ); + } + } + ComputeCommand::WriteTimestamp { + query_set_id, + query_index, + } => { + compute_ffi::wgpu_compute_pass_write_timestamp( + &mut dst_pass, + query_set_id, + query_index, + ); + } + ComputeCommand::BeginPipelineStatisticsQuery { + query_set_id, + query_index, + } => { + compute_ffi::wgpu_compute_pass_begin_pipeline_statistics_query( + &mut dst_pass, + query_set_id, + query_index, + ); + } + ComputeCommand::EndPipelineStatisticsQuery => { + compute_ffi::wgpu_compute_pass_end_pipeline_statistics_query(&mut dst_pass); + } + } + } + + dst_pass +} diff --git a/gfx/wgpu_bindings/src/lib.rs b/gfx/wgpu_bindings/src/lib.rs index 3299234182..6e6b79c991 100644 --- a/gfx/wgpu_bindings/src/lib.rs +++ b/gfx/wgpu_bindings/src/lib.rs @@ -10,6 +10,7 @@ pub use wgc::command::{compute_ffi::*, render_ffi::*}; pub mod client; pub mod error; pub mod server; +pub mod command; pub use wgc::device::trace::Command as CommandEncoderAction; diff --git a/gfx/wgpu_bindings/src/server.rs b/gfx/wgpu_bindings/src/server.rs index 7a7e08aa30..8417fe84fb 100644 --- a/gfx/wgpu_bindings/src/server.rs +++ b/gfx/wgpu_bindings/src/server.rs @@ -410,7 +410,9 @@ pub extern "C" fn wgpu_server_device_create_shader_module( if let Some(err) = error { out_message.set_error(&err, &source_str[..]); let err_type = match &err { - CreateShaderModuleError::Device(DeviceError::OutOfMemory) => ErrorBufferType::OutOfMemory, + CreateShaderModuleError::Device(DeviceError::OutOfMemory) => { + ErrorBufferType::OutOfMemory + } CreateShaderModuleError::Device(DeviceError::Lost) => ErrorBufferType::DeviceLost, _ => ErrorBufferType::Validation, }; @@ -497,7 +499,8 @@ pub unsafe extern "C" fn wgpu_server_buffer_map( // the returned value of buffer_map_async. let result = gfx_select!(buffer_id => global.buffer_map_async( buffer_id, - start .. start + size, + start, + Some(size), operation )); @@ -580,9 +583,10 @@ pub extern "C" fn wgpu_server_get_device_fence_handle( if device_id.backend() == wgt::Backend::Dx12 { let mut handle = ptr::null_mut(); let dx12_device = unsafe { - global.device_as_hal::<wgc::api::Dx12, _, Option<d3d12::Device>>(device_id, |hal_device| { - hal_device.map(|device| device.raw_device().clone()) - }) + global.device_as_hal::<wgc::api::Dx12, _, Option<d3d12::Device>>( + device_id, + |hal_device| hal_device.map(|device| device.raw_device().clone()), + ) }; let dx12_device = match dx12_device { Some(device) => device, @@ -592,9 +596,10 @@ pub extern "C" fn wgpu_server_get_device_fence_handle( }; let dx12_fence = unsafe { - global.device_fence_as_hal::<wgc::api::Dx12, _, Option<d3d12::Fence>>(device_id, |hal_fence| { - hal_fence.map(|fence| fence.raw_fence().clone()) - }) + global.device_fence_as_hal::<wgc::api::Dx12, _, Option<d3d12::Fence>>( + device_id, + |hal_fence| hal_fence.map(|fence| fence.raw_fence().clone()), + ) }; let dx12_fence = match dx12_fence { Some(fence) => fence, @@ -1054,6 +1059,32 @@ pub unsafe extern "C" fn wgpu_server_command_encoder_action( } #[no_mangle] +pub unsafe extern "C" fn wgpu_server_render_pass( + global: &Global, + encoder_id: id::CommandEncoderId, + byte_buf: &ByteBuf, + error_buf: ErrorBuffer, +) { + let pass = bincode::deserialize(byte_buf.as_slice()).unwrap(); + let action = crate::command::replay_render_pass(encoder_id, &pass).into_command(); + + gfx_select!(encoder_id => global.command_encoder_action(encoder_id, action, error_buf)); +} + +#[no_mangle] +pub unsafe extern "C" fn wgpu_server_compute_pass( + global: &Global, + encoder_id: id::CommandEncoderId, + byte_buf: &ByteBuf, + error_buf: ErrorBuffer, +) { + let pass = bincode::deserialize(byte_buf.as_slice()).unwrap(); + let action = crate::command::replay_compute_pass(encoder_id, &pass).into_command(); + + gfx_select!(encoder_id => global.command_encoder_action(encoder_id, action, error_buf)); +} + +#[no_mangle] pub extern "C" fn wgpu_server_device_create_encoder( global: &Global, self_id: id::DeviceId, diff --git a/gfx/wr/Cargo.lock b/gfx/wr/Cargo.lock index 02491f3993..2bf28a1b6e 100644 --- a/gfx/wr/Cargo.lock +++ b/gfx/wr/Cargo.lock @@ -996,29 +996,22 @@ dependencies = [ [[package]] name = "glean" -version = "57.0.0" +version = "58.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae5847ad58b7f925c984de7f4dffcad67d7d0befa59a5a888cf93741b5ef1e6a" +checksum = "f58388f10d013e2d12bb58e6e76983ede120789956fe827913a3d2560c66d44d" dependencies = [ - "chrono", - "crossbeam-channel", "glean-core", "inherent", "log", "once_cell", - "serde", - "serde_json", - "thiserror", - "time", - "uuid", "whatsys", ] [[package]] name = "glean-core" -version = "57.0.0" +version = "58.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6831cadd28b625bc296732d71dc7c978f208ba27911cad072785f87f23b1e634" +checksum = "ed9acc46fd38c5c995a0537e76364496addace660839dc279079e5957e3c1093" dependencies = [ "android_logger", "bincode", @@ -1121,9 +1114,9 @@ dependencies = [ [[package]] name = "glslopt" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74a3f5c04450dfdadb4b08f6e5ee6f5110f674de1acbd6199bfec68392a8cbaf" +checksum = "ee5be629003d587bab188f3e2e3b010aa2cde7c41ec967b3a244f388d4d81877" dependencies = [ "cc", ] diff --git a/gfx/wr/peek-poke/peek-poke-derive/src/lib.rs b/gfx/wr/peek-poke/peek-poke-derive/src/lib.rs index ac20b2b922..9e26b22fba 100644 --- a/gfx/wr/peek-poke/peek-poke-derive/src/lib.rs +++ b/gfx/wr/peek-poke/peek-poke-derive/src/lib.rs @@ -12,23 +12,6 @@ use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::{Ident, Index, TraitBound}; use synstructure::{decl_derive, Structure, BindStyle, AddBounds}; -use unicode_xid::UnicodeXID; - -// Internal method for sanitizing an identifier for hygiene purposes. -fn sanitize_ident(s: &str) -> Ident { - let mut res = String::with_capacity(s.len()); - for mut c in s.chars() { - if !UnicodeXID::is_xid_continue(c) { - c = '_' - } - // Deduplicate consecutive _ characters. - if res.ends_with('_') && c == '_' { - continue; - } - res.push(c); - } - Ident::new(&res, Span::call_site()) -} /// Calculates size type for number of variants (used for enums) fn get_discriminant_size_type(len: usize) -> TokenStream { @@ -241,11 +224,9 @@ fn peek_poke_derive(mut s: Structure) -> TokenStream { s.add_trait_bounds(&default_trait, &mut where_clause, AddBounds::Generics); s.add_trait_bounds(&peek_trait, &mut where_clause, AddBounds::Generics); - let dummy_const: Ident = sanitize_ident(&format!("_DERIVE_peek_poke_Peek_FOR_{}", name)); - let peek_impl = quote! { #[allow(non_upper_case_globals)] - const #dummy_const: () = { + const _: () = { extern crate peek_poke; impl #impl_generics peek_poke::Peek for #name #ty_generics #where_clause { diff --git a/gfx/wr/webrender/Cargo.toml b/gfx/wr/webrender/Cargo.toml index ed364fc34d..506226beca 100644 --- a/gfx/wr/webrender/Cargo.toml +++ b/gfx/wr/webrender/Cargo.toml @@ -18,12 +18,12 @@ serialize_program = ["serde", "webrender_build/serialize_program"] dynamic_freetype = ["glyph_rasterizer/dynamic_freetype"] static_freetype = ["glyph_rasterizer/static_freetype"] leak_checks = [] -gecko = ["firefox-on-glean", "glyph_rasterizer/gecko"] +gecko = ["firefox-on-glean", "glean", "glyph_rasterizer/gecko"] sw_compositor = ["swgl"] [build-dependencies] build-parallel = "0.1.2" -glslopt = "0.1.9" +glslopt = "0.1.10" webrender_build = { version = "0.0.2", path = "../webrender_build" } [dependencies] @@ -52,7 +52,7 @@ svg_fmt = "0.4" tracy-rs = "0.1.2" derive_more = { version = "0.99", default-features = false, features = ["add_assign"] } etagere = "0.2.6" -glean = "57.0.0" +glean = { version = "58.1.0", optional = true } firefox-on-glean = { version = "0.1.0", optional = true } swgl = { path = "../swgl", optional = true } topological-sort = "0.1" diff --git a/gfx/wr/webrender/res/brush.glsl b/gfx/wr/webrender/res/brush.glsl index 8d0d52ce82..67c9255831 100644 --- a/gfx/wr/webrender/res/brush.glsl +++ b/gfx/wr/webrender/res/brush.glsl @@ -214,7 +214,7 @@ void main(void) { Instance instance = decode_instance_attributes(); PrimitiveHeader ph = fetch_prim_header(instance.prim_header_address); Transform transform = fetch_transform(ph.transform_id); - PictureTask task = fetch_picture_task(instance.picture_task_address); + PictureTask task = fetch_picture_task(ph.picture_task_address); ClipArea clip_area = fetch_clip_area(instance.clip_address); WR_VERTEX_SHADER_MAIN_FUNCTION(instance, ph, transform, task, clip_area); diff --git a/gfx/wr/webrender/res/brush_linear_gradient.glsl b/gfx/wr/webrender/res/brush_linear_gradient.glsl index ceb1b14e5b..235be4b24b 100644 --- a/gfx/wr/webrender/res/brush_linear_gradient.glsl +++ b/gfx/wr/webrender/res/brush_linear_gradient.glsl @@ -82,12 +82,12 @@ Fragment brush_fs() { #ifdef SWGL_DRAW_SPAN void swgl_drawSpanRGBA8() { - int address = swgl_validateGradient(sGpuBuffer, get_gpu_buffer_uv(v_gradient_address.x), int(GRADIENT_ENTRIES + 2.0)); + int address = swgl_validateGradient(sGpuBufferF, get_gpu_buffer_uv(v_gradient_address.x), int(GRADIENT_ENTRIES + 2.0)); if (address < 0) { return; } - swgl_commitLinearGradientRGBA8(sGpuBuffer, address, GRADIENT_ENTRIES, true, v_gradient_repeat.x != 0.0, + swgl_commitLinearGradientRGBA8(sGpuBufferF, address, GRADIENT_ENTRIES, true, v_gradient_repeat.x != 0.0, v_pos, v_scale_dir, v_start_offset.x); } #endif diff --git a/gfx/wr/webrender/res/cs_border_segment.glsl b/gfx/wr/webrender/res/cs_border_segment.glsl index e684bfa6df..7deb62f6ef 100644 --- a/gfx/wr/webrender/res/cs_border_segment.glsl +++ b/gfx/wr/webrender/res/cs_border_segment.glsl @@ -13,7 +13,7 @@ flat varying mediump vec4 vColor11; // A point + tangent defining the line where the edge // transition occurs. Used for corners only. -flat varying mediump vec4 vColorLine; +flat varying highp vec4 vColorLine; // x: segment, y: clip mode // We cast these to/from floats rather than using an ivec due to a driver bug @@ -31,13 +31,13 @@ flat varying highp vec4 vClipCenter_Sign; // An outer and inner elliptical radii for border // corner clipping. -flat varying mediump vec4 vClipRadii; +flat varying highp vec4 vClipRadii; // Reference point for determine edge clip lines. -flat varying mediump vec4 vEdgeReference; +flat varying highp vec4 vEdgeReference; // Stores widths/2 and widths/3 to save doing this in FS. -flat varying mediump vec4 vPartialWidths; +flat varying highp vec4 vPartialWidths; // Clipping parameters for dot or dash. flat varying mediump vec4 vClipParams1; diff --git a/gfx/wr/webrender/res/cs_clip_image.glsl b/gfx/wr/webrender/res/cs_clip_image.glsl deleted file mode 100644 index 24ba1dab8e..0000000000 --- a/gfx/wr/webrender/res/cs_clip_image.glsl +++ /dev/null @@ -1,117 +0,0 @@ -/* 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 shared,clip_shared - -varying highp vec2 vLocalPos; -varying highp vec2 vClipMaskImageUv; - -flat varying highp vec4 vClipMaskUvInnerRect; - -#ifdef WR_VERTEX_SHADER - -PER_INSTANCE in vec4 aClipTileRect; -PER_INSTANCE in ivec2 aClipDataResourceAddress; -PER_INSTANCE in vec4 aClipLocalRect; - -struct ClipMaskInstanceImage { - ClipMaskInstanceCommon base; - RectWithEndpoint tile_rect; - ivec2 resource_address; - RectWithEndpoint local_rect; -}; - -ClipMaskInstanceImage fetch_clip_item() { - ClipMaskInstanceImage cmi; - - cmi.base = fetch_clip_item_common(); - - cmi.tile_rect = RectWithEndpoint(aClipTileRect.xy, aClipTileRect.zw); - cmi.resource_address = aClipDataResourceAddress; - cmi.local_rect = RectWithEndpoint(aClipLocalRect.xy, aClipLocalRect.zw); - - return cmi; -} - -struct ClipImageVertexInfo { - vec2 local_pos; - vec4 world_pos; -}; - -// This differs from write_clip_tile_vertex in that we forward transform the -// primitive's local-space tile rect into the target space. We use scissoring -// to ensure that the primitive does not draw outside the target bounds. -ClipImageVertexInfo write_clip_image_vertex(RectWithEndpoint tile_rect, - RectWithEndpoint local_clip_rect, - Transform prim_transform, - Transform clip_transform, - RectWithEndpoint sub_rect, - vec2 task_origin, - vec2 screen_origin, - float device_pixel_scale) { - vec2 local_pos = rect_clamp(local_clip_rect, mix(tile_rect.p0, tile_rect.p1, aPosition.xy)); - vec4 world_pos = prim_transform.m * vec4(local_pos, 0.0, 1.0); - vec4 final_pos = vec4( - world_pos.xy * device_pixel_scale + (task_origin - screen_origin) * world_pos.w, - 0.0, - world_pos.w - ); - gl_Position = uTransform * final_pos; - - init_transform_vs( - clip_transform.is_axis_aligned - ? vec4(vec2(-1.0e16), vec2(1.0e16)) - : vec4(local_clip_rect.p0, local_clip_rect.p1)); - - ClipImageVertexInfo vi = ClipImageVertexInfo(local_pos, world_pos); - return vi; -} - -void main(void) { - ClipMaskInstanceImage cmi = fetch_clip_item(); - Transform clip_transform = fetch_transform(cmi.base.clip_transform_id); - Transform prim_transform = fetch_transform(cmi.base.prim_transform_id); - ImageSource res = fetch_image_source_direct(cmi.resource_address); - - ClipImageVertexInfo vi = write_clip_image_vertex( - cmi.tile_rect, - cmi.local_rect, - prim_transform, - clip_transform, - cmi.base.sub_rect, - cmi.base.task_origin, - cmi.base.screen_origin, - cmi.base.device_pixel_scale - ); - vLocalPos = vi.local_pos; - vec2 uv = (vi.local_pos - cmi.tile_rect.p0) / rect_size(cmi.tile_rect); - - vec2 texture_size = vec2(TEX_SIZE(sColor0)); - vec4 uv_rect = vec4(res.uv_rect.p0, res.uv_rect.p1); - vClipMaskImageUv = mix(uv_rect.xy, uv_rect.zw, uv) / texture_size; - - // applying a half-texel offset to the UV boundaries to prevent linear samples from the outside - vClipMaskUvInnerRect = (uv_rect + vec4(0.5, 0.5, -0.5, -0.5)) / texture_size.xyxy; -} -#endif - -#ifdef WR_FRAGMENT_SHADER -void main(void) { - float alpha = init_transform_rough_fs(vLocalPos); - vec2 source_uv = clamp(vClipMaskImageUv, vClipMaskUvInnerRect.xy, vClipMaskUvInnerRect.zw); - float clip_alpha = texture(sColor0, source_uv).r; //careful: texture has type A8 - oFragColor = vec4(mix(1.0, clip_alpha, alpha), 0.0, 0.0, 1.0); -} - -#ifdef SWGL_DRAW_SPAN -void swgl_drawSpanR8() { - if (has_valid_transform_bounds()) { - return; - } - - swgl_commitTextureLinearR8(sColor0, vClipMaskImageUv, vClipMaskUvInnerRect); -} -#endif - -#endif diff --git a/gfx/wr/webrender/res/cs_linear_gradient.glsl b/gfx/wr/webrender/res/cs_linear_gradient.glsl index b1aff899a6..1afee5818b 100644 --- a/gfx/wr/webrender/res/cs_linear_gradient.glsl +++ b/gfx/wr/webrender/res/cs_linear_gradient.glsl @@ -54,12 +54,12 @@ void main(void) { #ifdef SWGL_DRAW_SPAN void swgl_drawSpanRGBA8() { - int address = swgl_validateGradient(sGpuBuffer, get_gpu_buffer_uv(v_gradient_address.x), int(GRADIENT_ENTRIES + 2.0)); + int address = swgl_validateGradient(sGpuBufferF, get_gpu_buffer_uv(v_gradient_address.x), int(GRADIENT_ENTRIES + 2.0)); if (address < 0) { return; } - swgl_commitLinearGradientRGBA8(sGpuBuffer, address, GRADIENT_ENTRIES, false, v_gradient_repeat.x != 0.0, + swgl_commitLinearGradientRGBA8(sGpuBufferF, address, GRADIENT_ENTRIES, false, v_gradient_repeat.x != 0.0, v_pos, v_scale_dir, v_start_offset.x); } #endif diff --git a/gfx/wr/webrender/res/cs_radial_gradient.glsl b/gfx/wr/webrender/res/cs_radial_gradient.glsl index 16ffe06376..10919ac628 100644 --- a/gfx/wr/webrender/res/cs_radial_gradient.glsl +++ b/gfx/wr/webrender/res/cs_radial_gradient.glsl @@ -58,12 +58,12 @@ void main(void) { #ifdef SWGL_DRAW_SPAN void swgl_drawSpanRGBA8() { - int address = swgl_validateGradient(sGpuBuffer, get_gpu_buffer_uv(v_gradient_address.x), + int address = swgl_validateGradient(sGpuBufferF, get_gpu_buffer_uv(v_gradient_address.x), int(GRADIENT_ENTRIES + 2.0)); if (address < 0) { return; } - swgl_commitRadialGradientRGBA8(sGpuBuffer, address, GRADIENT_ENTRIES, v_gradient_repeat.x != 0.0, + swgl_commitRadialGradientRGBA8(sGpuBufferF, address, GRADIENT_ENTRIES, v_gradient_repeat.x != 0.0, v_pos, v_start_radius.x); } #endif diff --git a/gfx/wr/webrender/res/gpu_buffer.glsl b/gfx/wr/webrender/res/gpu_buffer.glsl index 25f4622db2..4923a28ef9 100644 --- a/gfx/wr/webrender/res/gpu_buffer.glsl +++ b/gfx/wr/webrender/res/gpu_buffer.glsl @@ -2,41 +2,47 @@ * 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/. */ -uniform HIGHP_SAMPLER_FLOAT sampler2D sGpuBuffer; +uniform HIGHP_SAMPLER_FLOAT sampler2D sGpuBufferF; +uniform HIGHP_SAMPLER_FLOAT isampler2D sGpuBufferI; ivec2 get_gpu_buffer_uv(HIGHP_FS_ADDRESS int address) { return ivec2(uint(address) % WR_MAX_VERTEX_TEXTURE_WIDTH, uint(address) / WR_MAX_VERTEX_TEXTURE_WIDTH); } -vec4 fetch_from_gpu_buffer_1(HIGHP_FS_ADDRESS int address) { +vec4 fetch_from_gpu_buffer_1f(HIGHP_FS_ADDRESS int address) { ivec2 uv = get_gpu_buffer_uv(address); - return texelFetch(sGpuBuffer, uv, 0); + return texelFetch(sGpuBufferF, uv, 0); } -vec4[2] fetch_from_gpu_buffer_2(HIGHP_FS_ADDRESS int address) { +vec4[2] fetch_from_gpu_buffer_2f(HIGHP_FS_ADDRESS int address) { ivec2 uv = get_gpu_buffer_uv(address); return vec4[2]( - TEXEL_FETCH(sGpuBuffer, uv, 0, ivec2(0, 0)), - TEXEL_FETCH(sGpuBuffer, uv, 0, ivec2(1, 0)) + TEXEL_FETCH(sGpuBufferF, uv, 0, ivec2(0, 0)), + TEXEL_FETCH(sGpuBufferF, uv, 0, ivec2(1, 0)) ); } -vec4[3] fetch_from_gpu_buffer_3(HIGHP_FS_ADDRESS int address) { +vec4[3] fetch_from_gpu_buffer_3f(HIGHP_FS_ADDRESS int address) { ivec2 uv = get_gpu_buffer_uv(address); return vec4[3]( - TEXEL_FETCH(sGpuBuffer, uv, 0, ivec2(0, 0)), - TEXEL_FETCH(sGpuBuffer, uv, 0, ivec2(1, 0)), - TEXEL_FETCH(sGpuBuffer, uv, 0, ivec2(2, 0)) + TEXEL_FETCH(sGpuBufferF, uv, 0, ivec2(0, 0)), + TEXEL_FETCH(sGpuBufferF, uv, 0, ivec2(1, 0)), + TEXEL_FETCH(sGpuBufferF, uv, 0, ivec2(2, 0)) ); } -vec4[4] fetch_from_gpu_buffer_4(HIGHP_FS_ADDRESS int address) { +vec4[4] fetch_from_gpu_buffer_4f(HIGHP_FS_ADDRESS int address) { ivec2 uv = get_gpu_buffer_uv(address); return vec4[4]( - TEXEL_FETCH(sGpuBuffer, uv, 0, ivec2(0, 0)), - TEXEL_FETCH(sGpuBuffer, uv, 0, ivec2(1, 0)), - TEXEL_FETCH(sGpuBuffer, uv, 0, ivec2(2, 0)), - TEXEL_FETCH(sGpuBuffer, uv, 0, ivec2(3, 0)) + TEXEL_FETCH(sGpuBufferF, uv, 0, ivec2(0, 0)), + TEXEL_FETCH(sGpuBufferF, uv, 0, ivec2(1, 0)), + TEXEL_FETCH(sGpuBufferF, uv, 0, ivec2(2, 0)), + TEXEL_FETCH(sGpuBufferF, uv, 0, ivec2(3, 0)) ); } + +ivec4 fetch_from_gpu_buffer_1i(HIGHP_FS_ADDRESS int address) { + ivec2 uv = get_gpu_buffer_uv(address); + return texelFetch(sGpuBufferI, uv, 0); +} diff --git a/gfx/wr/webrender/res/gradient.glsl b/gfx/wr/webrender/res/gradient.glsl index 87c011fefc..6ed2e69871 100644 --- a/gfx/wr/webrender/res/gradient.glsl +++ b/gfx/wr/webrender/res/gradient.glsl @@ -54,7 +54,7 @@ vec4 sample_gradient(float offset) { float entry_fract = x - entry_index; // Fetch the start and end color. There is a [start, end] color per entry. - vec4 texels[2] = fetch_from_gpu_buffer_2(v_gradient_address.x + 2 * int(entry_index)); + vec4 texels[2] = fetch_from_gpu_buffer_2f(v_gradient_address.x + 2 * int(entry_index)); // Finally interpolate and apply dithering return dither(texels[0] + texels[1] * entry_fract); diff --git a/gfx/wr/webrender/res/prim_shared.glsl b/gfx/wr/webrender/res/prim_shared.glsl index 1a599bf980..9762658776 100644 --- a/gfx/wr/webrender/res/prim_shared.glsl +++ b/gfx/wr/webrender/res/prim_shared.glsl @@ -44,7 +44,6 @@ PER_INSTANCE in ivec4 aData; struct Instance { int prim_header_address; - int picture_task_address; int clip_address; int segment_index; int flags; @@ -56,8 +55,7 @@ Instance decode_instance_attributes() { Instance instance; instance.prim_header_address = aData.x; - instance.picture_task_address = aData.y >> 16; - instance.clip_address = aData.y & 0xffff; + instance.clip_address = aData.y; instance.segment_index = aData.z & 0xffff; instance.flags = aData.z >> 16; instance.resource_address = aData.w & 0xffffff; @@ -72,6 +70,7 @@ struct PrimitiveHeader { float z; int specific_prim_address; int transform_id; + int picture_task_address; ivec4 user_data; }; @@ -90,6 +89,7 @@ PrimitiveHeader fetch_prim_header(int index) { ph.z = float(data0.x); ph.specific_prim_address = data0.y; ph.transform_id = data0.z; + ph.picture_task_address = data0.w; ph.user_data = data1; return ph; diff --git a/gfx/wr/webrender/res/ps_quad.glsl b/gfx/wr/webrender/res/ps_quad.glsl index ed6b35c3b8..94c80a93f7 100644 --- a/gfx/wr/webrender/res/ps_quad.glsl +++ b/gfx/wr/webrender/res/ps_quad.glsl @@ -2,12 +2,40 @@ * 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/. */ +/// The common infrastructure for ps_quad_* shaders. +/// +/// # Memory layout +/// +/// The diagram below shows the the various pieces of data fectched in the vertex shader: +/// +///```ascii +/// (int gpu buffer) +/// +---------------+ (sGpuCache) +/// (instance-step vertex attr) | Int header | +-----------+ +/// +-----------------------------+ | | | Transform | +/// | Quad instance (uvec4) | +--> | transform id +--> +-----------+ +/// | | | | z id | +/// | x: int prim address +---+ +---------------+ (float gpu buffer) +/// | y: float prim address +--------------------------> +-----------+--------------+-+-+ +/// | z: quad flags | (sGpuCache) | Quad Prim | Quad Segment | | | +/// | edge flags | +--------------------+ | | | | | +/// | part index | | Picture task | | bounds | rect | | | +/// | segment index | | | | clip | uv rect | | | +/// | w: picture task address +--> | task rect | | color | | | | +/// +-----------------------------+ | device pixel scale | +-----------+--------------+-+-+ +/// | content origin | +/// +--------------------+ +///``` + #define WR_FEATURE_TEXTURE_2D #include shared,rect,transform,render_task,gpu_buffer flat varying mediump vec4 v_color; flat varying mediump vec4 v_uv_sample_bounds; +// x: (in ps_quad_textured) has edge flags +// y: has uv rect +// z: (in ps_quad_textured) sample as mask flat varying lowp ivec4 v_flags; varying highp vec2 v_uv; @@ -61,7 +89,7 @@ struct QuadPrimitive { QuadSegment fetch_segment(int base, int index) { QuadSegment seg; - vec4 texels[2] = fetch_from_gpu_buffer_2(base + 3 + index * 2); + vec4 texels[2] = fetch_from_gpu_buffer_2f(base + 3 + index * 2); seg.rect = RectWithEndpoint(texels[0].xy, texels[0].zw); seg.uv_rect = texels[1]; @@ -72,7 +100,7 @@ QuadSegment fetch_segment(int base, int index) { QuadPrimitive fetch_primitive(int index) { QuadPrimitive prim; - vec4 texels[3] = fetch_from_gpu_buffer_3(index); + vec4 texels[3] = fetch_from_gpu_buffer_3f(index); prim.bounds = RectWithEndpoint(texels[0].xy, texels[0].zw); prim.clip = RectWithEndpoint(texels[1].xy, texels[1].zw); @@ -81,37 +109,51 @@ QuadPrimitive fetch_primitive(int index) { return prim; } +struct QuadHeader { + int transform_id; + int z_id; +}; + +QuadHeader fetch_header(int address) { + ivec4 header = fetch_from_gpu_buffer_1i(address); + + QuadHeader qh = QuadHeader( + header.x, + header.y + ); + + return qh; +} + struct QuadInstance { // x - int prim_address; + int prim_address_i; // y - int quad_flags; - int edge_flags; - int picture_task_address; + int prim_address_f; // z + int quad_flags; + int edge_flags; int part_index; - int z_id; + int segment_index; // w - int segment_index; - int transform_id; + int picture_task_address; }; QuadInstance decode_instance() { QuadInstance qi = QuadInstance( aData.x, - (aData.y >> 24) & 0xff, - (aData.y >> 16) & 0xff, - aData.y & 0xffff, + aData.y, (aData.z >> 24) & 0xff, - aData.z & 0xffffff, + (aData.z >> 16) & 0xff, + (aData.z >> 8) & 0xff, + (aData.z >> 0) & 0xff, - (aData.w >> 24) & 0xff, - aData.w & 0xffffff + aData.w ); return qi; @@ -165,17 +207,18 @@ float edge_aa_offset(int edge, int flags) { PrimitiveInfo ps_quad_main(void) { QuadInstance qi = decode_instance(); - Transform transform = fetch_transform(qi.transform_id); + QuadHeader qh = fetch_header(qi.prim_address_i); + Transform transform = fetch_transform(qh.transform_id); PictureTask task = fetch_picture_task(qi.picture_task_address); - QuadPrimitive prim = fetch_primitive(qi.prim_address); - float z = float(qi.z_id); + QuadPrimitive prim = fetch_primitive(qi.prim_address_f); + float z = float(qh.z_id); QuadSegment seg; if (qi.segment_index == INVALID_SEGMENT_INDEX) { seg.rect = prim.bounds; seg.uv_rect = vec4(0.0); } else { - seg = fetch_segment(qi.prim_address, qi.segment_index); + seg = fetch_segment(qi.prim_address_f, qi.segment_index); } // The local space rect that we will draw, which is effectively: diff --git a/gfx/wr/webrender/res/ps_quad_mask.glsl b/gfx/wr/webrender/res/ps_quad_mask.glsl index 4b28109726..6b72714efb 100644 --- a/gfx/wr/webrender/res/ps_quad_mask.glsl +++ b/gfx/wr/webrender/res/ps_quad_mask.glsl @@ -2,6 +2,8 @@ * 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/. */ +/// This shader applies a (rounded) rectangle mask to the content of the framebuffer. + #include ps_quad,ellipse varying highp vec4 vClipLocalPos; @@ -45,12 +47,12 @@ Clip fetch_clip(int index) { clip.space = aClipData.z; #ifdef WR_FEATURE_FAST_PATH - vec4 texels[3] = fetch_from_gpu_buffer_3(index); + vec4 texels[3] = fetch_from_gpu_buffer_3f(index); clip.rect = RectWithEndpoint(texels[0].xy, texels[0].zw); clip.radii = texels[1]; clip.mode = texels[2].x; #else - vec4 texels[4] = fetch_from_gpu_buffer_4(index); + vec4 texels[4] = fetch_from_gpu_buffer_4f(index); clip.rect = RectWithEndpoint(texels[0].xy, texels[0].zw); clip.radii_top = texels[1]; clip.radii_bottom = texels[2]; diff --git a/gfx/wr/webrender/res/ps_quad_textured.glsl b/gfx/wr/webrender/res/ps_quad_textured.glsl index 48579eb4fe..2382623cdb 100644 --- a/gfx/wr/webrender/res/ps_quad_textured.glsl +++ b/gfx/wr/webrender/res/ps_quad_textured.glsl @@ -2,6 +2,8 @@ * 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/. */ +/// This shader renders solid colors or simple images in a color or alpha target. + #include ps_quad #ifndef SWGL_ANTIALIAS diff --git a/gfx/wr/webrender/res/ps_text_run.glsl b/gfx/wr/webrender/res/ps_text_run.glsl index aabc1e9d8a..9faac99620 100644 --- a/gfx/wr/webrender/res/ps_text_run.glsl +++ b/gfx/wr/webrender/res/ps_text_run.glsl @@ -100,7 +100,7 @@ void main() { PrimitiveHeader ph = fetch_prim_header(instance.prim_header_address); Transform transform = fetch_transform(ph.transform_id); ClipArea clip_area = fetch_clip_area(instance.clip_address); - PictureTask task = fetch_picture_task(instance.picture_task_address); + PictureTask task = fetch_picture_task(ph.picture_task_address); int glyph_index = instance.segment_index; int subpx_dir = (instance.flags >> 8) & 0xff; diff --git a/gfx/wr/webrender/res/render_task.glsl b/gfx/wr/webrender/res/render_task.glsl index cd9aea402c..e5d0c298cd 100644 --- a/gfx/wr/webrender/res/render_task.glsl +++ b/gfx/wr/webrender/res/render_task.glsl @@ -73,7 +73,7 @@ PictureTask fetch_picture_task(int address) { return task; } -#define CLIP_TASK_EMPTY 0x7FFF +#define CLIP_TASK_EMPTY 0x7FFFFFFF struct ClipArea { RectWithEndpoint task_rect; @@ -82,21 +82,22 @@ struct ClipArea { }; ClipArea fetch_clip_area(int index) { - ClipArea area; - + RenderTaskData task_data; if (index >= CLIP_TASK_EMPTY) { - area.task_rect = RectWithEndpoint(vec2(0.0), vec2(0.0)); - area.device_pixel_scale = 0.0; - area.screen_origin = vec2(0.0); + // We deliberately create a dummy RenderTaskData here then convert to a + // ClipArea after this if-else statement, rather than initialize the + // ClipArea in separate branches, to avoid a miscompile in some Adreno + // drivers. See bug 1884791. Unfortunately the specific details of the bug + // are unknown, so please take extra care not to regress this when + // refactoring. + task_data = RenderTaskData(RectWithEndpoint(vec2(0.0), vec2(0.0)), + vec4(0.0)); } else { - RenderTaskData task_data = fetch_render_task_data(index); - - area.task_rect = task_data.task_rect; - area.device_pixel_scale = task_data.user_data.x; - area.screen_origin = task_data.user_data.yz; + task_data = fetch_render_task_data(index); } - return area; + return ClipArea(task_data.task_rect, task_data.user_data.x, + task_data.user_data.yz); } #endif //WR_VERTEX_SHADER diff --git a/gfx/wr/webrender/src/batch.rs b/gfx/wr/webrender/src/batch.rs index f39b60acc6..605283c58d 100644 --- a/gfx/wr/webrender/src/batch.rs +++ b/gfx/wr/webrender/src/batch.rs @@ -16,7 +16,7 @@ use crate::gpu_types::{SplitCompositeInstance, QuadInstance}; use crate::gpu_types::{PrimitiveInstanceData, RasterizationSpace, GlyphInstance}; use crate::gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette}; use crate::gpu_types::{ImageBrushData, get_shader_opacity, BoxShadowData, MaskInstance}; -use crate::gpu_types::{ClipMaskInstanceCommon, ClipMaskInstanceImage, ClipMaskInstanceRect, ClipMaskInstanceBoxShadow}; +use crate::gpu_types::{ClipMaskInstanceCommon, ClipMaskInstanceRect, ClipMaskInstanceBoxShadow}; use crate::internal_types::{FastHashMap, Swizzle, TextureSource, Filter}; use crate::picture::{Picture3DContext, PictureCompositeMode, calculate_screen_uv}; use crate::prim_store::{PrimitiveInstanceKind, ClipData}; @@ -26,8 +26,8 @@ use crate::prim_store::{VECS_PER_SEGMENT, PrimitiveInstanceIndex}; use crate::render_target::RenderTargetContext; use crate::render_task_graph::{RenderTaskId, RenderTaskGraph}; use crate::render_task::{RenderTaskAddress, RenderTaskKind, SubPass}; -use crate::renderer::{BlendMode, ShaderColorMode}; -use crate::renderer::{MAX_VERTEX_TEXTURE_WIDTH, GpuBufferBuilder, GpuBufferAddress}; +use crate::renderer::{BlendMode, GpuBufferBuilder, ShaderColorMode}; +use crate::renderer::{MAX_VERTEX_TEXTURE_WIDTH, GpuBufferAddress}; use crate::resource_cache::{GlyphFetchResult, ImageProperties}; use crate::space::SpaceMapper; use crate::visibility::{PrimitiveVisibilityFlags, VisibilityState}; @@ -38,7 +38,7 @@ use crate::segment::EdgeAaSegmentMask; // Special sentinel value recognized by the shader. It is considered to be // a dummy task that doesn't mask out anything. -const OPAQUE_TASK_ADDRESS: RenderTaskAddress = RenderTaskAddress(0x7fff); +const OPAQUE_TASK_ADDRESS: RenderTaskAddress = RenderTaskAddress(0x7fffffff); /// Used to signal there are no segments provided with this primitive. pub const INVALID_SEGMENT_INDEX: i32 = 0xffff; @@ -745,13 +745,10 @@ impl BatchBuilder { prim_header_index: PrimitiveHeaderIndex, resource_address: i32, ) { - let render_task_address = self.batcher.render_task_address; - let instance = BrushInstance { segment_index, edge_flags, clip_task_address, - render_task_address, brush_flags, prim_header_index, resource_address, @@ -803,7 +800,7 @@ impl BatchBuilder { &mut self, prim_instance_index: PrimitiveInstanceIndex, transform_id: TransformPaletteId, - gpu_buffer_address: GpuBufferAddress, + prim_address_f: GpuBufferAddress, quad_flags: QuadFlags, edge_flags: EdgeAaSegmentMask, segment_index: u8, @@ -811,6 +808,7 @@ impl BatchBuilder { z_generator: &mut ZBufferIdGenerator, prim_instances: &[PrimitiveInstance], render_tasks: &RenderTaskGraph, + gpu_buffer_builder: &mut GpuBufferBuilder, ) { let prim_instance = &prim_instances[prim_instance_index.0 as usize]; let prim_info = &prim_instance.vis; @@ -820,13 +818,14 @@ impl BatchBuilder { add_quad_to_batch( self.batcher.render_task_address, transform_id, - gpu_buffer_address, + prim_address_f, quad_flags, edge_flags, segment_index, task_id, z_id, render_tasks, + gpu_buffer_builder, |key, instance| { let batch = self.batcher.set_params_and_get_batch( key, @@ -857,7 +856,7 @@ impl BatchBuilder { surface_spatial_node_index: SpatialNodeIndex, z_generator: &mut ZBufferIdGenerator, prim_instances: &[PrimitiveInstance], - _gpu_buffer_builder: &mut GpuBufferBuilder, + gpu_buffer_builder: &mut GpuBufferBuilder, segments: &[RenderTaskId], ) { let (prim_instance_index, extra_prim_gpu_address) = match cmd { @@ -883,6 +882,7 @@ impl BatchBuilder { z_generator, prim_instances, render_tasks, + gpu_buffer_builder, ); } else { for (i, task_id) in segments.iter().enumerate() { @@ -900,6 +900,7 @@ impl BatchBuilder { z_generator, prim_instances, render_tasks, + gpu_buffer_builder, ); } } @@ -1005,6 +1006,7 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, + self.batcher.render_task_address, [get_shader_opacity(1.0), 0, 0, 0], ); @@ -1083,6 +1085,7 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, + self.batcher.render_task_address, batch_params.prim_user_data, ); @@ -1137,6 +1140,7 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, + self.batcher.render_task_address, [ (run.raster_scale * 65535.0).round() as i32, 0, @@ -1312,7 +1316,6 @@ impl BatchBuilder { let key = BatchKey::new(kind, blend_mode, textures); - let render_task_address = batcher.render_task_address; let batch = batcher.alpha_batch_list.set_params_and_get_batch( key, batch_features, @@ -1323,7 +1326,6 @@ impl BatchBuilder { batch.reserve(glyphs.len()); for glyph in glyphs { batch.push(base_instance.build( - render_task_address, clip_task_address, subpx_dir, glyph.index_in_text_run, @@ -1397,6 +1399,7 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, + self.batcher.render_task_address, prim_user_data, ); @@ -1531,6 +1534,7 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, + self.batcher.render_task_address, ImageBrushData { color_mode: ShaderColorMode::Image, alpha_type: AlphaType::PremultipliedAlpha, @@ -1616,6 +1620,7 @@ impl BatchBuilder { let shadow_prim_header_index = prim_headers.push( &shadow_prim_header, z_id, + self.batcher.render_task_address, ImageBrushData { color_mode: ShaderColorMode::Alpha, alpha_type: AlphaType::PremultipliedAlpha, @@ -1642,6 +1647,7 @@ impl BatchBuilder { let content_prim_header_index = prim_headers.push( &prim_header, z_id_content, + self.batcher.render_task_address, ImageBrushData { color_mode: ShaderColorMode::Image, alpha_type: AlphaType::PremultipliedAlpha, @@ -1687,12 +1693,17 @@ impl BatchBuilder { textures, ); - let prim_header_index = prim_headers.push(&prim_header, z_id, [ - uv_rect_address.as_int(), - amount, - 0, - 0, - ]); + let prim_header_index = prim_headers.push( + &prim_header, + z_id, + self.batcher.render_task_address, + [ + uv_rect_address.as_int(), + amount, + 0, + 0, + ] + ); self.add_brush_instance_to_batches( key, @@ -1771,12 +1782,17 @@ impl BatchBuilder { textures, ); - let prim_header_index = prim_headers.push(&prim_header, z_id, [ - uv_rect_address.as_int(), - filter_mode, - user_data, - 0, - ]); + let prim_header_index = prim_headers.push( + &prim_header, + z_id, + self.batcher.render_task_address, + [ + uv_rect_address.as_int(), + filter_mode, + user_data, + 0, + ] + ); self.add_brush_instance_to_batches( key, @@ -1826,12 +1842,17 @@ impl BatchBuilder { textures, ); - let prim_header_index = prim_headers.push(&prim_header, z_id, [ - uv_rect_address.as_int(), - filter_mode, - user_data, - 0, - ]); + let prim_header_index = prim_headers.push( + &prim_header, + z_id, + self.batcher.render_task_address, + [ + uv_rect_address.as_int(), + filter_mode, + user_data, + 0, + ] + ); self.add_brush_instance_to_batches( key, @@ -1882,6 +1903,7 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, + self.batcher.render_task_address, ImageBrushData { color_mode: match key.blend_mode { BlendMode::MultiplyDualSource => ShaderColorMode::MultiplyDualSource, @@ -1924,8 +1946,6 @@ impl BatchBuilder { // and allow mix-blends to operate on picture cache surfaces without // a separate isolated intermediate surface. - let render_task_address = self.batcher.render_task_address; - let batch_key = BatchKey::new( BatchKind::Brush( BrushBatchKind::MixBlend { @@ -1953,18 +1973,22 @@ impl BatchBuilder { ); let src_uv_address = render_tasks[pic_task_id].get_texture_address(gpu_cache); let readback_uv_address = render_tasks[backdrop_id].get_texture_address(gpu_cache); - let prim_header_index = prim_headers.push(&prim_header, z_id, [ - mode as u32 as i32, - readback_uv_address.as_int(), - src_uv_address.as_int(), - 0, - ]); + let prim_header_index = prim_headers.push( + &prim_header, + z_id, + self.batcher.render_task_address, + [ + mode as u32 as i32, + readback_uv_address.as_int(), + src_uv_address.as_int(), + 0, + ] + ); let instance = BrushInstance { segment_index: INVALID_SEGMENT_INDEX, edge_flags: EdgeAaSegmentMask::all(), clip_task_address, - render_task_address, brush_flags, prim_header_index, resource_address: 0, @@ -2030,12 +2054,17 @@ impl BatchBuilder { // by this inner loop. let z_id = z_generator.next(); - let prim_header_index = prim_headers.push(&prim_header, z_id, [ - uv_rect_address.as_int(), - BrushFlags::PERSPECTIVE_INTERPOLATION.bits() as i32, - 0, - child_clip_task_address.0 as i32, - ]); + let prim_header_index = prim_headers.push( + &prim_header, + z_id, + self.batcher.render_task_address, + [ + uv_rect_address.as_int(), + BrushFlags::PERSPECTIVE_INTERPOLATION.bits() as i32, + 0, + child_clip_task_address.0 as i32, + ] + ); let key = BatchKey::new( BatchKind::SplitComposite, @@ -2088,6 +2117,7 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, + self.batcher.render_task_address, batch_params.prim_user_data, ); @@ -2141,6 +2171,7 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, + self.batcher.render_task_address, ImageBrushData { color_mode: ShaderColorMode::Image, alpha_type: AlphaType::PremultipliedAlpha, @@ -2215,6 +2246,7 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, + self.batcher.render_task_address, batch_params.prim_user_data, ); @@ -2274,6 +2306,7 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, + self.batcher.render_task_address, batch_params.prim_user_data, ); @@ -2394,6 +2427,7 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, + self.batcher.render_task_address, batch_params.prim_user_data, ); @@ -2498,6 +2532,7 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, + self.batcher.render_task_address, batch_params.prim_user_data, ); @@ -2547,7 +2582,12 @@ impl BatchBuilder { specific_prim_address: gpu_cache.get_address(&gpu_handle), transform_id, }; - let prim_header_index = prim_headers.push(&prim_header, z_id, prim_user_data); + let prim_header_index = prim_headers.push( + &prim_header, + z_id, + self.batcher.render_task_address, + prim_user_data, + ); for (i, tile) in chunk.iter().enumerate() { let (uv_rect_address, texture) = match render_tasks.resolve_location(tile.src_color, gpu_cache) { @@ -2616,7 +2656,12 @@ impl BatchBuilder { prim_header.specific_prim_address = gpu_cache.get_address(&prim_data.gpu_cache_handle); - let prim_header_index = prim_headers.push(&prim_header, z_id, user_data); + let prim_header_index = prim_headers.push( + &prim_header, + z_id, + self.batcher.render_task_address, + user_data, + ); let segments = if prim_data.brush_segments.is_empty() { None @@ -2660,7 +2705,12 @@ impl BatchBuilder { local_clip_rect: tile.local_clip_rect, ..prim_header }; - let prim_header_index = prim_headers.push(&tile_prim_header, z_id, user_data); + let prim_header_index = prim_headers.push( + &tile_prim_header, + z_id, + self.batcher.render_task_address, + user_data, + ); self.add_brush_instance_to_batches( key, @@ -2735,6 +2785,7 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, + self.batcher.render_task_address, batch_params.prim_user_data, ); @@ -2777,7 +2828,12 @@ impl BatchBuilder { local_clip_rect: tile.local_clip_rect, ..prim_header }; - let prim_header_index = prim_headers.push(&tile_prim_header, z_id, prim_user_data); + let prim_header_index = prim_headers.push( + &tile_prim_header, + z_id, + self.batcher.render_task_address, + prim_user_data, + ); self.add_brush_instance_to_batches( batch_key, @@ -2853,6 +2909,7 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, + self.batcher.render_task_address, batch_params.prim_user_data, ); @@ -2895,7 +2952,12 @@ impl BatchBuilder { local_clip_rect: tile.local_clip_rect, ..prim_header }; - let prim_header_index = prim_headers.push(&tile_prim_header, z_id, prim_user_data); + let prim_header_index = prim_headers.push( + &tile_prim_header, + z_id, + self.batcher.render_task_address, + prim_user_data, + ); self.add_brush_instance_to_batches( batch_key, @@ -2972,6 +3034,7 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, + self.batcher.render_task_address, batch_params.prim_user_data, ); @@ -3014,7 +3077,12 @@ impl BatchBuilder { local_clip_rect: tile.local_clip_rect, ..prim_header }; - let prim_header_index = prim_headers.push(&tile_prim_header, z_id, prim_user_data); + let prim_header_index = prim_headers.push( + &tile_prim_header, + z_id, + self.batcher.render_task_address, + prim_user_data, + ); self.add_brush_instance_to_batches( batch_key, @@ -3068,6 +3136,7 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, + self.batcher.render_task_address, ImageBrushData { color_mode: ShaderColorMode::Image, alpha_type: AlphaType::PremultipliedAlpha, @@ -3179,6 +3248,7 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, + self.batcher.render_task_address, [get_shader_opacity(1.0), 0, 0, 0], ); @@ -3477,8 +3547,6 @@ pub struct ClipBatchList { /// Rectangle draws fill up the rectangles with rounded corners. pub slow_rectangles: Vec<ClipMaskInstanceRect>, pub fast_rectangles: Vec<ClipMaskInstanceRect>, - /// Image draws apply the image masking. - pub images: FastHashMap<(TextureSource, Option<DeviceIntRect>), Vec<ClipMaskInstanceImage>>, pub box_shadows: FastHashMap<TextureSource, Vec<ClipMaskInstanceBoxShadow>>, } @@ -3487,7 +3555,6 @@ impl ClipBatchList { ClipBatchList { slow_rectangles: Vec::new(), fast_rectangles: Vec::new(), - images: FastHashMap::default(), box_shadows: FastHashMap::default(), } } @@ -3674,20 +3741,11 @@ impl ClipBatcher { ctx.spatial_tree, ); - // For clip mask images, we need to map from the primitive's layout space to - // the target space, as the cs_clip_image shader needs to forward transform - // the local image bounds, rather than backwards transform the target bounds - // as in done in write_clip_tile_vertex. - let prim_transform_id = match clip_node.item.kind { - ClipItemKind::Image { .. } => { panic!("bug: old path not supported") } - _ => { - transforms.get_id( - root_spatial_node_index, - ctx.root_spatial_node_index, - ctx.spatial_tree, - ) - } - }; + let prim_transform_id = transforms.get_id( + root_spatial_node_index, + ctx.root_spatial_node_index, + ctx.spatial_tree, + ); let common = ClipMaskInstanceCommon { sub_rect: DeviceRect::from_size(actual_rect.size()), @@ -3837,13 +3895,14 @@ impl<'a, 'rc> RenderTargetContext<'a, 'rc> { pub fn add_quad_to_batch<F>( render_task_address: RenderTaskAddress, transform_id: TransformPaletteId, - gpu_buffer_address: GpuBufferAddress, + prim_address_f: GpuBufferAddress, quad_flags: QuadFlags, edge_flags: EdgeAaSegmentMask, segment_index: u8, task_id: RenderTaskId, z_id: ZBufferId, render_tasks: &RenderTaskGraph, + gpu_buffer_builder: &mut GpuBufferBuilder, mut f: F, ) where F: FnMut(BatchKey, PrimitiveInstanceData) { @@ -3857,6 +3916,15 @@ pub fn add_quad_to_batch<F>( All = 5, } + let mut writer = gpu_buffer_builder.i32.write_blocks(1); + writer.push_one([ + transform_id.0 as i32, + z_id.0, + 0, + 0, + ]); + let prim_address_i = writer.finish(); + let texture = match task_id { RenderTaskId::INVALID => { TextureSource::Invalid @@ -3898,7 +3966,8 @@ pub fn add_quad_to_batch<F>( if edge_flags.is_empty() { let instance = QuadInstance { render_task_address, - prim_address: gpu_buffer_address, + prim_address_i, + prim_address_f, z_id, transform_id, edge_flags: edge_flags_bits, @@ -3911,7 +3980,8 @@ pub fn add_quad_to_batch<F>( } else if quad_flags.contains(QuadFlags::USE_AA_SEGMENTS) { let main_instance = QuadInstance { render_task_address, - prim_address: gpu_buffer_address, + prim_address_i, + prim_address_f, z_id, transform_id, edge_flags: edge_flags_bits, @@ -3956,7 +4026,8 @@ pub fn add_quad_to_batch<F>( } else { let instance = QuadInstance { render_task_address, - prim_address: gpu_buffer_address, + prim_address_i, + prim_address_f, z_id, transform_id, edge_flags: edge_flags_bits, diff --git a/gfx/wr/webrender/src/device/gl.rs b/gfx/wr/webrender/src/device/gl.rs index 5ad9469185..04a7e13023 100644 --- a/gfx/wr/webrender/src/device/gl.rs +++ b/gfx/wr/webrender/src/device/gl.rs @@ -138,9 +138,13 @@ pub enum UploadMethod { } /// Plain old data that can be used to initialize a texture. -pub unsafe trait Texel: Copy {} -unsafe impl Texel for u8 {} -unsafe impl Texel for f32 {} +pub unsafe trait Texel: Copy + Default { + fn image_format() -> ImageFormat; +} + +unsafe impl Texel for u8 { + fn image_format() -> ImageFormat { ImageFormat::R8 } +} /// Returns the size in bytes of a depth target with the given dimensions. fn depth_target_size_in_bytes(dimensions: &DeviceIntSize) -> usize { diff --git a/gfx/wr/webrender/src/frame_builder.rs b/gfx/wr/webrender/src/frame_builder.rs index 4ff798c103..b975c960eb 100644 --- a/gfx/wr/webrender/src/frame_builder.rs +++ b/gfx/wr/webrender/src/frame_builder.rs @@ -25,7 +25,7 @@ use crate::prim_store::{PictureIndex, PrimitiveScratchBuffer}; use crate::prim_store::{DeferredResolve, PrimitiveInstance}; use crate::profiler::{self, TransactionProfile}; use crate::render_backend::{DataStores, ScratchBuffer}; -use crate::renderer::{GpuBuffer, GpuBufferBuilder}; +use crate::renderer::{GpuBufferF, GpuBufferBuilderF, GpuBufferI, GpuBufferBuilderI, GpuBufferBuilder}; use crate::render_target::{RenderTarget, PictureCacheTarget, TextureCacheRenderTarget, PictureCacheTargetKind}; use crate::render_target::{RenderTargetContext, RenderTargetKind, AlphaRenderTarget, ColorRenderTarget}; use crate::render_task_graph::{RenderTaskGraph, Pass, SubPassSurface}; @@ -558,7 +558,10 @@ impl FrameBuilder { let mut cmd_buffers = CommandBufferList::new(); // TODO(gw): Recycle backing vec buffers for gpu buffer builder between frames - let mut gpu_buffer_builder = GpuBufferBuilder::new(); + let mut gpu_buffer_builder = GpuBufferBuilder { + f32: GpuBufferBuilderF::new(), + i32: GpuBufferBuilderI::new(), + }; self.build_layer_screen_rects_and_cull_layers( scene, @@ -690,7 +693,8 @@ impl FrameBuilder { scene.clip_store.end_frame(&mut scratch.clip_store); scratch.end_frame(); - let gpu_buffer = gpu_buffer_builder.finalize(&render_tasks); + let gpu_buffer_f = gpu_buffer_builder.f32.finalize(&render_tasks); + let gpu_buffer_i = gpu_buffer_builder.i32.finalize(&render_tasks); Frame { device_rect: DeviceIntRect::from_origin_and_size( @@ -707,7 +711,8 @@ impl FrameBuilder { prim_headers, debug_items: mem::replace(&mut scratch.primitive.debug_items, Vec::new()), composite_state, - gpu_buffer, + gpu_buffer_f, + gpu_buffer_i, } } @@ -759,7 +764,6 @@ impl FrameBuilder { const LAYOUT_PORT_COLOR: ColorF = debug_colors::RED; const VISUAL_PORT_COLOR: ColorF = debug_colors::BLUE; const DISPLAYPORT_COLOR: ColorF = debug_colors::LIME; - const NOTHING: ColorF = ColorF { r: 0.0, g: 0.0, b: 0.0, a: 0.0 }; let viewport = scroll_frame_info.viewport_rect; @@ -805,9 +809,10 @@ impl FrameBuilder { } let mut add_rect = |rect, border, fill| -> Option<()> { + const STROKE_WIDTH: f32 = 2.0; // Place rect in scroll frame's local coordinate space let transformed_rect = transform.outer_transformed_box2d(&rect)?; - + // Transform to world coordinates, using root-content coords as an intermediate step. let mut root_content_rect = local_to_root_content.outer_transformed_box2d(&transformed_rect)?; // In root-content coords, apply the root content node's viewport clip. @@ -820,21 +825,28 @@ impl FrameBuilder { } let world_rect = root_content_to_world.outer_transformed_box2d(&root_content_rect)?; + scratch.push_debug_rect_with_stroke_width(world_rect, border, STROKE_WIDTH); + // Add world coordinate rects to scratch.debug_items - // TODO: Add a parameter to control the border thickness of the rects, and make them a bit thicker. - scratch.push_debug_rect(world_rect * DevicePixelScale::new(1.0), border, fill); + if let Some(fill_color) = fill { + let interior_world_rect = WorldRect::new( + world_rect.min + WorldVector2D::new(STROKE_WIDTH, STROKE_WIDTH), + world_rect.max - WorldVector2D::new(STROKE_WIDTH, STROKE_WIDTH) + ); + scratch.push_debug_rect(interior_world_rect * DevicePixelScale::new(1.0), border, fill_color); + } Some(()) }; - add_rect(minimap_data.scrollable_rect, PAGE_BORDER_COLOR, BACKGROUND_COLOR); - add_rect(minimap_data.visual_viewport, VISUAL_PORT_COLOR, NOTHING); - add_rect(minimap_data.displayport, DISPLAYPORT_COLOR, DISPLAYPORT_BACKGROUND_COLOR); + add_rect(minimap_data.scrollable_rect, PAGE_BORDER_COLOR, Some(BACKGROUND_COLOR)); + add_rect(minimap_data.displayport, DISPLAYPORT_COLOR, Some(DISPLAYPORT_BACKGROUND_COLOR)); // Only render a distinct layout viewport for the root content. // For other scroll frames, the visual and layout viewports coincide. if minimap_data.is_root_content { - add_rect(minimap_data.layout_viewport, LAYOUT_PORT_COLOR, NOTHING); + add_rect(minimap_data.layout_viewport, LAYOUT_PORT_COLOR, None); } + add_rect(minimap_data.visual_viewport, VISUAL_PORT_COLOR, None); } } }); @@ -967,7 +979,6 @@ pub fn build_render_pass( let task_id = sub_pass.task_ids[0]; let task = &render_tasks[task_id]; let target_rect = task.get_target_rect(); - let mut gpu_buffer_builder = GpuBufferBuilder::new(); match task.kind { RenderTaskKind::Picture(ref pic_task) => { @@ -998,7 +1009,7 @@ pub fn build_render_pass( pic_task.surface_spatial_node_index, z_generator, prim_instances, - &mut gpu_buffer_builder, + gpu_buffer_builder, segments, ); }); @@ -1072,6 +1083,7 @@ pub fn build_render_pass( z_generator, prim_instances, cmd_buffers, + gpu_buffer_builder, ); pass.alpha.build( ctx, @@ -1082,6 +1094,7 @@ pub fn build_render_pass( z_generator, prim_instances, cmd_buffers, + gpu_buffer_builder, ); pass @@ -1127,7 +1140,8 @@ pub struct Frame { /// Main GPU data buffer constructed (primarily) during the prepare /// pass for primitives that were visible and dirty. - pub gpu_buffer: GpuBuffer, + pub gpu_buffer_f: GpuBufferF, + pub gpu_buffer_i: GpuBufferI, } impl Frame { diff --git a/gfx/wr/webrender/src/gpu_types.rs b/gfx/wr/webrender/src/gpu_types.rs index f6d24b2e39..e222ebed04 100644 --- a/gfx/wr/webrender/src/gpu_types.rs +++ b/gfx/wr/webrender/src/gpu_types.rs @@ -125,6 +125,7 @@ pub struct SvgFilterInstance { pub kind: u16, pub input_count: u16, pub generic_int: u16, + pub padding: u16, pub extra_data_address: GpuCacheAddress, } @@ -175,17 +176,6 @@ pub struct ClipMaskInstanceCommon { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] #[repr(C)] -pub struct ClipMaskInstanceImage { - pub common: ClipMaskInstanceCommon, - pub tile_rect: LayoutRect, - pub resource_address: GpuCacheAddress, - pub local_rect: LayoutRect, -} - -#[derive(Clone, Debug)] -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -#[repr(C)] pub struct ClipMaskInstanceRect { pub common: ClipMaskInstanceCommon, pub local_pos: LayoutPoint, @@ -428,6 +418,7 @@ impl PrimitiveHeaders { &mut self, prim_header: &PrimitiveHeader, z: ZBufferId, + render_task_address: RenderTaskAddress, user_data: [i32; 4], ) -> PrimitiveHeaderIndex { debug_assert_eq!(self.headers_int.len(), self.headers_float.len()); @@ -440,7 +431,7 @@ impl PrimitiveHeaders { self.headers_int.push(PrimitiveHeaderI { z, - unused: 0, + render_task_address, specific_prim_address: prim_header.specific_prim_address.as_int(), transform_id: prim_header.transform_id, user_data, @@ -480,7 +471,7 @@ pub struct PrimitiveHeaderI { pub z: ZBufferId, pub specific_prim_address: i32, pub transform_id: TransformPaletteId, - pub unused: i32, // To ensure required 16 byte alignment of vertex textures + pub render_task_address: RenderTaskAddress, pub user_data: [i32; 4], } @@ -501,7 +492,6 @@ impl GlyphInstance { // header since they are constant, and some can be // compressed to a smaller size. pub fn build(&self, - render_task: RenderTaskAddress, clip_task: RenderTaskAddress, subpx_dir: SubpixelDirection, glyph_index_in_text_run: i32, @@ -511,8 +501,7 @@ impl GlyphInstance { PrimitiveInstanceData { data: [ self.prim_header_index.0 as i32, - ((render_task.0 as i32) << 16) - | clip_task.0 as i32, + clip_task.0 as i32, (subpx_dir as u32 as i32) << 24 | (color_mode as u32 as i32) << 16 | glyph_index_in_text_run, @@ -536,7 +525,7 @@ impl From<SplitCompositeInstance> for PrimitiveInstanceData { instance.prim_header_index.0, instance.polygons_address, instance.z.0, - instance.render_task_address.0 as i32, + instance.render_task_address.0, ], } } @@ -547,7 +536,8 @@ impl From<SplitCompositeInstance> for PrimitiveInstanceData { #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct QuadInstance { pub render_task_address: RenderTaskAddress, - pub prim_address: GpuBufferAddress, + pub prim_address_i: GpuBufferAddress, + pub prim_address_f: GpuBufferAddress, pub z_id: ZBufferId, pub transform_id: TransformPaletteId, pub quad_flags: u8, @@ -559,19 +549,23 @@ pub struct QuadInstance { impl From<QuadInstance> for PrimitiveInstanceData { fn from(instance: QuadInstance) -> Self { /* - [32 bits prim address] - [8 bits quad flags] [8 bits edge flags] [16 bits render task address] - [8 bits segment flags] [24 bits z_id] - [8 bits segment index] [24 bits xf_id] - */ + [32 prim address_i] + [32 prim address_f] + [8888 qf ef pi si] + [32 render task address] + */ + PrimitiveInstanceData { data: [ - instance.prim_address.as_int(), - ((instance.quad_flags as i32) << 24) | - ((instance.edge_flags as i32) << 16) | - instance.render_task_address.0 as i32, - ((instance.part_index as i32) << 24) | instance.z_id.0, - ((instance.segment_index as i32) << 24) | instance.transform_id.0 as i32, + instance.prim_address_i.as_int(), + instance.prim_address_f.as_int(), + + ((instance.quad_flags as i32) << 24) | + ((instance.edge_flags as i32) << 16) | + ((instance.part_index as i32) << 8) | + ((instance.segment_index as i32) << 0), + + instance.render_task_address.0, ], } } @@ -659,7 +653,6 @@ impl core::fmt::Debug for BrushFlags { /// Convenience structure to encode into PrimitiveInstanceData. pub struct BrushInstance { pub prim_header_index: PrimitiveHeaderIndex, - pub render_task_address: RenderTaskAddress, pub clip_task_address: RenderTaskAddress, pub segment_index: i32, pub edge_flags: EdgeAaSegmentMask, @@ -672,8 +665,7 @@ impl From<BrushInstance> for PrimitiveInstanceData { PrimitiveInstanceData { data: [ instance.prim_header_index.0, - ((instance.render_task_address.0 as i32) << 16) - | instance.clip_task_address.0 as i32, + instance.clip_task_address.0, instance.segment_index | ((instance.brush_flags.bits() as i32) << 16) | ((instance.edge_flags.bits() as i32) << 28), diff --git a/gfx/wr/webrender/src/picture.rs b/gfx/wr/webrender/src/picture.rs index e8746ad161..1f1fd5e4f6 100644 --- a/gfx/wr/webrender/src/picture.rs +++ b/gfx/wr/webrender/src/picture.rs @@ -139,11 +139,11 @@ use std::collections::hash_map::Entry; use std::ops::Range; use crate::picture_textures::PictureCacheTextureHandle; use crate::util::{MaxRect, VecHelper, MatrixHelpers, Recycler, ScaleOffset}; -use crate::filterdata::{FilterDataHandle}; +use crate::filterdata::FilterDataHandle; use crate::tile_cache::{SliceDebugInfo, TileDebugInfo, DirtyTileDebugInfo}; use crate::visibility::{PrimitiveVisibilityFlags, FrameVisibilityContext}; use crate::visibility::{VisibilityState, FrameVisibilityState}; -use crate::scene_building::{SliceFlags}; +use crate::scene_building::SliceFlags; // Maximum blur radius for blur filter (different than box-shadow blur). // Taken from FilterNodeSoftware.cpp in Gecko. @@ -3951,7 +3951,7 @@ impl SurfaceInfo { &self, local_rect: &PictureRect, spatial_tree: &SpatialTree, - ) -> Option<DeviceRect> { + ) -> Option<DeviceIntRect> { let local_rect = match local_rect.intersection(&self.clipping_rect) { Some(rect) => rect, None => return None, @@ -3969,10 +3969,21 @@ impl SurfaceInfo { local_to_world.map(&local_rect).unwrap() } else { + // The content should have been culled out earlier. + assert!(self.device_pixel_scale.0 > 0.0); + local_rect.cast_unit() }; - Some((raster_rect * self.device_pixel_scale).round_out()) + let surface_rect = (raster_rect * self.device_pixel_scale).round_out().to_i32(); + if surface_rect.is_empty() { + // The local_rect computed above may have non-empty size that is very + // close to zero. Due to limited arithmetic precision, the SpaceMapper + // might transform the near-zero-sized rect into a zero-sized one. + return None; + } + + Some(surface_rect) } } @@ -5014,7 +5025,7 @@ impl PicturePrimitive { let content_device_rect = content_device_rect .intersection(&max_content_rect) - .expect("bug: no intersection with tile dirty rect"); + .expect("bug: no intersection with tile dirty rect: {content_device_rect:?} / {max_content_rect:?}"); let content_task_size = content_device_rect.size(); let normalized_content_rect = content_task_size.into(); @@ -6128,22 +6139,28 @@ impl PicturePrimitive { PictureCompositeMode::TileCache { slice_id } => { let tile_cache = tile_caches.get_mut(&slice_id).unwrap(); - // We only update the raster scale if we're in high quality zoom mode, or there is no - // pinch-zoom active. This means that in low quality pinch-zoom, we retain the initial - // scale factor until the zoom ends, then select a high quality zoom factor for the next - // frame to be drawn. - let update_raster_scale = - !frame_context.fb_config.low_quality_pinch_zoom || - !frame_context.spatial_tree.get_spatial_node(tile_cache.spatial_node_index).is_ancestor_or_self_zooming; - - if update_raster_scale { - // Get the complete scale-offset from local space to device space - let local_to_device = get_relative_scale_offset( - tile_cache.spatial_node_index, - frame_context.root_spatial_node_index, - frame_context.spatial_tree, - ); + // Get the complete scale-offset from local space to device space + let local_to_device = get_relative_scale_offset( + tile_cache.spatial_node_index, + frame_context.root_spatial_node_index, + frame_context.spatial_tree, + ); + let local_to_cur_raster_scale = local_to_device.scale.x / tile_cache.current_raster_scale; + // We only update the raster scale if we're in high quality zoom mode, or there is no + // pinch-zoom active, or the zoom has doubled or halved since the raster scale was + // last updated. During a low-quality zoom we therefore typically retain the previous + // scale factor, which avoids expensive re-rasterizations, except for when the zoom + // has become too large or too small when we re-rasterize to avoid bluriness or a + // proliferation of picture cache tiles. When the zoom ends we select a high quality + // scale factor for the next frame to be drawn. + if !frame_context.fb_config.low_quality_pinch_zoom + || !frame_context + .spatial_tree.get_spatial_node(tile_cache.spatial_node_index) + .is_ancestor_or_self_zooming + || local_to_cur_raster_scale <= 0.5 + || local_to_cur_raster_scale >= 2.0 + { tile_cache.current_raster_scale = local_to_device.scale.x; } diff --git a/gfx/wr/webrender/src/prepare.rs b/gfx/wr/webrender/src/prepare.rs index f32c94073e..a59eca0670 100644 --- a/gfx/wr/webrender/src/prepare.rs +++ b/gfx/wr/webrender/src/prepare.rs @@ -28,18 +28,18 @@ use crate::prim_store::line_dec::MAX_LINE_DECORATION_RESOLUTION; use crate::prim_store::*; use crate::prim_store::gradient::GradientGpuBlockBuilder; use crate::render_backend::DataStores; -use crate::render_task_graph::{RenderTaskId}; +use crate::render_task_graph::RenderTaskId; use crate::render_task_cache::RenderTaskCacheKeyKind; use crate::render_task_cache::{RenderTaskCacheKey, to_cache_size, RenderTaskParent}; use crate::render_task::{RenderTaskKind, RenderTask, SubPass, MaskSubPass, EmptyTask}; -use crate::renderer::{GpuBufferBuilder, GpuBufferAddress}; +use crate::renderer::{GpuBufferBuilderF, GpuBufferAddress}; use crate::segment::{EdgeAaSegmentMask, SegmentBuilder}; use crate::space::SpaceMapper; use crate::util::{clamp_to_scale_factor, pack_as_float, MaxRect}; use crate::visibility::{compute_conservative_visible_rect, PrimitiveVisibility, VisibilityState}; -const MAX_MASK_SIZE: f32 = 4096.0; +const MAX_MASK_SIZE: i32 = 4096; const MIN_BRUSH_SPLIT_SIZE: f32 = 256.0; const MIN_BRUSH_SPLIT_AREA: f32 = 128.0 * 128.0; @@ -141,14 +141,32 @@ fn can_use_clip_chain_for_quad_path( true } +/// Describes how clipping affects the rendering of a quad primitive. +/// +/// As a general rule, parts of the quad that require masking are prerendered in an +/// intermediate target and the mask is applied using multiplicative blending to +/// the intermediate result before compositing it into the destination target. +/// +/// Each segment can opt in or out of masking independently. #[derive(Debug, Copy, Clone)] pub enum QuadRenderStrategy { + /// The quad is not affected by any mask and is drawn directly in the destination + /// target. Direct, + /// The quad is drawn entirely in an intermediate target and a mask is applied + /// before compositing in the destination target. Indirect, + /// A rounded rectangle clip is applied to the quad primitive via a nine-patch. + /// The segments of the nine-patch that require a mask are rendered and masked in + /// an intermediate target, while other segments are drawn directly in the destination + /// target. NinePatch { radius: LayoutVector2D, clip_rect: LayoutRect, }, + /// Split the primitive into coarse tiles so that each tile independently + /// has the opportunity to be drawn directly in the destination target or + /// via an intermediate target if it is affected by a mask. Tiled { x_tiles: u16, y_tiles: u16, @@ -163,69 +181,67 @@ fn get_prim_render_strategy( can_use_nine_patch: bool, spatial_tree: &SpatialTree, ) -> QuadRenderStrategy { - if clip_chain.needs_mask { - fn tile_count_for_size(size: f32) -> u16 { - (size / MIN_BRUSH_SPLIT_SIZE).min(4.0).max(1.0).ceil() as u16 - } + if !clip_chain.needs_mask { + return QuadRenderStrategy::Direct + } - let prim_coverage_size = clip_chain.pic_coverage_rect.size(); - let x_tiles = tile_count_for_size(prim_coverage_size.width); - let y_tiles = tile_count_for_size(prim_coverage_size.height); - let try_split_prim = x_tiles > 1 || y_tiles > 1; - - if try_split_prim { - if can_use_nine_patch { - if clip_chain.clips_range.count == 1 { - let clip_instance = clip_store.get_instance_from_range(&clip_chain.clips_range, 0); - let clip_node = &data_stores.clip[clip_instance.handle]; - - if let ClipItemKind::RoundedRectangle { ref radius, mode: ClipMode::Clip, rect, .. } = clip_node.item.kind { - let max_corner_width = radius.top_left.width - .max(radius.bottom_left.width) - .max(radius.top_right.width) - .max(radius.bottom_right.width); - let max_corner_height = radius.top_left.height - .max(radius.bottom_left.height) - .max(radius.top_right.height) - .max(radius.bottom_right.height); - - if max_corner_width <= 0.5 * rect.size().width && - max_corner_height <= 0.5 * rect.size().height { - - let clip_prim_coords_match = spatial_tree.is_matching_coord_system( - prim_spatial_node_index, - clip_node.item.spatial_node_index, - ); + fn tile_count_for_size(size: f32) -> u16 { + (size / MIN_BRUSH_SPLIT_SIZE).min(4.0).max(1.0).ceil() as u16 + } - if clip_prim_coords_match { - let map_clip_to_prim = SpaceMapper::new_with_target( - prim_spatial_node_index, - clip_node.item.spatial_node_index, - LayoutRect::max_rect(), - spatial_tree, - ); + let prim_coverage_size = clip_chain.pic_coverage_rect.size(); + let x_tiles = tile_count_for_size(prim_coverage_size.width); + let y_tiles = tile_count_for_size(prim_coverage_size.height); + let try_split_prim = x_tiles > 1 || y_tiles > 1; - if let Some(rect) = map_clip_to_prim.map(&rect) { - return QuadRenderStrategy::NinePatch { - radius: LayoutVector2D::new(max_corner_width, max_corner_height), - clip_rect: rect, - }; - } - } - } + if !try_split_prim { + return QuadRenderStrategy::Indirect; + } + + if can_use_nine_patch && clip_chain.clips_range.count == 1 { + let clip_instance = clip_store.get_instance_from_range(&clip_chain.clips_range, 0); + let clip_node = &data_stores.clip[clip_instance.handle]; + + if let ClipItemKind::RoundedRectangle { ref radius, mode: ClipMode::Clip, rect, .. } = clip_node.item.kind { + let max_corner_width = radius.top_left.width + .max(radius.bottom_left.width) + .max(radius.top_right.width) + .max(radius.bottom_right.width); + let max_corner_height = radius.top_left.height + .max(radius.bottom_left.height) + .max(radius.top_right.height) + .max(radius.bottom_right.height); + + if max_corner_width <= 0.5 * rect.size().width && + max_corner_height <= 0.5 * rect.size().height { + + let clip_prim_coords_match = spatial_tree.is_matching_coord_system( + prim_spatial_node_index, + clip_node.item.spatial_node_index, + ); + + if clip_prim_coords_match { + let map_clip_to_prim = SpaceMapper::new_with_target( + prim_spatial_node_index, + clip_node.item.spatial_node_index, + LayoutRect::max_rect(), + spatial_tree, + ); + + if let Some(rect) = map_clip_to_prim.map(&rect) { + return QuadRenderStrategy::NinePatch { + radius: LayoutVector2D::new(max_corner_width, max_corner_height), + clip_rect: rect, + }; } } } - - QuadRenderStrategy::Tiled { - x_tiles, - y_tiles, - } - } else { - QuadRenderStrategy::Indirect } - } else { - QuadRenderStrategy::Direct + } + + QuadRenderStrategy::Tiled { + x_tiles, + y_tiles, } } @@ -452,7 +468,7 @@ fn prepare_interned_prim_for_render( kind: RenderTaskCacheKeyKind::LineDecoration(cache_key.clone()), }, frame_state.gpu_cache, - frame_state.frame_gpu_data, + &mut frame_state.frame_gpu_data.f32, frame_state.rg_builder, None, false, @@ -607,7 +623,7 @@ fn prepare_interned_prim_for_render( handles.push(frame_state.resource_cache.request_render_task( cache_key, frame_state.gpu_cache, - frame_state.frame_gpu_data, + &mut frame_state.frame_gpu_data.f32, frame_state.rg_builder, None, false, // TODO(gw): We don't calculate opacity for borders yet! @@ -764,7 +780,7 @@ fn prepare_interned_prim_for_render( // the written block count) to gpu-buffer, we could add a trait for // writing typed data? let main_prim_address = write_prim_blocks( - frame_state.frame_gpu_data, + &mut frame_state.frame_gpu_data.f32, prim_data.common.prim_rect, prim_instance.vis.clip_chain.local_clip_rect, premul_color, @@ -787,24 +803,21 @@ fn prepare_interned_prim_for_render( } QuadRenderStrategy::Indirect => { let surface = &frame_state.surfaces[pic_context.surface_index.0]; - let clipped_surface_rect = surface.get_surface_rect( + let Some(clipped_surface_rect) = surface.get_surface_rect( &prim_instance.vis.clip_chain.pic_coverage_rect, frame_context.spatial_tree, - ).expect("bug: what can cause this?"); - - let p0 = clipped_surface_rect.min.floor(); - let p1 = clipped_surface_rect.max.ceil(); + ) else { + return; + }; - let x0 = p0.x; - let y0 = p0.y; - let x1 = p1.x; - let y1 = p1.y; + let p0 = clipped_surface_rect.min.to_f32(); + let p1 = clipped_surface_rect.max.to_f32(); let segment = add_segment( - x0, - y0, - x1, - y1, + p0.x, + p0.y, + p1.x, + p1.y, true, prim_instance, prim_spatial_node_index, @@ -820,7 +833,7 @@ fn prepare_interned_prim_for_render( add_composite_prim( prim_instance_index, - LayoutRect::new(LayoutPoint::new(x0, y0), LayoutPoint::new(x1, y1)), + LayoutRect::new(p0.cast_unit(), p1.cast_unit()), premul_color, quad_flags, frame_state, @@ -831,10 +844,12 @@ fn prepare_interned_prim_for_render( QuadRenderStrategy::Tiled { x_tiles, y_tiles } => { let surface = &frame_state.surfaces[pic_context.surface_index.0]; - let clipped_surface_rect = surface.get_surface_rect( + let Some(clipped_surface_rect) = surface.get_surface_rect( &prim_instance.vis.clip_chain.pic_coverage_rect, frame_context.spatial_tree, - ).expect("bug: what can cause this?"); + ) else { + return; + }; let unclipped_surface_rect = surface.map_to_device_rect( &prim_instance.vis.clip_chain.pic_coverage_rect, @@ -843,21 +858,21 @@ fn prepare_interned_prim_for_render( scratch.quad_segments.clear(); - let mut x_coords = vec![clipped_surface_rect.min.x.round()]; - let mut y_coords = vec![clipped_surface_rect.min.y.round()]; + let mut x_coords = vec![clipped_surface_rect.min.x]; + let mut y_coords = vec![clipped_surface_rect.min.y]; - let dx = (clipped_surface_rect.max.x - clipped_surface_rect.min.x) / x_tiles as f32; - let dy = (clipped_surface_rect.max.y - clipped_surface_rect.min.y) / y_tiles as f32; + let dx = (clipped_surface_rect.max.x - clipped_surface_rect.min.x) as f32 / x_tiles as f32; + let dy = (clipped_surface_rect.max.y - clipped_surface_rect.min.y) as f32 / y_tiles as f32; - for x in 1 .. x_tiles { - x_coords.push((clipped_surface_rect.min.x + x as f32 * dx).round()); + for x in 1 .. (x_tiles as i32) { + x_coords.push((clipped_surface_rect.min.x as f32 + x as f32 * dx).round() as i32); } - for y in 1 .. y_tiles { - y_coords.push((clipped_surface_rect.min.y + y as f32 * dy).round()); + for y in 1 .. (y_tiles as i32) { + y_coords.push((clipped_surface_rect.min.y as f32 + y as f32 * dy).round() as i32); } - x_coords.push(clipped_surface_rect.max.x.round()); - y_coords.push(clipped_surface_rect.max.y.round()); + x_coords.push(clipped_surface_rect.max.x); + y_coords.push(clipped_surface_rect.max.y); for y in 0 .. y_coords.len()-1 { let y0 = y_coords[y]; @@ -877,18 +892,11 @@ fn prepare_interned_prim_for_render( let create_task = true; - let r = DeviceRect::new(DevicePoint::new(x0, y0), DevicePoint::new(x1, y1)); - - let x0 = r.min.x; - let y0 = r.min.y; - let x1 = r.max.x; - let y1 = r.max.y; - let segment = add_segment( - x0, - y0, - x1, - y1, + x0 as f32, + y0 as f32, + x1 as f32, + y1 as f32, create_task, prim_instance, prim_spatial_node_index, @@ -917,10 +925,12 @@ fn prepare_interned_prim_for_render( } QuadRenderStrategy::NinePatch { clip_rect, radius } => { let surface = &frame_state.surfaces[pic_context.surface_index.0]; - let clipped_surface_rect = surface.get_surface_rect( + let Some(clipped_surface_rect) = surface.get_surface_rect( &prim_instance.vis.clip_chain.pic_coverage_rect, frame_context.spatial_tree, - ).expect("bug: what can cause this?"); + ) else { + return; + }; let unclipped_surface_rect = surface.map_to_device_rect( &prim_instance.vis.clip_chain.pic_coverage_rect, @@ -943,17 +953,17 @@ fn prepare_interned_prim_for_render( let surface_rect_0 = surface.map_to_device_rect( &pic_corner_0, frame_context.spatial_tree, - ); + ).round_out().to_i32(); let surface_rect_1 = surface.map_to_device_rect( &pic_corner_1, frame_context.spatial_tree, - ); + ).round_out().to_i32(); - let p0 = surface_rect_0.min.floor(); - let p1 = surface_rect_0.max.ceil(); - let p2 = surface_rect_1.min.floor(); - let p3 = surface_rect_1.max.ceil(); + let p0 = surface_rect_0.min; + let p1 = surface_rect_0.max; + let p2 = surface_rect_1.min; + let p3 = surface_rect_1.max; let mut x_coords = [p0.x, p1.x, p2.x, p3.x]; let mut y_coords = [p0.y, p1.y, p2.y, p3.y]; @@ -985,7 +995,10 @@ fn prepare_interned_prim_for_render( true }; - let r = DeviceRect::new(DevicePoint::new(x0, y0), DevicePoint::new(x1, y1)); + let r = DeviceIntRect::new( + DeviceIntPoint::new(x0, y0), + DeviceIntPoint::new(x1, y1), + ); let r = match r.intersection(&clipped_surface_rect) { Some(r) => r, @@ -994,16 +1007,11 @@ fn prepare_interned_prim_for_render( } }; - let x0 = r.min.x; - let y0 = r.min.y; - let x1 = r.max.x; - let y1 = r.max.y; - let segment = add_segment( - x0, - y0, - x1, - y1, + r.min.x as f32, + r.min.y as f32, + r.max.x as f32, + r.max.y as f32, create_task, prim_instance, prim_spatial_node_index, @@ -1138,7 +1146,7 @@ fn prepare_interned_prim_for_render( let stops_address = GradientGpuBlockBuilder::build( prim_data.reverse_stops, - frame_state.frame_gpu_data, + &mut frame_state.frame_gpu_data.f32, &prim_data.stops, ); @@ -1296,8 +1304,8 @@ fn prepare_interned_prim_for_render( .clipped_local_rect .cast_unit(); - let main_prim_address = write_prim_blocks( - frame_state.frame_gpu_data, + let prim_address_f = write_prim_blocks( + &mut frame_state.frame_gpu_data.f32, prim_local_rect, prim_instance.vis.clip_chain.local_clip_rect, PremultipliedColorF::WHITE, @@ -1333,7 +1341,7 @@ fn prepare_interned_prim_for_render( let masks = MaskSubPass { clip_node_range, prim_spatial_node_index, - main_prim_address, + prim_address_f, }; // Add the mask as a sub-pass of the picture @@ -1353,30 +1361,22 @@ fn prepare_interned_prim_for_render( let device_pixel_scale = surface.device_pixel_scale; let raster_spatial_node_index = surface.raster_spatial_node_index; - let clipped_surface_rect = surface.get_surface_rect( + let Some(clipped_surface_rect) = surface.get_surface_rect( &coverage_rect, frame_context.spatial_tree, - ).expect("bug: what can cause this?"); - - let p0 = clipped_surface_rect.min.floor(); - let x0 = p0.x; - let y0 = p0.y; - - let content_origin = DevicePoint::new(x0, y0); + ) else { + return; + }; // Draw a normal screens-space mask to an alpha target that // can be sampled when compositing this picture. let empty_task = EmptyTask { - content_origin, + content_origin: clipped_surface_rect.min.to_f32(), device_pixel_scale, raster_spatial_node_index, }; - let p1 = clipped_surface_rect.max.ceil(); - let x1 = p1.x; - let y1 = p1.y; - - let task_size = DeviceSize::new(x1 - x0, y1 - y0).round().to_i32(); + let task_size = clipped_surface_rect.size(); let clip_task_id = frame_state.rg_builder.add().init(RenderTask::new_dynamic( task_size, @@ -1406,7 +1406,7 @@ fn prepare_interned_prim_for_render( let masks = MaskSubPass { clip_node_range, prim_spatial_node_index, - main_prim_address, + prim_address_f, }; let clip_task = frame_state.rg_builder.get_task_mut(clip_task_id); @@ -1814,13 +1814,19 @@ pub fn update_clip_task( unadjusted_device_rect, device_pixel_scale, ); + + if device_rect.size().to_i32().is_empty() { + log::warn!("Bad adjusted clip task size {:?} (was {:?})", device_rect.size(), unadjusted_device_rect.size()); + return false; + } + let clip_task_id = RenderTaskKind::new_mask( device_rect, instance.vis.clip_chain.clips_range, root_spatial_node_index, frame_state.clip_store, frame_state.gpu_cache, - frame_state.frame_gpu_data, + &mut frame_state.frame_gpu_data.f32, frame_state.resource_cache, frame_state.rg_builder, &mut data_stores.clip, @@ -1865,7 +1871,7 @@ pub fn update_brush_segment_clip_task( return ClipMaskKind::None; } - let device_rect = match frame_state.surfaces[surface_index.0].get_surface_rect( + let unadjusted_device_rect = match frame_state.surfaces[surface_index.0].get_surface_rect( &clip_chain.pic_coverage_rect, frame_context.spatial_tree, ) { @@ -1873,7 +1879,12 @@ pub fn update_brush_segment_clip_task( None => return ClipMaskKind::Clipped, }; - let (device_rect, device_pixel_scale) = adjust_mask_scale_for_max_size(device_rect, device_pixel_scale); + let (device_rect, device_pixel_scale) = adjust_mask_scale_for_max_size(unadjusted_device_rect, device_pixel_scale); + + if device_rect.size().to_i32().is_empty() { + log::warn!("Bad adjusted mask size {:?} (was {:?})", device_rect.size(), unadjusted_device_rect.size()); + return ClipMaskKind::Clipped; + } let clip_task_id = RenderTaskKind::new_mask( device_rect, @@ -1881,7 +1892,7 @@ pub fn update_brush_segment_clip_task( root_spatial_node_index, frame_state.clip_store, frame_state.gpu_cache, - frame_state.frame_gpu_data, + &mut frame_state.frame_gpu_data.f32, frame_state.resource_cache, frame_state.rg_builder, clip_data_store, @@ -2101,15 +2112,17 @@ fn build_segments_if_needed( } // Ensures that the size of mask render tasks are within MAX_MASK_SIZE. -fn adjust_mask_scale_for_max_size(device_rect: DeviceRect, device_pixel_scale: DevicePixelScale) -> (DeviceRect, DevicePixelScale) { +fn adjust_mask_scale_for_max_size(device_rect: DeviceIntRect, device_pixel_scale: DevicePixelScale) -> (DeviceIntRect, DevicePixelScale) { if device_rect.width() > MAX_MASK_SIZE || device_rect.height() > MAX_MASK_SIZE { // round_out will grow by 1 integer pixel if origin is on a // fractional position, so keep that margin for error with -1: - let scale = (MAX_MASK_SIZE - 1.0) / - f32::max(device_rect.width(), device_rect.height()); + let device_rect_f = device_rect.to_f32(); + let scale = (MAX_MASK_SIZE - 1) as f32 / + f32::max(device_rect_f.width(), device_rect_f.height()); let new_device_pixel_scale = device_pixel_scale * Scale::new(scale); - let new_device_rect = (device_rect.to_f32() * Scale::new(scale)) - .round_out(); + let new_device_rect = (device_rect_f * Scale::new(scale)) + .round_out() + .to_i32(); (new_device_rect, new_device_pixel_scale) } else { (device_rect, device_pixel_scale) @@ -2117,7 +2130,7 @@ fn adjust_mask_scale_for_max_size(device_rect: DeviceRect, device_pixel_scale: D } pub fn write_prim_blocks( - builder: &mut GpuBufferBuilder, + builder: &mut GpuBufferBuilderF, prim_rect: LayoutRect, clip_rect: LayoutRect, color: PremultipliedColorF, @@ -2153,7 +2166,7 @@ fn add_segment( prim_instance: &PrimitiveInstance, prim_spatial_node_index: SpatialNodeIndex, raster_spatial_node_index: SpatialNodeIndex, - main_prim_address: GpuBufferAddress, + prim_address_f: GpuBufferAddress, transform_id: TransformPaletteId, aa_flags: EdgeAaSegmentMask, quad_flags: QuadFlags, @@ -2177,7 +2190,7 @@ fn add_segment( raster_spatial_node_index, device_pixel_scale, content_origin, - main_prim_address, + prim_address_f, transform_id, aa_flags, quad_flags, @@ -2189,7 +2202,7 @@ fn add_segment( let masks = MaskSubPass { clip_node_range: prim_instance.vis.clip_chain.clips_range, prim_spatial_node_index, - main_prim_address, + prim_address_f, }; let task = frame_state.rg_builder.get_task_mut(task_id); @@ -2223,7 +2236,7 @@ fn add_composite_prim( segments: &[QuadSegment], ) { let composite_prim_address = write_prim_blocks( - frame_state.frame_gpu_data, + &mut frame_state.frame_gpu_data.f32, rect, rect, color, diff --git a/gfx/wr/webrender/src/prim_store/gradient/conic.rs b/gfx/wr/webrender/src/prim_store/gradient/conic.rs index d9c3f5d350..2c4818095e 100644 --- a/gfx/wr/webrender/src/prim_store/gradient/conic.rs +++ b/gfx/wr/webrender/src/prim_store/gradient/conic.rs @@ -254,7 +254,7 @@ impl ConicGradientTemplate { kind: RenderTaskCacheKeyKind::ConicGradient(cache_key), }, frame_state.gpu_cache, - frame_state.frame_gpu_data, + &mut frame_state.frame_gpu_data.f32, frame_state.rg_builder, None, false, diff --git a/gfx/wr/webrender/src/prim_store/gradient/linear.rs b/gfx/wr/webrender/src/prim_store/gradient/linear.rs index 85da4b670a..7075daac0d 100644 --- a/gfx/wr/webrender/src/prim_store/gradient/linear.rs +++ b/gfx/wr/webrender/src/prim_store/gradient/linear.rs @@ -522,7 +522,7 @@ impl LinearGradientTemplate { kind: RenderTaskCacheKeyKind::FastLinearGradient(gradient), }, frame_state.gpu_cache, - frame_state.frame_gpu_data, + &mut frame_state.frame_gpu_data.f32, frame_state.rg_builder, None, false, @@ -552,7 +552,7 @@ impl LinearGradientTemplate { kind: RenderTaskCacheKeyKind::LinearGradient(cache_key), }, frame_state.gpu_cache, - frame_state.frame_gpu_data, + &mut frame_state.frame_gpu_data.f32, frame_state.rg_builder, None, false, diff --git a/gfx/wr/webrender/src/prim_store/gradient/mod.rs b/gfx/wr/webrender/src/prim_store/gradient/mod.rs index d0b922c579..a0410549b0 100644 --- a/gfx/wr/webrender/src/prim_store/gradient/mod.rs +++ b/gfx/wr/webrender/src/prim_store/gradient/mod.rs @@ -4,7 +4,7 @@ use api::{ColorF, ColorU, GradientStop, PremultipliedColorF}; use api::units::{LayoutRect, LayoutSize, LayoutVector2D}; -use crate::renderer::{GpuBufferAddress, GpuBufferBuilder}; +use crate::renderer::{GpuBufferAddress, GpuBufferBuilderF}; use std::hash; mod linear; @@ -167,7 +167,7 @@ impl GradientGpuBlockBuilder { // Build the gradient data from the supplied stops, reversing them if necessary. pub fn build( reverse_stops: bool, - gpu_buffer_builder: &mut GpuBufferBuilder, + gpu_buffer_builder: &mut GpuBufferBuilderF, src_stops: &[GradientStop], ) -> GpuBufferAddress { // Preconditions (should be ensured by DisplayListBuilder): diff --git a/gfx/wr/webrender/src/prim_store/gradient/radial.rs b/gfx/wr/webrender/src/prim_store/gradient/radial.rs index f3f20f9a55..4d91b28633 100644 --- a/gfx/wr/webrender/src/prim_store/gradient/radial.rs +++ b/gfx/wr/webrender/src/prim_store/gradient/radial.rs @@ -220,7 +220,7 @@ impl RadialGradientTemplate { kind: RenderTaskCacheKeyKind::RadialGradient(cache_key), }, frame_state.gpu_cache, - frame_state.frame_gpu_data, + &mut frame_state.frame_gpu_data.f32, frame_state.rg_builder, None, false, diff --git a/gfx/wr/webrender/src/prim_store/image.rs b/gfx/wr/webrender/src/prim_store/image.rs index 6007b4ba9a..8a05965536 100644 --- a/gfx/wr/webrender/src/prim_store/image.rs +++ b/gfx/wr/webrender/src/prim_store/image.rs @@ -257,7 +257,7 @@ impl ImageData { kind: RenderTaskCacheKeyKind::Image(image_cache_key), }, frame_state.gpu_cache, - frame_state.frame_gpu_data, + &mut frame_state.frame_gpu_data.f32, frame_state.rg_builder, None, descriptor.is_opaque(), diff --git a/gfx/wr/webrender/src/prim_store/mod.rs b/gfx/wr/webrender/src/prim_store/mod.rs index db5480f597..cc09eab6b1 100644 --- a/gfx/wr/webrender/src/prim_store/mod.rs +++ b/gfx/wr/webrender/src/prim_store/mod.rs @@ -1312,6 +1312,37 @@ impl PrimitiveScratchBuffer { } } + pub fn push_debug_rect_with_stroke_width( + &mut self, + rect: WorldRect, + border: ColorF, + stroke_width: f32 + ) { + let top_edge = WorldRect::new( + WorldPoint::new(rect.min.x + stroke_width, rect.min.y), + WorldPoint::new(rect.max.x - stroke_width, rect.min.y + stroke_width) + ); + self.push_debug_rect(top_edge * DevicePixelScale::new(1.0), border, border); + + let bottom_edge = WorldRect::new( + WorldPoint::new(rect.min.x + stroke_width, rect.max.y - stroke_width), + WorldPoint::new(rect.max.x - stroke_width, rect.max.y) + ); + self.push_debug_rect(bottom_edge * DevicePixelScale::new(1.0), border, border); + + let right_edge = WorldRect::new( + WorldPoint::new(rect.max.x - stroke_width, rect.min.y), + rect.max + ); + self.push_debug_rect(right_edge * DevicePixelScale::new(1.0), border, border); + + let left_edge = WorldRect::new( + rect.min, + WorldPoint::new(rect.min.x + stroke_width, rect.max.y) + ); + self.push_debug_rect(left_edge * DevicePixelScale::new(1.0), border, border); + } + #[allow(dead_code)] pub fn push_debug_rect( &mut self, diff --git a/gfx/wr/webrender/src/render_target.rs b/gfx/wr/webrender/src/render_target.rs index 0db77d5ce0..f2d1c24c10 100644 --- a/gfx/wr/webrender/src/render_target.rs +++ b/gfx/wr/webrender/src/render_target.rs @@ -24,7 +24,7 @@ use crate::prim_store::gradient::{ FastLinearGradientInstance, LinearGradientInstance, RadialGradientInstance, ConicGradientInstance, }; -use crate::renderer::{GpuBufferBuilder, GpuBufferAddress}; +use crate::renderer::{GpuBufferAddress, GpuBufferBuilder}; use crate::render_backend::DataStores; use crate::render_task::{RenderTaskKind, RenderTaskAddress, SubPass}; use crate::render_task::{RenderTask, ScalingTask, SvgFilterInfo, MaskSubPass}; @@ -104,6 +104,7 @@ pub trait RenderTarget { _z_generator: &mut ZBufferIdGenerator, _prim_instances: &[PrimitiveInstance], _cmd_buffers: &CommandBufferList, + _gpu_buffer_builder: &mut GpuBufferBuilder, ) { } @@ -183,6 +184,7 @@ impl<T: RenderTarget> RenderTargetList<T> { z_generator: &mut ZBufferIdGenerator, prim_instances: &[PrimitiveInstance], cmd_buffers: &CommandBufferList, + gpu_buffer_builder: &mut GpuBufferBuilder, ) { if self.targets.is_empty() { return; @@ -198,6 +200,7 @@ impl<T: RenderTarget> RenderTargetList<T> { z_generator, prim_instances, cmd_buffers, + gpu_buffer_builder, ); } } @@ -274,10 +277,10 @@ impl RenderTarget for ColorRenderTarget { z_generator: &mut ZBufferIdGenerator, prim_instances: &[PrimitiveInstance], cmd_buffers: &CommandBufferList, + gpu_buffer_builder: &mut GpuBufferBuilder, ) { profile_scope!("build"); let mut merged_batches = AlphaBatchContainer::new(None); - let mut gpu_buffer_builder = GpuBufferBuilder::new(); for task_id in &self.alpha_tasks { profile_scope!("alpha_task"); @@ -326,7 +329,7 @@ impl RenderTarget for ColorRenderTarget { pic_task.surface_spatial_node_index, z_generator, prim_instances, - &mut gpu_buffer_builder, + gpu_buffer_builder, segments, ); }); @@ -376,13 +379,14 @@ impl RenderTarget for ColorRenderTarget { add_quad_to_batch( render_task_address, info.transform_id, - info.prim_address, + info.prim_address_f, info.quad_flags, info.edge_flags, INVALID_SEGMENT_INDEX as u8, RenderTaskId::INVALID, ZBufferId(0), render_tasks, + gpu_buffer_builder, |_, instance| { if info.prim_needs_scissor_rect { self.prim_instances_with_scissor @@ -921,6 +925,7 @@ fn add_svg_filter_instances( kind, input_count, generic_int, + padding: 0, extra_data_address: extra_data_address.unwrap_or(GpuCacheAddress::INVALID), }; @@ -978,7 +983,7 @@ fn build_mask_tasks( let (clip_address, fast_path) = match clip_node.item.kind { ClipItemKind::RoundedRectangle { rect, radius, mode } => { let (fast_path, clip_address) = if radius.is_uniform().is_some() { - let mut writer = gpu_buffer_builder.write_blocks(3); + let mut writer = gpu_buffer_builder.f32.write_blocks(3); writer.push_one(rect); writer.push_one([radius.top_left.width, 0.0, 0.0, 0.0]); writer.push_one([mode as i32 as f32, 0.0, 0.0, 0.0]); @@ -986,7 +991,7 @@ fn build_mask_tasks( (true, clip_address) } else { - let mut writer = gpu_buffer_builder.write_blocks(4); + let mut writer = gpu_buffer_builder.f32.write_blocks(4); writer.push_one(rect); writer.push_one([ radius.top_left.width, @@ -1011,7 +1016,7 @@ fn build_mask_tasks( ClipItemKind::Rectangle { rect, mode, .. } => { assert_eq!(mode, ClipMode::Clip); - let mut writer = gpu_buffer_builder.write_blocks(3); + let mut writer = gpu_buffer_builder.f32.write_blocks(3); writer.push_one(rect); writer.push_one([0.0, 0.0, 0.0, 0.0]); writer.push_one([mode as i32 as f32, 0.0, 0.0, 0.0]); @@ -1043,7 +1048,7 @@ fn build_mask_tasks( for tile in clip_store.visible_mask_tiles(&clip_instance) { let clip_prim_address = write_prim_blocks( - gpu_buffer_builder, + &mut gpu_buffer_builder.f32, rect, rect, PremultipliedColorF::WHITE, @@ -1067,6 +1072,7 @@ fn build_mask_tasks( tile.task_id, ZBufferId(0), render_tasks, + gpu_buffer_builder, |_, prim| { if clip_needs_scissor_rect { results @@ -1107,7 +1113,7 @@ fn build_mask_tasks( ); let main_prim_address = write_prim_blocks( - gpu_buffer_builder, + &mut gpu_buffer_builder.f32, task_world_rect.cast_unit(), task_world_rect.cast_unit(), PremultipliedColorF::WHITE, @@ -1162,6 +1168,7 @@ fn build_mask_tasks( RenderTaskId::INVALID, ZBufferId(0), render_tasks, + gpu_buffer_builder, |_, prim| { let instance = MaskInstance { prim, @@ -1235,7 +1242,7 @@ fn build_sub_pass( render_task_address, content_rect / device_pixel_scale, target_rect, - masks.main_prim_address, + masks.prim_address_f, masks.prim_spatial_node_index, raster_spatial_node_index, ctx.clip_store, diff --git a/gfx/wr/webrender/src/render_task.rs b/gfx/wr/webrender/src/render_task.rs index 4e920cb356..8889ae1ea6 100644 --- a/gfx/wr/webrender/src/render_task.rs +++ b/gfx/wr/webrender/src/render_task.rs @@ -10,7 +10,7 @@ use crate::clip::{ClipDataStore, ClipItemKind, ClipStore, ClipNodeRange}; use crate::command_buffer::{CommandBufferIndex, QuadFlags}; use crate::spatial_tree::SpatialNodeIndex; use crate::filterdata::SFilterData; -use crate::frame_builder::{FrameBuilderConfig}; +use crate::frame_builder::FrameBuilderConfig; use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle}; use crate::gpu_types::{BorderInstance, ImageSource, UvRectKind, TransformPaletteId}; use crate::internal_types::{CacheTextureId, FastHashMap, TextureSource, Swizzle}; @@ -22,7 +22,7 @@ use crate::prim_store::gradient::{ }; use crate::resource_cache::{ResourceCache, ImageRequest}; use std::{usize, f32, i32, u32}; -use crate::renderer::{GpuBufferAddress, GpuBufferBuilder}; +use crate::renderer::{GpuBufferAddress, GpuBufferBuilderF}; use crate::render_target::{ResolveOp, RenderTargetKind}; use crate::render_task_graph::{PassId, RenderTaskId, RenderTaskGraphBuilder}; use crate::render_task_cache::{RenderTaskCacheEntryHandle, RenderTaskCacheKey, RenderTaskCacheKeyKind, RenderTaskParent}; @@ -46,11 +46,11 @@ fn render_task_sanity_check(size: &DeviceIntSize) { #[repr(C)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct RenderTaskAddress(pub u16); +pub struct RenderTaskAddress(pub i32); impl Into<RenderTaskAddress> for RenderTaskId { fn into(self) -> RenderTaskAddress { - RenderTaskAddress(self.index as u16) + RenderTaskAddress(self.index as i32) } } @@ -186,7 +186,7 @@ pub struct EmptyTask { pub struct PrimTask { pub device_pixel_scale: DevicePixelScale, pub content_origin: DevicePoint, - pub prim_address: GpuBufferAddress, + pub prim_address_f: GpuBufferAddress, pub prim_spatial_node_index: SpatialNodeIndex, pub raster_spatial_node_index: SpatialNodeIndex, pub transform_id: TransformPaletteId, @@ -520,7 +520,7 @@ impl RenderTaskKind { raster_spatial_node_index: SpatialNodeIndex, device_pixel_scale: DevicePixelScale, content_origin: DevicePoint, - prim_address: GpuBufferAddress, + prim_address_f: GpuBufferAddress, transform_id: TransformPaletteId, edge_flags: EdgeAaSegmentMask, quad_flags: QuadFlags, @@ -532,7 +532,7 @@ impl RenderTaskKind { raster_spatial_node_index, device_pixel_scale, content_origin, - prim_address, + prim_address_f, transform_id, edge_flags, quad_flags, @@ -588,12 +588,12 @@ impl RenderTaskKind { } pub fn new_mask( - outer_rect: DeviceRect, + outer_rect: DeviceIntRect, clip_node_range: ClipNodeRange, root_spatial_node_index: SpatialNodeIndex, clip_store: &mut ClipStore, gpu_cache: &mut GpuCache, - gpu_buffer_builder: &mut GpuBufferBuilder, + gpu_buffer_builder: &mut GpuBufferBuilderF, resource_cache: &mut ResourceCache, rg_builder: &mut RenderTaskGraphBuilder, clip_data_store: &mut ClipDataStore, @@ -610,7 +610,7 @@ impl RenderTaskKind { // TODO(gw): If this ever shows up in a profile, we could pre-calculate // whether a ClipSources contains any box-shadows and skip // this iteration for the majority of cases. - let task_size = outer_rect.size().to_i32(); + let task_size = outer_rect.size(); // If we have a potentially tiled clip mask, clear the mask area first. Otherwise, // the first (primary) clip mask will overwrite all the clip mask pixels with @@ -620,7 +620,7 @@ impl RenderTaskKind { RenderTask::new_dynamic( task_size, RenderTaskKind::CacheMask(CacheMaskTask { - actual_rect: outer_rect, + actual_rect: outer_rect.to_f32(), clip_node_range, root_spatial_node_index, device_pixel_scale, @@ -883,7 +883,7 @@ pub type TaskDependencies = SmallVec<[RenderTaskId;2]>; pub struct MaskSubPass { pub clip_node_range: ClipNodeRange, pub prim_spatial_node_index: SpatialNodeIndex, - pub main_prim_address: GpuBufferAddress, + pub prim_address_f: GpuBufferAddress, } #[cfg_attr(feature = "capture", derive(Serialize))] @@ -940,6 +940,9 @@ impl RenderTask { size: DeviceIntSize, kind: RenderTaskKind, ) -> Self { + if size.is_empty() { + log::warn!("Bad {} render task size: {:?}", kind.as_str(), size); + } RenderTask::new( RenderTaskLocation::Unallocated { size }, kind, diff --git a/gfx/wr/webrender/src/render_task_cache.rs b/gfx/wr/webrender/src/render_task_cache.rs index 0454c1214f..2c81a9824f 100644 --- a/gfx/wr/webrender/src/render_task_cache.rs +++ b/gfx/wr/webrender/src/render_task_cache.rs @@ -22,7 +22,7 @@ use crate::resource_cache::CacheItem; use std::{mem, usize, f32, i32}; use crate::surface::SurfaceBuilder; use crate::texture_cache::{TextureCache, TextureCacheHandle, Eviction, TargetShader}; -use crate::renderer::GpuBufferBuilder; +use crate::renderer::GpuBufferBuilderF; use crate::render_target::RenderTargetKind; use crate::render_task::{RenderTask, StaticRenderTaskSurface, RenderTaskLocation, RenderTaskKind, CachedTask}; use crate::render_task_graph::{RenderTaskGraphBuilder, RenderTaskId}; @@ -228,7 +228,7 @@ impl RenderTaskCache { key: RenderTaskCacheKey, texture_cache: &mut TextureCache, gpu_cache: &mut GpuCache, - gpu_buffer_builder: &mut GpuBufferBuilder, + gpu_buffer_builder: &mut GpuBufferBuilderF, rg_builder: &mut RenderTaskGraphBuilder, user_data: Option<[f32; 4]>, is_opaque: bool, @@ -237,7 +237,7 @@ impl RenderTaskCache { f: F, ) -> Result<RenderTaskId, ()> where - F: FnOnce(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilder) -> Result<RenderTaskId, ()>, + F: FnOnce(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF) -> Result<RenderTaskId, ()>, { let frame_id = self.frame_id; let size = key.size; diff --git a/gfx/wr/webrender/src/render_task_graph.rs b/gfx/wr/webrender/src/render_task_graph.rs index 29ecf66a2e..6c02de8b65 100644 --- a/gfx/wr/webrender/src/render_task_graph.rs +++ b/gfx/wr/webrender/src/render_task_graph.rs @@ -445,6 +445,13 @@ impl RenderTaskGraphBuilder { ) }; + if surface_size.is_empty() { + // We would panic in the guillotine allocator. Instead, panic here + // with some context. + let task_name = graph.tasks[task_id.index as usize].kind.as_str(); + panic!("{} render task has invalid size {:?}", task_name, surface_size); + } + let format = match kind { RenderTargetKind::Color => ImageFormat::RGBA8, RenderTargetKind::Alpha => ImageFormat::R8, diff --git a/gfx/wr/webrender/src/renderer/gpu_buffer.rs b/gfx/wr/webrender/src/renderer/gpu_buffer.rs index 58a8aa6cbd..c8a2b87b0c 100644 --- a/gfx/wr/webrender/src/renderer/gpu_buffer.rs +++ b/gfx/wr/webrender/src/renderer/gpu_buffer.rs @@ -13,21 +13,57 @@ use crate::renderer::MAX_VERTEX_TEXTURE_WIDTH; use api::units::{DeviceIntRect, DeviceIntSize, LayoutRect, PictureRect, DeviceRect}; -use api::{PremultipliedColorF}; +use api::{PremultipliedColorF, ImageFormat}; use crate::device::Texel; use crate::render_task_graph::{RenderTaskGraph, RenderTaskId}; +pub struct GpuBufferBuilder { + pub i32: GpuBufferBuilderI, + pub f32: GpuBufferBuilderF, +} + +pub type GpuBufferF = GpuBuffer<GpuBufferBlockF>; +pub type GpuBufferBuilderF = GpuBufferBuilderImpl<GpuBufferBlockF>; + +pub type GpuBufferI = GpuBuffer<GpuBufferBlockI>; +pub type GpuBufferBuilderI = GpuBufferBuilderImpl<GpuBufferBlockI>; + +unsafe impl Texel for GpuBufferBlockF { + fn image_format() -> ImageFormat { ImageFormat::RGBAF32 } +} + +unsafe impl Texel for GpuBufferBlockI { + fn image_format() -> ImageFormat { ImageFormat::RGBAI32 } +} -unsafe impl Texel for GpuBufferBlock {} +impl Default for GpuBufferBlockF { + fn default() -> Self { + GpuBufferBlockF::EMPTY + } +} + +impl Default for GpuBufferBlockI { + fn default() -> Self { + GpuBufferBlockI::EMPTY + } +} /// A single texel in RGBAF32 texture - 16 bytes. #[derive(Copy, Clone, Debug, MallocSizeOf)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct GpuBufferBlock { +pub struct GpuBufferBlockF { data: [f32; 4], } +/// A single texel in RGBAI32 texture - 16 bytes. +#[derive(Copy, Clone, Debug, MallocSizeOf)] +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct GpuBufferBlockI { + data: [i32; 4], +} + #[derive(Copy, Debug, Clone, MallocSizeOf, Eq, PartialEq)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] @@ -48,13 +84,17 @@ impl GpuBufferAddress { pub const INVALID: GpuBufferAddress = GpuBufferAddress { u: !0, v: !0 }; } -impl GpuBufferBlock { - pub const EMPTY: Self = GpuBufferBlock { data: [0.0; 4] }; +impl GpuBufferBlockF { + pub const EMPTY: Self = GpuBufferBlockF { data: [0.0; 4] }; +} + +impl GpuBufferBlockI { + pub const EMPTY: Self = GpuBufferBlockI { data: [0; 4] }; } -impl Into<GpuBufferBlock> for LayoutRect { - fn into(self) -> GpuBufferBlock { - GpuBufferBlock { +impl Into<GpuBufferBlockF> for LayoutRect { + fn into(self) -> GpuBufferBlockF { + GpuBufferBlockF { data: [ self.min.x, self.min.y, @@ -65,9 +105,9 @@ impl Into<GpuBufferBlock> for LayoutRect { } } -impl Into<GpuBufferBlock> for PictureRect { - fn into(self) -> GpuBufferBlock { - GpuBufferBlock { +impl Into<GpuBufferBlockF> for PictureRect { + fn into(self) -> GpuBufferBlockF { + GpuBufferBlockF { data: [ self.min.x, self.min.y, @@ -78,9 +118,9 @@ impl Into<GpuBufferBlock> for PictureRect { } } -impl Into<GpuBufferBlock> for DeviceRect { - fn into(self) -> GpuBufferBlock { - GpuBufferBlock { +impl Into<GpuBufferBlockF> for DeviceRect { + fn into(self) -> GpuBufferBlockF { + GpuBufferBlockF { data: [ self.min.x, self.min.y, @@ -91,9 +131,9 @@ impl Into<GpuBufferBlock> for DeviceRect { } } -impl Into<GpuBufferBlock> for PremultipliedColorF { - fn into(self) -> GpuBufferBlock { - GpuBufferBlock { +impl Into<GpuBufferBlockF> for PremultipliedColorF { + fn into(self) -> GpuBufferBlockF { + GpuBufferBlockF { data: [ self.r, self.g, @@ -104,22 +144,43 @@ impl Into<GpuBufferBlock> for PremultipliedColorF { } } -impl Into<GpuBufferBlock> for DeviceIntRect { - fn into(self) -> GpuBufferBlock { - GpuBufferBlock { +impl From<DeviceIntRect> for GpuBufferBlockF { + fn from(rect: DeviceIntRect) -> Self { + GpuBufferBlockF { + data: [ + rect.min.x as f32, + rect.min.y as f32, + rect.max.x as f32, + rect.max.y as f32, + ], + } + } +} + +impl From<DeviceIntRect> for GpuBufferBlockI { + fn from(rect: DeviceIntRect) -> Self { + GpuBufferBlockI { data: [ - self.min.x as f32, - self.min.y as f32, - self.max.x as f32, - self.max.y as f32, + rect.min.x, + rect.min.y, + rect.max.x, + rect.max.y, ], } } } -impl Into<GpuBufferBlock> for [f32; 4] { - fn into(self) -> GpuBufferBlock { - GpuBufferBlock { +impl Into<GpuBufferBlockF> for [f32; 4] { + fn into(self) -> GpuBufferBlockF { + GpuBufferBlockF { + data: self, + } + } +} + +impl Into<GpuBufferBlockI> for [i32; 4] { + fn into(self) -> GpuBufferBlockI { + GpuBufferBlockI { data: self, } } @@ -132,16 +193,16 @@ struct DeferredBlock { } /// Interface to allow writing multiple GPU blocks, possibly of different types -pub struct GpuBufferWriter<'a> { - buffer: &'a mut Vec<GpuBufferBlock>, +pub struct GpuBufferWriter<'a, T> { + buffer: &'a mut Vec<T>, deferred: &'a mut Vec<DeferredBlock>, index: usize, block_count: usize, } -impl<'a> GpuBufferWriter<'a> { +impl<'a, T> GpuBufferWriter<'a, T> where T: Texel { fn new( - buffer: &'a mut Vec<GpuBufferBlock>, + buffer: &'a mut Vec<T>, deferred: &'a mut Vec<DeferredBlock>, index: usize, block_count: usize, @@ -155,7 +216,7 @@ impl<'a> GpuBufferWriter<'a> { } /// Push one (16 byte) block of data in to the writer - pub fn push_one<B>(&mut self, block: B) where B: Into<GpuBufferBlock> { + pub fn push_one<B>(&mut self, block: B) where B: Into<T> { self.buffer.push(block.into()); } @@ -166,7 +227,7 @@ impl<'a> GpuBufferWriter<'a> { task_id, index: self.buffer.len(), }); - self.buffer.push(GpuBufferBlock::EMPTY); + self.buffer.push(T::default()); } /// Close this writer, returning the GPU address of this set of block(s). @@ -180,20 +241,20 @@ impl<'a> GpuBufferWriter<'a> { } } -impl<'a> Drop for GpuBufferWriter<'a> { +impl<'a, T> Drop for GpuBufferWriter<'a, T> { fn drop(&mut self) { assert_eq!(self.buffer.len(), self.index + self.block_count, "Claimed block_count was not written"); } } -pub struct GpuBufferBuilder { - data: Vec<GpuBufferBlock>, +pub struct GpuBufferBuilderImpl<T> { + data: Vec<T>, deferred: Vec<DeferredBlock>, } -impl GpuBufferBuilder { +impl<T> GpuBufferBuilderImpl<T> where T: Texel + std::convert::From<DeviceIntRect> { pub fn new() -> Self { - GpuBufferBuilder { + GpuBufferBuilderImpl { data: Vec::new(), deferred: Vec::new(), } @@ -202,13 +263,13 @@ impl GpuBufferBuilder { #[allow(dead_code)] pub fn push( &mut self, - blocks: &[GpuBufferBlock], + blocks: &[T], ) -> GpuBufferAddress { assert!(blocks.len() <= MAX_VERTEX_TEXTURE_WIDTH); if (self.data.len() % MAX_VERTEX_TEXTURE_WIDTH) + blocks.len() > MAX_VERTEX_TEXTURE_WIDTH { while self.data.len() % MAX_VERTEX_TEXTURE_WIDTH != 0 { - self.data.push(GpuBufferBlock::EMPTY); + self.data.push(T::default()); } } @@ -226,12 +287,12 @@ impl GpuBufferBuilder { pub fn write_blocks( &mut self, block_count: usize, - ) -> GpuBufferWriter { + ) -> GpuBufferWriter<T> { assert!(block_count <= MAX_VERTEX_TEXTURE_WIDTH); if (self.data.len() % MAX_VERTEX_TEXTURE_WIDTH) + block_count > MAX_VERTEX_TEXTURE_WIDTH { while self.data.len() % MAX_VERTEX_TEXTURE_WIDTH != 0 { - self.data.push(GpuBufferBlock::EMPTY); + self.data.push(T::default()); } } @@ -248,11 +309,11 @@ impl GpuBufferBuilder { pub fn finalize( mut self, render_tasks: &RenderTaskGraph, - ) -> GpuBuffer { + ) -> GpuBuffer<T> { let required_len = (self.data.len() + MAX_VERTEX_TEXTURE_WIDTH-1) & !(MAX_VERTEX_TEXTURE_WIDTH-1); for _ in 0 .. required_len - self.data.len() { - self.data.push(GpuBufferBlock::EMPTY); + self.data.push(T::default()); } let len = self.data.len(); @@ -271,18 +332,20 @@ impl GpuBufferBuilder { GpuBuffer { data: self.data, size: DeviceIntSize::new(MAX_VERTEX_TEXTURE_WIDTH as i32, (len / MAX_VERTEX_TEXTURE_WIDTH) as i32), + format: T::image_format(), } } } #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct GpuBuffer { - pub data: Vec<GpuBufferBlock>, +pub struct GpuBuffer<T> { + pub data: Vec<T>, pub size: DeviceIntSize, + pub format: ImageFormat, } -impl GpuBuffer { +impl<T> GpuBuffer<T> { pub fn is_empty(&self) -> bool { self.data.is_empty() } @@ -292,13 +355,13 @@ impl GpuBuffer { #[test] fn test_gpu_buffer_sizing_push() { let render_task_graph = RenderTaskGraph::new_for_testing(); - let mut builder = GpuBufferBuilder::new(); + let mut builder = GpuBufferBuilderF::new(); - let row = vec![GpuBufferBlock::EMPTY; MAX_VERTEX_TEXTURE_WIDTH]; + let row = vec![GpuBufferBlockF::EMPTY; MAX_VERTEX_TEXTURE_WIDTH]; builder.push(&row); - builder.push(&[GpuBufferBlock::EMPTY]); - builder.push(&[GpuBufferBlock::EMPTY]); + builder.push(&[GpuBufferBlockF::EMPTY]); + builder.push(&[GpuBufferBlockF::EMPTY]); let buffer = builder.finalize(&render_task_graph); assert_eq!(buffer.data.len(), MAX_VERTEX_TEXTURE_WIDTH * 2); @@ -307,20 +370,20 @@ fn test_gpu_buffer_sizing_push() { #[test] fn test_gpu_buffer_sizing_writer() { let render_task_graph = RenderTaskGraph::new_for_testing(); - let mut builder = GpuBufferBuilder::new(); + let mut builder = GpuBufferBuilderF::new(); let mut writer = builder.write_blocks(MAX_VERTEX_TEXTURE_WIDTH); for _ in 0 .. MAX_VERTEX_TEXTURE_WIDTH { - writer.push_one(GpuBufferBlock::EMPTY); + writer.push_one(GpuBufferBlockF::EMPTY); } writer.finish(); let mut writer = builder.write_blocks(1); - writer.push_one(GpuBufferBlock::EMPTY); + writer.push_one(GpuBufferBlockF::EMPTY); writer.finish(); let mut writer = builder.write_blocks(1); - writer.push_one(GpuBufferBlock::EMPTY); + writer.push_one(GpuBufferBlockF::EMPTY); writer.finish(); let buffer = builder.finalize(&render_task_graph); diff --git a/gfx/wr/webrender/src/renderer/mod.rs b/gfx/wr/webrender/src/renderer/mod.rs index 0eded7ffb4..3a058ae8f4 100644 --- a/gfx/wr/webrender/src/renderer/mod.rs +++ b/gfx/wr/webrender/src/renderer/mod.rs @@ -59,7 +59,7 @@ use crate::composite::{CompositorConfig, NativeSurfaceOperationDetails, NativeSu use crate::composite::{TileKind}; use crate::debug_colors; use crate::device::{DepthFunction, Device, DrawTarget, ExternalTexture, GpuFrameId, UploadPBOPool}; -use crate::device::{ReadTarget, ShaderError, Texture, TextureFilter, TextureFlags, TextureSlot}; +use crate::device::{ReadTarget, ShaderError, Texture, TextureFilter, TextureFlags, TextureSlot, Texel}; use crate::device::query::{GpuSampler, GpuTimer}; #[cfg(feature = "capture")] use crate::device::FBOId; @@ -127,7 +127,7 @@ pub(crate) mod init; pub use debug::DebugRenderer; pub use shade::{Shaders, SharedShaders}; pub use vertex::{desc, VertexArrayKind, MAX_VERTEX_TEXTURE_WIDTH}; -pub use gpu_buffer::{GpuBuffer, GpuBufferBuilder, GpuBufferAddress}; +pub use gpu_buffer::{GpuBuffer, GpuBufferF, GpuBufferBuilderF, GpuBufferI, GpuBufferBuilderI, GpuBufferAddress, GpuBufferBuilder}; /// The size of the array of each type of vertex data texture that /// is round-robin-ed each frame during bind_frame_data. Doing this @@ -341,7 +341,8 @@ pub(crate) enum TextureSampler { PrimitiveHeadersF, PrimitiveHeadersI, ClipMask, - GpuBuffer, + GpuBufferF, + GpuBufferI, } impl TextureSampler { @@ -370,7 +371,8 @@ impl Into<TextureSlot> for TextureSampler { TextureSampler::PrimitiveHeadersF => TextureSlot(7), TextureSampler::PrimitiveHeadersI => TextureSlot(8), TextureSampler::ClipMask => TextureSlot(9), - TextureSampler::GpuBuffer => TextureSlot(10), + TextureSampler::GpuBufferF => TextureSlot(10), + TextureSampler::GpuBufferI => TextureSlot(11), } } } @@ -3616,7 +3618,6 @@ impl Renderer { fn draw_clip_batch_list( &mut self, list: &ClipBatchList, - draw_target: &DrawTarget, projection: &default::Transform3D<f32>, stats: &mut RendererStats, ) { @@ -3671,42 +3672,6 @@ impl Renderer { stats, ); } - - // draw image masks - let mut using_scissor = false; - for ((mask_texture_id, clip_rect), items) in list.images.iter() { - let _gm2 = self.gpu_profiler.start_marker("clip images"); - // Some image masks may require scissoring to ensure they don't draw - // outside their task's target bounds. Axis-aligned primitives will - // be clamped inside the shader and should not require scissoring. - // TODO: We currently assume scissor state is off by default for - // alpha targets here, but in the future we may want to track the - // current scissor state so that this can be properly saved and - // restored here. - if let Some(clip_rect) = clip_rect { - if !using_scissor { - self.device.enable_scissor(); - using_scissor = true; - } - let scissor_rect = draw_target.build_scissor_rect(Some(*clip_rect)); - self.device.set_scissor_rect(scissor_rect); - } else if using_scissor { - self.device.disable_scissor(); - using_scissor = false; - } - let textures = BatchTextures::composite_rgb(*mask_texture_id); - self.shaders.borrow_mut().cs_clip_image - .bind(&mut self.device, projection, None, &mut self.renderer_errors, &mut self.profile); - self.draw_instanced_batch( - items, - VertexArrayKind::ClipImage, - &textures, - stats, - ); - } - if using_scissor { - self.device.disable_scissor(); - } } fn draw_alpha_target( @@ -3861,7 +3826,6 @@ impl Renderer { self.set_blend(false, FramebufferKind::Other); self.draw_clip_batch_list( &target.clip_batcher.primary_clips, - &draw_target, projection, stats, ); @@ -3872,7 +3836,6 @@ impl Renderer { self.set_blend_mode_multiply(FramebufferKind::Other); self.draw_clip_batch_list( &target.clip_batcher.secondary_clips, - &draw_target, projection, stats, ); @@ -4452,6 +4415,38 @@ impl Renderer { } } + fn create_gpu_buffer_texture<T: Texel>( + &mut self, + buffer: &GpuBuffer<T>, + sampler: TextureSampler, + ) -> Option<Texture> { + if buffer.is_empty() { + None + } else { + let gpu_buffer_texture = self.device.create_texture( + ImageBufferKind::Texture2D, + buffer.format, + buffer.size.width, + buffer.size.height, + TextureFilter::Nearest, + None, + ); + + self.device.bind_texture( + sampler, + &gpu_buffer_texture, + Swizzle::default(), + ); + + self.device.upload_texture_immediate( + &gpu_buffer_texture, + &buffer.data, + ); + + Some(gpu_buffer_texture) + } + } + fn draw_frame( &mut self, frame: &mut Frame, @@ -4478,31 +4473,14 @@ impl Renderer { // Upload experimental GPU buffer texture if there is any data present // TODO: Recycle these textures, upload via PBO or best approach for platform - let gpu_buffer_texture = if frame.gpu_buffer.is_empty() { - None - } else { - let gpu_buffer_texture = self.device.create_texture( - ImageBufferKind::Texture2D, - ImageFormat::RGBAF32, - frame.gpu_buffer.size.width, - frame.gpu_buffer.size.height, - TextureFilter::Nearest, - None, - ); - - self.device.bind_texture( - TextureSampler::GpuBuffer, - &gpu_buffer_texture, - Swizzle::default(), - ); - - self.device.upload_texture_immediate( - &gpu_buffer_texture, - &frame.gpu_buffer.data, - ); - - Some(gpu_buffer_texture) - }; + let gpu_buffer_texture_f = self.create_gpu_buffer_texture( + &frame.gpu_buffer_f, + TextureSampler::GpuBufferF, + ); + let gpu_buffer_texture_i = self.create_gpu_buffer_texture( + &frame.gpu_buffer_i, + TextureSampler::GpuBufferI, + ); // Determine the present mode and dirty rects, if device_size // is Some(..). If it's None, no composite will occur and only @@ -4761,8 +4739,11 @@ impl Renderer { present_mode, ); - if let Some(gpu_buffer_texture) = gpu_buffer_texture { - self.device.delete_texture(gpu_buffer_texture); + if let Some(gpu_buffer_texture_f) = gpu_buffer_texture_f { + self.device.delete_texture(gpu_buffer_texture_f); + } + if let Some(gpu_buffer_texture_i) = gpu_buffer_texture_i { + self.device.delete_texture(gpu_buffer_texture_i); } frame.has_been_rendered = true; diff --git a/gfx/wr/webrender/src/renderer/shade.rs b/gfx/wr/webrender/src/renderer/shade.rs index 30baee0a19..777bfab44a 100644 --- a/gfx/wr/webrender/src/renderer/shade.rs +++ b/gfx/wr/webrender/src/renderer/shade.rs @@ -254,7 +254,6 @@ impl LazilyCompiledShader { VertexArrayKind::RadialGradient => &desc::RADIAL_GRADIENT, VertexArrayKind::ConicGradient => &desc::CONIC_GRADIENT, VertexArrayKind::Blur => &desc::BLUR, - VertexArrayKind::ClipImage => &desc::CLIP_IMAGE, VertexArrayKind::ClipRect => &desc::CLIP_RECT, VertexArrayKind::ClipBoxShadow => &desc::CLIP_BOX_SHADOW, VertexArrayKind::VectorStencil => &desc::VECTOR_STENCIL, @@ -282,7 +281,8 @@ impl LazilyCompiledShader { ("sGpuCache", TextureSampler::GpuCache), ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF), ("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI), - ("sGpuBuffer", TextureSampler::GpuBuffer), + ("sGpuBufferF", TextureSampler::GpuBufferF), + ("sGpuBufferI", TextureSampler::GpuBufferI), ], ); } @@ -300,7 +300,8 @@ impl LazilyCompiledShader { ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF), ("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI), ("sClipMask", TextureSampler::ClipMask), - ("sGpuBuffer", TextureSampler::GpuBuffer), + ("sGpuBufferF", TextureSampler::GpuBufferF), + ("sGpuBufferI", TextureSampler::GpuBufferI), ], ); } @@ -617,7 +618,6 @@ pub struct Shaders { pub cs_clip_rectangle_slow: LazilyCompiledShader, pub cs_clip_rectangle_fast: LazilyCompiledShader, pub cs_clip_box_shadow: LazilyCompiledShader, - pub cs_clip_image: LazilyCompiledShader, // The are "primitive shaders". These shaders draw and blend // final results on screen. They are aware of tile boundaries. @@ -817,16 +817,6 @@ impl Shaders { profile, )?; - let cs_clip_image = LazilyCompiledShader::new( - ShaderKind::ClipCache(VertexArrayKind::ClipImage), - "cs_clip_image", - &["TEXTURE_2D"], - device, - options.precache_flags, - &shader_list, - profile, - )?; - let mut cs_scale = Vec::new(); let scale_shader_num = IMAGE_BUFFER_KINDS.len(); // PrimitiveShader is not clonable. Use push() to initialize the vec. @@ -1128,7 +1118,6 @@ impl Shaders { cs_clip_rectangle_slow, cs_clip_rectangle_fast, cs_clip_box_shadow, - cs_clip_image, ps_text_run, ps_text_run_dual_source, ps_quad_textured, @@ -1274,7 +1263,6 @@ impl Shaders { self.cs_clip_rectangle_slow.deinit(device); self.cs_clip_rectangle_fast.deinit(device); self.cs_clip_box_shadow.deinit(device); - self.cs_clip_image.deinit(device); self.ps_text_run.deinit(device); if let Some(shader) = self.ps_text_run_dual_source { shader.deinit(device); diff --git a/gfx/wr/webrender/src/renderer/upload.rs b/gfx/wr/webrender/src/renderer/upload.rs index 0ba053cd76..c987038651 100644 --- a/gfx/wr/webrender/src/renderer/upload.rs +++ b/gfx/wr/webrender/src/renderer/upload.rs @@ -43,6 +43,7 @@ use crate::profiler; use crate::render_api::MemoryReport; pub const BATCH_UPLOAD_TEXTURE_SIZE: DeviceIntSize = DeviceIntSize::new(512, 512); +const BATCH_UPLOAD_FORMAT_COUNT: usize = 4; /// Upload a number of items to texture cache textures. /// @@ -627,10 +628,10 @@ pub struct UploadTexturePool { /// The textures in the pool associated with a last used frame index. /// /// The outer array corresponds to each of teh three supported texture formats. - textures: [VecDeque<(Texture, u64)>; 3], + textures: [VecDeque<(Texture, u64)>; BATCH_UPLOAD_FORMAT_COUNT], // Frame at which to deallocate some textures if there are too many in the pool, // for each format. - delay_texture_deallocation: [u64; 3], + delay_texture_deallocation: [u64; BATCH_UPLOAD_FORMAT_COUNT], current_frame: u64, /// Temporary buffers that are used when using staging uploads + glTexImage2D. @@ -646,8 +647,8 @@ pub struct UploadTexturePool { impl UploadTexturePool { pub fn new() -> Self { UploadTexturePool { - textures: [VecDeque::new(), VecDeque::new(), VecDeque::new()], - delay_texture_deallocation: [0; 3], + textures: [VecDeque::new(), VecDeque::new(), VecDeque::new(), VecDeque::new()], + delay_texture_deallocation: [0; BATCH_UPLOAD_FORMAT_COUNT], current_frame: 0, temporary_buffers: Vec::new(), min_temporary_buffers: 0, @@ -660,7 +661,8 @@ impl UploadTexturePool { ImageFormat::RGBA8 => 0, ImageFormat::BGRA8 => 1, ImageFormat::R8 => 2, - _ => { panic!("unexpected format"); } + ImageFormat::R16 => 3, + _ => { panic!("unexpected format {:?}", format); } } } diff --git a/gfx/wr/webrender/src/renderer/vertex.rs b/gfx/wr/webrender/src/renderer/vertex.rs index ff555363d8..cd73975ddd 100644 --- a/gfx/wr/webrender/src/renderer/vertex.rs +++ b/gfx/wr/webrender/src/renderer/vertex.rs @@ -49,12 +49,12 @@ pub mod desc { VertexAttribute { name: "aBlurRenderTaskAddress", count: 1, - kind: VertexAttributeKind::U16, + kind: VertexAttributeKind::I32, }, VertexAttribute { name: "aBlurSourceTaskAddress", count: 1, - kind: VertexAttributeKind::U16, + kind: VertexAttributeKind::I32, }, VertexAttribute { name: "aBlurDirection", @@ -488,53 +488,6 @@ pub mod desc { ], }; - pub const CLIP_IMAGE: VertexDescriptor = VertexDescriptor { - vertex_attributes: &[VertexAttribute { - name: "aPosition", - count: 2, - kind: VertexAttributeKind::U8Norm, - }], - instance_attributes: &[ - // common clip attributes - VertexAttribute { - name: "aClipDeviceArea", - count: 4, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aClipOrigins", - count: 4, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aDevicePixelScale", - count: 1, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aTransformIds", - count: 2, - kind: VertexAttributeKind::I32, - }, - // specific clip attributes - VertexAttribute { - name: "aClipTileRect", - count: 4, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aClipDataResourceAddress", - count: 2, - kind: VertexAttributeKind::U16, - }, - VertexAttribute { - name: "aClipLocalRect", - count: 4, - kind: VertexAttributeKind::F32, - }, - ], - }; - pub const GPU_CACHE_UPDATE: VertexDescriptor = VertexDescriptor { vertex_attributes: &[ VertexAttribute { @@ -574,17 +527,17 @@ pub mod desc { VertexAttribute { name: "aFilterRenderTaskAddress", count: 1, - kind: VertexAttributeKind::U16, + kind: VertexAttributeKind::I32, }, VertexAttribute { name: "aFilterInput1TaskAddress", count: 1, - kind: VertexAttributeKind::U16, + kind: VertexAttributeKind::I32, }, VertexAttribute { name: "aFilterInput2TaskAddress", count: 1, - kind: VertexAttributeKind::U16, + kind: VertexAttributeKind::I32, }, VertexAttribute { name: "aFilterKind", @@ -602,6 +555,11 @@ pub mod desc { kind: VertexAttributeKind::U16, }, VertexAttribute { + name: "aUnused", + count: 1, + kind: VertexAttributeKind::U16, + }, + VertexAttribute { name: "aFilterExtraDataAddress", count: 2, kind: VertexAttributeKind::U16, @@ -809,7 +767,6 @@ pub mod desc { pub enum VertexArrayKind { Primitive, Blur, - ClipImage, ClipRect, ClipBoxShadow, VectorStencil, @@ -1038,7 +995,6 @@ pub struct RendererVAOs { blur_vao: VAO, clip_rect_vao: VAO, clip_box_shadow_vao: VAO, - clip_image_vao: VAO, border_vao: VAO, line_vao: VAO, scale_vao: VAO, @@ -1086,7 +1042,6 @@ impl RendererVAOs { clip_rect_vao: device.create_vao_with_new_instances(&desc::CLIP_RECT, &prim_vao), clip_box_shadow_vao: device .create_vao_with_new_instances(&desc::CLIP_BOX_SHADOW, &prim_vao), - clip_image_vao: device.create_vao_with_new_instances(&desc::CLIP_IMAGE, &prim_vao), border_vao: device.create_vao_with_new_instances(&desc::BORDER, &prim_vao), scale_vao: device.create_vao_with_new_instances(&desc::SCALE, &prim_vao), line_vao: device.create_vao_with_new_instances(&desc::LINE, &prim_vao), @@ -1109,7 +1064,6 @@ impl RendererVAOs { device.delete_vao(self.resolve_vao); device.delete_vao(self.clip_rect_vao); device.delete_vao(self.clip_box_shadow_vao); - device.delete_vao(self.clip_image_vao); device.delete_vao(self.fast_linear_gradient_vao); device.delete_vao(self.linear_gradient_vao); device.delete_vao(self.radial_gradient_vao); @@ -1131,7 +1085,6 @@ impl ops::Index<VertexArrayKind> for RendererVAOs { fn index(&self, kind: VertexArrayKind) -> &VAO { match kind { VertexArrayKind::Primitive => &self.prim_vao, - VertexArrayKind::ClipImage => &self.clip_image_vao, VertexArrayKind::ClipRect => &self.clip_rect_vao, VertexArrayKind::ClipBoxShadow => &self.clip_box_shadow_vao, VertexArrayKind::Blur => &self.blur_vao, diff --git a/gfx/wr/webrender/src/resource_cache.rs b/gfx/wr/webrender/src/resource_cache.rs index 9459bf86da..349be25cb8 100644 --- a/gfx/wr/webrender/src/resource_cache.rs +++ b/gfx/wr/webrender/src/resource_cache.rs @@ -34,7 +34,7 @@ use crate::profiler::{self, TransactionProfile, bytes_to_mb}; use crate::render_task_graph::{RenderTaskId, RenderTaskGraphBuilder}; use crate::render_task_cache::{RenderTaskCache, RenderTaskCacheKey, RenderTaskParent}; use crate::render_task_cache::{RenderTaskCacheEntry, RenderTaskCacheEntryHandle}; -use crate::renderer::GpuBufferBuilder; +use crate::renderer::GpuBufferBuilderF; use crate::surface::SurfaceBuilder; use euclid::point2; use smallvec::SmallVec; @@ -594,7 +594,7 @@ impl ResourceCache { &mut self, key: RenderTaskCacheKey, gpu_cache: &mut GpuCache, - gpu_buffer_builder: &mut GpuBufferBuilder, + gpu_buffer_builder: &mut GpuBufferBuilderF, rg_builder: &mut RenderTaskGraphBuilder, user_data: Option<[f32; 4]>, is_opaque: bool, @@ -603,7 +603,7 @@ impl ResourceCache { f: F, ) -> RenderTaskId where - F: FnOnce(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilder) -> RenderTaskId, + F: FnOnce(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF) -> RenderTaskId, { self.cached_render_tasks.request_render_task( key, @@ -2087,14 +2087,14 @@ impl ResourceCache { index, } } - #[cfg(not(target_os = "macos"))] + #[cfg(not(any(target_os = "macos", target_os = "ios")))] FontTemplate::Native(native) => { PlainFontTemplate { data: native.path.to_string_lossy().to_string(), index: native.index, } } - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] FontTemplate::Native(native) => { PlainFontTemplate { data: native.name, diff --git a/gfx/wr/webrender/src/spatial_node.rs b/gfx/wr/webrender/src/spatial_node.rs index 9a2039e37b..6bf1313e0d 100644 --- a/gfx/wr/webrender/src/spatial_node.rs +++ b/gfx/wr/webrender/src/spatial_node.rs @@ -673,7 +673,7 @@ impl SpatialNode { pub fn prepare_state_for_children(&self, state: &mut TransformUpdateState) { state.current_coordinate_system_id = self.coordinate_system_id; - state.is_ancestor_or_self_zooming = self.is_async_zooming; + state.is_ancestor_or_self_zooming = self.is_ancestor_or_self_zooming; state.invertible &= self.invertible; // The transformation we are passing is the transformation of the parent diff --git a/gfx/wr/webrender/src/spatial_tree.rs b/gfx/wr/webrender/src/spatial_tree.rs index c2cd422076..0aa6bb5296 100644 --- a/gfx/wr/webrender/src/spatial_tree.rs +++ b/gfx/wr/webrender/src/spatial_tree.rs @@ -2042,3 +2042,46 @@ fn test_world_transforms() { st.get_world_viewport_transform(scroll).into_transform(), LayoutToWorldTransform::identity()); } + +/// Tests that a spatial node that is async zooming and all of its descendants +/// are correctly marked as having themselves an ancestor that is zooming. +#[test] +fn test_is_ancestor_or_self_zooming() { + let mut cst = SceneSpatialTree::new(); + let root_reference_frame_index = cst.root_reference_frame_index(); + + let root = add_reference_frame( + &mut cst, + root_reference_frame_index, + LayoutTransform::identity(), + LayoutVector2D::zero(), + SpatialTreeItemKey::new(0, 0), + ); + let child1 = add_reference_frame( + &mut cst, + root, + LayoutTransform::identity(), + LayoutVector2D::zero(), + SpatialTreeItemKey::new(0, 1), + ); + let child2 = add_reference_frame( + &mut cst, + child1, + LayoutTransform::identity(), + LayoutVector2D::zero(), + SpatialTreeItemKey::new(0, 2), + ); + + let mut st = SpatialTree::new(); + st.apply_updates(cst.end_frame_and_get_pending_updates()); + + // Mark the root node as async zooming + st.get_spatial_node_mut(root).is_async_zooming = true; + st.update_tree(&SceneProperties::new()); + + // Ensure that the root node and all descendants are marked as having + // themselves or an ancestor zooming + assert!(st.get_spatial_node(root).is_ancestor_or_self_zooming); + assert!(st.get_spatial_node(child1).is_ancestor_or_self_zooming); + assert!(st.get_spatial_node(child2).is_ancestor_or_self_zooming); +} diff --git a/gfx/wr/webrender/src/telemetry.rs b/gfx/wr/webrender/src/telemetry.rs index 9b4c02d68e..5fd67bb80c 100644 --- a/gfx/wr/webrender/src/telemetry.rs +++ b/gfx/wr/webrender/src/telemetry.rs @@ -2,6 +2,7 @@ * 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/. */ +#[cfg(feature = "gecko")] use glean::TimerId; #[cfg(feature = "gecko")] use firefox_on_glean::metrics::wr; @@ -9,16 +10,19 @@ use std::time::Duration; pub struct Telemetry; +#[cfg(not(feature = "gecko"))] +pub struct TimerId; + /// Defines the interface for hooking up an external telemetry reporter to WR. #[cfg(not(feature = "gecko"))] impl Telemetry { pub fn record_rasterize_blobs_time(_duration: Duration) { } - pub fn start_framebuild_time() -> TimerId { TimerId { id: 0 } } + pub fn start_framebuild_time() -> TimerId { TimerId } pub fn stop_and_accumulate_framebuild_time(_id: TimerId) { } pub fn record_renderer_time(_duration: Duration) { } pub fn record_renderer_time_no_sc(_duration: Duration) { } pub fn record_scenebuild_time(_duration: Duration) { } - pub fn start_sceneswap_time() -> TimerId { TimerId { id: 0 } } + pub fn start_sceneswap_time() -> TimerId { TimerId } pub fn stop_and_accumulate_sceneswap_time(_id: TimerId) { } pub fn cancel_sceneswap_time(_id: TimerId) { } pub fn record_texture_cache_update_time(_duration: Duration) { } diff --git a/gfx/wr/webrender_api/src/font.rs b/gfx/wr/webrender_api/src/font.rs index d4f3057a7c..fc245ddfab 100644 --- a/gfx/wr/webrender_api/src/font.rs +++ b/gfx/wr/webrender_api/src/font.rs @@ -5,7 +5,7 @@ use peek_poke::PeekPoke; use std::cmp::Ordering; use std::hash::{Hash, Hasher}; -#[cfg(not(target_os = "macos"))] +#[cfg(not(any(target_os = "macos", target_os = "ios")))] use std::path::PathBuf; use std::sync::Arc; // local imports @@ -52,14 +52,14 @@ impl FontSize { pub fn to_f64_px(&self) -> f64 { self.0 as f64 } } -#[cfg(not(target_os = "macos"))] +#[cfg(not(any(target_os = "macos", target_os = "ios")))] #[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct NativeFontHandle { pub path: PathBuf, pub index: u32, } -#[cfg(target_os = "macos")] +#[cfg(any(target_os = "macos", target_os = "ios"))] #[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct NativeFontHandle { pub name: String, @@ -236,13 +236,13 @@ impl Default for FontInstanceFlags { FontInstanceFlags::SUBPIXEL_POSITION } - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] fn default() -> FontInstanceFlags { FontInstanceFlags::SUBPIXEL_POSITION | FontInstanceFlags::FONT_SMOOTHING } - #[cfg(not(any(target_os = "macos", target_os = "windows")))] + #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))] fn default() -> FontInstanceFlags { FontInstanceFlags::SUBPIXEL_POSITION } @@ -332,14 +332,14 @@ impl Default for FontInstancePlatformOptions { } } -#[cfg(target_os = "macos")] +#[cfg(any(target_os = "macos", target_os = "ios"))] #[repr(C)] #[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] pub struct FontInstancePlatformOptions { pub unused: u32, } -#[cfg(target_os = "macos")] +#[cfg(any(target_os = "macos", target_os = "ios"))] impl Default for FontInstancePlatformOptions { fn default() -> FontInstancePlatformOptions { FontInstancePlatformOptions { @@ -348,7 +348,7 @@ impl Default for FontInstancePlatformOptions { } } -#[cfg(not(any(target_os = "macos", target_os = "windows")))] +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))] #[repr(u8)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] pub enum FontLCDFilter { @@ -358,7 +358,7 @@ pub enum FontLCDFilter { Legacy, } -#[cfg(not(any(target_os = "macos", target_os = "windows")))] +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))] #[repr(u8)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] pub enum FontHinting { @@ -369,7 +369,7 @@ pub enum FontHinting { LCD, } -#[cfg(not(any(target_os = "macos", target_os = "windows")))] +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))] #[repr(C)] #[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] pub struct FontInstancePlatformOptions { @@ -377,7 +377,7 @@ pub struct FontInstancePlatformOptions { pub hinting: FontHinting, } -#[cfg(not(any(target_os = "macos", target_os = "windows")))] +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))] impl Default for FontInstancePlatformOptions { fn default() -> FontInstancePlatformOptions { FontInstancePlatformOptions { diff --git a/gfx/wr/webrender_build/src/shader_features.rs b/gfx/wr/webrender_build/src/shader_features.rs index 2c5d03dc92..780a24a1aa 100644 --- a/gfx/wr/webrender_build/src/shader_features.rs +++ b/gfx/wr/webrender_build/src/shader_features.rs @@ -66,7 +66,6 @@ pub fn get_shader_features(flags: ShaderFeatureFlags) -> ShaderFeatures { // Clip shaders shaders.insert("cs_clip_rectangle", vec![String::new(), "FAST_PATH".to_string()]); - shaders.insert("cs_clip_image", vec!["TEXTURE_2D".to_string()]); shaders.insert("cs_clip_box_shadow", vec!["TEXTURE_2D".to_string()]); // Cache shaders diff --git a/gfx/wr/wr_glyph_rasterizer/Cargo.toml b/gfx/wr/wr_glyph_rasterizer/Cargo.toml index 1d94a460cc..b06cd0f084 100644 --- a/gfx/wr/wr_glyph_rasterizer/Cargo.toml +++ b/gfx/wr/wr_glyph_rasterizer/Cargo.toml @@ -25,7 +25,7 @@ tracy-rs = "0.1.2" log = "0.4" lazy_static = "1" fxhash = "0.2.1" -glean = { version = "57.0.0", optional = true } +glean = { version = "58.1.0", optional = true } firefox-on-glean = { version = "0.1.0", optional = true } serde = { optional = true, version = "1.0", features = ["serde_derive"] } @@ -37,14 +37,14 @@ glutin = "0.28" rayon = "1" winit = "0.26" -[target.'cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))'.dependencies] +[target.'cfg(any(target_os = "android", all(unix, not(any(target_os = "macos", target_os = "ios")))))'.dependencies] freetype = { version = "0.7", default-features = false } libc = "0.2" [target.'cfg(target_os = "windows")'.dependencies] dwrote = "0.11" -[target.'cfg(target_os = "macos")'.dependencies] +[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] core-foundation = "0.9.2" core-graphics = "0.23" core-text = { version = "20.1", default-features = false } diff --git a/gfx/wr/wr_glyph_rasterizer/src/gamma_lut.rs b/gfx/wr/wr_glyph_rasterizer/src/gamma_lut.rs index 15075bacbf..82555c8a06 100644 --- a/gfx/wr/wr_glyph_rasterizer/src/gamma_lut.rs +++ b/gfx/wr/wr_glyph_rasterizer/src/gamma_lut.rs @@ -168,7 +168,7 @@ impl ColorLut for ColorU { // so we can get linear values. // CoreGraphics obscurely defaults to 2.0 as the smoothing gamma value. // The color space used does not appear to affect this choice. -#[cfg(target_os="macos")] +#[cfg(any(target_os="macos", target_os = "ios"))] fn get_inverse_gamma_table_coregraphics_smoothing() -> [u8; 256] { let mut table = [0u8; 256]; @@ -250,7 +250,7 @@ pub fn build_gamma_correcting_lut(table: &mut [u8; 256], src: u8, contrast: f32, pub struct GammaLut { tables: [[u8; 256]; 1 << LUM_BITS], - #[cfg(target_os="macos")] + #[cfg(any(target_os="macos", target_os="ios"))] cg_inverse_gamma: [u8; 256], } @@ -280,12 +280,12 @@ impl GammaLut { } pub fn new(contrast: f32, paint_gamma: f32, device_gamma: f32) -> GammaLut { - #[cfg(target_os="macos")] + #[cfg(any(target_os="macos", target_os="ios"))] let mut table = GammaLut { tables: [[0; 256]; 1 << LUM_BITS], cg_inverse_gamma: get_inverse_gamma_table_coregraphics_smoothing(), }; - #[cfg(not(target_os="macos"))] + #[cfg(not(any(target_os="macos", target_os="ios")))] let mut table = GammaLut { tables: [[0; 256]; 1 << LUM_BITS], }; @@ -337,7 +337,7 @@ impl GammaLut { } } - #[cfg(target_os="macos")] + #[cfg(any(target_os="macos", target_os="ios"))] pub fn coregraphics_convert_to_linear(&self, pixels: &mut [u8]) { for pixel in pixels.chunks_mut(4) { pixel[0] = self.cg_inverse_gamma[pixel[0] as usize]; diff --git a/gfx/wr/wr_glyph_rasterizer/src/lib.rs b/gfx/wr/wr_glyph_rasterizer/src/lib.rs index 27ceb71992..3cf95d7c31 100644 --- a/gfx/wr/wr_glyph_rasterizer/src/lib.rs +++ b/gfx/wr/wr_glyph_rasterizer/src/lib.rs @@ -9,7 +9,7 @@ //! ## Usage //! -#[cfg(any(target_os = "macos", target_os = "windows"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "windows"))] mod gamma_lut; mod rasterizer; mod telemetry; @@ -38,18 +38,18 @@ extern crate serde; extern crate malloc_size_of; pub mod platform { - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] pub use crate::platform::macos::font; - #[cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))] + #[cfg(any(target_os = "android", all(unix, not(any(target_os = "ios", target_os = "macos")))))] pub use crate::platform::unix::font; #[cfg(target_os = "windows")] pub use crate::platform::windows::font; - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "ios", target_os = "macos"))] pub mod macos { pub mod font; } - #[cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))] + #[cfg(any(target_os = "android", all(unix, not(any(target_os = "macos", target_os = "ios")))))] pub mod unix { pub mod font; } |