我创建了一些C ++ AMP代码,用于在天文图像上执行背景渐变去除。它们以RGB的16位无符号整数形式出现。我的所有应用程序的处理和输出都是以单精度浮点运行的,所以我转换输入数据,运行C ++ AMP代码,然后将结果复制回CPU(实际上,图像将通过许多这些C ++ AMP过滤器在被复制之前在GPU上,但对于这个测试代码,我已将它隔离到一个这样的过滤器。
一切顺利,直到我启动concurrency :: copy操作将数据从GPU阵列复制回CPU。该操作会抛出异常,指示由于DXGI_ERROR_DEVICE_HUNG
已触发TDR。完整的错误是:
D3D11错误:ID3D11Device :: RemoveDevice:由于以下原因触发了设备删除(DXGI_ERROR_DEVICE_HUNG:设备执行其命令花费了不合理的时间,或硬件崩溃/挂起。因此,TDR(已经触发了超时检测和恢复机制。当挂起发生时,当前的设备上下文正在执行命令。应用程序可能希望重新生成并回退到不太积极地使用显示硬件)。 [执行错误#378:DEVICE_REMOVAL_PROCESS_AT_FAULT]
以下是相关代码。我省略了过滤器的代码,因为它使所有过滤器都很好(我在调试器中逐步完成)并且只在它复制回CPU时抛出异常。以下代码中的问题行为concurrency::copy(frame, begin(cpu_frame));
:
array<float_3, 2> convert_input(std::vector<float_3> &output, unsigned short *input, int n, int m) {
int o = 0;
for (int i = 0; i < n * m * 3; i += 3) {
output[o] = float_3((float)input[i] / (float)MAXUINT16, (float)input[i + 1] / (float)MAXUINT16, (float)input[i + 2] / (float)MAXUINT16);
o++;
}
return array<float_3, 2>(n, m, begin(output));
}
void _stdcall remove_gradient(unsigned short *input, float *output, int n, int m)
{
std::vector<float_3> cpu_frame(n * m);
array<float_3, 2> frame = convert_input(cpu_frame, input, n, m);
GradientRemovalFilter *filter = new GradientRemovalFilter();
try {
filter->FilterFrame(frame);
concurrency::copy(frame, begin(cpu_frame));
}
catch (accelerator_view_removed &ex) {
std::cout << ex.what() << std::endl;
std::cout << ex.get_view_removed_reason() << std::endl;
}
for (int i = 0; i < n * m; i ++) {
output[(i * 3)] = cpu_frame[i].r;
output[(i * 3) + 1] = cpu_frame[i].g;
output[(i * 3) + 2] = cpu_frame[i].b;
}
}
知道出了什么问题以及如何预防?我的测试图像大约是10,000个像素,所以非常小,比实际使用的小得多,所以我不明白为什么复制回来需要足够长的时间来导致TDR启动,特别是当复杂的处理和复制到GPU正在完成。
答案 0 :(得分:1)
上面的错误输出告诉你发生了什么:你的着色器花了这么长时间,驱动程序认为GPU挂了。
这里的recommendations是:
D3D11_CREATE_DEVICE_DISABLE_GPU_TIMEOUT
与DirectX 11.1+一起使用(请参阅this post) 编辑:问题最有可能发生在filter->FilterFrame
,这是C ++ AMP代码,它会成为可能导致TDR的DirectCompute着色器。由于CPU / GPU同步/时序差异,错误稍后返回的事实并不令人惊讶。