/*========================== begin_copyright_notice ============================
Copyright (C) 2021-2026 Intel Corporation

SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/

/*!
 * @file Basic GPGPU and 3D types. Basic GEN architecture definitions
 */

#ifndef GT_GPU_DEFS_H_
#define GT_GPU_DEFS_H_

#include <stdint.h>
#include "ged.h"

#if defined(__cplusplus)
#include <string>
#include <sstream>
#include <cctype>
#include <iomanip>
#include "gt_basic_defs.h"
#include "gt_basic_utils.h"
#endif  // __cplusplus

#if defined(__cplusplus)
namespace gtpin
{
#endif  // __cplusplus

#pragma pack(push, 8)

/* ===================================================================================================== */
// OpenCL runtime types
/* ===================================================================================================== */
typedef struct _cl_kernel*                  GtOclKernel;    ///< Handle to the kernel object in OpenCL
typedef struct _cl_program*                 GtOclProgram;   ///< Handle to the program object in OpenCL
typedef struct _cl_context*                 GtOclContext;   ///< Handle to the kernel object in OpenCL
typedef struct _cl_device_id*               GtOclDevice;    ///< Handle to the device object in OpenCL
typedef struct _cl_command_queue*           GtOclCmdQueue;  ///< Handle to the command queue object in OpenCL

/* ===================================================================================================== */
// Level-Zero runtime types
/* ===================================================================================================== */
typedef struct _ze_kernel_handle_t*         GtL0Kernel;     ///< Handle to the kernel object in Level-Zero
typedef struct _ze_module_handle_t*         GtL0Program;    ///< Handle to the module (program) object in Level-Zero
typedef struct _ze_context_handle_t*        GtL0Context;    ///< Handle to the context object in Level-Zero
typedef struct _ze_device_handle_t*         GtL0Device;     ///< Handle to the device object in Level-Zero
typedef struct _ze_command_queue_handle_t*  GtL0CmdQueue;   ///< Handle to the command queue object in Level-Zero
typedef struct _ze_command_list_handle_t*   GtL0CmdList;    ///< Handle to the command list object in Level-Zero

#if defined(__cplusplus)
/* ===================================================================================================== */
// Class GtGenModelId
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 * @brief The GEN model identifier
 */
class GtGenModelId
{
public:
    inline constexpr GtGenModelId(GED_MODEL v = GED_MODEL_INVALID) : _value(v) {}   ///< Conversion constructor
    inline constexpr operator GED_MODEL() const { return _value; }                  ///< Conversion operator

    inline constexpr bool IsValid()   const { return _value != GED_MODEL_INVALID; }
    inline const char*    ToString()  const { return GED_GetModelVersionString(_value); } ///< Return string representation
private:
    Enum32T<GED_MODEL> _value;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtGenModelId);

/* ===================================================================================================== */
// Class GtMemoryAddrModel
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 * @brief Class that represents Address Model of the memory surface access
 */
class GtMemoryAddrModel
{
public:
    /*!
     * @brief Types of memory surfaces / memory address models 
     * @see gfxspecs Index/57222 and Index/44800 
     * @note ADDR_TYPE does not distinguish between A32 and A64 stateless models
     */
    enum ADDR_TYPE :uint32_t
    {
        BTS_IDX_MIN         = 0,            ///< Min. Binding Table State Index
        BTS_IDX_MAX         = 0xef,         ///< Max. Binding Table State Index
        SS                  = 0xfb,         ///< Surface State address
        BSS                 = 0xfc,         ///< Bindless Surface State address
        SLM                 = 0xfe,         ///< Shared Local Memory address
        STATELESS           = 0xff,         ///< Stateless Coherent Memory address
        STATELESS_NC        = 0xfd,         ///< Stateless Non-Coherent Memory address
        ADDR_TYPE_MAX       = 0xff          ///< Max. valid value of this type
    };

public:
    /// Construct invalid address model
    inline constexpr GtMemoryAddrModel() : _bti(UINT16_MAX), _isA64(false) {}

    /*!
     * @brief Construct address model for the address type, specified by Binding Table Index, or a valid ADDR_TYPE value
     * 
     * @param[in]   bti         Binding Table Index, or any valid ADDR_TYPE value
     * @param[in]   isA64       True for a stateless A64 address model, false otherwise. This parameter is ignored if
     *                          'bti' unambiguously specifies a non-stateless model
     */
    inline constexpr GtMemoryAddrModel(uint32_t bti, bool isA64 = true);

    inline bool         constexpr IsValid()         const;  ///< Return true for a valid address model
    inline bool         constexpr IsBts()           const;  ///< Return true for Stateful BTS model
    inline bool         constexpr IsSurfaceState()  const;  ///< Return true for Surface State (SS) model
    inline bool         constexpr IsBss()           const;  ///< Return true for Bindless Surface State (BSS) model
    inline bool         constexpr IsSlm()           const;  ///< Return true for SLM address model
    inline bool         constexpr IsStateless()     const;  ///< Return true for a Stateless model
    inline bool         constexpr IsA64()           const;  ///< Return true for 64-bit Stateless address model
    inline bool         constexpr IsA32()           const;  ///< Return true for 32-bit Stateless address model
    inline uint32_t     constexpr PtrSize()         const;  ///< Return address size in bytes
    inline uint32_t     constexpr Bti()             const;  ///< Return Binding Table Index
    inline std::string            ToString()        const;  ///< Return string representation of the address model

    static inline           GtMemoryAddrModel Bts(uint32_t bti);                        ///< Make BTS model. @pre bti <= BTS_IDX_MAX
    static inline constexpr GtMemoryAddrModel SurfaceState();                           ///< Make SS model
    static inline constexpr GtMemoryAddrModel Bss();                                    ///< Make BSS model
    static inline constexpr GtMemoryAddrModel Slm();                                    ///< Make SLM model
    static inline constexpr GtMemoryAddrModel A64();                                    ///< Make A64 Coherent model
    static inline constexpr GtMemoryAddrModel A32();                                    ///< Make A32 Coherent model
    static inline constexpr GtMemoryAddrModel A64Nc();                                  ///< Make A64 Non-Coherent model
    static inline constexpr GtMemoryAddrModel A32Nc();                                  ///< Make A32 Non-Coherent model

private:
    uint16_t  _bti;
    uint16_t  _isA64;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtMemoryAddrModel);

/* ===================================================================================================== */
// Class GtAddrSpace
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 * @brief Logically distinct address spaces in GFX runtime (OpenCL, Level-Zero, etc.)
 */
class GtAddrSpace
{
public:
    enum ENUM :uint32_t
    {
        INVALID,    ///< Invalid / unknown address space
        GLOBAL,     ///< A memory region accessible to all work-items executing in a context
        LOCAL,      ///< A memory region accessible by work-items executing in a work-group
        CONSTANT,   ///< A memory region that remains constant during the execution of a kernel
        IMAGE,      ///< Address space that stores structured data in a predefined image format
        SAMPLER     ///< Address space that stores image samplers
    } value;

public:
    inline constexpr GtAddrSpace(ENUM v = INVALID) : value(v) {}    ///< Conversion constructor
    inline constexpr operator ENUM() const { return value; }        ///< Conversion operator

