Skip to content

Commit eb9f868

Browse files
committed
generalized Format enum instead of TextureFormat
1 parent a8770e8 commit eb9f868

10 files changed

Lines changed: 498 additions & 319 deletions

File tree

include/API/Device.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "API/Buffer.h"
1919
#include "API/Capabilities.h"
2020
#include "API/Texture.h"
21+
#include "Support/Pipeline.h"
2122
#include "llvm/ADT/StringRef.h"
2223
#include "llvm/ADT/iterator_range.h"
2324

include/API/FormatConversion.h

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
//===- FormatConversion.h - Bridge between DataFormat and Format -----------===//
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+
// Transitional helpers for converting between the legacy DataFormat + Channels
10+
// description system and the unified Format enum. This file should be deleted
11+
// once the pipeline is fully migrated to use Format directly.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef OFFLOADTEST_API_FORMATCONVERSION_H
16+
#define OFFLOADTEST_API_FORMATCONVERSION_H
17+
18+
#include "API/Resources.h"
19+
#include "API/Texture.h"
20+
#include "Support/Pipeline.h"
21+
22+
#include "llvm/Support/Error.h"
23+
24+
namespace offloadtest {
25+
26+
// Bridge for code that still describes textures as DataFormat + Channels (e.g.
27+
// render targets bound via CPUBuffer). Once the pipeline is refactored to use
28+
// Format directly, this function can be removed.
29+
inline llvm::Expected<Format> toFormat(DataFormat Format, int Channels) {
30+
switch (Format) {
31+
case DataFormat::Int16:
32+
switch (Channels) {
33+
case 1:
34+
return Format::R16Sint;
35+
case 2:
36+
return Format::RG16Sint;
37+
case 4:
38+
return Format::RGBA16Sint;
39+
}
40+
break;
41+
case DataFormat::UInt16:
42+
switch (Channels) {
43+
case 1:
44+
return Format::R16Uint;
45+
case 2:
46+
return Format::RG16Uint;
47+
case 4:
48+
return Format::RGBA16Uint;
49+
}
50+
break;
51+
case DataFormat::Int32:
52+
switch (Channels) {
53+
case 1:
54+
return Format::R32Sint;
55+
case 2:
56+
return Format::RG32Sint;
57+
case 4:
58+
return Format::RGBA32Sint;
59+
}
60+
break;
61+
case DataFormat::UInt32:
62+
switch (Channels) {
63+
case 1:
64+
return Format::R32Uint;
65+
case 2:
66+
return Format::RG32Uint;
67+
case 4:
68+
return Format::RGBA32Uint;
69+
}
70+
break;
71+
case DataFormat::Float32:
72+
switch (Channels) {
73+
case 1:
74+
return Format::R32Float;
75+
case 2:
76+
return Format::RG32Float;
77+
case 4:
78+
return Format::RGBA32Float;
79+
}
80+
break;
81+
case DataFormat::Depth32:
82+
// D32FloatS8Uint is not expressible as DataFormat + Channels because the
83+
// stencil component is uint8, not a second Depth32 channel. Once the
84+
// pipeline uses Format directly, this limitation goes away.
85+
if (Channels == 1)
86+
return Format::D32Float;
87+
break;
88+
// No Format mapping for these DataFormats.
89+
case DataFormat::Hex8:
90+
case DataFormat::Hex16:
91+
case DataFormat::Hex32:
92+
case DataFormat::Hex64:
93+
case DataFormat::UInt64:
94+
case DataFormat::Int64:
95+
case DataFormat::Float16:
96+
case DataFormat::Float64:
97+
case DataFormat::Bool:
98+
return llvm::createStringError(std::errc::invalid_argument,
99+
"DataFormat %d has no Format equivalent.",
100+
static_cast<int>(Format));
101+
}
102+
return llvm::createStringError(std::errc::invalid_argument,
103+
"No Format for DataFormat %d with %d "
104+
"channel(s).",
105+
static_cast<int>(Format), Channels);
106+
}
107+
108+
// Validates that a TextureCreateDesc is consistent with the CPUBuffer it was
109+
// derived from. Call this after building a TextureCreateDesc from a CPUBuffer
110+
// to catch mismatches between the two description systems.
111+
inline llvm::Error
112+
validateTextureDescMatchesCPUBuffer(const TextureCreateDesc &Desc,
113+
const CPUBuffer &Buf) {
114+
auto ExpectedFmt = toFormat(Buf.Format, Buf.Channels);
115+
if (!ExpectedFmt)
116+
return ExpectedFmt.takeError();
117+
if (Desc.Format != *ExpectedFmt)
118+
return llvm::createStringError(
119+
std::errc::invalid_argument,
120+
"TextureCreateDesc format '%s' does not match CPUBuffer format "
121+
"(DataFormat %d, %d channels -> '%s').",
122+
getFormatName(Desc.Format).data(), static_cast<int>(Buf.Format),
123+
Buf.Channels, getFormatName(*ExpectedFmt).data());
124+
if (Desc.Width != static_cast<uint32_t>(Buf.OutputProps.Width))
125+
return llvm::createStringError(
126+
std::errc::invalid_argument,
127+
"TextureCreateDesc width %u does not match CPUBuffer width %d.",
128+
Desc.Width, Buf.OutputProps.Width);
129+
if (Desc.Height != static_cast<uint32_t>(Buf.OutputProps.Height))
130+
return llvm::createStringError(
131+
std::errc::invalid_argument,
132+
"TextureCreateDesc height %u does not match CPUBuffer height %d.",
133+
Desc.Height, Buf.OutputProps.Height);
134+
if (Desc.MipLevels != static_cast<uint32_t>(Buf.OutputProps.MipLevels))
135+
return llvm::createStringError(
136+
std::errc::invalid_argument,
137+
"TextureCreateDesc mip levels %u does not match CPUBuffer mip "
138+
"levels %d.",
139+
Desc.MipLevels, Buf.OutputProps.MipLevels);
140+
uint32_t TexelSize = getFormatSize(Desc.Format);
141+
if (Buf.Stride > 0 && static_cast<uint32_t>(Buf.Stride) != TexelSize)
142+
return llvm::createStringError(
143+
std::errc::invalid_argument,
144+
"CPUBuffer stride %d does not match texture format element size %u.",
145+
Buf.Stride, TexelSize);
146+
uint64_t ExpectedSize =
147+
static_cast<uint64_t>(Desc.Width) * Desc.Height * TexelSize;
148+
if (static_cast<uint64_t>(Buf.size()) != ExpectedSize)
149+
return llvm::createStringError(
150+
std::errc::invalid_argument,
151+
"CPUBuffer size %u does not match expected size %llu "
152+
"(width %u * height %u * element size %u).",
153+
Buf.size(), ExpectedSize, Desc.Width, Desc.Height, TexelSize);
154+
return llvm::Error::success();
155+
}
156+
157+
} // namespace offloadtest
158+
159+
#endif // OFFLOADTEST_API_FORMATCONVERSION_H

