GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
8 / 8
100.0%
Branches:
8 / 13
61.5%
Functions:
-
-%

render/geometry.h
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file geometry.h
3 /// @brief The geometry the device scene traces: meshes as triangles, and UsdGeom's implicit
4 /// shapes as unit shapes in procedural boxes, intersected exactly at any size.
5 #pragma once
6
7 #include "ernie/device/arena.h"
8 #include "ernie/device/column.h"
9 #include "ernie/device/staging.h"
10 #include "ernie/graph/graph.h"
11 #include "ernie/render/prim_rows.h"
12 #include "ernie/scene/scene.h"
13 #include "ernie/shaders/scene/geometry.slang"
14
15 #include <glm/glm.hpp>
16
17 #include <cstdint>
18 #include <optional>
19 #include <span>
20 #include <vector>
21
22 namespace ernie {
23
24 /// Triangles, or the unit shapes procedural primitives stand for: a unit sphere and cube, a unit
25 /// cylinder and cone about +z with z in [-1, 1] (the cone's apex at +1), a capsule of radius 1
26 /// about a segment of half-length `Geometry::halfLength`, and a unit square in z = 0 facing +z
27 /// (planes, and ground planes 200 km across).
28 enum class GeometryKind : std::uint8_t {
29 Triangles = shaders::kTriangles,
30 Sphere = shaders::kSphere,
31 Cube = shaders::kCube,
32 Cylinder = shaders::kCylinder,
33 Cone = shaders::kCone,
34 Capsule = shaders::kCapsule,
35 Plane = shaders::kPlane,
36 };
37
38 using GeometryId = std::uint32_t;
39
40 /// @brief A piece of geometry on the device, shared by every prim and world that draws it.
41 struct Geometry {
42 GeometryKind kind = GeometryKind::Triangles;
43 /// Triangles' float x, y, z positions and uint32 indices; or the one procedural box.
44 BufferRange vertices;
45 BufferRange indices;
46 BufferRange box;
47 std::uint32_t vertexCount = 0;
48 std::uint32_t triangleCount = 0;
49 /// A capsule's segment half-length over its radius.
50 float halfLength = 0.0f;
51 };
52
53 /// @brief A geometry as kernels read it from `GeometryPool::Records`, as geometry.slang defines it.
54 using GeometryRecord = shaders::GeometryRecord;
55
56 /// @brief What a prim draws: its geometry, and the transform from the geometry's frame to the
57 /// prim's, which sizes and turns a unit shape.
58 struct PrimGeometry {
59 PrimId prim;
60 GeometryId geometry = 0;
61 glm::dmat4 shape{1.0};
62 /// Its albedo in linear RGB, from `primvars:displayColor`, until materials bind one.
63 glm::vec3 colour{0.5f};
64 };
65
66 /// @brief The scene's gprims as device geometry. Implicit shapes share one unit geometry a kind
67 /// (capsules one each, as their caps stay round), so a thousand spheres need one bottom level.
68 /// Updates follow the scene's changes and cost what changed: new points of the same count are
69 /// rewritten in place for a refit, new topology is a rebuild, and shape attributes change only
70 /// the prim's shape transform.
71 class GeometryPool {
72 public:
73 /// @brief What an update changed, for the bottom levels and instances that follow it.
74 struct Changes {
75 /// Prims added, or whose geometry, shape or colour changed.
76 std::vector<PrimGeometry> placed;
77 std::vector<PrimId> removed;
78 /// Geometries new or of new topology, whose bottom levels are built anew.
79 std::vector<GeometryId> rebuilt;
80 /// Geometries whose points moved in place, whose bottom levels may be refitted.
81 std::vector<GeometryId> refitted;
82 /// Geometries no prim draws any more.
83 std::vector<GeometryId> freed;
84 };
85
86 /// @param arenas Where the geometry lives.
87 GeometryPool(DeviceContext& context, Arenas& arenas, const Scene& scene);
88
89 /// @brief Follows the scene's gprims since the last update, staging their data's uploads.
90 /// @throws std::invalid_argument for a mesh with malformed topology, or points not on the host.
91 Changes Update();
92 /// @brief Adds the pass that uploads what the last update staged, before the passes that
93 /// import `Buffers` to build from them.
94 void AddUploads(graph::Graph& graph);
95
96 75 const Geometry& Get(GeometryId geometry) const {
97
6/9
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 42 times.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 8 not taken.
75 return geometries_[geometry];
98 }
99 /// @return What the prim draws, or none for a prim that is no gprim Ernie traces.
100 std::optional<PrimGeometry> Find(PrimId prim) const;
101 /// @return The buffers geometry lives in, as a ranges' arena indexes them.
102 54 const Buffer& Storage(const BufferRange& range) const {
103 48 return arenas_.Storage(range);
104 }
105 /// @brief Imports every buffer geometry lives in, for passes that read it.
106 std::vector<graph::Buffer> Import(graph::Graph& graph) const;
107 /// @return Each geometry's `GeometryRecord`, by geometry id, in the buffers `Import` imports.
108 28 const DeviceColumn& Records() const {
109
2/4
<unknown function 108>:
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
<unknown function 96>:
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
28 return *records_;
110 }
111
112 private:
113 /// Places a prim: its geometry, built or shared, its shape transform and its colour. A mesh's
114 /// points are uploaded when it is new or `points`, its triangles when `topology`.
115 void Place(PrimId prim, bool points, bool topology, Changes& changes);
116 /// @return The unit shape geometry of a kind, made the first time it is asked for.
117 GeometryId UnitShape(GeometryKind kind);
118 /// @return A new or recycled geometry id.
119 GeometryId Allocate(const Geometry& geometry);
120 void Free(GeometryId geometry, Changes& changes);
121 void UploadBox(const Geometry& geometry, const glm::vec3& low, const glm::vec3& high);
122 /// Uploads a mesh's points, and its triangles when `topology`; a refit when only points move.
123 void UploadMesh(PrimId prim, GeometryId geometry, bool topology, Changes& changes);
124 /// Marks a geometry's record for the next upload.
125 void Touch(GeometryId geometry);
126
127 DeviceContext& context_;
128 Arenas& arenas_;
129 const Scene& scene_;
130 Uploader uploader_;
131 std::uint64_t cursor_ = 0;
132 PrimRows rows_;
133 std::vector<Geometry> geometries_;
134 std::vector<GeometryId> unused_;
135 /// What each prim draws, by its id's slot.
136 std::vector<std::optional<PrimGeometry>> prims_;
137 std::vector<std::optional<GeometryId>> unitShapes_;
138 /// The records' host copies, and the geometries whose records changed.
139 std::vector<GeometryRecord> hostRecords_;
140 std::vector<std::uint32_t> dirtyRecords_;
141 std::unique_ptr<DeviceColumn> records_;
142 };
143
144 } // namespace ernie
145