mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 17:25:36 +00:00
5d101602fb
With DXVA2 hardware-video-decoding, the RendererOGL should have a synchronization mechanism to prevent the flickering of video texture. Create a SyncObject in RendererOGL to do the texture synchronization. The WebRenderAPI also exposes the RendererOGL's SyncHandle to WebRenderBridgeParent. Then, the WebRenderBridgeParent could pass this SyncHandle to the video decoding module for texture synchronization. MozReview-Commit-ID: toQ2mO5fzG
236 lines
6.3 KiB
C++
236 lines
6.3 KiB
C++
/* -*- 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 "RendererOGL.h"
|
|
#include "GLContext.h"
|
|
#include "GLContextProvider.h"
|
|
#include "mozilla/gfx/Logging.h"
|
|
#include "mozilla/layers/CompositorBridgeParent.h"
|
|
#include "mozilla/layers/CompositorThread.h"
|
|
#include "mozilla/webrender/RenderBufferTextureHost.h"
|
|
#include "mozilla/webrender/RenderTextureHostOGL.h"
|
|
#include "mozilla/widget/CompositorWidget.h"
|
|
|
|
namespace mozilla {
|
|
namespace wr {
|
|
|
|
wr::WrExternalImage LockExternalImage(void* aObj, wr::WrExternalImageId aId, uint8_t aChannelIndex)
|
|
{
|
|
RendererOGL* renderer = reinterpret_cast<RendererOGL*>(aObj);
|
|
RenderTextureHost* texture = renderer->GetRenderTexture(aId);
|
|
|
|
if (texture->AsBufferTextureHost()) {
|
|
RenderBufferTextureHost* bufferTexture = texture->AsBufferTextureHost();
|
|
MOZ_ASSERT(bufferTexture);
|
|
bufferTexture->Lock();
|
|
RenderBufferTextureHost::RenderBufferData data =
|
|
bufferTexture->GetBufferDataForRender(aChannelIndex);
|
|
|
|
return RawDataToWrExternalImage(data.mData, data.mBufferSize);
|
|
} else {
|
|
// texture handle case
|
|
RenderTextureHostOGL* textureOGL = texture->AsTextureHostOGL();
|
|
MOZ_ASSERT(textureOGL);
|
|
|
|
textureOGL->SetGLContext(renderer->mGL);
|
|
textureOGL->Lock();
|
|
gfx::IntSize size = textureOGL->GetSize(aChannelIndex);
|
|
|
|
return NativeTextureToWrExternalImage(textureOGL->GetGLHandle(aChannelIndex),
|
|
0, 0,
|
|
size.width, size.height);
|
|
}
|
|
}
|
|
|
|
void UnlockExternalImage(void* aObj, wr::WrExternalImageId aId, uint8_t aChannelIndex)
|
|
{
|
|
RendererOGL* renderer = reinterpret_cast<RendererOGL*>(aObj);
|
|
RenderTextureHost* texture = renderer->GetRenderTexture(aId);
|
|
MOZ_ASSERT(texture);
|
|
texture->Unlock();
|
|
}
|
|
|
|
RendererOGL::RendererOGL(RefPtr<RenderThread>&& aThread,
|
|
RefPtr<gl::GLContext>&& aGL,
|
|
RefPtr<widget::CompositorWidget>&& aWidget,
|
|
wr::WindowId aWindowId,
|
|
wr::Renderer* aRenderer,
|
|
layers::CompositorBridgeParentBase* aBridge)
|
|
: mThread(aThread)
|
|
, mGL(aGL)
|
|
, mWidget(aWidget)
|
|
, mRenderer(aRenderer)
|
|
, mBridge(aBridge)
|
|
, mWindowId(aWindowId)
|
|
{
|
|
MOZ_ASSERT(mThread);
|
|
MOZ_ASSERT(mGL);
|
|
MOZ_ASSERT(mWidget);
|
|
MOZ_ASSERT(mRenderer);
|
|
MOZ_ASSERT(mBridge);
|
|
MOZ_COUNT_CTOR(RendererOGL);
|
|
|
|
#ifdef XP_WIN
|
|
if (aGL->IsANGLE()) {
|
|
gl::GLLibraryEGL* egl = &gl::sEGLLibrary;
|
|
|
|
// Fetch the D3D11 device.
|
|
EGLDeviceEXT eglDevice = nullptr;
|
|
egl->fQueryDisplayAttribEXT(egl->Display(), LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice);
|
|
MOZ_ASSERT(eglDevice);
|
|
ID3D11Device* device = nullptr;
|
|
egl->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE, (EGLAttrib*)&device);
|
|
MOZ_ASSERT(device);
|
|
|
|
mSyncObject = layers::SyncObjectHost::CreateSyncObjectHost(device);
|
|
if (mSyncObject) {
|
|
if (!mSyncObject->Init()) {
|
|
// Some errors occur. Clear the mSyncObject here.
|
|
// Then, there will be no texture synchronization.
|
|
mSyncObject = nullptr;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
RendererOGL::~RendererOGL()
|
|
{
|
|
MOZ_COUNT_DTOR(RendererOGL);
|
|
if (!mGL->MakeCurrent()) {
|
|
gfxCriticalNote << "Failed to make render context current during destroying.";
|
|
// Leak resources!
|
|
return;
|
|
}
|
|
wr_renderer_delete(mRenderer);
|
|
}
|
|
|
|
wr::WrExternalImageHandler
|
|
RendererOGL::GetExternalImageHandler()
|
|
{
|
|
return wr::WrExternalImageHandler {
|
|
this,
|
|
LockExternalImage,
|
|
UnlockExternalImage,
|
|
};
|
|
}
|
|
|
|
void
|
|
RendererOGL::Update()
|
|
{
|
|
wr_renderer_update(mRenderer);
|
|
}
|
|
|
|
bool
|
|
RendererOGL::Render()
|
|
{
|
|
if (!mGL->MakeCurrent()) {
|
|
gfxCriticalNote << "Failed to make render context current, can't draw.";
|
|
// XXX This could cause oom in webrender since pending_texture_updates is not handled.
|
|
// It needs to be addressed.
|
|
return false;
|
|
}
|
|
|
|
mozilla::widget::WidgetRenderingContext widgetContext;
|
|
|
|
#if defined(XP_MACOSX)
|
|
widgetContext.mGL = mGL;
|
|
// TODO: we don't have a notion of compositor here.
|
|
//#elif defined(MOZ_WIDGET_ANDROID)
|
|
// widgetContext.mCompositor = mCompositor;
|
|
#endif
|
|
|
|
if (!mWidget->PreRender(&widgetContext)) {
|
|
// XXX This could cause oom in webrender since pending_texture_updates is not handled.
|
|
// It needs to be addressed.
|
|
return false;
|
|
}
|
|
// XXX set clear color if MOZ_WIDGET_ANDROID is defined.
|
|
|
|
auto size = mWidget->GetClientSize();
|
|
|
|
if (mSyncObject) {
|
|
// XXX: if the synchronization is failed, we should handle the device reset.
|
|
mSyncObject->Synchronize();
|
|
}
|
|
|
|
wr_renderer_render(mRenderer, size.width, size.height);
|
|
|
|
mGL->SwapBuffers();
|
|
mWidget->PostRender(&widgetContext);
|
|
|
|
#if defined(ENABLE_FRAME_LATENCY_LOG)
|
|
if (mFrameStartTime) {
|
|
uint32_t latencyMs = round((TimeStamp::Now() - mFrameStartTime).ToMilliseconds());
|
|
printf_stderr("generate frame latencyMs latencyMs %d\n", latencyMs);
|
|
}
|
|
// Clear frame start time
|
|
mFrameStartTime = TimeStamp();
|
|
#endif
|
|
|
|
// TODO: Flush pending actions such as texture deletions/unlocks and
|
|
// textureHosts recycling.
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
RendererOGL::Pause()
|
|
{
|
|
#ifdef MOZ_WIDGET_ANDROID
|
|
if (!mGL || mGL->IsDestroyed()) {
|
|
return;
|
|
}
|
|
// ReleaseSurface internally calls MakeCurrent.
|
|
mGL->ReleaseSurface();
|
|
#endif
|
|
}
|
|
|
|
bool
|
|
RendererOGL::Resume()
|
|
{
|
|
#ifdef MOZ_WIDGET_ANDROID
|
|
if (!mGL || mGL->IsDestroyed()) {
|
|
return false;
|
|
}
|
|
// RenewSurface internally calls MakeCurrent.
|
|
return mGL->RenewSurface(mWidget);
|
|
#else
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
RendererOGL::SetProfilerEnabled(bool aEnabled)
|
|
{
|
|
wr_renderer_set_profiler_enabled(mRenderer, aEnabled);
|
|
}
|
|
|
|
void
|
|
RendererOGL::SetFrameStartTime(const TimeStamp& aTime)
|
|
{
|
|
if (mFrameStartTime) {
|
|
// frame start time is already set. This could happen when multiple
|
|
// generate frame requests are merged by webrender.
|
|
return;
|
|
}
|
|
mFrameStartTime = aTime;
|
|
}
|
|
|
|
wr::WrRenderedEpochs*
|
|
RendererOGL::FlushRenderedEpochs()
|
|
{
|
|
return wr_renderer_flush_rendered_epochs(mRenderer);
|
|
}
|
|
|
|
RenderTextureHost*
|
|
RendererOGL::GetRenderTexture(wr::WrExternalImageId aExternalImageId)
|
|
{
|
|
return mThread->GetRenderTexture(aExternalImageId);
|
|
}
|
|
|
|
} // namespace wr
|
|
} // namespace mozilla
|