当前位置:首页 > 软件下载 > windows10 > 正文

使用纯C语言开发简单的Direct3D 12应用

来源:360圈   发布时间:2016-10-28 13:37:03 | 浏览次数: | 关键词:lpVtbl-,D3D12,if,NULL
热门标签:360社区 MM交友 棋牌游戏 情感美文 360圈游戏 360交友

由于微软官方给出的D3D12的demo都经过C++层层封装,即便是很简单的画三角形的程序都显得比较复杂。因此笔者这里就用纯C语言来改写画三角形的简单D3D12应用程序。这里面不包含任何已被废弃的D3DX的库,所以可以直接拿来使用。

各位要做的准备工作是,先要有一部装有Windows 10的PC。然后,在上面安装Visual Studio 2015开发环境,笔者这里用的是微软免费的Visual Studio 2015 Express Edition for Desktop,可支持部分C99语法特性,这会使得C语言代码更为精简~

安装完成之后,各位能够在安装目录中看到,除了Visual Studio 2015之外,还出现了Windows Kit,这里面就已经包含了Direct3D所需要的所有头文件以及库文件。

我们首先创建一个名为Direct3D12Test的工程,然后选择Win32 Application,不需要勾选SDL选项。然后,在项目选项中C/C++一栏下的General中,Additional Included Directories一栏输入D3D12所需要的头文件路径,笔者系统下是:C:\Program Files (x86)\Windows Kits\10\Include\10.0.14393.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.14393.0\shared

分号左边的路径是d3d12.h所在的目录;分号右边是dxgi相关的头文件所在的目录。

随后在Linker下的Additional Library Directories中输入我们所要连接的d3d12库文件所在的路径,笔者系统下是:C:\Program Files (x86)\Windows Kits\10\Lib\10.0.14393.0\um\x64

然后在Input一栏的Additional Dependencies中添加d3d12.lib;dxguid.lib;dxgi.lib;d3dcompiler.lib;

以上这些就是我们需要连接的静态库。然后,我们将Debug旁边的x86改为x64,也就是说,我们这里将构建64位应用程序。

接下来,我们把IDE自动生成的Direct3D12Test.cpp源文件先暂时移除,然后将文件名后缀改为.c,然后再添加到工程中去。

最后,我们在项目工程选项中,找到C/C++一栏下的Precompiled Header,我们将这里面的Precompiled Header选项改为Not Using Precompiled Headers。如果开启这个选项,由于在项目之前自动构建的时候用的是C++,我们再使用C源文件就会报错。完成之后,我们就可以用以下代码来替换掉原来该源文件中的内容了:

// Direct3D12Test.c : Defines the entry point for the application.

// 这是一个C语言源文件

#include "stdafx.h"

#include "Direct3D12Test.h"

#include#include#include#include#include#define MAX_LOADSTRING 100

// Global Variables:

static HINSTANCE hInst; // current instance

static WCHAR szTitle[MAX_LOADSTRING]; // The title bar text

static WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name

// Forward declarations of functions included in this code module:

static ATOM MyRegisterClass(HINSTANCE hInstance);

static HWND InitInstance(HINSTANCE, int);

static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

static INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);

static const int s_windowWidth = 640;

static const int s_windowHeight = 480;

#define FRAME_COUNT 2

// Pipeline objects.

static D3D12_VIEWPORT s_viewport;

static D3D12_RECT s_scissorRect;

static IDXGISwapChain3 *s_swapChain;

static ID3D12Device *s_device;

static ID3D12Resource *s_renderTargets[FRAME_COUNT];

static ID3D12CommandAllocator *s_commandAllocator;

static ID3D12CommandQueue *s_commandQueue;

static ID3D12RootSignature *s_rootSignature;

static ID3D12DescriptorHeap *s_rtvHeap;

static ID3D12PipelineState *s_pipelineState;

static ID3D12GraphicsCommandList *s_commandList;

