mirror of
https://github.com/LibreVR/Revive.git
synced 2026-08-04 00:54:37 -04:00
226 lines
7.9 KiB
C++
226 lines
7.9 KiB
C++
#include "CompositorD3D.h"
|
|
#include "TextureD3D.h"
|
|
|
|
#include <openvr.h>
|
|
#include <d3d11.h>
|
|
#include <d3d12.h>
|
|
#include <wrl/client.h>
|
|
|
|
#include "VertexShader.hlsl.h"
|
|
#include "MirrorShader.hlsl.h"
|
|
#include "CompositorShader.hlsl.h"
|
|
|
|
struct Vertex
|
|
{
|
|
ovrVector2f Position;
|
|
ovrVector2f TexCoord;
|
|
};
|
|
|
|
CompositorD3D* CompositorD3D::Create(IUnknown* d3dPtr)
|
|
{
|
|
// Get the device for this context
|
|
// TODO: DX12 support
|
|
ID3D11Device* pDevice = nullptr;
|
|
HRESULT hr = d3dPtr->QueryInterface(&pDevice);
|
|
if (SUCCEEDED(hr))
|
|
return new CompositorD3D(pDevice);
|
|
|
|
ID3D12CommandQueue* pQueue = nullptr;
|
|
hr = d3dPtr->QueryInterface(&pQueue);
|
|
if (SUCCEEDED(hr))
|
|
return new CompositorD3D(pQueue);
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
CompositorD3D::CompositorD3D(ID3D11Device* pDevice)
|
|
{
|
|
m_pDevice = pDevice;
|
|
m_pDevice->GetImmediateContext(m_pContext.GetAddressOf());
|
|
|
|
// Create the shaders.
|
|
m_pDevice->CreateVertexShader(g_VertexShader, sizeof(g_VertexShader), NULL, m_VertexShader.GetAddressOf());
|
|
m_pDevice->CreatePixelShader(g_MirrorShader, sizeof(g_MirrorShader), NULL, m_MirrorShader.GetAddressOf());
|
|
m_pDevice->CreatePixelShader(g_CompositorShader, sizeof(g_CompositorShader), NULL, m_CompositorShader.GetAddressOf());
|
|
|
|
// Create the vertex buffer.
|
|
D3D11_BUFFER_DESC bufferDesc;
|
|
bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
|
|
bufferDesc.ByteWidth = sizeof(Vertex) * 4;
|
|
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
|
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
|
bufferDesc.MiscFlags = 0;
|
|
m_pDevice->CreateBuffer(&bufferDesc, nullptr, m_VertexBuffer.GetAddressOf());
|
|
|
|
// Create the input layout.
|
|
D3D11_INPUT_ELEMENT_DESC layout[] =
|
|
{
|
|
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0,
|
|
D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
|
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8,
|
|
D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
|
};
|
|
HRESULT hr = m_pDevice->CreateInputLayout(layout, 2, g_VertexShader, sizeof(g_VertexShader), m_InputLayout.GetAddressOf());
|
|
|
|
// Create state objects.
|
|
D3D11_BLEND_DESC bm = { 0 };
|
|
bm.RenderTarget[0].BlendEnable = true;
|
|
bm.RenderTarget[0].BlendOp = bm.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
|
bm.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
|
|
bm.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
|
bm.RenderTarget[0].SrcBlendAlpha = bm.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
|
bm.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
|
m_pDevice->CreateBlendState(&bm, m_BlendState.GetAddressOf());
|
|
|
|
// Get the mirror textures
|
|
vr::VRCompositor()->GetMirrorTextureD3D11(vr::Eye_Left, m_pDevice.Get(), (void**)&m_pMirror[ovrEye_Left]);
|
|
vr::VRCompositor()->GetMirrorTextureD3D11(vr::Eye_Right, m_pDevice.Get(), (void**)&m_pMirror[ovrEye_Right]);
|
|
}
|
|
|
|
CompositorD3D::CompositorD3D(ID3D12CommandQueue* pQueue)
|
|
: m_pQueue(pQueue)
|
|
, m_pMirror()
|
|
{
|
|
}
|
|
|
|
CompositorD3D::~CompositorD3D()
|
|
{
|
|
if (m_pMirror[ovrEye_Left])
|
|
vr::VRCompositor()->ReleaseMirrorTextureD3D11(m_pMirror[ovrEye_Left]);
|
|
if (m_pMirror[ovrEye_Right])
|
|
vr::VRCompositor()->ReleaseMirrorTextureD3D11(m_pMirror[ovrEye_Right]);
|
|
}
|
|
|
|
TextureBase* CompositorD3D::CreateTexture()
|
|
{
|
|
if (m_pDevice)
|
|
return new TextureD3D(m_pDevice.Get());
|
|
else
|
|
return new TextureD3D(m_pQueue.Get());
|
|
}
|
|
|
|
void CompositorD3D::RenderMirrorTexture(ovrMirrorTexture mirrorTexture)
|
|
{
|
|
// TODO: Support mirror textures in DX12
|
|
if (!m_pDevice)
|
|
return;
|
|
|
|
// Get the current state objects
|
|
Microsoft::WRL::ComPtr<ID3D11BlendState> blend_state;
|
|
float blend_factor[4];
|
|
uint32_t sample_mask;
|
|
m_pContext->OMGetBlendState(blend_state.GetAddressOf(), blend_factor, &sample_mask);
|
|
|
|
D3D11_PRIMITIVE_TOPOLOGY topology;
|
|
m_pContext->IAGetPrimitiveTopology(&topology);
|
|
|
|
ID3D11RasterizerState* ras_state;
|
|
m_pContext->RSGetState(&ras_state);
|
|
|
|
// Get the mirror texture
|
|
TextureD3D* texture = (TextureD3D*)mirrorTexture->Texture.get();
|
|
|
|
// Set the mirror shaders
|
|
m_pContext->VSSetShader(m_VertexShader.Get(), NULL, 0);
|
|
m_pContext->PSSetShader(m_MirrorShader.Get(), NULL, 0);
|
|
m_pContext->PSSetShaderResources(0, ovrEye_Count, m_pMirror);
|
|
|
|
// Update the vertex buffer
|
|
Vertex vertices[4] = {
|
|
{ { -1.0f, 1.0f },{ 0.0f, 0.0f } },
|
|
{ { 1.0f, 1.0f },{ 1.0f, 0.0f } },
|
|
{ { -1.0f, -1.0f },{ 0.0f, 1.0f } },
|
|
{ { 1.0f, -1.0f },{ 1.0f, 1.0f } }
|
|
};
|
|
D3D11_MAPPED_SUBRESOURCE map = { 0 };
|
|
m_pContext->Map(m_VertexBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
|
memcpy(map.pData, vertices, sizeof(Vertex) * 4);
|
|
m_pContext->Unmap(m_VertexBuffer.Get(), 0);
|
|
|
|
// Prepare the render target
|
|
FLOAT clear[4] = { 0.0f };
|
|
D3D11_VIEWPORT viewport = { 0.0f, 0.0f, (float)mirrorTexture->Desc.Width, (float)mirrorTexture->Desc.Height, D3D11_MIN_DEPTH, D3D11_MIN_DEPTH };
|
|
m_pContext->RSSetViewports(1, &viewport);
|
|
|
|
ID3D11RenderTargetView* target = texture->Target();
|
|
m_pContext->ClearRenderTargetView(target, clear);
|
|
m_pContext->OMSetRenderTargets(1, &target, NULL);
|
|
m_pContext->OMSetBlendState(nullptr, nullptr, -1);
|
|
m_pContext->RSSetState(nullptr);
|
|
|
|
// Set and draw the vertices
|
|
UINT stride = sizeof(Vertex);
|
|
UINT offset = 0;
|
|
m_pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
|
m_pContext->IASetInputLayout(m_InputLayout.Get());
|
|
m_pContext->IASetVertexBuffers(0, 1, m_VertexBuffer.GetAddressOf(), &stride, &offset);
|
|
m_pContext->Draw(4, 0);
|
|
|
|
// Restore the state objects
|
|
m_pContext->RSSetState(ras_state);
|
|
m_pContext->OMSetBlendState(blend_state.Get(), blend_factor, sample_mask);
|
|
m_pContext->IASetPrimitiveTopology(topology);
|
|
}
|
|
|
|
void CompositorD3D::RenderTextureSwapChain(vr::EVREye eye, ovrTextureSwapChain swapChain, ovrTextureSwapChain sceneChain, ovrRecti viewport, vr::VRTextureBounds_t bounds, vr::HmdVector4_t quad)
|
|
{
|
|
// TODO: Support compositing layers in DX12
|
|
if (!m_pDevice)
|
|
return;
|
|
|
|
uint32_t width, height;
|
|
vr::VRSystem()->GetRecommendedRenderTargetSize(&width, &height);
|
|
TextureD3D* texture = (TextureD3D*)swapChain->Textures[swapChain->SubmitIndex].get();
|
|
TextureD3D* scene = (TextureD3D*)sceneChain->Textures[sceneChain->SubmitIndex].get();
|
|
|
|
// Get the current state objects
|
|
Microsoft::WRL::ComPtr<ID3D11BlendState> blend_state;
|
|
float blend_factor[4];
|
|
uint32_t sample_mask;
|
|
m_pContext->OMGetBlendState(blend_state.GetAddressOf(), blend_factor, &sample_mask);
|
|
|
|
D3D11_PRIMITIVE_TOPOLOGY topology;
|
|
m_pContext->IAGetPrimitiveTopology(&topology);
|
|
|
|
ID3D11RasterizerState* ras_state;
|
|
m_pContext->RSGetState(&ras_state);
|
|
|
|
// Set the compositor shaders
|
|
m_pContext->VSSetShader(m_VertexShader.Get(), NULL, 0);
|
|
m_pContext->PSSetShader(m_CompositorShader.Get(), NULL, 0);
|
|
ID3D11ShaderResourceView* resource = texture->Resource();
|
|
m_pContext->PSSetShaderResources(0, 1, &resource);
|
|
|
|
// Update the vertex buffer
|
|
Vertex vertices[4] = {
|
|
{ { quad.v[0], quad.v[2] },{ bounds.uMin, bounds.vMin } },
|
|
{ { quad.v[1], quad.v[2] },{ bounds.uMax, bounds.vMin } },
|
|
{ { quad.v[0], quad.v[3] },{ bounds.uMin, bounds.vMax } },
|
|
{ { quad.v[1], quad.v[3] },{ bounds.uMax, bounds.vMax } }
|
|
};
|
|
D3D11_MAPPED_SUBRESOURCE map = { 0 };
|
|
m_pContext->Map(m_VertexBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
|
memcpy(map.pData, vertices, sizeof(Vertex) * 4);
|
|
m_pContext->Unmap(m_VertexBuffer.Get(), 0);
|
|
|
|
// Prepare the render target
|
|
D3D11_VIEWPORT vp = { (float)viewport.Pos.x, (float)viewport.Pos.y, (float)viewport.Size.w, (float)viewport.Size.h, D3D11_MIN_DEPTH, D3D11_MIN_DEPTH };
|
|
m_pContext->RSSetViewports(1, &vp);
|
|
ID3D11RenderTargetView* target = scene->Target();
|
|
m_pContext->OMSetRenderTargets(1, &target, nullptr);
|
|
m_pContext->OMSetBlendState(m_BlendState.Get(), nullptr, -1);
|
|
m_pContext->RSSetState(nullptr);
|
|
|
|
// Set and draw the vertices
|
|
uint32_t stride = sizeof(Vertex);
|
|
uint32_t offset = 0;
|
|
m_pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
|
m_pContext->IASetInputLayout(m_InputLayout.Get());
|
|
m_pContext->IASetVertexBuffers(0, 1, m_VertexBuffer.GetAddressOf(), &stride, &offset);
|
|
m_pContext->Draw(4, 0);
|
|
|
|
// Restore the state objects
|
|
m_pContext->RSSetState(ras_state);
|
|
m_pContext->OMSetBlendState(blend_state.Get(), blend_factor, sample_mask);
|
|
m_pContext->IASetPrimitiveTopology(topology);
|
|
}
|