option(RENDERIVE_BUILD_TESTS "Build Renderive test targets" ON) option(RENDERIVE_ENABLE_ASAN "Build Renderive targets with AddressSanitizer" OFF) option(RENDERIVE_ENABLE_TSAN "Build Renderive targets with ThreadSanitizer" OFF) option(RENDERIVE_MEMORY_DOMAIN_STATS "Enable Renderive memory domain statistics" ON) option(RENDERIVE_MEMORY_GLOBAL_POOL "Enable Renderive small object synchronized pool" ON) option(RENDERIVE_FRAME_ARENA_GROW "Enable Renderive frame arena high-water growth" ON) set(renderive_dependencies global::blend2d ) if (RENDERIVE_BUILD_TESTS) list(APPEND renderive_dependencies global::GTest) endif () rcl_add_dependency_action_targets(renderive_env ${renderive_dependencies}) library_is_installed_with_rely(renderive_dependencies_installed ${renderive_dependencies}) if (NOT renderive_dependencies_installed) message(STATUS "============== Renderive dependencies are not installed, build renderive_env first") return() endif () find_package(blend2d CONFIG REQUIRED) if (NOT TARGET blend2d::blend2d) message(FATAL_ERROR "Renderive dependency error: blend2d::blend2d was not found") endif () if (RENDERIVE_BUILD_TESTS) find_package(GTest CONFIG REQUIRED) if (NOT TARGET GTest::gtest AND NOT TARGET GTest::GTest) message(FATAL_ERROR "Renderive dependency error: GTest target was not found") endif () endif () if (RENDERIVE_ENABLE_ASAN AND RENDERIVE_ENABLE_TSAN) message(FATAL_ERROR "Renderive cannot enable ASan and TSan simultaneously") endif () if (RENDERIVE_ENABLE_ASAN AND MSVC) string(REPLACE "/RTC1" "" __PSC_CMAKE_CXX_FLAGS_DEBUG "${__PSC_CMAKE_CXX_FLAGS_DEBUG}") string(REPLACE "/RTC1" "" __PSC_CMAKE_C_FLAGS_DEBUG "${__PSC_CMAKE_C_FLAGS_DEBUG}") set(__PSC_CMAKE_CXX_FLAGS_DEBUG "${__PSC_CMAKE_CXX_FLAGS_DEBUG}" CACHE STRING "" FORCE) set(__PSC_CMAKE_C_FLAGS_DEBUG "${__PSC_CMAKE_C_FLAGS_DEBUG}" CACHE STRING "" FORCE) add_library(Renderive_ASAN_Options INTERFACE) target_compile_options(Renderive_ASAN_Options INTERFACE /fsanitize=address) target_link_options(Renderive_ASAN_Options INTERFACE /fsanitize=address /INCREMENTAL:NO) endif () function(renderive_apply_sanitizer target) get_target_property(target_type ${target} TYPE) if (RENDERIVE_ENABLE_ASAN) if (MSVC) target_link_libraries(${target} PRIVATE Renderive_ASAN_Options) if (target_type STREQUAL "STATIC_LIBRARY") target_link_libraries(${target} INTERFACE Renderive_ASAN_Options) endif () else () target_compile_options(${target} PRIVATE -fsanitize=address -fno-omit-frame-pointer) if (target_type STREQUAL "STATIC_LIBRARY") target_link_options(${target} INTERFACE -fsanitize=address) else () target_link_options(${target} PRIVATE -fsanitize=address) endif () endif () endif () if (RENDERIVE_ENABLE_TSAN) if (MSVC) message(FATAL_ERROR "Renderive TSan is not supported by MSVC") endif () target_compile_options(${target} PRIVATE -fsanitize=thread -fno-omit-frame-pointer) if (target_type STREQUAL "STATIC_LIBRARY") target_link_options(${target} INTERFACE -fsanitize=thread) else () target_link_options(${target} PRIVATE -fsanitize=thread) endif () endif () endfunction() function(renderive_enable_qt_target target) set_target_properties(${target} PROPERTIES AUTOMOC ON AUTOUIC ON AUTORCC ON ) endfunction() function(renderive_assert_core_boundary) foreach(path IN LISTS ARGN) if (IS_DIRECTORY "${path}") continue() endif () file(READ "${path}" content) if (content MATCHES "#include[ \t]*" OR content MATCHES "#include[ \t]*" OR content MATCHES "QPainter|QImage|QPen|QBrush|QColor|QFont|QString|QPointF|QRectF|QSize|QMouseEvent|QWheelEvent|QKeyEvent|Qt::Orientation|Qt::Alignment|Data_Buffer_Role|_p\\.h") message(FATAL_ERROR "Renderive_Core boundary violation in ${path}") endif () endforeach () endfunction() set(renderive_root "${CMAKE_CURRENT_LIST_DIR}/Renderive") set(renderive_core_root "${renderive_root}/Core") set(renderive_widget_root "${CMAKE_CURRENT_LIST_DIR}/Widget") set(renderive_demo_root "${CMAKE_CURRENT_LIST_DIR}/Demo_Gallery") file(GLOB_RECURSE renderive_core_sources CONFIGURE_DEPENDS "${renderive_core_root}/*.cpp" "${renderive_core_root}/*.h" ) renderive_assert_core_boundary(${renderive_core_sources}) add_library(Renderive_Core STATIC ${renderive_core_sources}) target_include_directories(Renderive_Core PUBLIC "${CMAKE_CURRENT_LIST_DIR}") target_link_libraries(Renderive_Core PUBLIC blend2d::blend2d ) renderive_apply_sanitizer(Renderive_Core) set(ver 5.14.2) set(qt_candidates "D:/Qt/Qt${ver}" "C:/Qt/Qt${ver}" "D:/Qt/${ver}" "C:/Qt/${ver}" ) set(t msvc2017_64) select_first_existing_directory(qb ${qt_candidates}) set(Qt5_BaseDIR "${qb}/${ver}/${t}") set(Qt5_DIR "${Qt5_BaseDIR}/lib/cmake/Qt5") set(Qt5_Deploy "${Qt5_BaseDIR}/bin/windeployqt.exe") message("Qt5_DIR ${Qt5_DIR}") find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets Svg Xml Network Sql 3DCore 3DRender 3DInput 3DExtras Quick 3DQuickScene2D QuickWidgets Qml PrintSupport Multimedia SerialPort CONFIG ) # Qt5.cmake adds a directory-level Qt source include path. Keep it out of the # Core compile command; Core only needs its own public headers and Blend2D. set_target_properties(Renderive_Core PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_CURRENT_LIST_DIR}" ) set(renderive_qt_public_libraries Qt5::Widgets Qt5::Core Qt5::Svg Qt5::Xml Qt5::PrintSupport Qt5::Multimedia Qt5::QuickWidgets Core_Static Renderive_Core ) find_package(OpenGL QUIET) if (OpenGL_FOUND) list(APPEND renderive_qt_public_libraries OpenGL::GL) endif () file(GLOB_RECURSE renderive_sources CONFIGURE_DEPENDS "${renderive_root}/*.c" "${renderive_root}/*.cpp" "${renderive_root}/*.h" "${renderive_root}/*.qrc" ) list(FILTER renderive_sources EXCLUDE REGEX "main\\.cpp$") list(FILTER renderive_sources EXCLUDE REGEX "Performance_Shower(_p)?\\.(cpp|h)$") list(FILTER renderive_sources EXCLUDE REGEX "[/\\\\]Core[/\\\\]") add_library(Renderive STATIC ${renderive_sources}) target_include_directories(Renderive PUBLIC "${CMAKE_CURRENT_LIST_DIR}") target_link_libraries(Renderive PUBLIC ${renderive_qt_public_libraries}) target_compile_definitions(Renderive PUBLIC RENDERIVE_MEMORY_DOMAIN_STATS=$ RENDERIVE_MEMORY_GLOBAL_POOL=$ RENDERIVE_FRAME_ARENA_GROW=$ ) renderive_enable_qt_target(Renderive) renderive_apply_sanitizer(Renderive) set(renderive_diagnostics_sources "${renderive_root}/Diagnostics/Performance_Shower.h" "${renderive_root}/plottable/Performance_Shower.cpp" "${renderive_root}/plottable/Performance_Shower_p.h" "${renderive_root}/Core/Telemetry/Csv_Telemetry_Sink.h" ) add_library(Renderive_Diagnostics STATIC ${renderive_diagnostics_sources}) target_include_directories(Renderive_Diagnostics PUBLIC "${CMAKE_CURRENT_LIST_DIR}") target_link_libraries(Renderive_Diagnostics PUBLIC Renderive Renderive_Core) renderive_enable_qt_target(Renderive_Diagnostics) renderive_apply_sanitizer(Renderive_Diagnostics) file(GLOB_RECURSE renderive_widget_sources CONFIGURE_DEPENDS "${renderive_widget_root}/*.c" "${renderive_widget_root}/*.cpp" "${renderive_widget_root}/*.h" "${renderive_widget_root}/*.hpp" "${renderive_widget_root}/*.qrc" ) add_library(Renderive_Widget STATIC ${renderive_widget_sources}) target_include_directories(Renderive_Widget PUBLIC "${CMAKE_CURRENT_LIST_DIR}") target_link_libraries(Renderive_Widget PUBLIC Renderive) renderive_enable_qt_target(Renderive_Widget) renderive_apply_sanitizer(Renderive_Widget) if (RENDERIVE_BUILD_TESTS) enable_testing() if (TARGET GTest::gtest) set(renderive_gtest_library GTest::gtest) else () set(renderive_gtest_library GTest::GTest) endif () function(renderive_add_gtest target test_name source) add_executable(${target} EXCLUDE_FROM_ALL "${CMAKE_CURRENT_LIST_DIR}/tests/${source}") target_link_libraries(${target} PRIVATE Renderive ${renderive_gtest_library} ${ARGN} ) renderive_apply_sanitizer(${target}) add_test(NAME Renderive.${test_name} COMMAND ${target}) endfunction() function(renderive_add_core_gtest target test_name source) add_executable(${target} EXCLUDE_FROM_ALL "${CMAKE_CURRENT_LIST_DIR}/tests/${source}") target_link_libraries(${target} PRIVATE Renderive_Core ${renderive_gtest_library} ${ARGN} ) renderive_apply_sanitizer(${target}) add_test(NAME Renderive.${test_name} COMMAND ${target}) endfunction() renderive_add_core_gtest( Renderive_Core_Axis_Transform Axis_Transform Axis_Transform.cpp ) renderive_add_core_gtest( Renderive_Core_Batches_2_4 Core_Batches_2_4 Core_Batches_2_4.cpp ) renderive_add_gtest( Renderive_ASan_Runtime_Smoke ASan_Runtime_Smoke ASan_Runtime_Smoke.cpp ) renderive_add_gtest( Renderive_Update_Completion Update_Completion Update_Completion.cpp ) renderive_add_gtest( Renderive_Memory_Default Memory_Default Memory_Default.cpp ) renderive_add_gtest( Renderive_Memory_Callbacks Memory_Callbacks Memory_Callbacks.cpp ) renderive_add_gtest( Renderive_Memory_Failure Memory_Failure Memory_Failure.cpp ) renderive_add_gtest( Renderive_Memory_Late_Config Memory_Late_Config Memory_Late_Config.cpp ) renderive_add_gtest( Renderive_Memory_Plot_Late_Config Memory_Plot_Late_Config Memory_Plot_Late_Config.cpp ) set_tests_properties(Renderive.Memory_Plot_Late_Config PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" ) renderive_add_gtest( Renderive_Timeline_Stream_Consistency Timeline_Stream_Consistency Timeline_Stream_Consistency.cpp ) renderive_add_gtest( Renderive_Memory_Data_Path_Stress Memory_Data_Path_Stress Memory_Data_Path_Stress.cpp ) set_tests_properties(Renderive.Memory_Data_Path_Stress PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen;RENDERIVE_PERFORMANCE_LOG=0" TIMEOUT 20 ) renderive_add_gtest( Renderive_Renderable_Lifecycle_Stress Renderable_Lifecycle_Stress Renderable_Lifecycle_Stress.cpp ) set_tests_properties(Renderive.Renderable_Lifecycle_Stress PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen;RENDERIVE_PERFORMANCE_LOG=0" TIMEOUT 20 ) renderive_add_gtest( Renderive_Frame_Scheduler_Feedback Frame_Scheduler_Feedback Frame_Scheduler_Feedback.cpp Renderive_Diagnostics ) set_tests_properties(Renderive.Frame_Scheduler_Feedback PROPERTIES ENVIRONMENT "RENDERIVE_PERFORMANCE_LOG=1;RENDERIVE_PERFORMANCE_LOG_PATH=${CMAKE_BINARY_DIR}/renderive_feedback_test_log.csv" ) renderive_add_gtest( Renderive_Performance_Shower_Interaction Performance_Shower_Interaction Performance_Shower_Interaction.cpp Renderive_Diagnostics Renderive_Widget ) set_tests_properties(Renderive.Performance_Shower_Interaction PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen;RENDERIVE_PERFORMANCE_LOG=0" TIMEOUT 12 ) renderive_add_gtest( Renderive_Multithread_Input_Stress Multithread_Input_Stress Multithread_Input_Stress.cpp ) set_tests_properties(Renderive.Multithread_Input_Stress PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen;RENDERIVE_PERFORMANCE_LOG=0" TIMEOUT 15 ) endif () file(GLOB_RECURSE renderive_demo_sources CONFIGURE_DEPENDS "${renderive_demo_root}/*.c" "${renderive_demo_root}/*.cpp" "${renderive_demo_root}/*.h" "${renderive_demo_root}/*.hpp" ) add_library(Demo_Gallery_Lib STATIC ${renderive_demo_sources}) target_link_libraries(Demo_Gallery_Lib PUBLIC Renderive Renderive_Diagnostics Renderive_Widget ) renderive_apply_sanitizer(Demo_Gallery_Lib) add_executable(Demo_Gallery "${CMAKE_CURRENT_LIST_DIR}/demo_gallery_main.cpp") target_link_libraries(Demo_Gallery PRIVATE Demo_Gallery_Lib) renderive_enable_qt_target(Demo_Gallery) renderive_apply_sanitizer(Demo_Gallery)