std::string EnumString(const GLenum val) { const char* name = GetEnumName(val, nullptr); if (name) { return name; } const nsPrintfCString hex("<enum 0x%04x>", val); return hex.BeginReading(); }
bool UnlockObject(HANDLE hObject) const { bool ret = mWGL->fDXUnlockObjects(mDXGLDeviceHandle, 1, &hObject); if (!ret) { uint32_t error = GetLastError(); const nsPrintfCString errorMessage("wglDXUnlockObjects(0x%x, 1, {0x%x}) " "failed: GetLastError(): 0x%x\n", mDXGLDeviceHandle, hObject, error); gfxCriticalError() << errorMessage.BeginReading(); MOZ_CRASH("GFX: Problem unlocking DXGL device"); } return ret; }
void WebGLContext::ErrorImplementationBug(const char* fmt, ...) const { const nsPrintfCString warning("Implementation bug, please file at %s! %s", "https://bugzilla.mozilla.org/", fmt); va_list va; va_start(va, fmt); GenerateWarning(warning.BeginReading(), va); va_end(va); MOZ_ASSERT(false, "WebGLContext::ErrorImplementationBug"); NS_ERROR("WebGLContext::ErrorImplementationBug"); return SynthesizeGLError(LOCAL_GL_OUT_OF_MEMORY); }
bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName, WebGLTexture* tex, TexImageTarget target, GLint level, const webgl::DriverUnpackInfo* dui, GLint xOffset, GLint yOffset, GLint zOffset, const webgl::PackingInfo& pi, GLenum* const out_error) const { MOZ_ASSERT_IF(needsRespec, !isSubImage); WebGLContext* webgl = tex->mContext; gl::GLContext* gl = webgl->GL(); gl->MakeCurrent(); if (needsRespec) { *out_error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset, yOffset, zOffset, mWidth, mHeight, mDepth, nullptr); if (*out_error) return true; } const char* fallbackReason; do { if (mDepth != 1) { fallbackReason = "depth is not 1"; break; } if (webgl->mPixelStore_UnpackSkipPixels || webgl->mPixelStore_UnpackSkipRows || webgl->mPixelStore_UnpackSkipImages) { fallbackReason = "non-zero UNPACK_SKIP_* not yet supported"; break; } const auto fnHasPremultMismatch = [&]() { if (mSrcAlphaType == gfxAlphaType::Opaque) return false; const bool srcIsPremult = (mSrcAlphaType == gfxAlphaType::Premult); const auto& dstIsPremult = webgl->mPixelStore_PremultiplyAlpha; if (srcIsPremult == dstIsPremult) return false; if (dstIsPremult) { fallbackReason = "UNPACK_PREMULTIPLY_ALPHA_WEBGL is not true"; } else { fallbackReason = "UNPACK_PREMULTIPLY_ALPHA_WEBGL is not false"; } return true; }; if (fnHasPremultMismatch()) break; if (dui->unpackFormat != LOCAL_GL_RGB && dui->unpackFormat != LOCAL_GL_RGBA) { fallbackReason = "`format` is not RGB or RGBA"; break; } if (dui->unpackType != LOCAL_GL_UNSIGNED_BYTE) { fallbackReason = "`type` is not UNSIGNED_BYTE"; break; } gl::ScopedFramebuffer scopedFB(gl); gl::ScopedBindFramebuffer bindFB(gl, scopedFB.FB()); { gl::GLContext::LocalErrorScope errorScope(*gl); gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, target.get(), tex->mGLName, level); if (errorScope.GetError()) { fallbackReason = "bug: failed to attach to FB for blit"; break; } } const GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) { fallbackReason = "bug: failed to confirm FB for blit"; break; } const gfx::IntSize destSize(mWidth, mHeight); const auto dstOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft : gl::OriginPos::BottomLeft); if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, scopedFB.FB(), dstOrigin)) { fallbackReason = "likely bug: failed to blit"; break; } // Blitting was successful, so we're done! *out_error = 0; return true; } while (false); const nsPrintfCString perfMsg("%s: Failed to hit GPU-copy fast-path: %s (src type %u)", funcName, fallbackReason, uint32_t(mImage->GetFormat())); if (webgl->mPixelStore_RequireFastPath) { webgl->ErrorInvalidOperation("%s", perfMsg.BeginReading()); return false; } webgl->GeneratePerfWarning("%s Falling back to CPU upload.", perfMsg.BeginReading()); const RefPtr<gfx::SourceSurface> surf = mImage->GetAsSourceSurface(); RefPtr<gfx::DataSourceSurface> dataSurf; if (surf) { // WARNING: OSX can lose our MakeCurrent here. dataSurf = surf->GetDataSurface(); } if (!dataSurf) { webgl->ErrorOutOfMemory("%s: GetAsSourceSurface or GetDataSurface failed after" " blit failed for TexUnpackImage.", funcName); return false; } const TexUnpackSurface surfBlob(webgl, target, mWidth, mHeight, mDepth, dataSurf, mSrcAlphaType); return surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level, dui, xOffset, yOffset, zOffset, pi, out_error); }
bool GLBlitHelper::BlitImage(layers::MacIOSurfaceImage* const srcImage, const gfx::IntSize& destSize, const OriginPos destOrigin) const { MacIOSurface* const iosurf = srcImage->GetSurface(); if (mGL->GetContextType() != GLContextType::CGL) { MOZ_ASSERT(false); return false; } const auto glCGL = static_cast<GLContextCGL*>(mGL); const auto cglContext = glCGL->GetCGLContext(); const auto& srcOrigin = OriginPos::BottomLeft; DrawBlitProg::BaseArgs baseArgs; baseArgs.yFlip = (destOrigin != srcOrigin); baseArgs.destSize = destSize; DrawBlitProg::YUVArgs yuvArgs; yuvArgs.colorSpace = YUVColorSpace::BT601; const DrawBlitProg::YUVArgs* pYuvArgs = nullptr; auto planes = iosurf->GetPlaneCount(); if (!planes) { planes = 1; // Bad API. No cookie. } const GLenum texTarget = LOCAL_GL_TEXTURE_RECTANGLE; const char* const fragHeader = kFragHeader_Tex2DRect; const ScopedSaveMultiTex saveTex(mGL, planes, texTarget); const ScopedTexture tex0(mGL); const ScopedTexture tex1(mGL); const ScopedTexture tex2(mGL); const GLuint texs[3] = { tex0, tex1, tex2 }; const auto pixelFormat = iosurf->GetPixelFormat(); const auto formatChars = (const char*)&pixelFormat; const char formatStr[] = { formatChars[3], formatChars[2], formatChars[1], formatChars[0], 0 }; if (mGL->ShouldSpew()) { printf_stderr("iosurf format: %s (0x%08x)\n", formatStr, uint32_t(pixelFormat)); } const char* fragBody; GLenum internalFormats[3] = {0, 0, 0}; GLenum unpackFormats[3] = {0, 0, 0}; GLenum unpackTypes[3] = { LOCAL_GL_UNSIGNED_BYTE, LOCAL_GL_UNSIGNED_BYTE, LOCAL_GL_UNSIGNED_BYTE }; switch (planes) { case 1: fragBody = kFragBody_RGBA; internalFormats[0] = LOCAL_GL_RGBA; unpackFormats[0] = LOCAL_GL_RGBA; break; case 2: fragBody = kFragBody_NV12; if (mGL->Version() >= 300) { internalFormats[0] = LOCAL_GL_R8; unpackFormats[0] = LOCAL_GL_RED; internalFormats[1] = LOCAL_GL_RG8; unpackFormats[1] = LOCAL_GL_RG; } else { internalFormats[0] = LOCAL_GL_LUMINANCE; unpackFormats[0] = LOCAL_GL_LUMINANCE; internalFormats[1] = LOCAL_GL_LUMINANCE_ALPHA; unpackFormats[1] = LOCAL_GL_LUMINANCE_ALPHA; } pYuvArgs = &yuvArgs; break; case 3: fragBody = kFragBody_PlanarYUV; if (mGL->Version() >= 300) { internalFormats[0] = LOCAL_GL_R8; unpackFormats[0] = LOCAL_GL_RED; } else { internalFormats[0] = LOCAL_GL_LUMINANCE; unpackFormats[0] = LOCAL_GL_LUMINANCE; } internalFormats[1] = internalFormats[0]; internalFormats[2] = internalFormats[0]; unpackFormats[1] = unpackFormats[0]; unpackFormats[2] = unpackFormats[0]; pYuvArgs = &yuvArgs; break; default: gfxCriticalError() << "Unexpected plane count: " << planes; return false; } if (pixelFormat == '2vuy') { fragBody = kFragBody_CrYCb; // APPLE_rgb_422 adds RGB_RAW_422_APPLE for `internalFormat`, but only RGB seems // to work? internalFormats[0] = LOCAL_GL_RGB; unpackFormats[0] = LOCAL_GL_RGB_422_APPLE; unpackTypes[0] = LOCAL_GL_UNSIGNED_SHORT_8_8_APPLE; pYuvArgs = &yuvArgs; } for (uint32_t p = 0; p < planes; p++) { mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + p); mGL->fBindTexture(texTarget, texs[p]); mGL->TexParams_SetClampNoMips(texTarget); const auto width = iosurf->GetDevicePixelWidth(p); const auto height = iosurf->GetDevicePixelHeight(p); auto err = iosurf->CGLTexImageIOSurface2D(cglContext, texTarget, internalFormats[p], width, height, unpackFormats[p], unpackTypes[p], p); if (err) { const nsPrintfCString errStr("CGLTexImageIOSurface2D(context, target, 0x%04x," " %u, %u, 0x%04x, 0x%04x, iosurfPtr, %u) -> %i", internalFormats[p], uint32_t(width), uint32_t(height), unpackFormats[p], unpackTypes[p], p, err); gfxCriticalError() << errStr.get() << " (iosurf format: " << formatStr << ")"; return false; } if (p == 0) { baseArgs.texMatrix0 = SubRectMat3(0, 0, width, height); yuvArgs.texMatrix1 = SubRectMat3(0, 0, width / 2.0, height / 2.0); } } const auto& prog = GetDrawBlitProg({fragHeader, fragBody}); if (!prog) return false; prog->Draw(baseArgs, pYuvArgs); return true; }
WebGLContext::FakeBlackTexture::FakeBlackTexture(gl::GLContext* gl, TexTarget target, FakeBlackType type) : mGL(gl) , mGLName(CreateGLTexture(gl)) { GLenum texFormat; switch (type) { case FakeBlackType::RGBA0000: texFormat = LOCAL_GL_RGBA; break; case FakeBlackType::RGBA0001: texFormat = LOCAL_GL_RGB; break; default: MOZ_CRASH("bad type"); } gl::ScopedBindTexture scopedBind(mGL, mGLName, target.get()); mGL->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST); mGL->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST); // We allocate our zeros on the heap, and we overallocate (16 bytes instead of 4) to // minimize the risk of running into a driver bug in texImage2D, as it is a bit // unusual maybe to create 1x1 textures, and the stack may not have the alignment that // TexImage2D expects. const webgl::DriverUnpackInfo dui = {texFormat, texFormat, LOCAL_GL_UNSIGNED_BYTE}; UniqueBuffer zeros = moz_xcalloc(1, 16); // Infallible allocation. MOZ_ASSERT(gl->IsCurrent()); if (target == LOCAL_GL_TEXTURE_CUBE_MAP) { for (int i = 0; i < 6; ++i) { const TexImageTarget curTarget = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i; const GLenum error = DoTexImage(mGL, curTarget.get(), 0, &dui, 1, 1, 1, zeros.get()); if (error) { const nsPrintfCString text("DoTexImage failed with `error`: 0x%04x, " "for `curTarget`: 0x%04x, " "`dui`: {0x%04x, 0x%04x, 0x%04x}.", error, curTarget.get(), dui.internalFormat, dui.unpackFormat, dui.unpackType); gfxCriticalError() << text.BeginReading(); MOZ_CRASH("Unexpected error during cube map FakeBlack creation."); } } } else { const GLenum error = DoTexImage(mGL, target.get(), 0, &dui, 1, 1, 1, zeros.get()); if (error) { const nsPrintfCString text("DoTexImage failed with `error`: 0x%04x, " "for `target`: 0x%04x, " "`dui`: {0x%04x, 0x%04x, 0x%04x}.", error, target.get(), dui.internalFormat, dui.unpackFormat, dui.unpackType); gfxCriticalError() << text.BeginReading(); MOZ_CRASH("Unexpected error during FakeBlack creation."); } } }