    inline constexpr bool IsValid()     const { return value != INVALID; }
    inline constexpr bool IsMemory()    const { return (value == GLOBAL) || (value == LOCAL) || (value == CONSTANT); }
    inline const char*    ToString()    const;                      ///< Return string representation

    static inline GtAddrSpace MakeFromString(const char* cstr);     ///< Construct from string
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtAddrSpace);

/* ===================================================================================================== */
// Struct GtStateRegAccessor
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 * @brief Structure that defines some fields of the GEN State Register (SR) and provides access to these fields.
 * 
 * @note Some of these fields could be present in a subset of GEN models, but absent in the rest of models.
 *       If a field is not present in a concrete GEN model, it is represented by an empty BitField.
 * @note Instance of this class for a specific GEN model can be obtained by the IGtGenModel::StateRegAccessor()
 *       function.
 * 
 * Terminology:
 * The combination of {SliceID, Dual-SubSliceID, SubSliceID, EUID, ThreadSlot} fields is called Global HW
 * Thread Identifier (GTID). The term 'Global' in this context means that the identifier is unique across
 * all slices, subslices, EUs of the entire system.
 */
struct GtStateRegAccessor
{
    /*
     * Get sr0.0 fields.
     * If the field being queried is not present in the GEN model, the function returns an empty bit field.
     */
    inline BitFieldU32          SliceIdField()          const; ///< Return SliceID field
    inline BitFieldU32          DualSubSliceIdField()   const; ///< Return Dual-SubSliceID field
    inline BitFieldU32          SubSliceIdField()       const; ///< Return SubSliceID field
    inline ScatteredBitFieldU32 EuIdField()             const; ///< Return EUID field
    inline BitFieldU32          ThreadSlotField()       const; ///< Return Thread slot field
    inline ScatteredBitFieldU32 GlobalTidField()        const; ///< Return Global Thread Identifier field

    /*
     * Get Values of sr0.0 fields.
     * If the field being queried is not present in the GEN model, the function returns zero value
     */
    inline uint32_t GetSliceId(uint32_t sr00)          const;   ///< Return value of the SliceID field in sr00
    inline uint32_t GetDualSubSliceId(uint32_t sr00)   const;   ///< Return value of the Dual-SubSliceID field in sr00
    inline uint32_t GetSubSliceId(uint32_t sr00)       const;   ///< Return value of the SubSliceID field in sr00
    inline uint32_t GetEuId(uint32_t sr00)             const;   ///< Return value of the EuId field in sr00
    inline uint32_t GetThreadSlot(uint32_t sr00)       const;   ///< Return value of the ThreadSlot field in sr00
    inline uint32_t GetGlobalTid(uint32_t sr00)        const;   ///< Return value of the GlobalTid field in sr00

     /*!
      * @brief Set 'gtid' value in the GlobalTid field of sr00. @return modified sr00
      */
    inline uint32_t SetGlobalTid(uint32_t sr00, uint32_t gtid)  const;

    /*
     * Get sr0.1 fields
     */
    inline BitFieldU32 FfTidField() const;              ///< Return FFTid field
    inline BitFieldU32 TileIdField() const;             ///< Return Tile Id field

    /*
     * Get Values of sr0.1 fields
     */
    inline uint32_t GetFfTid(uint32_t sr01) const;      ///< Return value of the FFTid field in sr01
    inline uint32_t GetTileId(uint32_t sr01) const;     ///< Return value of the TileId in sr01

public:
    // sr0.0 fields
    BitFieldU32             sliceId;        ///< SliceID field
    BitFieldU32             dualSubSliceId; ///< Dual-SubSliceID field
    BitFieldU32             subSliceId;     ///< SubSliceID field
    ScatteredBitFieldU32    euId;           ///< EUID field
    BitFieldU32             threadSlot;     ///< ThreadSlot field

    // sr0.1 fields
    BitFieldU32             ffTid;          ///< Fixed Function Thread ID
    BitFieldU32             tileId;         ///< Physical tile ID

};
GTPIN_ASSERT_STANDARD_LAYOUT(GtStateRegAccessor);

/* ===================================================================================================== */
// Class GtSimdWidth
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 * @brief SIMD width
 */
enum SIMD_WIDTH :uint32_t
{
    SIMD_WIDTH_INVALID = 0,
    SIMD_WIDTH_1       = 1,     ///< SIMD 1
    SIMD_WIDTH_4x2     = 4,     ///< SIMD 4
    SIMD_WIDTH_8       = 8,     ///< SIMD 8
    SIMD_WIDTH_16      = 16,    ///< SIMD 16
    SIMD_WIDTH_32      = 32,    ///< SIMD 32
};

/*! @ingroup GTPIN_GEN_ARCH
 * @brief SIMD width
 */
class GtSimdWidth
{
public:
    inline constexpr GtSimdWidth(SIMD_WIDTH v = SIMD_WIDTH_INVALID) : _value(v) {}  ///< Conversion constructor
    inline constexpr operator SIMD_WIDTH() const { return _value; }                 ///< Conversion operator

    inline constexpr bool IsValid()   const { return _value != SIMD_WIDTH_INVALID; }
    inline const char*    ToString()  const;                                        ///< Return string representation
    inline uint32_t       ToUint()    const;                                        ///< Return integer representation

