Skip to content

Commit f6d9ff4

Browse files
MarijnS95claude
andcommitted
Add RT acceleration structure abstraction with size queries and resource allocation
Introduce the foundational types for ray tracing acceleration structures: abstract `AccelerationStructure` base class, geometry/instance descriptors, BLAS/TLAS build-request structs with size queries, the `AccelerationStructureBuildFlags` bitmask (using `LLVM_DECLARE_ENUM_AS_BITMASK` since `TextureUsage` already uses the intrusive `LLVM_MARK_AS_BITMASK_ENUM`; `TextureUsage` also gains its previously-missing `LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE()`), and AS resource allocation across DX12, Vulkan, and Metal. Recording build commands lands in a follow-up commit on top of the ComputeEncoder abstraction. Vulkan device creation switches to a single `vkGetPhysicalDeviceFeatures2` call covering every extension feature struct we care about (atomic-int64, mesh-shader, acceleration-structure, BDA on 1.1): each struct is chained into `pNext` before the query, and post-query we verify the gating bool and clear the sub-features we don't enable (capture-replay, indirect-build, multiview, etc.). Drive-by: rather than letting `vkCreateDevice` reject the device with a generic `VK_ERROR_FEATURE_NOT_PRESENT`, the code now returns a descriptive `llvm::Error` naming the extension and the bool that came back zero — pinpointing the case where a driver advertises an extension but reports its base feature as `VK_FALSE`. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f14ead0 commit f6d9ff4

10 files changed

Lines changed: 1018 additions & 45 deletions

