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