Bug 1861516 - Remove Translations fastText LanguageIdEngine r=gregtatum
[gecko.git] / gfx / webrender_bindings / RenderCompositorOGLSWGL.cpp
blob14095bee89df0a7959fc893877c19770546b1a39
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
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file,
7 * You can obtain one at http://mozilla.org/MPL/2.0/. */
9 #include "RenderCompositorOGLSWGL.h"
11 #include "GLContext.h"
12 #include "GLContextEGL.h"
13 #include "mozilla/layers/BuildConstants.h"
14 #include "mozilla/layers/CompositorOGL.h"
15 #include "mozilla/layers/Effects.h"
16 #include "mozilla/layers/TextureHostOGL.h"
17 #include "mozilla/widget/CompositorWidget.h"
18 #include "OGLShaderProgram.h"
20 #ifdef MOZ_WIDGET_ANDROID
21 # include "mozilla/java/GeckoSurfaceTextureWrappers.h"
22 # include "mozilla/layers/AndroidHardwareBuffer.h"
23 # include "mozilla/webrender/RenderAndroidHardwareBufferTextureHost.h"
24 # include "mozilla/webrender/RenderAndroidSurfaceTextureHost.h"
25 # include "mozilla/widget/AndroidCompositorWidget.h"
26 # include <android/native_window.h>
27 # include <android/native_window_jni.h>
28 #endif
30 #ifdef MOZ_WIDGET_GTK
31 # include "mozilla/widget/GtkCompositorWidget.h"
32 # include <gdk/gdk.h>
33 # ifdef MOZ_X11
34 # include <gdk/gdkx.h>
35 # endif
36 #endif
38 namespace mozilla {
39 using namespace layers;
40 using namespace gfx;
41 namespace wr {
43 extern LazyLogModule gRenderThreadLog;
44 #define LOG(...) MOZ_LOG(gRenderThreadLog, LogLevel::Debug, (__VA_ARGS__))
46 UniquePtr<RenderCompositor> RenderCompositorOGLSWGL::Create(
47 const RefPtr<widget::CompositorWidget>& aWidget, nsACString& aError) {
48 if (!aWidget->GetCompositorOptions().AllowSoftwareWebRenderOGL()) {
49 return nullptr;
52 RefPtr<Compositor> compositor;
53 #ifdef MOZ_WIDGET_ANDROID
54 RefPtr<gl::GLContext> context =
55 RenderThread::Get()->SingletonGLForCompositorOGL();
56 if (!context) {
57 gfxCriticalNote << "SingletonGL does not exist for SWGL";
58 return nullptr;
60 auto programs = RenderThread::Get()->GetProgramsForCompositorOGL();
61 if (!programs) {
62 gfxCriticalNote << "Failed to get Programs for CompositorOGL for SWGL";
63 return nullptr;
66 nsCString log;
67 RefPtr<CompositorOGL> compositorOGL;
68 compositorOGL = new CompositorOGL(aWidget, /* aSurfaceWidth */ -1,
69 /* aSurfaceHeight */ -1,
70 /* aUseExternalSurfaceSize */ true);
71 if (!compositorOGL->Initialize(context, programs, &log)) {
72 gfxCriticalNote << "Failed to initialize CompositorOGL for SWGL: "
73 << log.get();
74 return nullptr;
76 compositor = compositorOGL;
77 #elif defined(MOZ_WIDGET_GTK)
78 nsCString log;
79 RefPtr<CompositorOGL> compositorOGL;
80 compositorOGL = new CompositorOGL(aWidget);
81 if (!compositorOGL->Initialize(&log)) {
82 gfxCriticalNote << "Failed to initialize CompositorOGL for SWGL: "
83 << log.get();
84 return nullptr;
86 compositor = compositorOGL;
87 #endif
89 if (!compositor) {
90 return nullptr;
93 void* ctx = wr_swgl_create_context();
94 if (!ctx) {
95 gfxCriticalNote << "Failed SWGL context creation for WebRender";
96 return nullptr;
99 return MakeUnique<RenderCompositorOGLSWGL>(compositor, aWidget, ctx);
102 RenderCompositorOGLSWGL::RenderCompositorOGLSWGL(
103 Compositor* aCompositor, const RefPtr<widget::CompositorWidget>& aWidget,
104 void* aContext)
105 : RenderCompositorLayersSWGL(aCompositor, aWidget, aContext) {
106 LOG("RenderCompositorOGLSWGL::RenderCompositorOGLSWGL()");
109 RenderCompositorOGLSWGL::~RenderCompositorOGLSWGL() {
110 LOG("RRenderCompositorOGLSWGL::~RenderCompositorOGLSWGL()");
111 #ifdef MOZ_WIDGET_ANDROID
112 java::GeckoSurfaceTexture::DestroyUnused((int64_t)GetGLContext());
113 DestroyEGLSurface();
114 #endif
117 gl::GLContext* RenderCompositorOGLSWGL::GetGLContext() {
118 return mCompositor->AsCompositorOGL()->gl();
121 bool RenderCompositorOGLSWGL::MakeCurrent() {
122 GetGLContext()->MakeCurrent();
123 #ifdef MOZ_WIDGET_ANDROID
124 if (GetGLContext()->GetContextType() == gl::GLContextType::EGL) {
125 gl::GLContextEGL::Cast(GetGLContext())->SetEGLSurfaceOverride(mEGLSurface);
127 #endif
128 RenderCompositorLayersSWGL::MakeCurrent();
129 return true;
132 EGLSurface RenderCompositorOGLSWGL::CreateEGLSurface() {
133 MOZ_ASSERT(GetGLContext()->GetContextType() == gl::GLContextType::EGL);
135 EGLSurface surface = EGL_NO_SURFACE;
136 surface = gl::GLContextEGL::CreateEGLSurfaceForCompositorWidget(
137 mWidget, gl::GLContextEGL::Cast(GetGLContext())->mSurfaceConfig);
138 if (surface == EGL_NO_SURFACE) {
139 const auto* renderThread = RenderThread::Get();
140 gfxCriticalNote << "Failed to create EGLSurface. "
141 << renderThread->RendererCount() << " renderers, "
142 << renderThread->ActiveRendererCount() << " active.";
145 // The subsequent render after creating a new surface must be a full render.
146 mFullRender = true;
148 return surface;
151 void RenderCompositorOGLSWGL::DestroyEGLSurface() {
152 MOZ_ASSERT(GetGLContext()->GetContextType() == gl::GLContextType::EGL);
154 const auto& gle = gl::GLContextEGL::Cast(GetGLContext());
155 const auto& egl = gle->mEgl;
157 // Release EGLSurface of back buffer before calling ResizeBuffers().
158 if (mEGLSurface) {
159 gle->SetEGLSurfaceOverride(EGL_NO_SURFACE);
160 if (!egl->fMakeCurrent(EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
161 const EGLint err = egl->mLib->fGetError();
162 gfxCriticalNote << "Error in eglMakeCurrent: " << gfx::hexa(err);
164 if (!egl->fDestroySurface(mEGLSurface)) {
165 const EGLint err = egl->mLib->fGetError();
166 gfxCriticalNote << "Error in eglDestroySurface: " << gfx::hexa(err);
168 mEGLSurface = EGL_NO_SURFACE;
172 bool RenderCompositorOGLSWGL::BeginFrame() {
173 MOZ_ASSERT(!mInFrame);
174 RenderCompositorLayersSWGL::BeginFrame();
176 #ifdef MOZ_WIDGET_ANDROID
177 java::GeckoSurfaceTexture::DestroyUnused((int64_t)GetGLContext());
178 GetGLContext()
179 ->MakeCurrent(); // DestroyUnused can change the current context!
180 #endif
182 return true;
185 RenderedFrameId RenderCompositorOGLSWGL::EndFrame(
186 const nsTArray<DeviceIntRect>& aDirtyRects) {
187 mFullRender = false;
189 return RenderCompositorLayersSWGL::EndFrame(aDirtyRects);
192 void RenderCompositorOGLSWGL::HandleExternalImage(
193 RenderTextureHost* aExternalImage, FrameSurface& aFrameSurface) {
194 MOZ_ASSERT(aExternalImage);
196 #ifdef MOZ_WIDGET_ANDROID
197 GLenum target =
198 LOCAL_GL_TEXTURE_EXTERNAL; // This is required by SurfaceTexture
199 GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
201 if (auto* host = aExternalImage->AsRenderAndroidSurfaceTextureHost()) {
202 host->UpdateTexImageIfNecessary();
204 // We need to hold the texture source separately from the effect,
205 // since the effect doesn't hold a strong reference.
206 RefPtr<SurfaceTextureSource> layer = new SurfaceTextureSource(
207 (TextureSourceProvider*)mCompositor, host->mSurfTex, host->mFormat,
208 target, wrapMode, host->mSize, host->mTransformOverride);
209 RefPtr<TexturedEffect> texturedEffect =
210 CreateTexturedEffect(host->mFormat, layer, aFrameSurface.mFilter,
211 /* isAlphaPremultiplied */ true);
213 gfx::Rect drawRect(0, 0, host->mSize.width, host->mSize.height);
215 EffectChain effect;
216 effect.mPrimaryEffect = texturedEffect;
217 mCompositor->DrawQuad(drawRect, aFrameSurface.mClipRect, effect, 1.0,
218 aFrameSurface.mTransform, drawRect);
219 } else if (auto* host =
220 aExternalImage->AsRenderAndroidHardwareBufferTextureHost()) {
221 // We need to hold the texture source separately from the effect,
222 // since the effect doesn't hold a strong reference.
223 RefPtr<AndroidHardwareBufferTextureSource> layer =
224 new AndroidHardwareBufferTextureSource(
225 (TextureSourceProvider*)mCompositor,
226 host->GetAndroidHardwareBuffer(),
227 host->GetAndroidHardwareBuffer()->mFormat, target, wrapMode,
228 host->GetSize());
229 RefPtr<TexturedEffect> texturedEffect = CreateTexturedEffect(
230 host->GetAndroidHardwareBuffer()->mFormat, layer, aFrameSurface.mFilter,
231 /* isAlphaPremultiplied */ true);
233 gfx::Rect drawRect(0, 0, host->GetSize().width, host->GetSize().height);
235 EffectChain effect;
236 effect.mPrimaryEffect = texturedEffect;
237 mCompositor->DrawQuad(drawRect, aFrameSurface.mClipRect, effect, 1.0,
238 aFrameSurface.mTransform, drawRect);
239 } else if (!aExternalImage->IsWrappingAsyncRemoteTexture()) {
240 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
242 #endif
245 void RenderCompositorOGLSWGL::GetCompositorCapabilities(
246 CompositorCapabilities* aCaps) {
247 RenderCompositor::GetCompositorCapabilities(aCaps);
249 // max_update_rects are not yet handled properly
250 aCaps->max_update_rects = 0;
253 bool RenderCompositorOGLSWGL::RequestFullRender() { return mFullRender; }
255 void RenderCompositorOGLSWGL::Pause() {
256 #ifdef MOZ_WIDGET_ANDROID
257 DestroyEGLSurface();
258 #elif defined(MOZ_WIDGET_GTK)
259 mCompositor->Pause();
260 #endif
263 bool RenderCompositorOGLSWGL::Resume() {
264 #ifdef MOZ_WIDGET_ANDROID
265 // Destroy EGLSurface if it exists.
266 DestroyEGLSurface();
268 auto size = GetBufferSize();
269 GLint maxTextureSize = 0;
270 GetGLContext()->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE,
271 (GLint*)&maxTextureSize);
273 // When window size is too big, hardware buffer allocation could fail.
274 if (maxTextureSize < size.width || maxTextureSize < size.height) {
275 gfxCriticalNote << "Too big ANativeWindow size(" << size.width << ", "
276 << size.height << ") MaxTextureSize " << maxTextureSize;
277 return false;
280 mEGLSurface = CreateEGLSurface();
281 if (mEGLSurface == EGL_NO_SURFACE) {
282 // Often when we fail to create an EGL surface it is because the
283 // Java Surface we have been provided is invalid. Therefore the on
284 // the first occurence we don't raise a WebRenderError and instead
285 // just return failure. This allows the widget a chance to request
286 // a new Java Surface. On subsequent failures, raising the
287 // WebRenderError will result in the compositor being recreated,
288 // falling back through webrender configurations, and eventually
289 // crashing if we still do not succeed.
290 if (!mHandlingNewSurfaceError) {
291 mHandlingNewSurfaceError = true;
292 } else {
293 RenderThread::Get()->HandleWebRenderError(WebRenderError::NEW_SURFACE);
295 return false;
297 mHandlingNewSurfaceError = false;
299 gl::GLContextEGL::Cast(GetGLContext())->SetEGLSurfaceOverride(mEGLSurface);
300 mCompositor->SetDestinationSurfaceSize(size.ToUnknownSize());
301 #elif defined(MOZ_WIDGET_GTK)
302 bool resumed = mCompositor->Resume();
303 if (!resumed) {
304 RenderThread::Get()->HandleWebRenderError(WebRenderError::NEW_SURFACE);
305 return false;
307 #endif
308 return true;
311 bool RenderCompositorOGLSWGL::IsPaused() {
312 #ifdef MOZ_WIDGET_ANDROID
313 return mEGLSurface == EGL_NO_SURFACE;
314 #endif
315 return false;
318 LayoutDeviceIntSize RenderCompositorOGLSWGL::GetBufferSize() {
319 return mWidget->GetClientSize();
322 UniquePtr<RenderCompositorLayersSWGL::Tile>
323 RenderCompositorOGLSWGL::DoCreateTile(Surface* aSurface) {
324 auto source = MakeRefPtr<TextureImageTextureSourceOGL>(
325 mCompositor->AsCompositorOGL(), layers::TextureFlags::NO_FLAGS);
327 return MakeUnique<TileOGL>(std::move(source), aSurface->TileSize());
330 bool RenderCompositorOGLSWGL::MaybeReadback(
331 const gfx::IntSize& aReadbackSize, const wr::ImageFormat& aReadbackFormat,
332 const Range<uint8_t>& aReadbackBuffer, bool* aNeedsYFlip) {
333 #ifdef MOZ_WIDGET_ANDROID
334 MOZ_ASSERT(aReadbackFormat == wr::ImageFormat::RGBA8);
335 const GLenum format = LOCAL_GL_RGBA;
336 #else
337 MOZ_ASSERT(aReadbackFormat == wr::ImageFormat::BGRA8);
338 const GLenum format = LOCAL_GL_BGRA;
339 #endif
341 GetGLContext()->fReadPixels(0, 0, aReadbackSize.width, aReadbackSize.height,
342 format, LOCAL_GL_UNSIGNED_BYTE,
343 &aReadbackBuffer[0]);
345 if (aNeedsYFlip) {
346 *aNeedsYFlip = true;
349 return true;
352 // This is a DataSourceSurface that represents a 0-based PBO for GLTextureImage.
353 class PBOUnpackSurface : public gfx::DataSourceSurface {
354 public:
355 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PBOUnpackSurface, override)
357 explicit PBOUnpackSurface(const gfx::IntSize& aSize) : mSize(aSize) {}
359 uint8_t* GetData() override { return nullptr; }
360 int32_t Stride() override { return mSize.width * sizeof(uint32_t); }
361 gfx::SurfaceType GetType() const override {
362 return gfx::SurfaceType::DATA_ALIGNED;
364 gfx::IntSize GetSize() const override { return mSize; }
365 gfx::SurfaceFormat GetFormat() const override {
366 return gfx::SurfaceFormat::B8G8R8A8;
369 // PBO offsets need to start from a 0 address, but DataSourceSurface::Map
370 // checks for failure by comparing the address against nullptr. Override Map
371 // to work around this.
372 bool Map(MapType, MappedSurface* aMappedSurface) override {
373 aMappedSurface->mData = GetData();
374 aMappedSurface->mStride = Stride();
375 return true;
378 void Unmap() override {}
380 private:
381 gfx::IntSize mSize;
384 RenderCompositorOGLSWGL::TileOGL::TileOGL(
385 RefPtr<layers::TextureImageTextureSourceOGL>&& aTexture,
386 const gfx::IntSize& aSize)
387 : mTexture(aTexture) {
388 auto* gl = mTexture->gl();
389 if (gl && gl->HasPBOState() && gl->MakeCurrent()) {
390 mSurface = new PBOUnpackSurface(aSize);
391 // Create a PBO large enough to encompass any valid rects within the tile.
392 gl->fGenBuffers(1, &mPBO);
393 gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPBO);
394 gl->fBufferData(LOCAL_GL_PIXEL_UNPACK_BUFFER,
395 mSurface->Stride() * aSize.height, nullptr,
396 LOCAL_GL_DYNAMIC_DRAW);
397 gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
398 } else {
399 // Couldn't allocate a PBO, so just use a memory surface instead.
400 mSurface = gfx::Factory::CreateDataSourceSurface(
401 aSize, gfx::SurfaceFormat::B8G8R8A8);
405 RenderCompositorOGLSWGL::TileOGL::~TileOGL() {
406 if (mPBO) {
407 auto* gl = mTexture->gl();
408 if (gl && gl->MakeCurrent()) {
409 gl->fDeleteBuffers(1, &mPBO);
410 mPBO = 0;
415 layers::DataTextureSource*
416 RenderCompositorOGLSWGL::TileOGL::GetTextureSource() {
417 return mTexture.get();
420 bool RenderCompositorOGLSWGL::TileOGL::Map(wr::DeviceIntRect aDirtyRect,
421 wr::DeviceIntRect aValidRect,
422 void** aData, int32_t* aStride) {
423 if (mPBO) {
424 auto* gl = mTexture->gl();
425 if (!gl) {
426 return false;
428 // Map the PBO, but only within the range of the buffer that spans from the
429 // linear start offset to the linear end offset. Since we don't care about
430 // the previous contents of the buffer, we can just tell OpenGL to
431 // invalidate the entire buffer, even though we're only mapping a sub-range.
432 gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPBO);
433 size_t stride = mSurface->Stride();
434 size_t offset =
435 stride * aValidRect.min.y + aValidRect.min.x * sizeof(uint32_t);
436 size_t length = stride * (aValidRect.height() - 1) +
437 (aValidRect.width()) * sizeof(uint32_t);
438 void* data = gl->fMapBufferRange(
439 LOCAL_GL_PIXEL_UNPACK_BUFFER, offset, length,
440 LOCAL_GL_MAP_WRITE_BIT | LOCAL_GL_MAP_INVALIDATE_BUFFER_BIT);
441 gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
442 if (!data) {
443 return false;
445 *aData = data;
446 *aStride = stride;
447 } else {
448 // No PBO is available, so just directly write to the memory surface.
449 gfx::DataSourceSurface::MappedSurface map;
450 if (!mSurface->Map(gfx::DataSourceSurface::READ_WRITE, &map)) {
451 return false;
453 // Verify that we're not somehow using a PBOUnpackSurface.
454 MOZ_ASSERT(map.mData != nullptr);
455 // glTex(Sub)Image on ES doesn't support arbitrary strides without
456 // the EXT_unpack_subimage extension. To avoid needing to make a
457 // copy of the data we'll always draw it with stride = bpp*width
458 // unless we're uploading the entire texture.
459 if (!mTexture->IsValid()) {
460 // If we don't have a texture we need to position our
461 // data in the correct spot because we're going to upload
462 // the entire surface
463 *aData = map.mData + aValidRect.min.y * map.mStride +
464 aValidRect.min.x * sizeof(uint32_t);
466 *aStride = map.mStride;
467 mSubSurface = nullptr;
468 } else {
469 // Otherwise, we can just use the top left as a scratch space
470 *aData = map.mData;
471 *aStride = aDirtyRect.width() * BytesPerPixel(mSurface->GetFormat());
472 mSubSurface = Factory::CreateWrappingDataSourceSurface(
473 (uint8_t*)*aData, *aStride,
474 IntSize(aDirtyRect.width(), aDirtyRect.height()),
475 mSurface->GetFormat());
478 return true;
481 void RenderCompositorOGLSWGL::TileOGL::Unmap(const gfx::IntRect& aDirtyRect) {
482 nsIntRegion dirty(aDirtyRect);
483 if (mPBO) {
484 // If there is a PBO, it must be unmapped before it can be sourced from.
485 // Leave the PBO bound before the call to Update so that the texture uploads
486 // will source from it.
487 auto* gl = mTexture->gl();
488 if (!gl) {
489 return;
491 gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPBO);
492 gl->fUnmapBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER);
493 mTexture->Update(mSurface, &dirty);
494 gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
495 } else {
496 if (mSubSurface) {
497 mSurface->Unmap();
498 // Our subsurface has a stride = aDirtyRect.width
499 // We use a negative offset to move it to match
500 // the dirty rect's top-left. These two offsets
501 // will cancel each other out by the time we reach
502 // TexSubImage.
503 IntPoint srcOffset = {0, 0};
504 IntPoint dstOffset = aDirtyRect.TopLeft();
505 // adjust the dirty region to be relative to the dstOffset
506 dirty.MoveBy(-dstOffset);
507 mTexture->Update(mSubSurface, &dirty, &srcOffset, &dstOffset);
508 mSubSurface = nullptr;
509 } else {
510 mSurface->Unmap();
511 mTexture->Update(mSurface, &dirty);
516 } // namespace wr
517 } // namespace mozilla