/*
 *
 * Copyright (C) 2019-2025 Intel Corporation
 *
 * SPDX-License-Identifier: MIT
 *
 * @file ze_ldrddi.cpp
 *
 */
#include "ze_loader_internal.h"

using namespace loader_driver_ddi;

namespace loader
{
    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Initialize all DDI tables for a driver by calling *FromDriver functions
    ///
    /// @details This function can fail in the following scenarios:
    ///     - driver->initStatus is already set to a failure code (from a previous
    ///       required DDI initialization failure). Each *FromDriver call first checks
    ///       driver->initStatus and returns it immediately if it's already a failure.
    ///     - A required DDI table's getTable call into the driver returns a failure,
    ///       which updates driver->initStatus and is propagated back
    ///
    ///     Note: If GET_FUNCTION_PTR returns null (function not found in driver),
    ///     it only fails if driver->initStatus was already a failure. Otherwise,
    ///     driver->initStatus is returned (which would be SUCCESS).
    ///
    ///     Note: Optional DDI tables (when namespace != "zer") are ignored if they
    ///     fail, and this function continues to attempt loading remaining tables.
    ///     Only required DDI table failures cause this function to fail and return
    ///     immediately.
    ///
    /// @returns
    ///     - ::ZE_RESULT_SUCCESS if all required DDI tables loaded successfully
    ///     - ::ZE_RESULT_ERROR_* if any required DDI table failed to load
    __zedlllocal ze_result_t ZE_APICALL
    zeloaderInitDriverDDITables(loader::driver_t *driver) {
        ze_result_t result = ZE_RESULT_SUCCESS;
        result = zeGetGlobalProcAddrTableFromDriver(driver);
        if (result != ZE_RESULT_SUCCESS) {
            return result;
        }
        // Optional DDI Table, ignore failure if a driver implements the ddi table, but returns an error.
        zeGetRTASBuilderProcAddrTableFromDriver(driver);
        result = ZE_RESULT_SUCCESS;
        // Optional DDI Table, ignore failure if a driver implements the ddi table, but returns an error.
        zeGetRTASBuilderExpProcAddrTableFromDriver(driver);
        result = ZE_RESULT_SUCCESS;
        // Optional DDI Table, ignore failure if a driver implements the ddi table, but returns an error.
        zeGetRTASParallelOperationProcAddrTableFromDriver(driver);
        result = ZE_RESULT_SUCCESS;
        // Optional DDI Table, ignore failure if a driver implements the ddi table, but returns an error.
        zeGetRTASParallelOperationExpProcAddrTableFromDriver(driver);
        result = ZE_RESULT_SUCCESS;
        result = zeGetDriverProcAddrTableFromDriver(driver);
        if (result != ZE_RESULT_SUCCESS) {
            return result;
        }
        // Optional DDI Table, ignore failure if a driver implements the ddi table, but returns an error.
        zeGetDriverExpProcAddrTableFromDriver(driver);
        result = ZE_RESULT_SUCCESS;
        result = zeGetDeviceProcAddrTableFromDriver(driver);
        if (result != ZE_RESULT_SUCCESS) {
            return result;
        }
        // Optional DDI Table, ignore failure if a driver implements the ddi table, but returns an error.
        zeGetDeviceExpProcAddrTableFromDriver(driver);
        result = ZE_RESULT_SUCCESS;
        result = zeGetContextProcAddrTableFromDriver(driver);
        if (result != ZE_RESULT_SUCCESS) {
            return result;
        }
        result = zeGetCommandQueueProcAddrTableFromDriver(driver);
        if (result != ZE_RESULT_SUCCESS) {
            return result;
        }
        result = zeGetCommandListProcAddrTableFromDriver(driver);
        if (result != ZE_RESULT_SUCCESS) {
            return result;
        }
        // Optional DDI Table, ignore failure if a driver implements the ddi table, but returns an error.
        zeGetCommandListExpProcAddrTableFromDriver(driver);
        result = ZE_RESULT_SUCCESS;
        result = zeGetEventProcAddrTableFromDriver(driver);
        if (result != ZE_RESULT_SUCCESS) {
            return result;
        }
        // Optional DDI Table, ignore failure if a driver implements the ddi table, but returns an error.
        zeGetEventExpProcAddrTableFromDriver(driver);
        result = ZE_RESULT_SUCCESS;
        result = zeGetEventPoolProcAddrTableFromDriver(driver);
        if (result != ZE_RESULT_SUCCESS) {
            return result;
        }
        result = zeGetFenceProcAddrTableFromDriver(driver);
        if (result != ZE_RESULT_SUCCESS) {
            return result;
        }
        result = zeGetImageProcAddrTableFromDriver(driver);
        if (result != ZE_RESULT_SUCCESS) {
            return result;
        }
        // Optional DDI Table, ignore failure if a driver implements the ddi table, but returns an error.
        zeGetImageExpProcAddrTableFromDriver(driver);
        result = ZE_RESULT_SUCCESS;
        result = zeGetKernelProcAddrTableFromDriver(driver);
        if (result != ZE_RESULT_SUCCESS) {
            return result;
        }
        // Optional DDI Table, ignore failure if a driver implements the ddi table, but returns an error.
        zeGetKernelExpProcAddrTableFromDriver(driver);
        result = ZE_RESULT_SUCCESS;
        result = zeGetMemProcAddrTableFromDriver(driver);
        if (result != ZE_RESULT_SUCCESS) {
            return result;
        }
        // Optional DDI Table, ignore failure if a driver implements the ddi table, but returns an error.
        zeGetMemExpProcAddrTableFromDriver(driver);
        result = ZE_RESULT_SUCCESS;
        result = zeGetModuleProcAddrTableFromDriver(driver);
        if (result != ZE_RESULT_SUCCESS) {
            return result;
        }
        result = zeGetModuleBuildLogProcAddrTableFromDriver(driver);
        if (result != ZE_RESULT_SUCCESS) {
            return result;
        }
        result = zeGetPhysicalMemProcAddrTableFromDriver(driver);
        if (result != ZE_RESULT_SUCCESS) {
            return result;
        }
        result = zeGetSamplerProcAddrTableFromDriver(driver);
        if (result != ZE_RESULT_SUCCESS) {
            return result;
        }
        result = zeGetVirtualMemProcAddrTableFromDriver(driver);
        if (result != ZE_RESULT_SUCCESS) {
            return result;
        }
        // Optional DDI Table, ignore failure if a driver implements the ddi table, but returns an error.
        zeGetFabricEdgeExpProcAddrTableFromDriver(driver);
        result = ZE_RESULT_SUCCESS;
        // Optional DDI Table, ignore failure if a driver implements the ddi table, but returns an error.
        zeGetFabricVertexExpProcAddrTableFromDriver(driver);
        result = ZE_RESULT_SUCCESS;
        // Optional DDI Table, ignore failure if a driver implements the ddi table, but returns an error.
        zeGetExecutableGraphProcAddrTableFromDriver(driver);
        result = ZE_RESULT_SUCCESS;
        // Optional DDI Table, ignore failure if a driver implements the ddi table, but returns an error.
        zeGetGraphProcAddrTableFromDriver(driver);
        result = ZE_RESULT_SUCCESS;
        return result;
    }
    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeInit
    __zedlllocal ze_result_t ZE_APICALL
    zeInit(
        ze_init_flags_t flags                           ///< [in] initialization flags.
                                                        ///< must be 0 (default) or a combination of ::ze_init_flag_t.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        bool atLeastOneDriverValid = false;
        for( auto& drv : loader::context->zeDrivers )
        {
            if(drv.initStatus != ZE_RESULT_SUCCESS)
                continue;
            if (!drv.handle || !drv.ddiInitialized) {
                auto res = loader::context->init_driver( drv, flags, nullptr );
                if (res != ZE_RESULT_SUCCESS || drv.zeddiInitResult != ZE_RESULT_SUCCESS) {
                    drv.ddiInitialized = false;
                    continue;
                }
            }
            if (!drv.dditable.ze.Global.pfnInit) {
                drv.initStatus = ZE_RESULT_ERROR_UNINITIALIZED;
                continue;
            }
            drv.initStatus = drv.dditable.ze.Global.pfnInit( flags );
            if(drv.initStatus == ZE_RESULT_SUCCESS)
                atLeastOneDriverValid = true;
            drv.legacyInitAttempted = true;
        }

        if(!atLeastOneDriverValid)
            result=ZE_RESULT_ERROR_UNINITIALIZED;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDriverGet
    __zedlllocal ze_result_t ZE_APICALL
    zeDriverGet(
        uint32_t* pCount,                               ///< [in,out] pointer to the number of driver instances.
                                                        ///< if count is zero, then the loader shall update the value with the
                                                        ///< total number of drivers available.
                                                        ///< if count is greater than the number of drivers available, then the
                                                        ///< loader shall update the value with the correct number of drivers available.
        ze_driver_handle_t* phDrivers                   ///< [in,out][optional][range(0, *pCount)] array of driver instance handles.
                                                        ///< if count is less than the number of drivers available, then the loader
                                                        ///< shall only retrieve that number of drivers.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        uint32_t total_driver_handle_count = 0;

        {
            std::lock_guard<std::mutex> lock(loader::context->sortMutex);
            if (!loader::context->sortingInProgress.exchange(true) && !loader::context->instrumentationEnabled) {
                std::call_once(loader::context->coreDriverSortOnce, []() {
                    loader::context->driverSorting(&loader::context->zeDrivers, nullptr, false);
                    loader::defaultZerDdiTable = &loader::context->zeDrivers.front().dditable.zer;
                });
                loader::context->sortingInProgress.store(false);
            }
        }

        for( auto& drv : loader::context->zeDrivers )
        {
            if(drv.initStatus != ZE_RESULT_SUCCESS || !drv.ddiInitialized)
                continue;

            if( ( 0 < *pCount ) && ( *pCount == total_driver_handle_count))
                break;

            uint32_t library_driver_handle_count = 0;

            result = drv.dditable.ze.Driver.pfnGet( &library_driver_handle_count, nullptr );
            if( ZE_RESULT_SUCCESS != result ) {
                // If Get Drivers fails with Uninitialized, then update the driver init status to prevent reporting this driver in the next get call.
                if (ZE_RESULT_ERROR_UNINITIALIZED == result) {
                    drv.initStatus = result;
                }
                continue;
            }

            if( nullptr != phDrivers && *pCount !=0)
            {
                if( total_driver_handle_count + library_driver_handle_count > *pCount) {
                    library_driver_handle_count = *pCount - total_driver_handle_count;
                }
                result = drv.dditable.ze.Driver.pfnGet( &library_driver_handle_count, &phDrivers[ total_driver_handle_count ] );
                if( ZE_RESULT_SUCCESS != result ) break;

                drv.driverInuse = true;

                try
                {
                    for( uint32_t i = 0; i < library_driver_handle_count; ++i ) {
                        uint32_t driver_index = total_driver_handle_count + i;
                        if (drv.zerddiInitResult == ZE_RESULT_SUCCESS)
                            drv.zerDriverHandle = phDrivers[ driver_index ];
                        if (drv.driverDDIHandleSupportQueried == false) {
                            uint32_t extensionCount = 0;
                            ze_result_t res = drv.dditable.ze.Driver.pfnGetExtensionProperties(phDrivers[ driver_index ], &extensionCount, nullptr);
                            if (res != ZE_RESULT_SUCCESS) {
                                if (loader::context->debugTraceEnabled) {
                                    std::string message = drv.name + " failed zeDriverGetExtensionProperties query, returned ";
                                    loader::context->debug_trace_message(message, loader::to_string(res));
                                }
                                return res;
                            }
                            std::vector<ze_driver_extension_properties_t> extensionProperties(extensionCount);
                            res = drv.dditable.ze.Driver.pfnGetExtensionProperties(phDrivers[ driver_index ], &extensionCount, extensionProperties.data());
                            if (res != ZE_RESULT_SUCCESS) {
                                if (loader::context->debugTraceEnabled) {
                                    std::string message = drv.name + " failed zeDriverGetExtensionProperties query, returned ";
                                    loader::context->debug_trace_message(message, loader::to_string(res));
                                }
                                return res;
                            }
                            if (extensionCount > 0) {
                                for (uint32_t extIndex = 0; extIndex < extensionCount; extIndex++) {
                                    if (strcmp(extensionProperties[extIndex].name, ZE_DRIVER_DDI_HANDLES_EXT_NAME) == 0 && (!(extensionProperties[extIndex].version >= ZE_DRIVER_DDI_HANDLES_EXT_VERSION_1_1))) {
                                        // Driver supports DDI Handles but not the required version for ZER APIs so set the driverHandle to nullptr
                                        drv.zerDriverHandle = nullptr;
                                        drv.zerDriverDDISupported = false;
                                        break;
                                    }
                                }
                            }
                            drv.properties = {};
                            drv.properties.stype = ZE_STRUCTURE_TYPE_DRIVER_DDI_HANDLES_EXT_PROPERTIES;
                            drv.properties.pNext = nullptr;
                            ze_driver_properties_t driverProperties = {};
                            driverProperties.stype = ZE_STRUCTURE_TYPE_DRIVER_PROPERTIES;
                            driverProperties.pNext = nullptr;
                            driverProperties.pNext = &drv.properties;
                            res = drv.dditable.ze.Driver.pfnGetProperties(phDrivers[ driver_index ], &driverProperties);
                            if (res != ZE_RESULT_SUCCESS) {
                                if (loader::context->debugTraceEnabled) {
                                    std::string message = drv.name + " failed zeDriverGetProperties query, returned ";
                                    loader::context->debug_trace_message(message, loader::to_string(res));
                                }
                                return res;
                            }
                            drv.driverDDIHandleSupportQueried = true;
                        }
                        if (!(drv.properties.flags & ZE_DRIVER_DDI_HANDLE_EXT_FLAG_DDI_HANDLE_EXT_SUPPORTED) || !loader::context->driverDDIPathDefault) {
                            if (loader::context->debugTraceEnabled) {
                                std::string message = "Driver DDI Handles Not Supported for " + drv.name;
                                loader::context->debug_trace_message(message, "");
                            }
                            phDrivers[ driver_index ] = reinterpret_cast<ze_driver_handle_t>(
                                context->ze_driver_factory.getInstance( phDrivers[ driver_index ], &drv.dditable ) );
                            if (drv.zerDriverHandle != nullptr) {
                                drv.zerDriverHandle = phDrivers[ driver_index ];
                            }
                        } else if (drv.properties.flags & ZE_DRIVER_DDI_HANDLE_EXT_FLAG_DDI_HANDLE_EXT_SUPPORTED) {
                            if (loader::context->debugTraceEnabled) {
                                std::string message = "Driver DDI Handles Supported for " + drv.name;
                                loader::context->debug_trace_message(message, "");
                            }
                        }
                    }
                }
                catch( std::bad_alloc& )
                {
                    result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
                }
            }

            total_driver_handle_count += library_driver_handle_count;
        }

        // If the last driver get failed, but at least one driver succeeded, then return success with total count.
        if( ZE_RESULT_SUCCESS == result || total_driver_handle_count > 0)
            *pCount = total_driver_handle_count;
        if (total_driver_handle_count > 0) {
            result = ZE_RESULT_SUCCESS;
        }
        if (loader::context->zeDrivers.front().zerDriverDDISupported)
            loader::context->defaultZerDriverHandle = loader::context->zeDrivers.front().zerDriverHandle;
        else
            loader::context->defaultZerDriverHandle = nullptr;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeInitDrivers
    __zedlllocal ze_result_t ZE_APICALL
    zeInitDrivers(
        uint32_t* pCount,                               ///< [in,out] pointer to the number of driver instances.
                                                        ///< if count is zero, then the loader shall update the value with the
                                                        ///< total number of drivers available.
                                                        ///< if count is greater than the number of drivers available, then the
                                                        ///< loader shall update the value with the correct number of drivers available.
        ze_driver_handle_t* phDrivers,                  ///< [in,out][optional][range(0, *pCount)] array of driver instance handles.
                                                        ///< if count is less than the number of drivers available, then the loader
                                                        ///< shall only retrieve that number of drivers.
        ze_init_driver_type_desc_t* desc                ///< [in] descriptor containing the driver type initialization details
                                                        ///< including ::ze_init_driver_type_flag_t combinations.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        uint32_t total_driver_handle_count = 0;
        for( auto& drv : loader::context->zeDrivers ) {
            if (!drv.handle || !drv.ddiInitialized) {
                auto res = loader::context->init_driver( drv, 0, desc);
                if (res != ZE_RESULT_SUCCESS || drv.zeddiInitResult != ZE_RESULT_SUCCESS) {
                    drv.ddiInitialized = false;
                    continue;
                }
            }
        }

        {
            std::lock_guard<std::mutex> lock(loader::context->sortMutex);
            if (!loader::context->sortingInProgress.exchange(true) && !loader::context->instrumentationEnabled) {
                std::call_once(loader::context->coreDriverSortOnce, [desc]() {
                    loader::context->driverSorting(&loader::context->zeDrivers, desc, false);
                    loader::defaultZerDdiTable = &loader::context->zeDrivers.front().dditable.zer;
                });
                loader::context->sortingInProgress.store(false);
            }
        }

        for( auto& drv : loader::context->zeDrivers )
        {
            if (!drv.ddiInitialized || !drv.dditable.ze.Global.pfnInitDrivers) {
                drv.initDriversStatus = ZE_RESULT_ERROR_UNINITIALIZED;
                result = ZE_RESULT_ERROR_UNINITIALIZED;
                continue;
            }

            if( ( 0 < *pCount ) && ( *pCount == total_driver_handle_count))
                break;

            uint32_t library_driver_handle_count = 0;

            result = drv.dditable.ze.Global.pfnInitDrivers( &library_driver_handle_count, nullptr, desc );
            if( ZE_RESULT_SUCCESS != result ) {
                // If Get Drivers fails with Uninitialized, then update the driver init status to prevent reporting this driver in the next get call.
                if (ZE_RESULT_ERROR_UNINITIALIZED == result) {
                    drv.initDriversStatus = result;
                }
                continue;
            }

            if( nullptr != phDrivers && *pCount !=0)
            {
                if( total_driver_handle_count + library_driver_handle_count > *pCount) {
                    library_driver_handle_count = *pCount - total_driver_handle_count;
                }
                result = drv.dditable.ze.Global.pfnInitDrivers( &library_driver_handle_count, &phDrivers[ total_driver_handle_count ], desc );
                if( ZE_RESULT_SUCCESS != result ) break;

                drv.driverInuse = true;

                try
                {
                    for( uint32_t i = 0; i < library_driver_handle_count; ++i ) {
                        uint32_t driver_index = total_driver_handle_count + i;
                        if (drv.zerddiInitResult == ZE_RESULT_SUCCESS)
                            drv.zerDriverHandle = phDrivers[ driver_index ];
                        if (drv.driverDDIHandleSupportQueried == false) {
                            uint32_t extensionCount = 0;
                            ze_result_t res = drv.dditable.ze.Driver.pfnGetExtensionProperties(phDrivers[ driver_index ], &extensionCount, nullptr);
                            if (res != ZE_RESULT_SUCCESS) {
                                if (loader::context->debugTraceEnabled) {
                                    std::string message = drv.name + " failed zeDriverGetExtensionProperties query, returned ";
                                    loader::context->debug_trace_message(message, loader::to_string(res));
                                }
                                return res;
                            }
                            std::vector<ze_driver_extension_properties_t> extensionProperties(extensionCount);
                            res = drv.dditable.ze.Driver.pfnGetExtensionProperties(phDrivers[ driver_index ], &extensionCount, extensionProperties.data());
                            if (res != ZE_RESULT_SUCCESS) {
                                if (loader::context->debugTraceEnabled) {
                                    std::string message = drv.name + " failed zeDriverGetExtensionProperties query, returned ";
                                    loader::context->debug_trace_message(message, loader::to_string(res));
                                }
                                return res;
                            }
                            if (extensionCount > 0) {
                                for (uint32_t extIndex = 0; extIndex < extensionCount; extIndex++) {
                                    if (strcmp(extensionProperties[extIndex].name, ZE_DRIVER_DDI_HANDLES_EXT_NAME) == 0 && (!(extensionProperties[extIndex].version >= ZE_DRIVER_DDI_HANDLES_EXT_VERSION_1_1))) {
                                        // Driver supports DDI Handles but not the required version for ZER APIs so set the driverHandle to nullptr
                                        drv.zerDriverHandle = nullptr;
                                        drv.zerDriverDDISupported = false;
                                        break;
                                    }
                                }
                            }
                            drv.properties = {};
                            drv.properties.stype = ZE_STRUCTURE_TYPE_DRIVER_DDI_HANDLES_EXT_PROPERTIES;
                            drv.properties.pNext = nullptr;
                            ze_driver_properties_t driverProperties = {};
                            driverProperties.stype = ZE_STRUCTURE_TYPE_DRIVER_PROPERTIES;
                            driverProperties.pNext = nullptr;
                            driverProperties.pNext = &drv.properties;
                            res = drv.dditable.ze.Driver.pfnGetProperties(phDrivers[ driver_index ], &driverProperties);
                            if (res != ZE_RESULT_SUCCESS) {
                                if (loader::context->debugTraceEnabled) {
                                    std::string message = drv.name + " failed zeDriverGetProperties query, returned ";
                                    loader::context->debug_trace_message(message, loader::to_string(res));
                                }
                                return res;
                            }
                            drv.driverDDIHandleSupportQueried = true;
                        }
                        if (!(drv.properties.flags & ZE_DRIVER_DDI_HANDLE_EXT_FLAG_DDI_HANDLE_EXT_SUPPORTED) || !loader::context->driverDDIPathDefault) {
                            if (loader::context->debugTraceEnabled) {
                                std::string message = "Driver DDI Handles Not Supported for " + drv.name;
                                loader::context->debug_trace_message(message, "");
                            }
                            phDrivers[ driver_index ] = reinterpret_cast<ze_driver_handle_t>(
                                context->ze_driver_factory.getInstance( phDrivers[ driver_index ], &drv.dditable ) );
                            if (drv.zerDriverHandle != nullptr) {
                                drv.zerDriverHandle = phDrivers[ driver_index ];
                            }
                        } else if (drv.properties.flags & ZE_DRIVER_DDI_HANDLE_EXT_FLAG_DDI_HANDLE_EXT_SUPPORTED) {
                            if (loader::context->debugTraceEnabled) {
                                std::string message = "Driver DDI Handles Supported for " + drv.name;
                                loader::context->debug_trace_message(message, "");
                            }
                        }
                    }
                }
                catch( std::bad_alloc& )
                {
                    result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
                }
            }

            total_driver_handle_count += library_driver_handle_count;
        }

        // If the last driver get failed, but at least one driver succeeded, then return success with total count.
        if( ZE_RESULT_SUCCESS == result || total_driver_handle_count > 0)
            *pCount = total_driver_handle_count;
        if (total_driver_handle_count > 0) {
            result = ZE_RESULT_SUCCESS;
        }
        if (loader::context->zeDrivers.front().zerDriverDDISupported)
            loader::context->defaultZerDriverHandle = loader::context->zeDrivers.front().zerDriverHandle;
        else
            loader::context->defaultZerDriverHandle = nullptr;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDriverGetApiVersion
    __zedlllocal ze_result_t ZE_APICALL
    zeDriverGetApiVersion(
        ze_driver_handle_t hDriver,                     ///< [in] handle of the driver instance
        ze_api_version_t* version                       ///< [out] api version
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_driver_object_t*>( hDriver )->dditable;
        auto pfnGetApiVersion = dditable->ze.Driver.pfnGetApiVersion;
        if( nullptr == pfnGetApiVersion )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDriver = reinterpret_cast<ze_driver_object_t*>( hDriver )->handle;

        // forward to device-driver
        result = pfnGetApiVersion( hDriver, version );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDriverGetProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeDriverGetProperties(
        ze_driver_handle_t hDriver,                     ///< [in] handle of the driver instance
        ze_driver_properties_t* pDriverProperties       ///< [in,out] query result for driver properties
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_driver_object_t*>( hDriver )->dditable;
        auto pfnGetProperties = dditable->ze.Driver.pfnGetProperties;
        if( nullptr == pfnGetProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDriver = reinterpret_cast<ze_driver_object_t*>( hDriver )->handle;

        // forward to device-driver
        result = pfnGetProperties( hDriver, pDriverProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDriverGetIpcProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeDriverGetIpcProperties(
        ze_driver_handle_t hDriver,                     ///< [in] handle of the driver instance
        ze_driver_ipc_properties_t* pIpcProperties      ///< [in,out] query result for IPC properties
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_driver_object_t*>( hDriver )->dditable;
        auto pfnGetIpcProperties = dditable->ze.Driver.pfnGetIpcProperties;
        if( nullptr == pfnGetIpcProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDriver = reinterpret_cast<ze_driver_object_t*>( hDriver )->handle;

        // forward to device-driver
        result = pfnGetIpcProperties( hDriver, pIpcProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDriverGetExtensionProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeDriverGetExtensionProperties(
        ze_driver_handle_t hDriver,                     ///< [in] handle of the driver instance
        uint32_t* pCount,                               ///< [in,out] pointer to the number of extension properties.
                                                        ///< if count is zero, then the driver shall update the value with the
                                                        ///< total number of extension properties available.
                                                        ///< if count is greater than the number of extension properties available,
                                                        ///< then the driver shall update the value with the correct number of
                                                        ///< extension properties available.
        ze_driver_extension_properties_t* pExtensionProperties  ///< [in,out][optional][range(0, *pCount)] array of query results for
                                                        ///< extension properties.
                                                        ///< if count is less than the number of extension properties available,
                                                        ///< then driver shall only retrieve that number of extension properties.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_driver_object_t*>( hDriver )->dditable;
        auto pfnGetExtensionProperties = dditable->ze.Driver.pfnGetExtensionProperties;
        if( nullptr == pfnGetExtensionProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDriver = reinterpret_cast<ze_driver_object_t*>( hDriver )->handle;

        // forward to device-driver
        result = pfnGetExtensionProperties( hDriver, pCount, pExtensionProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDriverGetExtensionFunctionAddress
    __zedlllocal ze_result_t ZE_APICALL
    zeDriverGetExtensionFunctionAddress(
        ze_driver_handle_t hDriver,                     ///< [in] handle of the driver instance
        const char* name,                               ///< [in] extension function name
        void** ppFunctionAddress                        ///< [out] pointer to function pointer
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_driver_object_t*>( hDriver )->dditable;
        auto pfnGetExtensionFunctionAddress = dditable->ze.Driver.pfnGetExtensionFunctionAddress;
        if( nullptr == pfnGetExtensionFunctionAddress )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDriver = reinterpret_cast<ze_driver_object_t*>( hDriver )->handle;

        // forward to device-driver
        result = pfnGetExtensionFunctionAddress( hDriver, name, ppFunctionAddress );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDriverGetLastErrorDescription
    __zedlllocal ze_result_t ZE_APICALL
    zeDriverGetLastErrorDescription(
        ze_driver_handle_t hDriver,                     ///< [in] handle of the driver instance
        const char** ppString                           ///< [in,out] pointer to a null-terminated array of characters describing
                                                        ///< cause of error.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_driver_object_t*>( hDriver )->dditable;
        auto pfnGetLastErrorDescription = dditable->ze.Driver.pfnGetLastErrorDescription;
        if( nullptr == pfnGetLastErrorDescription )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDriver = reinterpret_cast<ze_driver_object_t*>( hDriver )->handle;

        // forward to device-driver
        result = pfnGetLastErrorDescription( hDriver, ppString );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDriverGetDefaultContext
    __zedlllocal ze_context_handle_t ZE_APICALL
    zeDriverGetDefaultContext(
        ze_driver_handle_t hDriver                      ///< [in] handle of the driver instance
        )
    {
        ze_context_handle_t result {};
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_driver_object_t*>( hDriver )->dditable;
        auto pfnGetDefaultContext = dditable->ze.Driver.pfnGetDefaultContext;
        if( nullptr == pfnGetDefaultContext )
            return nullptr;

        // convert loader handle to driver handle
        hDriver = reinterpret_cast<ze_driver_object_t*>( hDriver )->handle;

        // forward to device-driver
        result = pfnGetDefaultContext( hDriver );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGet
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGet(
        ze_driver_handle_t hDriver,                     ///< [in] handle of the driver instance
        uint32_t* pCount,                               ///< [in,out] pointer to the number of devices.
                                                        ///< if count is zero, then the driver shall update the value with the
                                                        ///< total number of devices available.
                                                        ///< if count is greater than the number of devices available, then the
                                                        ///< driver shall update the value with the correct number of devices available.
        ze_device_handle_t* phDevices                   ///< [in,out][optional][range(0, *pCount)] array of handle of devices.
                                                        ///< if count is less than the number of devices available, then driver
                                                        ///< shall only retrieve that number of devices.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_driver_object_t*>( hDriver )->dditable;
        auto pfnGet = dditable->ze.Device.pfnGet;
        if( nullptr == pfnGet )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDriver = reinterpret_cast<ze_driver_object_t*>( hDriver )->handle;

        // forward to device-driver
        result = pfnGet( hDriver, pCount, phDevices );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handles to loader handles
            for( size_t i = 0; ( nullptr != phDevices ) && ( i < *pCount ); ++i )
                phDevices[ i ] = reinterpret_cast<ze_device_handle_t>(
                    context->ze_device_factory.getInstance( phDevices[ i ], dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetRootDevice
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetRootDevice(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device object
        ze_device_handle_t* phRootDevice                ///< [in,out] parent root device.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetRootDevice = dditable->ze.Device.pfnGetRootDevice;
        if( nullptr == pfnGetRootDevice )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetRootDevice( hDevice, phRootDevice );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phRootDevice = reinterpret_cast<ze_device_handle_t>(
                context->ze_device_factory.getInstance( *phRootDevice, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetSubDevices
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetSubDevices(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device object
        uint32_t* pCount,                               ///< [in,out] pointer to the number of sub-devices.
                                                        ///< if count is zero, then the driver shall update the value with the
                                                        ///< total number of sub-devices available.
                                                        ///< if count is greater than the number of sub-devices available, then the
                                                        ///< driver shall update the value with the correct number of sub-devices available.
        ze_device_handle_t* phSubdevices                ///< [in,out][optional][range(0, *pCount)] array of handle of sub-devices.
                                                        ///< if count is less than the number of sub-devices available, then driver
                                                        ///< shall only retrieve that number of sub-devices.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetSubDevices = dditable->ze.Device.pfnGetSubDevices;
        if( nullptr == pfnGetSubDevices )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetSubDevices( hDevice, pCount, phSubdevices );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handles to loader handles
            for( size_t i = 0; ( nullptr != phSubdevices ) && ( i < *pCount ); ++i )
                phSubdevices[ i ] = reinterpret_cast<ze_device_handle_t>(
                    context->ze_device_factory.getInstance( phSubdevices[ i ], dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetProperties(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        ze_device_properties_t* pDeviceProperties       ///< [in,out] query result for device properties
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetProperties = dditable->ze.Device.pfnGetProperties;
        if( nullptr == pfnGetProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetProperties( hDevice, pDeviceProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetComputeProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetComputeProperties(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        ze_device_compute_properties_t* pComputeProperties  ///< [in,out] query result for compute properties
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetComputeProperties = dditable->ze.Device.pfnGetComputeProperties;
        if( nullptr == pfnGetComputeProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetComputeProperties( hDevice, pComputeProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetModuleProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetModuleProperties(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        ze_device_module_properties_t* pModuleProperties///< [in,out] query result for module properties
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetModuleProperties = dditable->ze.Device.pfnGetModuleProperties;
        if( nullptr == pfnGetModuleProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetModuleProperties( hDevice, pModuleProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetCommandQueueGroupProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetCommandQueueGroupProperties(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        uint32_t* pCount,                               ///< [in,out] pointer to the number of available command queue groups.
                                                        ///< If count is zero, then the driver shall update the value with the
                                                        ///< total number of command queue groups available.
                                                        ///< If count is less than the number of command queue groups available,
                                                        ///< then the driver shall only retrieve command queue group properties for
                                                        ///< the given number of command queue groups.
                                                        ///< If count is greater than or equal to the number of command queue
                                                        ///< groups available, then the driver shall retrieve command queue group
                                                        ///< properties for all available command queue groups.
        ze_command_queue_group_properties_t* pCommandQueueGroupProperties   ///< [in,out][optional][range(0, *pCount)] array of query results for
                                                        ///< command queue group properties.
                                                        ///< If count is less than the number of command queue groups available,
                                                        ///< then the driver shall only retrieve that number of command queue group properties.
                                                        ///< The order of properties in the array corresponds to the command queue
                                                        ///< group ordinal.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetCommandQueueGroupProperties = dditable->ze.Device.pfnGetCommandQueueGroupProperties;
        if( nullptr == pfnGetCommandQueueGroupProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetCommandQueueGroupProperties( hDevice, pCount, pCommandQueueGroupProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetMemoryProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetMemoryProperties(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        uint32_t* pCount,                               ///< [in,out] pointer to the number of memory properties.
                                                        ///< if count is zero, then the driver shall update the value with the
                                                        ///< total number of memory properties available.
                                                        ///< if count is greater than the number of memory properties available,
                                                        ///< then the driver shall update the value with the correct number of
                                                        ///< memory properties available.
        ze_device_memory_properties_t* pMemProperties   ///< [in,out][optional][range(0, *pCount)] array of query results for
                                                        ///< memory properties.
                                                        ///< if count is less than the number of memory properties available, then
                                                        ///< driver shall only retrieve that number of memory properties.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetMemoryProperties = dditable->ze.Device.pfnGetMemoryProperties;
        if( nullptr == pfnGetMemoryProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetMemoryProperties( hDevice, pCount, pMemProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetMemoryAccessProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetMemoryAccessProperties(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        ze_device_memory_access_properties_t* pMemAccessProperties  ///< [in,out] query result for memory access properties
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetMemoryAccessProperties = dditable->ze.Device.pfnGetMemoryAccessProperties;
        if( nullptr == pfnGetMemoryAccessProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetMemoryAccessProperties( hDevice, pMemAccessProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetCacheProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetCacheProperties(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        uint32_t* pCount,                               ///< [in,out] pointer to the number of cache properties.
                                                        ///< if count is zero, then the driver shall update the value with the
                                                        ///< total number of cache properties available.
                                                        ///< if count is greater than the number of cache properties available,
                                                        ///< then the driver shall update the value with the correct number of
                                                        ///< cache properties available.
        ze_device_cache_properties_t* pCacheProperties  ///< [in,out][optional][range(0, *pCount)] array of query results for cache properties.
                                                        ///< if count is less than the number of cache properties available, then
                                                        ///< driver shall only retrieve that number of cache properties.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetCacheProperties = dditable->ze.Device.pfnGetCacheProperties;
        if( nullptr == pfnGetCacheProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetCacheProperties( hDevice, pCount, pCacheProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetImageProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetImageProperties(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        ze_device_image_properties_t* pImageProperties  ///< [in,out] query result for image properties
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetImageProperties = dditable->ze.Device.pfnGetImageProperties;
        if( nullptr == pfnGetImageProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetImageProperties( hDevice, pImageProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetExternalMemoryProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetExternalMemoryProperties(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        ze_device_external_memory_properties_t* pExternalMemoryProperties   ///< [in,out] query result for external memory properties
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetExternalMemoryProperties = dditable->ze.Device.pfnGetExternalMemoryProperties;
        if( nullptr == pfnGetExternalMemoryProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetExternalMemoryProperties( hDevice, pExternalMemoryProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetP2PProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetP2PProperties(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device performing the access
        ze_device_handle_t hPeerDevice,                 ///< [in] handle of the peer device with the allocation
        ze_device_p2p_properties_t* pP2PProperties      ///< [in,out] Peer-to-Peer properties between source and peer device
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetP2PProperties = dditable->ze.Device.pfnGetP2PProperties;
        if( nullptr == pfnGetP2PProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // convert loader handle to driver handle
        hPeerDevice = reinterpret_cast<ze_device_object_t*>( hPeerDevice )->handle;

        // forward to device-driver
        result = pfnGetP2PProperties( hDevice, hPeerDevice, pP2PProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceCanAccessPeer
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceCanAccessPeer(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device performing the access
        ze_device_handle_t hPeerDevice,                 ///< [in] handle of the peer device with the allocation
        ze_bool_t* value                                ///< [out] returned access capability
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnCanAccessPeer = dditable->ze.Device.pfnCanAccessPeer;
        if( nullptr == pfnCanAccessPeer )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // convert loader handle to driver handle
        hPeerDevice = reinterpret_cast<ze_device_object_t*>( hPeerDevice )->handle;

        // forward to device-driver
        result = pfnCanAccessPeer( hDevice, hPeerDevice, value );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetStatus
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetStatus(
        ze_device_handle_t hDevice                      ///< [in] handle of the device
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetStatus = dditable->ze.Device.pfnGetStatus;
        if( nullptr == pfnGetStatus )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetStatus( hDevice );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetGlobalTimestamps
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetGlobalTimestamps(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        uint64_t* hostTimestamp,                        ///< [out] value of the Host's global timestamp in nanoseconds at the time
                                                        ///< of invoking the function.
        uint64_t* deviceTimestamp                       ///< [out] value of the Device's global timestamp in tick counts at the
                                                        ///< time of invoking the function.
                                                        ///< To get the devicetime stamp in nanoseconds, resolve the tick counts
                                                        ///< using the timestampValidBits as mask together with timerResolution
                                                        ///< members of the ::ze_device_properties_t structure.
                                                        ///< For example: deviceTimestampinNS = (deviceTimestamp &
                                                        ///< timestampValidBits) * 1/timerResolution.(when timer resolution is in cycle/sec)
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetGlobalTimestamps = dditable->ze.Device.pfnGetGlobalTimestamps;
        if( nullptr == pfnGetGlobalTimestamps )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetGlobalTimestamps( hDevice, hostTimestamp, deviceTimestamp );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceSynchronize
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceSynchronize(
        ze_device_handle_t hDevice                      ///< [in] handle of the device
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnSynchronize = dditable->ze.Device.pfnSynchronize;
        if( nullptr == pfnSynchronize )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnSynchronize( hDevice );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetAggregatedCopyOffloadIncrementValue
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetAggregatedCopyOffloadIncrementValue(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        uint32_t* incrementValue                        ///< [out] increment value that can be used for Event creation
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetAggregatedCopyOffloadIncrementValue = dditable->ze.Device.pfnGetAggregatedCopyOffloadIncrementValue;
        if( nullptr == pfnGetAggregatedCopyOffloadIncrementValue )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetAggregatedCopyOffloadIncrementValue( hDevice, incrementValue );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetCounterBasedEventMaxValue
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetCounterBasedEventMaxValue(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        uint64_t* maxValue                              ///< [out] maximum value that may appear under externally managed counter
                                                        ///< storage and that may be passed as `completionValue` when creating a
                                                        ///< Counter Based Event
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetCounterBasedEventMaxValue = dditable->ze.Device.pfnGetCounterBasedEventMaxValue;
        if( nullptr == pfnGetCounterBasedEventMaxValue )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetCounterBasedEventMaxValue( hDevice, maxValue );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetRuntimeRequirements
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetRuntimeRequirements(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        const void* pObjDesc,                           ///< [in] describes the object for which the requirements are to be
                                                        ///< gathered
        size_t* pSize,                                  ///< [in,out] size of requirements string in bytes.
        char* pRequirements                             ///< [in,out][optional] holds results of the query.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetRuntimeRequirements = dditable->ze.Device.pfnGetRuntimeRequirements;
        if( nullptr == pfnGetRuntimeRequirements )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetRuntimeRequirements( hDevice, pObjDesc, pSize, pRequirements );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetRuntimeRequirementsKey
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetRuntimeRequirementsKey(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        const char** pKey                               ///< [out] returned key
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetRuntimeRequirementsKey = dditable->ze.Device.pfnGetRuntimeRequirementsKey;
        if( nullptr == pfnGetRuntimeRequirementsKey )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetRuntimeRequirementsKey( hDevice, pKey );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceValidateRuntimeRequirements
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceValidateRuntimeRequirements(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        const char* pRequirements,                      ///< [in] requirements to be validated. Requirements should be
                                                        ///< null-terminated plain text representation of runtime requirements
                                                        ///< previously retrieved from the device.
        ze_validate_runtime_requirements_output_t* pOut ///< [in][out] Output of the validation call.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnValidateRuntimeRequirements = dditable->ze.Device.pfnValidateRuntimeRequirements;
        if( nullptr == pfnValidateRuntimeRequirements )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnValidateRuntimeRequirements( hDevice, pRequirements, pOut );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeContextCreate
    __zedlllocal ze_result_t ZE_APICALL
    zeContextCreate(
        ze_driver_handle_t hDriver,                     ///< [in] handle of the driver object
        const ze_context_desc_t* desc,                  ///< [in] pointer to context descriptor
        ze_context_handle_t* phContext                  ///< [out] pointer to handle of context object created
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_driver_object_t*>( hDriver )->dditable;
        auto pfnCreate = dditable->ze.Context.pfnCreate;
        if( nullptr == pfnCreate )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDriver = reinterpret_cast<ze_driver_object_t*>( hDriver )->handle;

        // forward to device-driver
        result = pfnCreate( hDriver, desc, phContext );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phContext = reinterpret_cast<ze_context_handle_t>(
                context->ze_context_factory.getInstance( *phContext, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeContextCreateEx
    __zedlllocal ze_result_t ZE_APICALL
    zeContextCreateEx(
        ze_driver_handle_t hDriver,                     ///< [in] handle of the driver object
        const ze_context_desc_t* desc,                  ///< [in] pointer to context descriptor
        uint32_t numDevices,                            ///< [in][optional] number of device handles; must be 0 if `nullptr ==
                                                        ///< phDevices`
        ze_device_handle_t* phDevices,                  ///< [in][optional][range(0, numDevices)] array of device handles which
                                                        ///< context has visibility.
                                                        ///< if nullptr, then all devices and any sub-devices supported by the
                                                        ///< driver instance are
                                                        ///< visible to the context.
                                                        ///< otherwise, the context only has visibility to the devices and any
                                                        ///< sub-devices of the
                                                        ///< devices in this array.
        ze_context_handle_t* phContext                  ///< [out] pointer to handle of context object created
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_driver_object_t*>( hDriver )->dditable;
        auto pfnCreateEx = dditable->ze.Context.pfnCreateEx;
        if( nullptr == pfnCreateEx )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDriver = reinterpret_cast<ze_driver_object_t*>( hDriver )->handle;

        // convert loader handles to driver handles
        auto phDevicesLocal = new ze_device_handle_t [numDevices];
        for( size_t i = 0; ( nullptr != phDevices ) && ( i < numDevices ); ++i )
            phDevicesLocal[ i ] = reinterpret_cast<ze_device_object_t*>( phDevices[ i ] )->handle;

        // forward to device-driver
        result = pfnCreateEx( hDriver, desc, numDevices, phDevicesLocal, phContext );
        delete []phDevicesLocal;

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phContext = reinterpret_cast<ze_context_handle_t>(
                context->ze_context_factory.getInstance( *phContext, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeContextDestroy
    __zedlllocal ze_result_t ZE_APICALL
    zeContextDestroy(
        ze_context_handle_t hContext                    ///< [in][release] handle of context object to destroy
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnDestroy = dditable->ze.Context.pfnDestroy;
        if( nullptr == pfnDestroy )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnDestroy( hContext );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_context_factory.release( hContext );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeContextGetStatus
    __zedlllocal ze_result_t ZE_APICALL
    zeContextGetStatus(
        ze_context_handle_t hContext                    ///< [in] handle of context object
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnGetStatus = dditable->ze.Context.pfnGetStatus;
        if( nullptr == pfnGetStatus )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnGetStatus( hContext );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandQueueCreate
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandQueueCreate(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_device_handle_t hDevice,                     ///< [in] handle of the device object
        const ze_command_queue_desc_t* desc,            ///< [in] pointer to command queue descriptor
        ze_command_queue_handle_t* phCommandQueue       ///< [out] pointer to handle of command queue object created
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnCreate = dditable->ze.CommandQueue.pfnCreate;
        if( nullptr == pfnCreate )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnCreate( hContext, hDevice, desc, phCommandQueue );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phCommandQueue = reinterpret_cast<ze_command_queue_handle_t>(
                context->ze_command_queue_factory.getInstance( *phCommandQueue, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandQueueDestroy
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandQueueDestroy(
        ze_command_queue_handle_t hCommandQueue         ///< [in][release] handle of command queue object to destroy
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_queue_object_t*>( hCommandQueue )->dditable;
        auto pfnDestroy = dditable->ze.CommandQueue.pfnDestroy;
        if( nullptr == pfnDestroy )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandQueue = reinterpret_cast<ze_command_queue_object_t*>( hCommandQueue )->handle;

        // forward to device-driver
        result = pfnDestroy( hCommandQueue );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_command_queue_factory.release( hCommandQueue );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandQueueExecuteCommandLists
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandQueueExecuteCommandLists(
        ze_command_queue_handle_t hCommandQueue,        ///< [in] handle of the command queue
        uint32_t numCommandLists,                       ///< [in] number of command lists to execute
        ze_command_list_handle_t* phCommandLists,       ///< [in][range(0, numCommandLists)] list of handles of the command lists
                                                        ///< to execute
        ze_fence_handle_t hFence                        ///< [in][optional] handle of the fence to signal on completion
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_queue_object_t*>( hCommandQueue )->dditable;
        auto pfnExecuteCommandLists = dditable->ze.CommandQueue.pfnExecuteCommandLists;
        if( nullptr == pfnExecuteCommandLists )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandQueue = reinterpret_cast<ze_command_queue_object_t*>( hCommandQueue )->handle;

        // convert loader handles to driver handles
        auto phCommandListsLocal = new ze_command_list_handle_t [numCommandLists];
        for( size_t i = 0; ( nullptr != phCommandLists ) && ( i < numCommandLists ); ++i )
            phCommandListsLocal[ i ] = reinterpret_cast<ze_command_list_object_t*>( phCommandLists[ i ] )->handle;

        // convert loader handle to driver handle
        hFence = ( hFence ) ? reinterpret_cast<ze_fence_object_t*>( hFence )->handle : nullptr;

        // forward to device-driver
        result = pfnExecuteCommandLists( hCommandQueue, numCommandLists, phCommandListsLocal, hFence );
        delete []phCommandListsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandQueueSynchronize
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandQueueSynchronize(
        ze_command_queue_handle_t hCommandQueue,        ///< [in] handle of the command queue
        uint64_t timeout                                ///< [in] if non-zero, then indicates the maximum time (in nanoseconds) to
                                                        ///< yield before returning ::ZE_RESULT_SUCCESS or ::ZE_RESULT_NOT_READY;
                                                        ///< if zero, then immediately returns the status of the command queue;
                                                        ///< if `UINT64_MAX`, then function will not return until complete or
                                                        ///< device is lost.
                                                        ///< Due to external dependencies, timeout may be rounded to the closest
                                                        ///< value allowed by the accuracy of those dependencies.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_queue_object_t*>( hCommandQueue )->dditable;
        auto pfnSynchronize = dditable->ze.CommandQueue.pfnSynchronize;
        if( nullptr == pfnSynchronize )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandQueue = reinterpret_cast<ze_command_queue_object_t*>( hCommandQueue )->handle;

        // forward to device-driver
        result = pfnSynchronize( hCommandQueue, timeout );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandQueueGetOrdinal
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandQueueGetOrdinal(
        ze_command_queue_handle_t hCommandQueue,        ///< [in] handle of the command queue
        uint32_t* pOrdinal                              ///< [out] command queue group ordinal
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_queue_object_t*>( hCommandQueue )->dditable;
        auto pfnGetOrdinal = dditable->ze.CommandQueue.pfnGetOrdinal;
        if( nullptr == pfnGetOrdinal )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandQueue = reinterpret_cast<ze_command_queue_object_t*>( hCommandQueue )->handle;

        // forward to device-driver
        result = pfnGetOrdinal( hCommandQueue, pOrdinal );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandQueueGetIndex
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandQueueGetIndex(
        ze_command_queue_handle_t hCommandQueue,        ///< [in] handle of the command queue
        uint32_t* pIndex                                ///< [out] command queue index within the group
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_queue_object_t*>( hCommandQueue )->dditable;
        auto pfnGetIndex = dditable->ze.CommandQueue.pfnGetIndex;
        if( nullptr == pfnGetIndex )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandQueue = reinterpret_cast<ze_command_queue_object_t*>( hCommandQueue )->handle;

        // forward to device-driver
        result = pfnGetIndex( hCommandQueue, pIndex );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandQueueGetFlags
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandQueueGetFlags(
        ze_command_queue_handle_t hCmdQueue,            ///< [in] handle of the command queue
        ze_command_queue_flags_t* pFlags                ///< [out] pointer to flags used during command queue creation
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_queue_object_t*>( hCmdQueue )->dditable;
        auto pfnGetFlags = dditable->ze.CommandQueue.pfnGetFlags;
        if( nullptr == pfnGetFlags )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCmdQueue = reinterpret_cast<ze_command_queue_object_t*>( hCmdQueue )->handle;

        // forward to device-driver
        result = pfnGetFlags( hCmdQueue, pFlags );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandQueueGetMode
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandQueueGetMode(
        ze_command_queue_handle_t hCmdQueue,            ///< [in] handle of the command queue
        ze_command_queue_mode_t* pMode                  ///< [out] pointer to mode used during command queue creation
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_queue_object_t*>( hCmdQueue )->dditable;
        auto pfnGetMode = dditable->ze.CommandQueue.pfnGetMode;
        if( nullptr == pfnGetMode )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCmdQueue = reinterpret_cast<ze_command_queue_object_t*>( hCmdQueue )->handle;

        // forward to device-driver
        result = pfnGetMode( hCmdQueue, pMode );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandQueueGetPriority
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandQueueGetPriority(
        ze_command_queue_handle_t hCmdQueue,            ///< [in] handle of the command queue
        ze_command_queue_priority_t* pPriority          ///< [out] pointer to priority used during command queue creation
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_queue_object_t*>( hCmdQueue )->dditable;
        auto pfnGetPriority = dditable->ze.CommandQueue.pfnGetPriority;
        if( nullptr == pfnGetPriority )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCmdQueue = reinterpret_cast<ze_command_queue_object_t*>( hCmdQueue )->handle;

        // forward to device-driver
        result = pfnGetPriority( hCmdQueue, pPriority );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListCreate
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListCreate(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_device_handle_t hDevice,                     ///< [in] handle of the device object
        const ze_command_list_desc_t* desc,             ///< [in] pointer to command list descriptor
        ze_command_list_handle_t* phCommandList         ///< [out] pointer to handle of command list object created
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnCreate = dditable->ze.CommandList.pfnCreate;
        if( nullptr == pfnCreate )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnCreate( hContext, hDevice, desc, phCommandList );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phCommandList = reinterpret_cast<ze_command_list_handle_t>(
                context->ze_command_list_factory.getInstance( *phCommandList, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListCreateImmediate
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListCreateImmediate(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_device_handle_t hDevice,                     ///< [in] handle of the device object
        const ze_command_queue_desc_t* altdesc,         ///< [in] pointer to command queue descriptor
        ze_command_list_handle_t* phCommandList         ///< [out] pointer to handle of command list object created
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnCreateImmediate = dditable->ze.CommandList.pfnCreateImmediate;
        if( nullptr == pfnCreateImmediate )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnCreateImmediate( hContext, hDevice, altdesc, phCommandList );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phCommandList = reinterpret_cast<ze_command_list_handle_t>(
                context->ze_command_list_factory.getInstance( *phCommandList, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListDestroy
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListDestroy(
        ze_command_list_handle_t hCommandList           ///< [in][release] handle of command list object to destroy
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnDestroy = dditable->ze.CommandList.pfnDestroy;
        if( nullptr == pfnDestroy )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnDestroy( hCommandList );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_command_list_factory.release( hCommandList );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListClose
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListClose(
        ze_command_list_handle_t hCommandList           ///< [in] handle of command list object to close
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnClose = dditable->ze.CommandList.pfnClose;
        if( nullptr == pfnClose )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnClose( hCommandList );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListReset
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListReset(
        ze_command_list_handle_t hCommandList           ///< [in] handle of command list object to reset
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnReset = dditable->ze.CommandList.pfnReset;
        if( nullptr == pfnReset )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnReset( hCommandList );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendWriteGlobalTimestamp
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendWriteGlobalTimestamp(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        uint64_t* dstptr,                               ///< [in,out] pointer to memory where timestamp value will be written; must
                                                        ///< be 8byte-aligned.
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before executing query;
                                                        ///< must be 0 if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before executing query
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendWriteGlobalTimestamp = dditable->ze.CommandList.pfnAppendWriteGlobalTimestamp;
        if( nullptr == pfnAppendWriteGlobalTimestamp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendWriteGlobalTimestamp( hCommandList, dstptr, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListHostSynchronize
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListHostSynchronize(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the immediate command list
        uint64_t timeout                                ///< [in] if non-zero, then indicates the maximum time (in nanoseconds) to
                                                        ///< yield before returning ::ZE_RESULT_SUCCESS or ::ZE_RESULT_NOT_READY;
                                                        ///< if zero, then immediately returns the status of the immediate command list;
                                                        ///< if `UINT64_MAX`, then function will not return until complete or
                                                        ///< device is lost.
                                                        ///< Due to external dependencies, timeout may be rounded to the closest
                                                        ///< value allowed by the accuracy of those dependencies.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnHostSynchronize = dditable->ze.CommandList.pfnHostSynchronize;
        if( nullptr == pfnHostSynchronize )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnHostSynchronize( hCommandList, timeout );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListGetDeviceHandle
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListGetDeviceHandle(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        ze_device_handle_t* phDevice                    ///< [out] handle of the device on which the command list was created
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnGetDeviceHandle = dditable->ze.CommandList.pfnGetDeviceHandle;
        if( nullptr == pfnGetDeviceHandle )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnGetDeviceHandle( hCommandList, phDevice );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phDevice = reinterpret_cast<ze_device_handle_t>(
                context->ze_device_factory.getInstance( *phDevice, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListGetContextHandle
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListGetContextHandle(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        ze_context_handle_t* phContext                  ///< [out] handle of the context on which the command list was created
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnGetContextHandle = dditable->ze.CommandList.pfnGetContextHandle;
        if( nullptr == pfnGetContextHandle )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnGetContextHandle( hCommandList, phContext );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phContext = reinterpret_cast<ze_context_handle_t>(
                context->ze_context_factory.getInstance( *phContext, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListGetOrdinal
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListGetOrdinal(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        uint32_t* pOrdinal                              ///< [out] command queue group ordinal to which command list is submitted
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnGetOrdinal = dditable->ze.CommandList.pfnGetOrdinal;
        if( nullptr == pfnGetOrdinal )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnGetOrdinal( hCommandList, pOrdinal );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListImmediateGetIndex
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListImmediateGetIndex(
        ze_command_list_handle_t hCommandListImmediate, ///< [in] handle of the immediate command list
        uint32_t* pIndex                                ///< [out] command queue index within the group to which the immediate
                                                        ///< command list is submitted
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandListImmediate )->dditable;
        auto pfnImmediateGetIndex = dditable->ze.CommandList.pfnImmediateGetIndex;
        if( nullptr == pfnImmediateGetIndex )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandListImmediate = reinterpret_cast<ze_command_list_object_t*>( hCommandListImmediate )->handle;

        // forward to device-driver
        result = pfnImmediateGetIndex( hCommandListImmediate, pIndex );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListIsImmediate
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListIsImmediate(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        ze_bool_t* pIsImmediate                         ///< [out] Boolean indicating whether the command list is an immediate
                                                        ///< command list (true) or not (false)
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnIsImmediate = dditable->ze.CommandList.pfnIsImmediate;
        if( nullptr == pfnIsImmediate )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnIsImmediate( hCommandList, pIsImmediate );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListGetFlags
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListGetFlags(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        ze_command_list_flags_t* pFlags                 ///< [out] pointer to flags used during command list creation
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnGetFlags = dditable->ze.CommandList.pfnGetFlags;
        if( nullptr == pfnGetFlags )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnGetFlags( hCommandList, pFlags );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListImmediateGetFlags
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListImmediateGetFlags(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        ze_command_queue_flags_t* pFlags                ///< [out] pointer to flags used during command list creation
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnImmediateGetFlags = dditable->ze.CommandList.pfnImmediateGetFlags;
        if( nullptr == pfnImmediateGetFlags )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnImmediateGetFlags( hCommandList, pFlags );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListImmediateGetMode
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListImmediateGetMode(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        ze_command_queue_mode_t* pMode                  ///< [out] pointer to mode used during command list creation
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnImmediateGetMode = dditable->ze.CommandList.pfnImmediateGetMode;
        if( nullptr == pfnImmediateGetMode )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnImmediateGetMode( hCommandList, pMode );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListImmediateGetPriority
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListImmediateGetPriority(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        ze_command_queue_priority_t* pPriority          ///< [out] pointer to priority used during command list creation
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnImmediateGetPriority = dditable->ze.CommandList.pfnImmediateGetPriority;
        if( nullptr == pfnImmediateGetPriority )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnImmediateGetPriority( hCommandList, pPriority );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendBarrier
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendBarrier(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before executing barrier;
                                                        ///< must be 0 if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before executing barrier
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendBarrier = dditable->ze.CommandList.pfnAppendBarrier;
        if( nullptr == pfnAppendBarrier )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendBarrier( hCommandList, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendMemoryRangesBarrier
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendMemoryRangesBarrier(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        uint32_t numRanges,                             ///< [in] number of memory ranges
        const size_t* pRangeSizes,                      ///< [in][range(0, numRanges)] array of sizes of memory range
        const void** pRanges,                           ///< [in][range(0, numRanges)] array of memory ranges
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before executing barrier;
                                                        ///< must be 0 if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before executing barrier
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendMemoryRangesBarrier = dditable->ze.CommandList.pfnAppendMemoryRangesBarrier;
        if( nullptr == pfnAppendMemoryRangesBarrier )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendMemoryRangesBarrier( hCommandList, numRanges, pRangeSizes, pRanges, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeContextSystemBarrier
    __zedlllocal ze_result_t ZE_APICALL
    zeContextSystemBarrier(
        ze_context_handle_t hContext,                   ///< [in] handle of context object
        ze_device_handle_t hDevice                      ///< [in] handle of the device
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnSystemBarrier = dditable->ze.Context.pfnSystemBarrier;
        if( nullptr == pfnSystemBarrier )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnSystemBarrier( hContext, hDevice );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendMemoryCopy
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendMemoryCopy(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of command list
        void* dstptr,                                   ///< [in] pointer to destination memory to copy to
        const void* srcptr,                             ///< [in] pointer to source memory to copy from
        size_t size,                                    ///< [in] size in bytes to copy
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendMemoryCopy = dditable->ze.CommandList.pfnAppendMemoryCopy;
        if( nullptr == pfnAppendMemoryCopy )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendMemoryCopy( hCommandList, dstptr, srcptr, size, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendMemoryCopyWithParameters
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendMemoryCopyWithParameters(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of command list
        void* dstptr,                                   ///< [in] pointer to destination memory to copy to
        const void* srcptr,                             ///< [in] pointer to source memory to copy from
        size_t size,                                    ///< [in] size in bytes to copy
        const void* pNext,                              ///< [in][optional] additional extensions passed to the function
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendMemoryCopyWithParameters = dditable->ze.CommandList.pfnAppendMemoryCopyWithParameters;
        if( nullptr == pfnAppendMemoryCopyWithParameters )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendMemoryCopyWithParameters( hCommandList, dstptr, srcptr, size, pNext, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendMemoryFill
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendMemoryFill(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of command list
        void* ptr,                                      ///< [in] pointer to memory to initialize
        const void* pattern,                            ///< [in] pointer to value to initialize memory to
        size_t pattern_size,                            ///< [in] size in bytes of the value to initialize memory to
        size_t size,                                    ///< [in] size in bytes to initialize
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendMemoryFill = dditable->ze.CommandList.pfnAppendMemoryFill;
        if( nullptr == pfnAppendMemoryFill )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendMemoryFill( hCommandList, ptr, pattern, pattern_size, size, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendMemoryFillWithParameters
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendMemoryFillWithParameters(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of command list
        void* ptr,                                      ///< [in] pointer to memory to initialize
        const void* pattern,                            ///< [in] pointer to value to initialize memory to
        size_t pattern_size,                            ///< [in] size in bytes of the value to initialize memory to
        size_t size,                                    ///< [in] size in bytes to initialize
        const void* pNext,                              ///< [in][optional] additional extensions passed to the function
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendMemoryFillWithParameters = dditable->ze.CommandList.pfnAppendMemoryFillWithParameters;
        if( nullptr == pfnAppendMemoryFillWithParameters )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendMemoryFillWithParameters( hCommandList, ptr, pattern, pattern_size, size, pNext, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendMemoryCopyRegion
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendMemoryCopyRegion(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of command list
        void* dstptr,                                   ///< [in] pointer to destination memory to copy to
        const ze_copy_region_t* dstRegion,              ///< [in] pointer to destination region to copy to
        uint32_t dstPitch,                              ///< [in] destination pitch in bytes
        uint32_t dstSlicePitch,                         ///< [in] destination slice pitch in bytes. This is required for 3D region
                                                        ///< copies where the `depth` member of ::ze_copy_region_t is not 0,
                                                        ///< otherwise it's ignored.
        const void* srcptr,                             ///< [in] pointer to source memory to copy from
        const ze_copy_region_t* srcRegion,              ///< [in] pointer to source region to copy from
        uint32_t srcPitch,                              ///< [in] source pitch in bytes
        uint32_t srcSlicePitch,                         ///< [in] source slice pitch in bytes. This is required for 3D region
                                                        ///< copies where the `depth` member of ::ze_copy_region_t is not 0,
                                                        ///< otherwise it's ignored.
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendMemoryCopyRegion = dditable->ze.CommandList.pfnAppendMemoryCopyRegion;
        if( nullptr == pfnAppendMemoryCopyRegion )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendMemoryCopyRegion( hCommandList, dstptr, dstRegion, dstPitch, dstSlicePitch, srcptr, srcRegion, srcPitch, srcSlicePitch, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendMemoryCopyFromContext
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendMemoryCopyFromContext(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of command list
        void* dstptr,                                   ///< [in] pointer to destination memory to copy to
        ze_context_handle_t hContextSrc,                ///< [in] handle of source context object
        const void* srcptr,                             ///< [in] pointer to source memory to copy from
        size_t size,                                    ///< [in] size in bytes to copy
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendMemoryCopyFromContext = dditable->ze.CommandList.pfnAppendMemoryCopyFromContext;
        if( nullptr == pfnAppendMemoryCopyFromContext )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hContextSrc = reinterpret_cast<ze_context_object_t*>( hContextSrc )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendMemoryCopyFromContext( hCommandList, dstptr, hContextSrc, srcptr, size, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendImageCopy
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendImageCopy(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of command list
        ze_image_handle_t hDstImage,                    ///< [in] handle of destination image to copy to
        ze_image_handle_t hSrcImage,                    ///< [in] handle of source image to copy from
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendImageCopy = dditable->ze.CommandList.pfnAppendImageCopy;
        if( nullptr == pfnAppendImageCopy )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hDstImage = reinterpret_cast<ze_image_object_t*>( hDstImage )->handle;

        // convert loader handle to driver handle
        hSrcImage = reinterpret_cast<ze_image_object_t*>( hSrcImage )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendImageCopy( hCommandList, hDstImage, hSrcImage, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendImageCopyRegion
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendImageCopyRegion(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of command list
        ze_image_handle_t hDstImage,                    ///< [in] handle of destination image to copy to
        ze_image_handle_t hSrcImage,                    ///< [in] handle of source image to copy from
        const ze_image_region_t* pDstRegion,            ///< [in][optional] destination region descriptor
        const ze_image_region_t* pSrcRegion,            ///< [in][optional] source region descriptor
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendImageCopyRegion = dditable->ze.CommandList.pfnAppendImageCopyRegion;
        if( nullptr == pfnAppendImageCopyRegion )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hDstImage = reinterpret_cast<ze_image_object_t*>( hDstImage )->handle;

        // convert loader handle to driver handle
        hSrcImage = reinterpret_cast<ze_image_object_t*>( hSrcImage )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendImageCopyRegion( hCommandList, hDstImage, hSrcImage, pDstRegion, pSrcRegion, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendImageCopyToMemory
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendImageCopyToMemory(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of command list
        void* dstptr,                                   ///< [in] pointer to destination memory to copy to
        ze_image_handle_t hSrcImage,                    ///< [in] handle of source image to copy from
        const ze_image_region_t* pSrcRegion,            ///< [in][optional] source region descriptor
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendImageCopyToMemory = dditable->ze.CommandList.pfnAppendImageCopyToMemory;
        if( nullptr == pfnAppendImageCopyToMemory )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hSrcImage = reinterpret_cast<ze_image_object_t*>( hSrcImage )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendImageCopyToMemory( hCommandList, dstptr, hSrcImage, pSrcRegion, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendImageCopyFromMemory
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendImageCopyFromMemory(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of command list
        ze_image_handle_t hDstImage,                    ///< [in] handle of destination image to copy to
        const void* srcptr,                             ///< [in] pointer to source memory to copy from
        const ze_image_region_t* pDstRegion,            ///< [in][optional] destination region descriptor
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendImageCopyFromMemory = dditable->ze.CommandList.pfnAppendImageCopyFromMemory;
        if( nullptr == pfnAppendImageCopyFromMemory )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hDstImage = reinterpret_cast<ze_image_object_t*>( hDstImage )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendImageCopyFromMemory( hCommandList, hDstImage, srcptr, pDstRegion, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendMemoryPrefetch
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendMemoryPrefetch(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of command list
        const void* ptr,                                ///< [in] pointer to start of the memory range to prefetch
        size_t size                                     ///< [in] size in bytes of the memory range to prefetch
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendMemoryPrefetch = dditable->ze.CommandList.pfnAppendMemoryPrefetch;
        if( nullptr == pfnAppendMemoryPrefetch )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnAppendMemoryPrefetch( hCommandList, ptr, size );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendMemAdvise
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendMemAdvise(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of command list
        ze_device_handle_t hDevice,                     ///< [in] device associated with the memory advice
        const void* ptr,                                ///< [in] Pointer to the start of the memory range
        size_t size,                                    ///< [in] Size in bytes of the memory range
        ze_memory_advice_t advice                       ///< [in] Memory advice for the memory range
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendMemAdvise = dditable->ze.CommandList.pfnAppendMemAdvise;
        if( nullptr == pfnAppendMemAdvise )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnAppendMemAdvise( hCommandList, hDevice, ptr, size, advice );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventPoolCreate
    __zedlllocal ze_result_t ZE_APICALL
    zeEventPoolCreate(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        const ze_event_pool_desc_t* desc,               ///< [in] pointer to event pool descriptor
        uint32_t numDevices,                            ///< [in][optional] number of device handles; must be 0 if `nullptr ==
                                                        ///< phDevices`
        ze_device_handle_t* phDevices,                  ///< [in][optional][range(0, numDevices)] array of device handles which
                                                        ///< have visibility to the event pool.
                                                        ///< if nullptr, then event pool is visible to all devices supported by the
                                                        ///< driver instance.
        ze_event_pool_handle_t* phEventPool             ///< [out] pointer handle of event pool object created
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnCreate = dditable->ze.EventPool.pfnCreate;
        if( nullptr == pfnCreate )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handles to driver handles
        auto phDevicesLocal = new ze_device_handle_t [numDevices];
        for( size_t i = 0; ( nullptr != phDevices ) && ( i < numDevices ); ++i )
            phDevicesLocal[ i ] = reinterpret_cast<ze_device_object_t*>( phDevices[ i ] )->handle;

        // forward to device-driver
        result = pfnCreate( hContext, desc, numDevices, phDevicesLocal, phEventPool );
        delete []phDevicesLocal;

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phEventPool = reinterpret_cast<ze_event_pool_handle_t>(
                context->ze_event_pool_factory.getInstance( *phEventPool, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventPoolDestroy
    __zedlllocal ze_result_t ZE_APICALL
    zeEventPoolDestroy(
        ze_event_pool_handle_t hEventPool               ///< [in][release] handle of event pool object to destroy
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_pool_object_t*>( hEventPool )->dditable;
        auto pfnDestroy = dditable->ze.EventPool.pfnDestroy;
        if( nullptr == pfnDestroy )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEventPool = reinterpret_cast<ze_event_pool_object_t*>( hEventPool )->handle;

        // forward to device-driver
        result = pfnDestroy( hEventPool );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_event_pool_factory.release( hEventPool );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventCreate
    __zedlllocal ze_result_t ZE_APICALL
    zeEventCreate(
        ze_event_pool_handle_t hEventPool,              ///< [in] handle of the event pool
        const ze_event_desc_t* desc,                    ///< [in] pointer to event descriptor
        ze_event_handle_t* phEvent                      ///< [out] pointer to handle of event object created
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_pool_object_t*>( hEventPool )->dditable;
        auto pfnCreate = dditable->ze.Event.pfnCreate;
        if( nullptr == pfnCreate )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEventPool = reinterpret_cast<ze_event_pool_object_t*>( hEventPool )->handle;

        // forward to device-driver
        result = pfnCreate( hEventPool, desc, phEvent );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phEvent = reinterpret_cast<ze_event_handle_t>(
                context->ze_event_factory.getInstance( *phEvent, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventCounterBasedCreate
    __zedlllocal ze_result_t ZE_APICALL
    zeEventCounterBasedCreate(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_device_handle_t hDevice,                     ///< [in] handle of the device object
        const ze_event_counter_based_desc_t* desc,      ///< [in] pointer to counter based event descriptor
        ze_event_handle_t* phEvent                      ///< [out] pointer to handle of event object created
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnCounterBasedCreate = dditable->ze.Event.pfnCounterBasedCreate;
        if( nullptr == pfnCounterBasedCreate )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnCounterBasedCreate( hContext, hDevice, desc, phEvent );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phEvent = reinterpret_cast<ze_event_handle_t>(
                context->ze_event_factory.getInstance( *phEvent, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventDestroy
    __zedlllocal ze_result_t ZE_APICALL
    zeEventDestroy(
        ze_event_handle_t hEvent                        ///< [in][release] handle of event object to destroy
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_object_t*>( hEvent )->dditable;
        auto pfnDestroy = dditable->ze.Event.pfnDestroy;
        if( nullptr == pfnDestroy )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEvent = reinterpret_cast<ze_event_object_t*>( hEvent )->handle;

        // forward to device-driver
        result = pfnDestroy( hEvent );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_event_factory.release( hEvent );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventPoolGetIpcHandle
    __zedlllocal ze_result_t ZE_APICALL
    zeEventPoolGetIpcHandle(
        ze_event_pool_handle_t hEventPool,              ///< [in] handle of event pool object
        ze_ipc_event_pool_handle_t* phIpc               ///< [out] Returned IPC event handle
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_pool_object_t*>( hEventPool )->dditable;
        auto pfnGetIpcHandle = dditable->ze.EventPool.pfnGetIpcHandle;
        if( nullptr == pfnGetIpcHandle )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEventPool = reinterpret_cast<ze_event_pool_object_t*>( hEventPool )->handle;

        // forward to device-driver
        result = pfnGetIpcHandle( hEventPool, phIpc );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventPoolPutIpcHandle
    __zedlllocal ze_result_t ZE_APICALL
    zeEventPoolPutIpcHandle(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object associated with the IPC event pool
                                                        ///< handle
        ze_ipc_event_pool_handle_t hIpc                 ///< [in] IPC event pool handle
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnPutIpcHandle = dditable->ze.EventPool.pfnPutIpcHandle;
        if( nullptr == pfnPutIpcHandle )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnPutIpcHandle( hContext, hIpc );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventPoolOpenIpcHandle
    __zedlllocal ze_result_t ZE_APICALL
    zeEventPoolOpenIpcHandle(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object to associate with the IPC event pool
                                                        ///< handle
        ze_ipc_event_pool_handle_t hIpc,                ///< [in] IPC event pool handle
        ze_event_pool_handle_t* phEventPool             ///< [out] pointer handle of event pool object created
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnOpenIpcHandle = dditable->ze.EventPool.pfnOpenIpcHandle;
        if( nullptr == pfnOpenIpcHandle )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnOpenIpcHandle( hContext, hIpc, phEventPool );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phEventPool = reinterpret_cast<ze_event_pool_handle_t>(
                context->ze_event_pool_factory.getInstance( *phEventPool, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventPoolCloseIpcHandle
    __zedlllocal ze_result_t ZE_APICALL
    zeEventPoolCloseIpcHandle(
        ze_event_pool_handle_t hEventPool               ///< [in][release] handle of event pool object
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_pool_object_t*>( hEventPool )->dditable;
        auto pfnCloseIpcHandle = dditable->ze.EventPool.pfnCloseIpcHandle;
        if( nullptr == pfnCloseIpcHandle )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEventPool = reinterpret_cast<ze_event_pool_object_t*>( hEventPool )->handle;

        // forward to device-driver
        result = pfnCloseIpcHandle( hEventPool );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_event_pool_factory.release( hEventPool );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventCounterBasedGetIpcHandle
    __zedlllocal ze_result_t ZE_APICALL
    zeEventCounterBasedGetIpcHandle(
        ze_event_handle_t hEvent,                       ///< [in] handle of event object
        ze_ipc_event_counter_based_handle_t* phIpc      ///< [out] Returned IPC event handle
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_object_t*>( hEvent )->dditable;
        auto pfnCounterBasedGetIpcHandle = dditable->ze.Event.pfnCounterBasedGetIpcHandle;
        if( nullptr == pfnCounterBasedGetIpcHandle )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEvent = reinterpret_cast<ze_event_object_t*>( hEvent )->handle;

        // forward to device-driver
        result = pfnCounterBasedGetIpcHandle( hEvent, phIpc );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventCounterBasedOpenIpcHandle
    __zedlllocal ze_result_t ZE_APICALL
    zeEventCounterBasedOpenIpcHandle(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object to associate with the IPC event
                                                        ///< handle
        ze_ipc_event_counter_based_handle_t hIpc,       ///< [in] IPC event handle
        ze_event_handle_t* phEvent                      ///< [out] pointer handle of event object created
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnCounterBasedOpenIpcHandle = dditable->ze.Event.pfnCounterBasedOpenIpcHandle;
        if( nullptr == pfnCounterBasedOpenIpcHandle )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnCounterBasedOpenIpcHandle( hContext, hIpc, phEvent );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phEvent = reinterpret_cast<ze_event_handle_t>(
                context->ze_event_factory.getInstance( *phEvent, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventCounterBasedCloseIpcHandle
    __zedlllocal ze_result_t ZE_APICALL
    zeEventCounterBasedCloseIpcHandle(
        ze_event_handle_t hEvent                        ///< [in][release] handle of event object
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_object_t*>( hEvent )->dditable;
        auto pfnCounterBasedCloseIpcHandle = dditable->ze.Event.pfnCounterBasedCloseIpcHandle;
        if( nullptr == pfnCounterBasedCloseIpcHandle )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEvent = reinterpret_cast<ze_event_object_t*>( hEvent )->handle;

        // forward to device-driver
        result = pfnCounterBasedCloseIpcHandle( hEvent );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_event_factory.release( hEvent );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventCounterBasedGetDeviceAddress
    __zedlllocal ze_result_t ZE_APICALL
    zeEventCounterBasedGetDeviceAddress(
        ze_event_handle_t hEvent,                       ///< [in] handle of event object
        uint64_t* completionValue,                      ///< [in][out] completion value
        uint64_t* deviceAddress                         ///< [in][out] counter device address
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_object_t*>( hEvent )->dditable;
        auto pfnCounterBasedGetDeviceAddress = dditable->ze.Event.pfnCounterBasedGetDeviceAddress;
        if( nullptr == pfnCounterBasedGetDeviceAddress )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEvent = reinterpret_cast<ze_event_object_t*>( hEvent )->handle;

        // forward to device-driver
        result = pfnCounterBasedGetDeviceAddress( hEvent, completionValue, deviceAddress );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendSignalEvent
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendSignalEvent(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        ze_event_handle_t hEvent                        ///< [in] handle of the event
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendSignalEvent = dditable->ze.CommandList.pfnAppendSignalEvent;
        if( nullptr == pfnAppendSignalEvent )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hEvent = reinterpret_cast<ze_event_object_t*>( hEvent )->handle;

        // forward to device-driver
        result = pfnAppendSignalEvent( hCommandList, hEvent );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendWaitOnEvents
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendWaitOnEvents(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        uint32_t numEvents,                             ///< [in] number of events to wait on before continuing
        ze_event_handle_t* phEvents                     ///< [in][range(0, numEvents)] handles of the events to wait on before
                                                        ///< continuing
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendWaitOnEvents = dditable->ze.CommandList.pfnAppendWaitOnEvents;
        if( nullptr == pfnAppendWaitOnEvents )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handles to driver handles
        auto phEventsLocal = new ze_event_handle_t [numEvents];
        for( size_t i = 0; ( nullptr != phEvents ) && ( i < numEvents ); ++i )
            phEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendWaitOnEvents( hCommandList, numEvents, phEventsLocal );
        delete []phEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventHostSignal
    __zedlllocal ze_result_t ZE_APICALL
    zeEventHostSignal(
        ze_event_handle_t hEvent                        ///< [in] handle of the event
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_object_t*>( hEvent )->dditable;
        auto pfnHostSignal = dditable->ze.Event.pfnHostSignal;
        if( nullptr == pfnHostSignal )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEvent = reinterpret_cast<ze_event_object_t*>( hEvent )->handle;

        // forward to device-driver
        result = pfnHostSignal( hEvent );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventHostSynchronize
    __zedlllocal ze_result_t ZE_APICALL
    zeEventHostSynchronize(
        ze_event_handle_t hEvent,                       ///< [in] handle of the event
        uint64_t timeout                                ///< [in] if non-zero, then indicates the maximum time (in nanoseconds) to
                                                        ///< yield before returning ::ZE_RESULT_SUCCESS or ::ZE_RESULT_NOT_READY;
                                                        ///< if zero, then operates exactly like ::zeEventQueryStatus;
                                                        ///< if `UINT64_MAX`, then function will not return until complete or
                                                        ///< device is lost.
                                                        ///< Due to external dependencies, timeout may be rounded to the closest
                                                        ///< value allowed by the accuracy of those dependencies.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_object_t*>( hEvent )->dditable;
        auto pfnHostSynchronize = dditable->ze.Event.pfnHostSynchronize;
        if( nullptr == pfnHostSynchronize )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEvent = reinterpret_cast<ze_event_object_t*>( hEvent )->handle;

        // forward to device-driver
        result = pfnHostSynchronize( hEvent, timeout );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventQueryStatus
    __zedlllocal ze_result_t ZE_APICALL
    zeEventQueryStatus(
        ze_event_handle_t hEvent                        ///< [in] handle of the event
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_object_t*>( hEvent )->dditable;
        auto pfnQueryStatus = dditable->ze.Event.pfnQueryStatus;
        if( nullptr == pfnQueryStatus )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEvent = reinterpret_cast<ze_event_object_t*>( hEvent )->handle;

        // forward to device-driver
        result = pfnQueryStatus( hEvent );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendEventReset
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendEventReset(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        ze_event_handle_t hEvent                        ///< [in] handle of the event
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendEventReset = dditable->ze.CommandList.pfnAppendEventReset;
        if( nullptr == pfnAppendEventReset )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hEvent = reinterpret_cast<ze_event_object_t*>( hEvent )->handle;

        // forward to device-driver
        result = pfnAppendEventReset( hCommandList, hEvent );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventHostReset
    __zedlllocal ze_result_t ZE_APICALL
    zeEventHostReset(
        ze_event_handle_t hEvent                        ///< [in] handle of the event
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_object_t*>( hEvent )->dditable;
        auto pfnHostReset = dditable->ze.Event.pfnHostReset;
        if( nullptr == pfnHostReset )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEvent = reinterpret_cast<ze_event_object_t*>( hEvent )->handle;

        // forward to device-driver
        result = pfnHostReset( hEvent );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventQueryKernelTimestamp
    __zedlllocal ze_result_t ZE_APICALL
    zeEventQueryKernelTimestamp(
        ze_event_handle_t hEvent,                       ///< [in] handle of the event
        ze_kernel_timestamp_result_t* dstptr            ///< [in,out] pointer to memory for where timestamp result will be written.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_object_t*>( hEvent )->dditable;
        auto pfnQueryKernelTimestamp = dditable->ze.Event.pfnQueryKernelTimestamp;
        if( nullptr == pfnQueryKernelTimestamp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEvent = reinterpret_cast<ze_event_object_t*>( hEvent )->handle;

        // forward to device-driver
        result = pfnQueryKernelTimestamp( hEvent, dstptr );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendQueryKernelTimestamps
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendQueryKernelTimestamps(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        uint32_t numEvents,                             ///< [in] the number of timestamp events to query
        ze_event_handle_t* phEvents,                    ///< [in][range(0, numEvents)] handles of timestamp events to query
        void* dstptr,                                   ///< [in,out] pointer to memory where ::ze_kernel_timestamp_result_t will
                                                        ///< be written; must be size-aligned.
        const size_t* pOffsets,                         ///< [in][optional][range(0, numEvents)] offset, in bytes, to write
                                                        ///< results; address must be 4byte-aligned and offsets must be
                                                        ///< size-aligned.
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before executing query;
                                                        ///< must be 0 if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before executing query
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendQueryKernelTimestamps = dditable->ze.CommandList.pfnAppendQueryKernelTimestamps;
        if( nullptr == pfnAppendQueryKernelTimestamps )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handles to driver handles
        auto phEventsLocal = new ze_event_handle_t [numEvents];
        for( size_t i = 0; ( nullptr != phEvents ) && ( i < numEvents ); ++i )
            phEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phEvents[ i ] )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendQueryKernelTimestamps( hCommandList, numEvents, phEventsLocal, dstptr, pOffsets, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phEventsLocal;
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventGetEventPool
    __zedlllocal ze_result_t ZE_APICALL
    zeEventGetEventPool(
        ze_event_handle_t hEvent,                       ///< [in] handle of the event
        ze_event_pool_handle_t* phEventPool             ///< [out] handle of the event pool for the event
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_object_t*>( hEvent )->dditable;
        auto pfnGetEventPool = dditable->ze.Event.pfnGetEventPool;
        if( nullptr == pfnGetEventPool )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEvent = reinterpret_cast<ze_event_object_t*>( hEvent )->handle;

        // forward to device-driver
        result = pfnGetEventPool( hEvent, phEventPool );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phEventPool = reinterpret_cast<ze_event_pool_handle_t>(
                context->ze_event_pool_factory.getInstance( *phEventPool, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventGetSignalScope
    __zedlllocal ze_result_t ZE_APICALL
    zeEventGetSignalScope(
        ze_event_handle_t hEvent,                       ///< [in] handle of the event
        ze_event_scope_flags_t* pSignalScope            ///< [out] signal event scope. This is the scope of relevant cache
                                                        ///< hierarchies that are flushed on a signal action before the event is
                                                        ///< triggered. May be 0 or a valid combination of ::ze_event_scope_flag_t.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_object_t*>( hEvent )->dditable;
        auto pfnGetSignalScope = dditable->ze.Event.pfnGetSignalScope;
        if( nullptr == pfnGetSignalScope )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEvent = reinterpret_cast<ze_event_object_t*>( hEvent )->handle;

        // forward to device-driver
        result = pfnGetSignalScope( hEvent, pSignalScope );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventGetWaitScope
    __zedlllocal ze_result_t ZE_APICALL
    zeEventGetWaitScope(
        ze_event_handle_t hEvent,                       ///< [in] handle of the event
        ze_event_scope_flags_t* pWaitScope              ///< [out] wait event scope. This is the scope of relevant cache
                                                        ///< hierarchies invalidated on a wait action after the event is complete.
                                                        ///< May be 0 or a valid combination of ::ze_event_scope_flag_t.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_object_t*>( hEvent )->dditable;
        auto pfnGetWaitScope = dditable->ze.Event.pfnGetWaitScope;
        if( nullptr == pfnGetWaitScope )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEvent = reinterpret_cast<ze_event_object_t*>( hEvent )->handle;

        // forward to device-driver
        result = pfnGetWaitScope( hEvent, pWaitScope );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventPoolGetContextHandle
    __zedlllocal ze_result_t ZE_APICALL
    zeEventPoolGetContextHandle(
        ze_event_pool_handle_t hEventPool,              ///< [in] handle of the event pool
        ze_context_handle_t* phContext                  ///< [out] handle of the context on which the event pool was created
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_pool_object_t*>( hEventPool )->dditable;
        auto pfnGetContextHandle = dditable->ze.EventPool.pfnGetContextHandle;
        if( nullptr == pfnGetContextHandle )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEventPool = reinterpret_cast<ze_event_pool_object_t*>( hEventPool )->handle;

        // forward to device-driver
        result = pfnGetContextHandle( hEventPool, phContext );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phContext = reinterpret_cast<ze_context_handle_t>(
                context->ze_context_factory.getInstance( *phContext, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventPoolGetFlags
    __zedlllocal ze_result_t ZE_APICALL
    zeEventPoolGetFlags(
        ze_event_pool_handle_t hEventPool,              ///< [in] handle of the event pool
        ze_event_pool_flags_t* pFlags                   ///< [out] creation flags used to create the event pool; may be 0 or a
                                                        ///< valid combination of ::ze_event_pool_flag_t
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_pool_object_t*>( hEventPool )->dditable;
        auto pfnGetFlags = dditable->ze.EventPool.pfnGetFlags;
        if( nullptr == pfnGetFlags )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEventPool = reinterpret_cast<ze_event_pool_object_t*>( hEventPool )->handle;

        // forward to device-driver
        result = pfnGetFlags( hEventPool, pFlags );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventGetCounterBasedFlags
    __zedlllocal ze_result_t ZE_APICALL
    zeEventGetCounterBasedFlags(
        ze_event_handle_t hEvent,                       ///< [in] handle of the event
        ze_event_counter_based_flags_t* pFlags          ///< [out] flags used during creation of a counter based event; may be 0 or
                                                        ///< a valid combination of ::ze_event_counter_based_flag_t
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_object_t*>( hEvent )->dditable;
        auto pfnGetCounterBasedFlags = dditable->ze.Event.pfnGetCounterBasedFlags;
        if( nullptr == pfnGetCounterBasedFlags )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEvent = reinterpret_cast<ze_event_object_t*>( hEvent )->handle;

        // forward to device-driver
        result = pfnGetCounterBasedFlags( hEvent, pFlags );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeFenceCreate
    __zedlllocal ze_result_t ZE_APICALL
    zeFenceCreate(
        ze_command_queue_handle_t hCommandQueue,        ///< [in] handle of command queue
        const ze_fence_desc_t* desc,                    ///< [in] pointer to fence descriptor
        ze_fence_handle_t* phFence                      ///< [out] pointer to handle of fence object created
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_queue_object_t*>( hCommandQueue )->dditable;
        auto pfnCreate = dditable->ze.Fence.pfnCreate;
        if( nullptr == pfnCreate )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandQueue = reinterpret_cast<ze_command_queue_object_t*>( hCommandQueue )->handle;

        // forward to device-driver
        result = pfnCreate( hCommandQueue, desc, phFence );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phFence = reinterpret_cast<ze_fence_handle_t>(
                context->ze_fence_factory.getInstance( *phFence, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeFenceDestroy
    __zedlllocal ze_result_t ZE_APICALL
    zeFenceDestroy(
        ze_fence_handle_t hFence                        ///< [in][release] handle of fence object to destroy
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_fence_object_t*>( hFence )->dditable;
        auto pfnDestroy = dditable->ze.Fence.pfnDestroy;
        if( nullptr == pfnDestroy )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hFence = reinterpret_cast<ze_fence_object_t*>( hFence )->handle;

        // forward to device-driver
        result = pfnDestroy( hFence );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_fence_factory.release( hFence );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeFenceHostSynchronize
    __zedlllocal ze_result_t ZE_APICALL
    zeFenceHostSynchronize(
        ze_fence_handle_t hFence,                       ///< [in] handle of the fence
        uint64_t timeout                                ///< [in] if non-zero, then indicates the maximum time (in nanoseconds) to
                                                        ///< yield before returning ::ZE_RESULT_SUCCESS or ::ZE_RESULT_NOT_READY;
                                                        ///< if zero, then operates exactly like ::zeFenceQueryStatus;
                                                        ///< if `UINT64_MAX`, then function will not return until complete or
                                                        ///< device is lost.
                                                        ///< Due to external dependencies, timeout may be rounded to the closest
                                                        ///< value allowed by the accuracy of those dependencies.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_fence_object_t*>( hFence )->dditable;
        auto pfnHostSynchronize = dditable->ze.Fence.pfnHostSynchronize;
        if( nullptr == pfnHostSynchronize )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hFence = reinterpret_cast<ze_fence_object_t*>( hFence )->handle;

        // forward to device-driver
        result = pfnHostSynchronize( hFence, timeout );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeFenceQueryStatus
    __zedlllocal ze_result_t ZE_APICALL
    zeFenceQueryStatus(
        ze_fence_handle_t hFence                        ///< [in] handle of the fence
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_fence_object_t*>( hFence )->dditable;
        auto pfnQueryStatus = dditable->ze.Fence.pfnQueryStatus;
        if( nullptr == pfnQueryStatus )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hFence = reinterpret_cast<ze_fence_object_t*>( hFence )->handle;

        // forward to device-driver
        result = pfnQueryStatus( hFence );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeFenceReset
    __zedlllocal ze_result_t ZE_APICALL
    zeFenceReset(
        ze_fence_handle_t hFence                        ///< [in] handle of the fence
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_fence_object_t*>( hFence )->dditable;
        auto pfnReset = dditable->ze.Fence.pfnReset;
        if( nullptr == pfnReset )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hFence = reinterpret_cast<ze_fence_object_t*>( hFence )->handle;

        // forward to device-driver
        result = pfnReset( hFence );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeImageGetProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeImageGetProperties(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        const ze_image_desc_t* desc,                    ///< [in] pointer to image descriptor
        ze_image_properties_t* pImageProperties         ///< [out] pointer to image properties
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetProperties = dditable->ze.Image.pfnGetProperties;
        if( nullptr == pfnGetProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetProperties( hDevice, desc, pImageProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeImageCreate
    __zedlllocal ze_result_t ZE_APICALL
    zeImageCreate(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        const ze_image_desc_t* desc,                    ///< [in] pointer to image descriptor
        ze_image_handle_t* phImage                      ///< [out] pointer to handle of image object created
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnCreate = dditable->ze.Image.pfnCreate;
        if( nullptr == pfnCreate )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnCreate( hContext, hDevice, desc, phImage );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            ze_image_handle_t internalHandlePtr = *phImage;
            *phImage = reinterpret_cast<ze_image_handle_t>(
                context->ze_image_factory.getInstance( *phImage, dditable ) );
            // convert loader handle to driver handle and store in map
            {
                std::lock_guard<std::mutex> lock(context->image_handle_map_lock);
                context->image_handle_map.insert({context->ze_image_factory.getInstance( internalHandlePtr, dditable ), internalHandlePtr});
            }
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeImageDestroy
    __zedlllocal ze_result_t ZE_APICALL
    zeImageDestroy(
        ze_image_handle_t hImage                        ///< [in][release] handle of image object to destroy
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_image_object_t*>( hImage )->dditable;
        auto pfnDestroy = dditable->ze.Image.pfnDestroy;
        if( nullptr == pfnDestroy )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // remove the handle from the kernel arugment map
        {
            std::lock_guard<std::mutex> lock(context->image_handle_map_lock);
            context->image_handle_map.erase(reinterpret_cast<ze_image_object_t*>(hImage));
        }
        // convert loader handle to driver handle
        hImage = reinterpret_cast<ze_image_object_t*>( hImage )->handle;

        // forward to device-driver
        result = pfnDestroy( hImage );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_image_factory.release( hImage );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeMemAllocShared
    __zedlllocal ze_result_t ZE_APICALL
    zeMemAllocShared(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        const ze_device_mem_alloc_desc_t* device_desc,  ///< [in] pointer to device memory allocation descriptor
        const ze_host_mem_alloc_desc_t* host_desc,      ///< [in] pointer to host memory allocation descriptor
        size_t size,                                    ///< [in] size in bytes to allocate; must be less than or equal to the
                                                        ///< `maxMemAllocSize` member of ::ze_device_properties_t
        size_t alignment,                               ///< [in] minimum alignment in bytes for the allocation; must be a power of
                                                        ///< two
        ze_device_handle_t hDevice,                     ///< [in][optional] device handle to associate with
        void** pptr                                     ///< [out] pointer to shared allocation
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnAllocShared = dditable->ze.Mem.pfnAllocShared;
        if( nullptr == pfnAllocShared )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = ( hDevice ) ? reinterpret_cast<ze_device_object_t*>( hDevice )->handle : nullptr;

        // forward to device-driver
        result = pfnAllocShared( hContext, device_desc, host_desc, size, alignment, hDevice, pptr );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeMemAllocDevice
    __zedlllocal ze_result_t ZE_APICALL
    zeMemAllocDevice(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        const ze_device_mem_alloc_desc_t* device_desc,  ///< [in] pointer to device memory allocation descriptor
        size_t size,                                    ///< [in] size in bytes to allocate; must be less than or equal to the
                                                        ///< `maxMemAllocSize` member of ::ze_device_properties_t
        size_t alignment,                               ///< [in] minimum alignment in bytes for the allocation; must be a power of
                                                        ///< two
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        void** pptr                                     ///< [out] pointer to device allocation
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnAllocDevice = dditable->ze.Mem.pfnAllocDevice;
        if( nullptr == pfnAllocDevice )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnAllocDevice( hContext, device_desc, size, alignment, hDevice, pptr );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeMemAllocHost
    __zedlllocal ze_result_t ZE_APICALL
    zeMemAllocHost(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        const ze_host_mem_alloc_desc_t* host_desc,      ///< [in] pointer to host memory allocation descriptor
        size_t size,                                    ///< [in] size in bytes to allocate; must be less than or equal to the
                                                        ///< `maxMemAllocSize` member of ::ze_device_properties_t
        size_t alignment,                               ///< [in] minimum alignment in bytes for the allocation; must be a power of
                                                        ///< two
        void** pptr                                     ///< [out] pointer to host allocation
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnAllocHost = dditable->ze.Mem.pfnAllocHost;
        if( nullptr == pfnAllocHost )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnAllocHost( hContext, host_desc, size, alignment, pptr );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeMemFree
    __zedlllocal ze_result_t ZE_APICALL
    zeMemFree(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        void* ptr                                       ///< [in][release] pointer to memory to free
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnFree = dditable->ze.Mem.pfnFree;
        if( nullptr == pfnFree )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnFree( hContext, ptr );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeMemGetAllocProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeMemGetAllocProperties(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        const void* ptr,                                ///< [in] memory pointer to query
        ze_memory_allocation_properties_t* pMemAllocProperties, ///< [in,out] query result for memory allocation properties
        ze_device_handle_t* phDevice                    ///< [out][optional] device associated with this allocation
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnGetAllocProperties = dditable->ze.Mem.pfnGetAllocProperties;
        if( nullptr == pfnGetAllocProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnGetAllocProperties( hContext, ptr, pMemAllocProperties, phDevice );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            if( nullptr != phDevice )
                *phDevice = reinterpret_cast<ze_device_handle_t>(
                    context->ze_device_factory.getInstance( *phDevice, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeMemGetAddressRange
    __zedlllocal ze_result_t ZE_APICALL
    zeMemGetAddressRange(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        const void* ptr,                                ///< [in] memory pointer to query
        void** pBase,                                   ///< [in,out][optional] base address of the allocation
        size_t* pSize                                   ///< [in,out][optional] size of the allocation
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnGetAddressRange = dditable->ze.Mem.pfnGetAddressRange;
        if( nullptr == pfnGetAddressRange )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnGetAddressRange( hContext, ptr, pBase, pSize );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeMemGetIpcHandle
    __zedlllocal ze_result_t ZE_APICALL
    zeMemGetIpcHandle(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        const void* ptr,                                ///< [in] pointer to the device memory allocation
        ze_ipc_mem_handle_t* pIpcHandle                 ///< [out] Returned IPC memory handle
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnGetIpcHandle = dditable->ze.Mem.pfnGetIpcHandle;
        if( nullptr == pfnGetIpcHandle )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnGetIpcHandle( hContext, ptr, pIpcHandle );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeMemGetIpcHandleFromFileDescriptorExp
    __zedlllocal ze_result_t ZE_APICALL
    zeMemGetIpcHandleFromFileDescriptorExp(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        uint64_t handle,                                ///< [in] file descriptor
        ze_ipc_mem_handle_t* pIpcHandle                 ///< [out] Returned IPC memory handle
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnGetIpcHandleFromFileDescriptorExp = dditable->ze.MemExp.pfnGetIpcHandleFromFileDescriptorExp;
        if( nullptr == pfnGetIpcHandleFromFileDescriptorExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnGetIpcHandleFromFileDescriptorExp( hContext, handle, pIpcHandle );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeMemGetFileDescriptorFromIpcHandleExp
    __zedlllocal ze_result_t ZE_APICALL
    zeMemGetFileDescriptorFromIpcHandleExp(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_ipc_mem_handle_t ipcHandle,                  ///< [in] IPC memory handle
        uint64_t* pHandle                               ///< [out] Returned file descriptor
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnGetFileDescriptorFromIpcHandleExp = dditable->ze.MemExp.pfnGetFileDescriptorFromIpcHandleExp;
        if( nullptr == pfnGetFileDescriptorFromIpcHandleExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnGetFileDescriptorFromIpcHandleExp( hContext, ipcHandle, pHandle );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeMemPutIpcHandle
    __zedlllocal ze_result_t ZE_APICALL
    zeMemPutIpcHandle(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_ipc_mem_handle_t handle                      ///< [in] IPC memory handle
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnPutIpcHandle = dditable->ze.Mem.pfnPutIpcHandle;
        if( nullptr == pfnPutIpcHandle )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnPutIpcHandle( hContext, handle );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeMemOpenIpcHandle
    __zedlllocal ze_result_t ZE_APICALL
    zeMemOpenIpcHandle(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_device_handle_t hDevice,                     ///< [in] handle of the device to associate with the IPC memory handle
        ze_ipc_mem_handle_t handle,                     ///< [in] IPC memory handle
        ze_ipc_memory_flags_t flags,                    ///< [in] flags controlling the operation.
                                                        ///< must be 0 (default) or a valid combination of ::ze_ipc_memory_flag_t.
        void** pptr                                     ///< [out] pointer to device allocation in this process
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnOpenIpcHandle = dditable->ze.Mem.pfnOpenIpcHandle;
        if( nullptr == pfnOpenIpcHandle )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnOpenIpcHandle( hContext, hDevice, handle, flags, pptr );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeMemCloseIpcHandle
    __zedlllocal ze_result_t ZE_APICALL
    zeMemCloseIpcHandle(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        const void* ptr                                 ///< [in][release] pointer to device allocation in this process
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnCloseIpcHandle = dditable->ze.Mem.pfnCloseIpcHandle;
        if( nullptr == pfnCloseIpcHandle )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnCloseIpcHandle( hContext, ptr );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeMemSetAtomicAccessAttributeExp
    __zedlllocal ze_result_t ZE_APICALL
    zeMemSetAtomicAccessAttributeExp(
        ze_context_handle_t hContext,                   ///< [in] handle of context
        ze_device_handle_t hDevice,                     ///< [in] device associated with the memory advice
        const void* ptr,                                ///< [in] Pointer to the start of the memory range
        size_t size,                                    ///< [in] Size in bytes of the memory range
        ze_memory_atomic_attr_exp_flags_t attr          ///< [in] Atomic access attributes to set for the specified range.
                                                        ///< Must be 0 (default) or a valid combination of ::ze_memory_atomic_attr_exp_flag_t.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnSetAtomicAccessAttributeExp = dditable->ze.MemExp.pfnSetAtomicAccessAttributeExp;
        if( nullptr == pfnSetAtomicAccessAttributeExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnSetAtomicAccessAttributeExp( hContext, hDevice, ptr, size, attr );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeMemGetAtomicAccessAttributeExp
    __zedlllocal ze_result_t ZE_APICALL
    zeMemGetAtomicAccessAttributeExp(
        ze_context_handle_t hContext,                   ///< [in] handle of context
        ze_device_handle_t hDevice,                     ///< [in] device associated with the memory advice
        const void* ptr,                                ///< [in] Pointer to the start of the memory range
        size_t size,                                    ///< [in] Size in bytes of the memory range
        ze_memory_atomic_attr_exp_flags_t* pAttr        ///< [out] Atomic access attributes for the specified range
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnGetAtomicAccessAttributeExp = dditable->ze.MemExp.pfnGetAtomicAccessAttributeExp;
        if( nullptr == pfnGetAtomicAccessAttributeExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetAtomicAccessAttributeExp( hContext, hDevice, ptr, size, pAttr );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeModuleCreate
    __zedlllocal ze_result_t ZE_APICALL
    zeModuleCreate(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        const ze_module_desc_t* desc,                   ///< [in] pointer to module descriptor
        ze_module_handle_t* phModule,                   ///< [out] pointer to handle of module object created
        ze_module_build_log_handle_t* phBuildLog        ///< [out][optional] pointer to handle of module's build log.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnCreate = dditable->ze.Module.pfnCreate;
        if( nullptr == pfnCreate )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnCreate( hContext, hDevice, desc, phModule, phBuildLog );

        try
        {
            // convert driver handle to loader handle
            *phModule = reinterpret_cast<ze_module_handle_t>(
                context->ze_module_factory.getInstance( *phModule, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            if( nullptr != phBuildLog )
                *phBuildLog = reinterpret_cast<ze_module_build_log_handle_t>(
                    context->ze_module_build_log_factory.getInstance( *phBuildLog, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeModuleDestroy
    __zedlllocal ze_result_t ZE_APICALL
    zeModuleDestroy(
        ze_module_handle_t hModule                      ///< [in][release] handle of the module
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_module_object_t*>( hModule )->dditable;
        auto pfnDestroy = dditable->ze.Module.pfnDestroy;
        if( nullptr == pfnDestroy )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hModule = reinterpret_cast<ze_module_object_t*>( hModule )->handle;

        // forward to device-driver
        result = pfnDestroy( hModule );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_module_factory.release( hModule );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeModuleDynamicLink
    __zedlllocal ze_result_t ZE_APICALL
    zeModuleDynamicLink(
        uint32_t numModules,                            ///< [in] number of modules to be linked pointed to by phModules.
        ze_module_handle_t* phModules,                  ///< [in][range(0, numModules)] pointer to an array of modules to
                                                        ///< dynamically link together.
        ze_module_build_log_handle_t* phLinkLog         ///< [out][optional] pointer to handle of dynamic link log.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_module_object_t*>( phModules[ 0 ] )->dditable;
        auto pfnDynamicLink = dditable->ze.Module.pfnDynamicLink;
        if( nullptr == pfnDynamicLink )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handles to driver handles
        auto phModulesLocal = new ze_module_handle_t [numModules];
        for( size_t i = 0; ( nullptr != phModules ) && ( i < numModules ); ++i )
            phModulesLocal[ i ] = reinterpret_cast<ze_module_object_t*>( phModules[ i ] )->handle;

        // forward to device-driver
        result = pfnDynamicLink( numModules, phModulesLocal, phLinkLog );
        delete []phModulesLocal;

        try
        {
            // convert driver handle to loader handle
            if( nullptr != phLinkLog )
                *phLinkLog = reinterpret_cast<ze_module_build_log_handle_t>(
                    context->ze_module_build_log_factory.getInstance( *phLinkLog, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        if( ZE_RESULT_SUCCESS != result )
            return result;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeModuleBuildLogDestroy
    __zedlllocal ze_result_t ZE_APICALL
    zeModuleBuildLogDestroy(
        ze_module_build_log_handle_t hModuleBuildLog    ///< [in][release] handle of the module build log object.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_module_build_log_object_t*>( hModuleBuildLog )->dditable;
        auto pfnDestroy = dditable->ze.ModuleBuildLog.pfnDestroy;
        if( nullptr == pfnDestroy )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hModuleBuildLog = reinterpret_cast<ze_module_build_log_object_t*>( hModuleBuildLog )->handle;

        // forward to device-driver
        result = pfnDestroy( hModuleBuildLog );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_module_build_log_factory.release( hModuleBuildLog );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeModuleBuildLogGetString
    __zedlllocal ze_result_t ZE_APICALL
    zeModuleBuildLogGetString(
        ze_module_build_log_handle_t hModuleBuildLog,   ///< [in] handle of the module build log object.
        size_t* pSize,                                  ///< [in,out] size of build log string.
        char* pBuildLog                                 ///< [in,out][optional] pointer to null-terminated string of the log.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_module_build_log_object_t*>( hModuleBuildLog )->dditable;
        auto pfnGetString = dditable->ze.ModuleBuildLog.pfnGetString;
        if( nullptr == pfnGetString )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hModuleBuildLog = reinterpret_cast<ze_module_build_log_object_t*>( hModuleBuildLog )->handle;

        // forward to device-driver
        result = pfnGetString( hModuleBuildLog, pSize, pBuildLog );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeModuleGetNativeBinary
    __zedlllocal ze_result_t ZE_APICALL
    zeModuleGetNativeBinary(
        ze_module_handle_t hModule,                     ///< [in] handle of the module
        size_t* pSize,                                  ///< [in,out] size of native binary in bytes.
        uint8_t* pModuleNativeBinary                    ///< [in,out][optional] byte pointer to native binary
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_module_object_t*>( hModule )->dditable;
        auto pfnGetNativeBinary = dditable->ze.Module.pfnGetNativeBinary;
        if( nullptr == pfnGetNativeBinary )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hModule = reinterpret_cast<ze_module_object_t*>( hModule )->handle;

        // forward to device-driver
        result = pfnGetNativeBinary( hModule, pSize, pModuleNativeBinary );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeModuleGetGlobalPointer
    __zedlllocal ze_result_t ZE_APICALL
    zeModuleGetGlobalPointer(
        ze_module_handle_t hModule,                     ///< [in] handle of the module
        const char* pGlobalName,                        ///< [in] name of global variable in module
        size_t* pSize,                                  ///< [in,out][optional] size of global variable
        void** pptr                                     ///< [in,out][optional] device visible pointer
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_module_object_t*>( hModule )->dditable;
        auto pfnGetGlobalPointer = dditable->ze.Module.pfnGetGlobalPointer;
        if( nullptr == pfnGetGlobalPointer )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hModule = reinterpret_cast<ze_module_object_t*>( hModule )->handle;

        // forward to device-driver
        result = pfnGetGlobalPointer( hModule, pGlobalName, pSize, pptr );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeModuleGetKernelNames
    __zedlllocal ze_result_t ZE_APICALL
    zeModuleGetKernelNames(
        ze_module_handle_t hModule,                     ///< [in] handle of the module
        uint32_t* pCount,                               ///< [in,out] pointer to the number of names.
                                                        ///< if count is zero, then the driver shall update the value with the
                                                        ///< total number of names available.
                                                        ///< if count is greater than the number of names available, then the
                                                        ///< driver shall update the value with the correct number of names available.
        const char** pNames                             ///< [in,out][optional][range(0, *pCount)] array of names of functions.
                                                        ///< if count is less than the number of names available, then driver shall
                                                        ///< only retrieve that number of names.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_module_object_t*>( hModule )->dditable;
        auto pfnGetKernelNames = dditable->ze.Module.pfnGetKernelNames;
        if( nullptr == pfnGetKernelNames )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hModule = reinterpret_cast<ze_module_object_t*>( hModule )->handle;

        // forward to device-driver
        result = pfnGetKernelNames( hModule, pCount, pNames );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeModuleGetProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeModuleGetProperties(
        ze_module_handle_t hModule,                     ///< [in] handle of the module
        ze_module_properties_t* pModuleProperties       ///< [in,out] query result for module properties.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_module_object_t*>( hModule )->dditable;
        auto pfnGetProperties = dditable->ze.Module.pfnGetProperties;
        if( nullptr == pfnGetProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hModule = reinterpret_cast<ze_module_object_t*>( hModule )->handle;

        // forward to device-driver
        result = pfnGetProperties( hModule, pModuleProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeKernelCreate
    __zedlllocal ze_result_t ZE_APICALL
    zeKernelCreate(
        ze_module_handle_t hModule,                     ///< [in] handle of the module
        const ze_kernel_desc_t* desc,                   ///< [in] pointer to kernel descriptor
        ze_kernel_handle_t* phKernel                    ///< [out] handle of the Function object
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_module_object_t*>( hModule )->dditable;
        auto pfnCreate = dditable->ze.Kernel.pfnCreate;
        if( nullptr == pfnCreate )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hModule = reinterpret_cast<ze_module_object_t*>( hModule )->handle;

        // forward to device-driver
        result = pfnCreate( hModule, desc, phKernel );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phKernel = reinterpret_cast<ze_kernel_handle_t>(
                context->ze_kernel_factory.getInstance( *phKernel, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeKernelDestroy
    __zedlllocal ze_result_t ZE_APICALL
    zeKernelDestroy(
        ze_kernel_handle_t hKernel                      ///< [in][release] handle of the kernel object
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_kernel_object_t*>( hKernel )->dditable;
        auto pfnDestroy = dditable->ze.Kernel.pfnDestroy;
        if( nullptr == pfnDestroy )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // forward to device-driver
        result = pfnDestroy( hKernel );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_kernel_factory.release( hKernel );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeModuleGetFunctionPointer
    __zedlllocal ze_result_t ZE_APICALL
    zeModuleGetFunctionPointer(
        ze_module_handle_t hModule,                     ///< [in] handle of the module
        const char* pFunctionName,                      ///< [in] Name of function to retrieve function pointer for.
        void** pfnFunction                              ///< [out] pointer to function.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_module_object_t*>( hModule )->dditable;
        auto pfnGetFunctionPointer = dditable->ze.Module.pfnGetFunctionPointer;
        if( nullptr == pfnGetFunctionPointer )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hModule = reinterpret_cast<ze_module_object_t*>( hModule )->handle;

        // forward to device-driver
        result = pfnGetFunctionPointer( hModule, pFunctionName, pfnFunction );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeKernelSetGroupSize
    __zedlllocal ze_result_t ZE_APICALL
    zeKernelSetGroupSize(
        ze_kernel_handle_t hKernel,                     ///< [in] handle of the kernel object
        uint32_t groupSizeX,                            ///< [in] group size for X dimension to use for this kernel
        uint32_t groupSizeY,                            ///< [in] group size for Y dimension to use for this kernel
        uint32_t groupSizeZ                             ///< [in] group size for Z dimension to use for this kernel
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_kernel_object_t*>( hKernel )->dditable;
        auto pfnSetGroupSize = dditable->ze.Kernel.pfnSetGroupSize;
        if( nullptr == pfnSetGroupSize )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // forward to device-driver
        result = pfnSetGroupSize( hKernel, groupSizeX, groupSizeY, groupSizeZ );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeKernelSuggestGroupSize
    __zedlllocal ze_result_t ZE_APICALL
    zeKernelSuggestGroupSize(
        ze_kernel_handle_t hKernel,                     ///< [in] handle of the kernel object
        uint32_t globalSizeX,                           ///< [in] global width for X dimension
        uint32_t globalSizeY,                           ///< [in] global width for Y dimension
        uint32_t globalSizeZ,                           ///< [in] global width for Z dimension
        uint32_t* groupSizeX,                           ///< [out] recommended size of group for X dimension
        uint32_t* groupSizeY,                           ///< [out] recommended size of group for Y dimension
        uint32_t* groupSizeZ                            ///< [out] recommended size of group for Z dimension
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_kernel_object_t*>( hKernel )->dditable;
        auto pfnSuggestGroupSize = dditable->ze.Kernel.pfnSuggestGroupSize;
        if( nullptr == pfnSuggestGroupSize )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // forward to device-driver
        result = pfnSuggestGroupSize( hKernel, globalSizeX, globalSizeY, globalSizeZ, groupSizeX, groupSizeY, groupSizeZ );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeKernelSuggestMaxCooperativeGroupCount
    __zedlllocal ze_result_t ZE_APICALL
    zeKernelSuggestMaxCooperativeGroupCount(
        ze_kernel_handle_t hKernel,                     ///< [in] handle of the kernel object
        uint32_t* totalGroupCount                       ///< [out] recommended total group count.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_kernel_object_t*>( hKernel )->dditable;
        auto pfnSuggestMaxCooperativeGroupCount = dditable->ze.Kernel.pfnSuggestMaxCooperativeGroupCount;
        if( nullptr == pfnSuggestMaxCooperativeGroupCount )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // forward to device-driver
        result = pfnSuggestMaxCooperativeGroupCount( hKernel, totalGroupCount );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeKernelSetArgumentValue
    __zedlllocal ze_result_t ZE_APICALL
    zeKernelSetArgumentValue(
        ze_kernel_handle_t hKernel,                     ///< [in] handle of the kernel object
        uint32_t argIndex,                              ///< [in] argument index in range [0, num args - 1]
        size_t argSize,                                 ///< [in] size of argument type
        const void* pArgValue                           ///< [in][optional] argument value represented as matching arg type. If
                                                        ///< null then argument value is considered null.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_kernel_object_t*>( hKernel )->dditable;
        auto pfnSetArgumentValue = dditable->ze.Kernel.pfnSetArgumentValue;
        if( nullptr == pfnSetArgumentValue )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // convert pArgValue to correct handle if applicable
        void *internalArgValue = const_cast<void *>(pArgValue);
        if (pArgValue) {
            // check if the arg value is a translated handle
            ze_image_object_t **imageHandle = static_cast<ze_image_object_t **>(internalArgValue);
            ze_sampler_object_t **samplerHandle = static_cast<ze_sampler_object_t **>(internalArgValue);
            {
                std::lock_guard<std::mutex> image_lock(context->image_handle_map_lock);
                std::lock_guard<std::mutex> sampler_lock(context->sampler_handle_map_lock);
                if( context->image_handle_map.find(*imageHandle) != context->image_handle_map.end() ) {
                    internalArgValue = &context->image_handle_map[*imageHandle];
                } else if( context->sampler_handle_map.find(*samplerHandle) != context->sampler_handle_map.end() ) {
                    internalArgValue = &context->sampler_handle_map[*samplerHandle];
                }
            }
        }
        // forward to device-driver
        result = pfnSetArgumentValue( hKernel, argIndex, argSize, const_cast<const void *>(internalArgValue) );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeKernelSetIndirectAccess
    __zedlllocal ze_result_t ZE_APICALL
    zeKernelSetIndirectAccess(
        ze_kernel_handle_t hKernel,                     ///< [in] handle of the kernel object
        ze_kernel_indirect_access_flags_t flags         ///< [in] kernel indirect access flags
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_kernel_object_t*>( hKernel )->dditable;
        auto pfnSetIndirectAccess = dditable->ze.Kernel.pfnSetIndirectAccess;
        if( nullptr == pfnSetIndirectAccess )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // forward to device-driver
        result = pfnSetIndirectAccess( hKernel, flags );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeKernelGetIndirectAccess
    __zedlllocal ze_result_t ZE_APICALL
    zeKernelGetIndirectAccess(
        ze_kernel_handle_t hKernel,                     ///< [in] handle of the kernel object
        ze_kernel_indirect_access_flags_t* pFlags       ///< [out] query result for kernel indirect access flags.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_kernel_object_t*>( hKernel )->dditable;
        auto pfnGetIndirectAccess = dditable->ze.Kernel.pfnGetIndirectAccess;
        if( nullptr == pfnGetIndirectAccess )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // forward to device-driver
        result = pfnGetIndirectAccess( hKernel, pFlags );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeKernelGetSourceAttributes
    __zedlllocal ze_result_t ZE_APICALL
    zeKernelGetSourceAttributes(
        ze_kernel_handle_t hKernel,                     ///< [in] handle of the kernel object
        uint32_t* pSize,                                ///< [in,out] pointer to size of string in bytes, including
                                                        ///< null-terminating character.
        char** pString                                  ///< [in,out][optional] pointer to application-managed character array
                                                        ///< (string data).
                                                        ///< If NULL, the string length of the kernel source attributes, including
                                                        ///< a null-terminating character, is returned in pSize. Otherwise, pString
                                                        ///< must point to valid application memory that is greater than or equal
                                                        ///< to *pSize bytes in length, and on return the pointed-to string will
                                                        ///< contain a space-separated list of kernel source attributes. Note: This
                                                        ///< API was originally intended to ship with a char *pString, however this
                                                        ///< typo was introduced. Thus the API has to stay this way for backwards
                                                        ///< compatible reasons. It can be corrected in v2.0. Suggestion is to
                                                        ///< create your own char *pString and then pass to this API with &pString.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_kernel_object_t*>( hKernel )->dditable;
        auto pfnGetSourceAttributes = dditable->ze.Kernel.pfnGetSourceAttributes;
        if( nullptr == pfnGetSourceAttributes )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // forward to device-driver
        result = pfnGetSourceAttributes( hKernel, pSize, pString );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeKernelSetCacheConfig
    __zedlllocal ze_result_t ZE_APICALL
    zeKernelSetCacheConfig(
        ze_kernel_handle_t hKernel,                     ///< [in] handle of the kernel object
        ze_cache_config_flags_t flags                   ///< [in] cache configuration.
                                                        ///< must be 0 (default configuration) or a valid combination of ::ze_cache_config_flag_t.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_kernel_object_t*>( hKernel )->dditable;
        auto pfnSetCacheConfig = dditable->ze.Kernel.pfnSetCacheConfig;
        if( nullptr == pfnSetCacheConfig )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // forward to device-driver
        result = pfnSetCacheConfig( hKernel, flags );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeKernelGetProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeKernelGetProperties(
        ze_kernel_handle_t hKernel,                     ///< [in] handle of the kernel object
        ze_kernel_properties_t* pKernelProperties       ///< [in,out] query result for kernel properties.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_kernel_object_t*>( hKernel )->dditable;
        auto pfnGetProperties = dditable->ze.Kernel.pfnGetProperties;
        if( nullptr == pfnGetProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // forward to device-driver
        result = pfnGetProperties( hKernel, pKernelProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeKernelGetName
    __zedlllocal ze_result_t ZE_APICALL
    zeKernelGetName(
        ze_kernel_handle_t hKernel,                     ///< [in] handle of the kernel object
        size_t* pSize,                                  ///< [in,out] size of kernel name string, including null terminator, in
                                                        ///< bytes.
        char* pName                                     ///< [in,out][optional] char pointer to kernel name.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_kernel_object_t*>( hKernel )->dditable;
        auto pfnGetName = dditable->ze.Kernel.pfnGetName;
        if( nullptr == pfnGetName )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // forward to device-driver
        result = pfnGetName( hKernel, pSize, pName );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendLaunchKernel
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendLaunchKernel(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        ze_kernel_handle_t hKernel,                     ///< [in] handle of the kernel object
        const ze_group_count_t* pLaunchFuncArgs,        ///< [in] thread group launch arguments
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendLaunchKernel = dditable->ze.CommandList.pfnAppendLaunchKernel;
        if( nullptr == pfnAppendLaunchKernel )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendLaunchKernel( hCommandList, hKernel, pLaunchFuncArgs, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendLaunchKernelWithParameters
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendLaunchKernelWithParameters(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        ze_kernel_handle_t hKernel,                     ///< [in] handle of the kernel object
        const ze_group_count_t* pGroupCounts,           ///< [in] thread group launch arguments
        const void * pNext,                             ///< [in][optional] additional parameters passed to the function
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendLaunchKernelWithParameters = dditable->ze.CommandList.pfnAppendLaunchKernelWithParameters;
        if( nullptr == pfnAppendLaunchKernelWithParameters )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendLaunchKernelWithParameters( hCommandList, hKernel, pGroupCounts, pNext, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendLaunchKernelWithArguments
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendLaunchKernelWithArguments(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        ze_kernel_handle_t hKernel,                     ///< [in] handle of the kernel object
        const ze_group_count_t groupCounts,             ///< [in] thread group counts
        const ze_group_size_t groupSizes,               ///< [in] thread group sizes
        void ** pArguments,                             ///< [in]pointer to an array of pointers
        const void * pNext,                             ///< [in][optional] additional extensions passed to the function
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendLaunchKernelWithArguments = dditable->ze.CommandList.pfnAppendLaunchKernelWithArguments;
        if( nullptr == pfnAppendLaunchKernelWithArguments )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendLaunchKernelWithArguments( hCommandList, hKernel, groupCounts, groupSizes, pArguments, pNext, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendLaunchCooperativeKernel
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendLaunchCooperativeKernel(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        ze_kernel_handle_t hKernel,                     ///< [in] handle of the kernel object
        const ze_group_count_t* pLaunchFuncArgs,        ///< [in] thread group launch arguments
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendLaunchCooperativeKernel = dditable->ze.CommandList.pfnAppendLaunchCooperativeKernel;
        if( nullptr == pfnAppendLaunchCooperativeKernel )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendLaunchCooperativeKernel( hCommandList, hKernel, pLaunchFuncArgs, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendLaunchKernelIndirect
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendLaunchKernelIndirect(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        ze_kernel_handle_t hKernel,                     ///< [in] handle of the kernel object
        const ze_group_count_t* pLaunchArgumentsBuffer, ///< [in] pointer to device buffer that will contain thread group launch
                                                        ///< arguments
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendLaunchKernelIndirect = dditable->ze.CommandList.pfnAppendLaunchKernelIndirect;
        if( nullptr == pfnAppendLaunchKernelIndirect )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendLaunchKernelIndirect( hCommandList, hKernel, pLaunchArgumentsBuffer, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendLaunchMultipleKernelsIndirect
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendLaunchMultipleKernelsIndirect(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        uint32_t numKernels,                            ///< [in] maximum number of kernels to launch
        ze_kernel_handle_t* phKernels,                  ///< [in][range(0, numKernels)] handles of the kernel objects
        const uint32_t* pCountBuffer,                   ///< [in] pointer to device memory location that will contain the actual
                                                        ///< number of kernels to launch; value must be less than or equal to
                                                        ///< numKernels
        const ze_group_count_t* pLaunchArgumentsBuffer, ///< [in][range(0, numKernels)] pointer to device buffer that will contain
                                                        ///< a contiguous array of thread group launch arguments
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendLaunchMultipleKernelsIndirect = dditable->ze.CommandList.pfnAppendLaunchMultipleKernelsIndirect;
        if( nullptr == pfnAppendLaunchMultipleKernelsIndirect )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handles to driver handles
        auto phKernelsLocal = new ze_kernel_handle_t [numKernels];
        for( size_t i = 0; ( nullptr != phKernels ) && ( i < numKernels ); ++i )
            phKernelsLocal[ i ] = reinterpret_cast<ze_kernel_object_t*>( phKernels[ i ] )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendLaunchMultipleKernelsIndirect( hCommandList, numKernels, phKernelsLocal, pCountBuffer, pLaunchArgumentsBuffer, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phKernelsLocal;
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeContextMakeMemoryResident
    __zedlllocal ze_result_t ZE_APICALL
    zeContextMakeMemoryResident(
        ze_context_handle_t hContext,                   ///< [in] handle of context object
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        void* ptr,                                      ///< [in] pointer to memory to make resident
        size_t size                                     ///< [in] size in bytes to make resident
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnMakeMemoryResident = dditable->ze.Context.pfnMakeMemoryResident;
        if( nullptr == pfnMakeMemoryResident )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnMakeMemoryResident( hContext, hDevice, ptr, size );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeContextEvictMemory
    __zedlllocal ze_result_t ZE_APICALL
    zeContextEvictMemory(
        ze_context_handle_t hContext,                   ///< [in] handle of context object
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        void* ptr,                                      ///< [in] pointer to memory to evict
        size_t size                                     ///< [in] size in bytes to evict
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnEvictMemory = dditable->ze.Context.pfnEvictMemory;
        if( nullptr == pfnEvictMemory )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnEvictMemory( hContext, hDevice, ptr, size );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeContextMakeImageResident
    __zedlllocal ze_result_t ZE_APICALL
    zeContextMakeImageResident(
        ze_context_handle_t hContext,                   ///< [in] handle of context object
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        ze_image_handle_t hImage                        ///< [in] handle of image to make resident
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnMakeImageResident = dditable->ze.Context.pfnMakeImageResident;
        if( nullptr == pfnMakeImageResident )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // convert loader handle to driver handle
        hImage = reinterpret_cast<ze_image_object_t*>( hImage )->handle;

        // forward to device-driver
        result = pfnMakeImageResident( hContext, hDevice, hImage );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeContextEvictImage
    __zedlllocal ze_result_t ZE_APICALL
    zeContextEvictImage(
        ze_context_handle_t hContext,                   ///< [in] handle of context object
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        ze_image_handle_t hImage                        ///< [in] handle of image to make evict
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnEvictImage = dditable->ze.Context.pfnEvictImage;
        if( nullptr == pfnEvictImage )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // convert loader handle to driver handle
        hImage = reinterpret_cast<ze_image_object_t*>( hImage )->handle;

        // forward to device-driver
        result = pfnEvictImage( hContext, hDevice, hImage );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeSamplerCreate
    __zedlllocal ze_result_t ZE_APICALL
    zeSamplerCreate(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        const ze_sampler_desc_t* desc,                  ///< [in] pointer to sampler descriptor
        ze_sampler_handle_t* phSampler                  ///< [out] handle of the sampler
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnCreate = dditable->ze.Sampler.pfnCreate;
        if( nullptr == pfnCreate )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnCreate( hContext, hDevice, desc, phSampler );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            ze_sampler_handle_t internalHandlePtr = *phSampler;
            *phSampler = reinterpret_cast<ze_sampler_handle_t>(
                context->ze_sampler_factory.getInstance( *phSampler, dditable ) );
            // convert loader handle to driver handle and store in map
            {
                std::lock_guard<std::mutex> lock(context->sampler_handle_map_lock);
                context->sampler_handle_map.insert({context->ze_sampler_factory.getInstance( internalHandlePtr, dditable ), internalHandlePtr});
            }
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeSamplerDestroy
    __zedlllocal ze_result_t ZE_APICALL
    zeSamplerDestroy(
        ze_sampler_handle_t hSampler                    ///< [in][release] handle of the sampler
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_sampler_object_t*>( hSampler )->dditable;
        auto pfnDestroy = dditable->ze.Sampler.pfnDestroy;
        if( nullptr == pfnDestroy )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // remove the handle from the kernel arugment map
        {
            std::lock_guard<std::mutex> lock(context->sampler_handle_map_lock);
            context->sampler_handle_map.erase(reinterpret_cast<ze_sampler_object_t*>(hSampler));
        }
        // convert loader handle to driver handle
        hSampler = reinterpret_cast<ze_sampler_object_t*>( hSampler )->handle;

        // forward to device-driver
        result = pfnDestroy( hSampler );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_sampler_factory.release( hSampler );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeVirtualMemReserve
    __zedlllocal ze_result_t ZE_APICALL
    zeVirtualMemReserve(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        const void* pStart,                             ///< [in][optional] pointer to start of region to reserve. If nullptr then
                                                        ///< implementation will choose a start address.
        size_t size,                                    ///< [in] size in bytes to reserve; must be page aligned.
        void** pptr                                     ///< [out] pointer to virtual reservation.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnReserve = dditable->ze.VirtualMem.pfnReserve;
        if( nullptr == pfnReserve )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnReserve( hContext, pStart, size, pptr );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeVirtualMemFree
    __zedlllocal ze_result_t ZE_APICALL
    zeVirtualMemFree(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        const void* ptr,                                ///< [in] pointer to start of region to free.
        size_t size                                     ///< [in] size in bytes to free; must be page aligned.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnFree = dditable->ze.VirtualMem.pfnFree;
        if( nullptr == pfnFree )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnFree( hContext, ptr, size );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeVirtualMemQueryPageSize
    __zedlllocal ze_result_t ZE_APICALL
    zeVirtualMemQueryPageSize(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_device_handle_t hDevice,                     ///< [in] handle of the device object
        size_t size,                                    ///< [in] unaligned allocation size in bytes
        size_t* pagesize                                ///< [out] pointer to page size to use for start address and size
                                                        ///< alignments.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnQueryPageSize = dditable->ze.VirtualMem.pfnQueryPageSize;
        if( nullptr == pfnQueryPageSize )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnQueryPageSize( hContext, hDevice, size, pagesize );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zePhysicalMemGetProperties
    __zedlllocal ze_result_t ZE_APICALL
    zePhysicalMemGetProperties(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_physical_mem_handle_t hPhysicalMem,          ///< [in] handle of the physical memory object
        ze_physical_mem_properties_t* pMemProperties    ///< [in,out] pointer to physical memory properties structure.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnGetProperties = dditable->ze.PhysicalMem.pfnGetProperties;
        if( nullptr == pfnGetProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hPhysicalMem = reinterpret_cast<ze_physical_mem_object_t*>( hPhysicalMem )->handle;

        // forward to device-driver
        result = pfnGetProperties( hContext, hPhysicalMem, pMemProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zePhysicalMemCreate
    __zedlllocal ze_result_t ZE_APICALL
    zePhysicalMemCreate(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_device_handle_t hDevice,                     ///< [in] handle of the device object, can be `nullptr` if creating
                                                        ///< physical host memory.
        ze_physical_mem_desc_t* desc,                   ///< [in] pointer to physical memory descriptor.
        ze_physical_mem_handle_t* phPhysicalMemory      ///< [out] pointer to handle of physical memory object created
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnCreate = dditable->ze.PhysicalMem.pfnCreate;
        if( nullptr == pfnCreate )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnCreate( hContext, hDevice, desc, phPhysicalMemory );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phPhysicalMemory = reinterpret_cast<ze_physical_mem_handle_t>(
                context->ze_physical_mem_factory.getInstance( *phPhysicalMemory, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zePhysicalMemDestroy
    __zedlllocal ze_result_t ZE_APICALL
    zePhysicalMemDestroy(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_physical_mem_handle_t hPhysicalMemory        ///< [in][release] handle of physical memory object to destroy
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnDestroy = dditable->ze.PhysicalMem.pfnDestroy;
        if( nullptr == pfnDestroy )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hPhysicalMemory = reinterpret_cast<ze_physical_mem_object_t*>( hPhysicalMemory )->handle;

        // forward to device-driver
        result = pfnDestroy( hContext, hPhysicalMemory );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_physical_mem_factory.release( hPhysicalMemory );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeVirtualMemMap
    __zedlllocal ze_result_t ZE_APICALL
    zeVirtualMemMap(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        const void* ptr,                                ///< [in] pointer to start of virtual address range to map.
        size_t size,                                    ///< [in] size in bytes of virtual address range to map; must be page
                                                        ///< aligned.
        ze_physical_mem_handle_t hPhysicalMemory,       ///< [in] handle to physical memory object.
        size_t offset,                                  ///< [in] offset into physical memory allocation object; must be page
                                                        ///< aligned.
        ze_memory_access_attribute_t access             ///< [in] specifies page access attributes to apply to the virtual address
                                                        ///< range.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnMap = dditable->ze.VirtualMem.pfnMap;
        if( nullptr == pfnMap )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hPhysicalMemory = reinterpret_cast<ze_physical_mem_object_t*>( hPhysicalMemory )->handle;

        // forward to device-driver
        result = pfnMap( hContext, ptr, size, hPhysicalMemory, offset, access );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeVirtualMemUnmap
    __zedlllocal ze_result_t ZE_APICALL
    zeVirtualMemUnmap(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        const void* ptr,                                ///< [in] pointer to start of region to unmap.
        size_t size                                     ///< [in] size in bytes to unmap; must be page aligned.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnUnmap = dditable->ze.VirtualMem.pfnUnmap;
        if( nullptr == pfnUnmap )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnUnmap( hContext, ptr, size );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeVirtualMemSetAccessAttribute
    __zedlllocal ze_result_t ZE_APICALL
    zeVirtualMemSetAccessAttribute(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        const void* ptr,                                ///< [in] pointer to start of reserved virtual address region.
        size_t size,                                    ///< [in] size in bytes; must be page aligned.
        ze_memory_access_attribute_t access             ///< [in] specifies page access attributes to apply to the virtual address
                                                        ///< range.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnSetAccessAttribute = dditable->ze.VirtualMem.pfnSetAccessAttribute;
        if( nullptr == pfnSetAccessAttribute )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnSetAccessAttribute( hContext, ptr, size, access );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeVirtualMemGetAccessAttribute
    __zedlllocal ze_result_t ZE_APICALL
    zeVirtualMemGetAccessAttribute(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        const void* ptr,                                ///< [in] pointer to start of virtual address region for query.
        size_t size,                                    ///< [in] size in bytes; must be page aligned.
        ze_memory_access_attribute_t* access,           ///< [out] query result for page access attribute.
        size_t* outSize                                 ///< [out] query result for size of virtual address range, starting at ptr,
                                                        ///< that shares same access attribute.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnGetAccessAttribute = dditable->ze.VirtualMem.pfnGetAccessAttribute;
        if( nullptr == pfnGetAccessAttribute )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnGetAccessAttribute( hContext, ptr, size, access, outSize );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeKernelSetGlobalOffsetExp
    __zedlllocal ze_result_t ZE_APICALL
    zeKernelSetGlobalOffsetExp(
        ze_kernel_handle_t hKernel,                     ///< [in] handle of the kernel object
        uint32_t offsetX,                               ///< [in] global offset for X dimension to use for this kernel
        uint32_t offsetY,                               ///< [in] global offset for Y dimension to use for this kernel
        uint32_t offsetZ                                ///< [in] global offset for Z dimension to use for this kernel
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_kernel_object_t*>( hKernel )->dditable;
        auto pfnSetGlobalOffsetExp = dditable->ze.KernelExp.pfnSetGlobalOffsetExp;
        if( nullptr == pfnSetGlobalOffsetExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // forward to device-driver
        result = pfnSetGlobalOffsetExp( hKernel, offsetX, offsetY, offsetZ );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceReserveCacheExt
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceReserveCacheExt(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device object
        size_t cacheLevel,                              ///< [in] cache level where application want to reserve. If zero, then the
                                                        ///< driver shall default to last level of cache and attempt to reserve in
                                                        ///< that cache.
        size_t cacheReservationSize                     ///< [in] value for reserving size, in bytes. If zero, then the driver
                                                        ///< shall remove prior reservation
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnReserveCacheExt = dditable->ze.Device.pfnReserveCacheExt;
        if( nullptr == pfnReserveCacheExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnReserveCacheExt( hDevice, cacheLevel, cacheReservationSize );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceSetCacheAdviceExt
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceSetCacheAdviceExt(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device object
        void* ptr,                                      ///< [in] memory pointer to query
        size_t regionSize,                              ///< [in] region size, in pages
        ze_cache_ext_region_t cacheRegion               ///< [in] reservation region
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnSetCacheAdviceExt = dditable->ze.Device.pfnSetCacheAdviceExt;
        if( nullptr == pfnSetCacheAdviceExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnSetCacheAdviceExt( hDevice, ptr, regionSize, cacheRegion );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventQueryTimestampsExp
    __zedlllocal ze_result_t ZE_APICALL
    zeEventQueryTimestampsExp(
        ze_event_handle_t hEvent,                       ///< [in] handle of the event
        ze_device_handle_t hDevice,                     ///< [in] handle of the device to query
        uint32_t* pCount,                               ///< [in,out] pointer to the number of timestamp results.
                                                        ///< if count is zero, then the driver shall update the value with the
                                                        ///< total number of timestamps available.
                                                        ///< if count is greater than the number of timestamps available, then the
                                                        ///< driver shall update the value with the correct number of timestamps available.
        ze_kernel_timestamp_result_t* pTimestamps       ///< [in,out][optional][range(0, *pCount)] array of timestamp results.
                                                        ///< if count is less than the number of timestamps available, then driver
                                                        ///< shall only retrieve that number of timestamps.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_object_t*>( hEvent )->dditable;
        auto pfnQueryTimestampsExp = dditable->ze.EventExp.pfnQueryTimestampsExp;
        if( nullptr == pfnQueryTimestampsExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEvent = reinterpret_cast<ze_event_object_t*>( hEvent )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnQueryTimestampsExp( hEvent, hDevice, pCount, pTimestamps );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeImageGetMemoryPropertiesExp
    __zedlllocal ze_result_t ZE_APICALL
    zeImageGetMemoryPropertiesExp(
        ze_image_handle_t hImage,                       ///< [in] handle of image object
        ze_image_memory_properties_exp_t* pMemoryProperties ///< [in,out] query result for image memory properties.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_image_object_t*>( hImage )->dditable;
        auto pfnGetMemoryPropertiesExp = dditable->ze.ImageExp.pfnGetMemoryPropertiesExp;
        if( nullptr == pfnGetMemoryPropertiesExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hImage = reinterpret_cast<ze_image_object_t*>( hImage )->handle;

        // forward to device-driver
        result = pfnGetMemoryPropertiesExp( hImage, pMemoryProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeImageViewCreateExt
    __zedlllocal ze_result_t ZE_APICALL
    zeImageViewCreateExt(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        const ze_image_desc_t* desc,                    ///< [in] pointer to image descriptor
        ze_image_handle_t hImage,                       ///< [in] handle of image object to create view from
        ze_image_handle_t* phImageView                  ///< [out] pointer to handle of image object created for view
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnViewCreateExt = dditable->ze.Image.pfnViewCreateExt;
        if( nullptr == pfnViewCreateExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // convert loader handle to driver handle
        hImage = reinterpret_cast<ze_image_object_t*>( hImage )->handle;

        // forward to device-driver
        result = pfnViewCreateExt( hContext, hDevice, desc, hImage, phImageView );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phImageView = reinterpret_cast<ze_image_handle_t>(
                context->ze_image_factory.getInstance( *phImageView, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeImageViewCreateExp
    __zedlllocal ze_result_t ZE_APICALL
    zeImageViewCreateExp(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        const ze_image_desc_t* desc,                    ///< [in] pointer to image descriptor
        ze_image_handle_t hImage,                       ///< [in] handle of image object to create view from
        ze_image_handle_t* phImageView                  ///< [out] pointer to handle of image object created for view
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnViewCreateExp = dditable->ze.ImageExp.pfnViewCreateExp;
        if( nullptr == pfnViewCreateExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // convert loader handle to driver handle
        hImage = reinterpret_cast<ze_image_object_t*>( hImage )->handle;

        // forward to device-driver
        result = pfnViewCreateExp( hContext, hDevice, desc, hImage, phImageView );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            ze_image_handle_t internalHandlePtr = *phImageView;
            *phImageView = reinterpret_cast<ze_image_handle_t>(
                context->ze_image_factory.getInstance( *phImageView, dditable ) );
            // convert loader handle to driver handle and store in map
            {
                std::lock_guard<std::mutex> lock(context->image_handle_map_lock);
                context->image_handle_map.insert({context->ze_image_factory.getInstance( internalHandlePtr, dditable ), internalHandlePtr});
            }
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeKernelSchedulingHintExp
    __zedlllocal ze_result_t ZE_APICALL
    zeKernelSchedulingHintExp(
        ze_kernel_handle_t hKernel,                     ///< [in] handle of the kernel object
        ze_scheduling_hint_exp_desc_t* pHint            ///< [in] pointer to kernel scheduling hint descriptor
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_kernel_object_t*>( hKernel )->dditable;
        auto pfnSchedulingHintExp = dditable->ze.KernelExp.pfnSchedulingHintExp;
        if( nullptr == pfnSchedulingHintExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // forward to device-driver
        result = pfnSchedulingHintExp( hKernel, pHint );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDevicePciGetPropertiesExt
    __zedlllocal ze_result_t ZE_APICALL
    zeDevicePciGetPropertiesExt(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device object.
        ze_pci_ext_properties_t* pPciProperties         ///< [in,out] returns the PCI properties of the device.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnPciGetPropertiesExt = dditable->ze.Device.pfnPciGetPropertiesExt;
        if( nullptr == pfnPciGetPropertiesExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnPciGetPropertiesExt( hDevice, pPciProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendImageCopyToMemoryExt
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendImageCopyToMemoryExt(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of command list
        void* dstptr,                                   ///< [in] pointer to destination memory to copy to
        ze_image_handle_t hSrcImage,                    ///< [in] handle of source image to copy from
        const ze_image_region_t* pSrcRegion,            ///< [in][optional] source region descriptor
        uint32_t destRowPitch,                          ///< [in] size in bytes of the 1D slice of the 2D region of a 2D or 3D
                                                        ///< image or each image of a 1D or 2D image array being written
        uint32_t destSlicePitch,                        ///< [in] size in bytes of the 2D slice of the 3D region of a 3D image or
                                                        ///< each image of a 1D or 2D image array being written
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendImageCopyToMemoryExt = dditable->ze.CommandList.pfnAppendImageCopyToMemoryExt;
        if( nullptr == pfnAppendImageCopyToMemoryExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hSrcImage = reinterpret_cast<ze_image_object_t*>( hSrcImage )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendImageCopyToMemoryExt( hCommandList, dstptr, hSrcImage, pSrcRegion, destRowPitch, destSlicePitch, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendImageCopyFromMemoryExt
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendImageCopyFromMemoryExt(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of command list
        ze_image_handle_t hDstImage,                    ///< [in] handle of destination image to copy to
        const void* srcptr,                             ///< [in] pointer to source memory to copy from
        const ze_image_region_t* pDstRegion,            ///< [in][optional] destination region descriptor
        uint32_t srcRowPitch,                           ///< [in] size in bytes of the 1D slice of the 2D region of a 2D or 3D
                                                        ///< image or each image of a 1D or 2D image array being read
        uint32_t srcSlicePitch,                         ///< [in] size in bytes of the 2D slice of the 3D region of a 3D image or
                                                        ///< each image of a 1D or 2D image array being read
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendImageCopyFromMemoryExt = dditable->ze.CommandList.pfnAppendImageCopyFromMemoryExt;
        if( nullptr == pfnAppendImageCopyFromMemoryExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hDstImage = reinterpret_cast<ze_image_object_t*>( hDstImage )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendImageCopyFromMemoryExt( hCommandList, hDstImage, srcptr, pDstRegion, srcRowPitch, srcSlicePitch, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeImageGetAllocPropertiesExt
    __zedlllocal ze_result_t ZE_APICALL
    zeImageGetAllocPropertiesExt(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_image_handle_t hImage,                       ///< [in] handle of image object to query
        ze_image_allocation_ext_properties_t* pImageAllocProperties ///< [in,out] query result for image allocation properties
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnGetAllocPropertiesExt = dditable->ze.Image.pfnGetAllocPropertiesExt;
        if( nullptr == pfnGetAllocPropertiesExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hImage = reinterpret_cast<ze_image_object_t*>( hImage )->handle;

        // forward to device-driver
        result = pfnGetAllocPropertiesExt( hContext, hImage, pImageAllocProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeModuleInspectLinkageExt
    __zedlllocal ze_result_t ZE_APICALL
    zeModuleInspectLinkageExt(
        ze_linkage_inspection_ext_desc_t* pInspectDesc, ///< [in] pointer to linkage inspection descriptor structure.
        uint32_t numModules,                            ///< [in] number of modules to be inspected pointed to by phModules.
        ze_module_handle_t* phModules,                  ///< [in][range(0, numModules)] pointer to an array of modules to be
                                                        ///< inspected for import dependencies.
        ze_module_build_log_handle_t* phLog             ///< [out] pointer to handle of linkage inspection log. Log object will
                                                        ///< contain separate lists of imports, un-resolvable imports, and exports.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_module_object_t*>( phModules[ 0 ] )->dditable;
        auto pfnInspectLinkageExt = dditable->ze.Module.pfnInspectLinkageExt;
        if( nullptr == pfnInspectLinkageExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handles to driver handles
        auto phModulesLocal = new ze_module_handle_t [numModules];
        for( size_t i = 0; ( nullptr != phModules ) && ( i < numModules ); ++i )
            phModulesLocal[ i ] = reinterpret_cast<ze_module_object_t*>( phModules[ i ] )->handle;

        // forward to device-driver
        result = pfnInspectLinkageExt( pInspectDesc, numModules, phModulesLocal, phLog );
        delete []phModulesLocal;

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phLog = reinterpret_cast<ze_module_build_log_handle_t>(
                context->ze_module_build_log_factory.getInstance( *phLog, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeMemFreeExt
    __zedlllocal ze_result_t ZE_APICALL
    zeMemFreeExt(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        const ze_memory_free_ext_desc_t* pMemFreeDesc,  ///< [in] pointer to memory free descriptor
        void* ptr                                       ///< [in][release] pointer to memory to free
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnFreeExt = dditable->ze.Mem.pfnFreeExt;
        if( nullptr == pfnFreeExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnFreeExt( hContext, pMemFreeDesc, ptr );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeFabricVertexGetExp
    __zedlllocal ze_result_t ZE_APICALL
    zeFabricVertexGetExp(
        ze_driver_handle_t hDriver,                     ///< [in] handle of the driver instance
        uint32_t* pCount,                               ///< [in,out] pointer to the number of fabric vertices.
                                                        ///< if count is zero, then the driver shall update the value with the
                                                        ///< total number of fabric vertices available.
                                                        ///< if count is greater than the number of fabric vertices available, then
                                                        ///< the driver shall update the value with the correct number of fabric
                                                        ///< vertices available.
        ze_fabric_vertex_handle_t* phVertices           ///< [in,out][optional][range(0, *pCount)] array of handle of fabric vertices.
                                                        ///< if count is less than the number of fabric vertices available, then
                                                        ///< driver shall only retrieve that number of fabric vertices.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_driver_object_t*>( hDriver )->dditable;
        auto pfnGetExp = dditable->ze.FabricVertexExp.pfnGetExp;
        if( nullptr == pfnGetExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDriver = reinterpret_cast<ze_driver_object_t*>( hDriver )->handle;

        // forward to device-driver
        result = pfnGetExp( hDriver, pCount, phVertices );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handles to loader handles
            for( size_t i = 0; ( nullptr != phVertices ) && ( i < *pCount ); ++i )
                phVertices[ i ] = reinterpret_cast<ze_fabric_vertex_handle_t>(
                    context->ze_fabric_vertex_factory.getInstance( phVertices[ i ], dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeFabricVertexGetSubVerticesExp
    __zedlllocal ze_result_t ZE_APICALL
    zeFabricVertexGetSubVerticesExp(
        ze_fabric_vertex_handle_t hVertex,              ///< [in] handle of the fabric vertex object
        uint32_t* pCount,                               ///< [in,out] pointer to the number of sub-vertices.
                                                        ///< if count is zero, then the driver shall update the value with the
                                                        ///< total number of sub-vertices available.
                                                        ///< if count is greater than the number of sub-vertices available, then
                                                        ///< the driver shall update the value with the correct number of
                                                        ///< sub-vertices available.
        ze_fabric_vertex_handle_t* phSubvertices        ///< [in,out][optional][range(0, *pCount)] array of handle of sub-vertices.
                                                        ///< if count is less than the number of sub-vertices available, then
                                                        ///< driver shall only retrieve that number of sub-vertices.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_fabric_vertex_object_t*>( hVertex )->dditable;
        auto pfnGetSubVerticesExp = dditable->ze.FabricVertexExp.pfnGetSubVerticesExp;
        if( nullptr == pfnGetSubVerticesExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hVertex = reinterpret_cast<ze_fabric_vertex_object_t*>( hVertex )->handle;

        // forward to device-driver
        result = pfnGetSubVerticesExp( hVertex, pCount, phSubvertices );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handles to loader handles
            for( size_t i = 0; ( nullptr != phSubvertices ) && ( i < *pCount ); ++i )
                phSubvertices[ i ] = reinterpret_cast<ze_fabric_vertex_handle_t>(
                    context->ze_fabric_vertex_factory.getInstance( phSubvertices[ i ], dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeFabricVertexGetPropertiesExp
    __zedlllocal ze_result_t ZE_APICALL
    zeFabricVertexGetPropertiesExp(
        ze_fabric_vertex_handle_t hVertex,              ///< [in] handle of the fabric vertex
        ze_fabric_vertex_exp_properties_t* pVertexProperties///< [in,out] query result for fabric vertex properties
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_fabric_vertex_object_t*>( hVertex )->dditable;
        auto pfnGetPropertiesExp = dditable->ze.FabricVertexExp.pfnGetPropertiesExp;
        if( nullptr == pfnGetPropertiesExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hVertex = reinterpret_cast<ze_fabric_vertex_object_t*>( hVertex )->handle;

        // forward to device-driver
        result = pfnGetPropertiesExp( hVertex, pVertexProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeFabricVertexGetDeviceExp
    __zedlllocal ze_result_t ZE_APICALL
    zeFabricVertexGetDeviceExp(
        ze_fabric_vertex_handle_t hVertex,              ///< [in] handle of the fabric vertex
        ze_device_handle_t* phDevice                    ///< [out] device handle corresponding to fabric vertex
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_fabric_vertex_object_t*>( hVertex )->dditable;
        auto pfnGetDeviceExp = dditable->ze.FabricVertexExp.pfnGetDeviceExp;
        if( nullptr == pfnGetDeviceExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hVertex = reinterpret_cast<ze_fabric_vertex_object_t*>( hVertex )->handle;

        // forward to device-driver
        result = pfnGetDeviceExp( hVertex, phDevice );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phDevice = reinterpret_cast<ze_device_handle_t>(
                context->ze_device_factory.getInstance( *phDevice, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetFabricVertexExp
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetFabricVertexExp(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        ze_fabric_vertex_handle_t* phVertex             ///< [out] fabric vertex handle corresponding to device
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetFabricVertexExp = dditable->ze.DeviceExp.pfnGetFabricVertexExp;
        if( nullptr == pfnGetFabricVertexExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetFabricVertexExp( hDevice, phVertex );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phVertex = reinterpret_cast<ze_fabric_vertex_handle_t>(
                context->ze_fabric_vertex_factory.getInstance( *phVertex, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeFabricEdgeGetExp
    __zedlllocal ze_result_t ZE_APICALL
    zeFabricEdgeGetExp(
        ze_fabric_vertex_handle_t hVertexA,             ///< [in] handle of first fabric vertex instance
        ze_fabric_vertex_handle_t hVertexB,             ///< [in] handle of second fabric vertex instance
        uint32_t* pCount,                               ///< [in,out] pointer to the number of fabric edges.
                                                        ///< if count is zero, then the driver shall update the value with the
                                                        ///< total number of fabric edges available.
                                                        ///< if count is greater than the number of fabric edges available, then
                                                        ///< the driver shall update the value with the correct number of fabric
                                                        ///< edges available.
        ze_fabric_edge_handle_t* phEdges                ///< [in,out][optional][range(0, *pCount)] array of handle of fabric edges.
                                                        ///< if count is less than the number of fabric edges available, then
                                                        ///< driver shall only retrieve that number of fabric edges.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_fabric_vertex_object_t*>( hVertexA )->dditable;
        auto pfnGetExp = dditable->ze.FabricEdgeExp.pfnGetExp;
        if( nullptr == pfnGetExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hVertexA = reinterpret_cast<ze_fabric_vertex_object_t*>( hVertexA )->handle;

        // convert loader handle to driver handle
        hVertexB = reinterpret_cast<ze_fabric_vertex_object_t*>( hVertexB )->handle;

        // forward to device-driver
        result = pfnGetExp( hVertexA, hVertexB, pCount, phEdges );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handles to loader handles
            for( size_t i = 0; ( nullptr != phEdges ) && ( i < *pCount ); ++i )
                phEdges[ i ] = reinterpret_cast<ze_fabric_edge_handle_t>(
                    context->ze_fabric_edge_factory.getInstance( phEdges[ i ], dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeFabricEdgeGetVerticesExp
    __zedlllocal ze_result_t ZE_APICALL
    zeFabricEdgeGetVerticesExp(
        ze_fabric_edge_handle_t hEdge,                  ///< [in] handle of the fabric edge instance
        ze_fabric_vertex_handle_t* phVertexA,           ///< [out] fabric vertex connected to one end of the given fabric edge.
        ze_fabric_vertex_handle_t* phVertexB            ///< [out] fabric vertex connected to other end of the given fabric edge.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_fabric_edge_object_t*>( hEdge )->dditable;
        auto pfnGetVerticesExp = dditable->ze.FabricEdgeExp.pfnGetVerticesExp;
        if( nullptr == pfnGetVerticesExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEdge = reinterpret_cast<ze_fabric_edge_object_t*>( hEdge )->handle;

        // forward to device-driver
        result = pfnGetVerticesExp( hEdge, phVertexA, phVertexB );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phVertexA = reinterpret_cast<ze_fabric_vertex_handle_t>(
                context->ze_fabric_vertex_factory.getInstance( *phVertexA, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        try
        {
            // convert driver handle to loader handle
            *phVertexB = reinterpret_cast<ze_fabric_vertex_handle_t>(
                context->ze_fabric_vertex_factory.getInstance( *phVertexB, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeFabricEdgeGetPropertiesExp
    __zedlllocal ze_result_t ZE_APICALL
    zeFabricEdgeGetPropertiesExp(
        ze_fabric_edge_handle_t hEdge,                  ///< [in] handle of the fabric edge
        ze_fabric_edge_exp_properties_t* pEdgeProperties///< [in,out] query result for fabric edge properties
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_fabric_edge_object_t*>( hEdge )->dditable;
        auto pfnGetPropertiesExp = dditable->ze.FabricEdgeExp.pfnGetPropertiesExp;
        if( nullptr == pfnGetPropertiesExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEdge = reinterpret_cast<ze_fabric_edge_object_t*>( hEdge )->handle;

        // forward to device-driver
        result = pfnGetPropertiesExp( hEdge, pEdgeProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeEventQueryKernelTimestampsExt
    __zedlllocal ze_result_t ZE_APICALL
    zeEventQueryKernelTimestampsExt(
        ze_event_handle_t hEvent,                       ///< [in] handle of the event
        ze_device_handle_t hDevice,                     ///< [in] handle of the device to query
        uint32_t* pCount,                               ///< [in,out] pointer to the number of event packets available.
                                                        ///<    - This value is implementation specific.
                                                        ///<    - if `*pCount` is zero, then the driver shall update the value with
                                                        ///< the total number of event packets available.
                                                        ///<    - if `*pCount` is greater than the number of event packets
                                                        ///< available, the driver shall update the value with the correct value.
                                                        ///<    - Buffer(s) for query results must be sized by the application to
                                                        ///< accommodate a minimum of `*pCount` elements.
        ze_event_query_kernel_timestamps_results_ext_properties_t* pResults ///< [in,out][optional][range(0, *pCount)] pointer to event query
                                                        ///< properties structure(s).
                                                        ///<    - This parameter may be null when `*pCount` is zero.
                                                        ///<    - if `*pCount` is less than the number of event packets available,
                                                        ///< the driver may only update `*pCount` elements, starting at element zero.
                                                        ///<    - if `*pCount` is greater than the number of event packets
                                                        ///< available, the driver may only update the valid elements.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_event_object_t*>( hEvent )->dditable;
        auto pfnQueryKernelTimestampsExt = dditable->ze.Event.pfnQueryKernelTimestampsExt;
        if( nullptr == pfnQueryKernelTimestampsExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hEvent = reinterpret_cast<ze_event_object_t*>( hEvent )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnQueryKernelTimestampsExt( hEvent, hDevice, pCount, pResults );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeRTASBuilderCreateExp
    __zedlllocal ze_result_t ZE_APICALL
    zeRTASBuilderCreateExp(
        ze_driver_handle_t hDriver,                     ///< [in] handle of driver object
        const ze_rtas_builder_exp_desc_t* pDescriptor,  ///< [in] pointer to builder descriptor
        ze_rtas_builder_exp_handle_t* phBuilder         ///< [out] handle of builder object
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_driver_object_t*>( hDriver )->dditable;
        auto pfnCreateExp = dditable->ze.RTASBuilderExp.pfnCreateExp;
        if( nullptr == pfnCreateExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDriver = reinterpret_cast<ze_driver_object_t*>( hDriver )->handle;

        // forward to device-driver
        result = pfnCreateExp( hDriver, pDescriptor, phBuilder );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phBuilder = reinterpret_cast<ze_rtas_builder_exp_handle_t>(
                context->ze_rtas_builder_exp_factory.getInstance( *phBuilder, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeRTASBuilderGetBuildPropertiesExp
    __zedlllocal ze_result_t ZE_APICALL
    zeRTASBuilderGetBuildPropertiesExp(
        ze_rtas_builder_exp_handle_t hBuilder,          ///< [in] handle of builder object
        const ze_rtas_builder_build_op_exp_desc_t* pBuildOpDescriptor,  ///< [in] pointer to build operation descriptor
        ze_rtas_builder_exp_properties_t* pProperties   ///< [in,out] query result for builder properties
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_rtas_builder_exp_object_t*>( hBuilder )->dditable;
        auto pfnGetBuildPropertiesExp = dditable->ze.RTASBuilderExp.pfnGetBuildPropertiesExp;
        if( nullptr == pfnGetBuildPropertiesExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hBuilder = reinterpret_cast<ze_rtas_builder_exp_object_t*>( hBuilder )->handle;

        // forward to device-driver
        result = pfnGetBuildPropertiesExp( hBuilder, pBuildOpDescriptor, pProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDriverRTASFormatCompatibilityCheckExp
    __zedlllocal ze_result_t ZE_APICALL
    zeDriverRTASFormatCompatibilityCheckExp(
        ze_driver_handle_t hDriver,                     ///< [in] handle of driver object
        ze_rtas_format_exp_t rtasFormatA,               ///< [in] operand A
        ze_rtas_format_exp_t rtasFormatB                ///< [in] operand B
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_driver_object_t*>( hDriver )->dditable;
        auto pfnRTASFormatCompatibilityCheckExp = dditable->ze.DriverExp.pfnRTASFormatCompatibilityCheckExp;
        if( nullptr == pfnRTASFormatCompatibilityCheckExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDriver = reinterpret_cast<ze_driver_object_t*>( hDriver )->handle;

        // forward to device-driver
        result = pfnRTASFormatCompatibilityCheckExp( hDriver, rtasFormatA, rtasFormatB );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeRTASBuilderBuildExp
    __zedlllocal ze_result_t ZE_APICALL
    zeRTASBuilderBuildExp(
        ze_rtas_builder_exp_handle_t hBuilder,          ///< [in] handle of builder object
        const ze_rtas_builder_build_op_exp_desc_t* pBuildOpDescriptor,  ///< [in] pointer to build operation descriptor
        void* pScratchBuffer,                           ///< [in][range(0, `scratchBufferSizeBytes`)] scratch buffer to be used
                                                        ///< during acceleration structure construction
        size_t scratchBufferSizeBytes,                  ///< [in] size of scratch buffer, in bytes
        void* pRtasBuffer,                              ///< [in] pointer to destination buffer
        size_t rtasBufferSizeBytes,                     ///< [in] destination buffer size, in bytes
        ze_rtas_parallel_operation_exp_handle_t hParallelOperation, ///< [in][optional] handle to parallel operation object
        void* pBuildUserPtr,                            ///< [in][optional] pointer passed to callbacks
        ze_rtas_aabb_exp_t* pBounds,                    ///< [in,out][optional] pointer to destination address for acceleration
                                                        ///< structure bounds
        size_t* pRtasBufferSizeBytes                    ///< [out][optional] updated acceleration structure size requirement, in
                                                        ///< bytes
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_rtas_builder_exp_object_t*>( hBuilder )->dditable;
        auto pfnBuildExp = dditable->ze.RTASBuilderExp.pfnBuildExp;
        if( nullptr == pfnBuildExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hBuilder = reinterpret_cast<ze_rtas_builder_exp_object_t*>( hBuilder )->handle;

        // convert loader handle to driver handle
        hParallelOperation = ( hParallelOperation ) ? reinterpret_cast<ze_rtas_parallel_operation_exp_object_t*>( hParallelOperation )->handle : nullptr;

        // forward to device-driver
        result = pfnBuildExp( hBuilder, pBuildOpDescriptor, pScratchBuffer, scratchBufferSizeBytes, pRtasBuffer, rtasBufferSizeBytes, hParallelOperation, pBuildUserPtr, pBounds, pRtasBufferSizeBytes );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeRTASBuilderDestroyExp
    __zedlllocal ze_result_t ZE_APICALL
    zeRTASBuilderDestroyExp(
        ze_rtas_builder_exp_handle_t hBuilder           ///< [in][release] handle of builder object to destroy
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_rtas_builder_exp_object_t*>( hBuilder )->dditable;
        auto pfnDestroyExp = dditable->ze.RTASBuilderExp.pfnDestroyExp;
        if( nullptr == pfnDestroyExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hBuilder = reinterpret_cast<ze_rtas_builder_exp_object_t*>( hBuilder )->handle;

        // forward to device-driver
        result = pfnDestroyExp( hBuilder );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_rtas_builder_exp_factory.release( hBuilder );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeRTASParallelOperationCreateExp
    __zedlllocal ze_result_t ZE_APICALL
    zeRTASParallelOperationCreateExp(
        ze_driver_handle_t hDriver,                     ///< [in] handle of driver object
        ze_rtas_parallel_operation_exp_handle_t* phParallelOperation///< [out] handle of parallel operation object
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_driver_object_t*>( hDriver )->dditable;
        auto pfnCreateExp = dditable->ze.RTASParallelOperationExp.pfnCreateExp;
        if( nullptr == pfnCreateExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDriver = reinterpret_cast<ze_driver_object_t*>( hDriver )->handle;

        // forward to device-driver
        result = pfnCreateExp( hDriver, phParallelOperation );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phParallelOperation = reinterpret_cast<ze_rtas_parallel_operation_exp_handle_t>(
                context->ze_rtas_parallel_operation_exp_factory.getInstance( *phParallelOperation, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeRTASParallelOperationGetPropertiesExp
    __zedlllocal ze_result_t ZE_APICALL
    zeRTASParallelOperationGetPropertiesExp(
        ze_rtas_parallel_operation_exp_handle_t hParallelOperation, ///< [in] handle of parallel operation object
        ze_rtas_parallel_operation_exp_properties_t* pProperties///< [in,out] query result for parallel operation properties
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_rtas_parallel_operation_exp_object_t*>( hParallelOperation )->dditable;
        auto pfnGetPropertiesExp = dditable->ze.RTASParallelOperationExp.pfnGetPropertiesExp;
        if( nullptr == pfnGetPropertiesExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hParallelOperation = reinterpret_cast<ze_rtas_parallel_operation_exp_object_t*>( hParallelOperation )->handle;

        // forward to device-driver
        result = pfnGetPropertiesExp( hParallelOperation, pProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeRTASParallelOperationJoinExp
    __zedlllocal ze_result_t ZE_APICALL
    zeRTASParallelOperationJoinExp(
        ze_rtas_parallel_operation_exp_handle_t hParallelOperation  ///< [in] handle of parallel operation object
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_rtas_parallel_operation_exp_object_t*>( hParallelOperation )->dditable;
        auto pfnJoinExp = dditable->ze.RTASParallelOperationExp.pfnJoinExp;
        if( nullptr == pfnJoinExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hParallelOperation = reinterpret_cast<ze_rtas_parallel_operation_exp_object_t*>( hParallelOperation )->handle;

        // forward to device-driver
        result = pfnJoinExp( hParallelOperation );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeRTASParallelOperationDestroyExp
    __zedlllocal ze_result_t ZE_APICALL
    zeRTASParallelOperationDestroyExp(
        ze_rtas_parallel_operation_exp_handle_t hParallelOperation  ///< [in][release] handle of parallel operation object to destroy
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_rtas_parallel_operation_exp_object_t*>( hParallelOperation )->dditable;
        auto pfnDestroyExp = dditable->ze.RTASParallelOperationExp.pfnDestroyExp;
        if( nullptr == pfnDestroyExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hParallelOperation = reinterpret_cast<ze_rtas_parallel_operation_exp_object_t*>( hParallelOperation )->handle;

        // forward to device-driver
        result = pfnDestroyExp( hParallelOperation );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_rtas_parallel_operation_exp_factory.release( hParallelOperation );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeMemGetPitchFor2dImage
    __zedlllocal ze_result_t ZE_APICALL
    zeMemGetPitchFor2dImage(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        size_t imageWidth,                              ///< [in] imageWidth
        size_t imageHeight,                             ///< [in] imageHeight
        unsigned int elementSizeInBytes,                ///< [in] Element size in bytes
        size_t * rowPitch                               ///< [out] rowPitch
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnGetPitchFor2dImage = dditable->ze.Mem.pfnGetPitchFor2dImage;
        if( nullptr == pfnGetPitchFor2dImage )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetPitchFor2dImage( hContext, hDevice, imageWidth, imageHeight, elementSizeInBytes, rowPitch );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeImageGetDeviceOffsetExp
    __zedlllocal ze_result_t ZE_APICALL
    zeImageGetDeviceOffsetExp(
        ze_image_handle_t hImage,                       ///< [in] handle of the image
        uint64_t* pDeviceOffset                         ///< [out] bindless device offset for image
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_image_object_t*>( hImage )->dditable;
        auto pfnGetDeviceOffsetExp = dditable->ze.ImageExp.pfnGetDeviceOffsetExp;
        if( nullptr == pfnGetDeviceOffsetExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hImage = reinterpret_cast<ze_image_object_t*>( hImage )->handle;

        // forward to device-driver
        result = pfnGetDeviceOffsetExp( hImage, pDeviceOffset );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListCreateCloneExp
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListCreateCloneExp(
        ze_command_list_handle_t hCommandList,          ///< [in] handle to source command list (the command list to clone)
        ze_command_list_handle_t* phClonedCommandList   ///< [out] pointer to handle of the cloned command list
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnCreateCloneExp = dditable->ze.CommandListExp.pfnCreateCloneExp;
        if( nullptr == pfnCreateCloneExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnCreateCloneExp( hCommandList, phClonedCommandList );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phClonedCommandList = reinterpret_cast<ze_command_list_handle_t>(
                context->ze_command_list_factory.getInstance( *phClonedCommandList, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListImmediateAppendCommandListsExp
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListImmediateAppendCommandListsExp(
        ze_command_list_handle_t hCommandListImmediate, ///< [in] handle of the immediate command list
        uint32_t numCommandLists,                       ///< [in] number of command lists
        ze_command_list_handle_t* phCommandLists,       ///< [in][range(0, numCommandLists)] handles of command lists
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
                                                        ///<    - if not null, this event is signaled after the completion of all
                                                        ///< appended command lists
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before executing appended
                                                        ///< command lists; must be 0 if nullptr == phWaitEvents
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before executing appended command lists.
                                                        ///<    - if not null, all wait events must be satisfied prior to the start
                                                        ///< of any appended command list(s)
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandListImmediate )->dditable;
        auto pfnImmediateAppendCommandListsExp = dditable->ze.CommandListExp.pfnImmediateAppendCommandListsExp;
        if( nullptr == pfnImmediateAppendCommandListsExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandListImmediate = reinterpret_cast<ze_command_list_object_t*>( hCommandListImmediate )->handle;

        // convert loader handles to driver handles
        auto phCommandListsLocal = new ze_command_list_handle_t [numCommandLists];
        for( size_t i = 0; ( nullptr != phCommandLists ) && ( i < numCommandLists ); ++i )
            phCommandListsLocal[ i ] = reinterpret_cast<ze_command_list_object_t*>( phCommandLists[ i ] )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnImmediateAppendCommandListsExp( hCommandListImmediate, numCommandLists, phCommandListsLocal, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phCommandListsLocal;
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListImmediateAppendCommandListsWithParameters
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListImmediateAppendCommandListsWithParameters(
        ze_command_list_handle_t hCommandListImmediate, ///< [in] handle of the immediate command list
        uint32_t numCommandLists,                       ///< [in] number of command lists
        ze_command_list_handle_t* phCommandLists,       ///< [in][range(0, numCommandLists)] handles of command lists
        const void* pNext,                              ///< [in][optional] additional extensions passed to the function
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
                                                        ///<    - if not null, this event is signaled after the completion of all
                                                        ///< appended command lists
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before executing appended
                                                        ///< command lists; must be 0 if nullptr == phWaitEvents
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before executing appended command lists.
                                                        ///<    - if not null, all wait events must be satisfied prior to the start
                                                        ///< of any appended command list(s)
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandListImmediate )->dditable;
        auto pfnImmediateAppendCommandListsWithParameters = dditable->ze.CommandList.pfnImmediateAppendCommandListsWithParameters;
        if( nullptr == pfnImmediateAppendCommandListsWithParameters )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandListImmediate = reinterpret_cast<ze_command_list_object_t*>( hCommandListImmediate )->handle;

        // convert loader handles to driver handles
        auto phCommandListsLocal = new ze_command_list_handle_t [numCommandLists];
        for( size_t i = 0; ( nullptr != phCommandLists ) && ( i < numCommandLists ); ++i )
            phCommandListsLocal[ i ] = reinterpret_cast<ze_command_list_object_t*>( phCommandLists[ i ] )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnImmediateAppendCommandListsWithParameters( hCommandListImmediate, numCommandLists, phCommandListsLocal, pNext, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phCommandListsLocal;
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListGetNextCommandIdExp
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListGetNextCommandIdExp(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        const ze_mutable_command_id_exp_desc_t* desc,   ///< [in] pointer to mutable command identifier descriptor
        uint64_t* pCommandId                            ///< [out] pointer to mutable command identifier to be written
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnGetNextCommandIdExp = dditable->ze.CommandListExp.pfnGetNextCommandIdExp;
        if( nullptr == pfnGetNextCommandIdExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnGetNextCommandIdExp( hCommandList, desc, pCommandId );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListGetNextCommandIdWithKernelsExp
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListGetNextCommandIdWithKernelsExp(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        const ze_mutable_command_id_exp_desc_t* desc,   ///< [in][out] pointer to mutable command identifier descriptor
        uint32_t numKernels,                            ///< [in][optional] number of entries on phKernels list
        ze_kernel_handle_t* phKernels,                  ///< [in][optional][range(0, numKernels)] list of kernels that user can
                                                        ///< switch between using ::zeCommandListUpdateMutableCommandKernelsExp
                                                        ///< call
        uint64_t* pCommandId                            ///< [out] pointer to mutable command identifier to be written
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnGetNextCommandIdWithKernelsExp = dditable->ze.CommandListExp.pfnGetNextCommandIdWithKernelsExp;
        if( nullptr == pfnGetNextCommandIdWithKernelsExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handles to driver handles
        auto phKernelsLocal = new ze_kernel_handle_t [numKernels];
        for( size_t i = 0; ( nullptr != phKernels ) && ( i < numKernels ); ++i )
            phKernelsLocal[ i ] = reinterpret_cast<ze_kernel_object_t*>( phKernels[ i ] )->handle;

        // forward to device-driver
        result = pfnGetNextCommandIdWithKernelsExp( hCommandList, desc, numKernels, phKernelsLocal, pCommandId );
        delete []phKernelsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListUpdateMutableCommandsExp
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListUpdateMutableCommandsExp(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        const ze_mutable_commands_exp_desc_t* desc      ///< [in] pointer to mutable commands descriptor; multiple descriptors may
                                                        ///< be chained via `pNext` member
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnUpdateMutableCommandsExp = dditable->ze.CommandListExp.pfnUpdateMutableCommandsExp;
        if( nullptr == pfnUpdateMutableCommandsExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnUpdateMutableCommandsExp( hCommandList, desc );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListIsMutableExp
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListIsMutableExp(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        ze_bool_t* pIsMutable                           ///< [out] pointer bool determining whether command list was created with
                                                        ///< mutable extension
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnIsMutableExp = dditable->ze.CommandListExp.pfnIsMutableExp;
        if( nullptr == pfnIsMutableExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnIsMutableExp( hCommandList, pIsMutable );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListUpdateMutableCommandSignalEventExp
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListUpdateMutableCommandSignalEventExp(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        uint64_t commandId,                             ///< [in] command identifier
        ze_event_handle_t hSignalEvent                  ///< [in][optional] handle of the event to signal on completion
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnUpdateMutableCommandSignalEventExp = dditable->ze.CommandListExp.pfnUpdateMutableCommandSignalEventExp;
        if( nullptr == pfnUpdateMutableCommandSignalEventExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // forward to device-driver
        result = pfnUpdateMutableCommandSignalEventExp( hCommandList, commandId, hSignalEvent );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListUpdateMutableCommandWaitEventsExp
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListUpdateMutableCommandWaitEventsExp(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        uint64_t commandId,                             ///< [in] command identifier
        uint32_t numWaitEvents,                         ///< [in][optional] the number of wait events
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnUpdateMutableCommandWaitEventsExp = dditable->ze.CommandListExp.pfnUpdateMutableCommandWaitEventsExp;
        if( nullptr == pfnUpdateMutableCommandWaitEventsExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnUpdateMutableCommandWaitEventsExp( hCommandList, commandId, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListUpdateMutableCommandKernelsExp
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListUpdateMutableCommandKernelsExp(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        uint32_t numKernels,                            ///< [in] the number of kernels to update
        uint64_t* pCommandId,                           ///< [in][range(0, numKernels)] command identifier
        ze_kernel_handle_t* phKernels                   ///< [in][range(0, numKernels)] handle of the kernel for a command
                                                        ///< identifier to switch to
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnUpdateMutableCommandKernelsExp = dditable->ze.CommandListExp.pfnUpdateMutableCommandKernelsExp;
        if( nullptr == pfnUpdateMutableCommandKernelsExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handles to driver handles
        auto phKernelsLocal = new ze_kernel_handle_t [numKernels];
        for( size_t i = 0; ( nullptr != phKernels ) && ( i < numKernels ); ++i )
            phKernelsLocal[ i ] = reinterpret_cast<ze_kernel_object_t*>( phKernels[ i ] )->handle;

        // forward to device-driver
        result = pfnUpdateMutableCommandKernelsExp( hCommandList, numKernels, pCommandId, phKernelsLocal );
        delete []phKernelsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeKernelGetBinaryExp
    __zedlllocal ze_result_t ZE_APICALL
    zeKernelGetBinaryExp(
        ze_kernel_handle_t hKernel,                     ///< [in] Kernel handle.
        size_t* pSize,                                  ///< [in,out] pointer to variable with size of GEN ISA binary.
        uint8_t* pKernelBinary                          ///< [in,out] pointer to storage area for GEN ISA binary function.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_kernel_object_t*>( hKernel )->dditable;
        auto pfnGetBinaryExp = dditable->ze.KernelExp.pfnGetBinaryExp;
        if( nullptr == pfnGetBinaryExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // forward to device-driver
        result = pfnGetBinaryExp( hKernel, pSize, pKernelBinary );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceImportExternalSemaphoreExt
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceImportExternalSemaphoreExt(
        ze_device_handle_t hDevice,                     ///< [in] The device handle.
        const ze_external_semaphore_ext_desc_t* desc,   ///< [in] The pointer to external semaphore descriptor.
        ze_external_semaphore_ext_handle_t* phSemaphore ///< [out] The handle of the external semaphore imported.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnImportExternalSemaphoreExt = dditable->ze.Device.pfnImportExternalSemaphoreExt;
        if( nullptr == pfnImportExternalSemaphoreExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnImportExternalSemaphoreExt( hDevice, desc, phSemaphore );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phSemaphore = reinterpret_cast<ze_external_semaphore_ext_handle_t>(
                context->ze_external_semaphore_ext_factory.getInstance( *phSemaphore, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceReleaseExternalSemaphoreExt
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceReleaseExternalSemaphoreExt(
        ze_external_semaphore_ext_handle_t hSemaphore   ///< [in] The handle of the external semaphore.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_external_semaphore_ext_object_t*>( hSemaphore )->dditable;
        auto pfnReleaseExternalSemaphoreExt = dditable->ze.Device.pfnReleaseExternalSemaphoreExt;
        if( nullptr == pfnReleaseExternalSemaphoreExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hSemaphore = reinterpret_cast<ze_external_semaphore_ext_object_t*>( hSemaphore )->handle;

        // forward to device-driver
        result = pfnReleaseExternalSemaphoreExt( hSemaphore );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendSignalExternalSemaphoreExt
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendSignalExternalSemaphoreExt(
        ze_command_list_handle_t hCommandList,          ///< [in] The command list handle.
        uint32_t numSemaphores,                         ///< [in] The number of external semaphores.
        ze_external_semaphore_ext_handle_t* phSemaphores,   ///< [in][range(0, numSemaphores)] The array of pointers to external
                                                        ///< semaphore handles to be appended into command list.
        ze_external_semaphore_signal_params_ext_t* signalParams,///< [in][range(0, numSemaphores)] The array of pointers to external
                                                        ///< semaphore signal parameters.
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendSignalExternalSemaphoreExt = dditable->ze.CommandList.pfnAppendSignalExternalSemaphoreExt;
        if( nullptr == pfnAppendSignalExternalSemaphoreExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handles to driver handles
        auto phSemaphoresLocal = new ze_external_semaphore_ext_handle_t [numSemaphores];
        for( size_t i = 0; ( nullptr != phSemaphores ) && ( i < numSemaphores ); ++i )
            phSemaphoresLocal[ i ] = reinterpret_cast<ze_external_semaphore_ext_object_t*>( phSemaphores[ i ] )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendSignalExternalSemaphoreExt( hCommandList, numSemaphores, phSemaphoresLocal, signalParams, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phSemaphoresLocal;
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendWaitExternalSemaphoreExt
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendWaitExternalSemaphoreExt(
        ze_command_list_handle_t hCommandList,          ///< [in] The command list handle.
        uint32_t numSemaphores,                         ///< [in] The number of external semaphores.
        ze_external_semaphore_ext_handle_t* phSemaphores,   ///< [in][range(0,numSemaphores)] The array of pointers to external
                                                        ///< semaphore handles to append into command list.
        ze_external_semaphore_wait_params_ext_t* waitParams,///< [in][range(0,numSemaphores)] The array of pointers to external
                                                        ///< semaphore wait parameters.
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendWaitExternalSemaphoreExt = dditable->ze.CommandList.pfnAppendWaitExternalSemaphoreExt;
        if( nullptr == pfnAppendWaitExternalSemaphoreExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handles to driver handles
        auto phSemaphoresLocal = new ze_external_semaphore_ext_handle_t [numSemaphores];
        for( size_t i = 0; ( nullptr != phSemaphores ) && ( i < numSemaphores ); ++i )
            phSemaphoresLocal[ i ] = reinterpret_cast<ze_external_semaphore_ext_object_t*>( phSemaphores[ i ] )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendWaitExternalSemaphoreExt( hCommandList, numSemaphores, phSemaphoresLocal, waitParams, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phSemaphoresLocal;
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeRTASBuilderCreateExt
    __zedlllocal ze_result_t ZE_APICALL
    zeRTASBuilderCreateExt(
        ze_driver_handle_t hDriver,                     ///< [in] handle of driver object
        const ze_rtas_builder_ext_desc_t* pDescriptor,  ///< [in] pointer to builder descriptor
        ze_rtas_builder_ext_handle_t* phBuilder         ///< [out] handle of builder object
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_driver_object_t*>( hDriver )->dditable;
        auto pfnCreateExt = dditable->ze.RTASBuilder.pfnCreateExt;
        if( nullptr == pfnCreateExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDriver = reinterpret_cast<ze_driver_object_t*>( hDriver )->handle;

        // forward to device-driver
        result = pfnCreateExt( hDriver, pDescriptor, phBuilder );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phBuilder = reinterpret_cast<ze_rtas_builder_ext_handle_t>(
                context->ze_rtas_builder_ext_factory.getInstance( *phBuilder, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeRTASBuilderGetBuildPropertiesExt
    __zedlllocal ze_result_t ZE_APICALL
    zeRTASBuilderGetBuildPropertiesExt(
        ze_rtas_builder_ext_handle_t hBuilder,          ///< [in] handle of builder object
        const ze_rtas_builder_build_op_ext_desc_t* pBuildOpDescriptor,  ///< [in] pointer to build operation descriptor
        ze_rtas_builder_ext_properties_t* pProperties   ///< [in,out] query result for builder properties
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_rtas_builder_ext_object_t*>( hBuilder )->dditable;
        auto pfnGetBuildPropertiesExt = dditable->ze.RTASBuilder.pfnGetBuildPropertiesExt;
        if( nullptr == pfnGetBuildPropertiesExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hBuilder = reinterpret_cast<ze_rtas_builder_ext_object_t*>( hBuilder )->handle;

        // forward to device-driver
        result = pfnGetBuildPropertiesExt( hBuilder, pBuildOpDescriptor, pProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDriverRTASFormatCompatibilityCheckExt
    __zedlllocal ze_result_t ZE_APICALL
    zeDriverRTASFormatCompatibilityCheckExt(
        ze_driver_handle_t hDriver,                     ///< [in] handle of driver object
        ze_rtas_format_ext_t rtasFormatA,               ///< [in] operand A
        ze_rtas_format_ext_t rtasFormatB                ///< [in] operand B
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_driver_object_t*>( hDriver )->dditable;
        auto pfnRTASFormatCompatibilityCheckExt = dditable->ze.Driver.pfnRTASFormatCompatibilityCheckExt;
        if( nullptr == pfnRTASFormatCompatibilityCheckExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDriver = reinterpret_cast<ze_driver_object_t*>( hDriver )->handle;

        // forward to device-driver
        result = pfnRTASFormatCompatibilityCheckExt( hDriver, rtasFormatA, rtasFormatB );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeRTASBuilderBuildExt
    __zedlllocal ze_result_t ZE_APICALL
    zeRTASBuilderBuildExt(
        ze_rtas_builder_ext_handle_t hBuilder,          ///< [in] handle of builder object
        const ze_rtas_builder_build_op_ext_desc_t* pBuildOpDescriptor,  ///< [in] pointer to build operation descriptor
        void* pScratchBuffer,                           ///< [in][range(0, `scratchBufferSizeBytes`)] scratch buffer to be used
                                                        ///< during acceleration structure construction
        size_t scratchBufferSizeBytes,                  ///< [in] size of scratch buffer, in bytes
        void* pRtasBuffer,                              ///< [in] pointer to destination buffer
        size_t rtasBufferSizeBytes,                     ///< [in] destination buffer size, in bytes
        ze_rtas_parallel_operation_ext_handle_t hParallelOperation, ///< [in][optional] handle to parallel operation object
        void* pBuildUserPtr,                            ///< [in][optional] pointer passed to callbacks
        ze_rtas_aabb_ext_t* pBounds,                    ///< [in,out][optional] pointer to destination address for acceleration
                                                        ///< structure bounds
        size_t* pRtasBufferSizeBytes                    ///< [out][optional] updated acceleration structure size requirement, in
                                                        ///< bytes
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_rtas_builder_ext_object_t*>( hBuilder )->dditable;
        auto pfnBuildExt = dditable->ze.RTASBuilder.pfnBuildExt;
        if( nullptr == pfnBuildExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hBuilder = reinterpret_cast<ze_rtas_builder_ext_object_t*>( hBuilder )->handle;

        // convert loader handle to driver handle
        hParallelOperation = ( hParallelOperation ) ? reinterpret_cast<ze_rtas_parallel_operation_ext_object_t*>( hParallelOperation )->handle : nullptr;

        // forward to device-driver
        result = pfnBuildExt( hBuilder, pBuildOpDescriptor, pScratchBuffer, scratchBufferSizeBytes, pRtasBuffer, rtasBufferSizeBytes, hParallelOperation, pBuildUserPtr, pBounds, pRtasBufferSizeBytes );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeRTASBuilderCommandListAppendCopyExt
    __zedlllocal ze_result_t ZE_APICALL
    zeRTASBuilderCommandListAppendCopyExt(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of command list
        void* dstptr,                                   ///< [in] pointer to destination in device memory to copy the ray tracing
                                                        ///< acceleration structure to
        const void* srcptr,                             ///< [in] pointer to a valid source ray tracing acceleration structure in
                                                        ///< host memory to copy from
        size_t size,                                    ///< [in] size in bytes to copy
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnCommandListAppendCopyExt = dditable->ze.RTASBuilder.pfnCommandListAppendCopyExt;
        if( nullptr == pfnCommandListAppendCopyExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnCommandListAppendCopyExt( hCommandList, dstptr, srcptr, size, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeRTASBuilderDestroyExt
    __zedlllocal ze_result_t ZE_APICALL
    zeRTASBuilderDestroyExt(
        ze_rtas_builder_ext_handle_t hBuilder           ///< [in][release] handle of builder object to destroy
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_rtas_builder_ext_object_t*>( hBuilder )->dditable;
        auto pfnDestroyExt = dditable->ze.RTASBuilder.pfnDestroyExt;
        if( nullptr == pfnDestroyExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hBuilder = reinterpret_cast<ze_rtas_builder_ext_object_t*>( hBuilder )->handle;

        // forward to device-driver
        result = pfnDestroyExt( hBuilder );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_rtas_builder_ext_factory.release( hBuilder );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeRTASParallelOperationCreateExt
    __zedlllocal ze_result_t ZE_APICALL
    zeRTASParallelOperationCreateExt(
        ze_driver_handle_t hDriver,                     ///< [in] handle of driver object
        ze_rtas_parallel_operation_ext_handle_t* phParallelOperation///< [out] handle of parallel operation object
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_driver_object_t*>( hDriver )->dditable;
        auto pfnCreateExt = dditable->ze.RTASParallelOperation.pfnCreateExt;
        if( nullptr == pfnCreateExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDriver = reinterpret_cast<ze_driver_object_t*>( hDriver )->handle;

        // forward to device-driver
        result = pfnCreateExt( hDriver, phParallelOperation );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phParallelOperation = reinterpret_cast<ze_rtas_parallel_operation_ext_handle_t>(
                context->ze_rtas_parallel_operation_ext_factory.getInstance( *phParallelOperation, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeRTASParallelOperationGetPropertiesExt
    __zedlllocal ze_result_t ZE_APICALL
    zeRTASParallelOperationGetPropertiesExt(
        ze_rtas_parallel_operation_ext_handle_t hParallelOperation, ///< [in] handle of parallel operation object
        ze_rtas_parallel_operation_ext_properties_t* pProperties///< [in,out] query result for parallel operation properties
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_rtas_parallel_operation_ext_object_t*>( hParallelOperation )->dditable;
        auto pfnGetPropertiesExt = dditable->ze.RTASParallelOperation.pfnGetPropertiesExt;
        if( nullptr == pfnGetPropertiesExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hParallelOperation = reinterpret_cast<ze_rtas_parallel_operation_ext_object_t*>( hParallelOperation )->handle;

        // forward to device-driver
        result = pfnGetPropertiesExt( hParallelOperation, pProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeRTASParallelOperationJoinExt
    __zedlllocal ze_result_t ZE_APICALL
    zeRTASParallelOperationJoinExt(
        ze_rtas_parallel_operation_ext_handle_t hParallelOperation  ///< [in] handle of parallel operation object
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_rtas_parallel_operation_ext_object_t*>( hParallelOperation )->dditable;
        auto pfnJoinExt = dditable->ze.RTASParallelOperation.pfnJoinExt;
        if( nullptr == pfnJoinExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hParallelOperation = reinterpret_cast<ze_rtas_parallel_operation_ext_object_t*>( hParallelOperation )->handle;

        // forward to device-driver
        result = pfnJoinExt( hParallelOperation );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeRTASParallelOperationDestroyExt
    __zedlllocal ze_result_t ZE_APICALL
    zeRTASParallelOperationDestroyExt(
        ze_rtas_parallel_operation_ext_handle_t hParallelOperation  ///< [in][release] handle of parallel operation object to destroy
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_rtas_parallel_operation_ext_object_t*>( hParallelOperation )->dditable;
        auto pfnDestroyExt = dditable->ze.RTASParallelOperation.pfnDestroyExt;
        if( nullptr == pfnDestroyExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hParallelOperation = reinterpret_cast<ze_rtas_parallel_operation_ext_object_t*>( hParallelOperation )->handle;

        // forward to device-driver
        result = pfnDestroyExt( hParallelOperation );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_rtas_parallel_operation_ext_factory.release( hParallelOperation );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeDeviceGetVectorWidthPropertiesExt
    __zedlllocal ze_result_t ZE_APICALL
    zeDeviceGetVectorWidthPropertiesExt(
        ze_device_handle_t hDevice,                     ///< [in] handle of the device
        uint32_t* pCount,                               ///< [in,out] pointer to the number of vector width properties.
                                                        ///< if count is zero, then the driver shall update the value with the
                                                        ///< total number of vector width properties available.
                                                        ///< if count is greater than the number of vector width properties
                                                        ///< available, then the driver shall update the value with the correct
                                                        ///< number of vector width properties available.
        ze_device_vector_width_properties_ext_t* pVectorWidthProperties ///< [in,out][optional][range(0, *pCount)] array of vector width properties.
                                                        ///< if count is less than the number of properties available, then the
                                                        ///< driver will return only the number requested.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_device_object_t*>( hDevice )->dditable;
        auto pfnGetVectorWidthPropertiesExt = dditable->ze.Device.pfnGetVectorWidthPropertiesExt;
        if( nullptr == pfnGetVectorWidthPropertiesExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hDevice = reinterpret_cast<ze_device_object_t*>( hDevice )->handle;

        // forward to device-driver
        result = pfnGetVectorWidthPropertiesExt( hDevice, pCount, pVectorWidthProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeKernelGetAllocationPropertiesExp
    __zedlllocal ze_result_t ZE_APICALL
    zeKernelGetAllocationPropertiesExp(
        ze_kernel_handle_t hKernel,                     ///< [in] Kernel handle.
        uint32_t* pCount,                               ///< [in,out] pointer to the number of kernel allocation properties.
                                                        ///< if count is zero, then the driver shall update the value with the
                                                        ///< total number of kernel allocation properties available.
                                                        ///< if count is greater than the number of kernel allocation properties
                                                        ///< available, then the driver shall update the value with the correct
                                                        ///< number of kernel allocation properties.
        ze_kernel_allocation_exp_properties_t* pAllocationProperties///< [in,out][optional][range(0, *pCount)] array of kernel allocation properties.
                                                        ///< if count is less than the number of kernel allocation properties
                                                        ///< available, then driver shall only retrieve that number of kernel
                                                        ///< allocation properties.
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_kernel_object_t*>( hKernel )->dditable;
        auto pfnGetAllocationPropertiesExp = dditable->ze.KernelExp.pfnGetAllocationPropertiesExp;
        if( nullptr == pfnGetAllocationPropertiesExp )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hKernel = reinterpret_cast<ze_kernel_object_t*>( hKernel )->handle;

        // forward to device-driver
        result = pfnGetAllocationPropertiesExp( hKernel, pCount, pAllocationProperties );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeMemGetIpcHandleWithProperties
    __zedlllocal ze_result_t ZE_APICALL
    zeMemGetIpcHandleWithProperties(
        ze_context_handle_t hContext,                   ///< [in] handle of the context object
        const void* ptr,                                ///< [in] pointer to the device memory allocation
        void* pNext,                                    ///< [in][optional] Pointer to extension-specific structure.
        ze_ipc_mem_handle_t* pIpcHandle                 ///< [out] Returned IPC memory handle
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnGetIpcHandleWithProperties = dditable->ze.Mem.pfnGetIpcHandleWithProperties;
        if( nullptr == pfnGetIpcHandleWithProperties )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnGetIpcHandleWithProperties( hContext, ptr, pNext, pIpcHandle );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeGraphCreateExt
    __zedlllocal ze_result_t ZE_APICALL
    zeGraphCreateExt(
        ze_context_handle_t hContext,                   ///< [in] handle of the context
        const void* pNext,                              ///< [in][optional] must be null or a pointer to an extension-specific
                                                        ///< structure (i.e. contains stype and pNext)
        ze_graph_handle_t* phGraph                      ///< [out] pointer to handle of the graph object created
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_context_object_t*>( hContext )->dditable;
        auto pfnCreateExt = dditable->ze.Graph.pfnCreateExt;
        if( nullptr == pfnCreateExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hContext = reinterpret_cast<ze_context_object_t*>( hContext )->handle;

        // forward to device-driver
        result = pfnCreateExt( hContext, pNext, phGraph );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phGraph = reinterpret_cast<ze_graph_handle_t>(
                context->ze_graph_factory.getInstance( *phGraph, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListBeginGraphCaptureExt
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListBeginGraphCaptureExt(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list to start capture on
        const void* pNext                               ///< [in][optional] must be null or a pointer to an extension-specific
                                                        ///< structure (i.e. contains stype and pNext)
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnBeginGraphCaptureExt = dditable->ze.CommandList.pfnBeginGraphCaptureExt;
        if( nullptr == pfnBeginGraphCaptureExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnBeginGraphCaptureExt( hCommandList, pNext );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListBeginCaptureIntoGraphExt
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListBeginCaptureIntoGraphExt(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list to start capture on
        ze_graph_handle_t hGraph,                       ///< [in] handle of the graph to capture into
        const void* pNext                               ///< [in][optional] must be null or a pointer to an extension-specific
                                                        ///< structure (i.e. contains stype and pNext)
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnBeginCaptureIntoGraphExt = dditable->ze.CommandList.pfnBeginCaptureIntoGraphExt;
        if( nullptr == pfnBeginCaptureIntoGraphExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hGraph = reinterpret_cast<ze_graph_object_t*>( hGraph )->handle;

        // forward to device-driver
        result = pfnBeginCaptureIntoGraphExt( hCommandList, hGraph, pNext );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListIsGraphCaptureEnabledExt
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListIsGraphCaptureEnabledExt(
        ze_command_list_handle_t hCommandList           ///< [in] handle of the command list
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnIsGraphCaptureEnabledExt = dditable->ze.CommandList.pfnIsGraphCaptureEnabledExt;
        if( nullptr == pfnIsGraphCaptureEnabledExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnIsGraphCaptureEnabledExt( hCommandList );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListEndGraphCaptureExt
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListEndGraphCaptureExt(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list to end capture on
        const void* pNext,                              ///< [in][optional] must be null or a pointer to an extension-specific
                                                        ///< structure (i.e. contains stype and pNext)
        ze_graph_handle_t* phGraph                      ///< [out] pointer to the captured graph handle
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnEndGraphCaptureExt = dditable->ze.CommandList.pfnEndGraphCaptureExt;
        if( nullptr == pfnEndGraphCaptureExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnEndGraphCaptureExt( hCommandList, pNext, phGraph );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phGraph = reinterpret_cast<ze_graph_handle_t>(
                context->ze_graph_factory.getInstance( *phGraph, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListGetGraphExt
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListGetGraphExt(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list that is in capture mode
        ze_graph_handle_t* phGraph                      ///< [out] pointer to the graph handle associated with the command list
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnGetGraphExt = dditable->ze.CommandList.pfnGetGraphExt;
        if( nullptr == pfnGetGraphExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // forward to device-driver
        result = pfnGetGraphExt( hCommandList, phGraph );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phGraph = reinterpret_cast<ze_graph_handle_t>(
                context->ze_graph_factory.getInstance( *phGraph, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeGraphGetPrimaryCommandListExt
    __zedlllocal ze_result_t ZE_APICALL
    zeGraphGetPrimaryCommandListExt(
        ze_graph_handle_t hGraph,                       ///< [in] handle of the graph
        ze_command_list_handle_t* phCommandList         ///< [out] pointer to the primary command list handle associated with the
                                                        ///< graph
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_graph_object_t*>( hGraph )->dditable;
        auto pfnGetPrimaryCommandListExt = dditable->ze.Graph.pfnGetPrimaryCommandListExt;
        if( nullptr == pfnGetPrimaryCommandListExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hGraph = reinterpret_cast<ze_graph_object_t*>( hGraph )->handle;

        // forward to device-driver
        result = pfnGetPrimaryCommandListExt( hGraph, phCommandList );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phCommandList = reinterpret_cast<ze_command_list_handle_t>(
                context->ze_command_list_factory.getInstance( *phCommandList, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeGraphSetDestructionCallbackExt
    __zedlllocal ze_result_t ZE_APICALL
    zeGraphSetDestructionCallbackExt(
        ze_graph_handle_t hGraph,                       ///< [in] handle of the graph
        zex_mem_graph_free_callback_fn_t pfnCallback,   ///< [in] callback function to invoke when the graph is destroyed
        void* pUserData,                                ///< [in][optional] user data to pass to the callback
        const void* pNext                               ///< [in][optional] must be null or a pointer to an extension-specific
                                                        ///< structure (i.e. contains stype and pNext)
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_graph_object_t*>( hGraph )->dditable;
        auto pfnSetDestructionCallbackExt = dditable->ze.Graph.pfnSetDestructionCallbackExt;
        if( nullptr == pfnSetDestructionCallbackExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hGraph = reinterpret_cast<ze_graph_object_t*>( hGraph )->handle;

        // forward to device-driver
        result = pfnSetDestructionCallbackExt( hGraph, pfnCallback, pUserData, pNext );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeGraphInstantiateExt
    __zedlllocal ze_result_t ZE_APICALL
    zeGraphInstantiateExt(
        ze_graph_handle_t hGraph,                       ///< [in] handle of the recorded graph
        const void* pNext,                              ///< [in][optional] must be null or a pointer to an extension-specific
                                                        ///< structure (i.e. contains stype and pNext)
        ze_executable_graph_handle_t* phExecutableGraph ///< [out] pointer to handle of the executable graph
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_graph_object_t*>( hGraph )->dditable;
        auto pfnInstantiateExt = dditable->ze.Graph.pfnInstantiateExt;
        if( nullptr == pfnInstantiateExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hGraph = reinterpret_cast<ze_graph_object_t*>( hGraph )->handle;

        // forward to device-driver
        result = pfnInstantiateExt( hGraph, pNext, phExecutableGraph );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phExecutableGraph = reinterpret_cast<ze_executable_graph_handle_t>(
                context->ze_executable_graph_factory.getInstance( *phExecutableGraph, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendGraphExt
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendGraphExt(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list to execute the graph on
        ze_executable_graph_handle_t hGraph,            ///< [in] handle of the executable graph
        const void* pNext,                              ///< [in][optional] must be null or a pointer to an extension-specific
                                                        ///< structure (i.e. contains stype and pNext)
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] number of events to wait on before launching; must be 0
                                                        ///< if `nullptr == phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendGraphExt = dditable->ze.CommandList.pfnAppendGraphExt;
        if( nullptr == pfnAppendGraphExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hGraph = reinterpret_cast<ze_executable_graph_object_t*>( hGraph )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendGraphExt( hCommandList, hGraph, pNext, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeExecutableGraphGetSourceGraphExt
    __zedlllocal ze_result_t ZE_APICALL
    zeExecutableGraphGetSourceGraphExt(
        ze_executable_graph_handle_t hGraph,            ///< [in] handle of the executable graph
        ze_graph_handle_t* phSourceGraph                ///< [out] pointer to the source recorded graph handle
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_executable_graph_object_t*>( hGraph )->dditable;
        auto pfnGetSourceGraphExt = dditable->ze.ExecutableGraph.pfnGetSourceGraphExt;
        if( nullptr == pfnGetSourceGraphExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hGraph = reinterpret_cast<ze_executable_graph_object_t*>( hGraph )->handle;

        // forward to device-driver
        result = pfnGetSourceGraphExt( hGraph, phSourceGraph );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        try
        {
            // convert driver handle to loader handle
            *phSourceGraph = reinterpret_cast<ze_graph_handle_t>(
                context->ze_graph_factory.getInstance( *phSourceGraph, dditable ) );
        }
        catch( std::bad_alloc& )
        {
            result = ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY;
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeGraphIsEmptyExt
    __zedlllocal ze_result_t ZE_APICALL
    zeGraphIsEmptyExt(
        ze_graph_handle_t hGraph                        ///< [in] handle of the graph
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_graph_object_t*>( hGraph )->dditable;
        auto pfnIsEmptyExt = dditable->ze.Graph.pfnIsEmptyExt;
        if( nullptr == pfnIsEmptyExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hGraph = reinterpret_cast<ze_graph_object_t*>( hGraph )->handle;

        // forward to device-driver
        result = pfnIsEmptyExt( hGraph );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeGraphDumpContentsExt
    __zedlllocal ze_result_t ZE_APICALL
    zeGraphDumpContentsExt(
        ze_graph_handle_t hGraph,                       ///< [in] handle of the graph
        const char* filePath,                           ///< [in] path where the DOT file is written
        const void* pNext                               ///< [in][optional] must be null or a pointer to an extension-specific
                                                        ///< structure (i.e. contains stype and pNext)
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_graph_object_t*>( hGraph )->dditable;
        auto pfnDumpContentsExt = dditable->ze.Graph.pfnDumpContentsExt;
        if( nullptr == pfnDumpContentsExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hGraph = reinterpret_cast<ze_graph_object_t*>( hGraph )->handle;

        // forward to device-driver
        result = pfnDumpContentsExt( hGraph, filePath, pNext );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeExecutableGraphDestroyExt
    __zedlllocal ze_result_t ZE_APICALL
    zeExecutableGraphDestroyExt(
        ze_executable_graph_handle_t hGraph             ///< [in][release] handle of the executable graph to destroy
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_executable_graph_object_t*>( hGraph )->dditable;
        auto pfnDestroyExt = dditable->ze.ExecutableGraph.pfnDestroyExt;
        if( nullptr == pfnDestroyExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hGraph = reinterpret_cast<ze_executable_graph_object_t*>( hGraph )->handle;

        // forward to device-driver
        result = pfnDestroyExt( hGraph );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_executable_graph_factory.release( hGraph );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeGraphDestroyExt
    __zedlllocal ze_result_t ZE_APICALL
    zeGraphDestroyExt(
        ze_graph_handle_t hGraph                        ///< [in][release] handle of the graph to destroy
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_graph_object_t*>( hGraph )->dditable;
        auto pfnDestroyExt = dditable->ze.Graph.pfnDestroyExt;
        if( nullptr == pfnDestroyExt )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hGraph = reinterpret_cast<ze_graph_object_t*>( hGraph )->handle;

        // forward to device-driver
        result = pfnDestroyExt( hGraph );

        if( ZE_RESULT_SUCCESS != result )
            return result;

        // release loader handle
        context->ze_graph_factory.release( hGraph );

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////
    /// @brief Intercept function for zeCommandListAppendHostFunction
    __zedlllocal ze_result_t ZE_APICALL
    zeCommandListAppendHostFunction(
        ze_command_list_handle_t hCommandList,          ///< [in] handle of the command list
        ze_host_function_callback_t pfnHostFunction,    ///< [in] host function to call, expected to be lightweight and
                                                        ///< non-blocking
        void* pUserData,                                ///< [in][optional] user specific data that would be passed to function;
                                                        ///< neither the runtime nor the device will dereference it
        const void* pNext,                              ///< [in][optional] additional extensions passed to the function
        ze_event_handle_t hSignalEvent,                 ///< [in][optional] handle of the event to signal on completion
        uint32_t numWaitEvents,                         ///< [in][optional] count of phWaitEvents; must be 0 if `nullptr ==
                                                        ///< phWaitEvents`
        ze_event_handle_t* phWaitEvents                 ///< [in][optional][range(0, numWaitEvents)] handle of the events to wait
                                                        ///< on before launching
        )
    {
        ze_result_t result = ZE_RESULT_SUCCESS;
        
        // extract driver's function pointer table
        auto dditable = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->dditable;
        auto pfnAppendHostFunction = dditable->ze.CommandList.pfnAppendHostFunction;
        if( nullptr == pfnAppendHostFunction )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        // convert loader handle to driver handle
        hCommandList = reinterpret_cast<ze_command_list_object_t*>( hCommandList )->handle;

        // convert loader handle to driver handle
        hSignalEvent = ( hSignalEvent ) ? reinterpret_cast<ze_event_object_t*>( hSignalEvent )->handle : nullptr;

        // convert loader handles to driver handles
        auto phWaitEventsLocal = new ze_event_handle_t [numWaitEvents];
        for( size_t i = 0; ( nullptr != phWaitEvents ) && ( i < numWaitEvents ); ++i )
            phWaitEventsLocal[ i ] = reinterpret_cast<ze_event_object_t*>( phWaitEvents[ i ] )->handle;

        // forward to device-driver
        result = pfnAppendHostFunction( hCommandList, pfnHostFunction, pUserData, pNext, hSignalEvent, numWaitEvents, phWaitEventsLocal );
        delete []phWaitEventsLocal;

        return result;
    }

} // namespace loader

#if defined(__cplusplus)
extern "C" {
#endif

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for Global table
__zedlllocal void ZE_APICALL
zeGetGlobalProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->Global->pfnInit                                     = loader::zeInit;
    loader::loaderDispatch->pCore->Global->pfnInitDrivers                              = loader::zeInitDrivers;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for RTASBuilder table
__zedlllocal void ZE_APICALL
zeGetRTASBuilderProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->RTASBuilder->pfnCreateExt                                = loader::zeRTASBuilderCreateExt;
    loader::loaderDispatch->pCore->RTASBuilder->pfnGetBuildPropertiesExt                    = loader::zeRTASBuilderGetBuildPropertiesExt;
    loader::loaderDispatch->pCore->RTASBuilder->pfnBuildExt                                 = loader::zeRTASBuilderBuildExt;
    loader::loaderDispatch->pCore->RTASBuilder->pfnCommandListAppendCopyExt                 = loader::zeRTASBuilderCommandListAppendCopyExt;
    loader::loaderDispatch->pCore->RTASBuilder->pfnDestroyExt                               = loader::zeRTASBuilderDestroyExt;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for RTASBuilderExp table
__zedlllocal void ZE_APICALL
zeGetRTASBuilderExpProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->RTASBuilderExp->pfnCreateExp                                = loader::zeRTASBuilderCreateExp;
    loader::loaderDispatch->pCore->RTASBuilderExp->pfnGetBuildPropertiesExp                    = loader::zeRTASBuilderGetBuildPropertiesExp;
    loader::loaderDispatch->pCore->RTASBuilderExp->pfnBuildExp                                 = loader::zeRTASBuilderBuildExp;
    loader::loaderDispatch->pCore->RTASBuilderExp->pfnDestroyExp                               = loader::zeRTASBuilderDestroyExp;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for RTASParallelOperation table
__zedlllocal void ZE_APICALL
zeGetRTASParallelOperationProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->RTASParallelOperation->pfnCreateExt                                = loader::zeRTASParallelOperationCreateExt;
    loader::loaderDispatch->pCore->RTASParallelOperation->pfnGetPropertiesExt                         = loader::zeRTASParallelOperationGetPropertiesExt;
    loader::loaderDispatch->pCore->RTASParallelOperation->pfnJoinExt                                  = loader::zeRTASParallelOperationJoinExt;
    loader::loaderDispatch->pCore->RTASParallelOperation->pfnDestroyExt                               = loader::zeRTASParallelOperationDestroyExt;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for RTASParallelOperationExp table
__zedlllocal void ZE_APICALL
zeGetRTASParallelOperationExpProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->RTASParallelOperationExp->pfnCreateExp                                = loader::zeRTASParallelOperationCreateExp;
    loader::loaderDispatch->pCore->RTASParallelOperationExp->pfnGetPropertiesExp                         = loader::zeRTASParallelOperationGetPropertiesExp;
    loader::loaderDispatch->pCore->RTASParallelOperationExp->pfnJoinExp                                  = loader::zeRTASParallelOperationJoinExp;
    loader::loaderDispatch->pCore->RTASParallelOperationExp->pfnDestroyExp                               = loader::zeRTASParallelOperationDestroyExp;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for Driver table
__zedlllocal void ZE_APICALL
zeGetDriverProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->Driver->pfnGet                                      = loader::zeDriverGet;
    loader::loaderDispatch->pCore->Driver->pfnGetApiVersion                            = loader::zeDriverGetApiVersion;
    loader::loaderDispatch->pCore->Driver->pfnGetProperties                            = loader::zeDriverGetProperties;
    loader::loaderDispatch->pCore->Driver->pfnGetIpcProperties                         = loader::zeDriverGetIpcProperties;
    loader::loaderDispatch->pCore->Driver->pfnGetExtensionProperties                   = loader::zeDriverGetExtensionProperties;
    loader::loaderDispatch->pCore->Driver->pfnGetExtensionFunctionAddress              = loader::zeDriverGetExtensionFunctionAddress;
    loader::loaderDispatch->pCore->Driver->pfnRTASFormatCompatibilityCheckExt          = loader::zeDriverRTASFormatCompatibilityCheckExt;
    loader::loaderDispatch->pCore->Driver->pfnGetDefaultContext                        = loader::zeDriverGetDefaultContext;
    loader::loaderDispatch->pCore->Driver->pfnGetLastErrorDescription                  = loader::zeDriverGetLastErrorDescription;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for DriverExp table
__zedlllocal void ZE_APICALL
zeGetDriverExpProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->DriverExp->pfnRTASFormatCompatibilityCheckExp          = loader::zeDriverRTASFormatCompatibilityCheckExp;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for Device table
__zedlllocal void ZE_APICALL
zeGetDeviceProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->Device->pfnGet                                      = loader::zeDeviceGet;
    loader::loaderDispatch->pCore->Device->pfnGetSubDevices                            = loader::zeDeviceGetSubDevices;
    loader::loaderDispatch->pCore->Device->pfnGetProperties                            = loader::zeDeviceGetProperties;
    loader::loaderDispatch->pCore->Device->pfnGetComputeProperties                     = loader::zeDeviceGetComputeProperties;
    loader::loaderDispatch->pCore->Device->pfnGetModuleProperties                      = loader::zeDeviceGetModuleProperties;
    loader::loaderDispatch->pCore->Device->pfnGetCommandQueueGroupProperties           = loader::zeDeviceGetCommandQueueGroupProperties;
    loader::loaderDispatch->pCore->Device->pfnGetMemoryProperties                      = loader::zeDeviceGetMemoryProperties;
    loader::loaderDispatch->pCore->Device->pfnGetMemoryAccessProperties                = loader::zeDeviceGetMemoryAccessProperties;
    loader::loaderDispatch->pCore->Device->pfnGetCacheProperties                       = loader::zeDeviceGetCacheProperties;
    loader::loaderDispatch->pCore->Device->pfnGetImageProperties                       = loader::zeDeviceGetImageProperties;
    loader::loaderDispatch->pCore->Device->pfnGetExternalMemoryProperties              = loader::zeDeviceGetExternalMemoryProperties;
    loader::loaderDispatch->pCore->Device->pfnGetP2PProperties                         = loader::zeDeviceGetP2PProperties;
    loader::loaderDispatch->pCore->Device->pfnCanAccessPeer                            = loader::zeDeviceCanAccessPeer;
    loader::loaderDispatch->pCore->Device->pfnGetStatus                                = loader::zeDeviceGetStatus;
    loader::loaderDispatch->pCore->Device->pfnGetGlobalTimestamps                      = loader::zeDeviceGetGlobalTimestamps;
    loader::loaderDispatch->pCore->Device->pfnImportExternalSemaphoreExt               = loader::zeDeviceImportExternalSemaphoreExt;
    loader::loaderDispatch->pCore->Device->pfnReleaseExternalSemaphoreExt              = loader::zeDeviceReleaseExternalSemaphoreExt;
    loader::loaderDispatch->pCore->Device->pfnGetVectorWidthPropertiesExt              = loader::zeDeviceGetVectorWidthPropertiesExt;
    loader::loaderDispatch->pCore->Device->pfnSynchronize                              = loader::zeDeviceSynchronize;
    loader::loaderDispatch->pCore->Device->pfnGetAggregatedCopyOffloadIncrementValue   = loader::zeDeviceGetAggregatedCopyOffloadIncrementValue;
    loader::loaderDispatch->pCore->Device->pfnGetRuntimeRequirements                   = loader::zeDeviceGetRuntimeRequirements;
    loader::loaderDispatch->pCore->Device->pfnGetRuntimeRequirementsKey                = loader::zeDeviceGetRuntimeRequirementsKey;
    loader::loaderDispatch->pCore->Device->pfnValidateRuntimeRequirements              = loader::zeDeviceValidateRuntimeRequirements;
    loader::loaderDispatch->pCore->Device->pfnGetCounterBasedEventMaxValue             = loader::zeDeviceGetCounterBasedEventMaxValue;
    loader::loaderDispatch->pCore->Device->pfnReserveCacheExt                          = loader::zeDeviceReserveCacheExt;
    loader::loaderDispatch->pCore->Device->pfnSetCacheAdviceExt                        = loader::zeDeviceSetCacheAdviceExt;
    loader::loaderDispatch->pCore->Device->pfnPciGetPropertiesExt                      = loader::zeDevicePciGetPropertiesExt;
    loader::loaderDispatch->pCore->Device->pfnGetRootDevice                            = loader::zeDeviceGetRootDevice;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for DeviceExp table
__zedlllocal void ZE_APICALL
zeGetDeviceExpProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->DeviceExp->pfnGetFabricVertexExp                       = loader::zeDeviceGetFabricVertexExp;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for Context table
__zedlllocal void ZE_APICALL
zeGetContextProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->Context->pfnCreate                                   = loader::zeContextCreate;
    loader::loaderDispatch->pCore->Context->pfnDestroy                                  = loader::zeContextDestroy;
    loader::loaderDispatch->pCore->Context->pfnGetStatus                                = loader::zeContextGetStatus;
    loader::loaderDispatch->pCore->Context->pfnSystemBarrier                            = loader::zeContextSystemBarrier;
    loader::loaderDispatch->pCore->Context->pfnMakeMemoryResident                       = loader::zeContextMakeMemoryResident;
    loader::loaderDispatch->pCore->Context->pfnEvictMemory                              = loader::zeContextEvictMemory;
    loader::loaderDispatch->pCore->Context->pfnMakeImageResident                        = loader::zeContextMakeImageResident;
    loader::loaderDispatch->pCore->Context->pfnEvictImage                               = loader::zeContextEvictImage;
    loader::loaderDispatch->pCore->Context->pfnCreateEx                                 = loader::zeContextCreateEx;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for CommandQueue table
__zedlllocal void ZE_APICALL
zeGetCommandQueueProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->CommandQueue->pfnCreate                                   = loader::zeCommandQueueCreate;
    loader::loaderDispatch->pCore->CommandQueue->pfnDestroy                                  = loader::zeCommandQueueDestroy;
    loader::loaderDispatch->pCore->CommandQueue->pfnExecuteCommandLists                      = loader::zeCommandQueueExecuteCommandLists;
    loader::loaderDispatch->pCore->CommandQueue->pfnSynchronize                              = loader::zeCommandQueueSynchronize;
    loader::loaderDispatch->pCore->CommandQueue->pfnGetFlags                                 = loader::zeCommandQueueGetFlags;
    loader::loaderDispatch->pCore->CommandQueue->pfnGetMode                                  = loader::zeCommandQueueGetMode;
    loader::loaderDispatch->pCore->CommandQueue->pfnGetPriority                              = loader::zeCommandQueueGetPriority;
    loader::loaderDispatch->pCore->CommandQueue->pfnGetOrdinal                               = loader::zeCommandQueueGetOrdinal;
    loader::loaderDispatch->pCore->CommandQueue->pfnGetIndex                                 = loader::zeCommandQueueGetIndex;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for CommandList table
__zedlllocal void ZE_APICALL
zeGetCommandListProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->CommandList->pfnCreate                                   = loader::zeCommandListCreate;
    loader::loaderDispatch->pCore->CommandList->pfnCreateImmediate                          = loader::zeCommandListCreateImmediate;
    loader::loaderDispatch->pCore->CommandList->pfnDestroy                                  = loader::zeCommandListDestroy;
    loader::loaderDispatch->pCore->CommandList->pfnClose                                    = loader::zeCommandListClose;
    loader::loaderDispatch->pCore->CommandList->pfnReset                                    = loader::zeCommandListReset;
    loader::loaderDispatch->pCore->CommandList->pfnAppendWriteGlobalTimestamp               = loader::zeCommandListAppendWriteGlobalTimestamp;
    loader::loaderDispatch->pCore->CommandList->pfnAppendBarrier                            = loader::zeCommandListAppendBarrier;
    loader::loaderDispatch->pCore->CommandList->pfnAppendMemoryRangesBarrier                = loader::zeCommandListAppendMemoryRangesBarrier;
    loader::loaderDispatch->pCore->CommandList->pfnAppendMemoryCopy                         = loader::zeCommandListAppendMemoryCopy;
    loader::loaderDispatch->pCore->CommandList->pfnAppendMemoryFill                         = loader::zeCommandListAppendMemoryFill;
    loader::loaderDispatch->pCore->CommandList->pfnAppendMemoryCopyRegion                   = loader::zeCommandListAppendMemoryCopyRegion;
    loader::loaderDispatch->pCore->CommandList->pfnAppendMemoryCopyFromContext              = loader::zeCommandListAppendMemoryCopyFromContext;
    loader::loaderDispatch->pCore->CommandList->pfnAppendImageCopy                          = loader::zeCommandListAppendImageCopy;
    loader::loaderDispatch->pCore->CommandList->pfnAppendImageCopyRegion                    = loader::zeCommandListAppendImageCopyRegion;
    loader::loaderDispatch->pCore->CommandList->pfnAppendImageCopyToMemory                  = loader::zeCommandListAppendImageCopyToMemory;
    loader::loaderDispatch->pCore->CommandList->pfnAppendImageCopyFromMemory                = loader::zeCommandListAppendImageCopyFromMemory;
    loader::loaderDispatch->pCore->CommandList->pfnAppendMemoryPrefetch                     = loader::zeCommandListAppendMemoryPrefetch;
    loader::loaderDispatch->pCore->CommandList->pfnAppendMemAdvise                          = loader::zeCommandListAppendMemAdvise;
    loader::loaderDispatch->pCore->CommandList->pfnAppendSignalEvent                        = loader::zeCommandListAppendSignalEvent;
    loader::loaderDispatch->pCore->CommandList->pfnAppendWaitOnEvents                       = loader::zeCommandListAppendWaitOnEvents;
    loader::loaderDispatch->pCore->CommandList->pfnAppendEventReset                         = loader::zeCommandListAppendEventReset;
    loader::loaderDispatch->pCore->CommandList->pfnAppendQueryKernelTimestamps              = loader::zeCommandListAppendQueryKernelTimestamps;
    loader::loaderDispatch->pCore->CommandList->pfnAppendLaunchKernel                       = loader::zeCommandListAppendLaunchKernel;
    loader::loaderDispatch->pCore->CommandList->pfnAppendLaunchCooperativeKernel            = loader::zeCommandListAppendLaunchCooperativeKernel;
    loader::loaderDispatch->pCore->CommandList->pfnAppendLaunchKernelIndirect               = loader::zeCommandListAppendLaunchKernelIndirect;
    loader::loaderDispatch->pCore->CommandList->pfnAppendLaunchMultipleKernelsIndirect      = loader::zeCommandListAppendLaunchMultipleKernelsIndirect;
    loader::loaderDispatch->pCore->CommandList->pfnAppendSignalExternalSemaphoreExt         = loader::zeCommandListAppendSignalExternalSemaphoreExt;
    loader::loaderDispatch->pCore->CommandList->pfnAppendWaitExternalSemaphoreExt           = loader::zeCommandListAppendWaitExternalSemaphoreExt;
    loader::loaderDispatch->pCore->CommandList->pfnAppendLaunchKernelWithParameters         = loader::zeCommandListAppendLaunchKernelWithParameters;
    loader::loaderDispatch->pCore->CommandList->pfnAppendLaunchKernelWithArguments          = loader::zeCommandListAppendLaunchKernelWithArguments;
    loader::loaderDispatch->pCore->CommandList->pfnAppendMemoryCopyWithParameters           = loader::zeCommandListAppendMemoryCopyWithParameters;
    loader::loaderDispatch->pCore->CommandList->pfnAppendMemoryFillWithParameters           = loader::zeCommandListAppendMemoryFillWithParameters;
    loader::loaderDispatch->pCore->CommandList->pfnImmediateAppendCommandListsWithParameters    = loader::zeCommandListImmediateAppendCommandListsWithParameters;
    loader::loaderDispatch->pCore->CommandList->pfnGetFlags                                 = loader::zeCommandListGetFlags;
    loader::loaderDispatch->pCore->CommandList->pfnImmediateGetFlags                        = loader::zeCommandListImmediateGetFlags;
    loader::loaderDispatch->pCore->CommandList->pfnImmediateGetMode                         = loader::zeCommandListImmediateGetMode;
    loader::loaderDispatch->pCore->CommandList->pfnImmediateGetPriority                     = loader::zeCommandListImmediateGetPriority;
    loader::loaderDispatch->pCore->CommandList->pfnBeginGraphCaptureExt                     = loader::zeCommandListBeginGraphCaptureExt;
    loader::loaderDispatch->pCore->CommandList->pfnBeginCaptureIntoGraphExt                 = loader::zeCommandListBeginCaptureIntoGraphExt;
    loader::loaderDispatch->pCore->CommandList->pfnIsGraphCaptureEnabledExt                 = loader::zeCommandListIsGraphCaptureEnabledExt;
    loader::loaderDispatch->pCore->CommandList->pfnEndGraphCaptureExt                       = loader::zeCommandListEndGraphCaptureExt;
    loader::loaderDispatch->pCore->CommandList->pfnGetGraphExt                              = loader::zeCommandListGetGraphExt;
    loader::loaderDispatch->pCore->CommandList->pfnAppendGraphExt                           = loader::zeCommandListAppendGraphExt;
    loader::loaderDispatch->pCore->CommandList->pfnAppendHostFunction                       = loader::zeCommandListAppendHostFunction;
    loader::loaderDispatch->pCore->CommandList->pfnAppendImageCopyToMemoryExt               = loader::zeCommandListAppendImageCopyToMemoryExt;
    loader::loaderDispatch->pCore->CommandList->pfnAppendImageCopyFromMemoryExt             = loader::zeCommandListAppendImageCopyFromMemoryExt;
    loader::loaderDispatch->pCore->CommandList->pfnHostSynchronize                          = loader::zeCommandListHostSynchronize;
    loader::loaderDispatch->pCore->CommandList->pfnGetDeviceHandle                          = loader::zeCommandListGetDeviceHandle;
    loader::loaderDispatch->pCore->CommandList->pfnGetContextHandle                         = loader::zeCommandListGetContextHandle;
    loader::loaderDispatch->pCore->CommandList->pfnGetOrdinal                               = loader::zeCommandListGetOrdinal;
    loader::loaderDispatch->pCore->CommandList->pfnImmediateGetIndex                        = loader::zeCommandListImmediateGetIndex;
    loader::loaderDispatch->pCore->CommandList->pfnIsImmediate                              = loader::zeCommandListIsImmediate;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for CommandListExp table
__zedlllocal void ZE_APICALL
zeGetCommandListExpProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->CommandListExp->pfnGetNextCommandIdWithKernelsExp           = loader::zeCommandListGetNextCommandIdWithKernelsExp;
    loader::loaderDispatch->pCore->CommandListExp->pfnUpdateMutableCommandKernelsExp           = loader::zeCommandListUpdateMutableCommandKernelsExp;
    loader::loaderDispatch->pCore->CommandListExp->pfnIsMutableExp                             = loader::zeCommandListIsMutableExp;
    loader::loaderDispatch->pCore->CommandListExp->pfnCreateCloneExp                           = loader::zeCommandListCreateCloneExp;
    loader::loaderDispatch->pCore->CommandListExp->pfnImmediateAppendCommandListsExp           = loader::zeCommandListImmediateAppendCommandListsExp;
    loader::loaderDispatch->pCore->CommandListExp->pfnGetNextCommandIdExp                      = loader::zeCommandListGetNextCommandIdExp;
    loader::loaderDispatch->pCore->CommandListExp->pfnUpdateMutableCommandsExp                 = loader::zeCommandListUpdateMutableCommandsExp;
    loader::loaderDispatch->pCore->CommandListExp->pfnUpdateMutableCommandSignalEventExp       = loader::zeCommandListUpdateMutableCommandSignalEventExp;
    loader::loaderDispatch->pCore->CommandListExp->pfnUpdateMutableCommandWaitEventsExp        = loader::zeCommandListUpdateMutableCommandWaitEventsExp;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for Event table
__zedlllocal void ZE_APICALL
zeGetEventProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->Event->pfnCreate                                   = loader::zeEventCreate;
    loader::loaderDispatch->pCore->Event->pfnDestroy                                  = loader::zeEventDestroy;
    loader::loaderDispatch->pCore->Event->pfnHostSignal                               = loader::zeEventHostSignal;
    loader::loaderDispatch->pCore->Event->pfnHostSynchronize                          = loader::zeEventHostSynchronize;
    loader::loaderDispatch->pCore->Event->pfnQueryStatus                              = loader::zeEventQueryStatus;
    loader::loaderDispatch->pCore->Event->pfnHostReset                                = loader::zeEventHostReset;
    loader::loaderDispatch->pCore->Event->pfnQueryKernelTimestamp                     = loader::zeEventQueryKernelTimestamp;
    loader::loaderDispatch->pCore->Event->pfnCounterBasedCreate                       = loader::zeEventCounterBasedCreate;
    loader::loaderDispatch->pCore->Event->pfnCounterBasedGetIpcHandle                 = loader::zeEventCounterBasedGetIpcHandle;
    loader::loaderDispatch->pCore->Event->pfnCounterBasedOpenIpcHandle                = loader::zeEventCounterBasedOpenIpcHandle;
    loader::loaderDispatch->pCore->Event->pfnCounterBasedCloseIpcHandle               = loader::zeEventCounterBasedCloseIpcHandle;
    loader::loaderDispatch->pCore->Event->pfnCounterBasedGetDeviceAddress             = loader::zeEventCounterBasedGetDeviceAddress;
    loader::loaderDispatch->pCore->Event->pfnGetCounterBasedFlags                     = loader::zeEventGetCounterBasedFlags;
    loader::loaderDispatch->pCore->Event->pfnQueryKernelTimestampsExt                 = loader::zeEventQueryKernelTimestampsExt;
    loader::loaderDispatch->pCore->Event->pfnGetEventPool                             = loader::zeEventGetEventPool;
    loader::loaderDispatch->pCore->Event->pfnGetSignalScope                           = loader::zeEventGetSignalScope;
    loader::loaderDispatch->pCore->Event->pfnGetWaitScope                             = loader::zeEventGetWaitScope;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for EventExp table
__zedlllocal void ZE_APICALL
zeGetEventExpProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->EventExp->pfnQueryTimestampsExp                       = loader::zeEventQueryTimestampsExp;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for EventPool table
__zedlllocal void ZE_APICALL
zeGetEventPoolProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->EventPool->pfnCreate                                   = loader::zeEventPoolCreate;
    loader::loaderDispatch->pCore->EventPool->pfnDestroy                                  = loader::zeEventPoolDestroy;
    loader::loaderDispatch->pCore->EventPool->pfnGetIpcHandle                             = loader::zeEventPoolGetIpcHandle;
    loader::loaderDispatch->pCore->EventPool->pfnOpenIpcHandle                            = loader::zeEventPoolOpenIpcHandle;
    loader::loaderDispatch->pCore->EventPool->pfnCloseIpcHandle                           = loader::zeEventPoolCloseIpcHandle;
    loader::loaderDispatch->pCore->EventPool->pfnPutIpcHandle                             = loader::zeEventPoolPutIpcHandle;
    loader::loaderDispatch->pCore->EventPool->pfnGetContextHandle                         = loader::zeEventPoolGetContextHandle;
    loader::loaderDispatch->pCore->EventPool->pfnGetFlags                                 = loader::zeEventPoolGetFlags;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for Fence table
__zedlllocal void ZE_APICALL
zeGetFenceProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->Fence->pfnCreate                                   = loader::zeFenceCreate;
    loader::loaderDispatch->pCore->Fence->pfnDestroy                                  = loader::zeFenceDestroy;
    loader::loaderDispatch->pCore->Fence->pfnHostSynchronize                          = loader::zeFenceHostSynchronize;
    loader::loaderDispatch->pCore->Fence->pfnQueryStatus                              = loader::zeFenceQueryStatus;
    loader::loaderDispatch->pCore->Fence->pfnReset                                    = loader::zeFenceReset;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for Image table
__zedlllocal void ZE_APICALL
zeGetImageProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->Image->pfnGetProperties                            = loader::zeImageGetProperties;
    loader::loaderDispatch->pCore->Image->pfnCreate                                   = loader::zeImageCreate;
    loader::loaderDispatch->pCore->Image->pfnDestroy                                  = loader::zeImageDestroy;
    loader::loaderDispatch->pCore->Image->pfnGetAllocPropertiesExt                    = loader::zeImageGetAllocPropertiesExt;
    loader::loaderDispatch->pCore->Image->pfnViewCreateExt                            = loader::zeImageViewCreateExt;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for ImageExp table
__zedlllocal void ZE_APICALL
zeGetImageExpProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->ImageExp->pfnGetMemoryPropertiesExp                   = loader::zeImageGetMemoryPropertiesExp;
    loader::loaderDispatch->pCore->ImageExp->pfnViewCreateExp                            = loader::zeImageViewCreateExp;
    loader::loaderDispatch->pCore->ImageExp->pfnGetDeviceOffsetExp                       = loader::zeImageGetDeviceOffsetExp;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for Kernel table
__zedlllocal void ZE_APICALL
zeGetKernelProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->Kernel->pfnCreate                                   = loader::zeKernelCreate;
    loader::loaderDispatch->pCore->Kernel->pfnDestroy                                  = loader::zeKernelDestroy;
    loader::loaderDispatch->pCore->Kernel->pfnSetCacheConfig                           = loader::zeKernelSetCacheConfig;
    loader::loaderDispatch->pCore->Kernel->pfnSetGroupSize                             = loader::zeKernelSetGroupSize;
    loader::loaderDispatch->pCore->Kernel->pfnSuggestGroupSize                         = loader::zeKernelSuggestGroupSize;
    loader::loaderDispatch->pCore->Kernel->pfnSuggestMaxCooperativeGroupCount          = loader::zeKernelSuggestMaxCooperativeGroupCount;
    loader::loaderDispatch->pCore->Kernel->pfnSetArgumentValue                         = loader::zeKernelSetArgumentValue;
    loader::loaderDispatch->pCore->Kernel->pfnSetIndirectAccess                        = loader::zeKernelSetIndirectAccess;
    loader::loaderDispatch->pCore->Kernel->pfnGetIndirectAccess                        = loader::zeKernelGetIndirectAccess;
    loader::loaderDispatch->pCore->Kernel->pfnGetSourceAttributes                      = loader::zeKernelGetSourceAttributes;
    loader::loaderDispatch->pCore->Kernel->pfnGetProperties                            = loader::zeKernelGetProperties;
    loader::loaderDispatch->pCore->Kernel->pfnGetName                                  = loader::zeKernelGetName;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for KernelExp table
__zedlllocal void ZE_APICALL
zeGetKernelExpProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->KernelExp->pfnSetGlobalOffsetExp                       = loader::zeKernelSetGlobalOffsetExp;
    loader::loaderDispatch->pCore->KernelExp->pfnGetBinaryExp                             = loader::zeKernelGetBinaryExp;
    loader::loaderDispatch->pCore->KernelExp->pfnGetAllocationPropertiesExp               = loader::zeKernelGetAllocationPropertiesExp;
    loader::loaderDispatch->pCore->KernelExp->pfnSchedulingHintExp                        = loader::zeKernelSchedulingHintExp;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for Mem table
__zedlllocal void ZE_APICALL
zeGetMemProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->Mem->pfnAllocShared                              = loader::zeMemAllocShared;
    loader::loaderDispatch->pCore->Mem->pfnAllocDevice                              = loader::zeMemAllocDevice;
    loader::loaderDispatch->pCore->Mem->pfnAllocHost                                = loader::zeMemAllocHost;
    loader::loaderDispatch->pCore->Mem->pfnFree                                     = loader::zeMemFree;
    loader::loaderDispatch->pCore->Mem->pfnGetAllocProperties                       = loader::zeMemGetAllocProperties;
    loader::loaderDispatch->pCore->Mem->pfnGetAddressRange                          = loader::zeMemGetAddressRange;
    loader::loaderDispatch->pCore->Mem->pfnGetIpcHandle                             = loader::zeMemGetIpcHandle;
    loader::loaderDispatch->pCore->Mem->pfnOpenIpcHandle                            = loader::zeMemOpenIpcHandle;
    loader::loaderDispatch->pCore->Mem->pfnCloseIpcHandle                           = loader::zeMemCloseIpcHandle;
    loader::loaderDispatch->pCore->Mem->pfnGetIpcHandleWithProperties               = loader::zeMemGetIpcHandleWithProperties;
    loader::loaderDispatch->pCore->Mem->pfnFreeExt                                  = loader::zeMemFreeExt;
    loader::loaderDispatch->pCore->Mem->pfnPutIpcHandle                             = loader::zeMemPutIpcHandle;
    loader::loaderDispatch->pCore->Mem->pfnGetPitchFor2dImage                       = loader::zeMemGetPitchFor2dImage;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for MemExp table
__zedlllocal void ZE_APICALL
zeGetMemExpProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->MemExp->pfnGetIpcHandleFromFileDescriptorExp        = loader::zeMemGetIpcHandleFromFileDescriptorExp;
    loader::loaderDispatch->pCore->MemExp->pfnGetFileDescriptorFromIpcHandleExp        = loader::zeMemGetFileDescriptorFromIpcHandleExp;
    loader::loaderDispatch->pCore->MemExp->pfnSetAtomicAccessAttributeExp              = loader::zeMemSetAtomicAccessAttributeExp;
    loader::loaderDispatch->pCore->MemExp->pfnGetAtomicAccessAttributeExp              = loader::zeMemGetAtomicAccessAttributeExp;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for Module table
__zedlllocal void ZE_APICALL
zeGetModuleProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->Module->pfnCreate                                   = loader::zeModuleCreate;
    loader::loaderDispatch->pCore->Module->pfnDestroy                                  = loader::zeModuleDestroy;
    loader::loaderDispatch->pCore->Module->pfnDynamicLink                              = loader::zeModuleDynamicLink;
    loader::loaderDispatch->pCore->Module->pfnGetNativeBinary                          = loader::zeModuleGetNativeBinary;
    loader::loaderDispatch->pCore->Module->pfnGetGlobalPointer                         = loader::zeModuleGetGlobalPointer;
    loader::loaderDispatch->pCore->Module->pfnGetKernelNames                           = loader::zeModuleGetKernelNames;
    loader::loaderDispatch->pCore->Module->pfnGetProperties                            = loader::zeModuleGetProperties;
    loader::loaderDispatch->pCore->Module->pfnGetFunctionPointer                       = loader::zeModuleGetFunctionPointer;
    loader::loaderDispatch->pCore->Module->pfnInspectLinkageExt                        = loader::zeModuleInspectLinkageExt;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for ModuleBuildLog table
__zedlllocal void ZE_APICALL
zeGetModuleBuildLogProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->ModuleBuildLog->pfnDestroy                                  = loader::zeModuleBuildLogDestroy;
    loader::loaderDispatch->pCore->ModuleBuildLog->pfnGetString                                = loader::zeModuleBuildLogGetString;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for PhysicalMem table
__zedlllocal void ZE_APICALL
zeGetPhysicalMemProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->PhysicalMem->pfnCreate                                   = loader::zePhysicalMemCreate;
    loader::loaderDispatch->pCore->PhysicalMem->pfnDestroy                                  = loader::zePhysicalMemDestroy;
    loader::loaderDispatch->pCore->PhysicalMem->pfnGetProperties                            = loader::zePhysicalMemGetProperties;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for Sampler table
__zedlllocal void ZE_APICALL
zeGetSamplerProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->Sampler->pfnCreate                                   = loader::zeSamplerCreate;
    loader::loaderDispatch->pCore->Sampler->pfnDestroy                                  = loader::zeSamplerDestroy;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for VirtualMem table
__zedlllocal void ZE_APICALL
zeGetVirtualMemProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->VirtualMem->pfnReserve                                  = loader::zeVirtualMemReserve;
    loader::loaderDispatch->pCore->VirtualMem->pfnFree                                     = loader::zeVirtualMemFree;
    loader::loaderDispatch->pCore->VirtualMem->pfnQueryPageSize                            = loader::zeVirtualMemQueryPageSize;
    loader::loaderDispatch->pCore->VirtualMem->pfnMap                                      = loader::zeVirtualMemMap;
    loader::loaderDispatch->pCore->VirtualMem->pfnUnmap                                    = loader::zeVirtualMemUnmap;
    loader::loaderDispatch->pCore->VirtualMem->pfnSetAccessAttribute                       = loader::zeVirtualMemSetAccessAttribute;
    loader::loaderDispatch->pCore->VirtualMem->pfnGetAccessAttribute                       = loader::zeVirtualMemGetAccessAttribute;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for FabricEdgeExp table
__zedlllocal void ZE_APICALL
zeGetFabricEdgeExpProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->FabricEdgeExp->pfnGetExp                                   = loader::zeFabricEdgeGetExp;
    loader::loaderDispatch->pCore->FabricEdgeExp->pfnGetVerticesExp                           = loader::zeFabricEdgeGetVerticesExp;
    loader::loaderDispatch->pCore->FabricEdgeExp->pfnGetPropertiesExp                         = loader::zeFabricEdgeGetPropertiesExp;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for FabricVertexExp table
__zedlllocal void ZE_APICALL
zeGetFabricVertexExpProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->FabricVertexExp->pfnGetExp                                   = loader::zeFabricVertexGetExp;
    loader::loaderDispatch->pCore->FabricVertexExp->pfnGetSubVerticesExp                        = loader::zeFabricVertexGetSubVerticesExp;
    loader::loaderDispatch->pCore->FabricVertexExp->pfnGetPropertiesExp                         = loader::zeFabricVertexGetPropertiesExp;
    loader::loaderDispatch->pCore->FabricVertexExp->pfnGetDeviceExp                             = loader::zeFabricVertexGetDeviceExp;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for ExecutableGraph table
__zedlllocal void ZE_APICALL
zeGetExecutableGraphProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->ExecutableGraph->pfnGetSourceGraphExt                        = loader::zeExecutableGraphGetSourceGraphExt;
    loader::loaderDispatch->pCore->ExecutableGraph->pfnDestroyExt                               = loader::zeExecutableGraphDestroyExt;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief function for filling the legacy api pointers for Graph table
__zedlllocal void ZE_APICALL
zeGetGraphProcAddrTableLegacy()
{
    // return pointers to the Loader's Functions.
    loader::loaderDispatch->pCore->Graph->pfnCreateExt                                = loader::zeGraphCreateExt;
    loader::loaderDispatch->pCore->Graph->pfnGetPrimaryCommandListExt                 = loader::zeGraphGetPrimaryCommandListExt;
    loader::loaderDispatch->pCore->Graph->pfnSetDestructionCallbackExt                = loader::zeGraphSetDestructionCallbackExt;
    loader::loaderDispatch->pCore->Graph->pfnInstantiateExt                           = loader::zeGraphInstantiateExt;
    loader::loaderDispatch->pCore->Graph->pfnIsEmptyExt                               = loader::zeGraphIsEmptyExt;
    loader::loaderDispatch->pCore->Graph->pfnDumpContentsExt                          = loader::zeGraphDumpContentsExt;
    loader::loaderDispatch->pCore->Graph->pfnDestroyExt                               = loader::zeGraphDestroyExt;
}


///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Global table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetGlobalProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetGlobalProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetGlobalProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    auto getTableResult = getTable( loader::context->ddi_init_version, &driver->dditable.ze.Global);
    if(getTableResult == ZE_RESULT_SUCCESS) {
        loader::context->configured_version = loader::context->ddi_init_version;
    } else
        driver->initStatus = getTableResult;
    if (driver->dditable.ze.Global.pfnInitDrivers) {
        loader::context->initDriversSupport = true;
    }
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's RTASBuilder table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetRTASBuilderProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetRTASBuilderProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetRTASBuilderProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    result = getTable( loader::context->ddi_init_version, &driver->dditable.ze.RTASBuilder);
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's RTASBuilderExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetRTASBuilderExpProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetRTASBuilderExpProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetRTASBuilderExpProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    result = getTable( loader::context->ddi_init_version, &driver->dditable.ze.RTASBuilderExp);
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's RTASParallelOperation table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetRTASParallelOperationProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetRTASParallelOperationProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetRTASParallelOperationProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    result = getTable( loader::context->ddi_init_version, &driver->dditable.ze.RTASParallelOperation);
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's RTASParallelOperationExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetRTASParallelOperationExpProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetRTASParallelOperationExpProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetRTASParallelOperationExpProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    result = getTable( loader::context->ddi_init_version, &driver->dditable.ze.RTASParallelOperationExp);
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Driver table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetDriverProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetDriverProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetDriverProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    auto getTableResult = getTable( loader::context->ddi_init_version, &driver->dditable.ze.Driver);
    if(getTableResult == ZE_RESULT_SUCCESS) {
        loader::context->configured_version = loader::context->ddi_init_version;
    } else
        driver->initStatus = getTableResult;
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's DriverExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetDriverExpProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetDriverExpProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetDriverExpProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    result = getTable( loader::context->ddi_init_version, &driver->dditable.ze.DriverExp);
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Device table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetDeviceProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetDeviceProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetDeviceProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    auto getTableResult = getTable( loader::context->ddi_init_version, &driver->dditable.ze.Device);
    if(getTableResult == ZE_RESULT_SUCCESS) {
        loader::context->configured_version = loader::context->ddi_init_version;
    } else
        driver->initStatus = getTableResult;
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's DeviceExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetDeviceExpProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetDeviceExpProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetDeviceExpProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    result = getTable( loader::context->ddi_init_version, &driver->dditable.ze.DeviceExp);
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Context table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetContextProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetContextProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetContextProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    auto getTableResult = getTable( loader::context->ddi_init_version, &driver->dditable.ze.Context);
    if(getTableResult == ZE_RESULT_SUCCESS) {
        loader::context->configured_version = loader::context->ddi_init_version;
    } else
        driver->initStatus = getTableResult;
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's CommandQueue table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetCommandQueueProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetCommandQueueProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetCommandQueueProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    auto getTableResult = getTable( loader::context->ddi_init_version, &driver->dditable.ze.CommandQueue);
    if(getTableResult == ZE_RESULT_SUCCESS) {
        loader::context->configured_version = loader::context->ddi_init_version;
    } else
        driver->initStatus = getTableResult;
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's CommandList table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetCommandListProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetCommandListProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetCommandListProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    auto getTableResult = getTable( loader::context->ddi_init_version, &driver->dditable.ze.CommandList);
    if(getTableResult == ZE_RESULT_SUCCESS) {
        loader::context->configured_version = loader::context->ddi_init_version;
    } else
        driver->initStatus = getTableResult;
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's CommandListExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetCommandListExpProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetCommandListExpProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetCommandListExpProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    result = getTable( loader::context->ddi_init_version, &driver->dditable.ze.CommandListExp);
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Event table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetEventProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetEventProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetEventProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    auto getTableResult = getTable( loader::context->ddi_init_version, &driver->dditable.ze.Event);
    if(getTableResult == ZE_RESULT_SUCCESS) {
        loader::context->configured_version = loader::context->ddi_init_version;
    } else
        driver->initStatus = getTableResult;
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's EventExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetEventExpProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetEventExpProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetEventExpProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    result = getTable( loader::context->ddi_init_version, &driver->dditable.ze.EventExp);
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's EventPool table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetEventPoolProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetEventPoolProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetEventPoolProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    auto getTableResult = getTable( loader::context->ddi_init_version, &driver->dditable.ze.EventPool);
    if(getTableResult == ZE_RESULT_SUCCESS) {
        loader::context->configured_version = loader::context->ddi_init_version;
    } else
        driver->initStatus = getTableResult;
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Fence table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetFenceProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetFenceProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetFenceProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    auto getTableResult = getTable( loader::context->ddi_init_version, &driver->dditable.ze.Fence);
    if(getTableResult == ZE_RESULT_SUCCESS) {
        loader::context->configured_version = loader::context->ddi_init_version;
    } else
        driver->initStatus = getTableResult;
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Image table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetImageProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetImageProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetImageProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    auto getTableResult = getTable( loader::context->ddi_init_version, &driver->dditable.ze.Image);
    if(getTableResult == ZE_RESULT_SUCCESS) {
        loader::context->configured_version = loader::context->ddi_init_version;
    } else
        driver->initStatus = getTableResult;
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's ImageExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetImageExpProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetImageExpProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetImageExpProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    result = getTable( loader::context->ddi_init_version, &driver->dditable.ze.ImageExp);
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Kernel table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetKernelProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetKernelProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetKernelProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    auto getTableResult = getTable( loader::context->ddi_init_version, &driver->dditable.ze.Kernel);
    if(getTableResult == ZE_RESULT_SUCCESS) {
        loader::context->configured_version = loader::context->ddi_init_version;
    } else
        driver->initStatus = getTableResult;
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's KernelExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetKernelExpProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetKernelExpProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetKernelExpProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    result = getTable( loader::context->ddi_init_version, &driver->dditable.ze.KernelExp);
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Mem table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetMemProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetMemProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetMemProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    auto getTableResult = getTable( loader::context->ddi_init_version, &driver->dditable.ze.Mem);
    if(getTableResult == ZE_RESULT_SUCCESS) {
        loader::context->configured_version = loader::context->ddi_init_version;
    } else
        driver->initStatus = getTableResult;
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's MemExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetMemExpProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetMemExpProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetMemExpProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    result = getTable( loader::context->ddi_init_version, &driver->dditable.ze.MemExp);
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Module table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetModuleProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetModuleProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetModuleProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    auto getTableResult = getTable( loader::context->ddi_init_version, &driver->dditable.ze.Module);
    if(getTableResult == ZE_RESULT_SUCCESS) {
        loader::context->configured_version = loader::context->ddi_init_version;
    } else
        driver->initStatus = getTableResult;
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's ModuleBuildLog table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetModuleBuildLogProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetModuleBuildLogProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetModuleBuildLogProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    auto getTableResult = getTable( loader::context->ddi_init_version, &driver->dditable.ze.ModuleBuildLog);
    if(getTableResult == ZE_RESULT_SUCCESS) {
        loader::context->configured_version = loader::context->ddi_init_version;
    } else
        driver->initStatus = getTableResult;
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's PhysicalMem table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetPhysicalMemProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetPhysicalMemProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetPhysicalMemProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    auto getTableResult = getTable( loader::context->ddi_init_version, &driver->dditable.ze.PhysicalMem);
    if(getTableResult == ZE_RESULT_SUCCESS) {
        loader::context->configured_version = loader::context->ddi_init_version;
    } else
        driver->initStatus = getTableResult;
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Sampler table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetSamplerProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetSamplerProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetSamplerProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    auto getTableResult = getTable( loader::context->ddi_init_version, &driver->dditable.ze.Sampler);
    if(getTableResult == ZE_RESULT_SUCCESS) {
        loader::context->configured_version = loader::context->ddi_init_version;
    } else
        driver->initStatus = getTableResult;
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's VirtualMem table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetVirtualMemProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetVirtualMemProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetVirtualMemProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    auto getTableResult = getTable( loader::context->ddi_init_version, &driver->dditable.ze.VirtualMem);
    if(getTableResult == ZE_RESULT_SUCCESS) {
        loader::context->configured_version = loader::context->ddi_init_version;
    } else
        driver->initStatus = getTableResult;
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's FabricEdgeExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetFabricEdgeExpProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetFabricEdgeExpProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetFabricEdgeExpProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    result = getTable( loader::context->ddi_init_version, &driver->dditable.ze.FabricEdgeExp);
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's FabricVertexExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetFabricVertexExpProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetFabricVertexExpProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetFabricVertexExpProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    result = getTable( loader::context->ddi_init_version, &driver->dditable.ze.FabricVertexExp);
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's ExecutableGraph table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetExecutableGraphProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetExecutableGraphProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetExecutableGraphProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    result = getTable( loader::context->ddi_init_version, &driver->dditable.ze.ExecutableGraph);
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Graph table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
__zedlllocal ze_result_t ZE_APICALL
zeGetGraphProcAddrTableFromDriver(loader::driver_t *driver)
{
    ze_result_t result = ZE_RESULT_SUCCESS;
    if(driver->initStatus != ZE_RESULT_SUCCESS)
        return driver->initStatus;
    auto getTable = reinterpret_cast<ze_pfnGetGraphProcAddrTable_t>(
        GET_FUNCTION_PTR( driver->handle, "zeGetGraphProcAddrTable") );
    if(!getTable) 
        return driver->initStatus;
    result = getTable( loader::context->ddi_init_version, &driver->dditable.ze.Graph);
    return result;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Global table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetGlobalProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_global_dditable_t* pDdiTable                 ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetGlobalProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->Global = new ze_global_dditable_t;
            if (version >= ZE_API_VERSION_1_0) {
            pDdiTable->pfnInit                                     = loader::zeInit;
            }
            if (version >= ZE_API_VERSION_1_10) {
            pDdiTable->pfnInitDrivers                              = loader::zeInitDrivers;
            }
            zeGetGlobalProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnInit                                     = firstDriver->dditable.ze.Global.pfnInit;
            }
            if (version >= ZE_API_VERSION_1_10) {
                pDdiTable->pfnInitDrivers                              = firstDriver->dditable.ze.Global.pfnInitDrivers;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetGlobalProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetGlobalProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetGlobalProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetGlobalProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_global_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_global_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.Global = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's RTASBuilder table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetRTASBuilderProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_rtas_builder_dditable_t* pDdiTable           ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetRTASBuilderProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->RTASBuilder = new ze_rtas_builder_dditable_t;
            if (version >= ZE_API_VERSION_1_13) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreateExt                                = loader_driver_ddi::zeRTASBuilderCreateExt;
            } else {
                pDdiTable->pfnCreateExt                                = loader::zeRTASBuilderCreateExt;
            }
            }
            if (version >= ZE_API_VERSION_1_13) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetBuildPropertiesExt                    = loader_driver_ddi::zeRTASBuilderGetBuildPropertiesExt;
            } else {
                pDdiTable->pfnGetBuildPropertiesExt                    = loader::zeRTASBuilderGetBuildPropertiesExt;
            }
            }
            if (version >= ZE_API_VERSION_1_13) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnBuildExt                                 = loader_driver_ddi::zeRTASBuilderBuildExt;
            } else {
                pDdiTable->pfnBuildExt                                 = loader::zeRTASBuilderBuildExt;
            }
            }
            if (version >= ZE_API_VERSION_1_13) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCommandListAppendCopyExt                 = loader_driver_ddi::zeRTASBuilderCommandListAppendCopyExt;
            } else {
                pDdiTable->pfnCommandListAppendCopyExt                 = loader::zeRTASBuilderCommandListAppendCopyExt;
            }
            }
            if (version >= ZE_API_VERSION_1_13) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroyExt                               = loader_driver_ddi::zeRTASBuilderDestroyExt;
            } else {
                pDdiTable->pfnDestroyExt                               = loader::zeRTASBuilderDestroyExt;
            }
            }
            zeGetRTASBuilderProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_13) {
                pDdiTable->pfnCreateExt                                = firstDriver->dditable.ze.RTASBuilder.pfnCreateExt;
            }
            if (version >= ZE_API_VERSION_1_13) {
                pDdiTable->pfnGetBuildPropertiesExt                    = firstDriver->dditable.ze.RTASBuilder.pfnGetBuildPropertiesExt;
            }
            if (version >= ZE_API_VERSION_1_13) {
                pDdiTable->pfnBuildExt                                 = firstDriver->dditable.ze.RTASBuilder.pfnBuildExt;
            }
            if (version >= ZE_API_VERSION_1_13) {
                pDdiTable->pfnCommandListAppendCopyExt                 = firstDriver->dditable.ze.RTASBuilder.pfnCommandListAppendCopyExt;
            }
            if (version >= ZE_API_VERSION_1_13) {
                pDdiTable->pfnDestroyExt                               = firstDriver->dditable.ze.RTASBuilder.pfnDestroyExt;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetRTASBuilderProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetRTASBuilderProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetRTASBuilderProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetRTASBuilderProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_rtas_builder_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_rtas_builder_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.RTASBuilder = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's RTASBuilderExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetRTASBuilderExpProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_rtas_builder_exp_dditable_t* pDdiTable       ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetRTASBuilderExpProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->RTASBuilderExp = new ze_rtas_builder_exp_dditable_t;
            if (version >= ZE_API_VERSION_1_7) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreateExp                                = loader_driver_ddi::zeRTASBuilderCreateExp;
            } else {
                pDdiTable->pfnCreateExp                                = loader::zeRTASBuilderCreateExp;
            }
            }
            if (version >= ZE_API_VERSION_1_7) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetBuildPropertiesExp                    = loader_driver_ddi::zeRTASBuilderGetBuildPropertiesExp;
            } else {
                pDdiTable->pfnGetBuildPropertiesExp                    = loader::zeRTASBuilderGetBuildPropertiesExp;
            }
            }
            if (version >= ZE_API_VERSION_1_7) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnBuildExp                                 = loader_driver_ddi::zeRTASBuilderBuildExp;
            } else {
                pDdiTable->pfnBuildExp                                 = loader::zeRTASBuilderBuildExp;
            }
            }
            if (version >= ZE_API_VERSION_1_7) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroyExp                               = loader_driver_ddi::zeRTASBuilderDestroyExp;
            } else {
                pDdiTable->pfnDestroyExp                               = loader::zeRTASBuilderDestroyExp;
            }
            }
            zeGetRTASBuilderExpProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_7) {
                pDdiTable->pfnCreateExp                                = firstDriver->dditable.ze.RTASBuilderExp.pfnCreateExp;
            }
            if (version >= ZE_API_VERSION_1_7) {
                pDdiTable->pfnGetBuildPropertiesExp                    = firstDriver->dditable.ze.RTASBuilderExp.pfnGetBuildPropertiesExp;
            }
            if (version >= ZE_API_VERSION_1_7) {
                pDdiTable->pfnBuildExp                                 = firstDriver->dditable.ze.RTASBuilderExp.pfnBuildExp;
            }
            if (version >= ZE_API_VERSION_1_7) {
                pDdiTable->pfnDestroyExp                               = firstDriver->dditable.ze.RTASBuilderExp.pfnDestroyExp;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetRTASBuilderExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetRTASBuilderExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetRTASBuilderExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetRTASBuilderExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_rtas_builder_exp_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_rtas_builder_exp_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.RTASBuilderExp = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's RTASParallelOperation table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetRTASParallelOperationProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_rtas_parallel_operation_dditable_t* pDdiTable///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetRTASParallelOperationProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->RTASParallelOperation = new ze_rtas_parallel_operation_dditable_t;
            if (version >= ZE_API_VERSION_1_13) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreateExt                                = loader_driver_ddi::zeRTASParallelOperationCreateExt;
            } else {
                pDdiTable->pfnCreateExt                                = loader::zeRTASParallelOperationCreateExt;
            }
            }
            if (version >= ZE_API_VERSION_1_13) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetPropertiesExt                         = loader_driver_ddi::zeRTASParallelOperationGetPropertiesExt;
            } else {
                pDdiTable->pfnGetPropertiesExt                         = loader::zeRTASParallelOperationGetPropertiesExt;
            }
            }
            if (version >= ZE_API_VERSION_1_13) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnJoinExt                                  = loader_driver_ddi::zeRTASParallelOperationJoinExt;
            } else {
                pDdiTable->pfnJoinExt                                  = loader::zeRTASParallelOperationJoinExt;
            }
            }
            if (version >= ZE_API_VERSION_1_13) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroyExt                               = loader_driver_ddi::zeRTASParallelOperationDestroyExt;
            } else {
                pDdiTable->pfnDestroyExt                               = loader::zeRTASParallelOperationDestroyExt;
            }
            }
            zeGetRTASParallelOperationProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_13) {
                pDdiTable->pfnCreateExt                                = firstDriver->dditable.ze.RTASParallelOperation.pfnCreateExt;
            }
            if (version >= ZE_API_VERSION_1_13) {
                pDdiTable->pfnGetPropertiesExt                         = firstDriver->dditable.ze.RTASParallelOperation.pfnGetPropertiesExt;
            }
            if (version >= ZE_API_VERSION_1_13) {
                pDdiTable->pfnJoinExt                                  = firstDriver->dditable.ze.RTASParallelOperation.pfnJoinExt;
            }
            if (version >= ZE_API_VERSION_1_13) {
                pDdiTable->pfnDestroyExt                               = firstDriver->dditable.ze.RTASParallelOperation.pfnDestroyExt;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetRTASParallelOperationProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetRTASParallelOperationProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetRTASParallelOperationProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetRTASParallelOperationProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_rtas_parallel_operation_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_rtas_parallel_operation_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.RTASParallelOperation = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's RTASParallelOperationExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetRTASParallelOperationExpProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_rtas_parallel_operation_exp_dditable_t* pDdiTable///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetRTASParallelOperationExpProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->RTASParallelOperationExp = new ze_rtas_parallel_operation_exp_dditable_t;
            if (version >= ZE_API_VERSION_1_7) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreateExp                                = loader_driver_ddi::zeRTASParallelOperationCreateExp;
            } else {
                pDdiTable->pfnCreateExp                                = loader::zeRTASParallelOperationCreateExp;
            }
            }
            if (version >= ZE_API_VERSION_1_7) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetPropertiesExp                         = loader_driver_ddi::zeRTASParallelOperationGetPropertiesExp;
            } else {
                pDdiTable->pfnGetPropertiesExp                         = loader::zeRTASParallelOperationGetPropertiesExp;
            }
            }
            if (version >= ZE_API_VERSION_1_7) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnJoinExp                                  = loader_driver_ddi::zeRTASParallelOperationJoinExp;
            } else {
                pDdiTable->pfnJoinExp                                  = loader::zeRTASParallelOperationJoinExp;
            }
            }
            if (version >= ZE_API_VERSION_1_7) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroyExp                               = loader_driver_ddi::zeRTASParallelOperationDestroyExp;
            } else {
                pDdiTable->pfnDestroyExp                               = loader::zeRTASParallelOperationDestroyExp;
            }
            }
            zeGetRTASParallelOperationExpProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_7) {
                pDdiTable->pfnCreateExp                                = firstDriver->dditable.ze.RTASParallelOperationExp.pfnCreateExp;
            }
            if (version >= ZE_API_VERSION_1_7) {
                pDdiTable->pfnGetPropertiesExp                         = firstDriver->dditable.ze.RTASParallelOperationExp.pfnGetPropertiesExp;
            }
            if (version >= ZE_API_VERSION_1_7) {
                pDdiTable->pfnJoinExp                                  = firstDriver->dditable.ze.RTASParallelOperationExp.pfnJoinExp;
            }
            if (version >= ZE_API_VERSION_1_7) {
                pDdiTable->pfnDestroyExp                               = firstDriver->dditable.ze.RTASParallelOperationExp.pfnDestroyExp;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetRTASParallelOperationExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetRTASParallelOperationExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetRTASParallelOperationExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetRTASParallelOperationExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_rtas_parallel_operation_exp_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_rtas_parallel_operation_exp_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.RTASParallelOperationExp = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Driver table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetDriverProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_driver_dditable_t* pDdiTable                 ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetDriverProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->Driver = new ze_driver_dditable_t;
            if (version >= ZE_API_VERSION_1_0) {
            pDdiTable->pfnGet                                      = loader::zeDriverGet;
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetApiVersion                            = loader_driver_ddi::zeDriverGetApiVersion;
            } else {
                pDdiTable->pfnGetApiVersion                            = loader::zeDriverGetApiVersion;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetProperties                            = loader_driver_ddi::zeDriverGetProperties;
            } else {
                pDdiTable->pfnGetProperties                            = loader::zeDriverGetProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetIpcProperties                         = loader_driver_ddi::zeDriverGetIpcProperties;
            } else {
                pDdiTable->pfnGetIpcProperties                         = loader::zeDriverGetIpcProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetExtensionProperties                   = loader_driver_ddi::zeDriverGetExtensionProperties;
            } else {
                pDdiTable->pfnGetExtensionProperties                   = loader::zeDriverGetExtensionProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_1) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetExtensionFunctionAddress              = loader_driver_ddi::zeDriverGetExtensionFunctionAddress;
            } else {
                pDdiTable->pfnGetExtensionFunctionAddress              = loader::zeDriverGetExtensionFunctionAddress;
            }
            }
            if (version >= ZE_API_VERSION_1_13) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnRTASFormatCompatibilityCheckExt          = loader_driver_ddi::zeDriverRTASFormatCompatibilityCheckExt;
            } else {
                pDdiTable->pfnRTASFormatCompatibilityCheckExt          = loader::zeDriverRTASFormatCompatibilityCheckExt;
            }
            }
            if (version >= ZE_API_VERSION_1_14) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetDefaultContext                        = loader_driver_ddi::zeDriverGetDefaultContext;
            } else {
                pDdiTable->pfnGetDefaultContext                        = loader::zeDriverGetDefaultContext;
            }
            }
            if (version >= ZE_API_VERSION_1_6) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetLastErrorDescription                  = loader_driver_ddi::zeDriverGetLastErrorDescription;
            } else {
                pDdiTable->pfnGetLastErrorDescription                  = loader::zeDriverGetLastErrorDescription;
            }
            }
            zeGetDriverProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGet                                      = firstDriver->dditable.ze.Driver.pfnGet;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetApiVersion                            = firstDriver->dditable.ze.Driver.pfnGetApiVersion;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetProperties                            = firstDriver->dditable.ze.Driver.pfnGetProperties;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetIpcProperties                         = firstDriver->dditable.ze.Driver.pfnGetIpcProperties;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetExtensionProperties                   = firstDriver->dditable.ze.Driver.pfnGetExtensionProperties;
            }
            if (version >= ZE_API_VERSION_1_1) {
                pDdiTable->pfnGetExtensionFunctionAddress              = firstDriver->dditable.ze.Driver.pfnGetExtensionFunctionAddress;
            }
            if (version >= ZE_API_VERSION_1_13) {
                pDdiTable->pfnRTASFormatCompatibilityCheckExt          = firstDriver->dditable.ze.Driver.pfnRTASFormatCompatibilityCheckExt;
            }
            if (version >= ZE_API_VERSION_1_14) {
                pDdiTable->pfnGetDefaultContext                        = firstDriver->dditable.ze.Driver.pfnGetDefaultContext;
            }
            if (version >= ZE_API_VERSION_1_6) {
                pDdiTable->pfnGetLastErrorDescription                  = firstDriver->dditable.ze.Driver.pfnGetLastErrorDescription;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetDriverProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetDriverProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetDriverProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetDriverProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_driver_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_driver_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.Driver = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's DriverExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetDriverExpProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_driver_exp_dditable_t* pDdiTable             ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetDriverExpProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->DriverExp = new ze_driver_exp_dditable_t;
            if (version >= ZE_API_VERSION_1_7) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnRTASFormatCompatibilityCheckExp          = loader_driver_ddi::zeDriverRTASFormatCompatibilityCheckExp;
            } else {
                pDdiTable->pfnRTASFormatCompatibilityCheckExp          = loader::zeDriverRTASFormatCompatibilityCheckExp;
            }
            }
            zeGetDriverExpProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_7) {
                pDdiTable->pfnRTASFormatCompatibilityCheckExp          = firstDriver->dditable.ze.DriverExp.pfnRTASFormatCompatibilityCheckExp;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetDriverExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetDriverExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetDriverExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetDriverExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_driver_exp_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_driver_exp_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.DriverExp = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Device table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetDeviceProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_device_dditable_t* pDdiTable                 ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetDeviceProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->Device = new ze_device_dditable_t;
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGet                                      = loader_driver_ddi::zeDeviceGet;
            } else {
                pDdiTable->pfnGet                                      = loader::zeDeviceGet;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetSubDevices                            = loader_driver_ddi::zeDeviceGetSubDevices;
            } else {
                pDdiTable->pfnGetSubDevices                            = loader::zeDeviceGetSubDevices;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetProperties                            = loader_driver_ddi::zeDeviceGetProperties;
            } else {
                pDdiTable->pfnGetProperties                            = loader::zeDeviceGetProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetComputeProperties                     = loader_driver_ddi::zeDeviceGetComputeProperties;
            } else {
                pDdiTable->pfnGetComputeProperties                     = loader::zeDeviceGetComputeProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetModuleProperties                      = loader_driver_ddi::zeDeviceGetModuleProperties;
            } else {
                pDdiTable->pfnGetModuleProperties                      = loader::zeDeviceGetModuleProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetCommandQueueGroupProperties           = loader_driver_ddi::zeDeviceGetCommandQueueGroupProperties;
            } else {
                pDdiTable->pfnGetCommandQueueGroupProperties           = loader::zeDeviceGetCommandQueueGroupProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetMemoryProperties                      = loader_driver_ddi::zeDeviceGetMemoryProperties;
            } else {
                pDdiTable->pfnGetMemoryProperties                      = loader::zeDeviceGetMemoryProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetMemoryAccessProperties                = loader_driver_ddi::zeDeviceGetMemoryAccessProperties;
            } else {
                pDdiTable->pfnGetMemoryAccessProperties                = loader::zeDeviceGetMemoryAccessProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetCacheProperties                       = loader_driver_ddi::zeDeviceGetCacheProperties;
            } else {
                pDdiTable->pfnGetCacheProperties                       = loader::zeDeviceGetCacheProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetImageProperties                       = loader_driver_ddi::zeDeviceGetImageProperties;
            } else {
                pDdiTable->pfnGetImageProperties                       = loader::zeDeviceGetImageProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetExternalMemoryProperties              = loader_driver_ddi::zeDeviceGetExternalMemoryProperties;
            } else {
                pDdiTable->pfnGetExternalMemoryProperties              = loader::zeDeviceGetExternalMemoryProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetP2PProperties                         = loader_driver_ddi::zeDeviceGetP2PProperties;
            } else {
                pDdiTable->pfnGetP2PProperties                         = loader::zeDeviceGetP2PProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCanAccessPeer                            = loader_driver_ddi::zeDeviceCanAccessPeer;
            } else {
                pDdiTable->pfnCanAccessPeer                            = loader::zeDeviceCanAccessPeer;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetStatus                                = loader_driver_ddi::zeDeviceGetStatus;
            } else {
                pDdiTable->pfnGetStatus                                = loader::zeDeviceGetStatus;
            }
            }
            if (version >= ZE_API_VERSION_1_1) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetGlobalTimestamps                      = loader_driver_ddi::zeDeviceGetGlobalTimestamps;
            } else {
                pDdiTable->pfnGetGlobalTimestamps                      = loader::zeDeviceGetGlobalTimestamps;
            }
            }
            if (version >= ZE_API_VERSION_1_12) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnImportExternalSemaphoreExt               = loader_driver_ddi::zeDeviceImportExternalSemaphoreExt;
            } else {
                pDdiTable->pfnImportExternalSemaphoreExt               = loader::zeDeviceImportExternalSemaphoreExt;
            }
            }
            if (version >= ZE_API_VERSION_1_12) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnReleaseExternalSemaphoreExt              = loader_driver_ddi::zeDeviceReleaseExternalSemaphoreExt;
            } else {
                pDdiTable->pfnReleaseExternalSemaphoreExt              = loader::zeDeviceReleaseExternalSemaphoreExt;
            }
            }
            if (version >= ZE_API_VERSION_1_13) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetVectorWidthPropertiesExt              = loader_driver_ddi::zeDeviceGetVectorWidthPropertiesExt;
            } else {
                pDdiTable->pfnGetVectorWidthPropertiesExt              = loader::zeDeviceGetVectorWidthPropertiesExt;
            }
            }
            if (version >= ZE_API_VERSION_1_14) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnSynchronize                              = loader_driver_ddi::zeDeviceSynchronize;
            } else {
                pDdiTable->pfnSynchronize                              = loader::zeDeviceSynchronize;
            }
            }
            if (version >= ZE_API_VERSION_1_15) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetAggregatedCopyOffloadIncrementValue   = loader_driver_ddi::zeDeviceGetAggregatedCopyOffloadIncrementValue;
            } else {
                pDdiTable->pfnGetAggregatedCopyOffloadIncrementValue   = loader::zeDeviceGetAggregatedCopyOffloadIncrementValue;
            }
            }
            if (version >= ZE_API_VERSION_1_16) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetRuntimeRequirements                   = loader_driver_ddi::zeDeviceGetRuntimeRequirements;
            } else {
                pDdiTable->pfnGetRuntimeRequirements                   = loader::zeDeviceGetRuntimeRequirements;
            }
            }
            if (version >= ZE_API_VERSION_1_16) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetRuntimeRequirementsKey                = loader_driver_ddi::zeDeviceGetRuntimeRequirementsKey;
            } else {
                pDdiTable->pfnGetRuntimeRequirementsKey                = loader::zeDeviceGetRuntimeRequirementsKey;
            }
            }
            if (version >= ZE_API_VERSION_1_16) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnValidateRuntimeRequirements              = loader_driver_ddi::zeDeviceValidateRuntimeRequirements;
            } else {
                pDdiTable->pfnValidateRuntimeRequirements              = loader::zeDeviceValidateRuntimeRequirements;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetCounterBasedEventMaxValue             = loader_driver_ddi::zeDeviceGetCounterBasedEventMaxValue;
            } else {
                pDdiTable->pfnGetCounterBasedEventMaxValue             = loader::zeDeviceGetCounterBasedEventMaxValue;
            }
            }
            if (version >= ZE_API_VERSION_1_2) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnReserveCacheExt                          = loader_driver_ddi::zeDeviceReserveCacheExt;
            } else {
                pDdiTable->pfnReserveCacheExt                          = loader::zeDeviceReserveCacheExt;
            }
            }
            if (version >= ZE_API_VERSION_1_2) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnSetCacheAdviceExt                        = loader_driver_ddi::zeDeviceSetCacheAdviceExt;
            } else {
                pDdiTable->pfnSetCacheAdviceExt                        = loader::zeDeviceSetCacheAdviceExt;
            }
            }
            if (version >= ZE_API_VERSION_1_3) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnPciGetPropertiesExt                      = loader_driver_ddi::zeDevicePciGetPropertiesExt;
            } else {
                pDdiTable->pfnPciGetPropertiesExt                      = loader::zeDevicePciGetPropertiesExt;
            }
            }
            if (version >= ZE_API_VERSION_1_7) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetRootDevice                            = loader_driver_ddi::zeDeviceGetRootDevice;
            } else {
                pDdiTable->pfnGetRootDevice                            = loader::zeDeviceGetRootDevice;
            }
            }
            zeGetDeviceProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGet                                      = firstDriver->dditable.ze.Device.pfnGet;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetSubDevices                            = firstDriver->dditable.ze.Device.pfnGetSubDevices;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetProperties                            = firstDriver->dditable.ze.Device.pfnGetProperties;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetComputeProperties                     = firstDriver->dditable.ze.Device.pfnGetComputeProperties;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetModuleProperties                      = firstDriver->dditable.ze.Device.pfnGetModuleProperties;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetCommandQueueGroupProperties           = firstDriver->dditable.ze.Device.pfnGetCommandQueueGroupProperties;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetMemoryProperties                      = firstDriver->dditable.ze.Device.pfnGetMemoryProperties;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetMemoryAccessProperties                = firstDriver->dditable.ze.Device.pfnGetMemoryAccessProperties;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetCacheProperties                       = firstDriver->dditable.ze.Device.pfnGetCacheProperties;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetImageProperties                       = firstDriver->dditable.ze.Device.pfnGetImageProperties;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetExternalMemoryProperties              = firstDriver->dditable.ze.Device.pfnGetExternalMemoryProperties;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetP2PProperties                         = firstDriver->dditable.ze.Device.pfnGetP2PProperties;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnCanAccessPeer                            = firstDriver->dditable.ze.Device.pfnCanAccessPeer;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetStatus                                = firstDriver->dditable.ze.Device.pfnGetStatus;
            }
            if (version >= ZE_API_VERSION_1_1) {
                pDdiTable->pfnGetGlobalTimestamps                      = firstDriver->dditable.ze.Device.pfnGetGlobalTimestamps;
            }
            if (version >= ZE_API_VERSION_1_12) {
                pDdiTable->pfnImportExternalSemaphoreExt               = firstDriver->dditable.ze.Device.pfnImportExternalSemaphoreExt;
            }
            if (version >= ZE_API_VERSION_1_12) {
                pDdiTable->pfnReleaseExternalSemaphoreExt              = firstDriver->dditable.ze.Device.pfnReleaseExternalSemaphoreExt;
            }
            if (version >= ZE_API_VERSION_1_13) {
                pDdiTable->pfnGetVectorWidthPropertiesExt              = firstDriver->dditable.ze.Device.pfnGetVectorWidthPropertiesExt;
            }
            if (version >= ZE_API_VERSION_1_14) {
                pDdiTable->pfnSynchronize                              = firstDriver->dditable.ze.Device.pfnSynchronize;
            }
            if (version >= ZE_API_VERSION_1_15) {
                pDdiTable->pfnGetAggregatedCopyOffloadIncrementValue   = firstDriver->dditable.ze.Device.pfnGetAggregatedCopyOffloadIncrementValue;
            }
            if (version >= ZE_API_VERSION_1_16) {
                pDdiTable->pfnGetRuntimeRequirements                   = firstDriver->dditable.ze.Device.pfnGetRuntimeRequirements;
            }
            if (version >= ZE_API_VERSION_1_16) {
                pDdiTable->pfnGetRuntimeRequirementsKey                = firstDriver->dditable.ze.Device.pfnGetRuntimeRequirementsKey;
            }
            if (version >= ZE_API_VERSION_1_16) {
                pDdiTable->pfnValidateRuntimeRequirements              = firstDriver->dditable.ze.Device.pfnValidateRuntimeRequirements;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnGetCounterBasedEventMaxValue             = firstDriver->dditable.ze.Device.pfnGetCounterBasedEventMaxValue;
            }
            if (version >= ZE_API_VERSION_1_2) {
                pDdiTable->pfnReserveCacheExt                          = firstDriver->dditable.ze.Device.pfnReserveCacheExt;
            }
            if (version >= ZE_API_VERSION_1_2) {
                pDdiTable->pfnSetCacheAdviceExt                        = firstDriver->dditable.ze.Device.pfnSetCacheAdviceExt;
            }
            if (version >= ZE_API_VERSION_1_3) {
                pDdiTable->pfnPciGetPropertiesExt                      = firstDriver->dditable.ze.Device.pfnPciGetPropertiesExt;
            }
            if (version >= ZE_API_VERSION_1_7) {
                pDdiTable->pfnGetRootDevice                            = firstDriver->dditable.ze.Device.pfnGetRootDevice;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetDeviceProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetDeviceProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetDeviceProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetDeviceProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_device_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_device_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.Device = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's DeviceExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetDeviceExpProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_device_exp_dditable_t* pDdiTable             ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetDeviceExpProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->DeviceExp = new ze_device_exp_dditable_t;
            if (version >= ZE_API_VERSION_1_4) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetFabricVertexExp                       = loader_driver_ddi::zeDeviceGetFabricVertexExp;
            } else {
                pDdiTable->pfnGetFabricVertexExp                       = loader::zeDeviceGetFabricVertexExp;
            }
            }
            zeGetDeviceExpProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_4) {
                pDdiTable->pfnGetFabricVertexExp                       = firstDriver->dditable.ze.DeviceExp.pfnGetFabricVertexExp;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetDeviceExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetDeviceExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetDeviceExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetDeviceExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_device_exp_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_device_exp_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.DeviceExp = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Context table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetContextProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_context_dditable_t* pDdiTable                ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetContextProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->Context = new ze_context_dditable_t;
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreate                                   = loader_driver_ddi::zeContextCreate;
            } else {
                pDdiTable->pfnCreate                                   = loader::zeContextCreate;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroy                                  = loader_driver_ddi::zeContextDestroy;
            } else {
                pDdiTable->pfnDestroy                                  = loader::zeContextDestroy;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetStatus                                = loader_driver_ddi::zeContextGetStatus;
            } else {
                pDdiTable->pfnGetStatus                                = loader::zeContextGetStatus;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnSystemBarrier                            = loader_driver_ddi::zeContextSystemBarrier;
            } else {
                pDdiTable->pfnSystemBarrier                            = loader::zeContextSystemBarrier;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnMakeMemoryResident                       = loader_driver_ddi::zeContextMakeMemoryResident;
            } else {
                pDdiTable->pfnMakeMemoryResident                       = loader::zeContextMakeMemoryResident;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnEvictMemory                              = loader_driver_ddi::zeContextEvictMemory;
            } else {
                pDdiTable->pfnEvictMemory                              = loader::zeContextEvictMemory;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnMakeImageResident                        = loader_driver_ddi::zeContextMakeImageResident;
            } else {
                pDdiTable->pfnMakeImageResident                        = loader::zeContextMakeImageResident;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnEvictImage                               = loader_driver_ddi::zeContextEvictImage;
            } else {
                pDdiTable->pfnEvictImage                               = loader::zeContextEvictImage;
            }
            }
            if (version >= ZE_API_VERSION_1_1) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreateEx                                 = loader_driver_ddi::zeContextCreateEx;
            } else {
                pDdiTable->pfnCreateEx                                 = loader::zeContextCreateEx;
            }
            }
            zeGetContextProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnCreate                                   = firstDriver->dditable.ze.Context.pfnCreate;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnDestroy                                  = firstDriver->dditable.ze.Context.pfnDestroy;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetStatus                                = firstDriver->dditable.ze.Context.pfnGetStatus;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnSystemBarrier                            = firstDriver->dditable.ze.Context.pfnSystemBarrier;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnMakeMemoryResident                       = firstDriver->dditable.ze.Context.pfnMakeMemoryResident;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnEvictMemory                              = firstDriver->dditable.ze.Context.pfnEvictMemory;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnMakeImageResident                        = firstDriver->dditable.ze.Context.pfnMakeImageResident;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnEvictImage                               = firstDriver->dditable.ze.Context.pfnEvictImage;
            }
            if (version >= ZE_API_VERSION_1_1) {
                pDdiTable->pfnCreateEx                                 = firstDriver->dditable.ze.Context.pfnCreateEx;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetContextProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetContextProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetContextProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetContextProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_context_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_context_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.Context = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's CommandQueue table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetCommandQueueProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_command_queue_dditable_t* pDdiTable          ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetCommandQueueProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->CommandQueue = new ze_command_queue_dditable_t;
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreate                                   = loader_driver_ddi::zeCommandQueueCreate;
            } else {
                pDdiTable->pfnCreate                                   = loader::zeCommandQueueCreate;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroy                                  = loader_driver_ddi::zeCommandQueueDestroy;
            } else {
                pDdiTable->pfnDestroy                                  = loader::zeCommandQueueDestroy;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnExecuteCommandLists                      = loader_driver_ddi::zeCommandQueueExecuteCommandLists;
            } else {
                pDdiTable->pfnExecuteCommandLists                      = loader::zeCommandQueueExecuteCommandLists;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnSynchronize                              = loader_driver_ddi::zeCommandQueueSynchronize;
            } else {
                pDdiTable->pfnSynchronize                              = loader::zeCommandQueueSynchronize;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetFlags                                 = loader_driver_ddi::zeCommandQueueGetFlags;
            } else {
                pDdiTable->pfnGetFlags                                 = loader::zeCommandQueueGetFlags;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetMode                                  = loader_driver_ddi::zeCommandQueueGetMode;
            } else {
                pDdiTable->pfnGetMode                                  = loader::zeCommandQueueGetMode;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetPriority                              = loader_driver_ddi::zeCommandQueueGetPriority;
            } else {
                pDdiTable->pfnGetPriority                              = loader::zeCommandQueueGetPriority;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetOrdinal                               = loader_driver_ddi::zeCommandQueueGetOrdinal;
            } else {
                pDdiTable->pfnGetOrdinal                               = loader::zeCommandQueueGetOrdinal;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetIndex                                 = loader_driver_ddi::zeCommandQueueGetIndex;
            } else {
                pDdiTable->pfnGetIndex                                 = loader::zeCommandQueueGetIndex;
            }
            }
            zeGetCommandQueueProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnCreate                                   = firstDriver->dditable.ze.CommandQueue.pfnCreate;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnDestroy                                  = firstDriver->dditable.ze.CommandQueue.pfnDestroy;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnExecuteCommandLists                      = firstDriver->dditable.ze.CommandQueue.pfnExecuteCommandLists;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnSynchronize                              = firstDriver->dditable.ze.CommandQueue.pfnSynchronize;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnGetFlags                                 = firstDriver->dditable.ze.CommandQueue.pfnGetFlags;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnGetMode                                  = firstDriver->dditable.ze.CommandQueue.pfnGetMode;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnGetPriority                              = firstDriver->dditable.ze.CommandQueue.pfnGetPriority;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnGetOrdinal                               = firstDriver->dditable.ze.CommandQueue.pfnGetOrdinal;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnGetIndex                                 = firstDriver->dditable.ze.CommandQueue.pfnGetIndex;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetCommandQueueProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetCommandQueueProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetCommandQueueProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetCommandQueueProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_command_queue_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_command_queue_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.CommandQueue = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's CommandList table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetCommandListProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_command_list_dditable_t* pDdiTable           ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetCommandListProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->CommandList = new ze_command_list_dditable_t;
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreate                                   = loader_driver_ddi::zeCommandListCreate;
            } else {
                pDdiTable->pfnCreate                                   = loader::zeCommandListCreate;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreateImmediate                          = loader_driver_ddi::zeCommandListCreateImmediate;
            } else {
                pDdiTable->pfnCreateImmediate                          = loader::zeCommandListCreateImmediate;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroy                                  = loader_driver_ddi::zeCommandListDestroy;
            } else {
                pDdiTable->pfnDestroy                                  = loader::zeCommandListDestroy;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnClose                                    = loader_driver_ddi::zeCommandListClose;
            } else {
                pDdiTable->pfnClose                                    = loader::zeCommandListClose;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnReset                                    = loader_driver_ddi::zeCommandListReset;
            } else {
                pDdiTable->pfnReset                                    = loader::zeCommandListReset;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendWriteGlobalTimestamp               = loader_driver_ddi::zeCommandListAppendWriteGlobalTimestamp;
            } else {
                pDdiTable->pfnAppendWriteGlobalTimestamp               = loader::zeCommandListAppendWriteGlobalTimestamp;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendBarrier                            = loader_driver_ddi::zeCommandListAppendBarrier;
            } else {
                pDdiTable->pfnAppendBarrier                            = loader::zeCommandListAppendBarrier;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendMemoryRangesBarrier                = loader_driver_ddi::zeCommandListAppendMemoryRangesBarrier;
            } else {
                pDdiTable->pfnAppendMemoryRangesBarrier                = loader::zeCommandListAppendMemoryRangesBarrier;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendMemoryCopy                         = loader_driver_ddi::zeCommandListAppendMemoryCopy;
            } else {
                pDdiTable->pfnAppendMemoryCopy                         = loader::zeCommandListAppendMemoryCopy;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendMemoryFill                         = loader_driver_ddi::zeCommandListAppendMemoryFill;
            } else {
                pDdiTable->pfnAppendMemoryFill                         = loader::zeCommandListAppendMemoryFill;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendMemoryCopyRegion                   = loader_driver_ddi::zeCommandListAppendMemoryCopyRegion;
            } else {
                pDdiTable->pfnAppendMemoryCopyRegion                   = loader::zeCommandListAppendMemoryCopyRegion;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendMemoryCopyFromContext              = loader_driver_ddi::zeCommandListAppendMemoryCopyFromContext;
            } else {
                pDdiTable->pfnAppendMemoryCopyFromContext              = loader::zeCommandListAppendMemoryCopyFromContext;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendImageCopy                          = loader_driver_ddi::zeCommandListAppendImageCopy;
            } else {
                pDdiTable->pfnAppendImageCopy                          = loader::zeCommandListAppendImageCopy;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendImageCopyRegion                    = loader_driver_ddi::zeCommandListAppendImageCopyRegion;
            } else {
                pDdiTable->pfnAppendImageCopyRegion                    = loader::zeCommandListAppendImageCopyRegion;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendImageCopyToMemory                  = loader_driver_ddi::zeCommandListAppendImageCopyToMemory;
            } else {
                pDdiTable->pfnAppendImageCopyToMemory                  = loader::zeCommandListAppendImageCopyToMemory;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendImageCopyFromMemory                = loader_driver_ddi::zeCommandListAppendImageCopyFromMemory;
            } else {
                pDdiTable->pfnAppendImageCopyFromMemory                = loader::zeCommandListAppendImageCopyFromMemory;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendMemoryPrefetch                     = loader_driver_ddi::zeCommandListAppendMemoryPrefetch;
            } else {
                pDdiTable->pfnAppendMemoryPrefetch                     = loader::zeCommandListAppendMemoryPrefetch;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendMemAdvise                          = loader_driver_ddi::zeCommandListAppendMemAdvise;
            } else {
                pDdiTable->pfnAppendMemAdvise                          = loader::zeCommandListAppendMemAdvise;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendSignalEvent                        = loader_driver_ddi::zeCommandListAppendSignalEvent;
            } else {
                pDdiTable->pfnAppendSignalEvent                        = loader::zeCommandListAppendSignalEvent;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendWaitOnEvents                       = loader_driver_ddi::zeCommandListAppendWaitOnEvents;
            } else {
                pDdiTable->pfnAppendWaitOnEvents                       = loader::zeCommandListAppendWaitOnEvents;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendEventReset                         = loader_driver_ddi::zeCommandListAppendEventReset;
            } else {
                pDdiTable->pfnAppendEventReset                         = loader::zeCommandListAppendEventReset;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendQueryKernelTimestamps              = loader_driver_ddi::zeCommandListAppendQueryKernelTimestamps;
            } else {
                pDdiTable->pfnAppendQueryKernelTimestamps              = loader::zeCommandListAppendQueryKernelTimestamps;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendLaunchKernel                       = loader_driver_ddi::zeCommandListAppendLaunchKernel;
            } else {
                pDdiTable->pfnAppendLaunchKernel                       = loader::zeCommandListAppendLaunchKernel;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendLaunchCooperativeKernel            = loader_driver_ddi::zeCommandListAppendLaunchCooperativeKernel;
            } else {
                pDdiTable->pfnAppendLaunchCooperativeKernel            = loader::zeCommandListAppendLaunchCooperativeKernel;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendLaunchKernelIndirect               = loader_driver_ddi::zeCommandListAppendLaunchKernelIndirect;
            } else {
                pDdiTable->pfnAppendLaunchKernelIndirect               = loader::zeCommandListAppendLaunchKernelIndirect;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendLaunchMultipleKernelsIndirect      = loader_driver_ddi::zeCommandListAppendLaunchMultipleKernelsIndirect;
            } else {
                pDdiTable->pfnAppendLaunchMultipleKernelsIndirect      = loader::zeCommandListAppendLaunchMultipleKernelsIndirect;
            }
            }
            if (version >= ZE_API_VERSION_1_12) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendSignalExternalSemaphoreExt         = loader_driver_ddi::zeCommandListAppendSignalExternalSemaphoreExt;
            } else {
                pDdiTable->pfnAppendSignalExternalSemaphoreExt         = loader::zeCommandListAppendSignalExternalSemaphoreExt;
            }
            }
            if (version >= ZE_API_VERSION_1_12) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendWaitExternalSemaphoreExt           = loader_driver_ddi::zeCommandListAppendWaitExternalSemaphoreExt;
            } else {
                pDdiTable->pfnAppendWaitExternalSemaphoreExt           = loader::zeCommandListAppendWaitExternalSemaphoreExt;
            }
            }
            if (version >= ZE_API_VERSION_1_14) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendLaunchKernelWithParameters         = loader_driver_ddi::zeCommandListAppendLaunchKernelWithParameters;
            } else {
                pDdiTable->pfnAppendLaunchKernelWithParameters         = loader::zeCommandListAppendLaunchKernelWithParameters;
            }
            }
            if (version >= ZE_API_VERSION_1_14) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendLaunchKernelWithArguments          = loader_driver_ddi::zeCommandListAppendLaunchKernelWithArguments;
            } else {
                pDdiTable->pfnAppendLaunchKernelWithArguments          = loader::zeCommandListAppendLaunchKernelWithArguments;
            }
            }
            if (version >= ZE_API_VERSION_1_16) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendMemoryCopyWithParameters           = loader_driver_ddi::zeCommandListAppendMemoryCopyWithParameters;
            } else {
                pDdiTable->pfnAppendMemoryCopyWithParameters           = loader::zeCommandListAppendMemoryCopyWithParameters;
            }
            }
            if (version >= ZE_API_VERSION_1_16) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendMemoryFillWithParameters           = loader_driver_ddi::zeCommandListAppendMemoryFillWithParameters;
            } else {
                pDdiTable->pfnAppendMemoryFillWithParameters           = loader::zeCommandListAppendMemoryFillWithParameters;
            }
            }
            if (version >= ZE_API_VERSION_1_16) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnImmediateAppendCommandListsWithParameters    = loader_driver_ddi::zeCommandListImmediateAppendCommandListsWithParameters;
            } else {
                pDdiTable->pfnImmediateAppendCommandListsWithParameters    = loader::zeCommandListImmediateAppendCommandListsWithParameters;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetFlags                                 = loader_driver_ddi::zeCommandListGetFlags;
            } else {
                pDdiTable->pfnGetFlags                                 = loader::zeCommandListGetFlags;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnImmediateGetFlags                        = loader_driver_ddi::zeCommandListImmediateGetFlags;
            } else {
                pDdiTable->pfnImmediateGetFlags                        = loader::zeCommandListImmediateGetFlags;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnImmediateGetMode                         = loader_driver_ddi::zeCommandListImmediateGetMode;
            } else {
                pDdiTable->pfnImmediateGetMode                         = loader::zeCommandListImmediateGetMode;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnImmediateGetPriority                     = loader_driver_ddi::zeCommandListImmediateGetPriority;
            } else {
                pDdiTable->pfnImmediateGetPriority                     = loader::zeCommandListImmediateGetPriority;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnBeginGraphCaptureExt                     = loader_driver_ddi::zeCommandListBeginGraphCaptureExt;
            } else {
                pDdiTable->pfnBeginGraphCaptureExt                     = loader::zeCommandListBeginGraphCaptureExt;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnBeginCaptureIntoGraphExt                 = loader_driver_ddi::zeCommandListBeginCaptureIntoGraphExt;
            } else {
                pDdiTable->pfnBeginCaptureIntoGraphExt                 = loader::zeCommandListBeginCaptureIntoGraphExt;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnIsGraphCaptureEnabledExt                 = loader_driver_ddi::zeCommandListIsGraphCaptureEnabledExt;
            } else {
                pDdiTable->pfnIsGraphCaptureEnabledExt                 = loader::zeCommandListIsGraphCaptureEnabledExt;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnEndGraphCaptureExt                       = loader_driver_ddi::zeCommandListEndGraphCaptureExt;
            } else {
                pDdiTable->pfnEndGraphCaptureExt                       = loader::zeCommandListEndGraphCaptureExt;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetGraphExt                              = loader_driver_ddi::zeCommandListGetGraphExt;
            } else {
                pDdiTable->pfnGetGraphExt                              = loader::zeCommandListGetGraphExt;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendGraphExt                           = loader_driver_ddi::zeCommandListAppendGraphExt;
            } else {
                pDdiTable->pfnAppendGraphExt                           = loader::zeCommandListAppendGraphExt;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendHostFunction                       = loader_driver_ddi::zeCommandListAppendHostFunction;
            } else {
                pDdiTable->pfnAppendHostFunction                       = loader::zeCommandListAppendHostFunction;
            }
            }
            if (version >= ZE_API_VERSION_1_3) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendImageCopyToMemoryExt               = loader_driver_ddi::zeCommandListAppendImageCopyToMemoryExt;
            } else {
                pDdiTable->pfnAppendImageCopyToMemoryExt               = loader::zeCommandListAppendImageCopyToMemoryExt;
            }
            }
            if (version >= ZE_API_VERSION_1_3) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAppendImageCopyFromMemoryExt             = loader_driver_ddi::zeCommandListAppendImageCopyFromMemoryExt;
            } else {
                pDdiTable->pfnAppendImageCopyFromMemoryExt             = loader::zeCommandListAppendImageCopyFromMemoryExt;
            }
            }
            if (version >= ZE_API_VERSION_1_6) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnHostSynchronize                          = loader_driver_ddi::zeCommandListHostSynchronize;
            } else {
                pDdiTable->pfnHostSynchronize                          = loader::zeCommandListHostSynchronize;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetDeviceHandle                          = loader_driver_ddi::zeCommandListGetDeviceHandle;
            } else {
                pDdiTable->pfnGetDeviceHandle                          = loader::zeCommandListGetDeviceHandle;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetContextHandle                         = loader_driver_ddi::zeCommandListGetContextHandle;
            } else {
                pDdiTable->pfnGetContextHandle                         = loader::zeCommandListGetContextHandle;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetOrdinal                               = loader_driver_ddi::zeCommandListGetOrdinal;
            } else {
                pDdiTable->pfnGetOrdinal                               = loader::zeCommandListGetOrdinal;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnImmediateGetIndex                        = loader_driver_ddi::zeCommandListImmediateGetIndex;
            } else {
                pDdiTable->pfnImmediateGetIndex                        = loader::zeCommandListImmediateGetIndex;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnIsImmediate                              = loader_driver_ddi::zeCommandListIsImmediate;
            } else {
                pDdiTable->pfnIsImmediate                              = loader::zeCommandListIsImmediate;
            }
            }
            zeGetCommandListProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnCreate                                   = firstDriver->dditable.ze.CommandList.pfnCreate;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnCreateImmediate                          = firstDriver->dditable.ze.CommandList.pfnCreateImmediate;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnDestroy                                  = firstDriver->dditable.ze.CommandList.pfnDestroy;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnClose                                    = firstDriver->dditable.ze.CommandList.pfnClose;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnReset                                    = firstDriver->dditable.ze.CommandList.pfnReset;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendWriteGlobalTimestamp               = firstDriver->dditable.ze.CommandList.pfnAppendWriteGlobalTimestamp;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendBarrier                            = firstDriver->dditable.ze.CommandList.pfnAppendBarrier;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendMemoryRangesBarrier                = firstDriver->dditable.ze.CommandList.pfnAppendMemoryRangesBarrier;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendMemoryCopy                         = firstDriver->dditable.ze.CommandList.pfnAppendMemoryCopy;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendMemoryFill                         = firstDriver->dditable.ze.CommandList.pfnAppendMemoryFill;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendMemoryCopyRegion                   = firstDriver->dditable.ze.CommandList.pfnAppendMemoryCopyRegion;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendMemoryCopyFromContext              = firstDriver->dditable.ze.CommandList.pfnAppendMemoryCopyFromContext;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendImageCopy                          = firstDriver->dditable.ze.CommandList.pfnAppendImageCopy;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendImageCopyRegion                    = firstDriver->dditable.ze.CommandList.pfnAppendImageCopyRegion;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendImageCopyToMemory                  = firstDriver->dditable.ze.CommandList.pfnAppendImageCopyToMemory;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendImageCopyFromMemory                = firstDriver->dditable.ze.CommandList.pfnAppendImageCopyFromMemory;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendMemoryPrefetch                     = firstDriver->dditable.ze.CommandList.pfnAppendMemoryPrefetch;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendMemAdvise                          = firstDriver->dditable.ze.CommandList.pfnAppendMemAdvise;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendSignalEvent                        = firstDriver->dditable.ze.CommandList.pfnAppendSignalEvent;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendWaitOnEvents                       = firstDriver->dditable.ze.CommandList.pfnAppendWaitOnEvents;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendEventReset                         = firstDriver->dditable.ze.CommandList.pfnAppendEventReset;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendQueryKernelTimestamps              = firstDriver->dditable.ze.CommandList.pfnAppendQueryKernelTimestamps;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendLaunchKernel                       = firstDriver->dditable.ze.CommandList.pfnAppendLaunchKernel;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendLaunchCooperativeKernel            = firstDriver->dditable.ze.CommandList.pfnAppendLaunchCooperativeKernel;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendLaunchKernelIndirect               = firstDriver->dditable.ze.CommandList.pfnAppendLaunchKernelIndirect;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAppendLaunchMultipleKernelsIndirect      = firstDriver->dditable.ze.CommandList.pfnAppendLaunchMultipleKernelsIndirect;
            }
            if (version >= ZE_API_VERSION_1_12) {
                pDdiTable->pfnAppendSignalExternalSemaphoreExt         = firstDriver->dditable.ze.CommandList.pfnAppendSignalExternalSemaphoreExt;
            }
            if (version >= ZE_API_VERSION_1_12) {
                pDdiTable->pfnAppendWaitExternalSemaphoreExt           = firstDriver->dditable.ze.CommandList.pfnAppendWaitExternalSemaphoreExt;
            }
            if (version >= ZE_API_VERSION_1_14) {
                pDdiTable->pfnAppendLaunchKernelWithParameters         = firstDriver->dditable.ze.CommandList.pfnAppendLaunchKernelWithParameters;
            }
            if (version >= ZE_API_VERSION_1_14) {
                pDdiTable->pfnAppendLaunchKernelWithArguments          = firstDriver->dditable.ze.CommandList.pfnAppendLaunchKernelWithArguments;
            }
            if (version >= ZE_API_VERSION_1_16) {
                pDdiTable->pfnAppendMemoryCopyWithParameters           = firstDriver->dditable.ze.CommandList.pfnAppendMemoryCopyWithParameters;
            }
            if (version >= ZE_API_VERSION_1_16) {
                pDdiTable->pfnAppendMemoryFillWithParameters           = firstDriver->dditable.ze.CommandList.pfnAppendMemoryFillWithParameters;
            }
            if (version >= ZE_API_VERSION_1_16) {
                pDdiTable->pfnImmediateAppendCommandListsWithParameters    = firstDriver->dditable.ze.CommandList.pfnImmediateAppendCommandListsWithParameters;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnGetFlags                                 = firstDriver->dditable.ze.CommandList.pfnGetFlags;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnImmediateGetFlags                        = firstDriver->dditable.ze.CommandList.pfnImmediateGetFlags;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnImmediateGetMode                         = firstDriver->dditable.ze.CommandList.pfnImmediateGetMode;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnImmediateGetPriority                     = firstDriver->dditable.ze.CommandList.pfnImmediateGetPriority;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnBeginGraphCaptureExt                     = firstDriver->dditable.ze.CommandList.pfnBeginGraphCaptureExt;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnBeginCaptureIntoGraphExt                 = firstDriver->dditable.ze.CommandList.pfnBeginCaptureIntoGraphExt;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnIsGraphCaptureEnabledExt                 = firstDriver->dditable.ze.CommandList.pfnIsGraphCaptureEnabledExt;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnEndGraphCaptureExt                       = firstDriver->dditable.ze.CommandList.pfnEndGraphCaptureExt;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnGetGraphExt                              = firstDriver->dditable.ze.CommandList.pfnGetGraphExt;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnAppendGraphExt                           = firstDriver->dditable.ze.CommandList.pfnAppendGraphExt;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnAppendHostFunction                       = firstDriver->dditable.ze.CommandList.pfnAppendHostFunction;
            }
            if (version >= ZE_API_VERSION_1_3) {
                pDdiTable->pfnAppendImageCopyToMemoryExt               = firstDriver->dditable.ze.CommandList.pfnAppendImageCopyToMemoryExt;
            }
            if (version >= ZE_API_VERSION_1_3) {
                pDdiTable->pfnAppendImageCopyFromMemoryExt             = firstDriver->dditable.ze.CommandList.pfnAppendImageCopyFromMemoryExt;
            }
            if (version >= ZE_API_VERSION_1_6) {
                pDdiTable->pfnHostSynchronize                          = firstDriver->dditable.ze.CommandList.pfnHostSynchronize;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnGetDeviceHandle                          = firstDriver->dditable.ze.CommandList.pfnGetDeviceHandle;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnGetContextHandle                         = firstDriver->dditable.ze.CommandList.pfnGetContextHandle;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnGetOrdinal                               = firstDriver->dditable.ze.CommandList.pfnGetOrdinal;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnImmediateGetIndex                        = firstDriver->dditable.ze.CommandList.pfnImmediateGetIndex;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnIsImmediate                              = firstDriver->dditable.ze.CommandList.pfnIsImmediate;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetCommandListProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetCommandListProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetCommandListProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetCommandListProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_command_list_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_command_list_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.CommandList = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's CommandListExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetCommandListExpProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_command_list_exp_dditable_t* pDdiTable       ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetCommandListExpProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->CommandListExp = new ze_command_list_exp_dditable_t;
            if (version >= ZE_API_VERSION_1_10) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetNextCommandIdWithKernelsExp           = loader_driver_ddi::zeCommandListGetNextCommandIdWithKernelsExp;
            } else {
                pDdiTable->pfnGetNextCommandIdWithKernelsExp           = loader::zeCommandListGetNextCommandIdWithKernelsExp;
            }
            }
            if (version >= ZE_API_VERSION_1_10) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnUpdateMutableCommandKernelsExp           = loader_driver_ddi::zeCommandListUpdateMutableCommandKernelsExp;
            } else {
                pDdiTable->pfnUpdateMutableCommandKernelsExp           = loader::zeCommandListUpdateMutableCommandKernelsExp;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnIsMutableExp                             = loader_driver_ddi::zeCommandListIsMutableExp;
            } else {
                pDdiTable->pfnIsMutableExp                             = loader::zeCommandListIsMutableExp;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreateCloneExp                           = loader_driver_ddi::zeCommandListCreateCloneExp;
            } else {
                pDdiTable->pfnCreateCloneExp                           = loader::zeCommandListCreateCloneExp;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnImmediateAppendCommandListsExp           = loader_driver_ddi::zeCommandListImmediateAppendCommandListsExp;
            } else {
                pDdiTable->pfnImmediateAppendCommandListsExp           = loader::zeCommandListImmediateAppendCommandListsExp;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetNextCommandIdExp                      = loader_driver_ddi::zeCommandListGetNextCommandIdExp;
            } else {
                pDdiTable->pfnGetNextCommandIdExp                      = loader::zeCommandListGetNextCommandIdExp;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnUpdateMutableCommandsExp                 = loader_driver_ddi::zeCommandListUpdateMutableCommandsExp;
            } else {
                pDdiTable->pfnUpdateMutableCommandsExp                 = loader::zeCommandListUpdateMutableCommandsExp;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnUpdateMutableCommandSignalEventExp       = loader_driver_ddi::zeCommandListUpdateMutableCommandSignalEventExp;
            } else {
                pDdiTable->pfnUpdateMutableCommandSignalEventExp       = loader::zeCommandListUpdateMutableCommandSignalEventExp;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnUpdateMutableCommandWaitEventsExp        = loader_driver_ddi::zeCommandListUpdateMutableCommandWaitEventsExp;
            } else {
                pDdiTable->pfnUpdateMutableCommandWaitEventsExp        = loader::zeCommandListUpdateMutableCommandWaitEventsExp;
            }
            }
            zeGetCommandListExpProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_10) {
                pDdiTable->pfnGetNextCommandIdWithKernelsExp           = firstDriver->dditable.ze.CommandListExp.pfnGetNextCommandIdWithKernelsExp;
            }
            if (version >= ZE_API_VERSION_1_10) {
                pDdiTable->pfnUpdateMutableCommandKernelsExp           = firstDriver->dditable.ze.CommandListExp.pfnUpdateMutableCommandKernelsExp;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnIsMutableExp                             = firstDriver->dditable.ze.CommandListExp.pfnIsMutableExp;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnCreateCloneExp                           = firstDriver->dditable.ze.CommandListExp.pfnCreateCloneExp;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnImmediateAppendCommandListsExp           = firstDriver->dditable.ze.CommandListExp.pfnImmediateAppendCommandListsExp;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnGetNextCommandIdExp                      = firstDriver->dditable.ze.CommandListExp.pfnGetNextCommandIdExp;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnUpdateMutableCommandsExp                 = firstDriver->dditable.ze.CommandListExp.pfnUpdateMutableCommandsExp;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnUpdateMutableCommandSignalEventExp       = firstDriver->dditable.ze.CommandListExp.pfnUpdateMutableCommandSignalEventExp;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnUpdateMutableCommandWaitEventsExp        = firstDriver->dditable.ze.CommandListExp.pfnUpdateMutableCommandWaitEventsExp;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetCommandListExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetCommandListExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetCommandListExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetCommandListExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_command_list_exp_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_command_list_exp_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.CommandListExp = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Event table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetEventProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_event_dditable_t* pDdiTable                  ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetEventProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->Event = new ze_event_dditable_t;
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreate                                   = loader_driver_ddi::zeEventCreate;
            } else {
                pDdiTable->pfnCreate                                   = loader::zeEventCreate;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroy                                  = loader_driver_ddi::zeEventDestroy;
            } else {
                pDdiTable->pfnDestroy                                  = loader::zeEventDestroy;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnHostSignal                               = loader_driver_ddi::zeEventHostSignal;
            } else {
                pDdiTable->pfnHostSignal                               = loader::zeEventHostSignal;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnHostSynchronize                          = loader_driver_ddi::zeEventHostSynchronize;
            } else {
                pDdiTable->pfnHostSynchronize                          = loader::zeEventHostSynchronize;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnQueryStatus                              = loader_driver_ddi::zeEventQueryStatus;
            } else {
                pDdiTable->pfnQueryStatus                              = loader::zeEventQueryStatus;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnHostReset                                = loader_driver_ddi::zeEventHostReset;
            } else {
                pDdiTable->pfnHostReset                                = loader::zeEventHostReset;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnQueryKernelTimestamp                     = loader_driver_ddi::zeEventQueryKernelTimestamp;
            } else {
                pDdiTable->pfnQueryKernelTimestamp                     = loader::zeEventQueryKernelTimestamp;
            }
            }
            if (version >= ZE_API_VERSION_1_15) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCounterBasedCreate                       = loader_driver_ddi::zeEventCounterBasedCreate;
            } else {
                pDdiTable->pfnCounterBasedCreate                       = loader::zeEventCounterBasedCreate;
            }
            }
            if (version >= ZE_API_VERSION_1_15) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCounterBasedGetIpcHandle                 = loader_driver_ddi::zeEventCounterBasedGetIpcHandle;
            } else {
                pDdiTable->pfnCounterBasedGetIpcHandle                 = loader::zeEventCounterBasedGetIpcHandle;
            }
            }
            if (version >= ZE_API_VERSION_1_15) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCounterBasedOpenIpcHandle                = loader_driver_ddi::zeEventCounterBasedOpenIpcHandle;
            } else {
                pDdiTable->pfnCounterBasedOpenIpcHandle                = loader::zeEventCounterBasedOpenIpcHandle;
            }
            }
            if (version >= ZE_API_VERSION_1_15) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCounterBasedCloseIpcHandle               = loader_driver_ddi::zeEventCounterBasedCloseIpcHandle;
            } else {
                pDdiTable->pfnCounterBasedCloseIpcHandle               = loader::zeEventCounterBasedCloseIpcHandle;
            }
            }
            if (version >= ZE_API_VERSION_1_15) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCounterBasedGetDeviceAddress             = loader_driver_ddi::zeEventCounterBasedGetDeviceAddress;
            } else {
                pDdiTable->pfnCounterBasedGetDeviceAddress             = loader::zeEventCounterBasedGetDeviceAddress;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetCounterBasedFlags                     = loader_driver_ddi::zeEventGetCounterBasedFlags;
            } else {
                pDdiTable->pfnGetCounterBasedFlags                     = loader::zeEventGetCounterBasedFlags;
            }
            }
            if (version >= ZE_API_VERSION_1_6) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnQueryKernelTimestampsExt                 = loader_driver_ddi::zeEventQueryKernelTimestampsExt;
            } else {
                pDdiTable->pfnQueryKernelTimestampsExt                 = loader::zeEventQueryKernelTimestampsExt;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetEventPool                             = loader_driver_ddi::zeEventGetEventPool;
            } else {
                pDdiTable->pfnGetEventPool                             = loader::zeEventGetEventPool;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetSignalScope                           = loader_driver_ddi::zeEventGetSignalScope;
            } else {
                pDdiTable->pfnGetSignalScope                           = loader::zeEventGetSignalScope;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetWaitScope                             = loader_driver_ddi::zeEventGetWaitScope;
            } else {
                pDdiTable->pfnGetWaitScope                             = loader::zeEventGetWaitScope;
            }
            }
            zeGetEventProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnCreate                                   = firstDriver->dditable.ze.Event.pfnCreate;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnDestroy                                  = firstDriver->dditable.ze.Event.pfnDestroy;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnHostSignal                               = firstDriver->dditable.ze.Event.pfnHostSignal;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnHostSynchronize                          = firstDriver->dditable.ze.Event.pfnHostSynchronize;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnQueryStatus                              = firstDriver->dditable.ze.Event.pfnQueryStatus;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnHostReset                                = firstDriver->dditable.ze.Event.pfnHostReset;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnQueryKernelTimestamp                     = firstDriver->dditable.ze.Event.pfnQueryKernelTimestamp;
            }
            if (version >= ZE_API_VERSION_1_15) {
                pDdiTable->pfnCounterBasedCreate                       = firstDriver->dditable.ze.Event.pfnCounterBasedCreate;
            }
            if (version >= ZE_API_VERSION_1_15) {
                pDdiTable->pfnCounterBasedGetIpcHandle                 = firstDriver->dditable.ze.Event.pfnCounterBasedGetIpcHandle;
            }
            if (version >= ZE_API_VERSION_1_15) {
                pDdiTable->pfnCounterBasedOpenIpcHandle                = firstDriver->dditable.ze.Event.pfnCounterBasedOpenIpcHandle;
            }
            if (version >= ZE_API_VERSION_1_15) {
                pDdiTable->pfnCounterBasedCloseIpcHandle               = firstDriver->dditable.ze.Event.pfnCounterBasedCloseIpcHandle;
            }
            if (version >= ZE_API_VERSION_1_15) {
                pDdiTable->pfnCounterBasedGetDeviceAddress             = firstDriver->dditable.ze.Event.pfnCounterBasedGetDeviceAddress;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnGetCounterBasedFlags                     = firstDriver->dditable.ze.Event.pfnGetCounterBasedFlags;
            }
            if (version >= ZE_API_VERSION_1_6) {
                pDdiTable->pfnQueryKernelTimestampsExt                 = firstDriver->dditable.ze.Event.pfnQueryKernelTimestampsExt;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnGetEventPool                             = firstDriver->dditable.ze.Event.pfnGetEventPool;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnGetSignalScope                           = firstDriver->dditable.ze.Event.pfnGetSignalScope;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnGetWaitScope                             = firstDriver->dditable.ze.Event.pfnGetWaitScope;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetEventProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetEventProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetEventProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetEventProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_event_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_event_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.Event = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's EventExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetEventExpProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_event_exp_dditable_t* pDdiTable              ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetEventExpProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->EventExp = new ze_event_exp_dditable_t;
            if (version >= ZE_API_VERSION_1_2) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnQueryTimestampsExp                       = loader_driver_ddi::zeEventQueryTimestampsExp;
            } else {
                pDdiTable->pfnQueryTimestampsExp                       = loader::zeEventQueryTimestampsExp;
            }
            }
            zeGetEventExpProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_2) {
                pDdiTable->pfnQueryTimestampsExp                       = firstDriver->dditable.ze.EventExp.pfnQueryTimestampsExp;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetEventExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetEventExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetEventExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetEventExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_event_exp_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_event_exp_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.EventExp = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's EventPool table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetEventPoolProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_event_pool_dditable_t* pDdiTable             ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetEventPoolProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->EventPool = new ze_event_pool_dditable_t;
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreate                                   = loader_driver_ddi::zeEventPoolCreate;
            } else {
                pDdiTable->pfnCreate                                   = loader::zeEventPoolCreate;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroy                                  = loader_driver_ddi::zeEventPoolDestroy;
            } else {
                pDdiTable->pfnDestroy                                  = loader::zeEventPoolDestroy;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetIpcHandle                             = loader_driver_ddi::zeEventPoolGetIpcHandle;
            } else {
                pDdiTable->pfnGetIpcHandle                             = loader::zeEventPoolGetIpcHandle;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnOpenIpcHandle                            = loader_driver_ddi::zeEventPoolOpenIpcHandle;
            } else {
                pDdiTable->pfnOpenIpcHandle                            = loader::zeEventPoolOpenIpcHandle;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCloseIpcHandle                           = loader_driver_ddi::zeEventPoolCloseIpcHandle;
            } else {
                pDdiTable->pfnCloseIpcHandle                           = loader::zeEventPoolCloseIpcHandle;
            }
            }
            if (version >= ZE_API_VERSION_1_6) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnPutIpcHandle                             = loader_driver_ddi::zeEventPoolPutIpcHandle;
            } else {
                pDdiTable->pfnPutIpcHandle                             = loader::zeEventPoolPutIpcHandle;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetContextHandle                         = loader_driver_ddi::zeEventPoolGetContextHandle;
            } else {
                pDdiTable->pfnGetContextHandle                         = loader::zeEventPoolGetContextHandle;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetFlags                                 = loader_driver_ddi::zeEventPoolGetFlags;
            } else {
                pDdiTable->pfnGetFlags                                 = loader::zeEventPoolGetFlags;
            }
            }
            zeGetEventPoolProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnCreate                                   = firstDriver->dditable.ze.EventPool.pfnCreate;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnDestroy                                  = firstDriver->dditable.ze.EventPool.pfnDestroy;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetIpcHandle                             = firstDriver->dditable.ze.EventPool.pfnGetIpcHandle;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnOpenIpcHandle                            = firstDriver->dditable.ze.EventPool.pfnOpenIpcHandle;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnCloseIpcHandle                           = firstDriver->dditable.ze.EventPool.pfnCloseIpcHandle;
            }
            if (version >= ZE_API_VERSION_1_6) {
                pDdiTable->pfnPutIpcHandle                             = firstDriver->dditable.ze.EventPool.pfnPutIpcHandle;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnGetContextHandle                         = firstDriver->dditable.ze.EventPool.pfnGetContextHandle;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnGetFlags                                 = firstDriver->dditable.ze.EventPool.pfnGetFlags;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetEventPoolProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetEventPoolProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetEventPoolProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetEventPoolProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_event_pool_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_event_pool_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.EventPool = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Fence table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetFenceProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_fence_dditable_t* pDdiTable                  ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetFenceProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->Fence = new ze_fence_dditable_t;
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreate                                   = loader_driver_ddi::zeFenceCreate;
            } else {
                pDdiTable->pfnCreate                                   = loader::zeFenceCreate;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroy                                  = loader_driver_ddi::zeFenceDestroy;
            } else {
                pDdiTable->pfnDestroy                                  = loader::zeFenceDestroy;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnHostSynchronize                          = loader_driver_ddi::zeFenceHostSynchronize;
            } else {
                pDdiTable->pfnHostSynchronize                          = loader::zeFenceHostSynchronize;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnQueryStatus                              = loader_driver_ddi::zeFenceQueryStatus;
            } else {
                pDdiTable->pfnQueryStatus                              = loader::zeFenceQueryStatus;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnReset                                    = loader_driver_ddi::zeFenceReset;
            } else {
                pDdiTable->pfnReset                                    = loader::zeFenceReset;
            }
            }
            zeGetFenceProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnCreate                                   = firstDriver->dditable.ze.Fence.pfnCreate;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnDestroy                                  = firstDriver->dditable.ze.Fence.pfnDestroy;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnHostSynchronize                          = firstDriver->dditable.ze.Fence.pfnHostSynchronize;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnQueryStatus                              = firstDriver->dditable.ze.Fence.pfnQueryStatus;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnReset                                    = firstDriver->dditable.ze.Fence.pfnReset;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetFenceProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetFenceProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetFenceProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetFenceProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_fence_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_fence_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.Fence = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Image table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetImageProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_image_dditable_t* pDdiTable                  ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetImageProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->Image = new ze_image_dditable_t;
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetProperties                            = loader_driver_ddi::zeImageGetProperties;
            } else {
                pDdiTable->pfnGetProperties                            = loader::zeImageGetProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreate                                   = loader_driver_ddi::zeImageCreate;
            } else {
                pDdiTable->pfnCreate                                   = loader::zeImageCreate;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroy                                  = loader_driver_ddi::zeImageDestroy;
            } else {
                pDdiTable->pfnDestroy                                  = loader::zeImageDestroy;
            }
            }
            if (version >= ZE_API_VERSION_1_3) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetAllocPropertiesExt                    = loader_driver_ddi::zeImageGetAllocPropertiesExt;
            } else {
                pDdiTable->pfnGetAllocPropertiesExt                    = loader::zeImageGetAllocPropertiesExt;
            }
            }
            if (version >= ZE_API_VERSION_1_5) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnViewCreateExt                            = loader_driver_ddi::zeImageViewCreateExt;
            } else {
                pDdiTable->pfnViewCreateExt                            = loader::zeImageViewCreateExt;
            }
            }
            zeGetImageProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetProperties                            = firstDriver->dditable.ze.Image.pfnGetProperties;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnCreate                                   = firstDriver->dditable.ze.Image.pfnCreate;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnDestroy                                  = firstDriver->dditable.ze.Image.pfnDestroy;
            }
            if (version >= ZE_API_VERSION_1_3) {
                pDdiTable->pfnGetAllocPropertiesExt                    = firstDriver->dditable.ze.Image.pfnGetAllocPropertiesExt;
            }
            if (version >= ZE_API_VERSION_1_5) {
                pDdiTable->pfnViewCreateExt                            = firstDriver->dditable.ze.Image.pfnViewCreateExt;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetImageProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetImageProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetImageProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetImageProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_image_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_image_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.Image = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's ImageExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetImageExpProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_image_exp_dditable_t* pDdiTable              ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetImageExpProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->ImageExp = new ze_image_exp_dditable_t;
            if (version >= ZE_API_VERSION_1_2) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetMemoryPropertiesExp                   = loader_driver_ddi::zeImageGetMemoryPropertiesExp;
            } else {
                pDdiTable->pfnGetMemoryPropertiesExp                   = loader::zeImageGetMemoryPropertiesExp;
            }
            }
            if (version >= ZE_API_VERSION_1_2) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnViewCreateExp                            = loader_driver_ddi::zeImageViewCreateExp;
            } else {
                pDdiTable->pfnViewCreateExp                            = loader::zeImageViewCreateExp;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetDeviceOffsetExp                       = loader_driver_ddi::zeImageGetDeviceOffsetExp;
            } else {
                pDdiTable->pfnGetDeviceOffsetExp                       = loader::zeImageGetDeviceOffsetExp;
            }
            }
            zeGetImageExpProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_2) {
                pDdiTable->pfnGetMemoryPropertiesExp                   = firstDriver->dditable.ze.ImageExp.pfnGetMemoryPropertiesExp;
            }
            if (version >= ZE_API_VERSION_1_2) {
                pDdiTable->pfnViewCreateExp                            = firstDriver->dditable.ze.ImageExp.pfnViewCreateExp;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnGetDeviceOffsetExp                       = firstDriver->dditable.ze.ImageExp.pfnGetDeviceOffsetExp;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetImageExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetImageExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetImageExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetImageExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_image_exp_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_image_exp_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.ImageExp = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Kernel table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetKernelProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_kernel_dditable_t* pDdiTable                 ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetKernelProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->Kernel = new ze_kernel_dditable_t;
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreate                                   = loader_driver_ddi::zeKernelCreate;
            } else {
                pDdiTable->pfnCreate                                   = loader::zeKernelCreate;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroy                                  = loader_driver_ddi::zeKernelDestroy;
            } else {
                pDdiTable->pfnDestroy                                  = loader::zeKernelDestroy;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnSetCacheConfig                           = loader_driver_ddi::zeKernelSetCacheConfig;
            } else {
                pDdiTable->pfnSetCacheConfig                           = loader::zeKernelSetCacheConfig;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnSetGroupSize                             = loader_driver_ddi::zeKernelSetGroupSize;
            } else {
                pDdiTable->pfnSetGroupSize                             = loader::zeKernelSetGroupSize;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnSuggestGroupSize                         = loader_driver_ddi::zeKernelSuggestGroupSize;
            } else {
                pDdiTable->pfnSuggestGroupSize                         = loader::zeKernelSuggestGroupSize;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnSuggestMaxCooperativeGroupCount          = loader_driver_ddi::zeKernelSuggestMaxCooperativeGroupCount;
            } else {
                pDdiTable->pfnSuggestMaxCooperativeGroupCount          = loader::zeKernelSuggestMaxCooperativeGroupCount;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnSetArgumentValue                         = loader_driver_ddi::zeKernelSetArgumentValue;
            } else {
                pDdiTable->pfnSetArgumentValue                         = loader::zeKernelSetArgumentValue;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnSetIndirectAccess                        = loader_driver_ddi::zeKernelSetIndirectAccess;
            } else {
                pDdiTable->pfnSetIndirectAccess                        = loader::zeKernelSetIndirectAccess;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetIndirectAccess                        = loader_driver_ddi::zeKernelGetIndirectAccess;
            } else {
                pDdiTable->pfnGetIndirectAccess                        = loader::zeKernelGetIndirectAccess;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetSourceAttributes                      = loader_driver_ddi::zeKernelGetSourceAttributes;
            } else {
                pDdiTable->pfnGetSourceAttributes                      = loader::zeKernelGetSourceAttributes;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetProperties                            = loader_driver_ddi::zeKernelGetProperties;
            } else {
                pDdiTable->pfnGetProperties                            = loader::zeKernelGetProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetName                                  = loader_driver_ddi::zeKernelGetName;
            } else {
                pDdiTable->pfnGetName                                  = loader::zeKernelGetName;
            }
            }
            zeGetKernelProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnCreate                                   = firstDriver->dditable.ze.Kernel.pfnCreate;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnDestroy                                  = firstDriver->dditable.ze.Kernel.pfnDestroy;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnSetCacheConfig                           = firstDriver->dditable.ze.Kernel.pfnSetCacheConfig;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnSetGroupSize                             = firstDriver->dditable.ze.Kernel.pfnSetGroupSize;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnSuggestGroupSize                         = firstDriver->dditable.ze.Kernel.pfnSuggestGroupSize;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnSuggestMaxCooperativeGroupCount          = firstDriver->dditable.ze.Kernel.pfnSuggestMaxCooperativeGroupCount;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnSetArgumentValue                         = firstDriver->dditable.ze.Kernel.pfnSetArgumentValue;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnSetIndirectAccess                        = firstDriver->dditable.ze.Kernel.pfnSetIndirectAccess;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetIndirectAccess                        = firstDriver->dditable.ze.Kernel.pfnGetIndirectAccess;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetSourceAttributes                      = firstDriver->dditable.ze.Kernel.pfnGetSourceAttributes;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetProperties                            = firstDriver->dditable.ze.Kernel.pfnGetProperties;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetName                                  = firstDriver->dditable.ze.Kernel.pfnGetName;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetKernelProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetKernelProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetKernelProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetKernelProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_kernel_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_kernel_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.Kernel = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's KernelExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetKernelExpProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_kernel_exp_dditable_t* pDdiTable             ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetKernelExpProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->KernelExp = new ze_kernel_exp_dditable_t;
            if (version >= ZE_API_VERSION_1_1) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnSetGlobalOffsetExp                       = loader_driver_ddi::zeKernelSetGlobalOffsetExp;
            } else {
                pDdiTable->pfnSetGlobalOffsetExp                       = loader::zeKernelSetGlobalOffsetExp;
            }
            }
            if (version >= ZE_API_VERSION_1_11) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetBinaryExp                             = loader_driver_ddi::zeKernelGetBinaryExp;
            } else {
                pDdiTable->pfnGetBinaryExp                             = loader::zeKernelGetBinaryExp;
            }
            }
            if (version >= ZE_API_VERSION_1_14) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetAllocationPropertiesExp               = loader_driver_ddi::zeKernelGetAllocationPropertiesExp;
            } else {
                pDdiTable->pfnGetAllocationPropertiesExp               = loader::zeKernelGetAllocationPropertiesExp;
            }
            }
            if (version >= ZE_API_VERSION_1_2) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnSchedulingHintExp                        = loader_driver_ddi::zeKernelSchedulingHintExp;
            } else {
                pDdiTable->pfnSchedulingHintExp                        = loader::zeKernelSchedulingHintExp;
            }
            }
            zeGetKernelExpProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_1) {
                pDdiTable->pfnSetGlobalOffsetExp                       = firstDriver->dditable.ze.KernelExp.pfnSetGlobalOffsetExp;
            }
            if (version >= ZE_API_VERSION_1_11) {
                pDdiTable->pfnGetBinaryExp                             = firstDriver->dditable.ze.KernelExp.pfnGetBinaryExp;
            }
            if (version >= ZE_API_VERSION_1_14) {
                pDdiTable->pfnGetAllocationPropertiesExp               = firstDriver->dditable.ze.KernelExp.pfnGetAllocationPropertiesExp;
            }
            if (version >= ZE_API_VERSION_1_2) {
                pDdiTable->pfnSchedulingHintExp                        = firstDriver->dditable.ze.KernelExp.pfnSchedulingHintExp;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetKernelExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetKernelExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetKernelExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetKernelExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_kernel_exp_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_kernel_exp_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.KernelExp = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Mem table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetMemProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_mem_dditable_t* pDdiTable                    ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetMemProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->Mem = new ze_mem_dditable_t;
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAllocShared                              = loader_driver_ddi::zeMemAllocShared;
            } else {
                pDdiTable->pfnAllocShared                              = loader::zeMemAllocShared;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAllocDevice                              = loader_driver_ddi::zeMemAllocDevice;
            } else {
                pDdiTable->pfnAllocDevice                              = loader::zeMemAllocDevice;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnAllocHost                                = loader_driver_ddi::zeMemAllocHost;
            } else {
                pDdiTable->pfnAllocHost                                = loader::zeMemAllocHost;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnFree                                     = loader_driver_ddi::zeMemFree;
            } else {
                pDdiTable->pfnFree                                     = loader::zeMemFree;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetAllocProperties                       = loader_driver_ddi::zeMemGetAllocProperties;
            } else {
                pDdiTable->pfnGetAllocProperties                       = loader::zeMemGetAllocProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetAddressRange                          = loader_driver_ddi::zeMemGetAddressRange;
            } else {
                pDdiTable->pfnGetAddressRange                          = loader::zeMemGetAddressRange;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetIpcHandle                             = loader_driver_ddi::zeMemGetIpcHandle;
            } else {
                pDdiTable->pfnGetIpcHandle                             = loader::zeMemGetIpcHandle;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnOpenIpcHandle                            = loader_driver_ddi::zeMemOpenIpcHandle;
            } else {
                pDdiTable->pfnOpenIpcHandle                            = loader::zeMemOpenIpcHandle;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCloseIpcHandle                           = loader_driver_ddi::zeMemCloseIpcHandle;
            } else {
                pDdiTable->pfnCloseIpcHandle                           = loader::zeMemCloseIpcHandle;
            }
            }
            if (version >= ZE_API_VERSION_1_15) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetIpcHandleWithProperties               = loader_driver_ddi::zeMemGetIpcHandleWithProperties;
            } else {
                pDdiTable->pfnGetIpcHandleWithProperties               = loader::zeMemGetIpcHandleWithProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_3) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnFreeExt                                  = loader_driver_ddi::zeMemFreeExt;
            } else {
                pDdiTable->pfnFreeExt                                  = loader::zeMemFreeExt;
            }
            }
            if (version >= ZE_API_VERSION_1_6) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnPutIpcHandle                             = loader_driver_ddi::zeMemPutIpcHandle;
            } else {
                pDdiTable->pfnPutIpcHandle                             = loader::zeMemPutIpcHandle;
            }
            }
            if (version >= ZE_API_VERSION_1_9) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetPitchFor2dImage                       = loader_driver_ddi::zeMemGetPitchFor2dImage;
            } else {
                pDdiTable->pfnGetPitchFor2dImage                       = loader::zeMemGetPitchFor2dImage;
            }
            }
            zeGetMemProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAllocShared                              = firstDriver->dditable.ze.Mem.pfnAllocShared;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAllocDevice                              = firstDriver->dditable.ze.Mem.pfnAllocDevice;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnAllocHost                                = firstDriver->dditable.ze.Mem.pfnAllocHost;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnFree                                     = firstDriver->dditable.ze.Mem.pfnFree;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetAllocProperties                       = firstDriver->dditable.ze.Mem.pfnGetAllocProperties;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetAddressRange                          = firstDriver->dditable.ze.Mem.pfnGetAddressRange;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetIpcHandle                             = firstDriver->dditable.ze.Mem.pfnGetIpcHandle;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnOpenIpcHandle                            = firstDriver->dditable.ze.Mem.pfnOpenIpcHandle;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnCloseIpcHandle                           = firstDriver->dditable.ze.Mem.pfnCloseIpcHandle;
            }
            if (version >= ZE_API_VERSION_1_15) {
                pDdiTable->pfnGetIpcHandleWithProperties               = firstDriver->dditable.ze.Mem.pfnGetIpcHandleWithProperties;
            }
            if (version >= ZE_API_VERSION_1_3) {
                pDdiTable->pfnFreeExt                                  = firstDriver->dditable.ze.Mem.pfnFreeExt;
            }
            if (version >= ZE_API_VERSION_1_6) {
                pDdiTable->pfnPutIpcHandle                             = firstDriver->dditable.ze.Mem.pfnPutIpcHandle;
            }
            if (version >= ZE_API_VERSION_1_9) {
                pDdiTable->pfnGetPitchFor2dImage                       = firstDriver->dditable.ze.Mem.pfnGetPitchFor2dImage;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetMemProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetMemProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetMemProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetMemProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_mem_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_mem_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.Mem = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's MemExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetMemExpProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_mem_exp_dditable_t* pDdiTable                ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetMemExpProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->MemExp = new ze_mem_exp_dditable_t;
            if (version >= ZE_API_VERSION_1_6) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetIpcHandleFromFileDescriptorExp        = loader_driver_ddi::zeMemGetIpcHandleFromFileDescriptorExp;
            } else {
                pDdiTable->pfnGetIpcHandleFromFileDescriptorExp        = loader::zeMemGetIpcHandleFromFileDescriptorExp;
            }
            }
            if (version >= ZE_API_VERSION_1_6) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetFileDescriptorFromIpcHandleExp        = loader_driver_ddi::zeMemGetFileDescriptorFromIpcHandleExp;
            } else {
                pDdiTable->pfnGetFileDescriptorFromIpcHandleExp        = loader::zeMemGetFileDescriptorFromIpcHandleExp;
            }
            }
            if (version >= ZE_API_VERSION_1_7) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnSetAtomicAccessAttributeExp              = loader_driver_ddi::zeMemSetAtomicAccessAttributeExp;
            } else {
                pDdiTable->pfnSetAtomicAccessAttributeExp              = loader::zeMemSetAtomicAccessAttributeExp;
            }
            }
            if (version >= ZE_API_VERSION_1_7) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetAtomicAccessAttributeExp              = loader_driver_ddi::zeMemGetAtomicAccessAttributeExp;
            } else {
                pDdiTable->pfnGetAtomicAccessAttributeExp              = loader::zeMemGetAtomicAccessAttributeExp;
            }
            }
            zeGetMemExpProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_6) {
                pDdiTable->pfnGetIpcHandleFromFileDescriptorExp        = firstDriver->dditable.ze.MemExp.pfnGetIpcHandleFromFileDescriptorExp;
            }
            if (version >= ZE_API_VERSION_1_6) {
                pDdiTable->pfnGetFileDescriptorFromIpcHandleExp        = firstDriver->dditable.ze.MemExp.pfnGetFileDescriptorFromIpcHandleExp;
            }
            if (version >= ZE_API_VERSION_1_7) {
                pDdiTable->pfnSetAtomicAccessAttributeExp              = firstDriver->dditable.ze.MemExp.pfnSetAtomicAccessAttributeExp;
            }
            if (version >= ZE_API_VERSION_1_7) {
                pDdiTable->pfnGetAtomicAccessAttributeExp              = firstDriver->dditable.ze.MemExp.pfnGetAtomicAccessAttributeExp;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetMemExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetMemExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetMemExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetMemExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_mem_exp_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_mem_exp_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.MemExp = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Module table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetModuleProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_module_dditable_t* pDdiTable                 ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetModuleProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->Module = new ze_module_dditable_t;
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreate                                   = loader_driver_ddi::zeModuleCreate;
            } else {
                pDdiTable->pfnCreate                                   = loader::zeModuleCreate;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroy                                  = loader_driver_ddi::zeModuleDestroy;
            } else {
                pDdiTable->pfnDestroy                                  = loader::zeModuleDestroy;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDynamicLink                              = loader_driver_ddi::zeModuleDynamicLink;
            } else {
                pDdiTable->pfnDynamicLink                              = loader::zeModuleDynamicLink;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetNativeBinary                          = loader_driver_ddi::zeModuleGetNativeBinary;
            } else {
                pDdiTable->pfnGetNativeBinary                          = loader::zeModuleGetNativeBinary;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetGlobalPointer                         = loader_driver_ddi::zeModuleGetGlobalPointer;
            } else {
                pDdiTable->pfnGetGlobalPointer                         = loader::zeModuleGetGlobalPointer;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetKernelNames                           = loader_driver_ddi::zeModuleGetKernelNames;
            } else {
                pDdiTable->pfnGetKernelNames                           = loader::zeModuleGetKernelNames;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetProperties                            = loader_driver_ddi::zeModuleGetProperties;
            } else {
                pDdiTable->pfnGetProperties                            = loader::zeModuleGetProperties;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetFunctionPointer                       = loader_driver_ddi::zeModuleGetFunctionPointer;
            } else {
                pDdiTable->pfnGetFunctionPointer                       = loader::zeModuleGetFunctionPointer;
            }
            }
            if (version >= ZE_API_VERSION_1_3) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnInspectLinkageExt                        = loader_driver_ddi::zeModuleInspectLinkageExt;
            } else {
                pDdiTable->pfnInspectLinkageExt                        = loader::zeModuleInspectLinkageExt;
            }
            }
            zeGetModuleProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnCreate                                   = firstDriver->dditable.ze.Module.pfnCreate;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnDestroy                                  = firstDriver->dditable.ze.Module.pfnDestroy;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnDynamicLink                              = firstDriver->dditable.ze.Module.pfnDynamicLink;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetNativeBinary                          = firstDriver->dditable.ze.Module.pfnGetNativeBinary;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetGlobalPointer                         = firstDriver->dditable.ze.Module.pfnGetGlobalPointer;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetKernelNames                           = firstDriver->dditable.ze.Module.pfnGetKernelNames;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetProperties                            = firstDriver->dditable.ze.Module.pfnGetProperties;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetFunctionPointer                       = firstDriver->dditable.ze.Module.pfnGetFunctionPointer;
            }
            if (version >= ZE_API_VERSION_1_3) {
                pDdiTable->pfnInspectLinkageExt                        = firstDriver->dditable.ze.Module.pfnInspectLinkageExt;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetModuleProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetModuleProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetModuleProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetModuleProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_module_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_module_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.Module = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's ModuleBuildLog table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetModuleBuildLogProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_module_build_log_dditable_t* pDdiTable       ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetModuleBuildLogProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->ModuleBuildLog = new ze_module_build_log_dditable_t;
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroy                                  = loader_driver_ddi::zeModuleBuildLogDestroy;
            } else {
                pDdiTable->pfnDestroy                                  = loader::zeModuleBuildLogDestroy;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetString                                = loader_driver_ddi::zeModuleBuildLogGetString;
            } else {
                pDdiTable->pfnGetString                                = loader::zeModuleBuildLogGetString;
            }
            }
            zeGetModuleBuildLogProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnDestroy                                  = firstDriver->dditable.ze.ModuleBuildLog.pfnDestroy;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetString                                = firstDriver->dditable.ze.ModuleBuildLog.pfnGetString;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetModuleBuildLogProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetModuleBuildLogProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetModuleBuildLogProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetModuleBuildLogProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_module_build_log_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_module_build_log_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.ModuleBuildLog = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's PhysicalMem table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetPhysicalMemProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_physical_mem_dditable_t* pDdiTable           ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetPhysicalMemProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->PhysicalMem = new ze_physical_mem_dditable_t;
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreate                                   = loader_driver_ddi::zePhysicalMemCreate;
            } else {
                pDdiTable->pfnCreate                                   = loader::zePhysicalMemCreate;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroy                                  = loader_driver_ddi::zePhysicalMemDestroy;
            } else {
                pDdiTable->pfnDestroy                                  = loader::zePhysicalMemDestroy;
            }
            }
            if (version >= ZE_API_VERSION_1_15) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetProperties                            = loader_driver_ddi::zePhysicalMemGetProperties;
            } else {
                pDdiTable->pfnGetProperties                            = loader::zePhysicalMemGetProperties;
            }
            }
            zeGetPhysicalMemProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnCreate                                   = firstDriver->dditable.ze.PhysicalMem.pfnCreate;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnDestroy                                  = firstDriver->dditable.ze.PhysicalMem.pfnDestroy;
            }
            if (version >= ZE_API_VERSION_1_15) {
                pDdiTable->pfnGetProperties                            = firstDriver->dditable.ze.PhysicalMem.pfnGetProperties;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetPhysicalMemProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetPhysicalMemProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetPhysicalMemProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetPhysicalMemProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_physical_mem_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_physical_mem_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.PhysicalMem = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Sampler table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetSamplerProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_sampler_dditable_t* pDdiTable                ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetSamplerProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->Sampler = new ze_sampler_dditable_t;
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreate                                   = loader_driver_ddi::zeSamplerCreate;
            } else {
                pDdiTable->pfnCreate                                   = loader::zeSamplerCreate;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroy                                  = loader_driver_ddi::zeSamplerDestroy;
            } else {
                pDdiTable->pfnDestroy                                  = loader::zeSamplerDestroy;
            }
            }
            zeGetSamplerProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnCreate                                   = firstDriver->dditable.ze.Sampler.pfnCreate;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnDestroy                                  = firstDriver->dditable.ze.Sampler.pfnDestroy;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetSamplerProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetSamplerProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetSamplerProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetSamplerProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_sampler_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_sampler_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.Sampler = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's VirtualMem table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetVirtualMemProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_virtual_mem_dditable_t* pDdiTable            ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetVirtualMemProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->VirtualMem = new ze_virtual_mem_dditable_t;
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnReserve                                  = loader_driver_ddi::zeVirtualMemReserve;
            } else {
                pDdiTable->pfnReserve                                  = loader::zeVirtualMemReserve;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnFree                                     = loader_driver_ddi::zeVirtualMemFree;
            } else {
                pDdiTable->pfnFree                                     = loader::zeVirtualMemFree;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnQueryPageSize                            = loader_driver_ddi::zeVirtualMemQueryPageSize;
            } else {
                pDdiTable->pfnQueryPageSize                            = loader::zeVirtualMemQueryPageSize;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnMap                                      = loader_driver_ddi::zeVirtualMemMap;
            } else {
                pDdiTable->pfnMap                                      = loader::zeVirtualMemMap;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnUnmap                                    = loader_driver_ddi::zeVirtualMemUnmap;
            } else {
                pDdiTable->pfnUnmap                                    = loader::zeVirtualMemUnmap;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnSetAccessAttribute                       = loader_driver_ddi::zeVirtualMemSetAccessAttribute;
            } else {
                pDdiTable->pfnSetAccessAttribute                       = loader::zeVirtualMemSetAccessAttribute;
            }
            }
            if (version >= ZE_API_VERSION_1_0) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetAccessAttribute                       = loader_driver_ddi::zeVirtualMemGetAccessAttribute;
            } else {
                pDdiTable->pfnGetAccessAttribute                       = loader::zeVirtualMemGetAccessAttribute;
            }
            }
            zeGetVirtualMemProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnReserve                                  = firstDriver->dditable.ze.VirtualMem.pfnReserve;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnFree                                     = firstDriver->dditable.ze.VirtualMem.pfnFree;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnQueryPageSize                            = firstDriver->dditable.ze.VirtualMem.pfnQueryPageSize;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnMap                                      = firstDriver->dditable.ze.VirtualMem.pfnMap;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnUnmap                                    = firstDriver->dditable.ze.VirtualMem.pfnUnmap;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnSetAccessAttribute                       = firstDriver->dditable.ze.VirtualMem.pfnSetAccessAttribute;
            }
            if (version >= ZE_API_VERSION_1_0) {
                pDdiTable->pfnGetAccessAttribute                       = firstDriver->dditable.ze.VirtualMem.pfnGetAccessAttribute;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetVirtualMemProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetVirtualMemProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetVirtualMemProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetVirtualMemProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_virtual_mem_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_virtual_mem_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.VirtualMem = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's FabricEdgeExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetFabricEdgeExpProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_fabric_edge_exp_dditable_t* pDdiTable        ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetFabricEdgeExpProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->FabricEdgeExp = new ze_fabric_edge_exp_dditable_t;
            if (version >= ZE_API_VERSION_1_4) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetExp                                   = loader_driver_ddi::zeFabricEdgeGetExp;
            } else {
                pDdiTable->pfnGetExp                                   = loader::zeFabricEdgeGetExp;
            }
            }
            if (version >= ZE_API_VERSION_1_4) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetVerticesExp                           = loader_driver_ddi::zeFabricEdgeGetVerticesExp;
            } else {
                pDdiTable->pfnGetVerticesExp                           = loader::zeFabricEdgeGetVerticesExp;
            }
            }
            if (version >= ZE_API_VERSION_1_4) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetPropertiesExp                         = loader_driver_ddi::zeFabricEdgeGetPropertiesExp;
            } else {
                pDdiTable->pfnGetPropertiesExp                         = loader::zeFabricEdgeGetPropertiesExp;
            }
            }
            zeGetFabricEdgeExpProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_4) {
                pDdiTable->pfnGetExp                                   = firstDriver->dditable.ze.FabricEdgeExp.pfnGetExp;
            }
            if (version >= ZE_API_VERSION_1_4) {
                pDdiTable->pfnGetVerticesExp                           = firstDriver->dditable.ze.FabricEdgeExp.pfnGetVerticesExp;
            }
            if (version >= ZE_API_VERSION_1_4) {
                pDdiTable->pfnGetPropertiesExp                         = firstDriver->dditable.ze.FabricEdgeExp.pfnGetPropertiesExp;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetFabricEdgeExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetFabricEdgeExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetFabricEdgeExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetFabricEdgeExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_fabric_edge_exp_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_fabric_edge_exp_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.FabricEdgeExp = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's FabricVertexExp table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetFabricVertexExpProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_fabric_vertex_exp_dditable_t* pDdiTable      ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetFabricVertexExpProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->FabricVertexExp = new ze_fabric_vertex_exp_dditable_t;
            if (version >= ZE_API_VERSION_1_4) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetExp                                   = loader_driver_ddi::zeFabricVertexGetExp;
            } else {
                pDdiTable->pfnGetExp                                   = loader::zeFabricVertexGetExp;
            }
            }
            if (version >= ZE_API_VERSION_1_4) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetSubVerticesExp                        = loader_driver_ddi::zeFabricVertexGetSubVerticesExp;
            } else {
                pDdiTable->pfnGetSubVerticesExp                        = loader::zeFabricVertexGetSubVerticesExp;
            }
            }
            if (version >= ZE_API_VERSION_1_4) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetPropertiesExp                         = loader_driver_ddi::zeFabricVertexGetPropertiesExp;
            } else {
                pDdiTable->pfnGetPropertiesExp                         = loader::zeFabricVertexGetPropertiesExp;
            }
            }
            if (version >= ZE_API_VERSION_1_4) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetDeviceExp                             = loader_driver_ddi::zeFabricVertexGetDeviceExp;
            } else {
                pDdiTable->pfnGetDeviceExp                             = loader::zeFabricVertexGetDeviceExp;
            }
            }
            zeGetFabricVertexExpProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_4) {
                pDdiTable->pfnGetExp                                   = firstDriver->dditable.ze.FabricVertexExp.pfnGetExp;
            }
            if (version >= ZE_API_VERSION_1_4) {
                pDdiTable->pfnGetSubVerticesExp                        = firstDriver->dditable.ze.FabricVertexExp.pfnGetSubVerticesExp;
            }
            if (version >= ZE_API_VERSION_1_4) {
                pDdiTable->pfnGetPropertiesExp                         = firstDriver->dditable.ze.FabricVertexExp.pfnGetPropertiesExp;
            }
            if (version >= ZE_API_VERSION_1_4) {
                pDdiTable->pfnGetDeviceExp                             = firstDriver->dditable.ze.FabricVertexExp.pfnGetDeviceExp;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetFabricVertexExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetFabricVertexExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetFabricVertexExpProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetFabricVertexExpProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_fabric_vertex_exp_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_fabric_vertex_exp_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.FabricVertexExp = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's ExecutableGraph table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetExecutableGraphProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_executable_graph_dditable_t* pDdiTable       ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetExecutableGraphProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->ExecutableGraph = new ze_executable_graph_dditable_t;
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetSourceGraphExt                        = loader_driver_ddi::zeExecutableGraphGetSourceGraphExt;
            } else {
                pDdiTable->pfnGetSourceGraphExt                        = loader::zeExecutableGraphGetSourceGraphExt;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroyExt                               = loader_driver_ddi::zeExecutableGraphDestroyExt;
            } else {
                pDdiTable->pfnDestroyExt                               = loader::zeExecutableGraphDestroyExt;
            }
            }
            zeGetExecutableGraphProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnGetSourceGraphExt                        = firstDriver->dditable.ze.ExecutableGraph.pfnGetSourceGraphExt;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnDestroyExt                               = firstDriver->dditable.ze.ExecutableGraph.pfnDestroyExt;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetExecutableGraphProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetExecutableGraphProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetExecutableGraphProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetExecutableGraphProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_executable_graph_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_executable_graph_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.ExecutableGraph = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Exported function for filling application's Graph table
///        with current process' addresses
///
/// @returns
///     - ::ZE_RESULT_SUCCESS
///     - ::ZE_RESULT_ERROR_UNINITIALIZED
///     - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER
///     - ::ZE_RESULT_ERROR_UNSUPPORTED_VERSION
ZE_DLLEXPORT ze_result_t ZE_APICALL
zeGetGraphProcAddrTable(
    ze_api_version_t version,                       ///< [in] API version requested
    ze_graph_dditable_t* pDdiTable                  ///< [in,out] pointer to table of DDI function pointers
    )
{
    if( loader::context->zeDrivers.size() < 1 ) {
        return ZE_RESULT_ERROR_UNINITIALIZED;
    }

    if( nullptr == pDdiTable )
        return ZE_RESULT_ERROR_INVALID_NULL_POINTER;

    if( loader::context->version < version )
        return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;

    loader::context->ddi_init_version = version;

    ze_result_t result = ZE_RESULT_SUCCESS;

    auto driverCount = loader::context->zeDrivers.size();
    auto firstDriver = &loader::context->zeDrivers[0];
    if (driverCount == 1 && firstDriver && !loader::context->forceIntercept) {
        result = zeGetGraphProcAddrTableFromDriver(firstDriver);
    }

    if( ZE_RESULT_SUCCESS == result )
    {
        if( ( loader::context->zeDrivers.size() > 1 ) || loader::context->forceIntercept )
        {
            // return pointers to loader's DDIs
            loader::loaderDispatch->pCore->Graph = new ze_graph_dditable_t;
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnCreateExt                                = loader_driver_ddi::zeGraphCreateExt;
            } else {
                pDdiTable->pfnCreateExt                                = loader::zeGraphCreateExt;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnGetPrimaryCommandListExt                 = loader_driver_ddi::zeGraphGetPrimaryCommandListExt;
            } else {
                pDdiTable->pfnGetPrimaryCommandListExt                 = loader::zeGraphGetPrimaryCommandListExt;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnSetDestructionCallbackExt                = loader_driver_ddi::zeGraphSetDestructionCallbackExt;
            } else {
                pDdiTable->pfnSetDestructionCallbackExt                = loader::zeGraphSetDestructionCallbackExt;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnInstantiateExt                           = loader_driver_ddi::zeGraphInstantiateExt;
            } else {
                pDdiTable->pfnInstantiateExt                           = loader::zeGraphInstantiateExt;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnIsEmptyExt                               = loader_driver_ddi::zeGraphIsEmptyExt;
            } else {
                pDdiTable->pfnIsEmptyExt                               = loader::zeGraphIsEmptyExt;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDumpContentsExt                          = loader_driver_ddi::zeGraphDumpContentsExt;
            } else {
                pDdiTable->pfnDumpContentsExt                          = loader::zeGraphDumpContentsExt;
            }
            }
            if (version >= ZE_API_VERSION_1_17) {
            if (loader::context->driverDDIPathDefault) {
                pDdiTable->pfnDestroyExt                               = loader_driver_ddi::zeGraphDestroyExt;
            } else {
                pDdiTable->pfnDestroyExt                               = loader::zeGraphDestroyExt;
            }
            }
            zeGetGraphProcAddrTableLegacy();
        }
        else
        {
            // return pointers directly to driver's DDIs
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnCreateExt                                = firstDriver->dditable.ze.Graph.pfnCreateExt;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnGetPrimaryCommandListExt                 = firstDriver->dditable.ze.Graph.pfnGetPrimaryCommandListExt;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnSetDestructionCallbackExt                = firstDriver->dditable.ze.Graph.pfnSetDestructionCallbackExt;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnInstantiateExt                           = firstDriver->dditable.ze.Graph.pfnInstantiateExt;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnIsEmptyExt                               = firstDriver->dditable.ze.Graph.pfnIsEmptyExt;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnDumpContentsExt                          = firstDriver->dditable.ze.Graph.pfnDumpContentsExt;
            }
            if (version >= ZE_API_VERSION_1_17) {
                pDdiTable->pfnDestroyExt                               = firstDriver->dditable.ze.Graph.pfnDestroyExt;
            }
        }
    }

    // If the validation layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->validationLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetGraphProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->validationLayer, "zeGetGraphProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        result = getTable( version, pDdiTable );
    }

    // If the API tracing layer is enabled, then intercept the loader's DDIs
    if(( ZE_RESULT_SUCCESS == result ) && ( nullptr != loader::context->tracingLayer ))
    {
        auto getTable = reinterpret_cast<ze_pfnGetGraphProcAddrTable_t>(
            GET_FUNCTION_PTR(loader::context->tracingLayer, "zeGetGraphProcAddrTable") );
        if(!getTable)
            return ZE_RESULT_ERROR_UNINITIALIZED;
        ze_graph_dditable_t dditable;
        memcpy(&dditable, pDdiTable, sizeof(ze_graph_dditable_t));
        result = getTable( version, &dditable );
        loader::context->tracing_dditable.ze.Graph = dditable;
        if ( loader::context->tracingLayerEnabled ) {
            result = getTable( version, pDdiTable );
        }
    }

    return result;
}


#if defined(__cplusplus)
};
#endif