Skip to content

Commit c7b3197

Browse files
[SYCL][Bindless][E2E] Test for host USM backed images (#16607)
This patch adds a test for an image backed by a host USM allocation. Related UR PR: oneapi-src/unified-runtime#2551
1 parent 80acd9b commit c7b3197

File tree

2 files changed

+153
-6
lines changed

2 files changed

+153
-6
lines changed
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
# commit b841691699393dd2375e987c3d38d5f59c3e35cf
2-
# Merge: c6859445 9de10cd9
1+
# commit 0bb6789f0113ea937d861fd67fd677b91ecdeb8b
2+
# Merge: e370a2b9 eeff9f4a
33
# Author: Kenneth Benzie (Benie) <[email protected]>
4-
# Date: Thu Jan 23 16:07:06 2025 +0000
5-
# Merge pull request #2559 from Bensuo/fix_kernel_arg_indices
6-
# [CUDA][HIP] Fix kernel arguments being overwritten when added out of order
7-
set(UNIFIED_RUNTIME_TAG b841691699393dd2375e987c3d38d5f59c3e35cf)
4+
# Date: Mon Jan 27 10:40:02 2025 +0000
5+
# Merge pull request #2551 from przemektmalon/przemek/bindless-images-host-usm
6+
# Enable creation of bindless images backed by host USM
7+
set(UNIFIED_RUNTIME_TAG 0bb6789f0113ea937d861fd67fd677b91ecdeb8b)
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
// REQUIRES: cuda
2+
// REQUIRES: aspect-ext_oneapi_bindless_images_2d_usm
3+
4+
// RUN: %{build} -o %t.out
5+
// RUN: %{run-unfiltered-devices} %t.out
6+
7+
#include <cmath>
8+
#include <iostream>
9+
#include <sycl/detail/core.hpp>
10+
11+
#include <sycl/ext/oneapi/bindless_images.hpp>
12+
#include <sycl/usm.hpp>
13+
14+
// Uncomment to print additional test information
15+
// #define VERBOSE_PRINT
16+
17+
class image_addition;
18+
19+
int main() {
20+
21+
sycl::device dev;
22+
sycl::queue q(dev);
23+
auto ctxt = q.get_context();
24+
25+
// declare image data
26+
size_t width = 5;
27+
size_t height = 6;
28+
size_t N = width * height;
29+
size_t widthInBytes = width * sizeof(float);
30+
std::vector<float> out(N);
31+
std::vector<float> expected(N);
32+
std::vector<float> dataIn(N);
33+
34+
for (int i = 0; i < width; i++) {
35+
for (int j = 0; j < height; j++) {
36+
expected[i + (width * j)] = i + (width * j);
37+
dataIn[i + (width * j)] = i + (width * j);
38+
}
39+
}
40+
41+
try {
42+
sycl::ext::oneapi::experimental::bindless_image_sampler samp(
43+
sycl::addressing_mode::clamp,
44+
sycl::coordinate_normalization_mode::normalized,
45+
sycl::filtering_mode::linear);
46+
47+
// Extension: image descriptor
48+
sycl::ext::oneapi::experimental::image_descriptor desc(
49+
{width, height}, 1, sycl::image_channel_type::fp32);
50+
51+
auto devicePitchAlign = dev.get_info<
52+
sycl::ext::oneapi::experimental::info::device::image_row_pitch_align>();
53+
auto deviceMaxPitch =
54+
dev.get_info<sycl::ext::oneapi::experimental::info::device::
55+
max_image_linear_row_pitch>();
56+
57+
// Pitch requirements:
58+
// - pitch % devicePitchAlign == 0
59+
// - pitch >= widthInBytes
60+
// - pitch <= deviceMaxPitch
61+
size_t pitch = devicePitchAlign *
62+
std::ceil(float(widthInBytes) / float(devicePitchAlign));
63+
assert(pitch <= deviceMaxPitch);
64+
65+
// Host USM allocation
66+
auto imgMem =
67+
sycl::aligned_alloc_host(devicePitchAlign, (pitch * height), ctxt);
68+
69+
if (imgMem == nullptr) {
70+
std::cerr << "Error allocating images!" << std::endl;
71+
return 1;
72+
}
73+
74+
// Copy to host USM and incorporate pitch
75+
for (size_t i = 0; i < height; i++) {
76+
memcpy(static_cast<float *>(imgMem) + (i * pitch / sizeof(float)),
77+
dataIn.data() + (i * width), widthInBytes);
78+
}
79+
80+
// Extension: create the image and return the handle
81+
sycl::ext::oneapi::experimental::sampled_image_handle imgHandle =
82+
sycl::ext::oneapi::experimental::create_image(imgMem, pitch, samp, desc,
83+
dev, ctxt);
84+
85+
sycl::buffer<float, 2> buf((float *)out.data(),
86+
sycl::range<2>{height, width});
87+
q.submit([&](sycl::handler &cgh) {
88+
auto outAcc = buf.get_access<sycl::access_mode::write>(
89+
cgh, sycl::range<2>{height, width});
90+
91+
cgh.parallel_for<image_addition>(
92+
sycl::nd_range<2>{{width, height}, {width, height}},
93+
[=](sycl::nd_item<2> it) {
94+
size_t dim0 = it.get_local_id(0);
95+
size_t dim1 = it.get_local_id(1);
96+
97+
// Normalize coordinates -- +0.5 to look towards centre of pixel
98+
float fdim0 = float(dim0 + 0.5f) / (float)width;
99+
float fdim1 = float(dim1 + 0.5f) / (float)height;
100+
101+
// Extension: sample image data from handle
102+
float px = sycl::ext::oneapi::experimental::sample_image<float>(
103+
imgHandle, sycl::float2(fdim0, fdim1));
104+
105+
outAcc[sycl::id<2>{dim1, dim0}] = px;
106+
});
107+
});
108+
109+
q.wait_and_throw();
110+
111+
// Extension: cleanup
112+
sycl::ext::oneapi::experimental::destroy_image_handle(imgHandle, dev, ctxt);
113+
sycl::free(imgMem, ctxt);
114+
} catch (sycl::exception e) {
115+
std::cerr << "SYCL exception caught! : " << e.what() << "\n";
116+
return 1;
117+
} catch (...) {
118+
std::cerr << "Unknown exception caught!\n";
119+
return 2;
120+
}
121+
122+
// collect and validate output
123+
bool validated = true;
124+
for (int i = 0; i < N; i++) {
125+
bool mismatch = false;
126+
if (out[i] != expected[i]) {
127+
mismatch = true;
128+
validated = false;
129+
}
130+
131+
if (mismatch) {
132+
#ifdef VERBOSE_PRINT
133+
std::cout << "Result mismatch! Expected: " << expected[i]
134+
<< ", Actual: " << out[i] << std::endl;
135+
#else
136+
break;
137+
#endif
138+
}
139+
}
140+
if (validated) {
141+
std::cout << "Test passed!" << std::endl;
142+
return 0;
143+
}
144+
145+
std::cout << "Test failed!" << std::endl;
146+
return 3;
147+
}

0 commit comments

Comments
 (0)