mirror of
https://github.com/servo/servo.git
synced 2025-07-28 17:50:37 +01:00
234 lines
10 KiB
C++
234 lines
10 KiB
C++
#include "pch.h"
|
|
|
|
#include "CameraResources.h"
|
|
#include "Common/DirectXHelper.h"
|
|
#include "DeviceResources.h"
|
|
|
|
using namespace DirectX;
|
|
using namespace Microsoft::WRL;
|
|
using namespace winrt::Windows::Foundation::Numerics;
|
|
using namespace winrt::Windows::Graphics::DirectX::Direct3D11;
|
|
using namespace winrt::Windows::Graphics::Holographic;
|
|
using namespace winrt::Windows::Perception::Spatial;
|
|
|
|
DX::CameraResources::CameraResources(HolographicCamera const &camera)
|
|
: m_holographicCamera(camera), m_isStereo(camera.IsStereo()),
|
|
m_d3dRenderTargetSize(camera.RenderTargetSize()) {
|
|
m_d3dViewport = CD3D11_VIEWPORT(0.f, 0.f, m_d3dRenderTargetSize.Width,
|
|
m_d3dRenderTargetSize.Height);
|
|
};
|
|
|
|
// Updates resources associated with a holographic camera's swap chain.
|
|
// The app does not access the swap chain directly, but it does create
|
|
// resource views for the back buffer.
|
|
void DX::CameraResources::CreateResourcesForBackBuffer(
|
|
DX::DeviceResources *pDeviceResources,
|
|
HolographicCameraRenderingParameters const &cameraParameters) {
|
|
ID3D11Device *device = pDeviceResources->GetD3DDevice();
|
|
|
|
// Get the WinRT object representing the holographic camera's back buffer.
|
|
IDirect3DSurface surface = cameraParameters.Direct3D11BackBuffer();
|
|
|
|
// Get the holographic camera's back buffer.
|
|
// Holographic apps do not create a swap chain themselves; instead, buffers
|
|
// are owned by the system. The Direct3D back buffer resources are provided to
|
|
// the app using WinRT interop APIs.
|
|
ComPtr<ID3D11Texture2D> cameraBackBuffer;
|
|
winrt::check_hresult(surface
|
|
.as<::Windows::Graphics::DirectX::Direct3D11::
|
|
IDirect3DDxgiInterfaceAccess>()
|
|
->GetInterface(IID_PPV_ARGS(&cameraBackBuffer)));
|
|
|
|
// Determine if the back buffer has changed. If so, ensure that the render
|
|
// target view is for the current back buffer.
|
|
if (m_d3dBackBuffer.Get() != cameraBackBuffer.Get()) {
|
|
// This can change every frame as the system moves to the next buffer in the
|
|
// swap chain. This mode of operation will occur when certain rendering
|
|
// modes are activated.
|
|
m_d3dBackBuffer = cameraBackBuffer;
|
|
|
|
// Create a render target view of the back buffer.
|
|
// Creating this resource is inexpensive, and is better than keeping track
|
|
// of the back buffers in order to pre-allocate render target views for each
|
|
// one.
|
|
winrt::check_hresult(device->CreateRenderTargetView(
|
|
m_d3dBackBuffer.Get(), nullptr, &m_d3dRenderTargetView));
|
|
|
|
// Get the DXGI format for the back buffer.
|
|
// This information can be accessed by the app using
|
|
// CameraResources::GetBackBufferDXGIFormat().
|
|
D3D11_TEXTURE2D_DESC backBufferDesc;
|
|
m_d3dBackBuffer->GetDesc(&backBufferDesc);
|
|
m_dxgiFormat = backBufferDesc.Format;
|
|
|
|
// Check for render target size changes.
|
|
winrt::Windows::Foundation::Size currentSize =
|
|
m_holographicCamera.RenderTargetSize();
|
|
if (m_d3dRenderTargetSize != currentSize) {
|
|
// Set render target size.
|
|
m_d3dRenderTargetSize = currentSize;
|
|
|
|
// A new depth stencil view is also needed.
|
|
m_d3dDepthStencilView.Reset();
|
|
}
|
|
}
|
|
|
|
// Refresh depth stencil resources, if needed.
|
|
if (m_d3dDepthStencilView == nullptr) {
|
|
// Create a depth stencil view for use with 3D rendering if needed.
|
|
CD3D11_TEXTURE2D_DESC depthStencilDesc(
|
|
DXGI_FORMAT_R16_TYPELESS,
|
|
static_cast<UINT>(m_d3dRenderTargetSize.Width),
|
|
static_cast<UINT>(m_d3dRenderTargetSize.Height),
|
|
m_isStereo ? 2 : 1, // Create two textures when rendering in stereo.
|
|
1, // Use a single mipmap level.
|
|
D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE);
|
|
|
|
winrt::check_hresult(device->CreateTexture2D(&depthStencilDesc, nullptr,
|
|
&m_d3dDepthStencil));
|
|
|
|
CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(
|
|
m_isStereo ? D3D11_DSV_DIMENSION_TEXTURE2DARRAY
|
|
: D3D11_DSV_DIMENSION_TEXTURE2D,
|
|
DXGI_FORMAT_D16_UNORM);
|
|
winrt::check_hresult(device->CreateDepthStencilView(
|
|
m_d3dDepthStencil.Get(), &depthStencilViewDesc,
|
|
&m_d3dDepthStencilView));
|
|
}
|
|
|
|
// Create the constant buffer, if needed.
|
|
if (m_viewProjectionConstantBuffer == nullptr) {
|
|
// Create a constant buffer to store view and projection matrices for the
|
|
// camera.
|
|
CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ViewProjectionConstantBuffer),
|
|
D3D11_BIND_CONSTANT_BUFFER);
|
|
winrt::check_hresult(device->CreateBuffer(&constantBufferDesc, nullptr,
|
|
&m_viewProjectionConstantBuffer));
|
|
}
|
|
}
|
|
|
|
// Releases resources associated with a back buffer.
|
|
void DX::CameraResources::ReleaseResourcesForBackBuffer(
|
|
DX::DeviceResources *pDeviceResources) {
|
|
ID3D11DeviceContext *context = pDeviceResources->GetD3DDeviceContext();
|
|
|
|
// Release camera-specific resources.
|
|
m_d3dBackBuffer.Reset();
|
|
m_d3dDepthStencil.Reset();
|
|
m_d3dRenderTargetView.Reset();
|
|
m_d3dDepthStencilView.Reset();
|
|
m_viewProjectionConstantBuffer.Reset();
|
|
|
|
// Ensure system references to the back buffer are released by clearing the
|
|
// render target from the graphics pipeline state, and then flushing the
|
|
// Direct3D context.
|
|
ID3D11RenderTargetView *nullViews[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {
|
|
nullptr};
|
|
context->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
|
|
context->Flush();
|
|
}
|
|
|
|
// Updates the view/projection constant buffer for a holographic camera.
|
|
void DX::CameraResources::UpdateViewProjectionBuffer(
|
|
std::shared_ptr<DX::DeviceResources> deviceResources,
|
|
HolographicCameraPose const &cameraPose,
|
|
SpatialCoordinateSystem const &coordinateSystem) {
|
|
// The system changes the viewport on a per-frame basis for system
|
|
// optimizations.
|
|
auto viewport = cameraPose.Viewport();
|
|
m_d3dViewport =
|
|
CD3D11_VIEWPORT(viewport.X, viewport.Y, viewport.Width, viewport.Height);
|
|
|
|
// The projection transform for each frame is provided by the
|
|
// HolographicCameraPose.
|
|
HolographicStereoTransform cameraProjectionTransform =
|
|
cameraPose.ProjectionTransform();
|
|
|
|
// Get a container object with the view and projection matrices for the given
|
|
// pose in the given coordinate system.
|
|
auto viewTransformContainer =
|
|
cameraPose.TryGetViewTransform(coordinateSystem);
|
|
|
|
// If TryGetViewTransform returns a null pointer, that means the pose and
|
|
// coordinate system cannot be understood relative to one another; content
|
|
// cannot be rendered in this coordinate system for the duration of the
|
|
// current frame. This usually means that positional tracking is not active
|
|
// for the current frame, in which case it is possible to use a
|
|
// SpatialLocatorAttachedFrameOfReference to render content that is not
|
|
// world-locked instead.
|
|
DX::ViewProjectionConstantBuffer viewProjectionConstantBufferData;
|
|
bool viewTransformAcquired = viewTransformContainer != nullptr;
|
|
if (viewTransformAcquired) {
|
|
// Otherwise, the set of view transforms can be retrieved.
|
|
HolographicStereoTransform viewCoordinateSystemTransform =
|
|
viewTransformContainer.Value();
|
|
|
|
// Update the view matrices. Holographic cameras (such as Microsoft
|
|
// HoloLens) are constantly moving relative to the world. The view matrices
|
|
// need to be updated every frame.
|
|
XMStoreFloat4x4(
|
|
&viewProjectionConstantBufferData.viewProjection[0],
|
|
XMMatrixTranspose(XMLoadFloat4x4(&viewCoordinateSystemTransform.Left) *
|
|
XMLoadFloat4x4(&cameraProjectionTransform.Left)));
|
|
XMStoreFloat4x4(
|
|
&viewProjectionConstantBufferData.viewProjection[1],
|
|
XMMatrixTranspose(XMLoadFloat4x4(&viewCoordinateSystemTransform.Right) *
|
|
XMLoadFloat4x4(&cameraProjectionTransform.Right)));
|
|
}
|
|
|
|
// Use the D3D device context to update Direct3D device-based resources.
|
|
ID3D11DeviceContext *context = deviceResources->GetD3DDeviceContext();
|
|
|
|
// Loading is asynchronous. Resources must be created before they can be
|
|
// updated.
|
|
if (context == nullptr || m_viewProjectionConstantBuffer == nullptr ||
|
|
!viewTransformAcquired) {
|
|
m_framePending = false;
|
|
} else {
|
|
// Update the view and projection matrices.
|
|
context->UpdateSubresource(m_viewProjectionConstantBuffer.Get(), 0, nullptr,
|
|
&viewProjectionConstantBufferData, 0, 0);
|
|
|
|
m_framePending = true;
|
|
}
|
|
}
|
|
|
|
// Gets the view-projection constant buffer for the HolographicCamera and
|
|
// attaches it to the shader pipeline.
|
|
bool DX::CameraResources::AttachViewProjectionBuffer(
|
|
std::shared_ptr<DX::DeviceResources> &deviceResources) {
|
|
// This method uses Direct3D device-based resources.
|
|
ID3D11DeviceContext *context = deviceResources->GetD3DDeviceContext();
|
|
|
|
// Loading is asynchronous. Resources must be created before they can be
|
|
// updated. Cameras can also be added asynchronously, in which case they must
|
|
// be initialized before they can be used.
|
|
if (context == nullptr || m_viewProjectionConstantBuffer == nullptr ||
|
|
m_framePending == false) {
|
|
return false;
|
|
}
|
|
|
|
// Set the viewport for this camera.
|
|
context->RSSetViewports(1, &m_d3dViewport);
|
|
|
|
// Send the constant buffer to the vertex shader.
|
|
context->VSSetConstantBuffers(1, 1,
|
|
m_viewProjectionConstantBuffer.GetAddressOf());
|
|
|
|
// The template includes a pass-through geometry shader that is used by
|
|
// default on systems that don't support the D3D11_FEATURE_D3D11_OPTIONS3::
|
|
// VPAndRTArrayIndexFromAnyShaderFeedingRasterizer extension. The shader
|
|
// will be enabled at run-time on systems that require it.
|
|
// If your app will also use the geometry shader for other tasks and those
|
|
// tasks require the view/projection matrix, uncomment the following line
|
|
// of code to send the constant buffer to the geometry shader as well.
|
|
/*context->GSSetConstantBuffers(
|
|
1,
|
|
1,
|
|
m_viewProjectionConstantBuffer.GetAddressOf()
|
|
);*/
|
|
|
|
m_framePending = false;
|
|
|
|
return true;
|
|
}
|