tor-browser

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

WebGLParent.cpp (14279B)


      1 /* -*- Mode: C++; tab-width: 20; 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 "WebGLParent.h"
      7 
      8 #include "HostWebGLContext.h"
      9 #include "ImageContainer.h"
     10 #include "WebGLChild.h"
     11 #include "WebGLMethodDispatcher.h"
     12 #include "mozilla/layers/SharedSurfacesParent.h"
     13 #include "mozilla/layers/TextureClientSharedSurface.h"
     14 
     15 namespace mozilla::dom {
     16 
     17 mozilla::ipc::IPCResult WebGLParent::RecvInitialize(
     18    const webgl::InitContextDesc& desc, webgl::InitContextResult* const out) {
     19  mHost = HostWebGLContext::Create({nullptr, this}, desc, out);
     20 
     21  if (!mHost) {
     22    MOZ_ASSERT(!out->error->empty());
     23  }
     24 
     25  return IPC_OK();
     26 }
     27 
     28 WebGLParent::WebGLParent(layers::SharedSurfacesHolder* aSharedSurfacesHolder,
     29                         const dom::ContentParentId& aContentId)
     30    : mSharedSurfacesHolder(aSharedSurfacesHolder), mContentId(aContentId) {}
     31 
     32 WebGLParent::~WebGLParent() = default;
     33 
     34 // -
     35 
     36 using IPCResult = mozilla::ipc::IPCResult;
     37 
     38 IPCResult WebGLParent::RecvDispatchCommands(BigBuffer&& shmem,
     39                                            const uint64_t cmdsByteSize) {
     40  AUTO_PROFILER_LABEL("WebGLParent::RecvDispatchCommands", GRAPHICS);
     41  if (!mHost) {
     42    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
     43  }
     44 
     45  const auto& gl = mHost->mContext->GL();
     46  const gl::GLContext::TlsScope tlsIsCurrent(gl);
     47 
     48  MOZ_ASSERT(cmdsByteSize);
     49  const auto shmemBytes = Range<uint8_t>{shmem.AsSpan()};
     50  const auto byteSize = std::min<uint64_t>(shmemBytes.length(), cmdsByteSize);
     51  const auto cmdsBytes =
     52      Range<const uint8_t>{shmemBytes.begin(), shmemBytes.begin() + byteSize};
     53  auto view = webgl::RangeConsumerView{cmdsBytes};
     54 
     55  if (kIsDebug) {
     56    const auto initialOffset =
     57        AlignmentOffset(kUniversalAlignment, cmdsBytes.begin().get());
     58    MOZ_ALWAYS_TRUE(!initialOffset);
     59  }
     60 
     61  std::optional<std::string> fatalError;
     62 
     63  while (true) {
     64    view.AlignTo(kUniversalAlignment);
     65    size_t id = 0;
     66    if (!view.ReadParam(&id)) break;
     67 
     68    // We split this up so that we don't end up in a long callstack chain of
     69    // WebGLMethodDispatcher<i>|i=0->N. First get the lambda for dispatch, then
     70    // invoke the lambda with our args.
     71    const auto pfn =
     72        WebGLMethodDispatcher<0>::DispatchCommandFuncById<HostWebGLContext>(id);
     73    if (!pfn) {
     74      const nsPrintfCString cstr(
     75          "MethodDispatcher<%zu> not found. Please file a bug!", id);
     76      fatalError = ToString(cstr);
     77      gfxCriticalError() << *fatalError;
     78      break;
     79    };
     80 
     81    const auto ok = (*pfn)(*mHost, view);
     82    if (!ok) {
     83      const nsPrintfCString cstr(
     84          "DispatchCommand(id: %zu) failed. Please file a bug!", id);
     85      fatalError = ToString(cstr);
     86      gfxCriticalError() << *fatalError;
     87      break;
     88    }
     89  }
     90 
     91  if (fatalError) {
     92    mHost->JsWarning(*fatalError);
     93    mHost->OnContextLoss(webgl::ContextLossReason::None);
     94  }
     95 
     96  return IPC_OK();
     97 }
     98 
     99 IPCResult WebGLParent::RecvTexImage(const uint32_t level,
    100                                    const uint32_t respecFormat,
    101                                    const uvec3& offset,
    102                                    const webgl::PackingInfo& pi,
    103                                    webgl::TexUnpackBlobDesc&& desc) {
    104  if (!mHost) {
    105    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    106  }
    107 
    108  mHost->TexImage(level, respecFormat, offset, pi, desc);
    109  return IPC_OK();
    110 }
    111 
    112 // -
    113 
    114 mozilla::ipc::IPCResult WebGLParent::Recv__delete__() {
    115  mHost = nullptr;
    116  return IPC_OK();
    117 }
    118 
    119 void WebGLParent::ActorDestroy(ActorDestroyReason aWhy) { mHost = nullptr; }
    120 
    121 mozilla::ipc::IPCResult WebGLParent::RecvWaitForTxn(
    122    layers::RemoteTextureOwnerId aOwnerId,
    123    layers::RemoteTextureTxnType aTxnType, layers::RemoteTextureTxnId aTxnId) {
    124  if (mHost) {
    125    mHost->WaitForTxn(aOwnerId, aTxnType, aTxnId);
    126  }
    127  return IPC_OK();
    128 }
    129 
    130 // -
    131 
    132 IPCResult WebGLParent::RecvGetFrontBufferSnapshot(
    133    webgl::FrontBufferSnapshotIpc* const ret) {
    134  return GetFrontBufferSnapshot(ret, this);
    135 }
    136 
    137 IPCResult WebGLParent::GetFrontBufferSnapshot(
    138    webgl::FrontBufferSnapshotIpc* const ret, IProtocol* aProtocol) {
    139  AUTO_PROFILER_LABEL("WebGLParent::GetFrontBufferSnapshot", GRAPHICS);
    140  *ret = {};
    141  if (!mHost) {
    142    return IPC_FAIL(aProtocol, "HostWebGLContext is not initialized.");
    143  }
    144 
    145  const bool ok = [&]() {
    146    const auto maybeSize = mHost->FrontBufferSnapshotInto({});
    147    if (maybeSize) {
    148      const auto& surfSize = *maybeSize;
    149      const auto byteSize = 4 * surfSize.x * surfSize.y;
    150      const auto byteStride = 4 * surfSize.x;
    151 
    152      auto shmem = webgl::RaiiShmem::Alloc(aProtocol, byteSize);
    153      if (!shmem) {
    154        NS_WARNING("Failed to alloc shmem for RecvGetFrontBufferSnapshot.");
    155        return false;
    156      }
    157      const auto range = shmem.ByteRange();
    158      *ret = {surfSize, byteStride, Some(shmem.Extract())};
    159 
    160      if (!mHost->FrontBufferSnapshotInto(Some(range))) {
    161        gfxCriticalNote << "WebGLParent::RecvGetFrontBufferSnapshot: "
    162                           "FrontBufferSnapshotInto(some) failed after "
    163                           "FrontBufferSnapshotInto(none)";
    164        return false;
    165      }
    166    }
    167    return true;
    168  }();
    169  if (!ok) {
    170    // Zero means failure, as we still need to send any shmem we alloc.
    171    ret->surfSize = {0, 0};
    172  }
    173  return IPC_OK();
    174 }
    175 
    176 IPCResult WebGLParent::RecvGetBufferSubData(const GLenum target,
    177                                            const uint64_t srcByteOffset,
    178                                            const uint64_t byteSize,
    179                                            Shmem* const ret) {
    180  AUTO_PROFILER_LABEL("WebGLParent::RecvGetBufferSubData", GRAPHICS);
    181  if (!mHost) {
    182    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    183  }
    184 
    185  const auto allocSize = 1 + byteSize;
    186  auto shmem = webgl::RaiiShmem::Alloc(this, allocSize);
    187  if (!shmem) {
    188    NS_WARNING("Failed to alloc shmem for RecvGetBufferSubData.");
    189    return IPC_OK();
    190  }
    191 
    192  const auto shmemRange = shmem.ByteRange();
    193  const auto dataRange =
    194      Range<uint8_t>{shmemRange.begin() + 1, shmemRange.end()};
    195 
    196  // We need to always send the shmem:
    197  // https://bugzilla.mozilla.org/show_bug.cgi?id=1463831#c2
    198  const auto ok = mHost->GetBufferSubData(target, srcByteOffset, dataRange);
    199  *(shmemRange.begin().get()) = ok;
    200  *ret = shmem.Extract();
    201  return IPC_OK();
    202 }
    203 
    204 IPCResult WebGLParent::RecvReadPixels(const webgl::ReadPixelsDesc& desc,
    205                                      ReadPixelsBuffer&& buffer,
    206                                      webgl::ReadPixelsResultIpc* const ret) {
    207  AUTO_PROFILER_LABEL("WebGLParent::RecvReadPixels", GRAPHICS);
    208  *ret = {};
    209  if (!mHost) {
    210    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    211  }
    212 
    213  if (buffer.type() == ReadPixelsBuffer::TShmem) {
    214    const auto& shmem = buffer.get_Shmem();
    215    const auto range = shmem.Range<uint8_t>();
    216    const auto res = mHost->ReadPixelsInto(desc, range);
    217    *ret = {res, {}};
    218    return IPC_OK();
    219  }
    220 
    221  const uint64_t byteSize = buffer.get_uint64_t();
    222  const auto allocSize = std::max<uint64_t>(1, byteSize);
    223  auto shmem = webgl::RaiiShmem::Alloc(this, allocSize);
    224  if (!shmem) {
    225    NS_WARNING("Failed to alloc shmem for RecvReadPixels.");
    226    return IPC_OK();
    227  }
    228 
    229  const auto range = shmem.ByteRange();
    230 
    231  const auto res = mHost->ReadPixelsInto(desc, range);
    232  *ret = {res, Some(shmem.Extract())};
    233  return IPC_OK();
    234 }
    235 
    236 // -
    237 
    238 IPCResult WebGLParent::RecvCheckFramebufferStatus(GLenum target,
    239                                                  GLenum* const ret) {
    240  if (!mHost) {
    241    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    242  }
    243 
    244  *ret = mHost->CheckFramebufferStatus(target);
    245  return IPC_OK();
    246 }
    247 
    248 IPCResult WebGLParent::RecvClientWaitSync(ObjectId id, GLbitfield flags,
    249                                          GLuint64 timeout, GLenum* const ret) {
    250  if (!mHost) {
    251    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    252  }
    253 
    254  *ret = mHost->ClientWaitSync(id, flags, timeout);
    255  return IPC_OK();
    256 }
    257 
    258 IPCResult WebGLParent::RecvCreateOpaqueFramebuffer(
    259    const ObjectId id, const OpaqueFramebufferOptions& options,
    260    bool* const ret) {
    261  if (!mHost) {
    262    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    263  }
    264 
    265  *ret = mHost->CreateOpaqueFramebuffer(id, options);
    266  return IPC_OK();
    267 }
    268 
    269 IPCResult WebGLParent::RecvDrawingBufferSize(uvec2* const ret) {
    270  if (!mHost) {
    271    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    272  }
    273 
    274  *ret = mHost->DrawingBufferSize();
    275  return IPC_OK();
    276 }
    277 
    278 IPCResult WebGLParent::RecvFinish() {
    279  if (!mHost) {
    280    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    281  }
    282 
    283  mHost->Finish();
    284  return IPC_OK();
    285 }
    286 
    287 IPCResult WebGLParent::RecvGetBufferParameter(GLenum target, GLenum pname,
    288                                              Maybe<double>* const ret) {
    289  if (!mHost) {
    290    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    291  }
    292 
    293  *ret = mHost->GetBufferParameter(target, pname);
    294  return IPC_OK();
    295 }
    296 
    297 IPCResult WebGLParent::RecvGetCompileResult(ObjectId id,
    298                                            webgl::CompileResult* const ret) {
    299  if (!mHost) {
    300    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    301  }
    302 
    303  *ret = mHost->GetCompileResult(id);
    304  return IPC_OK();
    305 }
    306 
    307 IPCResult WebGLParent::RecvGetError(GLenum* const ret) {
    308  if (!mHost) {
    309    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    310  }
    311 
    312  *ret = mHost->GetError();
    313  return IPC_OK();
    314 }
    315 
    316 IPCResult WebGLParent::RecvGetFragDataLocation(ObjectId id,
    317                                               const std::string& name,
    318                                               GLint* const ret) {
    319  if (!mHost) {
    320    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    321  }
    322 
    323  *ret = mHost->GetFragDataLocation(id, name);
    324  return IPC_OK();
    325 }
    326 
    327 IPCResult WebGLParent::RecvGetFramebufferAttachmentParameter(
    328    ObjectId id, GLenum attachment, GLenum pname, Maybe<double>* const ret) {
    329  if (!mHost) {
    330    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    331  }
    332 
    333  *ret = mHost->GetFramebufferAttachmentParameter(id, attachment, pname);
    334  return IPC_OK();
    335 }
    336 
    337 IPCResult WebGLParent::RecvGetFrontBuffer(
    338    ObjectId fb, const bool vr, Maybe<layers::SurfaceDescriptor>* const ret) {
    339  if (!mHost) {
    340    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    341  }
    342 
    343  *ret = mHost->GetFrontBuffer(fb, vr);
    344  return IPC_OK();
    345 }
    346 
    347 IPCResult WebGLParent::RecvGetIndexedParameter(GLenum target, GLuint index,
    348                                               Maybe<double>* const ret) {
    349  if (!mHost) {
    350    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    351  }
    352 
    353  *ret = mHost->GetIndexedParameter(target, index);
    354  return IPC_OK();
    355 }
    356 
    357 IPCResult WebGLParent::RecvGetInternalformatParameter(
    358    const GLenum target, const GLuint format, const GLuint pname,
    359    Maybe<std::vector<int32_t>>* const ret) {
    360  if (!mHost) {
    361    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    362  }
    363 
    364  *ret = mHost->GetInternalformatParameter(target, format, pname);
    365  return IPC_OK();
    366 }
    367 
    368 IPCResult WebGLParent::RecvGetLinkResult(ObjectId id,
    369                                         webgl::LinkResult* const ret) {
    370  if (!mHost) {
    371    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    372  }
    373 
    374  *ret = mHost->GetLinkResult(id);
    375  return IPC_OK();
    376 }
    377 
    378 IPCResult WebGLParent::RecvGetNumber(GLenum pname, Maybe<double>* const ret) {
    379  if (!mHost) {
    380    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    381  }
    382 
    383  *ret = mHost->GetNumber(pname);
    384  return IPC_OK();
    385 }
    386 
    387 IPCResult WebGLParent::RecvGetQueryParameter(ObjectId id, GLenum pname,
    388                                             Maybe<double>* const ret) {
    389  if (!mHost) {
    390    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    391  }
    392 
    393  *ret = mHost->GetQueryParameter(id, pname);
    394  return IPC_OK();
    395 }
    396 
    397 IPCResult WebGLParent::RecvGetRenderbufferParameter(ObjectId id, GLenum pname,
    398                                                    Maybe<double>* const ret) {
    399  if (!mHost) {
    400    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    401  }
    402 
    403  *ret = mHost->GetRenderbufferParameter(id, pname);
    404  return IPC_OK();
    405 }
    406 
    407 IPCResult WebGLParent::RecvGetSamplerParameter(ObjectId id, GLenum pname,
    408                                               Maybe<double>* const ret) {
    409  if (!mHost) {
    410    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    411  }
    412 
    413  *ret = mHost->GetSamplerParameter(id, pname);
    414  return IPC_OK();
    415 }
    416 
    417 IPCResult WebGLParent::RecvGetString(GLenum pname,
    418                                     Maybe<std::string>* const ret) {
    419  if (!mHost) {
    420    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    421  }
    422 
    423  *ret = mHost->GetString(pname);
    424  return IPC_OK();
    425 }
    426 
    427 IPCResult WebGLParent::RecvGetTexParameter(ObjectId id, GLenum pname,
    428                                           Maybe<double>* const ret) {
    429  if (!mHost) {
    430    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    431  }
    432 
    433  *ret = mHost->GetTexParameter(id, pname);
    434  return IPC_OK();
    435 }
    436 
    437 IPCResult WebGLParent::RecvGetUniform(ObjectId id, uint32_t loc,
    438                                      webgl::GetUniformData* const ret) {
    439  if (!mHost) {
    440    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    441  }
    442 
    443  *ret = mHost->GetUniform(id, loc);
    444  return IPC_OK();
    445 }
    446 
    447 IPCResult WebGLParent::RecvGetVertexAttrib(GLuint index, GLenum pname,
    448                                           Maybe<double>* const ret) {
    449  if (!mHost) {
    450    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    451  }
    452 
    453  *ret = mHost->GetVertexAttrib(index, pname);
    454  return IPC_OK();
    455 }
    456 
    457 IPCResult WebGLParent::RecvOnMemoryPressure() {
    458  if (!mHost) {
    459    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    460  }
    461 
    462  mHost->OnMemoryPressure();
    463  return IPC_OK();
    464 }
    465 
    466 IPCResult WebGLParent::RecvValidateProgram(ObjectId id, bool* const ret) {
    467  if (!mHost) {
    468    return IPC_FAIL(this, "HostWebGLContext is not initialized.");
    469  }
    470 
    471  *ret = mHost->ValidateProgram(id);
    472  return IPC_OK();
    473 }
    474 
    475 }  // namespace mozilla::dom