File tree

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
//===- AccelerationStructure.h - RT Acceleration Structure Types ----------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef OFFLOADTEST_API_ACCELERATIONSTRUCTURE_H
10+
#define OFFLOADTEST_API_ACCELERATIONSTRUCTURE_H
11+
12+
#include "API/API.h"
13+
#include "API/Buffer.h"
14+
#include "API/Resources.h"
15+
16+
#include "llvm/ADT/ArrayRef.h"
17+
#include "llvm/ADT/BitmaskEnum.h"
18+
#include "llvm/ADT/SmallVector.h"
19+
#include "llvm/Support/Error.h"
20+
21+
#include <cstdint>
22+
23+
namespace offloadtest {
24+
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
25+
26+
enum AccelerationStructureBuildFlags : uint32_t {
27+
BuildFlagNone = 0,
28+
AllowUpdate = 1 << 0,
29+
PreferFastTrace = 1 << 1,
30+
PreferFastBuild = 1 << 2,
31+
// NOTE: keep LargestValue in LLVM_DECLARE_ENUM_AS_BITMASK at the end of this
32+
// header in sync when adding new flags.
33+
};
34+
35+
struct AccelerationStructureSizes {
36+
uint64_t ResultDataMaxSizeInBytes = 0;
37+
uint64_t ScratchDataSizeInBytes = 0;
38+
uint64_t UpdateScratchDataSizeInBytes = 0;
39+
};
40+
41+
struct TriangleGeometryDesc {
42+
Buffer *VertexBuffer = nullptr;
43+
uint64_t VertexBufferOffset = 0;
44+
uint32_t VertexCount = 0;
45+
uint32_t VertexStride = 0;
46+
Format VertexFormat = Format::RGB32Float;
47+
Buffer *IndexBuffer = nullptr;
48+
uint64_t IndexBufferOffset = 0;
49+
uint32_t IndexCount = 0;
50+
IndexFormat IdxFormat = IndexFormat::Uint32;
51+
bool Opaque = true;
52+
};
53+
54+
struct AABBGeometryDesc {
55+
Buffer *AABBBuffer = nullptr;
56+
uint64_t AABBBufferOffset = 0;
57+
uint32_t AABBCount = 0;
58+
uint32_t AABBStride = 24;
59+
bool Opaque = true;
60+
};
61+
62+
class AccelerationStructure;
63+
64+
struct AccelerationStructureInstance {
65+
float Transform[3][4] = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}};
66+
uint32_t InstanceID = 0;
67+
uint8_t InstanceMask = 0xFF;
68+
AccelerationStructure *BLAS = nullptr;
69+
};
70+
71+
struct BLASBuildRequest {
72+
llvm::SmallVector<TriangleGeometryDesc> Triangles;
73+
llvm::SmallVector<AABBGeometryDesc> AABBs;
74+
AccelerationStructureBuildFlags Flags = BuildFlagNone;
75+
AccelerationStructureSizes Sizes;
76+
};
77+
78+
struct TLASBuildRequest {
79+
llvm::SmallVector<AccelerationStructureInstance> Instances;
80+
AccelerationStructureBuildFlags Flags = BuildFlagNone;
81+
AccelerationStructureSizes Sizes;
82+
};
83+
84+
inline llvm::Error validateTriangleGeometryDesc(const TriangleGeometryDesc &D) {
85+
if (!D.VertexBuffer)
86+
return llvm::createStringError(
87+
std::errc::invalid_argument,
88+
"TriangleGeometryDesc: VertexBuffer is null.");
89+
if (!isPositionCompatible(D.VertexFormat))
90+
return llvm::createStringError(
91+
std::errc::invalid_argument,
92+
"TriangleGeometryDesc: VertexFormat '%s' is not position-compatible.",
93+
getFormatName(D.VertexFormat).data());
94+
if (D.VertexStride < getFormatSizeInBytes(D.VertexFormat))
95+
return llvm::createStringError(
96+
std::errc::invalid_argument,
97+
"TriangleGeometryDesc: VertexStride (%u) must be >= format size (%u).",
98+
D.VertexStride, getFormatSizeInBytes(D.VertexFormat));
99+
if (D.VertexCount == 0)
100+
return llvm::createStringError(std::errc::invalid_argument,
101+
"TriangleGeometryDesc: VertexCount is 0.");
102+
if (D.IndexBuffer && D.IndexCount == 0)
103+
return llvm::createStringError(
104+
std::errc::invalid_argument,
105+
"TriangleGeometryDesc: IndexBuffer is set but IndexCount is 0.");
106+
if (!D.IndexBuffer && D.IndexCount != 0)
107+
return llvm::createStringError(
108+
std::errc::invalid_argument,
109+
"TriangleGeometryDesc: IndexCount is set but IndexBuffer is null.");
110+
if (D.IndexBuffer && D.IndexCount % 3 != 0)
111+
return llvm::createStringError(
112+
std::errc::invalid_argument,
113+
"TriangleGeometryDesc: IndexCount (%u) must be a multiple of 3.",
114+
D.IndexCount);
115+
if (!D.IndexBuffer && D.VertexCount % 3 != 0)
116+
return llvm::createStringError(
117+
std::errc::invalid_argument,
118+
"TriangleGeometryDesc: VertexCount (%u) must be a multiple of 3 when "
119+
"no index buffer is provided.",
120+
D.VertexCount);
121+
return llvm::Error::success();
122+
}
123+
124+
inline llvm::Error validateAABBGeometryDesc(const AABBGeometryDesc &D) {
125+
if (!D.AABBBuffer)
126+
return llvm::createStringError(std::errc::invalid_argument,
127+
"AABBGeometryDesc: AABBBuffer is null.");
128+
if (D.AABBCount == 0)
129+
return llvm::createStringError(std::errc::invalid_argument,
130+
"AABBGeometryDesc: AABBCount is 0.");
131+
if (D.AABBStride < 24)
132+
return llvm::createStringError(
133+
std::errc::invalid_argument,
134+
"AABBGeometryDesc: AABBStride (%u) must be >= 24.", D.AABBStride);
135+
return llvm::Error::success();
136+
}
137+
138+
inline llvm::Error validateBLASBuildRequest(const BLASBuildRequest &Req) {
139+
if (Req.Triangles.empty() && Req.AABBs.empty())
140+
return llvm::createStringError(
141+
std::errc::invalid_argument,
142+
"BLASBuildRequest: Must have at least one geometry descriptor.");
143+
// Vulkan and Metal forbid mixing triangle and AABB geometry in a single BLAS;
144+
// D3D12 technically permits it but is uncommon. Reject for portability.
145+
if (!Req.Triangles.empty() && !Req.AABBs.empty())
146+
return llvm::createStringError(
147+
std::errc::invalid_argument,
148+
"BLASBuildRequest: Cannot mix triangle and AABB geometry in a "
149+
"single BLAS.");
150+
for (const auto &T : Req.Triangles)
151+
if (auto Err = validateTriangleGeometryDesc(T))
152+
return Err;
153+
for (const auto &A : Req.AABBs)
154+
if (auto Err = validateAABBGeometryDesc(A))
155+
return Err;
156+
return llvm::Error::success();
157+
}
158+
159+
inline llvm::Error validateTLASBuildRequest(const TLASBuildRequest &Req) {
160+
if (Req.Instances.empty())
161+
return llvm::createStringError(
162+
std::errc::invalid_argument,
163+
"TLASBuildRequest: Must have at least one instance.");
164+
for (size_t I = 0; I < Req.Instances.size(); ++I)
165+
if (!Req.Instances[I].BLAS)
166+
return llvm::createStringError(
167+
std::errc::invalid_argument,
168+
"TLASBuildRequest: Instance %zu has a null BLAS pointer.", I);
169+
return llvm::Error::success();
170+
}
171+
172+
class AccelerationStructure {
173+
GPUAPI API;
174+
175+
public:
176+
virtual ~AccelerationStructure();
177+
AccelerationStructure(const AccelerationStructure &) = delete;
178+
AccelerationStructure &operator=(const AccelerationStructure &) = delete;
179+
180+
GPUAPI getAPI() const { return API; }
181+
182+
protected:
183+
explicit AccelerationStructure(GPUAPI API) : API(API) {}
184+
};
185+
186+
} // namespace offloadtest
187+
188+
namespace llvm {
189+
LLVM_DECLARE_ENUM_AS_BITMASK(::offloadtest::AccelerationStructureBuildFlags,
190+
::offloadtest::PreferFastBuild);
191+
} // namespace llvm
192+
193+
#endif // OFFLOADTEST_API_ACCELERATIONSTRUCTURE_H

