mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-08 08:48:39 +09:00
Merge remote-tracking branch 'origin/tracking' into custom
This commit is contained in:
commit
c889903081
34 changed files with 846 additions and 195 deletions
|
|
@ -9,9 +9,16 @@
|
|||
#include "ImageContainer.h"
|
||||
#include "mozilla/layers/SharedRGBImage.h"
|
||||
#include "YCbCrUtils.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h"
|
||||
#include "mozilla/layers/KnowsCompositor.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "mozilla/layers/D3D11YCbCrImage.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
|
@ -218,19 +225,14 @@ VideoData::ShallowCopyUpdateTimestampAndDuration(const VideoData* aOther,
|
|||
return v.forget();
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool VideoData::SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
|
||||
const VideoInfo& aInfo,
|
||||
const YCbCrBuffer &aBuffer,
|
||||
const IntRect& aPicture,
|
||||
bool aCopyData)
|
||||
PlanarYCbCrData
|
||||
ConstructPlanarYCbCrData(const VideoInfo& aInfo,
|
||||
const VideoData::YCbCrBuffer& aBuffer,
|
||||
const IntRect& aPicture)
|
||||
{
|
||||
if (!aVideoImage) {
|
||||
return false;
|
||||
}
|
||||
const YCbCrBuffer::Plane &Y = aBuffer.mPlanes[0];
|
||||
const YCbCrBuffer::Plane &Cb = aBuffer.mPlanes[1];
|
||||
const YCbCrBuffer::Plane &Cr = aBuffer.mPlanes[2];
|
||||
const VideoData::YCbCrBuffer::Plane& Y = aBuffer.mPlanes[0];
|
||||
const VideoData::YCbCrBuffer::Plane& Cb = aBuffer.mPlanes[1];
|
||||
const VideoData::YCbCrBuffer::Plane& Cr = aBuffer.mPlanes[2];
|
||||
|
||||
PlanarYCbCrData data;
|
||||
data.mYChannel = Y.mData + Y.mOffset;
|
||||
|
|
@ -249,6 +251,21 @@ bool VideoData::SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
|
|||
data.mStereoMode = aInfo.mStereoMode;
|
||||
data.mYUVColorSpace = aBuffer.mYUVColorSpace;
|
||||
data.mColorRange = aBuffer.mColorRange;
|
||||
return data;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
VideoData::SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
|
||||
const VideoInfo& aInfo,
|
||||
const YCbCrBuffer &aBuffer,
|
||||
const IntRect& aPicture,
|
||||
bool aCopyData)
|
||||
{
|
||||
if (!aVideoImage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PlanarYCbCrData data = ConstructPlanarYCbCrData(aInfo, aBuffer, aPicture);
|
||||
|
||||
aVideoImage->SetDelayedConversion(true);
|
||||
if (aCopyData) {
|
||||
|
|
@ -268,7 +285,8 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
|
|||
const YCbCrBuffer& aBuffer,
|
||||
bool aKeyframe,
|
||||
int64_t aTimecode,
|
||||
const IntRect& aPicture)
|
||||
const IntRect& aPicture,
|
||||
layers::KnowsCompositor* aAllocator)
|
||||
{
|
||||
if (!aContainer) {
|
||||
// Create a dummy VideoData with no image. This gives us something to
|
||||
|
|
@ -296,6 +314,23 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
|
|||
0));
|
||||
// Currently our decoder only knows how to output to ImageFormat::PLANAR_YCBCR
|
||||
// format.
|
||||
#if XP_WIN
|
||||
// We disable this code path on Windows 7 due to intermittent crashes with old drivers.
|
||||
// See Mozilla bug 1405110.
|
||||
if (IsWin8OrLater() && !XRE_IsParentProcess() &&
|
||||
aAllocator && aAllocator->GetCompositorBackendType()
|
||||
== layers::LayersBackend::LAYERS_D3D11) {
|
||||
RefPtr<layers::D3D11YCbCrImage> d3d11Image = new layers::D3D11YCbCrImage();
|
||||
PlanarYCbCrData data = ConstructPlanarYCbCrData(aInfo, aBuffer, aPicture);
|
||||
if (d3d11Image->SetData(layers::ImageBridgeChild::GetSingleton()
|
||||
? layers::ImageBridgeChild::GetSingleton().get()
|
||||
: aAllocator,
|
||||
aContainer, data)) {
|
||||
v->mImage = d3d11Image;
|
||||
return v.forget();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!v->mImage) {
|
||||
v->mImage = aContainer->CreatePlanarYCbCrImage();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ namespace mozilla {
|
|||
namespace layers {
|
||||
class Image;
|
||||
class ImageContainer;
|
||||
class KnowsCompositor;
|
||||
} // namespace layers
|
||||
|
||||
class MediaByteBuffer;
|
||||
|
|
@ -472,7 +473,8 @@ public:
|
|||
const YCbCrBuffer &aBuffer,
|
||||
bool aKeyframe,
|
||||
int64_t aTimecode,
|
||||
const IntRect& aPicture);
|
||||
const IntRect& aPicture,
|
||||
layers::KnowsCompositor* aAllocator = nullptr);
|
||||
|
||||
static already_AddRefed<VideoData> CreateAndCopyData(const VideoInfo& aInfo,
|
||||
ImageContainer* aContainer,
|
||||
|
|
|
|||
|
|
@ -1500,6 +1500,15 @@ MediaFormatReader::Update(TrackType aTrack)
|
|||
nsCString error;
|
||||
mVideo.mIsHardwareAccelerated =
|
||||
mVideo.mDecoder && mVideo.mDecoder->IsHardwareAccelerated(error);
|
||||
#ifdef XP_WIN
|
||||
// D3D11_YCBCR_IMAGE images are GPU based, we try to limit the amount
|
||||
// of GPU RAM used.
|
||||
VideoData* videoData = static_cast<VideoData*>(output.get());
|
||||
mVideo.mIsHardwareAccelerated =
|
||||
mVideo.mIsHardwareAccelerated ||
|
||||
(videoData->mImage &&
|
||||
videoData->mImage->GetFormat() == ImageFormat::D3D11_YCBCR_IMAGE);
|
||||
#endif
|
||||
}
|
||||
} else if (decoder.HasFatalError()) {
|
||||
LOG("Rejecting %s promise: DECODE_ERROR", TrackTypeToStr(aTrack));
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ ogg_packet InitTheoraPacket(const unsigned char* aData, size_t aLength,
|
|||
}
|
||||
|
||||
TheoraDecoder::TheoraDecoder(const CreateDecoderParams& aParams)
|
||||
: mImageContainer(aParams.mImageContainer)
|
||||
: mImageAllocator(aParams.mKnowsCompositor)
|
||||
, mImageContainer(aParams.mImageContainer)
|
||||
, mTaskQueue(aParams.mTaskQueue)
|
||||
, mCallback(aParams.mCallback)
|
||||
, mIsFlushing(false)
|
||||
|
|
@ -176,7 +177,8 @@ TheoraDecoder::DoDecode(MediaRawData* aSample)
|
|||
aSample->mKeyframe,
|
||||
aSample->mTimecode,
|
||||
mInfo.ScaledImageRect(mTheoraInfo.frame_width,
|
||||
mTheoraInfo.frame_height));
|
||||
mTheoraInfo.frame_height),
|
||||
mImageAllocator);
|
||||
if (!v) {
|
||||
LOG("Image allocation error source %ldx%ld display %ldx%ld picture %ldx%ld",
|
||||
mTheoraInfo.frame_width, mTheoraInfo.frame_height, mInfo.mDisplay.width, mInfo.mDisplay.height,
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ private:
|
|||
MediaResult DoDecode(MediaRawData* aSample);
|
||||
void ProcessDrain();
|
||||
|
||||
RefPtr<KnowsCompositor> mImageAllocator;
|
||||
RefPtr<ImageContainer> mImageContainer;
|
||||
RefPtr<TaskQueue> mTaskQueue;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ InitContext(vpx_codec_ctx_t* aCtx,
|
|||
|
||||
VPXDecoder::VPXDecoder(const CreateDecoderParams& aParams)
|
||||
: mImageContainer(aParams.mImageContainer)
|
||||
, mImageAllocator(aParams.mKnowsCompositor)
|
||||
, mTaskQueue(aParams.mTaskQueue)
|
||||
, mCallback(aParams.mCallback)
|
||||
, mIsFlushing(false)
|
||||
|
|
@ -149,7 +150,7 @@ VPXDecoder::DoDecode(MediaRawData* aSample)
|
|||
"WebM image format not I420 or I444");
|
||||
NS_ASSERTION(!alpha_decoded,
|
||||
"Multiple frames per packet that contains alpha");
|
||||
|
||||
|
||||
if (aSample->AlphaSize() > 0) {
|
||||
if(!alpha_decoded){
|
||||
MediaResult rv = DecodeAlpha(&img_alpha, aSample);
|
||||
|
|
@ -221,7 +222,8 @@ VPXDecoder::DoDecode(MediaRawData* aSample)
|
|||
aSample->mKeyframe,
|
||||
aSample->mTimecode,
|
||||
mInfo.ScaledImageRect(img->d_w,
|
||||
img->d_h));
|
||||
img->d_h),
|
||||
mImageAllocator);
|
||||
} else {
|
||||
VideoData::YCbCrBuffer::Plane alpha_plane;
|
||||
alpha_plane.mData = img_alpha->planes[0];
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ private:
|
|||
MediaRawData* aSample);
|
||||
|
||||
const RefPtr<ImageContainer> mImageContainer;
|
||||
RefPtr<layers::KnowsCompositor> mImageAllocator;
|
||||
const RefPtr<TaskQueue> mTaskQueue;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
Atomic<bool> mIsFlushing;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ public:
|
|||
aParams.mTaskQueue,
|
||||
aParams.mCallback,
|
||||
aParams.VideoConfig(),
|
||||
aParams.mKnowsCompositor,
|
||||
aParams.mImageContainer);
|
||||
return decoder.forget();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "MediaInfo.h"
|
||||
#include "VPXDecoder.h"
|
||||
#include "MP4Decoder.h"
|
||||
#include "mozilla/layers/KnowsCompositor.h"
|
||||
|
||||
#include "FFmpegVideoDecoder.h"
|
||||
#include "FFmpegLog.h"
|
||||
|
|
@ -109,8 +110,9 @@ FFmpegVideoDecoder<LIBAV_VER>::PtsCorrectionContext::Reset()
|
|||
FFmpegVideoDecoder<LIBAV_VER>::FFmpegVideoDecoder(FFmpegLibWrapper* aLib,
|
||||
TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
|
||||
const VideoInfo& aConfig,
|
||||
ImageContainer* aImageContainer)
|
||||
KnowsCompositor* aAllocator, ImageContainer* aImageContainer)
|
||||
: FFmpegDataDecoder(aLib, aTaskQueue, aCallback, GetCodecId(aConfig.mMimeType))
|
||||
, mImageAllocator(aAllocator)
|
||||
, mImageContainer(aImageContainer)
|
||||
, mInfo(aConfig)
|
||||
, mCodecParser(nullptr)
|
||||
|
|
@ -402,7 +404,8 @@ FFmpegVideoDecoder<LIBAV_VER>::CreateImage(int64_t aOffset, int64_t aPts,
|
|||
!!mFrame->key_frame,
|
||||
-1,
|
||||
mInfo.ScaledImageRect(mFrame->width,
|
||||
mFrame->height));
|
||||
mFrame->height),
|
||||
mImageAllocator);
|
||||
|
||||
if (!v) {
|
||||
return MediaResult(NS_ERROR_OUT_OF_MEMORY,
|
||||
|
|
|
|||
|
|
@ -24,11 +24,13 @@ class FFmpegVideoDecoder<LIBAV_VER> : public FFmpegDataDecoder<LIBAV_VER>
|
|||
{
|
||||
typedef mozilla::layers::Image Image;
|
||||
typedef mozilla::layers::ImageContainer ImageContainer;
|
||||
typedef mozilla::layers::KnowsCompositor KnowsCompositor;
|
||||
|
||||
public:
|
||||
FFmpegVideoDecoder(FFmpegLibWrapper* aLib, TaskQueue* aTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
const VideoInfo& aConfig,
|
||||
KnowsCompositor* aAllocator,
|
||||
ImageContainer* aImageContainer);
|
||||
virtual ~FFmpegVideoDecoder();
|
||||
|
||||
|
|
@ -62,6 +64,7 @@ private:
|
|||
int AllocateYUV420PVideoBuffer(AVCodecContext* aCodecContext,
|
||||
AVFrame* aFrame);
|
||||
|
||||
RefPtr<KnowsCompositor> mImageAllocator;
|
||||
RefPtr<ImageContainer> mImageContainer;
|
||||
VideoInfo mInfo;
|
||||
|
||||
|
|
|
|||
|
|
@ -53,29 +53,41 @@ LoadedScript::LoadedScript(ScriptKind aKind,
|
|||
LoadedScript::~LoadedScript() { DropJSObjects(this); }
|
||||
|
||||
void LoadedScript::AssociateWithScript(JSScript* aScript) {
|
||||
// Set a JSScript's private value to point to this object and
|
||||
// increment our reference count. This is decremented by
|
||||
// HostFinalizeTopLevelScript() below when the JSScript dies.
|
||||
// Set a JSScript's private value to point to this object. The JS engine will
|
||||
// increment our reference count by calling HostAddRefTopLevelScript(). This
|
||||
// is decremented by HostReleaseTopLevelScript() below when the JSScript dies.
|
||||
|
||||
MOZ_ASSERT(JS::GetScriptPrivate(aScript).isUndefined());
|
||||
JS::SetScriptPrivate(aScript, JS::PrivateValue(this));
|
||||
AddRef();
|
||||
}
|
||||
|
||||
void HostFinalizeTopLevelScript(JSFreeOp* aFop, const JS::Value& aPrivate) {
|
||||
// Decrement the reference count of a LoadedScript object that is
|
||||
// pointed to by a dying JSScript. The reference count was
|
||||
// originally incremented by AssociateWithScript() above.
|
||||
|
||||
auto script = static_cast<LoadedScript*>(aPrivate.toPrivate());
|
||||
|
||||
inline void CheckModuleScriptPrivate(LoadedScript* script,
|
||||
const JS::Value& aPrivate) {
|
||||
#ifdef DEBUG
|
||||
if (script->IsModuleScript()) {
|
||||
JSObject* module = script->AsModuleScript()->mModuleRecord.unbarrieredGet();
|
||||
MOZ_ASSERT_IF(module, JS::GetModulePrivate(module) == aPrivate);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void HostAddRefTopLevelScript(const JS::Value& aPrivate) {
|
||||
// Increment the reference count of a LoadedScript object that is now pointed
|
||||
// to by a JSScript. The reference count is decremented by
|
||||
// HostReleaseTopLevelScript() below.
|
||||
|
||||
auto script = static_cast<LoadedScript*>(aPrivate.toPrivate());
|
||||
CheckModuleScriptPrivate(script, aPrivate);
|
||||
script->AddRef();
|
||||
}
|
||||
|
||||
void HostReleaseTopLevelScript(const JS::Value& aPrivate) {
|
||||
// Decrement the reference count of a LoadedScript object that was pointed to
|
||||
// by a JSScript. The reference count was originally incremented by
|
||||
// HostAddRefTopLevelScript() above.
|
||||
|
||||
auto script = static_cast<LoadedScript*>(aPrivate.toPrivate());
|
||||
CheckModuleScriptPrivate(script, aPrivate);
|
||||
script->Release();
|
||||
}
|
||||
|
||||
|
|
@ -132,7 +144,6 @@ ModuleScript::UnlinkModuleRecord()
|
|||
this);
|
||||
JS::SetModulePrivate(mModuleRecord, JS::UndefinedValue());
|
||||
mModuleRecord = nullptr;
|
||||
Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,13 +162,13 @@ ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord)
|
|||
|
||||
mModuleRecord = aModuleRecord;
|
||||
|
||||
// Make module's host defined field point to this object and
|
||||
// increment our reference count. This is decremented by
|
||||
// UnlinkModuleRecord() above.
|
||||
// Make module's host defined field point to this object. The JS engine will
|
||||
// increment our reference count by calling HostAddRefTopLevelScript(). This
|
||||
// is decremented when the field is cleared in UnlinkModuleRecord() above or
|
||||
// when the module record dies.
|
||||
MOZ_ASSERT(JS::GetModulePrivate(mModuleRecord).isUndefined());
|
||||
JS::SetModulePrivate(mModuleRecord, JS::PrivateValue(this));
|
||||
HoldJSObjects(this);
|
||||
AddRef();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ namespace dom {
|
|||
|
||||
class ScriptLoader;
|
||||
|
||||
void HostFinalizeTopLevelScript(JSFreeOp* aFop, const JS::Value& aPrivate);
|
||||
void HostAddRefTopLevelScript(const JS::Value& aPrivate);
|
||||
void HostReleaseTopLevelScript(const JS::Value& aPrivate);
|
||||
|
||||
class ClassicScript;
|
||||
class ModuleScript;
|
||||
|
|
@ -63,7 +64,6 @@ class ClassicScript final : public LoadedScript
|
|||
|
||||
class ModuleScript final : public LoadedScript
|
||||
{
|
||||
JS::Heap<JSObject*> mModuleRecord;
|
||||
JS::Heap<JS::Value> mParseError;
|
||||
JS::Heap<JS::Value> mErrorToRethrow;
|
||||
|
||||
|
|
@ -74,6 +74,8 @@ public:
|
|||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ModuleScript,
|
||||
LoadedScript)
|
||||
|
||||
JS::Heap<JSObject*> mModuleRecord;
|
||||
|
||||
ModuleScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL);
|
||||
|
||||
void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord);
|
||||
|
|
@ -89,7 +91,7 @@ public:
|
|||
|
||||
void UnlinkModuleRecord();
|
||||
|
||||
friend void HostFinalizeTopLevelScript(JSFreeOp*, const JS::Value&);
|
||||
friend void CheckModuleScriptPrivate(LoadedScript*, const JS::Value&);
|
||||
};
|
||||
|
||||
ClassicScript* LoadedScript::AsClassicScript() {
|
||||
|
|
|
|||
|
|
@ -185,7 +185,11 @@ ScriptLoadRequest::MaybeCancelOffThreadScript()
|
|||
}
|
||||
|
||||
JSContext* cx = danger::GetJSContext();
|
||||
JS::CancelOffThreadScript(cx, mOffThreadToken);
|
||||
if (IsModuleRequest()) {
|
||||
JS::CancelOffThreadModule(cx, mOffThreadToken);
|
||||
} else {
|
||||
JS::CancelOffThreadScript(cx, mOffThreadToken);
|
||||
}
|
||||
mOffThreadToken = nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -1109,8 +1113,9 @@ void ScriptLoader::EnsureModuleHooksInitialized() {
|
|||
|
||||
JS::SetModuleResolveHook(rt, HostResolveImportedModule);
|
||||
JS::SetModuleMetadataHook(jsapi.cx(), HostPopulateImportMeta);
|
||||
JS::SetScriptPrivateFinalizeHook(jsapi.cx(), HostFinalizeTopLevelScript);
|
||||
|
||||
JS::SetScriptPrivateReferenceHooks(jsapi.cx(), HostAddRefTopLevelScript,
|
||||
HostReleaseTopLevelScript);
|
||||
|
||||
Preferences::RegisterCallbackAndCall(DynamicImportPrefChangedCallback,
|
||||
"javascript.options.dynamicImport",
|
||||
(void*)nullptr);
|
||||
|
|
@ -2648,7 +2653,7 @@ ScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
|||
// Process our request and/or any pending ones
|
||||
ProcessPendingRequests();
|
||||
|
||||
return NS_OK;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
@ -2758,6 +2763,9 @@ ScriptLoader::HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult) {
|
|||
if (aRequest->isInList()) {
|
||||
RefPtr<ScriptLoadRequest> req = mDynamicImportRequests.Steal(aRequest);
|
||||
modReq->Cancel();
|
||||
// FinishDynamicImport must happen exactly once for each dynamic import
|
||||
// request. If the load is aborted we do it when we remove the request
|
||||
// from mDynamicImportRequests.
|
||||
FinishDynamicImport(modReq, aResult);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -2979,8 +2987,12 @@ ScriptLoader::ParsingComplete(bool aTerminated)
|
|||
for (ScriptLoadRequest* req = mDynamicImportRequests.getFirst(); req;
|
||||
req = req->getNext()) {
|
||||
req->Cancel();
|
||||
// FinishDynamicImport must happen exactly once for each dynamic import
|
||||
// request. If the load is aborted we do it when we remove the request
|
||||
// from mDynamicImportRequests.
|
||||
FinishDynamicImport(req->AsModuleRequest(), NS_ERROR_ABORT);
|
||||
}
|
||||
mDynamicImportRequests.Clear();
|
||||
|
||||
if (mParserBlockingRequest) {
|
||||
mParserBlockingRequest->Cancel();
|
||||
|
|
|
|||
|
|
@ -426,17 +426,6 @@ SVGUseElement::LookupHref()
|
|||
nsCOMPtr<nsIURI> targetURI;
|
||||
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
|
||||
GetComposedDoc(), baseURI);
|
||||
|
||||
// Do not allow 'data:' schemes in <use> elements.
|
||||
// See spec update: https://github.com/w3c/svgwg/pull/901
|
||||
if (targetURI) {
|
||||
bool isData;
|
||||
mozilla::Unused << targetURI->SchemeIs("data", &isData);
|
||||
if (isData) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mSource.Reset(this, targetURI);
|
||||
}
|
||||
|
||||
|
|
|
|||
335
gfx/layers/D3D11YCbCrImage.cpp
Normal file
335
gfx/layers/D3D11YCbCrImage.cpp
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "D3D11YCbCrImage.h"
|
||||
|
||||
#include "gfx2DGlue.h"
|
||||
#include "YCbCrUtils.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "mozilla/layers/CompositableClient.h"
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/layers/TextureD3D11.h"
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
D3D11YCbCrImage::D3D11YCbCrImage()
|
||||
: Image(NULL, ImageFormat::D3D11_YCBCR_IMAGE)
|
||||
{
|
||||
}
|
||||
|
||||
D3D11YCbCrImage::~D3D11YCbCrImage() { }
|
||||
|
||||
bool
|
||||
D3D11YCbCrImage::SetData(KnowsCompositor* aAllocator,
|
||||
ImageContainer* aContainer,
|
||||
const PlanarYCbCrData& aData)
|
||||
{
|
||||
mPictureRect = IntRect(
|
||||
aData.mPicX, aData.mPicY, aData.mPicSize.width, aData.mPicSize.height);
|
||||
mYSize = aData.mYSize;
|
||||
mCbCrSize = aData.mCbCrSize;
|
||||
mColorSpace = aData.mYUVColorSpace;
|
||||
|
||||
D3D11YCbCrRecycleAllocator* allocator =
|
||||
aContainer->GetD3D11YCbCrRecycleAllocator(aAllocator);
|
||||
if (!allocator) {
|
||||
return false;
|
||||
}
|
||||
allocator->SetSizes(aData.mYSize, aData.mCbCrSize);
|
||||
|
||||
mTextureClient = allocator->CreateOrRecycle(SurfaceFormat::A8,
|
||||
mYSize,
|
||||
BackendSelector::Content,
|
||||
TextureFlags::DEFAULT);
|
||||
if (!mTextureClient) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DXGIYCbCrTextureData *data =
|
||||
static_cast<DXGIYCbCrTextureData*>(mTextureClient->GetInternalData());
|
||||
|
||||
ID3D11Texture2D* textureY = data->GetD3D11Texture(0);
|
||||
ID3D11Texture2D* textureCb = data->GetD3D11Texture(1);
|
||||
ID3D11Texture2D* textureCr = data->GetD3D11Texture(2);
|
||||
|
||||
RefPtr<ID3D10Multithread> mt;
|
||||
HRESULT hr = allocator->GetDevice()->QueryInterface(
|
||||
(ID3D10Multithread**)getter_AddRefs(mt));
|
||||
|
||||
if (FAILED(hr) || !mt) {
|
||||
gfxCriticalError() << "Multithread safety interface not supported. " << hr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mt->GetMultithreadProtected()) {
|
||||
gfxCriticalError() << "Device used not marked as multithread-safe.";
|
||||
return false;
|
||||
}
|
||||
|
||||
D3D11MTAutoEnter mtAutoEnter(mt.forget());
|
||||
|
||||
RefPtr<ID3D11DeviceContext> ctx;
|
||||
allocator->GetDevice()->GetImmediateContext(getter_AddRefs(ctx));
|
||||
|
||||
AutoLockD3D11Texture lockY(textureY);
|
||||
AutoLockD3D11Texture lockCb(textureCb);
|
||||
AutoLockD3D11Texture lockCr(textureCr);
|
||||
|
||||
ctx->UpdateSubresource(textureY,
|
||||
0,
|
||||
nullptr,
|
||||
aData.mYChannel,
|
||||
aData.mYStride,
|
||||
aData.mYStride * aData.mYSize.height);
|
||||
ctx->UpdateSubresource(textureCb,
|
||||
0,
|
||||
nullptr,
|
||||
aData.mCbChannel,
|
||||
aData.mCbCrStride,
|
||||
aData.mCbCrStride * aData.mCbCrSize.height);
|
||||
ctx->UpdateSubresource(textureCr,
|
||||
0,
|
||||
nullptr,
|
||||
aData.mCrChannel,
|
||||
aData.mCbCrStride,
|
||||
aData.mCbCrStride * aData.mCbCrSize.height);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IntSize
|
||||
D3D11YCbCrImage::GetSize()
|
||||
{
|
||||
return mPictureRect.Size();
|
||||
}
|
||||
|
||||
TextureClient*
|
||||
D3D11YCbCrImage::GetTextureClient(KnowsCompositor* aForwarder)
|
||||
{
|
||||
return mTextureClient;
|
||||
}
|
||||
|
||||
already_AddRefed<SourceSurface>
|
||||
D3D11YCbCrImage::GetAsSourceSurface()
|
||||
{
|
||||
if (!mTextureClient) {
|
||||
gfxWarning()
|
||||
<< "GetAsSourceSurface() called on uninitialized D3D11YCbCrImage.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gfx::IntSize size(mPictureRect.Size());
|
||||
gfx::SurfaceFormat format =
|
||||
gfx::ImageFormatToSurfaceFormat(gfxVars::OffscreenFormat());
|
||||
HRESULT hr;
|
||||
|
||||
PlanarYCbCrData data;
|
||||
|
||||
DXGIYCbCrTextureData *dxgiData =
|
||||
static_cast<DXGIYCbCrTextureData*>(mTextureClient->GetInternalData());
|
||||
|
||||
if (!dxgiData) {
|
||||
gfxCriticalError() << "Failed to get texture client internal data.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<ID3D11Texture2D> texY = dxgiData->GetD3D11Texture(0);
|
||||
RefPtr<ID3D11Texture2D> texCb = dxgiData->GetD3D11Texture(1);
|
||||
RefPtr<ID3D11Texture2D> texCr = dxgiData->GetD3D11Texture(2);
|
||||
RefPtr<ID3D11Texture2D> softTexY, softTexCb, softTexCr;
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
|
||||
RefPtr<ID3D11Device> dev;
|
||||
texY->GetDevice(getter_AddRefs(dev));
|
||||
|
||||
RefPtr<ID3D10Multithread> mt;
|
||||
hr = dev->QueryInterface((ID3D10Multithread**)getter_AddRefs(mt));
|
||||
|
||||
if (FAILED(hr) || !mt) {
|
||||
gfxCriticalError() << "Multithread safety interface not supported.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mt->GetMultithreadProtected()) {
|
||||
gfxCriticalError() << "Device used not marked as multithread-safe.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
D3D11MTAutoEnter mtAutoEnter(mt.forget());
|
||||
|
||||
texY->GetDesc(&desc);
|
||||
desc.BindFlags = 0;
|
||||
desc.MiscFlags = 0;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
desc.Usage = D3D11_USAGE_STAGING;
|
||||
|
||||
dev->CreateTexture2D(&desc, nullptr, getter_AddRefs(softTexY));
|
||||
|
||||
texCb->GetDesc(&desc);
|
||||
desc.BindFlags = 0;
|
||||
desc.MiscFlags = 0;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
desc.Usage = D3D11_USAGE_STAGING;
|
||||
|
||||
dev->CreateTexture2D(&desc, nullptr, getter_AddRefs(softTexCb));
|
||||
|
||||
texCr->GetDesc(&desc);
|
||||
desc.BindFlags = 0;
|
||||
desc.MiscFlags = 0;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
desc.Usage = D3D11_USAGE_STAGING;
|
||||
|
||||
dev->CreateTexture2D(&desc, nullptr, getter_AddRefs(softTexCr));
|
||||
|
||||
RefPtr<ID3D11DeviceContext> ctx;
|
||||
dev->GetImmediateContext(getter_AddRefs(ctx));
|
||||
|
||||
{
|
||||
AutoLockD3D11Texture lockY(texY);
|
||||
AutoLockD3D11Texture lockCb(texCb);
|
||||
AutoLockD3D11Texture lockCr(texCr);
|
||||
ctx->CopyResource(softTexY, texY);
|
||||
ctx->CopyResource(softTexCb, texCb);
|
||||
ctx->CopyResource(softTexCr, texCr);
|
||||
}
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mapY, mapCb, mapCr;
|
||||
RefPtr<gfx::DataSourceSurface> surface;
|
||||
mapY.pData = mapCb.pData = mapCr.pData = nullptr;
|
||||
|
||||
hr = ctx->Map(softTexY, 0, D3D11_MAP_READ, 0, &mapY);
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << "Failed to map Y plane (" << hr << ")";
|
||||
return nullptr;
|
||||
}
|
||||
hr = ctx->Map(softTexCb, 0, D3D11_MAP_READ, 0, &mapCb);
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << "Failed to map Y plane (" << hr << ")";
|
||||
return nullptr;
|
||||
}
|
||||
hr = ctx->Map(softTexCr, 0, D3D11_MAP_READ, 0, &mapCr);
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << "Failed to map Y plane (" << hr << ")";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mapCb.RowPitch == mapCr.RowPitch);
|
||||
|
||||
data.mPicX = mPictureRect.x;
|
||||
data.mPicY = mPictureRect.y;
|
||||
data.mPicSize = mPictureRect.Size();
|
||||
data.mStereoMode = StereoMode::MONO;
|
||||
data.mYUVColorSpace = mColorSpace;
|
||||
data.mYSkip = data.mCbSkip = data.mCrSkip = 0;
|
||||
data.mYSize = mYSize;
|
||||
data.mCbCrSize = mCbCrSize;
|
||||
data.mYChannel = static_cast<uint8_t*>(mapY.pData);
|
||||
data.mYStride = mapY.RowPitch;
|
||||
data.mCbChannel = static_cast<uint8_t*>(mapCb.pData);
|
||||
data.mCrChannel = static_cast<uint8_t*>(mapCr.pData);
|
||||
data.mCbCrStride = mapCb.RowPitch;
|
||||
|
||||
gfx::GetYCbCrToRGBDestFormatAndSize(data, format, size);
|
||||
if (size.width > PlanarYCbCrImage::MAX_DIMENSION ||
|
||||
size.height > PlanarYCbCrImage::MAX_DIMENSION) {
|
||||
gfxCriticalError() << "Illegal image dest width or height";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
surface = gfx::Factory::CreateDataSourceSurface(size, format);
|
||||
if (!surface) {
|
||||
gfxCriticalError() << "Failed to create DataSourceSurface for image: "
|
||||
<< size << " " << format;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DataSourceSurface::ScopedMap mapping(surface, DataSourceSurface::WRITE);
|
||||
if (!mapping.IsMapped()) {
|
||||
gfxCriticalError() << "Failed to map DataSourceSurface for D3D11YCbCrImage";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gfx::ConvertYCbCrToRGB(
|
||||
data, format, size, mapping.GetData(), mapping.GetStride());
|
||||
|
||||
ctx->Unmap(softTexY, 0);
|
||||
ctx->Unmap(softTexCb, 0);
|
||||
ctx->Unmap(softTexCr, 0);
|
||||
|
||||
return surface.forget();
|
||||
}
|
||||
|
||||
void
|
||||
D3D11YCbCrRecycleAllocator::SetSizes(const gfx::IntSize& aYSize,
|
||||
const gfx::IntSize& aCbCrSize)
|
||||
{
|
||||
mYSize = Some(aYSize);
|
||||
mCbCrSize = Some(aCbCrSize);
|
||||
}
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
D3D11YCbCrRecycleAllocator::Allocate(SurfaceFormat aFormat,
|
||||
IntSize aSize,
|
||||
BackendSelector aSelector,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocFlags)
|
||||
{
|
||||
MOZ_ASSERT(aFormat == SurfaceFormat::A8);
|
||||
|
||||
gfx::IntSize YSize = mYSize.refOr(aSize);
|
||||
gfx::IntSize CbCrSize =
|
||||
mCbCrSize.refOr(gfx::IntSize(YSize.width, YSize.height));
|
||||
CD3D11_TEXTURE2D_DESC newDesc(DXGI_FORMAT_R8_UNORM, YSize.width, YSize.height,
|
||||
1, 1);
|
||||
newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
|
||||
|
||||
RefPtr<ID3D10Multithread> mt;
|
||||
HRESULT hr = mDevice->QueryInterface(
|
||||
(ID3D10Multithread**)getter_AddRefs(mt));
|
||||
|
||||
if (FAILED(hr) || !mt) {
|
||||
gfxCriticalError() << "Multithread safety interface not supported. " << hr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mt->GetMultithreadProtected()) {
|
||||
gfxCriticalError() << "Device used not marked as multithread-safe.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
D3D11MTAutoEnter mtAutoEnter(mt.forget());
|
||||
|
||||
RefPtr<ID3D11Texture2D> textureY;
|
||||
hr = mDevice->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(textureY));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
|
||||
|
||||
newDesc.Width = CbCrSize.width;
|
||||
newDesc.Height = CbCrSize.height;
|
||||
|
||||
RefPtr<ID3D11Texture2D> textureCb;
|
||||
hr = mDevice->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(textureCb));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
|
||||
|
||||
RefPtr<ID3D11Texture2D> textureCr;
|
||||
hr = mDevice->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(textureCr));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
|
||||
|
||||
return TextureClient::CreateWithData(
|
||||
DXGIYCbCrTextureData::Create(
|
||||
textureY,
|
||||
textureCb,
|
||||
textureCr,
|
||||
aSize,
|
||||
YSize,
|
||||
CbCrSize),
|
||||
TextureFlags::DEFAULT,
|
||||
mSurfaceAllocator->GetTextureForwarder());
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
78
gfx/layers/D3D11YCbCrImage.h
Normal file
78
gfx/layers/D3D11YCbCrImage.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/* -*- 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 GFX_D3D11_YCBCR_IMAGE_H
|
||||
#define GFX_D3D11_YCBCR_IMAGE_H
|
||||
|
||||
#include "d3d11.h"
|
||||
#include "mozilla/layers/TextureClientRecycleAllocator.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "ImageContainer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ImageContainer;
|
||||
class DXGIYCbCrTextureClient;
|
||||
|
||||
class D3D11YCbCrRecycleAllocator : public TextureClientRecycleAllocator
|
||||
{
|
||||
public:
|
||||
explicit D3D11YCbCrRecycleAllocator(KnowsCompositor* aAllocator,
|
||||
ID3D11Device* aDevice)
|
||||
: TextureClientRecycleAllocator(aAllocator)
|
||||
, mDevice(aDevice)
|
||||
{
|
||||
}
|
||||
|
||||
ID3D11Device* GetDevice() { return mDevice; }
|
||||
KnowsCompositor* GetAllocator() { return mSurfaceAllocator; }
|
||||
void SetSizes(const gfx::IntSize& aYSize, const gfx::IntSize& aCbCrSize);
|
||||
|
||||
protected:
|
||||
already_AddRefed<TextureClient>
|
||||
Allocate(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
BackendSelector aSelector,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocFlags) override;
|
||||
|
||||
RefPtr<ID3D11Device> mDevice;
|
||||
Maybe<gfx::IntSize> mYSize;
|
||||
Maybe<gfx::IntSize> mCbCrSize;
|
||||
};
|
||||
|
||||
class D3D11YCbCrImage : public Image
|
||||
{
|
||||
public:
|
||||
D3D11YCbCrImage();
|
||||
virtual ~D3D11YCbCrImage();
|
||||
|
||||
// Copies the surface into a sharable texture's surface, and initializes
|
||||
// the image.
|
||||
bool SetData(KnowsCompositor* aAllocator,
|
||||
ImageContainer* aContainer,
|
||||
const PlanarYCbCrData& aData);
|
||||
|
||||
gfx::IntSize GetSize() override;
|
||||
|
||||
already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
|
||||
|
||||
TextureClient* GetTextureClient(KnowsCompositor* aForwarder) override;
|
||||
|
||||
gfx::IntRect GetPictureRect() override { return mPictureRect; }
|
||||
|
||||
private:
|
||||
gfx::IntSize mYSize;
|
||||
gfx::IntSize mCbCrSize;
|
||||
gfx::IntRect mPictureRect;
|
||||
YUVColorSpace mColorSpace;
|
||||
RefPtr<TextureClient> mTextureClient;
|
||||
};
|
||||
|
||||
} // namepace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GFX_D3D11_YCBCR_IMAGE_H
|
||||
|
|
@ -34,38 +34,6 @@ IMFYCbCrImage::~IMFYCbCrImage()
|
|||
}
|
||||
}
|
||||
|
||||
struct AutoLockTexture
|
||||
{
|
||||
AutoLockTexture(ID3D11Texture2D* aTexture)
|
||||
{
|
||||
aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mMutex));
|
||||
if (!mMutex) {
|
||||
return;
|
||||
}
|
||||
HRESULT hr = mMutex->AcquireSync(0, 10000);
|
||||
if (hr == WAIT_TIMEOUT) {
|
||||
MOZ_CRASH("GFX: IMFYCbCrImage timeout");
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to lock the texture");
|
||||
}
|
||||
}
|
||||
|
||||
~AutoLockTexture()
|
||||
{
|
||||
if (!mMutex) {
|
||||
return;
|
||||
}
|
||||
HRESULT hr = mMutex->ReleaseSync(0);
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to unlock the texture");
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<IDXGIKeyedMutex> mMutex;
|
||||
};
|
||||
|
||||
static already_AddRefed<IDirect3DTexture9>
|
||||
InitTextures(IDirect3DDevice9* aDevice,
|
||||
const IntSize &aSize,
|
||||
|
|
@ -226,6 +194,112 @@ IMFYCbCrImage::GetD3D9TextureClient(KnowsCompositor* aForwarder)
|
|||
return mTextureClient;
|
||||
}
|
||||
|
||||
DXGIYCbCrTextureData*
|
||||
IMFYCbCrImage::GetD3D11TextureData(Data aData, gfx::IntSize aSize)
|
||||
{
|
||||
HRESULT hr;
|
||||
RefPtr<ID3D10Multithread> mt;
|
||||
|
||||
RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetContentDevice();
|
||||
|
||||
if (!device) {
|
||||
device = gfx::DeviceManagerDx::Get()->GetCompositorDevice();
|
||||
}
|
||||
|
||||
if (!gfx::DeviceManagerDx::Get()->CanInitializeKeyedMutexTextures()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
hr = device->QueryInterface((ID3D10Multithread**)getter_AddRefs(mt));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mt->GetMultithreadProtected()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aData.mYStride < 0 || aData.mCbCrStride < 0) {
|
||||
// D3D11 only supports unsigned stride values.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CD3D11_TEXTURE2D_DESC newDesc(DXGI_FORMAT_R8_UNORM,
|
||||
aData.mYSize.width, aData.mYSize.height, 1, 1);
|
||||
|
||||
if (device == gfx::DeviceManagerDx::Get()->GetCompositorDevice()) {
|
||||
newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
|
||||
} else {
|
||||
newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
|
||||
}
|
||||
|
||||
RefPtr<ID3D11Texture2D> textureY;
|
||||
hr = device->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(textureY));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
|
||||
|
||||
newDesc.Width = aData.mCbCrSize.width;
|
||||
newDesc.Height = aData.mCbCrSize.height;
|
||||
|
||||
RefPtr<ID3D11Texture2D> textureCb;
|
||||
hr = device->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(textureCb));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
|
||||
|
||||
RefPtr<ID3D11Texture2D> textureCr;
|
||||
hr = device->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(textureCr));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
|
||||
|
||||
// The documentation here seems to suggest using the immediate mode context
|
||||
// on more than one thread is not allowed:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ff476891(v=vs.85).aspx
|
||||
// The Debug Layer seems to imply it is though. When the ID3D10Multithread
|
||||
// layer is on. The Enter/Leave of the critical section shouldn't even be
|
||||
// required but were added for extra security.
|
||||
|
||||
{
|
||||
AutoLockD3D11Texture lockY(textureY);
|
||||
AutoLockD3D11Texture lockCr(textureCr);
|
||||
AutoLockD3D11Texture lockCb(textureCb);
|
||||
|
||||
D3D11MTAutoEnter mtAutoEnter(mt.forget());
|
||||
|
||||
RefPtr<ID3D11DeviceContext> ctx;
|
||||
device->GetImmediateContext((ID3D11DeviceContext**)getter_AddRefs(ctx));
|
||||
|
||||
D3D11_BOX box;
|
||||
box.front = box.top = box.left = 0;
|
||||
box.back = 1;
|
||||
box.right = aData.mYSize.width;
|
||||
box.bottom = aData.mYSize.height;
|
||||
ctx->UpdateSubresource(textureY, 0, &box, aData.mYChannel, aData.mYStride, 0);
|
||||
|
||||
box.right = aData.mCbCrSize.width;
|
||||
box.bottom = aData.mCbCrSize.height;
|
||||
ctx->UpdateSubresource(textureCb, 0, &box, aData.mCbChannel, aData.mCbCrStride, 0);
|
||||
ctx->UpdateSubresource(textureCr, 0, &box, aData.mCrChannel, aData.mCbCrStride, 0);
|
||||
}
|
||||
|
||||
return DXGIYCbCrTextureData::Create(textureY, textureCb, textureCr,
|
||||
aSize, aData.mYSize, aData.mCbCrSize);
|
||||
}
|
||||
|
||||
TextureClient*
|
||||
IMFYCbCrImage::GetD3D11TextureClient(KnowsCompositor* aForwarder)
|
||||
{
|
||||
DXGIYCbCrTextureData* textureData = GetD3D11TextureData(mData, GetSize());
|
||||
|
||||
if (textureData == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mTextureClient = TextureClient::CreateWithData(
|
||||
textureData, TextureFlags::DEFAULT,
|
||||
aForwarder->GetTextureForwarder()
|
||||
);
|
||||
|
||||
return mTextureClient;
|
||||
}
|
||||
|
||||
TextureClient*
|
||||
IMFYCbCrImage::GetTextureClient(KnowsCompositor* aForwarder)
|
||||
{
|
||||
|
|
@ -233,11 +307,9 @@ IMFYCbCrImage::GetTextureClient(KnowsCompositor* aForwarder)
|
|||
return mTextureClient;
|
||||
}
|
||||
|
||||
RefPtr<ID3D11Device> device =
|
||||
gfx::DeviceManagerDx::Get()->GetContentDevice();
|
||||
RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetContentDevice();
|
||||
if (!device) {
|
||||
device =
|
||||
gfx::DeviceManagerDx::Get()->GetCompositorDevice();
|
||||
device = gfx::DeviceManagerDx::Get()->GetCompositorDevice();
|
||||
}
|
||||
|
||||
LayersBackend backend = aForwarder->GetCompositorBackendType();
|
||||
|
|
@ -248,60 +320,7 @@ IMFYCbCrImage::GetTextureClient(KnowsCompositor* aForwarder)
|
|||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!gfx::DeviceManagerDx::Get()->CanInitializeKeyedMutexTextures()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mData.mYStride < 0 || mData.mCbCrStride < 0) {
|
||||
// D3D11 only supports unsigned stride values.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CD3D11_TEXTURE2D_DESC newDesc(DXGI_FORMAT_R8_UNORM,
|
||||
mData.mYSize.width, mData.mYSize.height, 1, 1);
|
||||
|
||||
if (device == gfx::DeviceManagerDx::Get()->GetCompositorDevice()) {
|
||||
newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
|
||||
} else {
|
||||
newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
|
||||
}
|
||||
|
||||
RefPtr<ID3D11Texture2D> textureY;
|
||||
D3D11_SUBRESOURCE_DATA yData = { mData.mYChannel, (UINT)mData.mYStride, 0 };
|
||||
HRESULT hr = device->CreateTexture2D(&newDesc, &yData, getter_AddRefs(textureY));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
|
||||
|
||||
newDesc.Width = mData.mCbCrSize.width;
|
||||
newDesc.Height = mData.mCbCrSize.height;
|
||||
|
||||
RefPtr<ID3D11Texture2D> textureCb;
|
||||
D3D11_SUBRESOURCE_DATA cbData = { mData.mCbChannel, (UINT)mData.mCbCrStride, 0 };
|
||||
hr = device->CreateTexture2D(&newDesc, &cbData, getter_AddRefs(textureCb));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
|
||||
|
||||
RefPtr<ID3D11Texture2D> textureCr;
|
||||
D3D11_SUBRESOURCE_DATA crData = { mData.mCrChannel, (UINT)mData.mCbCrStride, 0 };
|
||||
hr = device->CreateTexture2D(&newDesc, &crData, getter_AddRefs(textureCr));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
|
||||
|
||||
// Even though the textures we created are meant to be protected by a keyed mutex,
|
||||
// it appears that D3D doesn't include the initial memory upload within this
|
||||
// synchronization. Add an empty lock/unlock pair since that appears to
|
||||
// be sufficient to make sure we synchronize.
|
||||
{
|
||||
AutoLockTexture lockCr(textureCr);
|
||||
}
|
||||
|
||||
mTextureClient = TextureClient::CreateWithData(
|
||||
DXGIYCbCrTextureData::Create(TextureFlags::DEFAULT,
|
||||
textureY, textureCb, textureCr,
|
||||
GetSize(), mData.mYSize, mData.mCbCrSize),
|
||||
TextureFlags::DEFAULT,
|
||||
aForwarder->GetTextureForwarder()
|
||||
);
|
||||
|
||||
return mTextureClient;
|
||||
return GetD3D11TextureClient(aForwarder);
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef GFX_IMFYCBCRIMAGE_H
|
||||
#define GFX_IMFYCBCRIMAGE_H
|
||||
|
||||
#include "mozilla/layers/TextureD3D11.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "mfidl.h"
|
||||
|
|
@ -22,10 +23,15 @@ public:
|
|||
|
||||
virtual TextureClient* GetTextureClient(KnowsCompositor* aForwarder) override;
|
||||
|
||||
static DXGIYCbCrTextureData* GetD3D11TextureData(Data aData,
|
||||
gfx::IntSize aSize);
|
||||
|
||||
protected:
|
||||
|
||||
TextureClient* GetD3D9TextureClient(KnowsCompositor* aForwarder);
|
||||
|
||||
TextureClient* GetD3D11TextureClient(KnowsCompositor* aForwarder);
|
||||
|
||||
~IMFYCbCrImage();
|
||||
|
||||
RefPtr<IMFMediaBuffer> mBuffer;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@
|
|||
#ifdef XP_WIN
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#include <d3d10_1.h>
|
||||
#include "mozilla/gfx/DeviceManagerDx.h"
|
||||
#include "mozilla/layers/D3D11YCbCrImage.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
|
@ -395,6 +397,40 @@ ImageContainer::NotifyCompositeInternal(const ImageCompositeNotification& aNotif
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
D3D11YCbCrRecycleAllocator*
|
||||
ImageContainer::GetD3D11YCbCrRecycleAllocator(KnowsCompositor* aAllocator)
|
||||
{
|
||||
if (mD3D11YCbCrRecycleAllocator &&
|
||||
aAllocator == mD3D11YCbCrRecycleAllocator->GetAllocator()) {
|
||||
return mD3D11YCbCrRecycleAllocator;
|
||||
}
|
||||
|
||||
RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetContentDevice();
|
||||
if (!device) {
|
||||
device = gfx::DeviceManagerDx::Get()->GetCompositorDevice();
|
||||
}
|
||||
|
||||
LayersBackend backend = aAllocator->GetCompositorBackendType();
|
||||
if (!device || backend != LayersBackend::LAYERS_D3D11) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<ID3D10Multithread> multi;
|
||||
HRESULT hr =
|
||||
device->QueryInterface((ID3D10Multithread**)getter_AddRefs(multi));
|
||||
if (FAILED(hr) || !multi) {
|
||||
gfxWarning() << "Multithread safety interface not supported. " << hr;
|
||||
return nullptr;
|
||||
}
|
||||
multi->SetMultithreadProtected(TRUE);
|
||||
|
||||
mD3D11YCbCrRecycleAllocator =
|
||||
new D3D11YCbCrRecycleAllocator(aAllocator, device);
|
||||
return mD3D11YCbCrRecycleAllocator;
|
||||
}
|
||||
#endif
|
||||
|
||||
PlanarYCbCrImage::PlanarYCbCrImage()
|
||||
: Image(nullptr, ImageFormat::PLANAR_YCBCR)
|
||||
, mOffscreenFormat(SurfaceFormat::UNKNOWN)
|
||||
|
|
|
|||
|
|
@ -153,6 +153,9 @@ class PlanarYCbCrImage;
|
|||
class TextureClient;
|
||||
class KnowsCompositor;
|
||||
class NVImage;
|
||||
#ifdef XP_WIN
|
||||
class D3D11YCbCrRecycleAllocator;
|
||||
#endif
|
||||
|
||||
struct ImageBackendData
|
||||
{
|
||||
|
|
@ -173,14 +176,14 @@ class MacIOSurfaceImage;
|
|||
/**
|
||||
* A class representing a buffer of pixel data. The data can be in one
|
||||
* of various formats including YCbCr.
|
||||
*
|
||||
*
|
||||
* Create an image using an ImageContainer. Fill the image with data, and
|
||||
* then call ImageContainer::SetImage to display it. An image must not be
|
||||
* modified after calling SetImage. Image implementations do not need to
|
||||
* perform locking; when filling an Image, the Image client is responsible
|
||||
* for ensuring only one thread accesses the Image at a time, and after
|
||||
* SetImage the image is immutable.
|
||||
*
|
||||
*
|
||||
* When resampling an Image, only pixels within the buffer should be
|
||||
* sampled. For example, cairo images should be sampled in EXTEND_PAD mode.
|
||||
*/
|
||||
|
|
@ -254,7 +257,7 @@ protected:
|
|||
|
||||
/**
|
||||
* A RecycleBin is owned by an ImageContainer. We store buffers in it that we
|
||||
* want to recycle from one image to the next.It's a separate object from
|
||||
* want to recycle from one image to the next.It's a separate object from
|
||||
* ImageContainer because images need to store a strong ref to their RecycleBin
|
||||
* and we must avoid creating a reference loop between an ImageContainer and
|
||||
* its active image.
|
||||
|
|
@ -319,7 +322,7 @@ protected:
|
|||
const gfx::IntSize& aScaleHint,
|
||||
BufferRecycleBin *aRecycleBin);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A class that manages Images for an ImageLayer. The only reason
|
||||
* we need a separate class here is that ImageLayers aren't threadsafe
|
||||
|
|
@ -399,7 +402,7 @@ public:
|
|||
* mProducerID is a unique ID for the stream of images. A change in the
|
||||
* mProducerID means changing to a new mFrameID namespace. All frames in
|
||||
* aImages must have the same mProducerID.
|
||||
*
|
||||
*
|
||||
* The Image data must not be modified after this method is called!
|
||||
* Note that this must not be called if ENABLE_ASYNC has not been set.
|
||||
*
|
||||
|
|
@ -435,11 +438,11 @@ public:
|
|||
* Set an Image as the current image to display. The Image must have
|
||||
* been created by this ImageContainer.
|
||||
* Must be called on the main thread, within a layers transaction.
|
||||
*
|
||||
*
|
||||
* This method takes mReentrantMonitor
|
||||
* when accessing thread-shared state.
|
||||
* aImage can be null. While it's null, nothing will be painted.
|
||||
*
|
||||
*
|
||||
* The Image data must not be modified after this method is called!
|
||||
* Note that this must not be called if ENABLE_ASYNC been set.
|
||||
*
|
||||
|
|
@ -521,6 +524,11 @@ public:
|
|||
return mImageFactory;
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
D3D11YCbCrRecycleAllocator* GetD3D11YCbCrRecycleAllocator(
|
||||
KnowsCompositor* aAllocator);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the delay between the last composited image's presentation
|
||||
* timestamp and when it was first composited. It's possible for the delay
|
||||
|
|
@ -587,6 +595,10 @@ private:
|
|||
// image", and any other state which is shared between threads.
|
||||
ReentrantMonitor mReentrantMonitor;
|
||||
|
||||
#ifdef XP_WIN
|
||||
RefPtr<D3D11YCbCrRecycleAllocator> mD3D11YCbCrRecycleAllocator;
|
||||
#endif
|
||||
|
||||
nsTArray<OwningImage> mCurrentImages;
|
||||
|
||||
// Updates every time mActiveImage changes
|
||||
|
|
@ -703,7 +715,7 @@ struct PlanarYCbCrData {
|
|||
*
|
||||
* The color format is detected based on the height/width ratios
|
||||
* defined above.
|
||||
*
|
||||
*
|
||||
* The Image that is rendered is the picture region defined by
|
||||
* mPicX, mPicY and mPicSize. The size of the rendered image is
|
||||
* mPicSize, not mYSize or mCbCrSize.
|
||||
|
|
|
|||
|
|
@ -99,6 +99,11 @@ enum class ImageFormat {
|
|||
*/
|
||||
TEXTURE_WRAPPER,
|
||||
|
||||
/**
|
||||
* A D3D11 backed YUV image.
|
||||
*/
|
||||
D3D11_YCBCR_IMAGE,
|
||||
|
||||
/**
|
||||
* An opaque handle that refers to an Image stored in the GPU
|
||||
* process.
|
||||
|
|
|
|||
|
|
@ -618,7 +618,7 @@ public:
|
|||
|
||||
/**
|
||||
* Set last transaction id of CompositableForwarder.
|
||||
*
|
||||
*
|
||||
* Called when TextureClient has TextureFlags::RECYCLE flag.
|
||||
* When CompositableForwarder forwards the TextureClient with
|
||||
* TextureFlags::RECYCLE, it holds TextureClient's ref until host side
|
||||
|
|
@ -644,7 +644,7 @@ public:
|
|||
|
||||
private:
|
||||
static void TextureClientRecycleCallback(TextureClient* aClient, void* aClosure);
|
||||
|
||||
|
||||
// Internal helpers for creating texture clients using the actual forwarder instead
|
||||
// of KnowsCompositor. TextureClientPool uses these to let it cache texture clients
|
||||
// per-process instead of per ShadowLayerForwarder, but everyone else should
|
||||
|
|
@ -659,7 +659,7 @@ private:
|
|||
BackendSelector aSelector,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT);
|
||||
|
||||
|
||||
static already_AddRefed<TextureClient>
|
||||
CreateForRawBufferAccess(LayersIPCChannel* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
|
|
@ -735,6 +735,8 @@ protected:
|
|||
friend class TextureChild;
|
||||
friend void TestTextureClientSurface(TextureClient*, gfxImageSurface*);
|
||||
friend void TestTextureClientYCbCr(TextureClient*, PlanarYCbCrData&);
|
||||
friend already_AddRefed<TextureHost> CreateTextureHostWithBackend(
|
||||
TextureClient*, LayersBackend&);
|
||||
|
||||
#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -516,10 +516,9 @@ D3D11TextureData::GetDXGIResource(IDXGIResource** aOutResource)
|
|||
}
|
||||
|
||||
DXGIYCbCrTextureData*
|
||||
DXGIYCbCrTextureData::Create(TextureFlags aFlags,
|
||||
IUnknown* aTextureY,
|
||||
IUnknown* aTextureCb,
|
||||
IUnknown* aTextureCr,
|
||||
DXGIYCbCrTextureData::Create(IDirect3DTexture9* aTextureY,
|
||||
IDirect3DTexture9* aTextureCb,
|
||||
IDirect3DTexture9* aTextureCr,
|
||||
HANDLE aHandleY,
|
||||
HANDLE aHandleCb,
|
||||
HANDLE aHandleCr,
|
||||
|
|
@ -536,9 +535,9 @@ DXGIYCbCrTextureData::Create(TextureFlags aFlags,
|
|||
texture->mHandles[0] = aHandleY;
|
||||
texture->mHandles[1] = aHandleCb;
|
||||
texture->mHandles[2] = aHandleCr;
|
||||
texture->mHoldRefs[0] = aTextureY;
|
||||
texture->mHoldRefs[1] = aTextureCb;
|
||||
texture->mHoldRefs[2] = aTextureCr;
|
||||
texture->mD3D9Textures[0] = aTextureY;
|
||||
texture->mD3D9Textures[1] = aTextureCb;
|
||||
texture->mD3D9Textures[2] = aTextureCr;
|
||||
texture->mSize = aSize;
|
||||
texture->mSizeY = aSizeY;
|
||||
texture->mSizeCbCr = aSizeCbCr;
|
||||
|
|
@ -547,8 +546,7 @@ DXGIYCbCrTextureData::Create(TextureFlags aFlags,
|
|||
}
|
||||
|
||||
DXGIYCbCrTextureData*
|
||||
DXGIYCbCrTextureData::Create(TextureFlags aFlags,
|
||||
ID3D11Texture2D* aTextureY,
|
||||
DXGIYCbCrTextureData::Create(ID3D11Texture2D* aTextureY,
|
||||
ID3D11Texture2D* aTextureCb,
|
||||
ID3D11Texture2D* aTextureCr,
|
||||
const gfx::IntSize& aSize,
|
||||
|
|
@ -591,10 +589,18 @@ DXGIYCbCrTextureData::Create(TextureFlags aFlags,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return DXGIYCbCrTextureData::Create(aFlags,
|
||||
aTextureY, aTextureCb, aTextureCr,
|
||||
handleY, handleCb, handleCr,
|
||||
aSize, aSizeY, aSizeCbCr);
|
||||
DXGIYCbCrTextureData* texture = new DXGIYCbCrTextureData();
|
||||
texture->mHandles[0] = handleY;
|
||||
texture->mHandles[1] = handleCb;
|
||||
texture->mHandles[2] = handleCr;
|
||||
texture->mD3D11Textures[0] = aTextureY;
|
||||
texture->mD3D11Textures[1] = aTextureCb;
|
||||
texture->mD3D11Textures[2] = aTextureCr;
|
||||
texture->mSize = aSize;
|
||||
texture->mSizeY = aSizeY;
|
||||
texture->mSizeCbCr = aSizeCbCr;
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -620,9 +626,12 @@ DXGIYCbCrTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
|||
void
|
||||
DXGIYCbCrTextureData::Deallocate(LayersIPCChannel*)
|
||||
{
|
||||
mHoldRefs[0] = nullptr;
|
||||
mHoldRefs[1] = nullptr;
|
||||
mHoldRefs[2] = nullptr;
|
||||
mD3D9Textures[0] = nullptr;
|
||||
mD3D9Textures[1] = nullptr;
|
||||
mD3D9Textures[2] = nullptr;
|
||||
mD3D11Textures[0] = nullptr;
|
||||
mD3D11Textures[1] = nullptr;
|
||||
mD3D11Textures[2] = nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<TextureHost>
|
||||
|
|
@ -1282,5 +1291,32 @@ SyncObjectD3D11::FinalizeFrame()
|
|||
}
|
||||
}
|
||||
|
||||
AutoLockD3D11Texture::AutoLockD3D11Texture(ID3D11Texture2D* aTexture)
|
||||
{
|
||||
aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mMutex));
|
||||
if (!mMutex) {
|
||||
return;
|
||||
}
|
||||
HRESULT hr = mMutex->AcquireSync(0, 10000);
|
||||
if (hr == WAIT_TIMEOUT) {
|
||||
MOZ_CRASH("GFX: IMFYCbCrImage timeout");
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to lock the texture");
|
||||
}
|
||||
}
|
||||
|
||||
AutoLockD3D11Texture::~AutoLockD3D11Texture()
|
||||
{
|
||||
if (!mMutex) {
|
||||
return;
|
||||
}
|
||||
HRESULT hr = mMutex->ReleaseSync(0);
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to unlock the texture");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,10 +127,9 @@ class DXGIYCbCrTextureData : public TextureData
|
|||
{
|
||||
public:
|
||||
static DXGIYCbCrTextureData*
|
||||
Create(TextureFlags aFlags,
|
||||
IUnknown* aTextureY,
|
||||
IUnknown* aTextureCb,
|
||||
IUnknown* aTextureCr,
|
||||
Create(IDirect3DTexture9* aTextureY,
|
||||
IDirect3DTexture9* aTextureCb,
|
||||
IDirect3DTexture9* aTextureCr,
|
||||
HANDLE aHandleY,
|
||||
HANDLE aHandleCb,
|
||||
HANDLE aHandleCr,
|
||||
|
|
@ -139,8 +138,7 @@ public:
|
|||
const gfx::IntSize& aSizeCbCr);
|
||||
|
||||
static DXGIYCbCrTextureData*
|
||||
Create(TextureFlags aFlags,
|
||||
ID3D11Texture2D* aTextureCb,
|
||||
Create(ID3D11Texture2D* aTextureCb,
|
||||
ID3D11Texture2D* aTextureY,
|
||||
ID3D11Texture2D* aTextureCr,
|
||||
const gfx::IntSize& aSize,
|
||||
|
|
@ -166,8 +164,11 @@ public:
|
|||
return TextureFlags::DEALLOCATE_MAIN_THREAD;
|
||||
}
|
||||
|
||||
ID3D11Texture2D* GetD3D11Texture(size_t index) { return mD3D11Textures[index]; }
|
||||
|
||||
protected:
|
||||
RefPtr<IUnknown> mHoldRefs[3];
|
||||
RefPtr<ID3D11Texture2D> mD3D11Textures[3];
|
||||
RefPtr<IDirect3DTexture9> mD3D9Textures[3];
|
||||
HANDLE mHandles[3];
|
||||
gfx::IntSize mSize;
|
||||
gfx::IntSize mSizeY;
|
||||
|
|
@ -450,6 +451,30 @@ inline uint32_t GetMaxTextureSizeForFeatureLevel(D3D_FEATURE_LEVEL aFeatureLevel
|
|||
return maxTextureSize;
|
||||
}
|
||||
|
||||
class AutoLockD3D11Texture
|
||||
{
|
||||
public:
|
||||
explicit AutoLockD3D11Texture(ID3D11Texture2D* aTexture);
|
||||
~AutoLockD3D11Texture();
|
||||
|
||||
private:
|
||||
RefPtr<IDXGIKeyedMutex> mMutex;
|
||||
};
|
||||
|
||||
class D3D11MTAutoEnter
|
||||
{
|
||||
public:
|
||||
explicit D3D11MTAutoEnter(already_AddRefed<ID3D10Multithread> aMT)
|
||||
: mMT(aMT)
|
||||
{
|
||||
mMT->Enter();
|
||||
}
|
||||
~D3D11MTAutoEnter() { mMT->Leave(); }
|
||||
|
||||
private:
|
||||
RefPtr<ID3D10Multithread> mMT;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ EXPORTS += [
|
|||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
SOURCES += [
|
||||
'D3D11ShareHandleImage.cpp',
|
||||
'D3D11YCbCrImage.cpp',
|
||||
]
|
||||
UNIFIED_SOURCES += [
|
||||
'D3D9SurfaceImage.cpp',
|
||||
|
|
@ -153,6 +154,7 @@ EXPORTS.mozilla.layers += [
|
|||
'Compositor.h',
|
||||
'CompositorTypes.h',
|
||||
'D3D11ShareHandleImage.h',
|
||||
'D3D11YCbCrImage.h',
|
||||
'D3D9SurfaceImage.h',
|
||||
'Effects.h',
|
||||
'ImageDataSerializer.h',
|
||||
|
|
|
|||
|
|
@ -781,7 +781,7 @@ DeviceManagerDx::CanInitializeKeyedMutexTextures()
|
|||
}
|
||||
// Disable this on all Intel devices because of crashes.
|
||||
// See bug 1292923.
|
||||
return mDeviceStatus->adapter().VendorId != 0x8086;
|
||||
return (mDeviceStatus->adapter().VendorId != 0x8086 || gfxPrefs::Direct3D11AllowIntelMutex());
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -376,6 +376,7 @@ private:
|
|||
DECL_GFX_PREF(Once, "gfx.direct2d.disabled", Direct2DDisabled, bool, false);
|
||||
DECL_GFX_PREF(Once, "gfx.direct2d.force-enabled", Direct2DForceEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.direct3d11.reuse-decoder-device", Direct3D11ReuseDecoderDevice, int32_t, -1);
|
||||
DECL_GFX_PREF(Live, "gfx.direct3d11.allow-intel-mutex", Direct3D11AllowIntelMutex, bool, true);
|
||||
DECL_GFX_PREF(Live, "gfx.draw-color-bars", CompositorDrawColorBars, bool, false);
|
||||
DECL_GFX_PREF(Once, "gfx.e10s.hide-plugins-for-scroll", HidePluginsForScroll, bool, true);
|
||||
DECL_GFX_PREF(Live, "gfx.gralloc.fence-with-readpixels", GrallocFenceWithReadPixels, bool, false);
|
||||
|
|
@ -601,7 +602,7 @@ private:
|
|||
DECL_GFX_PREF(Live, "webgl.lose-context-on-memory-pressure", WebGLLoseContextOnMemoryPressure, bool, false);
|
||||
DECL_GFX_PREF(Live, "webgl.max-warnings-per-context", WebGLMaxWarningsPerContext, uint32_t, 32);
|
||||
DECL_GFX_PREF(Live, "webgl.max-size-per-texture-mb", WebGLMaxSizePerTextureMB, uint32_t, 1024);
|
||||
DECL_GFX_PREF(Live, "webgl.max-vert-ids-per-draw", WebglMaxVertIDsPerDraw, uint32_t, 30*1000*1000);
|
||||
DECL_GFX_PREF(Live, "webgl.max-vert-ids-per-draw", WebglMaxVertIDsPerDraw, uint32_t, 30*1000*1000);
|
||||
DECL_GFX_PREF(Live, "webgl.min_capability_mode", WebGLMinCapabilityMode, bool, false);
|
||||
DECL_GFX_PREF(Live, "webgl.msaa-force", WebGLForceMSAA, bool, false);
|
||||
DECL_GFX_PREF(Live, "webgl.prefer-16bpp", WebGLPrefer16bpp, bool, false);
|
||||
|
|
|
|||
|
|
@ -1607,7 +1607,10 @@ js::StartDynamicModuleImport(JSContext* cx, HandleValue referencingPrivate, Hand
|
|||
|
||||
JS::ModuleDynamicImportHook importHook = cx->runtime()->moduleDynamicImportHook;
|
||||
MOZ_ASSERT(importHook);
|
||||
cx->runtime()->addRefScriptPrivate(referencingPrivate);
|
||||
if (!importHook(cx, referencingPrivate, specifier, promise)) {
|
||||
cx->runtime()->releaseScriptPrivate(referencingPrivate);
|
||||
|
||||
if (!RejectPromiseWithPendingError(cx, promise))
|
||||
return nullptr;
|
||||
return promise;
|
||||
|
|
@ -1622,6 +1625,9 @@ js::FinishDynamicModuleImport(JSContext* cx, HandleValue referencingPrivate, Han
|
|||
{
|
||||
Handle<PromiseObject*> promise = promiseArg.as<PromiseObject>();
|
||||
|
||||
auto releasePrivate = mozilla::MakeScopeExit(
|
||||
[&] { cx->runtime()->releaseScriptPrivate(referencingPrivate); });
|
||||
|
||||
if (cx->isExceptionPending()) {
|
||||
return RejectPromiseWithPendingError(cx, promise);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4729,7 +4729,8 @@ JS::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
|
|||
JS_PUBLIC_API(void)
|
||||
JS::SetModulePrivate(JSObject* module, const JS::Value& value)
|
||||
{
|
||||
module->as<ModuleObject>().scriptSourceObject()->setPrivate(value);
|
||||
JSRuntime* rt = module->compartment()->runtimeFromMainThread();
|
||||
module->as<ModuleObject>().scriptSourceObject()->setPrivate(rt, value);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JS::Value)
|
||||
|
|
@ -4741,7 +4742,8 @@ JS::GetModulePrivate(JSObject* module)
|
|||
JS_PUBLIC_API(void)
|
||||
JS::SetScriptPrivate(JSScript* script, const JS::Value& value)
|
||||
{
|
||||
script->scriptSourceUnwrap().setPrivate(value);
|
||||
JSRuntime* rt = script->compartment()->runtimeFromMainThread();
|
||||
script->scriptSourceUnwrap().setPrivate(rt, value);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JS::Value)
|
||||
|
|
@ -4764,18 +4766,13 @@ JS::GetScriptedCallerPrivate(JSContext* cx)
|
|||
return FindScriptOrModulePrivateForScript(iter.script());
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JS::ScriptPrivateFinalizeHook)
|
||||
JS::GetScriptPrivateFinalizeHook(JSContext* cx)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
return cx->runtime()->scriptPrivateFinalizeHook;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::SetScriptPrivateFinalizeHook(JSContext* cx, JS::ScriptPrivateFinalizeHook func)
|
||||
JS::SetScriptPrivateReferenceHooks(JSContext* cx, JS::ScriptPrivateReferenceHook addRefHook,
|
||||
JS::ScriptPrivateReferenceHook releaseHook)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
cx->runtime()->scriptPrivateFinalizeHook = func;
|
||||
cx->runtime()->scriptPrivateAddRefHook = addRefHook;
|
||||
cx->runtime()->scriptPrivateReleaseHook = releaseHook;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
|
|
|
|||
|
|
@ -4432,24 +4432,18 @@ extern JS_PUBLIC_API(JS::Value)
|
|||
GetScriptedCallerPrivate(JSContext* cx);
|
||||
|
||||
/**
|
||||
* A hook that's called whenever a script or module which has a private value
|
||||
* set with SetScriptPrivate() or SetModulePrivate() is finalized. This can be
|
||||
* used to clean up the private state. The private value is passed as an
|
||||
* argument.
|
||||
* Hooks called when references to a script private value are created or
|
||||
* destroyed. This allows use of a reference counted object as the
|
||||
* script private.
|
||||
*/
|
||||
using ScriptPrivateFinalizeHook = void (*)(JSFreeOp*, const JS::Value&);
|
||||
|
||||
/**
|
||||
* Get the script private finalize hook for the runtime.
|
||||
*/
|
||||
extern JS_PUBLIC_API(ScriptPrivateFinalizeHook)
|
||||
GetScriptPrivateFinalizeHook(JSContext* cx);
|
||||
using ScriptPrivateReferenceHook = void (*)(const JS::Value&);
|
||||
|
||||
/**
|
||||
* Set the script private finalize hook for the runtime to the given function.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
SetScriptPrivateFinalizeHook(JSContext* cx, ScriptPrivateFinalizeHook func);
|
||||
SetScriptPrivateReferenceHooks(JSContext* cx, ScriptPrivateReferenceHook addRefHook,
|
||||
ScriptPrivateReferenceHook releaseHook);
|
||||
|
||||
/*
|
||||
* Perform the ModuleInstantiate operation on the given source text module
|
||||
|
|
|
|||
|
|
@ -1419,15 +1419,8 @@ ScriptSourceObject::finalize(FreeOp* fop, JSObject* obj)
|
|||
sso->source()->decref();
|
||||
sso->setReservedSlot(SOURCE_SLOT, PrivateValue(nullptr));
|
||||
|
||||
Value value = sso->canonicalPrivate();
|
||||
if (!value.isUndefined()) {
|
||||
// The embedding may need to dispose of its private data.
|
||||
JS::AutoSuppressGCAnalysis suppressGC;
|
||||
if (JS::ScriptPrivateFinalizeHook hook =
|
||||
fop->runtime()->scriptPrivateFinalizeHook) {
|
||||
hook(fop, value);
|
||||
}
|
||||
}
|
||||
// Clear the private value, calling the release hook if necessary.
|
||||
sso->setPrivate(fop->runtime(), UndefinedValue());
|
||||
}
|
||||
|
||||
static const ClassOps ScriptSourceObjectClassOps = {
|
||||
|
|
@ -1532,6 +1525,25 @@ ScriptSourceObject::initFromOptions(JSContext* cx, HandleScriptSource source,
|
|||
return true;
|
||||
}
|
||||
|
||||
void ScriptSourceObject::setPrivate(JSRuntime* rt, const Value& value)
|
||||
{
|
||||
// Update the private value, calling addRef/release hooks if necessary
|
||||
// to allow the embedding to maintain a reference count for the
|
||||
// private data.
|
||||
Value prevValue = getReservedSlot(PRIVATE_SLOT);
|
||||
if (!prevValue.isUndefined()) {
|
||||
if (auto releaseHook = rt->scriptPrivateReleaseHook) {
|
||||
releaseHook(prevValue);
|
||||
}
|
||||
}
|
||||
setReservedSlot(PRIVATE_SLOT, value);
|
||||
if (!value.isUndefined()) {
|
||||
if (auto addRefHook = rt->scriptPrivateAddRefHook) {
|
||||
addRefHook(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
JSScript::loadSource(JSContext* cx, ScriptSource* ss, bool* worked)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -675,9 +675,7 @@ class ScriptSourceObject : public NativeObject
|
|||
return static_cast<JSScript*>(untyped);
|
||||
}
|
||||
|
||||
void setPrivate(const Value& value) {
|
||||
setReservedSlot(PRIVATE_SLOT, value);
|
||||
}
|
||||
void setPrivate(JSRuntime* rt, const Value& value);
|
||||
|
||||
Value getPrivate() const {
|
||||
return getReservedSlot(PRIVATE_SLOT);
|
||||
|
|
|
|||
|
|
@ -252,7 +252,8 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
|||
moduleResolveHook(),
|
||||
moduleMetadataHook(),
|
||||
moduleDynamicImportHook(),
|
||||
scriptPrivateFinalizeHook()
|
||||
scriptPrivateAddRefHook(),
|
||||
scriptPrivateReleaseHook()
|
||||
{
|
||||
setGCStoreBufferPtr(&gc.storeBuffer);
|
||||
|
||||
|
|
|
|||
|
|
@ -1316,8 +1316,21 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||
// HostImportModuleDynamically.
|
||||
JS::ModuleDynamicImportHook moduleDynamicImportHook;
|
||||
|
||||
// A hook called on script finalization.
|
||||
JS::ScriptPrivateFinalizeHook scriptPrivateFinalizeHook;
|
||||
// Hooks called when script private references are created and destroyed.
|
||||
JS::ScriptPrivateReferenceHook scriptPrivateAddRefHook;
|
||||
JS::ScriptPrivateReferenceHook scriptPrivateReleaseHook;
|
||||
|
||||
void addRefScriptPrivate(const JS::Value& value) {
|
||||
if (!value.isUndefined() && scriptPrivateAddRefHook) {
|
||||
scriptPrivateAddRefHook(value);
|
||||
}
|
||||
}
|
||||
|
||||
void releaseScriptPrivate(const JS::Value& value) {
|
||||
if (!value.isUndefined() && scriptPrivateReleaseHook) {
|
||||
scriptPrivateReleaseHook(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
namespace js {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue