Merge remote-tracking branch 'origin/tracking' into custom

This commit is contained in:
roytam1 2023-11-30 10:05:11 +08:00
commit c889903081
34 changed files with 846 additions and 195 deletions

View file

@ -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();
}

View file

@ -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,

View file

@ -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));

View file

@ -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,

View file

@ -43,6 +43,7 @@ private:
MediaResult DoDecode(MediaRawData* aSample);
void ProcessDrain();
RefPtr<KnowsCompositor> mImageAllocator;
RefPtr<ImageContainer> mImageContainer;
RefPtr<TaskQueue> mTaskQueue;
MediaDataDecoderCallback* mCallback;

View file

@ -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];

View file

@ -61,6 +61,7 @@ private:
MediaRawData* aSample);
const RefPtr<ImageContainer> mImageContainer;
RefPtr<layers::KnowsCompositor> mImageAllocator;
const RefPtr<TaskQueue> mTaskQueue;
MediaDataDecoderCallback* mCallback;
Atomic<bool> mIsFlushing;

View file

@ -44,6 +44,7 @@ public:
aParams.mTaskQueue,
aParams.mCallback,
aParams.VideoConfig(),
aParams.mKnowsCompositor,
aParams.mImageContainer);
return decoder.forget();
}

View file

@ -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,

View file

@ -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;

View file

@ -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

View file

@ -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() {

View file

@ -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();

View file

@ -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);
}

View 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

View 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

View file

@ -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

View file

@ -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;

View file

@ -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)

View file

@ -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.

View file

@ -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.

View file

@ -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:

View file

@ -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");
}
}
}
}

View file

@ -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;
};
}
}

View file

@ -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',

View file

@ -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

View file

@ -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);

View file

@ -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);
}

View file

@ -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)

View file

@ -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

View file

@ -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)
{

View file

@ -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);

View file

@ -252,7 +252,8 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
moduleResolveHook(),
moduleMetadataHook(),
moduleDynamicImportHook(),
scriptPrivateFinalizeHook()
scriptPrivateAddRefHook(),
scriptPrivateReleaseHook()
{
setGCStoreBufferPtr(&gc.storeBuffer);

View file

@ -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 {