Move stack trace capture out of gpuraytracer.cpp

This commit is contained in:
Magnus Norddahl 2021-10-31 19:20:23 +01:00
parent 5d514f8c4b
commit fb86b2054c
7 changed files with 285 additions and 227 deletions

View file

@ -168,6 +168,8 @@ set( SOURCES
src/lightmap/vulkanobjects.h
src/lightmap/vulkanbuilders.cpp
src/lightmap/vulkanbuilders.h
src/lightmap/stacktrace.cpp
src/lightmap/stacktrace.h
src/lightmap/gpuraytracer.cpp
src/lightmap/gpuraytracer.h
src/math/angle.cpp

View file

@ -9,205 +9,23 @@
#include "framework/templates.h"
#include "framework/halffloat.h"
#include "vulkanbuilders.h"
#include "stacktrace.h"
#include <map>
#include <vector>
#include <algorithm>
#include <zlib.h>
#ifdef WIN32
#include <DbgHelp.h>
#else
#include <execinfo.h>
#include <cxxabi.h>
#include <cstring>
#include <cstdlib>
#include <memory>
#endif
extern int Multisample;
extern int LightBounce;
extern float GridSize;
#ifdef WIN32
#pragma comment(lib, "dbghelp.lib")
class NativeSymbolResolver
{
public:
NativeSymbolResolver() { SymInitialize(GetCurrentProcess(), nullptr, TRUE); }
~NativeSymbolResolver() { SymCleanup(GetCurrentProcess()); }
std::string GetName(void* frame)
{
std::string s;
unsigned char buffer[sizeof(IMAGEHLP_SYMBOL64) + 128];
IMAGEHLP_SYMBOL64* symbol64 = reinterpret_cast<IMAGEHLP_SYMBOL64*>(buffer);
memset(symbol64, 0, sizeof(IMAGEHLP_SYMBOL64) + 128);
symbol64->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
symbol64->MaxNameLength = 128;
DWORD64 displacement = 0;
BOOL result = SymGetSymFromAddr64(GetCurrentProcess(), (DWORD64)frame, &displacement, symbol64);
if (result)
{
IMAGEHLP_LINE64 line64;
DWORD displacement = 0;
memset(&line64, 0, sizeof(IMAGEHLP_LINE64));
line64.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
result = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)frame, &displacement, &line64);
if (result)
{
s = std::string("Called from ") + symbol64->Name + " at " + line64.FileName + ", line " + std::to_string(line64.LineNumber) + "\n", symbol64->Name;
}
else
{
s = std::string("Called from ") + symbol64->Name + "\n";
}
}
return s;
}
};
#else
class NativeSymbolResolver
{
public:
std::string GetName(void* frame)
{
std::string s;
char** strings;
void* frames[1] = { frame };
strings = backtrace_symbols(frames, 1);
// Decode the strings
char* ptr = strings[0];
char* filename = ptr;
const char* function = "";
// Find function name
while (*ptr)
{
if (*ptr == '(') // Found function name
{
*(ptr++) = 0;
function = ptr;
break;
}
ptr++;
}
// Find offset
if (function[0]) // Only if function was found
{
while (*ptr)
{
if (*ptr == '+') // Found function offset
{
*(ptr++) = 0;
break;
}
if (*ptr == ')') // Not found function offset, but found, end of function
{
*(ptr++) = 0;
break;
}
ptr++;
}
}
int status;
char* new_function = abi::__cxa_demangle(function, nullptr, nullptr, &status);
if (new_function) // Was correctly decoded
{
function = new_function;
}
s = std::string("Called from ") + function + " at " + filename + "\n";
if (new_function)
{
free(new_function);
}
free(strings);
return s;
}
};
#endif
static int CaptureStackTrace(int max_frames, void** out_frames)
{
memset(out_frames, 0, sizeof(void*) * max_frames);
#ifdef _WIN64
// RtlCaptureStackBackTrace doesn't support RtlAddFunctionTable..
CONTEXT context;
RtlCaptureContext(&context);
UNWIND_HISTORY_TABLE history;
memset(&history, 0, sizeof(UNWIND_HISTORY_TABLE));
ULONG64 establisherframe = 0;
PVOID handlerdata = nullptr;
int frame;
for (frame = 0; frame < max_frames; frame++)
{
ULONG64 imagebase;
PRUNTIME_FUNCTION rtfunc = RtlLookupFunctionEntry(context.Rip, &imagebase, &history);
KNONVOLATILE_CONTEXT_POINTERS nvcontext;
memset(&nvcontext, 0, sizeof(KNONVOLATILE_CONTEXT_POINTERS));
if (!rtfunc)
{
// Leaf function
context.Rip = (ULONG64)(*(PULONG64)context.Rsp);
context.Rsp += 8;
}
else
{
RtlVirtualUnwind(UNW_FLAG_NHANDLER, imagebase, context.Rip, rtfunc, &context, &handlerdata, &establisherframe, &nvcontext);
}
if (!context.Rip)
break;
out_frames[frame] = (void*)context.Rip;
}
return frame;
#elif defined(WIN32)
return 0;//return RtlCaptureStackBackTrace(0, MIN(max_frames, 32), out_frames, nullptr);
#else
return backtrace(out_frames, max_frames);
#endif
}
std::string CaptureStackTraceText(int framesToSkip, bool includeNativeFrames)
{
void* frames[32];
int numframes = CaptureStackTrace(32, frames);
std::unique_ptr<NativeSymbolResolver> nativeSymbols;
if (includeNativeFrames)
nativeSymbols.reset(new NativeSymbolResolver());
std::string s;
for (int i = framesToSkip + 1; i < numframes; i++)
{
s += nativeSymbols->GetName(frames[i]);
}
return s;
}
GPURaytracer::GPURaytracer()
{
auto printLog = [](const char* typestr, const std::string& msg)
{
printf("\n[%s] %s\n", typestr, msg.c_str());
std::string callstack = CaptureStackTraceText(0, true);
std::string callstack = CaptureStackTraceText(0);
if (!callstack.empty())
printf("%s\n", callstack.c_str());
};
@ -615,7 +433,7 @@ void GPURaytracer::CreateTopLevelAccelerationStructure()
instance.instanceCustomIndex = 0;
instance.accelerationStructureReference = blAccelStructAddress;
instance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
instance.mask = 0xffffffff;
instance.mask = 0xff;
instance.instanceShaderBindingTableRecordOffset = 0;
BufferBuilder tbuilder;
@ -698,40 +516,6 @@ void GPURaytracer::CreateTopLevelAccelerationStructure()
void GPURaytracer::CreateShaders()
{
std::string code = R"(
#version 460
#extension GL_EXT_ray_tracing : require
struct hitPayload
{
vec3 hitValue;
};
layout(location = 0) rayPayloadEXT hitPayload prd;
layout(set = 0, binding = 0) uniform accelerationStructureEXT acc;
layout(set = 0, binding = 1, rgba32f) uniform image2D image;
layout(set = 0, binding = 2) uniform Uniforms
{
mat4 viewInverse;
mat4 projInverse;
};
void main()
{
const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5);
const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy);
vec2 d = inUV * 2.0 - 1.0;
vec4 origin = viewInverse * vec4(0, 0, 0, 1);
vec4 target = projInverse * vec4(d.x, d.y, 1, 1);
vec4 direction = viewInverse * vec4(normalize(target.xyz), 0);
traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, origin.xyz, 0.001, direction.xyz, 10000.0, 0);
imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(prd.hitValue, 1.0));
}
)";
static bool firstCall = true;
if (firstCall)
{
@ -739,7 +523,91 @@ void GPURaytracer::CreateShaders()
firstCall = false;
}
ShaderBuilder builder;
builder.setRayGenShader(code);
shaderRayGen = builder.create(device.get());
{
std::string code = R"(
#version 460
#extension GL_EXT_ray_tracing : require
struct hitPayload
{
vec3 hitValue;
};
layout(location = 0) rayPayloadEXT hitPayload payload;
layout(set = 0, binding = 0) uniform accelerationStructureEXT acc;
layout(set = 0, binding = 1, rgba32f) uniform image2D image;
layout(set = 0, binding = 2) uniform Uniforms
{
mat4 viewInverse;
mat4 projInverse;
};
void main()
{
const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5);
const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy);
vec2 d = inUV * 2.0 - 1.0;
vec4 origin = viewInverse * vec4(0, 0, 0, 1);
vec4 target = projInverse * vec4(d.x, d.y, 1, 1);
vec4 direction = viewInverse * vec4(normalize(target.xyz), 0);
traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, origin.xyz, 0.001, direction.xyz, 10000.0, 0);
imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(payload.hitValue, 1.0));
}
)";
ShaderBuilder builder;
builder.setRayGenShader(code);
shaderRayGen = builder.create(device.get());
}
{
std::string code = R"(
#version 460
#extension GL_EXT_ray_tracing : require
struct hitPayload
{
vec3 hitValue;
};
layout(location = 0) rayPayloadEXT hitPayload payload;
void main()
{
payload.hitValue = vec3(1.0);
}
)";
ShaderBuilder builder;
builder.setMissShader(code);
shaderMiss = builder.create(device.get());
}
{
std::string code = R"(
#version 460
#extension GL_EXT_ray_tracing : require
struct hitPayload
{
vec3 hitValue;
};
layout(location = 0) rayPayloadEXT hitPayload payload;
void main()
{
payload.hitValue = vec3(0.0);
}
)";
ShaderBuilder builder;
builder.setClosestHitShader(code);
shaderClosestHit = builder.create(device.get());
}
}

