Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #if defined(XP_WIN)
7 : #include "CompositorD3D11.h"
8 : #include "TextureD3D11.h"
9 : #include "mozilla/gfx/DeviceManagerDx.h"
10 : #endif // XP_WIN
11 :
12 : #include "mozilla/Base64.h"
13 : #include "mozilla/gfx/DataSurfaceHelpers.h"
14 : #include "gfxUtils.h"
15 : #include "gfxVRPuppet.h"
16 :
17 : #include "mozilla/dom/GamepadEventTypes.h"
18 : #include "mozilla/dom/GamepadBinding.h"
19 :
20 : // See CompositorD3D11Shaders.h
21 : namespace mozilla {
22 : namespace layers {
23 : struct ShaderBytes { const void* mData; size_t mLength; };
24 : extern ShaderBytes sRGBShader;
25 : extern ShaderBytes sLayerQuadVS;
26 : } // namespace layers
27 : } // namespace mozilla
28 :
29 : using namespace mozilla;
30 : using namespace mozilla::gfx;
31 : using namespace mozilla::gfx::impl;
32 : using namespace mozilla::layers;
33 :
34 : // Reminder: changing the order of these buttons may break web content
35 : static const uint64_t kPuppetButtonMask[] = {
36 : 1,
37 : 2,
38 : 4,
39 : 8
40 : };
41 :
42 : static const uint32_t kNumPuppetButtonMask = sizeof(kPuppetButtonMask) /
43 : sizeof(uint64_t);
44 :
45 : static const uint32_t kPuppetAxes[] = {
46 : 0,
47 : 1,
48 : 2
49 : };
50 :
51 : static const uint32_t kNumPuppetAxis = sizeof(kPuppetAxes) /
52 : sizeof(uint32_t);
53 :
54 : static const uint32_t kNumPuppetHaptcs = 1;
55 :
56 0 : VRDisplayPuppet::VRDisplayPuppet()
57 : : VRDisplayHost(VRDeviceType::Puppet)
58 0 : , mIsPresenting(false)
59 : {
60 0 : MOZ_COUNT_CTOR_INHERITED(VRDisplayPuppet, VRDisplayHost);
61 :
62 0 : mDisplayInfo.mDisplayName.AssignLiteral("Puppet HMD");
63 0 : mDisplayInfo.mIsConnected = true;
64 0 : mDisplayInfo.mIsMounted = false;
65 0 : mDisplayInfo.mCapabilityFlags = VRDisplayCapabilityFlags::Cap_None |
66 0 : VRDisplayCapabilityFlags::Cap_Orientation |
67 0 : VRDisplayCapabilityFlags::Cap_Position |
68 0 : VRDisplayCapabilityFlags::Cap_External |
69 0 : VRDisplayCapabilityFlags::Cap_Present |
70 0 : VRDisplayCapabilityFlags::Cap_StageParameters;
71 0 : mDisplayInfo.mEyeResolution.width = 1836; // 1080 * 1.7
72 0 : mDisplayInfo.mEyeResolution.height = 2040; // 1200 * 1.7
73 :
74 : // SteamVR gives the application a single FOV to use; it's not configurable as with Oculus
75 0 : for (uint32_t eye = 0; eye < 2; ++eye) {
76 0 : mDisplayInfo.mEyeTranslation[eye].x = 0.0f;
77 0 : mDisplayInfo.mEyeTranslation[eye].y = 0.0f;
78 0 : mDisplayInfo.mEyeTranslation[eye].z = 0.0f;
79 0 : mDisplayInfo.mEyeFOV[eye] = VRFieldOfView(45.0, 45.0, 45.0, 45.0);
80 : }
81 :
82 : // default: 1m x 1m space, 0.75m high in seated position
83 0 : mDisplayInfo.mStageSize.width = 1.0f;
84 0 : mDisplayInfo.mStageSize.height = 1.0f;
85 :
86 0 : mDisplayInfo.mSittingToStandingTransform._11 = 1.0f;
87 0 : mDisplayInfo.mSittingToStandingTransform._12 = 0.0f;
88 0 : mDisplayInfo.mSittingToStandingTransform._13 = 0.0f;
89 0 : mDisplayInfo.mSittingToStandingTransform._14 = 0.0f;
90 :
91 0 : mDisplayInfo.mSittingToStandingTransform._21 = 0.0f;
92 0 : mDisplayInfo.mSittingToStandingTransform._22 = 1.0f;
93 0 : mDisplayInfo.mSittingToStandingTransform._23 = 0.0f;
94 0 : mDisplayInfo.mSittingToStandingTransform._24 = 0.0f;
95 :
96 0 : mDisplayInfo.mSittingToStandingTransform._31 = 0.0f;
97 0 : mDisplayInfo.mSittingToStandingTransform._32 = 0.0f;
98 0 : mDisplayInfo.mSittingToStandingTransform._33 = 1.0f;
99 0 : mDisplayInfo.mSittingToStandingTransform._34 = 0.0f;
100 :
101 0 : mDisplayInfo.mSittingToStandingTransform._41 = 0.0f;
102 0 : mDisplayInfo.mSittingToStandingTransform._42 = 0.75f;
103 0 : mDisplayInfo.mSittingToStandingTransform._43 = 0.0f;
104 :
105 0 : gfx::Quaternion rot;
106 :
107 0 : mSensorState.flags |= VRDisplayCapabilityFlags::Cap_Orientation;
108 0 : mSensorState.orientation[0] = rot.x;
109 0 : mSensorState.orientation[1] = rot.y;
110 0 : mSensorState.orientation[2] = rot.z;
111 0 : mSensorState.orientation[3] = rot.w;
112 0 : mSensorState.angularVelocity[0] = 0.0f;
113 0 : mSensorState.angularVelocity[1] = 0.0f;
114 0 : mSensorState.angularVelocity[2] = 0.0f;
115 :
116 0 : mSensorState.flags |= VRDisplayCapabilityFlags::Cap_Position;
117 0 : mSensorState.position[0] = 0.0f;
118 0 : mSensorState.position[1] = 0.0f;
119 0 : mSensorState.position[2] = 0.0f;
120 0 : mSensorState.linearVelocity[0] = 0.0f;
121 0 : mSensorState.linearVelocity[1] = 0.0f;
122 0 : mSensorState.linearVelocity[2] = 0.0f;
123 0 : }
124 :
125 0 : VRDisplayPuppet::~VRDisplayPuppet()
126 : {
127 0 : MOZ_COUNT_DTOR_INHERITED(VRDisplayPuppet, VRDisplayHost);
128 0 : }
129 :
130 : void
131 0 : VRDisplayPuppet::SetDisplayInfo(const VRDisplayInfo& aDisplayInfo)
132 : {
133 : // We are only interested in the eye and mount info of the display info.
134 0 : mDisplayInfo.mEyeResolution = aDisplayInfo.mEyeResolution;
135 0 : mDisplayInfo.mIsMounted = aDisplayInfo.mIsMounted;
136 0 : memcpy(&mDisplayInfo.mEyeFOV, &aDisplayInfo.mEyeFOV,
137 0 : sizeof(mDisplayInfo.mEyeFOV[0]) * VRDisplayInfo::NumEyes);
138 0 : memcpy(&mDisplayInfo.mEyeTranslation, &aDisplayInfo.mEyeTranslation,
139 0 : sizeof(mDisplayInfo.mEyeTranslation[0]) * VRDisplayInfo::NumEyes);
140 0 : }
141 :
142 : void
143 0 : VRDisplayPuppet::Destroy()
144 : {
145 0 : StopPresentation();
146 0 : }
147 :
148 : void
149 0 : VRDisplayPuppet::ZeroSensor()
150 : {
151 0 : }
152 :
153 : VRHMDSensorState
154 0 : VRDisplayPuppet::GetSensorState()
155 : {
156 0 : mSensorState.inputFrameID = mDisplayInfo.mFrameId;
157 0 : return mSensorState;
158 : }
159 :
160 : void
161 0 : VRDisplayPuppet::SetSensorState(const VRHMDSensorState& aSensorState)
162 : {
163 0 : memcpy(&mSensorState, &aSensorState, sizeof(mSensorState));
164 0 : }
165 :
166 : void
167 0 : VRDisplayPuppet::StartPresentation()
168 : {
169 0 : if (mIsPresenting) {
170 0 : return;
171 : }
172 0 : mIsPresenting = true;
173 :
174 : #if defined(XP_WIN)
175 : if (!mDevice) {
176 : mDevice = gfx::DeviceManagerDx::Get()->GetCompositorDevice();
177 : if (!mDevice) {
178 : NS_WARNING("Failed to get a D3D11Device for Puppet");
179 : return;
180 : }
181 : }
182 :
183 : mDevice->GetImmediateContext(getter_AddRefs(mContext));
184 : if (!mContext) {
185 : NS_WARNING("Failed to get immediate context for Puppet");
186 : return;
187 : }
188 :
189 : if (FAILED(mDevice->CreateVertexShader(sLayerQuadVS.mData,
190 : sLayerQuadVS.mLength, nullptr, &mQuadVS))) {
191 : NS_WARNING("Failed to create vertex shader for Puppet");
192 : return;
193 : }
194 :
195 : if (FAILED(mDevice->CreatePixelShader(sRGBShader.mData,
196 : sRGBShader.mLength, nullptr, &mQuadPS))) {
197 : NS_WARNING("Failed to create pixel shader for Puppet");
198 : return;
199 : }
200 :
201 : CD3D11_BUFFER_DESC cBufferDesc(sizeof(layers::VertexShaderConstants),
202 : D3D11_BIND_CONSTANT_BUFFER,
203 : D3D11_USAGE_DYNAMIC,
204 : D3D11_CPU_ACCESS_WRITE);
205 :
206 : if (FAILED(mDevice->CreateBuffer(&cBufferDesc, nullptr, getter_AddRefs(mVSConstantBuffer)))) {
207 : NS_WARNING("Failed to vertex shader constant buffer for Puppet");
208 : return;
209 : }
210 :
211 : cBufferDesc.ByteWidth = sizeof(layers::PixelShaderConstants);
212 : if (FAILED(mDevice->CreateBuffer(&cBufferDesc, nullptr, getter_AddRefs(mPSConstantBuffer)))) {
213 : NS_WARNING("Failed to pixel shader constant buffer for Puppet");
214 : return;
215 : }
216 :
217 : CD3D11_SAMPLER_DESC samplerDesc(D3D11_DEFAULT);
218 : if (FAILED(mDevice->CreateSamplerState(&samplerDesc, getter_AddRefs(mLinearSamplerState)))) {
219 : NS_WARNING("Failed to create sampler state for Puppet");
220 : return;
221 : }
222 :
223 : D3D11_INPUT_ELEMENT_DESC layout[] =
224 : {
225 : { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
226 : };
227 :
228 : if (FAILED(mDevice->CreateInputLayout(layout,
229 : sizeof(layout) / sizeof(D3D11_INPUT_ELEMENT_DESC),
230 : sLayerQuadVS.mData,
231 : sLayerQuadVS.mLength,
232 : getter_AddRefs(mInputLayout)))) {
233 : NS_WARNING("Failed to create input layout for Puppet");
234 : return;
235 : }
236 :
237 : Vertex vertices[] = { { { 0.0, 0.0 } },{ { 1.0, 0.0 } },{ { 0.0, 1.0 } },{ { 1.0, 1.0 } } };
238 : CD3D11_BUFFER_DESC bufferDesc(sizeof(vertices), D3D11_BIND_VERTEX_BUFFER);
239 : D3D11_SUBRESOURCE_DATA data;
240 : data.pSysMem = (void*)vertices;
241 :
242 : if (FAILED(mDevice->CreateBuffer(&bufferDesc, &data, getter_AddRefs(mVertexBuffer)))) {
243 : NS_WARNING("Failed to create vertex buffer for Puppet");
244 : return;
245 : }
246 :
247 : memset(&mVSConstants, 0, sizeof(mVSConstants));
248 : memset(&mPSConstants, 0, sizeof(mPSConstants));
249 : #endif // XP_WIN
250 : }
251 :
252 : void
253 0 : VRDisplayPuppet::StopPresentation()
254 : {
255 0 : if (!mIsPresenting) {
256 0 : return;
257 : }
258 :
259 0 : mIsPresenting = false;
260 : }
261 :
262 : #if defined(XP_WIN)
263 : bool
264 : VRDisplayPuppet::UpdateConstantBuffers()
265 : {
266 : HRESULT hr;
267 : D3D11_MAPPED_SUBRESOURCE resource;
268 : resource.pData = nullptr;
269 :
270 : hr = mContext->Map(mVSConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
271 : if (FAILED(hr) || !resource.pData) {
272 : return false;
273 : }
274 : *(VertexShaderConstants*)resource.pData = mVSConstants;
275 : mContext->Unmap(mVSConstantBuffer, 0);
276 : resource.pData = nullptr;
277 :
278 : hr = mContext->Map(mPSConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
279 : if (FAILED(hr) || !resource.pData) {
280 : return false;
281 : }
282 : *(PixelShaderConstants*)resource.pData = mPSConstants;
283 : mContext->Unmap(mPSConstantBuffer, 0);
284 :
285 : ID3D11Buffer *buffer = mVSConstantBuffer;
286 : mContext->VSSetConstantBuffers(0, 1, &buffer);
287 : buffer = mPSConstantBuffer;
288 : mContext->PSSetConstantBuffers(0, 1, &buffer);
289 : return true;
290 : }
291 :
292 : bool
293 : VRDisplayPuppet::SubmitFrame(TextureSourceD3D11* aSource,
294 : const IntSize& aSize,
295 : const gfx::Rect& aLeftEyeRect,
296 : const gfx::Rect& aRightEyeRect)
297 : {
298 : if (!mIsPresenting) {
299 : return false;
300 : }
301 :
302 : VRManager *vm = VRManager::Get();
303 : MOZ_ASSERT(vm);
304 :
305 : switch (gfxPrefs::VRPuppetSubmitFrame()) {
306 : case 0:
307 : // The VR frame is not displayed.
308 : break;
309 : case 1:
310 : {
311 : // The frames are submitted to VR compositor are decoded
312 : // into a base64Image and dispatched to the DOM side.
313 : D3D11_TEXTURE2D_DESC desc;
314 : ID3D11Texture2D* texture = aSource->GetD3D11Texture();
315 : texture->GetDesc(&desc);
316 : MOZ_ASSERT(desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM,
317 : "Only support B8G8R8A8_UNORM format.");
318 : // Map the staging resource
319 : ID3D11Texture2D* mappedTexture = nullptr;
320 : D3D11_MAPPED_SUBRESOURCE mapInfo;
321 : HRESULT hr = mContext->Map(texture,
322 : 0, // Subsource
323 : D3D11_MAP_READ,
324 : 0, // MapFlags
325 : &mapInfo);
326 :
327 : if (FAILED(hr)) {
328 : // If we can't map this texture, copy it to a staging resource.
329 : if (hr == E_INVALIDARG) {
330 : D3D11_TEXTURE2D_DESC desc2;
331 : desc2.Width = desc.Width;
332 : desc2.Height = desc.Height;
333 : desc2.MipLevels = desc.MipLevels;
334 : desc2.ArraySize = desc.ArraySize;
335 : desc2.Format = desc.Format;
336 : desc2.SampleDesc = desc.SampleDesc;
337 : desc2.Usage = D3D11_USAGE_STAGING;
338 : desc2.BindFlags = 0;
339 : desc2.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
340 : desc2.MiscFlags = 0;
341 :
342 : ID3D11Texture2D* stagingTexture = nullptr;
343 : hr = mDevice->CreateTexture2D(&desc2, nullptr, &stagingTexture);
344 : if (FAILED(hr)) {
345 : MOZ_ASSERT(false, "Failed to create a staging texture");
346 : return false;
347 : }
348 : // Copy the texture to a staging resource
349 : mContext->CopyResource(stagingTexture, texture);
350 : // Map the staging resource
351 : hr = mContext->Map(stagingTexture,
352 : 0, // Subsource
353 : D3D11_MAP_READ,
354 : 0, // MapFlags
355 : &mapInfo);
356 : if (FAILED(hr)) {
357 : MOZ_ASSERT(false, "Failed to map staging texture");
358 : }
359 : mappedTexture = stagingTexture;
360 : } else {
361 : MOZ_ASSERT(false, "Failed to map staging texture");
362 : return false;
363 : }
364 : } else {
365 : mappedTexture = texture;
366 : }
367 : // Ideally, we should convert the srcData to a PNG image and decode it
368 : // to a Base64 string here, but the GPU process does not have the privilege to
369 : // access the image library. So, we have to convert the RAW image data
370 : // to a base64 string and forward it to let the content process to
371 : // do the image conversion.
372 : char* srcData = static_cast<char*>(mapInfo.pData);
373 : VRSubmitFrameResultInfo result;
374 : result.mFormat = SurfaceFormat::B8G8R8A8;
375 : // If the original texture size is not pow of 2, CopyResource() will add padding,
376 : // so the size is adjusted. We have to get the correct size by (mapInfo.RowPitch /
377 : // the format size).
378 : result.mWidth = mapInfo.RowPitch / 4;
379 : result.mHeight = desc.Height;
380 : result.mFrameNum = mDisplayInfo.mFrameId;
381 : nsCString rawString(Substring((char*)srcData, mapInfo.RowPitch * desc.Height));
382 :
383 : if (Base64Encode(rawString, result.mBase64Image) != NS_OK) {
384 : MOZ_ASSERT(false, "Failed to encode base64 images.");
385 : }
386 : mContext->Unmap(mappedTexture, 0);
387 : // Dispatch the base64 encoded string to the DOM side. Then, it will be decoded
388 : // and convert to a PNG image there.
389 : vm->DispatchSubmitFrameResult(mDisplayInfo.mDisplayID, result);
390 : break;
391 : }
392 : case 2:
393 : {
394 : // The VR compositor sumbmit frame to the screen window,
395 : // the current coordinate is at (0, 0, width, height).
396 : Matrix viewMatrix = Matrix::Translation(-1.0, 1.0);
397 : viewMatrix.PreScale(2.0f / float(aSize.width), 2.0f / float(aSize.height));
398 : viewMatrix.PreScale(1.0f, -1.0f);
399 : Matrix4x4 projection = Matrix4x4::From2D(viewMatrix);
400 : projection._33 = 0.0f;
401 :
402 : Matrix transform2d;
403 : gfx::Matrix4x4 transform = gfx::Matrix4x4::From2D(transform2d);
404 :
405 : const float posX = 0.0f, posY = 0.0f;
406 : D3D11_VIEWPORT viewport;
407 : viewport.MinDepth = 0.0f;
408 : viewport.MaxDepth = 1.0f;
409 : viewport.Width = aSize.width;
410 : viewport.Height = aSize.height;
411 : viewport.TopLeftX = posX;
412 : viewport.TopLeftY = posY;
413 :
414 : D3D11_RECT scissor;
415 : scissor.left = posX;
416 : scissor.right = aSize.width + posX;
417 : scissor.top = posY;
418 : scissor.bottom = aSize.height + posY;
419 :
420 : memcpy(&mVSConstants.layerTransform, &transform._11, sizeof(mVSConstants.layerTransform));
421 : memcpy(&mVSConstants.projection, &projection._11, sizeof(mVSConstants.projection));
422 : mVSConstants.renderTargetOffset[0] = 0.0f;
423 : mVSConstants.renderTargetOffset[1] = 0.0f;
424 : mVSConstants.layerQuad = Rect(0.0f, 0.0f, aSize.width, aSize.height);
425 : mVSConstants.textureCoords = Rect(0.0f, 1.0f, 1.0f, -1.0f);
426 :
427 : mPSConstants.layerOpacity[0] = 1.0f;
428 :
429 : ID3D11Buffer* vbuffer = mVertexBuffer;
430 : UINT vsize = sizeof(Vertex);
431 : UINT voffset = 0;
432 : mContext->IASetVertexBuffers(0, 1, &vbuffer, &vsize, &voffset);
433 : mContext->IASetIndexBuffer(nullptr, DXGI_FORMAT_R16_UINT, 0);
434 : mContext->IASetInputLayout(mInputLayout);
435 : mContext->RSSetViewports(1, &viewport);
436 : mContext->RSSetScissorRects(1, &scissor);
437 : mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
438 : mContext->VSSetShader(mQuadVS, nullptr, 0);
439 : mContext->PSSetShader(mQuadPS, nullptr, 0);
440 : ID3D11ShaderResourceView* srView = aSource->GetShaderResourceView();
441 : if (!srView) {
442 : NS_WARNING("Failed to get SRV for Puppet");
443 : return false;
444 : }
445 : mContext->PSSetShaderResources(0 /* 0 == TexSlot::RGB */, 1, &srView);
446 : // XXX Use Constant from TexSlot in CompositorD3D11.cpp?
447 :
448 : ID3D11SamplerState *sampler = mLinearSamplerState;
449 : mContext->PSSetSamplers(0, 1, &sampler);
450 :
451 : if (!UpdateConstantBuffers()) {
452 : NS_WARNING("Failed to update constant buffers for Puppet");
453 : return false;
454 : }
455 : mContext->Draw(4, 0);
456 : break;
457 : }
458 : }
459 :
460 : // We will always return false for gfxVRPuppet to ensure that the fallback "watchdog"
461 : // code in VRDisplayHost::NotifyVSync() throttles the render loop. This "watchdog" will
462 : // result in a refresh rate that is quite low compared to real hardware, but should be
463 : // sufficient for non-performance oriented tests. If we wish to simulate realistic frame
464 : // rates with VRDisplayPuppet, we should block here for the appropriate amount of time and
465 : // return true to indicate that we have blocked.
466 : return false;
467 : }
468 : #else
469 : bool
470 0 : VRDisplayPuppet::SubmitFrame(TextureSourceOGL* aSource,
471 : const IntSize& aSize,
472 : const gfx::Rect& aLeftEyeRect,
473 : const gfx::Rect& aRightEyeRect)
474 : {
475 0 : if (!mIsPresenting) {
476 0 : return false;
477 : }
478 :
479 : // TODO: Bug 1343730, Need to block until the next simulated
480 : // vblank interval and capture frames for use in reftests.
481 :
482 0 : return false;
483 : }
484 : #endif
485 :
486 : void
487 0 : VRDisplayPuppet::NotifyVSync()
488 : {
489 : // We update mIsConneced once per frame.
490 0 : mDisplayInfo.mIsConnected = true;
491 :
492 0 : VRDisplayHost::NotifyVSync();
493 0 : }
494 :
495 0 : VRControllerPuppet::VRControllerPuppet(dom::GamepadHand aHand)
496 : : VRControllerHost(VRDeviceType::Puppet)
497 0 : , mButtonPressState(0)
498 : {
499 0 : MOZ_COUNT_CTOR_INHERITED(VRControllerPuppet, VRControllerHost);
500 0 : mControllerInfo.mControllerName.AssignLiteral("Puppet Gamepad");
501 0 : mControllerInfo.mMappingType = GamepadMappingType::_empty;
502 0 : mControllerInfo.mHand = aHand;
503 0 : mControllerInfo.mNumButtons = kNumPuppetButtonMask;
504 0 : mControllerInfo.mNumAxes = kNumPuppetAxis;
505 0 : mControllerInfo.mNumHaptics = kNumPuppetHaptcs;
506 0 : }
507 :
508 0 : VRControllerPuppet::~VRControllerPuppet()
509 : {
510 0 : MOZ_COUNT_DTOR_INHERITED(VRControllerPuppet, VRControllerHost);
511 0 : }
512 :
513 : void
514 0 : VRControllerPuppet::SetButtonPressState(uint32_t aButton, bool aPressed)
515 : {
516 0 : const uint64_t buttonMask = kPuppetButtonMask[aButton];
517 0 : uint64_t pressedBit = GetButtonPressed();
518 :
519 0 : if (aPressed) {
520 0 : pressedBit |= kPuppetButtonMask[aButton];
521 0 : } else if (pressedBit & buttonMask) {
522 : // this button was pressed but is released now.
523 0 : uint64_t mask = 0xff ^ buttonMask;
524 0 : pressedBit &= mask;
525 : }
526 :
527 0 : mButtonPressState = pressedBit;
528 0 : }
529 :
530 : uint64_t
531 0 : VRControllerPuppet::GetButtonPressState()
532 : {
533 0 : return mButtonPressState;
534 : }
535 :
536 : void
537 0 : VRControllerPuppet::SetButtonTouchState(uint32_t aButton, bool aTouched)
538 : {
539 0 : const uint64_t buttonMask = kPuppetButtonMask[aButton];
540 0 : uint64_t touchedBit = GetButtonTouched();
541 :
542 0 : if (aTouched) {
543 0 : touchedBit |= kPuppetButtonMask[aButton];
544 0 : } else if (touchedBit & buttonMask) {
545 : // this button was touched but is released now.
546 0 : uint64_t mask = 0xff ^ buttonMask;
547 0 : touchedBit &= mask;
548 : }
549 :
550 0 : mButtonTouchState = touchedBit;
551 0 : }
552 :
553 : uint64_t
554 0 : VRControllerPuppet::GetButtonTouchState()
555 : {
556 0 : return mButtonTouchState;
557 : }
558 :
559 : void
560 0 : VRControllerPuppet::SetAxisMoveState(uint32_t aAxis, double aValue)
561 : {
562 : MOZ_ASSERT((sizeof(mAxisMoveState) / sizeof(float)) == kNumPuppetAxis);
563 0 : MOZ_ASSERT(aAxis <= kNumPuppetAxis);
564 :
565 0 : mAxisMoveState[aAxis] = aValue;
566 0 : }
567 :
568 : double
569 0 : VRControllerPuppet::GetAxisMoveState(uint32_t aAxis)
570 : {
571 0 : return mAxisMoveState[aAxis];
572 : }
573 :
574 : void
575 0 : VRControllerPuppet::SetPoseMoveState(const dom::GamepadPoseState& aPose)
576 : {
577 0 : mPoseState = aPose;
578 0 : }
579 :
580 : const dom::GamepadPoseState&
581 0 : VRControllerPuppet::GetPoseMoveState()
582 : {
583 0 : return mPoseState;
584 : }
585 :
586 : float
587 0 : VRControllerPuppet::GetAxisMove(uint32_t aAxis)
588 : {
589 0 : return mAxisMove[aAxis];
590 : }
591 :
592 : void
593 0 : VRControllerPuppet::SetAxisMove(uint32_t aAxis, float aValue)
594 : {
595 0 : mAxisMove[aAxis] = aValue;
596 0 : }
597 :
598 0 : VRSystemManagerPuppet::VRSystemManagerPuppet()
599 : {
600 0 : }
601 :
602 : /*static*/ already_AddRefed<VRSystemManagerPuppet>
603 0 : VRSystemManagerPuppet::Create()
604 : {
605 0 : if (!gfxPrefs::VREnabled() || !gfxPrefs::VRPuppetEnabled()) {
606 0 : return nullptr;
607 : }
608 :
609 0 : RefPtr<VRSystemManagerPuppet> manager = new VRSystemManagerPuppet();
610 0 : return manager.forget();
611 : }
612 :
613 : void
614 0 : VRSystemManagerPuppet::Destroy()
615 : {
616 0 : Shutdown();
617 0 : }
618 :
619 : void
620 0 : VRSystemManagerPuppet::Shutdown()
621 : {
622 0 : mPuppetHMD = nullptr;
623 0 : }
624 :
625 : bool
626 0 : VRSystemManagerPuppet::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
627 : {
628 0 : if (mPuppetHMD == nullptr) {
629 0 : mPuppetHMD = new VRDisplayPuppet();
630 : }
631 0 : aHMDResult.AppendElement(mPuppetHMD);
632 0 : return true;
633 : }
634 :
635 : bool
636 0 : VRSystemManagerPuppet::GetIsPresenting()
637 : {
638 0 : if (mPuppetHMD) {
639 0 : VRDisplayInfo displayInfo(mPuppetHMD->GetDisplayInfo());
640 0 : return displayInfo.GetPresentingGroups() != kVRGroupNone;
641 : }
642 :
643 0 : return false;
644 : }
645 :
646 : void
647 0 : VRSystemManagerPuppet::HandleInput()
648 : {
649 0 : RefPtr<impl::VRControllerPuppet> controller;
650 0 : for (uint32_t i = 0; i < mPuppetController.Length(); ++i) {
651 0 : controller = mPuppetController[i];
652 0 : for (uint32_t j = 0; j < kNumPuppetButtonMask; ++j) {
653 0 : HandleButtonPress(i, j, kPuppetButtonMask[i], controller->GetButtonPressState(),
654 0 : controller->GetButtonTouchState());
655 : }
656 0 : controller->SetButtonPressed(controller->GetButtonPressState());
657 :
658 0 : for (uint32_t j = 0; j < kNumPuppetAxis; ++j) {
659 0 : HandleAxisMove(i, j, controller->GetAxisMoveState(j));
660 : }
661 0 : HandlePoseTracking(i, controller->GetPoseMoveState(), controller);
662 : }
663 0 : }
664 :
665 : void
666 0 : VRSystemManagerPuppet::HandleButtonPress(uint32_t aControllerIdx,
667 : uint32_t aButton,
668 : uint64_t aButtonMask,
669 : uint64_t aButtonPressed,
670 : uint64_t aButtonTouched)
671 : {
672 0 : RefPtr<impl::VRControllerPuppet> controller(mPuppetController[aControllerIdx]);
673 0 : MOZ_ASSERT(controller);
674 0 : const uint64_t pressedDiff = (controller->GetButtonPressed() ^ aButtonPressed);
675 0 : const uint64_t touchedDiff = (controller->GetButtonTouched() ^ aButtonTouched);
676 :
677 0 : if (!pressedDiff && !touchedDiff) {
678 0 : return;
679 : }
680 :
681 0 : if (pressedDiff & aButtonMask
682 0 : || touchedDiff & aButtonMask) {
683 : // diff & (aButtonPressed, aButtonTouched) would be true while a new button pressed or
684 : // touched event, otherwise it is an old event and needs to notify
685 : // the button has been released.
686 0 : NewButtonEvent(aControllerIdx, aButton, aButtonMask & aButtonPressed,
687 0 : aButtonMask & aButtonPressed,
688 0 : (aButtonMask & aButtonPressed) ? 1.0L : 0.0L);
689 : }
690 : }
691 :
692 : void
693 0 : VRSystemManagerPuppet::HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
694 : float aValue)
695 : {
696 0 : RefPtr<impl::VRControllerPuppet> controller(mPuppetController[aControllerIdx]);
697 0 : MOZ_ASSERT(controller);
698 :
699 0 : if (controller->GetAxisMove(aAxis) != aValue) {
700 0 : NewAxisMove(aControllerIdx, aAxis, aValue);
701 0 : controller->SetAxisMove(aAxis, aValue);
702 : }
703 0 : }
704 :
705 : void
706 0 : VRSystemManagerPuppet::HandlePoseTracking(uint32_t aControllerIdx,
707 : const GamepadPoseState& aPose,
708 : VRControllerHost* aController)
709 : {
710 0 : MOZ_ASSERT(aController);
711 0 : if (aPose != aController->GetPose()) {
712 0 : aController->SetPose(aPose);
713 0 : NewPoseState(aControllerIdx, aPose);
714 : }
715 0 : }
716 :
717 : void
718 0 : VRSystemManagerPuppet::VibrateHaptic(uint32_t aControllerIdx,
719 : uint32_t aHapticIndex,
720 : double aIntensity,
721 : double aDuration,
722 : uint32_t aPromiseID)
723 : {
724 0 : }
725 :
726 : void
727 0 : VRSystemManagerPuppet::StopVibrateHaptic(uint32_t aControllerIdx)
728 : {
729 0 : }
730 :
731 : void
732 0 : VRSystemManagerPuppet::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
733 : {
734 0 : aControllerResult.Clear();
735 0 : for (uint32_t i = 0; i < mPuppetController.Length(); ++i) {
736 0 : aControllerResult.AppendElement(mPuppetController[i]);
737 : }
738 0 : }
739 :
740 : void
741 0 : VRSystemManagerPuppet::ScanForControllers()
742 : {
743 : // We make VRSystemManagerPuppet has two controllers always.
744 0 : const uint32_t newControllerCount = 2;
745 :
746 0 : if (newControllerCount != mControllerCount) {
747 0 : RemoveControllers();
748 :
749 : // Re-adding controllers to VRControllerManager.
750 0 : for (uint32_t i = 0; i < newControllerCount; ++i) {
751 0 : dom::GamepadHand hand = (i % 2) ? dom::GamepadHand::Right :
752 0 : dom::GamepadHand::Left;
753 0 : RefPtr<VRControllerPuppet> puppetController = new VRControllerPuppet(hand);
754 0 : mPuppetController.AppendElement(puppetController);
755 :
756 : // Not already present, add it.
757 0 : AddGamepad(puppetController->GetControllerInfo());
758 0 : ++mControllerCount;
759 : }
760 : }
761 0 : }
762 :
763 : void
764 0 : VRSystemManagerPuppet::RemoveControllers()
765 : {
766 : // controller count is changed, removing the existing gamepads first.
767 0 : for (uint32_t i = 0; i < mPuppetController.Length(); ++i) {
768 0 : RemoveGamepad(i);
769 : }
770 0 : mPuppetController.Clear();
771 0 : mControllerCount = 0;
772 0 : }
|