1 /*
2 * Copyright (C) 2018-2021 Intel Corporation
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 */
7
8 #include "shared/source/built_ins/built_ins.h"
9 #include "shared/source/utilities/perf_counter.h"
10 #include "shared/test/common/test_macros/test.h"
11
12 #include "opencl/source/built_ins/builtins_dispatch_builder.h"
13 #include "opencl/source/command_queue/command_queue_hw.h"
14 #include "opencl/source/command_queue/enqueue_copy_image.h"
15 #include "opencl/source/command_queue/enqueue_fill_image.h"
16 #include "opencl/source/command_queue/enqueue_read_image.h"
17 #include "opencl/source/command_queue/enqueue_write_image.h"
18 #include "opencl/source/command_queue/gpgpu_walker.h"
19 #include "opencl/source/event/event.h"
20 #include "opencl/source/helpers/hardware_commands_helper.h"
21 #include "opencl/source/kernel/kernel.h"
22 #include "opencl/test/unit_test/command_queue/command_enqueue_fixture.h"
23 #include "opencl/test/unit_test/command_queue/enqueue_fixture.h"
24 #include "opencl/test/unit_test/command_queue/enqueue_write_image_fixture.h"
25 #include "opencl/test/unit_test/fixtures/built_in_fixture.h"
26 #include "opencl/test/unit_test/fixtures/cl_device_fixture.h"
27 #include "opencl/test/unit_test/mocks/mock_kernel.h"
28
29 using namespace NEO;
30
31 struct GetSizeRequiredImageTest : public CommandEnqueueFixture,
32 public ::testing::Test {
33
GetSizeRequiredImageTestGetSizeRequiredImageTest34 GetSizeRequiredImageTest() {
35 }
36
SetUpGetSizeRequiredImageTest37 void SetUp() override {
38 REQUIRE_IMAGES_OR_SKIP(defaultHwInfo);
39 CommandEnqueueFixture::SetUp();
40
41 srcImage = Image2dHelper<>::create(context);
42 dstImage = Image2dHelper<>::create(context);
43
44 pDevice->setPreemptionMode(PreemptionMode::Disabled);
45 }
46
TearDownGetSizeRequiredImageTest47 void TearDown() override {
48 if (IsSkipped()) {
49 return;
50 }
51 delete dstImage;
52 delete srcImage;
53
54 CommandEnqueueFixture::TearDown();
55 }
56
57 Image *srcImage = nullptr;
58 Image *dstImage = nullptr;
59 };
60
HWTEST_F(GetSizeRequiredImageTest,WhenCopyingImageThenHeapsAndCommandBufferConsumedMinimumRequiredSize)61 HWTEST_F(GetSizeRequiredImageTest, WhenCopyingImageThenHeapsAndCommandBufferConsumedMinimumRequiredSize) {
62 auto &commandStream = pCmdQ->getCS(1024);
63 auto usedBeforeCS = commandStream.getUsed();
64 auto &dsh = pCmdQ->getIndirectHeap(IndirectHeap::DYNAMIC_STATE, 0u);
65 auto &ioh = pCmdQ->getIndirectHeap(IndirectHeap::INDIRECT_OBJECT, 0u);
66 auto &ssh = pCmdQ->getIndirectHeap(IndirectHeap::SURFACE_STATE, 0u);
67 auto usedBeforeDSH = dsh.getUsed();
68 auto usedBeforeIOH = ioh.getUsed();
69 auto usedBeforeSSH = ssh.getUsed();
70
71 auto retVal = EnqueueCopyImageHelper<>::enqueueCopyImage(pCmdQ);
72 EXPECT_EQ(CL_SUCCESS, retVal);
73
74 auto &builder = BuiltInDispatchBuilderOp::getBuiltinDispatchInfoBuilder(EBuiltInOps::CopyImageToImage3d,
75 pCmdQ->getClDevice());
76 ASSERT_NE(nullptr, &builder);
77
78 BuiltinOpParams dc;
79 dc.srcMemObj = srcImage;
80 dc.dstMemObj = dstImage;
81 dc.srcOffset = EnqueueCopyImageTraits::srcOrigin;
82 dc.dstOffset = EnqueueCopyImageTraits::dstOrigin;
83 dc.size = {1, 1, 1};
84
85 MultiDispatchInfo multiDispatchInfo(dc);
86 builder.buildDispatchInfos(multiDispatchInfo);
87 EXPECT_NE(0u, multiDispatchInfo.size());
88
89 auto kernel = multiDispatchInfo.begin()->getKernel();
90 ASSERT_NE(nullptr, kernel);
91
92 auto usedAfterCS = commandStream.getUsed();
93 auto usedAfterDSH = dsh.getUsed();
94 auto usedAfterIOH = ioh.getUsed();
95 auto usedAfterSSH = ssh.getUsed();
96
97 auto expectedSizeCS = EnqueueOperation<FamilyType>::getSizeRequiredCS(CL_COMMAND_COPY_IMAGE, false, false, *pCmdQ, kernel, {});
98 auto expectedSizeDSH = HardwareCommandsHelper<FamilyType>::getSizeRequiredDSH(*kernel);
99 auto expectedSizeIOH = HardwareCommandsHelper<FamilyType>::getSizeRequiredIOH(*kernel);
100 auto expectedSizeSSH = HardwareCommandsHelper<FamilyType>::getSizeRequiredSSH(*kernel);
101
102 // Since each enqueue* may flush, we may see a MI_BATCH_BUFFER_END appended.
103 expectedSizeCS += sizeof(typename FamilyType::MI_BATCH_BUFFER_END);
104 expectedSizeCS = alignUp(expectedSizeCS, MemoryConstants::cacheLineSize);
105
106 EXPECT_GE(expectedSizeCS, usedAfterCS - usedBeforeCS);
107 EXPECT_GE(expectedSizeDSH, usedAfterDSH - usedBeforeDSH);
108 EXPECT_GE(expectedSizeIOH, usedAfterIOH - usedBeforeIOH);
109 EXPECT_GE(expectedSizeSSH, usedAfterSSH - usedBeforeSSH);
110 }
111
HWTEST_F(GetSizeRequiredImageTest,WhenCopyingReadWriteImageThenHeapsAndCommandBufferConsumedMinimumRequiredSize)112 HWTEST_F(GetSizeRequiredImageTest, WhenCopyingReadWriteImageThenHeapsAndCommandBufferConsumedMinimumRequiredSize) {
113 auto &commandStream = pCmdQ->getCS(1024);
114 auto usedBeforeCS = commandStream.getUsed();
115 auto &dsh = pCmdQ->getIndirectHeap(IndirectHeap::DYNAMIC_STATE, 0u);
116 auto &ioh = pCmdQ->getIndirectHeap(IndirectHeap::INDIRECT_OBJECT, 0u);
117 auto &ssh = pCmdQ->getIndirectHeap(IndirectHeap::SURFACE_STATE, 0u);
118 auto usedBeforeDSH = dsh.getUsed();
119 auto usedBeforeIOH = ioh.getUsed();
120 auto usedBeforeSSH = ssh.getUsed();
121
122 std::unique_ptr<MockProgram> program(Program::createBuiltInFromSource<MockProgram>("CopyImageToImage3d", context, context->getDevices(), nullptr));
123 program->build(program->getDevices(), nullptr, false);
124 std::unique_ptr<Kernel> kernel(Kernel::create<MockKernel>(program.get(), program->getKernelInfoForKernel("CopyImageToImage3d"), *context->getDevice(0), nullptr));
125
126 EXPECT_NE(nullptr, kernel);
127 // This kernel does not operate on OpenCL 2.0 Read and Write images
128 EXPECT_FALSE(kernel->getKernelInfo().kernelDescriptor.kernelAttributes.flags.usesFencesForReadWriteImages);
129 // Simulate that the kernel actually operates on OpenCL 2.0 Read and Write images.
130 // Such kernel may require special WA DisableLSQCROPERFforOCL during construction of Command Buffer
131 const_cast<KernelDescriptor &>(kernel->getKernelInfo().kernelDescriptor).kernelAttributes.flags.usesFencesForReadWriteImages = true;
132
133 // Enqueue kernel that may require special WA DisableLSQCROPERFforOCL
134 auto retVal = EnqueueKernelHelper<>::enqueueKernel(pCmdQ, kernel.get());
135 EXPECT_EQ(CL_SUCCESS, retVal);
136
137 auto usedAfterCS = commandStream.getUsed();
138 auto usedAfterDSH = dsh.getUsed();
139 auto usedAfterIOH = ioh.getUsed();
140 auto usedAfterSSH = ssh.getUsed();
141
142 auto expectedSizeCS = EnqueueOperation<FamilyType>::getSizeRequiredCS(CL_COMMAND_COPY_IMAGE, false, false, *pCmdQ, kernel.get(), {});
143 auto expectedSizeDSH = HardwareCommandsHelper<FamilyType>::getSizeRequiredDSH(*kernel.get());
144 auto expectedSizeIOH = HardwareCommandsHelper<FamilyType>::getSizeRequiredIOH(*kernel.get());
145 auto expectedSizeSSH = HardwareCommandsHelper<FamilyType>::getSizeRequiredSSH(*kernel.get());
146
147 // Since each enqueue* may flush, we may see a MI_BATCH_BUFFER_END appended.
148 expectedSizeCS += sizeof(typename FamilyType::MI_BATCH_BUFFER_END);
149 expectedSizeCS = alignUp(expectedSizeCS, MemoryConstants::cacheLineSize);
150
151 const_cast<KernelDescriptor &>(kernel->getKernelInfo().kernelDescriptor).kernelAttributes.flags.usesFencesForReadWriteImages = false;
152
153 EXPECT_GE(expectedSizeCS, usedAfterCS - usedBeforeCS);
154 EXPECT_GE(expectedSizeDSH, usedAfterDSH - usedBeforeDSH);
155 EXPECT_GE(expectedSizeIOH, usedAfterIOH - usedBeforeIOH);
156 EXPECT_GE(expectedSizeSSH, usedAfterSSH - usedBeforeSSH);
157 }
158
HWTEST_F(GetSizeRequiredImageTest,WhenReadingImageNonBlockingThenHeapsAndCommandBufferConsumedMinimumRequiredSize)159 HWTEST_F(GetSizeRequiredImageTest, WhenReadingImageNonBlockingThenHeapsAndCommandBufferConsumedMinimumRequiredSize) {
160 auto &commandStream = pCmdQ->getCS(1024);
161 auto usedBeforeCS = commandStream.getUsed();
162 auto &dsh = pCmdQ->getIndirectHeap(IndirectHeap::DYNAMIC_STATE, 0u);
163 auto &ioh = pCmdQ->getIndirectHeap(IndirectHeap::INDIRECT_OBJECT, 0u);
164 auto &ssh = pCmdQ->getIndirectHeap(IndirectHeap::SURFACE_STATE, 0u);
165 auto usedBeforeDSH = dsh.getUsed();
166 auto usedBeforeIOH = ioh.getUsed();
167 auto usedBeforeSSH = ssh.getUsed();
168
169 auto retVal = EnqueueReadImageHelper<>::enqueueReadImage(
170 pCmdQ,
171 srcImage,
172 CL_FALSE);
173 EXPECT_EQ(CL_SUCCESS, retVal);
174
175 auto &builder = BuiltInDispatchBuilderOp::getBuiltinDispatchInfoBuilder(EBuiltInOps::CopyImage3dToBuffer,
176 pCmdQ->getClDevice());
177 ASSERT_NE(nullptr, &builder);
178
179 BuiltinOpParams dc;
180 dc.srcMemObj = srcImage;
181 dc.dstPtr = EnqueueReadImageTraits::hostPtr;
182 dc.srcOffset = EnqueueReadImageTraits::origin;
183 dc.size = EnqueueReadImageTraits::region;
184 dc.srcRowPitch = EnqueueReadImageTraits::rowPitch;
185 dc.srcSlicePitch = EnqueueReadImageTraits::slicePitch;
186
187 MultiDispatchInfo multiDispatchInfo(dc);
188 builder.buildDispatchInfos(multiDispatchInfo);
189 EXPECT_NE(0u, multiDispatchInfo.size());
190
191 auto kernel = multiDispatchInfo.begin()->getKernel();
192 ASSERT_NE(nullptr, kernel);
193
194 auto usedAfterCS = commandStream.getUsed();
195 auto usedAfterDSH = dsh.getUsed();
196 auto usedAfterIOH = ioh.getUsed();
197 auto usedAfterSSH = ssh.getUsed();
198
199 auto expectedSizeCS = EnqueueOperation<FamilyType>::getSizeRequiredCS(CL_COMMAND_READ_IMAGE, false, false, *pCmdQ, kernel, {});
200 auto expectedSizeDSH = HardwareCommandsHelper<FamilyType>::getSizeRequiredDSH(*kernel);
201 auto expectedSizeIOH = HardwareCommandsHelper<FamilyType>::getSizeRequiredIOH(*kernel);
202 auto expectedSizeSSH = HardwareCommandsHelper<FamilyType>::getSizeRequiredSSH(*kernel);
203
204 // Since each enqueue* may flush, we may see a MI_BATCH_BUFFER_END appended.
205 expectedSizeCS += sizeof(typename FamilyType::MI_BATCH_BUFFER_END);
206 expectedSizeCS = alignUp(expectedSizeCS, MemoryConstants::cacheLineSize);
207
208 EXPECT_GE(expectedSizeCS, usedAfterCS - usedBeforeCS);
209 EXPECT_GE(expectedSizeDSH, usedAfterDSH - usedBeforeDSH);
210 EXPECT_GE(expectedSizeIOH, usedAfterIOH - usedBeforeIOH);
211 EXPECT_GE(expectedSizeSSH, usedAfterSSH - usedBeforeSSH);
212 }
213
HWTEST_F(GetSizeRequiredImageTest,WhenReadingImageBlockingThenHeapsAndCommandBufferConsumedMinimumRequiredSize)214 HWTEST_F(GetSizeRequiredImageTest, WhenReadingImageBlockingThenHeapsAndCommandBufferConsumedMinimumRequiredSize) {
215 auto &commandStream = pCmdQ->getCS(1024);
216 auto usedBeforeCS = commandStream.getUsed();
217 auto &dsh = pCmdQ->getIndirectHeap(IndirectHeap::DYNAMIC_STATE, 0u);
218 auto &ioh = pCmdQ->getIndirectHeap(IndirectHeap::INDIRECT_OBJECT, 0u);
219 auto &ssh = pCmdQ->getIndirectHeap(IndirectHeap::SURFACE_STATE, 0u);
220 auto usedBeforeDSH = dsh.getUsed();
221 auto usedBeforeIOH = ioh.getUsed();
222 auto usedBeforeSSH = ssh.getUsed();
223
224 auto retVal = EnqueueReadImageHelper<>::enqueueReadImage(
225 pCmdQ,
226 srcImage,
227 CL_TRUE);
228 EXPECT_EQ(CL_SUCCESS, retVal);
229
230 auto &builder = BuiltInDispatchBuilderOp::getBuiltinDispatchInfoBuilder(EBuiltInOps::CopyImage3dToBuffer,
231 pCmdQ->getClDevice());
232 ASSERT_NE(nullptr, &builder);
233
234 BuiltinOpParams dc;
235 dc.srcMemObj = srcImage;
236 dc.dstPtr = EnqueueReadImageTraits::hostPtr;
237 dc.srcOffset = EnqueueReadImageTraits::origin;
238 dc.size = EnqueueReadImageTraits::region;
239 dc.srcRowPitch = EnqueueReadImageTraits::rowPitch;
240 dc.srcSlicePitch = EnqueueReadImageTraits::slicePitch;
241
242 MultiDispatchInfo multiDispatchInfo(dc);
243 builder.buildDispatchInfos(multiDispatchInfo);
244 EXPECT_NE(0u, multiDispatchInfo.size());
245
246 auto kernel = multiDispatchInfo.begin()->getKernel();
247 ASSERT_NE(nullptr, kernel);
248
249 auto usedAfterCS = commandStream.getUsed();
250 auto usedAfterDSH = dsh.getUsed();
251 auto usedAfterIOH = ioh.getUsed();
252 auto usedAfterSSH = ssh.getUsed();
253
254 auto expectedSizeCS = EnqueueOperation<FamilyType>::getSizeRequiredCS(CL_COMMAND_READ_IMAGE, false, false, *pCmdQ, kernel, {});
255 auto expectedSizeDSH = HardwareCommandsHelper<FamilyType>::getSizeRequiredDSH(*kernel);
256 auto expectedSizeIOH = HardwareCommandsHelper<FamilyType>::getSizeRequiredIOH(*kernel);
257 auto expectedSizeSSH = HardwareCommandsHelper<FamilyType>::getSizeRequiredSSH(*kernel);
258
259 // Since each enqueue* may flush, we may see a MI_BATCH_BUFFER_END appended.
260 expectedSizeCS += sizeof(typename FamilyType::MI_BATCH_BUFFER_END);
261 expectedSizeCS = alignUp(expectedSizeCS, MemoryConstants::cacheLineSize);
262
263 EXPECT_GE(expectedSizeCS, usedAfterCS - usedBeforeCS);
264 EXPECT_GE(expectedSizeDSH, usedAfterDSH - usedBeforeDSH);
265 EXPECT_GE(expectedSizeIOH, usedAfterIOH - usedBeforeIOH);
266 EXPECT_GE(expectedSizeSSH, usedAfterSSH - usedBeforeSSH);
267 }
268
HWTEST_F(GetSizeRequiredImageTest,WhenWritingImageNonBlockingThenHeapsAndCommandBufferConsumedMinimumRequiredSize)269 HWTEST_F(GetSizeRequiredImageTest, WhenWritingImageNonBlockingThenHeapsAndCommandBufferConsumedMinimumRequiredSize) {
270 auto &commandStream = pCmdQ->getCS(1024);
271 auto usedBeforeCS = commandStream.getUsed();
272 auto &dsh = pCmdQ->getIndirectHeap(IndirectHeap::DYNAMIC_STATE, 0u);
273 auto &ioh = pCmdQ->getIndirectHeap(IndirectHeap::INDIRECT_OBJECT, 0u);
274 auto &ssh = pCmdQ->getIndirectHeap(IndirectHeap::SURFACE_STATE, 0u);
275 auto usedBeforeDSH = dsh.getUsed();
276 auto usedBeforeIOH = ioh.getUsed();
277 auto usedBeforeSSH = ssh.getUsed();
278
279 auto retVal = EnqueueWriteImageHelper<>::enqueueWriteImage(
280 pCmdQ,
281 dstImage,
282 CL_FALSE);
283 EXPECT_EQ(CL_SUCCESS, retVal);
284
285 auto &builder = BuiltInDispatchBuilderOp::getBuiltinDispatchInfoBuilder(EBuiltInOps::CopyBufferToImage3d,
286 pCmdQ->getClDevice());
287 ASSERT_NE(nullptr, &builder);
288
289 BuiltinOpParams dc;
290 dc.srcPtr = EnqueueWriteImageTraits::hostPtr;
291 dc.dstMemObj = dstImage;
292 dc.dstOffset = EnqueueWriteImageTraits::origin;
293 dc.size = EnqueueWriteImageTraits::region;
294 dc.dstRowPitch = EnqueueWriteImageTraits::rowPitch;
295 dc.dstSlicePitch = EnqueueWriteImageTraits::slicePitch;
296
297 MultiDispatchInfo multiDispatchInfo(dc);
298 builder.buildDispatchInfos(multiDispatchInfo);
299 EXPECT_NE(0u, multiDispatchInfo.size());
300
301 auto kernel = multiDispatchInfo.begin()->getKernel();
302 ASSERT_NE(nullptr, kernel);
303
304 auto usedAfterCS = commandStream.getUsed();
305 auto usedAfterDSH = dsh.getUsed();
306 auto usedAfterIOH = ioh.getUsed();
307 auto usedAfterSSH = ssh.getUsed();
308
309 auto expectedSizeCS = EnqueueOperation<FamilyType>::getSizeRequiredCS(CL_COMMAND_WRITE_IMAGE, false, false, *pCmdQ, kernel, {});
310 auto expectedSizeDSH = HardwareCommandsHelper<FamilyType>::getSizeRequiredDSH(*kernel);
311 auto expectedSizeIOH = HardwareCommandsHelper<FamilyType>::getSizeRequiredIOH(*kernel);
312 auto expectedSizeSSH = HardwareCommandsHelper<FamilyType>::getSizeRequiredSSH(*kernel);
313
314 // Since each enqueue* may flush, we may see a MI_BATCH_BUFFER_END appended.
315 expectedSizeCS += sizeof(typename FamilyType::MI_BATCH_BUFFER_END);
316 expectedSizeCS = alignUp(expectedSizeCS, MemoryConstants::cacheLineSize);
317
318 EXPECT_GE(expectedSizeCS, usedAfterCS - usedBeforeCS);
319 EXPECT_GE(expectedSizeDSH, usedAfterDSH - usedBeforeDSH);
320 EXPECT_GE(expectedSizeIOH, usedAfterIOH - usedBeforeIOH);
321 EXPECT_GE(expectedSizeSSH, usedAfterSSH - usedBeforeSSH);
322 }
323
HWTEST_F(GetSizeRequiredImageTest,WhenWritingImageBlockingThenHeapsAndCommandBufferConsumedMinimumRequiredSize)324 HWTEST_F(GetSizeRequiredImageTest, WhenWritingImageBlockingThenHeapsAndCommandBufferConsumedMinimumRequiredSize) {
325 auto &commandStream = pCmdQ->getCS(1024);
326 auto usedBeforeCS = commandStream.getUsed();
327 auto &dsh = pCmdQ->getIndirectHeap(IndirectHeap::DYNAMIC_STATE, 0u);
328 auto &ioh = pCmdQ->getIndirectHeap(IndirectHeap::INDIRECT_OBJECT, 0u);
329 auto &ssh = pCmdQ->getIndirectHeap(IndirectHeap::SURFACE_STATE, 0u);
330 auto usedBeforeDSH = dsh.getUsed();
331 auto usedBeforeIOH = ioh.getUsed();
332 auto usedBeforeSSH = ssh.getUsed();
333
334 auto retVal = EnqueueWriteImageHelper<>::enqueueWriteImage(
335 pCmdQ,
336 dstImage,
337 CL_TRUE);
338 EXPECT_EQ(CL_SUCCESS, retVal);
339
340 auto &builder = BuiltInDispatchBuilderOp::getBuiltinDispatchInfoBuilder(EBuiltInOps::CopyBufferToImage3d,
341 pCmdQ->getClDevice());
342 ASSERT_NE(nullptr, &builder);
343
344 BuiltinOpParams dc;
345 dc.srcPtr = EnqueueWriteImageTraits::hostPtr;
346 dc.dstMemObj = dstImage;
347 dc.dstOffset = EnqueueWriteImageTraits::origin;
348 dc.size = EnqueueWriteImageTraits::region;
349 dc.dstRowPitch = EnqueueWriteImageTraits::rowPitch;
350 dc.dstSlicePitch = EnqueueWriteImageTraits::slicePitch;
351
352 MultiDispatchInfo multiDispatchInfo(dc);
353 builder.buildDispatchInfos(multiDispatchInfo);
354 EXPECT_NE(0u, multiDispatchInfo.size());
355
356 auto kernel = multiDispatchInfo.begin()->getKernel();
357 ASSERT_NE(nullptr, kernel);
358
359 auto usedAfterCS = commandStream.getUsed();
360 auto usedAfterDSH = dsh.getUsed();
361 auto usedAfterIOH = ioh.getUsed();
362 auto usedAfterSSH = ssh.getUsed();
363
364 auto expectedSizeCS = EnqueueOperation<FamilyType>::getSizeRequiredCS(CL_COMMAND_WRITE_IMAGE, false, false, *pCmdQ, kernel, {});
365 auto expectedSizeDSH = HardwareCommandsHelper<FamilyType>::getSizeRequiredDSH(*kernel);
366 auto expectedSizeIOH = HardwareCommandsHelper<FamilyType>::getSizeRequiredIOH(*kernel);
367 auto expectedSizeSSH = HardwareCommandsHelper<FamilyType>::getSizeRequiredSSH(*kernel);
368
369 // Since each enqueue* may flush, we may see a MI_BATCH_BUFFER_END appended.
370 expectedSizeCS += sizeof(typename FamilyType::MI_BATCH_BUFFER_END);
371 expectedSizeCS = alignUp(expectedSizeCS, MemoryConstants::cacheLineSize);
372
373 EXPECT_GE(expectedSizeCS, usedAfterCS - usedBeforeCS);
374 EXPECT_GE(expectedSizeDSH, usedAfterDSH - usedBeforeDSH);
375 EXPECT_GE(expectedSizeIOH, usedAfterIOH - usedBeforeIOH);
376 EXPECT_GE(expectedSizeSSH, usedAfterSSH - usedBeforeSSH);
377 }
378