tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WebGL2ContextFramebuffers.cpp (7733B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      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 "GLContext.h"
      7 #include "GLScreenBuffer.h"
      8 #include "WebGL2Context.h"
      9 #include "WebGLContextUtils.h"
     10 #include "WebGLFormats.h"
     11 #include "WebGLFramebuffer.h"
     12 #include "mozilla/CheckedInt.h"
     13 
     14 namespace mozilla {
     15 
     16 void WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1,
     17                                    GLint srcY1, GLint dstX0, GLint dstY0,
     18                                    GLint dstX1, GLint dstY1, GLbitfield mask,
     19                                    GLenum filter) {
     20  const FuncScope funcScope(*this, "blitFramebuffer");
     21  if (IsContextLost()) return;
     22 
     23  const GLbitfield validBits = LOCAL_GL_COLOR_BUFFER_BIT |
     24                               LOCAL_GL_DEPTH_BUFFER_BIT |
     25                               LOCAL_GL_STENCIL_BUFFER_BIT;
     26  if ((mask | validBits) != validBits) {
     27    ErrorInvalidValue("Invalid bit set in mask.");
     28    return;
     29  }
     30 
     31  switch (filter) {
     32    case LOCAL_GL_NEAREST:
     33    case LOCAL_GL_LINEAR:
     34      break;
     35    default:
     36      ErrorInvalidEnumInfo("filter", filter);
     37      return;
     38  }
     39 
     40  // --
     41 
     42  const auto fnLikelyOverflow = [](GLint p0, GLint p1) {
     43    auto checked = CheckedInt<GLint>(p1) - p0;
     44    checked = -checked;  // And check the negation!
     45    return !checked.isValid();
     46  };
     47 
     48  if (fnLikelyOverflow(srcX0, srcX1) || fnLikelyOverflow(srcY0, srcY1) ||
     49      fnLikelyOverflow(dstX0, dstX1) || fnLikelyOverflow(dstY0, dstY1)) {
     50    ErrorInvalidValue("Likely-to-overflow large ranges are forbidden.");
     51    return;
     52  }
     53 
     54  // --
     55 
     56  if (!ValidateAndInitFB(mBoundReadFramebuffer) ||
     57      !ValidateAndInitFB(mBoundDrawFramebuffer)) {
     58    return;
     59  }
     60 
     61  DoBindFB(mBoundReadFramebuffer, LOCAL_GL_READ_FRAMEBUFFER);
     62  DoBindFB(mBoundDrawFramebuffer, LOCAL_GL_DRAW_FRAMEBUFFER);
     63 
     64  WebGLFramebuffer::BlitFramebuffer(this, srcX0, srcY0, srcX1, srcY1, dstX0,
     65                                    dstY0, dstX1, dstY1, mask, filter);
     66 }
     67 
     68 ////
     69 
     70 static bool ValidateBackbufferAttachmentEnum(WebGLContext* webgl,
     71                                             GLenum attachment) {
     72  switch (attachment) {
     73    case LOCAL_GL_COLOR:
     74    case LOCAL_GL_DEPTH:
     75    case LOCAL_GL_STENCIL:
     76      return true;
     77 
     78    default:
     79      webgl->ErrorInvalidEnumInfo("attachment", attachment);
     80      return false;
     81  }
     82 }
     83 
     84 static bool ValidateFramebufferAttachmentEnum(WebGLContext* webgl,
     85                                              GLenum attachment) {
     86  switch (attachment) {
     87    case LOCAL_GL_DEPTH_ATTACHMENT:
     88    case LOCAL_GL_STENCIL_ATTACHMENT:
     89    case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
     90      return true;
     91  }
     92 
     93  if (attachment < LOCAL_GL_COLOR_ATTACHMENT0) {
     94    webgl->ErrorInvalidEnumInfo("attachment", attachment);
     95    return false;
     96  }
     97 
     98  if (attachment > webgl->LastColorAttachmentEnum()) {
     99    // That these errors have different types is ridiculous.
    100    webgl->ErrorInvalidOperation("Too-large LOCAL_GL_COLOR_ATTACHMENTn.");
    101    return false;
    102  }
    103 
    104  return true;
    105 }
    106 
    107 bool WebGLContext::ValidateInvalidateFramebuffer(
    108    GLenum target, const Span<const GLenum>& attachments,
    109    std::vector<GLenum>* const scopedVector,
    110    GLsizei* const out_glNumAttachments,
    111    const GLenum** const out_glAttachments) {
    112  if (IsContextLost()) return false;
    113 
    114  if (!ValidateFramebufferTarget(target)) return false;
    115 
    116  const WebGLFramebuffer* fb;
    117  bool isDefaultFB = false;
    118  switch (target) {
    119    case LOCAL_GL_FRAMEBUFFER:
    120    case LOCAL_GL_DRAW_FRAMEBUFFER:
    121      fb = mBoundDrawFramebuffer;
    122      break;
    123 
    124    case LOCAL_GL_READ_FRAMEBUFFER:
    125      fb = mBoundReadFramebuffer;
    126      break;
    127 
    128    default:
    129      MOZ_CRASH("GFX: Bad target.");
    130  }
    131 
    132  if (fb) {
    133    const auto fbStatus = fb->CheckFramebufferStatus();
    134    if (fbStatus != LOCAL_GL_FRAMEBUFFER_COMPLETE)
    135      return false;  // Not an error, but don't run forward to driver either.
    136  } else {
    137    if (!EnsureDefaultFB()) return false;
    138  }
    139  DoBindFB(fb, target);
    140 
    141  *out_glNumAttachments = AutoAssertCast(attachments.size());
    142  *out_glAttachments = attachments.data();
    143 
    144  if (fb) {
    145    for (const auto& attachment : attachments) {
    146      if (!ValidateFramebufferAttachmentEnum(this, attachment)) return false;
    147    }
    148  } else {
    149    for (const auto& attachment : attachments) {
    150      if (!ValidateBackbufferAttachmentEnum(this, attachment)) return false;
    151    }
    152 
    153    if (!isDefaultFB) {
    154      MOZ_ASSERT(scopedVector->empty());
    155      scopedVector->reserve(attachments.size());
    156      for (const auto& attachment : attachments) {
    157        switch (attachment) {
    158          case LOCAL_GL_COLOR:
    159            scopedVector->push_back(LOCAL_GL_COLOR_ATTACHMENT0);
    160            break;
    161 
    162          case LOCAL_GL_DEPTH:
    163            scopedVector->push_back(LOCAL_GL_DEPTH_ATTACHMENT);
    164            break;
    165 
    166          case LOCAL_GL_STENCIL:
    167            scopedVector->push_back(LOCAL_GL_STENCIL_ATTACHMENT);
    168            break;
    169 
    170          default:
    171            MOZ_CRASH();
    172        }
    173      }
    174      *out_glNumAttachments = AutoAssertCast(scopedVector->size());
    175      *out_glAttachments = scopedVector->data();
    176    }
    177  }
    178 
    179  ////
    180 
    181  return true;
    182 }
    183 
    184 void WebGL2Context::InvalidateFramebuffer(
    185    GLenum target, const Span<const GLenum>& attachments) {
    186  const FuncScope funcScope(*this, "invalidateFramebuffer");
    187 
    188  std::vector<GLenum> scopedVector;
    189  GLsizei glNumAttachments;
    190  const GLenum* glAttachments;
    191  if (!ValidateInvalidateFramebuffer(target, attachments, &scopedVector,
    192                                     &glNumAttachments, &glAttachments)) {
    193    return;
    194  }
    195 
    196  ////
    197 
    198  // Some drivers (like OSX 10.9 GL) just don't support invalidate_framebuffer.
    199  const bool useFBInvalidation =
    200      (mAllowFBInvalidation &&
    201       gl->IsSupported(gl::GLFeature::invalidate_framebuffer));
    202  if (useFBInvalidation) {
    203    gl->fInvalidateFramebuffer(target, glNumAttachments, glAttachments);
    204    return;
    205  }
    206 
    207  // Use clear instead?
    208  // No-op for now.
    209 }
    210 
    211 void WebGL2Context::InvalidateSubFramebuffer(
    212    GLenum target, const Span<const GLenum>& attachments, GLint x, GLint y,
    213    GLsizei width, GLsizei height) {
    214  const FuncScope funcScope(*this, "invalidateSubFramebuffer");
    215 
    216  std::vector<GLenum> scopedVector;
    217  GLsizei glNumAttachments;
    218  const GLenum* glAttachments;
    219  if (!ValidateInvalidateFramebuffer(target, attachments, &scopedVector,
    220                                     &glNumAttachments, &glAttachments)) {
    221    return;
    222  }
    223 
    224  if (!ValidateNonNegative("width", width) ||
    225      !ValidateNonNegative("height", height)) {
    226    return;
    227  }
    228 
    229  ////
    230 
    231  // Some drivers (like OSX 10.9 GL) just don't support invalidate_framebuffer.
    232  const bool useFBInvalidation =
    233      (mAllowFBInvalidation &&
    234       gl->IsSupported(gl::GLFeature::invalidate_framebuffer));
    235  if (useFBInvalidation) {
    236    gl->fInvalidateSubFramebuffer(target, glNumAttachments, glAttachments, x, y,
    237                                  width, height);
    238    return;
    239  }
    240 
    241  // Use clear instead?
    242  // No-op for now.
    243 }
    244 
    245 void WebGL2Context::ReadBuffer(GLenum mode) {
    246  const FuncScope funcScope(*this, "readBuffer");
    247  if (IsContextLost()) return;
    248 
    249  if (mBoundReadFramebuffer) {
    250    mBoundReadFramebuffer->ReadBuffer(mode);
    251    return;
    252  }
    253 
    254  // Operating on the default framebuffer.
    255  if (mode != LOCAL_GL_NONE && mode != LOCAL_GL_BACK) {
    256    nsCString enumName;
    257    EnumName(mode, &enumName);
    258    ErrorInvalidOperation(
    259        "If READ_FRAMEBUFFER is null, `mode` must be BACK or"
    260        " NONE. Was %s.",
    261        enumName.BeginReading());
    262    return;
    263  }
    264 
    265  mDefaultFB_ReadBuffer = mode;
    266 }
    267 
    268 }  // namespace mozilla