    static inline GtSimdWidth MakeFromString(const char* simdCstr);                 ///< Construct from string
    static inline GtSimdWidth MakeFromUint(uint32_t simdUint);                      ///< Construct from integer

private:
    SIMD_WIDTH _value;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtSimdWidth);

/* ===================================================================================================== */
// Class GtGpuPlatform
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 * @brief GPU platform
 */
enum GPU_PLATFORM :uint32_t
{
    GPU_PLATFORM_INVALID,
    GPU_PLATFORM_OCL,       ///< Open CL
    GPU_PLATFORM_DX11,      ///< DirectX 11
    GPU_PLATFORM_DX12,      ///< DirectX 12
    GPU_PLATFORM_VULKAN,    ///< Vulkan
    GPU_PLATFORM_L0         ///< Level 0
};

/*! @ingroup GTPIN_GEN_ARCH
 * @brief GPU platform
 */
class GtGpuPlatform
{
public:
    inline constexpr GtGpuPlatform(GPU_PLATFORM v = GPU_PLATFORM_INVALID) : _value(v) {}    ///< Conversion constructor
    inline constexpr operator GPU_PLATFORM() const { return _value; }                       ///< Conversion operator

    inline constexpr bool IsValid()   const { return _value != GPU_PLATFORM_INVALID; }      ///< Return true for a valid platform
    inline constexpr bool IsCompute() const;                                                ///< Return true for a compute platform
    inline const char*    ToString()  const;                                                ///< Return string representation
private:
    GPU_PLATFORM _value;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtGpuPlatform);

/* ===================================================================================================== */
// Class GtBinaryFormat
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 * @brief Format of a binary GFX program module
 */
class GtBinaryFormat
{
public:
    enum ENUM :uint32_t
    {
        INVALID,      ///< Invalid / unknown format
        ZEBIN,        ///< zeBin ELF binary format
        PATCH_TOKEN   ///< Patch token binary format (deprecated)
    } value;

public:
    inline constexpr GtBinaryFormat(ENUM v = INVALID) : value(v) {} ///< Conversion constructor
    inline constexpr operator ENUM() const { return value; }        ///< Conversion operator

    inline constexpr bool IsValid()      const { return value != INVALID; }
    inline constexpr bool IsZeBin()      const { return value == ZEBIN; }
    inline const char*    ToString()     const;                     ///< Return string representation
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtBinaryFormat);

#endif  // __cplusplus

/* ===================================================================================================== */
// Enum GT_ACCESS_TYPE
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 * @brief Bit flags that represent types of accesses to memory regions, registers, etc.
 * Any combination of these flags is a valid access type.
 */
/// 
enum GT_ACCESS_TYPE : uint32_t
{
    GT_ACCESS_NONE         = 0,    ///< No access
    GT_ACCESS_READ         = 0x1,  ///< Read-only access
    GT_ACCESS_WRITE        = 0x2,  ///< Write-only access
    GT_ACCESS_READ_WRITE   = (uint32_t(GT_ACCESS_READ) | uint32_t(GT_ACCESS_WRITE))  ///< Read-write access
};

#if defined(__cplusplus)
/*! @ingroup GTPIN_GEN_ARCH
 * @brief Type of access to memory region, register, etc.
 */
class GtAccessType
{
public:
    inline constexpr GtAccessType(GT_ACCESS_TYPE v = GT_ACCESS_NONE) : _value(v) {}      ///< Conversion constructor
    inline constexpr operator GT_ACCESS_TYPE() const { return _value; }                  ///< Conversion operator

    inline constexpr bool IsNone()      const { return _value == GT_ACCESS_NONE; }       ///< Return true for denied/unknown access
    inline constexpr bool IsReadOnly()  const { return _value == GT_ACCESS_READ; }       ///< Return true for a read-only access
    inline constexpr bool IsWriteOnly() const { return _value == GT_ACCESS_WRITE; }      ///< Return true for a write-only access
    inline constexpr bool IsReadWrite() const { return _value == GT_ACCESS_READ_WRITE; } ///< Return true for a read-write access
    inline constexpr bool IsRead()      const { return _value & GT_ACCESS_READ; }        ///< Return true for a read access
    inline constexpr bool IsWrite()     const { return _value & GT_ACCESS_WRITE; }       ///< Return true for a write access
    inline const char*    ToString()    const;                                           ///< Return string representation

    ///< Return true if this access includes (wider than) 'other' access
    inline constexpr bool Includes(GtAccessType other) const { return (other._value & ~_value) == 0; }