include/API/Device.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "Config.h"
1616

1717
#include "API/API.h"
18+
#include "API/AccelerationStructure.h"
1819
#include "API/Buffer.h"
1920
#include "API/Capabilities.h"
2021
#include "API/CommandBuffer.h"
@@ -226,6 +227,21 @@ class Device {
226227
virtual llvm::Expected<std::unique_ptr<CommandBuffer>>
227228
createCommandBuffer() = 0;
228229

230+
virtual llvm::Expected<BLASBuildRequest> createBLASBuildRequest(
231+
llvm::ArrayRef<TriangleGeometryDesc> Triangles,
232+
llvm::ArrayRef<AABBGeometryDesc> AABBs,
233+
AccelerationStructureBuildFlags Flags = BuildFlagNone) = 0;
234+
235+
virtual llvm::Expected<TLASBuildRequest> createTLASBuildRequest(
236+
llvm::ArrayRef<AccelerationStructureInstance> Instances,
237+
AccelerationStructureBuildFlags Flags = BuildFlagNone) = 0;
238+
239+
virtual llvm::Expected<std::unique_ptr<AccelerationStructure>>
240+
createAccelerationStructure(const BLASBuildRequest &Request) = 0;
241+
242+
virtual llvm::Expected<std::unique_ptr<AccelerationStructure>>
243+
createAccelerationStructure(const TLASBuildRequest &Request) = 0;
244+
229245
virtual ~Device() = 0;
230246

231247
llvm::StringRef getDescription() const { return Description; }

include/API/Texture.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <variant>
2727

2828
namespace offloadtest {
29+
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
2930

3031
enum TextureUsage : uint32_t {
3132
Sampled = 1 << 0,

lib/API/DX/DXResources.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,16 @@ inline D3D12_RESOURCE_FLAGS getDXResourceFlags(TextureUsage Usage) {
8484
return Flags;
8585
}
8686

87+
inline DXGI_FORMAT getDXGIIndexFormat(IndexFormat Fmt) {
88+
switch (Fmt) {
89+
case IndexFormat::Uint16:
90+
return DXGI_FORMAT_R16_UINT;
91+
case IndexFormat::Uint32:
92+
return DXGI_FORMAT_R32_UINT;
93+
}
94+
llvm_unreachable("All IndexFormat cases handled");
95+
}
96+
8797
} // namespace offloadtest
8898

8999
#endif // OFFLOADTEST_API_DXRESOURCES_H

0 commit comments

Comments
 (0)