diff --git a/src/gui/rhi/cs_tdr.h b/src/gui/rhi/cs_tdr.h new file mode 100644 index 0000000000..f80cb3a498 --- /dev/null +++ b/src/gui/rhi/cs_tdr.h @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Gui module +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#ifdef Q_OS_WIN + +#include + +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 10.1 +// +// +// Buffer Definitions: +// +// cbuffer ConstantBuffer +// { +// +// uint zero; // Offset: 0 Size: 4 +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim HLSL Bind Count +// ------------------------------ ---------- ------- ----------- -------------- ------ +// uav UAV uint buf u0 1 +// ConstantBuffer cbuffer NA NA cb0 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// no Input +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// no Output +cs_5_0 +dcl_globalFlags refactoringAllowed +dcl_constantbuffer CB0[1], immediateIndexed +dcl_uav_typed_buffer (uint,uint,uint,uint) u0 +dcl_input vThreadID.x +dcl_thread_group 256, 1, 1 +loop + breakc_nz cb0[0].x + store_uav_typed u0.xyzw, vThreadID.xxxx, cb0[0].xxxx +endloop +ret +// Approximately 5 instruction slots used +#endif + +const BYTE g_killDeviceByTimingOut[] = +{ + 68, 88, 66, 67, 217, 62, + 220, 38, 136, 51, 86, 245, + 161, 96, 18, 35, 141, 17, + 26, 13, 1, 0, 0, 0, + 164, 2, 0, 0, 5, 0, + 0, 0, 52, 0, 0, 0, + 100, 1, 0, 0, 116, 1, + 0, 0, 132, 1, 0, 0, + 8, 2, 0, 0, 82, 68, + 69, 70, 40, 1, 0, 0, + 1, 0, 0, 0, 144, 0, + 0, 0, 2, 0, 0, 0, + 60, 0, 0, 0, 0, 5, + 83, 67, 0, 1, 0, 0, + 0, 1, 0, 0, 82, 68, + 49, 49, 60, 0, 0, 0, + 24, 0, 0, 0, 32, 0, + 0, 0, 40, 0, 0, 0, + 36, 0, 0, 0, 12, 0, + 0, 0, 0, 0, 0, 0, + 124, 0, 0, 0, 4, 0, + 0, 0, 4, 0, 0, 0, + 1, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 128, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 117, 97, + 118, 0, 67, 111, 110, 115, + 116, 97, 110, 116, 66, 117, + 102, 102, 101, 114, 0, 171, + 128, 0, 0, 0, 1, 0, + 0, 0, 168, 0, 0, 0, + 16, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 208, 0, 0, 0, 0, 0, + 0, 0, 4, 0, 0, 0, + 2, 0, 0, 0, 220, 0, + 0, 0, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 122, 101, + 114, 111, 0, 100, 119, 111, + 114, 100, 0, 171, 0, 0, + 19, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 213, 0, 0, 0, 77, 105, + 99, 114, 111, 115, 111, 102, + 116, 32, 40, 82, 41, 32, + 72, 76, 83, 76, 32, 83, + 104, 97, 100, 101, 114, 32, + 67, 111, 109, 112, 105, 108, + 101, 114, 32, 49, 48, 46, + 49, 0, 73, 83, 71, 78, + 8, 0, 0, 0, 0, 0, + 0, 0, 8, 0, 0, 0, + 79, 83, 71, 78, 8, 0, + 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 83, 72, + 69, 88, 124, 0, 0, 0, + 80, 0, 5, 0, 31, 0, + 0, 0, 106, 8, 0, 1, + 89, 0, 0, 4, 70, 142, + 32, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 156, 8, + 0, 4, 0, 224, 17, 0, + 0, 0, 0, 0, 68, 68, + 0, 0, 95, 0, 0, 2, + 18, 0, 2, 0, 155, 0, + 0, 4, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 48, 0, 0, 1, + 3, 0, 4, 4, 10, 128, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 164, 0, + 0, 7, 242, 224, 17, 0, + 0, 0, 0, 0, 6, 0, + 2, 0, 6, 128, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 22, 0, 0, 1, + 62, 0, 0, 1, 83, 84, + 65, 84, 148, 0, 0, 0, + 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0 +}; + +#endif // Q_OS_WIN diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 93eadc047d..f12e376b58 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -36,6 +36,7 @@ #include "qrhid3d11_p_p.h" #include "qshader_p.h" +#include "cs_tdr.h" #include #include #include @@ -119,9 +120,14 @@ QT_BEGIN_NAMESPACE */ QRhiD3D11::QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *importDevice) - : ofr(this) + : ofr(this), + deviceCurse(this) { debugLayer = params->enableDebugLayer; + + deviceCurse.framesToActivate = params->framesUntilKillingDeviceViaTdr; + deviceCurse.permanent = params->repeatDeviceKill; + importedDevice = importDevice != nullptr; if (importedDevice) { dev = reinterpret_cast(importDevice->dev); @@ -264,6 +270,9 @@ bool QRhiD3D11::create(QRhi::Flags flags) nativeHandlesStruct.dev = dev; nativeHandlesStruct.context = context; + if (deviceCurse.framesToActivate > 0) + deviceCurse.initResources(); + return true; } @@ -281,6 +290,8 @@ void QRhiD3D11::destroy() clearShaderCache(); + deviceCurse.releaseResources(); + if (annotations) { annotations->Release(); annotations = nullptr; @@ -1003,6 +1014,20 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame swapChainD->frameCount += 1; contextState.currentSwapChain = nullptr; + + if (deviceCurse.framesToActivate > 0) { + deviceCurse.framesLeft -= 1; + if (deviceCurse.framesLeft == 0) { + deviceCurse.framesLeft = deviceCurse.framesToActivate; + if (!deviceCurse.permanent) + deviceCurse.framesToActivate = -1; + + deviceCurse.activate(); + } else if (deviceCurse.framesLeft % 100 == 0) { + qDebug("Impending doom: %d frames left", deviceCurse.framesLeft); + } + } + return QRhi::FrameOpSuccess; } @@ -3914,4 +3939,34 @@ bool QD3D11SwapChain::buildOrResize() return true; } +void QRhiD3D11::DeviceCurse::initResources() +{ + framesLeft = framesToActivate; + + HRESULT hr = q->dev->CreateComputeShader(g_killDeviceByTimingOut, sizeof(g_killDeviceByTimingOut), nullptr, &cs); + if (FAILED(hr)) { + qWarning("Failed to create compute shader: %s", qPrintable(comErrorMessage(hr))); + return; + } +} + +void QRhiD3D11::DeviceCurse::releaseResources() +{ + if (cs) { + cs->Release(); + cs = nullptr; + } +} + +void QRhiD3D11::DeviceCurse::activate() +{ + if (!cs) + return; + + qDebug("Activating Curse. Goodbye Cruel World."); + + q->context->CSSetShader(cs, nullptr, 0); + q->context->Dispatch(256, 1, 1); +} + QT_END_NAMESPACE diff --git a/src/gui/rhi/qrhid3d11_p.h b/src/gui/rhi/qrhid3d11_p.h index 3e2e492d9c..5df1843b1e 100644 --- a/src/gui/rhi/qrhid3d11_p.h +++ b/src/gui/rhi/qrhid3d11_p.h @@ -58,6 +58,9 @@ QT_BEGIN_NAMESPACE struct Q_GUI_EXPORT QRhiD3D11InitParams : public QRhiInitParams { bool enableDebugLayer = false; + + int framesUntilKillingDeviceViaTdr = -1; + bool repeatDeviceKill = false; }; struct Q_GUI_EXPORT QRhiD3D11NativeHandles : public QRhiNativeHandles diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index cd44519aaa..cc4e095d10 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -694,6 +694,19 @@ public: QByteArray bytecode; }; QHash m_shaderCache; + + struct DeviceCurse { + DeviceCurse(QRhiD3D11 *impl) : q(impl) { } + QRhiD3D11 *q; + int framesToActivate = -1; + bool permanent = false; + int framesLeft = 0; + ID3D11ComputeShader *cs = nullptr; + + void initResources(); + void releaseResources(); + void activate(); + } deviceCurse; }; Q_DECLARE_TYPEINFO(QRhiD3D11::ActiveReadback, Q_MOVABLE_TYPE); diff --git a/src/gui/rhi/tdr.hlsl b/src/gui/rhi/tdr.hlsl new file mode 100644 index 0000000000..f79de91c4a --- /dev/null +++ b/src/gui/rhi/tdr.hlsl @@ -0,0 +1,9 @@ +RWBuffer uav; +cbuffer ConstantBuffer { uint zero; } + +[numthreads(256, 1, 1)] +void killDeviceByTimingOut(uint3 id: SV_DispatchThreadID) +{ + while (zero == 0) + uav[id.x] = zero; +} diff --git a/tests/manual/rhi/shared/examplefw.h b/tests/manual/rhi/shared/examplefw.h index 1a29ef5f7e..8afacc074a 100644 --- a/tests/manual/rhi/shared/examplefw.h +++ b/tests/manual/rhi/shared/examplefw.h @@ -126,6 +126,7 @@ int sampleCount = 1; QRhiSwapChain::Flags scFlags = 0; QRhi::BeginFrameFlags beginFrameFlags = 0; QRhi::EndFrameFlags endFrameFlags = 0; +int framesUntilTdr = -1; class Window : public QWindow { @@ -278,6 +279,10 @@ void Window::init() if (graphicsApi == D3D11) { QRhiD3D11InitParams params; params.enableDebugLayer = true; + if (framesUntilTdr > 0) { + params.framesUntilKillingDeviceViaTdr = framesUntilTdr; + params.repeatDeviceKill = true; + } m_r = QRhi::create(QRhi::D3D11, ¶ms, rhiFlags); } #endif @@ -461,8 +466,13 @@ int main(int argc, char **argv) // Testing cleanup both with QWindow::close() (hitting X or Alt-F4) and // QCoreApplication::quit() (e.g. what a menu widget would do) is important. // Use this parameter for the latter. - QCommandLineOption sdOption({ "s", "self-destruct" }, QLatin1String("Self destruct after 5 seconds")); + QCommandLineOption sdOption({ "s", "self-destruct" }, QLatin1String("Self-destruct after 5 seconds.")); cmdLineParser.addOption(sdOption); + // Attempt testing device lost situations on D3D at least. + QCommandLineOption tdrOption(QLatin1String("curse"), QLatin1String("Curse the graphics device. " + "(generate a device reset every frames when on D3D11)"), + QLatin1String("count")); + cmdLineParser.addOption(tdrOption); cmdLineParser.process(app); if (cmdLineParser.isSet(nullOption)) @@ -521,6 +531,9 @@ int main(int argc, char **argv) } #endif + if (cmdLineParser.isSet(tdrOption)) + framesUntilTdr = cmdLineParser.value(tdrOption).toInt(); + // Create and show the window. Window w; #if QT_CONFIG(vulkan)