    ///< Construct access type from string
    static inline GtAccessType MakeFromString(const char* cstr);

private:
    GT_ACCESS_TYPE _value;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtAccessType);

inline GT_ACCESS_TYPE operator| (const GT_ACCESS_TYPE& a1, const GT_ACCESS_TYPE& a2) { return GT_ACCESS_TYPE(uint32_t(a1) | uint32_t(a2)); }
inline GT_ACCESS_TYPE& operator|= (GT_ACCESS_TYPE& a1, const GT_ACCESS_TYPE& a2)     { return (a1 = a1 | a2); }

#endif  // __cplusplus

/* ===================================================================================================== */
// Enum GT_MEM_ACCESS_CHANNEL_TYPE
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 * @brief Bit flags that represent types of accesses to memory  with XYZW channels.
 * Specifies which components of the data payload 4-element vector (X,Y,Z,W) is packed into the register payload.
 * Any combination of none zero flags is a valid access type.
 */

enum GT_MEM_ACCESS_CHANNEL_TYPE : uint32_t
{
    GT_MEM_ACCESS_CHANNEL_TYPE_NONE = 0,
    GT_MEM_ACCESS_CHANNEL_TYPE_X    = 1,
    GT_MEM_ACCESS_CHANNEL_TYPE_Y    = 1 << 1,
    GT_MEM_ACCESS_CHANNEL_TYPE_Z    = 1 << 2,
    GT_MEM_ACCESS_CHANNEL_TYPE_W    = 1 << 3,
    GT_MEM_ACCESS_CHANNEL_TYPE_XY   = GT_MEM_ACCESS_CHANNEL_TYPE_X | GT_MEM_ACCESS_CHANNEL_TYPE_Y,
    GT_MEM_ACCESS_CHANNEL_TYPE_XZ   = GT_MEM_ACCESS_CHANNEL_TYPE_X | GT_MEM_ACCESS_CHANNEL_TYPE_Z,
    GT_MEM_ACCESS_CHANNEL_TYPE_XW   = GT_MEM_ACCESS_CHANNEL_TYPE_X | GT_MEM_ACCESS_CHANNEL_TYPE_W,
    GT_MEM_ACCESS_CHANNEL_TYPE_YZ   = GT_MEM_ACCESS_CHANNEL_TYPE_Y | GT_MEM_ACCESS_CHANNEL_TYPE_Z,
    GT_MEM_ACCESS_CHANNEL_TYPE_YW   = GT_MEM_ACCESS_CHANNEL_TYPE_Y | GT_MEM_ACCESS_CHANNEL_TYPE_W,
    GT_MEM_ACCESS_CHANNEL_TYPE_ZW   = GT_MEM_ACCESS_CHANNEL_TYPE_Z | GT_MEM_ACCESS_CHANNEL_TYPE_W,
    GT_MEM_ACCESS_CHANNEL_TYPE_XYZ  = GT_MEM_ACCESS_CHANNEL_TYPE_X | GT_MEM_ACCESS_CHANNEL_TYPE_Y | GT_MEM_ACCESS_CHANNEL_TYPE_Z,
    GT_MEM_ACCESS_CHANNEL_TYPE_XYW  = GT_MEM_ACCESS_CHANNEL_TYPE_X | GT_MEM_ACCESS_CHANNEL_TYPE_Y | GT_MEM_ACCESS_CHANNEL_TYPE_W,
    GT_MEM_ACCESS_CHANNEL_TYPE_YZW  = GT_MEM_ACCESS_CHANNEL_TYPE_Y | GT_MEM_ACCESS_CHANNEL_TYPE_Z | GT_MEM_ACCESS_CHANNEL_TYPE_W,
    GT_MEM_ACCESS_CHANNEL_TYPE_XZW  = GT_MEM_ACCESS_CHANNEL_TYPE_X | GT_MEM_ACCESS_CHANNEL_TYPE_Z | GT_MEM_ACCESS_CHANNEL_TYPE_W,
    GT_MEM_ACCESS_CHANNEL_TYPE_XYZW = GT_MEM_ACCESS_CHANNEL_TYPE_X | GT_MEM_ACCESS_CHANNEL_TYPE_Y | GT_MEM_ACCESS_CHANNEL_TYPE_Z | GT_MEM_ACCESS_CHANNEL_TYPE_W
};

#if defined(__cplusplus)
/*! @ingroup GTPIN_GEN_ARCH
 * @brief Type of access to memory with XYZW channels.
 */
class GtMemoryAccessChannelType
{
public:
    inline constexpr GtMemoryAccessChannelType(GT_MEM_ACCESS_CHANNEL_TYPE v = GT_MEM_ACCESS_CHANNEL_TYPE_NONE) : _value(v) {}      ///< Conversion constructor
    inline constexpr operator GT_MEM_ACCESS_CHANNEL_TYPE() const { return _value; }                  ///< Conversion operator

    inline constexpr bool IsValid() const { return _value != GT_MEM_ACCESS_CHANNEL_TYPE_NONE; }      ///< Return true for a valid access channel type

    inline uint32_t NumOfChannels() const
    {
        uint32_t count = 0;
        if (_value & GT_MEM_ACCESS_CHANNEL_TYPE_X) count++;
        if (_value & GT_MEM_ACCESS_CHANNEL_TYPE_Y) count++;
        if (_value & GT_MEM_ACCESS_CHANNEL_TYPE_Z) count++;
        if (_value & GT_MEM_ACCESS_CHANNEL_TYPE_W) count++;
        return count;
    }

private:
    GT_MEM_ACCESS_CHANNEL_TYPE _value;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtMemoryAccessChannelType);


/* ===================================================================================================== */
// Type GtDeviceAddr
/* ===================================================================================================== */
/// Address in the virtual address space of the device; zero value denotes invalid address
using GtDeviceAddr = UintPtrValidatable<>;

/* ===================================================================================================== */
// Struct GtMemoryBuffer
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 * @brief Memory buffer in the virtual address space of the device
 */
struct GtMemoryBuffer
{
    AddrRange       range;  ///< Range of virtual addresses occupied by the buffer
    GtAccessType    access; ///< Access attributes of the buffer

public:
    constexpr GtMemoryBuffer() = default;                                                                   ///< Default constructor
    constexpr GtMemoryBuffer(uintptr_t base, size_t size, GtAccessType a) : range(base, size), access(a) {} ///< Constructor
    constexpr GtMemoryBuffer(const AddrRange& r, GtAccessType a)          : range(r), access(a) {}          ///< Constructor

    inline constexpr uintptr_t    Base()     const { return range.First(); }   ///< Return virtual base address of the buffer
    inline constexpr uintptr_t    End()      const { return range.End(); }     ///< Return end address of the buffer
    inline constexpr size_t       Size()     const { return range.Size(); }    ///< Return size of the buffer, in bytes
    inline constexpr AddrRange    Range()    const { return range; }           ///< Return Buffer's range of virtual addresses
    inline constexpr bool         IsEmpty()  const { return range.IsEmpty(); } ///< Return true if this buffer is empty
    inline constexpr GtAccessType Access()   const { return access; }          ///< Access attributes of the buffer
    inline std::string            ToString() const;                            ///< Return string representation
};

using  GtMemoryBufferSpan      = Span<GtMemoryBuffer>;          /// Span of memory buffers
using  GtMemoryBufferConstSpan = Span<const GtMemoryBuffer>;    /// Span of immutable memory buffers

#endif  // __cplusplus

/* ===================================================================================================== */
// Struct GtKernelDispatchOclRuntime
/* ===================================================================================================== */
/*! @ingroup GTPIN_KERNEL_DISPATCH
 * @brief OpenCL runtime information associated with the kernel instance dispatched for execution
 */
struct GtKernelDispatchOclRuntime
{
    GtOclKernel     kernel;         ///< Handle to the kernel object in OpenCL
    GtOclProgram    program;        ///< Handle to the OpenCL program that contains the kernel
    GtOclContext    context;        ///< OpenCL context, the kernel is created for
    GtOclDevice     device;         ///< OpenCL device, the kernel is build for
    GtOclCmdQueue   cmdQueue;       ///< OpenCL command queue, the kernel is submitted for execution

#if defined(__cplusplus)
    GtKernelDispatchOclRuntime() = default;
    GtKernelDispatchOclRuntime(GtOclKernel k, GtOclProgram p, GtOclContext c, GtOclDevice d, GtOclCmdQueue q):
        kernel(k), program(p), context(c), device(d), cmdQueue(q) {}

