diff --git a/README.md b/README.md index cb07e0d0..497b911d 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,9 @@ The behaviour of DXVK can be modified with environment variables. ## Samples and executables In addition to the DLLs, the following standalone programs are included in the project: -- `d3d11-triangle`: Renders a triangle using D3D11. Requires native `d3dcompiler_47.dll`. +- `d3d11-compute`: Runs a simple compute shader demo. Requires native `d3dcompiler_47.dll`. +- `d3d11-triangle`: Renders a bunch of triangles using D3D11. Requires native `d3dcompiler_47.dll`. - `dxgi-factory`: Enumerates DXGI adapters and outputs for debugging purposes. -- `dxbc-dcompiler`: Compiles a DXBC shader to SPIR-V. +- `dxbc-compiler`: Compiles a DXBC shader to SPIR-V. - `dxbc-disasm`: Disassembles a DXBC shader. Requires native `d3dcompiler_47.dll`. -- `dxvk-triangle`: Renders a triangle using pure DXVK, which is the Vulkan-based state tracker that the D3D11 implementation is based on. \ No newline at end of file +- `hlsl-compiler`: Compiles a HLSL shader to DXBC. Requires native `d3dcompiler_47.dll`. \ No newline at end of file diff --git a/tests/d3d11/test_d3d11_compute.cpp b/tests/d3d11/test_d3d11_compute.cpp index 0942953d..eaaa04e2 100644 --- a/tests/d3d11/test_d3d11_compute.cpp +++ b/tests/d3d11/test_d3d11_compute.cpp @@ -1,3 +1,6 @@ +#include + +#include #include #include @@ -7,12 +10,28 @@ using namespace dxvk; +const std::string g_computeShaderCode = + "StructuredBuffer buf_in : register(t0);\n" + "RWStructuredBuffer buf_out : register(u0);\n" + "[numthreads(1,1,1)]\n" + "void main() {\n" + " buf_out[0] = buf_in[0] * buf_in[1];\n" + "}\n"; + int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { Com device; Com context; + Com computeShader; + + Com srcBuffer; + Com dstBuffer; + Com readBuffer; + + Com srcView; + Com dstView; if (FAILED(D3D11CreateDevice( nullptr, D3D_DRIVER_TYPE_HARDWARE, @@ -22,7 +41,119 @@ int WINAPI WinMain(HINSTANCE hInstance, return 1; } + Com computeShaderBlob; + if (FAILED(D3DCompile( + g_computeShaderCode.data(), + g_computeShaderCode.size(), + "Compute shader", + nullptr, nullptr, + "main", "cs_5_0", 0, 0, + &computeShaderBlob, + nullptr))) { + std::cerr << "Failed to compile compute shader" << std::endl; + return 1; + } + if (FAILED(device->CreateComputeShader( + computeShaderBlob->GetBufferPointer(), + computeShaderBlob->GetBufferSize(), + nullptr, &computeShader))) { + std::cerr << "Failed to create compute shader" << std::endl; + return 1; + } + + std::array srcData; + for (uint32_t i = 0; i < srcData.size(); i++) + srcData[i] = i + 1; + + D3D11_BUFFER_DESC srcBufferDesc; + srcBufferDesc.ByteWidth = sizeof(uint32_t) * srcData.size(); + srcBufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + srcBufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + srcBufferDesc.CPUAccessFlags = 0; + srcBufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; + srcBufferDesc.StructureByteStride = sizeof(uint32_t); + + D3D11_SUBRESOURCE_DATA srcDataInfo; + srcDataInfo.pSysMem = srcData.data(); + srcDataInfo.SysMemPitch = 0; + srcDataInfo.SysMemSlicePitch = 0; + + if (FAILED(device->CreateBuffer(&srcBufferDesc, &srcDataInfo, &srcBuffer))) { + std::cerr << "Failed to create source buffer" << std::endl; + return 1; + } + + D3D11_BUFFER_DESC dstBufferDesc; + dstBufferDesc.ByteWidth = sizeof(uint32_t); + dstBufferDesc.Usage = D3D11_USAGE_DEFAULT; + dstBufferDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS; + dstBufferDesc.CPUAccessFlags = 0; + dstBufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; + dstBufferDesc.StructureByteStride = sizeof(uint32_t); + + if (FAILED(device->CreateBuffer(&dstBufferDesc, nullptr, &dstBuffer))) { + std::cerr << "Failed to create destination buffer" << std::endl; + return 1; + } + + D3D11_BUFFER_DESC readBufferDesc; + readBufferDesc.ByteWidth = sizeof(uint32_t); + readBufferDesc.Usage = D3D11_USAGE_STAGING; + readBufferDesc.BindFlags = 0; + readBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + readBufferDesc.MiscFlags = 0; + readBufferDesc.StructureByteStride = 0; + + if (FAILED(device->CreateBuffer(&readBufferDesc, nullptr, &readBuffer))) { + std::cerr << "Failed to create readback buffer" << std::endl; + return 1; + } + + D3D11_SHADER_RESOURCE_VIEW_DESC srcViewDesc; + srcViewDesc.Format = DXGI_FORMAT_UNKNOWN; + srcViewDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX; + srcViewDesc.BufferEx.FirstElement = 0; + srcViewDesc.BufferEx.NumElements = srcData.size(); + srcViewDesc.BufferEx.Flags = 0; + + if (FAILED(device->CreateShaderResourceView(srcBuffer.ptr(), &srcViewDesc, &srcView))) { + std::cerr << "Failed to create shader resource view" << std::endl; + return 1; + } + + D3D11_UNORDERED_ACCESS_VIEW_DESC dstViewDesc; + dstViewDesc.Format = DXGI_FORMAT_UNKNOWN; + dstViewDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; + dstViewDesc.Buffer.FirstElement = 0; + dstViewDesc.Buffer.NumElements = 1; + dstViewDesc.Buffer.Flags = 0; + + if (FAILED(device->CreateUnorderedAccessView(dstBuffer.ptr(), &dstViewDesc, &dstView))) { + std::cerr << "Failed to create unordered access view" << std::endl; + return 1; + } + + // Compute sum of the source buffer values + context->CSSetShader(computeShader.ptr(), nullptr, 0); + context->CSSetShaderResources(0, 1, &srcView); + context->CSSetUnorderedAccessViews(0, 1, &dstView, nullptr); + context->Dispatch(1, 1, 1); + + // Write data to the readback buffer and query the result + context->CopyResource(readBuffer.ptr(), dstBuffer.ptr()); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + if (FAILED(context->Map(readBuffer.ptr(), 0, D3D11_MAP_READ, 0, &mappedResource))) { + std::cerr << "Failed to map readback buffer" << std::endl; + return 1; + } + + uint32_t result = 0; + std::memcpy(&result, mappedResource.pData, sizeof(result)); + context->Unmap(readBuffer.ptr(), 0); + + std::cout << "Sum: " << result << std::endl; return 0; }