From 9b80aeaee18a2192b05e6936e6f1e372b634ece5 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Mon, 11 May 2026 02:52:05 +0800 Subject: [PATCH] Fix macOS build --- CMakeLists.txt | 15 +++ src/OpenColorIO/CMakeLists.txt | 24 ++++- src/OpenColorIO/CPUInfo.cpp | 11 +++ src/OpenColorIO/Platform.h | 9 +- src/OpenColorIO/SystemMonitor_macos.cpp | 95 ++++++++----------- .../fileformats/FileFormatIridasLook.cpp | 4 +- src/apps/ociodisplay/main.cpp | 14 +-- src/libutils/oglapphelpers/CMakeLists.txt | 17 +++- src/libutils/oglapphelpers/glsl.cpp | 6 +- src/libutils/oglapphelpers/oglapp.cpp | 7 +- src/utils/NumberUtils.h | 2 +- tests/cpu/CMakeLists.txt | 15 ++- tests/gpu/GPUUnitTest.cpp | 9 +- 13 files changed, 138 insertions(+), 90 deletions(-) diff --git CMakeLists.txt CMakeLists.txt index 5c00322b..22cbf262 100755 --- CMakeLists.txt +++ CMakeLists.txt @@ -152,6 +152,11 @@ set (OCIO_PYTHON_VERSION "" CACHE STRING option(OCIO_BUILD_JAVA "Specify whether to build java bindings" OFF) +if (APPLE) + option(OCIO_METAL_ENABLED "Compile with Metal support" OFF) + option(OCIO_USE_APPLE_GL "Use native Apple OpenGL" ON) +endif() + if (WIN32) option(OCIO_USE_WINDOWS_UNICODE "Compile with Windows Unicode support" ON) endif() @@ -230,6 +235,11 @@ elseif (APPLE) set(OCIO_BUILD_ENABLE_OPTIMIZATIONS_AVX OFF) # Turn F16C off since they are x86_64 instructions. set(OCIO_BUILD_ENABLE_OPTIMIZATIONS_F16C OFF) + else() + set(OCIO_ARCH_X86 0) + set(OCIO_BUILD_ENABLE_OPTIMIZATIONS_SSE OFF) + set(OCIO_BUILD_ENABLE_OPTIMIZATIONS_AVX OFF) + set(OCIO_BUILD_ENABLE_OPTIMIZATIONS_F16C OFF) endif() else() # Cross-compiling to another Apple architecture (x86_64, arm64, or both (universal)) @@ -260,6 +270,11 @@ elseif (APPLE) # The AVX and F16C will be compiled, but they won't used at runtime by Rosetta. set(OCIO_BUILD_ENABLE_OPTIMIZATIONS_AVX ON) set(OCIO_BUILD_ENABLE_OPTIMIZATIONS_F16C ON) + else() + set(OCIO_ARCH_X86 0) + set(OCIO_BUILD_ENABLE_OPTIMIZATIONS_SSE OFF) + set(OCIO_BUILD_ENABLE_OPTIMIZATIONS_AVX OFF) + set(OCIO_BUILD_ENABLE_OPTIMIZATIONS_F16C OFF) endif() endif() endif() diff --git src/OpenColorIO/CMakeLists.txt src/OpenColorIO/CMakeLists.txt index f56b6219..efecbdae 100755 --- src/OpenColorIO/CMakeLists.txt +++ src/OpenColorIO/CMakeLists.txt @@ -307,6 +307,15 @@ set(BUILD_INCLUDES ${CMAKE_CURRENT_BINARY_DIR} ) +if(APPLE) + if(OCIO_METAL_ENABLED) + add_compile_definitions(OCIO_USE_METAL) + endif() + if(OCIO_USE_APPLE_GL) + add_compile_definitions(OCIO_USE_APPLE_GL) + endif() +endif() + target_include_directories(OpenColorIO PUBLIC "$" @@ -333,13 +342,20 @@ if(OCIO_USE_SIMD AND OCIO_USE_SSE2NEON AND COMPILER_SUPPORTS_SSE_WITH_SSE2NEON) endif() if(APPLE) - target_link_libraries(OpenColorIO - PRIVATE + if(OCIO_METAL_ENABLED) + target_link_libraries(OpenColorIO + PRIVATE "-framework ColorSync" "-framework CoreFoundation" "-framework CoreGraphics" - "-framework IOKit" - ) + "-framework IOKit") + else() + target_link_libraries(OpenColorIO + PRIVATE + "-framework ApplicationServices" + "-framework Carbon" + "-framework IOKit") + endif() endif() if(NOT BUILD_SHARED_LIBS) diff --git src/OpenColorIO/CPUInfo.cpp src/OpenColorIO/CPUInfo.cpp index edf34179..8f95c0a0 100644 --- src/OpenColorIO/CPUInfo.cpp +++ src/OpenColorIO/CPUInfo.cpp @@ -210,6 +210,17 @@ CPUInfo::CPUInfo() } } +#elif defined(__POWERPC__) + +CPUInfo::CPUInfo() // Unknown Processor +{ + flags = 0; + memset(name, 0, sizeof(name)); + memset(vendor, 0, sizeof(vendor)); + snprintf(name, sizeof(name), "%s", "PowerPC"); + snprintf(vendor, sizeof(vendor), "%s", "Apple"); +} + #else CPUInfo::CPUInfo() // Unknown Processor diff --git src/OpenColorIO/Platform.h src/OpenColorIO/Platform.h index 67413c76..fd16a6ab 100644 --- src/OpenColorIO/Platform.h +++ src/OpenColorIO/Platform.h @@ -49,9 +49,12 @@ typedef ostringstream tostringstream; namespace OCIO_NAMESPACE { -// TODO: Add proper endian detection using architecture / compiler mojo -// In the meantime, hardcode to x86 -#define OCIO_LITTLE_ENDIAN 1 // This is correct on x86 +#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ + __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + #define OCIO_BIG_ENDIAN 1 +#else + #define OCIO_LITTLE_ENDIAN 1 +#endif namespace Platform { diff --git src/OpenColorIO/SystemMonitor_macos.cpp src/OpenColorIO/SystemMonitor_macos.cpp index 4b212e68..de5039bb 100644 --- src/OpenColorIO/SystemMonitor_macos.cpp +++ src/OpenColorIO/SystemMonitor_macos.cpp @@ -1,16 +1,14 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright Contributors to the OpenColorIO Project. +// Modified for macOS 10.6 SDK compatibility #if !defined(__APPLE__) - #error The file is for the macOS platform only. - #endif - -#include -#include +#include +#include #include #include "Logging.h" @@ -19,10 +17,8 @@ namespace OCIO_NAMESPACE { - static constexpr char ErrorMsg[] { "Problem obtaining monitor profile information from operating system." }; - // Some variables must be released. template struct Guard @@ -52,75 +48,64 @@ struct Guard std::string GetICCProfilePath(CGDirectDisplayID dispId) { - CFUUIDRef displayUUID = CGDisplayCreateUUIDFromDisplayID(dispId); - Guard uuid(displayUUID); + // macOS 10.6 compatibility: + // Use deprecated ColorSync Manager API instead of modern ColorSync API + // (CGDisplayCreateUUIDFromDisplayID and ColorSyncDeviceCopyDeviceInfo don't exist in 10.6) + + CMProfileRef cmProfile = nullptr; + + // Get the ColorSync profile for the display using deprecated API + CMError err = CMGetProfileByAVID((CMDisplayIDType)dispId, &cmProfile); - if (!displayUUID) + if (err != noErr || cmProfile == nullptr) { throw Exception(ErrorMsg); } - CFDictionaryRef displayInfo = ColorSyncDeviceCopyDeviceInfo(kColorSyncDisplayDeviceClass, displayUUID); - Guard info(displayInfo); + // Get the profile location + CMProfileLocation profileLoc; - uuid.release(); + // In 10.6, CMGetProfileLocation takes only 2 parameters (not 3) + err = CMGetProfileLocation(cmProfile, &profileLoc); - if (!displayInfo) + if (err != noErr) { + CMCloseProfile(cmProfile); throw Exception(ErrorMsg); } - CFDictionaryRef factoryInfo - = (CFDictionaryRef)CFDictionaryGetValue(displayInfo, kColorSyncFactoryProfiles); - if (!factoryInfo) - { - throw Exception(ErrorMsg); - } + char path[PATH_MAX]; + bool gotPath = false; - CFStringRef defaultProfileID - = (CFStringRef)CFDictionaryGetValue(factoryInfo, kColorSyncDeviceDefaultProfileID); - if (!defaultProfileID) + // In 10.6, profile locations use cmFileBasedProfile (not cmPathBasedProfile) + if (profileLoc.locType == cmFileBasedProfile) { - throw Exception(ErrorMsg); - } + // Convert FSSpec to FSRef, then to POSIX path + FSRef fsRef; + OSStatus status = FSpMakeFSRef(&profileLoc.u.fileLoc.spec, &fsRef); - CFURLRef profileURL; - CFDictionaryRef customProfileInfo - = (CFDictionaryRef)CFDictionaryGetValue(displayInfo, kColorSyncCustomProfiles); - if (customProfileInfo) - { - profileURL = (CFURLRef)CFDictionaryGetValue(customProfileInfo, defaultProfileID); - if (!profileURL) + if (status == noErr) { - throw Exception(ErrorMsg); + status = FSRefMakePath(&fsRef, (UInt8*)path, PATH_MAX); + if (status == noErr) + { + gotPath = true; + } } } - else - { - CFDictionaryRef factoryProfileInfo - = (CFDictionaryRef)CFDictionaryGetValue(factoryInfo, defaultProfileID); - if (!factoryProfileInfo) - { - throw Exception(ErrorMsg); - } - profileURL - = (CFURLRef)CFDictionaryGetValue(factoryProfileInfo, kColorSyncDeviceProfileURL); - if (!profileURL) - { - throw Exception(ErrorMsg); - } - } + CMCloseProfile(cmProfile); - char path[PATH_MAX]; - const bool result - = CFURLGetFileSystemRepresentation(profileURL, true, (UInt8 *)path, PATH_MAX); + if (!gotPath) + { + throw Exception(ErrorMsg); + } - return result ? std::string(path) : throw Exception(ErrorMsg); + return std::string(path); } // Some references for 'Quartz Display Services' part of the 'Core Graphics' framework: -// * https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/QuartzDisplayServicesConceptual/Introduction/Introduction.html#//apple_ref/doc/uid/TP40004245-SW1 +// * https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/QuartzDisplayServicesConceptual/Introduction/Introduction.html#//apple_ref/doc/uid/TP40004245-SW1 // * https://developer.apple.com/documentation/coregraphics/quartz_display_services?language=objc void SystemMonitorsImpl::getAllMonitors() @@ -130,7 +115,7 @@ void SystemMonitorsImpl::getAllMonitors() // TODO: Needs to have all displays with a status to indicate the active ones? // CGGetActiveDisplayList provides only the list of displays that are active (i.e. drawable). - // Note: CGGetOnlineDisplayList provides the list of all displays that are online (active, + // Note: CGGetOnlineDisplayList provides the list of all displays that are online (active, // mirrored, or sleeping). // Get the number of active monitors. @@ -192,7 +177,7 @@ void SystemMonitorsImpl::getAllMonitors() const CFIndex bufferSize = CFStringGetLength(values[0]) + 1; // +1 for null termination std::vector buffer(bufferSize); - // Return false if the buffer is too small or if the conversion fails. + // Return false if the buffer is too small or if the conversion fails. if (CFStringGetCString(values[0], buffer.data(), buffer.size(), kCFStringEncodingUTF8)) { // Build a name using the vendor information. diff --git src/OpenColorIO/fileformats/FileFormatIridasLook.cpp src/OpenColorIO/fileformats/FileFormatIridasLook.cpp index 0ba209a9..2798657f 100755 --- src/OpenColorIO/fileformats/FileFormatIridasLook.cpp +++ src/OpenColorIO/fileformats/FileFormatIridasLook.cpp @@ -118,13 +118,15 @@ bool hexasciitofloat(float& fval, const char * ascii) fvalbytes[1] = (unsigned char) (asciinums[3] | (asciinums[2] << 4)); fvalbytes[2] = (unsigned char) (asciinums[5] | (asciinums[4] << 4)); fvalbytes[3] = (unsigned char) (asciinums[7] | (asciinums[6] << 4)); -#else +#elif OCIO_BIG_ENDIAN // Since incoming values are little endian, and we're on big endian // flip the byte order fvalbytes[3] = (unsigned char) (asciinums[1] | (asciinums[0] << 4)); fvalbytes[2] = (unsigned char) (asciinums[3] | (asciinums[2] << 4)); fvalbytes[1] = (unsigned char) (asciinums[5] | (asciinums[4] << 4)); fvalbytes[0] = (unsigned char) (asciinums[7] | (asciinums[6] << 4)); +#else + #error "Endianness is unknown." #endif return true; } diff --git src/apps/ociodisplay/main.cpp src/apps/ociodisplay/main.cpp index ed7f0975..f00b8a8f 100644 --- src/apps/ociodisplay/main.cpp +++ src/apps/ociodisplay/main.cpp @@ -16,7 +16,7 @@ #include namespace OCIO = OCIO_NAMESPACE; -#ifdef __APPLE__ +#if defined(__APPLE__) && defined(OCIO_USE_APPLE_GL) #include #include #include @@ -28,7 +28,7 @@ namespace OCIO = OCIO_NAMESPACE; #include #include #endif -#if __APPLE__ +#if defined(__APPLE__) && defined(OCIO_USE_METAL) #include "metalapp.h" #endif @@ -39,7 +39,7 @@ namespace OCIO = OCIO_NAMESPACE; bool g_verbose = false; bool g_gpulegacy = false; bool g_gpuinfo = false; -#if __APPLE__ +#if defined(__APPLE__) && defined(OCIO_USE_METAL) bool g_useMetal = false; #endif @@ -403,7 +403,7 @@ void UpdateOCIOGLState() // Set the shader context. OCIO::GpuShaderDescRcPtr shaderDesc = OCIO::GpuShaderDesc::CreateShaderDesc(); shaderDesc->setLanguage( -#if __APPLE__ +#if defined(__APPLE__) && defined(OCIO_USE_METAL) g_useMetal ? OCIO::GPU_LANGUAGE_MSL_2_0 : #endif OCIO::GPU_LANGUAGE_GLSL_1_2); @@ -614,7 +614,7 @@ void parseArguments(int argc, char **argv) { g_gpuinfo = true; } -#if __APPLE__ +#if defined(__APPLE__) && defined(OCIO_USE_METAL) else if (0 == strcmp(argv[i], "-metal")) { g_useMetal = true; @@ -631,7 +631,7 @@ void parseArguments(int argc, char **argv) std::cout << " -v : displays the color space information" << std::endl; std::cout << " -gpulegacy : use the legacy (i.e. baked) GPU color processing" << std::endl; std::cout << " -gpuinfo : output the OCIO shader program" << std::endl; -#if __APPLE__ +#if defined(__APPLE__) && defined(OCIO_USE_METAL) std::cout << " -metal : use metal OCIO shader backend " << std::endl; #endif std::cout << std::endl; @@ -650,7 +650,7 @@ int main(int argc, char **argv) try { -#if __APPLE__ +#if defined(__APPLE__) && defined(OCIO_USE_METAL) if (g_useMetal) { g_oglApp = std::make_shared("ociodisplay", 512, 512); diff --git src/libutils/oglapphelpers/CMakeLists.txt src/libutils/oglapphelpers/CMakeLists.txt index cef50ede..657a9c82 100644 --- src/libutils/oglapphelpers/CMakeLists.txt +++ src/libutils/oglapphelpers/CMakeLists.txt @@ -15,7 +15,7 @@ set(INCLUDES oglapp.h ) -if(APPLE) +if(APPLE AND OCIO_METAL_ENABLED) list(APPEND SOURCES msl.mm @@ -100,15 +100,22 @@ else() endif() if(APPLE) - target_link_libraries(oglapphelpers - PRIVATE + if(OCIO_METAL_ENABLED) + target_link_libraries(oglapphelpers + PRIVATE "-framework ColorSync" "-framework CoreFoundation" "-framework CoreGraphics" "-framework IOKit" "-framework Metal" - "-framework CoreVideo" - ) + "-framework CoreVideo") + else() + target_link_libraries(oglapphelpers + PRIVATE + "-framework ApplicationServices" + "-framework Carbon" + "-framework IOKit") + endif() endif() if(${OCIO_EGL_HEADLESS}) diff --git src/libutils/oglapphelpers/glsl.cpp src/libutils/oglapphelpers/glsl.cpp index 791648e6..a9228976 100644 --- src/libutils/oglapphelpers/glsl.cpp +++ src/libutils/oglapphelpers/glsl.cpp @@ -2,7 +2,7 @@ // Copyright Contributors to the OpenColorIO Project. -#ifdef __APPLE__ +#if defined(__APPLE__) && defined(OCIO_USE_APPLE_GL) #include #include @@ -37,7 +37,7 @@ bool GetGLError(std::string & error) const GLenum glErr = glGetError(); if(glErr!=GL_NO_ERROR) { -#ifdef __APPLE__ +#if defined(__APPLE__) && defined(OCIO_USE_APPLE_GL) // Unfortunately no gluErrorString equivalent on Mac. error = "OpenGL Error"; #else @@ -552,7 +552,7 @@ unsigned OpenGLBuilder::GetTextureMaxWidth() } } -#ifndef __APPLE__ +#if defined(__APPLE__) && defined(OCIO_USE_APPLE_GL) // // In case of Linux, if glTexImage2D() succeeds // glGetTexLevelParameteriv() could fail. diff --git src/libutils/oglapphelpers/oglapp.cpp src/libutils/oglapphelpers/oglapp.cpp index 32528a55..96ac8910 100644 --- src/libutils/oglapphelpers/oglapp.cpp +++ src/libutils/oglapphelpers/oglapp.cpp @@ -6,7 +6,7 @@ #include #include -#ifdef __APPLE__ +#if defined(__APPLE__) && defined(OCIO_USE_APPLE_GL) #include #include @@ -238,7 +238,8 @@ void OglApp::printGLInfo() const noexcept void OglApp::setupCommon() { -#ifndef __APPLE__ +// Perhaps allow GL 2.0? +#if !defined(__APPLE__) || !defined(OCIO_USE_APPLE_GL) glewInit(); // TO DO: Find out why glewInit() != GLEW_OK @@ -253,7 +254,7 @@ void OglApp::setupCommon() glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment -#ifndef __APPLE__ +#if !defined(__APPLE__) || !defined(OCIO_USE_APPLE_GL) glClampColor(GL_CLAMP_READ_COLOR, GL_FALSE); // glClampColor(GL_CLAMP_VERTEX_COLOR, GL_FALSE); // avoid any kind of clamping glClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE); // diff --git src/utils/NumberUtils.h src/utils/NumberUtils.h index e6b273f4..690754e1 100644 --- src/utils/NumberUtils.h +++ src/utils/NumberUtils.h @@ -178,7 +178,7 @@ really_inline from_chars_result from_chars(const char *first, const char *last, #else tempval = _strtof_l(first, &endptr, loc.local); #endif -#elif __APPLE__ +#elif defined(__APPLE__) // On OSX, strtod_l is for some reason drastically faster than strtof_l. tempval = static_cast(::strtod_l(first, &endptr, loc.local)); #else diff --git tests/cpu/CMakeLists.txt tests/cpu/CMakeLists.txt index 12fd06c1..e2dff9ff 100755 --- tests/cpu/CMakeLists.txt +++ tests/cpu/CMakeLists.txt @@ -47,13 +47,20 @@ function(add_ocio_test NAME SOURCES PRIVATE_INCLUDES) if(APPLE) # Frameworks needed to access the ICC monitor profile. - target_link_libraries(${TEST_BINARY} - PRIVATE + if(OCIO_METAL_ENABLED) + target_link_libraries(${TEST_BINARY} + PRIVATE "-framework ColorSync" "-framework CoreFoundation" "-framework CoreGraphics" - "-framework IOKit" - ) + "-framework IOKit") + else() + target_link_libraries(${TEST_BINARY} + PRIVATE + "-framework ApplicationServices" + "-framework Carbon" + "-framework IOKit") + endif() endif(APPLE) if(PRIVATE_INCLUDES) diff --git tests/gpu/GPUUnitTest.cpp tests/gpu/GPUUnitTest.cpp index 65081312..da94ad5a 100644 --- tests/gpu/GPUUnitTest.cpp +++ tests/gpu/GPUUnitTest.cpp @@ -16,7 +16,7 @@ #include "utils/StringUtils.h" #include "oglapp.h" -#if __APPLE__ +#if defined(__APPLE__) && defined(OCIO_USE_METAL) #include "metalapp.h" #endif @@ -226,9 +226,10 @@ namespace // It means to generate the input values. -#if __APPLE__ && __aarch64__ +#if defined(__APPLE__) && (defined(__aarch64__) || (__POWERPC__)) // The Apple M1 chip handles differently the Nan and Inf processing introducing // differences with CPU processing. + // Perhaps include PowerPC too. const bool testNaN = false; const bool testInfinity = false; #else @@ -594,7 +595,7 @@ int main(int argc, const char ** argv) { if(useMetalRenderer) { -#if __APPLE__ +#if defined(__APPLE__) && defined(OCIO_USE_METAL) app = OCIO::MetalApp::CreateMetalGlApp("GPU tests - Metal", 10, 10); #else std::cerr << std::endl << "'GPU tests - Metal' is not supported" << std::endl; @@ -662,7 +663,7 @@ int main(int argc, const char ** argv) test->setVerbose(verbose); test->setShadingLanguage( -#if __APPLE__ +#if defined(__APPLE__) && defined(OCIO_USE_METAL) useMetalRenderer ? OCIO::GPU_LANGUAGE_MSL_2_0 : #endif -- 2.54.0