    inline std::string ToString(const std::string& separator = " ") const;   ///< Return string representation
#endif  // __cplusplus
};

#if defined(__cplusplus)
GTPIN_ASSERT_STANDARD_LAYOUT(GtKernelDispatchOclRuntime);
#endif  // __cplusplus

/* ===================================================================================================== */
// Struct GtKernelDispatchL0Runtime
/* ===================================================================================================== */
/*! @ingroup GTPIN_KERNEL_DISPATCH
 * @brief Level-Zero runtime information associated with the kernel instance dispatched for execution
 */
struct GtKernelDispatchL0Runtime
{
    GtL0Kernel      kernel;         ///< Handle to the kernel object in Level-Zero
    GtL0Program     program;        ///< Handle to the Level-Zero program that contains the kernel
    GtL0Context     context;        ///< Level-Zero context, the kernel is created for
    GtL0Device      device;         ///< Level-Zero device, the kernel is build for
    GtL0CmdList     cmdList;        ///< Level-Zero command list, the kernel is appended to

#if defined(__cplusplus)
    GtKernelDispatchL0Runtime() = default;
    GtKernelDispatchL0Runtime(GtL0Kernel k, GtL0Program p, GtL0Context c, GtL0Device d, GtL0CmdList cl):
        kernel(k), program(p), context(c), device(d), cmdList(cl) {}

    inline std::string ToString(const std::string& separator = " ") const;   ///< Return string representation
#endif  // __cplusplus
};

#if defined(__cplusplus)
GTPIN_ASSERT_STANDARD_LAYOUT(GtKernelDispatchL0Runtime);
#endif  // __cplusplus

#if defined(__cplusplus)
/* ===================================================================================================== */
// Struct GtKernelExecDescFormat
/* ===================================================================================================== */
/*! @internal
 * Utility structure that helps to generate formatted string representation of GtKernelExecDesc objects.
 * It is used as an input of the GtKernelExecDesc::ToString() function.
 * This structure defines default formats for GtKernelExecDesc elements, and allows customization of
 * these formats by overriding functions of this class.
 */
struct GtKernelExecDescFormat
{
    /// Formatted string representations of GtKernelExecDesc elements
    std::string Device(uint32_t device)             const { return gtpin::ToString(device); }
    std::string Enqueue(uint32_t enqueue)           const { return gtpin::ToString(enqueue); }
    std::string Draw(uint32_t draw)                 const { return gtpin::ToString(draw); }
    std::string CommandList(uint32_t cl)            const { return gtpin::ToString(cl); }
    std::string Bus(uint32_t bus)                   const { return gtpin::ToString(bus); }
    std::string Function(uint32_t function)         const { return gtpin::ToString(function); }
    std::string Pso(uint32_t pso)                   const { return gtpin::ToString(pso); }
    std::string Frame(uint32_t frame)               const { return gtpin::ToString(frame); }

    // By default, the GFX runtime information is not included into string representation
    std::string Runtime(const GtKernelDispatchOclRuntime&) const { return ""; }
    std::string Runtime(const GtKernelDispatchL0Runtime&)  const { return ""; }

    /// @return Separator between GtKernelExecDesc elements
    std::string Separator()                         const { return " "; }
};
#endif  // __cplusplus

/* ===================================================================================================== */
// GtKernelExecDesc
/* ===================================================================================================== */
/*! @addtogroup GTPIN_KERNEL_DISPATCH
@{
*/

/// Execution descriptor of the DX11 shader (GPU_PLATFORM_DX11)
struct GtDx11ExecDesc
{
    uint32_t        device_index;
    uint32_t        draw_index;
    uint32_t        cl_id;
    uint32_t        frame_id;

#if defined(__cplusplus)
    GtDx11ExecDesc() = default;
    GtDx11ExecDesc(uint32_t deviceIndex, uint32_t drawIndex, uint32_t clId, uint32_t frameId) :
        device_index(deviceIndex), draw_index(drawIndex), cl_id(clId), frame_id(frameId) {}

    template <typename F = GtKernelExecDescFormat> std::string ToString(const F& format = F())  const;
#endif  // __cplusplus
};

/// Execution descriptor of the DX12 shader (GPU_PLATFORM_DX12)
struct GtDx12ExecDesc
{
    uint32_t        device_index;
    uint32_t        draw_index;
    uint32_t        cl_id;
    uint32_t        pso_id;
    uint32_t        frame_id;

#if defined(__cplusplus)
    GtDx12ExecDesc() = default;
    GtDx12ExecDesc(uint32_t deviceIndex, uint32_t drawIndex, uint32_t clId, uint32_t psoId, uint32_t frameId) :
        device_index(deviceIndex), draw_index(drawIndex), cl_id(clId), pso_id(psoId), frame_id(frameId) {}

    template <typename F = GtKernelExecDescFormat> std::string ToString(const F& format = F())  const;
#endif  // __cplusplus
};

/// Execution descriptor of the DX12 RayTracing shader (GPU_PLATFORM_DX12)
struct GtDx12RtExecDesc
{
    struct GtDx12ExecDesc  dx12_exec_desc;

    uint64_t        miss_shader_table_address;
    uint32_t        miss_shader_table_record_size;
    uint64_t        hit_group_shader_table_address;
    uint32_t        hit_group_shader_table_record_size;
    uint64_t        callable_shader_table_address;
    uint32_t        callable_shader_table_record_size;
    uint64_t        raygen_shader_record_address;

#if defined(__cplusplus)
    GtDx12RtExecDesc() = default;
    inline GtDx12RtExecDesc(uint32_t deviceIndex, uint32_t drawIndex, uint32_t clId, uint32_t psoId, uint32_t frameId,
                            uint64_t msAddr, uint32_t msSize, uint64_t hsAddr, uint32_t hsSize,
                            uint64_t csAddr, uint32_t csSize, uint64_t rsAddr);

    template <typename F = GtKernelExecDescFormat> std::string ToString(const F& format = F())  const;
#endif  // __cplusplus
};

/// Execution descriptor of the OCL kernel (GPU_PLATFORM_OCL)
struct GtOclExecDesc
{
    uint32_t        device_index;  ///< PCI BDF device number
    uint32_t        bus;           ///< PCI BDF bus number
    uint32_t        function;      ///< PCI BDF function number
    uint32_t        enqueue_index; ///< Enqueue ID

