mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
357 lines
12 KiB
C++
357 lines
12 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
|
|
/* 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 "GLBlitHelper.h"
|
|
|
|
#include <d3d11.h>
|
|
|
|
#include "GLContext.h"
|
|
#include "GLLibraryEGL.h"
|
|
#include "GPUVideoImage.h"
|
|
#include "ScopedGLHelpers.h"
|
|
|
|
#include "mozilla/layers/D3D11YCbCrImage.h"
|
|
#include "mozilla/layers/TextureD3D11.h"
|
|
|
|
namespace mozilla {
|
|
namespace gl {
|
|
|
|
static EGLStreamKHR
|
|
StreamFromD3DTexture(ID3D11Texture2D* const texD3D, const EGLAttrib* const postAttribs)
|
|
{
|
|
auto& egl = sEGLLibrary;
|
|
if (!egl.IsExtensionSupported(GLLibraryEGL::NV_stream_consumer_gltexture_yuv) ||
|
|
!egl.IsExtensionSupported(GLLibraryEGL::ANGLE_stream_producer_d3d_texture_nv12))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
const auto& display = egl.Display();
|
|
const auto stream = egl.fCreateStreamKHR(display, nullptr);
|
|
MOZ_ASSERT(stream);
|
|
if (!stream)
|
|
return 0;
|
|
bool ok = true;
|
|
MOZ_ALWAYS_TRUE( ok &= bool(egl.fStreamConsumerGLTextureExternalAttribsNV(display,
|
|
stream,
|
|
nullptr)) );
|
|
MOZ_ALWAYS_TRUE( ok &= bool(egl.fCreateStreamProducerD3DTextureNV12ANGLE(display,
|
|
stream,
|
|
nullptr)) );
|
|
MOZ_ALWAYS_TRUE( ok &= bool(egl.fStreamPostD3DTextureNV12ANGLE(display, stream,
|
|
texD3D,
|
|
postAttribs)) );
|
|
if (ok)
|
|
return stream;
|
|
|
|
(void)egl.fDestroyStreamKHR(display, stream);
|
|
return 0;
|
|
}
|
|
|
|
static RefPtr<ID3D11Texture2D>
|
|
OpenSharedTexture(ID3D11Device* const d3d, const WindowsHandle handle)
|
|
{
|
|
RefPtr<ID3D11Texture2D> tex;
|
|
auto hr = d3d->OpenSharedResource((HANDLE)handle, __uuidof(ID3D11Texture2D),
|
|
(void**)(ID3D11Texture2D**)getter_AddRefs(tex));
|
|
if (FAILED(hr)) {
|
|
gfxCriticalError() << "Error code from OpenSharedResource: " << gfx::hexa(hr);
|
|
return nullptr;
|
|
}
|
|
return tex;
|
|
}
|
|
|
|
// -------------------------------------
|
|
|
|
class BindAnglePlanes final
|
|
{
|
|
const GLBlitHelper& mParent;
|
|
const uint8_t mNumPlanes;
|
|
const ScopedSaveMultiTex mMultiTex;
|
|
GLuint mTempTexs[3];
|
|
EGLStreamKHR mStreams[3];
|
|
RefPtr<IDXGIKeyedMutex> mMutexList[3];
|
|
bool mSuccess;
|
|
|
|
public:
|
|
BindAnglePlanes(const GLBlitHelper* const parent, const uint8_t numPlanes,
|
|
const RefPtr<ID3D11Texture2D>* const texD3DList,
|
|
const EGLAttrib* const* postAttribsList = nullptr)
|
|
: mParent(*parent)
|
|
, mNumPlanes(numPlanes)
|
|
, mMultiTex(mParent.mGL, mNumPlanes, LOCAL_GL_TEXTURE_EXTERNAL)
|
|
, mTempTexs{0}
|
|
, mStreams{0}
|
|
, mSuccess(true)
|
|
{
|
|
MOZ_RELEASE_ASSERT(numPlanes >= 1 && numPlanes <= 3);
|
|
|
|
const auto& gl = mParent.mGL;
|
|
auto& egl = sEGLLibrary;
|
|
const auto& display = egl.Display();
|
|
|
|
gl->fGenTextures(numPlanes, mTempTexs);
|
|
|
|
for (uint8_t i = 0; i < mNumPlanes; i++) {
|
|
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
|
|
gl->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, mTempTexs[i]);
|
|
const EGLAttrib* postAttribs = nullptr;
|
|
if (postAttribsList) {
|
|
postAttribs = postAttribsList[i];
|
|
}
|
|
mStreams[i] = StreamFromD3DTexture(texD3DList[i], postAttribs);
|
|
mSuccess &= bool(mStreams[i]);
|
|
}
|
|
|
|
if (mSuccess) {
|
|
for (uint8_t i = 0; i < mNumPlanes; i++) {
|
|
MOZ_ALWAYS_TRUE( egl.fStreamConsumerAcquireKHR(display, mStreams[i]) );
|
|
|
|
auto& mutex = mMutexList[i];
|
|
texD3DList[i]->QueryInterface(IID_IDXGIKeyedMutex,
|
|
(void**)getter_AddRefs(mutex));
|
|
if (mutex) {
|
|
const auto hr = mutex->AcquireSync(0, 100);
|
|
if (FAILED(hr)) {
|
|
NS_WARNING("BindAnglePlanes failed to acquire KeyedMutex.");
|
|
mSuccess = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
~BindAnglePlanes()
|
|
{
|
|
const auto& gl = mParent.mGL;
|
|
auto& egl = sEGLLibrary;
|
|
const auto& display = egl.Display();
|
|
|
|
if (mSuccess) {
|
|
for (uint8_t i = 0; i < mNumPlanes; i++) {
|
|
MOZ_ALWAYS_TRUE( egl.fStreamConsumerReleaseKHR(display, mStreams[i]) );
|
|
if (mMutexList[i]) {
|
|
mMutexList[i]->ReleaseSync(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (uint8_t i = 0; i < mNumPlanes; i++) {
|
|
(void)egl.fDestroyStreamKHR(display, mStreams[i]);
|
|
}
|
|
|
|
gl->fDeleteTextures(mNumPlanes, mTempTexs);
|
|
}
|
|
|
|
const bool& Success() const { return mSuccess; }
|
|
};
|
|
|
|
// -------------------------------------
|
|
|
|
ID3D11Device*
|
|
GLBlitHelper::GetD3D11() const
|
|
{
|
|
if (mD3D11)
|
|
return mD3D11;
|
|
|
|
if (!mGL->IsANGLE())
|
|
return nullptr;
|
|
|
|
auto& egl = sEGLLibrary;
|
|
EGLDeviceEXT deviceEGL = 0;
|
|
MOZ_ALWAYS_TRUE( egl.fQueryDisplayAttribEXT(egl.Display(), LOCAL_EGL_DEVICE_EXT,
|
|
(EGLAttrib*)&deviceEGL) );
|
|
if (!egl.fQueryDeviceAttribEXT(deviceEGL, LOCAL_EGL_D3D11_DEVICE_ANGLE,
|
|
(EGLAttrib*)(ID3D11Device**)getter_AddRefs(mD3D11)))
|
|
{
|
|
MOZ_ASSERT(false, "d3d9?");
|
|
return nullptr;
|
|
}
|
|
return mD3D11;
|
|
}
|
|
|
|
// -------------------------------------
|
|
|
|
bool
|
|
GLBlitHelper::BlitImage(layers::GPUVideoImage* const srcImage,
|
|
const gfx::IntSize& destSize, const OriginPos destOrigin) const
|
|
{
|
|
const auto& data = srcImage->GetData();
|
|
if (!data)
|
|
return false;
|
|
|
|
const auto& desc = data->SD();
|
|
const auto& subdescUnion = desc.subdesc();
|
|
switch (subdescUnion.type()) {
|
|
case subdescUnion.TSurfaceDescriptorD3D10:
|
|
{
|
|
const auto& subdesc = subdescUnion.get_SurfaceDescriptorD3D10();
|
|
return BlitDescriptor(subdesc, destSize, destOrigin);
|
|
}
|
|
case subdescUnion.TSurfaceDescriptorDXGIYCbCr:
|
|
{
|
|
const auto& subdesc = subdescUnion.get_SurfaceDescriptorDXGIYCbCr();
|
|
|
|
const auto& clipSize = subdesc.size();
|
|
const auto& ySize = subdesc.sizeY();
|
|
const auto& uvSize = subdesc.sizeCbCr();
|
|
const auto& colorSpace = subdesc.yUVColorSpace();
|
|
|
|
const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height);
|
|
|
|
const WindowsHandle handles[3] = {
|
|
subdesc.handleY(),
|
|
subdesc.handleCb(),
|
|
subdesc.handleCr()
|
|
};
|
|
return BlitAngleYCbCr(handles, clipRect, ySize, uvSize, colorSpace, destSize,
|
|
destOrigin);
|
|
}
|
|
default:
|
|
gfxCriticalError() << "Unhandled subdesc type: " << uint32_t(subdescUnion.type());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// -------------------------------------
|
|
|
|
bool
|
|
GLBlitHelper::BlitImage(layers::D3D11YCbCrImage* const srcImage,
|
|
const gfx::IntSize& destSize, const OriginPos destOrigin) const
|
|
{
|
|
const auto& data = srcImage->GetData();
|
|
if (!data)
|
|
return false;
|
|
|
|
const auto& clipRect = srcImage->mPictureRect;
|
|
const auto& colorSpace = srcImage->mColorSpace;
|
|
|
|
const WindowsHandle handles[3] = {
|
|
(WindowsHandle)data->mHandles[0],
|
|
(WindowsHandle)data->mHandles[1],
|
|
(WindowsHandle)data->mHandles[2]
|
|
};
|
|
return BlitAngleYCbCr(handles, srcImage->mPictureRect, srcImage->mYSize,
|
|
srcImage->mCbCrSize, srcImage->mColorSpace, destSize,
|
|
destOrigin);
|
|
}
|
|
|
|
// -------------------------------------
|
|
|
|
bool
|
|
GLBlitHelper::BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc,
|
|
const gfx::IntSize& destSize,
|
|
const OriginPos destOrigin) const
|
|
{
|
|
const auto& d3d = GetD3D11();
|
|
if (!d3d)
|
|
return false;
|
|
|
|
const auto& handle = desc.handle();
|
|
const auto& format = desc.format();
|
|
const auto& clipSize = desc.size();
|
|
|
|
const auto srcOrigin = OriginPos::BottomLeft;
|
|
const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height);
|
|
const auto colorSpace = YUVColorSpace::BT601;
|
|
|
|
if (format != gfx::SurfaceFormat::NV12) {
|
|
gfxCriticalError() << "Non-NV12 format for SurfaceDescriptorD3D10: "
|
|
<< uint32_t(format);
|
|
return false;
|
|
}
|
|
|
|
const auto tex = OpenSharedTexture(d3d, handle);
|
|
if (!tex) {
|
|
MOZ_ASSERT(false, "Get a nullptr from OpenSharedResource.");
|
|
return false;
|
|
}
|
|
const RefPtr<ID3D11Texture2D> texList[2] = { tex, tex };
|
|
const EGLAttrib postAttribs0[] = {
|
|
LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0,
|
|
LOCAL_EGL_NONE
|
|
};
|
|
const EGLAttrib postAttribs1[] = {
|
|
LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 1,
|
|
LOCAL_EGL_NONE
|
|
};
|
|
const EGLAttrib* const postAttribsList[2] = { postAttribs0, postAttribs1 };
|
|
// /layers/d3d11/CompositorD3D11.cpp uses bt601 for EffectTypes::NV12.
|
|
//return BlitAngleNv12(tex, YUVColorSpace::BT601, destSize, destOrigin);
|
|
|
|
const BindAnglePlanes bindPlanes(this, 2, texList, postAttribsList);
|
|
|
|
D3D11_TEXTURE2D_DESC texDesc = {0};
|
|
tex->GetDesc(&texDesc);
|
|
|
|
const gfx::IntSize ySize(texDesc.Width, texDesc.Height);
|
|
const gfx::IntSize divisors(2, 2);
|
|
MOZ_ASSERT(ySize.width % divisors.width == 0);
|
|
MOZ_ASSERT(ySize.height % divisors.height == 0);
|
|
const gfx::IntSize uvSize(ySize.width / divisors.width,
|
|
ySize.height / divisors.height);
|
|
|
|
const bool yFlip = destOrigin != srcOrigin;
|
|
const DrawBlitProg::BaseArgs baseArgs = {
|
|
SubRectMat3(clipRect, ySize),
|
|
yFlip, destSize, Nothing()
|
|
};
|
|
const DrawBlitProg::YUVArgs yuvArgs = {
|
|
SubRectMat3(clipRect, uvSize, divisors),
|
|
colorSpace
|
|
};
|
|
|
|
const auto& prog = GetDrawBlitProg({kFragHeader_TexExt, kFragBody_NV12});
|
|
MOZ_RELEASE_ASSERT(prog);
|
|
prog->Draw(baseArgs, &yuvArgs);
|
|
return true;
|
|
}
|
|
|
|
// --
|
|
|
|
bool
|
|
GLBlitHelper::BlitAngleYCbCr(const WindowsHandle (&handleList)[3],
|
|
const gfx::IntRect& clipRect,
|
|
const gfx::IntSize& ySize, const gfx::IntSize& uvSize,
|
|
const YUVColorSpace colorSpace, const gfx::IntSize& destSize,
|
|
const OriginPos destOrigin) const
|
|
{
|
|
const auto& d3d = GetD3D11();
|
|
if (!d3d)
|
|
return false;
|
|
|
|
const auto srcOrigin = OriginPos::BottomLeft;
|
|
|
|
gfx::IntSize divisors;
|
|
if (!GuessDivisors(ySize, uvSize, &divisors))
|
|
return false;
|
|
|
|
const RefPtr<ID3D11Texture2D> texList[3] = {
|
|
OpenSharedTexture(d3d, handleList[0]),
|
|
OpenSharedTexture(d3d, handleList[1]),
|
|
OpenSharedTexture(d3d, handleList[2])
|
|
};
|
|
const BindAnglePlanes bindPlanes(this, 3, texList);
|
|
|
|
const bool yFlip = destOrigin != srcOrigin;
|
|
const DrawBlitProg::BaseArgs baseArgs = {
|
|
SubRectMat3(clipRect, ySize),
|
|
yFlip, destSize, Nothing()
|
|
};
|
|
const DrawBlitProg::YUVArgs yuvArgs = {
|
|
SubRectMat3(clipRect, uvSize, divisors),
|
|
colorSpace
|
|
};
|
|
|
|
const auto& prog = GetDrawBlitProg({kFragHeader_TexExt, kFragBody_PlanarYUV});
|
|
MOZ_RELEASE_ASSERT(prog);
|
|
prog->Draw(baseArgs, &yuvArgs);
|
|
return true;
|
|
}
|
|
|
|
} // namespace gl
|
|
} // namespace mozilla
|