1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "RendererOGL.h"
8 #include "GLContext.h"
9 #include "mozilla/gfx/Logging.h"
10 #include "mozilla/gfx/gfxVars.h"
11 #include "mozilla/layers/CompositorBridgeParent.h"
12 #include "mozilla/layers/CompositorThread.h"
13 #include "mozilla/layers/LayersTypes.h"
14 #include "mozilla/webrender/RenderCompositor.h"
15 #include "mozilla/webrender/RenderTextureHost.h"
16 #include "mozilla/widget/CompositorWidget.h"
17 
18 namespace mozilla {
19 namespace wr {
20 
LockExternalImage(void * aObj,wr::WrExternalImageId aId,uint8_t aChannelIndex)21 wr::WrExternalImage LockExternalImage(void* aObj, wr::WrExternalImageId aId,
22                                       uint8_t aChannelIndex) {
23   RendererOGL* renderer = reinterpret_cast<RendererOGL*>(aObj);
24   RenderTextureHost* texture = renderer->GetRenderTexture(aId);
25   MOZ_ASSERT(texture);
26   if (!texture) {
27     gfxCriticalNote << "Failed to lock ExternalImage for extId:"
28                     << AsUint64(aId);
29     return InvalidToWrExternalImage();
30   }
31   return texture->Lock(aChannelIndex, renderer->gl());
32 }
33 
UnlockExternalImage(void * aObj,wr::WrExternalImageId aId,uint8_t aChannelIndex)34 void UnlockExternalImage(void* aObj, wr::WrExternalImageId aId,
35                          uint8_t aChannelIndex) {
36   RendererOGL* renderer = reinterpret_cast<RendererOGL*>(aObj);
37   RenderTextureHost* texture = renderer->GetRenderTexture(aId);
38   MOZ_ASSERT(texture);
39   if (!texture) {
40     return;
41   }
42   texture->Unlock();
43 }
44 
RendererOGL(RefPtr<RenderThread> && aThread,UniquePtr<RenderCompositor> aCompositor,wr::WindowId aWindowId,wr::Renderer * aRenderer,layers::CompositorBridgeParentBase * aBridge)45 RendererOGL::RendererOGL(RefPtr<RenderThread>&& aThread,
46                          UniquePtr<RenderCompositor> aCompositor,
47                          wr::WindowId aWindowId, wr::Renderer* aRenderer,
48                          layers::CompositorBridgeParentBase* aBridge)
49     : mThread(aThread),
50       mCompositor(Move(aCompositor)),
51       mRenderer(aRenderer),
52       mBridge(aBridge),
53       mWindowId(aWindowId),
54       mDebugFlags({0}) {
55   MOZ_ASSERT(mThread);
56   MOZ_ASSERT(mCompositor);
57   MOZ_ASSERT(mRenderer);
58   MOZ_ASSERT(mBridge);
59   MOZ_COUNT_CTOR(RendererOGL);
60 }
61 
~RendererOGL()62 RendererOGL::~RendererOGL() {
63   MOZ_COUNT_DTOR(RendererOGL);
64   if (!mCompositor->gl()->MakeCurrent()) {
65     gfxCriticalNote
66         << "Failed to make render context current during destroying.";
67     // Leak resources!
68     return;
69   }
70   wr_renderer_delete(mRenderer);
71 }
72 
GetExternalImageHandler()73 wr::WrExternalImageHandler RendererOGL::GetExternalImageHandler() {
74   return wr::WrExternalImageHandler{
75       this,
76       LockExternalImage,
77       UnlockExternalImage,
78   };
79 }
80 
Update()81 void RendererOGL::Update() {
82   uint32_t flags = gfx::gfxVars::WebRenderDebugFlags();
83   if (mDebugFlags.mBits != flags) {
84     mDebugFlags.mBits = flags;
85     wr_renderer_set_debug_flags(mRenderer, mDebugFlags);
86   }
87 
88   if (gl()->MakeCurrent()) {
89     wr_renderer_update(mRenderer);
90   }
91 }
92 
UpdateAndRender(bool aReadback)93 bool RendererOGL::UpdateAndRender(bool aReadback) {
94   uint32_t flags = gfx::gfxVars::WebRenderDebugFlags();
95   // Disable debug flags during readback
96   if (aReadback) {
97     flags = 0;
98   }
99 
100   if (mDebugFlags.mBits != flags) {
101     mDebugFlags.mBits = flags;
102     wr_renderer_set_debug_flags(mRenderer, mDebugFlags);
103   }
104 
105   mozilla::widget::WidgetRenderingContext widgetContext;
106 
107 #if defined(XP_MACOSX)
108   widgetContext.mGL = mCompositor->gl();
109 // TODO: we don't have a notion of compositor here.
110 //#elif defined(MOZ_WIDGET_ANDROID)
111 //  widgetContext.mCompositor = mCompositor;
112 #endif
113 
114   if (!mCompositor->GetWidget()->PreRender(&widgetContext)) {
115     // XXX This could cause oom in webrender since pending_texture_updates is
116     // not handled. It needs to be addressed.
117     return false;
118   }
119   // XXX set clear color if MOZ_WIDGET_ANDROID is defined.
120 
121   if (!mCompositor->BeginFrame()) {
122     return false;
123   }
124 
125   wr_renderer_update(mRenderer);
126 
127   auto size = mCompositor->GetBufferSize();
128 
129   if (!wr_renderer_render(mRenderer, size.width, size.height)) {
130     NotifyWebRenderError(WebRenderError::RENDER);
131   }
132 
133   mCompositor->EndFrame();
134 
135   mCompositor->GetWidget()->PostRender(&widgetContext);
136 
137 #if defined(ENABLE_FRAME_LATENCY_LOG)
138   if (mFrameStartTime) {
139     uint32_t latencyMs =
140         round((TimeStamp::Now() - mFrameStartTime).ToMilliseconds());
141     printf_stderr("generate frame latencyMs latencyMs %d\n", latencyMs);
142   }
143   // Clear frame start time
144   mFrameStartTime = TimeStamp();
145 #endif
146 
147   // TODO: Flush pending actions such as texture deletions/unlocks and
148   //       textureHosts recycling.
149 
150   return true;
151 }
152 
Pause()153 void RendererOGL::Pause() { mCompositor->Pause(); }
154 
Resume()155 bool RendererOGL::Resume() { return mCompositor->Resume(); }
156 
GetSyncObject() const157 layers::SyncObjectHost* RendererOGL::GetSyncObject() const {
158   return mCompositor->GetSyncObject();
159 }
160 
gl() const161 gl::GLContext* RendererOGL::gl() const { return mCompositor->gl(); }
162 
SetFrameStartTime(const TimeStamp & aTime)163 void RendererOGL::SetFrameStartTime(const TimeStamp& aTime) {
164   if (mFrameStartTime) {
165     // frame start time is already set. This could happen when multiple
166     // generate frame requests are merged by webrender.
167     return;
168   }
169   mFrameStartTime = aTime;
170 }
171 
FlushPipelineInfo()172 wr::WrPipelineInfo* RendererOGL::FlushPipelineInfo() {
173   return wr_renderer_flush_pipeline_info(mRenderer);
174 }
175 
GetRenderTexture(wr::WrExternalImageId aExternalImageId)176 RenderTextureHost* RendererOGL::GetRenderTexture(
177     wr::WrExternalImageId aExternalImageId) {
178   return mThread->GetRenderTexture(aExternalImageId);
179 }
180 
DoNotifyWebRenderError(layers::CompositorBridgeParentBase * aBridge,WebRenderError aError)181 static void DoNotifyWebRenderError(layers::CompositorBridgeParentBase* aBridge,
182                                    WebRenderError aError) {
183   aBridge->NotifyWebRenderError(aError);
184 }
185 
NotifyWebRenderError(WebRenderError aError)186 void RendererOGL::NotifyWebRenderError(WebRenderError aError) {
187   layers::CompositorThreadHolder::Loop()->PostTask(
188       NewRunnableFunction("DoNotifyWebRenderErrorRunnable",
189                           &DoNotifyWebRenderError, mBridge, aError));
190 }
191 
192 }  // namespace wr
193 }  // namespace mozilla
194