我正在尝试在DirectX12中编写最简单的计算着色器,以便我可以为真实的项目提供一个起点。然而,似乎无论我做什么,我都无法让我的GPU处理“1+1”并看到输出。由于几乎没有关于计算着色器的文档,我认为现在唯一的选择就是查询StackOverflow。
我使用D3D12nBodyGravity项目编写了以下代码。首先,我尽可能逐字地复制代码,修复“小”的东西,然后一旦所有工作都正常,我就开始将代码削减到最基本的部分。我正在使用Visual Studio 2019。
myClass.cpp:
#include "pch.h"
#include "myClass.h"
#include <d3dcompiler.h> // D3DReadFileToBlob
#include "Common\DirectXHelper.h" // NAME_D3D12_OBJECT
#include "Common\Device.h"
#include <iostream>
// InterlockedCompareExchange returns the object's value if the
// comparison fails. If it is already 0, then its value won't
// change and 0 will be returned.
#define InterlockedGetValue(object) InterlockedCompareExchange(object, 0, 0)
myClass::myClass()
: m_frameIndex(0)
, m_UavDescriptorSize(0)
, m_renderContextFenceValue(0)
, m_frameFenceValues{} {
std::cout << "Initializing myClass" << std::endl;
m_FenceValue = 0;
//std::cout << "Calling DXGIDeclareAdapterRemovalSupport()" << std::endl;
//DX::ThrowIfFailed(DXGIDeclareAdapterRemovalSupport());
// Identify the device
std::cout << "Identifying the device" << std::endl;
auto m_device = Device::Get().GetDevice();
std::cout << "Leading the rendering pipeline dependencies" << std::endl;
// Load the rendering pipeline dependencies.
{
std::cout << " Creating the root signatures" << std::endl;
// Create the root signatures.
{
CD3DX12_ROOT_PARAMETER rootParameter;
rootParameter.InitAsUnorderedAccessView(0);
Microsoft::WRL::ComPtr<ID3DBlob> signature;
Microsoft::WRL::ComPtr<ID3DBlob> error;
CD3DX12_ROOT_SIGNATURE_DESC computeRootSignatureDesc(1, &rootParameter, 0, nullptr);
DX::ThrowIfFailed(D3D12SerializeRootSignature(&computeRootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error));
DX::ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_computeRootSignature)));
}
// Describe and create the command queue.
std::cout << " Describing and creating the command queue" << std::endl;
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
DX::ThrowIfFailed(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue)));
NAME_D3D12_OBJECT(m_commandQueue);
std::cout << " Creating descriptor heaps" << std::endl;
// Create descriptor heaps.
{
// Describe and create a shader resource view (SRV) and unordered
// access view (UAV) descriptor heap.
D3D12_DESCRIPTOR_HEAP_DESC UavHeapDesc = {};
UavHeapDesc.NumDescriptors = DescriptorCount;
UavHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
UavHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
DX::ThrowIfFailed(m_device->CreateDescriptorHeap(&UavHeapDesc, IID_PPV_ARGS(&m_UavHeap)));
NAME_D3D12_OBJECT(m_UavHeap);
m_UavDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
std::cout << " Creating a command allocator for each frame" << std::endl;
// Create a command allocator for each frame.
for (UINT n = 0; n < FrameCount; n++) {
DX::ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocators[n])));
}
} // Load the rendering pipeline dependencies.
std::cout << "Loading the sample assets" << std::endl;
// Load the sample assets.
{
std::cout << " Creating the pipeline states, including compiling and loading shaders" << std::endl;
// Create the pipeline states, which includes compiling and loading shaders.
{
Microsoft::WRL::ComPtr<ID3DBlob> computeShader;
#if defined(_DEBUG)
// Enable better shader debugging with the graphics debugging tools.
UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
#else
UINT compileFlags = 0;
#endif
// Load and compile the compute shader.
DX::ThrowIfFailed(D3DReadFileToBlob(L"ComputeShader.cso", &computeShader));
auto convert_blob_to_byte = [](Microsoft::WRL::ComPtr<ID3DBlob> blob) {
auto* p = reinterpret_cast<unsigned char*>(blob->GetBufferPointer());
auto n = blob->GetBufferSize();
std::vector<unsigned char> buff;
buff.reserve(n);
std::copy(p, p + n, std::back_inserter(buff));
return buff;
};
std::vector<BYTE> m_computeShader = convert_blob_to_byte(computeShader);
// Describe and create the compute pipeline state object (PSO).
D3D12_COMPUTE_PIPELINE_STATE_DESC computePsoDesc = {};
computePsoDesc.pRootSignature = m_computeRootSignature.Get();
computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(computeShader.Get());
DX::ThrowIfFailed(m_device->CreateComputePipelineState(&computePsoDesc, IID_PPV_ARGS(&m_computeState)));
NAME_D3D12_OBJECT(m_computeState);
}
std::cout << " Creating the command list" << std::endl;
// Create the command list.
DX::ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[m_frameIndex].Get(), m_computeState.Get(), IID_PPV_ARGS(&m_commandList)));
NAME_D3D12_OBJECT(m_commandList);
std::cout << " Initializing the data in the buffers" << std::endl;
// Initialize the data in the buffers.
{
data.resize(2);
for (unsigned int i = 0; i < data.size(); i++) {
data[i] = 0.0f;
}
const UINT dataSize = data.size() * sizeof(data[0]);
D3D12_HEAP_PROPERTIES defaultHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
D3D12_HEAP_PROPERTIES uploadHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
D3D12_HEAP_PROPERTIES readbackHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK);
D3D12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(dataSize, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
D3D12_RESOURCE_DESC uploadBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(dataSize);
readbackBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(dataSize);
DX::ThrowIfFailed(m_device->CreateCommittedResource(
&defaultHeapProperties,
D3D12_HEAP_FLAG_NONE,
&bufferDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(&m_dataBuffer)));
m_dataBuffer.Get()->SetName(L"m_dataBuffer");
DX::ThrowIfFailed(m_device->CreateCommittedResource(
&uploadHeapProperties,
D3D12_HEAP_FLAG_NONE,
&uploadBufferDesc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&m_dataBufferUpload)));
m_dataBufferUpload.Get()->SetName(L"m_dataBufferUpload");
DX::ThrowIfFailed(m_device->CreateCommittedResource(
&readbackHeapProperties,
D3D12_HEAP_FLAG_NONE,
&readbackBufferDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(&m_dataBufferReadback)));
m_dataBufferReadback.Get()->SetName(L"m_dataBufferReadback");
NAME_D3D12_OBJECT(m_dataBuffer);
dataSubResource = {};
dataSubResource.pData = &data[0];
dataSubResource.RowPitch = dataSize;
dataSubResource.SlicePitch = dataSubResource.RowPitch;
UpdateSubresources<1>(m_commandList.Get(), m_dataBuffer.Get(), m_dataBufferUpload.Get(), 0, 0, 1, &dataSubResource);
m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_dataBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COMMON));
m_commandList->CopyResource(m_dataBufferReadback.Get(), m_dataBufferUpload.Get());
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
uavDesc.Format = DXGI_FORMAT_UNKNOWN;
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
uavDesc.Buffer.FirstElement = 0;
uavDesc.Buffer.NumElements = 1;
uavDesc.Buffer.StructureByteStride = sizeof(data[0]);
uavDesc.Buffer.CounterOffsetInBytes = 0;
uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
CD3DX12_CPU_DESCRIPTOR_HANDLE uavHandle0(m_UavHeap->GetCPUDescriptorHandleForHeapStart(), Uav, m_UavDescriptorSize);
m_device->CreateUnorderedAccessView(m_dataBuffer.Get(), nullptr, &uavDesc, uavHandle0);
} // Initialize the data in the buffers.
std::cout << " Closing the command list and executing it to begind the initial GPU setup" << std::endl;
// Close the command list and execute it to begin the initial GPU setup.
DX::ThrowIfFailed(m_commandList->Close());
ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
std::cout << " Creating synchronization objects and wait until assets have been uploaded to the GPU" << std::endl;
// Create synchronization objects and wait until assets have been uploaded to the GPU.
{
DX::ThrowIfFailed(m_device->CreateFence(m_renderContextFenceValue, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_renderContextFence)));
m_renderContextFenceValue++;
m_renderContextFenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (m_renderContextFenceEvent == nullptr) {
DX::ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()));
}
// Add a signal command to the queue.
DX::ThrowIfFailed(m_commandQueue->Signal(m_renderContextFence.Get(), m_renderContextFenceValue));
// Instruct the fence to set the event object when the signal command completes.
DX::ThrowIfFailed(m_renderContextFence->SetEventOnCompletion(m_renderContextFenceValue, m_renderContextFenceEvent));
m_renderContextFenceValue++;
// Wait until the signal command has been processed.
WaitForSingleObject(m_renderContextFenceEvent, INFINITE);
}
} // Load the sample assets.
std::cout << "Creating compute resources" << std::endl;
{
// Create compute resources.
D3D12_COMMAND_QUEUE_DESC queueDesc = { D3D12_COMMAND_LIST_TYPE_COMPUTE, 0, D3D12_COMMAND_QUEUE_FLAG_NONE };
DX::ThrowIfFailed(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_computeCommandQueue)));
DX::ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COMPUTE, IID_PPV_ARGS(&m_computeAllocator)));
DX::ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COMPUTE, m_computeAllocator.Get(), nullptr, IID_PPV_ARGS(&m_computeCommandList)));
DX::ThrowIfFailed(m_device->CreateFence(0, D3D12_FENCE_FLAG_SHARED, IID_PPV_ARGS(&m_Fence)));
m_FenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (m_FenceEvent == nullptr) {
DX::ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()));
}
}
std::cout << "Calculating" << std::endl;
Calculate();
std::cout << "Finished" << std::endl;
}
void myClass::Calculate() {
m_computeCommandList.Get()->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_dataBuffer.Get(), D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_UNORDERED_ACCESS));
m_computeCommandList.Get()->SetPipelineState(m_computeState.Get());
m_computeCommandList.Get()->SetComputeRootSignature(m_computeRootSignature.Get());
ID3D12DescriptorHeap* ppHeaps[] = { m_UavHeap.Get() };
m_computeCommandList.Get()->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
CD3DX12_GPU_DESCRIPTOR_HANDLE uavHandle(m_UavHeap->GetGPUDescriptorHandleForHeapStart(), Uav, m_UavDescriptorSize);
m_computeCommandList.Get()->SetComputeRootUnorderedAccessView(ComputeRootUAVTable, m_dataBuffer->GetGPUVirtualAddress());
m_computeCommandList.Get()->Dispatch(1, 1, 1);
m_computeCommandList.Get()->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_dataBuffer.Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COMMON));
// Close and execute the command list.
DX::ThrowIfFailed(m_computeCommandList.Get()->Close());
ID3D12CommandList* commandLists[] = { m_computeCommandList.Get() };
m_computeCommandQueue->ExecuteCommandLists(1, commandLists);
// Wait for the compute shader to complete the calculation.
UINT64 FenceValue = InterlockedIncrement(&m_FenceValue);
DX::ThrowIfFailed(m_computeCommandQueue.Get()->Signal(m_Fence.Get(), FenceValue));
DX::ThrowIfFailed(m_Fence.Get()->SetEventOnCompletion(FenceValue, m_FenceEvent));
WaitForSingleObject(m_FenceEvent, INFINITE);
std::cout << "FenceValue = " << FenceValue << " " << m_FenceValue << " " << m_Fence.Get()->GetCompletedValue() << std::endl;
// Check the output!
float* dataptr = nullptr;
D3D12_RANGE range = { 0, readbackBufferDesc.Width };
DX::ThrowIfFailed(m_dataBufferReadback->Map(0, &range, (void**)&dataptr));
for (int i = 0; i < readbackBufferDesc.Width / sizeof(data[0]); i++)
printf("uav[%d] = %.2f\n", i, dataptr[i]);
m_dataBufferReadback->Unmap(0, nullptr);
for (unsigned int i = 0; i < data.size(); i++) {
std::cout << "data[" << i << "] = " << data[i] << std::endl;
}
}
myClass.h:
#pragma once
#include "Common\Device.h"
#include <iostream>
// We have to write all of this as its own class, otherwise we cannot
// use the "this" pointer when we create compute resources. We need to
// do that because this code tagets multithreading.
class myClass {
public:
myClass();
private:
// Two buffers full of data are used. The compute thread alternates
// writing to each of them. The render thread renders using the
// buffer that is not currently in use by the compute shader.
//struct Data {
// float c;
//};
//std::vector<Data> data;
std::vector<float> data;
// For the compute pipeline, the CBV is a struct containing some
// constants used in the compute shader.
struct ConstantBufferCS {
float a;
float b;
};
D3D12_SUBRESOURCE_DATA dataSubResource;
static const UINT FrameCount = 1;
//static const UINT ThreadCount = 1;
UINT m_heightInstances;
UINT m_widthInstances;
UINT m_frameIndex;
Microsoft::WRL::ComPtr<ID3D12RootSignature> m_rootSignature;
Microsoft::WRL::ComPtr<ID3D12RootSignature> m_computeRootSignature;
Microsoft::WRL::ComPtr<ID3D12CommandQueue> m_commandQueue;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> m_UavHeap;
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> m_commandAllocators[FrameCount];
Microsoft::WRL::ComPtr<ID3D12PipelineState> m_computeState;
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> m_commandList;
Microsoft::WRL::ComPtr<ID3D12Resource> m_constantBufferCS;
UINT64 m_renderContextFenceValue;
HANDLE m_renderContextFenceEvent;
UINT64 m_frameFenceValues[FrameCount];
UINT m_UavDescriptorSize;
ConstantBufferCS constantBufferCS;
Microsoft::WRL::ComPtr<ID3D12Resource> constantBufferCSUpload;
Microsoft::WRL::ComPtr<ID3D12Fence> m_renderContextFence;
Microsoft::WRL::ComPtr<ID3D12Resource> m_dataBuffer;
Microsoft::WRL::ComPtr<ID3D12Resource> m_dataBufferUpload;
Microsoft::WRL::ComPtr<ID3D12Resource> m_dataBufferReadback;
// Compute objects.
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> m_computeAllocator;
Microsoft::WRL::ComPtr<ID3D12CommandQueue> m_computeCommandQueue;
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> m_computeCommandList;
Microsoft::WRL::ComPtr<ID3D12Fence> m_Fence;
volatile HANDLE m_FenceEvent;
D3D12_RESOURCE_DESC readbackBufferDesc;
// State
UINT64 volatile m_FenceValue;
/*
struct ThreadData {
myClass* pContext;
UINT threadIndex;
};
ThreadData m_threadData;
HANDLE m_threadHandles;
*/
void Calculate();
// Indices of shader resources in the descriptor heap.
enum DescriptorHeapIndex : UINT32 {
Uav = 0,
DescriptorCount = 1
};
enum ComputeRootParameters : UINT32 {
//ComputeRootCBV = 0,
ComputeRootUAVTable = 0,
ComputeRootParametersCount
};
};
Device.cpp:
#pragma once
#include "pch.h"
#include "Device.h"
#include "DirectXHelper.h"
#include <cassert> // for "assert"
#include <iostream>
static Device* gs_pSingelton = nullptr;
// Constructor
Device::Device(HINSTANCE hInst, bool useWarp)
: m_hInstance(hInst)
, m_useWarp(useWarp)
{
}
void Device::Initialize() {
#if defined(_DEBUG)
// Always enable the debug layer before doing anything DX12 related
// so all possible errors generated while creating DX12 objects
// are caught by the debug layer.
Microsoft::WRL::ComPtr<ID3D12Debug1> debugInterface;
DX::ThrowIfFailed(D3D12GetDebugInterface(IID_PPV_ARGS(&debugInterface)));
debugInterface->EnableDebugLayer();
// Enable these if you want full validation (will slow down rendering a lot).
//debugInterface->SetEnableGPUBasedValidation(TRUE);
//debugInterface->SetEnableSynchronizedCommandQueueValidation(TRUE);
#endif
auto dxgiAdapter = GetAdapter(false);
if (!dxgiAdapter) { // If no supporting DX12 adapters exist, fall back to WARP
dxgiAdapter = GetAdapter(true);
}
if (dxgiAdapter) {
m_device = CreateDevice(dxgiAdapter);
}
else {
throw std::exception("DXGI adapter enumeration failed.");
}
}
void Device::Create(HINSTANCE hInst) {
if (!gs_pSingelton) {
gs_pSingelton = new Device(hInst);
gs_pSingelton->Initialize();
}
}
Device& Device::Get() {
assert(gs_pSingelton);
return *gs_pSingelton;
}
void Device::Destroy() {
if (gs_pSingelton) {
delete gs_pSingelton;
gs_pSingelton = nullptr;
}
}
// Destructor
Device::~Device() {
}
Microsoft::WRL::ComPtr<ID3D12Device2> Device::CreateDevice(Microsoft::WRL::ComPtr<IDXGIAdapter4> adapter) {
Microsoft::WRL::ComPtr<ID3D12Device2> d3d12Device2;
DX::ThrowIfFailed(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&d3d12Device2)));
// Enable debug messages in debug mode.
#if defined(_DEBUG)
Microsoft::WRL::ComPtr<ID3D12InfoQueue> pInfoQueue;
if (SUCCEEDED(d3d12Device2.As(&pInfoQueue))) {
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE);
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, TRUE);
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, TRUE);
// Suppress whole categories of messages
//D3D12_MESSAGE_CATEGORY Categories[] = {};
// Suppress messages based on their severity level
D3D12_MESSAGE_SEVERITY Severities[] = { D3D12_MESSAGE_SEVERITY_INFO };
// Suppress individual messages by their ID
D3D12_MESSAGE_ID DenyIds[] = {
D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE, // I'm really not sure how to avoid this message.
D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE, // This warning occurs when using capture frame while graphics debugging.
D3D12_MESSAGE_ID_UNMAP_INVALID_NULLRANGE, // This warning occurs when using capture frame while graphics debugging.
};
D3D12_INFO_QUEUE_FILTER NewFilter = {};
//NewFilter.DenyList.NumCategories = _countof(Categories);
//NewFilter.DenyList.pCategoryList = Categories;
NewFilter.DenyList.NumSeverities = _countof(Severities);
NewFilter.DenyList.pSeverityList = Severities;
NewFilter.DenyList.NumIDs = _countof(DenyIds);
NewFilter.DenyList.pIDList = DenyIds;
DX::ThrowIfFailed(pInfoQueue->PushStorageFilter(&NewFilter));
}
#endif
return d3d12Device2;
}
Microsoft::WRL::ComPtr<IDXGIAdapter4> Device::GetAdapter(bool useWarp) {
UINT createFactoryFlags = 0;
#if defined(_DEBUG)
createFactoryFlags = DXGI_CREATE_FACTORY_DEBUG;
#endif
DX::ThrowIfFailed(CreateDXGIFactory2(createFactoryFlags, IID_PPV_ARGS(&m_factory)));
Microsoft::WRL::ComPtr<IDXGIAdapter1> dxgiAdapter1;
Microsoft::WRL::ComPtr<IDXGIAdapter4> dxgiAdapter4;
if (useWarp) {
DX::ThrowIfFailed(m_factory->EnumWarpAdapter(IID_PPV_ARGS(&dxgiAdapter1)));
DX::ThrowIfFailed(dxgiAdapter1.As(&dxgiAdapter4));
}
else {
SIZE_T maxDedicatedVideoMemory = 0;
for (UINT i = 0; m_factory->EnumAdapters1(i, &dxgiAdapter1) != DXGI_ERROR_NOT_FOUND; ++i) {
DXGI_ADAPTER_DESC1 dxgiAdapterDesc1;
dxgiAdapter1->GetDesc1(&dxgiAdapterDesc1);
// Check to see if the adapter can create a D3D12 device without actually
// creating it. The adapter with the largest dedicated video memory
// is favored.
if ((dxgiAdapterDesc1.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) == 0 &&
SUCCEEDED(D3D12CreateDevice(dxgiAdapter1.Get(),
D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), nullptr)) &&
dxgiAdapterDesc1.DedicatedVideoMemory > maxDedicatedVideoMemory) {
maxDedicatedVideoMemory = dxgiAdapterDesc1.DedicatedVideoMemory;
DX::ThrowIfFailed(dxgiAdapter1.As(&dxgiAdapter4));
}
}
}
return dxgiAdapter4;
}
设备h:
#pragma once
#include <dxgi1_6.h> // IDXGIAdapter4
// We require this file because we are unable to pass the device pointer to everywhere we need to.
class Device {
public:
/**
* Create the device singleton with the device instance handle.
*/
static void Create(HINSTANCE hInst);
/**
* Destroy the device instance.
*/
static void Destroy();
/**
* Get the device singleton.
*/
static Device& Get();
/**
* Get the Direct3D 12 device
*/
Microsoft::WRL::ComPtr<ID3D12Device2> GetDevice() const { return m_device; }
Microsoft::WRL::ComPtr<IDXGIFactory4> GetFactory() const { return m_factory; }
protected:
// Create a device instance
Device(HINSTANCE hInst, bool useWarp = false);
// Destroy the device instance.
virtual ~Device();
// Initialize the device instance.
void Initialize();
Microsoft::WRL::ComPtr<IDXGIAdapter4> GetAdapter(bool useWarp);
Microsoft::WRL::ComPtr<ID3D12Device2> CreateDevice(Microsoft::WRL::ComPtr<IDXGIAdapter4> adapter);
private:
Device(const Device& copy) = delete;
Device& operator=(const Device& other) = delete;
HINSTANCE m_hInstance;
Microsoft::WRL::ComPtr<ID3D12Device2> m_device;
Microsoft::WRL::ComPtr<IDXGIFactory4> m_factory;
bool m_useWarp;
};
ComputeShader.hlsl:
RWStructuredBuffer<float> output : register(u0); // UAV
[numthreads(1, 1, 1)]
void main( uint3 DTid : SV_DispatchThreadID ) {
output[DTid.x] = 1 + 1;
}
请让我知道如果你能找到我不明白的。我也可以尝试将我的项目上传到GitHub,如果有帮助的话。SOS:(
1条答案
按热度按时间yfjy0ee71#
下面的链接应该有帮助。https://github.com/zenny-chen/Use-Direct3D-12-Compute-Shader-in-C-Basic-