Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include "WebGLContext.h" |
michael@0 | 7 | #include "WebGLFramebuffer.h" |
michael@0 | 8 | #include "WebGLExtensions.h" |
michael@0 | 9 | #include "WebGLRenderbuffer.h" |
michael@0 | 10 | #include "WebGLTexture.h" |
michael@0 | 11 | #include "mozilla/dom/WebGLRenderingContextBinding.h" |
michael@0 | 12 | #include "WebGLTexture.h" |
michael@0 | 13 | #include "WebGLRenderbuffer.h" |
michael@0 | 14 | #include "GLContext.h" |
michael@0 | 15 | #include "WebGLContextUtils.h" |
michael@0 | 16 | |
michael@0 | 17 | using namespace mozilla; |
michael@0 | 18 | using namespace mozilla::gl; |
michael@0 | 19 | |
michael@0 | 20 | JSObject* |
michael@0 | 21 | WebGLFramebuffer::WrapObject(JSContext* cx) |
michael@0 | 22 | { |
michael@0 | 23 | return dom::WebGLFramebufferBinding::Wrap(cx, this); |
michael@0 | 24 | } |
michael@0 | 25 | |
michael@0 | 26 | WebGLFramebuffer::WebGLFramebuffer(WebGLContext* context) |
michael@0 | 27 | : WebGLContextBoundObject(context) |
michael@0 | 28 | , mStatus(0) |
michael@0 | 29 | , mHasEverBeenBound(false) |
michael@0 | 30 | , mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT) |
michael@0 | 31 | , mStencilAttachment(LOCAL_GL_STENCIL_ATTACHMENT) |
michael@0 | 32 | , mDepthStencilAttachment(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) |
michael@0 | 33 | { |
michael@0 | 34 | SetIsDOMBinding(); |
michael@0 | 35 | mContext->MakeContextCurrent(); |
michael@0 | 36 | mContext->gl->fGenFramebuffers(1, &mGLName); |
michael@0 | 37 | mContext->mFramebuffers.insertBack(this); |
michael@0 | 38 | |
michael@0 | 39 | mColorAttachments.SetLength(1); |
michael@0 | 40 | mColorAttachments[0].mAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0; |
michael@0 | 41 | } |
michael@0 | 42 | |
michael@0 | 43 | bool |
michael@0 | 44 | WebGLFramebuffer::Attachment::IsDeleteRequested() const |
michael@0 | 45 | { |
michael@0 | 46 | return Texture() ? Texture()->IsDeleteRequested() |
michael@0 | 47 | : Renderbuffer() ? Renderbuffer()->IsDeleteRequested() |
michael@0 | 48 | : false; |
michael@0 | 49 | } |
michael@0 | 50 | |
michael@0 | 51 | bool |
michael@0 | 52 | WebGLFramebuffer::Attachment::HasAlpha() const |
michael@0 | 53 | { |
michael@0 | 54 | MOZ_ASSERT(HasImage()); |
michael@0 | 55 | |
michael@0 | 56 | GLenum format = 0; |
michael@0 | 57 | if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel)) |
michael@0 | 58 | format = Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).WebGLFormat(); |
michael@0 | 59 | else if (Renderbuffer()) |
michael@0 | 60 | format = Renderbuffer()->InternalFormat(); |
michael@0 | 61 | return FormatHasAlpha(format); |
michael@0 | 62 | } |
michael@0 | 63 | |
michael@0 | 64 | bool |
michael@0 | 65 | WebGLFramebuffer::Attachment::IsReadableFloat() const |
michael@0 | 66 | { |
michael@0 | 67 | if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel)) { |
michael@0 | 68 | GLenum type = Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).WebGLType(); |
michael@0 | 69 | switch (type) { |
michael@0 | 70 | case LOCAL_GL_FLOAT: |
michael@0 | 71 | case LOCAL_GL_HALF_FLOAT_OES: |
michael@0 | 72 | return true; |
michael@0 | 73 | } |
michael@0 | 74 | return false; |
michael@0 | 75 | } |
michael@0 | 76 | |
michael@0 | 77 | if (Renderbuffer()) { |
michael@0 | 78 | GLenum format = Renderbuffer()->InternalFormat(); |
michael@0 | 79 | switch (format) { |
michael@0 | 80 | case LOCAL_GL_RGB16F: |
michael@0 | 81 | case LOCAL_GL_RGBA16F: |
michael@0 | 82 | case LOCAL_GL_RGB32F: |
michael@0 | 83 | case LOCAL_GL_RGBA32F: |
michael@0 | 84 | return true; |
michael@0 | 85 | } |
michael@0 | 86 | return false; |
michael@0 | 87 | } |
michael@0 | 88 | |
michael@0 | 89 | MOZ_ASSERT(false, "Should not get here."); |
michael@0 | 90 | return false; |
michael@0 | 91 | } |
michael@0 | 92 | |
michael@0 | 93 | void |
michael@0 | 94 | WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex, GLenum target, GLint level) |
michael@0 | 95 | { |
michael@0 | 96 | mTexturePtr = tex; |
michael@0 | 97 | mRenderbufferPtr = nullptr; |
michael@0 | 98 | mTexImageTarget = target; |
michael@0 | 99 | mTexImageLevel = level; |
michael@0 | 100 | |
michael@0 | 101 | mNeedsFinalize = true; |
michael@0 | 102 | } |
michael@0 | 103 | |
michael@0 | 104 | void |
michael@0 | 105 | WebGLFramebuffer::Attachment::SetRenderbuffer(WebGLRenderbuffer* rb) |
michael@0 | 106 | { |
michael@0 | 107 | mTexturePtr = nullptr; |
michael@0 | 108 | mRenderbufferPtr = rb; |
michael@0 | 109 | |
michael@0 | 110 | mNeedsFinalize = true; |
michael@0 | 111 | } |
michael@0 | 112 | |
michael@0 | 113 | bool |
michael@0 | 114 | WebGLFramebuffer::Attachment::HasUninitializedImageData() const |
michael@0 | 115 | { |
michael@0 | 116 | if (!HasImage()) |
michael@0 | 117 | return false; |
michael@0 | 118 | |
michael@0 | 119 | if (Renderbuffer()) { |
michael@0 | 120 | return Renderbuffer()->HasUninitializedImageData(); |
michael@0 | 121 | } |
michael@0 | 122 | |
michael@0 | 123 | if (Texture()) { |
michael@0 | 124 | MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel)); |
michael@0 | 125 | return Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).HasUninitializedImageData(); |
michael@0 | 126 | } |
michael@0 | 127 | |
michael@0 | 128 | MOZ_ASSERT(false, "Should not get here."); |
michael@0 | 129 | return false; |
michael@0 | 130 | } |
michael@0 | 131 | |
michael@0 | 132 | void |
michael@0 | 133 | WebGLFramebuffer::Attachment::SetImageDataStatus(WebGLImageDataStatus newStatus) |
michael@0 | 134 | { |
michael@0 | 135 | if (!HasImage()) |
michael@0 | 136 | return; |
michael@0 | 137 | |
michael@0 | 138 | if (Renderbuffer()) { |
michael@0 | 139 | Renderbuffer()->SetImageDataStatus(newStatus); |
michael@0 | 140 | return; |
michael@0 | 141 | } |
michael@0 | 142 | |
michael@0 | 143 | if (Texture()) { |
michael@0 | 144 | Texture()->SetImageDataStatus(mTexImageTarget, mTexImageLevel, newStatus); |
michael@0 | 145 | return; |
michael@0 | 146 | } |
michael@0 | 147 | |
michael@0 | 148 | MOZ_ASSERT(false, "Should not get here."); |
michael@0 | 149 | } |
michael@0 | 150 | |
michael@0 | 151 | bool |
michael@0 | 152 | WebGLFramebuffer::Attachment::HasImage() const |
michael@0 | 153 | { |
michael@0 | 154 | if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel)) |
michael@0 | 155 | return true; |
michael@0 | 156 | |
michael@0 | 157 | if (Renderbuffer()) |
michael@0 | 158 | return true; |
michael@0 | 159 | |
michael@0 | 160 | return false; |
michael@0 | 161 | } |
michael@0 | 162 | |
michael@0 | 163 | const WebGLRectangleObject& |
michael@0 | 164 | WebGLFramebuffer::Attachment::RectangleObject() const |
michael@0 | 165 | { |
michael@0 | 166 | MOZ_ASSERT(HasImage(), "Make sure it has an image before requesting the rectangle."); |
michael@0 | 167 | |
michael@0 | 168 | if (Texture()) { |
michael@0 | 169 | MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel)); |
michael@0 | 170 | return Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel); |
michael@0 | 171 | } |
michael@0 | 172 | |
michael@0 | 173 | if (Renderbuffer()) { |
michael@0 | 174 | return *Renderbuffer(); |
michael@0 | 175 | } |
michael@0 | 176 | |
michael@0 | 177 | MOZ_CRASH("Should not get here."); |
michael@0 | 178 | } |
michael@0 | 179 | |
michael@0 | 180 | /* The following IsValidFBOTextureXXX functions check the internal |
michael@0 | 181 | format that is used by GL or GL ES texture formats. This |
michael@0 | 182 | corresponds to the state that is stored in |
michael@0 | 183 | WebGLTexture::ImageInfo::InternalFormat()*/ |
michael@0 | 184 | static inline bool |
michael@0 | 185 | IsValidFBOTextureColorFormat(GLenum internalFormat) |
michael@0 | 186 | { |
michael@0 | 187 | /* These formats are internal formats for each texture -- the actual |
michael@0 | 188 | * low level format, which we might have to do conversions for when |
michael@0 | 189 | * running against desktop GL (e.g. GL_RGBA + GL_FLOAT -> GL_RGBA32F). |
michael@0 | 190 | * |
michael@0 | 191 | * This function just handles all of them whether desktop GL or ES. |
michael@0 | 192 | */ |
michael@0 | 193 | |
michael@0 | 194 | return ( |
michael@0 | 195 | /* linear 8-bit formats */ |
michael@0 | 196 | internalFormat == LOCAL_GL_ALPHA || |
michael@0 | 197 | internalFormat == LOCAL_GL_LUMINANCE || |
michael@0 | 198 | internalFormat == LOCAL_GL_LUMINANCE_ALPHA || |
michael@0 | 199 | internalFormat == LOCAL_GL_RGB || |
michael@0 | 200 | internalFormat == LOCAL_GL_RGBA || |
michael@0 | 201 | /* sRGB 8-bit formats */ |
michael@0 | 202 | internalFormat == LOCAL_GL_SRGB_EXT || |
michael@0 | 203 | internalFormat == LOCAL_GL_SRGB_ALPHA_EXT || |
michael@0 | 204 | /* linear float32 formats */ |
michael@0 | 205 | internalFormat == LOCAL_GL_ALPHA32F_ARB || |
michael@0 | 206 | internalFormat == LOCAL_GL_LUMINANCE32F_ARB || |
michael@0 | 207 | internalFormat == LOCAL_GL_LUMINANCE_ALPHA32F_ARB || |
michael@0 | 208 | internalFormat == LOCAL_GL_RGB32F_ARB || |
michael@0 | 209 | internalFormat == LOCAL_GL_RGBA32F_ARB || |
michael@0 | 210 | /* texture_half_float formats */ |
michael@0 | 211 | internalFormat == LOCAL_GL_ALPHA16F_ARB || |
michael@0 | 212 | internalFormat == LOCAL_GL_LUMINANCE16F_ARB || |
michael@0 | 213 | internalFormat == LOCAL_GL_LUMINANCE_ALPHA16F_ARB || |
michael@0 | 214 | internalFormat == LOCAL_GL_RGB16F_ARB || |
michael@0 | 215 | internalFormat == LOCAL_GL_RGBA16F_ARB |
michael@0 | 216 | ); |
michael@0 | 217 | } |
michael@0 | 218 | |
michael@0 | 219 | static inline bool |
michael@0 | 220 | IsValidFBOTextureDepthFormat(GLenum internalFormat) |
michael@0 | 221 | { |
michael@0 | 222 | return ( |
michael@0 | 223 | internalFormat == LOCAL_GL_DEPTH_COMPONENT || |
michael@0 | 224 | internalFormat == LOCAL_GL_DEPTH_COMPONENT16 || |
michael@0 | 225 | internalFormat == LOCAL_GL_DEPTH_COMPONENT32); |
michael@0 | 226 | } |
michael@0 | 227 | |
michael@0 | 228 | static inline bool |
michael@0 | 229 | IsValidFBOTextureDepthStencilFormat(GLenum internalFormat) |
michael@0 | 230 | { |
michael@0 | 231 | return ( |
michael@0 | 232 | internalFormat == LOCAL_GL_DEPTH_STENCIL || |
michael@0 | 233 | internalFormat == LOCAL_GL_DEPTH24_STENCIL8); |
michael@0 | 234 | } |
michael@0 | 235 | |
michael@0 | 236 | /* The following IsValidFBORenderbufferXXX functions check the internal |
michael@0 | 237 | format that is stored by WebGLRenderbuffer::InternalFormat(). Valid |
michael@0 | 238 | values can be found in WebGLContext::RenderbufferStorage. */ |
michael@0 | 239 | static inline bool |
michael@0 | 240 | IsValidFBORenderbufferColorFormat(GLenum internalFormat) |
michael@0 | 241 | { |
michael@0 | 242 | return ( |
michael@0 | 243 | internalFormat == LOCAL_GL_RGB565 || |
michael@0 | 244 | internalFormat == LOCAL_GL_RGB5_A1 || |
michael@0 | 245 | internalFormat == LOCAL_GL_RGBA4 || |
michael@0 | 246 | internalFormat == LOCAL_GL_SRGB8_ALPHA8_EXT); |
michael@0 | 247 | } |
michael@0 | 248 | |
michael@0 | 249 | static inline bool |
michael@0 | 250 | IsValidFBORenderbufferDepthFormat(GLenum internalFormat) |
michael@0 | 251 | { |
michael@0 | 252 | return internalFormat == LOCAL_GL_DEPTH_COMPONENT16; |
michael@0 | 253 | } |
michael@0 | 254 | |
michael@0 | 255 | static inline bool |
michael@0 | 256 | IsValidFBORenderbufferDepthStencilFormat(GLenum internalFormat) |
michael@0 | 257 | { |
michael@0 | 258 | return internalFormat == LOCAL_GL_DEPTH_STENCIL; |
michael@0 | 259 | } |
michael@0 | 260 | |
michael@0 | 261 | static inline bool |
michael@0 | 262 | IsValidFBORenderbufferStencilFormat(GLenum internalFormat) |
michael@0 | 263 | { |
michael@0 | 264 | return internalFormat == LOCAL_GL_STENCIL_INDEX8; |
michael@0 | 265 | } |
michael@0 | 266 | |
michael@0 | 267 | bool |
michael@0 | 268 | WebGLFramebuffer::Attachment::IsComplete() const |
michael@0 | 269 | { |
michael@0 | 270 | if (!HasImage()) |
michael@0 | 271 | return false; |
michael@0 | 272 | |
michael@0 | 273 | const WebGLRectangleObject& rect = RectangleObject(); |
michael@0 | 274 | |
michael@0 | 275 | if (!rect.Width() || |
michael@0 | 276 | !rect.Height()) |
michael@0 | 277 | { |
michael@0 | 278 | return false; |
michael@0 | 279 | } |
michael@0 | 280 | |
michael@0 | 281 | if (Texture()) { |
michael@0 | 282 | MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel)); |
michael@0 | 283 | const WebGLTexture::ImageInfo& imageInfo = |
michael@0 | 284 | Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel); |
michael@0 | 285 | GLenum webGLFormat = imageInfo.WebGLFormat(); |
michael@0 | 286 | |
michael@0 | 287 | if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT) |
michael@0 | 288 | return IsValidFBOTextureDepthFormat(webGLFormat); |
michael@0 | 289 | |
michael@0 | 290 | if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) |
michael@0 | 291 | return IsValidFBOTextureDepthStencilFormat(webGLFormat); |
michael@0 | 292 | |
michael@0 | 293 | if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 && |
michael@0 | 294 | mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + |
michael@0 | 295 | WebGLContext::sMaxColorAttachments)) |
michael@0 | 296 | { |
michael@0 | 297 | return IsValidFBOTextureColorFormat(webGLFormat); |
michael@0 | 298 | } |
michael@0 | 299 | MOZ_ASSERT(false, "Invalid WebGL attachment point?"); |
michael@0 | 300 | return false; |
michael@0 | 301 | } |
michael@0 | 302 | |
michael@0 | 303 | if (Renderbuffer()) { |
michael@0 | 304 | GLenum internalFormat = Renderbuffer()->InternalFormat(); |
michael@0 | 305 | |
michael@0 | 306 | if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT) |
michael@0 | 307 | return IsValidFBORenderbufferDepthFormat(internalFormat); |
michael@0 | 308 | |
michael@0 | 309 | if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT) |
michael@0 | 310 | return IsValidFBORenderbufferStencilFormat(internalFormat); |
michael@0 | 311 | |
michael@0 | 312 | if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) |
michael@0 | 313 | return IsValidFBORenderbufferDepthStencilFormat(internalFormat); |
michael@0 | 314 | |
michael@0 | 315 | if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 && |
michael@0 | 316 | mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + |
michael@0 | 317 | WebGLContext::sMaxColorAttachments)) |
michael@0 | 318 | { |
michael@0 | 319 | return IsValidFBORenderbufferColorFormat(internalFormat); |
michael@0 | 320 | } |
michael@0 | 321 | MOZ_ASSERT(false, "Invalid WebGL attachment point?"); |
michael@0 | 322 | return false; |
michael@0 | 323 | } |
michael@0 | 324 | |
michael@0 | 325 | MOZ_ASSERT(false, "Should not get here."); |
michael@0 | 326 | return false; |
michael@0 | 327 | } |
michael@0 | 328 | |
michael@0 | 329 | void |
michael@0 | 330 | WebGLFramebuffer::Attachment::FinalizeAttachment(GLContext* gl, GLenum attachmentLoc) const |
michael@0 | 331 | { |
michael@0 | 332 | if (!mNeedsFinalize) |
michael@0 | 333 | return; |
michael@0 | 334 | |
michael@0 | 335 | mNeedsFinalize = false; |
michael@0 | 336 | |
michael@0 | 337 | if (!HasImage()) { |
michael@0 | 338 | if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { |
michael@0 | 339 | gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, |
michael@0 | 340 | LOCAL_GL_RENDERBUFFER, 0); |
michael@0 | 341 | gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, |
michael@0 | 342 | LOCAL_GL_RENDERBUFFER, 0); |
michael@0 | 343 | } else { |
michael@0 | 344 | gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachmentLoc, |
michael@0 | 345 | LOCAL_GL_RENDERBUFFER, 0); |
michael@0 | 346 | } |
michael@0 | 347 | |
michael@0 | 348 | return; |
michael@0 | 349 | } |
michael@0 | 350 | MOZ_ASSERT(HasImage()); |
michael@0 | 351 | |
michael@0 | 352 | if (Texture()) { |
michael@0 | 353 | MOZ_ASSERT(gl == Texture()->Context()->gl); |
michael@0 | 354 | |
michael@0 | 355 | if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { |
michael@0 | 356 | gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, |
michael@0 | 357 | TexImageTarget(), Texture()->GLName(), TexImageLevel()); |
michael@0 | 358 | gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, |
michael@0 | 359 | TexImageTarget(), Texture()->GLName(), TexImageLevel()); |
michael@0 | 360 | } else { |
michael@0 | 361 | gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentLoc, |
michael@0 | 362 | TexImageTarget(), Texture()->GLName(), TexImageLevel()); |
michael@0 | 363 | } |
michael@0 | 364 | return; |
michael@0 | 365 | } |
michael@0 | 366 | |
michael@0 | 367 | if (Renderbuffer()) { |
michael@0 | 368 | Renderbuffer()->FramebufferRenderbuffer(attachmentLoc); |
michael@0 | 369 | return; |
michael@0 | 370 | } |
michael@0 | 371 | |
michael@0 | 372 | MOZ_ASSERT(false, "Should not get here."); |
michael@0 | 373 | } |
michael@0 | 374 | |
michael@0 | 375 | void |
michael@0 | 376 | WebGLFramebuffer::Delete() |
michael@0 | 377 | { |
michael@0 | 378 | DetachAllAttachments(); |
michael@0 | 379 | mColorAttachments.Clear(); |
michael@0 | 380 | mDepthAttachment.Reset(); |
michael@0 | 381 | mStencilAttachment.Reset(); |
michael@0 | 382 | mDepthStencilAttachment.Reset(); |
michael@0 | 383 | |
michael@0 | 384 | mContext->MakeContextCurrent(); |
michael@0 | 385 | mContext->gl->fDeleteFramebuffers(1, &mGLName); |
michael@0 | 386 | LinkedListElement<WebGLFramebuffer>::removeFrom(mContext->mFramebuffers); |
michael@0 | 387 | } |
michael@0 | 388 | |
michael@0 | 389 | void |
michael@0 | 390 | WebGLFramebuffer::DetachAttachment(WebGLFramebuffer::Attachment& attachment) |
michael@0 | 391 | { |
michael@0 | 392 | if (attachment.Texture()) |
michael@0 | 393 | attachment.Texture()->DetachFrom(this, attachment.mAttachmentPoint); |
michael@0 | 394 | |
michael@0 | 395 | if (attachment.Renderbuffer()) |
michael@0 | 396 | attachment.Renderbuffer()->DetachFrom(this, attachment.mAttachmentPoint); |
michael@0 | 397 | } |
michael@0 | 398 | |
michael@0 | 399 | void |
michael@0 | 400 | WebGLFramebuffer::DetachAllAttachments() |
michael@0 | 401 | { |
michael@0 | 402 | size_t count = mColorAttachments.Length(); |
michael@0 | 403 | for (size_t i = 0; i < count; i++) { |
michael@0 | 404 | DetachAttachment(mColorAttachments[i]); |
michael@0 | 405 | } |
michael@0 | 406 | |
michael@0 | 407 | DetachAttachment(mDepthAttachment); |
michael@0 | 408 | DetachAttachment(mStencilAttachment); |
michael@0 | 409 | DetachAttachment(mDepthStencilAttachment); |
michael@0 | 410 | } |
michael@0 | 411 | |
michael@0 | 412 | void |
michael@0 | 413 | WebGLFramebuffer::FramebufferRenderbuffer(GLenum target, |
michael@0 | 414 | GLenum attachment, |
michael@0 | 415 | GLenum rbtarget, |
michael@0 | 416 | WebGLRenderbuffer* wrb) |
michael@0 | 417 | { |
michael@0 | 418 | MOZ_ASSERT(mContext->mBoundFramebuffer == this); |
michael@0 | 419 | |
michael@0 | 420 | if (!mContext->ValidateObjectAllowNull("framebufferRenderbuffer: renderbuffer", wrb)) |
michael@0 | 421 | return; |
michael@0 | 422 | |
michael@0 | 423 | if (target != LOCAL_GL_FRAMEBUFFER) |
michael@0 | 424 | return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: target", target); |
michael@0 | 425 | |
michael@0 | 426 | if (rbtarget != LOCAL_GL_RENDERBUFFER) |
michael@0 | 427 | return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: renderbuffer target:", rbtarget); |
michael@0 | 428 | |
michael@0 | 429 | /* Get the requested attachment. If result is NULL, attachment is |
michael@0 | 430 | * invalid and an error is generated. |
michael@0 | 431 | * |
michael@0 | 432 | * Don't use GetAttachment(...) here because it opt builds it |
michael@0 | 433 | * returns mColorAttachment[0] for invalid attachment, which we |
michael@0 | 434 | * really don't want to mess with. |
michael@0 | 435 | */ |
michael@0 | 436 | Attachment* a = GetAttachmentOrNull(attachment); |
michael@0 | 437 | if (!a) |
michael@0 | 438 | return; // Error generated internally to GetAttachmentOrNull. |
michael@0 | 439 | |
michael@0 | 440 | /* Invalidate cached framebuffer status and inform texture of it's |
michael@0 | 441 | * new attachment |
michael@0 | 442 | */ |
michael@0 | 443 | mStatus = 0; |
michael@0 | 444 | // Detach current |
michael@0 | 445 | if (a->Texture()) |
michael@0 | 446 | a->Texture()->DetachFrom(this, attachment); |
michael@0 | 447 | else if (a->Renderbuffer()) |
michael@0 | 448 | a->Renderbuffer()->DetachFrom(this, attachment); |
michael@0 | 449 | |
michael@0 | 450 | // Attach new |
michael@0 | 451 | if (wrb) |
michael@0 | 452 | wrb->AttachTo(this, attachment); |
michael@0 | 453 | |
michael@0 | 454 | a->SetRenderbuffer(wrb); |
michael@0 | 455 | } |
michael@0 | 456 | |
michael@0 | 457 | void |
michael@0 | 458 | WebGLFramebuffer::FramebufferTexture2D(GLenum target, |
michael@0 | 459 | GLenum attachment, |
michael@0 | 460 | GLenum textarget, |
michael@0 | 461 | WebGLTexture* wtex, |
michael@0 | 462 | GLint level) |
michael@0 | 463 | { |
michael@0 | 464 | MOZ_ASSERT(mContext->mBoundFramebuffer == this); |
michael@0 | 465 | |
michael@0 | 466 | if (!mContext->ValidateObjectAllowNull("framebufferTexture2D: texture", wtex)) |
michael@0 | 467 | return; |
michael@0 | 468 | |
michael@0 | 469 | if (target != LOCAL_GL_FRAMEBUFFER) |
michael@0 | 470 | return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: target", target); |
michael@0 | 471 | |
michael@0 | 472 | if (textarget != LOCAL_GL_TEXTURE_2D && |
michael@0 | 473 | (textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X || |
michael@0 | 474 | textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)) |
michael@0 | 475 | { |
michael@0 | 476 | return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget); |
michael@0 | 477 | } |
michael@0 | 478 | |
michael@0 | 479 | if (wtex) { |
michael@0 | 480 | bool isTexture2D = wtex->Target() == LOCAL_GL_TEXTURE_2D; |
michael@0 | 481 | bool isTexTarget2D = textarget == LOCAL_GL_TEXTURE_2D; |
michael@0 | 482 | if (isTexture2D != isTexTarget2D) { |
michael@0 | 483 | return mContext->ErrorInvalidOperation("framebufferTexture2D: mismatched texture and texture target"); |
michael@0 | 484 | } |
michael@0 | 485 | } |
michael@0 | 486 | |
michael@0 | 487 | if (level != 0) |
michael@0 | 488 | return mContext->ErrorInvalidValue("framebufferTexture2D: level must be 0"); |
michael@0 | 489 | |
michael@0 | 490 | /* Get the requested attachment. If result is NULL, attachment is |
michael@0 | 491 | * invalid and an error is generated. |
michael@0 | 492 | * |
michael@0 | 493 | * Don't use GetAttachment(...) here because it opt builds it |
michael@0 | 494 | * returns mColorAttachment[0] for invalid attachment, which we |
michael@0 | 495 | * really don't want to mess with. |
michael@0 | 496 | */ |
michael@0 | 497 | Attachment* a = GetAttachmentOrNull(attachment); |
michael@0 | 498 | if (!a) |
michael@0 | 499 | return; // Error generated internally to GetAttachmentOrNull. |
michael@0 | 500 | |
michael@0 | 501 | /* Invalidate cached framebuffer status and inform texture of it's |
michael@0 | 502 | * new attachment |
michael@0 | 503 | */ |
michael@0 | 504 | mStatus = 0; |
michael@0 | 505 | // Detach current |
michael@0 | 506 | if (a->Texture()) |
michael@0 | 507 | a->Texture()->DetachFrom(this, attachment); |
michael@0 | 508 | else if (a->Renderbuffer()) |
michael@0 | 509 | a->Renderbuffer()->DetachFrom(this, attachment); |
michael@0 | 510 | |
michael@0 | 511 | // Attach new |
michael@0 | 512 | if (wtex) |
michael@0 | 513 | wtex->AttachTo(this, attachment); |
michael@0 | 514 | |
michael@0 | 515 | a->SetTexImage(wtex, textarget, level); |
michael@0 | 516 | } |
michael@0 | 517 | |
michael@0 | 518 | WebGLFramebuffer::Attachment* |
michael@0 | 519 | WebGLFramebuffer::GetAttachmentOrNull(GLenum attachment) |
michael@0 | 520 | { |
michael@0 | 521 | if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) |
michael@0 | 522 | return &mDepthStencilAttachment; |
michael@0 | 523 | |
michael@0 | 524 | if (attachment == LOCAL_GL_DEPTH_ATTACHMENT) |
michael@0 | 525 | return &mDepthAttachment; |
michael@0 | 526 | |
michael@0 | 527 | if (attachment == LOCAL_GL_STENCIL_ATTACHMENT) |
michael@0 | 528 | return &mStencilAttachment; |
michael@0 | 529 | |
michael@0 | 530 | if (!CheckColorAttachmentNumber(attachment, "getAttachmentOrNull")) |
michael@0 | 531 | return nullptr; |
michael@0 | 532 | |
michael@0 | 533 | size_t colorAttachmentId = attachment - LOCAL_GL_COLOR_ATTACHMENT0; |
michael@0 | 534 | EnsureColorAttachments(colorAttachmentId); |
michael@0 | 535 | |
michael@0 | 536 | return &mColorAttachments[colorAttachmentId]; |
michael@0 | 537 | } |
michael@0 | 538 | |
michael@0 | 539 | const WebGLFramebuffer::Attachment& |
michael@0 | 540 | WebGLFramebuffer::GetAttachment(GLenum attachment) const |
michael@0 | 541 | { |
michael@0 | 542 | if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) |
michael@0 | 543 | return mDepthStencilAttachment; |
michael@0 | 544 | if (attachment == LOCAL_GL_DEPTH_ATTACHMENT) |
michael@0 | 545 | return mDepthAttachment; |
michael@0 | 546 | if (attachment == LOCAL_GL_STENCIL_ATTACHMENT) |
michael@0 | 547 | return mStencilAttachment; |
michael@0 | 548 | |
michael@0 | 549 | if (!CheckColorAttachmentNumber(attachment, "getAttachment")) { |
michael@0 | 550 | MOZ_ASSERT(false); |
michael@0 | 551 | return mColorAttachments[0]; |
michael@0 | 552 | } |
michael@0 | 553 | |
michael@0 | 554 | size_t colorAttachmentId = attachment - LOCAL_GL_COLOR_ATTACHMENT0; |
michael@0 | 555 | if (colorAttachmentId >= mColorAttachments.Length()) { |
michael@0 | 556 | MOZ_ASSERT(false); |
michael@0 | 557 | return mColorAttachments[0]; |
michael@0 | 558 | } |
michael@0 | 559 | |
michael@0 | 560 | return mColorAttachments[colorAttachmentId]; |
michael@0 | 561 | } |
michael@0 | 562 | |
michael@0 | 563 | void |
michael@0 | 564 | WebGLFramebuffer::DetachTexture(const WebGLTexture* tex) |
michael@0 | 565 | { |
michael@0 | 566 | size_t count = mColorAttachments.Length(); |
michael@0 | 567 | for (size_t i = 0; i < count; i++) { |
michael@0 | 568 | if (mColorAttachments[i].Texture() == tex) { |
michael@0 | 569 | FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0+i, LOCAL_GL_TEXTURE_2D, nullptr, 0); |
michael@0 | 570 | // a texture might be attached more that once while editing the framebuffer |
michael@0 | 571 | } |
michael@0 | 572 | } |
michael@0 | 573 | |
michael@0 | 574 | if (mDepthAttachment.Texture() == tex) |
michael@0 | 575 | FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nullptr, 0); |
michael@0 | 576 | if (mStencilAttachment.Texture() == tex) |
michael@0 | 577 | FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nullptr, 0); |
michael@0 | 578 | if (mDepthStencilAttachment.Texture() == tex) |
michael@0 | 579 | FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nullptr, 0); |
michael@0 | 580 | } |
michael@0 | 581 | |
michael@0 | 582 | void |
michael@0 | 583 | WebGLFramebuffer::DetachRenderbuffer(const WebGLRenderbuffer* rb) |
michael@0 | 584 | { |
michael@0 | 585 | size_t count = mColorAttachments.Length(); |
michael@0 | 586 | for (size_t i = 0; i < count; i++) { |
michael@0 | 587 | if (mColorAttachments[i].Renderbuffer() == rb) { |
michael@0 | 588 | FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0+i, LOCAL_GL_RENDERBUFFER, nullptr); |
michael@0 | 589 | // a renderbuffer might be attached more that once while editing the framebuffer |
michael@0 | 590 | } |
michael@0 | 591 | } |
michael@0 | 592 | |
michael@0 | 593 | if (mDepthAttachment.Renderbuffer() == rb) |
michael@0 | 594 | FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nullptr); |
michael@0 | 595 | if (mStencilAttachment.Renderbuffer() == rb) |
michael@0 | 596 | FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nullptr); |
michael@0 | 597 | if (mDepthStencilAttachment.Renderbuffer() == rb) |
michael@0 | 598 | FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nullptr); |
michael@0 | 599 | } |
michael@0 | 600 | |
michael@0 | 601 | bool |
michael@0 | 602 | WebGLFramebuffer::HasDefinedAttachments() const |
michael@0 | 603 | { |
michael@0 | 604 | bool hasAttachments = false; |
michael@0 | 605 | |
michael@0 | 606 | size_t count = mColorAttachments.Length(); |
michael@0 | 607 | for (size_t i = 0; i < count; i++) { |
michael@0 | 608 | hasAttachments |= mColorAttachments[i].IsDefined(); |
michael@0 | 609 | } |
michael@0 | 610 | |
michael@0 | 611 | hasAttachments |= mDepthAttachment.IsDefined(); |
michael@0 | 612 | hasAttachments |= mStencilAttachment.IsDefined(); |
michael@0 | 613 | hasAttachments |= mDepthStencilAttachment.IsDefined(); |
michael@0 | 614 | |
michael@0 | 615 | return hasAttachments; |
michael@0 | 616 | } |
michael@0 | 617 | |
michael@0 | 618 | |
michael@0 | 619 | static bool |
michael@0 | 620 | IsIncomplete(const WebGLFramebuffer::Attachment& cur) |
michael@0 | 621 | { |
michael@0 | 622 | return cur.IsDefined() && !cur.IsComplete(); |
michael@0 | 623 | } |
michael@0 | 624 | |
michael@0 | 625 | bool |
michael@0 | 626 | WebGLFramebuffer::HasIncompleteAttachments() const |
michael@0 | 627 | { |
michael@0 | 628 | bool hasIncomplete = false; |
michael@0 | 629 | |
michael@0 | 630 | size_t count = mColorAttachments.Length(); |
michael@0 | 631 | for (size_t i = 0; i < count; i++) { |
michael@0 | 632 | hasIncomplete |= IsIncomplete(mColorAttachments[i]); |
michael@0 | 633 | } |
michael@0 | 634 | |
michael@0 | 635 | hasIncomplete |= IsIncomplete(mDepthAttachment); |
michael@0 | 636 | hasIncomplete |= IsIncomplete(mStencilAttachment); |
michael@0 | 637 | hasIncomplete |= IsIncomplete(mDepthStencilAttachment); |
michael@0 | 638 | |
michael@0 | 639 | return hasIncomplete; |
michael@0 | 640 | } |
michael@0 | 641 | |
michael@0 | 642 | |
michael@0 | 643 | const WebGLRectangleObject& |
michael@0 | 644 | WebGLFramebuffer::GetAnyRectObject() const |
michael@0 | 645 | { |
michael@0 | 646 | MOZ_ASSERT(HasDefinedAttachments()); |
michael@0 | 647 | |
michael@0 | 648 | size_t count = mColorAttachments.Length(); |
michael@0 | 649 | for (size_t i = 0; i < count; i++) { |
michael@0 | 650 | if (mColorAttachments[i].HasImage()) |
michael@0 | 651 | return mColorAttachments[i].RectangleObject(); |
michael@0 | 652 | } |
michael@0 | 653 | |
michael@0 | 654 | if (mDepthAttachment.HasImage()) |
michael@0 | 655 | return mDepthAttachment.RectangleObject(); |
michael@0 | 656 | |
michael@0 | 657 | if (mStencilAttachment.HasImage()) |
michael@0 | 658 | return mStencilAttachment.RectangleObject(); |
michael@0 | 659 | |
michael@0 | 660 | if (mDepthStencilAttachment.HasImage()) |
michael@0 | 661 | return mDepthStencilAttachment.RectangleObject(); |
michael@0 | 662 | |
michael@0 | 663 | MOZ_CRASH("Should not get here."); |
michael@0 | 664 | } |
michael@0 | 665 | |
michael@0 | 666 | |
michael@0 | 667 | static bool |
michael@0 | 668 | RectsMatch(const WebGLFramebuffer::Attachment& attachment, |
michael@0 | 669 | const WebGLRectangleObject& rect) |
michael@0 | 670 | { |
michael@0 | 671 | return attachment.RectangleObject().HasSameDimensionsAs(rect); |
michael@0 | 672 | } |
michael@0 | 673 | |
michael@0 | 674 | bool |
michael@0 | 675 | WebGLFramebuffer::AllImageRectsMatch() const |
michael@0 | 676 | { |
michael@0 | 677 | MOZ_ASSERT(HasDefinedAttachments()); |
michael@0 | 678 | MOZ_ASSERT(!HasIncompleteAttachments()); |
michael@0 | 679 | |
michael@0 | 680 | const WebGLRectangleObject& rect = GetAnyRectObject(); |
michael@0 | 681 | |
michael@0 | 682 | // Alright, we have *a* rect, let's check all the others. |
michael@0 | 683 | bool imageRectsMatch = true; |
michael@0 | 684 | |
michael@0 | 685 | size_t count = mColorAttachments.Length(); |
michael@0 | 686 | for (size_t i = 0; i < count; i++) { |
michael@0 | 687 | if (mColorAttachments[i].HasImage()) |
michael@0 | 688 | imageRectsMatch &= RectsMatch(mColorAttachments[i], rect); |
michael@0 | 689 | } |
michael@0 | 690 | |
michael@0 | 691 | if (mDepthAttachment.HasImage()) |
michael@0 | 692 | imageRectsMatch &= RectsMatch(mDepthAttachment, rect); |
michael@0 | 693 | |
michael@0 | 694 | if (mStencilAttachment.HasImage()) |
michael@0 | 695 | imageRectsMatch &= RectsMatch(mStencilAttachment, rect); |
michael@0 | 696 | |
michael@0 | 697 | if (mDepthStencilAttachment.HasImage()) |
michael@0 | 698 | imageRectsMatch &= RectsMatch(mDepthStencilAttachment, rect); |
michael@0 | 699 | |
michael@0 | 700 | return imageRectsMatch; |
michael@0 | 701 | } |
michael@0 | 702 | |
michael@0 | 703 | |
michael@0 | 704 | const WebGLRectangleObject& |
michael@0 | 705 | WebGLFramebuffer::RectangleObject() const |
michael@0 | 706 | { |
michael@0 | 707 | // If we're using this as the RectObj of an FB, we need to be sure the FB |
michael@0 | 708 | // has a consistent rect. |
michael@0 | 709 | MOZ_ASSERT(AllImageRectsMatch(), "Did you mean `GetAnyRectObject`?"); |
michael@0 | 710 | return GetAnyRectObject(); |
michael@0 | 711 | } |
michael@0 | 712 | |
michael@0 | 713 | GLenum |
michael@0 | 714 | WebGLFramebuffer::PrecheckFramebufferStatus() const |
michael@0 | 715 | { |
michael@0 | 716 | MOZ_ASSERT(mContext->mBoundFramebuffer == this); |
michael@0 | 717 | |
michael@0 | 718 | if (!HasDefinedAttachments()) |
michael@0 | 719 | return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; // No attachments |
michael@0 | 720 | |
michael@0 | 721 | if (HasIncompleteAttachments()) |
michael@0 | 722 | return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; |
michael@0 | 723 | |
michael@0 | 724 | if (!AllImageRectsMatch()) |
michael@0 | 725 | return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; // Inconsistent sizes |
michael@0 | 726 | |
michael@0 | 727 | if (HasDepthStencilConflict()) |
michael@0 | 728 | return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED; |
michael@0 | 729 | |
michael@0 | 730 | return LOCAL_GL_FRAMEBUFFER_COMPLETE; |
michael@0 | 731 | } |
michael@0 | 732 | |
michael@0 | 733 | GLenum |
michael@0 | 734 | WebGLFramebuffer::CheckFramebufferStatus() const |
michael@0 | 735 | { |
michael@0 | 736 | if (mStatus != 0) |
michael@0 | 737 | return mStatus; |
michael@0 | 738 | |
michael@0 | 739 | mStatus = PrecheckFramebufferStatus(); |
michael@0 | 740 | if (mStatus != LOCAL_GL_FRAMEBUFFER_COMPLETE) |
michael@0 | 741 | return mStatus; |
michael@0 | 742 | |
michael@0 | 743 | // Looks good on our end. Let's ask the driver. |
michael@0 | 744 | mContext->MakeContextCurrent(); |
michael@0 | 745 | |
michael@0 | 746 | // Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}. |
michael@0 | 747 | FinalizeAttachments(); |
michael@0 | 748 | |
michael@0 | 749 | mStatus = mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); |
michael@0 | 750 | return mStatus; |
michael@0 | 751 | } |
michael@0 | 752 | |
michael@0 | 753 | bool |
michael@0 | 754 | WebGLFramebuffer::HasCompletePlanes(GLbitfield mask) |
michael@0 | 755 | { |
michael@0 | 756 | if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE) |
michael@0 | 757 | return false; |
michael@0 | 758 | |
michael@0 | 759 | MOZ_ASSERT(mContext->mBoundFramebuffer == this); |
michael@0 | 760 | bool hasPlanes = true; |
michael@0 | 761 | if (mask & LOCAL_GL_COLOR_BUFFER_BIT) { |
michael@0 | 762 | hasPlanes &= ColorAttachmentCount() && |
michael@0 | 763 | ColorAttachment(0).IsDefined(); |
michael@0 | 764 | } |
michael@0 | 765 | |
michael@0 | 766 | if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) { |
michael@0 | 767 | hasPlanes &= DepthAttachment().IsDefined() || |
michael@0 | 768 | DepthStencilAttachment().IsDefined(); |
michael@0 | 769 | } |
michael@0 | 770 | |
michael@0 | 771 | if (mask & LOCAL_GL_STENCIL_BUFFER_BIT) { |
michael@0 | 772 | hasPlanes &= StencilAttachment().IsDefined() || |
michael@0 | 773 | DepthStencilAttachment().IsDefined(); |
michael@0 | 774 | } |
michael@0 | 775 | |
michael@0 | 776 | return hasPlanes; |
michael@0 | 777 | } |
michael@0 | 778 | |
michael@0 | 779 | bool |
michael@0 | 780 | WebGLFramebuffer::CheckAndInitializeAttachments() |
michael@0 | 781 | { |
michael@0 | 782 | MOZ_ASSERT(mContext->mBoundFramebuffer == this); |
michael@0 | 783 | |
michael@0 | 784 | if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE) |
michael@0 | 785 | return false; |
michael@0 | 786 | |
michael@0 | 787 | // Cool! We've checked out ok. Just need to initialize. |
michael@0 | 788 | size_t colorAttachmentCount = mColorAttachments.Length(); |
michael@0 | 789 | |
michael@0 | 790 | // Check if we need to initialize anything |
michael@0 | 791 | { |
michael@0 | 792 | bool hasUninitializedAttachments = false; |
michael@0 | 793 | |
michael@0 | 794 | for (size_t i = 0; i < colorAttachmentCount; i++) { |
michael@0 | 795 | if (mColorAttachments[i].HasImage()) |
michael@0 | 796 | hasUninitializedAttachments |= mColorAttachments[i].HasUninitializedImageData(); |
michael@0 | 797 | } |
michael@0 | 798 | |
michael@0 | 799 | if (mDepthAttachment.HasImage()) |
michael@0 | 800 | hasUninitializedAttachments |= mDepthAttachment.HasUninitializedImageData(); |
michael@0 | 801 | if (mStencilAttachment.HasImage()) |
michael@0 | 802 | hasUninitializedAttachments |= mStencilAttachment.HasUninitializedImageData(); |
michael@0 | 803 | if (mDepthStencilAttachment.HasImage()) |
michael@0 | 804 | hasUninitializedAttachments |= mDepthStencilAttachment.HasUninitializedImageData(); |
michael@0 | 805 | |
michael@0 | 806 | if (!hasUninitializedAttachments) |
michael@0 | 807 | return true; |
michael@0 | 808 | } |
michael@0 | 809 | |
michael@0 | 810 | // Get buffer-bit-mask and color-attachment-mask-list |
michael@0 | 811 | uint32_t mask = 0; |
michael@0 | 812 | bool colorAttachmentsMask[WebGLContext::sMaxColorAttachments] = { false }; |
michael@0 | 813 | MOZ_ASSERT(colorAttachmentCount <= WebGLContext::sMaxColorAttachments); |
michael@0 | 814 | |
michael@0 | 815 | for (size_t i = 0; i < colorAttachmentCount; i++) { |
michael@0 | 816 | if (mColorAttachments[i].HasUninitializedImageData()) { |
michael@0 | 817 | colorAttachmentsMask[i] = true; |
michael@0 | 818 | mask |= LOCAL_GL_COLOR_BUFFER_BIT; |
michael@0 | 819 | } |
michael@0 | 820 | } |
michael@0 | 821 | |
michael@0 | 822 | if (mDepthAttachment.HasUninitializedImageData() || |
michael@0 | 823 | mDepthStencilAttachment.HasUninitializedImageData()) |
michael@0 | 824 | { |
michael@0 | 825 | mask |= LOCAL_GL_DEPTH_BUFFER_BIT; |
michael@0 | 826 | } |
michael@0 | 827 | |
michael@0 | 828 | if (mStencilAttachment.HasUninitializedImageData() || |
michael@0 | 829 | mDepthStencilAttachment.HasUninitializedImageData()) |
michael@0 | 830 | { |
michael@0 | 831 | mask |= LOCAL_GL_STENCIL_BUFFER_BIT; |
michael@0 | 832 | } |
michael@0 | 833 | |
michael@0 | 834 | // Clear! |
michael@0 | 835 | mContext->ForceClearFramebufferWithDefaultValues(mask, colorAttachmentsMask); |
michael@0 | 836 | |
michael@0 | 837 | // Mark all the uninitialized images as initialized. |
michael@0 | 838 | for (size_t i = 0; i < colorAttachmentCount; i++) { |
michael@0 | 839 | if (mColorAttachments[i].HasUninitializedImageData()) |
michael@0 | 840 | mColorAttachments[i].SetImageDataStatus(WebGLImageDataStatus::InitializedImageData); |
michael@0 | 841 | } |
michael@0 | 842 | |
michael@0 | 843 | if (mDepthAttachment.HasUninitializedImageData()) |
michael@0 | 844 | mDepthAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData); |
michael@0 | 845 | if (mStencilAttachment.HasUninitializedImageData()) |
michael@0 | 846 | mStencilAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData); |
michael@0 | 847 | if (mDepthStencilAttachment.HasUninitializedImageData()) |
michael@0 | 848 | mDepthStencilAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData); |
michael@0 | 849 | |
michael@0 | 850 | return true; |
michael@0 | 851 | } |
michael@0 | 852 | |
michael@0 | 853 | bool WebGLFramebuffer::CheckColorAttachmentNumber(GLenum attachment, const char* functionName) const |
michael@0 | 854 | { |
michael@0 | 855 | const char* const errorFormating = "%s: attachment: invalid enum value 0x%x"; |
michael@0 | 856 | |
michael@0 | 857 | if (mContext->IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) { |
michael@0 | 858 | if (attachment < LOCAL_GL_COLOR_ATTACHMENT0 || |
michael@0 | 859 | attachment >= GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + mContext->mGLMaxColorAttachments)) |
michael@0 | 860 | { |
michael@0 | 861 | mContext->ErrorInvalidEnum(errorFormating, functionName, attachment); |
michael@0 | 862 | return false; |
michael@0 | 863 | } |
michael@0 | 864 | } else if (attachment != LOCAL_GL_COLOR_ATTACHMENT0) { |
michael@0 | 865 | if (attachment > LOCAL_GL_COLOR_ATTACHMENT0 && |
michael@0 | 866 | attachment <= LOCAL_GL_COLOR_ATTACHMENT15) |
michael@0 | 867 | { |
michael@0 | 868 | mContext->ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x. " |
michael@0 | 869 | "Try the WEBGL_draw_buffers extension if supported.", functionName, attachment); |
michael@0 | 870 | return false; |
michael@0 | 871 | } else { |
michael@0 | 872 | mContext->ErrorInvalidEnum(errorFormating, functionName, attachment); |
michael@0 | 873 | return false; |
michael@0 | 874 | } |
michael@0 | 875 | } |
michael@0 | 876 | |
michael@0 | 877 | return true; |
michael@0 | 878 | } |
michael@0 | 879 | |
michael@0 | 880 | void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId) |
michael@0 | 881 | { |
michael@0 | 882 | MOZ_ASSERT(colorAttachmentId < WebGLContext::sMaxColorAttachments); |
michael@0 | 883 | |
michael@0 | 884 | size_t currentAttachmentCount = mColorAttachments.Length(); |
michael@0 | 885 | if (colorAttachmentId < currentAttachmentCount) |
michael@0 | 886 | return; |
michael@0 | 887 | |
michael@0 | 888 | mColorAttachments.SetLength(colorAttachmentId + 1); |
michael@0 | 889 | |
michael@0 | 890 | for (size_t i = colorAttachmentId; i >= currentAttachmentCount; i--) { |
michael@0 | 891 | mColorAttachments[i].mAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0 + i; |
michael@0 | 892 | } |
michael@0 | 893 | } |
michael@0 | 894 | |
michael@0 | 895 | void |
michael@0 | 896 | WebGLFramebuffer::NotifyAttachableChanged() const |
michael@0 | 897 | { |
michael@0 | 898 | // Attachment has changed, so invalidate cached status |
michael@0 | 899 | mStatus = 0; |
michael@0 | 900 | } |
michael@0 | 901 | |
michael@0 | 902 | static void |
michael@0 | 903 | FinalizeDrawAndReadBuffers(GLContext* aGL, bool aColorBufferDefined) |
michael@0 | 904 | { |
michael@0 | 905 | MOZ_ASSERT(aGL, "Expected a valid GLContext ptr."); |
michael@0 | 906 | // GLES don't support DrawBuffer()/ReadBuffer. |
michael@0 | 907 | // According to http://www.opengl.org/wiki/Framebuffer_Object |
michael@0 | 908 | // |
michael@0 | 909 | // Each draw buffers must either specify color attachment points that have images |
michael@0 | 910 | // attached or must be GL_NONE. (GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER when false). |
michael@0 | 911 | // |
michael@0 | 912 | // If the read buffer is set, then it must specify an attachment point that has an |
michael@0 | 913 | // image attached. (GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER when false). |
michael@0 | 914 | // |
michael@0 | 915 | // Note that this test is not performed if OpenGL 4.2 or ARB_ES2_compatibility is |
michael@0 | 916 | // available. |
michael@0 | 917 | if (aGL->IsGLES() || |
michael@0 | 918 | aGL->IsSupported(GLFeature::ES2_compatibility) || |
michael@0 | 919 | aGL->IsAtLeast(ContextProfile::OpenGL, 420)) |
michael@0 | 920 | { |
michael@0 | 921 | return; |
michael@0 | 922 | } |
michael@0 | 923 | |
michael@0 | 924 | // TODO(djg): Assert that fDrawBuffer/fReadBuffer is not NULL. |
michael@0 | 925 | GLenum colorBufferSource = aColorBufferDefined ? LOCAL_GL_COLOR_ATTACHMENT0 : LOCAL_GL_NONE; |
michael@0 | 926 | aGL->fDrawBuffer(colorBufferSource); |
michael@0 | 927 | aGL->fReadBuffer(colorBufferSource); |
michael@0 | 928 | } |
michael@0 | 929 | |
michael@0 | 930 | void |
michael@0 | 931 | WebGLFramebuffer::FinalizeAttachments() const |
michael@0 | 932 | { |
michael@0 | 933 | GLContext* gl = mContext->gl; |
michael@0 | 934 | |
michael@0 | 935 | size_t count = ColorAttachmentCount(); |
michael@0 | 936 | for (size_t i = 0; i < count; i++) { |
michael@0 | 937 | ColorAttachment(i).FinalizeAttachment(gl, LOCAL_GL_COLOR_ATTACHMENT0 + i); |
michael@0 | 938 | } |
michael@0 | 939 | |
michael@0 | 940 | DepthAttachment().FinalizeAttachment(gl, LOCAL_GL_DEPTH_ATTACHMENT); |
michael@0 | 941 | StencilAttachment().FinalizeAttachment(gl, LOCAL_GL_STENCIL_ATTACHMENT); |
michael@0 | 942 | DepthStencilAttachment().FinalizeAttachment(gl, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT); |
michael@0 | 943 | |
michael@0 | 944 | FinalizeDrawAndReadBuffers(gl, ColorAttachment(0).IsDefined()); |
michael@0 | 945 | } |
michael@0 | 946 | |
michael@0 | 947 | inline void |
michael@0 | 948 | ImplCycleCollectionUnlink(mozilla::WebGLFramebuffer::Attachment& aField) |
michael@0 | 949 | { |
michael@0 | 950 | aField.mTexturePtr = nullptr; |
michael@0 | 951 | aField.mRenderbufferPtr = nullptr; |
michael@0 | 952 | } |
michael@0 | 953 | |
michael@0 | 954 | inline void |
michael@0 | 955 | ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, |
michael@0 | 956 | mozilla::WebGLFramebuffer::Attachment& aField, |
michael@0 | 957 | const char* aName, |
michael@0 | 958 | uint32_t aFlags = 0) |
michael@0 | 959 | { |
michael@0 | 960 | CycleCollectionNoteChild(aCallback, aField.mTexturePtr.get(), |
michael@0 | 961 | aName, aFlags); |
michael@0 | 962 | |
michael@0 | 963 | CycleCollectionNoteChild(aCallback, aField.mRenderbufferPtr.get(), |
michael@0 | 964 | aName, aFlags); |
michael@0 | 965 | } |
michael@0 | 966 | |
michael@0 | 967 | NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(WebGLFramebuffer, |
michael@0 | 968 | mColorAttachments, |
michael@0 | 969 | mDepthAttachment, |
michael@0 | 970 | mStencilAttachment, |
michael@0 | 971 | mDepthStencilAttachment) |
michael@0 | 972 | |
michael@0 | 973 | NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLFramebuffer, AddRef) |
michael@0 | 974 | NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLFramebuffer, Release) |