forked from mirrors/gecko-dev
Bug 1771011 - part2 : wrap media engine's dcomp handle, and use it on our gfx pipeline in the GPU process.r=jolin,sotaro
In this patch, we ask the media engine to return a handle for shareable dcomp surface, which will then be packaged into a new texture data type and being shared with the GPU process via the video bridge. DcompSurfaceImage is the image which contains the handle texture data, which doesn't support being accessed in the content process. When the compositor uploads the image to the GPU process, the corresponding texture host will be created. The render texture host will be created by that texture host, and it will be used in DCLayerTree. In DCLayerTree, we create a new type of surface for our dcomp handle. DCSurfaceHandle will ask the render texture host to reconstruct the surface by the handle shared from the remote process (the handle is actually duplicated to the parent process first due to the sandbox policy, and then be duplicated to the GPU process later) DCSurfaceHandle will attach that surface to its visual in order to display the video frame directly. In the whole process, it's not possible for Gecko to access any decoded video data which is protected by the media engine itself. Depends on D149941 Differential Revision: https://phabricator.services.mozilla.com/D151019
This commit is contained in:
parent
0e65c9d8b5
commit
efe35b01d5
28 changed files with 841 additions and 58 deletions
|
|
@ -101,6 +101,9 @@ static layers::SurfaceDescriptor Flatten(const layers::SurfaceDescriptor& sd) {
|
|||
case layers::RemoteDecoderVideoSubDescriptor::
|
||||
TSurfaceDescriptorMacIOSurface:
|
||||
return subdesc.get_SurfaceDescriptorMacIOSurface();
|
||||
case layers::RemoteDecoderVideoSubDescriptor::
|
||||
TSurfaceDescriptorDcompSurface:
|
||||
return subdesc.get_SurfaceDescriptorDcompSurface();
|
||||
}
|
||||
MOZ_CRASH("unreachable");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -737,9 +737,8 @@ void ExternalEngineStateMachine::OnRequestVideo() {
|
|||
MEDIA_PLAYBACK);
|
||||
MOZ_ASSERT(aVideo);
|
||||
RunningEngineUpdate(MediaData::Type::VIDEO_DATA);
|
||||
// TODO : figure out the relationship between setting image and the
|
||||
// DCOMP mode.
|
||||
SetBlankVideoToVideoContainer();
|
||||
mVideoFrameContainer->SetCurrentFrame(
|
||||
mInfo->mVideo.mDisplay, aVideo->mImage, TimeStamp::Now());
|
||||
},
|
||||
[this, self](const MediaResult& aError) {
|
||||
mVideoDataRequest.Complete();
|
||||
|
|
@ -766,18 +765,6 @@ void ExternalEngineStateMachine::OnRequestVideo() {
|
|||
->Track(mVideoDataRequest);
|
||||
}
|
||||
|
||||
void ExternalEngineStateMachine::SetBlankVideoToVideoContainer() {
|
||||
AssertOnTaskQueue();
|
||||
MOZ_ASSERT(mState.IsRunningEngine() || mState.IsSeekingData());
|
||||
if (!mBlankImage) {
|
||||
mBlankImage =
|
||||
mVideoFrameContainer->GetImageContainer()->CreatePlanarYCbCrImage();
|
||||
}
|
||||
MOZ_ASSERT(mInfo->HasVideo());
|
||||
mVideoFrameContainer->SetCurrentFrame(mInfo->mVideo.mDisplay, mBlankImage,
|
||||
TimeStamp::Now());
|
||||
}
|
||||
|
||||
void ExternalEngineStateMachine::OnLoadedFirstFrame() {
|
||||
AssertOnTaskQueue();
|
||||
MediaDecoderEventVisibility visibility =
|
||||
|
|
|
|||
|
|
@ -267,8 +267,6 @@ class ExternalEngineStateMachine final
|
|||
bool mSentPlaybackEndedEvent = false;
|
||||
|
||||
const RefPtr<VideoFrameContainer> mVideoFrameContainer;
|
||||
// TODO : before implementing a video output, we use this for our image.
|
||||
RefPtr<layers::Image> mBlankImage;
|
||||
};
|
||||
|
||||
class ExternalPlaybackEngine {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <mfapi.h>
|
||||
|
||||
#include "MFMediaEngineExtension.h"
|
||||
#include "MFMediaEngineVideoStream.h"
|
||||
#include "MFMediaEngineUtils.h"
|
||||
#include "MFMediaEngineStream.h"
|
||||
#include "MFMediaSource.h"
|
||||
|
|
@ -153,20 +154,13 @@ void MFMediaEngineParent::CreateMediaEngine() {
|
|||
nullptr, CLSCTX_INPROC_SERVER,
|
||||
IID_PPV_ARGS(&factory)));
|
||||
const bool isLowLatency =
|
||||
(StaticPrefs::media_wmf_low_latency_enabled() || IsWin10OrLater()) &&
|
||||
StaticPrefs::media_wmf_low_latency_enabled() &&
|
||||
!StaticPrefs::media_wmf_low_latency_force_disabled();
|
||||
static const DWORD MF_MEDIA_ENGINE_DEFAULT = 0;
|
||||
RETURN_VOID_IF_FAILED(factory->CreateInstance(
|
||||
isLowLatency ? MF_MEDIA_ENGINE_REAL_TIME_MODE : MF_MEDIA_ENGINE_DEFAULT,
|
||||
creationAttributes.Get(), &mMediaEngine));
|
||||
|
||||
if (StaticPrefs::media_wmf_media_engine_video_output_enabled()) {
|
||||
// Set Dcomp mode for the media engine.
|
||||
ComPtr<IMFMediaEngineEx> mediaEngineEx;
|
||||
RETURN_VOID_IF_FAILED(mMediaEngine.As(&mediaEngineEx));
|
||||
RETURN_VOID_IF_FAILED(mediaEngineEx->EnableWindowlessSwapchainMode(true));
|
||||
}
|
||||
|
||||
// TODO : deal with encrypted content (set ContentProtectionManager and cdm
|
||||
// proxy)
|
||||
|
||||
|
|
@ -237,7 +231,13 @@ void MFMediaEngineParent::HandleMediaEngineEvent(
|
|||
NotifyError(error, result);
|
||||
break;
|
||||
}
|
||||
case MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY:
|
||||
case MF_MEDIA_ENGINE_EVENT_FORMATCHANGE:
|
||||
case MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY: {
|
||||
if (mMediaEngine->HasVideo()) {
|
||||
EnsureDcompSurfaceHandle();
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
case MF_MEDIA_ENGINE_EVENT_LOADEDDATA:
|
||||
case MF_MEDIA_ENGINE_EVENT_WAITING:
|
||||
case MF_MEDIA_ENGINE_EVENT_SEEKED:
|
||||
|
|
@ -308,6 +308,7 @@ MFMediaEngineStreamWrapper* MFMediaEngineParent::GetMediaEngineStream(
|
|||
// output implementation. Our first step is to make audio playback work.
|
||||
if (StaticPrefs::media_wmf_media_engine_video_output_enabled()) {
|
||||
auto* stream = mMediaSource->GetVideoStream();
|
||||
stream->AsVideoStream()->SetKnowsCompositor(aParam.mKnowsCompositor);
|
||||
return new MFMediaEngineStreamWrapper(stream, stream->GetTaskQueue(),
|
||||
aParam);
|
||||
}
|
||||
|
|
@ -462,6 +463,45 @@ void MFMediaEngineParent::AssertOnManagerThread() const {
|
|||
MOZ_ASSERT(mManagerThread->IsOnCurrentThread());
|
||||
}
|
||||
|
||||
void MFMediaEngineParent::EnsureDcompSurfaceHandle() {
|
||||
AssertOnManagerThread();
|
||||
MOZ_ASSERT(mMediaEngine);
|
||||
MOZ_ASSERT(mMediaEngine->HasVideo());
|
||||
|
||||
ComPtr<IMFMediaEngineEx> mediaEngineEx;
|
||||
RETURN_VOID_IF_FAILED(mMediaEngine.As(&mediaEngineEx));
|
||||
DWORD width, height;
|
||||
RETURN_VOID_IF_FAILED(mMediaEngine->GetNativeVideoSize(&width, &height));
|
||||
if (width != mDisplayWidth || height != mDisplayHeight) {
|
||||
// Update stream size before asking for a handle. If we don't update the
|
||||
// size, media engine will create the dcomp surface in a wrong size. If
|
||||
// the size isn't changed, then we don't need to recreate the surface.
|
||||
mDisplayWidth = width;
|
||||
mDisplayHeight = height;
|
||||
RECT rect = {0, 0, (LONG)mDisplayWidth, (LONG)mDisplayHeight};
|
||||
RETURN_VOID_IF_FAILED(mediaEngineEx->UpdateVideoStream(
|
||||
nullptr /* pSrc */, &rect, nullptr /* pBorderClr */));
|
||||
LOG("Updated video size for engine=[%lux%lu]", mDisplayWidth,
|
||||
mDisplayHeight);
|
||||
}
|
||||
|
||||
if (!mIsEnableDcompMode) {
|
||||
RETURN_VOID_IF_FAILED(mediaEngineEx->EnableWindowlessSwapchainMode(true));
|
||||
LOG("Enabled dcomp swap chain mode");
|
||||
mIsEnableDcompMode = true;
|
||||
}
|
||||
|
||||
HANDLE surfaceHandle = INVALID_HANDLE_VALUE;
|
||||
RETURN_VOID_IF_FAILED(mediaEngineEx->GetVideoSwapchainHandle(&surfaceHandle));
|
||||
if (surfaceHandle && surfaceHandle != INVALID_HANDLE_VALUE) {
|
||||
LOG("EnsureDcompSurfaceHandle, handle=%p, size=[%lux%lu]", surfaceHandle,
|
||||
width, height);
|
||||
mMediaSource->SetDCompSurfaceHandle(surfaceHandle);
|
||||
} else {
|
||||
NS_WARNING("SurfaceHandle is not ready yet");
|
||||
}
|
||||
}
|
||||
|
||||
#undef LOG
|
||||
#undef RETURN_IF_FAILED
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#define DOM_MEDIA_IPC_MFMEDIAENGINEPARENT_H_
|
||||
|
||||
#include <Mfidl.h>
|
||||
#include <winnt.h>
|
||||
#include <wrl.h>
|
||||
|
||||
#include "MediaInfo.h"
|
||||
|
|
@ -78,6 +79,8 @@ class MFMediaEngineParent final : public PMFMediaEngineParent {
|
|||
|
||||
void DestroyEngineIfExists(const Maybe<MediaResult>& aError = Nothing());
|
||||
|
||||
void EnsureDcompSurfaceHandle();
|
||||
|
||||
// This generates unique id for each MFMediaEngineParent instance, and it
|
||||
// would be increased monotonically.
|
||||
static inline uint64_t sMediaEngineIdx = 0;
|
||||
|
|
@ -106,6 +109,14 @@ class MFMediaEngineParent final : public PMFMediaEngineParent {
|
|||
HWND mVirtualVideoWindow = nullptr;
|
||||
|
||||
Microsoft::WRL::ComPtr<IMFDXGIDeviceManager> mDXGIDeviceManager;
|
||||
|
||||
// These will be always zero for audio playback.
|
||||
DWORD mDisplayWidth = 0;
|
||||
DWORD mDisplayHeight = 0;
|
||||
|
||||
// When it's true, the media engine will output decoded video frames to a
|
||||
// shareable dcomp surface.
|
||||
bool mIsEnableDcompMode = false;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -48,9 +48,14 @@ RefPtr<MediaDataDecoder::DecodePromise> MFMediaEngineStreamWrapper::Decode(
|
|||
Unused << mTaskQueue->Dispatch(NS_NewRunnableFunction(
|
||||
"MFMediaEngineStreamWrapper::Decode",
|
||||
[sample = RefPtr{aSample}, stream]() { stream->NotifyNewData(sample); }));
|
||||
|
||||
// We don't return a real data, all data would be processed inside the media
|
||||
// engine. We return an empty data back instead.
|
||||
// TODO : for video, we should only resolve the promise when we get the dcomp
|
||||
// handle.
|
||||
RefPtr<MediaData> outputData = mStream->OutputData(aSample);
|
||||
if (outputData) {
|
||||
return DecodePromise::CreateAndResolve(DecodedData{outputData}, __func__);
|
||||
}
|
||||
// The stream don't support returning output, all data would be processed
|
||||
// inside the media engine. We return an empty data back instead.
|
||||
MOZ_ASSERT(mFakeDataCreator->Type() == mStream->TrackType());
|
||||
return mFakeDataCreator->Decode(aSample);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
class MFMediaEngineVideoStream;
|
||||
class MFMediaSource;
|
||||
|
||||
/**
|
||||
|
|
@ -86,6 +87,13 @@ class MFMediaEngineStream
|
|||
// True if the stream has been shutdown, it's a thread safe method.
|
||||
bool IsShutdown() const { return mIsShutdown; }
|
||||
|
||||
virtual MFMediaEngineVideoStream* AsVideoStream() { return nullptr; }
|
||||
|
||||
// Overwrite this method to support returning decoded data.
|
||||
virtual already_AddRefed<MediaData> OutputData(MediaRawData* aSample) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
HRESULT GenerateStreamDescriptor(uint64_t aStreamId, const TrackInfo& aInfo);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "MFMediaEngineVideoStream.h"
|
||||
|
||||
#include "mozilla/layers/DcompSurfaceImage.h"
|
||||
#include "MFMediaEngineUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
|
@ -25,13 +26,25 @@ MFMediaEngineVideoStream* MFMediaEngineVideoStream::Create(
|
|||
&stream, aStreamId, aInfo, aParentSource))) {
|
||||
return nullptr;
|
||||
}
|
||||
stream->SetDCompSurfaceHandle(INVALID_HANDLE_VALUE);
|
||||
return stream;
|
||||
}
|
||||
|
||||
void MFMediaEngineVideoStream::SetDCompSurfaceHandle(
|
||||
HANDLE aDCompSurfaceHandle) {
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mDCompSurfaceHandle == aDCompSurfaceHandle) {
|
||||
return;
|
||||
}
|
||||
mDCompSurfaceHandle = aDCompSurfaceHandle;
|
||||
mNeedRecreateImage = true;
|
||||
LOGV("Set DCompSurfaceHandle, handle=%p", mDCompSurfaceHandle);
|
||||
}
|
||||
|
||||
HRESULT MFMediaEngineVideoStream::CreateMediaType(const TrackInfo& aInfo,
|
||||
IMFMediaType** aMediaType) {
|
||||
const VideoInfo& info = *aInfo.GetAsVideoInfo();
|
||||
GUID subType = VideoMimeTypeToMediaFoundationSubtype(info.mMimeType);
|
||||
mInfo = *aInfo.GetAsVideoInfo();
|
||||
GUID subType = VideoMimeTypeToMediaFoundationSubtype(mInfo.mMimeType);
|
||||
NS_ENSURE_TRUE(subType != GUID_NULL, MF_E_TOPO_CODEC_NOT_FOUND);
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/medfound/media-type-attributes
|
||||
|
|
@ -40,14 +53,14 @@ HRESULT MFMediaEngineVideoStream::CreateMediaType(const TrackInfo& aInfo,
|
|||
RETURN_IF_FAILED(mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video));
|
||||
RETURN_IF_FAILED(mediaType->SetGUID(MF_MT_SUBTYPE, subType));
|
||||
|
||||
const auto& image = info.mImage;
|
||||
const auto& image = mInfo.mImage;
|
||||
UINT32 imageWidth = image.Width();
|
||||
UINT32 imageHeight = image.Height();
|
||||
RETURN_IF_FAILED(MFSetAttributeSize(mediaType.Get(), MF_MT_FRAME_SIZE,
|
||||
imageWidth, imageHeight));
|
||||
|
||||
UINT32 displayWidth = info.mDisplay.Width();
|
||||
UINT32 displayHeight = info.mDisplay.Height();
|
||||
UINT32 displayWidth = mInfo.mDisplay.Width();
|
||||
UINT32 displayHeight = mInfo.mDisplay.Height();
|
||||
// PAR = DAR / SAR = (DW / DH) / (SW / SH) = (DW * SH) / (DH * SW)
|
||||
RETURN_IF_FAILED(MFSetAttributeRatio(
|
||||
mediaType.Get(), MF_MT_PIXEL_ASPECT_RATIO, displayWidth * imageHeight,
|
||||
|
|
@ -62,8 +75,8 @@ HRESULT MFMediaEngineVideoStream::CreateMediaType(const TrackInfo& aInfo,
|
|||
return offset;
|
||||
};
|
||||
MFVideoArea area;
|
||||
area.OffsetX = ToMFOffset(info.ImageRect().x);
|
||||
area.OffsetY = ToMFOffset(info.ImageRect().y);
|
||||
area.OffsetX = ToMFOffset(mInfo.ImageRect().x);
|
||||
area.OffsetY = ToMFOffset(mInfo.ImageRect().y);
|
||||
area.Area = {(LONG)imageWidth, (LONG)imageHeight};
|
||||
RETURN_IF_FAILED(mediaType->SetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&area,
|
||||
sizeof(area)));
|
||||
|
|
@ -84,7 +97,7 @@ HRESULT MFMediaEngineVideoStream::CreateMediaType(const TrackInfo& aInfo,
|
|||
return MFVideoRotationFormat_270;
|
||||
}
|
||||
};
|
||||
const auto rotation = ToMFVideoRotationFormat(info.mRotation);
|
||||
const auto rotation = ToMFVideoRotationFormat(mInfo.mRotation);
|
||||
RETURN_IF_FAILED(mediaType->SetUINT32(MF_MT_VIDEO_ROTATION, rotation));
|
||||
|
||||
static const auto ToMFVideoTransFunc =
|
||||
|
|
@ -106,7 +119,7 @@ HRESULT MFMediaEngineVideoStream::CreateMediaType(const TrackInfo& aInfo,
|
|||
return MFVideoTransFunc_Unknown;
|
||||
}
|
||||
};
|
||||
const auto transFunc = ToMFVideoTransFunc(info.mColorSpace);
|
||||
const auto transFunc = ToMFVideoTransFunc(mInfo.mColorSpace);
|
||||
RETURN_IF_FAILED(mediaType->SetUINT32(MF_MT_TRANSFER_FUNCTION, transFunc));
|
||||
|
||||
static const auto ToMFVideoPrimaries =
|
||||
|
|
@ -129,7 +142,7 @@ HRESULT MFMediaEngineVideoStream::CreateMediaType(const TrackInfo& aInfo,
|
|||
return MFVideoPrimaries_Unknown;
|
||||
}
|
||||
};
|
||||
const auto videoPrimaries = ToMFVideoPrimaries(info.mColorSpace);
|
||||
const auto videoPrimaries = ToMFVideoPrimaries(mInfo.mColorSpace);
|
||||
RETURN_IF_FAILED(mediaType->SetUINT32(MF_MT_VIDEO_PRIMARIES, videoPrimaries));
|
||||
|
||||
LOGV(
|
||||
|
|
@ -150,6 +163,43 @@ bool MFMediaEngineVideoStream::HasEnoughRawData() const {
|
|||
return mRawDataQueue.Duration() >= VIDEO_VIDEO_USECS;
|
||||
}
|
||||
|
||||
layers::Image* MFMediaEngineVideoStream::GetDcompSurfaceImage() {
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (!mDCompSurfaceHandle || mDCompSurfaceHandle == INVALID_HANDLE_VALUE) {
|
||||
LOGV("Can't create image without a valid dcomp surface handle");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mKnowsCompositor) {
|
||||
LOGV("Can't create image without the knows compositor");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mDcompSurfaceImage || mNeedRecreateImage) {
|
||||
// DirectComposition only supports RGBA. We use DXGI_FORMAT_B8G8R8A8_UNORM
|
||||
// as a default because we can't know what format the dcomp surface is.
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/dcomp/nf-dcomp-idcompositionsurfacefactory-createsurface
|
||||
mDcompSurfaceImage = new layers::DcompSurfaceImage(
|
||||
mDCompSurfaceHandle, mInfo.mDisplay, gfx::SurfaceFormat::B8G8R8A8,
|
||||
mKnowsCompositor);
|
||||
mNeedRecreateImage = false;
|
||||
LOGV("Created dcomp surface image, handle=%p, size=[%u,%u]",
|
||||
mDCompSurfaceHandle, mInfo.mDisplay.Width(), mInfo.mDisplay.Height());
|
||||
}
|
||||
return mDcompSurfaceImage;
|
||||
}
|
||||
|
||||
already_AddRefed<MediaData> MFMediaEngineVideoStream::OutputData(
|
||||
MediaRawData* aSample) {
|
||||
RefPtr<layers::Image> image = GetDcompSurfaceImage();
|
||||
if (!image) {
|
||||
return nullptr;
|
||||
}
|
||||
return VideoData::CreateFromImage(mInfo.mDisplay, aSample->mOffset,
|
||||
aSample->mTime, aSample->mDuration, image,
|
||||
aSample->mKeyframe, aSample->mTimecode);
|
||||
}
|
||||
|
||||
#undef LOGV
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -6,8 +6,15 @@
|
|||
#define DOM_MEDIA_PLATFORM_WMF_MFMEDIAENGINEVIDEOSTREAM_H
|
||||
|
||||
#include "MFMediaEngineStream.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class Image;
|
||||
class DcompSurfaceImage;
|
||||
|
||||
} // namespace layers
|
||||
|
||||
class MFMediaSource;
|
||||
|
||||
|
|
@ -26,11 +33,41 @@ class MFMediaEngineVideoStream final : public MFMediaEngineStream {
|
|||
return TrackInfo::TrackType::kVideoTrack;
|
||||
}
|
||||
|
||||
void SetKnowsCompositor(layers::KnowsCompositor* aKnowsCompositor) {
|
||||
MutexAutoLock lock(mMutex);
|
||||
mKnowsCompositor = aKnowsCompositor;
|
||||
}
|
||||
|
||||
HANDLE GetDcompSurfaceHandle() {
|
||||
MutexAutoLock lock(mMutex);
|
||||
return mDCompSurfaceHandle;
|
||||
}
|
||||
void SetDCompSurfaceHandle(HANDLE aDCompSurfaceHandle);
|
||||
|
||||
MFMediaEngineVideoStream* AsVideoStream() override { return this; }
|
||||
|
||||
layers::Image* GetDcompSurfaceImage();
|
||||
|
||||
already_AddRefed<MediaData> OutputData(MediaRawData* aSample) override;
|
||||
|
||||
private:
|
||||
HRESULT CreateMediaType(const TrackInfo& aInfo,
|
||||
IMFMediaType** aMediaType) override;
|
||||
HRESULT
|
||||
CreateMediaType(const TrackInfo& aInfo, IMFMediaType** aMediaType) override;
|
||||
|
||||
bool HasEnoughRawData() const override;
|
||||
|
||||
// This info will be set inside the ctor of video stream, and shouldn't be
|
||||
// changed after that.
|
||||
VideoInfo mInfo;
|
||||
|
||||
Mutex mMutex{"MFMediaEngineVideoStream"};
|
||||
|
||||
HANDLE mDCompSurfaceHandle MOZ_GUARDED_BY(mMutex);
|
||||
bool mNeedRecreateImage MOZ_GUARDED_BY(mMutex);
|
||||
RefPtr<layers::KnowsCompositor> mKnowsCompositor MOZ_GUARDED_BY(mMutex);
|
||||
|
||||
// Created and accessed in the decoder thread.
|
||||
RefPtr<layers::DcompSurfaceImage> mDcompSurfaceImage;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -347,6 +347,13 @@ void MFMediaSource::HandleStreamEnded(TrackInfo::TrackType aType) {
|
|||
}
|
||||
}
|
||||
|
||||
void MFMediaSource::SetDCompSurfaceHandle(HANDLE aDCompSurfaceHandle) {
|
||||
// On MediaEngineParent's manager thread.
|
||||
if (mVideoStream) {
|
||||
mVideoStream->AsVideoStream()->SetDCompSurfaceHandle(aDCompSurfaceHandle);
|
||||
}
|
||||
}
|
||||
|
||||
void MFMediaSource::AssertOnTaskQueue() const {
|
||||
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ class MFMediaSource : public Microsoft::WRL::RuntimeClass<
|
|||
};
|
||||
State GetState() const { return mState; }
|
||||
|
||||
void SetDCompSurfaceHandle(HANDLE aDCompSurfaceHandle);
|
||||
|
||||
private:
|
||||
void AssertOnTaskQueue() const;
|
||||
void AssertOnMFThreadPool() const;
|
||||
|
|
|
|||
|
|
@ -178,6 +178,9 @@ HRESULT MFLockDXGIDeviceManager(UINT* pResetToken,
|
|||
|
||||
HRESULT MFUnlockDXGIDeviceManager();
|
||||
|
||||
HRESULT MFPutWorkItem(DWORD dwQueue, IMFAsyncCallback* pCallback,
|
||||
IUnknown* pState);
|
||||
|
||||
} // namespace mozilla::wmf
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -613,5 +613,11 @@ HRESULT MFUnlockDXGIDeviceManager() {
|
|||
return (MFUnlockDXGIDeviceManagerPtr)();
|
||||
}
|
||||
|
||||
HRESULT MFPutWorkItem(DWORD dwQueue, IMFAsyncCallback* pCallback,
|
||||
IUnknown* pState) {
|
||||
ENSURE_FUNCTION_PTR(MFPutWorkItem, mfplat.dll);
|
||||
return (MFPutWorkItemPtr)(dwQueue, pCallback, pState);
|
||||
}
|
||||
|
||||
} // end namespace wmf
|
||||
} // end namespace mozilla
|
||||
|
|
|
|||
|
|
@ -812,11 +812,14 @@ bool GLBlitHelper::BlitImageToFramebuffer(layers::Image* const srcImage,
|
|||
destSize, destOrigin);
|
||||
case ImageFormat::D3D9_RGB32_TEXTURE:
|
||||
return false; // todo
|
||||
case ImageFormat::DCOMP_SURFACE:
|
||||
return false;
|
||||
#else
|
||||
case ImageFormat::D3D11_SHARE_HANDLE_TEXTURE:
|
||||
case ImageFormat::D3D11_TEXTURE_IMF_SAMPLE:
|
||||
case ImageFormat::D3D11_YCBCR_IMAGE:
|
||||
case ImageFormat::D3D9_RGB32_TEXTURE:
|
||||
case ImageFormat::DCOMP_SURFACE:
|
||||
MOZ_ASSERT(false);
|
||||
return false;
|
||||
#endif
|
||||
|
|
|
|||
150
gfx/layers/DcompSurfaceImage.cpp
Normal file
150
gfx/layers/DcompSurfaceImage.cpp
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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 "DcompSurfaceImage.h"
|
||||
|
||||
#include "mozilla/ipc/FileDescriptor.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
#include "mozilla/layers/LayersSurfaces.h"
|
||||
#include "mozilla/layers/TextureForwarder.h"
|
||||
#include "mozilla/layers/KnowsCompositor.h"
|
||||
#include "mozilla/webrender/RenderDcompSurfaceTextureHost.h"
|
||||
#include "mozilla/webrender/WebRenderAPI.h"
|
||||
|
||||
extern mozilla::LazyLogModule gDcompSurface;
|
||||
#define LOG(...) MOZ_LOG(gDcompSurface, LogLevel::Debug, (__VA_ARGS__))
|
||||
|
||||
namespace mozilla::layers {
|
||||
|
||||
already_AddRefed<TextureHost> CreateTextureHostDcompSurface(
|
||||
const SurfaceDescriptor& aDesc, ISurfaceAllocator* aDeallocator,
|
||||
LayersBackend aBackend, TextureFlags aFlags) {
|
||||
MOZ_ASSERT(aDesc.type() == SurfaceDescriptor::TSurfaceDescriptorDcompSurface);
|
||||
RefPtr<TextureHost> result = new DcompSurfaceHandleHost(
|
||||
aFlags, aDesc.get_SurfaceDescriptorDcompSurface());
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<TextureClient> DcompSurfaceTexture::CreateTextureClient(
|
||||
HANDLE aHandle, gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
KnowsCompositor* aKnowsCompositor) {
|
||||
RefPtr<TextureClient> textureClient = MakeAndAddRef<TextureClient>(
|
||||
new DcompSurfaceTexture(aHandle, aSize, aFormat), TextureFlags::NO_FLAGS,
|
||||
aKnowsCompositor->GetTextureForwarder());
|
||||
return textureClient.forget();
|
||||
}
|
||||
|
||||
DcompSurfaceTexture::~DcompSurfaceTexture() {
|
||||
LOG("Destroy DcompSurfaceTexture %p, close handle=%p", this, mHandle);
|
||||
CloseHandle(mHandle);
|
||||
}
|
||||
|
||||
bool DcompSurfaceTexture::Serialize(SurfaceDescriptor& aOutDescriptor) {
|
||||
aOutDescriptor = SurfaceDescriptorDcompSurface(ipc::FileDescriptor(mHandle),
|
||||
mSize, mFormat);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DcompSurfaceTexture::GetSubDescriptor(
|
||||
RemoteDecoderVideoSubDescriptor* aOutDesc) {
|
||||
*aOutDesc = SurfaceDescriptorDcompSurface(ipc::FileDescriptor(mHandle), mSize,
|
||||
mFormat);
|
||||
}
|
||||
|
||||
DcompSurfaceImage::DcompSurfaceImage(HANDLE aHandle, gfx::IntSize aSize,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
KnowsCompositor* aKnowsCompositor)
|
||||
: Image(nullptr, ImageFormat::DCOMP_SURFACE),
|
||||
mTextureClient(DcompSurfaceTexture::CreateTextureClient(
|
||||
aHandle, aSize, aFormat, aKnowsCompositor)) {
|
||||
// Dcomp surface supports DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
// DXGI_FORMAT_R8G8B8A8_UNORM and DXGI_FORMAT_R16G16B16A16_FLOAT
|
||||
MOZ_ASSERT(aFormat == gfx::SurfaceFormat::B8G8R8A8 ||
|
||||
aFormat == gfx::SurfaceFormat::R8G8B8A8);
|
||||
}
|
||||
|
||||
TextureClient* DcompSurfaceImage::GetTextureClient(
|
||||
KnowsCompositor* aKnowsCompositor) {
|
||||
return mTextureClient;
|
||||
}
|
||||
|
||||
DcompSurfaceHandleHost::DcompSurfaceHandleHost(
|
||||
TextureFlags aFlags, const SurfaceDescriptorDcompSurface& aDescriptor)
|
||||
: TextureHost(aFlags),
|
||||
mHandle(const_cast<ipc::FileDescriptor&>(aDescriptor.handle())
|
||||
.TakePlatformHandle()),
|
||||
mSize(aDescriptor.size()),
|
||||
mFormat(aDescriptor.format()) {
|
||||
LOG("Create DcompSurfaceHandleHost %p", this);
|
||||
}
|
||||
|
||||
DcompSurfaceHandleHost::~DcompSurfaceHandleHost() {
|
||||
LOG("Destroy DcompSurfaceHandleHost %p", this);
|
||||
}
|
||||
|
||||
void DcompSurfaceHandleHost::CreateRenderTexture(
|
||||
const wr::ExternalImageId& aExternalImageId) {
|
||||
LOG("DcompSurfaceHandleHost %p CreateRenderTexture, ext-id=%" PRIu64, this,
|
||||
wr::AsUint64(aExternalImageId));
|
||||
RefPtr<wr::RenderTextureHost> texture =
|
||||
new wr::RenderDcompSurfaceTextureHost(mHandle.get(), mSize, mFormat);
|
||||
wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId,
|
||||
texture.forget());
|
||||
}
|
||||
|
||||
void DcompSurfaceHandleHost::PushResourceUpdates(
|
||||
wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
|
||||
const Range<wr::ImageKey>& aImageKeys,
|
||||
const wr::ExternalImageId& aExternalImageId) {
|
||||
if (!gfx::gfxVars::UseWebRenderANGLE()) {
|
||||
MOZ_ASSERT_UNREACHABLE("Unexpected to be called without ANGLE");
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mHandle);
|
||||
MOZ_ASSERT(aImageKeys.length() == 1);
|
||||
auto method = aOp == TextureHost::ADD_IMAGE
|
||||
? &wr::TransactionBuilder::AddExternalImage
|
||||
: &wr::TransactionBuilder::UpdateExternalImage;
|
||||
wr::ImageDescriptor descriptor(mSize, GetFormat());
|
||||
// Prefer TextureExternal unless the backend requires TextureRect.
|
||||
TextureHost::NativeTexturePolicy policy =
|
||||
TextureHost::BackendNativeTexturePolicy(aResources.GetBackendType(),
|
||||
mSize);
|
||||
auto imageType = policy == TextureHost::NativeTexturePolicy::REQUIRE
|
||||
? wr::ExternalImageType::TextureHandle(
|
||||
wr::ImageBufferKind::TextureRect)
|
||||
: wr::ExternalImageType::TextureHandle(
|
||||
wr::ImageBufferKind::TextureExternal);
|
||||
LOG("DcompSurfaceHandleHost %p PushResourceUpdate, exi-id=%" PRIu64
|
||||
", type=%s",
|
||||
this, wr::AsUint64(aExternalImageId),
|
||||
policy == TextureHost::NativeTexturePolicy::REQUIRE ? "rect" : "ext");
|
||||
(aResources.*method)(aImageKeys[0], descriptor, aExternalImageId, imageType,
|
||||
0);
|
||||
}
|
||||
|
||||
void DcompSurfaceHandleHost::PushDisplayItems(
|
||||
wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds,
|
||||
const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
|
||||
const Range<wr::ImageKey>& aImageKeys, PushDisplayItemFlagSet aFlags) {
|
||||
if (!gfx::gfxVars::UseWebRenderANGLE()) {
|
||||
MOZ_ASSERT_UNREACHABLE("Unexpected to be called without ANGLE");
|
||||
return;
|
||||
}
|
||||
LOG("DcompSurfaceHandleHost %p PushDisplayItems", this);
|
||||
MOZ_ASSERT(aImageKeys.length() == 1);
|
||||
aBuilder.PushImage(
|
||||
aBounds, aClip, true, false, aFilter, aImageKeys[0],
|
||||
!(mFlags & TextureFlags::NON_PREMULTIPLIED),
|
||||
wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f},
|
||||
aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE),
|
||||
SupportsExternalCompositing(aBuilder.GetBackendType()));
|
||||
}
|
||||
|
||||
} // namespace mozilla::layers
|
||||
|
||||
#undef LOG
|
||||
131
gfx/layers/DcompSurfaceImage.h
Normal file
131
gfx/layers/DcompSurfaceImage.h
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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_LAYER_DCOMP_SURFACE_IMAGE_H
|
||||
#define GFX_LAYER_DCOMP_SURFACE_IMAGE_H
|
||||
|
||||
#include "ImageContainer.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/layers/TextureHost.h"
|
||||
|
||||
namespace mozilla::wr {
|
||||
class DisplayListBuilder;
|
||||
class TransactionBuilder;
|
||||
} // namespace mozilla::wr
|
||||
|
||||
namespace mozilla::layers {
|
||||
|
||||
already_AddRefed<TextureHost> CreateTextureHostDcompSurface(
|
||||
const SurfaceDescriptor& aDesc, ISurfaceAllocator* aDeallocator,
|
||||
LayersBackend aBackend, TextureFlags aFlags);
|
||||
|
||||
/**
|
||||
* A texture data wrapping a dcomp surface handle, which is provided by the
|
||||
* media foundation media engine. We won't be able to control real texture data
|
||||
* because that is protected by the media engine.
|
||||
*/
|
||||
class DcompSurfaceTexture final : public TextureData {
|
||||
public:
|
||||
static already_AddRefed<TextureClient> CreateTextureClient(
|
||||
HANDLE aHandle, gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
KnowsCompositor* aKnowsCompositor);
|
||||
|
||||
~DcompSurfaceTexture();
|
||||
|
||||
bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
|
||||
void GetSubDescriptor(RemoteDecoderVideoSubDescriptor* aOutDesc) override;
|
||||
void FillInfo(TextureData::Info& aInfo) const {
|
||||
aInfo.size = mSize;
|
||||
aInfo.supportsMoz2D = false;
|
||||
aInfo.canExposeMappedData = false;
|
||||
aInfo.hasSynchronization = false;
|
||||
}
|
||||
bool Lock(OpenMode) override { return true; }
|
||||
void Unlock() override {}
|
||||
void Deallocate(LayersIPCChannel* aAllocator) override {}
|
||||
|
||||
private:
|
||||
DcompSurfaceTexture(HANDLE aHandle, gfx::IntSize aSize,
|
||||
gfx::SurfaceFormat aFormat)
|
||||
: mHandle(aHandle), mSize(aSize), mFormat(aFormat) {}
|
||||
|
||||
const HANDLE mHandle;
|
||||
const gfx::IntSize mSize;
|
||||
const gfx::SurfaceFormat mFormat;
|
||||
};
|
||||
|
||||
/**
|
||||
* A image data which holds a dcomp texture which is provided by the media
|
||||
* foundation media engine. As the real texture is protected, it does not
|
||||
* support being accessed as a source surface.
|
||||
*/
|
||||
class DcompSurfaceImage : public Image {
|
||||
public:
|
||||
DcompSurfaceImage(HANDLE aHandle, gfx::IntSize aSize,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
KnowsCompositor* aKnowsCompositor);
|
||||
virtual ~DcompSurfaceImage() = default;
|
||||
|
||||
already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gfx::IntSize GetSize() const { return mTextureClient->GetSize(); };
|
||||
|
||||
TextureClient* GetTextureClient(KnowsCompositor* aKnowsCompositor) override;
|
||||
|
||||
private:
|
||||
RefPtr<TextureClient> mTextureClient;
|
||||
};
|
||||
|
||||
/**
|
||||
* A Texture host living in GPU process which owns a dcomp surface handle which
|
||||
* is provided by the media foundation media engine.
|
||||
*/
|
||||
class DcompSurfaceHandleHost : public TextureHost {
|
||||
public:
|
||||
DcompSurfaceHandleHost(TextureFlags aFlags,
|
||||
const SurfaceDescriptorDcompSurface& aDescriptor);
|
||||
|
||||
gfx::SurfaceFormat GetFormat() const override { return mFormat; }
|
||||
|
||||
gfx::IntSize GetSize() const override { return mSize; }
|
||||
|
||||
const char* Name() override { return "DcompSurfaceHandleHost"; }
|
||||
|
||||
already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CreateRenderTexture(
|
||||
const wr::ExternalImageId& aExternalImageId) override;
|
||||
|
||||
void PushResourceUpdates(
|
||||
wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
|
||||
const Range<wr::ImageKey>& aImageKeys,
|
||||
const wr::ExternalImageId& aExternalImageId) override;
|
||||
|
||||
void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
|
||||
const wr::LayoutRect& aBounds,
|
||||
const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
|
||||
const Range<wr::ImageKey>& aImageKeys,
|
||||
PushDisplayItemFlagSet aFlags) override;
|
||||
|
||||
bool SupportsExternalCompositing(WebRenderBackend aBackend) override {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
~DcompSurfaceHandleHost();
|
||||
|
||||
// Handle will be closed automatically when `UniqueFileHandle` gets destroyed.
|
||||
const mozilla::UniqueFileHandle mHandle;
|
||||
const gfx::IntSize mSize;
|
||||
const gfx::SurfaceFormat mFormat;
|
||||
};
|
||||
|
||||
} // namespace mozilla::layers
|
||||
|
||||
#endif // GFX_LAYER_DCOMP_SURFACE_IMAGE_H
|
||||
|
|
@ -98,6 +98,12 @@ enum class ImageFormat {
|
|||
* data in DMABUF memory. Used by VAAPI decoder on Linux.
|
||||
*/
|
||||
DMABUF,
|
||||
|
||||
/**
|
||||
* A Wrapper of Dcomp surface handle, used by the windows media foundation
|
||||
* media engine playback.
|
||||
*/
|
||||
DCOMP_SURFACE,
|
||||
};
|
||||
|
||||
enum class StereoMode {
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@
|
|||
|
||||
#ifdef XP_WIN
|
||||
# include "mozilla/layers/TextureD3D11.h"
|
||||
# ifdef MOZ_WMF_MEDIA_ENGINE
|
||||
# include "mozilla/layers/DcompSurfaceImage.h"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
|
|
@ -211,6 +214,12 @@ already_AddRefed<TextureHost> TextureHost::Create(
|
|||
case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr:
|
||||
result = CreateTextureHostD3D11(aDesc, aDeallocator, aBackend, aFlags);
|
||||
break;
|
||||
# ifdef MOZ_WMF_MEDIA_ENGINE
|
||||
case SurfaceDescriptor::TSurfaceDescriptorDcompSurface:
|
||||
result =
|
||||
CreateTextureHostDcompSurface(aDesc, aDeallocator, aBackend, aFlags);
|
||||
break;
|
||||
# endif
|
||||
#endif
|
||||
case SurfaceDescriptor::TSurfaceDescriptorRecorded: {
|
||||
const SurfaceDescriptorRecorded& desc =
|
||||
|
|
|
|||
|
|
@ -105,12 +105,18 @@ namespace layers {
|
|||
bool hasAlpha;
|
||||
};
|
||||
|
||||
[Comparable] struct SurfaceDescriptorDcompSurface {
|
||||
FileDescriptor handle;
|
||||
IntSize size;
|
||||
SurfaceFormat format;
|
||||
};
|
||||
|
||||
[Comparable] union RemoteDecoderVideoSubDescriptor {
|
||||
SurfaceDescriptorD3D10;
|
||||
SurfaceDescriptorDXGIYCbCr;
|
||||
SurfaceDescriptorDMABuf;
|
||||
SurfaceDescriptorMacIOSurface;
|
||||
SurfaceDescriptorDcompSurface;
|
||||
null_t;
|
||||
};
|
||||
|
||||
|
|
@ -190,6 +196,7 @@ namespace layers {
|
|||
SurfaceDescriptorGPUVideo;
|
||||
SurfaceDescriptorRecorded;
|
||||
SurfaceDescriptorRemoteTexture;
|
||||
SurfaceDescriptorDcompSurface;
|
||||
null_t;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,13 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows":
|
|||
"d3d11/CompositorD3D11.cpp",
|
||||
"d3d11/DeviceAttachmentsD3D11.cpp",
|
||||
]
|
||||
if CONFIG["MOZ_WMF_MEDIA_ENGINE"]:
|
||||
EXPORTS.mozilla.layers += [
|
||||
"DcompSurfaceImage.h",
|
||||
]
|
||||
UNIFIED_SOURCES += [
|
||||
"DcompSurfaceImage.cpp",
|
||||
]
|
||||
|
||||
EXPORTS.gfxipc += [
|
||||
"ipc/ShadowLayerUtils.h",
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "mozilla/StaticPrefs_gfx.h"
|
||||
#include "mozilla/webrender/RenderD3D11TextureHost.h"
|
||||
#include "mozilla/webrender/RenderDcompSurfaceTextureHost.h"
|
||||
#include "mozilla/webrender/RenderTextureHost.h"
|
||||
#include "mozilla/webrender/RenderThread.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
|
|
@ -38,6 +39,10 @@ namespace wr {
|
|||
extern LazyLogModule gRenderThreadLog;
|
||||
#define LOG(...) MOZ_LOG(gRenderThreadLog, LogLevel::Debug, (__VA_ARGS__))
|
||||
|
||||
#define LOG_H(msg, ...) \
|
||||
MOZ_LOG(gDcompSurface, LogLevel::Debug, \
|
||||
("DCSurfaceHandle=%p, " msg, this, ##__VA_ARGS__))
|
||||
|
||||
UniquePtr<GpuOverlayInfo> DCLayerTree::sGpuOverlayInfo;
|
||||
|
||||
/* static */
|
||||
|
|
@ -497,9 +502,9 @@ void DCLayerTree::CreateExternalSurface(wr::NativeSurfaceId aId,
|
|||
auto it = mDCSurfaces.find(aId);
|
||||
MOZ_RELEASE_ASSERT(it == mDCSurfaces.end());
|
||||
|
||||
auto surface = MakeUnique<DCSurfaceVideo>(aIsOpaque, this);
|
||||
auto surface = MakeUnique<DCExternalSurfaceWrapper>(aIsOpaque, this);
|
||||
if (!surface->Initialize()) {
|
||||
gfxCriticalNote << "Failed to initialize DCSurfaceVideo: "
|
||||
gfxCriticalNote << "Failed to initialize DCExternalSurfaceWrapper: "
|
||||
<< wr::AsUint64(aId);
|
||||
return;
|
||||
}
|
||||
|
|
@ -530,10 +535,60 @@ void DCLayerTree::AttachExternalImage(wr::NativeSurfaceId aId,
|
|||
wr::ExternalImageId aExternalImage) {
|
||||
auto surface_it = mDCSurfaces.find(aId);
|
||||
MOZ_RELEASE_ASSERT(surface_it != mDCSurfaces.end());
|
||||
auto* surfaceVideo = surface_it->second->AsDCSurfaceVideo();
|
||||
MOZ_RELEASE_ASSERT(surfaceVideo);
|
||||
surface_it->second->AttachExternalImage(aExternalImage);
|
||||
}
|
||||
|
||||
surfaceVideo->AttachExternalImage(aExternalImage);
|
||||
void DCExternalSurfaceWrapper::AttachExternalImage(
|
||||
wr::ExternalImageId aExternalImage) {
|
||||
if (auto* surface = EnsureSurfaceForExternalImage(aExternalImage)) {
|
||||
surface->AttachExternalImage(aExternalImage);
|
||||
}
|
||||
}
|
||||
|
||||
DCSurface* DCExternalSurfaceWrapper::EnsureSurfaceForExternalImage(
|
||||
wr::ExternalImageId aExternalImage) {
|
||||
if (mSurface) {
|
||||
return mSurface.get();
|
||||
}
|
||||
|
||||
// Create a new surface based on the texture type.
|
||||
RenderTextureHost* texture =
|
||||
RenderThread::Get()->GetRenderTexture(aExternalImage);
|
||||
if (texture && texture->AsRenderDXGITextureHost()) {
|
||||
mSurface.reset(new DCSurfaceVideo(mIsOpaque, mDCLayerTree));
|
||||
if (!mSurface->Initialize()) {
|
||||
gfxCriticalNote << "Failed to initialize DCSurfaceVideo: "
|
||||
<< wr::AsUint64(aExternalImage);
|
||||
mSurface = nullptr;
|
||||
}
|
||||
} else if (texture && texture->AsRenderDcompSurfaceTextureHost()) {
|
||||
mSurface.reset(new DCSurfaceHandle(mIsOpaque, mDCLayerTree));
|
||||
if (!mSurface->Initialize()) {
|
||||
gfxCriticalNote << "Failed to initialize DCSurfaceHandle: "
|
||||
<< wr::AsUint64(aExternalImage);
|
||||
mSurface = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (mSurface) {
|
||||
// Add surface's visual which will contain video data to our root visual.
|
||||
mVisual->AddVisual(mSurface->GetVisual(), TRUE, nullptr);
|
||||
} else {
|
||||
gfxCriticalNote << "Failed to create a surface for external image: "
|
||||
<< gfx::hexa(texture);
|
||||
}
|
||||
return mSurface.get();
|
||||
}
|
||||
|
||||
void DCExternalSurfaceWrapper::PresentExternalSurface(gfx::Matrix& aTransform) {
|
||||
MOZ_ASSERT(mSurface);
|
||||
if (auto* surface = mSurface->AsDCSurfaceVideo()) {
|
||||
if (surface->CalculateSwapChainSize(aTransform)) {
|
||||
surface->PresentVideo();
|
||||
}
|
||||
} else if (auto* surface = mSurface->AsDCSurfaceHandle()) {
|
||||
surface->PresentSurfaceHandle();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
@ -560,19 +615,14 @@ void DCLayerTree::AddSurface(wr::NativeSurfaceId aId,
|
|||
gfx::Matrix transform(aTransform.m11, aTransform.m12, aTransform.m21,
|
||||
aTransform.m22, aTransform.m41, aTransform.m42);
|
||||
|
||||
auto* surfaceVideo = surface->AsDCSurfaceVideo();
|
||||
if (surfaceVideo) {
|
||||
if (surfaceVideo->CalculateSwapChainSize(transform)) {
|
||||
surfaceVideo->PresentVideo();
|
||||
}
|
||||
}
|
||||
surface->PresentExternalSurface(transform);
|
||||
|
||||
transform.PreTranslate(-virtualOffset.x, -virtualOffset.y);
|
||||
|
||||
// The DirectComposition API applies clipping *before* any transforms/offset,
|
||||
// whereas we want the clip applied after.
|
||||
// Right now, we only support rectilinear transforms, and then we transform
|
||||
// our clip into pre-transform coordinate space for it to be applied there.
|
||||
// The DirectComposition API applies clipping *before* any
|
||||
// transforms/offset, whereas we want the clip applied after. Right now, we
|
||||
// only support rectilinear transforms, and then we transform our clip into
|
||||
// pre-transform coordinate space for it to be applied there.
|
||||
// DirectComposition does have an option for pre-transform clipping, if you
|
||||
// create an explicit IDCompositionEffectGroup object and set a 3D transform
|
||||
// on that. I suspect that will perform worse though, so we should only do
|
||||
|
|
@ -692,7 +742,8 @@ bool DCLayerTree::EnsureVideoProcessor(const gfx::IntSize& aInputSize,
|
|||
}
|
||||
|
||||
// Reduce power cosumption
|
||||
// By default, the driver might perform certain processing tasks automatically
|
||||
// By default, the driver might perform certain processing tasks
|
||||
// automatically
|
||||
mVideoContext->VideoProcessorSetStreamAutoProcessingMode(mVideoProcessor, 0,
|
||||
FALSE);
|
||||
|
||||
|
|
@ -1219,6 +1270,67 @@ void DCSurfaceVideo::ReleaseDecodeSwapChainResources() {
|
|||
}
|
||||
}
|
||||
|
||||
DCSurfaceHandle::DCSurfaceHandle(bool aIsOpaque, DCLayerTree* aDCLayerTree)
|
||||
: DCSurface(wr::DeviceIntSize{}, wr::DeviceIntPoint{}, aIsOpaque,
|
||||
aDCLayerTree) {}
|
||||
|
||||
void DCSurfaceHandle::AttachExternalImage(wr::ExternalImageId aExternalImage) {
|
||||
RenderTextureHost* texture =
|
||||
RenderThread::Get()->GetRenderTexture(aExternalImage);
|
||||
RenderDcompSurfaceTextureHost* renderTexture =
|
||||
texture ? texture->AsRenderDcompSurfaceTextureHost() : nullptr;
|
||||
if (!renderTexture) {
|
||||
gfxCriticalNote << "Unsupported RenderTexture for DCSurfaceHandle: "
|
||||
<< gfx::hexa(texture);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto handle = renderTexture->GetDcompSurfaceHandle();
|
||||
if (GetSurfaceHandle() == handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_H("AttachExternalImage, ext-image=%" PRIu64 ", texture=%p, handle=%p",
|
||||
wr::AsUint64(aExternalImage), renderTexture, handle);
|
||||
mDcompTextureHost = renderTexture;
|
||||
}
|
||||
|
||||
HANDLE DCSurfaceHandle::GetSurfaceHandle() const {
|
||||
if (mDcompTextureHost) {
|
||||
return mDcompTextureHost->GetDcompSurfaceHandle();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IDCompositionSurface* DCSurfaceHandle::EnsureSurface() {
|
||||
if (auto* surface = mDcompTextureHost->GetSurface()) {
|
||||
return surface;
|
||||
}
|
||||
|
||||
// Texture host hasn't created the surface yet, ask it to create a new one.
|
||||
RefPtr<IDCompositionDevice> device;
|
||||
HRESULT hr = mDCLayerTree->GetCompositionDevice()->QueryInterface(
|
||||
(IDCompositionDevice**)getter_AddRefs(device));
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalNote
|
||||
<< "Failed to convert IDCompositionDevice2 to IDCompositionDevice: "
|
||||
<< gfx::hexa(hr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return mDcompTextureHost->CreateSurfaceFromDevice(device);
|
||||
}
|
||||
|
||||
void DCSurfaceHandle::PresentSurfaceHandle() {
|
||||
LOG_H("PresentSurfaceHandle");
|
||||
if (IDCompositionSurface* surface = EnsureSurface()) {
|
||||
LOG_H("Set surface %p to visual", surface);
|
||||
mVisual->SetContent(surface);
|
||||
} else {
|
||||
mVisual->SetContent(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
DCTile::DCTile(DCLayerTree* aDCLayerTree) : mDCLayerTree(aDCLayerTree) {}
|
||||
|
||||
DCTile::~DCTile() {}
|
||||
|
|
@ -1332,3 +1444,5 @@ void DCLayerTree::DestroyEGLSurface() {
|
|||
|
||||
} // namespace wr
|
||||
} // namespace mozilla
|
||||
|
||||
#undef LOG_H
|
||||
|
|
|
|||
|
|
@ -51,7 +51,9 @@ namespace wr {
|
|||
class DCTile;
|
||||
class DCSurface;
|
||||
class DCSurfaceVideo;
|
||||
class DCSurfaceHandle;
|
||||
class RenderTextureHost;
|
||||
class RenderDcompSurfaceTextureHost;
|
||||
|
||||
struct GpuOverlayInfo {
|
||||
bool mSupportsOverlays = false;
|
||||
|
|
@ -247,7 +249,16 @@ class DCSurface {
|
|||
void UpdateAllocatedRect();
|
||||
void DirtyAllocatedRect();
|
||||
|
||||
// Implement these if the inherited surface supports attaching external image.
|
||||
virtual void AttachExternalImage(wr::ExternalImageId aExternalImage) {
|
||||
MOZ_RELEASE_ASSERT(true, "Not support attaching external image");
|
||||
}
|
||||
virtual void PresentExternalSurface(gfx::Matrix& aTransform) {
|
||||
MOZ_RELEASE_ASSERT(true, "Not support presenting external surface");
|
||||
}
|
||||
|
||||
virtual DCSurfaceVideo* AsDCSurfaceVideo() { return nullptr; }
|
||||
virtual DCSurfaceHandle* AsDCSurfaceHandle() { return nullptr; }
|
||||
|
||||
protected:
|
||||
DCLayerTree* mDCLayerTree;
|
||||
|
|
@ -272,11 +283,41 @@ class DCSurface {
|
|||
RefPtr<IDCompositionVirtualSurface> mVirtualSurface;
|
||||
};
|
||||
|
||||
/**
|
||||
* A wrapper surface which can contain either a DCVideo or a DCSurfaceHandle.
|
||||
*/
|
||||
class DCExternalSurfaceWrapper : public DCSurface {
|
||||
public:
|
||||
DCExternalSurfaceWrapper(bool aIsOpaque, DCLayerTree* aDCLayerTree)
|
||||
: DCSurface(wr::DeviceIntSize{}, wr::DeviceIntPoint{}, false /* opaque */,
|
||||
aDCLayerTree),
|
||||
mIsOpaque(aIsOpaque) {}
|
||||
~DCExternalSurfaceWrapper() = default;
|
||||
|
||||
void AttachExternalImage(wr::ExternalImageId aExternalImage) override;
|
||||
|
||||
void PresentExternalSurface(gfx::Matrix& aTransform) override;
|
||||
|
||||
DCSurfaceVideo* AsDCSurfaceVideo() override {
|
||||
return mSurface ? mSurface->AsDCSurfaceVideo() : nullptr;
|
||||
}
|
||||
|
||||
DCSurfaceHandle* AsDCSurfaceHandle() override {
|
||||
return mSurface ? mSurface->AsDCSurfaceHandle() : nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
DCSurface* EnsureSurfaceForExternalImage(wr::ExternalImageId aExternalImage);
|
||||
|
||||
UniquePtr<DCSurface> mSurface;
|
||||
const bool mIsOpaque;
|
||||
};
|
||||
|
||||
class DCSurfaceVideo : public DCSurface {
|
||||
public:
|
||||
DCSurfaceVideo(bool aIsOpaque, DCLayerTree* aDCLayerTree);
|
||||
|
||||
void AttachExternalImage(wr::ExternalImageId aExternalImage);
|
||||
void AttachExternalImage(wr::ExternalImageId aExternalImage) override;
|
||||
bool CalculateSwapChainSize(gfx::Matrix& aTransform);
|
||||
void PresentVideo();
|
||||
|
||||
|
|
@ -301,6 +342,28 @@ class DCSurfaceVideo : public DCSurface {
|
|||
RefPtr<RenderTextureHost> mPrevTexture;
|
||||
};
|
||||
|
||||
/**
|
||||
* A DC surface contains a IDCompositionSurface that is directly constructed by
|
||||
* a handle. This is used by the Media Foundataion media engine, which would
|
||||
* store the decoded video content in the surface.
|
||||
*/
|
||||
class DCSurfaceHandle : public DCSurface {
|
||||
public:
|
||||
DCSurfaceHandle(bool aIsOpaque, DCLayerTree* aDCLayerTree);
|
||||
~DCSurfaceHandle() = default;
|
||||
|
||||
void AttachExternalImage(wr::ExternalImageId aExternalImage) override;
|
||||
void PresentSurfaceHandle();
|
||||
|
||||
DCSurfaceHandle* AsDCSurfaceHandle() override { return this; }
|
||||
|
||||
protected:
|
||||
HANDLE GetSurfaceHandle() const;
|
||||
IDCompositionSurface* EnsureSurface();
|
||||
|
||||
RefPtr<RenderDcompSurfaceTextureHost> mDcompTextureHost;
|
||||
};
|
||||
|
||||
class DCTile {
|
||||
public:
|
||||
explicit DCTile(DCLayerTree* aDCLayerTree);
|
||||
|
|
|
|||
50
gfx/webrender_bindings/RenderDcompSurfaceTextureHost.cpp
Normal file
50
gfx/webrender_bindings/RenderDcompSurfaceTextureHost.cpp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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 "RenderDcompSurfaceTextureHost.h"
|
||||
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT _WIN32_WINNT_WINBLUE
|
||||
#undef NTDDI_VERSION
|
||||
#define NTDDI_VERSION NTDDI_WINBLUE
|
||||
|
||||
#include <dcomp.h>
|
||||
|
||||
#define LOG(msg, ...) \
|
||||
MOZ_LOG(gDcompSurface, LogLevel::Debug, \
|
||||
("RenderDcompSurfaceTextureHost=%p, handle=%p, size=[%u,%u] " msg, \
|
||||
this, this->mHandle, this->mSize.Width(), this->mSize.Height(), \
|
||||
##__VA_ARGS__))
|
||||
|
||||
namespace mozilla::wr {
|
||||
|
||||
RenderDcompSurfaceTextureHost::RenderDcompSurfaceTextureHost(
|
||||
HANDLE aHandle, gfx::IntSize aSize, gfx::SurfaceFormat aFormat)
|
||||
: mHandle(aHandle), mSize(aSize), mFormat(aFormat) {
|
||||
MOZ_ASSERT(aHandle && aHandle != INVALID_HANDLE_VALUE);
|
||||
}
|
||||
|
||||
IDCompositionSurface* RenderDcompSurfaceTextureHost::CreateSurfaceFromDevice(
|
||||
IDCompositionDevice* aDevice) {
|
||||
// Already created surface, no need to recreate it again.
|
||||
if (mDcompSurface) {
|
||||
return mDcompSurface;
|
||||
}
|
||||
|
||||
auto* surface =
|
||||
static_cast<IDCompositionSurface**>(getter_AddRefs(mDcompSurface));
|
||||
auto hr = aDevice->CreateSurfaceFromHandle(
|
||||
mHandle, reinterpret_cast<IUnknown**>(surface));
|
||||
if (FAILED(hr)) {
|
||||
LOG("Failed to create surface from Dcomp handle %p, hr=%lx", mHandle, hr);
|
||||
return nullptr;
|
||||
}
|
||||
LOG("Created surface %p correctly", surface);
|
||||
return mDcompSurface;
|
||||
}
|
||||
|
||||
} // namespace mozilla::wr
|
||||
|
||||
#undef LOG
|
||||
70
gfx/webrender_bindings/RenderDcompSurfaceTextureHost.h
Normal file
70
gfx/webrender_bindings/RenderDcompSurfaceTextureHost.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/* -*- Mode: C++; tab-width: ; 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 MOZILLA_GFX_RENDERDCOMPSURFACETEXTUREHOST_H
|
||||
#define MOZILLA_GFX_RENDERDCOMPSURFACETEXTUREHOST_H
|
||||
|
||||
#include "GLTypes.h"
|
||||
#include "RenderTextureHostSWGL.h"
|
||||
#include "mozilla/webrender/RenderThread.h"
|
||||
|
||||
struct IDCompositionDevice;
|
||||
struct IDCompositionSurface;
|
||||
|
||||
inline mozilla::LazyLogModule gDcompSurface("DcompSurface");
|
||||
|
||||
namespace mozilla::wr {
|
||||
|
||||
/**
|
||||
* A render texture host is responsible to create a dcomp surface from an
|
||||
* existing dcomp handle. Currently usage is that MF media engine will create
|
||||
* a surface handle from another remote process, and we reconstruct the surface
|
||||
* and use it in the DCLayerTree in the GPU process.
|
||||
*/
|
||||
class RenderDcompSurfaceTextureHost final : public RenderTextureHostSWGL {
|
||||
public:
|
||||
RenderDcompSurfaceTextureHost(HANDLE aHandle, gfx::IntSize aSize,
|
||||
gfx::SurfaceFormat aFormat);
|
||||
|
||||
// RenderTextureHost
|
||||
RenderDcompSurfaceTextureHost* AsRenderDcompSurfaceTextureHost() override {
|
||||
return this;
|
||||
}
|
||||
|
||||
// RenderTextureHostSWGL
|
||||
gfx::SurfaceFormat GetFormat() const override { return mFormat; }
|
||||
gfx::ColorDepth GetColorDepth() const override {
|
||||
return gfx::ColorDepth::COLOR_8;
|
||||
}
|
||||
size_t GetPlaneCount() const override { return 1; }
|
||||
bool MapPlane(RenderCompositor* aCompositor, uint8_t aChannelIndex,
|
||||
PlaneInfo& aPlaneInfo) override {
|
||||
return false;
|
||||
}
|
||||
void UnmapPlanes() override {}
|
||||
gfx::YUVRangedColorSpace GetYUVColorSpace() const override {
|
||||
return gfx::YUVRangedColorSpace::GbrIdentity;
|
||||
}
|
||||
size_t Bytes() override { return 0; }
|
||||
|
||||
gfx::IntSize GetSize() const { return mSize; };
|
||||
|
||||
HANDLE GetDcompSurfaceHandle() const { return mHandle; }
|
||||
|
||||
// Not thread-safe. They should only be called on the renderer thread on the
|
||||
// GPU process.
|
||||
IDCompositionSurface* CreateSurfaceFromDevice(IDCompositionDevice* aDevice);
|
||||
IDCompositionSurface* GetSurface() const { return mDcompSurface; };
|
||||
|
||||
private:
|
||||
const HANDLE mHandle;
|
||||
const gfx::IntSize mSize;
|
||||
const gfx::SurfaceFormat mFormat;
|
||||
RefPtr<IDCompositionSurface> mDcompSurface;
|
||||
};
|
||||
|
||||
} // namespace mozilla::wr
|
||||
|
||||
#endif // MOZILLA_GFX_RENDERDCOMPSURFACETEXTUREHOST_H
|
||||
|
|
@ -28,6 +28,7 @@ class RenderAndroidSurfaceTextureHost;
|
|||
class RenderCompositor;
|
||||
class RenderDXGITextureHost;
|
||||
class RenderDXGIYCbCrTextureHost;
|
||||
class RenderDcompSurfaceTextureHost;
|
||||
class RenderMacIOSurfaceTextureHost;
|
||||
class RenderBufferTextureHost;
|
||||
class RenderTextureHostSWGL;
|
||||
|
|
@ -88,6 +89,10 @@ class RenderTextureHost {
|
|||
|
||||
virtual RenderTextureHostSWGL* AsRenderTextureHostSWGL() { return nullptr; }
|
||||
|
||||
virtual RenderDcompSurfaceTextureHost* AsRenderDcompSurfaceTextureHost() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~RenderTextureHost();
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,14 @@ RenderTextureHostWrapper::AsRenderDXGIYCbCrTextureHost() {
|
|||
return mTextureHost->AsRenderDXGIYCbCrTextureHost();
|
||||
}
|
||||
|
||||
RenderDcompSurfaceTextureHost*
|
||||
RenderTextureHostWrapper::AsRenderDcompSurfaceTextureHost() {
|
||||
if (!mTextureHost) {
|
||||
return nullptr;
|
||||
}
|
||||
return mTextureHost->AsRenderDcompSurfaceTextureHost();
|
||||
}
|
||||
|
||||
RenderTextureHostSWGL* RenderTextureHostWrapper::EnsureRenderTextureHostSWGL()
|
||||
const {
|
||||
if (!mTextureHost) {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class RenderTextureHostWrapper final : public RenderTextureHostSWGL {
|
|||
RenderMacIOSurfaceTextureHost* AsRenderMacIOSurfaceTextureHost() override;
|
||||
RenderDXGITextureHost* AsRenderDXGITextureHost() override;
|
||||
RenderDXGIYCbCrTextureHost* AsRenderDXGIYCbCrTextureHost() override;
|
||||
RenderDcompSurfaceTextureHost* AsRenderDcompSurfaceTextureHost() override;
|
||||
|
||||
// RenderTextureHostSWGL
|
||||
size_t GetPlaneCount() const override;
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ if CONFIG["MOZ_ENABLE_D3D10_LAYER"]:
|
|||
"RenderCompositorANGLE.h",
|
||||
"RenderCompositorD3D11SWGL.h",
|
||||
"RenderD3D11TextureHost.h",
|
||||
"RenderDcompSurfaceTextureHost.h",
|
||||
]
|
||||
UNIFIED_SOURCES += [
|
||||
"RenderCompositorD3D11SWGL.cpp",
|
||||
|
|
@ -87,6 +88,7 @@ if CONFIG["MOZ_ENABLE_D3D10_LAYER"]:
|
|||
SOURCES += [
|
||||
"DCLayerTree.cpp",
|
||||
"RenderCompositorANGLE.cpp",
|
||||
"RenderDcompSurfaceTextureHost.cpp",
|
||||
]
|
||||
|
||||
if CONFIG["MOZ_WAYLAND"]:
|
||||
|
|
|
|||
Loading…
Reference in a new issue