1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Vulkan Fill Buffer Tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktApiFillBufferTests.hpp"
26 #include "vktApiBufferAndImageAllocationUtil.hpp"
27
28 #include "deStringUtil.hpp"
29 #include "deUniquePtr.hpp"
30 #include "vkImageUtil.hpp"
31 #include "vkMemUtil.hpp"
32 #include "vkCmdUtil.hpp"
33 #include "vktTestCase.hpp"
34 #include "vktTestCaseUtil.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkRefUtil.hpp"
37 #include "vkCmdUtil.hpp"
38 #include "tcuImageCompare.hpp"
39 #include "tcuTexture.hpp"
40 #include "tcuTextureUtil.hpp"
41 #include "tcuVectorType.hpp"
42 #include "deSharedPtr.hpp"
43
44 namespace vkt
45 {
46
47 namespace api
48 {
49
50 using namespace vk;
51
52 namespace
53 {
54
55 struct TestParams
56 {
57 enum
58 {
59 TEST_DATA_SIZE = 256
60 };
61
62 VkDeviceSize dstSize;
63 VkDeviceSize dstOffset;
64 VkDeviceSize size;
65 deUint32 testData[TEST_DATA_SIZE];
66 de::SharedPtr<IBufferAllocator> bufferAllocator;
67 };
68
69 class FillBufferTestInstance : public vkt::TestInstance
70 {
71 public:
72 FillBufferTestInstance (Context& context,
73 TestParams testParams);
74 virtual tcu::TestStatus iterate (void);
75 protected:
76 const TestParams m_params;
77
78 Move<VkCommandPool> m_cmdPool;
79 Move<VkCommandBuffer> m_cmdBuffer;
80 de::MovePtr<tcu::TextureLevel> m_destinationTextureLevel;
81 de::MovePtr<tcu::TextureLevel> m_expectedTextureLevel;
82
83 VkCommandBufferBeginInfo m_cmdBufferBeginInfo;
84
85 Move<VkBuffer> m_destination;
86 de::MovePtr<Allocation> m_destinationBufferAlloc;
87
88 void generateBuffer (tcu::PixelBufferAccess buffer,
89 int width,
90 int height,
91 int depth = 1);
92 virtual void generateExpectedResult (void);
93 void uploadBuffer (tcu::ConstPixelBufferAccess
94 bufferAccess,
95 const Allocation& bufferAlloc);
96 virtual tcu::TestStatus checkTestResult (tcu::ConstPixelBufferAccess
97 result);
calculateSize(tcu::ConstPixelBufferAccess src) const98 deUint32 calculateSize (tcu::ConstPixelBufferAccess
99 src) const
100 {
101 return src.getWidth() * src.getHeight() * src.getDepth() * tcu::getPixelSize(src.getFormat());
102 }
103 };
104
FillBufferTestInstance(Context & context,TestParams testParams)105 FillBufferTestInstance::FillBufferTestInstance
106 (Context& context,
107 TestParams testParams)
108 : vkt::TestInstance (context)
109 , m_params (testParams)
110 {
111 const DeviceInterface& vk = context.getDeviceInterface();
112 const VkDevice vkDevice = context.getDevice();
113 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
114 Allocator& memAlloc = context.getDefaultAllocator();
115
116 // Create command pool
117 m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
118
119 // Create command buffer
120 m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
121
122 testParams.bufferAllocator->createTestBuffer(m_params.dstSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, context, memAlloc, m_destination, MemoryRequirement::HostVisible, m_destinationBufferAlloc);
123 }
124
iterate(void)125 tcu::TestStatus FillBufferTestInstance::iterate (void)
126 {
127 const int dstLevelWidth = (int)(m_params.dstSize / 4);
128 m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(mapVkFormat(VK_FORMAT_R8G8B8A8_UINT), dstLevelWidth, 1));
129
130 generateBuffer(m_destinationTextureLevel->getAccess(), dstLevelWidth, 1, 1);
131
132 generateExpectedResult();
133
134 uploadBuffer(m_destinationTextureLevel->getAccess(), *m_destinationBufferAlloc);
135
136 const DeviceInterface& vk = m_context.getDeviceInterface();
137 const VkDevice vkDevice = m_context.getDevice();
138 const VkQueue queue = m_context.getUniversalQueue();
139
140 const VkBufferMemoryBarrier dstBufferBarrier =
141 {
142 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
143 DE_NULL, // const void* pNext;
144 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
145 VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
146 VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
147 VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
148 *m_destination, // VkBuffer buffer;
149 m_params.dstOffset, // VkDeviceSize offset;
150 VK_WHOLE_SIZE // VkDeviceSize size;
151 };
152
153 beginCommandBuffer(vk, *m_cmdBuffer);
154 vk.cmdFillBuffer(*m_cmdBuffer, *m_destination, m_params.dstOffset, m_params.size, m_params.testData[0]);
155 vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &dstBufferBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
156 endCommandBuffer(vk, *m_cmdBuffer);
157
158 submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get());
159
160 // Read buffer data
161 de::MovePtr<tcu::TextureLevel> resultLevel (new tcu::TextureLevel(m_destinationTextureLevel->getAccess().getFormat(), dstLevelWidth, 1));
162 invalidateAlloc(vk, vkDevice, *m_destinationBufferAlloc);
163 tcu::copy(*resultLevel, tcu::ConstPixelBufferAccess(resultLevel->getFormat(), resultLevel->getSize(), m_destinationBufferAlloc->getHostPtr()));
164
165 return checkTestResult(resultLevel->getAccess());
166 }
167
generateBuffer(tcu::PixelBufferAccess buffer,int width,int height,int depth)168 void FillBufferTestInstance::generateBuffer
169 (tcu::PixelBufferAccess buffer,
170 int width,
171 int height,
172 int depth)
173 {
174 for (int z = 0; z < depth; z++)
175 {
176 for (int y = 0; y < height; y++)
177 {
178 for (int x = 0; x < width; x++)
179 buffer.setPixel(tcu::UVec4(x, y, z, 255), x, y, z);
180 }
181 }
182 }
183
uploadBuffer(tcu::ConstPixelBufferAccess bufferAccess,const Allocation & bufferAlloc)184 void FillBufferTestInstance::uploadBuffer
185 (tcu::ConstPixelBufferAccess
186 bufferAccess,
187 const Allocation& bufferAlloc)
188 {
189 const DeviceInterface& vk = m_context.getDeviceInterface();
190 const VkDevice vkDevice = m_context.getDevice();
191 const deUint32 bufferSize = calculateSize(bufferAccess);
192
193 // Write buffer data
194 deMemcpy(bufferAlloc.getHostPtr(), bufferAccess.getDataPtr(), bufferSize);
195 flushAlloc(vk, vkDevice, bufferAlloc);
196 }
197
checkTestResult(tcu::ConstPixelBufferAccess result)198 tcu::TestStatus FillBufferTestInstance::checkTestResult
199 (tcu::ConstPixelBufferAccess
200 result)
201 {
202 const tcu::ConstPixelBufferAccess
203 expected = m_expectedTextureLevel->getAccess();
204 const tcu::UVec4 threshold (0, 0, 0, 0);
205
206 if (!tcu::intThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparsion", expected, result, threshold, tcu::COMPARE_LOG_RESULT))
207 {
208 return tcu::TestStatus::fail("Fill and Update Buffer test");
209 }
210
211 return tcu::TestStatus::pass("Fill and Update Buffer test");
212 }
213
generateExpectedResult(void)214 void FillBufferTestInstance::generateExpectedResult
215 (void)
216 {
217 const tcu::ConstPixelBufferAccess
218 dst = m_destinationTextureLevel->getAccess();
219
220 m_expectedTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(dst.getFormat(), dst.getWidth(), dst.getHeight(), dst.getDepth()));
221 tcu::copy(m_expectedTextureLevel->getAccess(), dst);
222
223 deUint32* currentPtr = (deUint32*) m_expectedTextureLevel->getAccess().getDataPtr() + m_params.dstOffset / 4;
224 deUint32* endPtr = currentPtr + m_params.size / 4;
225
226 while (currentPtr < endPtr)
227 {
228 *currentPtr = m_params.testData[0];
229 currentPtr++;
230 }
231 }
232
233 class FillBufferTestCase : public vkt::TestCase
234 {
235 public:
FillBufferTestCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams params)236 FillBufferTestCase (tcu::TestContext& testCtx,
237 const std::string& name,
238 const std::string& description,
239 const TestParams params)
240 : vkt::TestCase (testCtx, name, description)
241 , m_params (params)
242 {}
243
createInstance(Context & context) const244 virtual TestInstance* createInstance (Context& context) const
245 {
246 return static_cast<TestInstance*>(new FillBufferTestInstance(context, m_params));
247 }
248 private:
249 const TestParams m_params;
250 };
251
252 // Update Buffer
253
254 class UpdateBufferTestInstance : public FillBufferTestInstance
255 {
256 public:
UpdateBufferTestInstance(Context & context,TestParams testParams)257 UpdateBufferTestInstance (Context& context,
258 TestParams testParams)
259 : FillBufferTestInstance (context, testParams)
260 {}
261 virtual tcu::TestStatus iterate (void);
262
263 protected:
264 virtual void generateExpectedResult (void);
265 };
266
iterate(void)267 tcu::TestStatus UpdateBufferTestInstance::iterate (void)
268 {
269 const int dstLevelWidth = (int)(m_params.dstSize / 4);
270 m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(mapVkFormat(VK_FORMAT_R8G8B8A8_UINT), dstLevelWidth, 1));
271
272 generateBuffer(m_destinationTextureLevel->getAccess(), dstLevelWidth, 1, 1);
273
274 generateExpectedResult();
275
276 uploadBuffer(m_destinationTextureLevel->getAccess(), *m_destinationBufferAlloc);
277
278 const DeviceInterface& vk = m_context.getDeviceInterface();
279 const VkDevice vkDevice = m_context.getDevice();
280 const VkQueue queue = m_context.getUniversalQueue();
281
282 const VkBufferMemoryBarrier dstBufferBarrier =
283 {
284 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
285 DE_NULL, // const void* pNext;
286 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
287 VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
288 VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
289 VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
290 *m_destination, // VkBuffer buffer;
291 m_params.dstOffset, // VkDeviceSize offset;
292 VK_WHOLE_SIZE // VkDeviceSize size;
293 };
294
295 beginCommandBuffer(vk, *m_cmdBuffer);
296 vk.cmdUpdateBuffer(*m_cmdBuffer, *m_destination, m_params.dstOffset, m_params.size, m_params.testData);
297 vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &dstBufferBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
298 endCommandBuffer(vk, *m_cmdBuffer);
299
300 submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get());
301
302 // Read buffer data
303 de::MovePtr<tcu::TextureLevel> resultLevel (new tcu::TextureLevel(m_destinationTextureLevel->getAccess().getFormat(), dstLevelWidth, 1));
304 invalidateAlloc(vk, vkDevice, *m_destinationBufferAlloc);
305 tcu::copy(*resultLevel, tcu::ConstPixelBufferAccess(resultLevel->getFormat(), resultLevel->getSize(), m_destinationBufferAlloc->getHostPtr()));
306
307 return checkTestResult(resultLevel->getAccess());
308 }
309
generateExpectedResult(void)310 void UpdateBufferTestInstance::generateExpectedResult
311 (void)
312 {
313 const tcu::ConstPixelBufferAccess
314 dst = m_destinationTextureLevel->getAccess();
315
316 m_expectedTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(dst.getFormat(), dst.getWidth(), dst.getHeight(), dst.getDepth()));
317 tcu::copy(m_expectedTextureLevel->getAccess(), dst);
318
319 deUint32* currentPtr = (deUint32*) m_expectedTextureLevel->getAccess().getDataPtr() + m_params.dstOffset / 4;
320
321 deMemcpy(currentPtr, m_params.testData, (size_t)m_params.size);
322 }
323
324 class UpdateBufferTestCase : public vkt::TestCase
325 {
326 public:
UpdateBufferTestCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams params)327 UpdateBufferTestCase (tcu::TestContext& testCtx,
328 const std::string& name,
329 const std::string& description,
330 const TestParams params)
331 : vkt::TestCase (testCtx, name, description)
332 , m_params (params)
333 {}
334
createInstance(Context & context) const335 virtual TestInstance* createInstance (Context& context) const
336 {
337 return (TestInstance*) new UpdateBufferTestInstance(context, m_params);
338 }
339 private:
340 TestParams m_params;
341 };
342
343 } // anonymous
344
createFillAndUpdateBufferTests(tcu::TestContext & testCtx)345 tcu::TestCaseGroup* createFillAndUpdateBufferTests (tcu::TestContext& testCtx)
346 {
347 const de::SharedPtr<IBufferAllocator>
348 bufferAllocators[] =
349 {
350 de::SharedPtr<BufferSuballocation>(new BufferSuballocation()),
351 de::SharedPtr<BufferDedicatedAllocation>(new BufferDedicatedAllocation())
352 };
353
354 de::MovePtr<tcu::TestCaseGroup> fillAndUpdateBufferTests (new tcu::TestCaseGroup(testCtx, "fill_and_update_buffer", "Fill and Update Buffer Tests"));
355 tcu::TestCaseGroup* bufferViewAllocationGroupTests[]
356 =
357 {
358 new tcu::TestCaseGroup(testCtx, "suballocation", "BufferView Fill and Update Tests for Suballocated Objects"),
359 new tcu::TestCaseGroup(testCtx, "dedicated_alloc", "BufferView Fill and Update Tests for Dedicatedly Allocated Objects")
360 };
361 for (deUint32 subgroupNdx = 0u; subgroupNdx < DE_LENGTH_OF_ARRAY(bufferViewAllocationGroupTests); ++subgroupNdx)
362 {
363 if (bufferViewAllocationGroupTests[subgroupNdx] == DE_NULL)
364 {
365 TCU_THROW(InternalError, "Could not create test subgroup.");
366 }
367 fillAndUpdateBufferTests->addChild(bufferViewAllocationGroupTests[subgroupNdx]);
368 }
369 TestParams params;
370 params.dstSize = TestParams::TEST_DATA_SIZE;
371
372
373 for (deUint32 buffersAllocationNdx = 0u; buffersAllocationNdx < DE_LENGTH_OF_ARRAY(bufferAllocators); ++buffersAllocationNdx)
374 {
375 DE_ASSERT(params.dstSize <= TestParams::TEST_DATA_SIZE);
376 deUint8* data = (deUint8*) params.testData;
377 for (deUint32 b = 0u; b < (params.dstSize * sizeof(params.testData[0])); b++)
378 data[b] = (deUint8) (b % 255);
379 params.bufferAllocator = bufferAllocators[buffersAllocationNdx];
380 const deUint32 testCaseGroupNdx = buffersAllocationNdx;
381 tcu::TestCaseGroup* currentTestsGroup = bufferViewAllocationGroupTests[testCaseGroupNdx];
382
383 {
384 const std::string description ("whole buffer");
385 const std::string testName ("buffer_whole");
386
387 params.dstOffset = 0;
388 params.size = params.dstSize;
389
390 currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, "Fill " + description, params));
391 currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, "Update " + description, params));
392 }
393
394 {
395 const std::string description ("first word in buffer");
396 const std::string testName ("buffer_first_one");
397
398 params.dstOffset = 0;
399 params.size = 4;
400
401 currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, "Fill " + description, params));
402 currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, "Update " + description, params));
403 }
404
405 {
406 const std::string description ("second word in buffer");
407 const std::string testName ("buffer_second_one");
408
409 params.dstOffset = 4;
410 params.size = 4;
411
412 currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, "Fill " + description, params));
413 currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, "Update " + description, params));
414 }
415
416 {
417 const std::string description ("buffer second part");
418 const std::string testName ("buffer_second_part");
419
420 params.dstOffset = params.dstSize / 2;
421 params.size = params.dstSize / 2;
422
423 currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, "Fill " + description, params));
424 currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, "Update " + description, params));
425 }
426 }
427
428 return fillAndUpdateBufferTests.release();
429 }
430
431 } // api
432 } // vkt
433