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