Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modify DirectML_ESRGAN's default adapter selection. #667

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 36 additions & 16 deletions Samples/DirectML_ESRGAN/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,31 +37,51 @@ Run CMake to configure and build the sample:

## Run

Running the compiled executable will list all enumerate DX adapters, select a DX adapter (by default the first), then use this adapter to run inference with the model:
Running the compiled executable will list all enumerate DX adapters. DX adapter without graphics attribute (NPU) will be selected first. If there is no compatible<sup>1</sup> NPU adapter or there is a failure, DX adapter with graphics attribute (GPU) will be selected to retry. Selected adapter will be used to run inference with the model.

```
> cd build/win-<arch>/<config>
> .\directml_esrgan.exe

Adapter[0]: NVIDIA GeForce RTX 4080 (SELECTED)
Adapter[1]: Intel(R) UHD Graphics 770
Adapter[2]: Microsoft Basic Render Driver
Saving cropped/scaled image to input.png
Saving inference results to output.png
Trying on NPU
Adapter[0]:
not NPU
Snapdragon(R) X Elite - X1E78100 - Qualcomm(R) Adreno(TM) GPU
Adapter[1]: (SELECTED)
NPU
Snapdragon(R) X Elite - X1E78100 - Qualcomm(R) Hexagon(TM) NPU
...
```

### NPU Support

You may use the `-a <adapter_substring>` to select a different adapter that contains part of the `<adapter_substring>` in its description. For example, you can run on a compatible<sup>1</sup> NPU using `-a NPU`:

```
> cd build/win-arm64/release
> .\directml_esrgan.exe -a NPU
Adapter[0]: Snapdragon(R) X Elite - X1E78100 - Qualcomm(R) Adreno(TM) GPU
Adapter[1]: Snapdragon(R) X Elite - X1E78100 - Qualcomm(R) Hexagon(TM) NPU (SELECTED)
> cd build/win-<arch>/<config>
> .\directml_esrgan.exe
Trying on NPU
Adapter[0]:
not NPU
NVIDIA GeForce RTX 4080
Adapter[1]:
not NPU
Intel(R) UHD Graphics 770
Adapter[2]:
not NPU
Microsoft Basic Render Driver
NPU Error: No compatible adapters found.

Trying on GPU
Adapter[0]: (SELECTED)
GPU
NVIDIA GeForce RTX 4080
Adapter[1]:
GPU
Intel(R) UHD Graphics 770
Adapter[2]:
GPU
Microsoft Basic Render Driver
...
```

You may use the `-a <adapter_substring>` to select a specific adapter that contains part of the `<adapter_substring>` in its description.

You must have Windows 11 24H2 installed to run this sample using an NPU.

<sup>1</sup> Currently, this sample is only supported with the NPU available in Copilot+ PCs with Snapdragon X Series processors. Support for additional NPUs will come soon. To run this sample with the QC NPU, refer to our [blog post](https://blogs.windows.com/windowsdeveloper/2024/08/29/directml-expands-npu-support-to-copilot-pcs-and-webnn/) for list of technical requirements required.
Expand All @@ -72,4 +92,4 @@ Error in cpuinfo: Unknown chip model name 'snapdragon (tm) 8cx gen 3 @ 3.40 GHz'
```
```
unknown Qualcomm CPU part 0x1 ignored
```
```
41 changes: 32 additions & 9 deletions Samples/DirectML_ESRGAN/helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "helpers.h"

std::tuple<Microsoft::WRL::ComPtr<IDXCoreAdapter>, D3D_FEATURE_LEVEL> SelectAdapter(
std::string adapterType,
bool useGraphicsAdapter,
std::string_view adapterNameFilter)
{
using Microsoft::WRL::ComPtr;
Expand Down Expand Up @@ -52,6 +54,7 @@ std::tuple<Microsoft::WRL::ComPtr<IDXCoreAdapter>, D3D_FEATURE_LEVEL> SelectAdap
std::vector<ComPtr<IDXCoreAdapter>> adapters;
std::vector<std::string> adapterDescriptions;
std::optional<uint32_t> firstAdapterMatchingNameFilter;
bool foundPotentialAdapter = false;

for (uint32_t i = 0; i < adapterList->GetAdapterCount(); i++)
{
Expand Down Expand Up @@ -80,16 +83,33 @@ std::tuple<Microsoft::WRL::ComPtr<IDXCoreAdapter>, D3D_FEATURE_LEVEL> SelectAdap
adapters.push_back(adapter);
adapterDescriptions.push_back(adapterDescription);

if (!firstAdapterMatchingNameFilter &&
adapterDescription.find(adapterNameFilter) != std::string::npos)
if (adapter->IsAttributeSupported(DXCORE_ADAPTER_ATTRIBUTE_D3D12_GRAPHICS) == useGraphicsAdapter)
{
firstAdapterMatchingNameFilter = i;
std::cout << "Adapter[" << i << "]: " << adapterDescription << " (SELECTED)\n";
}
foundPotentialAdapter = true;
if (!firstAdapterMatchingNameFilter &&
adapterDescription.find(adapterNameFilter) != std::string::npos)
{
firstAdapterMatchingNameFilter = i;
std::cout << "Adapter[" << i << "] (SELECTED):\n";
}
else
{
std::cout << "Adapter[" << i << "]:\n";

}
std::cout << " " << adapterType << "\n";
}
else
{
std::cout << "Adapter[" << i << "]: " << adapterDescription << "\n";
std::cout << "Adapter[" << i << "]:\n";
std::cout << " not " << adapterType << "\n";
}
std::cout << " " << adapterDescription << "\n";
}

if (!foundPotentialAdapter)
{
throw std::runtime_error("No compatible adapters found.");
}

if (!firstAdapterMatchingNameFilter)
Expand All @@ -100,11 +120,14 @@ std::tuple<Microsoft::WRL::ComPtr<IDXCoreAdapter>, D3D_FEATURE_LEVEL> SelectAdap
return { adapters[*firstAdapterMatchingNameFilter], featureLevel };
}

