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