View file

@ -52,6 +52,8 @@ private:
std::unique_ptr<VulkanAccelerationStructure> tlAccelStruct;
std::unique_ptr<VulkanShader> shaderRayGen;
std::unique_ptr<VulkanShader> shaderMiss;
std::unique_ptr<VulkanShader> shaderClosestHit;
std::unique_ptr<VulkanCommandPool> cmdpool;
std::unique_ptr<VulkanCommandBuffer> cmdbuffer;

184
src/lightmap/stacktrace.cpp Normal file
View file

@ -0,0 +1,184 @@
#include "stacktrace.h"
#ifdef WIN32
#include <Windows.h>
#include <DbgHelp.h>
#else
#include <execinfo.h>
#include <cxxabi.h>
#include <cstring>
#include <cstdlib>
#include <memory>
#endif
#ifdef WIN32
#pragma comment(lib, "dbghelp.lib")
class NativeSymbolResolver
{
public:
NativeSymbolResolver() { SymInitialize(GetCurrentProcess(), nullptr, TRUE); }
~NativeSymbolResolver() { SymCleanup(GetCurrentProcess()); }
std::string GetName(void* frame)
{
std::string s;
unsigned char buffer[sizeof(IMAGEHLP_SYMBOL64) + 128];
IMAGEHLP_SYMBOL64* symbol64 = reinterpret_cast<IMAGEHLP_SYMBOL64*>(buffer);
memset(symbol64, 0, sizeof(IMAGEHLP_SYMBOL64) + 128);
symbol64->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
symbol64->MaxNameLength = 128;
DWORD64 displacement = 0;
BOOL result = SymGetSymFromAddr64(GetCurrentProcess(), (DWORD64)frame, &displacement, symbol64);
if (result)
{
IMAGEHLP_LINE64 line64;
DWORD displacement = 0;
memset(&line64, 0, sizeof(IMAGEHLP_LINE64));
line64.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
result = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)frame, &displacement, &line64);
if (result)
{
s = std::string("Called from ") + symbol64->Name + " at " + line64.FileName + ", line " + std::to_string(line64.LineNumber) + "\n", symbol64->Name;
}
else
{
s = std::string("Called from ") + symbol64->Name + "\n";
}
}
return s;
}
};
#else
class NativeSymbolResolver
{
public:
std::string GetName(void* frame)
{
std::string s;
char** strings;
void* frames[1] = { frame };
strings = backtrace_symbols(frames, 1);
// Decode the strings
char* ptr = strings[0];
char* filename = ptr;
const char* function = "";
// Find function name
while (*ptr)
{
if (*ptr == '(') // Found function name
{
*(ptr++) = 0;
function = ptr;
break;
}
ptr++;
}
// Find offset
if (function[0]) // Only if function was found
{
while (*ptr)
{
if (*ptr == '+') // Found function offset
{
*(ptr++) = 0;
break;
}
if (*ptr == ')') // Not found function offset, but found, end of function
{
*(ptr++) = 0;
break;
}
ptr++;
}
}
int status;
char* new_function = abi::__cxa_demangle(function, nullptr, nullptr, &status);
if (new_function) // Was correctly decoded
{
function = new_function;
}
s = std::string("Called from ") + function + " at " + filename + "\n";
if (new_function)
{
free(new_function);
}
free(strings);
return s;
}
};
#endif
static int CaptureStackTrace(int max_frames, void** out_frames)
{
memset(out_frames, 0, sizeof(void*) * max_frames);
#ifdef _WIN64
// RtlCaptureStackBackTrace doesn't support RtlAddFunctionTable..
CONTEXT context;
RtlCaptureContext(&context);
UNWIND_HISTORY_TABLE history;
memset(&history, 0, sizeof(UNWIND_HISTORY_TABLE));
ULONG64 establisherframe = 0;
PVOID handlerdata = nullptr;
int frame;
for (frame = 0; frame < max_frames; frame++)
{
ULONG64 imagebase;
PRUNTIME_FUNCTION rtfunc = RtlLookupFunctionEntry(context.Rip, &imagebase, &history);
KNONVOLATILE_CONTEXT_POINTERS nvcontext;
memset(&nvcontext, 0, sizeof(KNONVOLATILE_CONTEXT_POINTERS));
if (!rtfunc)
{
// Leaf function
context.Rip = (ULONG64)(*(PULONG64)context.Rsp);
context.Rsp += 8;
}
else
{
RtlVirtualUnwind(UNW_FLAG_NHANDLER, imagebase, context.Rip, rtfunc, &context, &handlerdata, &establisherframe, &nvcontext);
}
if (!context.Rip)
break;
out_frames[frame] = (void*)context.Rip;
}
return frame;
#elif defined(WIN32)
return 0;//return RtlCaptureStackBackTrace(0, MIN(max_frames, 32), out_frames, nullptr);
#else
return backtrace(out_frames, max_frames);
#endif
}
std::string CaptureStackTraceText(int framesToSkip)
{
void* frames[32];
int numframes = CaptureStackTrace(32, frames);
NativeSymbolResolver nativeSymbols;
std::string s;
for (int i = framesToSkip + 1; i < numframes; i++)
{
s += nativeSymbols.GetName(frames[i]);
}
return s;
}

