2018-11-30 19:52:05 +00:00
|
|
|
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */
|
2017-12-19 02:19:38 +00:00
|
|
|
/* 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 "MozFramebuffer.h"
|
|
|
|
|
|
|
|
#include "GLContext.h"
|
2017-12-22 01:14:54 +00:00
|
|
|
#include "mozilla/gfx/Logging.h"
|
2017-12-19 02:19:38 +00:00
|
|
|
#include "ScopedGLHelpers.h"
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace gl {
|
|
|
|
|
|
|
|
static void DeleteByTarget(GLContext* const gl, const GLenum target,
|
|
|
|
const GLuint name) {
|
|
|
|
if (target == LOCAL_GL_RENDERBUFFER) {
|
|
|
|
gl->DeleteRenderbuffer(name);
|
|
|
|
} else {
|
|
|
|
gl->DeleteTexture(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
UniquePtr<MozFramebuffer> MozFramebuffer::Create(GLContext* const gl,
|
|
|
|
const gfx::IntSize& size,
|
|
|
|
const uint32_t samples,
|
|
|
|
const bool depthStencil) {
|
|
|
|
if (samples && !gl->IsSupported(GLFeature::framebuffer_multisample))
|
|
|
|
return nullptr;
|
2018-11-30 10:46:48 +00:00
|
|
|
|
2017-12-21 03:39:58 +00:00
|
|
|
if (uint32_t(size.width) > gl->MaxTexOrRbSize() ||
|
|
|
|
uint32_t(size.height) > gl->MaxTexOrRbSize() ||
|
|
|
|
samples > gl->MaxSamples()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2018-11-30 10:46:48 +00:00
|
|
|
|
2017-12-19 02:19:38 +00:00
|
|
|
gl->MakeCurrent();
|
2018-11-30 10:46:48 +00:00
|
|
|
|
2017-12-19 02:19:38 +00:00
|
|
|
GLContext::LocalErrorScope errorScope(*gl);
|
2018-11-30 10:46:48 +00:00
|
|
|
|
2017-12-19 02:19:38 +00:00
|
|
|
GLenum colorTarget;
|
|
|
|
GLuint colorName;
|
|
|
|
if (samples) {
|
|
|
|
colorTarget = LOCAL_GL_RENDERBUFFER;
|
|
|
|
colorName = gl->CreateRenderbuffer();
|
|
|
|
const ScopedBindRenderbuffer bindRB(gl, colorName);
|
|
|
|
gl->fRenderbufferStorageMultisample(colorTarget, samples, LOCAL_GL_RGBA8,
|
|
|
|
size.width, size.height);
|
|
|
|
} else {
|
|
|
|
colorTarget = LOCAL_GL_TEXTURE_2D;
|
|
|
|
colorName = gl->CreateTexture();
|
|
|
|
const ScopedBindTexture bindTex(gl, colorName);
|
|
|
|
gl->TexParams_SetClampNoMips();
|
|
|
|
gl->fTexImage2D(colorTarget, 0, LOCAL_GL_RGBA, size.width, size.height, 0,
|
|
|
|
LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, nullptr);
|
|
|
|
}
|
2018-11-30 10:46:48 +00:00
|
|
|
|
2017-12-19 02:19:38 +00:00
|
|
|
const auto err = errorScope.GetError();
|
|
|
|
if (err) {
|
2017-12-22 01:14:54 +00:00
|
|
|
if (err != LOCAL_GL_OUT_OF_MEMORY) {
|
|
|
|
gfxCriticalNote << "Unexpected error: " << gfx::hexa(err) << ": "
|
|
|
|
<< GLContext::GLErrorToString(err);
|
2017-12-19 02:19:38 +00:00
|
|
|
}
|
|
|
|
DeleteByTarget(gl, colorTarget, colorName);
|
|
|
|
return nullptr;
|
2018-11-30 10:46:48 +00:00
|
|
|
}
|
2017-12-19 02:19:38 +00:00
|
|
|
|
|
|
|
return CreateWith(gl, size, samples, depthStencil, colorTarget, colorName);
|
|
|
|
}
|
|
|
|
|
|
|
|
UniquePtr<MozFramebuffer> MozFramebuffer::CreateWith(
|
|
|
|
GLContext* const gl, const gfx::IntSize& size, const uint32_t samples,
|
|
|
|
const bool depthStencil, const GLenum colorTarget, const GLuint colorName) {
|
|
|
|
UniquePtr<MozFramebuffer> mozFB(new MozFramebuffer(
|
|
|
|
gl, size, samples, depthStencil, colorTarget, colorName));
|
2018-11-30 10:46:48 +00:00
|
|
|
|
2017-12-19 02:19:38 +00:00
|
|
|
const ScopedBindFramebuffer bindFB(gl, mozFB->mFB);
|
2018-11-30 10:46:48 +00:00
|
|
|
|
2017-12-19 02:19:38 +00:00
|
|
|
if (colorTarget == LOCAL_GL_RENDERBUFFER) {
|
|
|
|
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
|
|
|
|
LOCAL_GL_COLOR_ATTACHMENT0, colorTarget,
|
|
|
|
colorName);
|
2018-11-30 10:46:48 +00:00
|
|
|
} else {
|
2017-12-19 02:19:38 +00:00
|
|
|
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
|
|
|
|
colorTarget, colorName, 0);
|
2018-11-30 10:46:48 +00:00
|
|
|
}
|
|
|
|
|
2017-12-19 02:19:38 +00:00
|
|
|
const auto fnAllocRB = [&](GLuint rb, GLenum format) {
|
|
|
|
const ScopedBindRenderbuffer bindRB(gl, rb);
|
|
|
|
if (samples) {
|
|
|
|
gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, samples,
|
|
|
|
format, size.width, size.height);
|
|
|
|
} else {
|
|
|
|
gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, format, size.width,
|
|
|
|
size.height);
|
|
|
|
}
|
|
|
|
return rb;
|
2018-11-30 10:46:48 +00:00
|
|
|
};
|
2017-12-19 02:19:38 +00:00
|
|
|
|
|
|
|
if (depthStencil) {
|
|
|
|
GLuint depthRB, stencilRB;
|
|
|
|
|
2018-11-30 10:46:48 +00:00
|
|
|
{
|
2017-12-19 02:19:38 +00:00
|
|
|
GLContext::LocalErrorScope errorScope(*gl);
|
2018-11-30 10:46:48 +00:00
|
|
|
|
2017-12-19 02:19:38 +00:00
|
|
|
if (gl->IsSupported(GLFeature::packed_depth_stencil)) {
|
|
|
|
depthRB = fnAllocRB(mozFB->mDepthRB, LOCAL_GL_DEPTH24_STENCIL8);
|
|
|
|
stencilRB = depthRB; // Ignore unused mStencilRB.
|
2018-11-30 10:46:48 +00:00
|
|
|
} else {
|
2017-12-19 02:19:38 +00:00
|
|
|
depthRB = fnAllocRB(mozFB->mDepthRB, LOCAL_GL_DEPTH_COMPONENT24);
|
|
|
|
stencilRB = fnAllocRB(mozFB->mStencilRB, LOCAL_GL_STENCIL_INDEX8);
|
2018-11-30 10:46:48 +00:00
|
|
|
}
|
|
|
|
|
2017-12-19 02:19:38 +00:00
|
|
|
const auto err = errorScope.GetError();
|
|
|
|
if (err) {
|
|
|
|
MOZ_ASSERT(err == LOCAL_GL_OUT_OF_MEMORY);
|
|
|
|
return nullptr;
|
2018-11-30 10:46:48 +00:00
|
|
|
}
|
2017-12-19 02:19:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
|
|
|
|
LOCAL_GL_DEPTH_ATTACHMENT,
|
|
|
|
LOCAL_GL_RENDERBUFFER, depthRB);
|
|
|
|
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
|
|
|
|
LOCAL_GL_STENCIL_ATTACHMENT,
|
|
|
|
LOCAL_GL_RENDERBUFFER, stencilRB);
|
2018-11-30 10:46:48 +00:00
|
|
|
}
|
|
|
|
|
2017-12-19 02:19:38 +00:00
|
|
|
const auto status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
|
|
|
|
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
|
|
|
MOZ_ASSERT(false);
|
|
|
|
return nullptr;
|
2018-11-30 10:46:48 +00:00
|
|
|
}
|
|
|
|
|
2018-06-01 15:59:07 +00:00
|
|
|
return mozFB;
|
2017-12-19 02:19:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////
|
|
|
|
|
|
|
|
MozFramebuffer::MozFramebuffer(GLContext* const gl, const gfx::IntSize& size,
|
|
|
|
const uint32_t samples, const bool depthStencil,
|
|
|
|
const GLenum colorTarget, const GLuint colorName)
|
|
|
|
: mWeakGL(gl),
|
|
|
|
mSize(size),
|
|
|
|
mSamples(samples),
|
|
|
|
mFB(gl->CreateFramebuffer()),
|
|
|
|
mColorTarget(colorTarget),
|
|
|
|
mColorName(colorName),
|
|
|
|
mDepthRB(depthStencil ? gl->CreateRenderbuffer() : 0),
|
|
|
|
mStencilRB(depthStencil ? gl->CreateRenderbuffer() : 0) {
|
|
|
|
MOZ_ASSERT(mColorTarget);
|
|
|
|
MOZ_ASSERT(mColorName);
|
|
|
|
}
|
|
|
|
|
|
|
|
MozFramebuffer::~MozFramebuffer() {
|
|
|
|
GLContext* const gl = mWeakGL;
|
|
|
|
if (!gl || !gl->MakeCurrent()) return;
|
|
|
|
|
|
|
|
gl->DeleteFramebuffer(mFB);
|
|
|
|
gl->DeleteRenderbuffer(mDepthRB);
|
|
|
|
gl->DeleteRenderbuffer(mStencilRB);
|
|
|
|
|
|
|
|
DeleteByTarget(gl, mColorTarget, mColorName);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace gl
|
|
|
|
} // namespace mozilla
|