static uint32_t s_rtvDescriptorSize;

// App resources.

static ID3D12Resource *s_vertexBuffer;

static D3D12_VERTEX_BUFFER_VIEW s_vertexBufferView;

// Synchronization objects.

static uint32_t s_frameIndex;

static HANDLE s_fenceEvent;

static ID3D12Fence *s_fence;

static uint64_t s_fenceValue;

// 自己定制是否使用warp device

static const bool s_useWarpDevice = true;

/**

加载渲染流水线

*/

static bool LoadPipeline(HWND hWnd)

{

// 我们这里采用调试模式

ID3D12Debug *debugController;

if (SUCCEEDED(D3D12GetDebugInterface(&IID_IDebug, &debugController)))

debugController->lpVtbl->EnableDebugLayer(debugController);

IDXGIFactory4 *factory;

if (CreateDXGIFactory1(&IID_IDXGIFactory4, &factory) lpVtbl->EnumWarpAdapter(factory, &IID_IDXGIAdapter, &warpAdapter) lpVtbl->EnumAdapters1(factory, i, &hardwareAdapter);

if (D3D12CreateDevice((IUnknown*)hardwareAdapter, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, &s_device) >= 0)

break;

hardwareAdapter->lpVtbl->Release(hardwareAdapter);

}

if (hardwareAdapter == NULL)

return false;

}

// Describe and create the command queue.

D3D12_COMMAND_QUEUE_DESC queueDesc = { 0 };

queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;

queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;