std::tuple<Microsoft::WRL::ComPtr<IDMLDevice>, Microsoft::WRL::ComPtr<ID3D12CommandQueue>> CreateDmlDeviceAndCommandQueue(std::string_view adapterNameFilter)
std::tuple<Microsoft::WRL::ComPtr<IDMLDevice>, Microsoft::WRL::ComPtr<ID3D12CommandQueue>> CreateDmlDeviceAndCommandQueue(
std::string adapterType,
bool useGraphicsAdapter,
std::string_view adapterNameFilter)
{
using Microsoft::WRL::ComPtr;

auto [adapter, featureLevel] = SelectAdapter(adapterNameFilter);
auto [adapter, featureLevel] = SelectAdapter(adapterType, useGraphicsAdapter, adapterNameFilter);

ComPtr<ID3D12Device> d3d12Device;
THROW_IF_FAILED(D3D12CreateDevice(adapter.Get(), featureLevel, IID_PPV_ARGS(&d3d12Device)));
Expand Down Expand Up @@ -457,4 +480,4 @@ void SaveNCHWBufferToImageFilename(
THROW_IF_FAILED(frame->WriteSource(bitmap.Get(), nullptr));
THROW_IF_FAILED(frame->Commit());
THROW_IF_FAILED(encoder->Commit());
}
}
4 changes: 3 additions & 1 deletion Samples/DirectML_ESRGAN/helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ enum class ChannelOrder
};

std::tuple<Microsoft::WRL::ComPtr<IDMLDevice>, Microsoft::WRL::ComPtr<ID3D12CommandQueue>> CreateDmlDeviceAndCommandQueue(
std::string adapterType,
bool useGraphicsAdapter,
std::string_view adapterNameFilter = ""
);

Expand Down Expand Up @@ -53,4 +55,4 @@ void SaveNCHWBufferToImageFilename(
uint32_t bufferWidth,
ONNXTensorElementDataType bufferDataType = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT,
ChannelOrder bufferChannelOrder = ChannelOrder::RGB
);
);
45 changes: 33 additions & 12 deletions Samples/DirectML_ESRGAN/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,22 +136,43 @@ int main(int argc, char** argv)

auto commandLineArgs = commandLineParams.parse(argc, argv);

// See helpers.h for logic to select a DXCore adapter, create DML device, and create D3D command queue.
auto [dmlDevice, commandQueue] = CreateDmlDeviceAndCommandQueue(commandLineArgs["adapter"].as<std::string>());

RunModel(
dmlDevice.Get(),
commandQueue.Get(),
commandLineArgs["model"].as<std::string>(),
commandLineArgs["image"].as<std::string>()
);
// First try to run on NPU, then GPU.
std::vector<std::tuple<std::string, bool>> adapters = {{"NPU", false}, {"GPU", true}};
for (uint32_t i = 0; i < adapters.size(); i++)
{
auto [adapterType, isGraphicsAdapter] = adapters[i];
std::cout << "Trying on " << adapterType << std::endl;
try
{
// See helpers.h for logic to select a DXCore adapter, create DML device, and create D3D command queue.
auto [dmlDevice, commandQueue] = CreateDmlDeviceAndCommandQueue(
adapterType,
isGraphicsAdapter,
commandLineArgs["adapter"].as<std::string>()
);

RunModel(
dmlDevice.Get(),
commandQueue.Get(),
commandLineArgs["model"].as<std::string>(),
commandLineArgs["image"].as<std::string>()
);
}
catch (const std::exception& e)
{
std::cerr << adapterType << " Error: " << e.what() << std::endl;
continue;
}

return 0;
}

}
catch (const std::exception& e)
{
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}

return 0;
}
return 1;
}