1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */
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/. */
6 #include "MozFramebuffer.h"
9 #include "mozilla/gfx/Logging.h"
10 #include "ScopedGLHelpers.h"
15 static void DeleteByTarget(GLContext
* const gl
, const GLenum target
,
17 if (target
== LOCAL_GL_RENDERBUFFER
) {
18 gl
->DeleteRenderbuffer(name
);
20 gl
->DeleteTexture(name
);
24 UniquePtr
<MozFramebuffer
> MozFramebuffer::Create(GLContext
* const gl
,
25 const gfx::IntSize
& size
,
26 const uint32_t samples
,
27 const bool depthStencil
) {
28 if (samples
&& !gl
->IsSupported(GLFeature::framebuffer_multisample
))
31 if (uint32_t(size
.width
) > gl
->MaxTexOrRbSize() ||
32 uint32_t(size
.height
) > gl
->MaxTexOrRbSize() ||
33 samples
> gl
->MaxSamples()) {
39 GLContext::LocalErrorScope
errorScope(*gl
);
44 colorTarget
= LOCAL_GL_RENDERBUFFER
;
45 colorName
= gl
->CreateRenderbuffer();
46 const ScopedBindRenderbuffer
bindRB(gl
, colorName
);
47 gl
->fRenderbufferStorageMultisample(colorTarget
, samples
, LOCAL_GL_RGBA8
,
48 size
.width
, size
.height
);
50 colorTarget
= LOCAL_GL_TEXTURE_2D
;
51 colorName
= gl
->CreateTexture();
52 const ScopedBindTexture
bindTex(gl
, colorName
);
53 gl
->TexParams_SetClampNoMips();
54 gl
->fTexImage2D(colorTarget
, 0, LOCAL_GL_RGBA
, size
.width
, size
.height
, 0,
55 LOCAL_GL_RGBA
, LOCAL_GL_UNSIGNED_BYTE
, nullptr);
58 const auto err
= errorScope
.GetError();
60 if (err
!= LOCAL_GL_OUT_OF_MEMORY
) {
61 gfxCriticalNote
<< "Unexpected error: " << gfx::hexa(err
) << ": "
62 << GLContext::GLErrorToString(err
);
64 DeleteByTarget(gl
, colorTarget
, colorName
);
70 depthStencil
? DepthAndStencilBuffer::Create(gl
, size
, samples
) : nullptr,
71 colorTarget
, colorName
);
74 UniquePtr
<MozFramebuffer
> MozFramebuffer::CreateForBacking(
75 GLContext
* const gl
, const gfx::IntSize
& size
, const uint32_t samples
,
76 bool depthStencil
, const GLenum colorTarget
, const GLuint colorName
) {
79 depthStencil
? DepthAndStencilBuffer::Create(gl
, size
, samples
) : nullptr,
80 colorTarget
, colorName
);
83 /* static */ UniquePtr
<MozFramebuffer
>
84 MozFramebuffer::CreateForBackingWithSharedDepthAndStencil(
85 const gfx::IntSize
& size
, const uint32_t samples
, GLenum colorTarget
,
87 const RefPtr
<DepthAndStencilBuffer
>& depthAndStencilBuffer
) {
88 auto gl
= depthAndStencilBuffer
->gl();
89 if (!gl
|| !gl
->MakeCurrent()) {
92 return CreateImpl(gl
, size
, samples
, depthAndStencilBuffer
, colorTarget
,
96 /* static */ UniquePtr
<MozFramebuffer
> MozFramebuffer::CreateImpl(
97 GLContext
* const gl
, const gfx::IntSize
& size
, const uint32_t samples
,
98 const RefPtr
<DepthAndStencilBuffer
>& depthAndStencilBuffer
,
99 const GLenum colorTarget
, const GLuint colorName
) {
100 GLuint fb
= gl
->CreateFramebuffer();
101 const ScopedBindFramebuffer
bindFB(gl
, fb
);
103 if (colorTarget
== LOCAL_GL_RENDERBUFFER
) {
104 gl
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
,
105 LOCAL_GL_COLOR_ATTACHMENT0
, colorTarget
,
108 gl
->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_COLOR_ATTACHMENT0
,
109 colorTarget
, colorName
, 0);
112 if (depthAndStencilBuffer
) {
113 gl
->fFramebufferRenderbuffer(
114 LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_DEPTH_ATTACHMENT
, LOCAL_GL_RENDERBUFFER
,
115 depthAndStencilBuffer
->mDepthRB
);
116 gl
->fFramebufferRenderbuffer(
117 LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_STENCIL_ATTACHMENT
,
118 LOCAL_GL_RENDERBUFFER
, depthAndStencilBuffer
->mStencilRB
);
121 const auto status
= gl
->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER
);
122 if (status
!= LOCAL_GL_FRAMEBUFFER_COMPLETE
) {
123 gfxCriticalNote
<< "MozFramebuffer::CreateImpl(size:" << size
124 << ", samples:" << samples
125 << ", depthAndStencil:" << bool(depthAndStencilBuffer
)
126 << ", colorTarget:" << gfx::hexa(colorTarget
)
127 << ", colorName:" << colorName
<< "): Incomplete: 0x"
128 << gfx::hexa(status
);
132 return UniquePtr
<MozFramebuffer
>(new MozFramebuffer(
133 gl
, size
, fb
, samples
, depthAndStencilBuffer
, colorTarget
, colorName
));
136 /* static */ RefPtr
<DepthAndStencilBuffer
> DepthAndStencilBuffer::Create(
137 GLContext
* const gl
, const gfx::IntSize
& size
, const uint32_t samples
) {
138 const auto fnAllocRB
= [&](GLenum format
) {
139 GLuint rb
= gl
->CreateRenderbuffer();
140 const ScopedBindRenderbuffer
bindRB(gl
, rb
);
142 gl
->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER
, samples
,
143 format
, size
.width
, size
.height
);
145 gl
->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER
, format
, size
.width
,
151 GLuint depthRB
, stencilRB
;
153 GLContext::LocalErrorScope
errorScope(*gl
);
155 if (gl
->IsSupported(GLFeature::packed_depth_stencil
)) {
156 depthRB
= fnAllocRB(LOCAL_GL_DEPTH24_STENCIL8
);
157 stencilRB
= depthRB
; // Ignore unused mStencilRB.
159 depthRB
= fnAllocRB(LOCAL_GL_DEPTH_COMPONENT24
);
160 stencilRB
= fnAllocRB(LOCAL_GL_STENCIL_INDEX8
);
163 const auto err
= errorScope
.GetError();
165 MOZ_ASSERT(err
== LOCAL_GL_OUT_OF_MEMORY
);
170 return new DepthAndStencilBuffer(gl
, size
, depthRB
, stencilRB
);
175 MozFramebuffer::MozFramebuffer(
176 GLContext
* const gl
, const gfx::IntSize
& size
, GLuint fb
,
177 const uint32_t samples
, RefPtr
<DepthAndStencilBuffer
> depthAndStencilBuffer
,
178 const GLenum colorTarget
, const GLuint colorName
)
183 mColorTarget(colorTarget
),
184 mDepthAndStencilBuffer(std::move(depthAndStencilBuffer
)),
185 mColorName(colorName
) {
186 MOZ_ASSERT(mColorTarget
);
187 MOZ_ASSERT(mColorName
);
190 MozFramebuffer::~MozFramebuffer() {
191 GLContext
* const gl
= mWeakGL
;
192 if (!gl
|| !gl
->MakeCurrent()) {
196 gl
->DeleteFramebuffer(mFB
);
198 DeleteByTarget(gl
, mColorTarget
, mColorName
);
201 bool MozFramebuffer::HasDepth() const {
202 return mDepthAndStencilBuffer
&& mDepthAndStencilBuffer
->mDepthRB
;
205 bool MozFramebuffer::HasStencil() const {
206 return mDepthAndStencilBuffer
&& mDepthAndStencilBuffer
->mStencilRB
;
209 DepthAndStencilBuffer::DepthAndStencilBuffer(GLContext
* gl
,
210 const gfx::IntSize
& size
,
211 GLuint depthRB
, GLuint stencilRB
)
212 : mWeakGL(gl
), mSize(size
), mDepthRB(depthRB
), mStencilRB(stencilRB
) {}
214 DepthAndStencilBuffer::~DepthAndStencilBuffer() {
215 GLContext
* const gl
= mWeakGL
;
216 if (!gl
|| !gl
->MakeCurrent()) {
220 gl
->DeleteRenderbuffer(mDepthRB
);
221 gl
->DeleteRenderbuffer(mStencilRB
);
225 } // namespace mozilla