gecko-dev/gfx/gl/SharedSurfaceGL.cpp
Wes Kocher df8b1437b6 Backed out 6 changesets (bug 877115) for mochitest-1 and reftest orange on this CLOSED TREE
Backed out changeset 65ad9d8860d6 (bug 877115)
Backed out changeset bf8095c168fb (bug 877115)
Backed out changeset 290ad5863615 (bug 877115)
Backed out changeset 4488ec28910e (bug 877115)
Backed out changeset 45f8859c6fd6 (bug 877115)
Backed out changeset 111cc426fa9e (bug 877115)
2013-12-16 16:33:07 -08:00

396 lines
11 KiB
C++

/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
/* 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 "SharedSurfaceGL.h"
#include "GLContext.h"
#include "GLBlitHelper.h"
#include "ScopedGLHelpers.h"
#include "gfxImageSurface.h"
using namespace mozilla::gfx;
namespace mozilla {
namespace gl {
// |src| must begin and end locked, though we may
// temporarily unlock it if we need to.
void
SharedSurface_GL::Copy(SharedSurface_GL* src, SharedSurface_GL* dest,
SurfaceFactory_GL* factory)
{
GLContext* gl = src->GL();
if (src->AttachType() == AttachmentType::Screen &&
dest->AttachType() == AttachmentType::Screen)
{
// Here, we actually need to blit through a temp surface, so let's make one.
nsAutoPtr<SharedSurface_GLTexture> tempSurf(
SharedSurface_GLTexture::Create(gl, gl,
factory->Formats(),
src->Size(),
factory->Caps().alpha));
Copy(src, tempSurf, factory);
Copy(tempSurf, dest, factory);
return;
}
if (src->AttachType() == AttachmentType::Screen) {
SharedSurface* origLocked = gl->GetLockedSurface();
bool srcNeedsUnlock = false;
bool origNeedsRelock = false;
if (origLocked != src) {
if (origLocked) {
origLocked->UnlockProd();
origNeedsRelock = true;
}
src->LockProd();
srcNeedsUnlock = true;
}
if (dest->AttachType() == AttachmentType::GLTexture) {
GLuint destTex = dest->Texture();
GLenum destTarget = dest->TextureTarget();
gl->BlitHelper()->BlitFramebufferToTexture(0, destTex, src->Size(), dest->Size(), destTarget);
} else if (dest->AttachType() == AttachmentType::GLRenderbuffer) {
GLuint destRB = dest->Renderbuffer();
ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
gl->BlitHelper()->BlitFramebufferToFramebuffer(0, destWrapper.FB(),
src->Size(), dest->Size());
} else {
MOZ_CRASH("Unhandled dest->AttachType().");
}
if (srcNeedsUnlock)
src->UnlockProd();
if (origNeedsRelock)
origLocked->LockProd();
return;
}
if (dest->AttachType() == AttachmentType::Screen) {
SharedSurface* origLocked = gl->GetLockedSurface();
bool destNeedsUnlock = false;
bool origNeedsRelock = false;
if (origLocked != dest) {
if (origLocked) {
origLocked->UnlockProd();
origNeedsRelock = true;
}
dest->LockProd();
destNeedsUnlock = true;
}
if (src->AttachType() == AttachmentType::GLTexture) {
GLuint srcTex = src->Texture();
GLenum srcTarget = src->TextureTarget();
gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, 0, src->Size(), dest->Size(), srcTarget);
} else if (src->AttachType() == AttachmentType::GLRenderbuffer) {
GLuint srcRB = src->Renderbuffer();
ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB);
gl->BlitHelper()->BlitFramebufferToFramebuffer(srcWrapper.FB(), 0,
src->Size(), dest->Size());
} else {
MOZ_CRASH("Unhandled src->AttachType().");
}
if (destNeedsUnlock)
dest->UnlockProd();
if (origNeedsRelock)
origLocked->LockProd();
return;
}
// Alright, done with cases involving Screen types.
// Only {src,dest}x{texture,renderbuffer} left.
if (src->AttachType() == AttachmentType::GLTexture) {
GLuint srcTex = src->Texture();
GLenum srcTarget = src->TextureTarget();
if (dest->AttachType() == AttachmentType::GLTexture) {
GLuint destTex = dest->Texture();
GLenum destTarget = dest->TextureTarget();
gl->BlitHelper()->BlitTextureToTexture(srcTex, destTex,
src->Size(), dest->Size(),
srcTarget, destTarget);
return;
}
if (dest->AttachType() == AttachmentType::GLRenderbuffer) {
GLuint destRB = dest->Renderbuffer();
ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, destWrapper.FB(),
src->Size(), dest->Size(), srcTarget);
return;
}
MOZ_CRASH("Unhandled dest->AttachType().");
}
if (src->AttachType() == AttachmentType::GLRenderbuffer) {
GLuint srcRB = src->Renderbuffer();
ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB);
if (dest->AttachType() == AttachmentType::GLTexture) {
GLuint destTex = dest->Texture();
GLenum destTarget = dest->TextureTarget();
gl->BlitHelper()->BlitFramebufferToTexture(srcWrapper.FB(), destTex,
src->Size(), dest->Size(), destTarget);
return;
}
if (dest->AttachType() == AttachmentType::GLRenderbuffer) {
GLuint destRB = dest->Renderbuffer();
ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
gl->BlitHelper()->BlitFramebufferToFramebuffer(srcWrapper.FB(), destWrapper.FB(),
src->Size(), dest->Size());
return;
}
MOZ_CRASH("Unhandled dest->AttachType().");
}
MOZ_CRASH("Unhandled src->AttachType().");
}
void
SharedSurface_GL::LockProd()
{
MOZ_ASSERT(!mIsLocked);
LockProdImpl();
mGL->LockSurface(this);
mIsLocked = true;
}
void
SharedSurface_GL::UnlockProd()
{
if (!mIsLocked)
return;
UnlockProdImpl();
mGL->UnlockSurface(this);
mIsLocked = false;
}
SurfaceFactory_GL::SurfaceFactory_GL(GLContext* gl,
SharedSurfaceType type,
const SurfaceCaps& caps)
: SurfaceFactory(type, caps)
, mGL(gl)
, mFormats(gl->ChooseGLFormats(caps))
{
ChooseBufferBits(caps, mDrawCaps, mReadCaps);
}
void
SurfaceFactory_GL::ChooseBufferBits(const SurfaceCaps& caps,
SurfaceCaps& drawCaps,
SurfaceCaps& readCaps) const
{
SurfaceCaps screenCaps;
screenCaps.color = caps.color;
screenCaps.alpha = caps.alpha;
screenCaps.bpp16 = caps.bpp16;
screenCaps.depth = caps.depth;
screenCaps.stencil = caps.stencil;
screenCaps.antialias = caps.antialias;
screenCaps.preserve = caps.preserve;
if (caps.antialias) {
drawCaps = screenCaps;
readCaps.Clear();
// Color caps need to be duplicated in readCaps.
readCaps.color = caps.color;
readCaps.alpha = caps.alpha;
readCaps.bpp16 = caps.bpp16;
} else {
drawCaps.Clear();
readCaps = screenCaps;
}
}
SharedSurface_Basic*
SharedSurface_Basic::Create(GLContext* gl,
const GLFormats& formats,
const gfxIntSize& size,
bool hasAlpha)
{
gl->MakeCurrent();
GLuint tex = CreateTexture(gl, formats.color_texInternalFormat,
formats.color_texFormat,
formats.color_texType,
size);
gfxImageFormat format = gfxImageFormatRGB24;
switch (formats.color_texInternalFormat) {
case LOCAL_GL_RGB:
case LOCAL_GL_RGB8:
if (formats.color_texType == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
format = gfxImageFormatRGB16_565;
else
format = gfxImageFormatRGB24;
break;
case LOCAL_GL_RGBA:
case LOCAL_GL_RGBA8:
format = gfxImageFormatARGB32;
break;
default:
MOZ_CRASH("Unhandled Tex format.");
}
return new SharedSurface_Basic(gl, size, hasAlpha, format, tex);
}
SharedSurface_Basic::SharedSurface_Basic(GLContext* gl,
const gfxIntSize& size,
bool hasAlpha,
gfxImageFormat format,
GLuint tex)
: SharedSurface_GL(SharedSurfaceType::Basic,
AttachmentType::GLTexture,
gl,
size,
hasAlpha)
, mTex(tex)
{
mData = new gfxImageSurface(size, format);
}
SharedSurface_Basic::~SharedSurface_Basic()
{
if (!mGL->MakeCurrent())
return;
GLuint tex = mTex;
mGL->fDeleteTextures(1, &tex);
}
void
SharedSurface_Basic::Fence()
{
MOZ_ASSERT(mData->GetSize() == mGL->OffscreenSize());
mGL->MakeCurrent();
mData->Flush();
mGL->ReadScreenIntoImageSurface(mData);
mData->MarkDirty();
}
SharedSurface_GLTexture*
SharedSurface_GLTexture::Create(GLContext* prodGL,
GLContext* consGL,
const GLFormats& formats,
const gfxIntSize& size,
bool hasAlpha)
{
MOZ_ASSERT(prodGL);
MOZ_ASSERT(!consGL || prodGL->SharesWith(consGL));
prodGL->MakeCurrent();
GLuint tex = CreateTextureForOffscreen(prodGL, formats, size);
return new SharedSurface_GLTexture(prodGL, consGL, size, hasAlpha, tex);
}
SharedSurface_GLTexture::~SharedSurface_GLTexture()
{
if (!mGL->MakeCurrent())
return;
GLuint tex = mTex;
mGL->fDeleteTextures(1, &tex);
if (mSync) {
mGL->fDeleteSync(mSync);
}
}
void
SharedSurface_GLTexture::Fence()
{
MutexAutoLock lock(mMutex);
mGL->MakeCurrent();
if (mConsGL && mGL->IsExtensionSupported(GLContext::ARB_sync)) {
if (mSync) {
mGL->fDeleteSync(mSync);
mSync = 0;
}
mSync = mGL->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
if (mSync) {
mGL->fFlush();
return;
}
}
MOZ_ASSERT(!mSync);
mGL->fFinish();
}
bool
SharedSurface_GLTexture::WaitSync()
{
MutexAutoLock lock(mMutex);
if (!mSync) {
// We must have used glFinish instead of glFenceSync.
return true;
}
MOZ_ASSERT(mConsGL, "Did you forget to call a deferred `SetConsumerGL()`?");
mConsGL->MakeCurrent();
MOZ_ASSERT(mConsGL->IsExtensionSupported(GLContext::ARB_sync));
mConsGL->fWaitSync(mSync,
0,
LOCAL_GL_TIMEOUT_IGNORED);
mConsGL->fDeleteSync(mSync);
mSync = 0;
return true;
}
void
SharedSurface_GLTexture::SetConsumerGL(GLContext* consGL)
{
MutexAutoLock lock(mMutex);
MOZ_ASSERT(consGL);
MOZ_ASSERT(mGL->SharesWith(consGL));
mConsGL = consGL;
}
} /* namespace gfx */
} /* namespace mozilla */