Ejemplo n.º 1
0
void
CompositorOGL::DrawVRDistortion(const gfx::Rect& aRect,
                                const gfx::Rect& aClipRect,
                                const EffectChain& aEffectChain,
                                gfx::Float aOpacity,
                                const gfx::Matrix4x4& aTransform)
{
  MOZ_ASSERT(aEffectChain.mPrimaryEffect->mType == EffectTypes::VR_DISTORTION);
  MOZ_ASSERT(mVR.mInitialized);

  if (aEffectChain.mSecondaryEffects[EffectTypes::MASK] ||
      aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE])
  {
    NS_WARNING("DrawVRDistortion: ignoring secondary effect!");
  }

  EffectVRDistortion* vrEffect =
    static_cast<EffectVRDistortion*>(aEffectChain.mPrimaryEffect.get());

  GLenum textureTarget = LOCAL_GL_TEXTURE_2D;
  if (vrEffect->mRenderTarget)
    textureTarget = mFBOTextureTarget;

  RefPtr<CompositingRenderTargetOGL> surface =
    static_cast<CompositingRenderTargetOGL*>(vrEffect->mRenderTarget.get());

  VRHMDInfo* hmdInfo = vrEffect->mHMD;
  VRDistortionConstants shaderConstants;

  if (hmdInfo->GetConfiguration() != mVR.mConfiguration) {
    for (uint32_t eye = 0; eye < 2; eye++) {
      const gfx::VRDistortionMesh& mesh = hmdInfo->GetDistortionMesh(eye);
      gl()->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mVR.mDistortionVertices[eye]);
      gl()->fBufferData(LOCAL_GL_ARRAY_BUFFER,
                       mesh.mVertices.Length() * sizeof(gfx::VRDistortionVertex),
                       mesh.mVertices.Elements(),
                       LOCAL_GL_STATIC_DRAW);

      gl()->fBindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER, mVR.mDistortionIndices[eye]);
      gl()->fBufferData(LOCAL_GL_ELEMENT_ARRAY_BUFFER,
                       mesh.mIndices.Length() * sizeof(uint16_t),
                       mesh.mIndices.Elements(),
                       LOCAL_GL_STATIC_DRAW);

      mVR.mDistortionIndexCount[eye] = mesh.mIndices.Length();
    }

    mVR.mConfiguration = hmdInfo->GetConfiguration();
  }

  int programIndex = textureTarget == LOCAL_GL_TEXTURE_2D ? 0 : 1;

  gl()->fScissor(aClipRect.x, FlipY(aClipRect.y + aClipRect.height),
                 aClipRect.width, aClipRect.height);

  // Clear out the entire area that we want to render; this ensures that
  // the layer will be opaque, even though the mesh geometry we'll be
  // drawing below won't cover the full rectangle.
  gl()->fClearColor(0.0, 0.0, 0.0, 1.0);
  gl()->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);

  // Make sure that the cached current program is reset for the
  // rest of the compositor, since we're using a custom program here
  ResetProgram();

  gl()->fUseProgram(mVR.mDistortionProgram[programIndex]);

  gl()->fEnableVertexAttribArray(mVR.mAPosition);
  gl()->fEnableVertexAttribArray(mVR.mATexCoord0);
  gl()->fEnableVertexAttribArray(mVR.mATexCoord1);
  gl()->fEnableVertexAttribArray(mVR.mATexCoord2);
  gl()->fEnableVertexAttribArray(mVR.mAGenericAttribs);

  surface->BindTexture(LOCAL_GL_TEXTURE0, mFBOTextureTarget);
  gl()->fUniform1i(mVR.mUTexture[programIndex], 0);

  Rect destRect = aTransform.TransformBounds(aRect);
  gfx::IntSize preDistortionSize = surface->GetInitSize(); // XXX source->GetSize()
  gfx::Size vpSize = destRect.Size();

  for (uint32_t eye = 0; eye < 2; eye++) {
    gfx::IntRect eyeViewport;
    eyeViewport.x = eye * preDistortionSize.width / 2;
    eyeViewport.y = 0;
    eyeViewport.width = preDistortionSize.width / 2;
    eyeViewport.height = preDistortionSize.height;

    hmdInfo->FillDistortionConstants(eye,
                                     preDistortionSize, eyeViewport,
                                     vpSize, destRect,
                                     shaderConstants);

    float height = 1.0f;
    float texScaleAndOffset[4] = { shaderConstants.eyeToSourceScaleAndOffset[0],
                                   shaderConstants.eyeToSourceScaleAndOffset[1],
                                   shaderConstants.eyeToSourceScaleAndOffset[2],
                                   shaderConstants.eyeToSourceScaleAndOffset[3] };
    if (textureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
      texScaleAndOffset[0] *= preDistortionSize.width;
      texScaleAndOffset[1] *= preDistortionSize.height;
      texScaleAndOffset[2] *= preDistortionSize.width;
      texScaleAndOffset[3] *= preDistortionSize.height;
      height = preDistortionSize.height;
    }

    gl()->fUniform4fv(mVR.mUVRDestionatinScaleAndOffset[programIndex], 1, shaderConstants.destinationScaleAndOffset);
    gl()->fUniform4fv(mVR.mUVREyeToSource[programIndex], 1, texScaleAndOffset);
    gl()->fUniform1f(mVR.mUHeight[programIndex], height);

    gl()->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mVR.mDistortionVertices[eye]);

    /* This is for Oculus DistortionVertex */

    gl()->fVertexAttribPointer(mVR.mAPosition,  2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, sizeof(gfx::VRDistortionVertex), (void*) (sizeof(float) * 0));
    gl()->fVertexAttribPointer(mVR.mATexCoord0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, sizeof(gfx::VRDistortionVertex), (void*) (sizeof(float) * 2));
    gl()->fVertexAttribPointer(mVR.mATexCoord1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, sizeof(gfx::VRDistortionVertex), (void*) (sizeof(float) * 4));
    gl()->fVertexAttribPointer(mVR.mATexCoord2, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, sizeof(gfx::VRDistortionVertex), (void*) (sizeof(float) * 6));
    gl()->fVertexAttribPointer(mVR.mAGenericAttribs, 4, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, sizeof(gfx::VRDistortionVertex),  (void*) (sizeof(float) * 8));

    gl()->fBindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER, mVR.mDistortionIndices[eye]);
    gl()->fDrawElements(LOCAL_GL_TRIANGLES, mVR.mDistortionIndexCount[eye], LOCAL_GL_UNSIGNED_SHORT, 0);
  }

  // Not clear if I should disable all of this; but going to do it and hope that
  // any later code will enable what it needs.
  gl()->fDisableVertexAttribArray(mVR.mAPosition);
  gl()->fDisableVertexAttribArray(mVR.mATexCoord0);
  gl()->fDisableVertexAttribArray(mVR.mATexCoord1);
  gl()->fDisableVertexAttribArray(mVR.mATexCoord2);
  gl()->fDisableVertexAttribArray(mVR.mAGenericAttribs);
}
void
CompositorD3D11::DrawVRDistortion(const gfx::Rect& aRect,
                                  const gfx::Rect& aClipRect,
                                  const EffectChain& aEffectChain,
                                  gfx::Float aOpacity,
                                  const gfx::Matrix4x4& aTransform)
{
  MOZ_ASSERT(aEffectChain.mPrimaryEffect->mType == EffectTypes::VR_DISTORTION);

  if (aEffectChain.mSecondaryEffects[EffectTypes::MASK] ||
      aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE])
  {
    NS_WARNING("DrawVRDistortion: ignoring secondary effect!");
  }

  HRESULT hr;

  EffectVRDistortion* vrEffect =
    static_cast<EffectVRDistortion*>(aEffectChain.mPrimaryEffect.get());

  TextureSourceD3D11* source = vrEffect->mTexture->AsSourceD3D11();
  gfx::IntSize size = vrEffect->mRenderTarget->GetSize(); // XXX source->GetSize()

  VRHMDInfo* hmdInfo = vrEffect->mHMD;
  VRDistortionConstants shaderConstants;

  // do we need to recreate the VR buffers, since the config has changed?
  if (hmdInfo->GetConfiguration() != mAttachments->mVRConfiguration) {
    D3D11_SUBRESOURCE_DATA sdata = { 0 };
    CD3D11_BUFFER_DESC desc(0, D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_IMMUTABLE);

    // XXX as an optimization, we should really pack the indices and vertices for both eyes
    // into one buffer instead of needing one eye each.  Then we can just bind them once.
    for (uint32_t eye = 0; eye < 2; eye++) {
      const gfx::VRDistortionMesh& mesh = hmdInfo->GetDistortionMesh(eye);

      desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
      desc.ByteWidth = mesh.mVertices.Length() * sizeof(gfx::VRDistortionVertex);
      sdata.pSysMem = mesh.mVertices.Elements();
      
      hr = mDevice->CreateBuffer(&desc, &sdata, byRef(mAttachments->mVRDistortionVertices[eye]));
      if (FAILED(hr)) {
        NS_WARNING("CreateBuffer failed");
        return;
      }

      desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
      desc.ByteWidth = mesh.mIndices.Length() * sizeof(uint16_t);
      sdata.pSysMem = mesh.mIndices.Elements();

      hr = mDevice->CreateBuffer(&desc, &sdata, byRef(mAttachments->mVRDistortionIndices[eye]));
      if (FAILED(hr)) {
        NS_WARNING("CreateBuffer failed");
        return;
      }

      mAttachments->mVRDistortionIndexCount[eye] = mesh.mIndices.Length();
    }

    mAttachments->mVRConfiguration = hmdInfo->GetConfiguration();
  }

  // XXX do I need to set a scissor rect? Is this the right scissor rect?
  D3D11_RECT scissor;
  scissor.left = aClipRect.x;
  scissor.right = aClipRect.XMost();
  scissor.top = aClipRect.y;
  scissor.bottom = aClipRect.YMost();
  mContext->RSSetScissorRects(1, &scissor);

  // Triangle lists and same layout for both eyes
  mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
  mContext->IASetInputLayout(mAttachments->mVRDistortionInputLayout);

  // Shaders for this HMD
  mContext->VSSetShader(mAttachments->mVRDistortionVS[mAttachments->mVRConfiguration.hmdType], nullptr, 0);
  mContext->PSSetShader(mAttachments->mVRDistortionPS[mAttachments->mVRConfiguration.hmdType], nullptr, 0);

  // This is the source texture SRV for the pixel shader
  // XXX, um should we cache this SRV?
  RefPtr<ID3D11ShaderResourceView> view;
  mDevice->CreateShaderResourceView(source->GetD3D11Texture(), nullptr, byRef(view));
  ID3D11ShaderResourceView* srView = view;
  mContext->PSSetShaderResources(0, 1, &srView);


  gfx::IntSize vpSizeInt = mCurrentRT->GetSize();
  gfx::Size vpSize(vpSizeInt.width, vpSizeInt.height);
  ID3D11Buffer* vbuffer;
  UINT vsize, voffset;

  for (uint32_t eye = 0; eye < 2; eye++) {
    gfx::IntRect eyeViewport;
    eyeViewport.x = eye * size.width / 2;
    eyeViewport.y = 0;
    eyeViewport.width = size.width / 2;
    eyeViewport.height = size.height;

    hmdInfo->FillDistortionConstants(eye,
                                     size, eyeViewport,
                                     vpSize, aRect,
                                     shaderConstants);

    // D3D has clip space top-left as -1,1 so we need to flip the Y coordinate offset here
    shaderConstants.destinationScaleAndOffset[1] = - shaderConstants.destinationScaleAndOffset[1];

    // XXX I really want to write a templated helper for these next 4 lines
    D3D11_MAPPED_SUBRESOURCE resource;
    mContext->Map(mAttachments->mVRDistortionConstants, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
    *(gfx::VRDistortionConstants*)resource.pData = shaderConstants;
    mContext->Unmap(mAttachments->mVRDistortionConstants, 0);

    // XXX is there a better way to change a bunch of these things from what they were set to
    // in BeginFrame/etc?
    vbuffer = mAttachments->mVRDistortionVertices[eye];
    vsize = sizeof(gfx::VRDistortionVertex);
    voffset = 0;
    mContext->IASetVertexBuffers(0, 1, &vbuffer, &vsize, &voffset);
    mContext->IASetIndexBuffer(mAttachments->mVRDistortionIndices[eye], DXGI_FORMAT_R16_UINT, 0);

    ID3D11Buffer* constBuf = mAttachments->mVRDistortionConstants;
    mContext->VSSetConstantBuffers(0, 1, &constBuf);

    mContext->DrawIndexed(mAttachments->mVRDistortionIndexCount[eye], 0, 0);
  }

  // restore previous configurations
  vbuffer = mAttachments->mVertexBuffer;
  vsize = sizeof(Vertex);
  voffset = 0;
  mContext->IASetVertexBuffers(0, 1, &vbuffer, &vsize, &voffset);
  mContext->IASetIndexBuffer(nullptr, DXGI_FORMAT_R16_UINT, 0);
  mContext->IASetInputLayout(mAttachments->mInputLayout);
}