Logging Layer Filters
The logging prints graphics API calls to the standard output or directed to a file. It is a useful debugging tool used for crash analysis, particularly in verbose mode which prints function args and API object pointers. This can help track lifetime of API - when they are created/destroyed and where they are still being referenced. However, logging can incur immense overhead and can affect application's rendering performance when in use. This leads to low FPS and can delay the time taken to reach the crash portion. In most cases, a crash can be isolated to a handful of API calls of interest. We introduced a new feature in GPA Framework 2024.4 to filter unnecessary calls when using the logging layer. Let's look at its usage.
Usage
Each class or function has a unique 32 bit integer token assigned to it in GPA. The logging layer filter uses this unique token to keep track of functions calls that are allowed or filtered. For APIs such as DirectX which has class interfaces, you can also limit calls made by specific API classes. For example, specifying a class token for ID3D12Device, will only show calls made on this object.
The logging layer takes an argument to json file which has the list of allowed classes/functions. To make a custom filter json file, we have provided a json file starter with the list of all the available classes/functions tokens. The starter json file can found in the install tree under the layers directory. There is starter file with function/class tokens per api.
Here is an example, where we are interested in tracking descriptors and their associated resources. We are narrowing it down the following set of calls which create descriptor/resources and calls that reference them in commandlist methods. This json file now represents calls that are allowed to go through the logging layer.
And here's how it is used :code: .gpa-injector.exe --layer logging:log-filter=D:log-filter.json 'C:Program FilesD3D12Game.exe'. The console output now shows a filtered function calls in stdout or log file.
{
"classes":{
},
"functions":{
"CreateCommittedResource": 4119695225,
"CreateCommittedResource1": 114875210,
"CreateCommittedResource2": 114875209,
"CreateCommittedResource3": 114875208,
"CreatePlacedResource": 1569246458,
"CreatePlacedResource1": 945466815,
"CreatePlacedResource2": 945466812,
"CreateReservedResource": 2059774121,
"CreateReservedResource1": 3995632186,
"CreateReservedResource2": 3995632185,
"CreateDescriptorHeap": 783477524,
"GetDescriptorHandleIncrementSize": 805089638,
"CreateRenderTargetView": 115632565,
"CreateRenderTargetView1": 2391959518,
"CreateDepthStencilView": 931824775,
"CreateShaderResourceView": 741961537,
"GetBuffer": 2763589909,
"CreateSwapChain": 231629267,
"CreateSwapChainForHwnd": 2077791641,
"CreateSwapChainForCoreWindow": 1661026945,
"CreateSwapChainForComposition": 2053642626,
"CreateSwapChainForCompositionSurfaceHandle": 2883696929,
"OMSetRenderTargets": 2021921931,
"ClearRenderTargetView": 3691578364,
"ClearDepthStencilView": 1579770690
}
}
For quick reference, the full list of function tokens for DirectX and Vulkan are shown here:
DirectX tokens:
Vulkan tokens: