#include "pch.h"
#include "X12ViewModel.h"
#include "..\Common\DirectXHelper.h"
#include <ppltasks.h>
#include <synchapi.h>
using namespace App1;
using namespace Concurrency;
using namespace DirectX;
using namespace Microsoft::WRL;
using namespace Windows::Foundation;
using namespace Windows::Storage;
// ファイルから頂点とピクセル シェーダーを読み込み、キューブのジオメトリをインスタンス化します。
X12ViewModel::X12ViewModel(const std::shared_ptr<DX::DeviceResources>& deviceResources) :
m_loadingComplete(false),
m_mappedConstantBuffer(nullptr),
m_deviceResources(deviceResources)
{
}
X12ViewModel::~X12ViewModel()
{
m_constantBuffer->Unmap(0, nullptr);
m_mappedConstantBuffer = nullptr;
}
void X12ViewModel::Load()
{
OutputDebugString(L"**Start Load\n");
auto d3dDevice = m_deviceResources->GetD3DDevice();
//単一の定数バッファー スロットがあるルート署名を作成します。
{
CD3DX12_DESCRIPTOR_RANGE range;
CD3DX12_ROOT_PARAMETER parameter;
range.Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0);
parameter.InitAsDescriptorTable(1, &range, D3D12_SHADER_VISIBILITY_VERTEX);
D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | //定数バッファーにアクセスする必要があるのは、入力アセンブラー ステージだけです。
D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS;
CD3DX12_ROOT_SIGNATURE_DESC descRootSignature;
descRootSignature.Init(1, ¶meter, 0, nullptr, rootSignatureFlags);
ComPtr<ID3DBlob> pSignature;
ComPtr<ID3DBlob> pError;
DX::ThrowIfFailed(D3D12SerializeRootSignature(&descRootSignature, D3D_ROOT_SIGNATURE_VERSION_1, pSignature.GetAddressOf(), pError.GetAddressOf()));
DX::ThrowIfFailed(d3dDevice->CreateRootSignature(0, pSignature->GetBufferPointer(), pSignature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature)));
NAME_D3D12_OBJECT(m_rootSignature);
}
// シェーダーを非同期で読み込みます。
auto createVSTask = DX::ReadDataAsync(L"SampleVertexShader.cso").then([this](std::vector<byte>& fileData) {
m_vertexShader = fileData;
});
auto createPSTask = DX::ReadDataAsync(L"SamplePixelShader.cso").then([this](std::vector<byte>& fileData) {
m_pixelShader = fileData;
});
//シェーダーが読み込まれた後に、パイプライン状態を作成します。
auto createPipelineStateTask = (createPSTask && createVSTask).then([this]() {
static const D3D12_INPUT_ELEMENT_DESC inputLayout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
};
D3D12_GRAPHICS_PIPELINE_STATE_DESC state = {};
state.InputLayout = { inputLayout, _countof(inputLayout) };
state.pRootSignature = m_rootSignature.Get();
state.VS = CD3DX12_SHADER_BYTECODE(&m_vertexShader[0], m_vertexShader.size());
state.PS = CD3DX12_SHADER_BYTECODE(&m_pixelShader[0], m_pixelShader.size());
state.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
state.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
state.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
state.SampleMask = UINT_MAX;
state.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
state.NumRenderTargets = 1;
state.RTVFormats[0] = m_deviceResources->GetBackBufferFormat();
state.DSVFormat = m_deviceResources->GetDepthBufferFormat();
state.SampleDesc.Count = 1;
DX::ThrowIfFailed(m_deviceResources->GetD3DDevice()->CreateGraphicsPipelineState(&state, IID_PPV_ARGS(&m_pipelineState)));
// シェーダー データは、パイプライン状態が作成された後に削除できます。
m_vertexShader.clear();
m_pixelShader.clear();
});
createPipelineStateTask.then([this]()
{ CreateModel();
});
}
// Model を作成
void X12ViewModel::CreateModel()
{
//キューブ ジオメトリ リソースを作成して GPU にアップロードします。
auto d3dDevice = m_deviceResources->GetD3DDevice();
// コマンド一覧を作成します。
DX::ThrowIfFailed(d3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_deviceResources->GetCommandAllocator(), m_pipelineState.Get(), IID_PPV_ARGS(&m_commandList)));
NAME_D3D12_OBJECT(m_commandList);
//キューブの頂点。各頂点には位置と色があります。
VertexPositionColor cubeVertices[] =
{
{ XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT3(0.0f, 0.0f, 0.0f) },
{ XMFLOAT3(-0.5f, -0.5f, 0.5f), XMFLOAT3(0.0f, 0.0f, 1.0f) },
{ XMFLOAT3(-0.5f, 0.5f, -0.5f), XMFLOAT3(0.0f, 1.0f, 0.0f) },
{ XMFLOAT3(-0.5f, 0.5f, 0.5f), XMFLOAT3(0.0f, 1.0f, 1.0f) },
{ XMFLOAT3(0.5f, -0.5f, -0.5f), XMFLOAT3(1.0f, 0.0f, 0.0f) },
{ XMFLOAT3(0.5f, -0.5f, 0.5f), XMFLOAT3(1.0f, 0.0f, 1.0f) },
{ XMFLOAT3(0.5f, 0.5f, -0.5f), XMFLOAT3(1.0f, 1.0f, 0.0f) },
{ XMFLOAT3(0.5f, 0.5f, 0.5f), XMFLOAT3(1.0f, 1.0f, 1.0f) },
};
const UINT vertexBufferSize = sizeof(cubeVertices);
//GPU の既定のヒープに頂点バッファー リソースを作成し、アップロード ヒープを使用して、頂点データをそれにコピーします。
//アップロード リソースは、GPU による使用が終了するまで解放できません。
Microsoft::WRL::ComPtr<ID3D12Resource> vertexBufferUpload;
CD3DX12_HEAP_PROPERTIES defaultHeapProperties(D3D12_HEAP_TYPE_DEFAULT);
CD3DX12_RESOURCE_DESC vertexBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize);
DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
&defaultHeapProperties,
D3D12_HEAP_FLAG_NONE,
&vertexBufferDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(&m_vertexBuffer)));
CD3DX12_HEAP_PROPERTIES uploadHeapProperties(D3D12_HEAP_TYPE_UPLOAD);
DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
&uploadHeapProperties,
D3D12_HEAP_FLAG_NONE,
&vertexBufferDesc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&vertexBufferUpload)));
NAME_D3D12_OBJECT(m_vertexBuffer);
//頂上バッファーを GPU にアップロードします。
{
D3D12_SUBRESOURCE_DATA vertexData = {};
vertexData.pData = reinterpret_cast<BYTE*>(cubeVertices);
vertexData.RowPitch = vertexBufferSize;
vertexData.SlicePitch = vertexData.RowPitch;
UpdateSubresources(m_commandList.Get(), m_vertexBuffer.Get(), vertexBufferUpload.Get(), 0, 0, 1, &vertexData);
CD3DX12_RESOURCE_BARRIER vertexBufferResourceBarrier =
CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
m_commandList->ResourceBarrier(1, &vertexBufferResourceBarrier);
}
//メッシュ インデックスを読み込みます。インデックスの各 3 つ組みは、画面に表示する三角形を表します。
//たとえば、0,2,1 は、頂点バッファーにあるインデックス 0、2、および 1 の各頂点によって、このメッシュの
// 最初の三角形を構成することを意味します。
unsigned short cubeIndices[] =
{
0, 2, 1, 1, 2, 3, // -x
4, 5, 6, 5, 7, 6, // +x
0, 1, 5, 0, 5, 4, // -y
2, 6, 7, 2, 7, 3, // +y
0, 4, 6, 0, 6, 2, // -z
1, 3, 7, 1, 7, 5, // +z
};
const UINT indexBufferSize = sizeof(cubeIndices);
//GPU の既定のヒープにインデックス バッファー リソースを作成し、アップロード ヒープを使用してインデックス データをそれにコピーします。
//アップロード リソースは、GPU による使用が終了するまで解放できません。
Microsoft::WRL::ComPtr<ID3D12Resource> indexBufferUpload;
CD3DX12_RESOURCE_DESC indexBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(indexBufferSize);
DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
&defaultHeapProperties,
D3D12_HEAP_FLAG_NONE,
&indexBufferDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(&m_indexBuffer)));
DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
&uploadHeapProperties,
D3D12_HEAP_FLAG_NONE,
&indexBufferDesc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&indexBufferUpload)));
NAME_D3D12_OBJECT(m_indexBuffer);
//インデックス バッファーを GPU にアップロードします。
{
D3D12_SUBRESOURCE_DATA indexData = {};
indexData.pData = reinterpret_cast<BYTE*>(cubeIndices);
indexData.RowPitch = indexBufferSize;
indexData.SlicePitch = indexData.RowPitch;
UpdateSubresources(m_commandList.Get(), m_indexBuffer.Get(), indexBufferUpload.Get(), 0, 0, 1, &indexData);
CD3DX12_RESOURCE_BARRIER indexBufferResourceBarrier =
CD3DX12_RESOURCE_BARRIER::Transition(m_indexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER);
m_commandList->ResourceBarrier(1, &indexBufferResourceBarrier);
}
// 定数バッファーのために記述子ヒープを作成します。
{
D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
heapDesc.NumDescriptors = DX::c_frameCount;
heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
//このフラグは、この記述子ヒープをパイプラインに結合できること、およびそれに含まれる記述子をルート テーブルから参照できることを示します。
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
DX::ThrowIfFailed(d3dDevice->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&m_cbvHeap)));
NAME_D3D12_OBJECT(m_cbvHeap);
}
CD3DX12_RESOURCE_DESC constantBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(DX::c_frameCount * c_alignedConstantBufferSize);
DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
&uploadHeapProperties,
D3D12_HEAP_FLAG_NONE,
&constantBufferDesc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&m_constantBuffer)));
NAME_D3D12_OBJECT(m_constantBuffer);
// アップロード バッファーにアクセスするための定数バッファー ビューを作成します。
D3D12_GPU_VIRTUAL_ADDRESS cbvGpuAddress = m_constantBuffer->GetGPUVirtualAddress();
CD3DX12_CPU_DESCRIPTOR_HANDLE cbvCpuHandle(m_cbvHeap->GetCPUDescriptorHandleForHeapStart());
m_cbvDescriptorSize = d3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
for (int n = 0; n < DX::c_frameCount; n++)
{
D3D12_CONSTANT_BUFFER_VIEW_DESC desc;
desc.BufferLocation = cbvGpuAddress;
desc.SizeInBytes = c_alignedConstantBufferSize;
d3dDevice->CreateConstantBufferView(&desc, cbvCpuHandle);
cbvGpuAddress += desc.SizeInBytes;
cbvCpuHandle.Offset(m_cbvDescriptorSize);
}
// 定数バッファーをマッピングします。
CD3DX12_RANGE readRange(0, 0); // CPU 上のこのリソースから読み取りません。
DX::ThrowIfFailed(m_constantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_mappedConstantBuffer)));
ZeroMemory(m_mappedConstantBuffer, DX::c_frameCount * c_alignedConstantBufferSize);
//アプリが終了するまで、このマッピングを解除しません。リソースの存続期間中、マッピングを維持しても問題ありません。
// コマンド リストを閉じて、それを実行することにより、GPU の既定のヒープへの頂点/インデックス バッファーのコピーを開始します。
DX::ThrowIfFailed(m_commandList->Close());
ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
m_deviceResources->GetCommandQueue()->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
//頂上/インデックス バッファー ビューを作成します。
m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress();
m_vertexBufferView.StrideInBytes = sizeof(VertexPositionColor);
m_vertexBufferView.SizeInBytes = sizeof(cubeVertices);
m_indexBufferView.BufferLocation = m_indexBuffer->GetGPUVirtualAddress();
m_indexBufferView.SizeInBytes = sizeof(cubeIndices);
m_indexBufferView.Format = DXGI_FORMAT_R16_UINT;
//コマンド リストが実行を完了するまで待機します。頂点/インデックス バッファーは、アップロード リソースが範囲外になる前にアップロードする必要があります。
m_deviceResources->WaitForGpu();
m_loadingComplete = true;
}
// 頂点とピクセル シェーダーを使用して、1 つのフレームを描画します。
bool X12ViewModel::View()
{
// 読み込みは非同期です。読み込みが完了した後にのみ描画してください。
if (!m_loadingComplete)
{ return false; }
DX::ThrowIfFailed(m_deviceResources->GetCommandAllocator()->Reset());
// ExecuteCommandList() が呼び出された後、コマンド一覧をいつでもリセットできます。
DX::ThrowIfFailed(m_commandList->Reset(m_deviceResources->GetCommandAllocator(), m_pipelineState.Get()));
PIXBeginEvent(m_commandList.Get(), 0, L"Draw the cube");
{
//このフレームで使用されるグラフィックのルート署名と記述子ヒープを設定します。
m_commandList->SetGraphicsRootSignature(m_rootSignature.Get());
ID3D12DescriptorHeap* ppHeaps[] = { m_cbvHeap.Get() };
m_commandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
// 現在のフレームの定数バッファーをパイプラインにバインドします。
CD3DX12_GPU_DESCRIPTOR_HANDLE gpuHandle(m_cbvHeap->GetGPUDescriptorHandleForHeapStart(), m_deviceResources->GetCurrentFrameIndex(), m_cbvDescriptorSize);
m_commandList->SetGraphicsRootDescriptorTable(0, gpuHandle);
// ビューポートとシザリング四角形を設定します。
D3D12_VIEWPORT viewport = m_deviceResources->GetScreenViewport();
m_commandList->RSSetViewports(1, &viewport);
m_commandList->RSSetScissorRects(1, &m_scissorRect);
//このリソースをレンダー ターゲットとして使用することを指定します。
CD3DX12_RESOURCE_BARRIER renderTargetResourceBarrier =
CD3DX12_RESOURCE_BARRIER::Transition(m_deviceResources->GetRenderTarget(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
m_commandList->ResourceBarrier(1, &renderTargetResourceBarrier);
//描画コマンドを記録します。
D3D12_CPU_DESCRIPTOR_HANDLE renderTargetView = m_deviceResources->GetRenderTargetView();
D3D12_CPU_DESCRIPTOR_HANDLE depthStencilView = m_deviceResources->GetDepthStencilView();
m_commandList->ClearRenderTargetView(renderTargetView, DirectX::Colors::CornflowerBlue, 0, nullptr);
m_commandList->ClearDepthStencilView(depthStencilView, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
m_commandList->OMSetRenderTargets(1, &renderTargetView, false, &depthStencilView);
m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView);
m_commandList->IASetIndexBuffer(&m_indexBufferView);
m_commandList->DrawIndexedInstanced(36, 1, 0, 0, 0);
//レンダー ターゲットが、コマンド リストがいつ実行を完了するかを表すために使用されることを示します。
CD3DX12_RESOURCE_BARRIER presentResourceBarrier =
CD3DX12_RESOURCE_BARRIER::Transition(m_deviceResources->GetRenderTarget(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
m_commandList->ResourceBarrier(1, &presentResourceBarrier);
}
PIXEndEvent(m_commandList.Get());
DX::ThrowIfFailed(m_commandList->Close());
//コマンド リストを実行します。
ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
m_deviceResources->GetCommandQueue()->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
return true;
}
void X12ViewModel::UpResource(ModelViewProjectionConstantBuffer BufferData)
{
UINT8* destination = m_mappedConstantBuffer + (m_deviceResources->GetCurrentFrameIndex() * c_alignedConstantBufferSize);
memcpy(destination, &BufferData, sizeof(BufferData));
}
|