tor-browser

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

WebGLContextState.cpp (12941B)


      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 "MozFramebuffer.h"
      9 #include "WebGLBuffer.h"
     10 #include "WebGLContext.h"
     11 #include "WebGLContextUtils.h"
     12 #include "WebGLFormats.h"
     13 #include "WebGLFramebuffer.h"
     14 #include "WebGLProgram.h"
     15 #include "WebGLRenderbuffer.h"
     16 #include "WebGLShader.h"
     17 #include "WebGLTexture.h"
     18 #include "WebGLVertexArray.h"
     19 #include "mozilla/Maybe.h"
     20 #include "mozilla/Preferences.h"
     21 #include "nsString.h"
     22 
     23 namespace mozilla {
     24 
     25 void WebGLContext::SetEnabled(const GLenum cap, const Maybe<GLuint> i,
     26                              const bool enabled) {
     27  const FuncScope funcScope(*this, "enable(i)/disable(i)");
     28  if (IsContextLost()) return;
     29 
     30  if (!mIsEnabledMapKeys.count(cap)) {
     31    MOZ_ASSERT(false, "Bad cap.");
     32    return;
     33  }
     34 
     35  if (cap == LOCAL_GL_BLEND) {
     36    if (i) {
     37      const auto limit = MaxValidDrawBuffers();
     38      if (*i >= limit) {
     39        ErrorInvalidValue("`index` (%u) must be < %s (%u)", *i,
     40                          "MAX_DRAW_BUFFERS", limit);
     41        return;
     42      }
     43      mBlendEnabled[*i] = enabled;
     44    } else {
     45      if (enabled) {
     46        mBlendEnabled.set();
     47      } else {
     48        mBlendEnabled.reset();
     49      }
     50    }
     51  } else {
     52    if (i) {
     53      MOZ_ASSERT(false, "i");
     54      return;
     55    }
     56    const auto slot = GetStateTrackingSlot(cap);
     57    if (slot) {
     58      *slot = enabled;
     59    }
     60  }
     61 
     62  switch (cap) {
     63    case LOCAL_GL_DEPTH_TEST:
     64    case LOCAL_GL_STENCIL_TEST:
     65      break;  // Lazily applied, so don't tell GL yet or we will desync.
     66 
     67    default:
     68      // Non-lazy caps.
     69      if (i) {
     70        if (enabled) {
     71          gl->fEnablei(cap, *i);
     72        } else {
     73          gl->fDisablei(cap, *i);
     74        }
     75      } else {
     76        gl->SetEnabled(cap, enabled);
     77      }
     78      break;
     79  }
     80 }
     81 
     82 bool WebGLContext::GetStencilBits(GLint* const out_stencilBits) const {
     83  *out_stencilBits = 0;
     84  if (mBoundDrawFramebuffer) {
     85    if (!mBoundDrawFramebuffer->IsCheckFramebufferStatusComplete()) {
     86      // Error, we don't know which stencil buffer's bits to use
     87      ErrorInvalidFramebufferOperation(
     88          "getParameter: framebuffer has two stencil buffers bound");
     89      return false;
     90    }
     91 
     92    if (mBoundDrawFramebuffer->StencilAttachment().HasAttachment() ||
     93        mBoundDrawFramebuffer->DepthStencilAttachment().HasAttachment()) {
     94      *out_stencilBits = 8;
     95    }
     96  } else if (mOptions.stencil) {
     97    *out_stencilBits = 8;
     98  }
     99 
    100  return true;
    101 }
    102 
    103 Maybe<double> WebGLContext::GetParameter(const GLenum pname) {
    104  const FuncScope funcScope(*this, "getParameter");
    105  if (IsContextLost()) return {};
    106 
    107  if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) {
    108    if (pname == LOCAL_GL_MAX_COLOR_ATTACHMENTS) {
    109      return Some(MaxValidDrawBuffers());
    110 
    111    } else if (pname == LOCAL_GL_MAX_DRAW_BUFFERS) {
    112      return Some(MaxValidDrawBuffers());
    113 
    114    } else if (pname >= LOCAL_GL_DRAW_BUFFER0 &&
    115               pname < GLenum(LOCAL_GL_DRAW_BUFFER0 + MaxValidDrawBuffers())) {
    116      const auto slotId = pname - LOCAL_GL_DRAW_BUFFER0;
    117      GLenum ret = LOCAL_GL_NONE;
    118      if (!mBoundDrawFramebuffer) {
    119        if (slotId == 0) {
    120          ret = mDefaultFB_DrawBuffer0;
    121        }
    122      } else {
    123        const auto& fb = *mBoundDrawFramebuffer;
    124        const auto& bs = fb.DrawBufferEnabled();
    125        if (bs[slotId]) {
    126          ret = LOCAL_GL_COLOR_ATTACHMENT0 + slotId;
    127        }
    128      }
    129      return Some(ret);
    130    }
    131  }
    132 
    133  if (IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) {
    134    switch (pname) {
    135      case LOCAL_GL_TIMESTAMP_EXT: {
    136        uint64_t val = 0;
    137        if (Has64BitTimestamps()) {
    138          gl->fGetInteger64v(pname, (GLint64*)&val);
    139        } else {
    140          gl->fGetIntegerv(pname, (GLint*)&val);
    141        }
    142        // TODO: JS doesn't support 64-bit integers. Be lossy and
    143        // cast to double (53 bits)
    144        return Some(val);
    145      }
    146 
    147      case LOCAL_GL_GPU_DISJOINT_EXT: {
    148        realGLboolean val = false;  // Not disjoint by default.
    149        if (gl->IsExtensionSupported(gl::GLContext::EXT_disjoint_timer_query)) {
    150          gl->fGetBooleanv(pname, &val);
    151        }
    152        return Some(bool(val));
    153      }
    154 
    155      default:
    156        break;
    157    }
    158  }
    159 
    160  if (IsWebGL2() ||
    161      IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) {
    162    if (pname == LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT) {
    163      GLint i = 0;
    164      gl->fGetIntegerv(pname, &i);
    165      return Some(i);
    166    }
    167  }
    168 
    169  if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) {
    170    if (pname == LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT) {
    171      GLfloat f = 0.f;
    172      gl->fGetFloatv(pname, &f);
    173      return Some(f);
    174    }
    175  }
    176 
    177  if (IsExtensionEnabled(WebGLExtensionID::MOZ_debug)) {
    178    if (pname == dom::MOZ_debug_Binding::DOES_INDEX_VALIDATION) {
    179      return Some(mNeedsIndexValidation);
    180    }
    181  }
    182 
    183  switch (pname) {
    184    ////////////////////////////////
    185    // Single-value params
    186 
    187    // unsigned int
    188    case LOCAL_GL_CULL_FACE_MODE:
    189    case LOCAL_GL_FRONT_FACE:
    190    case LOCAL_GL_ACTIVE_TEXTURE:
    191    case LOCAL_GL_STENCIL_FUNC:
    192    case LOCAL_GL_STENCIL_FAIL:
    193    case LOCAL_GL_STENCIL_PASS_DEPTH_FAIL:
    194    case LOCAL_GL_STENCIL_PASS_DEPTH_PASS:
    195    case LOCAL_GL_STENCIL_BACK_FUNC:
    196    case LOCAL_GL_STENCIL_BACK_FAIL:
    197    case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_FAIL:
    198    case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_PASS:
    199    case LOCAL_GL_DEPTH_FUNC:
    200    case LOCAL_GL_BLEND_SRC_RGB:
    201    case LOCAL_GL_BLEND_SRC_ALPHA:
    202    case LOCAL_GL_BLEND_DST_RGB:
    203    case LOCAL_GL_BLEND_DST_ALPHA:
    204    case LOCAL_GL_BLEND_EQUATION_RGB:
    205    case LOCAL_GL_BLEND_EQUATION_ALPHA: {
    206      GLint i = 0;
    207      gl->fGetIntegerv(pname, &i);
    208      return Some(i);
    209    }
    210 
    211    case LOCAL_GL_GENERATE_MIPMAP_HINT:
    212      return Some(mGenerateMipmapHint);
    213 
    214    case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT:
    215    case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE: {
    216      const webgl::FormatUsageInfo* usage;
    217      uint32_t width, height;
    218      if (!BindCurFBForColorRead(&usage, &width, &height,
    219                                 LOCAL_GL_INVALID_OPERATION))
    220        return Nothing();
    221 
    222      const auto implPI = ValidImplementationColorReadPI(usage);
    223 
    224      GLenum ret;
    225      if (pname == LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT) {
    226        ret = implPI.format;
    227      } else {
    228        ret = implPI.type;
    229      }
    230      return Some(ret);
    231    }
    232 
    233    // int
    234    case LOCAL_GL_STENCIL_REF:
    235    case LOCAL_GL_STENCIL_BACK_REF: {
    236      GLint stencilBits = 0;
    237      if (!GetStencilBits(&stencilBits)) return Nothing();
    238 
    239      // Assuming stencils have 8 bits
    240      const GLint stencilMask = (1 << stencilBits) - 1;
    241 
    242      GLint refValue = 0;
    243      gl->fGetIntegerv(pname, &refValue);
    244 
    245      return Some(refValue & stencilMask);
    246    }
    247 
    248    case LOCAL_GL_SAMPLE_BUFFERS:
    249    case LOCAL_GL_SAMPLES: {
    250      const auto& fb = mBoundDrawFramebuffer;
    251      auto samples = [&]() -> Maybe<uint32_t> {
    252        if (!fb) {
    253          if (!EnsureDefaultFB()) return Nothing();
    254          return Some(mDefaultFB->mSamples);
    255        }
    256 
    257        if (!fb->IsCheckFramebufferStatusComplete()) return Some(0);
    258 
    259        DoBindFB(fb, LOCAL_GL_FRAMEBUFFER);
    260        return Some(gl->GetIntAs<uint32_t>(LOCAL_GL_SAMPLES));
    261      }();
    262      if (samples && pname == LOCAL_GL_SAMPLE_BUFFERS) {
    263        samples = Some(uint32_t(bool(samples.value())));
    264      }
    265      if (!samples) return Nothing();
    266      return Some(samples.value());
    267    }
    268 
    269    case LOCAL_GL_STENCIL_CLEAR_VALUE:
    270    case LOCAL_GL_SUBPIXEL_BITS: {
    271      GLint i = 0;
    272      gl->fGetIntegerv(pname, &i);
    273      return Some(i);
    274    }
    275 
    276    case LOCAL_GL_RED_BITS:
    277    case LOCAL_GL_GREEN_BITS:
    278    case LOCAL_GL_BLUE_BITS:
    279    case LOCAL_GL_ALPHA_BITS:
    280    case LOCAL_GL_DEPTH_BITS:
    281    case LOCAL_GL_STENCIL_BITS: {
    282      const auto format = [&]() -> const webgl::FormatInfo* {
    283        const auto& fb = mBoundDrawFramebuffer;
    284        if (fb) {
    285          if (!fb->IsCheckFramebufferStatusComplete()) return nullptr;
    286 
    287          const auto& attachment = [&]() -> const auto& {
    288            switch (pname) {
    289              case LOCAL_GL_DEPTH_BITS:
    290                if (fb->DepthStencilAttachment().HasAttachment())
    291                  return fb->DepthStencilAttachment();
    292                return fb->DepthAttachment();
    293 
    294              case LOCAL_GL_STENCIL_BITS:
    295                if (fb->DepthStencilAttachment().HasAttachment())
    296                  return fb->DepthStencilAttachment();
    297                return fb->StencilAttachment();
    298 
    299              default:
    300                return fb->ColorAttachment0();
    301            }
    302          }();
    303 
    304          const auto imageInfo = attachment.GetImageInfo();
    305          if (!imageInfo) return nullptr;
    306          return imageInfo->mFormat->format;
    307        }
    308 
    309        auto effFormat = webgl::EffectiveFormat::RGB8;
    310        switch (pname) {
    311          case LOCAL_GL_DEPTH_BITS:
    312            if (mOptions.depth) {
    313              effFormat = webgl::EffectiveFormat::DEPTH24_STENCIL8;
    314            }
    315            break;
    316 
    317          case LOCAL_GL_STENCIL_BITS:
    318            if (mOptions.stencil) {
    319              effFormat = webgl::EffectiveFormat::DEPTH24_STENCIL8;
    320            }
    321            break;
    322 
    323          default:
    324            if (mOptions.alpha) {
    325              effFormat = webgl::EffectiveFormat::RGBA8;
    326            }
    327            break;
    328        }
    329        return webgl::GetFormat(effFormat);
    330      }();
    331      int32_t ret = 0;
    332      if (format) {
    333        switch (pname) {
    334          case LOCAL_GL_RED_BITS:
    335            ret = format->r;
    336            break;
    337          case LOCAL_GL_GREEN_BITS:
    338            ret = format->g;
    339            break;
    340          case LOCAL_GL_BLUE_BITS:
    341            ret = format->b;
    342            break;
    343          case LOCAL_GL_ALPHA_BITS:
    344            ret = format->a;
    345            break;
    346          case LOCAL_GL_DEPTH_BITS:
    347            ret = format->d;
    348            break;
    349          case LOCAL_GL_STENCIL_BITS:
    350            ret = format->s;
    351            break;
    352        }
    353      }
    354      return Some(ret);
    355    }
    356 
    357    case LOCAL_GL_MAX_RENDERBUFFER_SIZE:
    358      return Some(mGLMaxRenderbufferSize);
    359 
    360    case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
    361      return Some(mGLMaxVertexTextureImageUnits);
    362 
    363    case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS:
    364      return Some(mGLMaxFragmentTextureImageUnits);
    365 
    366    case LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS:
    367      return Some(mGLMaxVertexUniformVectors);
    368 
    369    case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
    370      return Some(mGLMaxFragmentUniformVectors);
    371 
    372    case LOCAL_GL_MAX_VARYING_VECTORS:
    373      return Some(mGLMaxFragmentInputVectors);
    374 
    375    // unsigned int. here we may have to return very large values like 2^32-1
    376    // that can't be represented as javascript integer values. We just return
    377    // them as doubles and javascript doesn't care.
    378    case LOCAL_GL_STENCIL_BACK_VALUE_MASK:
    379      return Some(mStencilValueMaskBack);
    380      // pass as FP value to allow large values such as 2^32-1.
    381 
    382    case LOCAL_GL_STENCIL_BACK_WRITEMASK:
    383      return Some(mStencilWriteMaskBack);
    384 
    385    case LOCAL_GL_STENCIL_VALUE_MASK:
    386      return Some(mStencilValueMaskFront);
    387 
    388    case LOCAL_GL_STENCIL_WRITEMASK:
    389      return Some(mStencilWriteMaskFront);
    390 
    391    case LOCAL_GL_COLOR_WRITEMASK:
    392      return Some(mColorWriteMask0);
    393 
    394    // float
    395    case LOCAL_GL_LINE_WIDTH:
    396      return Some((double)mLineWidth);
    397 
    398    case LOCAL_GL_DEPTH_CLEAR_VALUE:
    399    case LOCAL_GL_POLYGON_OFFSET_FACTOR:
    400    case LOCAL_GL_POLYGON_OFFSET_UNITS:
    401    case LOCAL_GL_SAMPLE_COVERAGE_VALUE: {
    402      GLfloat f = 0.f;
    403      gl->fGetFloatv(pname, &f);
    404      return Some(f);
    405    }
    406 
    407    // bool
    408    case LOCAL_GL_DEPTH_TEST:
    409      return Some((bool)mDepthTestEnabled);
    410    case LOCAL_GL_STENCIL_TEST:
    411      return Some((bool)mStencilTestEnabled);
    412 
    413    case LOCAL_GL_BLEND:
    414    case LOCAL_GL_CULL_FACE:
    415    case LOCAL_GL_DITHER:
    416    case LOCAL_GL_POLYGON_OFFSET_FILL:
    417    case LOCAL_GL_SCISSOR_TEST:
    418    case LOCAL_GL_SAMPLE_COVERAGE_INVERT:
    419    case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE:
    420    case LOCAL_GL_SAMPLE_COVERAGE:
    421    case LOCAL_GL_DEPTH_WRITEMASK: {
    422      realGLboolean b = 0;
    423      gl->fGetBooleanv(pname, &b);
    424      return Some(bool(b));
    425    }
    426 
    427    default:
    428      break;
    429  }
    430 
    431  ErrorInvalidEnumInfo("pname", pname);
    432  return Nothing();
    433 }
    434 
    435 bool* WebGLContext::GetStateTrackingSlot(GLenum cap) {
    436  switch (cap) {
    437    case LOCAL_GL_DEPTH_TEST:
    438      return &mDepthTestEnabled;
    439    case LOCAL_GL_DITHER:
    440      return &mDitherEnabled;
    441    case LOCAL_GL_RASTERIZER_DISCARD:
    442      return &mRasterizerDiscardEnabled;
    443    case LOCAL_GL_SCISSOR_TEST:
    444      return &mScissorTestEnabled;
    445    case LOCAL_GL_STENCIL_TEST:
    446      return &mStencilTestEnabled;
    447  }
    448 
    449  return nullptr;
    450 }
    451 
    452 }  // namespace mozilla