374 lines
11 KiB
C++
374 lines
11 KiB
C++
// Copyright 2018 Intel Corporation
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
#include "device.h"
|
|
#include "subdevice.h"
|
|
#include "engine.h"
|
|
#include "context.h"
|
|
#include "rt_filter.h"
|
|
#include "rtlightmap_filter.h"
|
|
|
|
OIDN_NAMESPACE_BEGIN
|
|
|
|
thread_local Device::ErrorState Device::globalError;
|
|
|
|
int PhysicalDevice::getInt(const std::string& name) const
|
|
{
|
|
if (name == "type")
|
|
return static_cast<int>(type);
|
|
else if (name == "uuidSupported")
|
|
return uuidSupported;
|
|
else if (name == "luidSupported")
|
|
return luidSupported;
|
|
else if (name == "nodeMask")
|
|
{
|
|
if (!luidSupported)
|
|
throw Exception(Error::InvalidArgument,
|
|
"physical device node mask unavailable, check luidSupported first");
|
|
return nodeMask;
|
|
}
|
|
else if (name == "pciAddressSupported")
|
|
return pciAddressSupported;
|
|
else if (name == "pciDomain")
|
|
{
|
|
if (!pciAddressSupported)
|
|
throw Exception(Error::InvalidArgument,
|
|
"physical device PCI domain number unavailable, check pciAddressSupported first");
|
|
return pciDomain;
|
|
}
|
|
else if (name == "pciBus")
|
|
{
|
|
if (!pciAddressSupported)
|
|
throw Exception(Error::InvalidArgument,
|
|
"physical device PCI bus number unavailable, check pciAddressSupported first");
|
|
return pciBus;
|
|
}
|
|
else if (name == "pciDevice")
|
|
{
|
|
if (!pciAddressSupported)
|
|
throw Exception(Error::InvalidArgument,
|
|
"physical device PCI device number unavailable, check pciAddressSupported first");
|
|
return pciDevice;
|
|
}
|
|
else if (name == "pciFunction")
|
|
{
|
|
if (!pciAddressSupported)
|
|
throw Exception(Error::InvalidArgument,
|
|
"physical device PCI function number unavailable, check pciAddressSupported first");
|
|
return pciFunction;
|
|
}
|
|
else
|
|
throw Exception(Error::InvalidArgument, "unknown physical device parameter or type mismatch: '" + name + "'");
|
|
}
|
|
|
|
const char* PhysicalDevice::getString(const std::string& name) const
|
|
{
|
|
if (name == "name")
|
|
return this->name.c_str();
|
|
else
|
|
throw Exception(Error::InvalidArgument, "unknown physical device parameter or type mismatch: '" + name + "'");
|
|
}
|
|
|
|
Data PhysicalDevice::getData(const std::string& name) const
|
|
{
|
|
if (name == "uuid")
|
|
{
|
|
if (!uuidSupported)
|
|
throw Exception(Error::InvalidArgument, "physical device UUID unavailable, check uuidSupported first");
|
|
return {uuid.bytes, sizeof(uuid.bytes)};
|
|
}
|
|
else if (name == "luid")
|
|
{
|
|
if (!luidSupported)
|
|
throw Exception(Error::InvalidArgument, "physical device LUID unavailable, check luidSupported first");
|
|
return {luid.bytes, sizeof(luid.bytes)};
|
|
}
|
|
else
|
|
throw Exception(Error::InvalidArgument, "unknown physical device parameter or type mismatch: '" + name + "'");
|
|
}
|
|
|
|
Device::Device()
|
|
{
|
|
// Get default values from environment variables
|
|
if (getEnvVar("OIDN_VERBOSE", verbose))
|
|
error.setVerbose(verbose);
|
|
}
|
|
|
|
void Device::setError(Device* device, Error code, const std::string& message)
|
|
{
|
|
// Update the stored error only if the previous error was queried
|
|
if (device)
|
|
{
|
|
ErrorState& curError = device->error.get();
|
|
|
|
if (curError.code == Error::None)
|
|
{
|
|
curError.code = code;
|
|
curError.message = message;
|
|
}
|
|
|
|
// Print the error message in verbose mode
|
|
device->printError(message);
|
|
|
|
// Call the error callback function
|
|
ErrorFunction errorFunc = nullptr;
|
|
void* errorUserPtr = nullptr;
|
|
|
|
{
|
|
// setError is called outside the device lock, so we need to lock it here
|
|
std::lock_guard<std::mutex> lock(device->mutex);
|
|
errorFunc = device->errorFunc;
|
|
errorUserPtr = device->errorUserPtr;
|
|
}
|
|
|
|
if (errorFunc)
|
|
errorFunc(errorUserPtr, code, (code == Error::None) ? nullptr : message.c_str());
|
|
}
|
|
else
|
|
{
|
|
if (globalError.code == Error::None)
|
|
{
|
|
globalError.code = code;
|
|
globalError.message = message;
|
|
}
|
|
|
|
// Print the error message in verbose mode
|
|
Context::get().printError(message);
|
|
}
|
|
}
|
|
|
|
Error Device::getError(Device* device, const char** outMessage)
|
|
{
|
|
// Return and clear the stored error code, but keep the error message so pointers to it will
|
|
// remain valid until the next getError call
|
|
if (device)
|
|
{
|
|
ErrorState& curError = device->error.get();
|
|
const Error code = curError.code;
|
|
if (outMessage)
|
|
*outMessage = (code == Error::None) ? nullptr : curError.message.c_str();
|
|
curError.code = Error::None;
|
|
return code;
|
|
}
|
|
else
|
|
{
|
|
const Error code = globalError.code;
|
|
if (outMessage)
|
|
*outMessage = (code == Error::None) ? nullptr : globalError.message.c_str();
|
|
globalError.code = Error::None;
|
|
return code;
|
|
}
|
|
}
|
|
|
|
void Device::setAsyncError(Error code, const std::string& message)
|
|
{
|
|
// Update the stored async error only if the previous error was thrown
|
|
std::lock_guard<std::mutex> lock(asyncErrorMutex);
|
|
if (asyncError.code == Error::None)
|
|
{
|
|
asyncError.code = code;
|
|
asyncError.message = message;
|
|
}
|
|
}
|
|
|
|
void Device::setErrorFunction(ErrorFunction func, void* userPtr)
|
|
{
|
|
errorFunc = func;
|
|
errorUserPtr = userPtr;
|
|
}
|
|
|
|
int Device::getInt(const std::string& name)
|
|
{
|
|
if (name == "type")
|
|
return static_cast<int>(getType());
|
|
else if (name == "version")
|
|
return OIDN_VERSION;
|
|
else if (name == "versionMajor")
|
|
return OIDN_VERSION_MAJOR;
|
|
else if (name == "versionMinor")
|
|
return OIDN_VERSION_MINOR;
|
|
else if (name == "versionPatch")
|
|
return OIDN_VERSION_PATCH;
|
|
else if (name == "verbose")
|
|
return verbose;
|
|
else if (name == "systemMemorySupported")
|
|
return systemMemorySupported;
|
|
else if (name == "managedMemorySupported")
|
|
return managedMemorySupported;
|
|
else if (name == "externalMemoryTypes")
|
|
return static_cast<OIDNFlags>(externalMemoryTypes);
|
|
else if (name == "externalSemaphoreTypes")
|
|
return static_cast<OIDNFlags>(externalSemaphoreTypes);
|
|
else
|
|
throw Exception(Error::InvalidArgument, "unknown device parameter or type mismatch: '" + name + "'");
|
|
}
|
|
|
|
void Device::setInt(const std::string& name, int value)
|
|
{
|
|
if (name == "verbose")
|
|
{
|
|
if (!isEnvVar("OIDN_VERBOSE"))
|
|
{
|
|
verbose = value;
|
|
error.setVerbose(value);
|
|
}
|
|
else if (verbose != value)
|
|
printWarning("OIDN_VERBOSE environment variable overrides device parameter");
|
|
}
|
|
else
|
|
printWarning("unknown device parameter or type mismatch: '" + name + "'");
|
|
|
|
dirty = true;
|
|
}
|
|
|
|
void Device::commit()
|
|
{
|
|
if (isCommitted())
|
|
throw Exception(Error::InvalidOperation, "device can be committed only once");
|
|
|
|
if (isVerbose())
|
|
{
|
|
std::cout << std::endl;
|
|
std::cout << "Intel(R) Open Image Denoise " << OIDN_VERSION_STRING << std::endl;
|
|
std::cout << " Compiler : " << getCompilerName() << std::endl;
|
|
std::cout << " Build : " << getBuildName() << std::endl;
|
|
std::cout << " OS : " << getOSName() << std::endl;
|
|
}
|
|
|
|
init();
|
|
|
|
if (isVerbose())
|
|
std::cout << std::endl;
|
|
|
|
dirty = false;
|
|
committed = true;
|
|
}
|
|
|
|
void Device::checkCommitted()
|
|
{
|
|
if (dirty)
|
|
throw Exception(Error::InvalidOperation, "changes to the device are not committed");
|
|
}
|
|
|
|
Engine* Device::getEngine(int i) const
|
|
{
|
|
return getSubdevice(i)->getEngine();
|
|
}
|
|
|
|
Ref<Buffer> Device::newUserBuffer(size_t byteSize, Storage storage)
|
|
{
|
|
return getEngine()->newBuffer(byteSize, storage)->toUser();
|
|
}
|
|
|
|
Ref<Buffer> Device::newUserBuffer(void* ptr, size_t byteSize)
|
|
{
|
|
return getEngine()->newBuffer(ptr, byteSize)->toUser();
|
|
}
|
|
|
|
Ref<Buffer> Device::newNativeUserBuffer(void* handle)
|
|
{
|
|
return getEngine()->newNativeBuffer(handle)->toUser();
|
|
}
|
|
|
|
Ref<Buffer> Device::newExternalUserBuffer(ExternalMemoryTypeFlags fdType,
|
|
int fd, size_t byteSize)
|
|
{
|
|
return getEngine()->newExternalBuffer(fdType, fd, byteSize)->toUser();
|
|
}
|
|
|
|
Ref<Buffer> Device::newExternalUserBuffer(ExternalMemoryTypeFlags handleType,
|
|
void* handle, const void* name, size_t byteSize)
|
|
{
|
|
return getEngine()->newExternalBuffer(handleType, handle, name, byteSize)->toUser();
|
|
}
|
|
|
|
Ref<Semaphore> Device::newExternalSemaphore(ExternalSemaphoreTypeFlags fdType, int fd)
|
|
{
|
|
return getEngine()->newExternalSemaphore(fdType, fd);
|
|
}
|
|
|
|
Ref<Semaphore> Device::newExternalSemaphore(ExternalSemaphoreTypeFlags handleType,
|
|
void* handle, const void* name)
|
|
{
|
|
return getEngine()->newExternalSemaphore(handleType, handle, name);
|
|
}
|
|
|
|
void Device::submitSignalSemaphores(Semaphore* const* semaphores,
|
|
const uint64_t* values,
|
|
int numSemaphores)
|
|
{
|
|
getEngine()->submitSignalSemaphores(semaphores, values, numSemaphores);
|
|
}
|
|
|
|
void Device::submitWaitSemaphores(Semaphore* const* semaphores,
|
|
const uint64_t* values,
|
|
const uint32_t* timeoutsMs,
|
|
int numSemaphores)
|
|
{
|
|
getEngine()->submitWaitSemaphores(semaphores, values, timeoutsMs, numSemaphores);
|
|
}
|
|
|
|
Ref<Filter> Device::newFilter(const std::string& type)
|
|
{
|
|
if (isVerbose(2))
|
|
std::cout << "Filter: " << type << std::endl;
|
|
|
|
Ref<Filter> filter;
|
|
|
|
if (type == "RT")
|
|
filter = makeRef<RTFilter>(this);
|
|
else if (type == "RTLightmap")
|
|
filter = makeRef<RTLightmapFilter>(this);
|
|
else
|
|
throw Exception(Error::InvalidArgument, "unknown filter type: '" + type + "'");
|
|
|
|
return filter;
|
|
}
|
|
|
|
void Device::trimScratch()
|
|
{
|
|
for (const auto& subdevice : subdevices)
|
|
subdevice->trimScratch();
|
|
}
|
|
|
|
void Device::execute(std::function<void()>&& f, SyncMode sync)
|
|
{
|
|
try
|
|
{
|
|
f();
|
|
}
|
|
catch (...)
|
|
{
|
|
// Make sure to synchronize even if an exception has been thrown
|
|
syncAndThrow(sync);
|
|
throw;
|
|
}
|
|
|
|
syncAndThrow(sync);
|
|
}
|
|
|
|
void Device::waitAndThrow()
|
|
{
|
|
wait();
|
|
|
|
// If an asynchronous error was stored, throw it now
|
|
std::lock_guard<std::mutex> asyncErrorLock(asyncErrorMutex);
|
|
if (asyncError.code != Error::None)
|
|
{
|
|
const Error code = asyncError.code;
|
|
const std::string message = std::move(asyncError.message);
|
|
asyncError = {}; // clear the error
|
|
throw Exception(code, message);
|
|
}
|
|
}
|
|
|
|
void Device::syncAndThrow(SyncMode sync)
|
|
{
|
|
if (sync == SyncMode::Blocking)
|
|
waitAndThrow();
|
|
else
|
|
flush();
|
|
}
|
|
|
|
OIDN_NAMESPACE_END
|