bool CompositableHost::AddMaskEffect(EffectChain& aEffects, const gfx::Matrix4x4& aTransform, bool aIs3D) { CompositableTextureSourceRef source; RefPtr<TextureHost> host = GetAsTextureHost(); if (!host) { NS_WARNING("Using compositable with no valid TextureHost as mask"); return false; } if (!host->Lock()) { NS_WARNING("Failed to lock the mask texture"); return false; } if (!host->BindTextureSource(source)) { NS_WARNING("The TextureHost was successfully locked but can't provide a TextureSource"); host->Unlock(); return false; } MOZ_ASSERT(source); RefPtr<EffectMask> effect = new EffectMask(source, source->GetSize(), aTransform); effect->mIs3D = aIs3D; aEffects.mSecondaryEffects[EffectTypes::MASK] = effect; return true; }
void VRDisplayHost::SubmitFrame(VRLayerParent* aLayer, const int32_t& aInputFrameID, PTextureParent* aTexture, const gfx::Rect& aLeftEyeRect, const gfx::Rect& aRightEyeRect) { // aInputFrameID is no longer controlled by content with the WebVR 1.1 API // update; however, we will later use this code to enable asynchronous // submission of multiple layers to be composited. This will enable // us to build browser UX that remains responsive even when content does // not consistently submit frames. int32_t inputFrameID = aInputFrameID; if (inputFrameID == 0) { inputFrameID = mInputFrameID; } if (inputFrameID < 0) { // Sanity check to prevent invalid memory access on builds with assertions // disabled. inputFrameID = 0; } VRHMDSensorState sensorState = mLastSensorState[inputFrameID % kMaxLatencyFrames]; // It is possible to get a cache miss on mLastSensorState if latency is // longer than kMaxLatencyFrames. An optimization would be to find a frame // that is closer than the one selected with the modulus. // If we hit this; however, latency is already so high that the site is // un-viewable and a more accurate pose prediction is not likely to // compensate. TextureHost* th = TextureHost::AsTextureHost(aTexture); // WebVR doesn't use the compositor to compose the frame, so use // AutoLockTextureHostWithoutCompositor here. AutoLockTextureHostWithoutCompositor autoLock(th); if (autoLock.Failed()) { NS_WARNING("Failed to lock the VR layer texture"); return; } CompositableTextureSourceRef source; if (!th->BindTextureSource(source)) { NS_WARNING("The TextureHost was successfully locked but can't provide a TextureSource"); return; } MOZ_ASSERT(source); IntSize texSize = source->GetSize(); TextureSourceD3D11* sourceD3D11 = source->AsSourceD3D11(); if (!sourceD3D11) { NS_WARNING("WebVR support currently only implemented for D3D11"); return; } SubmitFrame(sourceD3D11, texSize, sensorState, aLeftEyeRect, aRightEyeRect); }
void VRDisplayHost::SubmitFrame(VRLayerParent* aLayer, PTextureParent* aTexture, const gfx::Rect& aLeftEyeRect, const gfx::Rect& aRightEyeRect) { if ((mDisplayInfo.mGroupMask & aLayer->GetGroup()) == 0) { // Suppress layers hidden by the group mask return; } TextureHost* th = TextureHost::AsTextureHost(aTexture); // WebVR doesn't use the compositor to compose the frame, so use // AutoLockTextureHostWithoutCompositor here. AutoLockTextureHostWithoutCompositor autoLock(th); if (autoLock.Failed()) { NS_WARNING("Failed to lock the VR layer texture"); return; } CompositableTextureSourceRef source; if (!th->BindTextureSource(source)) { NS_WARNING("The TextureHost was successfully locked but can't provide a TextureSource"); return; } MOZ_ASSERT(source); IntSize texSize = source->GetSize(); TextureSourceD3D11* sourceD3D11 = source->AsSourceD3D11(); if (!sourceD3D11) { NS_WARNING("WebVR support currently only implemented for D3D11"); return; } if (!SubmitFrame(sourceD3D11, texSize, aLeftEyeRect, aRightEyeRect)) { return; } /** * Trigger the next VSync immediately after we are successfully * submitting frames. As SubmitFrame is responsible for throttling * the render loop, if we don't successfully call it, we shouldn't trigger * NotifyVRVsync immediately, as it will run unbounded. * If NotifyVRVsync is not called here due to SubmitFrame failing, the * fallback "watchdog" code in VRDisplayHost::NotifyVSync() will cause * frames to continue at a lower refresh rate until frame submission * succeeds again. */ VRManager *vm = VRManager::Get(); MOZ_ASSERT(vm); vm->NotifyVRVsync(mDisplayInfo.mDisplayID); }
void GrallocTextureHostOGL::PrepareTextureSource(CompositableTextureSourceRef& aTextureSource) { // This happens during the layers transaction. // All of the gralloc magic goes here. The only thing that happens externally // and that is good to keep in mind is that when the TextureSource is deleted, // it destroys its gl texture handle which is important for genlock. // If this TextureHost's mGLTextureSource member is non-null, it means we are // still bound to the TextureSource, in which case we can skip the driver // overhead of binding the texture again (fEGLImageTargetTexture2D) // As a result, if the TextureHost is used with several CompositableHosts, // it will be bound to only one TextureSource, and we'll do the driver work // only once, which is great. This means that all of the compositables that // use this TextureHost will keep a reference to this TextureSource at least // for the duration of this frame. // If the compositable already has a TextureSource (the aTextureSource parameter), // that is compatible and is not in use by several compositable, we try to // attach to it. This has the effect of unlocking the previous TextureHost that // we attached to the TextureSource (the previous frame) // If the TextureSource used by the compositable is also used by other // compositables (see NumCompositableRefs), we have to create a new TextureSource, // because otherwise we would be modifying the content of every layer that uses // the TextureSource in question, even thoug they don't use this TextureHost. MOZ_ASSERT(!mTilingTextureSource); android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get(); MOZ_ASSERT(graphicBuffer); if (!graphicBuffer) { mGLTextureSource = nullptr; return; } if (mGLTextureSource && !mGLTextureSource->IsValid()) { mGLTextureSource = nullptr; } if (mGLTextureSource) { // We are already attached to a TextureSource, nothing to do except tell // the compositable to use it. aTextureSource = mGLTextureSource.get(); return; } gl::GLContext* gl = GetGLContext(); if (!gl || !gl->MakeCurrent()) { mGLTextureSource = nullptr; return; } if (mEGLImage == EGL_NO_IMAGE) { // Should only happen the first time. mEGLImage = EGLImageCreateFromNativeBuffer(gl, graphicBuffer->getNativeBuffer()); } GLenum textureTarget = GetTextureTarget(gl, graphicBuffer->getPixelFormat()); GLTextureSource* glSource = aTextureSource.get() ? aTextureSource->AsSourceOGL()->AsGLTextureSource() : nullptr; bool shouldCreateTextureSource = !glSource || !glSource->IsValid() || glSource->NumCompositableRefs() > 1 || glSource->GetTextureTarget() != textureTarget; if (shouldCreateTextureSource) { GLuint textureHandle; gl->fGenTextures(1, &textureHandle); gl->fBindTexture(textureTarget, textureHandle); gl->fTexParameteri(textureTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); gl->fTexParameteri(textureTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); gl->fEGLImageTargetTexture2D(textureTarget, mEGLImage); mGLTextureSource = new GLTextureSource(mCompositor, textureHandle, textureTarget, mSize, mFormat); aTextureSource = mGLTextureSource.get(); } else { gl->fBindTexture(textureTarget, glSource->GetTextureHandle()); gl->fEGLImageTargetTexture2D(textureTarget, mEGLImage); glSource->SetSize(mSize); glSource->SetFormat(mFormat); mGLTextureSource = glSource; } }
TiledLayerBufferComposite::TiledLayerBufferComposite(ISurfaceAllocator* aAllocator, const SurfaceDescriptorTiles& aDescriptor, const nsIntRegion& aOldPaintedRegion, Compositor* aCompositor) { mIsValid = true; mHasDoubleBufferedTiles = false; mValidRegion = aDescriptor.validRegion(); mPaintedRegion = aDescriptor.paintedRegion(); mRetainedWidth = aDescriptor.retainedWidth(); mRetainedHeight = aDescriptor.retainedHeight(); mResolution = aDescriptor.resolution(); mFrameResolution = CSSToParentLayerScale(aDescriptor.frameResolution()); if (mResolution == 0 || IsNaN(mResolution)) { // There are divisions by mResolution so this protects the compositor process // against malicious content processes and fuzzing. mIsValid = false; return; } // Combine any valid content that wasn't already uploaded nsIntRegion oldPaintedRegion(aOldPaintedRegion); oldPaintedRegion.And(oldPaintedRegion, mValidRegion); mPaintedRegion.Or(mPaintedRegion, oldPaintedRegion); bool isSameProcess = aAllocator->IsSameProcess(); const InfallibleTArray<TileDescriptor>& tiles = aDescriptor.tiles(); for(size_t i = 0; i < tiles.Length(); i++) { CompositableTextureHostRef texture; CompositableTextureHostRef textureOnWhite; const TileDescriptor& tileDesc = tiles[i]; switch (tileDesc.type()) { case TileDescriptor::TTexturedTileDescriptor : { texture = TextureHost::AsTextureHost(tileDesc.get_TexturedTileDescriptor().textureParent()); MaybeTexture onWhite = tileDesc.get_TexturedTileDescriptor().textureOnWhite(); if (onWhite.type() == MaybeTexture::TPTextureParent) { textureOnWhite = TextureHost::AsTextureHost(onWhite.get_PTextureParent()); } const TileLock& ipcLock = tileDesc.get_TexturedTileDescriptor().sharedLock(); nsRefPtr<gfxSharedReadLock> sharedLock; if (ipcLock.type() == TileLock::TShmemSection) { sharedLock = gfxShmSharedReadLock::Open(aAllocator, ipcLock.get_ShmemSection()); } else { if (!isSameProcess) { // Trying to use a memory based lock instead of a shmem based one in // the cross-process case is a bad security violation. NS_ERROR("A client process may be trying to peek at the host's address space!"); // This tells the TiledContentHost that deserialization failed so that // it can propagate the error. mIsValid = false; mRetainedTiles.Clear(); return; } sharedLock = reinterpret_cast<gfxMemorySharedReadLock*>(ipcLock.get_uintptr_t()); if (sharedLock) { // The corresponding AddRef is in TiledClient::GetTileDescriptor sharedLock.get()->Release(); } } CompositableTextureSourceRef textureSource; CompositableTextureSourceRef textureSourceOnWhite; if (texture) { texture->SetCompositor(aCompositor); texture->PrepareTextureSource(textureSource); } if (textureOnWhite) { textureOnWhite->SetCompositor(aCompositor); textureOnWhite->PrepareTextureSource(textureSourceOnWhite); } mRetainedTiles.AppendElement(TileHost(sharedLock, texture.get(), textureOnWhite.get(), textureSource.get(), textureSourceOnWhite.get())); break; } default: NS_WARNING("Unrecognised tile descriptor type"); // Fall through case TileDescriptor::TPlaceholderTileDescriptor : mRetainedTiles.AppendElement(GetPlaceholderTile()); break; } if (texture && !texture->HasInternalBuffer()) { mHasDoubleBufferedTiles = true; } } }