1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file vktSparseResourcesImageSparseResidency.cpp
21 * \brief Sparse partially resident images tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktSparseResourcesBufferSparseBinding.hpp"
25 #include "vktSparseResourcesTestsUtil.hpp"
26 #include "vktSparseResourcesBase.hpp"
27 #include "vktTestCaseUtil.hpp"
28
29 #include "vkDefs.hpp"
30 #include "vkRef.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vkPlatform.hpp"
33 #include "vkPrograms.hpp"
34 #include "vkMemUtil.hpp"
35 #include "vkBarrierUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkTypeUtil.hpp"
40 #include "vkCmdUtil.hpp"
41 #include "vkObjUtil.hpp"
42 #include "tcuTestLog.hpp"
43
44 #include "deMath.h"
45 #include "deUniquePtr.hpp"
46 #include "deStringUtil.hpp"
47
48 #include "tcuTextureUtil.hpp"
49 #include "tcuTexVerifierUtil.hpp"
50
51 #include <string>
52 #include <vector>
53 #include <sstream>
54
55 using namespace vk;
56
57 namespace vkt
58 {
59 namespace sparse
60 {
61 namespace
62 {
63
getFormatValueString(const std::vector<std::pair<deUint32,deUint32>> & channelsOnPlane,const std::vector<std::string> & formatValueStrings)64 std::string getFormatValueString (const std::vector<std::pair<deUint32, deUint32>>& channelsOnPlane,
65 const std::vector<std::string>& formatValueStrings)
66 {
67 std::string result = "( ";
68 deUint32 i;
69 for (i=0; i<channelsOnPlane.size(); ++i)
70 {
71 result += formatValueStrings[channelsOnPlane[i].first];
72 if (i < 3)
73 result += ", ";
74 }
75 for (; i < 4; ++i)
76 {
77 result += "0";
78 if (i < 3)
79 result += ", ";
80 }
81 result += " )";
82 return result;
83 }
84
getCoordStr(const ImageType imageType,const std::string & x,const std::string & y,const std::string & z)85 const std::string getCoordStr (const ImageType imageType,
86 const std::string& x,
87 const std::string& y,
88 const std::string& z)
89 {
90 switch (imageType)
91 {
92 case IMAGE_TYPE_1D:
93 case IMAGE_TYPE_BUFFER:
94 return x;
95
96 case IMAGE_TYPE_1D_ARRAY:
97 case IMAGE_TYPE_2D:
98 return "ivec2(" + x + "," + y + ")";
99
100 case IMAGE_TYPE_2D_ARRAY:
101 case IMAGE_TYPE_3D:
102 case IMAGE_TYPE_CUBE:
103 case IMAGE_TYPE_CUBE_ARRAY:
104 return "ivec3(" + x + "," + y + "," + z + ")";
105
106 default:
107 DE_ASSERT(false);
108 return "";
109 }
110 }
111
computeWorkGroupSize(const VkExtent3D & planeExtent)112 tcu::UVec3 computeWorkGroupSize (const VkExtent3D& planeExtent)
113 {
114 const deUint32 maxComputeWorkGroupInvocations = 128u;
115 const tcu::UVec3 maxComputeWorkGroupSize = tcu::UVec3(128u, 128u, 64u);
116
117 const deUint32 xWorkGroupSize = std::min(std::min(planeExtent.width, maxComputeWorkGroupSize.x()), maxComputeWorkGroupInvocations);
118 const deUint32 yWorkGroupSize = std::min(std::min(planeExtent.height, maxComputeWorkGroupSize.y()), maxComputeWorkGroupInvocations / xWorkGroupSize);
119 const deUint32 zWorkGroupSize = std::min(std::min(planeExtent.depth, maxComputeWorkGroupSize.z()), maxComputeWorkGroupInvocations / (xWorkGroupSize*yWorkGroupSize));
120
121 return tcu::UVec3(xWorkGroupSize, yWorkGroupSize, zWorkGroupSize);
122 }
123
124 class ImageSparseResidencyCase : public TestCase
125 {
126 public:
127 ImageSparseResidencyCase (tcu::TestContext& testCtx,
128 const std::string& name,
129 const std::string& description,
130 const ImageType imageType,
131 const tcu::UVec3& imageSize,
132 const VkFormat format,
133 const glu::GLSLVersion glslVersion,
134 const bool useDeviceGroups);
135
136 void initPrograms (SourceCollections& sourceCollections) const;
137 virtual void checkSupport (Context& context) const;
138 TestInstance* createInstance (Context& context) const;
139
140 private:
141 const bool m_useDeviceGroups;
142 const ImageType m_imageType;
143 const tcu::UVec3 m_imageSize;
144 const VkFormat m_format;
145 const glu::GLSLVersion m_glslVersion;
146 };
147
ImageSparseResidencyCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const ImageType imageType,const tcu::UVec3 & imageSize,const VkFormat format,const glu::GLSLVersion glslVersion,const bool useDeviceGroups)148 ImageSparseResidencyCase::ImageSparseResidencyCase (tcu::TestContext& testCtx,
149 const std::string& name,
150 const std::string& description,
151 const ImageType imageType,
152 const tcu::UVec3& imageSize,
153 const VkFormat format,
154 const glu::GLSLVersion glslVersion,
155 const bool useDeviceGroups)
156 : TestCase (testCtx, name, description)
157 , m_useDeviceGroups (useDeviceGroups)
158 , m_imageType (imageType)
159 , m_imageSize (imageSize)
160 , m_format (format)
161 , m_glslVersion (glslVersion)
162 {
163 }
164
initPrograms(SourceCollections & sourceCollections) const165 void ImageSparseResidencyCase::initPrograms (SourceCollections& sourceCollections) const
166 {
167 // Create compute program
168 const char* const versionDecl = glu::getGLSLVersionDeclaration(m_glslVersion);
169 const PlanarFormatDescription formatDescription = getPlanarFormatDescription(m_format);
170 const std::string imageTypeStr = getShaderImageType(formatDescription, m_imageType);
171 const std::string formatDataStr = getShaderImageDataType(formatDescription);
172 const tcu::UVec3 shaderGridSize = getShaderGridSize(m_imageType, m_imageSize);
173
174 std::vector<std::string> formatValueStrings;
175 switch (formatDescription.channels[0].type)
176 {
177 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
178 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
179 formatValueStrings = {
180 "int(gl_GlobalInvocationID.x) % 127",
181 "int(gl_GlobalInvocationID.y) % 127",
182 "int(gl_GlobalInvocationID.z) % 127",
183 "1"
184 };
185 break;
186 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
187 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
188 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
189 formatValueStrings = {
190 "float(int(gl_GlobalInvocationID.x) % 127) / 127.0" ,
191 "float(int(gl_GlobalInvocationID.y) % 127) / 127.0",
192 "float(int(gl_GlobalInvocationID.z) % 127) / 127.0",
193 "1.0"
194 };
195 break;
196 default: DE_ASSERT(false); break;
197 }
198
199 for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
200 {
201 VkFormat planeCompatibleFormat = getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
202 vk::PlanarFormatDescription compatibleFormatDescription = (planeCompatibleFormat != getPlaneCompatibleFormat(formatDescription, planeNdx)) ? getPlanarFormatDescription(planeCompatibleFormat) : formatDescription;
203 VkExtent3D compatibleShaderGridSize { shaderGridSize.x() / formatDescription.blockWidth, shaderGridSize.y() / formatDescription.blockHeight, shaderGridSize.z() / 1u };
204
205 std::vector<std::pair<deUint32, deUint32>> channelsOnPlane;
206 for (deUint32 channelNdx = 0; channelNdx < 4; ++channelNdx)
207 {
208 if (!formatDescription.hasChannelNdx(channelNdx))
209 continue;
210 if (formatDescription.channels[channelNdx].planeNdx != planeNdx)
211 continue;
212 channelsOnPlane.push_back({ channelNdx,formatDescription.channels[channelNdx].offsetBits });
213 }
214 // reorder channels for multi-planar images
215 if(formatDescription.numPlanes>1)
216 std::sort(begin(channelsOnPlane), end(channelsOnPlane), [](const std::pair<deUint32, deUint32>& lhs, const std::pair<deUint32, deUint32>& rhs) { return lhs.second < rhs.second; });
217 std::string formatValueStr = getFormatValueString(channelsOnPlane, formatValueStrings);
218 VkExtent3D shaderExtent = getPlaneExtent(compatibleFormatDescription, compatibleShaderGridSize, planeNdx, 0);
219 const std::string formatQualifierStr = getShaderImageFormatQualifier(planeCompatibleFormat);
220 const tcu::UVec3 workGroupSize = computeWorkGroupSize(shaderExtent);
221
222 std::ostringstream src;
223 src << versionDecl << "\n";
224 if (formatIsR64(m_format))
225 {
226 src << "#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require\n"
227 << "#extension GL_EXT_shader_image_int64 : require\n";
228 }
229 src << "layout (local_size_x = " << workGroupSize.x() << ", local_size_y = " << workGroupSize.y() << ", local_size_z = " << workGroupSize.z() << ") in; \n"
230 << "layout (binding = 0, " << formatQualifierStr << ") writeonly uniform highp " << imageTypeStr << " u_image;\n"
231 << "void main (void)\n"
232 << "{\n"
233 << " if( gl_GlobalInvocationID.x < " << shaderExtent.width << " ) \n"
234 << " if( gl_GlobalInvocationID.y < " << shaderExtent.height << " ) \n"
235 << " if( gl_GlobalInvocationID.z < " << shaderExtent.depth << " ) \n"
236 << " {\n"
237 << " imageStore(u_image, " << getCoordStr(m_imageType, "gl_GlobalInvocationID.x", "gl_GlobalInvocationID.y", "gl_GlobalInvocationID.z") << ","
238 << formatDataStr << formatValueStr << ");\n"
239 << " }\n"
240 << "}\n";
241 std::ostringstream shaderName;
242 shaderName << "comp" << planeNdx;
243 sourceCollections.glslSources.add(shaderName.str()) << glu::ComputeSource(src.str())
244 << vk::ShaderBuildOptions(sourceCollections.usedVulkanVersion, vk::SPIRV_VERSION_1_3, vk::ShaderBuildOptions::FLAG_ALLOW_SCALAR_OFFSETS);
245 }
246 }
247
checkSupport(Context & context) const248 void ImageSparseResidencyCase::checkSupport(Context& context) const
249 {
250 const InstanceInterface& instance = context.getInstanceInterface();
251 const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
252
253 // Check if image size does not exceed device limits
254 if (!isImageSizeSupported(instance, physicalDevice, m_imageType, m_imageSize))
255 TCU_THROW(NotSupportedError, "Image size not supported for device");
256
257 // Check if device supports sparse operations for image type
258 if (!checkSparseSupportForImageType(instance, physicalDevice, m_imageType))
259 TCU_THROW(NotSupportedError, "Sparse residency for image type is not supported");
260
261 //Check if image format supports storage images
262 const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(instance, physicalDevice, m_format);
263 if ((formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0)
264 TCU_THROW(NotSupportedError, "Storage images are not supported for this format");
265
266 if (formatIsR64(m_format))
267 {
268 context.requireDeviceFunctionality("VK_EXT_shader_image_atomic_int64");
269
270 if (context.getShaderImageAtomicInt64FeaturesEXT().shaderImageInt64Atomics == VK_FALSE)
271 {
272 TCU_THROW(NotSupportedError, "shaderImageInt64Atomics is not supported");
273 }
274
275 if (context.getShaderImageAtomicInt64FeaturesEXT().sparseImageInt64Atomics == VK_FALSE)
276 {
277 TCU_THROW(NotSupportedError, "sparseImageInt64Atomics is not supported for device");
278 }
279 }
280 }
281
282 class ImageSparseResidencyInstance : public SparseResourcesBaseInstance
283 {
284 public:
285 ImageSparseResidencyInstance (Context& context,
286 const ImageType imageType,
287 const tcu::UVec3& imageSize,
288 const VkFormat format,
289 const bool useDeviceGroups);
290
291
292 tcu::TestStatus iterate (void);
293
294 private:
295 const bool m_useDeviceGroups;
296 const ImageType m_imageType;
297 const tcu::UVec3 m_imageSize;
298 const VkFormat m_format;
299 };
300
ImageSparseResidencyInstance(Context & context,const ImageType imageType,const tcu::UVec3 & imageSize,const VkFormat format,const bool useDeviceGroups)301 ImageSparseResidencyInstance::ImageSparseResidencyInstance (Context& context,
302 const ImageType imageType,
303 const tcu::UVec3& imageSize,
304 const VkFormat format,
305 const bool useDeviceGroups)
306 : SparseResourcesBaseInstance (context, useDeviceGroups)
307 , m_useDeviceGroups (useDeviceGroups)
308 , m_imageType (imageType)
309 , m_imageSize (imageSize)
310 , m_format (format)
311 {
312 }
313
iterate(void)314 tcu::TestStatus ImageSparseResidencyInstance::iterate (void)
315 {
316 const float epsilon = 1e-5f;
317 const InstanceInterface& instance = m_context.getInstanceInterface();
318
319 {
320 // Create logical device supporting both sparse and compute queues
321 QueueRequirementsVec queueRequirements;
322 queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
323 queueRequirements.push_back(QueueRequirements(VK_QUEUE_COMPUTE_BIT, 1u));
324
325 createDeviceSupportingQueues(queueRequirements);
326 }
327
328 VkImageCreateInfo imageCreateInfo;
329 std::vector<DeviceMemorySp> deviceMemUniquePtrVec;
330
331 const DeviceInterface& deviceInterface = getDeviceInterface();
332 const Queue& sparseQueue = getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0);
333 const Queue& computeQueue = getQueue(VK_QUEUE_COMPUTE_BIT, 0);
334 const PlanarFormatDescription formatDescription = getPlanarFormatDescription(m_format);
335
336 // Go through all physical devices
337 for (deUint32 physDevID = 0; physDevID < m_numPhysicalDevices; physDevID++)
338 {
339 const deUint32 firstDeviceID = physDevID;
340 const deUint32 secondDeviceID = (firstDeviceID + 1) % m_numPhysicalDevices;
341
342 const VkPhysicalDevice physicalDevice = getPhysicalDevice(firstDeviceID);
343 const VkPhysicalDeviceProperties physicalDeviceProperties = getPhysicalDeviceProperties(instance, physicalDevice);
344
345 imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
346 imageCreateInfo.pNext = DE_NULL;
347 imageCreateInfo.flags = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_BINDING_BIT;
348 imageCreateInfo.imageType = mapImageType(m_imageType);
349 imageCreateInfo.format = m_format;
350 imageCreateInfo.extent = makeExtent3D(getLayerSize(m_imageType, m_imageSize));
351 imageCreateInfo.mipLevels = 1u;
352 imageCreateInfo.arrayLayers = getNumLayers(m_imageType, m_imageSize);
353 imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
354 imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
355 imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
356 imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
357 VK_IMAGE_USAGE_STORAGE_BIT;
358 imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
359 imageCreateInfo.queueFamilyIndexCount = 0u;
360 imageCreateInfo.pQueueFamilyIndices = DE_NULL;
361
362 if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
363 {
364 imageCreateInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
365 }
366
367 // check if we need to create VkImageView with different VkFormat than VkImage format
368 VkFormat planeCompatibleFormat0 = getPlaneCompatibleFormatForWriting(formatDescription, 0);
369 if (planeCompatibleFormat0 != getPlaneCompatibleFormat(formatDescription, 0))
370 {
371 imageCreateInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
372 }
373
374 // Check if device supports sparse operations for image format
375 if (!checkSparseSupportForImageFormat(instance, physicalDevice, imageCreateInfo))
376 TCU_THROW(NotSupportedError, "The image format does not support sparse operations");
377
378 // Create sparse image
379 const Unique<VkImage> imageSparse(createImage(deviceInterface, getDevice(), &imageCreateInfo));
380
381 // Create sparse image memory bind semaphore
382 const Unique<VkSemaphore> imageMemoryBindSemaphore(createSemaphore(deviceInterface, getDevice()));
383
384 std::vector<VkSparseImageMemoryRequirements> sparseMemoryRequirements;
385
386 {
387 // Get image general memory requirements
388 const VkMemoryRequirements imageMemoryRequirements = getImageMemoryRequirements(deviceInterface, getDevice(), *imageSparse);
389
390 if (imageMemoryRequirements.size > physicalDeviceProperties.limits.sparseAddressSpaceSize)
391 TCU_THROW(NotSupportedError, "Required memory size for sparse resource exceeds device limits");
392
393 DE_ASSERT((imageMemoryRequirements.size % imageMemoryRequirements.alignment) == 0);
394
395 const deUint32 memoryType = findMatchingMemoryType(instance, getPhysicalDevice(secondDeviceID), imageMemoryRequirements, MemoryRequirement::Any);
396
397 if (memoryType == NO_MATCH_FOUND)
398 return tcu::TestStatus::fail("No matching memory type found");
399
400 if (firstDeviceID != secondDeviceID)
401 {
402 VkPeerMemoryFeatureFlags peerMemoryFeatureFlags = (VkPeerMemoryFeatureFlags)0;
403 const deUint32 heapIndex = getHeapIndexForMemoryType(instance, getPhysicalDevice(secondDeviceID), memoryType);
404 deviceInterface.getDeviceGroupPeerMemoryFeatures(getDevice(), heapIndex, firstDeviceID, secondDeviceID, &peerMemoryFeatureFlags);
405
406 if (((peerMemoryFeatureFlags & VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT) == 0) ||
407 ((peerMemoryFeatureFlags & VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT) == 0))
408 {
409 TCU_THROW(NotSupportedError, "Peer memory does not support COPY_SRC and GENERIC_DST");
410 }
411 }
412
413 // Get sparse image sparse memory requirements
414 sparseMemoryRequirements = getImageSparseMemoryRequirements(deviceInterface, getDevice(), *imageSparse);
415 DE_ASSERT(sparseMemoryRequirements.size() != 0);
416
417 const deUint32 metadataAspectIndex = getSparseAspectRequirementsIndex(sparseMemoryRequirements, VK_IMAGE_ASPECT_METADATA_BIT);
418
419 std::vector<VkSparseImageMemoryBind> imageResidencyMemoryBinds;
420 std::vector<VkSparseMemoryBind> imageMipTailMemoryBinds;
421
422 // Bind device memory for each aspect
423 for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
424 {
425 const VkImageAspectFlags aspect = (formatDescription.numPlanes > 1) ? getPlaneAspect(planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT;
426 const deUint32 aspectIndex = getSparseAspectRequirementsIndex(sparseMemoryRequirements, aspect);
427
428 if (aspectIndex == NO_MATCH_FOUND)
429 TCU_THROW(NotSupportedError, "Not supported image aspect");
430
431 VkSparseImageMemoryRequirements aspectRequirements = sparseMemoryRequirements[aspectIndex];
432 VkExtent3D imageGranularity = aspectRequirements.formatProperties.imageGranularity;
433
434 for (deUint32 layerNdx = 0; layerNdx < imageCreateInfo.arrayLayers; ++layerNdx)
435 {
436 for (deUint32 mipLevelNdx = 0; mipLevelNdx < aspectRequirements.imageMipTailFirstLod; ++mipLevelNdx)
437 {
438 const VkImageSubresource subresource = { aspect, mipLevelNdx, layerNdx };
439 const VkExtent3D planeExtent = getPlaneExtent(formatDescription, imageCreateInfo.extent, planeNdx, mipLevelNdx);
440 const tcu::UVec3 numSparseBinds = alignedDivide(planeExtent, imageGranularity);
441 const tcu::UVec3 lastBlockExtent = tcu::UVec3(planeExtent.width % imageGranularity.width ? planeExtent.width % imageGranularity.width : imageGranularity.width,
442 planeExtent.height % imageGranularity.height ? planeExtent.height % imageGranularity.height : imageGranularity.height,
443 planeExtent.depth % imageGranularity.depth ? planeExtent.depth % imageGranularity.depth : imageGranularity.depth);
444
445 for (deUint32 z = 0; z < numSparseBinds.z(); ++z)
446 for (deUint32 y = 0; y < numSparseBinds.y(); ++y)
447 for (deUint32 x = 0; x < numSparseBinds.x(); ++x)
448 {
449 const deUint32 linearIndex = x + y * numSparseBinds.x() + z * numSparseBinds.x() * numSparseBinds.y() + layerNdx * numSparseBinds.x() * numSparseBinds.y() * numSparseBinds.z();
450
451 if (linearIndex % 2u == 0u)
452 {
453 VkOffset3D offset;
454 offset.x = x * imageGranularity.width;
455 offset.y = y * imageGranularity.height;
456 offset.z = z * imageGranularity.depth;
457
458 VkExtent3D extent;
459 extent.width = (x == numSparseBinds.x() - 1) ? lastBlockExtent.x() : imageGranularity.width;
460 extent.height = (y == numSparseBinds.y() - 1) ? lastBlockExtent.y() : imageGranularity.height;
461 extent.depth = (z == numSparseBinds.z() - 1) ? lastBlockExtent.z() : imageGranularity.depth;
462
463 const VkSparseImageMemoryBind imageMemoryBind = makeSparseImageMemoryBind(deviceInterface, getDevice(),
464 imageMemoryRequirements.alignment, memoryType, subresource, offset, extent);
465
466 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
467
468 imageResidencyMemoryBinds.push_back(imageMemoryBind);
469 }
470 }
471 }
472
473 if (!(aspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT) && aspectRequirements.imageMipTailFirstLod < imageCreateInfo.mipLevels)
474 {
475 const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
476 aspectRequirements.imageMipTailSize, memoryType, aspectRequirements.imageMipTailOffset + layerNdx * aspectRequirements.imageMipTailStride);
477
478 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
479
480 imageMipTailMemoryBinds.push_back(imageMipTailMemoryBind);
481 }
482
483 // Metadata
484 if (metadataAspectIndex != NO_MATCH_FOUND)
485 {
486 const VkSparseImageMemoryRequirements metadataAspectRequirements = sparseMemoryRequirements[metadataAspectIndex];
487
488 if (!(metadataAspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT))
489 {
490 const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
491 metadataAspectRequirements.imageMipTailSize, memoryType,
492 metadataAspectRequirements.imageMipTailOffset + layerNdx * metadataAspectRequirements.imageMipTailStride,
493 VK_SPARSE_MEMORY_BIND_METADATA_BIT);
494
495 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
496
497 imageMipTailMemoryBinds.push_back(imageMipTailMemoryBind);
498 }
499 }
500 }
501
502 if ((aspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT) && aspectRequirements.imageMipTailFirstLod < imageCreateInfo.mipLevels)
503 {
504 const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
505 aspectRequirements.imageMipTailSize, memoryType, aspectRequirements.imageMipTailOffset);
506
507 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
508
509 imageMipTailMemoryBinds.push_back(imageMipTailMemoryBind);
510 }
511 }
512
513 // Metadata
514 if (metadataAspectIndex != NO_MATCH_FOUND)
515 {
516 const VkSparseImageMemoryRequirements metadataAspectRequirements = sparseMemoryRequirements[metadataAspectIndex];
517
518 if ((metadataAspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT))
519 {
520 const VkSparseMemoryBind imageMipTailMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(),
521 metadataAspectRequirements.imageMipTailSize, memoryType, metadataAspectRequirements.imageMipTailOffset,
522 VK_SPARSE_MEMORY_BIND_METADATA_BIT);
523
524 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(imageMipTailMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
525
526 imageMipTailMemoryBinds.push_back(imageMipTailMemoryBind);
527 }
528 }
529
530 const VkDeviceGroupBindSparseInfo devGroupBindSparseInfo =
531 {
532 VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR, //VkStructureType sType;
533 DE_NULL, //const void* pNext;
534 firstDeviceID, //deUint32 resourceDeviceIndex;
535 secondDeviceID, //deUint32 memoryDeviceIndex;
536 };
537
538 VkBindSparseInfo bindSparseInfo =
539 {
540 VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, //VkStructureType sType;
541 m_useDeviceGroups ? &devGroupBindSparseInfo : DE_NULL, //const void* pNext;
542 0u, //deUint32 waitSemaphoreCount;
543 DE_NULL, //const VkSemaphore* pWaitSemaphores;
544 0u, //deUint32 bufferBindCount;
545 DE_NULL, //const VkSparseBufferMemoryBindInfo* pBufferBinds;
546 0u, //deUint32 imageOpaqueBindCount;
547 DE_NULL, //const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds;
548 0u, //deUint32 imageBindCount;
549 DE_NULL, //const VkSparseImageMemoryBindInfo* pImageBinds;
550 1u, //deUint32 signalSemaphoreCount;
551 &imageMemoryBindSemaphore.get() //const VkSemaphore* pSignalSemaphores;
552 };
553
554 VkSparseImageMemoryBindInfo imageResidencyBindInfo;
555 VkSparseImageOpaqueMemoryBindInfo imageMipTailBindInfo;
556
557 if (imageResidencyMemoryBinds.size() > 0)
558 {
559 imageResidencyBindInfo.image = *imageSparse;
560 imageResidencyBindInfo.bindCount = static_cast<deUint32>(imageResidencyMemoryBinds.size());
561 imageResidencyBindInfo.pBinds = imageResidencyMemoryBinds.data();
562
563 bindSparseInfo.imageBindCount = 1u;
564 bindSparseInfo.pImageBinds = &imageResidencyBindInfo;
565 }
566
567 if (imageMipTailMemoryBinds.size() > 0)
568 {
569 imageMipTailBindInfo.image = *imageSparse;
570 imageMipTailBindInfo.bindCount = static_cast<deUint32>(imageMipTailMemoryBinds.size());
571 imageMipTailBindInfo.pBinds = imageMipTailMemoryBinds.data();
572
573 bindSparseInfo.imageOpaqueBindCount = 1u;
574 bindSparseInfo.pImageOpaqueBinds = &imageMipTailBindInfo;
575 }
576
577 // Submit sparse bind commands for execution
578 VK_CHECK(deviceInterface.queueBindSparse(sparseQueue.queueHandle, 1u, &bindSparseInfo, DE_NULL));
579 }
580
581 // Create command buffer for compute and transfer operations
582 const Unique<VkCommandPool> commandPool(makeCommandPool(deviceInterface, getDevice(), computeQueue.queueFamilyIndex));
583 const Unique<VkCommandBuffer> commandBuffer(allocateCommandBuffer(deviceInterface, getDevice(), *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
584
585 // Start recording commands
586 beginCommandBuffer(deviceInterface, *commandBuffer);
587
588 // Create descriptor set layout
589 const Unique<VkDescriptorSetLayout> descriptorSetLayout(
590 DescriptorSetLayoutBuilder()
591 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
592 .build(deviceInterface, getDevice()));
593
594 // Create and bind descriptor set
595 const Unique<VkDescriptorPool> descriptorPool(
596 DescriptorPoolBuilder()
597 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1u)
598 .build(deviceInterface, getDevice(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, vk::PlanarFormatDescription::MAX_PLANES));
599
600 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(deviceInterface, getDevice(), *descriptorSetLayout));
601 std::vector<de::SharedPtr<vk::Unique<vk::VkShaderModule>>> shaderModules;
602 std::vector<de::SharedPtr<vk::Unique<vk::VkPipeline>>> computePipelines;
603 std::vector<de::SharedPtr<vk::Unique<vk::VkDescriptorSet>>> descriptorSets;
604 std::vector<de::SharedPtr<vk::Unique<vk::VkImageView>>> imageViews;
605
606 const tcu::UVec3 shaderGridSize = getShaderGridSize(m_imageType, m_imageSize);
607
608 // Run compute shader for each image plane
609 for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
610 {
611 const VkImageAspectFlags aspect = (formatDescription.numPlanes > 1) ? getPlaneAspect(planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT;
612 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(aspect, 0u, 1u, 0u, getNumLayers(m_imageType, m_imageSize));
613 VkFormat planeCompatibleFormat = getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
614 vk::PlanarFormatDescription compatibleFormatDescription = (planeCompatibleFormat != getPlaneCompatibleFormat(formatDescription, planeNdx)) ? getPlanarFormatDescription(planeCompatibleFormat) : formatDescription;
615 const tcu::UVec3 compatibleShaderGridSize ( shaderGridSize.x() / formatDescription.blockWidth, shaderGridSize.y() / formatDescription.blockHeight, shaderGridSize.z() / 1u);
616 VkExtent3D shaderExtent = getPlaneExtent(compatibleFormatDescription, VkExtent3D{ compatibleShaderGridSize.x(), compatibleShaderGridSize.y(), compatibleShaderGridSize.z() }, planeNdx, 0u);
617
618 // Create and bind compute pipeline
619 std::ostringstream shaderName;
620 shaderName << "comp" << planeNdx;
621 auto shaderModule = makeVkSharedPtr(createShaderModule(deviceInterface, getDevice(), m_context.getBinaryCollection().get(shaderName.str()), DE_NULL));
622 shaderModules.push_back(shaderModule);
623 auto computePipeline = makeVkSharedPtr(makeComputePipeline(deviceInterface, getDevice(), *pipelineLayout, shaderModule->get()));
624 computePipelines.push_back(computePipeline);
625 deviceInterface.cmdBindPipeline (*commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline->get());
626
627 auto descriptorSet = makeVkSharedPtr(makeDescriptorSet(deviceInterface, getDevice(), *descriptorPool, *descriptorSetLayout));
628 descriptorSets.push_back(descriptorSet);
629
630 auto imageView = makeVkSharedPtr(makeImageView(deviceInterface, getDevice(), *imageSparse, mapImageViewType(m_imageType), planeCompatibleFormat, subresourceRange));
631 imageViews.push_back(imageView);
632 const VkDescriptorImageInfo imageSparseInfo = makeDescriptorImageInfo(DE_NULL, imageView->get(), VK_IMAGE_LAYOUT_GENERAL);
633
634 DescriptorSetUpdateBuilder()
635 .writeSingle(descriptorSet->get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageSparseInfo)
636 .update(deviceInterface, getDevice());
637
638 deviceInterface.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet->get(), 0u, DE_NULL);
639
640 {
641 const VkImageMemoryBarrier imageSparseLayoutChangeBarrier = makeImageMemoryBarrier
642 (
643 0u,
644 VK_ACCESS_SHADER_WRITE_BIT,
645 VK_IMAGE_LAYOUT_UNDEFINED,
646 VK_IMAGE_LAYOUT_GENERAL,
647 *imageSparse,
648 subresourceRange,
649 sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex ? sparseQueue.queueFamilyIndex : VK_QUEUE_FAMILY_IGNORED,
650 sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex ? computeQueue.queueFamilyIndex : VK_QUEUE_FAMILY_IGNORED
651 );
652
653 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageSparseLayoutChangeBarrier);
654 }
655
656 {
657 const tcu::UVec3 workGroupSize = computeWorkGroupSize(shaderExtent);
658
659 const deUint32 xWorkGroupCount = shaderExtent.width / workGroupSize.x() + (shaderExtent.width % workGroupSize.x() ? 1u : 0u);
660 const deUint32 yWorkGroupCount = shaderExtent.height / workGroupSize.y() + (shaderExtent.height % workGroupSize.y() ? 1u : 0u);
661 const deUint32 zWorkGroupCount = shaderExtent.depth / workGroupSize.z() + (shaderExtent.depth % workGroupSize.z() ? 1u : 0u);
662
663 const tcu::UVec3 maxComputeWorkGroupCount = tcu::UVec3(65535u, 65535u, 65535u);
664
665 if (maxComputeWorkGroupCount.x() < xWorkGroupCount ||
666 maxComputeWorkGroupCount.y() < yWorkGroupCount ||
667 maxComputeWorkGroupCount.z() < zWorkGroupCount)
668 {
669 TCU_THROW(NotSupportedError, "Image size is not supported");
670 }
671
672 deviceInterface.cmdDispatch(*commandBuffer, xWorkGroupCount, yWorkGroupCount, zWorkGroupCount);
673 }
674
675 {
676 const VkImageMemoryBarrier imageSparseTransferBarrier = makeImageMemoryBarrier
677 (
678 VK_ACCESS_SHADER_WRITE_BIT,
679 VK_ACCESS_TRANSFER_READ_BIT,
680 VK_IMAGE_LAYOUT_GENERAL,
681 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
682 *imageSparse,
683 subresourceRange
684 );
685
686 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageSparseTransferBarrier);
687 }
688 }
689
690 deUint32 imageSizeInBytes = 0;
691 deUint32 planeOffsets[PlanarFormatDescription::MAX_PLANES];
692 deUint32 planeRowPitches[PlanarFormatDescription::MAX_PLANES];
693
694 for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
695 {
696 planeOffsets[planeNdx] = imageSizeInBytes;
697 const deUint32 planeW = imageCreateInfo.extent.width / (formatDescription.blockWidth * formatDescription.planes[planeNdx].widthDivisor);
698 planeRowPitches[planeNdx] = formatDescription.planes[planeNdx].elementSizeBytes * planeW;
699 imageSizeInBytes += getImageMipLevelSizeInBytes(imageCreateInfo.extent, imageCreateInfo.arrayLayers, formatDescription, planeNdx, 0, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY);
700 }
701
702 const VkBufferCreateInfo outputBufferCreateInfo = makeBufferCreateInfo(imageSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
703 const Unique<VkBuffer> outputBuffer (createBuffer(deviceInterface, getDevice(), &outputBufferCreateInfo));
704 const de::UniquePtr<Allocation> outputBufferAlloc (bindBuffer(deviceInterface, getDevice(), getAllocator(), *outputBuffer, MemoryRequirement::HostVisible));
705 std::vector<VkBufferImageCopy> bufferImageCopy (formatDescription.numPlanes);
706
707 for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
708 {
709 const VkImageAspectFlags aspect = (formatDescription.numPlanes > 1) ? getPlaneAspect(planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT;
710
711 bufferImageCopy[planeNdx] =
712 {
713 planeOffsets[planeNdx], // VkDeviceSize bufferOffset;
714 0u, // deUint32 bufferRowLength;
715 0u, // deUint32 bufferImageHeight;
716 makeImageSubresourceLayers(aspect, 0u, 0u, imageCreateInfo.arrayLayers), // VkImageSubresourceLayers imageSubresource;
717 makeOffset3D(0, 0, 0), // VkOffset3D imageOffset;
718 vk::getPlaneExtent(formatDescription, imageCreateInfo.extent, planeNdx, 0) // VkExtent3D imageExtent;
719 };
720 }
721 deviceInterface.cmdCopyImageToBuffer(*commandBuffer, *imageSparse, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *outputBuffer, static_cast<deUint32>(bufferImageCopy.size()), bufferImageCopy.data());
722
723 {
724 const VkBufferMemoryBarrier outputBufferHostReadBarrier = makeBufferMemoryBarrier
725 (
726 VK_ACCESS_TRANSFER_WRITE_BIT,
727 VK_ACCESS_HOST_READ_BIT,
728 *outputBuffer,
729 0u,
730 imageSizeInBytes
731 );
732
733 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &outputBufferHostReadBarrier, 0u, DE_NULL);
734 }
735
736 // End recording commands
737 endCommandBuffer(deviceInterface, *commandBuffer);
738
739 // The stage at which execution is going to wait for finish of sparse binding operations
740 const VkPipelineStageFlags stageBits[] = { VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT };
741
742 // Submit commands for execution and wait for completion
743 submitCommandsAndWait(deviceInterface, getDevice(), computeQueue.queueHandle, *commandBuffer, 1u, &imageMemoryBindSemaphore.get(), stageBits,
744 0, DE_NULL, m_useDeviceGroups, firstDeviceID);
745
746 // Retrieve data from buffer to host memory
747 invalidateAlloc(deviceInterface, getDevice(), *outputBufferAlloc);
748 deUint8* outputData = static_cast<deUint8*>(outputBufferAlloc->getHostPtr());
749 void* planePointers[PlanarFormatDescription::MAX_PLANES];
750
751 for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
752 planePointers[planeNdx] = outputData + static_cast<size_t>(planeOffsets[planeNdx]);
753
754 // Wait for sparse queue to become idle
755 //vsk fails:
756 deviceInterface.queueWaitIdle(sparseQueue.queueHandle);
757
758 // write result images to log file
759 for (deUint32 channelNdx = 0; channelNdx < 4; ++channelNdx)
760 {
761 if (!formatDescription.hasChannelNdx(channelNdx))
762 continue;
763 deUint32 planeNdx = formatDescription.channels[channelNdx].planeNdx;
764 vk::VkFormat planeCompatibleFormat = getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
765 vk::PlanarFormatDescription compatibleFormatDescription = (planeCompatibleFormat != getPlaneCompatibleFormat(formatDescription, planeNdx)) ? getPlanarFormatDescription(planeCompatibleFormat) : formatDescription;
766 const tcu::UVec3 compatibleShaderGridSize (shaderGridSize.x() / formatDescription.blockWidth, shaderGridSize.y() / formatDescription.blockHeight, shaderGridSize.z() / 1u);
767 tcu::ConstPixelBufferAccess pixelBuffer = vk::getChannelAccess(compatibleFormatDescription, compatibleShaderGridSize, planeRowPitches, (const void* const*)planePointers, channelNdx);
768 std::ostringstream str;
769 str << "image" << channelNdx;
770 m_context.getTestContext().getLog() << tcu::LogImage(str.str(), str.str(), pixelBuffer);
771 }
772
773 // Validate results
774 for (deUint32 channelNdx = 0; channelNdx < 4; ++channelNdx)
775 {
776 if (!formatDescription.hasChannelNdx(channelNdx))
777 continue;
778
779 deUint32 planeNdx = formatDescription.channels[channelNdx].planeNdx;
780 const VkImageAspectFlags aspect = (formatDescription.numPlanes > 1) ? getPlaneAspect(planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT;
781 const deUint32 aspectIndex = getSparseAspectRequirementsIndex(sparseMemoryRequirements, aspect);
782
783 if (aspectIndex == NO_MATCH_FOUND)
784 TCU_THROW(NotSupportedError, "Not supported image aspect");
785
786 VkSparseImageMemoryRequirements aspectRequirements = sparseMemoryRequirements[aspectIndex];
787
788 vk::VkFormat planeCompatibleFormat = getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
789 vk::PlanarFormatDescription compatibleFormatDescription = (planeCompatibleFormat != getPlaneCompatibleFormat(formatDescription, planeNdx)) ? getPlanarFormatDescription(planeCompatibleFormat) : formatDescription;
790 const tcu::UVec3 compatibleShaderGridSize ( shaderGridSize.x() / formatDescription.blockWidth, shaderGridSize.y() / formatDescription.blockHeight, shaderGridSize.z() / 1u );
791 VkExtent3D compatibleImageSize { imageCreateInfo.extent.width / formatDescription.blockWidth, imageCreateInfo.extent.height / formatDescription.blockHeight, imageCreateInfo.extent.depth / 1u };
792 VkExtent3D compatibleImageGranularity { aspectRequirements.formatProperties.imageGranularity.width / formatDescription.blockWidth,
793 aspectRequirements.formatProperties.imageGranularity.height / formatDescription.blockHeight,
794 aspectRequirements.formatProperties.imageGranularity.depth / 1u };
795 tcu::ConstPixelBufferAccess pixelBuffer = vk::getChannelAccess(compatibleFormatDescription, compatibleShaderGridSize, planeRowPitches, (const void* const*)planePointers, channelNdx);
796 VkExtent3D planeExtent = getPlaneExtent(compatibleFormatDescription, compatibleImageSize, planeNdx, 0u);
797 tcu::IVec3 pixelDivider = pixelBuffer.getDivider();
798
799 if( aspectRequirements.imageMipTailFirstLod > 0u )
800 {
801 const tcu::UVec3 numSparseBinds = alignedDivide(planeExtent, compatibleImageGranularity);
802 const tcu::UVec3 lastBlockExtent = tcu::UVec3(planeExtent.width % compatibleImageGranularity.width ? planeExtent.width % compatibleImageGranularity.width : compatibleImageGranularity.width,
803 planeExtent.height % compatibleImageGranularity.height ? planeExtent.height % compatibleImageGranularity.height : compatibleImageGranularity.height,
804 planeExtent.depth % compatibleImageGranularity.depth ? planeExtent.depth % compatibleImageGranularity.depth : compatibleImageGranularity.depth);
805
806 for (deUint32 layerNdx = 0; layerNdx < imageCreateInfo.arrayLayers; ++layerNdx)
807 {
808 for (deUint32 z = 0; z < numSparseBinds.z(); ++z)
809 for (deUint32 y = 0; y < numSparseBinds.y(); ++y)
810 for (deUint32 x = 0; x < numSparseBinds.x(); ++x)
811 {
812 VkExtent3D offset;
813 offset.width = x * compatibleImageGranularity.width;
814 offset.height = y * compatibleImageGranularity.height;
815 offset.depth = z * compatibleImageGranularity.depth + layerNdx * numSparseBinds.z()*compatibleImageGranularity.depth;
816
817 VkExtent3D extent;
818 extent.width = (x == numSparseBinds.x() - 1) ? lastBlockExtent.x() : compatibleImageGranularity.width;
819 extent.height = (y == numSparseBinds.y() - 1) ? lastBlockExtent.y() : compatibleImageGranularity.height;
820 extent.depth = (z == numSparseBinds.z() - 1) ? lastBlockExtent.z() : compatibleImageGranularity.depth;
821
822 const deUint32 linearIndex = x + y * numSparseBinds.x() + z * numSparseBinds.x() * numSparseBinds.y() + layerNdx * numSparseBinds.x() * numSparseBinds.y() * numSparseBinds.z();
823
824 if (linearIndex % 2u == 0u)
825 {
826 for (deUint32 offsetZ = offset.depth; offsetZ < offset.depth + extent.depth; ++offsetZ)
827 for (deUint32 offsetY = offset.height; offsetY < offset.height + extent.height; ++offsetY)
828 for (deUint32 offsetX = offset.width; offsetX < offset.width + extent.width; ++offsetX)
829 {
830 deUint32 iReferenceValue;
831 float fReferenceValue;
832
833 switch (channelNdx)
834 {
835 case 0:
836 iReferenceValue = offsetX % 127u;
837 fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
838 break;
839 case 1:
840 iReferenceValue = offsetY % 127u;
841 fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
842 break;
843 case 2:
844 iReferenceValue = offsetZ % 127u;
845 fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
846 break;
847 case 3:
848 iReferenceValue = 1u;
849 fReferenceValue = 1.f;
850 break;
851 default: DE_FATAL("Unexpected channel index"); break;
852 }
853
854 float acceptableError = epsilon;
855
856 switch (formatDescription.channels[channelNdx].type)
857 {
858 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
859 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
860 {
861 const tcu::UVec4 outputValue = pixelBuffer.getPixelUint(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
862
863 if (outputValue.x() != iReferenceValue)
864 return tcu::TestStatus::fail("Failed");
865
866 break;
867 }
868 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
869 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
870 {
871 float fixedPointError = tcu::TexVerifierUtil::computeFixedPointError(formatDescription.channels[channelNdx].sizeBits);
872 acceptableError += fixedPointError;
873 const tcu::Vec4 outputValue = pixelBuffer.getPixel(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
874
875 if (deAbs(outputValue.x() - fReferenceValue) > acceptableError)
876 return tcu::TestStatus::fail("Failed");
877
878 break;
879 }
880 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
881 {
882 const tcu::Vec4 outputValue = pixelBuffer.getPixel(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
883
884 if (deAbs( outputValue.x() - fReferenceValue) > acceptableError)
885 return tcu::TestStatus::fail("Failed");
886
887 break;
888 }
889 default: DE_FATAL("Unexpected channel type"); break;
890 }
891 }
892 }
893 else if (physicalDeviceProperties.sparseProperties.residencyNonResidentStrict)
894 {
895 for (deUint32 offsetZ = offset.depth; offsetZ < offset.depth + extent.depth; ++offsetZ)
896 for (deUint32 offsetY = offset.height; offsetY < offset.height + extent.height; ++offsetY)
897 for (deUint32 offsetX = offset.width; offsetX < offset.width + extent.width; ++offsetX)
898 {
899 float acceptableError = epsilon;
900
901 switch (formatDescription.channels[channelNdx].type)
902 {
903 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
904 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
905 {
906 const tcu::UVec4 outputValue = pixelBuffer.getPixelUint(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
907
908 if (outputValue.x() != 0u)
909 return tcu::TestStatus::fail("Failed");
910
911 break;
912 }
913 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
914 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
915 {
916 float fixedPointError = tcu::TexVerifierUtil::computeFixedPointError(formatDescription.channels[channelNdx].sizeBits);
917 acceptableError += fixedPointError;
918 const tcu::Vec4 outputValue = pixelBuffer.getPixel(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
919
920 if (deAbs(outputValue.x()) > acceptableError)
921 return tcu::TestStatus::fail("Failed");
922
923 break;
924 }
925 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
926 {
927 const tcu::Vec4 outputValue = pixelBuffer.getPixel(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
928
929 if (deAbs(outputValue.x()) > acceptableError)
930 return tcu::TestStatus::fail("Failed");
931
932 break;
933 }
934 default: DE_FATAL("Unexpected channel type"); break;
935 }
936 }
937 }
938 }
939 }
940 }
941 else
942 {
943 for (deUint32 offsetZ = 0u; offsetZ < planeExtent.depth * imageCreateInfo.arrayLayers; ++offsetZ)
944 for (deUint32 offsetY = 0u; offsetY < planeExtent.height; ++offsetY)
945 for (deUint32 offsetX = 0u; offsetX < planeExtent.width; ++offsetX)
946 {
947 deUint32 iReferenceValue;
948 float fReferenceValue;
949 switch (channelNdx)
950 {
951 case 0:
952 iReferenceValue = offsetX % 127u;
953 fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
954 break;
955 case 1:
956 iReferenceValue = offsetY % 127u;
957 fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
958 break;
959 case 2:
960 iReferenceValue = offsetZ % 127u;
961 fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
962 break;
963 case 3:
964 iReferenceValue = 1u;
965 fReferenceValue = 1.f;
966 break;
967 default: DE_FATAL("Unexpected channel index"); break;
968 }
969 float acceptableError = epsilon;
970
971 switch (formatDescription.channels[channelNdx].type)
972 {
973 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
974 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
975 {
976 const tcu::UVec4 outputValue = pixelBuffer.getPixelUint(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
977
978 if (outputValue.x() != iReferenceValue)
979 return tcu::TestStatus::fail("Failed");
980
981 break;
982 }
983 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
984 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
985 {
986 float fixedPointError = tcu::TexVerifierUtil::computeFixedPointError(formatDescription.channels[channelNdx].sizeBits);
987 acceptableError += fixedPointError;
988 const tcu::Vec4 outputValue = pixelBuffer.getPixel(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
989
990 if (deAbs(outputValue.x() - fReferenceValue) > acceptableError)
991 return tcu::TestStatus::fail("Failed");
992
993 break;
994 }
995 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
996 {
997 const tcu::Vec4 outputValue = pixelBuffer.getPixel(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), offsetZ * pixelDivider.z());
998
999 if (deAbs( outputValue.x() - fReferenceValue) > acceptableError)
1000 return tcu::TestStatus::fail("Failed");
1001
1002 break;
1003 }
1004 default: DE_FATAL("Unexpected channel type"); break;
1005 }
1006 }
1007 }
1008 }
1009 }
1010
1011 return tcu::TestStatus::pass("Passed");
1012 }
1013
createInstance(Context & context) const1014 TestInstance* ImageSparseResidencyCase::createInstance (Context& context) const
1015 {
1016 return new ImageSparseResidencyInstance(context, m_imageType, m_imageSize, m_format, m_useDeviceGroups);
1017 }
1018
1019 } // anonymous ns
1020
createImageSparseResidencyTestsCommon(tcu::TestContext & testCtx,de::MovePtr<tcu::TestCaseGroup> testGroup,const bool useDeviceGroup=false)1021 tcu::TestCaseGroup* createImageSparseResidencyTestsCommon (tcu::TestContext& testCtx, de::MovePtr<tcu::TestCaseGroup> testGroup, const bool useDeviceGroup = false)
1022 {
1023 const std::vector<TestImageParameters> imageParameters =
1024 {
1025 { IMAGE_TYPE_2D, { tcu::UVec3(512u, 256u, 1u), tcu::UVec3(1024u, 128u, 1u), tcu::UVec3(11u, 137u, 1u) }, getTestFormats(IMAGE_TYPE_2D) },
1026 { IMAGE_TYPE_2D_ARRAY, { tcu::UVec3(512u, 256u, 6u), tcu::UVec3(1024u, 128u, 8u), tcu::UVec3(11u, 137u, 3u) }, getTestFormats(IMAGE_TYPE_2D_ARRAY) },
1027 { IMAGE_TYPE_CUBE, { tcu::UVec3(256u, 256u, 1u), tcu::UVec3(128u, 128u, 1u), tcu::UVec3(137u, 137u, 1u) }, getTestFormats(IMAGE_TYPE_CUBE) },
1028 { IMAGE_TYPE_CUBE_ARRAY, { tcu::UVec3(256u, 256u, 6u), tcu::UVec3(128u, 128u, 8u), tcu::UVec3(137u, 137u, 3u) }, getTestFormats(IMAGE_TYPE_CUBE_ARRAY) },
1029 { IMAGE_TYPE_3D, { tcu::UVec3(512u, 256u, 16u), tcu::UVec3(1024u, 128u, 8u), tcu::UVec3(11u, 137u, 3u) }, getTestFormats(IMAGE_TYPE_3D) }
1030 };
1031
1032 for (size_t imageTypeNdx = 0; imageTypeNdx < imageParameters.size(); ++imageTypeNdx)
1033 {
1034 const ImageType imageType = imageParameters[imageTypeNdx].imageType;
1035 de::MovePtr<tcu::TestCaseGroup> imageTypeGroup(new tcu::TestCaseGroup(testCtx, getImageTypeName(imageType).c_str(), ""));
1036
1037 for (size_t formatNdx = 0; formatNdx < imageParameters[imageTypeNdx].formats.size(); ++formatNdx)
1038 {
1039 const VkFormat format = imageParameters[imageTypeNdx].formats[formatNdx].format;
1040 tcu::UVec3 imageSizeAlignment = getImageSizeAlignment(format);
1041 de::MovePtr<tcu::TestCaseGroup> formatGroup (new tcu::TestCaseGroup(testCtx, getImageFormatID(format).c_str(), ""));
1042
1043 for (size_t imageSizeNdx = 0; imageSizeNdx < imageParameters[imageTypeNdx].imageSizes.size(); ++imageSizeNdx)
1044 {
1045 const tcu::UVec3 imageSize = imageParameters[imageTypeNdx].imageSizes[imageSizeNdx];
1046
1047 // skip test for images with odd sizes for some YCbCr formats
1048 if ((imageSize.x() % imageSizeAlignment.x()) != 0)
1049 continue;
1050 if ((imageSize.y() % imageSizeAlignment.y()) != 0)
1051 continue;
1052
1053 std::ostringstream stream;
1054 stream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z();
1055
1056 formatGroup->addChild(new ImageSparseResidencyCase(testCtx, stream.str(), "", imageType, imageSize, format, glu::GLSL_VERSION_440, useDeviceGroup));
1057 }
1058 imageTypeGroup->addChild(formatGroup.release());
1059 }
1060 testGroup->addChild(imageTypeGroup.release());
1061 }
1062
1063 return testGroup.release();
1064 }
1065
createImageSparseResidencyTests(tcu::TestContext & testCtx)1066 tcu::TestCaseGroup* createImageSparseResidencyTests (tcu::TestContext& testCtx)
1067 {
1068 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "image_sparse_residency", "Image Sparse Residency"));
1069 return createImageSparseResidencyTestsCommon(testCtx, testGroup);
1070 }
1071
createDeviceGroupImageSparseResidencyTests(tcu::TestContext & testCtx)1072 tcu::TestCaseGroup* createDeviceGroupImageSparseResidencyTests (tcu::TestContext& testCtx)
1073 {
1074 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "device_group_image_sparse_residency", "Image Sparse Residency"));
1075 return createImageSparseResidencyTestsCommon(testCtx, testGroup, true);
1076 }
1077
1078 } // sparse
1079 } // vkt
1080