    GtKernelDispatchOclRuntime runtime;  ///< OpenCL runtime information associated with the kernel dispatch

#if defined(__cplusplus)
    GtOclExecDesc() = default;
    GtOclExecDesc(uint32_t deviceIndex, uint32_t busId, uint32_t functionId, uint32_t enqueueIndex,
                  const GtKernelDispatchOclRuntime& runtimeInfo) :
        device_index(deviceIndex), bus(busId), function(functionId), enqueue_index(enqueueIndex), runtime(runtimeInfo) {}

    template <typename F = GtKernelExecDescFormat> std::string ToString(const F& format = F())  const;
#endif  // __cplusplus
};

/// Execution descriptor of the Vulkan shader (GPU_PLATFORM_VULKAN)
struct GtVulkanExecDesc
{
    uint32_t        device_index;
    uint32_t        draw_index;
    uint32_t        cl_id;
    uint32_t        pso_id;
    uint32_t        frame_id;

#if defined(__cplusplus)
    GtVulkanExecDesc() = default;
    GtVulkanExecDesc(uint32_t deviceIndex, uint32_t drawIndex, uint32_t clId, uint32_t psoId, uint32_t frameId) :
        device_index(deviceIndex), draw_index(drawIndex), cl_id(clId), pso_id(psoId), frame_id(frameId) {}

    template <typename F = GtKernelExecDescFormat> std::string ToString(const F& format = F())  const;
#endif  // __cplusplus
};

/// Execution descriptor of the L0 kernel (GPU_PLATFORM_L0)
struct GtL0ExecDesc
{
    uint32_t        device_index;  ///< PCI BDF device number
    uint32_t        bus;           ///< PCI BDF bus number
    uint32_t        function;      ///< PCI BDF function number
    uint32_t        enqueue_index; ///< Enqueue ID

    GtKernelDispatchL0Runtime runtime;  ///< Level-Zero runtime information associated with the kernel dispatch

#if defined(__cplusplus)
    GtL0ExecDesc() = default;
    GtL0ExecDesc(uint32_t deviceIndex, uint32_t busId, uint32_t functionId, uint32_t enqueueIndex,
                 const GtKernelDispatchL0Runtime& runtimeInfo) :
        device_index(deviceIndex), bus(busId), function(functionId), enqueue_index(enqueueIndex), runtime(runtimeInfo) {}

    template <typename F = GtKernelExecDescFormat> std::string ToString(const F& format = F())  const;
#endif  // __cplusplus
};

/*! @ingroup GTPIN_GEN_ARCH
 * @brief Kernel execution descriptor
 */
union GtKernelExecDesc
{
    struct GtDx11ExecDesc      dx11ExecDesc;    ///< Execution descriptor of the DX11 shader
    struct GtDx12ExecDesc      dx12ExecDesc;    ///< Execution descriptor of the DX12 shader
    struct GtDx12RtExecDesc    dx12RtExecDesc;  ///< Execution descriptor of the DX12 RayTracing shader
    struct GtOclExecDesc       oclExecDesc;     ///< Execution descriptor of the OpenCL kernel
    struct GtVulkanExecDesc    vulkanExecDesc;  ///< Execution descriptor of the Vulkan shader
    struct GtL0ExecDesc        l0ExecDesc;      ///< Execution descriptor of the L0 kernel

#if defined(__cplusplus)
    GtKernelExecDesc() = default;

    /*!
     * Initialize this union by assigning the specified kernel execution descriptor of a concrete type.
     * @pre Type T is either GtDx11ExecDesc, GtDx12ExecDesc, GtDx12RtExecDesc, GtVulkanExecDesc,
     *      GtOclExecDesc, GtL0ExecDesc, or GtKernelExecDesc.
     */
    template <typename T> inline GtKernelExecDesc(const T& desc);

