Add Embree 4.4.1 C# bindings - #1
Merged
Merged
Conversation
Low-level P/Invoke bindings for Intel Embree following the Evergine binding pattern: a CppAst-based generator parses the vendored Embree 4.4.1 headers and emits Constants/Enums/Delegates/Handles/Structs/Functions into Evergine.Bindings.Embree (153 functions, 13 enums, 35 structs, 15 function pointer typedefs, 7 opaque handles). Notable points: - The generator parses in C mode against stub system headers under EmbreeGen/Headers/stubs and a pinned x86_64 target, so the output is identical on a Windows dev box and on the linux-x64 CI runner. - rtcore_config.h is vendored because CMake generates it and it decides the layout of several public structs. The native build workflow uploads it alongside the binaries so the two never drift. - Embree declares most structs RTC_ALIGN(16/32/64), which rounds their C sizeof up (RTCHit is 36 bytes of fields but 48 bytes wide). Generated structs carry an explicit StructLayout Size so RTCRayHit and friends match the C layout. - The RTC_FORCEINLINE helpers have no exported symbol, so hand-written equivalents live in Embree.Inline.cs together with the SoA RayN_/HitN_ packet accessors. - A module initializer registers a DllImport resolver so project references behave like the NuGet package. Samples: - HelloEmbree: console smoke test that asserts struct sizes and runs rtcIntersect1/rtcOccluded1 against a triangle. - HelloEmbree.Evergine: CPU ray tracer drawn through the Evergine low-level graphics API, with a --bench mode reporting per-stage cost. Native binaries are produced by the manually dispatched Build Embree Libraries workflow (EMBREE_TASKING_SYSTEM=INTERNAL, five RIDs) and are not committed yet.
HelloEmbreeEvergine was only chosen because HelloEmbree.Evergine shadowed the Evergine.* namespaces from inside the project. Plain HelloEmbree has no such clash and matches the console sample.
The sample used to let FormsWindowsSystem create its own window. It now owns a MainForm with a toolbar and a status bar, and Evergine renders into an EvergineControl docked inside it, so the ray traced image sits in a normal WinForms layout. The HWND is read after the control is parented, because WinForms recreates a control's handle when it is added to a container. AutoRegisterWindow is turned off and the render loop is pointed at the form, so closing the window ends it. The status bar shows the live per-stage timings, the toolbar can freeze the camera and save a PNG on demand, and resizing only resizes the swapchain: the ray traced image keeps its own resolution and is stretched by the fullscreen triangle, so it costs nothing on the CPU.
…tput CI failed with 'script not found at: build/scripts/Generate-Bindings-DotNet.ps1'. The reusable binding-common-ci workflow calls that script, which is one of the files evergine-standards syncs into every binding repo; it was missing here. Copied the three scripts from the sibling binding repos, sync-standards will keep them up to date from now on. That surfaced a latent bug. The script runs the generator from bin/<cfg>/<tfm>/<rid>/publish/, one level deeper than a local dotnet run, so the hardcoded '../../../../..' resolved to EmbreeGen/ instead of the repository root and the bindings would have been written to the wrong place without any error. The generator now walks up looking for the binding project and fails loudly if it cannot find it.
Removes the console smoke test and renames HelloEmbree.Evergine to HelloEmbree, taking over the freed name: project file, solution entry, README and gitignore entry follow. The namespace was already HelloEmbree. The struct-size assertions the console sample existed for are also in the Evergine sample's CheckStructLayouts, so the rtcore_config.h drift check survives the removal. What is lost is the only sample that ran outside Windows: what remains is WinForms plus DX11.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Low-level P/Invoke bindings for Intel Embree 4.4.1,
following the Evergine binding pattern: a CppAst-based generator parses the vendored Embree
headers and emits the
.csfiles that make upEvergine.Bindings.Embree.What is generated
153 functions, 13 enums, 35 structs, 15 function-pointer typedefs and 7 opaque handle types,
split into
Constants.cs,Enums.cs,Delegates.cs,Handles.cs,Structs.csandFunctions.cs. The full C API is covered: devices, scenes, all geometry types, ray queries(1/4/8/16 plus the
TraversableandForwardvariants), point queries, the BVH builder andevery callback.
Points worth reviewing
EmbreeGen/Headers/stubsand a pinnedx86_64-pc-windowstarget, so the output is identicalon a Windows dev box and on the linux-x64 CI runner. Without the stubs it picked up whatever
MSVC or libc headers the machine happened to have.
rtcore_config.his vendored. CMake generates it and it decides the layout of severalpublic structs (
RTC_MAX_INSTANCE_LEVEL_COUNT,RTC_GEOMETRY_INSTANCE_ARRAY,RTC_MIN_WIDTH). The native build workflow uploads it next to the binaries so the two cannotdrift;
HelloEmbreeasserts the resulting struct sizes at startup.StructLayout.Size. Embree declares most structsRTC_ALIGN(16/32/64), whichrounds their C
sizeofup:RTCHithas 36 bytes of fields but is 48 bytes wide. A plainsequential C# struct would be narrower and
RTCRayHitwould be laid out wrong, so generatedstructs carry the size clang computed.
RTC_FORCEINLINEhelpers. They have no exported symbol, so the generator skips them andhand-written equivalents live in
Embree.Inline.cs, together with the SoARayN_*/HitN_*packet accessors from the C++ section of
rtcore_ray.h.boolmaps tobyte, notbool: the default .NET marshalling ofboolis the 4-byteWin32
BOOL, not the 1-byte C_Bool.DllImportresolver so project references behave like theNuGet package.
Samples
HelloEmbree— console smoke test: asserts struct sizes, then runsrtcIntersect1andrtcOccluded1against a triangle.HelloEmbree.Evergine— CPU ray tracer drawn through the Evergine low-level graphics API,hosted in a Windows Forms window, with a
--benchmode reporting per-stage cost.One thing this surfaced that is worth knowing when using the binding:
RTCRayandRTCRayHitmust be 16-byte aligned. Embree's kernels use aligned SIMD loads and a C# local carries no such
guarantee, so
&someLocalcrashes on some code paths and silently works on others. Both samplesallocate rays with
NativeMemory.AlignedAlloc, and the READMEs call it out.Not done yet
runtimes/only has.gitkeep. They are produced by the manuallydispatched
Build Embree Librariesworkflow (EMBREE_TASKING_SYSTEM=INTERNAL, so each binaryis self-contained with no TBB dependency) and have to be committed together with the
rtcore_config.hfrom the same build. Until then neither sample runs from a fresh clone.win-arm64is untested. Itswindows-11-armrunner leg may need toolchain adjustments; ifit does not work, dropping that RID from the first release and from the README is reasonable.
embree4.dllfor win-x64, whosertcore_config.hmatches the vendored one exactly.