blob: 7d680675005199f7acd4abdd9ab9dc34718a9944 [file] [log] [blame]
/*
* MVKBaseObject.mm
*
* Copyright (c) 2015-2022 The Brenwill Workshop Ltd. (http://www.brenwill.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "MVKBaseObject.h"
#include "MVKVulkanAPIObject.h"
#include "MVKInstance.h"
#include "MVKFoundation.h"
#include "MVKOSExtensions.h"
#include <cxxabi.h>
using namespace std;
static const char* getReportingLevelString(MVKConfigLogLevel logLevel) {
switch (logLevel) {
case MVK_CONFIG_LOG_LEVEL_DEBUG:
return "mvk-debug";
case MVK_CONFIG_LOG_LEVEL_INFO:
return "mvk-info";
case MVK_CONFIG_LOG_LEVEL_WARNING:
return "mvk-warn";
case MVK_CONFIG_LOG_LEVEL_ERROR:
default:
return "mvk-error";
}
}
#pragma mark -
#pragma mark MVKBaseObject
string MVKBaseObject::getClassName() {
int status;
char* demangled = abi::__cxa_demangle(typeid(*this).name(), 0, 0, &status);
string clzName = demangled;
free(demangled);
return clzName;
}
void MVKBaseObject::reportMessage(MVKConfigLogLevel logLevel, const char* format, ...) {
va_list args;
va_start(args, format);
reportMessage(this, logLevel, format, args);
va_end(args);
}
void MVKBaseObject::reportMessage(MVKBaseObject* mvkObj, MVKConfigLogLevel logLevel, const char* format, ...) {
va_list args;
va_start(args, format);
reportMessage(mvkObj, logLevel, format, args);
va_end(args);
}
// This is the core reporting implementation. Other similar functions delegate here.
void MVKBaseObject::reportMessage(MVKBaseObject* mvkObj, MVKConfigLogLevel logLevel, const char* format, va_list args) {
MVKVulkanAPIObject* mvkAPIObj = mvkObj ? mvkObj->getVulkanAPIObject() : nullptr;
MVKInstance* mvkInst = mvkAPIObj ? mvkAPIObj->getInstance() : nullptr;
bool hasDebugCallbacks = mvkInst && mvkInst->hasDebugCallbacks();
bool shouldLog = logLevel <= mvkConfig().logLevel;
// Fail fast to avoid further unnecessary processing.
if ( !(shouldLog || hasDebugCallbacks) ) { return; }
va_list origArgs, redoArgs;
va_copy(origArgs, args);
va_copy(redoArgs, args);
// Choose a buffer size suitable for most messages and attempt to write it out.
const int kOrigBuffSize = 2 * KIBI;
char origBuff[kOrigBuffSize];
char* pMessage = origBuff;
int msgLen = vsnprintf(origBuff, kOrigBuffSize, format, origArgs);
// If message is too big for original buffer, allocate a buffer big enough to hold it and
// write the message out again. We only want to do this double writing if we have to.
int redoBuffSize = (msgLen >= kOrigBuffSize) ? msgLen + 1 : 0;
char *redoBuff = NULL;
if (redoBuffSize > 0 && (redoBuff = (char *)malloc(redoBuffSize))) {
pMessage = redoBuff;
vsnprintf(redoBuff, redoBuffSize, format, redoArgs);
}
va_end(redoArgs);
va_end(origArgs);
// Log the message to the standard error stream
if (shouldLog) { fprintf(stderr, "[%s] %s\n", getReportingLevelString(logLevel), pMessage); }
// Broadcast the message to any Vulkan debug report callbacks
if (hasDebugCallbacks) { mvkInst->debugReportMessage(mvkAPIObj, logLevel, pMessage); }
free(redoBuff);
}
VkResult MVKBaseObject::reportError(VkResult vkErr, const char* format, ...) {
va_list args;
va_start(args, format);
VkResult rslt = reportError(this, vkErr, format, args);
va_end(args);
return rslt;
}
VkResult MVKBaseObject::reportError(MVKBaseObject* mvkObj, VkResult vkErr, const char* format, ...) {
va_list args;
va_start(args, format);
VkResult rslt = reportError(mvkObj, vkErr, format, args);
va_end(args);
return rslt;
}
// This is the core reporting implementation. Other similar functions delegate here.
VkResult MVKBaseObject::reportError(MVKBaseObject* mvkObj, VkResult vkErr, const char* format, va_list args) {
// Prepend the error code to the format string
const char* vkRsltName = mvkVkResultName(vkErr);
size_t rsltLen = strlen(vkRsltName) + strlen(format) + 4;
char fmtStr[rsltLen];
snprintf(fmtStr, rsltLen, "%s: %s", vkRsltName, format);
// Report the error
va_list lclArgs;
va_copy(lclArgs, args);
reportMessage(mvkObj, MVK_CONFIG_LOG_LEVEL_ERROR, fmtStr, lclArgs);
va_end(lclArgs);
return vkErr;
}