MozFramebuffer.cpp (7722B)
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/. */ 5 6 #include "MozFramebuffer.h" 7 8 #include "GLContext.h" 9 #include "mozilla/gfx/Logging.h" 10 #include "ScopedGLHelpers.h" 11 12 namespace mozilla { 13 namespace gl { 14 15 static void DeleteByTarget(GLContext* const gl, const GLenum target, 16 const GLuint name) { 17 if (target == LOCAL_GL_RENDERBUFFER) { 18 gl->DeleteRenderbuffer(name); 19 } else { 20 gl->DeleteTexture(name); 21 } 22 } 23 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)) 29 return nullptr; 30 31 if (uint32_t(size.width) > gl->MaxTexOrRbSize() || 32 uint32_t(size.height) > gl->MaxTexOrRbSize() || 33 samples > gl->MaxSamples()) { 34 return nullptr; 35 } 36 37 gl->MakeCurrent(); 38 39 GLContext::LocalErrorScope errorScope(*gl); 40 41 GLenum colorTarget; 42 GLuint colorName; 43 if (samples) { 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); 49 } else { 50 colorTarget = LOCAL_GL_TEXTURE_2D; 51 colorName = gl->CreateTexture(); 52 const ScopedBindTexture bindTex(gl, colorName, colorTarget); 53 gl->TexParams_SetClampNoMips(colorTarget); 54 gl->fTexImage2D(colorTarget, 0, LOCAL_GL_RGBA, size.width, size.height, 0, 55 LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, nullptr); 56 } 57 58 const auto err = errorScope.GetError(); 59 if (err) { 60 if (err != LOCAL_GL_OUT_OF_MEMORY) { 61 gfxCriticalNote << "Unexpected error: " << gfx::hexa(err) << ": " 62 << GLContext::GLErrorToString(err); 63 } 64 DeleteByTarget(gl, colorTarget, colorName); 65 return nullptr; 66 } 67 68 return CreateImpl( 69 gl, size, samples, 70 depthStencil ? DepthAndStencilBuffer::Create(gl, size, samples) : nullptr, 71 colorTarget, colorName); 72 } 73 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) { 77 return CreateImpl( 78 gl, size, samples, 79 depthStencil ? DepthAndStencilBuffer::Create(gl, size, samples) : nullptr, 80 colorTarget, colorName); 81 } 82 83 /* static */ UniquePtr<MozFramebuffer> 84 MozFramebuffer::CreateForBackingWithSharedDepthAndStencil( 85 const gfx::IntSize& size, const uint32_t samples, GLenum colorTarget, 86 GLuint colorName, 87 const RefPtr<DepthAndStencilBuffer>& depthAndStencilBuffer) { 88 auto gl = depthAndStencilBuffer->gl(); 89 if (!gl || !gl->MakeCurrent()) { 90 return nullptr; 91 } 92 return CreateImpl(gl, size, samples, depthAndStencilBuffer, colorTarget, 93 colorName); 94 } 95 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); 102 103 if (colorTarget == LOCAL_GL_RENDERBUFFER) { 104 gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, 105 LOCAL_GL_COLOR_ATTACHMENT0, colorTarget, 106 colorName); 107 } else { 108 gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, 109 colorTarget, colorName, 0); 110 } 111 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); 119 } 120 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); 129 return nullptr; 130 } 131 132 return UniquePtr<MozFramebuffer>(new MozFramebuffer( 133 gl, size, fb, samples, depthAndStencilBuffer, colorTarget, colorName)); 134 } 135 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); 141 if (samples) { 142 gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, samples, 143 format, size.width, size.height); 144 } else { 145 gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, format, size.width, 146 size.height); 147 } 148 return rb; 149 }; 150 151 GLuint depthRB, stencilRB; 152 { 153 GLContext::LocalErrorScope errorScope(*gl); 154 155 if (gl->IsSupported(GLFeature::packed_depth_stencil)) { 156 depthRB = fnAllocRB(LOCAL_GL_DEPTH24_STENCIL8); 157 stencilRB = depthRB; // Ignore unused mStencilRB. 158 } else { 159 depthRB = fnAllocRB(LOCAL_GL_DEPTH_COMPONENT24); 160 stencilRB = fnAllocRB(LOCAL_GL_STENCIL_INDEX8); 161 } 162 163 const auto err = errorScope.GetError(); 164 if (err) { 165 MOZ_ASSERT(err == LOCAL_GL_OUT_OF_MEMORY); 166 return nullptr; 167 } 168 } 169 170 return new DepthAndStencilBuffer(gl, size, depthRB, stencilRB); 171 } 172 173 //////////////////// 174 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) 179 : mWeakGL(gl), 180 mSize(size), 181 mSamples(samples), 182 mFB(fb), 183 mColorTarget(colorTarget), 184 mDepthAndStencilBuffer(std::move(depthAndStencilBuffer)), 185 mColorName(colorName) { 186 MOZ_ASSERT(mColorTarget); 187 MOZ_ASSERT(mColorName); 188 } 189 190 MozFramebuffer::~MozFramebuffer() { 191 GLContext* const gl = mWeakGL; 192 if (!gl || !gl->MakeCurrent()) { 193 return; 194 } 195 196 gl->DeleteFramebuffer(mFB); 197 198 DeleteByTarget(gl, mColorTarget, mColorName); 199 } 200 201 bool MozFramebuffer::HasDepth() const { 202 return mDepthAndStencilBuffer && mDepthAndStencilBuffer->mDepthRB; 203 } 204 205 bool MozFramebuffer::HasStencil() const { 206 return mDepthAndStencilBuffer && mDepthAndStencilBuffer->mStencilRB; 207 } 208 209 DepthAndStencilBuffer::DepthAndStencilBuffer(GLContext* gl, 210 const gfx::IntSize& size, 211 GLuint depthRB, GLuint stencilRB) 212 : mWeakGL(gl), mSize(size), mDepthRB(depthRB), mStencilRB(stencilRB) {} 213 214 DepthAndStencilBuffer::~DepthAndStencilBuffer() { 215 GLContext* const gl = mWeakGL; 216 if (!gl || !gl->MakeCurrent()) { 217 return; 218 } 219 220 gl->DeleteRenderbuffer(mDepthRB); 221 gl->DeleteRenderbuffer(mStencilRB); 222 } 223 224 } // namespace gl 225 } // namespace mozilla