// Copyright (c) 2014-2020 Khronos Group.
//
// SPDX-License-Identifier: CC-BY-4.0


[[fault-handling]]
== Fault Handling

The fault handling mechanism provides a method for the implementation to
pass fault information to the application.
A fault indicates that an issue has occurred with the host or device that
could impact the implementation's ability to function correctly.
It consists of a slink:VkFaultData structure that is used to communicate
information about the fault between the implementation and the application,
with two methods to obtain the data.
The application can: obtain the fault data from the implementation using
flink:vkGetFaultData.
Alternatively, the implementation can: directly call a pre-registered fault
handler function (tlink:PFN_vkFaultCallbackFunction) in the application when
a fault occurs.

The sname:VkFaultData structure provides categories the implementation must:
set to provide basic information on a fault.
These allow the implementation to provide a coarse classification of a fault
to the application.
As the potential faults that could occur will vary between different
platforms, it is expected that an implementation would also provide
additional implementation-specific data on the fault, enabling the
application to take appropriate action.

The implementation must: also define whether a particular fault results in
the fault callback function being called, is communicated via
flink:vkGetFaultData, or both.
This will be decided by several factors including:

  * the severity of the fault,
  * the application's ability to handle the fault, and
  * how the application should handle the fault.

The implementation must: document the implementation-specific fault data,
how the faults are communicated, and expected responses from the application
for each of the faults that it can: report.

[[fault-data]]
=== Fault Data

[open,refpage='VkFaultData',desc='structure describing fault data',type='structs']
--
The information on a single fault is returned using the sname:VkFaultData
structure.
The sname:VkFaultData structure is defined as:

include::{generated}/api/structs/VkFaultData.adoc[]

  * pname:sType is a elink:VkStructureType value identifying this structure.
  * pname:pNext is `NULL` or a pointer to a structure extending this
    structure that provides implementation-specific data on the fault.
  * pname:faultLevel is a elink:VkFaultLevel that provides the severity of
    the fault.
  * pname:faultType is a elink:VkFaultType that provides the type of the
    fault.

To retrieve implementation-specific fault data, pname:pNext can: point to
one or more implementation-defined fault structures or `NULL` to not
retrieve implementation-specific data.

.Valid Usage
****
  * [[VUID-VkFaultData-pNext-05019]]
    pname:pNext must: be `NULL` or a valid pointer to an
    implementation-specific structure
****

include::{generated}/validity/structs/VkFaultData.adoc[]

--

[open,refpage='VkFaultLevel',desc='The different fault severity levels that can be returned',type='enums']
--
Possible values of slink:VkFaultData::pname:faultLevel, specifying the fault
severity, are:

include::{generated}/api/enums/VkFaultLevel.adoc[]

  * ename:VK_FAULT_LEVEL_UNASSIGNED A fault level has not been assigned.
  * ename:VK_FAULT_LEVEL_CRITICAL A fault that cannot: be recovered by the
    application.
  * ename:VK_FAULT_LEVEL_RECOVERABLE A fault that can: be recovered by the
    application.
  * ename:VK_FAULT_LEVEL_WARNING A fault that indicates a non-optimal
    condition has occurred, but no recovery is necessary at this point.

--

[open,refpage='VkFaultType',desc='The different fault types that can be returned',type='enums']
--

Possible values of slink:VkFaultData::pname:faultType, specifying the fault
type, are:

include::{generated}/api/enums/VkFaultType.adoc[]

  * ename:VK_FAULT_TYPE_INVALID The fault data does not contain a valid
    fault.
  * ename:VK_FAULT_TYPE_UNASSIGNED A fault type has not been assigned.
  * ename:VK_FAULT_TYPE_IMPLEMENTATION Implementation-defined fault.
  * ename:VK_FAULT_TYPE_SYSTEM A fault occurred in the system components.
  * ename:VK_FAULT_TYPE_PHYSICAL_DEVICE A fault occurred with the physical
    device.
  * ename:VK_FAULT_TYPE_COMMAND_BUFFER_FULL Command buffer memory was
    exhausted before flink:vkEndCommandBuffer was called.
  * ename:VK_FAULT_TYPE_INVALID_API_USAGE Invalid usage of the API was
    detected by the implementation.
