1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
11 # include "DrawTargetCairo.h"
12 # include "PathCairo.h"
13 # include "SourceSurfaceCairo.h"
16 #include "DrawTargetSkia.h"
18 #include "ScaledFontBase.h"
21 # include "ScaledFontWin.h"
22 # include "NativeFontResourceGDI.h"
23 # include "UnscaledFontGDI.h"
27 # include "ScaledFontMac.h"
28 # include "NativeFontResourceMac.h"
29 # include "UnscaledFontMac.h"
33 # include "ScaledFontFontconfig.h"
34 # include "NativeFontResourceFreeType.h"
35 # include "UnscaledFontFreeType.h"
38 #ifdef MOZ_WIDGET_ANDROID
39 # include "ScaledFontFreeType.h"
40 # include "NativeFontResourceFreeType.h"
41 # include "UnscaledFontFreeType.h"
45 # include "DrawTargetD2D1.h"
47 # include "ScaledFontDWrite.h"
48 # include "NativeFontResourceDWrite.h"
49 # include "UnscaledFontDWrite.h"
52 # include "HelpersD2D.h"
53 # include "DXVA2Manager.h"
54 # include "ImageContainer.h"
55 # include "mozilla/gfx/D3D11Checks.h"
56 # include "mozilla/layers/LayersSurfaces.h"
57 # include "mozilla/layers/TextureD3D11.h"
58 # include "nsWindowsHelpers.h"
61 #include "DrawTargetOffset.h"
62 #include "DrawTargetRecording.h"
64 #include "SourceSurfaceRawData.h"
66 #include "mozilla/CheckedInt.h"
68 #ifdef MOZ_ENABLE_FREETYPE
69 # include "ft2build.h"
70 # include FT_FREETYPE_H
72 #include "mozilla/StaticPrefs_gfx.h"
74 #if defined(MOZ_LOGGING)
75 GFX2D_API
mozilla::LogModule
* GetGFX2DLog() {
76 static mozilla::LazyLogModule
sLog("gfx2d");
81 // The following code was largely taken from xpcom/glue/SSE.cpp and
82 // made a little simpler.
83 enum CPUIDRegister
{ eax
= 0, ebx
= 1, ecx
= 2, edx
= 3 };
87 # if !(defined(__SSE2__) || defined(_M_X64) || \
88 (defined(_M_IX86_FP) && _M_IX86_FP >= 2)) || \
90 // cpuid.h is available on gcc 4.3 and higher on i386 and x86_64
93 static inline bool HasCPUIDBit(unsigned int level
, CPUIDRegister reg
,
96 return __get_cpuid(level
, ®s
[0], ®s
[1], ®s
[2], ®s
[3]) &&
101 # define HAVE_CPU_DETECTION
104 # if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64))
105 // MSVC 2005 or later supports __cpuid by intrin.h
108 # define HAVE_CPU_DETECTION
109 # elif defined(__SUNPRO_CC) && (defined(__i386) || defined(__x86_64__))
111 // Define a function identical to MSVC function.
113 static void __cpuid(int CPUInfo
[4], int InfoType
) {
114 asm("xchg %esi, %ebx\n"
116 "movl %eax, (%edi)\n"
117 "movl %ebx, 4(%edi)\n"
118 "movl %ecx, 8(%edi)\n"
119 "movl %edx, 12(%edi)\n"
122 : "a"(InfoType
), // %eax
124 : "%ecx", "%edx", "%esi");
127 static void __cpuid(int CPUInfo
[4], int InfoType
) {
128 asm("xchg %rsi, %rbx\n"
130 "movl %eax, (%rdi)\n"
131 "movl %ebx, 4(%rdi)\n"
132 "movl %ecx, 8(%rdi)\n"
133 "movl %edx, 12(%rdi)\n"
136 : "a"(InfoType
), // %eax
138 : "%ecx", "%edx", "%rsi");
141 # define HAVE_CPU_DETECTION
145 # ifdef HAVE_CPU_DETECTION
146 static inline bool HasCPUIDBit(unsigned int level
, CPUIDRegister reg
,
148 // Check that the level in question is supported.
149 volatile int regs
[4];
150 __cpuid((int*)regs
, level
& 0x80000000u
);
151 if (unsigned(regs
[0]) < level
) return false;
152 __cpuid((int*)regs
, level
);
153 return !!(unsigned(regs
[reg
]) & bit
);
158 #ifdef MOZ_ENABLE_FREETYPE
161 void mozilla_AddRefSharedFTFace(void* aContext
) {
163 static_cast<mozilla::gfx::SharedFTFace
*>(aContext
)->AddRef();
167 void mozilla_ReleaseSharedFTFace(void* aContext
, void* aOwner
) {
169 auto* sharedFace
= static_cast<mozilla::gfx::SharedFTFace
*>(aContext
);
170 sharedFace
->ForgetLockOwner(aOwner
);
171 sharedFace
->Release();
175 void mozilla_ForgetSharedFTFaceLockOwner(void* aContext
, void* aOwner
) {
176 static_cast<mozilla::gfx::SharedFTFace
*>(aContext
)->ForgetLockOwner(aOwner
);
179 int mozilla_LockSharedFTFace(void* aContext
,
180 void* aOwner
) MOZ_NO_THREAD_SAFETY_ANALYSIS
{
181 return int(static_cast<mozilla::gfx::SharedFTFace
*>(aContext
)->Lock(aOwner
));
184 void mozilla_UnlockSharedFTFace(void* aContext
) MOZ_NO_THREAD_SAFETY_ANALYSIS
{
185 static_cast<mozilla::gfx::SharedFTFace
*>(aContext
)->Unlock();
188 FT_Error
mozilla_LoadFTGlyph(FT_Face aFace
, uint32_t aGlyphIndex
,
190 return mozilla::gfx::Factory::LoadFTGlyph(aFace
, aGlyphIndex
, aFlags
);
193 void mozilla_LockFTLibrary(FT_Library aFTLibrary
) {
194 mozilla::gfx::Factory::LockFTLibrary(aFTLibrary
);
197 void mozilla_UnlockFTLibrary(FT_Library aFTLibrary
) {
198 mozilla::gfx::Factory::UnlockFTLibrary(aFTLibrary
);
203 namespace mozilla::gfx
{
205 #ifdef MOZ_ENABLE_FREETYPE
206 FT_Library
Factory::mFTLibrary
= nullptr;
207 StaticMutex
Factory::mFTLock
;
209 already_AddRefed
<SharedFTFace
> FTUserFontData::CloneFace(int aFaceIndex
) {
211 RefPtr
<SharedFTFace
> face
= Factory::NewSharedFTFaceFromData(
212 nullptr, mFontData
, mLength
, aFaceIndex
, this);
214 (FT_Select_Charmap(face
->GetFace(), FT_ENCODING_UNICODE
) != FT_Err_Ok
&&
215 FT_Select_Charmap(face
->GetFace(), FT_ENCODING_MS_SYMBOL
) !=
219 return face
.forget();
221 FT_Face face
= Factory::NewFTFace(nullptr, mFilename
.c_str(), aFaceIndex
);
223 return MakeAndAddRef
<SharedFTFace
>(face
, this);
230 // Note: mDeviceLock must be held when mutating these values.
231 static uint32_t mDeviceSeq
= 0;
232 StaticRefPtr
<ID3D11Device
> Factory::mD3D11Device
;
233 StaticRefPtr
<ID2D1Device
> Factory::mD2D1Device
;
234 StaticRefPtr
<IDWriteFactory
> Factory::mDWriteFactory
;
235 StaticRefPtr
<ID2D1DeviceContext
> Factory::mMTDC
;
236 StaticRefPtr
<ID2D1DeviceContext
> Factory::mOffMTDC
;
237 bool Factory::mDWriteFactoryInitialized
= false;
238 StaticRefPtr
<IDWriteFontCollection
> Factory::mDWriteSystemFonts
;
239 StaticMutex
Factory::mDeviceLock
;
240 StaticMutex
Factory::mDTDependencyLock
;
243 bool Factory::mBGRSubpixelOrder
= false;
245 mozilla::gfx::Config
* Factory::sConfig
= nullptr;
247 void Factory::Init(const Config
& aConfig
) {
248 MOZ_ASSERT(!sConfig
);
249 sConfig
= new Config(aConfig
);
252 NativeFontResourceMac::RegisterMemoryReporter();
254 NativeFontResource::RegisterMemoryReporter();
258 void Factory::ShutDown() {
260 delete sConfig
->mLogForwarder
;
265 #ifdef MOZ_ENABLE_FREETYPE
266 mFTLibrary
= nullptr;
270 bool Factory::HasSSE2() {
271 #if defined(__SSE2__) || defined(_M_X64) || \
272 (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
273 // gcc with -msse2 (default on OSX and x86-64)
274 // cl.exe with -arch:SSE2 (default on x64 compiler)
276 #elif defined(HAVE_CPU_DETECTION)
281 } sDetectionState
= UNINITIALIZED
;
283 if (sDetectionState
== UNINITIALIZED
) {
284 sDetectionState
= HasCPUIDBit(1u, edx
, (1u << 26)) ? HAS_SSE2
: NO_SSE2
;
286 return sDetectionState
== HAS_SSE2
;
292 bool Factory::HasSSE4() {
293 #if defined(__SSE4__)
294 // gcc with -msse2 (default on OSX and x86-64)
295 // cl.exe with -arch:SSE2 (default on x64 compiler)
297 #elif defined(HAVE_CPU_DETECTION)
302 } sDetectionState
= UNINITIALIZED
;
304 if (sDetectionState
== UNINITIALIZED
) {
305 sDetectionState
= HasCPUIDBit(1u, ecx
, (1u << 19)) ? HAS_SSE4
: NO_SSE4
;
307 return sDetectionState
== HAS_SSE4
;
313 // If the size is "reasonable", we want gfxCriticalError to assert, so
314 // this is the option set up for it.
315 inline int LoggerOptionsBasedOnSize(const IntSize
& aSize
) {
316 return CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize
));
319 bool Factory::ReasonableSurfaceSize(const IntSize
& aSize
) {
320 return Factory::CheckSurfaceSize(aSize
, kReasonableSurfaceSize
);
323 bool Factory::AllowedSurfaceSize(const IntSize
& aSize
) {
325 return Factory::CheckSurfaceSize(aSize
, sConfig
->mMaxTextureSize
,
326 sConfig
->mMaxAllocSize
);
329 return CheckSurfaceSize(aSize
);
332 bool Factory::CheckSurfaceSize(const IntSize
& sz
, int32_t extentLimit
,
333 int32_t allocLimit
) {
334 if (sz
.width
<= 0 || sz
.height
<= 0) {
338 // reject images with sides bigger than limit
339 if (extentLimit
&& (sz
.width
> extentLimit
|| sz
.height
> extentLimit
)) {
340 gfxDebug() << "Surface size too large (exceeds extent limit)!";
344 // assuming 4 bytes per pixel, make sure the allocation size
345 // doesn't overflow a int32_t either
346 CheckedInt
<int32_t> stride
= GetAlignedStride
<16>(sz
.width
, 4);
347 if (!stride
.isValid() || stride
.value() == 0) {
348 gfxDebug() << "Surface size too large (stride overflows int32_t)!";
352 CheckedInt
<int32_t> numBytes
= stride
* sz
.height
;
353 if (!numBytes
.isValid()) {
355 << "Surface size too large (allocation size would overflow int32_t)!";
359 if (allocLimit
&& allocLimit
< numBytes
.value()) {
360 gfxDebug() << "Surface size too large (exceeds allocation limit)!";
367 already_AddRefed
<DrawTarget
> Factory::CreateDrawTarget(BackendType aBackend
,
368 const IntSize
& aSize
,
369 SurfaceFormat aFormat
) {
370 if (!AllowedSurfaceSize(aSize
)) {
371 gfxCriticalError(LoggerOptionsBasedOnSize(aSize
))
372 << "Failed to allocate a surface due to invalid size (CDT) " << aSize
;
376 RefPtr
<DrawTarget
> retVal
;
379 case BackendType::DIRECT2D1_1
: {
380 RefPtr
<DrawTargetD2D1
> newTarget
;
381 newTarget
= new DrawTargetD2D1();
382 if (newTarget
->Init(aSize
, aFormat
)) {
388 case BackendType::SKIA
: {
389 RefPtr
<DrawTargetSkia
> newTarget
;
390 newTarget
= new DrawTargetSkia();
391 if (newTarget
->Init(aSize
, aFormat
)) {
397 case BackendType::CAIRO
: {
398 RefPtr
<DrawTargetCairo
> newTarget
;
399 newTarget
= new DrawTargetCairo();
400 if (newTarget
->Init(aSize
, aFormat
)) {
412 gfxCriticalError(LoggerOptionsBasedOnSize(aSize
))
413 << "Failed to create DrawTarget, Type: " << int(aBackend
)
414 << " Size: " << aSize
;
417 return retVal
.forget();
420 already_AddRefed
<PathBuilder
> Factory::CreatePathBuilder(BackendType aBackend
,
421 FillRule aFillRule
) {
424 case BackendType::DIRECT2D1_1
:
425 return PathBuilderD2D::Create(aFillRule
);
427 case BackendType::SKIA
:
428 case BackendType::WEBGL
:
429 return PathBuilderSkia::Create(aFillRule
);
431 case BackendType::CAIRO
:
432 return PathBuilderCairo::Create(aFillRule
);
435 gfxCriticalNote
<< "Invalid PathBuilder type specified: "
441 already_AddRefed
<PathBuilder
> Factory::CreateSimplePathBuilder() {
442 return CreatePathBuilder(BackendType::SKIA
);
445 already_AddRefed
<DrawTarget
> Factory::CreateRecordingDrawTarget(
446 DrawEventRecorder
* aRecorder
, DrawTarget
* aDT
, IntRect aRect
) {
447 return MakeAndAddRef
<DrawTargetRecording
>(aRecorder
, aDT
, aRect
);
450 already_AddRefed
<DrawTarget
> Factory::CreateDrawTargetForData(
451 BackendType aBackend
, unsigned char* aData
, const IntSize
& aSize
,
452 int32_t aStride
, SurfaceFormat aFormat
, bool aUninitialized
) {
454 if (!AllowedSurfaceSize(aSize
)) {
455 gfxCriticalError(LoggerOptionsBasedOnSize(aSize
))
456 << "Failed to allocate a surface due to invalid size (DTD) " << aSize
;
460 RefPtr
<DrawTarget
> retVal
;
463 case BackendType::SKIA
: {
464 RefPtr
<DrawTargetSkia
> newTarget
;
465 newTarget
= new DrawTargetSkia();
466 if (newTarget
->Init(aData
, aSize
, aStride
, aFormat
, aUninitialized
)) {
472 case BackendType::CAIRO
: {
473 RefPtr
<DrawTargetCairo
> newTarget
;
474 newTarget
= new DrawTargetCairo();
475 if (newTarget
->Init(aData
, aSize
, aStride
, aFormat
)) {
476 retVal
= std::move(newTarget
);
482 gfxCriticalNote
<< "Invalid draw target type specified: "
488 gfxCriticalNote
<< "Failed to create DrawTarget, Type: " << int(aBackend
)
489 << " Size: " << aSize
<< ", Data: " << hexa((void*)aData
)
490 << ", Stride: " << aStride
;
493 return retVal
.forget();
496 already_AddRefed
<DrawTarget
> Factory::CreateOffsetDrawTarget(
497 DrawTarget
* aDrawTarget
, IntPoint aTileOrigin
) {
498 RefPtr
<DrawTargetOffset
> dt
= new DrawTargetOffset();
500 if (!dt
->Init(aDrawTarget
, aTileOrigin
)) {
507 bool Factory::DoesBackendSupportDataDrawtarget(BackendType aType
) {
509 case BackendType::DIRECT2D
:
510 case BackendType::DIRECT2D1_1
:
511 case BackendType::RECORDING
:
512 case BackendType::NONE
:
513 case BackendType::BACKEND_LAST
:
514 case BackendType::WEBRENDER_TEXT
:
515 case BackendType::WEBGL
:
517 case BackendType::CAIRO
:
518 case BackendType::SKIA
:
525 uint32_t Factory::GetMaxSurfaceSize(BackendType aType
) {
527 case BackendType::CAIRO
:
528 return DrawTargetCairo::GetMaxSurfaceSize();
529 case BackendType::SKIA
:
530 return DrawTargetSkia::GetMaxSurfaceSize();
532 case BackendType::DIRECT2D1_1
:
533 return DrawTargetD2D1::GetMaxSurfaceSize();
540 already_AddRefed
<NativeFontResource
> Factory::CreateNativeFontResource(
541 uint8_t* aData
, uint32_t aSize
, FontType aFontType
, void* aFontContext
) {
544 case FontType::DWRITE
:
545 return NativeFontResourceDWrite::Create(aData
, aSize
);
547 return NativeFontResourceGDI::Create(aData
, aSize
);
548 #elif defined(XP_DARWIN)
550 return NativeFontResourceMac::Create(aData
, aSize
);
551 #elif defined(MOZ_WIDGET_GTK)
552 case FontType::FONTCONFIG
:
553 return NativeFontResourceFontconfig::Create(
554 aData
, aSize
, static_cast<FT_Library
>(aFontContext
));
555 #elif defined(MOZ_WIDGET_ANDROID)
556 case FontType::FREETYPE
:
557 return NativeFontResourceFreeType::Create(
558 aData
, aSize
, static_cast<FT_Library
>(aFontContext
));
562 << "Unable to create requested font resource from truetype data";
567 already_AddRefed
<UnscaledFont
> Factory::CreateUnscaledFontFromFontDescriptor(
568 FontType aType
, const uint8_t* aData
, uint32_t aDataLength
,
572 case FontType::DWRITE
:
573 return UnscaledFontDWrite::CreateFromFontDescriptor(aData
, aDataLength
,
576 return UnscaledFontGDI::CreateFromFontDescriptor(aData
, aDataLength
,
578 #elif defined(XP_DARWIN)
580 return UnscaledFontMac::CreateFromFontDescriptor(aData
, aDataLength
,
582 #elif defined(MOZ_WIDGET_GTK)
583 case FontType::FONTCONFIG
:
584 return UnscaledFontFontconfig::CreateFromFontDescriptor(
585 aData
, aDataLength
, aIndex
);
586 #elif defined(MOZ_WIDGET_ANDROID)
587 case FontType::FREETYPE
:
588 return UnscaledFontFreeType::CreateFromFontDescriptor(aData
, aDataLength
,
592 gfxWarning() << "Invalid type specified for UnscaledFont font descriptor";
598 already_AddRefed
<ScaledFont
> Factory::CreateScaledFontForMacFont(
599 CGFontRef aCGFont
, const RefPtr
<UnscaledFont
>& aUnscaledFont
, Float aSize
,
600 bool aUseFontSmoothing
, bool aApplySyntheticBold
, bool aHasColorGlyphs
) {
601 return MakeAndAddRef
<ScaledFontMac
>(aCGFont
, aUnscaledFont
, aSize
, false,
602 aUseFontSmoothing
, aApplySyntheticBold
,
607 #ifdef MOZ_WIDGET_GTK
608 already_AddRefed
<ScaledFont
> Factory::CreateScaledFontForFontconfigFont(
609 const RefPtr
<UnscaledFont
>& aUnscaledFont
, Float aSize
,
610 RefPtr
<SharedFTFace
> aFace
, FcPattern
* aPattern
) {
611 return MakeAndAddRef
<ScaledFontFontconfig
>(std::move(aFace
), aPattern
,
612 aUnscaledFont
, aSize
);
616 #ifdef MOZ_WIDGET_ANDROID
617 already_AddRefed
<ScaledFont
> Factory::CreateScaledFontForFreeTypeFont(
618 const RefPtr
<UnscaledFont
>& aUnscaledFont
, Float aSize
,
619 RefPtr
<SharedFTFace
> aFace
, bool aApplySyntheticBold
) {
620 return MakeAndAddRef
<ScaledFontFreeType
>(std::move(aFace
), aUnscaledFont
,
621 aSize
, aApplySyntheticBold
);
625 void Factory::SetBGRSubpixelOrder(bool aBGR
) { mBGRSubpixelOrder
= aBGR
; }
627 bool Factory::GetBGRSubpixelOrder() { return mBGRSubpixelOrder
; }
629 #ifdef MOZ_ENABLE_FREETYPE
630 SharedFTFace::SharedFTFace(FT_Face aFace
, SharedFTFaceData
* aData
)
633 mLock("SharedFTFace::mLock"),
634 mLastLockOwner(nullptr) {
640 SharedFTFace::~SharedFTFace() {
641 Factory::ReleaseFTFace(mFace
);
643 mData
->ReleaseData();
647 void Factory::SetFTLibrary(FT_Library aFTLibrary
) { mFTLibrary
= aFTLibrary
; }
649 FT_Library
Factory::GetFTLibrary() {
650 MOZ_ASSERT(mFTLibrary
);
654 FT_Library
Factory::NewFTLibrary() {
656 if (FT_Init_FreeType(&library
) != FT_Err_Ok
) {
662 void Factory::ReleaseFTLibrary(FT_Library aFTLibrary
) {
663 FT_Done_FreeType(aFTLibrary
);
666 void Factory::LockFTLibrary(FT_Library aFTLibrary
)
667 MOZ_CAPABILITY_ACQUIRE(mFTLock
) MOZ_NO_THREAD_SAFETY_ANALYSIS
{
671 void Factory::UnlockFTLibrary(FT_Library aFTLibrary
)
672 MOZ_CAPABILITY_RELEASE(mFTLock
) MOZ_NO_THREAD_SAFETY_ANALYSIS
{
676 FT_Face
Factory::NewFTFace(FT_Library aFTLibrary
, const char* aFileName
,
678 StaticMutexAutoLock
lock(mFTLock
);
680 aFTLibrary
= mFTLibrary
;
683 if (FT_New_Face(aFTLibrary
, aFileName
, aFaceIndex
, &face
) != FT_Err_Ok
) {
689 already_AddRefed
<SharedFTFace
> Factory::NewSharedFTFace(FT_Library aFTLibrary
,
690 const char* aFilename
,
692 FT_Face face
= NewFTFace(aFTLibrary
, aFilename
, aFaceIndex
);
697 RefPtr
<FTUserFontData
> data
;
699 // If the font has variations, we may later need to "clone" it in
700 // UnscaledFontFreeType::CreateScaledFont. To support this, we attach an
701 // FTUserFontData that records the filename used to instantiate the face.
702 if (face
->face_flags
& FT_FACE_FLAG_MULTIPLE_MASTERS
) {
703 data
= new FTUserFontData(aFilename
);
706 return MakeAndAddRef
<SharedFTFace
>(face
, data
);
709 FT_Face
Factory::NewFTFaceFromData(FT_Library aFTLibrary
, const uint8_t* aData
,
710 size_t aDataSize
, int aFaceIndex
) {
711 StaticMutexAutoLock
lock(mFTLock
);
713 aFTLibrary
= mFTLibrary
;
716 if (FT_New_Memory_Face(aFTLibrary
, aData
, aDataSize
, aFaceIndex
, &face
) !=
723 already_AddRefed
<SharedFTFace
> Factory::NewSharedFTFaceFromData(
724 FT_Library aFTLibrary
, const uint8_t* aData
, size_t aDataSize
,
725 int aFaceIndex
, SharedFTFaceData
* aSharedData
) {
727 NewFTFaceFromData(aFTLibrary
, aData
, aDataSize
, aFaceIndex
)) {
728 return MakeAndAddRef
<SharedFTFace
>(face
, aSharedData
);
734 void Factory::ReleaseFTFace(FT_Face aFace
) {
735 StaticMutexAutoLock
lock(mFTLock
);
739 FT_Error
Factory::LoadFTGlyph(FT_Face aFace
, uint32_t aGlyphIndex
,
741 StaticMutexAutoLock
lock(mFTLock
);
742 return FT_Load_Glyph(aFace
, aGlyphIndex
, aFlags
);
746 AutoSerializeWithMoz2D::AutoSerializeWithMoz2D(BackendType aBackendType
) {
748 // We use a multi-threaded ID2D1Factory1, so that makes the calls through the
749 // Direct2D API thread-safe. However, if the Moz2D objects are using Direct3D
750 // resources we need to make sure that calls through the Direct3D or DXGI API
751 // use the Direct2D synchronization. It's possible that this should be pushed
752 // down into the TextureD3D11 objects, so that we always use this.
753 if (aBackendType
== BackendType::DIRECT2D1_1
||
754 aBackendType
== BackendType::DIRECT2D
) {
755 auto factory
= D2DFactory();
757 factory
->QueryInterface(
758 static_cast<ID2D1Multithread
**>(getter_AddRefs(mMT
)));
767 AutoSerializeWithMoz2D::~AutoSerializeWithMoz2D() {
776 already_AddRefed
<DrawTarget
> Factory::CreateDrawTargetForD3D11Texture(
777 ID3D11Texture2D
* aTexture
, SurfaceFormat aFormat
) {
778 MOZ_ASSERT(aTexture
);
780 RefPtr
<DrawTargetD2D1
> newTarget
;
782 newTarget
= new DrawTargetD2D1();
783 if (newTarget
->Init(aTexture
, aFormat
)) {
784 RefPtr
<DrawTarget
> retVal
= newTarget
;
785 return retVal
.forget();
788 gfxWarning() << "Failed to create draw target for D3D11 texture.";
794 bool Factory::SetDirect3D11Device(ID3D11Device
* aDevice
) {
795 MOZ_RELEASE_ASSERT(NS_IsMainThread());
797 // D2DFactory already takes the device lock, so we get the factory before
798 // entering the lock scope.
799 RefPtr
<ID2D1Factory1
> factory
= D2DFactory();
801 StaticMutexAutoLock
lock(mDeviceLock
);
803 mD3D11Device
= aDevice
;
806 mD2D1Device
= nullptr;
815 RefPtr
<IDXGIDevice
> device
;
816 aDevice
->QueryInterface((IDXGIDevice
**)getter_AddRefs(device
));
818 RefPtr
<ID2D1Device
> d2dDevice
;
819 HRESULT hr
= factory
->CreateDevice(device
, getter_AddRefs(d2dDevice
));
822 << "[D2D1] Failed to create gfx factory's D2D1 device, code: "
825 mD3D11Device
= nullptr;
830 mD2D1Device
= d2dDevice
;
834 RefPtr
<ID3D11Device
> Factory::GetDirect3D11Device() {
835 StaticMutexAutoLock
lock(mDeviceLock
);
839 RefPtr
<ID2D1Device
> Factory::GetD2D1Device(uint32_t* aOutSeqNo
) {
840 StaticMutexAutoLock
lock(mDeviceLock
);
842 *aOutSeqNo
= mDeviceSeq
;
844 return mD2D1Device
.get();
847 bool Factory::HasD2D1Device() { return !!GetD2D1Device(); }
849 RefPtr
<IDWriteFactory
> Factory::GetDWriteFactory() {
850 StaticMutexAutoLock
lock(mDeviceLock
);
851 return mDWriteFactory
;
854 RefPtr
<IDWriteFactory
> Factory::EnsureDWriteFactory() {
855 StaticMutexAutoLock
lock(mDeviceLock
);
857 if (mDWriteFactoryInitialized
) {
858 return mDWriteFactory
;
861 mDWriteFactoryInitialized
= true;
863 HMODULE dwriteModule
= LoadLibrarySystem32(L
"dwrite.dll");
864 decltype(DWriteCreateFactory
)* createDWriteFactory
=
865 (decltype(DWriteCreateFactory
)*)GetProcAddress(dwriteModule
,
866 "DWriteCreateFactory");
868 if (!createDWriteFactory
) {
869 gfxWarning() << "Failed to locate DWriteCreateFactory function.";
874 createDWriteFactory(DWRITE_FACTORY_TYPE_SHARED
, __uuidof(IDWriteFactory
),
875 reinterpret_cast<IUnknown
**>(&mDWriteFactory
));
878 gfxWarning() << "Failed to create DWrite Factory.";
881 return mDWriteFactory
;
884 RefPtr
<IDWriteFontCollection
> Factory::GetDWriteSystemFonts(bool aUpdate
) {
885 StaticMutexAutoLock
lock(mDeviceLock
);
887 if (mDWriteSystemFonts
&& !aUpdate
) {
888 return mDWriteSystemFonts
;
891 if (!mDWriteFactory
) {
892 if ((rand() & 0x3f) == 0) {
893 gfxCriticalError(int(gfx::LogOptions::AssertOnCall
))
894 << "Failed to create DWrite factory";
896 gfxWarning() << "Failed to create DWrite factory";
902 RefPtr
<IDWriteFontCollection
> systemFonts
;
904 mDWriteFactory
->GetSystemFontCollection(getter_AddRefs(systemFonts
));
905 if (FAILED(hr
) || !systemFonts
) {
906 // only crash some of the time so those experiencing this problem
907 // don't stop using Firefox
908 if ((rand() & 0x3f) == 0) {
909 gfxCriticalError(int(gfx::LogOptions::AssertOnCall
))
910 << "Failed to create DWrite system font collection";
912 gfxWarning() << "Failed to create DWrite system font collection";
916 mDWriteSystemFonts
= systemFonts
;
918 return mDWriteSystemFonts
;
921 RefPtr
<ID2D1DeviceContext
> Factory::GetD2DDeviceContext() {
922 StaticRefPtr
<ID2D1DeviceContext
>* ptr
;
924 if (NS_IsMainThread()) {
934 RefPtr
<ID2D1Device
> device
= GetD2D1Device();
940 RefPtr
<ID2D1DeviceContext
> dc
;
941 HRESULT hr
= device
->CreateDeviceContext(
942 D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS
,
946 gfxCriticalError() << "Failed to create global device context";
955 bool Factory::SupportsD2D1() { return !!D2DFactory(); }
957 BYTE sSystemTextQuality
= CLEARTYPE_QUALITY
;
958 void Factory::SetSystemTextQuality(uint8_t aQuality
) {
959 sSystemTextQuality
= aQuality
;
962 uint64_t Factory::GetD2DVRAMUsageDrawTarget() {
963 return DrawTargetD2D1::mVRAMUsageDT
;
966 uint64_t Factory::GetD2DVRAMUsageSourceSurface() {
967 return DrawTargetD2D1::mVRAMUsageSS
;
970 void Factory::D2DCleanup() {
971 StaticMutexAutoLock
lock(mDeviceLock
);
973 mD2D1Device
= nullptr;
975 DrawTargetD2D1::CleanupD2D();
978 already_AddRefed
<ScaledFont
> Factory::CreateScaledFontForDWriteFont(
979 IDWriteFontFace
* aFontFace
, const gfxFontStyle
* aStyle
,
980 const RefPtr
<UnscaledFont
>& aUnscaledFont
, float aSize
,
981 bool aUseEmbeddedBitmap
, bool aUseMultistrikeBold
, bool aGDIForced
) {
982 return MakeAndAddRef
<ScaledFontDWrite
>(
983 aFontFace
, aUnscaledFont
, aSize
, aUseEmbeddedBitmap
, aUseMultistrikeBold
,
987 already_AddRefed
<ScaledFont
> Factory::CreateScaledFontForGDIFont(
988 const void* aLogFont
, const RefPtr
<UnscaledFont
>& aUnscaledFont
,
990 return MakeAndAddRef
<ScaledFontWin
>(static_cast<const LOGFONT
*>(aLogFont
),
991 aUnscaledFont
, aSize
);
995 already_AddRefed
<DrawTarget
> Factory::CreateDrawTargetWithSkCanvas(
997 RefPtr
<DrawTargetSkia
> newTarget
= new DrawTargetSkia();
998 if (!newTarget
->Init(aCanvas
)) {
1001 return newTarget
.forget();
1004 void Factory::PurgeAllCaches() {}
1006 already_AddRefed
<DrawTarget
> Factory::CreateDrawTargetForCairoSurface(
1007 cairo_surface_t
* aSurface
, const IntSize
& aSize
, SurfaceFormat
* aFormat
) {
1008 if (!AllowedSurfaceSize(aSize
)) {
1009 gfxWarning() << "Allowing surface with invalid size (Cairo) " << aSize
;
1012 RefPtr
<DrawTarget
> retVal
;
1015 RefPtr
<DrawTargetCairo
> newTarget
= new DrawTargetCairo();
1017 if (newTarget
->Init(aSurface
, aSize
, aFormat
)) {
1021 return retVal
.forget();
1024 already_AddRefed
<SourceSurface
> Factory::CreateSourceSurfaceForCairoSurface(
1025 cairo_surface_t
* aSurface
, const IntSize
& aSize
, SurfaceFormat aFormat
) {
1026 if (aSize
.width
<= 0 || aSize
.height
<= 0) {
1027 gfxWarning() << "Can't create a SourceSurface without a valid size";
1032 return MakeAndAddRef
<SourceSurfaceCairo
>(aSurface
, aSize
, aFormat
);
1038 already_AddRefed
<DataSourceSurface
> Factory::CreateWrappingDataSourceSurface(
1039 uint8_t* aData
, int32_t aStride
, const IntSize
& aSize
,
1040 SurfaceFormat aFormat
,
1041 SourceSurfaceDeallocator aDeallocator
/* = nullptr */,
1042 void* aClosure
/* = nullptr */) {
1043 // Just check for negative/zero size instead of the full AllowedSurfaceSize()
1044 // - since the data is already allocated we do not need to check for a
1045 // possible overflow - it already worked.
1046 if (aSize
.width
<= 0 || aSize
.height
<= 0) {
1049 if (!aDeallocator
&& aClosure
) {
1055 RefPtr
<SourceSurfaceRawData
> newSurf
= new SourceSurfaceRawData();
1056 newSurf
->InitWrappingData(aData
, aSize
, aStride
, aFormat
, aDeallocator
,
1059 return newSurf
.forget();
1062 already_AddRefed
<DataSourceSurface
> Factory::CreateDataSourceSurface(
1063 const IntSize
& aSize
, SurfaceFormat aFormat
, bool aZero
) {
1064 if (!AllowedSurfaceSize(aSize
)) {
1065 gfxCriticalError(LoggerOptionsBasedOnSize(aSize
))
1066 << "Failed to allocate a surface due to invalid size (DSS) " << aSize
;
1070 // Skia doesn't support RGBX, so memset RGBX to 0xFF
1071 bool clearSurface
= aZero
|| aFormat
== SurfaceFormat::B8G8R8X8
;
1072 uint8_t clearValue
= aFormat
== SurfaceFormat::B8G8R8X8
? 0xFF : 0;
1074 RefPtr
<SourceSurfaceAlignedRawData
> newSurf
=
1075 new SourceSurfaceAlignedRawData();
1076 if (newSurf
->Init(aSize
, aFormat
, clearSurface
, clearValue
)) {
1077 return newSurf
.forget();
1080 gfxWarning() << "CreateDataSourceSurface failed in init";
1084 already_AddRefed
<DataSourceSurface
> Factory::CreateDataSourceSurfaceWithStride(
1085 const IntSize
& aSize
, SurfaceFormat aFormat
, int32_t aStride
, bool aZero
) {
1086 if (!AllowedSurfaceSize(aSize
) ||
1087 aStride
< aSize
.width
* BytesPerPixel(aFormat
)) {
1088 gfxCriticalError(LoggerOptionsBasedOnSize(aSize
))
1089 << "CreateDataSourceSurfaceWithStride failed with bad stride "
1090 << aStride
<< ", " << aSize
<< ", " << aFormat
;
1094 // Skia doesn't support RGBX, so memset RGBX to 0xFF
1095 bool clearSurface
= aZero
|| aFormat
== SurfaceFormat::B8G8R8X8
;
1096 uint8_t clearValue
= aFormat
== SurfaceFormat::B8G8R8X8
? 0xFF : 0;
1098 RefPtr
<SourceSurfaceAlignedRawData
> newSurf
=
1099 new SourceSurfaceAlignedRawData();
1100 if (newSurf
->Init(aSize
, aFormat
, clearSurface
, clearValue
, aStride
)) {
1101 return newSurf
.forget();
1104 gfxCriticalError(LoggerOptionsBasedOnSize(aSize
))
1105 << "CreateDataSourceSurfaceWithStride failed to initialize " << aSize
1106 << ", " << aFormat
<< ", " << aStride
<< ", " << aZero
;
1110 void Factory::CopyDataSourceSurface(DataSourceSurface
* aSource
,
1111 DataSourceSurface
* aDest
) {
1112 // Don't worry too much about speed.
1113 MOZ_ASSERT(aSource
->GetSize() == aDest
->GetSize());
1114 MOZ_ASSERT(aSource
->GetFormat() == SurfaceFormat::R8G8B8A8
||
1115 aSource
->GetFormat() == SurfaceFormat::R8G8B8X8
||
1116 aSource
->GetFormat() == SurfaceFormat::B8G8R8A8
||
1117 aSource
->GetFormat() == SurfaceFormat::B8G8R8X8
);
1118 MOZ_ASSERT(aDest
->GetFormat() == SurfaceFormat::R8G8B8A8
||
1119 aDest
->GetFormat() == SurfaceFormat::R8G8B8X8
||
1120 aDest
->GetFormat() == SurfaceFormat::B8G8R8A8
||
1121 aDest
->GetFormat() == SurfaceFormat::B8G8R8X8
||
1122 aDest
->GetFormat() == SurfaceFormat::R5G6B5_UINT16
);
1124 DataSourceSurface::MappedSurface srcMap
;
1125 DataSourceSurface::MappedSurface destMap
;
1126 if (!aSource
->Map(DataSourceSurface::MapType::READ
, &srcMap
) ||
1127 !aDest
->Map(DataSourceSurface::MapType::WRITE
, &destMap
)) {
1128 MOZ_ASSERT(false, "CopyDataSourceSurface: Failed to map surface.");
1132 SwizzleData(srcMap
.mData
, srcMap
.mStride
, aSource
->GetFormat(), destMap
.mData
,
1133 destMap
.mStride
, aDest
->GetFormat(), aSource
->GetSize());
1142 already_AddRefed
<DataSourceSurface
>
1143 Factory::CreateBGRA8DataSourceSurfaceForD3D11Texture(
1144 ID3D11Texture2D
* aSrcTexture
, uint32_t aArrayIndex
) {
1145 D3D11_TEXTURE2D_DESC srcDesc
= {0};
1146 aSrcTexture
->GetDesc(&srcDesc
);
1148 RefPtr
<gfx::DataSourceSurface
> destTexture
=
1149 gfx::Factory::CreateDataSourceSurface(
1150 IntSize(srcDesc
.Width
, srcDesc
.Height
), gfx::SurfaceFormat::B8G8R8A8
);
1151 if (NS_WARN_IF(!destTexture
)) {
1154 if (!ReadbackTexture(destTexture
, aSrcTexture
, aArrayIndex
)) {
1157 return destTexture
.forget();
1160 /* static */ nsresult
Factory::CreateSdbForD3D11Texture(
1161 ID3D11Texture2D
* aSrcTexture
, const IntSize
& aSrcSize
,
1162 layers::SurfaceDescriptorBuffer
& aSdBuffer
,
1163 const std::function
<layers::MemoryOrShmem(uint32_t)>& aAllocate
) {
1164 D3D11_TEXTURE2D_DESC srcDesc
= {0};
1165 aSrcTexture
->GetDesc(&srcDesc
);
1166 if (srcDesc
.Width
!= uint32_t(aSrcSize
.width
) ||
1167 srcDesc
.Height
!= uint32_t(aSrcSize
.height
) ||
1168 srcDesc
.Format
!= DXGI_FORMAT_B8G8R8A8_UNORM
) {
1169 return NS_ERROR_NOT_IMPLEMENTED
;
1172 const auto format
= gfx::SurfaceFormat::B8G8R8A8
;
1173 uint8_t* buffer
= nullptr;
1175 nsresult rv
= layers::Image::AllocateSurfaceDescriptorBufferRgb(
1176 aSrcSize
, format
, buffer
, aSdBuffer
, stride
, aAllocate
);
1177 if (NS_WARN_IF(NS_FAILED(rv
))) {
1181 if (!ReadbackTexture(buffer
, stride
, aSrcTexture
)) {
1182 return NS_ERROR_FAILURE
;
1189 template <typename DestTextureT
>
1190 bool Factory::ConvertSourceAndRetryReadback(DestTextureT
* aDestCpuTexture
,
1191 ID3D11Texture2D
* aSrcTexture
,
1192 uint32_t aArrayIndex
) {
1193 RefPtr
<ID3D11Device
> device
;
1194 aSrcTexture
->GetDevice(getter_AddRefs(device
));
1196 gfxWarning() << "Failed to get D3D11 device from source texture";
1200 nsAutoCString error
;
1201 std::unique_ptr
<DXVA2Manager
> manager(
1202 DXVA2Manager::CreateD3D11DXVA(nullptr, error
, device
));
1204 gfxWarning() << "Failed to create DXVA2 manager!";
1208 RefPtr
<ID3D11Texture2D
> newSrcTexture
;
1209 HRESULT hr
= manager
->CopyToBGRATexture(aSrcTexture
, aArrayIndex
,
1210 getter_AddRefs(newSrcTexture
));
1212 gfxWarning() << "Failed to copy to BGRA texture.";
1216 return ReadbackTexture(aDestCpuTexture
, newSrcTexture
);
1220 bool Factory::ReadbackTexture(layers::TextureData
* aDestCpuTexture
,
1221 ID3D11Texture2D
* aSrcTexture
) {
1222 layers::MappedTextureData mappedData
;
1223 if (!aDestCpuTexture
->BorrowMappedData(mappedData
)) {
1224 gfxWarning() << "Could not access in-memory texture";
1228 D3D11_TEXTURE2D_DESC srcDesc
= {0};
1229 aSrcTexture
->GetDesc(&srcDesc
);
1231 // Special case: If the source and destination have different formats and the
1232 // destination is B8G8R8A8 then convert the source to B8G8R8A8 and readback.
1233 if ((srcDesc
.Format
!= DXGIFormat(mappedData
.format
)) &&
1234 (mappedData
.format
== SurfaceFormat::B8G8R8A8
)) {
1235 return ConvertSourceAndRetryReadback(aDestCpuTexture
, aSrcTexture
);
1238 if ((IntSize(srcDesc
.Width
, srcDesc
.Height
) != mappedData
.size
) ||
1239 (srcDesc
.Format
!= DXGIFormat(mappedData
.format
))) {
1240 gfxWarning() << "Attempted readback between incompatible textures";
1244 return ReadbackTexture(mappedData
.data
, mappedData
.stride
, aSrcTexture
);
1248 bool Factory::ReadbackTexture(DataSourceSurface
* aDestCpuTexture
,
1249 ID3D11Texture2D
* aSrcTexture
,
1250 uint32_t aArrayIndex
) {
1251 D3D11_TEXTURE2D_DESC srcDesc
= {0};
1252 aSrcTexture
->GetDesc(&srcDesc
);
1254 // Special case: If the source and destination have different formats and the
1255 // destination is B8G8R8A8 then convert the source to B8G8R8A8 and readback.
1256 if ((srcDesc
.Format
!= DXGIFormat(aDestCpuTexture
->GetFormat())) &&
1257 (aDestCpuTexture
->GetFormat() == SurfaceFormat::B8G8R8A8
)) {
1258 return ConvertSourceAndRetryReadback(aDestCpuTexture
, aSrcTexture
,
1262 if ((IntSize(srcDesc
.Width
, srcDesc
.Height
) != aDestCpuTexture
->GetSize()) ||
1263 (srcDesc
.Format
!= DXGIFormat(aDestCpuTexture
->GetFormat()))) {
1264 gfxWarning() << "Attempted readback between incompatible textures";
1268 gfx::DataSourceSurface::MappedSurface mappedSurface
;
1269 if (!aDestCpuTexture
->Map(gfx::DataSourceSurface::WRITE
, &mappedSurface
)) {
1273 MOZ_ASSERT(aArrayIndex
== 0);
1276 ReadbackTexture(mappedSurface
.mData
, mappedSurface
.mStride
, aSrcTexture
);
1277 aDestCpuTexture
->Unmap();
1282 bool Factory::ReadbackTexture(uint8_t* aDestData
, int32_t aDestStride
,
1283 ID3D11Texture2D
* aSrcTexture
) {
1284 MOZ_ASSERT(aDestData
&& aDestStride
&& aSrcTexture
);
1286 RefPtr
<ID3D11Device
> device
;
1287 aSrcTexture
->GetDevice(getter_AddRefs(device
));
1289 gfxWarning() << "Failed to get D3D11 device from source texture";
1293 RefPtr
<ID3D11DeviceContext
> context
;
1294 device
->GetImmediateContext(getter_AddRefs(context
));
1296 gfxWarning() << "Could not get an immediate D3D11 context";
1300 D3D11_TEXTURE2D_DESC srcDesc
= {0};
1301 RefPtr
<ID3D11Texture2D
> srcCpuTexture
;
1305 RefPtr
<IDXGIKeyedMutex
> mutex
;
1306 hr
= aSrcTexture
->QueryInterface(__uuidof(IDXGIKeyedMutex
),
1307 (void**)getter_AddRefs(mutex
));
1308 layers::AutoTextureLock
lock(__func__
, mutex
, hr
, 2000);
1309 if (NS_WARN_IF(!lock
.Succeeded())) {
1313 aSrcTexture
->GetDesc(&srcDesc
);
1314 srcDesc
.CPUAccessFlags
= D3D11_CPU_ACCESS_READ
;
1315 srcDesc
.Usage
= D3D11_USAGE_STAGING
;
1316 srcDesc
.BindFlags
= 0;
1317 srcDesc
.MiscFlags
= 0;
1318 srcDesc
.MipLevels
= 1;
1319 hr
= device
->CreateTexture2D(&srcDesc
, nullptr,
1320 getter_AddRefs(srcCpuTexture
));
1322 gfxWarning() << "Could not create source texture for mapping";
1326 context
->CopyResource(srcCpuTexture
, aSrcTexture
);
1329 D3D11_MAPPED_SUBRESOURCE srcMap
;
1330 hr
= context
->Map(srcCpuTexture
, 0, D3D11_MAP_READ
, 0, &srcMap
);
1332 gfxWarning() << "Could not map source texture";
1336 uint32_t width
= srcDesc
.Width
;
1337 uint32_t height
= srcDesc
.Height
;
1338 int bpp
= BytesPerPixel(gfx::ToPixelFormat(srcDesc
.Format
));
1339 for (uint32_t y
= 0; y
< height
; y
++) {
1340 memcpy(aDestData
+ aDestStride
* y
,
1341 (unsigned char*)(srcMap
.pData
) + srcMap
.RowPitch
* y
, width
* bpp
);
1344 context
->Unmap(srcCpuTexture
, 0);
1351 void CriticalLogger::OutputMessage(const std::string
& aString
, int aLevel
,
1353 if (Factory::GetLogForwarder()) {
1354 Factory::GetLogForwarder()->Log(aString
);
1357 BasicLogger::OutputMessage(aString
, aLevel
, aNoNewline
);
1360 void CriticalLogger::CrashAction(LogReason aReason
) {
1361 if (Factory::GetLogForwarder()) {
1362 Factory::GetLogForwarder()->CrashAction(aReason
);
1367 void LogWStr(const wchar_t* aWStr
, std::stringstream
& aOut
) {
1369 WideCharToMultiByte(CP_ACP
, 0, aWStr
, -1, nullptr, 0, nullptr, nullptr);
1371 std::vector
<char> str(n
);
1372 WideCharToMultiByte(CP_ACP
, 0, aWStr
, -1, str
.data(), n
, nullptr, nullptr);
1378 } // namespace mozilla::gfx