#pragma once #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers. #endif #pragma comment(lib, "d3d12.lib") #pragma comment(lib, "dxgi.lib") #pragma comment(lib, "d3dcompiler.lib") #include #include "Types.hpp" #include "Allocator.hpp" #include "Memory.hpp" #include "Thread.hpp" #include #include #include #include #include "d3dx12.h" #include #include #include using namespace DirectX; using namespace Microsoft::WRL; #define SAFE_RELEASE(p) { if ( (p) ) { (p)->Release(); (p) = 0; } } struct ConstantBufferPerObject { XMFLOAT4X4 wvpMat; }; struct Vertex { Vertex(float x, float y, float z, float r, float g, float b, float a) : pos(x, y, z), color(r, g, b, a) {} XMFLOAT3 pos; XMFLOAT4 color; }; HWND hwnd = NULL; int32 Width = 800; int32 Height = 600; bool FullScreen = false; bool Running = true; bool InitializeWindow(HINSTANCE hInstance, int32 ShowWnd, bool fullscreen); bool InitD3D(); void Update(); void UpdatePipeline(); void Render(); void Cleanup(); void WaitForPreviousFrame(); LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); const int32 frameBufferCount = 3; ComPtr device; IDXGISwapChain3* swapChain; ID3D12CommandQueue* commandQueue; ID3D12DescriptorHeap* rtvDescriptorHeap; ID3D12Resource* renderTargets[frameBufferCount]; ID3D12CommandAllocator* commandAllocator[frameBufferCount]; ID3D12GraphicsCommandList* commandList; ID3D12Fence* fence[frameBufferCount]; HANDLE fenceEvent; uint64 fenceValue[frameBufferCount]; SIZE_T frameIndex; int32 rtvDescriptorSize; ID3D12PipelineState* pipelineStateObject; ID3D12RootSignature* rootSignature; D3D12_VIEWPORT viewport; D3D12_RECT scissorRect; ID3D12Resource* vertexBuffer; ID3D12Resource* indexBuffer; D3D12_VERTEX_BUFFER_VIEW vertexBufferView; D3D12_INDEX_BUFFER_VIEW indexBufferView; ID3D12Resource* depthStencilBuffer; ID3D12DescriptorHeap* dsDescriptorHeap; int32 ConstantBufferPerObjectAlignedSize = (sizeof(ConstantBufferPerObject) + 255) & ~255; ConstantBufferPerObject cbPerObject; ID3D12Resource* constantBufferUploadHeaps[frameBufferCount]; uint8* cbvGPUAddress[frameBufferCount]; XMFLOAT4X4 cameraProjMat; XMFLOAT4X4 cameraViewMat; XMFLOAT4 cameraPosition; XMFLOAT4 cameraTarget; XMFLOAT4 cameraUp; XMFLOAT4X4 cube1WorldMat; XMFLOAT4X4 cube1RotMat; XMFLOAT4 cube1Position; XMFLOAT4X4 cube2WorldMat; XMFLOAT4X4 cube2RotMat; XMFLOAT4 cube2PositionOffset; int32 numCubeIndices; struct SThreadTest { uint8 DoWork() { for (SIZE_T i = 0; i < 100; ++i) { OutputDebugStringA("thread stuff\n"); } return 0; } }; struct SThreadTest2 { uint8 DoWork() { for (SIZE_T i = 0; i < 100; ++i) { OutputDebugStringA("thread stuff2\n"); } return 0; } }; int32 WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int32 nShowCmd) { using namespace Aberration::Memory; using namespace Aberration::OS; //default memory allocator, basically aligned malloc and aligned free IAllocator* allocator = GlobalAllocator; //allocate single int auto mem = TMemory::Allocate(allocator); //do something with memory mem //free single int TMemory::Free(allocator, mem); //allocate an array of 10 ints, non initialized auto array = TMemory::Allocate(allocator, 10); //do something with memory array //free array of ints TMemory::Free(allocator, array, 10); //allocate an array of 10 ints, initialized auto defaultinitedarray = TMemory::Allocate(allocator, 10, 7); //do something with memory defaultinitedarray //free array of ints TMemory::Free(allocator, defaultinitedarray, 10); Aberration::OS::FThread::FMainFunctionType ThreadMain; SThreadTest ThreadTest; ThreadMain.Bind(&ThreadTest); Aberration::OS::FThread::FMainFunctionType ThreadMain2; SThreadTest2 ThreadTest2; ThreadMain2.Bind(&ThreadTest2); //FThread TestThread; //auto err = TestThread.Create(ThreadMain, "test", 0); //FThread TestThread2; //err = TestThread2.Create(ThreadMain2, "test2", 0); /*for (SIZE_T i = 0; i < 100; ++i) { OutputDebugStringA("main thread\n"); } */ if (!InitializeWindow(hInstance, nShowCmd, FullScreen)) { MessageBox(0, L"Window Initialization - Failed", L"Error", MB_OK); return 1; } if (!InitD3D()) { MessageBox(0, L"Failed to initialize direct3d 12", L"Error", MB_OK); Cleanup(); return 1; } MSG msg = MSG(); while (Running) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } else { Update(); Render(); } } WaitForPreviousFrame(); CloseHandle(fenceEvent); Cleanup(); return 0; } bool InitializeWindow(HINSTANCE hInstance, int32 ShowWnd, bool fullscreen) { if (fullscreen) { HMONITOR hmon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); MONITORINFO mi = { sizeof(mi) }; GetMonitorInfo(hmon, &mi); Width = mi.rcMonitor.right - mi.rcMonitor.left; Height = mi.rcMonitor.bottom - mi.rcMonitor.top; } WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.cbClsExtra = NULL; wc.cbWndExtra = NULL; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2); wc.lpszMenuName = NULL; wc.lpszClassName = L"AberrationEngineWindowName"; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if (!RegisterClassEx(&wc)) { MessageBox(NULL, L"Error registering class", L"Error", MB_OK | MB_ICONERROR); return false; } hwnd = CreateWindowEx(NULL, L"AberrationEngineWindowName", L"Aberration Engine", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, Width, Height, NULL, NULL, hInstance, NULL); if (!hwnd) { MessageBox(NULL, L"Error creating window", L"Error", MB_OK | MB_ICONERROR); return false; } if (fullscreen) { SetWindowLong(hwnd, GWL_STYLE, 0); } ShowWindow(hwnd, ShowWnd); UpdateWindow(hwnd); return true; } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_KEYDOWN: if (wParam == VK_ESCAPE) { if (MessageBox(0, L"Are you sure you want to exit?", L"Really?", MB_YESNO | MB_ICONQUESTION) == IDYES) { Running = false; DestroyWindow(hwnd); } } return 0; case WM_DESTROY: Running = false; PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); } bool InitD3D() { IDXGIFactory4* dxgiFactory; auto hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)); if (FAILED(hr)) { return false; } IDXGIAdapter1* adapter; int32 adapterIndex = 0; bool adapterFound = false; while (dxgiFactory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND) { DXGI_ADAPTER_DESC1 desc; adapter->GetDesc1(&desc); if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) { adapterIndex++; continue; } auto hresult = D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr); if (SUCCEEDED(hresult)) { adapterFound = true; break; } adapterIndex++; } if (!adapterFound) { return false; } { // Create the device auto res = D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device)); if (FAILED(res)) { return false; } } D3D12_COMMAND_QUEUE_DESC cqDesc = {}; cqDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; cqDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; if (FAILED(device->CreateCommandQueue(&cqDesc, IID_PPV_ARGS(&commandQueue)))) { return false; } DXGI_MODE_DESC backBufferDesc = {}; backBufferDesc.Width = Width; backBufferDesc.Height = Height; backBufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; swapChainDesc.BufferCount = frameBufferCount; swapChainDesc.BufferDesc = backBufferDesc; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapChainDesc.OutputWindow = hwnd; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.Windowed = !FullScreen; IDXGISwapChain* tempSwapChain; dxgiFactory->CreateSwapChain(commandQueue, &swapChainDesc, &tempSwapChain); swapChain = static_cast(tempSwapChain); frameIndex = swapChain->GetCurrentBackBufferIndex(); D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = D3D12_DESCRIPTOR_HEAP_DESC(); rtvHeapDesc.NumDescriptors = frameBufferCount; rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; hr = device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&rtvDescriptorHeap)); if (FAILED(hr)) { return false; } rtvDescriptorSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle(rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart()); for (SIZE_T i = 0; i < frameBufferCount; i++) { hr = swapChain->GetBuffer((UINT)i, IID_PPV_ARGS(&renderTargets[i])); if (FAILED(hr)) { return false; } device->CreateRenderTargetView(renderTargets[i], nullptr, rtvHandle); rtvHandle.ptr += 1 * rtvDescriptorSize; } for (SIZE_T i = 0; i < frameBufferCount; i++) { if (FAILED(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator[i])))) { return false; } } if (FAILED(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator[frameIndex], NULL, IID_PPV_ARGS(&commandList)))) { return false; } for (SIZE_T i = 0; i < frameBufferCount; i++) { hr = device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence[i])); if (FAILED(hr)) { return false; } fenceValue[i] = 0; } fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (fenceEvent == nullptr) { return false; } D3D12_ROOT_DESCRIPTOR rootCBVDescriptor; rootCBVDescriptor.RegisterSpace = 0; rootCBVDescriptor.ShaderRegister = 0; D3D12_ROOT_PARAMETER rootParameters[1]; rootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; rootParameters[0].Descriptor = rootCBVDescriptor; rootParameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = D3D12_ROOT_SIGNATURE_DESC(); rootSignatureDesc.NumParameters = _countof(rootParameters); rootSignatureDesc.pParameters = rootParameters; rootSignatureDesc.NumStaticSamplers = 0; rootSignatureDesc.pStaticSamplers = nullptr; rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS; ID3DBlob* signature; if (FAILED(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, nullptr))) { return false; } if (FAILED(device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&rootSignature)))) { return false; } ID3DBlob* vertexShader; ID3DBlob* errorBuff; hr = D3DCompileFromFile(L"BaseShader.vs.hlsl", nullptr, nullptr, "main", "vs_5_0", D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION, 0, &vertexShader, &errorBuff); if (FAILED(hr)) { OutputDebugStringA((LPCSTR)errorBuff->GetBufferPointer()); return false; } D3D12_SHADER_BYTECODE vertexShaderBytecode = {}; vertexShaderBytecode.BytecodeLength = vertexShader->GetBufferSize(); vertexShaderBytecode.pShaderBytecode = vertexShader->GetBufferPointer(); // compile pixel shader ID3DBlob* pixelShader; hr = D3DCompileFromFile(L"BaseShader.ps.hlsl", nullptr, nullptr, "main", "ps_5_0", D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION, 0, &pixelShader, &errorBuff); if (FAILED(hr)) { OutputDebugStringA((LPCSTR)errorBuff->GetBufferPointer()); return false; } D3D12_SHADER_BYTECODE pixelShaderBytecode = {}; pixelShaderBytecode.BytecodeLength = pixelShader->GetBufferSize(); pixelShaderBytecode.pShaderBytecode = pixelShader->GetBufferPointer(); 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_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; D3D12_INPUT_LAYOUT_DESC inputLayoutDesc = {}; inputLayoutDesc.NumElements = sizeof(inputLayout) / sizeof(D3D12_INPUT_ELEMENT_DESC); inputLayoutDesc.pInputElementDescs = inputLayout; D3D12_RASTERIZER_DESC rasterDesc = D3D12_RASTERIZER_DESC(); rasterDesc.FillMode = D3D12_FILL_MODE_SOLID; rasterDesc.CullMode = D3D12_CULL_MODE_BACK; rasterDesc.FrontCounterClockwise = FALSE; rasterDesc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS; rasterDesc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP; rasterDesc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; rasterDesc.DepthClipEnable = TRUE; rasterDesc.MultisampleEnable = FALSE; rasterDesc.AntialiasedLineEnable = FALSE; rasterDesc.ForcedSampleCount = 0; rasterDesc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; D3D12_BLEND_DESC blendDesc = D3D12_BLEND_DESC(); blendDesc.IndependentBlendEnable = FALSE; const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = { FALSE,FALSE, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, D3D12_LOGIC_OP_NOOP, D3D12_COLOR_WRITE_ENABLE_ALL, }; for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) { blendDesc.RenderTarget[i] = defaultRenderTargetBlendDesc; } D3D12_DEPTH_STENCIL_DESC dsDesc = D3D12_DEPTH_STENCIL_DESC(); dsDesc.DepthEnable = TRUE; dsDesc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; dsDesc.DepthFunc = D3D12_COMPARISON_FUNC_LESS; dsDesc.StencilEnable = FALSE; dsDesc.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK; dsDesc.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK; const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp = { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS }; dsDesc.FrontFace = defaultStencilOp; dsDesc.BackFace = defaultStencilOp; D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = inputLayoutDesc; psoDesc.pRootSignature = rootSignature; psoDesc.VS = vertexShaderBytecode; psoDesc.PS = pixelShaderBytecode; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; psoDesc.SampleDesc.Count = 1; psoDesc.SampleMask = 0xffffffff; psoDesc.RasterizerState = rasterDesc; psoDesc.BlendState = blendDesc; psoDesc.NumRenderTargets = 1; psoDesc.DepthStencilState = dsDesc; // create the pso if (FAILED(device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipelineStateObject)))) { return false; } Vertex vList[] = { // front face { -0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f }, { 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 1.0f, 1.0f }, { -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f }, { 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f }, // right side face { 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f }, { 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 1.0f }, { 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f }, { 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f }, // left side face { -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f }, { -0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 1.0f, 1.0f }, { -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f }, { -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f }, // back face { 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f }, { -0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 1.0f }, { 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f }, { -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f }, // top face { -0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f }, { 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 1.0f }, { 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f }, { -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f }, // bottom face { 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f }, { -0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 1.0f, 1.0f }, { 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f }, { -0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f }, }; int32 vBufferSize = sizeof(vList); D3D12_HEAP_PROPERTIES heapProps = D3D12_HEAP_PROPERTIES(); heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; heapProps.CreationNodeMask = 1; heapProps.VisibleNodeMask = 1; D3D12_RESOURCE_DESC bufferResourceDesc = D3D12_RESOURCE_DESC(); bufferResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; bufferResourceDesc.Alignment = 0; bufferResourceDesc.Width = vBufferSize; bufferResourceDesc.Height = 1; bufferResourceDesc.DepthOrArraySize = 1; bufferResourceDesc.MipLevels = 1; bufferResourceDesc.Format = DXGI_FORMAT_UNKNOWN; bufferResourceDesc.SampleDesc.Count = 1; bufferResourceDesc.SampleDesc.Quality = 0; bufferResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; bufferResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &bufferResourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&vertexBuffer)); vertexBuffer->SetName(L"Vertex Buffer Resource Heap"); ID3D12Resource* vBufferUploadHeap; heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &bufferResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&vBufferUploadHeap)); vBufferUploadHeap->SetName(L"Vertex Buffer Upload Resource Heap"); D3D12_SUBRESOURCE_DATA vertexData = {}; vertexData.pData = reinterpret_cast(vList); vertexData.RowPitch = vBufferSize; vertexData.SlicePitch = vBufferSize; UpdateSubresources(commandList, vertexBuffer, vBufferUploadHeap, 0, 0, 1, &vertexData); D3D12_RESOURCE_BARRIER barrier = D3D12_RESOURCE_BARRIER(); barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Transition.pResource = vertexBuffer; barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; commandList->ResourceBarrier(1, &barrier); DWORD iList[] = { // ffront face 0, 1, 2, // first triangle 0, 3, 1, // second triangle // left face 4, 5, 6, // first triangle 4, 7, 5, // second triangle // right face 8, 9, 10, // first triangle 8, 11, 9, // second triangle // back face 12, 13, 14, // first triangle 12, 15, 13, // second triangle // top face 16, 17, 18, // first triangle 16, 19, 17, // second triangle // bottom face 20, 21, 22, // first triangle 20, 23, 21, // second triangle }; int32 iBufferSize = sizeof(iList); numCubeIndices = sizeof(iList) / sizeof(DWORD); D3D12_RESOURCE_DESC indexBufferResourceDesc = D3D12_RESOURCE_DESC(); indexBufferResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; indexBufferResourceDesc.Alignment = 0; indexBufferResourceDesc.Width = iBufferSize; indexBufferResourceDesc.Height = 1; indexBufferResourceDesc.DepthOrArraySize = 1; indexBufferResourceDesc.MipLevels = 1; indexBufferResourceDesc.Format = DXGI_FORMAT_UNKNOWN; indexBufferResourceDesc.SampleDesc.Count = 1; indexBufferResourceDesc.SampleDesc.Quality = 0; indexBufferResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; indexBufferResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &indexBufferResourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&indexBuffer)); vertexBuffer->SetName(L"Index Buffer Resource Heap"); ID3D12Resource* iBufferUploadHeap; heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &bufferResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&iBufferUploadHeap)); vBufferUploadHeap->SetName(L"Index Buffer Upload Resource Heap"); D3D12_SUBRESOURCE_DATA indexData = {}; indexData.pData = reinterpret_cast(iList); indexData.RowPitch = iBufferSize; indexData.SlicePitch = iBufferSize; UpdateSubresources(commandList, indexBuffer, iBufferUploadHeap, 0, 0, 1, &indexData); D3D12_RESOURCE_BARRIER indexBufferBarrier = D3D12_RESOURCE_BARRIER(); indexBufferBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; indexBufferBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; indexBufferBarrier.Transition.pResource = indexBuffer; indexBufferBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; indexBufferBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; indexBufferBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; commandList->ResourceBarrier(1, &indexBufferBarrier); D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {}; dsvHeapDesc.NumDescriptors = 1; dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; if (FAILED(device->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(&dsDescriptorHeap)))) { Running = false; } D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilDesc = {}; depthStencilDesc.Format = DXGI_FORMAT_D32_FLOAT; depthStencilDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; depthStencilDesc.Flags = D3D12_DSV_FLAG_NONE; D3D12_CLEAR_VALUE depthOptimizedClearValue = {}; depthOptimizedClearValue.Format = DXGI_FORMAT_D32_FLOAT; depthOptimizedClearValue.DepthStencil.Depth = 1.0f; depthOptimizedClearValue.DepthStencil.Stencil = 0; D3D12_RESOURCE_DESC depthstencilResourceDesc = D3D12_RESOURCE_DESC(); depthstencilResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; depthstencilResourceDesc.Alignment = 0; depthstencilResourceDesc.Width = Width; depthstencilResourceDesc.Height = Height; depthstencilResourceDesc.DepthOrArraySize = 1; depthstencilResourceDesc.MipLevels = 0; depthstencilResourceDesc.Format = DXGI_FORMAT_D32_FLOAT; depthstencilResourceDesc.SampleDesc.Count = 1; depthstencilResourceDesc.SampleDesc.Quality = 0; depthstencilResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; depthstencilResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &depthstencilResourceDesc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &depthOptimizedClearValue, IID_PPV_ARGS(&depthStencilBuffer)); dsDescriptorHeap->SetName(L"Depth/Stencil Resource Heap"); device->CreateDepthStencilView(depthStencilBuffer, &depthStencilDesc, dsDescriptorHeap->GetCPUDescriptorHandleForHeapStart()); for (int32 i = 0; i < frameBufferCount; ++i) { D3D12_RESOURCE_DESC constantBufferResourceDesc = D3D12_RESOURCE_DESC(); constantBufferResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; constantBufferResourceDesc.Alignment = 0; constantBufferResourceDesc.Width = 1024 * 64; constantBufferResourceDesc.Height = 1; constantBufferResourceDesc.DepthOrArraySize = 1; constantBufferResourceDesc.MipLevels = 1; constantBufferResourceDesc.Format = DXGI_FORMAT_UNKNOWN; constantBufferResourceDesc.SampleDesc.Count = 1; constantBufferResourceDesc.SampleDesc.Quality = 0; constantBufferResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; constantBufferResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; hr = device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &constantBufferResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&constantBufferUploadHeaps[i])); constantBufferUploadHeaps[i]->SetName(L"Constant Buffer Upload Resource Heap"); ZeroMemory(&cbPerObject, sizeof(cbPerObject)); D3D12_RANGE readRange = D3D12_RANGE(); readRange.Begin = 0; readRange.End = 0; hr = constantBufferUploadHeaps[i]->Map(0, &readRange, reinterpret_cast(&cbvGPUAddress[i])); memcpy(cbvGPUAddress[i], &cbPerObject, sizeof(cbPerObject)); memcpy(cbvGPUAddress[i] + ConstantBufferPerObjectAlignedSize, &cbPerObject, sizeof(cbPerObject)); } commandList->Close(); ID3D12CommandList* ppCommandLists[] = { commandList }; commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); fenceValue[frameIndex]++; hr = commandQueue->Signal(fence[frameIndex], fenceValue[frameIndex]); if (FAILED(hr)) { Running = false; } vertexBufferView.BufferLocation = vertexBuffer->GetGPUVirtualAddress(); vertexBufferView.StrideInBytes = sizeof(Vertex); vertexBufferView.SizeInBytes = vBufferSize; indexBufferView.BufferLocation = indexBuffer->GetGPUVirtualAddress(); indexBufferView.Format = DXGI_FORMAT_R32_UINT; indexBufferView.SizeInBytes = iBufferSize; viewport.TopLeftX = 0; viewport.TopLeftY = 0; viewport.Width = (FLOAT)Width; viewport.Height = (FLOAT)Height; viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; scissorRect.left = 0; scissorRect.top = 0; scissorRect.right = (LONG)Width; scissorRect.bottom = (LONG)Height; XMMATRIX tmpMat = XMMatrixPerspectiveFovLH(45.0f*(3.14f / 180.0f), (float)Width / (float)Height, 0.1f, 1000.0f); XMStoreFloat4x4(&cameraProjMat, tmpMat); cameraPosition = XMFLOAT4(0.0f, 2.0f, -4.0f, 0.0f); cameraTarget = XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f); cameraUp = XMFLOAT4(0.0f, 1.0f, 0.0f, 0.0f); XMVECTOR cPos = XMLoadFloat4(&cameraPosition); XMVECTOR cTarg = XMLoadFloat4(&cameraTarget); XMVECTOR cUp = XMLoadFloat4(&cameraUp); tmpMat = XMMatrixLookAtLH(cPos, cTarg, cUp); XMStoreFloat4x4(&cameraViewMat, tmpMat); // first cube cube1Position = XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f); XMVECTOR posVec = XMLoadFloat4(&cube1Position); tmpMat = XMMatrixTranslationFromVector(posVec); XMStoreFloat4x4(&cube1RotMat, XMMatrixIdentity()); XMStoreFloat4x4(&cube1WorldMat, tmpMat); // second cube cube2PositionOffset = XMFLOAT4(1.5f, 0.0f, 0.0f, 0.0f); posVec = XMLoadFloat4(&cube2PositionOffset) + XMLoadFloat4(&cube1Position); tmpMat = XMMatrixTranslationFromVector(posVec); XMStoreFloat4x4(&cube2RotMat, XMMatrixIdentity()); XMStoreFloat4x4(&cube2WorldMat, tmpMat); return true; } void Update() { XMMATRIX rotXMat = XMMatrixRotationX(0.0001f); XMMATRIX rotYMat = XMMatrixRotationY(0.0002f); XMMATRIX rotZMat = XMMatrixRotationZ(0.0003f); XMMATRIX rotMat = XMLoadFloat4x4(&cube1RotMat) * rotXMat * rotYMat * rotZMat; XMStoreFloat4x4(&cube1RotMat, rotMat); XMMATRIX translationMat = XMMatrixTranslationFromVector(XMLoadFloat4(&cube1Position)); XMMATRIX worldMat = rotMat * translationMat; XMStoreFloat4x4(&cube1WorldMat, worldMat); XMMATRIX viewMat = XMLoadFloat4x4(&cameraViewMat); XMMATRIX projMat = XMLoadFloat4x4(&cameraProjMat); XMMATRIX wvpMat = XMLoadFloat4x4(&cube1WorldMat) * viewMat * projMat; XMMATRIX transposed = XMMatrixTranspose(wvpMat); XMStoreFloat4x4(&cbPerObject.wvpMat, transposed); memcpy(cbvGPUAddress[frameIndex], &cbPerObject, sizeof(cbPerObject)); rotXMat = XMMatrixRotationX(0.0003f); rotYMat = XMMatrixRotationY(0.0002f); rotZMat = XMMatrixRotationZ(0.0001f); rotMat = rotZMat * (XMLoadFloat4x4(&cube2RotMat) * (rotXMat * rotYMat)); XMStoreFloat4x4(&cube2RotMat, rotMat); XMMATRIX translationOffsetMat = XMMatrixTranslationFromVector(XMLoadFloat4(&cube2PositionOffset)); XMMATRIX scaleMat = XMMatrixScaling(0.5f, 0.5f, 0.5f); worldMat = scaleMat * translationOffsetMat * rotMat * translationMat; wvpMat = XMLoadFloat4x4(&cube2WorldMat) * viewMat * projMat; transposed = XMMatrixTranspose(wvpMat); XMStoreFloat4x4(&cbPerObject.wvpMat, transposed); memcpy(cbvGPUAddress[frameIndex] + ConstantBufferPerObjectAlignedSize, &cbPerObject, sizeof(cbPerObject)); XMStoreFloat4x4(&cube2WorldMat, worldMat); } void UpdatePipeline() { HRESULT hr; WaitForPreviousFrame(); if (FAILED(commandAllocator[frameIndex]->Reset())) { Running = false; } hr = commandList->Reset(commandAllocator[frameIndex], pipelineStateObject); if (FAILED(hr)) { Running = false; } D3D12_RESOURCE_BARRIER renderTargetsBarrier = D3D12_RESOURCE_BARRIER(); renderTargetsBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; renderTargetsBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; renderTargetsBarrier.Transition.pResource = renderTargets[frameIndex]; renderTargetsBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; renderTargetsBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; renderTargetsBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; commandList->ResourceBarrier(1, &renderTargetsBarrier); D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle(rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart()); rtvHandle.ptr += (int32)frameIndex * rtvDescriptorSize; D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle(dsDescriptorHeap->GetCPUDescriptorHandleForHeapStart()); commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle); const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f }; commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr); commandList->ClearDepthStencilView(dsDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); commandList->SetGraphicsRootSignature(rootSignature); commandList->RSSetViewports(1, &viewport); commandList->RSSetScissorRects(1, &scissorRect); commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); commandList->IASetVertexBuffers(0, 1, &vertexBufferView); commandList->IASetIndexBuffer(&indexBufferView); //first cube commandList->SetGraphicsRootConstantBufferView(0, constantBufferUploadHeaps[frameIndex]->GetGPUVirtualAddress()); commandList->DrawIndexedInstanced(numCubeIndices, 1, 0, 0, 0); //second cube commandList->SetGraphicsRootConstantBufferView(0, constantBufferUploadHeaps[frameIndex]->GetGPUVirtualAddress() + ConstantBufferPerObjectAlignedSize); commandList->DrawIndexedInstanced(numCubeIndices, 1, 0, 0, 0); D3D12_RESOURCE_BARRIER presentBarrier = D3D12_RESOURCE_BARRIER(); presentBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; presentBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; presentBarrier.Transition.pResource = renderTargets[frameIndex]; presentBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; presentBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; presentBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; commandList->ResourceBarrier(1, &presentBarrier); hr = commandList->Close(); if (FAILED(hr)) { Running = false; } } void Render() { UpdatePipeline(); ID3D12CommandList* ppCommandLists[] = { commandList }; commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); auto hr = commandQueue->Signal(fence[frameIndex], fenceValue[frameIndex]); if (FAILED(hr)) { Running = false; } hr = swapChain->Present(0, 0); if (FAILED(hr)) { Running = false; } } void Cleanup() { for (SIZE_T i = 0; i < frameBufferCount; ++i) { frameIndex = i; WaitForPreviousFrame(); } BOOL fs = false; if (swapChain->GetFullscreenState(&fs, NULL)) { swapChain->SetFullscreenState(false, NULL); } SAFE_RELEASE(swapChain); SAFE_RELEASE(commandQueue); SAFE_RELEASE(rtvDescriptorHeap); SAFE_RELEASE(commandList); for (SIZE_T i = 0; i < frameBufferCount; ++i) { SAFE_RELEASE(renderTargets[i]); SAFE_RELEASE(commandAllocator[i]); SAFE_RELEASE(fence[i]); }; SAFE_RELEASE(pipelineStateObject); SAFE_RELEASE(rootSignature); SAFE_RELEASE(vertexBuffer); SAFE_RELEASE(indexBuffer); SAFE_RELEASE(depthStencilBuffer); SAFE_RELEASE(dsDescriptorHeap); for (SIZE_T i = 0; i < frameBufferCount; ++i) { SAFE_RELEASE(constantBufferUploadHeaps[i]); }; } void WaitForPreviousFrame() { frameIndex = swapChain->GetCurrentBackBufferIndex(); if (fence[frameIndex]->GetCompletedValue() < fenceValue[frameIndex]) { auto hr = fence[frameIndex]->SetEventOnCompletion(fenceValue[frameIndex], fenceEvent); if (FAILED(hr)) { Running = false; } WaitForSingleObject(fenceEvent, INFINITE); } fenceValue[frameIndex]++; }