Skip to content

Commit 83db85f

Browse files
authored
[SYCL][Bindless] Update and add support for SPV_INTEL_bindless_image extension new revision (#13753)
Add support to emit instructions that convert handles to images, samplers and sampled images
1 parent 7fa793b commit 83db85f

File tree

7 files changed

+346
-48
lines changed

7 files changed

+346
-48
lines changed

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10411,7 +10411,8 @@ static void getOtherSPIRVTransOpts(Compilation &C,
1041110411
",+SPV_INTEL_fpga_argument_interfaces"
1041210412
",+SPV_INTEL_fpga_invocation_pipelining_attributes"
1041310413
",+SPV_INTEL_fpga_latency_control"
10414-
",+SPV_INTEL_task_sequence";
10414+
",+SPV_INTEL_task_sequence"
10415+
",+SPV_INTEL_bindless_images";
1041510416
ExtArg = ExtArg + DefaultExtArg + INTELExtArg;
1041610417
if (C.getDriver().IsFPGAHWMode())
1041710418
// Enable several extensions on FPGA H/W exclusively

clang/test/Driver/sycl-spirv-ext.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
// CHECK-DEFAULT-SAME:,+SPV_INTEL_fpga_invocation_pipelining_attributes
4949
// CHECK-DEFAULT-SAME:,+SPV_INTEL_fpga_latency_control
5050
// CHECK-DEFAULT-SAME:,+SPV_INTEL_task_sequence
51+
// CHECK-DEFAULT-SAME:,+SPV_INTEL_bindless_images
5152
// CHECK-DEFAULT-SAME:,+SPV_INTEL_token_type
5253
// CHECK-DEFAULT-SAME:,+SPV_INTEL_bfloat16_conversion
5354
// CHECK-DEFAULT-SAME:,+SPV_INTEL_joint_matrix

sycl/doc/design/spirv-extensions/SPV_INTEL_bindless_images.asciidoc

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
:capability_token: 6528
22
:handle_to_image_token: 6529
33
:handle_to_sampler_token: 6530
4+
:handle_to_sampled_image_token: 6531
45

56
SPV_INTEL_bindless_images
67
=========================
@@ -37,8 +38,8 @@ In Development
3738

3839
[width="40%",cols="25,25"]
3940
|========================================
40-
| Last Modified Date | 2024-03-25
41-
| Revision | 6
41+
| Last Modified Date | 2024-05-01
42+
| Revision | 7
4243
|========================================
4344

4445
== Dependencies
@@ -52,7 +53,7 @@ This extension requires SPIR-V 1.0.
5253

5354
This extension adds support for bindless images.
5455
This is done by adding support for SPIR-V to convert unsigned integer handles to
55-
images/samplers.
56+
images, samplers and sampled images.
5657

5758
Bindless images are a feature that provides flexibility on how images are
5859
accessed and used, such as removing limitations on how many images can be
@@ -84,6 +85,7 @@ Instructions added under *BindlessImagesINTEL* capability.
8485
----
8586
OpConvertHandleToImageINTEL
8687
OpConvertHandleToSamplerINTEL
88+
OpConvertHandleToSampledImageINTEL
8789
----
8890

8991
== Token Number Assignments
@@ -93,9 +95,10 @@ OpConvertHandleToSamplerINTEL
9395
[cols="70%,30%"]
9496
[grid="rows"]
9597
|====
96-
|BindlessImagesINTEL |{capability_token}
97-
|OpConvertHandleToImageINTEL |{handle_to_image_token}
98-
|OpConvertHandleToSamplerINTEL |{handle_to_sampler_token}
98+
|BindlessImagesINTEL |{capability_token}
99+
|OpConvertHandleToImageINTEL |{handle_to_image_token}
100+
|OpConvertHandleToSamplerINTEL |{handle_to_sampler_token}
101+
|OpConvertHandleToSampledImageINTEL |{handle_to_sampled_image_token}
99102
|====
100103
--
101104

@@ -134,6 +137,21 @@ _Result type_ must be an `OpTypeSampler`.
134137
'<id> Operand'
135138
|======
136139

140+
[cols="2*1,3*2"]
141+
|======
142+
5+|[[OpConvertHandleToSampledImageINTEL]]*OpConvertHandleToSampledImageINTEL* +
143+
+
144+
Converts an unsigned integer pointed by _Operand_ to sampled image type.
145+
146+
Unsigned integer is either a 32 or 64 bit unsigned integer.
147+
Depending on if the addressing model is set to *Physical32* or *Physical64*.
148+
149+
_Result type_ must be an `OpTypeSampledImage`.
150+
151+
| 4 | {handle_to_sampled_image_token} | '<id> Result Type' | 'Result <id>' |
152+
'<id> Operand'
153+
|======
154+
137155
Modify Section 3.31, Capability, adding row to the capability table:
138156

139157
[width="40%"]
@@ -164,6 +182,7 @@ None Yet.
164182
instruction and clarify return types
165183
|6|2024-03-25|Duncan Brawley| Wording/formatting improvements, clarify sections
166184
edited, make capability addition explicit and
167-
substitute instruction numbers
185+
substitute instruction numbers
186+
|7|2024-05-01|Duncan Brawley| Add OpConvertHandleToSampledImageINTEL instruction
168187
|========================================
169188

sycl/include/CL/__spirv/spirv_ops.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,16 @@ template <typename SampledType, typename TempRetT, typename TempArgT>
230230
extern __DPCPP_SYCL_EXTERNAL TempRetT __spirv_ImageSampleCubemap(SampledType,
231231
TempArgT);
232232

233+
template <typename RetT, class HandleT>
234+
extern __DPCPP_SYCL_EXTERNAL RetT __spirv_ConvertHandleToImageINTEL(HandleT);
235+
236+
template <typename RetT, class HandleT>
237+
extern __DPCPP_SYCL_EXTERNAL RetT __spirv_ConvertHandleToSamplerINTEL(HandleT);
238+
239+
template <typename RetT, class HandleT>
240+
extern __DPCPP_SYCL_EXTERNAL
241+
RetT __spirv_ConvertHandleToSampledImageINTEL(HandleT);
242+
233243
#define __SYCL_OpGroupAsyncCopyGlobalToLocal __spirv_GroupAsyncCopy
234244
#define __SYCL_OpGroupAsyncCopyLocalToGlobal __spirv_GroupAsyncCopy
235245

sycl/include/sycl/ext/oneapi/bindless_images.hpp

Lines changed: 101 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ struct sampled_image_handle {
5050

5151
sampled_image_handle() : raw_handle(~0) {}
5252

53-
sampled_image_handle(raw_image_handle_type raw_image_handle)
54-
: raw_handle(raw_image_handle) {}
53+
sampled_image_handle(raw_image_handle_type handle) : raw_handle(handle) {}
5554

5655
raw_image_handle_type raw_handle;
5756
};
@@ -792,6 +791,43 @@ template <typename DataT> constexpr bool is_recognized_standard_type() {
792791
std::is_floating_point_v<DataT> || std::is_same_v<DataT, sycl::half>);
793792
}
794793

794+
#ifdef __SYCL_DEVICE_ONLY__
795+
796+
// Image types used for generating SPIR-V
797+
template <int NDims>
798+
using OCLImageTyRead =
799+
typename sycl::detail::opencl_image_type<NDims, sycl::access::mode::read,
800+
sycl::access::target::image>::type;
801+
802+
template <int NDims>
803+
using OCLImageTyWrite =
804+
typename sycl::detail::opencl_image_type<NDims, sycl::access::mode::write,
805+
sycl::access::target::image>::type;
806+
807+
// Macros are required because it is not legal for a function to return
808+
// a variable of type 'opencl_image_type'.
809+
#if defined(__SPIR__)
810+
#define CONVERT_HANDLE_TO_IMAGE(raw_handle, ImageType) \
811+
__spirv_ConvertHandleToImageINTEL<ImageType>(raw_handle)
812+
813+
#define CONVERT_HANDLE_TO_SAMPLED_IMAGE(raw_handle, NDims) \
814+
__spirv_ConvertHandleToSampledImageINTEL< \
815+
typename sycl::detail::sampled_opencl_image_type< \
816+
detail::OCLImageTyRead<NDims>>::type>(raw_handle)
817+
818+
#define FETCH_UNSAMPLED_IMAGE(DataT, raw_handle, coords) \
819+
__invoke__ImageRead<DataT>(raw_handle, coords)
820+
#else
821+
#define CONVERT_HANDLE_TO_IMAGE(raw_handle, ImageType) raw_handle
822+
823+
#define CONVERT_HANDLE_TO_SAMPLED_IMAGE(raw_handle, NDims) raw_handle
824+
825+
#define FETCH_UNSAMPLED_IMAGE(DataT, raw_handle, coords) \
826+
__invoke__ImageFetch<DataT>(raw_handle, coords)
827+
#endif
828+
829+
#endif
830+
795831
} // namespace detail
796832