--


[[querrying-fault]]
=== Querying Fault Status

[open,refpage='vkGetFaultData',desc='Query fault information',type='protos']
--
:refpage: vkGetFaultData

To query the number of current faults and obtain the fault data, call
flink:vkGetFaultData.

include::{generated}/api/protos/vkGetFaultData.adoc[]

  * pname:device is the logical device to obtain faults from.
  * pname:faultQueryBehavior is a elink:VkFaultQueryBehavior that specifies
    the types of faults to obtain from the implementation, and how those
    faults should be handled.
  * pname:pUnrecordedFaults is a return boolean that specifies if the logged
    fault information is incomplete and does not contain entries for all
    faults that have been detected by the implementation and may: be
    reported via flink:vkGetFaultData.
  * pname:pFaultCount is a pointer to an integer that specifies the number
    of fault entries.
  * pname:pFaults is either `NULL` or a pointer to an array of
    pname:pFaultCount slink:VkFaultData structures to be updated with the
    recorded fault data.

Access to fault data is internally synchronized, meaning
flink:vkGetFaultData can: be called from multiple threads simultaneously.

The implementation must: not record more than <<limits-maxQueryFaultCount,
pname:maxQueryFaultCount>> faults to be reported by flink:vkGetFaultData.

pname:pUnrecordedFaults is set to ename:VK_TRUE if the implementation has
detected one or more faults since the last successful retrieval of fault
data using this command, but was unable to record fault information for all
faults.
Otherwise, pname:pUnrecordedFaults is set to ename:VK_FALSE.

If pname:pFaults is `NULL`, then the number of faults with the specified
pname:faultQueryBehavior characteristics associated with pname:device is
returned in pname:pFaultCount, and pname:pUnrecordedFaults is set as
indicated above.
Otherwise, pname:pFaultCount must: point to a variable set by the user to
the number of elements in the pname:pFaults array, and on return the
variable is overwritten with the number of faults actually written to
pname:pFaults.
If pname:pFaultCount is less than the number of recorded pname:device faults
with the specified pname:faultQueryBehavior characteristics, at most
pname:pFaultCount faults will be written, and ename:VK_INCOMPLETE will be
returned instead of ename:VK_SUCCESS, to indicate that not all the available
faults were returned.

On success, the fault information stored by the implementation for the
faults that were returned will be handled as specified by
pname:faultQueryBehavior.

For each filled pname:pFaults entry, if pname:pNext is not `NULL`, the
implementation will fill in any implementation-specific structures
applicable to that fault that are included in the pname:pNext chain.

[NOTE]
.Note
====
In order to simplify the application logic, an application could have a
static allocation sized to <<limits-maxQueryFaultCount,
pname:maxQueryFaultCount>> which it passes in to each call of
flink:vkGetFaultData.
This allows an application to obtain all the faults available at this time
in a single call to flink:vkGetFaultData.
Furthermore, under this usage pattern, the command will never return
ename:VK_INCOMPLETE.
====

include::{chapters}/commonvalidity/no_dynamic_allocations_common.adoc[]

.Valid Usage
****
  * [[VUID-vkGetFaultData-pFaultCount-05020]]
    pname:pFaultCount must: be less than or equal to
    <<limits-maxQueryFaultCount,pname:maxQueryFaultCount>>
****

include::{generated}/validity/protos/vkGetFaultData.adoc[]
--


[open,refpage='VkFaultQueryBehavior',desc='Controls how the faults are retrieved by vkGetFaultData',type='enums']
--
Possible values that can: be set in elink:VkFaultQueryBehavior, specifying
which faults to return, are:

include::{generated}/api/enums/VkFaultQueryBehavior.adoc[]

  * ename:VK_FAULT_QUERY_BEHAVIOR_GET_AND_CLEAR_ALL_FAULTS All fault types
    and severities are reported and are cleared from the internal fault
    storage after retrieval.

--

[[fault-callback]]
=== Fault Callback