    /*!
     * @brief Use the specified format to convert this execution descriptor into string
     * @param F   Object that implements GtKernelExecDescFormat interface
     * @return Formatted string representation of this execution descriptor
     */
    template <typename F = GtKernelExecDescFormat> std::string ToString(GPU_PLATFORM platform, const F& format = F())  const;
#endif  // __cplusplus
};

/*! @} */

#if defined(__cplusplus)
GTPIN_ASSERT_STANDARD_LAYOUT(GtKernelExecDesc);
GTPIN_ASSERT_TRIVIALLY_COPYABLE(GtKernelExecDesc);
#endif  // __cplusplus

#if defined(__cplusplus)

/* ===================================================================================================== */
// GtMemoryAddrModel implementation
/* ===================================================================================================== */
constexpr GtMemoryAddrModel::GtMemoryAddrModel(uint32_t bti, bool isA64) :
    _bti((bti <= ADDR_TYPE_MAX) ? uint16_t(bti) : UINT16_MAX), _isA64(isA64) {}

bool     constexpr GtMemoryAddrModel::IsValid()         const   { return (_bti <= ADDR_TYPE_MAX); }
bool     constexpr GtMemoryAddrModel::IsBts()           const   { return (_bti <=  BTS_IDX_MAX); }
bool     constexpr GtMemoryAddrModel::IsSurfaceState()  const   { return (_bti == SS); }
bool     constexpr GtMemoryAddrModel::IsBss()           const   { return (_bti == BSS); }
bool     constexpr GtMemoryAddrModel::IsSlm()           const   { return (_bti == SLM); }
bool     constexpr GtMemoryAddrModel::IsStateless()     const   { return ((_bti == STATELESS) || (_bti == STATELESS_NC)); }
bool     constexpr GtMemoryAddrModel::IsA64()           const   { return (_isA64  && IsStateless()); }
bool     constexpr GtMemoryAddrModel::IsA32()           const   { return (!_isA64 && IsStateless()); }
uint32_t constexpr GtMemoryAddrModel::PtrSize()         const   { return IsA64() ? sizeof(uint64_t) : sizeof(uint32_t); }
uint32_t constexpr GtMemoryAddrModel::Bti()             const   { return _bti; }

GtMemoryAddrModel           GtMemoryAddrModel::Bts(uint32_t bti)             { GTPIN_ASSERT(bti <= BTS_IDX_MAX); return {bti, false }; }
constexpr GtMemoryAddrModel GtMemoryAddrModel::SurfaceState()                { return {SS, false}; }
constexpr GtMemoryAddrModel GtMemoryAddrModel::Bss()                         { return {BSS, false}; }
constexpr GtMemoryAddrModel GtMemoryAddrModel::Slm()                         { return {SLM, false}; }
constexpr GtMemoryAddrModel GtMemoryAddrModel::A64()                         { return {STATELESS, true}; }
constexpr GtMemoryAddrModel GtMemoryAddrModel::A32()                         { return {STATELESS, false}; }
constexpr GtMemoryAddrModel GtMemoryAddrModel::A64Nc()                       { return {STATELESS_NC, true}; }
constexpr GtMemoryAddrModel GtMemoryAddrModel::A32Nc()                       { return {STATELESS_NC, false}; }

std::string GtMemoryAddrModel::ToString() const
{
    if (IsBts())            { return std::string("BTS:") + gtpin::ToString(Bti());}
    if (IsSurfaceState())   { return "SS";}
    if (IsBss())            { return "BSS";}
    if (IsSlm())            { return "SLM";}
    if (IsA64())            { return "A64";}
    if (IsA32())            { return "A32";}
    return "";
}

/* ===================================================================================================== */
// GtAddrSpace implementation
/* ===================================================================================================== */
const char* GtAddrSpace::ToString() const
{
    switch (value)
    {
    case GLOBAL:    return "global";
    case LOCAL:     return "local";
    case CONSTANT:  return "constant";
    case IMAGE:     return "image";
    case SAMPLER:   return "sampler";
    default:        return "";
    }
}

GtAddrSpace GtAddrSpace::MakeFromString(const char* cstr)
{
    std::string str(cstr);
    if (str == "global")    return GLOBAL;
    if (str == "local")     return LOCAL;
    if (str == "constant")  return CONSTANT;
    if (str == "image")     return IMAGE;
    if (str == "sampler")   return SAMPLER;
    return INVALID;
}

/* ===================================================================================================== */
// GtStateRegAccessor implementation
/* ===================================================================================================== */
BitFieldU32             GtStateRegAccessor::SliceIdField()          const { return sliceId; }
BitFieldU32             GtStateRegAccessor::DualSubSliceIdField()   const { return dualSubSliceId; }
BitFieldU32             GtStateRegAccessor::SubSliceIdField()       const { return subSliceId; }
ScatteredBitFieldU32    GtStateRegAccessor::EuIdField()             const { return euId; }
BitFieldU32             GtStateRegAccessor::ThreadSlotField()       const { return threadSlot; }
ScatteredBitFieldU32    GtStateRegAccessor::GlobalTidField()        const
{
    return ScatteredBitFieldU32(threadSlot, euId, subSliceId, dualSubSliceId, sliceId);
}
BitFieldU32             GtStateRegAccessor::FfTidField()            const { return ffTid; }
BitFieldU32             GtStateRegAccessor::TileIdField()           const { return tileId; }

uint32_t GtStateRegAccessor::GetSliceId(uint32_t sr00)          const { return sliceId.GetValue(sr00); }
uint32_t GtStateRegAccessor::GetDualSubSliceId(uint32_t sr00)   const { return dualSubSliceId.GetValue(sr00); }
uint32_t GtStateRegAccessor::GetSubSliceId(uint32_t sr00)       const { return subSliceId.GetValue(sr00); }
uint32_t GtStateRegAccessor::GetEuId(uint32_t sr00)             const { return euId.GetValue(sr00); }
uint32_t GtStateRegAccessor::GetThreadSlot(uint32_t sr00)       const { return threadSlot.GetValue(sr00); }
uint32_t GtStateRegAccessor::GetGlobalTid(uint32_t sr00)        const { return GlobalTidField().GetValue(sr00); }
uint32_t GtStateRegAccessor::GetFfTid(uint32_t sr01)            const { return ffTid.GetValue(sr01); }
uint32_t GtStateRegAccessor::GetTileId(uint32_t sr01)           const { return tileId.GetValue(sr01); }

uint32_t GtStateRegAccessor::SetGlobalTid(uint32_t sr00, uint32_t gtid) const
{
    return GlobalTidField().SetValue(sr00, gtid);
}

/* ===================================================================================================== */
// GtSimdWidth implementation
/* ===================================================================================================== */
GTPIN_STATIC_ASSERT(SIMD_WIDTH_1   == 1);
GTPIN_STATIC_ASSERT(SIMD_WIDTH_4x2 == 4);
GTPIN_STATIC_ASSERT(SIMD_WIDTH_8   == 8);
GTPIN_STATIC_ASSERT(SIMD_WIDTH_16  == 16);
GTPIN_STATIC_ASSERT(SIMD_WIDTH_32  == 32);

const char* GtSimdWidth::ToString() const
{
    switch (_value)
    {
    case SIMD_WIDTH_1:     return "1";
    case SIMD_WIDTH_4x2:   return "4x2";
    case SIMD_WIDTH_8:     return "8";
    case SIMD_WIDTH_16:    return "16";
    case SIMD_WIDTH_32:    return "32";
    default:               return "";
    }
}

uint32_t GtSimdWidth::ToUint() const
{
    return _value;
}

GtSimdWidth GtSimdWidth::MakeFromString(const char* simdCstr)
{
    std::string str(simdCstr);
    if (str == "1")     return SIMD_WIDTH_1;
    if (str == "4")     return SIMD_WIDTH_4x2;
    if (str == "4x2")   return SIMD_WIDTH_4x2;
    if (str == "8")     return SIMD_WIDTH_8;
    if (str == "16")    return SIMD_WIDTH_16;
    if (str == "32")    return SIMD_WIDTH_32;
    return SIMD_WIDTH_INVALID;
}

GtSimdWidth GtSimdWidth::MakeFromUint(uint32_t simdUint)
{
    return static_cast<SIMD_WIDTH>(simdUint);
}

/* ===================================================================================================== */
// GtGpuPlatform implementation
/* ===================================================================================================== */
constexpr bool GtGpuPlatform::IsCompute() const
{
    return ((_value == GPU_PLATFORM_L0) || (_value == GPU_PLATFORM_OCL));
}

const char* GtGpuPlatform::ToString() const
{
    switch (_value)
    {
    case GPU_PLATFORM_OCL:           return "OpenCL";
    case GPU_PLATFORM_DX11:          return "DX11";
    case GPU_PLATFORM_DX12:          return "DX12";
    case GPU_PLATFORM_VULKAN:        return "Vulkan";
    case GPU_PLATFORM_L0:            return "L0";
    default:                         return "";
    }
}

/* ===================================================================================================== */
// GtBinaryFormat implementation
/* ===================================================================================================== */
const char* GtBinaryFormat::ToString() const
{
    switch (value)
    {
    case ZEBIN:                      return "ZeBin";
    case PATCH_TOKEN:                return "PatchToken";
    default:                         return "";
    }
}

/* ===================================================================================================== */
// GtAccessType implementation
/* ===================================================================================================== */
const char* GtAccessType::ToString() const
{
    switch (_value)
    {
    case GT_ACCESS_NONE:        return "none";
    case GT_ACCESS_READ:        return "readonly";
    case GT_ACCESS_WRITE:       return "writeonly";
    case GT_ACCESS_READ_WRITE:  return "readwrite";
    default:                    return "";
    }
}

GtAccessType GtAccessType::MakeFromString(const char* cstr)
{
    std::string str(cstr);
    if (str == "readonly")      return GT_ACCESS_READ;
    if (str == "writeonly")     return GT_ACCESS_WRITE;
    if (str == "readwrite")     return GT_ACCESS_READ_WRITE;
    return GT_ACCESS_NONE;
}

/* ===================================================================================================== */
// GtMemoryBuffer implementation
/* ===================================================================================================== */
std::string GtMemoryBuffer::ToString() const
{
    std::ostringstream os;
    os << "[" << std::hex << Base() << ", " << End() << "] : " << Access().ToString();
    return os.str();
}

/* ===================================================================================================== */
// GtKernelDispatchOclRuntime implementation
/* ===================================================================================================== */
std::string GtKernelDispatchOclRuntime::ToString(const std::string& separator) const
{
    std::ostringstream os;
    os << kernel << separator << program << separator << context << separator << device << separator << cmdQueue;
    return os.str();
}

/* ===================================================================================================== */
// GtKernelDispatchL0Runtime implementation
/* ===================================================================================================== */
std::string GtKernelDispatchL0Runtime::ToString(const std::string& separator) const
{
    std::ostringstream os;
    os << kernel << separator << program << separator << context << separator << device << separator << cmdList;
    return os.str();
}

/* ===================================================================================================== */
// GtKernelExecDesc implementation
/* ===================================================================================================== */
GtDx12RtExecDesc::GtDx12RtExecDesc(uint32_t deviceIndex, uint32_t drawIndex, uint32_t clId, uint32_t psoId, uint32_t frameId,
                                   uint64_t msAddr, uint32_t msSize, uint64_t hsAddr, uint32_t hsSize,
                                   uint64_t csAddr, uint32_t csSize, uint64_t rsAddr) :
    dx12_exec_desc(deviceIndex, drawIndex, clId, psoId, frameId),
    miss_shader_table_address(msAddr),
    miss_shader_table_record_size(msSize),
    hit_group_shader_table_address(hsAddr),
    hit_group_shader_table_record_size(hsSize),
    callable_shader_table_address(csAddr),
    callable_shader_table_record_size(csSize),
    raygen_shader_record_address(rsAddr)
{}

template <typename F> std::string _Separate(const F& format, const std::string& str)
{
    return (str.empty() ? str : (format.Separator() + str));
}

template <typename F> std::string GtDx11ExecDesc::ToString(const F& format)  const
{
    return format.Device(device_index) + _Separate(format, format.Draw(draw_index)) + _Separate(format, format.Frame(frame_id));
}

template <typename F> std::string GtDx12ExecDesc::ToString(const F& format)  const
{
    return format.Device(device_index) + _Separate(format, format.CommandList(cl_id)) +
           _Separate(format, format.Draw(draw_index)) + _Separate(format, format.Pso(pso_id)) + _Separate(format, format.Frame(frame_id));
}

template <typename F> std::string GtDx12RtExecDesc::ToString(const F& format)  const
{
    return dx12_exec_desc.ToString(format);
}

template <typename F> std::string GtOclExecDesc::ToString(const F& format)  const
{
    return format.Device(device_index) + _Separate(format, format.Bus(bus)) + _Separate(format, format.Function(function)) +
        _Separate(format, format.Enqueue(enqueue_index)) + _Separate(format, format.Runtime(runtime));
}

template <typename F> std::string GtVulkanExecDesc::ToString(const F& format)  const
{
    return format.Device(device_index) + _Separate(format, format.CommandList(cl_id)) +
           _Separate(format, format.Draw(draw_index)) + _Separate(format, format.Pso(pso_id)) + _Separate(format, format.Frame(frame_id));
}

template <typename F> std::string GtL0ExecDesc::ToString(const F& format)  const
{
    return format.Device(device_index) + _Separate(format, format.Bus(bus)) + _Separate(format, format.Function(function)) +
        _Separate(format, format.Enqueue(enqueue_index)) + _Separate(format, format.Runtime(runtime));
}

template <typename F> std::string GtKernelExecDesc::ToString(GPU_PLATFORM platform, const F& format) const
{
    switch (platform)
    {
    case GPU_PLATFORM_DX11:     return dx11ExecDesc.ToString(format);
    case GPU_PLATFORM_DX12:     return dx12ExecDesc.ToString(format);
    case GPU_PLATFORM_OCL:      return oclExecDesc.ToString(format);
    case GPU_PLATFORM_VULKAN:   return vulkanExecDesc.ToString(format);
    case GPU_PLATFORM_L0:       return l0ExecDesc.ToString(format);
    default:                    return "";
    }
}

template <> inline GtKernelExecDesc::GtKernelExecDesc(const GtKernelExecDesc& desc)   { *this = desc; }
template <> inline GtKernelExecDesc::GtKernelExecDesc(const GtDx11ExecDesc& desc)     { dx11ExecDesc = desc; }
template <> inline GtKernelExecDesc::GtKernelExecDesc(const GtDx12ExecDesc& desc)     { dx12ExecDesc = desc; }
template <> inline GtKernelExecDesc::GtKernelExecDesc(const GtDx12RtExecDesc& desc)   { dx12RtExecDesc = desc; }
template <> inline GtKernelExecDesc::GtKernelExecDesc(const GtVulkanExecDesc& desc)   { vulkanExecDesc = desc; }
template <> inline GtKernelExecDesc::GtKernelExecDesc(const GtOclExecDesc& desc)      { oclExecDesc = desc; }
template <> inline GtKernelExecDesc::GtKernelExecDesc(const GtL0ExecDesc& desc)       { l0ExecDesc = desc; }

#endif

#pragma pack(pop)

#if defined(__cplusplus)
}       // namespace
#endif  // __cplusplus

#endif
