Skip to content

Methane Kit v0.8.2

Latest

Choose a tag to compare

@egorodet egorodet released this 27 Aug 18:26

Summary

Methane Kit v0.8.2 update restores build compatibility with the latest compilers, updates all external dependencies and fixes a large number of graphics API validation errors, thread-safety issues and runtime stability bugs, most of which were found with the newly added automated applications run test:

  • New compilers support: build was fixed for Visual Studio 2026 (MSVC 19.5+), GCC 15.2 on Ubuntu 26.04 and AppleClang from Xcode 26 on MacOS Sequoia. New VS2026-* CMake presets were added along with the existing VS2022-* presets.
  • Graphics API validation messages logging: validation and runtime messages of all three graphics APIs are now printed with the same severity and category format - with ID3D12InfoQueue1 message callback in DirectX 12, VK_EXT_debug_utils messenger in Vulkan and MTLLogState with command buffer error reporting in Metal. New test script Build/Unix/CI/RunApplicationsTest.sh runs all applications and fails on any validation or runtime error printed to the console output. It's not used in CI yet, because build environment has no GUI and GPU support.
  • Vulkan RHI stability: swap-chain image acquisition semaphore lifecycle, surface-lost recovery, runtime rendering device switching on multi-GPU systems, mutable descriptor sets copying, pipeline barrier stage masks and primitive restart on MoltenVK were fixed (close #158).
  • Thread safety: race conditions were fixed in Base::CommandQueueTracking, Vulkan::QueueFamilyReservation, Vulkan::CommandListSet and in the timestamp query pools, which caused sporadic hangs and crashes in multi-threaded rendering.

Graphics libraries

  • Base::CommandQueueTracking: GetNextExecutingCommandListSet() was replaced with PopNextExecutingCommandListSet(), which atomically pops the command list set and waits for it, eliminating the race between WaitUntilCompleted, CompleteExecution and the background execution-waiting thread; template helper ProcessExecutingCommandListSet and IsExecutingOnFrameIndex were added for the FIFO-ordered frame completion. Timestamp query pool initialization was guarded with a mutex and ICommandQueue::GetTimestampQueryPoolPtr() now returns Ptr by value instead of a reference, which could dangle.
  • Fixed logic inversion in Base::RenderCommandList::UpdateDrawingState, which incorrectly skipped tracking of the primitive type change.
  • CommandListSet::GetCombinedName() was made const and Base::CommandQueueTracking execution thread was switched to std::jthread.
  • Added Methane/StbImage.h wrapper header, which suppresses external code compiler warnings and disables SIMD in GCC debug builds, replacing ad-hoc stb_image.h inclusions in ImageLoader.cpp and AppLin.cpp.
  • Fixed self-assignment in Camera::ResetOrientation and reduced enums verbosity in QuadMesh with using enum (SonarQube issues).
  • Base::Context: lazily created default command kits were guarded with a mutex; m_requested_action and m_is_completing_initialization were replaced with atomics, with the deferred action escalated by a compare-exchange loop and cleared only when performed.
  • Base::CommandKit: lazily created command queue, lists, fences and list sets were guarded with a mutex, with the *Unlocked() helpers added for the nested access.
  • Base::CommandQueueTracking: CompleteCommandListSetExecution() does not pop the executing queue any more, because PopNextExecutingCommandListSet() already pops the command list set atomically with waiting for it.
  • Base::RenderPass: stencil attachment texture is invalidated on Update() together with the other attachment texture caches, under the mutex guarding their initialization.
  • GetFrameScissorRect() computes bounds in a signed 64-bit type and clamps them to the render attachment size, fixing the unsigned underflow of the offset and extent for a frame rect moved outside of the attachment.
  • Rhi::TextureView and Rhi::CommandListSet constructors were made explicit.

DirectX RHI

  • Debug layer message callback was registered with ID3D12InfoQueue1 to print DirectX 12 validation messages to the platform debug output and unregistered on device release.
  • Fixed resource state transitions done with the command lists of COPY type: resources are kept in Common state, which is implicitly promoted by the copy queue, fixing validation error D3D12_MESSAGE_ID_RESOURCE_BARRIER_MISMATCHING_COMMAND_LIST_TYPE.
  • Fixed RenderState pipeline description: ForcedSampleCount is left zero (error CREATEGRAPHICSPIPELINESTATE_INVALID_FORCED_SAMPLE_COUNT) and DSVFormat always matches the render pattern depth attachment format (error COMMAND_LIST_DRAW_DEPTH_STENCIL_VIEW_NOT_SET).
  • Removed assertion on the failed switch of GPU to the stable power state, which requires Windows Developer Mode enabled.

Vulkan RHI

  • Frame semaphores lifecycle: per-frame vk::Fence was removed from RenderContext::FrameSync; image acquisition now waits for completion of the render submission which consumed the image-available semaphore, satisfying VUID-vkAcquireNextImageKHR-semaphore-01779. Bounded acquisition timeout and retries count were added instead of the infinite UINT64_MAX timeout.
  • Execution-completed semaphore: CommandListSet execution-completed semaphore is created lazily and is signalled only for the command list sets targeting a specific frame buffer, fixing VUID-vkQueueSubmit-pSignalSemaphores-00067 caused by permanently signalled semaphores of non-frame command lists.
  • Surface lost recovery: swap-chain resources are released before the lost surface is destroyed (VUID-vkDestroySurfaceKHR-surface-01266) and the swap-chain is re-initialized directly to avoid recursive re-entrance to GetNextFrameBufferIndex().
  • Runtime device switching: VULKAN_HPP_DEFAULT_DISPATCHER is no longer specialized with vk::Device, because the single global dispatcher was resolving device-level entry points of the last created device and dispatched calls to a wrong ICD on multi-GPU systems. Native device handle is now updated in RenderContext::Initialize() and descriptor pools are destroyed instead of being reset, because they can not be reused with another device.
  • HLSL reflection extensions: VK_GOOGLE_HLSL_FUNCTIONALITY_1 and VK_GOOGLE_USER_TYPE device extensions were enabled and SPIRV byte code is stripped of the reflection instructions with RemoveHlslReflectionFromSpirv() when they are not supported, fixing VUID-VkShaderModuleCreateInfo-pCode-08742.
  • Mutable descriptor sets copying in ProgramBindings was fixed to iterate per-binding instead of using a single flat descriptors count, which caused out-of-bounds descriptor access with non-contiguous bindings.
  • Pipeline barriers: empty srcStageMask / dstStageMask are replaced with eTopOfPipe / eBottomOfPipe, fixing VUID-vkCmdPipelineBarrier-srcStageMask-03937 and dstStageMask-03937.
  • Primitive restart: RenderState detects VK_KHR_portability_subset and enables primitive restart for strip and dynamic topologies on devices which can not disable it, silencing MoltenVK warning "Metal does not support disabling primitive restart".
  • Timestamp queries: unbounded CPU-GPU calibration loop was replaced with a bounded number of attempts with relaxation of the acceptable deviation, which was hanging the command queue tracking thread and all threads waiting for the command lists execution under load.
  • Queue family reservation free indices set and the deferred pipelines release queue were guarded with mutexes.
  • RenderPass::CreateNativeFrameBuffer now validates attachment texture dimensions against the render pass frame size.
  • Removed MoltenVK workarounds for VkSubmitInfo with VkTimelineSemaphoreSubmitInfo and stale message-ID filters of the debug messenger callback, which are not needed with the current Vulkan SDK. Debug messenger callback signature was migrated to vk:: types.
  • Disabled Objective-C ARC for RenderContext.mm and PlatformExt.mm on Apple platforms (workaround of vulkan.hpp constant-expression issue with CAMetalLayer) and added explicit release of the Metal view in the RenderContext destructor.
  • Vulkan::TimestampQueryPool takes the first CPU time domain supported by the device from the platform preference list instead of one hard-coded domain, because MoltenVK exposes CLOCK_MONOTONIC_RAW only.
  • Query pool is created with exactly as many queries as its data buffer can hold timestamps: over-allocating made MoltenVK fail to create MTLCounterSampleBuffer and fall back to emulated timestamps.

Metal RHI

  • Added Metal::DebugMessages which prints GPU shader validation messages (MTLLogState, MTLFunctionLog) and command buffer execution errors to the platform debug output when the Metal debug layer is enabled with MTL_DEBUG_LAYER / MTL_SHADER_VALIDATION environment variables.
  • All native command buffers are created via CommandQueue::CreateNativeCommandBuffer() with per-encoder execution status error reporting enabled in debug builds.
  • Metal::ProgramArgumentBinding native resources were moved to the immutable NativeResourceViews snapshot, which is built locally and published under the mutex, so that Metal::ProgramBindings readers keep using the previous one until it is complete.

Platform libraries

  • Added Platform::SetPrintToConsoleEnabled() and application command line flag --print_debug_messages_to_console, which redirects debug output to std::cout instead of OutputDebugString on Windows and NSLog on MacOS, so that graphics API validation messages can be captured by the CI test script.
  • MacOS AppDelegate disables window state restoration, which is not implemented, and opts in to the secure restorable state coding to silence the AppKit warning.

Common changes

  • Dropped GitPod (Uno) support (removed gitpod config, docker, references and description).

Tutorial applications

  • Fixed prerequisite binaries copying for the ConsoleCompute tutorial with add_prerequisite_binaries(...) extended with the IS_CONSOLE_APP argument.
  • ConsoleCompute now waits for the compute command list completion instead of the whole context, fixing the GPU wait done in the invalid command list state, uses std::jthread for the UI refresh thread and declares the image format in the GameOfLife.hlsl compute shader.
  • Fixed Typography tutorial crash on resizing done before the text items were created by Init().
  • AppBase::IsResizing() returns false after an initialization error, so that partially constructed application state is not resized.

Tests

  • Added unit-tests covering RenderCommandList drawing with multiple primitive types in a single command list (Draw and DrawIndexed), which cover the fixed primitive type change tracking bug.
  • RenderPass unit-tests were extended to cover invalidation of the attachment texture caches on settings update, with a separate stencil attachment added to the test render pattern.

External libraries

Build

  • Added VS2026-* CMake configure and build presets using Visual Studio 18 2026 generator for Win64/Win32 x DX/VK x Default/Profile/Scan variants (require CMake 4.2+).
  • Build\Windows\Build.bat uses Visual Studio 2026 generator by default, --vs2022 option was added for backward compatibility. Support of Visual Studio 2019 build was dropped.
  • Added Build/Unix/CI/InstallMacOsPrerequisites.sh script, which downloads and installs the Metal Toolchain required since Xcode 26.
  • Fixed ARM64 architecture detection in CMake/MethaneModules.cmake for the different spellings of CMAKE_SYSTEM_PROCESSOR.
  • Fixed Tracy, FMT, HLSL++ and TaskFlow builds with the new compilers by disabling the newly introduced warnings.
  • Fixed or silenced with comment all static analysis issues from SonarQube .
  • Dropped GitPod (Uno) support (removed gitpod config, docker, references and description).

Continuous Integration

  • All CI workflows were switched to the VS2026-* presets on Windows and were updated to the latest GitHub actions: actions/checkout@v7, actions/cache@v6, actions/upload-artifact@v7, github/codeql-action/*@v4.
  • Sonar Scanner was migrated from the legacy RunSonarScanner.sh script to SonarSource/sonarqube-scan-action@v8.2.0 with separate steps for push and pull-request events; images were excluded from the analysis to fix invalid encoding errors.
  • Added MacOS prerequisites installation step to the CI Build, CodeQL and Sonar Scan workflows. CodeQL scan on MacOS was temporarily disabled because of the Metal Toolchain availability issue.
  • Added Build/Unix/CI/RunApplicationsTest.sh script, which runs all applications in GUI mode and checks the console output for the graphics API validation and runtime errors on all platforms.
  • Vulkan SDK was updated to v1.4.350.1 and Tracy release binaries to v0.14.0.1.

Documentation

  • Added Docs/Performance.md with the measured comparison of the DirectX 12 and Vulkan backends frame rates on Windows and with the explanation of the present rate drop after switching the rendering device in runtime.
  • Updated Build/README.md with the new build presets, and Externals/README.md with the updated dependency versions.
  • Added CLAUDE.md with the project guidance for Claude Code.

Note

For MacOS users: In case of error "App Is Damaged and Can't Be Opened" on attempt to run bundled application, try removing application from quarantine using the following command:

sudo xattr -d com.apple.quarantine MethaneHelloTriangle.app
open MethaneHelloTriangle.app