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 "SourceSurfaceCairo.h"
15 #include "DrawTargetSkia.h"
17 #include "ScaledFontBase.h"
20 # include "ScaledFontWin.h"
21 # include "NativeFontResourceGDI.h"
22 # include "UnscaledFontGDI.h"
26 # include "ScaledFontMac.h"
27 # include "NativeFontResourceMac.h"
28 # include "UnscaledFontMac.h"
32 # include "ScaledFontFontconfig.h"
33 # include "NativeFontResourceFreeType.h"
34 # include "UnscaledFontFreeType.h"
37 #ifdef MOZ_WIDGET_ANDROID
38 # include "ScaledFontFreeType.h"
39 # include "NativeFontResourceFreeType.h"
40 # include "UnscaledFontFreeType.h"
44 # include "DrawTargetD2D1.h"
45 # include "ScaledFontDWrite.h"
46 # include "NativeFontResourceDWrite.h"
47 # include "UnscaledFontDWrite.h"
50 # include "HelpersD2D.h"
51 # include "DXVA2Manager.h"
52 # include "mozilla/layers/TextureD3D11.h"
53 # include "nsWindowsHelpers.h"
56 #include "DrawTargetOffset.h"
57 #include "DrawTargetRecording.h"
59 #include "SourceSurfaceRawData.h"
61 #include "DrawEventRecorder.h"
65 #include "mozilla/CheckedInt.h"
67 #include "mozilla/layers/TextureClient.h"
69 #ifdef MOZ_ENABLE_FREETYPE
70 # include "ft2build.h"
71 # include FT_FREETYPE_H
73 #include "MainThreadUtils.h"
74 #include "mozilla/Preferences.h"
75 #include "mozilla/StaticPrefs_gfx.h"
77 #if defined(MOZ_LOGGING)
78 GFX2D_API
mozilla::LogModule
* GetGFX2DLog() {
79 static mozilla::LazyLogModule
sLog("gfx2d");
84 // The following code was largely taken from xpcom/glue/SSE.cpp and
85 // made a little simpler.
86 enum CPUIDRegister
{ eax
= 0, ebx
= 1, ecx
= 2, edx
= 3 };
90 # if !(defined(__SSE2__) || defined(_M_X64) || \
91 (defined(_M_IX86_FP) && _M_IX86_FP >= 2)) || \
93 // cpuid.h is available on gcc 4.3 and higher on i386 and x86_64
96 static inline bool HasCPUIDBit(unsigned int level
, CPUIDRegister reg
,
99 return __get_cpuid(level
, ®s
[0], ®s
[1], ®s
[2], ®s
[3]) &&
104 # define HAVE_CPU_DETECTION
107 # if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64))
108 // MSVC 2005 or later supports __cpuid by intrin.h
111 # define HAVE_CPU_DETECTION
112 # elif defined(__SUNPRO_CC) && (defined(__i386) || defined(__x86_64__))
114 // Define a function identical to MSVC function.
116 static void __cpuid(int CPUInfo
[4], int InfoType
) {
117 asm("xchg %esi, %ebx\n"
119 "movl %eax, (%edi)\n"
120 "movl %ebx, 4(%edi)\n"
121 "movl %ecx, 8(%edi)\n"
122 "movl %edx, 12(%edi)\n"
125 : "a"(InfoType
), // %eax
127 : "%ecx", "%edx", "%esi");
130 static void __cpuid(int CPUInfo
[4], int InfoType
) {
131 asm("xchg %rsi, %rbx\n"
133 "movl %eax, (%rdi)\n"
134 "movl %ebx, 4(%rdi)\n"
135 "movl %ecx, 8(%rdi)\n"
136 "movl %edx, 12(%rdi)\n"
139 : "a"(InfoType
), // %eax
141 : "%ecx", "%edx", "%rsi");
144 # define HAVE_CPU_DETECTION
148 # ifdef HAVE_CPU_DETECTION
149 static inline bool HasCPUIDBit(unsigned int level
, CPUIDRegister reg
,
151 // Check that the level in question is supported.
152 volatile int regs
[4];
153 __cpuid((int*)regs
, level
& 0x80000000u
);
154 if (unsigned(regs
[0]) < level
) return false;
155 __cpuid((int*)regs
, level
);
156 return !!(unsigned(regs
[reg
]) & bit
);
161 #ifdef MOZ_ENABLE_FREETYPE
164 void mozilla_AddRefSharedFTFace(void* aContext
) {
166 static_cast<mozilla::gfx::SharedFTFace
*>(aContext
)->AddRef();
170 void mozilla_ReleaseSharedFTFace(void* aContext
, void* aOwner
) {
172 auto* sharedFace
= static_cast<mozilla::gfx::SharedFTFace
*>(aContext
);
173 sharedFace
->ForgetLockOwner(aOwner
);
174 sharedFace
->Release();
178 void mozilla_ForgetSharedFTFaceLockOwner(void* aContext
, void* aOwner
) {
179 static_cast<mozilla::gfx::SharedFTFace
*>(aContext
)->ForgetLockOwner(aOwner
);
182 int mozilla_LockSharedFTFace(void* aContext
,
183 void* aOwner
) NO_THREAD_SAFETY_ANALYSIS
{
184 return int(static_cast<mozilla::gfx::SharedFTFace
*>(aContext
)->Lock(aOwner
));
187 void mozilla_UnlockSharedFTFace(void* aContext
) NO_THREAD_SAFETY_ANALYSIS
{
188 static_cast<mozilla::gfx::SharedFTFace
*>(aContext
)->Unlock();
191 FT_Error
mozilla_LoadFTGlyph(FT_Face aFace
, uint32_t aGlyphIndex
,
193 return mozilla::gfx::Factory::LoadFTGlyph(aFace
, aGlyphIndex
, aFlags
);
196 void mozilla_LockFTLibrary(FT_Library aFTLibrary
) {
197 mozilla::gfx::Factory::LockFTLibrary(aFTLibrary
);
200 void mozilla_UnlockFTLibrary(FT_Library aFTLibrary
) {
201 mozilla::gfx::Factory::UnlockFTLibrary(aFTLibrary
);
206 namespace mozilla::gfx
{
208 #ifdef MOZ_ENABLE_FREETYPE
209 FT_Library
Factory::mFTLibrary
= nullptr;
210 StaticMutex
Factory::mFTLock
;
214 // Note: mDeviceLock must be held when mutating these values.
215 static uint32_t mDeviceSeq
= 0;
216 StaticRefPtr
<ID3D11Device
> Factory::mD3D11Device
;
217 StaticRefPtr
<ID2D1Device
> Factory::mD2D1Device
;
218 StaticRefPtr
<IDWriteFactory
> Factory::mDWriteFactory
;
219 StaticRefPtr
<ID2D1DeviceContext
> Factory::mMTDC
;
220 StaticRefPtr
<ID2D1DeviceContext
> Factory::mOffMTDC
;
221 bool Factory::mDWriteFactoryInitialized
= false;
222 StaticRefPtr
<IDWriteFontCollection
> Factory::mDWriteSystemFonts
;
223 StaticMutex
Factory::mDeviceLock
;
224 StaticMutex
Factory::mDTDependencyLock
;
227 bool Factory::mBGRSubpixelOrder
= false;
229 mozilla::gfx::Config
* Factory::sConfig
= nullptr;
231 void Factory::Init(const Config
& aConfig
) {
232 MOZ_ASSERT(!sConfig
);
233 sConfig
= new Config(aConfig
);
236 NativeFontResourceMac::RegisterMemoryReporter();
238 NativeFontResource::RegisterMemoryReporter();
242 void Factory::ShutDown() {
244 delete sConfig
->mLogForwarder
;
249 #ifdef MOZ_ENABLE_FREETYPE
250 mFTLibrary
= nullptr;
254 bool Factory::HasSSE2() {
255 #if defined(__SSE2__) || defined(_M_X64) || \
256 (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
257 // gcc with -msse2 (default on OSX and x86-64)
258 // cl.exe with -arch:SSE2 (default on x64 compiler)
260 #elif defined(HAVE_CPU_DETECTION)
265 } sDetectionState
= UNINITIALIZED
;
267 if (sDetectionState
== UNINITIALIZED
) {
268 sDetectionState
= HasCPUIDBit(1u, edx
, (1u << 26)) ? HAS_SSE2
: NO_SSE2
;
270 return sDetectionState
== HAS_SSE2
;
276 bool Factory::HasSSE4() {
277 #if defined(__SSE4__)
278 // gcc with -msse2 (default on OSX and x86-64)
279 // cl.exe with -arch:SSE2 (default on x64 compiler)
281 #elif defined(HAVE_CPU_DETECTION)
286 } sDetectionState
= UNINITIALIZED
;
288 if (sDetectionState
== UNINITIALIZED
) {
289 sDetectionState
= HasCPUIDBit(1u, ecx
, (1u << 19)) ? HAS_SSE4
: NO_SSE4
;
291 return sDetectionState
== HAS_SSE4
;
297 // If the size is "reasonable", we want gfxCriticalError to assert, so
298 // this is the option set up for it.
299 inline int LoggerOptionsBasedOnSize(const IntSize
& aSize
) {
300 return CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize
));
303 bool Factory::ReasonableSurfaceSize(const IntSize
& aSize
) {
304 return Factory::CheckSurfaceSize(aSize
, kReasonableSurfaceSize
);
307 bool Factory::AllowedSurfaceSize(const IntSize
& aSize
) {
309 return Factory::CheckSurfaceSize(aSize
, sConfig
->mMaxTextureSize
,
310 sConfig
->mMaxAllocSize
);
313 return CheckSurfaceSize(aSize
);
316 bool Factory::CheckBufferSize(int32_t bufSize
) {
317 return !sConfig
|| bufSize
< sConfig
->mMaxAllocSize
;
320 bool Factory::CheckSurfaceSize(const IntSize
& sz
, int32_t extentLimit
,
321 int32_t allocLimit
) {
322 if (sz
.width
<= 0 || sz
.height
<= 0) {
326 // reject images with sides bigger than limit
327 if (extentLimit
&& (sz
.width
> extentLimit
|| sz
.height
> extentLimit
)) {
328 gfxDebug() << "Surface size too large (exceeds extent limit)!";
332 // assuming 4 bytes per pixel, make sure the allocation size
333 // doesn't overflow a int32_t either
334 CheckedInt
<int32_t> stride
= GetAlignedStride
<16>(sz
.width
, 4);
335 if (!stride
.isValid() || stride
.value() == 0) {
336 gfxDebug() << "Surface size too large (stride overflows int32_t)!";
340 CheckedInt
<int32_t> numBytes
= stride
* sz
.height
;
341 if (!numBytes
.isValid()) {
343 << "Surface size too large (allocation size would overflow int32_t)!";
347 if (allocLimit
&& allocLimit
< numBytes
.value()) {
348 gfxDebug() << "Surface size too large (exceeds allocation limit)!";
355 already_AddRefed
<DrawTarget
> Factory::CreateDrawTarget(BackendType aBackend
,
356 const IntSize
& aSize
,
357 SurfaceFormat aFormat
) {
358 if (!AllowedSurfaceSize(aSize
)) {
359 gfxCriticalError(LoggerOptionsBasedOnSize(aSize
))
360 << "Failed to allocate a surface due to invalid size (CDT) " << aSize
;
364 RefPtr
<DrawTarget
> retVal
;
367 case BackendType::DIRECT2D1_1
: {
368 RefPtr
<DrawTargetD2D1
> newTarget
;
369 newTarget
= new DrawTargetD2D1();
370 if (newTarget
->Init(aSize
, aFormat
)) {
376 case BackendType::SKIA
: {
377 RefPtr
<DrawTargetSkia
> newTarget
;
378 newTarget
= new DrawTargetSkia();
379 if (newTarget
->Init(aSize
, aFormat
)) {
385 case BackendType::CAIRO
: {
386 RefPtr
<DrawTargetCairo
> newTarget
;
387 newTarget
= new DrawTargetCairo();
388 if (newTarget
->Init(aSize
, aFormat
)) {
400 gfxCriticalError(LoggerOptionsBasedOnSize(aSize
))
401 << "Failed to create DrawTarget, Type: " << int(aBackend
)
402 << " Size: " << aSize
;
405 return retVal
.forget();
408 already_AddRefed
<PathBuilder
> Factory::CreateSimplePathBuilder() {
409 return MakeAndAddRef
<PathBuilderSkia
>(FillRule::FILL_WINDING
);
412 already_AddRefed
<DrawTarget
> Factory::CreateRecordingDrawTarget(
413 DrawEventRecorder
* aRecorder
, DrawTarget
* aDT
, IntRect aRect
) {
414 return MakeAndAddRef
<DrawTargetRecording
>(aRecorder
, aDT
, aRect
);
417 already_AddRefed
<DrawTarget
> Factory::CreateDrawTargetForData(
418 BackendType aBackend
, unsigned char* aData
, const IntSize
& aSize
,
419 int32_t aStride
, SurfaceFormat aFormat
, bool aUninitialized
) {
421 if (!AllowedSurfaceSize(aSize
)) {
422 gfxCriticalError(LoggerOptionsBasedOnSize(aSize
))
423 << "Failed to allocate a surface due to invalid size (DTD) " << aSize
;
427 RefPtr
<DrawTarget
> retVal
;
430 case BackendType::SKIA
: {
431 RefPtr
<DrawTargetSkia
> newTarget
;
432 newTarget
= new DrawTargetSkia();
433 if (newTarget
->Init(aData
, aSize
, aStride
, aFormat
, aUninitialized
)) {
439 case BackendType::CAIRO
: {
440 RefPtr
<DrawTargetCairo
> newTarget
;
441 newTarget
= new DrawTargetCairo();
442 if (newTarget
->Init(aData
, aSize
, aStride
, aFormat
)) {
443 retVal
= std::move(newTarget
);
449 gfxCriticalNote
<< "Invalid draw target type specified: "
455 gfxCriticalNote
<< "Failed to create DrawTarget, Type: " << int(aBackend
)
456 << " Size: " << aSize
<< ", Data: " << hexa((void*)aData
)
457 << ", Stride: " << aStride
;
460 return retVal
.forget();
463 already_AddRefed
<DrawTarget
> Factory::CreateOffsetDrawTarget(
464 DrawTarget
* aDrawTarget
, IntPoint aTileOrigin
) {
465 RefPtr
<DrawTargetOffset
> dt
= new DrawTargetOffset();
467 if (!dt
->Init(aDrawTarget
, aTileOrigin
)) {
474 bool Factory::DoesBackendSupportDataDrawtarget(BackendType aType
) {
476 case BackendType::DIRECT2D
:
477 case BackendType::DIRECT2D1_1
:
478 case BackendType::RECORDING
:
479 case BackendType::NONE
:
480 case BackendType::BACKEND_LAST
:
481 case BackendType::WEBRENDER_TEXT
:
482 case BackendType::WEBGL
:
484 case BackendType::CAIRO
:
485 case BackendType::SKIA
:
492 uint32_t Factory::GetMaxSurfaceSize(BackendType aType
) {
494 case BackendType::CAIRO
:
495 return DrawTargetCairo::GetMaxSurfaceSize();
496 case BackendType::SKIA
:
497 return DrawTargetSkia::GetMaxSurfaceSize();
499 case BackendType::DIRECT2D1_1
:
500 return DrawTargetD2D1::GetMaxSurfaceSize();
507 already_AddRefed
<NativeFontResource
> Factory::CreateNativeFontResource(
508 uint8_t* aData
, uint32_t aSize
, FontType aFontType
, void* aFontContext
) {
511 case FontType::DWRITE
:
512 return NativeFontResourceDWrite::Create(aData
, aSize
);
514 return NativeFontResourceGDI::Create(aData
, aSize
);
515 #elif defined(XP_DARWIN)
517 return NativeFontResourceMac::Create(aData
, aSize
);
518 #elif defined(MOZ_WIDGET_GTK)
519 case FontType::FONTCONFIG
:
520 return NativeFontResourceFontconfig::Create(
521 aData
, aSize
, static_cast<FT_Library
>(aFontContext
));
522 #elif defined(MOZ_WIDGET_ANDROID)
523 case FontType::FREETYPE
:
524 return NativeFontResourceFreeType::Create(
525 aData
, aSize
, static_cast<FT_Library
>(aFontContext
));
529 << "Unable to create requested font resource from truetype data";
534 already_AddRefed
<UnscaledFont
> Factory::CreateUnscaledFontFromFontDescriptor(
535 FontType aType
, const uint8_t* aData
, uint32_t aDataLength
,
539 case FontType::DWRITE
:
540 return UnscaledFontDWrite::CreateFromFontDescriptor(aData
, aDataLength
,
543 return UnscaledFontGDI::CreateFromFontDescriptor(aData
, aDataLength
,
545 #elif defined(XP_DARWIN)
547 return UnscaledFontMac::CreateFromFontDescriptor(aData
, aDataLength
,
549 #elif defined(MOZ_WIDGET_GTK)
550 case FontType::FONTCONFIG
:
551 return UnscaledFontFontconfig::CreateFromFontDescriptor(
552 aData
, aDataLength
, aIndex
);
553 #elif defined(MOZ_WIDGET_ANDROID)
554 case FontType::FREETYPE
:
555 return UnscaledFontFreeType::CreateFromFontDescriptor(aData
, aDataLength
,
559 gfxWarning() << "Invalid type specified for UnscaledFont font descriptor";
565 already_AddRefed
<ScaledFont
> Factory::CreateScaledFontForMacFont(
566 CGFontRef aCGFont
, const RefPtr
<UnscaledFont
>& aUnscaledFont
, Float aSize
,
567 const DeviceColor
& aFontSmoothingBackgroundColor
, bool aUseFontSmoothing
,
568 bool aApplySyntheticBold
, bool aHasColorGlyphs
) {
569 return MakeAndAddRef
<ScaledFontMac
>(
570 aCGFont
, aUnscaledFont
, aSize
, false, aFontSmoothingBackgroundColor
,
571 aUseFontSmoothing
, aApplySyntheticBold
, aHasColorGlyphs
);
575 #ifdef MOZ_WIDGET_GTK
576 already_AddRefed
<ScaledFont
> Factory::CreateScaledFontForFontconfigFont(
577 const RefPtr
<UnscaledFont
>& aUnscaledFont
, Float aSize
,
578 RefPtr
<SharedFTFace
> aFace
, FcPattern
* aPattern
) {
579 return MakeAndAddRef
<ScaledFontFontconfig
>(std::move(aFace
), aPattern
,
580 aUnscaledFont
, aSize
);
584 #ifdef MOZ_WIDGET_ANDROID
585 already_AddRefed
<ScaledFont
> Factory::CreateScaledFontForFreeTypeFont(
586 const RefPtr
<UnscaledFont
>& aUnscaledFont
, Float aSize
,
587 RefPtr
<SharedFTFace
> aFace
, bool aApplySyntheticBold
) {
588 return MakeAndAddRef
<ScaledFontFreeType
>(std::move(aFace
), aUnscaledFont
,
589 aSize
, aApplySyntheticBold
);
593 void Factory::SetBGRSubpixelOrder(bool aBGR
) { mBGRSubpixelOrder
= aBGR
; }
595 bool Factory::GetBGRSubpixelOrder() { return mBGRSubpixelOrder
; }
597 #ifdef MOZ_ENABLE_FREETYPE
598 SharedFTFace::SharedFTFace(FT_Face aFace
, SharedFTFaceData
* aData
)
601 mLock("SharedFTFace::mLock"),
602 mLastLockOwner(nullptr) {
608 SharedFTFace::~SharedFTFace() {
609 Factory::ReleaseFTFace(mFace
);
611 mData
->ReleaseData();
615 void Factory::SetFTLibrary(FT_Library aFTLibrary
) { mFTLibrary
= aFTLibrary
; }
617 FT_Library
Factory::GetFTLibrary() {
618 MOZ_ASSERT(mFTLibrary
);
622 FT_Library
Factory::NewFTLibrary() {
624 if (FT_Init_FreeType(&library
) != FT_Err_Ok
) {
630 void Factory::ReleaseFTLibrary(FT_Library aFTLibrary
) {
631 FT_Done_FreeType(aFTLibrary
);
634 void Factory::LockFTLibrary(FT_Library aFTLibrary
)
635 CAPABILITY_ACQUIRE(mFTLock
) NO_THREAD_SAFETY_ANALYSIS
{
639 void Factory::UnlockFTLibrary(FT_Library aFTLibrary
)
640 CAPABILITY_RELEASE(mFTLock
) NO_THREAD_SAFETY_ANALYSIS
{
644 FT_Face
Factory::NewFTFace(FT_Library aFTLibrary
, const char* aFileName
,
646 StaticMutexAutoLock
lock(mFTLock
);
648 aFTLibrary
= mFTLibrary
;
651 if (FT_New_Face(aFTLibrary
, aFileName
, aFaceIndex
, &face
) != FT_Err_Ok
) {
657 already_AddRefed
<SharedFTFace
> Factory::NewSharedFTFace(FT_Library aFTLibrary
,
658 const char* aFilename
,
660 if (FT_Face face
= NewFTFace(aFTLibrary
, aFilename
, aFaceIndex
)) {
661 return MakeAndAddRef
<SharedFTFace
>(face
);
667 FT_Face
Factory::NewFTFaceFromData(FT_Library aFTLibrary
, const uint8_t* aData
,
668 size_t aDataSize
, int aFaceIndex
) {
669 StaticMutexAutoLock
lock(mFTLock
);
671 aFTLibrary
= mFTLibrary
;
674 if (FT_New_Memory_Face(aFTLibrary
, aData
, aDataSize
, aFaceIndex
, &face
) !=
681 already_AddRefed
<SharedFTFace
> Factory::NewSharedFTFaceFromData(
682 FT_Library aFTLibrary
, const uint8_t* aData
, size_t aDataSize
,
683 int aFaceIndex
, SharedFTFaceData
* aSharedData
) {
685 NewFTFaceFromData(aFTLibrary
, aData
, aDataSize
, aFaceIndex
)) {
686 return MakeAndAddRef
<SharedFTFace
>(face
, aSharedData
);
692 void Factory::ReleaseFTFace(FT_Face aFace
) {
693 StaticMutexAutoLock
lock(mFTLock
);
697 FT_Error
Factory::LoadFTGlyph(FT_Face aFace
, uint32_t aGlyphIndex
,
699 StaticMutexAutoLock
lock(mFTLock
);
700 return FT_Load_Glyph(aFace
, aGlyphIndex
, aFlags
);
704 AutoSerializeWithMoz2D::AutoSerializeWithMoz2D(BackendType aBackendType
) {
706 // We use a multi-threaded ID2D1Factory1, so that makes the calls through the
707 // Direct2D API thread-safe. However, if the Moz2D objects are using Direct3D
708 // resources we need to make sure that calls through the Direct3D or DXGI API
709 // use the Direct2D synchronization. It's possible that this should be pushed
710 // down into the TextureD3D11 objects, so that we always use this.
711 if (aBackendType
== BackendType::DIRECT2D1_1
||
712 aBackendType
== BackendType::DIRECT2D
) {
713 auto factory
= D2DFactory();
715 factory
->QueryInterface(
716 static_cast<ID2D1Multithread
**>(getter_AddRefs(mMT
)));
725 AutoSerializeWithMoz2D::~AutoSerializeWithMoz2D() {
734 already_AddRefed
<DrawTarget
> Factory::CreateDrawTargetForD3D11Texture(
735 ID3D11Texture2D
* aTexture
, SurfaceFormat aFormat
) {
736 MOZ_ASSERT(aTexture
);
738 RefPtr
<DrawTargetD2D1
> newTarget
;
740 newTarget
= new DrawTargetD2D1();
741 if (newTarget
->Init(aTexture
, aFormat
)) {
742 RefPtr
<DrawTarget
> retVal
= newTarget
;
743 return retVal
.forget();
746 gfxWarning() << "Failed to create draw target for D3D11 texture.";
752 bool Factory::SetDirect3D11Device(ID3D11Device
* aDevice
) {
753 MOZ_RELEASE_ASSERT(NS_IsMainThread());
755 // D2DFactory already takes the device lock, so we get the factory before
756 // entering the lock scope.
757 RefPtr
<ID2D1Factory1
> factory
= D2DFactory();
759 StaticMutexAutoLock
lock(mDeviceLock
);
761 mD3D11Device
= aDevice
;
764 mD2D1Device
= nullptr;
773 RefPtr
<IDXGIDevice
> device
;
774 aDevice
->QueryInterface((IDXGIDevice
**)getter_AddRefs(device
));
776 RefPtr
<ID2D1Device
> d2dDevice
;
777 HRESULT hr
= factory
->CreateDevice(device
, getter_AddRefs(d2dDevice
));
780 << "[D2D1] Failed to create gfx factory's D2D1 device, code: "
783 mD3D11Device
= nullptr;
788 mD2D1Device
= d2dDevice
;
792 RefPtr
<ID3D11Device
> Factory::GetDirect3D11Device() {
793 StaticMutexAutoLock
lock(mDeviceLock
);
797 RefPtr
<ID2D1Device
> Factory::GetD2D1Device(uint32_t* aOutSeqNo
) {
798 StaticMutexAutoLock
lock(mDeviceLock
);
800 *aOutSeqNo
= mDeviceSeq
;
802 return mD2D1Device
.get();
805 bool Factory::HasD2D1Device() { return !!GetD2D1Device(); }
807 RefPtr
<IDWriteFactory
> Factory::GetDWriteFactory() {
808 StaticMutexAutoLock
lock(mDeviceLock
);
809 return mDWriteFactory
;
812 RefPtr
<IDWriteFactory
> Factory::EnsureDWriteFactory() {
813 StaticMutexAutoLock
lock(mDeviceLock
);
815 if (mDWriteFactoryInitialized
) {
816 return mDWriteFactory
;
819 mDWriteFactoryInitialized
= true;
821 HMODULE dwriteModule
= LoadLibrarySystem32(L
"dwrite.dll");
822 decltype(DWriteCreateFactory
)* createDWriteFactory
=
823 (decltype(DWriteCreateFactory
)*)GetProcAddress(dwriteModule
,
824 "DWriteCreateFactory");
826 if (!createDWriteFactory
) {
827 gfxWarning() << "Failed to locate DWriteCreateFactory function.";
832 createDWriteFactory(DWRITE_FACTORY_TYPE_SHARED
, __uuidof(IDWriteFactory
),
833 reinterpret_cast<IUnknown
**>(&mDWriteFactory
));
836 gfxWarning() << "Failed to create DWrite Factory.";
839 return mDWriteFactory
;
842 RefPtr
<IDWriteFontCollection
> Factory::GetDWriteSystemFonts(bool aUpdate
) {
843 StaticMutexAutoLock
lock(mDeviceLock
);
845 if (mDWriteSystemFonts
&& !aUpdate
) {
846 return mDWriteSystemFonts
;
849 if (!mDWriteFactory
) {
850 if ((rand() & 0x3f) == 0) {
851 gfxCriticalError(int(gfx::LogOptions::AssertOnCall
))
852 << "Failed to create DWrite factory";
854 gfxWarning() << "Failed to create DWrite factory";
860 RefPtr
<IDWriteFontCollection
> systemFonts
;
862 mDWriteFactory
->GetSystemFontCollection(getter_AddRefs(systemFonts
));
863 if (FAILED(hr
) || !systemFonts
) {
864 // only crash some of the time so those experiencing this problem
865 // don't stop using Firefox
866 if ((rand() & 0x3f) == 0) {
867 gfxCriticalError(int(gfx::LogOptions::AssertOnCall
))
868 << "Failed to create DWrite system font collection";
870 gfxWarning() << "Failed to create DWrite system font collection";
874 mDWriteSystemFonts
= systemFonts
;
876 return mDWriteSystemFonts
;
879 RefPtr
<ID2D1DeviceContext
> Factory::GetD2DDeviceContext() {
880 StaticRefPtr
<ID2D1DeviceContext
>* ptr
;
882 if (NS_IsMainThread()) {
892 RefPtr
<ID2D1Device
> device
= GetD2D1Device();
898 RefPtr
<ID2D1DeviceContext
> dc
;
899 HRESULT hr
= device
->CreateDeviceContext(
900 D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS
,
904 gfxCriticalError() << "Failed to create global device context";
913 bool Factory::SupportsD2D1() { return !!D2DFactory(); }
915 BYTE sSystemTextQuality
= CLEARTYPE_QUALITY
;
916 void Factory::SetSystemTextQuality(uint8_t aQuality
) {
917 sSystemTextQuality
= aQuality
;
920 uint64_t Factory::GetD2DVRAMUsageDrawTarget() {
921 return DrawTargetD2D1::mVRAMUsageDT
;
924 uint64_t Factory::GetD2DVRAMUsageSourceSurface() {
925 return DrawTargetD2D1::mVRAMUsageSS
;
928 void Factory::D2DCleanup() {
929 StaticMutexAutoLock
lock(mDeviceLock
);
931 mD2D1Device
= nullptr;
933 DrawTargetD2D1::CleanupD2D();
936 already_AddRefed
<ScaledFont
> Factory::CreateScaledFontForDWriteFont(
937 IDWriteFontFace
* aFontFace
, const gfxFontStyle
* aStyle
,
938 const RefPtr
<UnscaledFont
>& aUnscaledFont
, float aSize
,
939 bool aUseEmbeddedBitmap
, bool aUseMultistrikeBold
, bool aGDIForced
) {
940 return MakeAndAddRef
<ScaledFontDWrite
>(
941 aFontFace
, aUnscaledFont
, aSize
, aUseEmbeddedBitmap
, aUseMultistrikeBold
,
945 already_AddRefed
<ScaledFont
> Factory::CreateScaledFontForGDIFont(
946 const void* aLogFont
, const RefPtr
<UnscaledFont
>& aUnscaledFont
,
948 return MakeAndAddRef
<ScaledFontWin
>(static_cast<const LOGFONT
*>(aLogFont
),
949 aUnscaledFont
, aSize
);
953 already_AddRefed
<DrawTarget
> Factory::CreateDrawTargetWithSkCanvas(
955 RefPtr
<DrawTargetSkia
> newTarget
= new DrawTargetSkia();
956 if (!newTarget
->Init(aCanvas
)) {
959 return newTarget
.forget();
962 void Factory::PurgeAllCaches() {}
964 already_AddRefed
<DrawTarget
> Factory::CreateDrawTargetForCairoSurface(
965 cairo_surface_t
* aSurface
, const IntSize
& aSize
, SurfaceFormat
* aFormat
) {
966 if (!AllowedSurfaceSize(aSize
)) {
967 gfxWarning() << "Allowing surface with invalid size (Cairo) " << aSize
;
970 RefPtr
<DrawTarget
> retVal
;
973 RefPtr
<DrawTargetCairo
> newTarget
= new DrawTargetCairo();
975 if (newTarget
->Init(aSurface
, aSize
, aFormat
)) {
979 return retVal
.forget();
982 already_AddRefed
<SourceSurface
> Factory::CreateSourceSurfaceForCairoSurface(
983 cairo_surface_t
* aSurface
, const IntSize
& aSize
, SurfaceFormat aFormat
) {
984 if (aSize
.width
<= 0 || aSize
.height
<= 0) {
985 gfxWarning() << "Can't create a SourceSurface without a valid size";
990 return MakeAndAddRef
<SourceSurfaceCairo
>(aSurface
, aSize
, aFormat
);
996 already_AddRefed
<DataSourceSurface
> Factory::CreateWrappingDataSourceSurface(
997 uint8_t* aData
, int32_t aStride
, const IntSize
& aSize
,
998 SurfaceFormat aFormat
,
999 SourceSurfaceDeallocator aDeallocator
/* = nullptr */,
1000 void* aClosure
/* = nullptr */) {
1001 // Just check for negative/zero size instead of the full AllowedSurfaceSize()
1002 // - since the data is already allocated we do not need to check for a
1003 // possible overflow - it already worked.
1004 if (aSize
.width
<= 0 || aSize
.height
<= 0) {
1007 if (!aDeallocator
&& aClosure
) {
1013 RefPtr
<SourceSurfaceRawData
> newSurf
= new SourceSurfaceRawData();
1014 newSurf
->InitWrappingData(aData
, aSize
, aStride
, aFormat
, aDeallocator
,
1017 return newSurf
.forget();
1020 already_AddRefed
<DataSourceSurface
> Factory::CreateDataSourceSurface(
1021 const IntSize
& aSize
, SurfaceFormat aFormat
, bool aZero
) {
1022 if (!AllowedSurfaceSize(aSize
)) {
1023 gfxCriticalError(LoggerOptionsBasedOnSize(aSize
))
1024 << "Failed to allocate a surface due to invalid size (DSS) " << aSize
;
1028 // Skia doesn't support RGBX, so memset RGBX to 0xFF
1029 bool clearSurface
= aZero
|| aFormat
== SurfaceFormat::B8G8R8X8
;
1030 uint8_t clearValue
= aFormat
== SurfaceFormat::B8G8R8X8
? 0xFF : 0;
1032 RefPtr
<SourceSurfaceAlignedRawData
> newSurf
=
1033 new SourceSurfaceAlignedRawData();
1034 if (newSurf
->Init(aSize
, aFormat
, clearSurface
, clearValue
)) {
1035 return newSurf
.forget();
1038 gfxWarning() << "CreateDataSourceSurface failed in init";
1042 already_AddRefed
<DataSourceSurface
> Factory::CreateDataSourceSurfaceWithStride(
1043 const IntSize
& aSize
, SurfaceFormat aFormat
, int32_t aStride
, bool aZero
) {
1044 if (!AllowedSurfaceSize(aSize
) ||
1045 aStride
< aSize
.width
* BytesPerPixel(aFormat
)) {
1046 gfxCriticalError(LoggerOptionsBasedOnSize(aSize
))
1047 << "CreateDataSourceSurfaceWithStride failed with bad stride "
1048 << aStride
<< ", " << aSize
<< ", " << aFormat
;
1052 // Skia doesn't support RGBX, so memset RGBX to 0xFF
1053 bool clearSurface
= aZero
|| aFormat
== SurfaceFormat::B8G8R8X8
;
1054 uint8_t clearValue
= aFormat
== SurfaceFormat::B8G8R8X8
? 0xFF : 0;
1056 RefPtr
<SourceSurfaceAlignedRawData
> newSurf
=
1057 new SourceSurfaceAlignedRawData();
1058 if (newSurf
->Init(aSize
, aFormat
, clearSurface
, clearValue
, aStride
)) {
1059 return newSurf
.forget();
1062 gfxCriticalError(LoggerOptionsBasedOnSize(aSize
))
1063 << "CreateDataSourceSurfaceWithStride failed to initialize " << aSize
1064 << ", " << aFormat
<< ", " << aStride
<< ", " << aZero
;
1068 void Factory::CopyDataSourceSurface(DataSourceSurface
* aSource
,
1069 DataSourceSurface
* aDest
) {
1070 // Don't worry too much about speed.
1071 MOZ_ASSERT(aSource
->GetSize() == aDest
->GetSize());
1072 MOZ_ASSERT(aSource
->GetFormat() == SurfaceFormat::R8G8B8A8
||
1073 aSource
->GetFormat() == SurfaceFormat::R8G8B8X8
||
1074 aSource
->GetFormat() == SurfaceFormat::B8G8R8A8
||
1075 aSource
->GetFormat() == SurfaceFormat::B8G8R8X8
);
1076 MOZ_ASSERT(aDest
->GetFormat() == SurfaceFormat::R8G8B8A8
||
1077 aDest
->GetFormat() == SurfaceFormat::R8G8B8X8
||
1078 aDest
->GetFormat() == SurfaceFormat::B8G8R8A8
||
1079 aDest
->GetFormat() == SurfaceFormat::B8G8R8X8
||
1080 aDest
->GetFormat() == SurfaceFormat::R5G6B5_UINT16
);
1082 DataSourceSurface::MappedSurface srcMap
;
1083 DataSourceSurface::MappedSurface destMap
;
1084 if (!aSource
->Map(DataSourceSurface::MapType::READ
, &srcMap
) ||
1085 !aDest
->Map(DataSourceSurface::MapType::WRITE
, &destMap
)) {
1086 MOZ_ASSERT(false, "CopyDataSourceSurface: Failed to map surface.");
1090 SwizzleData(srcMap
.mData
, srcMap
.mStride
, aSource
->GetFormat(), destMap
.mData
,
1091 destMap
.mStride
, aDest
->GetFormat(), aSource
->GetSize());
1100 already_AddRefed
<DataSourceSurface
>
1101 Factory::CreateBGRA8DataSourceSurfaceForD3D11Texture(
1102 ID3D11Texture2D
* aSrcTexture
) {
1103 D3D11_TEXTURE2D_DESC srcDesc
= {0};
1104 aSrcTexture
->GetDesc(&srcDesc
);
1106 RefPtr
<gfx::DataSourceSurface
> destTexture
=
1107 gfx::Factory::CreateDataSourceSurface(
1108 IntSize(srcDesc
.Width
, srcDesc
.Height
), gfx::SurfaceFormat::B8G8R8A8
);
1109 if (NS_WARN_IF(!destTexture
)) {
1112 if (!ReadbackTexture(destTexture
, aSrcTexture
)) {
1115 return destTexture
.forget();
1119 template <typename DestTextureT
>
1120 bool Factory::ConvertSourceAndRetryReadback(DestTextureT
* aDestCpuTexture
,
1121 ID3D11Texture2D
* aSrcTexture
) {
1122 RefPtr
<ID3D11Device
> device
;
1123 aSrcTexture
->GetDevice(getter_AddRefs(device
));
1125 gfxWarning() << "Failed to get D3D11 device from source texture";
1129 nsAutoCString error
;
1130 std::unique_ptr
<DXVA2Manager
> manager(
1131 DXVA2Manager::CreateD3D11DXVA(nullptr, error
, device
));
1133 gfxWarning() << "Failed to create DXVA2 manager!";
1137 RefPtr
<ID3D11Texture2D
> newSrcTexture
;
1139 manager
->CopyToBGRATexture(aSrcTexture
, getter_AddRefs(newSrcTexture
));
1141 gfxWarning() << "Failed to copy to BGRA texture.";
1145 return ReadbackTexture(aDestCpuTexture
, newSrcTexture
);
1149 bool Factory::ReadbackTexture(layers::TextureData
* aDestCpuTexture
,
1150 ID3D11Texture2D
* aSrcTexture
) {
1151 layers::MappedTextureData mappedData
;
1152 if (!aDestCpuTexture
->BorrowMappedData(mappedData
)) {
1153 gfxWarning() << "Could not access in-memory texture";
1157 D3D11_TEXTURE2D_DESC srcDesc
= {0};
1158 aSrcTexture
->GetDesc(&srcDesc
);
1160 // Special case: If the source and destination have different formats and the
1161 // destination is B8G8R8A8 then convert the source to B8G8R8A8 and readback.
1162 if ((srcDesc
.Format
!= DXGIFormat(mappedData
.format
)) &&
1163 (mappedData
.format
== SurfaceFormat::B8G8R8A8
)) {
1164 return ConvertSourceAndRetryReadback(aDestCpuTexture
, aSrcTexture
);
1167 if ((IntSize(srcDesc
.Width
, srcDesc
.Height
) != mappedData
.size
) ||
1168 (srcDesc
.Format
!= DXGIFormat(mappedData
.format
))) {
1169 gfxWarning() << "Attempted readback between incompatible textures";
1173 return ReadbackTexture(mappedData
.data
, mappedData
.stride
, aSrcTexture
);
1177 bool Factory::ReadbackTexture(DataSourceSurface
* aDestCpuTexture
,
1178 ID3D11Texture2D
* aSrcTexture
) {
1179 D3D11_TEXTURE2D_DESC srcDesc
= {0};
1180 aSrcTexture
->GetDesc(&srcDesc
);
1182 // Special case: If the source and destination have different formats and the
1183 // destination is B8G8R8A8 then convert the source to B8G8R8A8 and readback.
1184 if ((srcDesc
.Format
!= DXGIFormat(aDestCpuTexture
->GetFormat())) &&
1185 (aDestCpuTexture
->GetFormat() == SurfaceFormat::B8G8R8A8
)) {
1186 return ConvertSourceAndRetryReadback(aDestCpuTexture
, aSrcTexture
);
1189 if ((IntSize(srcDesc
.Width
, srcDesc
.Height
) != aDestCpuTexture
->GetSize()) ||
1190 (srcDesc
.Format
!= DXGIFormat(aDestCpuTexture
->GetFormat()))) {
1191 gfxWarning() << "Attempted readback between incompatible textures";
1195 gfx::DataSourceSurface::MappedSurface mappedSurface
;
1196 if (!aDestCpuTexture
->Map(gfx::DataSourceSurface::WRITE
, &mappedSurface
)) {
1201 ReadbackTexture(mappedSurface
.mData
, mappedSurface
.mStride
, aSrcTexture
);
1202 aDestCpuTexture
->Unmap();
1207 bool Factory::ReadbackTexture(uint8_t* aDestData
, int32_t aDestStride
,
1208 ID3D11Texture2D
* aSrcTexture
) {
1209 MOZ_ASSERT(aDestData
&& aDestStride
&& aSrcTexture
);
1211 RefPtr
<ID3D11Device
> device
;
1212 aSrcTexture
->GetDevice(getter_AddRefs(device
));
1214 gfxWarning() << "Failed to get D3D11 device from source texture";
1218 RefPtr
<ID3D11DeviceContext
> context
;
1219 device
->GetImmediateContext(getter_AddRefs(context
));
1221 gfxWarning() << "Could not get an immediate D3D11 context";
1225 RefPtr
<IDXGIKeyedMutex
> mutex
;
1226 HRESULT hr
= aSrcTexture
->QueryInterface(__uuidof(IDXGIKeyedMutex
),
1227 (void**)getter_AddRefs(mutex
));
1228 if (SUCCEEDED(hr
) && mutex
) {
1229 hr
= mutex
->AcquireSync(0, 2000);
1231 gfxWarning() << "Could not acquire DXGI surface lock in 2 seconds";
1236 D3D11_TEXTURE2D_DESC srcDesc
= {0};
1237 aSrcTexture
->GetDesc(&srcDesc
);
1238 srcDesc
.CPUAccessFlags
= D3D11_CPU_ACCESS_READ
;
1239 srcDesc
.Usage
= D3D11_USAGE_STAGING
;
1240 srcDesc
.BindFlags
= 0;
1241 srcDesc
.MiscFlags
= 0;
1242 srcDesc
.MipLevels
= 1;
1243 RefPtr
<ID3D11Texture2D
> srcCpuTexture
;
1245 device
->CreateTexture2D(&srcDesc
, nullptr, getter_AddRefs(srcCpuTexture
));
1247 gfxWarning() << "Could not create source texture for mapping";
1249 mutex
->ReleaseSync(0);
1254 context
->CopyResource(srcCpuTexture
, aSrcTexture
);
1257 mutex
->ReleaseSync(0);
1261 D3D11_MAPPED_SUBRESOURCE srcMap
;
1262 hr
= context
->Map(srcCpuTexture
, 0, D3D11_MAP_READ
, 0, &srcMap
);
1264 gfxWarning() << "Could not map source texture";
1268 uint32_t width
= srcDesc
.Width
;
1269 uint32_t height
= srcDesc
.Height
;
1270 int bpp
= BytesPerPixel(gfx::ToPixelFormat(srcDesc
.Format
));
1271 for (int y
= 0; y
< height
; y
++) {
1272 memcpy(aDestData
+ aDestStride
* y
,
1273 (unsigned char*)(srcMap
.pData
) + srcMap
.RowPitch
* y
, width
* bpp
);
1276 context
->Unmap(srcCpuTexture
, 0);
1283 void CriticalLogger::OutputMessage(const std::string
& aString
, int aLevel
,
1285 if (Factory::GetLogForwarder()) {
1286 Factory::GetLogForwarder()->Log(aString
);
1289 BasicLogger::OutputMessage(aString
, aLevel
, aNoNewline
);
1292 void CriticalLogger::CrashAction(LogReason aReason
) {
1293 if (Factory::GetLogForwarder()) {
1294 Factory::GetLogForwarder()->CrashAction(aReason
);
1299 void LogWStr(const wchar_t* aWStr
, std::stringstream
& aOut
) {
1301 WideCharToMultiByte(CP_ACP
, 0, aWStr
, -1, nullptr, 0, nullptr, nullptr);
1303 std::vector
<char> str(n
);
1304 WideCharToMultiByte(CP_ACP
, 0, aWStr
, -1, str
.data(), n
, nullptr, nullptr);
1310 } // namespace mozilla::gfx