Line data Source code
1 : /* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "GLScreenBuffer.h"
7 :
8 : #include <cstring>
9 : #include "CompositorTypes.h"
10 : #include "gfxPrefs.h"
11 : #include "GLContext.h"
12 : #include "GLBlitHelper.h"
13 : #include "GLReadTexImageHelper.h"
14 : #include "SharedSurfaceEGL.h"
15 : #include "SharedSurfaceGL.h"
16 : #include "ScopedGLHelpers.h"
17 : #include "gfx2DGlue.h"
18 : #include "../layers/ipc/ShadowLayers.h"
19 : #include "mozilla/layers/TextureForwarder.h"
20 : #include "mozilla/layers/TextureClientSharedSurface.h"
21 :
22 : #ifdef XP_WIN
23 : #include "SharedSurfaceANGLE.h" // for SurfaceFactory_ANGLEShareHandle
24 : #include "SharedSurfaceD3D11Interop.h" // for SurfaceFactory_D3D11Interop
25 : #include "mozilla/gfx/DeviceManagerDx.h"
26 : #endif
27 :
28 : #ifdef XP_MACOSX
29 : #include "SharedSurfaceIO.h"
30 : #endif
31 :
32 : #ifdef GL_PROVIDER_GLX
33 : #include "GLXLibrary.h"
34 : #include "SharedSurfaceGLX.h"
35 : #endif
36 :
37 : namespace mozilla {
38 : namespace gl {
39 :
40 : using gfx::SurfaceFormat;
41 :
42 : UniquePtr<GLScreenBuffer>
43 0 : GLScreenBuffer::Create(GLContext* gl,
44 : const gfx::IntSize& size,
45 : const SurfaceCaps& caps)
46 : {
47 0 : UniquePtr<GLScreenBuffer> ret;
48 0 : if (caps.antialias &&
49 0 : !gl->IsSupported(GLFeature::framebuffer_multisample))
50 : {
51 0 : return Move(ret);
52 : }
53 :
54 0 : layers::TextureFlags flags = layers::TextureFlags::ORIGIN_BOTTOM_LEFT;
55 0 : if (!caps.premultAlpha) {
56 0 : flags |= layers::TextureFlags::NON_PREMULTIPLIED;
57 : }
58 :
59 0 : UniquePtr<SurfaceFactory> factory = MakeUnique<SurfaceFactory_Basic>(gl, caps, flags);
60 :
61 0 : ret.reset( new GLScreenBuffer(gl, caps, Move(factory)) );
62 0 : return Move(ret);
63 : }
64 :
65 : /* static */ UniquePtr<SurfaceFactory>
66 0 : GLScreenBuffer::CreateFactory(GLContext* gl,
67 : const SurfaceCaps& caps,
68 : KnowsCompositor* compositorConnection,
69 : const layers::TextureFlags& flags)
70 : {
71 0 : return CreateFactory(gl, caps, compositorConnection->GetTextureForwarder(),
72 0 : compositorConnection->GetCompositorBackendType(), flags);
73 : }
74 :
75 : /* static */ UniquePtr<SurfaceFactory>
76 0 : GLScreenBuffer::CreateFactory(GLContext* gl,
77 : const SurfaceCaps& caps,
78 : LayersIPCChannel* ipcChannel,
79 : const mozilla::layers::LayersBackend backend,
80 : const layers::TextureFlags& flags)
81 : {
82 0 : UniquePtr<SurfaceFactory> factory = nullptr;
83 0 : if (!gfxPrefs::WebGLForceLayersReadback()) {
84 0 : switch (backend) {
85 : case mozilla::layers::LayersBackend::LAYERS_OPENGL: {
86 : #if defined(XP_MACOSX)
87 : factory = SurfaceFactory_IOSurface::Create(gl, caps, ipcChannel, flags);
88 : #elif defined(GL_PROVIDER_GLX)
89 0 : if (sGLXLibrary.UseTextureFromPixmap())
90 0 : factory = SurfaceFactory_GLXDrawable::Create(gl, caps, ipcChannel, flags);
91 : #elif defined(MOZ_WIDGET_UIKIT)
92 : factory = MakeUnique<SurfaceFactory_GLTexture>(mGLContext, caps, ipcChannel, mFlags);
93 : #elif defined(MOZ_WIDGET_ANDROID)
94 : if (XRE_IsParentProcess()) {
95 : factory = SurfaceFactory_EGLImage::Create(gl, caps, ipcChannel, flags);
96 : } else {
97 : factory = SurfaceFactory_SurfaceTexture::Create(gl, caps, ipcChannel, flags);
98 : }
99 : #else
100 : if (gl->GetContextType() == GLContextType::EGL) {
101 : if (XRE_IsParentProcess()) {
102 : factory = SurfaceFactory_EGLImage::Create(gl, caps, ipcChannel, flags);
103 : }
104 : }
105 : #endif
106 0 : break;
107 : }
108 : case mozilla::layers::LayersBackend::LAYERS_D3D11: {
109 : #ifdef XP_WIN
110 : // Enable surface sharing only if ANGLE and compositing devices
111 : // are both WARP or both not WARP
112 : gfx::DeviceManagerDx* dm = gfx::DeviceManagerDx::Get();
113 : if (gl->IsANGLE() &&
114 : (gl->IsWARP() == dm->IsWARP()) &&
115 : dm->TextureSharingWorks())
116 : {
117 : factory = SurfaceFactory_ANGLEShareHandle::Create(gl, caps, ipcChannel, flags);
118 : }
119 :
120 : if (!factory && gfxPrefs::WebGLDXGLEnabled()) {
121 : factory = SurfaceFactory_D3D11Interop::Create(gl, caps, ipcChannel, flags);
122 : }
123 : #endif
124 0 : break;
125 : }
126 : default:
127 0 : break;
128 : }
129 :
130 : #ifdef GL_PROVIDER_GLX
131 0 : if (!factory && sGLXLibrary.UseTextureFromPixmap()) {
132 0 : factory = SurfaceFactory_GLXDrawable::Create(gl, caps, ipcChannel, flags);
133 : }
134 : #endif
135 : }
136 :
137 0 : return factory;
138 : }
139 :
140 0 : GLScreenBuffer::GLScreenBuffer(GLContext* gl,
141 : const SurfaceCaps& caps,
142 0 : UniquePtr<SurfaceFactory> factory)
143 : : mGL(gl)
144 : , mCaps(caps)
145 0 : , mFactory(Move(factory))
146 : , mNeedsBlit(true)
147 : , mUserReadBufferMode(LOCAL_GL_BACK)
148 : , mUserDrawBufferMode(LOCAL_GL_BACK)
149 : , mUserDrawFB(0)
150 : , mUserReadFB(0)
151 : , mInternalDrawFB(0)
152 : , mInternalReadFB(0)
153 : #ifdef DEBUG
154 : , mInInternalMode_DrawFB(true)
155 0 : , mInInternalMode_ReadFB(true)
156 : #endif
157 0 : { }
158 :
159 0 : GLScreenBuffer::~GLScreenBuffer()
160 : {
161 0 : mFactory = nullptr;
162 0 : mDraw = nullptr;
163 0 : mRead = nullptr;
164 :
165 0 : if (!mBack)
166 0 : return;
167 :
168 : // Detach mBack cleanly.
169 0 : mBack->Surf()->ProducerRelease();
170 0 : }
171 :
172 : void
173 0 : GLScreenBuffer::BindAsFramebuffer(GLContext* const gl, GLenum target) const
174 : {
175 0 : GLuint drawFB = DrawFB();
176 0 : GLuint readFB = ReadFB();
177 :
178 0 : if (!gl->IsSupported(GLFeature::split_framebuffer)) {
179 0 : MOZ_ASSERT(drawFB == readFB);
180 0 : gl->raw_fBindFramebuffer(target, readFB);
181 0 : return;
182 : }
183 :
184 0 : switch (target) {
185 : case LOCAL_GL_FRAMEBUFFER:
186 0 : gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB);
187 0 : gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB);
188 0 : break;
189 :
190 : case LOCAL_GL_DRAW_FRAMEBUFFER_EXT:
191 0 : gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB);
192 0 : break;
193 :
194 : case LOCAL_GL_READ_FRAMEBUFFER_EXT:
195 0 : gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB);
196 0 : break;
197 :
198 : default:
199 0 : MOZ_CRASH("GFX: Bad `target` for BindFramebuffer.");
200 : }
201 : }
202 :
203 : void
204 0 : GLScreenBuffer::BindFB(GLuint fb)
205 : {
206 0 : GLuint drawFB = DrawFB();
207 0 : GLuint readFB = ReadFB();
208 :
209 0 : mUserDrawFB = fb;
210 0 : mUserReadFB = fb;
211 0 : mInternalDrawFB = (fb == 0) ? drawFB : fb;
212 0 : mInternalReadFB = (fb == 0) ? readFB : fb;
213 :
214 0 : if (mInternalDrawFB == mInternalReadFB) {
215 0 : mGL->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mInternalDrawFB);
216 : } else {
217 0 : MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
218 0 : mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
219 0 : mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
220 : }
221 :
222 : #ifdef DEBUG
223 0 : mInInternalMode_DrawFB = false;
224 0 : mInInternalMode_ReadFB = false;
225 : #endif
226 0 : }
227 :
228 : void
229 0 : GLScreenBuffer::BindDrawFB(GLuint fb)
230 : {
231 0 : MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
232 :
233 0 : GLuint drawFB = DrawFB();
234 0 : mUserDrawFB = fb;
235 0 : mInternalDrawFB = (fb == 0) ? drawFB : fb;
236 :
237 0 : mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
238 :
239 : #ifdef DEBUG
240 0 : mInInternalMode_DrawFB = false;
241 : #endif
242 0 : }
243 :
244 : void
245 0 : GLScreenBuffer::BindReadFB(GLuint fb)
246 : {
247 0 : MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
248 :
249 0 : GLuint readFB = ReadFB();
250 0 : mUserReadFB = fb;
251 0 : mInternalReadFB = (fb == 0) ? readFB : fb;
252 :
253 0 : mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
254 :
255 : #ifdef DEBUG
256 0 : mInInternalMode_ReadFB = false;
257 : #endif
258 0 : }
259 :
260 : void
261 0 : GLScreenBuffer::BindFB_Internal(GLuint fb)
262 : {
263 0 : mInternalDrawFB = mUserDrawFB = fb;
264 0 : mInternalReadFB = mUserReadFB = fb;
265 0 : mGL->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mInternalDrawFB);
266 :
267 : #ifdef DEBUG
268 0 : mInInternalMode_DrawFB = true;
269 0 : mInInternalMode_ReadFB = true;
270 : #endif
271 0 : }
272 :
273 : void
274 0 : GLScreenBuffer::BindDrawFB_Internal(GLuint fb)
275 : {
276 0 : MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
277 :
278 0 : mInternalDrawFB = mUserDrawFB = fb;
279 0 : mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
280 :
281 : #ifdef DEBUG
282 0 : mInInternalMode_DrawFB = true;
283 : #endif
284 0 : }
285 :
286 : void
287 0 : GLScreenBuffer::BindReadFB_Internal(GLuint fb)
288 : {
289 0 : MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
290 :
291 0 : mInternalReadFB = mUserReadFB = fb;
292 0 : mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
293 :
294 : #ifdef DEBUG
295 0 : mInInternalMode_ReadFB = true;
296 : #endif
297 0 : }
298 :
299 :
300 : GLuint
301 0 : GLScreenBuffer::GetDrawFB() const
302 : {
303 : #ifdef DEBUG
304 0 : MOZ_ASSERT(mGL->IsCurrent());
305 0 : MOZ_ASSERT(!mInInternalMode_DrawFB);
306 :
307 : // Don't need a branch here, because:
308 : // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT == LOCAL_GL_FRAMEBUFFER_BINDING == 0x8CA6
309 : // We use raw_ here because this is debug code and we need to see what
310 : // the driver thinks.
311 0 : GLuint actual = 0;
312 0 : mGL->raw_fGetIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual);
313 :
314 0 : GLuint predicted = mInternalDrawFB;
315 0 : if (predicted != actual) {
316 : printf_stderr("Misprediction: Bound draw FB predicted: %d. Was: %d.\n",
317 0 : predicted, actual);
318 0 : MOZ_ASSERT(false, "Draw FB binding misprediction!");
319 : }
320 : #endif
321 :
322 0 : return mUserDrawFB;
323 : }
324 :
325 : GLuint
326 0 : GLScreenBuffer::GetReadFB() const
327 : {
328 : #ifdef DEBUG
329 0 : MOZ_ASSERT(mGL->IsCurrent());
330 0 : MOZ_ASSERT(!mInInternalMode_ReadFB);
331 :
332 : // We use raw_ here because this is debug code and we need to see what
333 : // the driver thinks.
334 0 : GLuint actual = 0;
335 0 : if (mGL->IsSupported(GLFeature::split_framebuffer))
336 0 : mGL->raw_fGetIntegerv(LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual);
337 : else
338 0 : mGL->raw_fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&actual);
339 :
340 0 : GLuint predicted = mInternalReadFB;
341 0 : if (predicted != actual) {
342 : printf_stderr("Misprediction: Bound read FB predicted: %d. Was: %d.\n",
343 0 : predicted, actual);
344 0 : MOZ_ASSERT(false, "Read FB binding misprediction!");
345 : }
346 : #endif
347 :
348 0 : return mUserReadFB;
349 : }
350 :
351 : GLuint
352 0 : GLScreenBuffer::GetFB() const
353 : {
354 0 : MOZ_ASSERT(GetDrawFB() == GetReadFB());
355 0 : return GetDrawFB();
356 : }
357 :
358 :
359 : void
360 0 : GLScreenBuffer::DeletingFB(GLuint fb)
361 : {
362 0 : if (fb == mInternalDrawFB) {
363 0 : mInternalDrawFB = 0;
364 0 : mUserDrawFB = 0;
365 : }
366 0 : if (fb == mInternalReadFB) {
367 0 : mInternalReadFB = 0;
368 0 : mUserReadFB = 0;
369 : }
370 0 : }
371 :
372 :
373 : void
374 0 : GLScreenBuffer::AfterDrawCall()
375 : {
376 0 : if (mUserDrawFB != 0)
377 0 : return;
378 :
379 0 : RequireBlit();
380 : }
381 :
382 : void
383 0 : GLScreenBuffer::BeforeReadCall()
384 : {
385 0 : if (mUserReadFB != 0)
386 0 : return;
387 :
388 0 : AssureBlitted();
389 : }
390 :
391 : bool
392 0 : GLScreenBuffer::CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x,
393 : GLint y, GLsizei width, GLsizei height, GLint border)
394 : {
395 : SharedSurface* surf;
396 0 : if (GetReadFB() == 0) {
397 0 : surf = SharedSurf();
398 : } else {
399 0 : surf = mGL->mFBOMapping[GetReadFB()];
400 : }
401 0 : if (surf) {
402 0 : return surf->CopyTexImage2D(target, level, internalformat, x, y, width, height, border);
403 : }
404 :
405 0 : return false;
406 : }
407 :
408 : bool
409 0 : GLScreenBuffer::ReadPixels(GLint x, GLint y,
410 : GLsizei width, GLsizei height,
411 : GLenum format, GLenum type,
412 : GLvoid* pixels)
413 : {
414 : // If the currently bound framebuffer is backed by a SharedSurface
415 : // then it might want to override how we read pixel data from it.
416 : // This is normally only the default framebuffer, but we can also
417 : // have SharedSurfaces bound to other framebuffers when doing
418 : // readback for BasicLayers.
419 : SharedSurface* surf;
420 0 : if (GetReadFB() == 0) {
421 0 : surf = SharedSurf();
422 : } else {
423 0 : surf = mGL->mFBOMapping[GetReadFB()];
424 : }
425 0 : if (surf) {
426 0 : return surf->ReadPixels(x, y, width, height, format, type, pixels);
427 : }
428 :
429 0 : return false;
430 : }
431 :
432 : void
433 0 : GLScreenBuffer::RequireBlit()
434 : {
435 0 : mNeedsBlit = true;
436 0 : }
437 :
438 : void
439 0 : GLScreenBuffer::AssureBlitted()
440 : {
441 0 : if (!mNeedsBlit)
442 0 : return;
443 :
444 0 : if (mDraw) {
445 0 : GLuint drawFB = DrawFB();
446 0 : GLuint readFB = ReadFB();
447 :
448 0 : MOZ_ASSERT(drawFB != 0);
449 0 : MOZ_ASSERT(drawFB != readFB);
450 0 : MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
451 0 : MOZ_ASSERT(mDraw->mSize == mRead->Size());
452 :
453 0 : ScopedBindFramebuffer boundFB(mGL);
454 0 : ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
455 :
456 0 : BindReadFB_Internal(drawFB);
457 0 : BindDrawFB_Internal(readFB);
458 :
459 0 : if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
460 0 : const gfx::IntSize& srcSize = mDraw->mSize;
461 0 : const gfx::IntSize& destSize = mRead->Size();
462 :
463 0 : mGL->raw_fBlitFramebuffer(0, 0, srcSize.width, srcSize.height,
464 0 : 0, 0, destSize.width, destSize.height,
465 : LOCAL_GL_COLOR_BUFFER_BIT,
466 0 : LOCAL_GL_NEAREST);
467 0 : } else if (mGL->IsExtensionSupported(GLContext::APPLE_framebuffer_multisample)) {
468 0 : mGL->fResolveMultisampleFramebufferAPPLE();
469 : } else {
470 0 : MOZ_CRASH("GFX: No available blit methods.");
471 : }
472 : // Done!
473 : }
474 :
475 0 : mNeedsBlit = false;
476 : }
477 :
478 : void
479 0 : GLScreenBuffer::Morph(UniquePtr<SurfaceFactory> newFactory)
480 : {
481 0 : MOZ_RELEASE_ASSERT(newFactory, "newFactory must not be null");
482 0 : mFactory = Move(newFactory);
483 0 : }
484 :
485 : bool
486 0 : GLScreenBuffer::Attach(SharedSurface* surf, const gfx::IntSize& size)
487 : {
488 0 : ScopedBindFramebuffer autoFB(mGL);
489 :
490 0 : const bool readNeedsUnlock = (mRead && SharedSurf());
491 0 : if (readNeedsUnlock) {
492 0 : SharedSurf()->UnlockProd();
493 : }
494 :
495 0 : surf->LockProd();
496 :
497 0 : if (mRead &&
498 0 : surf->mAttachType == SharedSurf()->mAttachType &&
499 0 : size == Size())
500 : {
501 : // Same size, same type, ready for reuse!
502 0 : mRead->Attach(surf);
503 : } else {
504 : // Else something changed, so resize:
505 0 : UniquePtr<DrawBuffer> draw;
506 0 : bool drawOk = true;
507 :
508 : /* Don't change out the draw buffer unless we resize. In the
509 : * preserveDrawingBuffer:true case, prior contents of the buffer must
510 : * be retained. If we're using a draw buffer, it's an MSAA buffer, so
511 : * even if we copy the previous frame into the (single-sampled) read
512 : * buffer, if we need to re-resolve from draw to read (as triggered by
513 : * drawing), we'll need the old MSAA content to still be in the draw
514 : * buffer.
515 : */
516 0 : if (!mDraw || size != Size())
517 0 : drawOk = CreateDraw(size, &draw); // Can be null.
518 :
519 0 : UniquePtr<ReadBuffer> read = CreateRead(surf);
520 0 : bool readOk = !!read;
521 :
522 0 : if (!drawOk || !readOk) {
523 0 : surf->UnlockProd();
524 0 : if (readNeedsUnlock) {
525 0 : SharedSurf()->LockProd();
526 : }
527 0 : return false;
528 : }
529 :
530 0 : if (draw)
531 0 : mDraw = Move(draw);
532 :
533 0 : mRead = Move(read);
534 : }
535 :
536 : // Check that we're all set up.
537 0 : MOZ_ASSERT(SharedSurf() == surf);
538 :
539 : // Update the ReadBuffer mode.
540 0 : if (mGL->IsSupported(gl::GLFeature::read_buffer)) {
541 0 : BindFB(0);
542 0 : mRead->SetReadBuffer(mUserReadBufferMode);
543 : }
544 :
545 : // Update the DrawBuffer mode.
546 0 : if (mGL->IsSupported(gl::GLFeature::draw_buffers)) {
547 0 : BindFB(0);
548 0 : SetDrawBuffer(mUserDrawBufferMode);
549 : }
550 :
551 0 : RequireBlit();
552 :
553 0 : return true;
554 : }
555 :
556 : bool
557 0 : GLScreenBuffer::Swap(const gfx::IntSize& size)
558 : {
559 0 : RefPtr<SharedSurfaceTextureClient> newBack = mFactory->NewTexClient(size);
560 0 : if (!newBack)
561 0 : return false;
562 :
563 : // In the case of DXGL interop, the new surface needs to be acquired before
564 : // it is attached so that the interop surface is locked, which populates
565 : // the GL renderbuffer. This results in the renderbuffer being ready and
566 : // attachment to framebuffer succeeds in Attach() call.
567 0 : newBack->Surf()->ProducerAcquire();
568 :
569 0 : if (!Attach(newBack->Surf(), size)) {
570 0 : newBack->Surf()->ProducerRelease();
571 0 : return false;
572 : }
573 : // Attach was successful.
574 :
575 0 : mFront = mBack;
576 0 : mBack = newBack;
577 :
578 0 : if (ShouldPreserveBuffer() &&
579 0 : mFront &&
580 0 : mBack &&
581 0 : !mDraw)
582 : {
583 0 : auto src = mFront->Surf();
584 0 : auto dest = mBack->Surf();
585 :
586 : //uint32_t srcPixel = ReadPixel(src);
587 : //uint32_t destPixel = ReadPixel(dest);
588 : //printf_stderr("Before: src: 0x%08x, dest: 0x%08x\n", srcPixel, destPixel);
589 : #ifdef DEBUG
590 0 : GLContext::LocalErrorScope errorScope(*mGL);
591 : #endif
592 :
593 0 : SharedSurface::ProdCopy(src, dest, mFactory.get());
594 :
595 : #ifdef DEBUG
596 0 : MOZ_ASSERT(!errorScope.GetError());
597 : #endif
598 :
599 : //srcPixel = ReadPixel(src);
600 : //destPixel = ReadPixel(dest);
601 : //printf_stderr("After: src: 0x%08x, dest: 0x%08x\n", srcPixel, destPixel);
602 : }
603 :
604 : // XXX: We would prefer to fence earlier on platforms that don't need
605 : // the full ProducerAcquire/ProducerRelease semantics, so that the fence
606 : // doesn't include the copy operation. Unfortunately, the current API
607 : // doesn't expose a good way to do that.
608 0 : if (mFront) {
609 0 : mFront->Surf()->ProducerRelease();
610 : }
611 :
612 0 : return true;
613 : }
614 :
615 : bool
616 0 : GLScreenBuffer::PublishFrame(const gfx::IntSize& size)
617 : {
618 0 : AssureBlitted();
619 :
620 0 : bool good = Swap(size);
621 0 : return good;
622 : }
623 :
624 : bool
625 0 : GLScreenBuffer::Resize(const gfx::IntSize& size)
626 : {
627 0 : RefPtr<SharedSurfaceTextureClient> newBack = mFactory->NewTexClient(size);
628 0 : if (!newBack)
629 0 : return false;
630 :
631 0 : if (!Attach(newBack->Surf(), size))
632 0 : return false;
633 :
634 0 : if (mBack)
635 0 : mBack->Surf()->ProducerRelease();
636 :
637 0 : mBack = newBack;
638 :
639 0 : mBack->Surf()->ProducerAcquire();
640 :
641 0 : return true;
642 : }
643 :
644 : bool
645 0 : GLScreenBuffer::CreateDraw(const gfx::IntSize& size,
646 : UniquePtr<DrawBuffer>* out_buffer)
647 : {
648 0 : GLContext* gl = mFactory->mGL;
649 0 : const GLFormats& formats = mFactory->mFormats;
650 0 : const SurfaceCaps& caps = mFactory->DrawCaps();
651 :
652 0 : return DrawBuffer::Create(gl, caps, formats, size, out_buffer);
653 : }
654 :
655 : UniquePtr<ReadBuffer>
656 0 : GLScreenBuffer::CreateRead(SharedSurface* surf)
657 : {
658 0 : GLContext* gl = mFactory->mGL;
659 0 : const GLFormats& formats = mFactory->mFormats;
660 0 : const SurfaceCaps& caps = mFactory->ReadCaps();
661 :
662 0 : return ReadBuffer::Create(gl, caps, formats, surf);
663 : }
664 :
665 : void
666 0 : GLScreenBuffer::SetDrawBuffer(GLenum mode)
667 : {
668 0 : MOZ_ASSERT(mGL->IsSupported(gl::GLFeature::draw_buffers));
669 0 : MOZ_ASSERT(GetDrawFB() == 0);
670 :
671 0 : if (!mGL->IsSupported(GLFeature::draw_buffers))
672 0 : return;
673 :
674 0 : mUserDrawBufferMode = mode;
675 :
676 0 : GLuint fb = mDraw ? mDraw->mFB : mRead->mFB;
677 : GLenum internalMode;
678 :
679 0 : switch (mode) {
680 : case LOCAL_GL_BACK:
681 0 : internalMode = (fb == 0) ? LOCAL_GL_BACK
682 : : LOCAL_GL_COLOR_ATTACHMENT0;
683 0 : break;
684 :
685 : case LOCAL_GL_NONE:
686 0 : internalMode = LOCAL_GL_NONE;
687 0 : break;
688 :
689 : default:
690 0 : MOZ_CRASH("GFX: Bad value.");
691 : }
692 :
693 0 : mGL->MakeCurrent();
694 0 : mGL->fDrawBuffers(1, &internalMode);
695 : }
696 :
697 : void
698 0 : GLScreenBuffer::SetReadBuffer(GLenum mode)
699 : {
700 0 : MOZ_ASSERT(mGL->IsSupported(gl::GLFeature::read_buffer));
701 0 : MOZ_ASSERT(GetReadFB() == 0);
702 :
703 0 : mUserReadBufferMode = mode;
704 0 : mRead->SetReadBuffer(mUserReadBufferMode);
705 0 : }
706 :
707 : bool
708 0 : GLScreenBuffer::IsDrawFramebufferDefault() const
709 : {
710 0 : if (!mDraw)
711 0 : return IsReadFramebufferDefault();
712 0 : return mDraw->mFB == 0;
713 : }
714 :
715 : bool
716 0 : GLScreenBuffer::IsReadFramebufferDefault() const
717 : {
718 0 : return SharedSurf()->mAttachType == AttachmentType::Screen;
719 : }
720 :
721 : uint32_t
722 0 : GLScreenBuffer::DepthBits() const
723 : {
724 0 : const GLFormats& formats = mFactory->mFormats;
725 :
726 0 : if (formats.depth == LOCAL_GL_DEPTH_COMPONENT16)
727 0 : return 16;
728 :
729 0 : return 24;
730 : }
731 :
732 : ////////////////////////////////////////////////////////////////////////
733 : // Utils
734 :
735 : static void
736 0 : RenderbufferStorageBySamples(GLContext* aGL, GLsizei aSamples,
737 : GLenum aInternalFormat, const gfx::IntSize& aSize)
738 : {
739 0 : if (aSamples) {
740 : aGL->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER,
741 : aSamples,
742 : aInternalFormat,
743 0 : aSize.width, aSize.height);
744 : } else {
745 : aGL->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
746 : aInternalFormat,
747 0 : aSize.width, aSize.height);
748 : }
749 0 : }
750 :
751 : static GLuint
752 0 : CreateRenderbuffer(GLContext* aGL, GLenum aFormat, GLsizei aSamples,
753 : const gfx::IntSize& aSize)
754 : {
755 0 : GLuint rb = 0;
756 0 : aGL->fGenRenderbuffers(1, &rb);
757 0 : ScopedBindRenderbuffer autoRB(aGL, rb);
758 :
759 0 : RenderbufferStorageBySamples(aGL, aSamples, aFormat, aSize);
760 :
761 0 : return rb;
762 : }
763 :
764 : static void
765 0 : CreateRenderbuffersForOffscreen(GLContext* aGL, const GLFormats& aFormats,
766 : const gfx::IntSize& aSize, bool aMultisample,
767 : GLuint* aColorMSRB, GLuint* aDepthRB,
768 : GLuint* aStencilRB)
769 : {
770 0 : GLsizei samples = aMultisample ? aFormats.samples : 0;
771 0 : if (aColorMSRB) {
772 0 : MOZ_ASSERT(aFormats.samples > 0);
773 0 : MOZ_ASSERT(aFormats.color_rbFormat);
774 :
775 0 : GLenum colorFormat = aFormats.color_rbFormat;
776 0 : if (aGL->IsANGLE()) {
777 0 : MOZ_ASSERT(colorFormat == LOCAL_GL_RGBA8);
778 0 : colorFormat = LOCAL_GL_BGRA8_EXT;
779 : }
780 :
781 0 : *aColorMSRB = CreateRenderbuffer(aGL, colorFormat, samples, aSize);
782 : }
783 :
784 0 : if (aDepthRB &&
785 0 : aStencilRB &&
786 0 : aFormats.depthStencil)
787 : {
788 0 : *aDepthRB = CreateRenderbuffer(aGL, aFormats.depthStencil, samples, aSize);
789 0 : *aStencilRB = *aDepthRB;
790 : } else {
791 0 : if (aDepthRB) {
792 0 : MOZ_ASSERT(aFormats.depth);
793 :
794 0 : *aDepthRB = CreateRenderbuffer(aGL, aFormats.depth, samples, aSize);
795 : }
796 :
797 0 : if (aStencilRB) {
798 0 : MOZ_ASSERT(aFormats.stencil);
799 :
800 0 : *aStencilRB = CreateRenderbuffer(aGL, aFormats.stencil, samples, aSize);
801 : }
802 : }
803 0 : }
804 :
805 : ////////////////////////////////////////////////////////////////////////
806 : // DrawBuffer
807 :
808 : bool
809 0 : DrawBuffer::Create(GLContext* const gl,
810 : const SurfaceCaps& caps,
811 : const GLFormats& formats,
812 : const gfx::IntSize& size,
813 : UniquePtr<DrawBuffer>* out_buffer)
814 : {
815 0 : MOZ_ASSERT(out_buffer);
816 0 : *out_buffer = nullptr;
817 :
818 0 : if (!caps.color) {
819 0 : MOZ_ASSERT(!caps.alpha && !caps.depth && !caps.stencil);
820 :
821 : // Nothing is needed.
822 0 : return true;
823 : }
824 :
825 0 : if (caps.antialias) {
826 0 : if (formats.samples == 0)
827 0 : return false; // Can't create it.
828 :
829 0 : MOZ_ASSERT(formats.samples <= gl->MaxSamples());
830 : }
831 :
832 0 : GLuint colorMSRB = 0;
833 0 : GLuint depthRB = 0;
834 0 : GLuint stencilRB = 0;
835 :
836 0 : GLuint* pColorMSRB = caps.antialias ? &colorMSRB : nullptr;
837 0 : GLuint* pDepthRB = caps.depth ? &depthRB : nullptr;
838 0 : GLuint* pStencilRB = caps.stencil ? &stencilRB : nullptr;
839 :
840 0 : if (!formats.color_rbFormat)
841 0 : pColorMSRB = nullptr;
842 :
843 0 : if (pDepthRB && pStencilRB) {
844 0 : if (!formats.depth && !formats.depthStencil)
845 0 : pDepthRB = nullptr;
846 :
847 0 : if (!formats.stencil && !formats.depthStencil)
848 0 : pStencilRB = nullptr;
849 : } else {
850 0 : if (!formats.depth)
851 0 : pDepthRB = nullptr;
852 :
853 0 : if (!formats.stencil)
854 0 : pStencilRB = nullptr;
855 : }
856 :
857 0 : GLContext::LocalErrorScope localError(*gl);
858 :
859 0 : CreateRenderbuffersForOffscreen(gl, formats, size, caps.antialias,
860 0 : pColorMSRB, pDepthRB, pStencilRB);
861 :
862 0 : GLuint fb = 0;
863 0 : gl->fGenFramebuffers(1, &fb);
864 0 : gl->AttachBuffersToFB(0, colorMSRB, depthRB, stencilRB, fb);
865 :
866 0 : const GLsizei samples = formats.samples;
867 : UniquePtr<DrawBuffer> ret( new DrawBuffer(gl, size, samples, fb, colorMSRB,
868 0 : depthRB, stencilRB) );
869 :
870 0 : GLenum err = localError.GetError();
871 0 : MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_OUT_OF_MEMORY);
872 0 : if (err || !gl->IsFramebufferComplete(fb))
873 0 : return false;
874 :
875 0 : *out_buffer = Move(ret);
876 0 : return true;
877 : }
878 :
879 0 : DrawBuffer::~DrawBuffer()
880 : {
881 0 : if (!mGL->MakeCurrent())
882 0 : return;
883 :
884 0 : GLuint fb = mFB;
885 : GLuint rbs[] = {
886 0 : mColorMSRB,
887 0 : mDepthRB,
888 0 : (mStencilRB != mDepthRB) ? mStencilRB : 0, // Don't double-delete DEPTH_STENCIL RBs.
889 0 : };
890 :
891 0 : mGL->fDeleteFramebuffers(1, &fb);
892 0 : mGL->fDeleteRenderbuffers(3, rbs);
893 0 : }
894 :
895 : ////////////////////////////////////////////////////////////////////////
896 : // ReadBuffer
897 :
898 : UniquePtr<ReadBuffer>
899 0 : ReadBuffer::Create(GLContext* gl,
900 : const SurfaceCaps& caps,
901 : const GLFormats& formats,
902 : SharedSurface* surf)
903 : {
904 0 : MOZ_ASSERT(surf);
905 :
906 0 : if (surf->mAttachType == AttachmentType::Screen) {
907 : // Don't need anything. Our read buffer will be the 'screen'.
908 : return UniquePtr<ReadBuffer>( new ReadBuffer(gl, 0, 0, 0,
909 0 : surf) );
910 : }
911 :
912 0 : GLuint depthRB = 0;
913 0 : GLuint stencilRB = 0;
914 :
915 0 : GLuint* pDepthRB = caps.depth ? &depthRB : nullptr;
916 0 : GLuint* pStencilRB = caps.stencil ? &stencilRB : nullptr;
917 :
918 0 : GLContext::LocalErrorScope localError(*gl);
919 :
920 0 : CreateRenderbuffersForOffscreen(gl, formats, surf->mSize, caps.antialias,
921 0 : nullptr, pDepthRB, pStencilRB);
922 :
923 0 : GLuint colorTex = 0;
924 0 : GLuint colorRB = 0;
925 0 : GLenum target = 0;
926 :
927 0 : switch (surf->mAttachType) {
928 : case AttachmentType::GLTexture:
929 0 : colorTex = surf->ProdTexture();
930 0 : target = surf->ProdTextureTarget();
931 0 : break;
932 : case AttachmentType::GLRenderbuffer:
933 0 : colorRB = surf->ProdRenderbuffer();
934 0 : break;
935 : default:
936 0 : MOZ_CRASH("GFX: Unknown attachment type, create?");
937 : }
938 0 : MOZ_ASSERT(colorTex || colorRB);
939 :
940 0 : GLuint fb = 0;
941 0 : gl->fGenFramebuffers(1, &fb);
942 0 : gl->AttachBuffersToFB(colorTex, colorRB, depthRB, stencilRB, fb, target);
943 0 : gl->mFBOMapping[fb] = surf;
944 :
945 : UniquePtr<ReadBuffer> ret( new ReadBuffer(gl, fb, depthRB,
946 0 : stencilRB, surf) );
947 :
948 0 : GLenum err = localError.GetError();
949 0 : MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_OUT_OF_MEMORY);
950 0 : if (err)
951 0 : return nullptr;
952 :
953 0 : const bool needsAcquire = !surf->IsProducerAcquired();
954 0 : if (needsAcquire) {
955 0 : surf->ProducerReadAcquire();
956 : }
957 0 : const bool isComplete = gl->IsFramebufferComplete(fb);
958 0 : if (needsAcquire) {
959 0 : surf->ProducerReadRelease();
960 : }
961 :
962 0 : if (!isComplete)
963 0 : return nullptr;
964 :
965 0 : return Move(ret);
966 : }
967 :
968 0 : ReadBuffer::~ReadBuffer()
969 : {
970 0 : if (!mGL->MakeCurrent())
971 0 : return;
972 :
973 0 : GLuint fb = mFB;
974 : GLuint rbs[] = {
975 0 : mDepthRB,
976 0 : (mStencilRB != mDepthRB) ? mStencilRB : 0, // Don't double-delete DEPTH_STENCIL RBs.
977 0 : };
978 :
979 0 : mGL->fDeleteFramebuffers(1, &fb);
980 0 : mGL->fDeleteRenderbuffers(2, rbs);
981 :
982 0 : mGL->mFBOMapping.erase(mFB);
983 0 : }
984 :
985 : void
986 0 : ReadBuffer::Attach(SharedSurface* surf)
987 : {
988 0 : MOZ_ASSERT(surf && mSurf);
989 0 : MOZ_ASSERT(surf->mAttachType == mSurf->mAttachType);
990 0 : MOZ_ASSERT(surf->mSize == mSurf->mSize);
991 :
992 : // Nothing else is needed for AttachType Screen.
993 0 : if (surf->mAttachType != AttachmentType::Screen) {
994 0 : GLuint colorTex = 0;
995 0 : GLuint colorRB = 0;
996 0 : GLenum target = 0;
997 :
998 0 : switch (surf->mAttachType) {
999 : case AttachmentType::GLTexture:
1000 0 : colorTex = surf->ProdTexture();
1001 0 : target = surf->ProdTextureTarget();
1002 0 : break;
1003 : case AttachmentType::GLRenderbuffer:
1004 0 : colorRB = surf->ProdRenderbuffer();
1005 0 : break;
1006 : default:
1007 0 : MOZ_CRASH("GFX: Unknown attachment type, attach?");
1008 : }
1009 :
1010 0 : mGL->AttachBuffersToFB(colorTex, colorRB, 0, 0, mFB, target);
1011 0 : mGL->mFBOMapping[mFB] = surf;
1012 0 : MOZ_ASSERT(mGL->IsFramebufferComplete(mFB));
1013 : }
1014 :
1015 0 : mSurf = surf;
1016 0 : }
1017 :
1018 : const gfx::IntSize&
1019 0 : ReadBuffer::Size() const
1020 : {
1021 0 : return mSurf->mSize;
1022 : }
1023 :
1024 : void
1025 0 : ReadBuffer::SetReadBuffer(GLenum userMode) const
1026 : {
1027 0 : if (!mGL->IsSupported(GLFeature::read_buffer))
1028 0 : return;
1029 :
1030 : GLenum internalMode;
1031 :
1032 0 : switch (userMode) {
1033 : case LOCAL_GL_BACK:
1034 : case LOCAL_GL_FRONT:
1035 0 : internalMode = (mFB == 0) ? userMode
1036 : : LOCAL_GL_COLOR_ATTACHMENT0;
1037 0 : break;
1038 :
1039 : case LOCAL_GL_NONE:
1040 0 : internalMode = LOCAL_GL_NONE;
1041 0 : break;
1042 :
1043 : default:
1044 0 : MOZ_CRASH("GFX: Bad value.");
1045 : }
1046 :
1047 0 : mGL->MakeCurrent();
1048 0 : mGL->fReadBuffer(internalMode);
1049 : }
1050 :
1051 : } /* namespace gl */
1052 : } /* namespace mozilla */
|