View file

@ -0,0 +1,6 @@
#pragma once
#include <string>
std::string CaptureStackTraceText(int framesToSkip);

View file

@ -135,8 +135,6 @@ void ShaderBuilder::setAnyHitShader(const std::string &c) { code = c; stage = ES
void ShaderBuilder::setClosestHitShader(const std::string &c) { code = c; stage = EShLanguage::EShLangClosestHit; }
void ShaderBuilder::setMissShader(const std::string &c) { code = c; stage = EShLanguage::EShLangMiss; }
void ShaderBuilder::setCallableShader(const std::string &c) { code = c; stage = EShLanguage::EShLangCallable; }
//void ShaderBuilder::setTaskShader(const std::string &c) { code = c; stage = EShLanguage::EShLangTaskNV; }
//void ShaderBuilder::setMeshShader(const std::string &c) { code = c; stage = EShLanguage::EShLangMeshNV; }
std::unique_ptr<VulkanShader> ShaderBuilder::create(VulkanDevice *device)
{

View file

@ -121,14 +121,12 @@ public:
void setClosestHitShader(const std::string &code);
void setMissShader(const std::string &code);
void setCallableShader(const std::string &code);
//void setTaskShader(const std::string &code);
//void setMeshShader(const std::string &code);
std::unique_ptr<VulkanShader> create(VulkanDevice *device);
private:
std::string code;
int stage;
int stage = 0;
};
class AccelerationStructureBuilderNV