Add custom viewport color correction (sRGB/OCIO), bypassing HdxColorCorrectionTask
Hydra's HdxColorCorrectionTask rendered prims black in OCIO mode and could corrupt the GlfDrawTarget bind stack on failure (skipping Unbind), blacking out every later frame including sRGB. Replace it with our own GL post-process: the scene renders linear (RGBA16F) and is corrected by a fullscreen shader -- linear->sRGB encode, or OCIO via the OCIO 2.1 GPU API (GpuShaderDesc plus uploaded 1D/3D LUT textures). OCIO build failures fall back to sRGB (never black) and USD diagnostics are routed to the app log. - core: ViewportColorCorrector + ApplyViewportColorCorrection in UsdSceneRenderer - utils: OcioConfigParser enumerates displays/views/colorspaces/looks from $OCIO - ui: gear-menu OCIO controls (ViewportTile) + per-viewport persistence (ViewportPanel) - Application: point $OCIO at the bundled ACES 1.2 config - CMake: link/copy OpenColorIO, download ACES 1.2 config; plus hdCycles build config (disable OpenVDB/Embree, fix TBB/OpenSubdiv/Imath dirs, exclude CRT DLLs) - main: pre-flight plugin DLL load check to skip plugins with missing deps Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+52
-3
@@ -1,6 +1,7 @@
|
||||
#include "ui/Application.h"
|
||||
#include "utils/Logger.h"
|
||||
#include <pxr/base/plug/registry.h>
|
||||
#include <cstdio>
|
||||
#include <exception>
|
||||
#include <Windows.h>
|
||||
#include <string>
|
||||
@@ -37,16 +38,64 @@ static void SetUsdPluginPath() {
|
||||
FindClose(hFind);
|
||||
}
|
||||
|
||||
if (!pluginPaths.empty()) {
|
||||
// Pre-flight: attempt to load each plugin DLL before registering it.
|
||||
// This catches missing dependencies (e.g. sycl8.dll → Intel GPU drivers)
|
||||
// gracefully and shows our own warning rather than a cryptic TF_ERROR.
|
||||
std::vector<std::string> checkedPaths;
|
||||
for (const auto& infoPath : pluginPaths) {
|
||||
// Derive the DLL path from the plugInfo.json location:
|
||||
// <plugin>/resources/plugInfo.json → ../<plugin>.dll
|
||||
// e.g. usd/hdCycles/resources/plugInfo.json → usd/hdCycles.dll
|
||||
size_t resPos = infoPath.rfind("\\resources\\plugInfo.json");
|
||||
if (resPos != std::string::npos) {
|
||||
std::string pluginDir = infoPath.substr(0, resPos);
|
||||
size_t dirSlash = pluginDir.rfind('\\');
|
||||
std::string pluginName = (dirSlash != std::string::npos)
|
||||
? pluginDir.substr(dirSlash + 1) : pluginDir;
|
||||
std::string dllPath = pluginPath + "\\" + pluginName + ".dll";
|
||||
DWORD dllAttrs = GetFileAttributesA(dllPath.c_str());
|
||||
if (dllAttrs != INVALID_FILE_ATTRIBUTES) {
|
||||
// DLL file exists — verify it can actually be loaded.
|
||||
// No LOAD_WITH_ALTERED_SEARCH_PATH: keep the application
|
||||
// directory (exe dir, where embree4.dll etc. live) in the
|
||||
// DLL search path so transitive deps resolve correctly.
|
||||
HMODULE h = LoadLibraryA(dllPath.c_str());
|
||||
if (!h) {
|
||||
DWORD err = GetLastError();
|
||||
char msg[256] = {};
|
||||
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, err, 0, msg, static_cast<DWORD>(sizeof(msg) - 1), nullptr);
|
||||
std::string errMsg(msg);
|
||||
while (!errMsg.empty() && (errMsg.back() == '\r' || errMsg.back() == '\n'))
|
||||
errMsg.pop_back();
|
||||
char hexErr[12] = {};
|
||||
sprintf_s(hexErr, "0x%08X", static_cast<unsigned>(err));
|
||||
LOG_WARNING("Skipping plugin " + pluginName
|
||||
+ " (DLL load failed " + hexErr + "): " + errMsg);
|
||||
continue; // Skip registering this plugin
|
||||
}
|
||||
// Intentionally do NOT FreeLibrary here. Releasing the handle
|
||||
// drops the refcount to 0 and unloads the DLL; when USD's plug
|
||||
// system later loads it again DllMain re-fires, re-registering
|
||||
// any TfEnvSettings and causing "duplicate definition" warnings.
|
||||
// Keeping the handle loaded means USD's LoadLibrary is a no-op
|
||||
// (refcount bump only, no DllMain call), preventing duplicates.
|
||||
// The process holds these handles for its entire lifetime anyway.
|
||||
}
|
||||
}
|
||||
checkedPaths.push_back(infoPath);
|
||||
}
|
||||
|
||||
if (!checkedPaths.empty()) {
|
||||
auto& registry = pxr::PlugRegistry::GetInstance();
|
||||
auto registered = registry.RegisterPlugins(pluginPaths);
|
||||
auto registered = registry.RegisterPlugins(checkedPaths);
|
||||
LOG_INFO("Registered " + std::to_string(registered.size()) + " USD plugins from " + pluginPath);
|
||||
} else {
|
||||
LOG_WARNING("No USD plugins found at " + pluginPath);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int main(int /*argc*/, char* /*argv*/[]) {
|
||||
try {
|
||||
UsdLayerManager::Logger::Instance().SetLogLevel(UsdLayerManager::LogLevel::Info);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user