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;
}
Example #2
0
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);
}
Example #3
0
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;
  }
}
Example #5
0
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;
    }
  }
}