include/API/Resources.h

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
#ifndef OFFLOADTEST_API_RESOURCES_H
1313
#define OFFLOADTEST_API_RESOURCES_H
1414

15+
#include "llvm/ADT/StringRef.h"
16+
#include "llvm/Support/Error.h"
17+
18+
#include <cstdint>
19+
1520
namespace offloadtest {
1621

1722
enum class MemoryLocation {
@@ -20,6 +25,213 @@ enum class MemoryLocation {
2025
GpuToCpu,
2126
};
2227

28+
// TODO: Add Unorm types (e.g. R8Unorm, RGBA8Unorm) which can be sampled as
29+
// floats.
30+
// TODO: Add SRGB types (e.g. RGBA8Srgb) once needed.
31+
enum class Format {
32+
R16Sint,
33+
R16Uint,
34+
RG16Sint,
35+
RG16Uint,
36+
RGBA16Sint,
37+
RGBA16Uint,
38+
R32Sint,
39+
R32Uint,
40+
R32Float,
41+
RG32Sint,
42+
RG32Uint,
43+
RG32Float,
44+
RGB32Float,
45+
RGBA32Sint,
46+
RGBA32Uint,
47+
RGBA32Float,
48+
D32Float,
49+
D32FloatS8Uint,
50+
};
51+
52+
inline llvm::StringRef getFormatName(Format Format) {
53+
switch (Format) {
54+
case Format::R16Sint:
55+
return "R16Sint";
56+
case Format::R16Uint:
57+
return "R16Uint";
58+
case Format::RG16Sint:
59+
return "RG16Sint";
60+
case Format::RG16Uint:
61+
return "RG16Uint";
62+
case Format::RGBA16Sint:
63+
return "RGBA16Sint";
64+
case Format::RGBA16Uint:
65+
return "RGBA16Uint";
66+
case Format::R32Sint:
67+
return "R32Sint";
68+
case Format::R32Uint:
69+
return "R32Uint";
70+
case Format::R32Float:
71+
return "R32Float";
72+
case Format::RG32Sint:
73+
return "RG32Sint";
74+
case Format::RG32Uint:
75+
return "RG32Uint";
76+
case Format::RG32Float:
77+
return "RG32Float";
78+
case Format::RGB32Float:
79+
return "RGB32Float";
80+
case Format::RGBA32Sint:
81+
return "RGBA32Sint";
82+
case Format::RGBA32Uint:
83+
return "RGBA32Uint";
84+
case Format::RGBA32Float:
85+
return "RGBA32Float";
86+
case Format::D32Float:
87+
return "D32Float";
88+
case Format::D32FloatS8Uint:
89+
return "D32FloatS8Uint";
90+
}
91+
llvm_unreachable("All Format cases handled");
92+
}
93+
94+
// Returns the size in bytes of a single texel/element for the given format.
95+
inline uint32_t getFormatSize(Format Format) {
96+
switch (Format) {
97+
case Format::R16Sint:
98+
case Format::R16Uint:
99+
return 2;
100+
case Format::RG16Sint:
101+
case Format::RG16Uint:
102+
case Format::R32Sint:
103+
case Format::R32Uint:
104+
case Format::R32Float:
105+
case Format::D32Float:
106+
return 4;
107+
case Format::RGBA16Sint:
108+
case Format::RGBA16Uint:
109+
case Format::RG32Sint:
110+
case Format::RG32Uint:
111+
case Format::RG32Float:
112+
case Format::D32FloatS8Uint:
113+
return 8;
114+
case Format::RGB32Float:
115+
return 12;
116+
case Format::RGBA32Sint:
117+
case Format::RGBA32Uint:
118+
case Format::RGBA32Float:
119+
return 16;
120+
}
121+
llvm_unreachable("All Format cases handled");
122+
}
123+
124+
inline bool isDepthFormat(Format Format) {
125+
switch (Format) {
126+
case Format::R16Sint:
127+
case Format::R16Uint:
128+
case Format::RG16Sint:
129+
case Format::RG16Uint:
130+
case Format::R32Sint:
131+
case Format::R32Uint:
132+
case Format::R32Float:
133+
case Format::RGBA16Sint:
134+
case Format::RGBA16Uint:
135+
case Format::RG32Sint:
136+
case Format::RG32Uint:
137+
case Format::RG32Float:
138+
case Format::RGB32Float:
139+
case Format::RGBA32Sint:
140+
case Format::RGBA32Uint:
141+
case Format::RGBA32Float:
142+
return false;
143+
case Format::D32Float:
144+
case Format::D32FloatS8Uint:
145+
return true;
146+
}
147+
llvm_unreachable("All Format cases handled");
148+
}
149+
150+
// Returns true if the format can be used as a texture pixel format across all
151+
// backends. Formats like RGB32Float are valid for vertex attributes but have no
152+
// pixel format equivalent on some APIs (e.g. Metal).
153+
inline bool isTextureCompatible(Format Format) {
154+
switch (Format) {
155+
case Format::RGB32Float:
156+
return false;
157+
case Format::R16Sint:
158+
case Format::R16Uint:
159+
case Format::RG16Sint:
160+
case Format::RG16Uint:
161+
case Format::RGBA16Sint:
162+
case Format::RGBA16Uint:
163+
case Format::R32Sint:
164+
case Format::R32Uint:
165+
case Format::R32Float:
166+
case Format::RG32Sint:
167+
case Format::RG32Uint:
168+
case Format::RG32Float:
169+
case Format::RGBA32Sint:
170+
case Format::RGBA32Uint:
171+
case Format::RGBA32Float:
172+
case Format::D32Float:
173+
case Format::D32FloatS8Uint:
174+
return true;
175+
}
176+
llvm_unreachable("All Format cases handled");
177+
}
178+
179+
// Returns true if the format can be used as a vertex attribute.
180+
inline bool isVertexCompatible(Format Format) {
181+
switch (Format) {
182+
case Format::R16Sint:
183+
case Format::R16Uint:
184+
case Format::RG16Sint:
185+
case Format::RG16Uint:
186+
case Format::RGBA16Sint:
187+
case Format::RGBA16Uint:
188+
case Format::R32Sint:
189+
case Format::R32Uint:
190+
case Format::R32Float:
191+
case Format::RG32Sint:
192+
case Format::RG32Uint:
193+
case Format::RG32Float:
194+
case Format::RGB32Float:
195+
case Format::RGBA32Sint:
196+
case Format::RGBA32Uint:
197+
case Format::RGBA32Float:
198+
return true;
199+
case Format::D32Float:
200+
case Format::D32FloatS8Uint:
201+
return false;
202+
}
203+
llvm_unreachable("All Format cases handled");
204+
}
205+
206+
// Returns true if the format can be used as a BLAS position attribute for
207+
// raytracing acceleration structure builds. Only a small subset of floating
208+
// point formats are supported across DX12, Vulkan, and Metal.
209+
inline bool isPositionCompatible(Format Format) {
210+
switch (Format) {
211+
case Format::RG32Float:
212+
case Format::RGB32Float:
213+
case Format::RGBA32Float:
214+
return true;
215+
case Format::R16Sint:
216+
case Format::R16Uint:
217+
case Format::RG16Sint:
218+
case Format::RG16Uint:
219+
case Format::RGBA16Sint:
220+
case Format::RGBA16Uint:
221+
case Format::R32Sint:
222+
case Format::R32Uint:
223+
case Format::R32Float:
224+
case Format::RG32Sint:
225+
case Format::RG32Uint:
226+
case Format::RGBA32Sint:
227+
case Format::RGBA32Uint:
228+
case Format::D32Float:
229+
case Format::D32FloatS8Uint:
230+
return false;
231+
}
232+
llvm_unreachable("All Format cases handled");
233+
}
234+
23235
} // namespace offloadtest
24236

25237
#endif // OFFLOADTEST_API_RESOURCES_H

0 commit comments

Comments
 (0)