The slink:VkFaultCallbackInfo structure allows an application to register a
function at device creation that the implementation can call to report
faults when they occur.
A callback function is registered by attaching a valid
sname:VkFaultCallbackInfo structure to the pname:pNext chain of the
slink:VkDeviceCreateInfo structure.
The callback function is only called by the implementation during a call to
the API, using the same thread that is making the API call.
The sname:VkFaultCallbackInfo structure provides the function pointer to be
called by the implementation, and optionally, application memory to store
fault data.

[open,refpage='VkFaultCallbackInfo',desc='Fault call back information',type='structs']
--

The sname:VkFaultCallbackInfo structure is defined as:

include::{generated}/api/structs/VkFaultCallbackInfo.adoc[]

  * pname:sType is a elink:VkStructureType value identifying this structure.
  * pname:pNext is `NULL` or pointer to a structure extending this
    structure.
  * pname:faultCount is the number of reported faults in the array pointed
    to by pname:pFaults.
  * pname:pFaults is either `NULL` or a pointer to an array of
    pname:faultCount slink:VkFaultData structures.
  * pname:pfnFaultCallback is a function pointer to the fault handler
    function that will be called by the implementation when a fault occurs.

If provided, the implementation may: make use of the pname:pFaults array to
return fault data to the application when using the fault callback.

[NOTE]
.Note
====
Prior to Vulkan SC 1.0.11, the application was required to provide the
pname:pFaults array for fault callback data.
This proved to be unwieldy for both applications and implementations and it
was made optional as of version 1.0.11.
It is expected that most implementations will ignore this and use stack or
other preallocated memory for fault callback parameters.
====

If provided, the application memory referenced by pname:pFaults must: remain
accessible throughout the lifetime of the logical device that was created
with this structure.

[NOTE]
.Note
====
The memory pointed to by pname:pFaults will be updated by the implementation
and should not be used or accessed by the application outside of the fault
handling function pointed to by pname:pfnFaultCallback.
This restriction also applies to any implementation-specific structure
chained to an element of pname:pFaults by pname:pNext.

It is expected that implementations will maintain separate storage for fault
information and populate the array pointed to by pname:pFaults ahead of
calling the fault callback function.
====

.Valid Usage
****
  * [[VUID-VkFaultCallbackInfo-faultCount-05138]]
    pname:faultCount must: either be 0, or equal to
    <<limits-maxCallbackFaultCount,
    sname:VkPhysicalDeviceVulkanSC10Properties::pname:maxCallbackFaultCount>>
****

include::{generated}/validity/structs/VkFaultCallbackInfo.adoc[]
--

[open,refpage='PFN_vkFaultCallbackFunction',desc='Fault Callback Function',type='funcpointers']
--

The function pointer tlink:PFN_vkFaultCallbackFunction is defined as:

include::{generated}/api/funcpointers/PFN_vkFaultCallbackFunction.adoc[]

  * pname:unrecordedFaults is a boolean that specifies if the supplied fault
    information is incomplete and does not contain entries for all faults
    that have been detected by the implementation and may: be reported via
    tlink:PFN_vkFaultCallbackFunction since the last call to this callback.
  * pname:faultCount will contain the number of reported faults in the array
    pointed to by pname:pFaults.
  * pname:pFaults will point to an array of pname:faultCount
    slink:VkFaultData structures containing the fault information.

An implementation must: only make calls to pname:pfnFaultCallback during the
execution of an API command.
An implementation must: only make calls into the application-provided fault
callback from the same thread that called the API command.
The implementation should: not synchronize calls to the callback.
If synchronization is needed, the callback must: provide it.

The fault callback must: not call any Vulkan commands.

It is implementation-dependent whether faults reported by this callback are
also reported via flink:vkGetFaultData, but each unique fault will be
reported by at most one callback.
--

ifdef::hidden[]
// tag::scaddition[]
  * slink:VkFaultData <<SCID-6>>
  * slink:VkFaultCallbackInfo <<SCID-6>>
  * elink:VkFaultLevel <<SCID-6>>
  * elink:VkFaultType <<SCID-6>>
  * elink:VkFaultQueryBehavior <<SCID-6>>
  * tlink:PFN_vkFaultCallbackFunction <<SCID-6>>
  * flink:vkGetFaultData <<SCID-6>>
// end::scaddition[]
endif::hidden[]