if (s_device->lpVtbl->CreateCommandQueue(s_device, &queueDesc, &IID_ID3D12CommandQueue, &s_commandQueue) lpVtbl->CreateSwapChain(factory, (IUnknown*)s_commandQueue, &swapChainDesc, &swapChain) lpVtbl->MakeWindowAssociation(factory, hWnd, DXGI_MWA_NO_ALT_ENTER) lpVtbl->GetCurrentBackBufferIndex(s_swapChain);

// Create descriptor heaps

// Describe and create a render target view (RTV) descriptor heap.

D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = { 0 };

rtvHeapDesc.NumDescriptors = FRAME_COUNT;

rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;

rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;

if (s_device->lpVtbl->CreateDescriptorHeap(s_device, &rtvHeapDesc, &IID_ID3D12DescriptorHeap, &s_rtvHeap) lpVtbl->GetDescriptorHandleIncrementSize(s_device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);

// Create frame resources

D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle;

s_rtvHeap->lpVtbl->GetCPUDescriptorHandleForHeapStart(s_rtvHeap, &rtvHandle);

// Create a RTV for each frame.

for (int n = 0; n lpVtbl->GetBuffer(s_swapChain, n, &IID_ID3D12Resource, &s_renderTargets[n]) lpVtbl->CreateRenderTargetView(s_device, s_renderTargets[n], NULL, rtvHandle);

rtvHandle.ptr += s_rtvDescriptorSize;

}

if (s_device->lpVtbl->CreateCommandAllocator(s_device, D3D12_COMMAND_LIST_TYPE_DIRECT, &IID_ID3D12CommandAllocator, &s_commandAllocator) lpVtbl->Signal(s_commandQueue, s_fence, fence) lpVtbl->GetCompletedValue(s_fence) lpVtbl->SetEventOnCompletion(s_fence, fence, s_fenceEvent) lpVtbl->GetCurrentBackBufferIndex(s_swapChain);

return true;

}

/**

加载本demo所需的物资

*/

static bool LoadAssets(void)

{

// Create an empty root signature.

D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = { 0, NULL, 0, NULL, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT };

ID3DBlob *signature;

ID3DBlob *error;

if (D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error) lpVtbl->CreateRootSignature(s_device, 0, signature->lpVtbl->GetBufferPointer(signature),

signature->lpVtbl->GetBufferSize(signature), &IID_ID3D12RootSignature, &s_rootSignature) lpVtbl->GetBufferPointer(vertexShader),

vertexShader->lpVtbl->GetBufferSize(vertexShader) };

psoDesc.PS = (D3D12_SHADER_BYTECODE) { pixelShader->lpVtbl->GetBufferPointer(pixelShader),

pixelShader->lpVtbl->GetBufferSize(pixelShader) };

// 使用默认的光栅化状态

psoDesc.RasterizerState = (D3D12_RASTERIZER_DESC) { D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_NONE, FALSE, 0, 0.0f, 0.0f,

TRUE, FALSE, FALSE, 0, D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF };

psoDesc.BlendState = (D3D12_BLEND_DESC) { FALSE, FALSE,

{ [0] = { FALSE, FALSE, D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD, D3D12_BLEND_ONE, D3D12_BLEND_ZERO,

D3D12_BLEND_OP_ADD, D3D12_LOGIC_OP_NOOP, D3D12_COLOR_WRITE_ENABLE_ALL } }

};

psoDesc.DepthStencilState.DepthEnable = FALSE;

psoDesc.DepthStencilState.StencilEnable = FALSE;

psoDesc.SampleMask = UINT32_MAX;

psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;

psoDesc.NumRenderTargets = 1;

psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;

psoDesc.SampleDesc.Count = 1;

if (s_device->lpVtbl->CreateGraphicsPipelineState(s_device, &psoDesc, &IID_ID3D12PipelineState, &s_pipelineState) lpVtbl->CreateCommandList(s_device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT, s_commandAllocator, s_pipelineState,

&IID_ID3D12GraphicsCommandList, &s_commandList) lpVtbl->Close(s_commandList) lpVtbl->CreateCommittedResource(s_device, &heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc,

D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &IID_ID3D12Resource, &s_vertexBuffer) lpVtbl->Map(s_vertexBuffer, 0, &readRange, &pVertexDataBegin) lpVtbl->Unmap(s_vertexBuffer, 0, NULL);

// Initialize the vertex buffer view.

s_vertexBufferView.BufferLocation = s_vertexBuffer->lpVtbl->GetGPUVirtualAddress(s_vertexBuffer);

s_vertexBufferView.StrideInBytes = sizeof(triangleVertices[0]);

s_vertexBufferView.SizeInBytes = (uint32_t)vertexBufferSize;

// Create synchronization objects and wait until assets have been uploaded to the GPU.

if (s_device->lpVtbl->CreateFence(s_device, 0, D3D12_FENCE_FLAG_NONE, &IID_ID3D12Fence, &s_fence) lpVtbl->Reset(s_commandAllocator) lpVtbl->Reset(s_commandList, s_commandAllocator, s_pipelineState) lpVtbl->SetGraphicsRootSignature(s_commandList, s_rootSignature);

s_commandList->lpVtbl->RSSetViewports(s_commandList, 1, &s_viewport);

s_commandList->lpVtbl->RSSetScissorRects(s_commandList, 1, &s_scissorRect);

// Indicate that the back buffer will be used as a render target.

D3D12_RESOURCE_BARRIER barrier = { D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE,

.Transition = {s_renderTargets[s_frameIndex], D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET} };

s_commandList->lpVtbl->ResourceBarrier(s_commandList, 1, &barrier);

D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle;

s_rtvHeap->lpVtbl->GetCPUDescriptorHandleForHeapStart(s_rtvHeap, &rtvHandle);

rtvHandle.ptr += s_frameIndex * s_rtvDescriptorSize;

s_commandList->lpVtbl->OMSetRenderTargets(s_commandList, 1, &rtvHandle, FALSE, NULL);

// Record commands.

const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };

s_commandList->lpVtbl->ClearRenderTargetView(s_commandList, rtvHandle, clearColor, 0, NULL);

s_commandList->lpVtbl->IASetPrimitiveTopology(s_commandList, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

s_commandList->lpVtbl->IASetVertexBuffers(s_commandList, 0, 1, &s_vertexBufferView);

s_commandList->lpVtbl->DrawInstanced(s_commandList, 3, 1, 0, 0);

// Indicate that the back buffer will now be used to present.

D3D12_RESOURCE_BARRIER barrier2 = { D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE,

.Transition = { s_renderTargets[s_frameIndex], D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT } };

s_commandList->lpVtbl->ResourceBarrier(s_commandList, 1, &barrier2);

if (s_commandList->lpVtbl->Close(s_commandList) lpVtbl->ExecuteCommandLists(s_commandQueue, _countof(ppCommandLists), ppCommandLists);

// Present the frame.

if (s_swapChain->lpVtbl->Present(s_swapChain, 1, 0) lpVtbl->Release(s_fence);

if (s_vertexBuffer != NULL)

s_vertexBuffer->lpVtbl->Release(s_vertexBuffer);

if (s_rootSignature != NULL)

s_rootSignature->lpVtbl->Release(s_rootSignature);

if (s_rtvHeap != NULL)

s_rtvHeap->lpVtbl->Release(s_rtvHeap);

for (int i = 0; i lpVtbl->Release(s_renderTargets[i]);

}

if (s_pipelineState != NULL)

s_pipelineState->lpVtbl->Release(s_pipelineState);

if (s_commandList != NULL)

s_commandList->lpVtbl->Release(s_commandList);

if (s_commandAllocator != NULL)

s_commandAllocator->lpVtbl->Release(s_commandAllocator);

if (s_commandQueue != NULL)

s_commandQueue->lpVtbl->Release(s_commandQueue);

if (s_swapChain != NULL)

s_swapChain->lpVtbl->Release(s_swapChain);

if (s_device != NULL)

s_device->lpVtbl->Release(s_device);

}

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,

_In_opt_ HINSTANCE hPrevInstance,

_In_ LPWSTR lpCmdLine,

_In_ int nCmdShow)

{

UNREFERENCED_PARAMETER(hPrevInstance);

UNREFERENCED_PARAMETER(lpCmdLine);

// TODO: Place code here.

// Initialize global strings

LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);

LoadStringW(hInstance, IDC_DIRECT3D12TEST, szWindowClass, MAX_LOADSTRING);

MyRegisterClass(hInstance);

// Perform application initialization:

HWND hWnd = InitInstance(hInstance, nCmdShow);

if (hWnd == NULL)

{

return FALSE;

}

HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_DIRECT3D12TEST));

// 初始化s_viewport与s_scissorRect对象

s_viewport.Width = (float)s_windowWidth;

s_viewport.Height = (float)s_windowHeight;

s_viewport.MaxDepth = 1.0f;

s_scissorRect.right = (long)s_windowWidth;

s_scissorRect.bottom = (long)s_windowHeight;

if (!LoadPipeline(hWnd))

return FALSE;

if (!LoadAssets())

return FALSE;

if (!Render())

return FALSE;

MSG msg;

// Main message loop:

while (GetMessage(&msg, NULL, 0, 0))

{

if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

return (int) msg.wParam;

}

//

// FUNCTION: MyRegisterClass()

//

// PURPOSE: Registers the window class.

//

ATOM MyRegisterClass(HINSTANCE hInstance)

{

WNDCLASSEXW wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;

wcex.lpfnWndProc = WndProc;

wcex.cbClsExtra = 0;

wcex.cbWndExtra = 0;

wcex.hInstance = hInstance;

wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DIRECT3D12TEST));

wcex.hCursor = LoadCursor(NULL, IDC_ARROW);

wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_DIRECT3D12TEST);

