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); }