mirror of
https://gitee.com/openharmony/third_party_vulkan-loader
synced 2025-01-13 02:34:09 +00:00
427 lines
11 KiB
C
427 lines
11 KiB
C
/*
|
|
* XGL
|
|
*
|
|
* Copyright (C) 2014 LunarG, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
|
|
#include <dlfcn.h>
|
|
#include <pthread.h>
|
|
|
|
#include <xgl.h>
|
|
#include <xglDbg.h>
|
|
|
|
#include "loader.generated"
|
|
|
|
typedef XGL_RESULT (XGLAPI *InitAndEnumerateGpusT)(const XGL_APPLICATION_INFO* pAppInfo, const XGL_ALLOC_CALLBACKS* pAllocCb, XGL_UINT maxGpus, XGL_UINT* pGpuCount, XGL_PHYSICAL_GPU* pGpus);
|
|
typedef XGL_RESULT (XGLAPI *DbgRegisterMsgCallbackT)(XGL_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback, XGL_VOID* pUserData);
|
|
typedef XGL_RESULT (XGLAPI *DbgUnregisterMsgCallbackT)(XGL_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback);
|
|
typedef XGL_RESULT (XGLAPI *DbgSetGlobalOptionT)(XGL_INT dbgOption, XGL_SIZE dataSize, const XGL_VOID* pData);
|
|
|
|
struct loader_icd {
|
|
void *handle;
|
|
|
|
InitAndEnumerateGpusT InitAndEnumerateGpus;
|
|
DbgRegisterMsgCallbackT DbgRegisterMsgCallback;
|
|
DbgUnregisterMsgCallbackT DbgUnregisterMsgCallback;
|
|
DbgSetGlobalOptionT DbgSetGlobalOption;
|
|
|
|
struct loader_icd *next;
|
|
};
|
|
|
|
struct loader_msg_callback {
|
|
XGL_DBG_MSG_CALLBACK_FUNCTION func;
|
|
XGL_VOID *data;
|
|
|
|
struct loader_msg_callback *next;
|
|
};
|
|
|
|
static struct {
|
|
bool scanned;
|
|
struct loader_icd *icds;
|
|
|
|
struct loader_msg_callback *msg_callbacks;
|
|
|
|
bool debug_echo_enable;
|
|
bool break_on_error;
|
|
bool break_on_warning;
|
|
} loader;
|
|
|
|
static XGL_RESULT loader_msg_callback_add(XGL_DBG_MSG_CALLBACK_FUNCTION func,
|
|
XGL_VOID *data)
|
|
{
|
|
struct loader_msg_callback *cb;
|
|
|
|
cb = malloc(sizeof(*cb));
|
|
if (!cb)
|
|
return XGL_ERROR_OUT_OF_MEMORY;
|
|
|
|
cb->func = func;
|
|
cb->data = data;
|
|
|
|
cb->next = loader.msg_callbacks;
|
|
loader.msg_callbacks = cb;
|
|
|
|
return XGL_SUCCESS;
|
|
}
|
|
|
|
static XGL_RESULT loader_msg_callback_remove(XGL_DBG_MSG_CALLBACK_FUNCTION func)
|
|
{
|
|
struct loader_msg_callback *cb = loader.msg_callbacks;
|
|
|
|
/*
|
|
* Find the first match (last registered).
|
|
*
|
|
* XXX What if the same callback function is registered more than once?
|
|
*/
|
|
while (cb) {
|
|
if (cb->func == func) {
|
|
break;
|
|
}
|
|
|
|
cb = cb->next;
|
|
}
|
|
|
|
if (!cb)
|
|
return XGL_ERROR_INVALID_POINTER;
|
|
|
|
free(cb);
|
|
|
|
return XGL_SUCCESS;
|
|
}
|
|
|
|
static void loader_msg_callback_clear(void)
|
|
{
|
|
struct loader_msg_callback *cb = loader.msg_callbacks;
|
|
|
|
while (cb) {
|
|
struct loader_msg_callback *next = cb->next;
|
|
free(cb);
|
|
cb = next;
|
|
}
|
|
|
|
loader.msg_callbacks = NULL;
|
|
}
|
|
|
|
static void loader_log(XGL_DBG_MSG_TYPE msg_type, XGL_INT msg_code,
|
|
const char *format, ...)
|
|
{
|
|
const struct loader_msg_callback *cb = loader.msg_callbacks;
|
|
char msg[256];
|
|
va_list ap;
|
|
int ret;
|
|
|
|
va_start(ap, format);
|
|
ret = vsnprintf(msg, sizeof(msg), format, ap);
|
|
if (ret >= sizeof(msg) || ret < 0) {
|
|
msg[sizeof(msg) - 1] = '\0';
|
|
}
|
|
va_end(ap);
|
|
|
|
if (loader.debug_echo_enable || !cb) {
|
|
fputs(msg, stderr);
|
|
fputc('\n', stderr);
|
|
}
|
|
|
|
while (cb) {
|
|
cb->func(msg_type, XGL_VALIDATION_LEVEL_0, XGL_NULL_HANDLE, 0,
|
|
msg_code, (const XGL_CHAR *) msg, cb->data);
|
|
cb = cb->next;
|
|
}
|
|
|
|
switch (msg_type) {
|
|
case XGL_DBG_MSG_ERROR:
|
|
if (loader.break_on_error) {
|
|
exit(1);
|
|
}
|
|
/* fall through */
|
|
case XGL_DBG_MSG_WARNING:
|
|
if (loader.break_on_warning) {
|
|
exit(1);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
loader_icd_destroy(struct loader_icd *icd)
|
|
{
|
|
dlclose(icd->handle);
|
|
free(icd);
|
|
}
|
|
|
|
static struct loader_icd *
|
|
loader_icd_create(const char *filename)
|
|
{
|
|
struct loader_icd *icd;
|
|
|
|
icd = malloc(sizeof(*icd));
|
|
if (!icd)
|
|
return NULL;
|
|
|
|
icd->handle = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
|
|
if (!icd->handle) {
|
|
loader_log(XGL_DBG_MSG_WARNING, 0, dlerror());
|
|
free(icd);
|
|
return NULL;
|
|
}
|
|
|
|
#define LOOKUP(icd, func) do { \
|
|
icd->func = (func## T) dlsym(icd->handle, "xgl" #func); \
|
|
if (!icd->func) { \
|
|
loader_log(XGL_DBG_MSG_WARNING, 0, dlerror()); \
|
|
loader_icd_destroy(icd); \
|
|
return NULL; \
|
|
} \
|
|
} while (0)
|
|
LOOKUP(icd, InitAndEnumerateGpus);
|
|
LOOKUP(icd, DbgRegisterMsgCallback);
|
|
LOOKUP(icd, DbgUnregisterMsgCallback);
|
|
LOOKUP(icd, DbgSetGlobalOption);
|
|
#undef LOOKUP
|
|
|
|
return icd;
|
|
}
|
|
|
|
static XGL_RESULT loader_icd_register_msg_callbacks(const struct loader_icd *icd)
|
|
{
|
|
const struct loader_msg_callback *cb = loader.msg_callbacks;
|
|
XGL_RESULT res;
|
|
|
|
while (cb) {
|
|
res = icd->DbgRegisterMsgCallback(cb->func, cb->data);
|
|
if (res != XGL_SUCCESS) {
|
|
break;
|
|
}
|
|
|
|
cb = cb->next;
|
|
}
|
|
|
|
/* roll back on errors */
|
|
if (cb) {
|
|
const struct loader_msg_callback *tmp = loader.msg_callbacks;
|
|
|
|
while (tmp != cb) {
|
|
icd->DbgUnregisterMsgCallback(cb->func);
|
|
tmp = tmp->next;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
return XGL_SUCCESS;
|
|
}
|
|
|
|
static XGL_RESULT loader_icd_set_global_options(const struct loader_icd *icd)
|
|
{
|
|
#define SETB(icd, opt, val) do { \
|
|
if (val) { \
|
|
const XGL_RESULT res = \
|
|
icd->DbgSetGlobalOption(opt, sizeof(val), &val); \
|
|
if (res != XGL_SUCCESS) \
|
|
return res; \
|
|
} \
|
|
} while (0)
|
|
SETB(icd, XGL_DBG_OPTION_DEBUG_ECHO_ENABLE, loader.debug_echo_enable);
|
|
SETB(icd, XGL_DBG_OPTION_BREAK_ON_ERROR, loader.break_on_error);
|
|
SETB(icd, XGL_DBG_OPTION_BREAK_ON_WARNING, loader.break_on_warning);
|
|
#undef SETB
|
|
|
|
return XGL_SUCCESS;
|
|
}
|
|
|
|
static void
|
|
loader_icd_scan(void)
|
|
{
|
|
/* XXX How to discover ICDs? */
|
|
static const char *filenames[] = {
|
|
"libmesaxgl.so",
|
|
"libintelxgl.so",
|
|
"libxgl.so",
|
|
};
|
|
int i;
|
|
|
|
for (i = 0; i < sizeof(filenames) / sizeof(filenames[0]); i++) {
|
|
struct loader_icd *icd;
|
|
|
|
icd = loader_icd_create(filenames[i]);
|
|
if (!icd) {
|
|
continue;
|
|
}
|
|
|
|
if (loader_icd_set_global_options(icd) != XGL_SUCCESS ||
|
|
loader_icd_register_msg_callbacks(icd) != XGL_SUCCESS) {
|
|
loader_log(XGL_DBG_MSG_WARNING, 0,
|
|
"%s ignored: failed to migrate settings", filenames[i]);
|
|
loader_icd_destroy(icd);
|
|
continue;
|
|
}
|
|
|
|
/* prepend to the list */
|
|
icd->next = loader.icds;
|
|
loader.icds = icd;
|
|
}
|
|
|
|
/* we have nothing to log anymore */
|
|
loader_msg_callback_clear();
|
|
|
|
loader.scanned = true;
|
|
}
|
|
|
|
XGL_RESULT XGLAPI xglInitAndEnumerateGpus(const XGL_APPLICATION_INFO* pAppInfo, const XGL_ALLOC_CALLBACKS* pAllocCb, XGL_UINT maxGpus, XGL_UINT* pGpuCount, XGL_PHYSICAL_GPU* pGpus)
|
|
{
|
|
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
|
const struct loader_icd *icd;
|
|
XGL_UINT count = 0;
|
|
XGL_RESULT res;
|
|
|
|
pthread_once(&once, loader_icd_scan);
|
|
|
|
if (!loader.icds)
|
|
return XGL_ERROR_UNAVAILABLE;
|
|
|
|
icd = loader.icds;
|
|
while (icd) {
|
|
XGL_PHYSICAL_GPU gpus[XGL_MAX_PHYSICAL_GPUS];
|
|
XGL_UINT n, max = maxGpus - count;
|
|
|
|
if (max > XGL_MAX_PHYSICAL_GPUS) {
|
|
max = XGL_MAX_PHYSICAL_GPUS;
|
|
}
|
|
|
|
res = icd->InitAndEnumerateGpus(pAppInfo, pAllocCb, max, &n, gpus);
|
|
if (res == XGL_SUCCESS) {
|
|
memcpy(pGpus + count, gpus, sizeof(*pGpus) * n);
|
|
count += n;
|
|
|
|
if (count >= maxGpus) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
icd = icd->next;
|
|
}
|
|
|
|
*pGpuCount = count;
|
|
|
|
return (count > 0) ? XGL_SUCCESS : res;
|
|
}
|
|
|
|
XGL_RESULT XGLAPI xglDbgRegisterMsgCallback(XGL_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback, XGL_VOID* pUserData)
|
|
{
|
|
const struct loader_icd *icd = loader.icds;
|
|
XGL_RESULT res;
|
|
|
|
if (!loader.scanned) {
|
|
return loader_msg_callback_add(pfnMsgCallback, pUserData);
|
|
}
|
|
|
|
while (icd) {
|
|
res = icd->DbgRegisterMsgCallback(pfnMsgCallback, pUserData);
|
|
if (res != XGL_SUCCESS) {
|
|
break;
|
|
}
|
|
|
|
icd = icd->next;
|
|
}
|
|
|
|
/* roll back on errors */
|
|
if (icd) {
|
|
const struct loader_icd *tmp = loader.icds;
|
|
|
|
while (tmp != icd) {
|
|
tmp->DbgUnregisterMsgCallback(pfnMsgCallback);
|
|
tmp = tmp->next;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
return XGL_SUCCESS;
|
|
}
|
|
|
|
XGL_RESULT XGLAPI xglDbgUnregisterMsgCallback(XGL_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback)
|
|
{
|
|
const struct loader_icd *icd = loader.icds;
|
|
XGL_RESULT res = XGL_SUCCESS;
|
|
|
|
if (!loader.scanned) {
|
|
return loader_msg_callback_remove(pfnMsgCallback);
|
|
}
|
|
|
|
while (icd) {
|
|
XGL_RESULT r = icd->DbgUnregisterMsgCallback(pfnMsgCallback);
|
|
if (r != XGL_SUCCESS) {
|
|
res = r;
|
|
}
|
|
icd = icd->next;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
XGL_RESULT XGLAPI xglDbgSetGlobalOption(XGL_DBG_GLOBAL_OPTION dbgOption, XGL_SIZE dataSize, const XGL_VOID* pData)
|
|
{
|
|
const struct loader_icd *icd = loader.icds;
|
|
XGL_RESULT res = XGL_SUCCESS;
|
|
|
|
if (!loader.scanned) {
|
|
if (dataSize == 0)
|
|
return XGL_ERROR_INVALID_VALUE;
|
|
|
|
switch (dbgOption) {
|
|
case XGL_DBG_OPTION_DEBUG_ECHO_ENABLE:
|
|
loader.debug_echo_enable = *((const bool *) pData);
|
|
break;
|
|
case XGL_DBG_OPTION_BREAK_ON_ERROR:
|
|
loader.break_on_error = *((const bool *) pData);
|
|
break;
|
|
case XGL_DBG_OPTION_BREAK_ON_WARNING:
|
|
loader.break_on_warning = *((const bool *) pData);
|
|
break;
|
|
default:
|
|
res = XGL_ERROR_INVALID_VALUE;
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
while (icd) {
|
|
XGL_RESULT r = icd->DbgSetGlobalOption(dbgOption, dataSize, pData);
|
|
/* unfortunately we cannot roll back */
|
|
if (r != XGL_SUCCESS) {
|
|
res = r;
|
|
}
|
|
|
|
icd = icd->next;
|
|
}
|
|
|
|
return res;
|
|
}
|