wcex.lpszClassName = szWindowClass;

wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassExW(&wcex);

}

//

// FUNCTION: InitInstance(HINSTANCE, int)

//

// PURPOSE: Saves instance handle and creates main window

//

// COMMENTS:

//

// In this function, we save the instance handle in a global variable and

// create and display the main program window.

//

HWND InitInstance(HINSTANCE hInstance, int nCmdShow)

{

hInst = hInstance; // Store instance handle in our global variable

HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, 0, s_windowWidth, s_windowHeight, NULL, NULL, hInstance, NULL);

if (!hWnd)

{

return NULL;

}

ShowWindow(hWnd, nCmdShow);

UpdateWindow(hWnd);

return hWnd;

}

//

// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)

//

// PURPOSE: Processes messages for the main window.

//

// WM_COMMAND - process the application menu

// WM_PAINT - Paint the main window

// WM_DESTROY - post a quit message and return

//

//

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

switch (message)

{

case WM_COMMAND:

{

int wmId = LOWORD(wParam);

// Parse the menu selections:

switch (wmId)

{

case IDM_ABOUT:

DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);

break;

case IDM_EXIT:

DestroyWindow(hWnd);

break;

default:

return DefWindowProc(hWnd, message, wParam, lParam);

}

}

break;

case WM_PAINT:

{

PAINTSTRUCT ps;

HDC hdc = BeginPaint(hWnd, &ps);

// TODO: Add any drawing code that uses hdc here...

// 我们这里再绘制一帧

if(s_pipelineState != NULL)

Render();

EndPaint(hWnd, &ps);

}

break;

case WM_DESTROY:

// 清除D3D相关的资源

CleanupResource();

PostQuitMessage(0);

break;

default:

return DefWindowProc(hWnd, message, wParam, lParam);

}

return 0;

}

// Message handler for about box.

INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)

{

UNREFERENCED_PARAMETER(lParam);

switch (message)

{

case WM_INITDIALOG:

return (INT_PTR)TRUE;

case WM_COMMAND:

if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)

{

EndDialog(hDlg, LOWORD(wParam));

return (INT_PTR)TRUE;

}

break;

}

return (INT_PTR)FALSE;

}

输入完成之后,我们可以在菜单栏File下面找到Advanced Save Options...,可以将Encoding改为Unicode(UTF-8 without Signature),这样我们就可以在所有操作系统上看到正常的中文汉字了。否则在不少系统上不支持GBK或GB2312,会导致汉字部分出现乱码。

下面这个文件就是绘制三角形时所需要的HLSL文件,我们不能直接将它们添加到工程中,因为IDE会自动编译它们,然后导致找不到main入口而出现连接错误。所以我们将这个文件存放到与上述源文件同一目录下即可,然后再将它复制到与我们最后生成的exe可执行文件的同一目录下,这样就可以直接点击加载应用了,而不需要通过Visual Studio来启动。该文件名为shaders.hlsl。

//*********************************************************

//

// 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.

//

//*********************************************************

struct PSInput

{

float4 position : SV_POSITION;

float4 color : COLOR;

};

PSInput VSMain(float4 position : POSITION, float4 color : COLOR)

{

PSInput result;

result.position = position;

result.color = color;

return result;

}

float4 PSMain(PSInput input) : SV_TARGET

{

return input.color;

}

全都完成之后,我们就可以编译构建应用,然后会自动弹出窗口显示一个彩色三角形了。我们还可以点击窗口放大按钮与还原按钮,这些操作都能正常显示。


转载请注明出处"360圈".本文网址:http://www.360quan.com/windows10/24213.html

相关标签搜索: lpVtbl- D3D12 if NULL

下一篇:最后一页
  • 热门评论
  • Zora头像
    Zora 2016年10月28日 15:21

    发表了博文《芜湖缇香婚纱摄影之韩式个性结婚请帖定制属于自己的请柬》想办好一场婚礼不仅要妥善安排好婚礼进程,作为最先映入宾客视线有关婚礼的物品

  • 穆清水头像
    穆清水 2016年10月28日 16:07

    其实每个人心里都有这样的人吧?那个可以NULL主宰你情感的人,那个让你失去理智的人,让你欲罢不能的人,你就是那么无可奈何的喜欢着。