797833
/**
@@ -826,15 +862,23 @@ DataT fetch_image(const unsampled_image_handle &imageHandle [[maybe_unused]],
826862

827863
#ifdef __SYCL_DEVICE_ONLY__
828864
if constexpr (detail::is_recognized_standard_type<DataT>()) {
829-
return __invoke__ImageFetch<DataT>(imageHandle.raw_handle, coords);
865+
return FETCH_UNSAMPLED_IMAGE(
866+
DataT,
867+
CONVERT_HANDLE_TO_IMAGE(imageHandle.raw_handle,
868+
detail::OCLImageTyRead<coordSize>),
869+
coords);
870+
830871
} else {
831872
static_assert(sizeof(HintT) == sizeof(DataT),
832873
"When trying to read a user-defined type, HintT must be of "
833874
"the same size as the user-defined DataT.");
834875
static_assert(detail::is_recognized_standard_type<HintT>(),
835876
"HintT must always be a recognized standard type");
836-
return sycl::bit_cast<DataT>(
837-
__invoke__ImageFetch<HintT>(imageHandle.raw_handle, coords));
877+
return sycl::bit_cast<DataT>(FETCH_UNSAMPLED_IMAGE(
878+
HintT,
879+
CONVERT_HANDLE_TO_IMAGE(imageHandle.raw_handle,
880+
detail::OCLImageTyRead<coordSize>),
881+
coords));
838882
}
839883
#else
840884
assert(false); // Bindless images not yet implemented on host
@@ -907,10 +951,13 @@ DataT fetch_image(const sampled_image_handle &imageHandle [[maybe_unused]],
907951

908952
#ifdef __SYCL_DEVICE_ONLY__
909953
if constexpr (detail::is_recognized_standard_type<DataT>()) {
910-
return __invoke__SampledImageFetch<DataT>(imageHandle.raw_handle, coords);
954+
return __invoke__SampledImageFetch<DataT>(
955+
CONVERT_HANDLE_TO_SAMPLED_IMAGE(imageHandle.raw_handle, coordSize),
956+
coords);
911957
} else {
912-
return sycl::bit_cast<DataT>(
913-
__invoke__SampledImageFetch<HintT>(imageHandle.raw_handle, coords));
958+
return sycl::bit_cast<DataT>(__invoke__SampledImageFetch<HintT>(
959+
CONVERT_HANDLE_TO_SAMPLED_IMAGE(imageHandle.raw_handle, coordSize),
960+
coords));
914961
}
915962
#else
916963
assert(false); // Bindless images not yet implemented on host.
@@ -954,10 +1001,13 @@ DataT sample_image(const sampled_image_handle &imageHandle [[maybe_unused]],
9541001

9551002
#ifdef __SYCL_DEVICE_ONLY__
9561003
if constexpr (detail::is_recognized_standard_type<DataT>()) {
957-
return __invoke__ImageRead<DataT>(imageHandle.raw_handle, coords);
1004+
return __invoke__ImageRead<DataT>(
1005+
CONVERT_HANDLE_TO_SAMPLED_IMAGE(imageHandle.raw_handle, coordSize),
1006+
coords);
9581007
} else {
959-
return sycl::bit_cast<DataT>(
960-
__invoke__ImageRead<HintT>(imageHandle.raw_handle, coords));
1008+
return sycl::bit_cast<DataT>(__invoke__ImageRead<HintT>(
1009+
CONVERT_HANDLE_TO_SAMPLED_IMAGE(imageHandle.raw_handle, coordSize),
1010+
coords));
9611011
}
9621012
#else
9631013
assert(false); // Bindless images not yet implemented on host.
@@ -1026,15 +1076,18 @@ DataT sample_mipmap(const sampled_image_handle &imageHandle [[maybe_unused]],
10261076

10271077
#ifdef __SYCL_DEVICE_ONLY__
10281078
if constexpr (detail::is_recognized_standard_type<DataT>()) {
1029-
return __invoke__ImageReadLod<DataT>(imageHandle.raw_handle, coords, level);
1079+
return __invoke__ImageReadLod<DataT>(
1080+
CONVERT_HANDLE_TO_SAMPLED_IMAGE(imageHandle.raw_handle, coordSize),
1081+
coords, level);
10301082
} else {
10311083
static_assert(sizeof(HintT) == sizeof(DataT),
10321084
"When trying to read a user-defined type, HintT must be of "
10331085
"the same size as the user-defined DataT.");
10341086
static_assert(detail::is_recognized_standard_type<HintT>(),
10351087
"HintT must always be a recognized standard type");
1036-
return sycl::bit_cast<DataT>(
1037-
__invoke__ImageReadLod<HintT>(imageHandle.raw_handle, coords, level));
1088+
return sycl::bit_cast<DataT>(__invoke__ImageReadLod<HintT>(
1089+
CONVERT_HANDLE_TO_SAMPLED_IMAGE(imageHandle.raw_handle, coordSize),
1090+
coords, level));
10381091
}
10391092
#else
10401093
assert(false); // Bindless images not yet implemented on host
@@ -1070,16 +1123,18 @@ DataT sample_mipmap(const sampled_image_handle &imageHandle [[maybe_unused]],
10701123

10711124
#ifdef __SYCL_DEVICE_ONLY__
10721125
if constexpr (detail::is_recognized_standard_type<DataT>()) {
1073-
return __invoke__ImageReadGrad<DataT>(imageHandle.raw_handle, coords, dX,
1074-
dY);
1126+
return __invoke__ImageReadGrad<DataT>(
1127+
CONVERT_HANDLE_TO_SAMPLED_IMAGE(imageHandle.raw_handle, coordSize),
1128+
coords, dX, dY);
10751129
} else {
10761130
static_assert(sizeof(HintT) == sizeof(DataT),
10771131
"When trying to read a user-defined type, HintT must be of "
10781132
"the same size as the user-defined DataT.");
10791133
static_assert(detail::is_recognized_standard_type<HintT>(),
10801134
"HintT must always be a recognized standard type");
1081-
return sycl::bit_cast<DataT>(
1082-
__invoke__ImageReadGrad<HintT>(imageHandle.raw_handle, coords, dX, dY));
1135+
return sycl::bit_cast<DataT>(__invoke__ImageReadGrad<HintT>(
1136+
CONVERT_HANDLE_TO_SAMPLED_IMAGE(imageHandle.raw_handle, coordSize),
1137+
coords, dX, dY));
10831138
}
10841139
#else
10851140
assert(false); // Bindless images not yet implemented on host
@@ -1224,16 +1279,20 @@ DataT fetch_image_array(const unsampled_image_handle &imageHandle
12241279

12251280
#ifdef __SYCL_DEVICE_ONLY__
12261281
if constexpr (detail::is_recognized_standard_type<DataT>()) {
1227-
return __invoke__ImageArrayFetch<DataT>(imageHandle.raw_handle, coords,
1228-
arrayLayer);
1282+
return __invoke__ImageArrayFetch<DataT>(
1283+
CONVERT_HANDLE_TO_IMAGE(imageHandle.raw_handle,
1284+
detail::OCLImageTyRead<coordSize>),
1285+
coords, arrayLayer);
12291286
} else {
12301287
static_assert(sizeof(HintT) == sizeof(DataT),
12311288
"When trying to fetch a user-defined type, HintT must be of "
12321289
"the same size as the user-defined DataT.");
12331290
static_assert(detail::is_recognized_standard_type<HintT>(),
12341291
"HintT must always be a recognized standard type");
12351292
return sycl::bit_cast<DataT>(__invoke__ImageArrayFetch<HintT>(
1236-
imageHandle.raw_handle, coords, arrayLayer));
1293+
CONVERT_HANDLE_TO_IMAGE(imageHandle.raw_handle,
1294+
detail::OCLImageTyRead<coordSize>),
1295+
coords, arrayLayer));
12371296
}
12381297
#else
12391298
assert(false); // Bindless images not yet implemented on host.
@@ -1277,19 +1336,21 @@ DataT fetch_cubemap(const unsampled_image_handle &imageHandle,
12771336
template <typename DataT, typename HintT = DataT>
12781337
DataT sample_cubemap(const sampled_image_handle &imageHandle [[maybe_unused]],
12791338
const sycl::float3 &dirVec [[maybe_unused]]) {
1339+
[[maybe_unused]] constexpr size_t NDims = 2;
12801340

12811341
#ifdef __SYCL_DEVICE_ONLY__
12821342
if constexpr (detail::is_recognized_standard_type<DataT>()) {
1283-
return __invoke__ImageReadCubemap<DataT, uint64_t>(imageHandle.raw_handle,
1284-
dirVec);
1343+
return __invoke__ImageReadCubemap<DataT, uint64_t>(
1344+
CONVERT_HANDLE_TO_SAMPLED_IMAGE(imageHandle.raw_handle, NDims), dirVec);
12851345
} else {
12861346
static_assert(sizeof(HintT) == sizeof(DataT),
12871347
"When trying to read a user-defined type, HintT must be of "
12881348
"the same size as the user-defined DataT.");
12891349
static_assert(detail::is_recognized_standard_type<HintT>(),
12901350
"HintT must always be a recognized standard type");
12911351
return sycl::bit_cast<DataT>(__invoke__ImageReadCubemap<HintT, uint64_t>(
1292-
imageHandle.raw_handle, dirVec));
1352+
CONVERT_HANDLE_TO_SAMPLED_IMAGE(imageHandle.raw_handle, NDims),
1353+
dirVec));
12931354
}
12941355
#else
12951356
assert(false); // Bindless images not yet implemented on host
@@ -1318,12 +1379,17 @@ void write_image(unsampled_image_handle imageHandle [[maybe_unused]],
13181379

13191380
#ifdef __SYCL_DEVICE_ONLY__
13201381
if constexpr (detail::is_recognized_standard_type<DataT>()) {
1321-
__invoke__ImageWrite((uint64_t)imageHandle.raw_handle, coords, color);
1382+
__invoke__ImageWrite(
1383+
CONVERT_HANDLE_TO_IMAGE(imageHandle.raw_handle,
1384+
detail::OCLImageTyWrite<coordSize>),
1385+
coords, color);
13221386
} else {
13231387
// Convert DataT to a supported backend write type when user-defined type is
13241388
// passed
1325-
__invoke__ImageWrite((uint64_t)imageHandle.raw_handle, coords,
1326-
detail::convert_color(color));
1389+
__invoke__ImageWrite(
1390+
CONVERT_HANDLE_TO_IMAGE(imageHandle.raw_handle,
1391+
detail::OCLImageTyWrite<coordSize>),
1392+
coords, detail::convert_color(color));
13271393
}
13281394
#else
13291395
assert(false); // Bindless images not yet implemented on host
@@ -1354,13 +1420,17 @@ void write_image_array(unsampled_image_handle imageHandle [[maybe_unused]],
13541420

13551421
#ifdef __SYCL_DEVICE_ONLY__
13561422
if constexpr (detail::is_recognized_standard_type<DataT>()) {
1357-
__invoke__ImageArrayWrite(static_cast<uint64_t>(imageHandle.raw_handle),
1358-
coords, arrayLayer, color);
1423+
__invoke__ImageArrayWrite(
1424+
CONVERT_HANDLE_TO_IMAGE(imageHandle.raw_handle,
1425+
detail::OCLImageTyRead<coordSize>),
1426+
coords, arrayLayer, color);
13591427
} else {
13601428
// Convert DataT to a supported backend write type when user-defined type is
13611429
// passed
1362-
__invoke__ImageArrayWrite(static_cast<uint64_t>(imageHandle.raw_handle),
1363-
coords, arrayLayer, detail::convert_color(color));
1430+
__invoke__ImageArrayWrite(
1431+
CONVERT_HANDLE_TO_IMAGE(imageHandle.raw_handle,
1432+
detail::OCLImageTyRead<coordSize>),
1433+
coords, arrayLayer, detail::convert_color(color));
13641434
}
13651435
#else
13661436
assert(false); // Bindless images not yet implemented on host.

0 commit comments

Comments
 (0)