如何触发GPU崩溃?求UE4/UE5相关代码用于研究崩溃处理流程
当然有,GPU崩溃通常源于驱动无法处理非法渲染指令、资源访问越界或硬件层面的无效操作——和CPU写空指针触发崩溃的逻辑类似,我们可以构造对应的GPU操作来触发崩溃。下面分原生DirectX和UE4/5两种场景给出代码示例,重点针对UE的场景,方便你研究它的GPU崩溃处理流程:
原生DirectX简单触发示例
在DX11环境下,绑定无效资源视图到管线,或者让Compute Shader越界访问,都能快速触发GPU崩溃:
// DX11环境下触发GPU崩溃的极简代码 void TriggerGPUDXCrash(ID3D11Device* Device, ID3D11DeviceContext* Context) { // 创建一个仅1字节的Buffer D3D11_BUFFER_DESC BufferDesc{}; BufferDesc.ByteWidth = 1; BufferDesc.Usage = D3D11_USAGE_DEFAULT; BufferDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS; BufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; BufferDesc.StructureByteStride = 1; ID3D11Buffer* TestBuffer = nullptr; Device->CreateBuffer(&BufferDesc, nullptr, &TestBuffer); // 创建对应的UAV ID3D11UnorderedAccessView* TestUAV = nullptr; Device->CreateUnorderedAccessView(TestBuffer, nullptr, &TestUAV); // 绑定UAV到计算着色器槽位 Context->CSSetUnorderedAccessViews(0, 1, &TestUAV, nullptr); // 或者更简单:绑定空的SRV后执行绘制,GPU会因访问无效资源崩溃 ID3D11ShaderResourceView* InvalidSRV = nullptr; Context->PSSetShaderResources(0, 1, &InvalidSRV); Context->Draw(3, 0); }
UE4/5 专属代码示例
UE中所有渲染操作必须在渲染线程执行,因此需要将崩溃触发逻辑提交到渲染线程处理。以下是两种可靠的触发方式:
方式1:Compute Shader越界写入(最直接)
首先创建自定义Compute Shader文件GPUDebugShader.usf:
RWStructuredBuffer<float> TestBuffer : register(u0); [numthreads(64,1,1)] void CS(uint3 DispatchThreadID : SV_DispatchThreadID) { // 故意写入超出Buffer范围的索引,触发GPU内存访问错误 TestBuffer[1000] = 1.0f; }
然后在Actor中实现调用逻辑:
头文件(GPUDebugActor.h)
#pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "GPUDebugActor.generated.h" UCLASS() class YOURPROJECT_API AGPUDebugActor : public AActor { GENERATED_BODY() public: AGPUDebugActor(); protected: virtual void BeginPlay() override; private: void TriggerGPUCrushOnRenderThread(); };
实现文件(GPUDebugActor.cpp)
#include "GPUDebugActor.h" #include "RenderCore.h" #include "RHI.h" #include "ShaderParameterUtils.h" #include "GlobalShader.h" #include "ShaderParameterStruct.h" // 声明自定义Compute Shader class FGPUDebugComputeShader : public FGlobalShader { DECLARE_GLOBAL_SHADER(FGPUDebugComputeShader); SHADER_USE_PARAMETER_STRUCT(FGPUDebugComputeShader, FGlobalShader); BEGIN_SHADER_PARAMETER_STRUCT(FParameters, ) SHADER_PARAMETER_UAV(RWStructuredBuffer<float>, TestBuffer) END_SHADER_PARAMETER_STRUCT() public: static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5); } static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment); } }; IMPLEMENT_GLOBAL_SHADER(FGPUDebugComputeShader, "/Shaders/GPUDebugShader.usf", "CS", SF_Compute); AGPUDebugActor::AGPUDebugActor() { PrimaryActorTick.bCanEverTick = false; } void AGPUDebugActor::BeginPlay() { Super::BeginPlay(); // 将崩溃逻辑提交到渲染线程执行 ENQUEUE_RENDER_COMMAND(TriggerGPUCrushCmd)( [this](FRHICommandListImmediate& RHICmdList) { TriggerGPUCrushOnRenderThread(); }); } void AGPUDebugActor::TriggerGPUCrushOnRenderThread() { // 创建仅能容纳1个float的Buffer(4字节) FRHIResourceCreateInfo CreateInfo; FStructuredBufferRHIRef TestBuffer = RHICreateStructuredBuffer(sizeof(float), 1, BUF_UnorderedAccess, CreateInfo); FUnorderedAccessViewRHIRef TestUAV = RHICreateUnorderedAccessView(TestBuffer, false, 0); // 获取Shader并设置参数 const auto ShaderMap = GetGlobalShaderMap(GMaxRHIFeatureLevel); TShaderRef<FGPUDebugComputeShader> ComputeShader(ShaderMap); FGPUDebugComputeShader::FParameters* Parameters = RHICmdList.AllocParameters<FGPUDebugComputeShader::FParameters>(); Parameters->TestBuffer = TestUAV; RHICmdList.SetComputeShader(ComputeShader); SetShaderParameters(RHICmdList, ComputeShader, ComputeShader.GetShader(), *Parameters); // 调度足够多的线程组,确保有线程执行到越界写入操作 RHICmdList.DispatchComputeShader(20, 1, 1); }
方式2:绑定无效资源视图(无需自定义Shader)
如果不想编写自定义Shader,可直接在渲染线程绑定无效资源视图,后续渲染时GPU会触发崩溃:
修改TriggerGPUCrushOnRenderThread函数:
void AGPUDebugActor::TriggerGPUCrushOnRenderThread() { // 创建空的纹理视图(无效资源) FTextureRHIRef InvalidTexture = nullptr; FRHITextureViewRHIRef InvalidSRV = RHICreateShaderResourceView(InvalidTexture, 0); // 将无效SRV绑定到像素着色器的第一个槽位 RHICmdList.SetShaderResourceView(0, InvalidSRV); // 下一帧渲染时,所有使用该槽位的材质都会尝试访问无效资源,触发GPU崩溃 }
注意事项
- 不同GPU厂商对非法操作的处理有差异:NVIDIA通常触发硬件重置,AMD可能返回驱动错误,Intel的表现介于两者之间。
- UE默认有GPU崩溃防护机制,测试时可在
Project Settings > Engine > Rendering > GPU Crash Handling中关闭相关选项,确保触发真实崩溃。 - 崩溃日志会输出到
Saved/Logs目录,可通过日志分析UE的GPU崩溃处理流程。
内容的提问来源于stack exchange,提问作者yuki
相关产品推荐
相关产品推荐

