前些天想根据DX11的SDk自己写一个最简单的Direct Compute,中间又病倒了,耽搁了这些天昨晚才调好,鉴于网上太少dx11的学习资料了,总结下。
首先要说的是我的改写版本主要是为了代码上的简明,去掉了很多硬件检测,以便迅速明白dx11的Direct Compute的架构,所以在很多人的机器上怕一时还运行不了,这个可以先明白基本架构后再进行向下兼容。
首先说下Directx11的存储读写模型。在Dx11的硬件中主要用buffer存储数据,device来进行计算,shader resource view和unordered access view来作为前两者沟通的桥梁 也就是device通过shader resource view来读buffer,通过unordereed access view来读写buffer。
我们要实现的功能是将CPU中的数据读写入GPU,然后在GPU中执行简单的计算:将两个buffer的数据相加到另一个buffer,再读回到CPU中以验证。在GPU中主要执行的计算是
struct BufType
{
int i;
float f;
};
BufferOut[DTid.x].i = Buffer0[DTid.x].i+Buffer1[DTid.x].i;
BufferOut[DTid.x].f = Buffer0[DTid.x].f+Buffer1[DTid.x].f;
下面集中讲解下DX11的代码,虽然有点繁琐,但是记住我们的工作关键点大部分是一一依次初始化上面说的三个存储模型ID3D11Device,ID3D11Buffer,ID3D11ShaderResourceView,ID3D11UnorderedAccessView就可以抓住关键不会乱了。
#include<stdio.h>
#include<crtdbg.h>
#include <d3dcommon.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <d3dx11.h>
#include<iostream>
#include <algorithm>
using namespace std;
#define SAFE_RELEASE(p) {if(p){(p)->Release();(p)=NULL;}}
const UINT NUM_ELEMENTS=512;
//为了程序易读性,全局声明所有的函数
//1-创建D3d11的设备
HRESULT CreateComputeDevice(ID3D11Device** ppDeviceOut,ID3D11DeviceContext** ppContextDeviceOut);
//2-编译HLSL程序以生成computeShader接口:主要调用D3DX11CompileFromFile(),ID3D11Device::CreateComputeShader()
HRESULT CreateComputeShader(LPCWSTR pSrcFile,LPCSTR pFunctionName,ID3D11Device* pDevice,ID3D11ComputeShader** ppShaderOut);
//3-根据CPU中的数据void* pInitData创建GPU中的structure buffer:主要调用ID3D11Device::CreateBuffer()
HRESULT CreateStructureBuffer(ID3D11Device* gDevice,UINT elementSize,UINT uCount,void* gInitData,ID3D11Buffer** ppBufferOut);
//4-创建ShaderResourceView,让GPU能够读取相应的buffer:主要调用ID3D11Device::CreateShaderResourceView()
HRESULT CreateBufferSRV(ID3D11Device* pDevice,ID3D11Buffer* pBuffer,ID3D11ShaderResourceView** ppSRVOut);
//5-创建UnorderAccessView,让GPU能够读取和写入相应的buffer:主要调用ID3D11Device::CreateUnorderedAccessView()
HRESULT CreateBufferUAV(ID3D11Device* pDevice,ID3D11Buffer* pBuffer,ID3D11UnorderedAccessView** ppUAVOut);
//6-运行Compute Shader的程序
void RunComputeShader(ID3D11DeviceContext* pImmediateContext,ID3D11ComputeShader* pComputeShader,UINT nNumViews,ID3D11ShaderResourceView** pShaderResourceViews,ID3D11UnorderedAccessView* pUnorderedView,
UINT X,UINT Y,UINT Z);
//7-将GPU输出的Buffer拷贝回CPU中,以检验运算结果:主要调用ID3D11DeviceContext::CopyResource();
ID3D11Buffer* CreateAndCopyToDebugBuf(ID3D11Device* pDevice,ID3D11DeviceContext* pd3dImmediateContext,ID3D11Buffer* pBuffer);
//声明和定义全局变量
//与设备相关的指针借口
ID3D11Device* g_pDevice=NULL;
ID3D11DeviceContext* g_pContext=NULL;
ID3D11ComputeShader* g_pCS=NULL;
//各个Buffer指针变量
ID3D11Buffer* g_pBuffer0=NULL;
ID3D11Buffer* g_pBuffer1=NULL;
ID3D11Buffer* g_pBufferResult=NULL;
//读写上面buffer的ID3D11ShaderResourceView和UnorderedAccessView接口
ID3D11ShaderResourceView* g_pBuf0SRV=NULL;
ID3D11ShaderResourceView* g_pBuf1SRV=NULL;
ID3D11UnorderedAccessView* g_pBufResultUAV=NULL;
struct BufType
{
int i;
float f;
};
BufType g_vBuf0[NUM_ELEMENTS];
BufType g_vBuf1[NUM_ELEMENTS];
int main()
{
//在debug模式下,开启run-time时的内存检查
#if defined(DEBUG)||defined(_DEBUG)
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
#endif
cout<<"创建设备"<<endl;
if(FAILED(CreateCompute