You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
This represents UE4/Main @ 14768117 For ReleaseObjectVersion.h #lockdown Marcus.Wassmer [CL 14811440 by Marc Audy in ue5-main branch]
656 lines
25 KiB
C++
656 lines
25 KiB
C++
//*********************************************************
|
|
//
|
|
// Copyright (c) Microsoft. All rights reserved.
|
|
// This code is licensed under the MIT License (MIT).
|
|
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
|
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
|
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
|
//
|
|
//*********************************************************
|
|
|
|
#include "stdafx.h"
|
|
#include "D3D12HelloTexture.h"
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// TextureShare
|
|
//--------------------------------------------------------------------------------------
|
|
#include "TextureShareD3D12Client.h"
|
|
|
|
// TextureShare client object
|
|
FTextureShareD3D12Client* TextureShareClient = nullptr;
|
|
|
|
enum D3D12SRVConst
|
|
{
|
|
// Reserve 2 SRV textures in d3d12 heap
|
|
ReadSRVCount = 2
|
|
};
|
|
|
|
// Define share and texture names
|
|
enum ESharedTextureName
|
|
{
|
|
// Read textures
|
|
SceneDepth = 0,
|
|
BackBuffer,
|
|
COUNT
|
|
};
|
|
std::wstring ShareName1 = L"vp_1";
|
|
std::wstring ReceiveTextureNames[] = { L"SceneDepth" , L"BackBuffer" };
|
|
std::wstring SendBackbufferTextureName = L"InBackbuffer";
|
|
|
|
// Store all received textures to ShareData1
|
|
struct FTextureShareReceiverData
|
|
{
|
|
ID3D12Resource* TextureSRV = nullptr;
|
|
};
|
|
FTextureShareReceiverData ShareData1[] = { FTextureShareReceiverData(), FTextureShareReceiverData() };
|
|
|
|
// Call once, create TextureShare object, and register textures for send+receive
|
|
void InitializeTextureShareClient(ID3D12Device* pD3D12Device, ID3D12GraphicsCommandList* pCmdList, ID3D12DescriptorHeap* pD3D12HeapSRV, ID3D12Resource* BackbufferRTTTexture)
|
|
{
|
|
TextureShareClient = new FTextureShareD3D12Client(pD3D12Device, pCmdList, pD3D12HeapSRV);
|
|
TextureShareClient->CreateShare(ShareName1);
|
|
|
|
// Register receive textures:
|
|
TextureShareClient->RegisterTexture(ShareName1, ReceiveTextureNames[ESharedTextureName::SceneDepth], ETextureShareSurfaceOp::Read, 0, 0, DXGI_FORMAT_R10G10B10A2_UNORM);
|
|
TextureShareClient->RegisterTexture(ShareName1, ReceiveTextureNames[ESharedTextureName::BackBuffer], ETextureShareSurfaceOp::Read);
|
|
|
|
// Register backbuffer texture size&format for send
|
|
{
|
|
D3D12_RESOURCE_DESC DescRTT = BackbufferRTTTexture->GetDesc();
|
|
TextureShareClient->RegisterTexture(ShareName1, SendBackbufferTextureName, ETextureShareSurfaceOp::Write, (uint32)DescRTT.Width, (uint32)DescRTT.Height, DescRTT.Format);
|
|
}
|
|
|
|
// Begin share session
|
|
TextureShareClient->BeginSession(ShareName1);
|
|
}
|
|
|
|
void ReleaseTextureShareClient()
|
|
{
|
|
if (TextureShareClient)
|
|
{
|
|
TextureShareClient->EndSession(ShareName1);
|
|
TextureShareClient->DeleteShare(ShareName1);
|
|
delete TextureShareClient;
|
|
TextureShareClient = nullptr;
|
|
}
|
|
}
|
|
|
|
// Update Frame Receive&send textures
|
|
bool UpdateTextureShareClient_RenderThread(ID3D12Resource* BackbufferRTTTexture)
|
|
{
|
|
bool bResult = false;
|
|
if (TextureShareClient && TextureShareClient->BeginFrame_RenderThread(ShareName1))
|
|
{
|
|
// Receive all textures
|
|
for (int i = 0; i < ESharedTextureName::COUNT; i++)
|
|
{
|
|
// Map to SRV heap
|
|
int SRVIndex = i + 1;
|
|
|
|
// Read shared texture
|
|
if (TextureShareClient->ReadTextureFrame_RenderThread(ShareName1, ReceiveTextureNames[i], &ShareData1[i].TextureSRV, SRVIndex))
|
|
{
|
|
bResult = true;
|
|
}
|
|
}
|
|
|
|
//Send backbuffer:
|
|
if (TextureShareClient->IsRemoteTextureUsed(ShareName1, SendBackbufferTextureName))
|
|
{
|
|
TextureShareClient->WriteTextureFrame_RenderThread(ShareName1, SendBackbufferTextureName, BackbufferRTTTexture);
|
|
}
|
|
|
|
// Get frame data
|
|
FTextureShareSDKAdditionalData FrameData;
|
|
TextureShareClient->ReadAdditionalData(ShareName1, &FrameData);
|
|
|
|
TextureShareClient->EndFrame_RenderThread(ShareName1);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
D3D12HelloTexture::D3D12HelloTexture(UINT width, UINT height, std::wstring name) :
|
|
DXSample(width, height, name),
|
|
m_frameIndex(0),
|
|
m_viewport(0.0f, 0.0f, static_cast<float>(width), static_cast<float>(height)),
|
|
m_scissorRect(0, 0, static_cast<LONG>(width), static_cast<LONG>(height)),
|
|
m_rtvDescriptorSize(0)
|
|
{
|
|
}
|
|
|
|
void D3D12HelloTexture::OnInit()
|
|
{
|
|
LoadPipeline();
|
|
LoadAssets();
|
|
InitializeTextureShareClient(m_device.Get(), m_commandList.Get(), m_srvHeap.Get(), m_renderTargets[m_frameIndex].Get());
|
|
}
|
|
|
|
// Load the rendering pipeline dependencies.
|
|
void D3D12HelloTexture::LoadPipeline()
|
|
{
|
|
UINT dxgiFactoryFlags = 0;
|
|
|
|
#if defined(_DEBUG)
|
|
// Enable the debug layer (requires the Graphics Tools "optional feature").
|
|
// NOTE: Enabling the debug layer after device creation will invalidate the active device.
|
|
{
|
|
ComPtr<ID3D12Debug> debugController;
|
|
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
|
|
{
|
|
debugController->EnableDebugLayer();
|
|
|
|
// Enable additional debug layers.
|
|
dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
ComPtr<IDXGIFactory4> factory;
|
|
ThrowIfFailed(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&factory)));
|
|
|
|
if (m_useWarpDevice)
|
|
{
|
|
ComPtr<IDXGIAdapter> warpAdapter;
|
|
ThrowIfFailed(factory->EnumWarpAdapter(IID_PPV_ARGS(&warpAdapter)));
|
|
|
|
ThrowIfFailed(D3D12CreateDevice(warpAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device) ));
|
|
}
|
|
else
|
|
{
|
|
ComPtr<IDXGIAdapter1> hardwareAdapter;
|
|
GetHardwareAdapter(factory.Get(), &hardwareAdapter);
|
|
|
|
ThrowIfFailed(D3D12CreateDevice(hardwareAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device)));
|
|
}
|
|
|
|
// Describe and create the command queue.
|
|
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
|
|
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
|
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
|
|
|
ThrowIfFailed(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue)));
|
|
|
|
// Describe and create the swap chain.
|
|
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
|
|
swapChainDesc.BufferCount = FrameCount;
|
|
swapChainDesc.Width = m_width;
|
|
swapChainDesc.Height = m_height;
|
|
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
|
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
|
swapChainDesc.SampleDesc.Count = 1;
|
|
|
|
ComPtr<IDXGISwapChain1> swapChain;
|
|
ThrowIfFailed(factory->CreateSwapChainForHwnd(
|
|
m_commandQueue.Get(), // Swap chain needs the queue so that it can force a flush on it.
|
|
Win32Application::GetHwnd(),
|
|
&swapChainDesc,
|
|
nullptr,
|
|
nullptr,
|
|
&swapChain
|
|
));
|
|
|
|
// This sample does not support fullscreen transitions.
|
|
ThrowIfFailed(factory->MakeWindowAssociation(Win32Application::GetHwnd(), DXGI_MWA_NO_ALT_ENTER));
|
|
|
|
ThrowIfFailed(swapChain.As(&m_swapChain));
|
|
m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
|
|
|
|
// Create descriptor heaps.
|
|
{
|
|
// Describe and create a render target view (RTV) descriptor heap.
|
|
D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
|
|
rtvHeapDesc.NumDescriptors = FrameCount;
|
|
rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
|
rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
|
ThrowIfFailed(m_device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeap)));
|
|
|
|
// Describe and create a shader resource view (SRV) heap for the texture.
|
|
D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
|
|
srvHeapDesc.NumDescriptors = 1 + ReadSRVCount;
|
|
srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
|
srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
|
ThrowIfFailed(m_device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&m_srvHeap)));
|
|
|
|
m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
|
}
|
|
|
|
// Create frame resources.
|
|
{
|
|
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart());
|
|
|
|
// Create a RTV for each frame.
|
|
for (UINT n = 0; n < FrameCount; n++)
|
|
{
|
|
ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets[n])));
|
|
m_device->CreateRenderTargetView(m_renderTargets[n].Get(), nullptr, rtvHandle);
|
|
rtvHandle.Offset(1, m_rtvDescriptorSize);
|
|
}
|
|
}
|
|
|
|
ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator)));
|
|
}
|
|
|
|
|
|
|
|
// Load the sample assets.
|
|
void D3D12HelloTexture::LoadAssets()
|
|
{
|
|
// Create the root signature.
|
|
{
|
|
D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = {};
|
|
|
|
// This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this.
|
|
featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1;
|
|
|
|
if (FAILED(m_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, sizeof(featureData))))
|
|
{
|
|
featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0;
|
|
}
|
|
|
|
CD3DX12_DESCRIPTOR_RANGE1 ranges[1];
|
|
ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);
|
|
|
|
CD3DX12_ROOT_PARAMETER1 rootParameters[1];
|
|
rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL);
|
|
|
|
D3D12_STATIC_SAMPLER_DESC sampler = {};
|
|
sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
|
|
sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
|
|
sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
|
|
sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
|
|
sampler.MipLODBias = 0;
|
|
sampler.MaxAnisotropy = 0;
|
|
sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
|
|
sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
|
|
sampler.MinLOD = 0.0f;
|
|
sampler.MaxLOD = D3D12_FLOAT32_MAX;
|
|
sampler.ShaderRegister = 0;
|
|
sampler.RegisterSpace = 0;
|
|
sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc;
|
|
rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 1, &sampler, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
|
|
|
|
ComPtr<ID3DBlob> signature;
|
|
ComPtr<ID3DBlob> error;
|
|
ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &signature, &error));
|
|
ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature)));
|
|
}
|
|
|
|
// Create the pipeline state, which includes compiling and loading shaders.
|
|
{
|
|
ComPtr<ID3DBlob> vertexShader;
|
|
ComPtr<ID3DBlob> pixelShader;
|
|
|
|
#if defined(_DEBUG)
|
|
// Enable better shader debugging with the graphics debugging tools.
|
|
UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
|
|
#else
|
|
UINT compileFlags = 0;
|
|
#endif
|
|
|
|
static const char* hlslShader =
|
|
"struct PSInput\
|
|
{\
|
|
float4 position : SV_POSITION;\
|
|
float2 uv : TEXCOORD;\
|
|
};\
|
|
Texture2D g_texture : register(t0);\
|
|
SamplerState g_sampler : register(s0);\
|
|
PSInput VSMain(float4 position : POSITION, float4 uv : TEXCOORD)\
|
|
{\
|
|
PSInput result;\
|
|
result.position = position;\
|
|
result.uv = uv;\
|
|
return result;\
|
|
}\
|
|
float4 PSMain(PSInput input) : SV_TARGET\
|
|
{\
|
|
return g_texture.Sample(g_sampler, input.uv);\
|
|
}";
|
|
|
|
ThrowIfFailed(D3DCompile(hlslShader, strlen(hlslShader), nullptr, nullptr, nullptr, "VSMain", "vs_5_0", 0, 0, &vertexShader, nullptr));
|
|
ThrowIfFailed(D3DCompile(hlslShader, strlen(hlslShader), nullptr, nullptr, nullptr, "PSMain", "ps_5_0", 0, 0, &pixelShader, nullptr));
|
|
|
|
// Define the vertex input layout.
|
|
D3D12_INPUT_ELEMENT_DESC inputElementDescs[] =
|
|
{
|
|
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
|
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
|
|
};
|
|
|
|
// Describe and create the graphics pipeline state object (PSO).
|
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
|
|
psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };
|
|
psoDesc.pRootSignature = m_rootSignature.Get();
|
|
psoDesc.VS = CD3DX12_SHADER_BYTECODE(vertexShader.Get());
|
|
psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShader.Get());
|
|
psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
|
|
psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
|
|
psoDesc.DepthStencilState.DepthEnable = FALSE;
|
|
psoDesc.DepthStencilState.StencilEnable = FALSE;
|
|
psoDesc.SampleMask = UINT_MAX;
|
|
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
psoDesc.NumRenderTargets = 1;
|
|
psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
psoDesc.SampleDesc.Count = 1;
|
|
ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState)));
|
|
}
|
|
|
|
// Create the command list.
|
|
ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator.Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_commandList)));
|
|
|
|
// Create the vertex buffer.
|
|
{
|
|
// Define the geometry for a triangle.
|
|
Vertex triangleVertices[] =
|
|
{
|
|
{ { -0.5f, 0.5f * m_aspectRatio, 0.0f }, { 0.5f, 0.0f } },
|
|
{ { 0.f, -0.5f * m_aspectRatio, 0.0f }, { 1.0f, 1.0f } },
|
|
{ { -1.f, -0.5f * m_aspectRatio, 0.0f }, { 0.0f, 1.0f } }
|
|
};
|
|
|
|
const UINT vertexBufferSize = sizeof(triangleVertices);
|
|
|
|
// Note: using upload heaps to transfer static data like vert buffers is not
|
|
// recommended. Every time the GPU needs it, the upload heap will be marshalled
|
|
// over. Please read up on Default Heap usage. An upload heap is used here for
|
|
// code simplicity and because there are very few verts to actually transfer.
|
|
ThrowIfFailed(m_device->CreateCommittedResource(
|
|
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
|
|
D3D12_HEAP_FLAG_NONE,
|
|
&CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize),
|
|
D3D12_RESOURCE_STATE_GENERIC_READ,
|
|
nullptr,
|
|
IID_PPV_ARGS(&m_vertexBuffer)));
|
|
|
|
// Copy the triangle data to the vertex buffer.
|
|
UINT8* pVertexDataBegin;
|
|
CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU.
|
|
ThrowIfFailed(m_vertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin)));
|
|
memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices));
|
|
m_vertexBuffer->Unmap(0, nullptr);
|
|
|
|
// Initialize the vertex buffer view.
|
|
m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress();
|
|
m_vertexBufferView.StrideInBytes = sizeof(Vertex);
|
|
m_vertexBufferView.SizeInBytes = vertexBufferSize;
|
|
}
|
|
// VB 2
|
|
{
|
|
// Define the geometry for a triangle.
|
|
Vertex triangleVertices[] =
|
|
{
|
|
{ { 0.5f, 0.5f * m_aspectRatio, 0.0f }, { 0.5f, 0.0f } },
|
|
{ { 1.f, -0.5f * m_aspectRatio, 0.0f }, { 1.0f, 1.0f } },
|
|
{ { 0.f, -0.5f * m_aspectRatio, 0.0f }, { 0.0f, 1.0f } }
|
|
};
|
|
|
|
const UINT vertexBufferSize = sizeof(triangleVertices);
|
|
|
|
// Note: using upload heaps to transfer static data like vert buffers is not
|
|
// recommended. Every time the GPU needs it, the upload heap will be marshalled
|
|
// over. Please read up on Default Heap usage. An upload heap is used here for
|
|
// code simplicity and because there are very few verts to actually transfer.
|
|
ThrowIfFailed(m_device->CreateCommittedResource(
|
|
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
|
|
D3D12_HEAP_FLAG_NONE,
|
|
&CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize),
|
|
D3D12_RESOURCE_STATE_GENERIC_READ,
|
|
nullptr,
|
|
IID_PPV_ARGS(&m_vertexBuffer2)));
|
|
|
|
// Copy the triangle data to the vertex buffer.
|
|
UINT8* pVertexDataBegin;
|
|
CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU.
|
|
ThrowIfFailed(m_vertexBuffer2->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin)));
|
|
memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices));
|
|
m_vertexBuffer2->Unmap(0, nullptr);
|
|
|
|
// Initialize the vertex buffer view.
|
|
m_vertexBufferView2.BufferLocation = m_vertexBuffer2->GetGPUVirtualAddress();
|
|
m_vertexBufferView2.StrideInBytes = sizeof(Vertex);
|
|
m_vertexBufferView2.SizeInBytes = vertexBufferSize;
|
|
}
|
|
|
|
// Note: ComPtr's are CPU objects but this resource needs to stay in scope until
|
|
// the command list that references it has finished executing on the GPU.
|
|
// We will flush the GPU at the end of this method to ensure the resource is not
|
|
// prematurely destroyed.
|
|
ComPtr<ID3D12Resource> textureUploadHeap;
|
|
|
|
// Create the texture.
|
|
{
|
|
// Describe and create a Texture2D.
|
|
D3D12_RESOURCE_DESC textureDesc = {};
|
|
textureDesc.MipLevels = 1;
|
|
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
textureDesc.Width = TextureWidth;
|
|
textureDesc.Height = TextureHeight;
|
|
textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
textureDesc.DepthOrArraySize = 1;
|
|
textureDesc.SampleDesc.Count = 1;
|
|
textureDesc.SampleDesc.Quality = 0;
|
|
textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
|
|
ThrowIfFailed(m_device->CreateCommittedResource(
|
|
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
|
|
D3D12_HEAP_FLAG_NONE,
|
|
&textureDesc,
|
|
D3D12_RESOURCE_STATE_COPY_DEST,
|
|
nullptr,
|
|
IID_PPV_ARGS(&m_texture)));
|
|
|
|
const UINT64 uploadBufferSize = GetRequiredIntermediateSize(m_texture.Get(), 0, 1);
|
|
|
|
// Create the GPU upload buffer.
|
|
ThrowIfFailed(m_device->CreateCommittedResource(
|
|
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
|
|
D3D12_HEAP_FLAG_NONE,
|
|
&CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize),
|
|
D3D12_RESOURCE_STATE_GENERIC_READ,
|
|
nullptr,
|
|
IID_PPV_ARGS(&textureUploadHeap)));
|
|
|
|
// Copy data to the intermediate upload heap and then schedule a copy
|
|
// from the upload heap to the Texture2D.
|
|
std::vector<UINT8> texture = GenerateTextureData();
|
|
|
|
D3D12_SUBRESOURCE_DATA textureData = {};
|
|
textureData.pData = &texture[0];
|
|
textureData.RowPitch = TextureWidth * TexturePixelSize;
|
|
textureData.SlicePitch = textureData.RowPitch * TextureHeight;
|
|
|
|
UpdateSubresources(m_commandList.Get(), m_texture.Get(), textureUploadHeap.Get(), 0, 0, 1, &textureData);
|
|
m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_texture.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));
|
|
|
|
// Describe and create a SRV for the texture.
|
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
|
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
|
srvDesc.Format = textureDesc.Format;
|
|
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
|
srvDesc.Texture2D.MipLevels = 1;
|
|
m_device->CreateShaderResourceView(m_texture.Get(), &srvDesc, m_srvHeap->GetCPUDescriptorHandleForHeapStart());
|
|
}
|
|
|
|
// Close the command list and execute it to begin the initial GPU setup.
|
|
ThrowIfFailed(m_commandList->Close());
|
|
ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
|
|
m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
|
|
|
|
// Create synchronization objects and wait until assets have been uploaded to the GPU.
|
|
{
|
|
ThrowIfFailed(m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence)));
|
|
m_fenceValue = 1;
|
|
|
|
// Create an event handle to use for frame synchronization.
|
|
m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
|
if (m_fenceEvent == nullptr)
|
|
{
|
|
ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
// Wait for the command list to execute; we are reusing the same command
|
|
// list in our main loop but for now, we just want to wait for setup to
|
|
// complete before continuing.
|
|
WaitForPreviousFrame();
|
|
}
|
|
}
|
|
|
|
// Generate a simple black and white checkerboard texture.
|
|
std::vector<UINT8> D3D12HelloTexture::GenerateTextureData()
|
|
{
|
|
const UINT rowPitch = TextureWidth * TexturePixelSize;
|
|
const UINT cellPitch = rowPitch >> 3; // The width of a cell in the checkboard texture.
|
|
const UINT cellHeight = TextureWidth >> 3; // The height of a cell in the checkerboard texture.
|
|
const UINT textureSize = rowPitch * TextureHeight;
|
|
|
|
std::vector<UINT8> data(textureSize);
|
|
UINT8* pData = &data[0];
|
|
|
|
for (UINT n = 0; n < textureSize; n += TexturePixelSize)
|
|
{
|
|
UINT x = n % rowPitch;
|
|
UINT y = n / rowPitch;
|
|
UINT i = x / cellPitch;
|
|
UINT j = y / cellHeight;
|
|
|
|
if (i % 2 == j % 2)
|
|
{
|
|
pData[n] = 0x00; // R
|
|
pData[n + 1] = 0x00; // G
|
|
pData[n + 2] = 0x00; // B
|
|
pData[n + 3] = 0xff; // A
|
|
}
|
|
else
|
|
{
|
|
pData[n] = 0xff; // R
|
|
pData[n + 1] = 0xff; // G
|
|
pData[n + 2] = 0xff; // B
|
|
pData[n + 3] = 0xff; // A
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
// Update frame-based values.
|
|
void D3D12HelloTexture::OnUpdate()
|
|
{
|
|
}
|
|
|
|
// Render the scene.
|
|
void D3D12HelloTexture::OnRender()
|
|
{
|
|
PopulateCommandList();
|
|
|
|
// Execute the command list.
|
|
ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
|
|
m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
|
|
|
|
// Present the frame.
|
|
ThrowIfFailed(m_swapChain->Present(1, 0));
|
|
|
|
WaitForPreviousFrame();
|
|
}
|
|
|
|
void D3D12HelloTexture::OnDestroy()
|
|
{
|
|
// Ensure that the GPU is no longer referencing resources that are about to be
|
|
// cleaned up by the destructor.
|
|
WaitForPreviousFrame();
|
|
|
|
// Release textureShare before destory (this send info to server, and correctly stop share session)
|
|
ReleaseTextureShareClient();
|
|
|
|
CloseHandle(m_fenceEvent);
|
|
}
|
|
|
|
void D3D12HelloTexture::BindTexture(int SRVIndex)
|
|
{
|
|
uint32 DescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
|
CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandle(m_srvHeap->GetGPUDescriptorHandleForHeapStart(), SRVIndex, DescriptorSize);
|
|
m_commandList->SetGraphicsRootDescriptorTable(0, srvHandle);
|
|
}
|
|
|
|
void D3D12HelloTexture::PopulateCommandList()
|
|
{
|
|
// Command list allocators can only be reset when the associated
|
|
// command lists have finished execution on the GPU; apps should use
|
|
// fences to determine GPU execution progress.
|
|
ThrowIfFailed(m_commandAllocator->Reset());
|
|
|
|
// However, when ExecuteCommandList() is called on a particular command
|
|
// list, that command list can then be reset at any time and must be before
|
|
// re-recording.
|
|
ThrowIfFailed(m_commandList->Reset(m_commandAllocator.Get(), m_pipelineState.Get()));
|
|
|
|
// Set necessary state.
|
|
m_commandList->SetGraphicsRootSignature(m_rootSignature.Get());
|
|
|
|
ID3D12DescriptorHeap* ppHeaps[] = { m_srvHeap.Get() };
|
|
m_commandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
|
|
|
|
m_commandList->RSSetViewports(1, &m_viewport);
|
|
m_commandList->RSSetScissorRects(1, &m_scissorRect);
|
|
|
|
// Indicate that the back buffer will be used as a render target.
|
|
m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
|
|
|
|
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize);
|
|
m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);
|
|
|
|
/** Receive & Send texture from share (required opended commands list)*/
|
|
UpdateTextureShareClient_RenderThread(m_renderTargets[m_frameIndex].Get());
|
|
|
|
const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
|
|
m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
|
|
m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
|
|
|
{
|
|
// Render Tri 1
|
|
int SRVTextureIndex = ShareData1[ESharedTextureName::SceneDepth].TextureSRV ? (ESharedTextureName::SceneDepth + 1) : 0;
|
|
BindTexture(SRVTextureIndex);
|
|
m_commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView);
|
|
m_commandList->DrawInstanced(3, 1, 0, 0);
|
|
}
|
|
{
|
|
// Render Tri 2
|
|
int SRVTextureIndex = ShareData1[ESharedTextureName::BackBuffer].TextureSRV ? (ESharedTextureName::BackBuffer + 1) : 0;
|
|
BindTexture(SRVTextureIndex);
|
|
m_commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView2);
|
|
m_commandList->DrawInstanced(3, 1, 0, 0);
|
|
}
|
|
|
|
// Indicate that the back buffer will now be used to present.
|
|
m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
|
|
|
|
ThrowIfFailed(m_commandList->Close());
|
|
}
|
|
|
|
void D3D12HelloTexture::WaitForPreviousFrame()
|
|
{
|
|
// WAITING FOR THE FRAME TO COMPLETE BEFORE CONTINUING IS NOT BEST PRACTICE.
|
|
// This is code implemented as such for simplicity. The D3D12HelloFrameBuffering
|
|
// sample illustrates how to use fences for efficient resource usage and to
|
|
// maximize GPU utilization.
|
|
|
|
// Signal and increment the fence value.
|
|
const UINT64 fence = m_fenceValue;
|
|
ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), fence));
|
|
m_fenceValue++;
|
|
|
|
// Wait until the previous frame is finished.
|
|
if (m_fence->GetCompletedValue() < fence)
|
|
{
|
|
ThrowIfFailed(m_fence->SetEventOnCompletion(fence, m_fenceEvent));
|
|
WaitForSingleObject(m_fenceEvent, INFINITE);
|
|
}
|
|
|
|
m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
|
|
}
|