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
21 * \brief Image Tests Utility Classes
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktImageTestsUtil.hpp"
25 #include "vkQueryUtil.hpp"
26 #include "vkTypeUtil.hpp"
27 #include "vkCmdUtil.hpp"
28 #include "vkObjUtil.hpp"
29 #include "tcuTextureUtil.hpp"
30
31 using namespace vk;
32
33 namespace vkt
34 {
35 namespace image
36 {
37
Image(const DeviceInterface & vk,const VkDevice device,Allocator & allocator,const VkImageCreateInfo & imageCreateInfo,const MemoryRequirement memoryRequirement)38 Image::Image (const DeviceInterface& vk,
39 const VkDevice device,
40 Allocator& allocator,
41 const VkImageCreateInfo& imageCreateInfo,
42 const MemoryRequirement memoryRequirement)
43 {
44 m_image = createImage(vk, device, &imageCreateInfo);
45 de::SharedPtr<vk::Allocation> allocation(allocator.allocate(getImageMemoryRequirements(vk, device, *m_image), memoryRequirement).release());
46 m_allocations.push_back(allocation);
47 VK_CHECK(vk.bindImageMemory(device, *m_image, allocation->getMemory(), allocation->getOffset()));
48 }
49
Image(void)50 Image::Image (void)
51 : m_allocations ()
52 , m_image ()
53 {}
54
55 #ifndef CTS_USES_VULKANSC
SparseImage(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkPhysicalDevice physicalDevice,const vk::InstanceInterface & vki,const vk::VkImageCreateInfo & createInfo,const vk::VkQueue sparseQueue,vk::Allocator & allocator,const tcu::TextureFormat & format)56 SparseImage::SparseImage (const vk::DeviceInterface& vkd,
57 vk::VkDevice device,
58 vk::VkPhysicalDevice physicalDevice,
59 const vk::InstanceInterface& vki,
60 const vk::VkImageCreateInfo& createInfo,
61 const vk::VkQueue sparseQueue,
62 vk::Allocator& allocator,
63 const tcu::TextureFormat& format)
64 : Image ()
65 , m_semaphore ()
66 {
67 m_image = createImage(vkd, device, &createInfo);
68 m_semaphore = createSemaphore(vkd, device);
69 allocateAndBindSparseImage(vkd, device, physicalDevice, vki, createInfo, m_semaphore.get(), sparseQueue, allocator, m_allocations, format, m_image.get());
70 }
71 #endif // CTS_USES_VULKANSC
72
getShaderGridSize(const ImageType imageType,const tcu::UVec3 & imageSize)73 tcu::UVec3 getShaderGridSize (const ImageType imageType, const tcu::UVec3& imageSize)
74 {
75 switch (imageType)
76 {
77 case IMAGE_TYPE_1D:
78 case IMAGE_TYPE_BUFFER:
79 return tcu::UVec3(imageSize.x(), 1u, 1u);
80
81 case IMAGE_TYPE_1D_ARRAY:
82 return tcu::UVec3(imageSize.x(), imageSize.z(), 1u);
83
84 case IMAGE_TYPE_2D:
85 return tcu::UVec3(imageSize.x(), imageSize.y(), 1u);
86
87 case IMAGE_TYPE_2D_ARRAY:
88 case IMAGE_TYPE_3D:
89 return tcu::UVec3(imageSize.x(), imageSize.y(), imageSize.z());
90
91 case IMAGE_TYPE_CUBE:
92 return tcu::UVec3(imageSize.x(), imageSize.y(), 6u);
93
94 case IMAGE_TYPE_CUBE_ARRAY:
95 return tcu::UVec3(imageSize.x(), imageSize.y(), 6u * imageSize.z());
96
97 default:
98 DE_FATAL("Unknown image type");
99 return tcu::UVec3(1u, 1u, 1u);
100 }
101 }
102
getLayerSize(const ImageType imageType,const tcu::UVec3 & imageSize)103 tcu::UVec3 getLayerSize (const ImageType imageType, const tcu::UVec3& imageSize)
104 {
105 switch (imageType)
106 {
107 case IMAGE_TYPE_1D:
108 case IMAGE_TYPE_1D_ARRAY:
109 case IMAGE_TYPE_BUFFER:
110 return tcu::UVec3(imageSize.x(), 1u, 1u);
111
112 case IMAGE_TYPE_2D:
113 case IMAGE_TYPE_2D_ARRAY:
114 case IMAGE_TYPE_CUBE:
115 case IMAGE_TYPE_CUBE_ARRAY:
116 return tcu::UVec3(imageSize.x(), imageSize.y(), 1u);
117
118 case IMAGE_TYPE_3D:
119 return tcu::UVec3(imageSize.x(), imageSize.y(), imageSize.z());
120
121 default:
122 DE_FATAL("Unknown image type");
123 return tcu::UVec3(1u, 1u, 1u);
124 }
125 }
126
getNumLayers(const ImageType imageType,const tcu::UVec3 & imageSize)127 deUint32 getNumLayers (const ImageType imageType, const tcu::UVec3& imageSize)
128 {
129 switch (imageType)
130 {
131 case IMAGE_TYPE_1D:
132 case IMAGE_TYPE_2D:
133 case IMAGE_TYPE_3D:
134 case IMAGE_TYPE_BUFFER:
135 return 1u;
136
137 case IMAGE_TYPE_1D_ARRAY:
138 case IMAGE_TYPE_2D_ARRAY:
139 return imageSize.z();
140
141 case IMAGE_TYPE_CUBE:
142 return 6u;
143
144 case IMAGE_TYPE_CUBE_ARRAY:
145 return imageSize.z() * 6u;
146
147 default:
148 DE_FATAL("Unknown image type");
149 return 0u;
150 }
151 }
152
getNumPixels(const ImageType imageType,const tcu::UVec3 & imageSize)153 deUint32 getNumPixels (const ImageType imageType, const tcu::UVec3& imageSize)
154 {
155 const tcu::UVec3 gridSize = getShaderGridSize(imageType, imageSize);
156
157 return gridSize.x() * gridSize.y() * gridSize.z();
158 }
159
getDimensions(const ImageType imageType)160 deUint32 getDimensions (const ImageType imageType)
161 {
162 switch (imageType)
163 {
164 case IMAGE_TYPE_1D:
165 case IMAGE_TYPE_BUFFER:
166 return 1u;
167
168 case IMAGE_TYPE_1D_ARRAY:
169 case IMAGE_TYPE_2D:
170 return 2u;
171
172 case IMAGE_TYPE_2D_ARRAY:
173 case IMAGE_TYPE_CUBE:
174 case IMAGE_TYPE_CUBE_ARRAY:
175 case IMAGE_TYPE_3D:
176 return 3u;
177
178 default:
179 DE_FATAL("Unknown image type");
180 return 0u;
181 }
182 }
183
getLayerDimensions(const ImageType imageType)184 deUint32 getLayerDimensions (const ImageType imageType)
185 {
186 switch (imageType)
187 {
188 case IMAGE_TYPE_1D:
189 case IMAGE_TYPE_BUFFER:
190 case IMAGE_TYPE_1D_ARRAY:
191 return 1u;
192
193 case IMAGE_TYPE_2D:
194 case IMAGE_TYPE_2D_ARRAY:
195 case IMAGE_TYPE_CUBE:
196 case IMAGE_TYPE_CUBE_ARRAY:
197 return 2u;
198
199 case IMAGE_TYPE_3D:
200 return 3u;
201
202 default:
203 DE_FATAL("Unknown image type");
204 return 0u;
205 }
206 }
207
makeBufferImageCopy(const VkExtent3D extent,const deUint32 arraySize)208 VkBufferImageCopy makeBufferImageCopy (const VkExtent3D extent,
209 const deUint32 arraySize)
210 {
211 const VkBufferImageCopy copyParams =
212 {
213 0ull, // VkDeviceSize bufferOffset;
214 0u, // deUint32 bufferRowLength;
215 0u, // deUint32 bufferImageHeight;
216 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, arraySize), // VkImageSubresourceLayers imageSubresource;
217 makeOffset3D(0, 0, 0), // VkOffset3D imageOffset;
218 extent, // VkExtent3D imageExtent;
219 };
220 return copyParams;
221 }
222
makeGraphicsPipeline(const DeviceInterface & vk,const VkDevice device,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const VkShaderModule vertexModule,const VkShaderModule fragmentModule,const VkExtent2D renderSize,const deUint32 colorAttachmentCount,const bool dynamicSize)223 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface& vk,
224 const VkDevice device,
225 const VkPipelineLayout pipelineLayout,
226 const VkRenderPass renderPass,
227 const VkShaderModule vertexModule,
228 const VkShaderModule fragmentModule,
229 const VkExtent2D renderSize,
230 const deUint32 colorAttachmentCount,
231 const bool dynamicSize)
232 {
233 std::vector<VkViewport> viewports;
234 std::vector<VkRect2D> scissors;
235
236 const VkViewport viewport = makeViewport(renderSize);
237 const VkRect2D scissor = makeRect2D(renderSize);
238
239 const VkFormat vertexFormatPosition = VK_FORMAT_R32G32B32A32_SFLOAT;
240 const deUint32 vertexSizePosition = tcu::getPixelSize(mapVkFormat(vertexFormatPosition));
241 const deUint32 vertexBufferOffsetPosition = 0u;
242 const deUint32 vertexDataStride = vertexSizePosition;
243
244 if (!dynamicSize)
245 {
246 viewports.push_back(viewport);
247 scissors.push_back(scissor);
248 }
249
250 const VkVertexInputBindingDescription vertexInputBindingDescription =
251 {
252 0u, // deUint32 binding;
253 vertexDataStride, // deUint32 stride;
254 VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate inputRate;
255 };
256
257 const VkVertexInputAttributeDescription vertexInputAttributeDescription =
258 {
259 0u, // deUint32 location;
260 0u, // deUint32 binding;
261 vertexFormatPosition, // VkFormat format;
262 vertexBufferOffsetPosition, // deUint32 offset;
263 };
264
265 const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo =
266 {
267 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
268 DE_NULL, // const void* pNext;
269 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags;
270 1u, // deUint32 vertexBindingDescriptionCount;
271 &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
272 1u, // deUint32 vertexAttributeDescriptionCount;
273 &vertexInputAttributeDescription // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
274 };
275
276 const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
277 const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
278 {
279 VK_FALSE, // VkBool32 blendEnable;
280 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
281 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
282 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
283 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
284 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
285 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
286 colorComponentsAll // VkColorComponentFlags colorWriteMask;
287 };
288
289 std::vector<VkPipelineColorBlendAttachmentState> colorAttachments (colorAttachmentCount, colorBlendAttachmentState);
290
291 const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
292 {
293 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
294 DE_NULL, // const void* pNext;
295 (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags;
296 VK_FALSE, // VkBool32 logicOpEnable;
297 VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
298 (deUint32)colorAttachments.size(), // deUint32 attachmentCount;
299 colorAttachments.size() != 0 ? &colorAttachments[0] : DE_NULL, // const VkPipelineColorBlendAttachmentState* pAttachments;
300 { 0.0f, 0.0f, 0.0f, 0.0f } // float blendConstants[4];
301 };
302
303 return vk::makeGraphicsPipeline(vk, // const DeviceInterface& vk
304 device, // const VkDevice device
305 pipelineLayout, // const VkPipelineLayout pipelineLayout
306 vertexModule, // const VkShaderModule vertexShaderModule
307 DE_NULL, // const VkShaderModule tessellationControlModule
308 DE_NULL, // const VkShaderModule tessellationEvalModule
309 DE_NULL, // const VkShaderModule geometryShaderModule
310 fragmentModule, // const VkShaderModule fragmentShaderModule
311 renderPass, // const VkRenderPass renderPass
312 viewports, // const std::vector<VkViewport>& viewports
313 scissors, // const std::vector<VkRect2D>& scissors
314 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology
315 0u, // const deUint32 subpass
316 0u, // const deUint32 patchControlPoints
317 &vertexInputStateCreateInfo, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
318 DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
319 DE_NULL, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo
320 DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo
321 &pipelineColorBlendStateInfo); // const VkPipelineColorBlendStateCreateInfo* colorBlendStateCreateInfo
322 }
323
324 //! A single-subpass render pass.
makeRenderPass(const DeviceInterface & vk,const VkDevice device,const VkFormat inputFormat,const VkFormat colorFormat)325 Move<VkRenderPass> makeRenderPass (const DeviceInterface& vk,
326 const VkDevice device,
327 const VkFormat inputFormat,
328 const VkFormat colorFormat)
329 {
330 const VkAttachmentReference inputAttachmentRef =
331 {
332 0u, // deUint32 attachment;
333 VK_IMAGE_LAYOUT_GENERAL // VkImageLayout layout;
334 };
335
336 const VkAttachmentReference colorAttachmentRef =
337 {
338 1u, // deUint32 attachment;
339 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
340 };
341
342 const VkSubpassDescription subpassDescription =
343 {
344 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags;
345 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
346 1u, // deUint32 inputAttachmentCount;
347 &inputAttachmentRef, // const VkAttachmentReference* pInputAttachments;
348 1u, // deUint32 colorAttachmentCount;
349 &colorAttachmentRef, // const VkAttachmentReference* pColorAttachments;
350 DE_NULL, // const VkAttachmentReference* pResolveAttachments;
351 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment;
352 0u, // deUint32 preserveAttachmentCount;
353 DE_NULL // const deUint32* pPreserveAttachments;
354 };
355
356 const VkAttachmentDescription attachmentsDescriptions[] =
357 {
358 //inputAttachmentDescription,
359 {
360 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
361 inputFormat, // VkFormat format;
362 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
363 VK_ATTACHMENT_LOAD_OP_LOAD, // VkAttachmentLoadOp loadOp;
364 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp;
365 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
366 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
367 VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout initialLayout;
368 VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout finalLayout;
369 },
370 //colorAttachmentDescription
371 {
372 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
373 colorFormat, // VkFormat format;
374 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
375 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
376 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
377 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
378 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
379 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
380 VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout finalLayout;
381 }
382 };
383
384 const VkRenderPassCreateInfo renderPassInfo =
385 {
386 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
387 DE_NULL, // const void* pNext;
388 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags;
389 DE_LENGTH_OF_ARRAY(attachmentsDescriptions), // deUint32 attachmentCount;
390 attachmentsDescriptions, // const VkAttachmentDescription* pAttachments;
391 1u, // deUint32 subpassCount;
392 &subpassDescription, // const VkSubpassDescription* pSubpasses;
393 0u, // deUint32 dependencyCount;
394 DE_NULL // const VkSubpassDependency* pDependencies;
395 };
396
397 return createRenderPass(vk, device, &renderPassInfo);
398 }
399
makeImageViewUsageCreateInfo(const VkImageUsageFlags imageUsageFlags)400 VkImageViewUsageCreateInfo makeImageViewUsageCreateInfo (const VkImageUsageFlags imageUsageFlags)
401 {
402 VkImageViewUsageCreateInfo imageViewUsageCreateInfo =
403 {
404 VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, //VkStructureType sType;
405 DE_NULL, //const void* pNext;
406 imageUsageFlags, //VkImageUsageFlags usage;
407 };
408
409 return imageViewUsageCreateInfo;
410 }
411
makeSamplerCreateInfo()412 VkSamplerCreateInfo makeSamplerCreateInfo ()
413 {
414 const VkSamplerCreateInfo defaultSamplerParams =
415 {
416 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType;
417 DE_NULL, // const void* pNext;
418 0u, // VkSamplerCreateFlags flags;
419 VK_FILTER_NEAREST, // VkFilter magFilter;
420 VK_FILTER_NEAREST, // VkFilter minFilter;
421 VK_SAMPLER_MIPMAP_MODE_NEAREST, // VkSamplerMipmapMode mipmapMode;
422 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeU;
423 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeV;
424 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeW;
425 0.0f, // float mipLodBias;
426 VK_FALSE, // VkBool32 anisotropyEnable;
427 1.0f, // float maxAnisotropy;
428 VK_FALSE, // VkBool32 compareEnable;
429 VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
430 0.0f, // float minLod;
431 0.25f, // float maxLod;
432 VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor;
433 VK_FALSE // VkBool32 unnormalizedCoordinates;
434 };
435
436 return defaultSamplerParams;
437 }
438
getCompressedImageResolutionInBlocks(const vk::VkFormat format,const tcu::UVec3 & size)439 tcu::UVec3 getCompressedImageResolutionInBlocks (const vk::VkFormat format, const tcu::UVec3& size)
440 {
441 deUint32 blockWidth = getBlockWidth(format);
442 deUint32 blockHeight = getBlockHeight(format);
443
444 DE_ASSERT(size[2] == 1);
445 DE_ASSERT(blockWidth != 0 && blockHeight != 0);
446
447 deUint32 widthInBlocks = (size[0] + blockWidth - 1) / blockWidth;
448 deUint32 heightInBlocks = (size[1] + blockHeight - 1) / blockHeight;
449
450 return tcu::UVec3(widthInBlocks, heightInBlocks, 1);
451 }
452
getCompressedImageResolutionBlockCeil(const vk::VkFormat format,const tcu::UVec3 & size)453 tcu::UVec3 getCompressedImageResolutionBlockCeil (const vk::VkFormat format, const tcu::UVec3& size)
454 {
455 deUint32 blockWidth = getBlockWidth(format);
456 deUint32 blockHeight = getBlockHeight(format);
457
458 DE_ASSERT(size[2] == 1);
459 DE_ASSERT(blockWidth != 0 && blockHeight != 0);
460
461 deUint32 widthInBlocks = (size[0] + blockWidth - 1) / blockWidth;
462 deUint32 heightInBlocks = (size[1] + blockHeight - 1) / blockHeight;
463
464 return tcu::UVec3(blockWidth * widthInBlocks, blockHeight * heightInBlocks, 1);
465 }
466
getCompressedImageSizeInBytes(const vk::VkFormat format,const tcu::UVec3 & size)467 VkDeviceSize getCompressedImageSizeInBytes (const vk::VkFormat format, const tcu::UVec3& size)
468 {
469 tcu::UVec3 sizeInBlocks = getCompressedImageResolutionInBlocks(format, size);
470 deUint32 blockBytes = getBlockSizeInBytes(format);
471 VkDeviceSize sizeBytes = sizeInBlocks[0] * sizeInBlocks[1] * sizeInBlocks[2] * blockBytes;
472
473 return sizeBytes;
474 }
475
getUncompressedImageSizeInBytes(const vk::VkFormat format,const tcu::UVec3 & size)476 VkDeviceSize getUncompressedImageSizeInBytes (const vk::VkFormat format, const tcu::UVec3& size)
477 {
478 const tcu::IVec3 sizeAsIVec3 = tcu::IVec3((int)size.x(), (int)size.y(), (int)size.z());
479 const VkDeviceSize sizeBytes = getImageSizeBytes(sizeAsIVec3, format);
480
481 return sizeBytes;
482 }
483
mapImageType(const ImageType imageType)484 VkImageType mapImageType (const ImageType imageType)
485 {
486 switch (imageType)
487 {
488 case IMAGE_TYPE_1D:
489 case IMAGE_TYPE_1D_ARRAY:
490 case IMAGE_TYPE_BUFFER:
491 return VK_IMAGE_TYPE_1D;
492
493 case IMAGE_TYPE_2D:
494 case IMAGE_TYPE_2D_ARRAY:
495 case IMAGE_TYPE_CUBE:
496 case IMAGE_TYPE_CUBE_ARRAY:
497 return VK_IMAGE_TYPE_2D;
498
499 case IMAGE_TYPE_3D:
500 return VK_IMAGE_TYPE_3D;
501
502 default:
503 DE_ASSERT(false);
504 return VK_IMAGE_TYPE_LAST;
505 }
506 }
507
mapImageViewType(const ImageType imageType)508 VkImageViewType mapImageViewType (const ImageType imageType)
509 {
510 switch (imageType)
511 {
512 case IMAGE_TYPE_1D: return VK_IMAGE_VIEW_TYPE_1D;
513 case IMAGE_TYPE_1D_ARRAY: return VK_IMAGE_VIEW_TYPE_1D_ARRAY;
514 case IMAGE_TYPE_2D: return VK_IMAGE_VIEW_TYPE_2D;
515 case IMAGE_TYPE_2D_ARRAY: return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
516 case IMAGE_TYPE_3D: return VK_IMAGE_VIEW_TYPE_3D;
517 case IMAGE_TYPE_CUBE: return VK_IMAGE_VIEW_TYPE_CUBE;
518 case IMAGE_TYPE_CUBE_ARRAY: return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
519
520 default:
521 DE_ASSERT(false);
522 return VK_IMAGE_VIEW_TYPE_LAST;
523 }
524 }
525
getImageTypeName(const ImageType imageType)526 std::string getImageTypeName (const ImageType imageType)
527 {
528 switch (imageType)
529 {
530 case IMAGE_TYPE_1D: return "1d";
531 case IMAGE_TYPE_1D_ARRAY: return "1d_array";
532 case IMAGE_TYPE_2D: return "2d";
533 case IMAGE_TYPE_2D_ARRAY: return "2d_array";
534 case IMAGE_TYPE_3D: return "3d";
535 case IMAGE_TYPE_CUBE: return "cube";
536 case IMAGE_TYPE_CUBE_ARRAY: return "cube_array";
537 case IMAGE_TYPE_BUFFER: return "buffer";
538
539 default:
540 DE_ASSERT(false);
541 return "";
542 }
543 }
544
getFormatPrefix(const tcu::TextureFormat & format)545 std::string getFormatPrefix (const tcu::TextureFormat& format)
546 {
547 const std::string image64 = ((mapTextureFormat(format) == VK_FORMAT_R64_UINT || mapTextureFormat(format) == VK_FORMAT_R64_SINT) ? "64" : "");
548 return tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER ? "u" + image64 :
549 tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER ? "i" + image64 : "";
550 }
551
getShaderImageType(const tcu::TextureFormat & format,const ImageType imageType,const bool multisample)552 std::string getShaderImageType (const tcu::TextureFormat& format, const ImageType imageType, const bool multisample)
553 {
554 std::string formatPart = getFormatPrefix(format);
555
556 std::string imageTypePart;
557 if (multisample)
558 {
559 switch (imageType)
560 {
561 case IMAGE_TYPE_2D: imageTypePart = "2DMS"; break;
562 case IMAGE_TYPE_2D_ARRAY: imageTypePart = "2DMSArray"; break;
563
564 default:
565 DE_ASSERT(false);
566 }
567 }
568 else
569 {
570 switch (imageType)
571 {
572 case IMAGE_TYPE_1D: imageTypePart = "1D"; break;
573 case IMAGE_TYPE_1D_ARRAY: imageTypePart = "1DArray"; break;
574 case IMAGE_TYPE_2D: imageTypePart = "2D"; break;
575 case IMAGE_TYPE_2D_ARRAY: imageTypePart = "2DArray"; break;
576 case IMAGE_TYPE_3D: imageTypePart = "3D"; break;
577 case IMAGE_TYPE_CUBE: imageTypePart = "Cube"; break;
578 case IMAGE_TYPE_CUBE_ARRAY: imageTypePart = "CubeArray"; break;
579 case IMAGE_TYPE_BUFFER: imageTypePart = "Buffer"; break;
580
581 default:
582 DE_ASSERT(false);
583 }
584 }
585
586 return formatPart + "image" + imageTypePart;
587 }
588
getShaderImageFormatQualifier(const tcu::TextureFormat & format)589 std::string getShaderImageFormatQualifier (const tcu::TextureFormat& format)
590 {
591 if (!isPackedType(mapTextureFormat(format)))
592 {
593 const char* orderPart;
594 const char* typePart;
595
596 switch (format.order)
597 {
598 case tcu::TextureFormat::R: orderPart = "r"; break;
599 case tcu::TextureFormat::RG: orderPart = "rg"; break;
600 case tcu::TextureFormat::RGB: orderPart = "rgb"; break;
601 case tcu::TextureFormat::RGBA: orderPart = "rgba"; break;
602 case tcu::TextureFormat::sRGBA: orderPart = "rgba"; break;
603
604 default:
605 DE_FATAL("Order not found");
606 orderPart = DE_NULL;
607 }
608
609 switch (format.type)
610 {
611 case tcu::TextureFormat::FLOAT: typePart = "32f"; break;
612 case tcu::TextureFormat::HALF_FLOAT: typePart = "16f"; break;
613
614 case tcu::TextureFormat::UNSIGNED_INT64: typePart = "64ui"; break;
615 case tcu::TextureFormat::UNSIGNED_INT32: typePart = "32ui"; break;
616 case tcu::TextureFormat::USCALED_INT16:
617 case tcu::TextureFormat::UNSIGNED_INT16: typePart = "16ui"; break;
618 case tcu::TextureFormat::USCALED_INT8:
619 case tcu::TextureFormat::UNSIGNED_INT8: typePart = "8ui"; break;
620
621 case tcu::TextureFormat::SIGNED_INT64: typePart = "64i"; break;
622 case tcu::TextureFormat::SIGNED_INT32: typePart = "32i"; break;
623 case tcu::TextureFormat::SSCALED_INT16:
624 case tcu::TextureFormat::SIGNED_INT16: typePart = "16i"; break;
625 case tcu::TextureFormat::SSCALED_INT8:
626 case tcu::TextureFormat::SIGNED_INT8: typePart = "8i"; break;
627
628 case tcu::TextureFormat::UNORM_INT16: typePart = "16"; break;
629 case tcu::TextureFormat::UNORM_INT8: typePart = "8"; break;
630
631 case tcu::TextureFormat::SNORM_INT16: typePart = "16_snorm"; break;
632 case tcu::TextureFormat::SNORM_INT8: typePart = "8_snorm"; break;
633
634 default:
635 DE_FATAL("Type not found");
636 typePart = DE_NULL;
637 }
638
639 return std::string() + orderPart + typePart;
640 }
641 else
642 {
643 switch (mapTextureFormat(format))
644 {
645 case VK_FORMAT_B10G11R11_UFLOAT_PACK32: return "r11f_g11f_b10f";
646 case VK_FORMAT_A2B10G10R10_UNORM_PACK32: return "rgb10_a2";
647 case VK_FORMAT_A2B10G10R10_UINT_PACK32: return "rgb10_a2ui";
648
649 default:
650 DE_FATAL("Qualifier not found");
651 return "";
652 }
653 }
654 }
655
getGlslSamplerType(const tcu::TextureFormat & format,VkImageViewType type)656 std::string getGlslSamplerType (const tcu::TextureFormat& format, VkImageViewType type)
657 {
658 const char* typePart = DE_NULL;
659 const char* formatPart = tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER ? "u" :
660 tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER ? "i" : "";
661
662 switch (type)
663 {
664 case VK_IMAGE_VIEW_TYPE_1D: typePart = "sampler1D"; break;
665 case VK_IMAGE_VIEW_TYPE_1D_ARRAY: typePart = "sampler1DArray"; break;
666 case VK_IMAGE_VIEW_TYPE_2D: typePart = "sampler2D"; break;
667 case VK_IMAGE_VIEW_TYPE_2D_ARRAY: typePart = "sampler2DArray"; break;
668 case VK_IMAGE_VIEW_TYPE_3D: typePart = "sampler3D"; break;
669 case VK_IMAGE_VIEW_TYPE_CUBE: typePart = "samplerCube"; break;
670 case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: typePart = "samplerCubeArray"; break;
671
672 default:
673 DE_FATAL("Unknown image view type");
674 break;
675 }
676
677 return std::string(formatPart) + typePart;
678 }
679
680
getGlslInputFormatType(const vk::VkFormat format)681 const char* getGlslInputFormatType (const vk::VkFormat format)
682 {
683 switch (format)
684 {
685 // 64-bit
686 case VK_FORMAT_R16G16B16A16_UNORM: return "subpassInput";
687 case VK_FORMAT_R16G16B16A16_SNORM: return "subpassInput";
688 case VK_FORMAT_R16G16B16A16_USCALED: return "subpassInput";
689 case VK_FORMAT_R16G16B16A16_SSCALED: return "subpassInput";
690 case VK_FORMAT_R16G16B16A16_UINT: return "usubpassInput";
691 case VK_FORMAT_R16G16B16A16_SINT: return "isubpassInput";
692 case VK_FORMAT_R16G16B16A16_SFLOAT: return "subpassInput";
693 case VK_FORMAT_R32G32_UINT: return "usubpassInput";
694 case VK_FORMAT_R32G32_SINT: return "isubpassInput";
695 case VK_FORMAT_R32G32_SFLOAT: return "subpassInput";
696 // TODO: case VK_FORMAT_R64_UINT: return "usubpassInput";
697 // TODO: case VK_FORMAT_R64_SINT: return "isubpassInput";
698 // TODO: case VK_FORMAT_R64_SFLOAT: return "subpassInput";
699
700 // 128-bit
701 case VK_FORMAT_R32G32B32A32_UINT: return "usubpassInput";
702 case VK_FORMAT_R32G32B32A32_SINT: return "isubpassInput";
703 case VK_FORMAT_R32G32B32A32_SFLOAT: return "subpassInput";
704 // TODO: case VK_FORMAT_R64G64_UINT: return "usubpassInput";
705 // TODO: case VK_FORMAT_R64G64_SINT: return "isubpassInput";
706 // TODO: case VK_FORMAT_R64G64_SFLOAT: return "subpassInput";
707
708 default: TCU_THROW(InternalError, "Unknown format");
709 }
710 }
711
getGlslFormatType(const vk::VkFormat format)712 const char* getGlslFormatType (const vk::VkFormat format)
713 {
714 switch (format)
715 {
716 // 64-bit
717 case VK_FORMAT_R16G16B16A16_UNORM: return "vec4";
718 case VK_FORMAT_R16G16B16A16_SNORM: return "vec4";
719 case VK_FORMAT_R16G16B16A16_USCALED: return "vec4";
720 case VK_FORMAT_R16G16B16A16_SSCALED: return "vec4";
721 case VK_FORMAT_R16G16B16A16_UINT: return "uvec4";
722 case VK_FORMAT_R16G16B16A16_SINT: return "ivec4";
723 case VK_FORMAT_R16G16B16A16_SFLOAT: return "vec4";
724 case VK_FORMAT_R32G32_UINT: return "uvec2";
725 case VK_FORMAT_R32G32_SINT: return "ivec2";
726 case VK_FORMAT_R32G32_SFLOAT: return "vec2";
727 // TODO: case VK_FORMAT_R64_UINT: return "uint64";
728 // TODO: case VK_FORMAT_R64_SINT: return "int64";
729 // TODO: case VK_FORMAT_R64_SFLOAT: return "double";
730
731 // 128-bit
732 case VK_FORMAT_R32G32B32A32_UINT: return "uvec4";
733 case VK_FORMAT_R32G32B32A32_SINT: return "ivec4";
734 case VK_FORMAT_R32G32B32A32_SFLOAT: return "vec4";
735 // TODO: case VK_FORMAT_R64G64_UINT: return "ulvec2";
736 // TODO: case VK_FORMAT_R64G64_SINT: return "ilvec2";
737 // TODO: case VK_FORMAT_R64G64_SFLOAT: return "dvec2";
738
739 default: TCU_THROW(InternalError, "Unknown format");
740 }
741 }
742
getGlslAttachmentType(const vk::VkFormat format)743 const char* getGlslAttachmentType (const vk::VkFormat format)
744 {
745 const tcu::TextureFormat textureFormat = mapVkFormat(format);
746 const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(textureFormat.type);
747
748 switch (channelClass)
749 {
750 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
751 return "ivec4";
752
753 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
754 return "uvec4";
755
756 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
757 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
758 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
759 return "vec4";
760
761 default:
762 DE_FATAL("Unknown channel class");
763 return "";
764 }
765 }
766
getGlslInputAttachmentType(const vk::VkFormat format)767 const char* getGlslInputAttachmentType (const vk::VkFormat format)
768 {
769 const tcu::TextureFormat textureFormat = mapVkFormat(format);
770 const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(textureFormat.type);
771
772 switch (channelClass)
773 {
774 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
775 return "isubpassInput";
776
777 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
778 return "usubpassInput";
779
780 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
781 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
782 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
783 return "subpassInput";
784
785 default:
786 DE_FATAL("Unknown channel class");
787 return "";
788 }
789 }
790
isPackedType(const vk::VkFormat format)791 bool isPackedType (const vk::VkFormat format)
792 {
793 const tcu::TextureFormat textureFormat = mapVkFormat(format);
794
795 DE_STATIC_ASSERT(tcu::TextureFormat::CHANNELTYPE_LAST == 48);
796
797 switch (textureFormat.type)
798 {
799 case tcu::TextureFormat::UNORM_BYTE_44:
800 case tcu::TextureFormat::UNORM_SHORT_565:
801 case tcu::TextureFormat::UNORM_SHORT_555:
802 case tcu::TextureFormat::UNORM_SHORT_4444:
803 case tcu::TextureFormat::UNORM_SHORT_5551:
804 case tcu::TextureFormat::UNORM_SHORT_1555:
805 case tcu::TextureFormat::UNORM_INT_101010:
806 case tcu::TextureFormat::SNORM_INT_1010102_REV:
807 case tcu::TextureFormat::UNORM_INT_1010102_REV:
808 case tcu::TextureFormat::UNSIGNED_BYTE_44:
809 case tcu::TextureFormat::UNSIGNED_SHORT_565:
810 case tcu::TextureFormat::UNSIGNED_SHORT_4444:
811 case tcu::TextureFormat::UNSIGNED_SHORT_5551:
812 case tcu::TextureFormat::SIGNED_INT_1010102_REV:
813 case tcu::TextureFormat::UNSIGNED_INT_1010102_REV:
814 case tcu::TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
815 case tcu::TextureFormat::UNSIGNED_INT_999_E5_REV:
816 case tcu::TextureFormat::UNSIGNED_INT_16_8_8:
817 case tcu::TextureFormat::UNSIGNED_INT_24_8:
818 case tcu::TextureFormat::UNSIGNED_INT_24_8_REV:
819 case tcu::TextureFormat::SSCALED_INT_1010102_REV:
820 case tcu::TextureFormat::USCALED_INT_1010102_REV:
821 return true;
822
823 default:
824 return false;
825 }
826 }
827
isComponentSwizzled(const vk::VkFormat format)828 bool isComponentSwizzled (const vk::VkFormat format)
829 {
830 const tcu::TextureFormat textureFormat = mapVkFormat(format);
831
832 DE_STATIC_ASSERT(tcu::TextureFormat::CHANNELORDER_LAST == 22);
833
834 switch (textureFormat.order)
835 {
836 case tcu::TextureFormat::ARGB:
837 case tcu::TextureFormat::ABGR:
838 case tcu::TextureFormat::BGR:
839 case tcu::TextureFormat::BGRA:
840 case tcu::TextureFormat::sBGR:
841 case tcu::TextureFormat::sBGRA:
842 return true;
843
844 default:
845 return false;
846 }
847 }
848
getNumUsedChannels(const vk::VkFormat format)849 int getNumUsedChannels (const vk::VkFormat format)
850 {
851 // make sure this function will be checked if type table is updated
852 DE_STATIC_ASSERT(tcu::TextureFormat::CHANNELORDER_LAST == 22);
853
854 const tcu::TextureFormat textureFormat = mapVkFormat(format);
855
856 return getNumUsedChannels(textureFormat.order);
857 }
858
isFormatImageLoadStoreCapable(const vk::VkFormat format)859 bool isFormatImageLoadStoreCapable (const vk::VkFormat format)
860 {
861 // These come from https://www.khronos.org/registry/vulkan/specs/1.1/html/vkspec.html#spirvenv-image-formats
862 switch (format)
863 {
864 case VK_FORMAT_R32G32B32A32_SFLOAT:
865 case VK_FORMAT_R16G16B16A16_SFLOAT:
866 case VK_FORMAT_R32_SFLOAT:
867 case VK_FORMAT_R8G8B8A8_UNORM:
868 case VK_FORMAT_R8G8B8A8_SNORM:
869 case VK_FORMAT_R32G32_SFLOAT:
870 case VK_FORMAT_R16G16_SFLOAT:
871 case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
872 case VK_FORMAT_R16_SFLOAT:
873 case VK_FORMAT_R16G16B16A16_UNORM:
874 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
875 case VK_FORMAT_R16G16_UNORM:
876 case VK_FORMAT_R8G8_UNORM:
877 case VK_FORMAT_R16_UNORM:
878 case VK_FORMAT_R8_UNORM:
879 case VK_FORMAT_R16G16B16A16_SNORM:
880 case VK_FORMAT_R16G16_SNORM:
881 case VK_FORMAT_R8G8_SNORM:
882 case VK_FORMAT_R16_SNORM:
883 case VK_FORMAT_R8_SNORM:
884 case VK_FORMAT_R32G32B32A32_SINT:
885 case VK_FORMAT_R16G16B16A16_SINT:
886 case VK_FORMAT_R8G8B8A8_SINT:
887 case VK_FORMAT_R32_SINT:
888 case VK_FORMAT_R32G32_SINT:
889 case VK_FORMAT_R16G16_SINT:
890 case VK_FORMAT_R8G8_SINT:
891 case VK_FORMAT_R16_SINT:
892 case VK_FORMAT_R8_SINT:
893 case VK_FORMAT_R32G32B32A32_UINT:
894 case VK_FORMAT_R16G16B16A16_UINT:
895 case VK_FORMAT_R8G8B8A8_UINT:
896 case VK_FORMAT_R32_UINT:
897 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
898 case VK_FORMAT_R32G32_UINT:
899 case VK_FORMAT_R16G16_UINT:
900 case VK_FORMAT_R8G8_UINT:
901 case VK_FORMAT_R16_UINT:
902 case VK_FORMAT_R8_UINT:
903 return true;
904
905 default:
906 return false;
907 }
908 }
909
getFormatShortString(const VkFormat format)910 std::string getFormatShortString (const VkFormat format)
911 {
912 const std::string fullName = getFormatName(format);
913
914 DE_ASSERT(de::beginsWith(fullName, "VK_FORMAT_"));
915
916 return de::toLower(fullName.substr(10));
917 }
918
createFullscreenQuad(void)919 std::vector<tcu::Vec4> createFullscreenQuad (void)
920 {
921 const tcu::Vec4 lowerLeftVertex (-1.0f, -1.0f, 0.0f, 1.0f);
922 const tcu::Vec4 upperLeftVertex (-1.0f, 1.0f, 0.0f, 1.0f);
923 const tcu::Vec4 lowerRightVertex (1.0f, -1.0f, 0.0f, 1.0f);
924 const tcu::Vec4 upperRightVertex (1.0f, 1.0f, 0.0f, 1.0f);
925
926 const tcu::Vec4 vertices[6] =
927 {
928 lowerLeftVertex,
929 lowerRightVertex,
930 upperLeftVertex,
931
932 upperLeftVertex,
933 lowerRightVertex,
934 upperRightVertex
935 };
936
937 return std::vector<tcu::Vec4>(vertices, vertices + DE_LENGTH_OF_ARRAY(vertices));
938 }
939
makeBufferImageCopy(const deUint32 imageWidth,const deUint32 imageHeight,const deUint32 mipLevel,const deUint32 layer)940 vk::VkBufferImageCopy makeBufferImageCopy (const deUint32 imageWidth, const deUint32 imageHeight, const deUint32 mipLevel, const deUint32 layer)
941 {
942 const VkBufferImageCopy copyParams =
943 {
944 (VkDeviceSize)0u, // bufferOffset
945 imageWidth, // bufferRowLength
946 imageHeight, // bufferImageHeight
947 {
948 VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
949 mipLevel, // mipLevel
950 layer, // baseArrayLayer
951 1u, // layerCount
952 }, // imageSubresource
953 { 0u, 0u, 0u }, // imageOffset
954 {
955 imageWidth,
956 imageHeight,
957 1u
958 } // imageExtent
959 };
960
961 return copyParams;
962 }
963
makeBufferImageCopy(const deUint32 imageWidth,const deUint32 imageHeight,const deUint32 mipLevel,const deUint32 layer,const deUint32 bufferRowLength,const deUint32 bufferImageHeight)964 vk::VkBufferImageCopy makeBufferImageCopy (const deUint32 imageWidth, const deUint32 imageHeight, const deUint32 mipLevel, const deUint32 layer, const deUint32 bufferRowLength, const deUint32 bufferImageHeight)
965 {
966 const VkBufferImageCopy copyParams =
967 {
968 (VkDeviceSize)0u, // bufferOffset
969 bufferRowLength, // bufferRowLength
970 bufferImageHeight, // bufferImageHeight
971 {
972 VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
973 mipLevel, // mipLevel
974 layer, // baseArrayLayer
975 1u, // layerCount
976 }, // imageSubresource
977 { 0u, 0u, 0u }, // imageOffset
978 {
979 imageWidth,
980 imageHeight,
981 1u
982 } // imageExtent
983 };
984
985 return copyParams;
986 }
987
beginRenderPass(const DeviceInterface & vk,const VkCommandBuffer commandBuffer,const VkRenderPass renderPass,const VkFramebuffer framebuffer,const VkExtent2D & renderSize)988 void beginRenderPass (const DeviceInterface& vk,
989 const VkCommandBuffer commandBuffer,
990 const VkRenderPass renderPass,
991 const VkFramebuffer framebuffer,
992 const VkExtent2D& renderSize)
993 {
994 const VkRect2D renderArea =
995 {
996 {0, 0}, // VkOffset2D offset;
997 renderSize, // VkExtent2D extent;
998 };
999
1000 beginRenderPass(vk, commandBuffer, renderPass, framebuffer, renderArea, tcu::Vec4(0.0f), 0.0f, 0u);
1001 }
1002
1003 } // image
1004 } // vkt
1005