1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2019 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 Tests fragment density map extension ( VK_EXT_fragment_density_map )
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktRenderPassFragmentDensityMapTests.hpp"
25 #include "pipeline/vktPipelineImageUtil.hpp"
26 #include "deMath.h"
27 #include "vktTestCase.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vktCustomInstancesDevices.hpp"
30 #include "vkImageUtil.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkCmdUtil.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkObjUtil.hpp"
35 #include "vkBarrierUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "tcuCommandLine.hpp"
38 #include "tcuStringTemplate.hpp"
39 #include "tcuTextureUtil.hpp"
40 #include "tcuTestLog.hpp"
41 #include <sstream>
42 #include <vector>
43 #include <set>
44
45 // Each test generates an image with a color gradient where all colors should be unique when rendered without density map
46 // ( and for multi_view tests - the quantity of each color in a histogram should be 2 instead of 1 ).
47 // The whole density map has the same values defined by input fragment area ( one of the test input parameters ).
48 // With density map enabled - the number of each color in a histogram should be [ fragmentArea.x * fragmentArea.y ]
49 // ( that value will be doubled for multi_view case ).
50 //
51 // Additionally test checks if gl_FragSizeEXT shader variable has proper value ( as defined by fragmentArea input parameter ).
52 //
53 // Test variations:
54 // - multi_view tests check if density map also works when VK_KHR_multiview extension is in use
55 // - render_copy tests check if it's possible to copy results using input attachment descriptor ( this simulates deferred rendering behaviour )
56 // - non_divisible_density_size tests check if subsampled images work when its dimension is not divisible by minFragmentDensityTexelSize
57 // - N_samples tests check if multisampling works with VK_EXT_fragment_density_map extension
58 // - static_* tests use density map loaded from CPU during vkCmdBeginRenderPass.
59 // - dynamic_* tests use density map rendered on a GPU in a separate render pass
60 // - deffered_* tests use density map loaded from CPU during VkEndCommandBuffer.
61 // - *_nonsubsampled tests check if it's possible to use nonsubsampled images instead of subsampled ones
62
63 // There are 3 render passes performed during most of the tests:
64 // - render pass that produces density map ( this rp is skipped when density map is static )
65 // - render pass that produces subsampled image using density map and eventually copies results to different image ( render_copy )
66 // - render pass that copies subsampled image to traditional image using sampler with VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT flag.
67 // ( because subsampled images cannot be retrieved to CPU in any other way ).
68 // There are few tests that use additional subpass that resamples subsampled image using diferent density map.
69
70 // Code of FragmentDensityMapTestInstance is also used to test subsampledLoads, subsampledCoarseReconstructionEarlyAccess,
71 // maxDescriptorSetSubsampledSamplers properties.
72
73 // set value of DRY_RUN_WITHOUT_FDM_EXTENSION to 1 for dummy run hat checks the correctness of the code without using VK_EXT_fragment_density_map extension
74 #define DRY_RUN_WITHOUT_FDM_EXTENSION 0
75
76 namespace vkt
77 {
78
79 namespace renderpass
80 {
81
82 using namespace vk;
83
84 namespace
85 {
86
87 struct TestParams
88 {
89 bool dynamicDensityMap;
90 bool deferredDensityMap;
91 bool nonSubsampledImages;
92 bool subsampledLoads;
93 bool coarseReconstruction;
94 deUint32 samplersCount;
95 deUint32 viewCount;
96 bool makeCopy;
97 float renderMultiplier;
98 VkSampleCountFlagBits colorSamples;
99 tcu::UVec2 fragmentArea;
100 tcu::UVec2 densityMapSize;
101 VkFormat densityMapFormat;
102 };
103
104 struct Vertex4RGBA
105 {
106 tcu::Vec4 position;
107 tcu::Vec4 uv;
108 tcu::Vec4 color;
109 };
110
111 de::SharedPtr<Move<vk::VkDevice>> g_singletonDevice;
112
removeExtensions(const std::vector<std::string> & a,const std::vector<const char * > & b)113 static std::vector<std::string> removeExtensions (const std::vector<std::string>& a, const std::vector<const char*>& b)
114 {
115 std::vector<std::string> res;
116 std::set<std::string> removeExts (b.begin(), b.end());
117
118 for (std::vector<std::string>::const_iterator aIter = a.begin(); aIter != a.end(); ++aIter)
119 {
120 if (!de::contains(removeExts, *aIter))
121 res.push_back(*aIter);
122 }
123
124 return res;
125 }
126
getDevice(Context & context)127 VkDevice getDevice(Context& context)
128 {
129 if (!g_singletonDevice)
130 {
131 const float queuePriority = 1.0f;
132
133 // Create a universal queue that supports graphics and compute
134 const VkDeviceQueueCreateInfo queueParams =
135 {
136 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
137 DE_NULL, // const void* pNext;
138 0u, // VkDeviceQueueCreateFlags flags;
139 context.getUniversalQueueFamilyIndex(), // deUint32 queueFamilyIndex;
140 1u, // deUint32 queueCount;
141 &queuePriority // const float* pQueuePriorities;
142 };
143
144 // \note Extensions in core are not explicitly enabled even though
145 // they are in the extension list advertised to tests.
146 std::vector<const char*> extensionPtrs;
147 std::vector<const char*> coreExtensions;
148 getCoreDeviceExtensions(context.getUsedApiVersion(), coreExtensions);
149 std::vector<std::string> nonCoreExtensions(removeExtensions(context.getDeviceExtensions(), coreExtensions));
150
151 extensionPtrs.resize(nonCoreExtensions.size());
152
153 for (size_t ndx = 0; ndx < nonCoreExtensions.size(); ++ndx)
154 extensionPtrs[ndx] = nonCoreExtensions[ndx].c_str();
155
156 VkPhysicalDeviceFragmentDensityMapFeaturesEXT fragmentDensityMapFeatures = initVulkanStructure();
157 VkPhysicalDeviceFragmentDensityMap2FeaturesEXT fragmentDensityMap2Features = initVulkanStructure(&fragmentDensityMapFeatures);
158 VkPhysicalDeviceFeatures2 features2 = initVulkanStructure(&fragmentDensityMap2Features);
159
160 context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &features2);
161 const VkPhysicalDeviceFeatures2 & feature2ptr = context.getDeviceFeatures2();
162
163 const VkDeviceCreateInfo deviceCreateInfo =
164 {
165 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, //sType;
166 &feature2ptr, //pNext;
167 (VkDeviceCreateFlags)0u, //flags
168 1, //queueRecordCount;
169 &queueParams, //pRequestedQueues;
170 0, //layerCount;
171 DE_NULL, //ppEnabledLayerNames;
172 (deUint32)extensionPtrs.size(), // deUint32 enabledExtensionCount;
173 (extensionPtrs.empty() ? DE_NULL : &extensionPtrs[0]), // const char* const* ppEnabledExtensionNames;
174 DE_NULL, //pEnabledFeatures;
175 };
176
177 Move<VkDevice> device = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), context.getPlatformInterface(), context.getInstance(), context.getInstanceInterface(), context.getPhysicalDevice(), &deviceCreateInfo);
178 g_singletonDevice = de::SharedPtr<Move<VkDevice>>(new Move<VkDevice>(device));
179 }
180
181 return g_singletonDevice->get();
182 }
183
createFullscreenMesh(deUint32 viewCount,tcu::Vec2 redGradient,tcu::Vec2 greenGradient)184 std::vector<Vertex4RGBA> createFullscreenMesh(deUint32 viewCount, tcu::Vec2 redGradient, tcu::Vec2 greenGradient)
185 {
186 DE_ASSERT(viewCount > 0);
187
188 const auto& r = redGradient;
189 const auto& g = greenGradient;
190 const float step = 2.0f / static_cast<float>(viewCount);
191 float xStart = -1.0f;
192
193 std::vector<Vertex4RGBA> resultMesh;
194 for (deUint32 viewIndex = 0; viewIndex < viewCount ; ++viewIndex)
195 {
196 const float fIndex = static_cast<float>(viewIndex);
197 const deUint32 nextIndex = viewIndex + 1;
198 const float xEnd = (nextIndex == viewCount) ? 1.0f : (-1.0f + step * static_cast<float>(nextIndex));
199
200 // quad vertex position uv color
201 const Vertex4RGBA lowerLeftVertex = { { xStart, 1.0f, 0.0f, 1.0f }, { 0.0f, 1.0f, fIndex, 1.0f }, { r.x(), g.y(), 0.0f, 1.0f } };
202 const Vertex4RGBA upperLeftVertex = { { xStart, -1.0f, 0.0f, 1.0f }, { 0.0f, 0.0f, fIndex, 1.0f }, { r.x(), g.x(), 0.0f, 1.0f } };
203 const Vertex4RGBA lowerRightVertex = { { xEnd, 1.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, fIndex, 1.0f }, { r.y(), g.y(), 0.0f, 1.0f } };
204 const Vertex4RGBA upperRightVertex = { { xEnd, -1.0f, 0.0f, 1.0f }, { 1.0f, 0.0f, fIndex, 1.0f }, { r.y(), g.x(), 0.0f, 1.0f } };
205
206 const std::vector<Vertex4RGBA> viewData
207 {
208 lowerLeftVertex, lowerRightVertex, upperLeftVertex,
209 upperLeftVertex, lowerRightVertex, upperRightVertex
210 };
211
212 resultMesh.insert(resultMesh.end(), viewData.begin(), viewData.end());
213 xStart = xEnd;
214 }
215
216 return resultMesh;
217 }
218
219 template <typename T>
createVertexBuffer(const DeviceInterface & vk,VkDevice vkDevice,const deUint32 & queueFamilyIndex,SimpleAllocator & memAlloc,const std::vector<T> & vertices,Move<VkBuffer> & vertexBuffer,de::MovePtr<Allocation> & vertexAlloc)220 void createVertexBuffer(const DeviceInterface& vk,
221 VkDevice vkDevice,
222 const deUint32& queueFamilyIndex,
223 SimpleAllocator& memAlloc,
224 const std::vector<T>& vertices,
225 Move<VkBuffer>& vertexBuffer,
226 de::MovePtr<Allocation>& vertexAlloc)
227 {
228 const VkBufferCreateInfo vertexBufferParams =
229 {
230 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
231 DE_NULL, // const void* pNext;
232 0u, // VkBufferCreateFlags flags;
233 (VkDeviceSize)(sizeof(T) * vertices.size()), // VkDeviceSize size;
234 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
235 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
236 1u, // deUint32 queueFamilyIndexCount;
237 &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
238 };
239
240 vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams);
241 vertexAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *vertexBuffer), MemoryRequirement::HostVisible);
242 VK_CHECK(vk.bindBufferMemory(vkDevice, *vertexBuffer, vertexAlloc->getMemory(), vertexAlloc->getOffset()));
243
244 // Upload vertex data
245 deMemcpy(vertexAlloc->getHostPtr(), vertices.data(), vertices.size() * sizeof(T));
246 flushAlloc(vk, vkDevice, *vertexAlloc);
247 }
248
prepareImageAndImageView(const DeviceInterface & vk,VkDevice vkDevice,SimpleAllocator & memAlloc,VkImageCreateFlags imageCreateFlags,VkFormat format,VkExtent3D extent,deUint32 arrayLayers,VkSampleCountFlagBits samples,VkImageUsageFlags usage,deUint32 queueFamilyIndex,VkImageViewCreateFlags viewFlags,VkImageViewType viewType,const VkComponentMapping & channels,const VkImageSubresourceRange & subresourceRange,Move<VkImage> & image,de::MovePtr<Allocation> & imageAlloc,Move<VkImageView> & imageView)249 void prepareImageAndImageView (const DeviceInterface& vk,
250 VkDevice vkDevice,
251 SimpleAllocator& memAlloc,
252 VkImageCreateFlags imageCreateFlags,
253 VkFormat format,
254 VkExtent3D extent,
255 deUint32 arrayLayers,
256 VkSampleCountFlagBits samples,
257 VkImageUsageFlags usage,
258 deUint32 queueFamilyIndex,
259 VkImageViewCreateFlags viewFlags,
260 VkImageViewType viewType,
261 const VkComponentMapping& channels,
262 const VkImageSubresourceRange& subresourceRange,
263 Move<VkImage>& image,
264 de::MovePtr<Allocation>& imageAlloc,
265 Move<VkImageView>& imageView)
266 {
267 const VkImageCreateInfo imageCreateInfo
268 {
269 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
270 DE_NULL, // const void* pNext;
271 imageCreateFlags, // VkImageCreateFlags flags;
272 VK_IMAGE_TYPE_2D, // VkImageType imageType;
273 format, // VkFormat format;
274 extent, // VkExtent3D extent;
275 1u, // deUint32 mipLevels;
276 arrayLayers, // deUint32 arrayLayers;
277 samples, // VkSampleCountFlagBits samples;
278 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
279 usage, // VkImageUsageFlags usage;
280 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
281 1u, // deUint32 queueFamilyIndexCount;
282 &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
283 VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
284 };
285
286 image = createImage(vk, vkDevice, &imageCreateInfo);
287
288 // Allocate and bind color image memory
289 imageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *image), MemoryRequirement::Any);
290 VK_CHECK(vk.bindImageMemory(vkDevice, *image, imageAlloc->getMemory(), imageAlloc->getOffset()));
291
292 // create image view for subsampled image
293 const VkImageViewCreateInfo imageViewCreateInfo =
294 {
295 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
296 DE_NULL, // const void* pNext;
297 viewFlags, // VkImageViewCreateFlags flags;
298 *image, // VkImage image;
299 viewType, // VkImageViewType viewType;
300 format, // VkFormat format;
301 channels, // VkChannelMapping channels;
302 subresourceRange // VkImageSubresourceRange subresourceRange;
303 };
304
305 imageView = createImageView(vk, vkDevice, &imageViewCreateInfo);
306 }
307
createRenderPassProduceDynamicDensityMap(const DeviceInterface & vk,VkDevice vkDevice,deUint32 viewMask,const TestParams & testParams)308 Move<VkRenderPass> createRenderPassProduceDynamicDensityMap(const DeviceInterface& vk,
309 VkDevice vkDevice,
310 deUint32 viewMask,
311 const TestParams& testParams)
312 {
313 DE_ASSERT(testParams.dynamicDensityMap);
314
315 typedef AttachmentDescription2 AttachmentDesc;
316 typedef AttachmentReference2 AttachmentRef;
317 typedef SubpassDescription2 SubpassDesc;
318 typedef SubpassDependency2 SubpassDep;
319 typedef RenderPassCreateInfo2 RenderPassCreateInfo;
320
321 std::vector<AttachmentDesc> attachmentDescriptions
322 {
323 {
324 DE_NULL, // const void* pNext
325 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags
326 testParams.densityMapFormat, // VkFormat format
327 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
328 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp
329 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
330 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
331 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
332 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
333 #if DRY_RUN_WITHOUT_FDM_EXTENSION
334 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout
335 #else
336 VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT // VkImageLayout finalLayout
337 #endif
338 }
339 };
340
341 std::vector<AttachmentRef> colorAttachmentRefs
342 {
343 { DE_NULL, 0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT }
344 };
345
346 std::vector<SubpassDesc> subpassDescriptions
347 {
348 {
349 DE_NULL,
350 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags
351 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
352 viewMask, // deUint32 viewMask
353 0u, // deUint32 inputAttachmentCount
354 DE_NULL, // const VkAttachmentReference* pInputAttachments
355 static_cast<deUint32>(colorAttachmentRefs.size()), // deUint32 colorAttachmentCount
356 colorAttachmentRefs.data(), // const VkAttachmentReference* pColorAttachments
357 DE_NULL, // const VkAttachmentReference* pResolveAttachments
358 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment
359 0u, // deUint32 preserveAttachmentCount
360 DE_NULL // const deUint32* pPreserveAttachments
361 }
362 };
363
364 std::vector<SubpassDep> subpassDependencies
365 {
366 {
367 DE_NULL, // const void* pNext
368 0u, // uint32_t srcSubpass
369 VK_SUBPASS_EXTERNAL, // uint32_t dstSubpass
370 #if DRY_RUN_WITHOUT_FDM_EXTENSION
371 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask
372 VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags dstStageMask
373 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask
374 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, // VkAccessFlags dstAccessMask
375 #else
376 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask
377 VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT, // VkPipelineStageFlags dstStageMask
378 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask
379 VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT, // VkAccessFlags dstAccessMask
380 #endif
381 VK_DEPENDENCY_BY_REGION_BIT, // VkDependencyFlags dependencyFlags
382 0u // deInt32 viewOffset
383 }
384 };
385
386 const RenderPassCreateInfo renderPassInfo(
387 DE_NULL, // const void* pNext
388 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags
389 static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount
390 attachmentDescriptions.data(), // const VkAttachmentDescription* pAttachments
391 static_cast<deUint32>(subpassDescriptions.size()), // deUint32 subpassCount
392 subpassDescriptions.data(), // const VkSubpassDescription* pSubpasses
393 static_cast<deUint32>(subpassDependencies.size()), // deUint32 dependencyCount
394 subpassDependencies.empty() ? DE_NULL : subpassDependencies.data(), // const VkSubpassDependency* pDependencies
395 0u, // deUint32 correlatedViewMaskCount
396 DE_NULL // const deUint32* pCorrelatedViewMasks
397 );
398
399 return renderPassInfo.createRenderPass(vk, vkDevice);
400 }
401
createRenderPassProduceSubsampledImage(const DeviceInterface & vk,VkDevice vkDevice,deUint32 viewMask,bool makeCopySubpass,bool resampleSubsampled,const TestParams & testParams)402 Move<VkRenderPass> createRenderPassProduceSubsampledImage(const DeviceInterface& vk,
403 VkDevice vkDevice,
404 deUint32 viewMask,
405 bool makeCopySubpass,
406 bool resampleSubsampled,
407 const TestParams& testParams)
408 {
409 typedef AttachmentDescription2 AttachmentDesc;
410 typedef AttachmentReference2 AttachmentRef;
411 typedef SubpassDescription2 SubpassDesc;
412 typedef SubpassDependency2 SubpassDep;
413 typedef RenderPassCreateInfo2 RenderPassCreateInfo;
414
415 const void* constNullPtr = DE_NULL;
416 deUint32 multisampleAttachmentIndex = 0;
417 deUint32 copyAttachmentIndex = 0;
418 deUint32 densityMapAttachmentIndex = 0;
419
420 // add color image
421 VkAttachmentLoadOp loadOp = resampleSubsampled ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
422 std::vector<AttachmentDesc> attachmentDescriptions
423 {
424 // Output color attachment
425 {
426 DE_NULL, // const void* pNext
427 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags
428 VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format
429 testParams.colorSamples, // VkSampleCountFlagBits samples
430 loadOp, // VkAttachmentLoadOp loadOp
431 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
432 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
433 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
434 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
435 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout finalLayout
436 }
437 };
438
439 // add resolve image when we use more than one sample per fragment
440 if (testParams.colorSamples != VK_SAMPLE_COUNT_1_BIT)
441 {
442 multisampleAttachmentIndex = static_cast<deUint32>(attachmentDescriptions.size());
443 attachmentDescriptions.emplace_back(
444 constNullPtr, // const void* pNext
445 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags
446 VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format
447 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
448 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp
449 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
450 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
451 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
452 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
453 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout finalLayout
454 );
455 }
456
457 // add color image copy ( when render_copy is used )
458 if (makeCopySubpass)
459 {
460 copyAttachmentIndex = static_cast<deUint32>(attachmentDescriptions.size());
461 attachmentDescriptions.emplace_back(
462 constNullPtr, // const void* pNext
463 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags
464 VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format
465 testParams.colorSamples, // VkSampleCountFlagBits samples
466 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp
467 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
468 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
469 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
470 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
471 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout finalLayout
472 );
473 }
474
475 // add density map
476 densityMapAttachmentIndex = static_cast<deUint32>(attachmentDescriptions.size());
477 attachmentDescriptions.emplace_back(
478 constNullPtr, // const void* pNext
479 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags
480 testParams.densityMapFormat, // VkFormat format
481 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
482 VK_ATTACHMENT_LOAD_OP_LOAD, // VkAttachmentLoadOp loadOp
483 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp
484 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
485 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
486 VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT, // VkImageLayout initialLayout
487 VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT // VkImageLayout finalLayout
488 );
489
490 std::vector<AttachmentRef> colorAttachmentRefs0
491 {
492 { DE_NULL, 0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT }
493 };
494
495 // for multisampled scenario we need to add resolve attachment
496 // (for makeCopy scenario it is used in second subpass)
497 AttachmentRef* pResolveAttachments = DE_NULL;
498 AttachmentRef resolveAttachmentRef
499 {
500 DE_NULL,
501 multisampleAttachmentIndex,
502 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
503 VK_IMAGE_ASPECT_COLOR_BIT
504 };
505 if (testParams.colorSamples != VK_SAMPLE_COUNT_1_BIT)
506 pResolveAttachments = &resolveAttachmentRef;
507
508 std::vector<SubpassDesc> subpassDescriptions
509 {
510 {
511 DE_NULL,
512 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags
513 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
514 viewMask, // deUint32 viewMask
515 0u, // deUint32 inputAttachmentCount
516 DE_NULL, // const VkAttachmentReference* pInputAttachments
517 static_cast<deUint32>(colorAttachmentRefs0.size()), // deUint32 colorAttachmentCount
518 colorAttachmentRefs0.data(), // const VkAttachmentReference* pColorAttachments
519 makeCopySubpass ? DE_NULL : pResolveAttachments, // const VkAttachmentReference* pResolveAttachments
520 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment
521 0u, // deUint32 preserveAttachmentCount
522 DE_NULL // const deUint32* pPreserveAttachments
523 }
524 };
525
526 std::vector<AttachmentRef> inputAttachmentRefs1
527 {
528 { DE_NULL, 0u, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT }
529 };
530 std::vector<AttachmentRef> colorAttachmentRefs1
531 {
532 { DE_NULL, copyAttachmentIndex, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT }
533 };
534 std::vector<SubpassDep> subpassDependencies;
535
536 if (makeCopySubpass)
537 {
538 subpassDescriptions.push_back({
539 DE_NULL,
540 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags
541 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
542 viewMask, // deUint32 viewMask
543 static_cast<deUint32>(inputAttachmentRefs1.size()), // deUint32 inputAttachmentCount
544 inputAttachmentRefs1.data(), // const VkAttachmentReference* pInputAttachments
545 static_cast<deUint32>(colorAttachmentRefs1.size()), // deUint32 colorAttachmentCount
546 colorAttachmentRefs1.data(), // const VkAttachmentReference* pColorAttachments
547 pResolveAttachments, // const VkAttachmentReference* pResolveAttachments
548 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment
549 0u, // deUint32 preserveAttachmentCount
550 DE_NULL // const deUint32* pPreserveAttachments
551 });
552
553 VkDependencyFlags dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
554 if (testParams.viewCount > 1)
555 dependencyFlags |= VK_DEPENDENCY_VIEW_LOCAL_BIT;
556
557 subpassDependencies.emplace_back(
558 constNullPtr, // const void* pNext
559 0u, // uint32_t srcSubpass
560 1u, // uint32_t dstSubpass
561 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask
562 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags dstStageMask
563 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask
564 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, // VkAccessFlags dstAccessMask
565 dependencyFlags, // VkDependencyFlags dependencyFlags
566 0u // deInt32 viewOffset
567 );
568 }
569
570 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
571
572 // for coarse reconstruction we need to put barrier on vertex stage
573 if (testParams.coarseReconstruction)
574 dstStageMask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
575
576 subpassDependencies.emplace_back(
577 constNullPtr, // const void* pNext
578 static_cast<deUint32>(subpassDescriptions.size())-1u, // uint32_t srcSubpass
579 VK_SUBPASS_EXTERNAL, // uint32_t dstSubpass
580 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask
581 dstStageMask, // VkPipelineStageFlags dstStageMask
582 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask
583 VK_ACCESS_SHADER_READ_BIT, // VkAccessFlags dstAccessMask
584 VK_DEPENDENCY_BY_REGION_BIT, // VkDependencyFlags dependencyFlags
585 0u // deInt32 viewOffset
586 );
587
588 VkRenderPassFragmentDensityMapCreateInfoEXT renderPassFragmentDensityMap =
589 {
590 VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT,
591 DE_NULL,
592 { densityMapAttachmentIndex, VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT }
593 };
594
595 void* renderPassInfoPNext = (void*)&renderPassFragmentDensityMap;
596
597 #if DRY_RUN_WITHOUT_FDM_EXTENSION
598 // density map description is at the end - pop it from vector
599 attachmentDescriptions.pop_back();
600 renderPassInfoPNext = DE_NULL;
601 #endif
602
603 const RenderPassCreateInfo renderPassInfo(
604 renderPassInfoPNext, // const void* pNext
605 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags
606 static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount
607 attachmentDescriptions.data(), // const VkAttachmentDescription* pAttachments
608 static_cast<deUint32>(subpassDescriptions.size()), // deUint32 subpassCount
609 subpassDescriptions.data(), // const VkSubpassDescription* pSubpasses
610 static_cast<deUint32>(subpassDependencies.size()), // deUint32 dependencyCount
611 subpassDependencies.data(), // const VkSubpassDependency* pDependencies
612 0u, // deUint32 correlatedViewMaskCount
613 DE_NULL // const deUint32* pCorrelatedViewMasks
614 );
615
616 return renderPassInfo.createRenderPass(vk, vkDevice);
617 }
618
createRenderPassOutputSubsampledImage(const DeviceInterface & vk,VkDevice vkDevice)619 Move<VkRenderPass> createRenderPassOutputSubsampledImage(const DeviceInterface& vk,
620 VkDevice vkDevice)
621 {
622 typedef AttachmentDescription2 AttachmentDesc;
623 typedef AttachmentReference2 AttachmentRef;
624 typedef SubpassDescription2 SubpassDesc;
625 typedef RenderPassCreateInfo2 RenderPassCreateInfo;
626
627 // copy subsampled image to ordinary image - you cannot retrieve subsampled image to CPU in any way.
628 // You must first convert it into plain image through rendering
629 std::vector<AttachmentDesc> attachmentDescriptions =
630 {
631 // output attachment
632 {
633 DE_NULL, // const void* pNext
634 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags
635 VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format
636 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
637 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp
638 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
639 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
640 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
641 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
642 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout
643 },
644 };
645
646 std::vector<AttachmentRef> colorAttachmentRefs
647 {
648 { DE_NULL, 0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT }
649 };
650
651 std::vector<SubpassDesc> subpassDescriptions =
652 {
653 {
654 DE_NULL,
655 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags
656 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
657 0u, // deUint32 viewMask
658 0u, // deUint32 inputAttachmentCount
659 DE_NULL, // const VkAttachmentReference* pInputAttachments
660 static_cast<deUint32>(colorAttachmentRefs.size()), // deUint32 colorAttachmentCount
661 colorAttachmentRefs.data(), // const VkAttachmentReference* pColorAttachments
662 DE_NULL, // const VkAttachmentReference* pResolveAttachments
663 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment
664 0u, // deUint32 preserveAttachmentCount
665 DE_NULL // const deUint32* pPreserveAttachments
666 }
667 };
668
669 const RenderPassCreateInfo renderPassInfo(
670 DE_NULL, // const void* pNext
671 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags
672 static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount
673 attachmentDescriptions.data(), // const VkAttachmentDescription* pAttachments
674 static_cast<deUint32>(subpassDescriptions.size()), // deUint32 subpassCount
675 subpassDescriptions.data(), // const VkSubpassDescription* pSubpasses
676 0, // deUint32 dependencyCount
677 DE_NULL, // const VkSubpassDependency* pDependencies
678 0u, // deUint32 correlatedViewMaskCount
679 DE_NULL // const deUint32* pCorrelatedViewMasks
680 );
681
682 return renderPassInfo.createRenderPass(vk, vkDevice);
683 }
684
createFrameBuffer(const DeviceInterface & vk,VkDevice vkDevice,VkRenderPass renderPass,VkExtent3D size,const std::vector<VkImageView> & imageViews)685 Move<VkFramebuffer> createFrameBuffer( const DeviceInterface& vk, VkDevice vkDevice, VkRenderPass renderPass, VkExtent3D size, const std::vector<VkImageView>& imageViews)
686 {
687 const VkFramebufferCreateInfo framebufferParams =
688 {
689 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
690 DE_NULL, // const void* pNext;
691 0u, // VkFramebufferCreateFlags flags;
692 renderPass, // VkRenderPass renderPass;
693 static_cast<deUint32>(imageViews.size()), // deUint32 attachmentCount;
694 imageViews.data(), // const VkImageView* pAttachments;
695 size.width, // deUint32 width;
696 size.height, // deUint32 height;
697 1u // deUint32 layers;
698 };
699
700 return createFramebuffer(vk, vkDevice, &framebufferParams);
701 }
702
copyBufferToImage(const DeviceInterface & vk,VkDevice device,VkQueue queue,deUint32 queueFamilyIndex,const VkBuffer & buffer,VkDeviceSize bufferSize,const VkExtent3D & imageSize,deUint32 arrayLayers,VkImage destImage)703 void copyBufferToImage(const DeviceInterface& vk,
704 VkDevice device,
705 VkQueue queue,
706 deUint32 queueFamilyIndex,
707 const VkBuffer& buffer,
708 VkDeviceSize bufferSize,
709 const VkExtent3D& imageSize,
710 deUint32 arrayLayers,
711 VkImage destImage)
712 {
713 Move<VkCommandPool> cmdPool = createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
714 Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
715 Move<VkFence> fence = createFence(vk, device);
716 VkImageLayout destImageLayout = VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT;
717 VkPipelineStageFlags destImageDstStageFlags = VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT;
718 VkAccessFlags finalAccessMask = VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT;
719
720 #if DRY_RUN_WITHOUT_FDM_EXTENSION
721 destImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
722 destImageDstStageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
723 finalAccessMask = VK_ACCESS_SHADER_READ_BIT;
724 #endif
725
726 const VkCommandBufferBeginInfo cmdBufferBeginInfo =
727 {
728 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
729 DE_NULL, // const void* pNext;
730 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // VkCommandBufferUsageFlags flags;
731 (const VkCommandBufferInheritanceInfo*)DE_NULL,
732 };
733
734 const VkBufferImageCopy copyRegion =
735 {
736 0, // VkDeviceSize bufferOffset
737 0, // deUint32 bufferRowLength
738 0, // deUint32 bufferImageHeight
739 { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, arrayLayers }, // VkImageSubresourceLayers imageSubresource
740 { 0, 0, 0 }, // VkOffset3D imageOffset
741 imageSize // VkExtent3D imageExtent
742 };
743
744 // Barriers for copying buffer to image
745 const VkBufferMemoryBarrier preBufferBarrier = makeBufferMemoryBarrier(
746 VK_ACCESS_HOST_WRITE_BIT, // VkAccessFlags srcAccessMask;
747 VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
748 buffer, // VkBuffer buffer;
749 0u, // VkDeviceSize offset;
750 bufferSize // VkDeviceSize size;
751 );
752
753 const VkImageSubresourceRange subresourceRange
754 { // VkImageSubresourceRange subresourceRange;
755 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspect;
756 0u, // deUint32 baseMipLevel;
757 1u, // deUint32 mipLevels;
758 0u, // deUint32 baseArraySlice;
759 arrayLayers // deUint32 arraySize;
760 };
761
762 const VkImageMemoryBarrier preImageBarrier = makeImageMemoryBarrier(
763 0u, // VkAccessFlags srcAccessMask;
764 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask;
765 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
766 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout;
767 destImage, // VkImage image;
768 subresourceRange // VkImageSubresourceRange subresourceRange;
769 );
770
771 const VkImageMemoryBarrier postImageBarrier = makeImageMemoryBarrier(
772 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
773 finalAccessMask, // VkAccessFlags dstAccessMask;
774 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout;
775 destImageLayout, // VkImageLayout newLayout;
776 destImage, // VkImage image;
777 subresourceRange // VkImageSubresourceRange subresourceRange;
778 );
779
780 VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
781 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &preBufferBarrier, 1, &preImageBarrier);
782 vk.cmdCopyBufferToImage(*cmdBuffer, buffer, destImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, ©Region);
783 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, destImageDstStageFlags, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &postImageBarrier);
784 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
785
786 const VkPipelineStageFlags pipelineStageFlags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
787
788 const VkSubmitInfo submitInfo =
789 {
790 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
791 DE_NULL, // const void* pNext;
792 0u, // deUint32 waitSemaphoreCount;
793 DE_NULL, // const VkSemaphore* pWaitSemaphores;
794 &pipelineStageFlags, // const VkPipelineStageFlags* pWaitDstStageMask;
795 1u, // deUint32 commandBufferCount;
796 &cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers;
797 0u, // deUint32 signalSemaphoreCount;
798 DE_NULL // const VkSemaphore* pSignalSemaphores;
799 };
800
801 try
802 {
803 VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *fence));
804 VK_CHECK(vk.waitForFences(device, 1, &fence.get(), true, ~(0ull) /* infinity */));
805 }
806 catch (...)
807 {
808 VK_CHECK(vk.deviceWaitIdle(device));
809 throw;
810 }
811 }
812
813 class FragmentDensityMapTest : public vkt::TestCase
814 {
815 public:
816 FragmentDensityMapTest (tcu::TestContext& testContext,
817 const std::string& name,
818 const std::string& description,
819 const TestParams& testParams);
820 virtual void initPrograms (SourceCollections& sourceCollections) const;
821 virtual TestInstance* createInstance (Context& context) const;
822 virtual void checkSupport (Context& context) const;
823
824 private:
825 const TestParams m_testParams;
826 };
827
828 class FragmentDensityMapTestInstance : public vkt::TestInstance
829 {
830 public:
831 FragmentDensityMapTestInstance (Context& context,
832 const TestParams& testParams);
833 virtual tcu::TestStatus iterate (void);
834
835 private:
836
837 tcu::TestStatus verifyImage (void);
838
839 private:
840
841 typedef de::SharedPtr<Unique<VkSampler> > VkSamplerSp;
842 typedef de::SharedPtr<Unique<VkImage> > VkImageSp;
843 typedef de::SharedPtr<Allocation> AllocationSp;
844 typedef de::SharedPtr<Unique<VkImageView> > VkImageViewSp;
845
846 TestParams m_testParams;
847 tcu::UVec2 m_renderSize;
848 tcu::Vec2 m_densityValue;
849 deUint32 m_viewMask;
850
851 Move<VkCommandPool> m_cmdPool;
852
853 std::vector<VkImageSp> m_densityMapImages;
854 std::vector<AllocationSp> m_densityMapImageAllocs;
855 std::vector<VkImageViewSp> m_densityMapImageViews;
856
857 Move<VkImage> m_colorImage;
858 de::MovePtr<Allocation> m_colorImageAlloc;
859 Move<VkImageView> m_colorImageView;
860
861 Move<VkImage> m_colorCopyImage;
862 de::MovePtr<Allocation> m_colorCopyImageAlloc;
863 Move<VkImageView> m_colorCopyImageView;
864
865 Move<VkImage> m_colorResolvedImage;
866 de::MovePtr<Allocation> m_colorResolvedImageAlloc;
867 Move<VkImageView> m_colorResolvedImageView;
868
869 Move<VkImage> m_outputImage;
870 de::MovePtr<Allocation> m_outputImageAlloc;
871 Move<VkImageView> m_outputImageView;
872
873 std::vector<VkSamplerSp> m_colorSamplers;
874
875 Move<VkRenderPass> m_renderPassProduceDynamicDensityMap;
876 Move<VkRenderPass> m_renderPassProduceSubsampledImage;
877 Move<VkRenderPass> m_renderPassUpdateSubsampledImage;
878 Move<VkRenderPass> m_renderPassOutputSubsampledImage;
879 Move<VkFramebuffer> m_framebufferProduceDynamicDensityMap;
880 Move<VkFramebuffer> m_framebufferProduceSubsampledImage;
881 Move<VkFramebuffer> m_framebufferUpdateSubsampledImage;
882 Move<VkFramebuffer> m_framebufferOutputSubsampledImage;
883
884 Move<VkDescriptorSetLayout> m_descriptorSetLayoutProduceSubsampled;
885
886 Move<VkDescriptorSetLayout> m_descriptorSetLayoutOperateOnSubsampledImage;
887 Move<VkDescriptorPool> m_descriptorPoolOperateOnSubsampledImage;
888 Move<VkDescriptorSet> m_descriptorSetOperateOnSubsampledImage;
889
890 Move<VkDescriptorSetLayout> m_descriptorSetLayoutOutputSubsampledImage;
891 Move<VkDescriptorPool> m_descriptorPoolOutputSubsampledImage;
892 Move<VkDescriptorSet> m_descriptorSetOutputSubsampledImage;
893
894 Move<VkShaderModule> m_vertexCommonShaderModule;
895 Move<VkShaderModule> m_fragmentShaderModuleProduceSubsampledImage;
896 Move<VkShaderModule> m_fragmentShaderModuleCopySubsampledImage;
897 Move<VkShaderModule> m_fragmentShaderModuleUpdateSubsampledImage;
898 Move<VkShaderModule> m_fragmentShaderModuleOutputSubsampledImage;
899
900 std::vector<Vertex4RGBA> m_verticesDDM;
901 Move<VkBuffer> m_vertexBufferDDM;
902 de::MovePtr<Allocation> m_vertexBufferAllocDDM;
903
904 std::vector<Vertex4RGBA> m_vertices;
905 Move<VkBuffer> m_vertexBuffer;
906 de::MovePtr<Allocation> m_vertexBufferAlloc;
907
908 std::vector<Vertex4RGBA> m_verticesOutput;
909 Move<VkBuffer> m_vertexBufferOutput;
910 de::MovePtr<Allocation> m_vertexBufferOutputAlloc;
911
912 Move<VkPipelineLayout> m_pipelineLayoutNoDescriptors;
913 Move<VkPipelineLayout> m_pipelineLayoutOperateOnSubsampledImage;
914 Move<VkPipelineLayout> m_pipelineLayoutOutputSubsampledImage;
915 Move<VkPipeline> m_graphicsPipelineProduceDynamicDensityMap;
916 Move<VkPipeline> m_graphicsPipelineProduceSubsampledImage;
917 Move<VkPipeline> m_graphicsPipelineCopySubsampledImage;
918 Move<VkPipeline> m_graphicsPipelineUpdateSubsampledImage;
919 Move<VkPipeline> m_graphicsPipelineOutputSubsampledImage;
920
921 Move<VkCommandBuffer> m_cmdBuffer;
922 };
923
FragmentDensityMapTest(tcu::TestContext & testContext,const std::string & name,const std::string & description,const TestParams & testParams)924 FragmentDensityMapTest::FragmentDensityMapTest (tcu::TestContext& testContext,
925 const std::string& name,
926 const std::string& description,
927 const TestParams& testParams)
928 : vkt::TestCase (testContext, name, description)
929 , m_testParams (testParams)
930 {
931 DE_ASSERT(testParams.samplersCount > 0);
932 }
933
initPrograms(SourceCollections & sourceCollections) const934 void FragmentDensityMapTest::initPrograms(SourceCollections& sourceCollections) const
935 {
936 sourceCollections.glslSources.add("vert") << glu::VertexSource(
937 "#version 450\n"
938 "#extension GL_EXT_multiview : enable\n"
939 "layout(location = 0) in vec4 inPosition;\n"
940 "layout(location = 1) in vec4 inUV;\n"
941 "layout(location = 2) in vec4 inColor;\n"
942 "layout(location = 0) out vec4 outUV;\n"
943 "layout(location = 1) out vec4 outColor;\n"
944 "void main(void)\n"
945 "{\n"
946 " gl_Position = inPosition;\n"
947 " outUV = inUV;\n"
948 " outColor = inColor;\n"
949 "}\n"
950 );
951
952 #if DRY_RUN_WITHOUT_FDM_EXTENSION
953 sourceCollections.glslSources.add("frag_produce_subsampled") << glu::FragmentSource(
954 "#version 450\n"
955 "#extension GL_EXT_multiview : enable\n"
956 "layout(location = 0) in vec4 inUV;\n"
957 "layout(location = 1) in vec4 inColor;\n"
958 "layout(location = 0) out vec4 fragColor;\n"
959 "void main(void)\n"
960 "{\n"
961 " fragColor = vec4(inColor.x, inColor.y, 0.5, 0.5);\n"
962 "}\n"
963 );
964
965 sourceCollections.glslSources.add("frag_update_subsampled") << glu::FragmentSource(
966 "#version 450\n"
967 "#extension GL_EXT_multiview : enable\n"
968 "layout(location = 0) in vec4 inUV;\n"
969 "layout(location = 1) in vec4 inColor;\n"
970 "layout(location = 0) out vec4 fragColor;\n"
971 "void main(void)\n"
972 "{\n"
973 " if (gl_FragCoord.y < 0.5)\n"
974 " discard;\n"
975 " fragColor = vec4(inColor.x, inColor.y, 0.5, 0.5);\n"
976 "}\n"
977 );
978 #else
979 sourceCollections.glslSources.add("frag_produce_subsampled") << glu::FragmentSource(
980 "#version 450\n"
981 "#extension GL_EXT_fragment_invocation_density : enable\n"
982 "#extension GL_EXT_multiview : enable\n"
983 "layout(location = 0) in vec4 inUV;\n"
984 "layout(location = 1) in vec4 inColor;\n"
985 "layout(location = 0) out vec4 fragColor;\n"
986 "void main(void)\n"
987 "{\n"
988 " fragColor = vec4(inColor.x, inColor.y, 1.0/float(gl_FragSizeEXT.x), 1.0/(gl_FragSizeEXT.y));\n"
989 "}\n"
990 );
991
992 sourceCollections.glslSources.add("frag_update_subsampled") << glu::FragmentSource(
993 "#version 450\n"
994 "#extension GL_EXT_fragment_invocation_density : enable\n"
995 "#extension GL_EXT_multiview : enable\n"
996 "layout(location = 0) in vec4 inUV;\n"
997 "layout(location = 1) in vec4 inColor;\n"
998 "layout(location = 0) out vec4 fragColor;\n"
999 "void main(void)\n"
1000 "{\n"
1001 " if (gl_FragCoord.y < 0.5)\n"
1002 " discard;\n"
1003 " fragColor = vec4(inColor.x, inColor.y, 1.0/float(gl_FragSizeEXT.x), 1.0/(gl_FragSizeEXT.y));\n"
1004 "}\n"
1005 );
1006 #endif
1007 sourceCollections.glslSources.add("frag_copy_subsampled") << glu::FragmentSource(
1008 "#version 450\n"
1009 "#extension GL_EXT_fragment_invocation_density : enable\n"
1010 "#extension GL_EXT_multiview : enable\n"
1011 "layout(location = 0) in vec4 inUV;\n"
1012 "layout(location = 1) in vec4 inColor;\n"
1013 "layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput inputAtt;\n"
1014 "layout(location = 0) out vec4 fragColor;\n"
1015 "void main(void)\n"
1016 "{\n"
1017 " fragColor = subpassLoad(inputAtt);\n"
1018 "}\n"
1019 );
1020
1021 sourceCollections.glslSources.add("frag_copy_subsampled_ms") << glu::FragmentSource(
1022 "#version 450\n"
1023 "#extension GL_EXT_fragment_invocation_density : enable\n"
1024 "#extension GL_EXT_multiview : enable\n"
1025 "layout(location = 0) in vec4 inUV;\n"
1026 "layout(location = 1) in vec4 inColor;\n"
1027 "layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInputMS inputAtt;\n"
1028 "layout(location = 0) out vec4 fragColor;\n"
1029 "void main(void)\n"
1030 "{\n"
1031 " fragColor = subpassLoad(inputAtt, gl_SampleID);\n"
1032 "}\n"
1033 );
1034
1035 const char* samplersDefTemplate =
1036 "layout(binding = ${BINDING}) uniform ${SAMPLER} subsampledImage${BINDING};\n";
1037 const char* sumColorsTemplate =
1038 " fragColor += texture(subsampledImage${BINDING}, inUV.${COMPONENTS});\n";
1039
1040 const char* densitymapOutputTemplate =
1041 "#version 450\n"
1042 "layout(location = 0) in vec4 inUV;\n"
1043 "layout(location = 1) in vec4 inColor;\n"
1044 "${SAMPLERS_DEF}"
1045 "layout(location = 0) out vec4 fragColor;\n"
1046 "void main(void)\n"
1047 "{\n"
1048 " fragColor = vec4(0);\n"
1049 "${SUM_COLORS}"
1050 " fragColor /= float(${COUNT});\n"
1051 "}\n";
1052
1053 std::map<std::string, std::string> parameters
1054 {
1055 { "SAMPLER", "" },
1056 { "BINDING", "" },
1057 { "COMPONENTS", "" },
1058 { "COUNT", std::to_string(m_testParams.samplersCount) },
1059 { "SAMPLERS_DEF", "" },
1060 { "SUM_COLORS", "" },
1061 };
1062
1063 std::string sampler2dDefs;
1064 std::string sampler2dSumColors;
1065 std::string sampler2dArrayDefs;
1066 std::string sampler2dArraySumColors;
1067 for (deUint32 samplerIndex = 0; samplerIndex < m_testParams.samplersCount; ++samplerIndex)
1068 {
1069 parameters["BINDING"] = std::to_string(samplerIndex);
1070
1071 parameters["COMPONENTS"] = "xy";
1072 parameters["SAMPLER"] = "sampler2D";
1073 sampler2dDefs += tcu::StringTemplate(samplersDefTemplate).specialize(parameters);
1074 sampler2dSumColors += tcu::StringTemplate(sumColorsTemplate).specialize(parameters);
1075
1076 parameters["COMPONENTS"] = "xyz";
1077 parameters["SAMPLER"] = "sampler2DArray";
1078 sampler2dArrayDefs += tcu::StringTemplate(samplersDefTemplate).specialize(parameters);
1079 sampler2dArraySumColors += tcu::StringTemplate(sumColorsTemplate).specialize(parameters);
1080 }
1081
1082 parameters["SAMPLERS_DEF"] = sampler2dDefs;
1083 parameters["SUM_COLORS"] = sampler2dSumColors;
1084 sourceCollections.glslSources.add("frag_output_2d")
1085 << glu::FragmentSource(tcu::StringTemplate(densitymapOutputTemplate).specialize(parameters));
1086
1087 parameters["SAMPLERS_DEF"] = sampler2dArrayDefs;
1088 parameters["SUM_COLORS"] = sampler2dArraySumColors;
1089 sourceCollections.glslSources.add("frag_output_2darray")
1090 << glu::FragmentSource(tcu::StringTemplate(densitymapOutputTemplate).specialize(parameters));
1091 }
1092
createInstance(Context & context) const1093 TestInstance* FragmentDensityMapTest::createInstance(Context& context) const
1094 {
1095 return new FragmentDensityMapTestInstance(context, m_testParams);
1096 }
1097
checkSupport(Context & context) const1098 void FragmentDensityMapTest::checkSupport(Context& context) const
1099 {
1100 const InstanceInterface& vki = context.getInstanceInterface();
1101 const VkPhysicalDevice vkPhysicalDevice = context.getPhysicalDevice();
1102
1103 #if DRY_RUN_WITHOUT_FDM_EXTENSION
1104 if (m_testParams.viewCount > 1)
1105 {
1106 context.requireDeviceFunctionality("VK_KHR_multiview");
1107 if (!context.getMultiviewFeatures().multiview)
1108 TCU_THROW(NotSupportedError, "Implementation does not support multiview feature");
1109 }
1110 #else
1111 context.requireDeviceFunctionality("VK_EXT_fragment_density_map");
1112
1113
1114
1115 VkPhysicalDeviceFragmentDensityMapFeaturesEXT fragmentDensityMapFeatures = initVulkanStructure();
1116 VkPhysicalDeviceFragmentDensityMap2FeaturesEXT fragmentDensityMap2Features = initVulkanStructure(&fragmentDensityMapFeatures);
1117 VkPhysicalDeviceFeatures2KHR features2 = initVulkanStructure(&fragmentDensityMap2Features);
1118
1119 context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &features2);
1120
1121 const auto& fragmentDensityMap2Properties = context.getFragmentDensityMap2PropertiesEXT();
1122
1123 if (!fragmentDensityMapFeatures.fragmentDensityMap)
1124 TCU_THROW(NotSupportedError, "fragmentDensityMap feature is not supported");
1125 if (m_testParams.dynamicDensityMap && !fragmentDensityMapFeatures.fragmentDensityMapDynamic)
1126 TCU_THROW(NotSupportedError, "fragmentDensityMapDynamic feature is not supported");
1127 if (m_testParams.nonSubsampledImages && !fragmentDensityMapFeatures.fragmentDensityMapNonSubsampledImages)
1128 TCU_THROW(NotSupportedError, "fragmentDensityMapNonSubsampledImages feature is not supported");
1129
1130 if (m_testParams.deferredDensityMap)
1131 {
1132 context.requireDeviceFunctionality("VK_EXT_fragment_density_map2");
1133 if (!fragmentDensityMap2Features.fragmentDensityMapDeferred)
1134 TCU_THROW(NotSupportedError, "fragmentDensityMapDeferred feature is not supported");
1135 }
1136 if (m_testParams.subsampledLoads)
1137 {
1138 context.requireDeviceFunctionality("VK_EXT_fragment_density_map2");
1139 if (!fragmentDensityMap2Properties.subsampledLoads)
1140 TCU_THROW(NotSupportedError, "subsampledLoads property is not supported");
1141 }
1142 if (m_testParams.coarseReconstruction)
1143 {
1144 context.requireDeviceFunctionality("VK_EXT_fragment_density_map2");
1145 if (!fragmentDensityMap2Properties.subsampledCoarseReconstructionEarlyAccess)
1146 TCU_THROW(NotSupportedError, "subsampledCoarseReconstructionEarlyAccess property is not supported");
1147 }
1148
1149 if (m_testParams.viewCount > 1)
1150 {
1151 context.requireDeviceFunctionality("VK_KHR_multiview");
1152 if (!context.getMultiviewFeatures().multiview)
1153 TCU_THROW(NotSupportedError, "Implementation does not support multiview feature");
1154
1155 if (m_testParams.viewCount > 2)
1156 {
1157 context.requireDeviceFunctionality("VK_EXT_fragment_density_map2");
1158 if (m_testParams.viewCount > fragmentDensityMap2Properties.maxSubsampledArrayLayers)
1159 TCU_THROW(NotSupportedError, "Maximum number of VkImageView array layers for usages supporting subsampled samplers is to small");
1160 }
1161 }
1162
1163 if (!m_testParams.nonSubsampledImages && (m_testParams.samplersCount > 1))
1164 {
1165 context.requireDeviceFunctionality("VK_EXT_fragment_density_map2");
1166 if (m_testParams.samplersCount > fragmentDensityMap2Properties.maxDescriptorSetSubsampledSamplers)
1167 TCU_THROW(NotSupportedError, "Required number of subsampled samplers is not supported");
1168 }
1169 #endif
1170
1171 vk::VkImageUsageFlags colorImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
1172 if (m_testParams.makeCopy)
1173 colorImageUsage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
1174
1175 deUint32 colorImageCreateFlags = m_testParams.nonSubsampledImages ? 0u : (deUint32)VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT;
1176 VkImageFormatProperties imageFormatProperties (getPhysicalDeviceImageFormatProperties(vki, vkPhysicalDevice, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, colorImageUsage, colorImageCreateFlags));
1177
1178 if ((imageFormatProperties.sampleCounts & m_testParams.colorSamples) == 0)
1179 TCU_THROW(NotSupportedError, "Color image type not supported");
1180
1181 if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
1182 !context.getPortabilitySubsetFeatures().multisampleArrayImage &&
1183 (m_testParams.colorSamples != VK_SAMPLE_COUNT_1_BIT) && (m_testParams.viewCount != 1))
1184 {
1185 TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Implementation does not support image array with multiple samples per texel");
1186 }
1187 }
1188
FragmentDensityMapTestInstance(Context & context,const TestParams & testParams)1189 FragmentDensityMapTestInstance::FragmentDensityMapTestInstance(Context& context,
1190 const TestParams& testParams)
1191 : vkt::TestInstance (context)
1192 , m_testParams (testParams)
1193 {
1194 m_renderSize = tcu::UVec2(deFloorFloatToInt32(m_testParams.renderMultiplier * static_cast<float>(m_testParams.densityMapSize.x())),
1195 deFloorFloatToInt32(m_testParams.renderMultiplier * static_cast<float>(m_testParams.densityMapSize.y())));
1196 m_densityValue = tcu::Vec2(1.0f / static_cast<float>(m_testParams.fragmentArea.x()),
1197 1.0f / static_cast<float>(m_testParams.fragmentArea.y()));
1198 m_viewMask = (m_testParams.viewCount > 1) ? ((1u << m_testParams.viewCount) - 1u) : 0u;
1199
1200 const DeviceInterface& vk = m_context.getDeviceInterface();
1201 const VkDevice vkDevice = getDevice(m_context);
1202 const VkPhysicalDevice vkPhysicalDevice = m_context.getPhysicalDevice();
1203 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1204 const VkQueue queue = getDeviceQueue(vk, vkDevice, queueFamilyIndex, 0);
1205 SimpleAllocator memAlloc (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), vkPhysicalDevice));
1206 const VkComponentMapping componentMappingRGBA = makeComponentMappingRGBA();
1207
1208 // calculate all image sizes, image usage flags, view types etc.
1209 deUint32 densitiMapCount = 1 + m_testParams.subsampledLoads;
1210 VkExtent3D densityMapImageSize { m_testParams.densityMapSize.x(), m_testParams.densityMapSize.y(), 1 };
1211 deUint32 densityMapImageLayers = m_testParams.viewCount;
1212 VkImageViewType densityMapImageViewType = (m_testParams.viewCount > 1) ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
1213 vk::VkImageUsageFlags densityMapImageUsage = VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
1214 deUint32 densityMapImageViewFlags = 0u;
1215
1216 VkExtent3D colorImageSize { m_renderSize.x() / m_testParams.viewCount, m_renderSize.y(), 1 };
1217 deUint32 colorImageLayers = densityMapImageLayers;
1218 VkImageViewType colorImageViewType = densityMapImageViewType;
1219 vk::VkImageUsageFlags colorImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
1220 deUint32 colorImageCreateFlags = m_testParams.nonSubsampledImages ? 0u : (deUint32)VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT;
1221 bool isColorImageMultisampled = m_testParams.colorSamples != VK_SAMPLE_COUNT_1_BIT;
1222
1223 VkExtent3D outputImageSize { m_renderSize.x(), m_renderSize.y(), 1 };
1224
1225 if (m_testParams.dynamicDensityMap)
1226 {
1227 DE_ASSERT(!m_testParams.subsampledLoads);
1228
1229 densityMapImageUsage = VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1230 densityMapImageViewFlags = (deUint32)VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT;
1231 }
1232 else if (m_testParams.deferredDensityMap)
1233 densityMapImageViewFlags = (deUint32)VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT;
1234 if (m_testParams.makeCopy)
1235 colorImageUsage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
1236
1237 #if DRY_RUN_WITHOUT_FDM_EXTENSION
1238 colorImageCreateFlags = 0u;
1239 densityMapImageUsage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
1240 densityMapImageViewFlags = 0u;
1241 #endif
1242
1243 // Create subsampled color image
1244 prepareImageAndImageView(vk, vkDevice, memAlloc, colorImageCreateFlags, VK_FORMAT_R8G8B8A8_UNORM,
1245 colorImageSize, colorImageLayers, m_testParams.colorSamples,
1246 colorImageUsage, queueFamilyIndex, 0u, colorImageViewType,
1247 componentMappingRGBA, { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, colorImageLayers },
1248 m_colorImage, m_colorImageAlloc, m_colorImageView);
1249
1250 // Create subsampled color image for resolve operation ( when multisampling is used )
1251 if (isColorImageMultisampled)
1252 {
1253 prepareImageAndImageView(vk, vkDevice, memAlloc, colorImageCreateFlags, VK_FORMAT_R8G8B8A8_UNORM,
1254 colorImageSize, colorImageLayers, VK_SAMPLE_COUNT_1_BIT,
1255 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, queueFamilyIndex, 0u, colorImageViewType,
1256 componentMappingRGBA, { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, colorImageLayers },
1257 m_colorResolvedImage, m_colorResolvedImageAlloc, m_colorResolvedImageView);
1258 }
1259
1260 // Create subsampled image copy
1261 if (m_testParams.makeCopy)
1262 {
1263 prepareImageAndImageView(vk, vkDevice, memAlloc, colorImageCreateFlags, VK_FORMAT_R8G8B8A8_UNORM,
1264 colorImageSize, colorImageLayers, m_testParams.colorSamples,
1265 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, queueFamilyIndex, 0u, colorImageViewType,
1266 componentMappingRGBA, { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, colorImageLayers },
1267 m_colorCopyImage, m_colorCopyImageAlloc, m_colorCopyImageView);
1268 }
1269
1270 // Create output image ( data from subsampled color image will be copied into it using sampler with VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT )
1271 prepareImageAndImageView(vk, vkDevice, memAlloc, 0u, VK_FORMAT_R8G8B8A8_UNORM,
1272 outputImageSize, 1u, VK_SAMPLE_COUNT_1_BIT,
1273 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, queueFamilyIndex, 0u, VK_IMAGE_VIEW_TYPE_2D,
1274 componentMappingRGBA, { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },
1275 m_outputImage, m_outputImageAlloc, m_outputImageView);
1276
1277 // Create density map image/images
1278 for (deUint32 mapIndex = 0; mapIndex < densitiMapCount; ++mapIndex)
1279 {
1280 Move<VkImage> densityMapImage;
1281 de::MovePtr<Allocation> densityMapImageAlloc;
1282 Move<VkImageView> densityMapImageView;
1283
1284 prepareImageAndImageView(vk, vkDevice, memAlloc, 0u, m_testParams.densityMapFormat,
1285 densityMapImageSize, densityMapImageLayers, VK_SAMPLE_COUNT_1_BIT,
1286 densityMapImageUsage, queueFamilyIndex, densityMapImageViewFlags, densityMapImageViewType,
1287 componentMappingRGBA, { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, densityMapImageLayers },
1288 densityMapImage, densityMapImageAlloc, densityMapImageView);
1289
1290 m_densityMapImages.push_back(VkImageSp(new Unique<VkImage>(densityMapImage)));
1291 m_densityMapImageAllocs.push_back(AllocationSp(densityMapImageAlloc.release()));
1292 m_densityMapImageViews.push_back(VkImageViewSp(new Unique<VkImageView>(densityMapImageView)));
1293 }
1294
1295 // Create and fill staging buffer, copy its data to density map image
1296 if (!m_testParams.dynamicDensityMap)
1297 {
1298 tcu::TextureFormat densityMapTextureFormat = vk::mapVkFormat(m_testParams.densityMapFormat);
1299 VkDeviceSize stagingBufferSize = tcu::getPixelSize(densityMapTextureFormat) * densityMapImageSize.width * densityMapImageSize.height * densityMapImageLayers;
1300 const vk::VkBufferCreateInfo stagingBufferCreateInfo =
1301 {
1302 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1303 DE_NULL,
1304 0u, // flags
1305 stagingBufferSize, // size
1306 VK_BUFFER_USAGE_TRANSFER_SRC_BIT, // usage
1307 vk::VK_SHARING_MODE_EXCLUSIVE, // sharingMode
1308 0u, // queueFamilyCount
1309 DE_NULL, // pQueueFamilyIndices
1310 };
1311 vk::Move<vk::VkBuffer> stagingBuffer = vk::createBuffer(vk, vkDevice, &stagingBufferCreateInfo);
1312 const vk::VkMemoryRequirements stagingRequirements = vk::getBufferMemoryRequirements(vk, vkDevice, *stagingBuffer);
1313 de::MovePtr<vk::Allocation> stagingAllocation = memAlloc.allocate(stagingRequirements, MemoryRequirement::HostVisible);
1314 VK_CHECK(vk.bindBufferMemory(vkDevice, *stagingBuffer, stagingAllocation->getMemory(), stagingAllocation->getOffset()));
1315 tcu::PixelBufferAccess stagingBufferAccess (densityMapTextureFormat, densityMapImageSize.width, densityMapImageSize.height, densityMapImageLayers, stagingAllocation->getHostPtr());
1316 tcu::Vec4 fragmentArea (m_densityValue.x(), m_densityValue.y(), 0.0f, 1.0f);
1317
1318 for (deUint32 mapIndex = 0; mapIndex < densitiMapCount; ++mapIndex)
1319 {
1320 // Fill staging buffer with one color
1321 tcu::clear(stagingBufferAccess, fragmentArea);
1322 flushAlloc(vk, vkDevice, *stagingAllocation);
1323
1324 copyBufferToImage
1325 (
1326 vk, vkDevice, queue, queueFamilyIndex,
1327 *stagingBuffer, stagingBufferSize,
1328 densityMapImageSize, densityMapImageLayers, **m_densityMapImages[mapIndex]
1329 );
1330
1331 std::swap(fragmentArea.m_data[0], fragmentArea.m_data[1]);
1332 }
1333 }
1334
1335 deUint32 samplerCreateFlags = (deUint32)VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT;
1336 if (m_testParams.coarseReconstruction)
1337 samplerCreateFlags |= (deUint32)VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT;
1338 if (m_testParams.nonSubsampledImages)
1339 samplerCreateFlags = 0u;
1340
1341 #if DRY_RUN_WITHOUT_FDM_EXTENSION
1342 samplerCreateFlags = 0u;
1343 #endif
1344
1345 const struct VkSamplerCreateInfo samplerInfo
1346 {
1347 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // sType
1348 DE_NULL, // pNext
1349 (VkSamplerCreateFlags)samplerCreateFlags, // flags
1350 VK_FILTER_NEAREST, // magFilter
1351 VK_FILTER_NEAREST, // minFilter
1352 VK_SAMPLER_MIPMAP_MODE_NEAREST, // mipmapMode
1353 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU
1354 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeV
1355 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeW
1356 0.0f, // mipLodBias
1357 VK_FALSE, // anisotropyEnable
1358 1.0f, // maxAnisotropy
1359 DE_FALSE, // compareEnable
1360 VK_COMPARE_OP_ALWAYS, // compareOp
1361 0.0f, // minLod
1362 0.0f, // maxLod
1363 VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // borderColor
1364 VK_FALSE, // unnormalizedCoords
1365 };
1366
1367 // Create a sampler that are able to read from subsampled image
1368 // (more than one sampler is needed only for 4 maxDescriptorSetSubsampledSamplers tests)
1369 for (deUint32 samplerIndex = 0; samplerIndex < testParams.samplersCount; ++samplerIndex)
1370 m_colorSamplers.push_back(VkSamplerSp(new Unique<VkSampler>(createSampler(vk, vkDevice, &samplerInfo))));
1371
1372 // Create render passes
1373 if (testParams.dynamicDensityMap)
1374 m_renderPassProduceDynamicDensityMap = createRenderPassProduceDynamicDensityMap(vk, vkDevice, m_viewMask, testParams);
1375 m_renderPassProduceSubsampledImage = createRenderPassProduceSubsampledImage(vk, vkDevice, m_viewMask, testParams.makeCopy, false, testParams);
1376 if (testParams.subsampledLoads)
1377 m_renderPassUpdateSubsampledImage = createRenderPassProduceSubsampledImage(vk, vkDevice, m_viewMask, false, true, testParams);
1378 m_renderPassOutputSubsampledImage = createRenderPassOutputSubsampledImage(vk, vkDevice);
1379
1380 std::vector<VkImageView> imageViewsProduceSubsampledImage = { *m_colorImageView };
1381 if (isColorImageMultisampled)
1382 imageViewsProduceSubsampledImage.push_back(*m_colorResolvedImageView);
1383 if (testParams.makeCopy)
1384 imageViewsProduceSubsampledImage.push_back(*m_colorCopyImageView);
1385 imageViewsProduceSubsampledImage.push_back(**m_densityMapImageViews[0]);
1386
1387 std::vector<VkImageView> imageViewsUpdateSubsampledImage = { *m_colorImageView };
1388 if (testParams.subsampledLoads)
1389 imageViewsUpdateSubsampledImage.push_back(**m_densityMapImageViews[1]);
1390
1391 #if DRY_RUN_WITHOUT_FDM_EXTENSION
1392 imageViewsProduceSubsampledImage.pop_back();
1393 imageViewsUpdateSubsampledImage.pop_back();
1394 #endif
1395
1396 // Create framebuffers
1397 if (testParams.dynamicDensityMap)
1398 {
1399 m_framebufferProduceDynamicDensityMap = createFrameBuffer(vk, vkDevice,
1400 *m_renderPassProduceDynamicDensityMap,
1401 densityMapImageSize,
1402 { **m_densityMapImageViews[0] });
1403 }
1404 m_framebufferProduceSubsampledImage = createFrameBuffer(vk, vkDevice,
1405 *m_renderPassProduceSubsampledImage,
1406 colorImageSize,
1407 imageViewsProduceSubsampledImage);
1408 if (testParams.subsampledLoads)
1409 {
1410 m_framebufferUpdateSubsampledImage = createFrameBuffer(vk, vkDevice,
1411 *m_renderPassUpdateSubsampledImage,
1412 colorImageSize,
1413 imageViewsUpdateSubsampledImage);
1414 }
1415 m_framebufferOutputSubsampledImage = createFrameBuffer(vk, vkDevice,
1416 *m_renderPassOutputSubsampledImage,
1417 outputImageSize,
1418 { *m_outputImageView });
1419
1420 // Create pipeline layout for subpasses that do not use any descriptors
1421 {
1422 const VkPipelineLayoutCreateInfo pipelineLayoutParams =
1423 {
1424 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
1425 DE_NULL, // const void* pNext;
1426 0u, // VkPipelineLayoutCreateFlags flags;
1427 0u, // deUint32 setLayoutCount;
1428 DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
1429 0u, // deUint32 pushConstantRangeCount;
1430 DE_NULL // const VkPushConstantRange* pPushConstantRanges;
1431 };
1432
1433 m_pipelineLayoutNoDescriptors = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
1434 }
1435
1436 // Create pipeline layout for subpass that copies data or resamples subsampled image
1437 if (m_testParams.makeCopy || m_testParams.subsampledLoads)
1438 {
1439 m_descriptorSetLayoutOperateOnSubsampledImage =
1440 DescriptorSetLayoutBuilder()
1441 .addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, VK_SHADER_STAGE_FRAGMENT_BIT, DE_NULL)
1442 .build(vk, vkDevice);
1443
1444 // Create and bind descriptor set
1445 m_descriptorPoolOperateOnSubsampledImage =
1446 DescriptorPoolBuilder()
1447 .addType(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1u)
1448 .build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1449
1450 m_pipelineLayoutOperateOnSubsampledImage = makePipelineLayout(vk, vkDevice, *m_descriptorSetLayoutOperateOnSubsampledImage);
1451 m_descriptorSetOperateOnSubsampledImage = makeDescriptorSet(vk, vkDevice, *m_descriptorPoolOperateOnSubsampledImage, *m_descriptorSetLayoutOperateOnSubsampledImage);
1452
1453 const VkDescriptorImageInfo inputImageInfo =
1454 {
1455 DE_NULL, // VkSampleri sampler;
1456 *m_colorImageView, // VkImageView imageView;
1457 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout imageLayout;
1458 };
1459 DescriptorSetUpdateBuilder()
1460 .writeSingle(*m_descriptorSetOperateOnSubsampledImage, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, &inputImageInfo)
1461 .update(vk, vkDevice);
1462 }
1463
1464 // Create pipeline layout for last render pass (output subsampled image)
1465 {
1466 DescriptorSetLayoutBuilder descriptorSetLayoutBuilder;
1467 DescriptorPoolBuilder descriptorPoolBuilder;
1468 for (deUint32 samplerIndex = 0; samplerIndex < testParams.samplersCount; ++samplerIndex)
1469 {
1470 descriptorSetLayoutBuilder.addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, &(*m_colorSamplers[samplerIndex]).get());
1471 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, samplerIndex + 1u);
1472 }
1473
1474 m_descriptorSetLayoutOutputSubsampledImage = descriptorSetLayoutBuilder.build(vk, vkDevice);
1475 m_descriptorPoolOutputSubsampledImage = descriptorPoolBuilder.build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1476 m_pipelineLayoutOutputSubsampledImage = makePipelineLayout(vk, vkDevice, *m_descriptorSetLayoutOutputSubsampledImage);
1477 m_descriptorSetOutputSubsampledImage = makeDescriptorSet(vk, vkDevice, *m_descriptorPoolOutputSubsampledImage, *m_descriptorSetLayoutOutputSubsampledImage);
1478
1479 VkImageView srcImageView = *m_colorImageView;
1480 if (isColorImageMultisampled)
1481 srcImageView = *m_colorResolvedImageView;
1482 else if (m_testParams.makeCopy)
1483 srcImageView = *m_colorCopyImageView;
1484
1485 const VkDescriptorImageInfo inputImageInfo =
1486 {
1487 DE_NULL, // VkSampleri sampler;
1488 srcImageView, // VkImageView imageView;
1489 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout imageLayout;
1490 };
1491
1492 DescriptorSetUpdateBuilder descriptorSetUpdateBuilder;
1493 for (deUint32 samplerIndex = 0; samplerIndex < testParams.samplersCount; ++samplerIndex)
1494 descriptorSetUpdateBuilder.writeSingle(*m_descriptorSetOutputSubsampledImage, DescriptorSetUpdateBuilder::Location::binding(samplerIndex), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &inputImageInfo);
1495 descriptorSetUpdateBuilder.update(vk, vkDevice);
1496 }
1497
1498 // Load vertex and fragment shaders
1499 auto& bc = m_context.getBinaryCollection();
1500 m_vertexCommonShaderModule = createShaderModule(vk, vkDevice, bc.get("vert"), 0);
1501 m_fragmentShaderModuleProduceSubsampledImage = createShaderModule(vk, vkDevice, bc.get("frag_produce_subsampled"), 0);
1502 if (m_testParams.makeCopy)
1503 {
1504 const char* moduleName = isColorImageMultisampled ? "frag_copy_subsampled_ms" : "frag_copy_subsampled";
1505 m_fragmentShaderModuleCopySubsampledImage = createShaderModule(vk, vkDevice, bc.get(moduleName), 0);
1506 }
1507 if (m_testParams.subsampledLoads)
1508 {
1509 const char* moduleName = "frag_update_subsampled";
1510 m_fragmentShaderModuleUpdateSubsampledImage = createShaderModule(vk, vkDevice, bc.get(moduleName), 0);
1511 }
1512 const char* moduleName = (m_testParams.viewCount > 1) ? "frag_output_2darray" : "frag_output_2d";
1513 m_fragmentShaderModuleOutputSubsampledImage = createShaderModule(vk, vkDevice, bc.get(moduleName), 0);
1514
1515 // Create pipelines
1516 {
1517 const VkVertexInputBindingDescription vertexInputBindingDescription =
1518 {
1519 0u, // deUint32 binding;
1520 sizeof(Vertex4RGBA), // deUint32 strideInBytes;
1521 VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate inputRate;
1522 };
1523
1524 std::vector<VkVertexInputAttributeDescription> vertexInputAttributeDescriptions =
1525 {
1526 { 0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u },
1527 { 1u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, (deUint32)(sizeof(float) * 4) },
1528 { 2u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, (deUint32)(sizeof(float) * 8) }
1529 };
1530
1531 const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
1532 {
1533 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
1534 DE_NULL, // const void* pNext;
1535 0u, // VkPipelineVertexInputStateCreateFlags flags;
1536 1u, // deUint32 vertexBindingDescriptionCount;
1537 &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
1538 static_cast<deUint32>(vertexInputAttributeDescriptions.size()), // deUint32 vertexAttributeDescriptionCount;
1539 vertexInputAttributeDescriptions.data() // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
1540 };
1541
1542 const VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo
1543 {
1544 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType
1545 DE_NULL, // const void* pNext
1546 (VkPipelineMultisampleStateCreateFlags)0u, // VkPipelineMultisampleStateCreateFlags flags
1547 (VkSampleCountFlagBits)m_testParams.colorSamples, // VkSampleCountFlagBits rasterizationSamples
1548 VK_FALSE, // VkBool32 sampleShadingEnable
1549 1.0f, // float minSampleShading
1550 DE_NULL, // const VkSampleMask* pSampleMask
1551 VK_FALSE, // VkBool32 alphaToCoverageEnable
1552 VK_FALSE // VkBool32 alphaToOneEnable
1553 };
1554
1555 const std::vector<VkViewport> viewportsProduceDynamicDensityMap { makeViewport(densityMapImageSize.width, densityMapImageSize.height) };
1556 const std::vector<VkRect2D> scissorsProduceDynamicDensityMap { makeRect2D(densityMapImageSize.width, densityMapImageSize.height) };
1557 const std::vector<VkViewport> viewportsSubsampledImage { makeViewport(colorImageSize.width, colorImageSize.height) };
1558 const std::vector<VkRect2D> scissorsSubsampledImage { makeRect2D(colorImageSize.width, colorImageSize.height) };
1559 const std::vector<VkViewport> viewportsOutputSubsampledImage { makeViewport(outputImageSize.width, outputImageSize.height) };
1560 const std::vector<VkRect2D> scissorsOutputSubsampledImage { makeRect2D(outputImageSize.width, outputImageSize.height) };
1561
1562 if (testParams.dynamicDensityMap)
1563 m_graphicsPipelineProduceDynamicDensityMap = makeGraphicsPipeline(vk, // const DeviceInterface& vk
1564 vkDevice, // const VkDevice device
1565 *m_pipelineLayoutNoDescriptors, // const VkPipelineLayout pipelineLayout
1566 *m_vertexCommonShaderModule, // const VkShaderModule vertexShaderModule
1567 DE_NULL, // const VkShaderModule tessellationControlModule
1568 DE_NULL, // const VkShaderModule tessellationEvalModule
1569 DE_NULL, // const VkShaderModule geometryShaderModule
1570 *m_fragmentShaderModuleProduceSubsampledImage, // const VkShaderModule fragmentShaderModule
1571 *m_renderPassProduceDynamicDensityMap, // const VkRenderPass renderPass
1572 viewportsProduceDynamicDensityMap, // const std::vector<VkViewport>& viewports
1573 scissorsProduceDynamicDensityMap, // const std::vector<VkRect2D>& scissors
1574 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology
1575 0u, // const deUint32 subpass
1576 0u, // const deUint32 patchControlPoints
1577 &vertexInputStateParams); // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
1578
1579 m_graphicsPipelineProduceSubsampledImage = makeGraphicsPipeline(vk, // const DeviceInterface& vk
1580 vkDevice, // const VkDevice device
1581 *m_pipelineLayoutNoDescriptors, // const VkPipelineLayout pipelineLayout
1582 *m_vertexCommonShaderModule, // const VkShaderModule vertexShaderModule
1583 DE_NULL, // const VkShaderModule tessellationControlModule
1584 DE_NULL, // const VkShaderModule tessellationEvalModule
1585 DE_NULL, // const VkShaderModule geometryShaderModule
1586 *m_fragmentShaderModuleProduceSubsampledImage, // const VkShaderModule fragmentShaderModule
1587 *m_renderPassProduceSubsampledImage, // const VkRenderPass renderPass
1588 viewportsSubsampledImage, // const std::vector<VkViewport>& viewports
1589 scissorsSubsampledImage, // const std::vector<VkRect2D>& scissors
1590 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology
1591 0u, // const deUint32 subpass
1592 0u, // const deUint32 patchControlPoints
1593 &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
1594 DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
1595 &multisampleStateCreateInfo); // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo
1596 if(m_testParams.makeCopy)
1597 m_graphicsPipelineCopySubsampledImage = makeGraphicsPipeline(vk, // const DeviceInterface& vk
1598 vkDevice, // const VkDevice device
1599 *m_pipelineLayoutOperateOnSubsampledImage, // const VkPipelineLayout pipelineLayout
1600 *m_vertexCommonShaderModule, // const VkShaderModule vertexShaderModule
1601 DE_NULL, // const VkShaderModule tessellationControlModule
1602 DE_NULL, // const VkShaderModule tessellationEvalModule
1603 DE_NULL, // const VkShaderModule geometryShaderModule
1604 *m_fragmentShaderModuleCopySubsampledImage, // const VkShaderModule fragmentShaderModule
1605 *m_renderPassProduceSubsampledImage, // const VkRenderPass renderPass
1606 viewportsSubsampledImage, // const std::vector<VkViewport>& viewports
1607 scissorsSubsampledImage, // const std::vector<VkRect2D>& scissors
1608 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology
1609 1u, // const deUint32 subpass
1610 0u, // const deUint32 patchControlPoints
1611 &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
1612 DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
1613 &multisampleStateCreateInfo); // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo
1614 if (m_testParams.subsampledLoads)
1615 m_graphicsPipelineUpdateSubsampledImage = makeGraphicsPipeline(vk, // const DeviceInterface& vk
1616 vkDevice, // const VkDevice device
1617 *m_pipelineLayoutOperateOnSubsampledImage, // const VkPipelineLayout pipelineLayout
1618 *m_vertexCommonShaderModule, // const VkShaderModule vertexShaderModule
1619 DE_NULL, // const VkShaderModule tessellationControlModule
1620 DE_NULL, // const VkShaderModule tessellationEvalModule
1621 DE_NULL, // const VkShaderModule geometryShaderModule
1622 *m_fragmentShaderModuleUpdateSubsampledImage, // const VkShaderModule fragmentShaderModule
1623 *m_renderPassUpdateSubsampledImage, // const VkRenderPass renderPass
1624 viewportsSubsampledImage, // const std::vector<VkViewport>& viewports
1625 scissorsSubsampledImage, // const std::vector<VkRect2D>& scissors
1626 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology
1627 0u, // const deUint32 subpass
1628 0u, // const deUint32 patchControlPoints
1629 &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
1630 DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
1631 &multisampleStateCreateInfo); // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo
1632
1633 m_graphicsPipelineOutputSubsampledImage = makeGraphicsPipeline(vk, // const DeviceInterface& vk
1634 vkDevice, // const VkDevice device
1635 *m_pipelineLayoutOutputSubsampledImage, // const VkPipelineLayout pipelineLayout
1636 *m_vertexCommonShaderModule, // const VkShaderModule vertexShaderModule
1637 DE_NULL, // const VkShaderModule tessellationControlModule
1638 DE_NULL, // const VkShaderModule tessellationEvalModule
1639 DE_NULL, // const VkShaderModule geometryShaderModule
1640 *m_fragmentShaderModuleOutputSubsampledImage, // const VkShaderModule fragmentShaderModule
1641 *m_renderPassOutputSubsampledImage, // const VkRenderPass renderPass
1642 viewportsOutputSubsampledImage, // const std::vector<VkViewport>& viewports
1643 scissorsOutputSubsampledImage, // const std::vector<VkRect2D>& scissors
1644 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology
1645 0u, // const deUint32 subpass
1646 0u, // const deUint32 patchControlPoints
1647 &vertexInputStateParams); // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
1648 }
1649
1650 // Create vertex buffers
1651 const tcu::Vec2 densityX(m_densityValue.x());
1652 const tcu::Vec2 densityY(m_densityValue.y());
1653 m_vertices = createFullscreenMesh(1, {0.0f, 1.0f}, {0.0f, 1.0f}); // create fullscreen quad with gradient
1654 if (testParams.dynamicDensityMap)
1655 m_verticesDDM = createFullscreenMesh(1, densityX, densityY); // create fullscreen quad with single color
1656 m_verticesOutput = createFullscreenMesh(m_testParams.viewCount, { 0.0f, 0.0f }, { 0.0f, 0.0f }); // create fullscreen mesh with black color
1657
1658 createVertexBuffer(vk, vkDevice, queueFamilyIndex, memAlloc, m_vertices, m_vertexBuffer, m_vertexBufferAlloc);
1659 if (testParams.dynamicDensityMap)
1660 createVertexBuffer(vk, vkDevice, queueFamilyIndex, memAlloc, m_verticesDDM, m_vertexBufferDDM, m_vertexBufferAllocDDM);
1661 createVertexBuffer(vk, vkDevice, queueFamilyIndex, memAlloc, m_verticesOutput, m_vertexBufferOutput, m_vertexBufferOutputAlloc);
1662
1663 // Create command pool and command buffer
1664 m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
1665 m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1666
1667 typedef RenderpassSubpass2 RPS2;
1668 const typename RPS2::SubpassBeginInfo subpassBeginInfo (DE_NULL, VK_SUBPASS_CONTENTS_INLINE);
1669 const typename RPS2::SubpassEndInfo subpassEndInfo (DE_NULL);
1670 const VkDeviceSize vertexBufferOffset = 0;
1671 const VkClearValue attachmentClearValue = makeClearValueColorF32(0.0f, 0.0f, 0.0f, 1.0f);
1672 const deUint32 attachmentCount = 1 + testParams.makeCopy + isColorImageMultisampled;
1673 const std::vector<VkClearValue> attachmentClearValues (attachmentCount, attachmentClearValue);
1674
1675 beginCommandBuffer(vk, *m_cmdBuffer, 0u);
1676
1677 // First render pass - render dynamic density map
1678 if (testParams.dynamicDensityMap)
1679 {
1680 std::vector<VkClearValue> attachmentClearValuesDDM { makeClearValueColorF32(1.0f, 1.0f, 1.0f, 1.0f) };
1681 const VkRenderPassBeginInfo renderPassBeginInfoProduceDynamicDensityMap
1682 {
1683 VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
1684 DE_NULL, // const void* pNext;
1685 *m_renderPassProduceDynamicDensityMap, // VkRenderPass renderPass;
1686 *m_framebufferProduceDynamicDensityMap, // VkFramebuffer framebuffer;
1687 makeRect2D(densityMapImageSize.width, densityMapImageSize.height), // VkRect2D renderArea;
1688 static_cast<deUint32>(attachmentClearValuesDDM.size()), // uint32_t clearValueCount;
1689 attachmentClearValuesDDM.data() // const VkClearValue* pClearValues;
1690 };
1691 RPS2::cmdBeginRenderPass(vk, *m_cmdBuffer, &renderPassBeginInfoProduceDynamicDensityMap, &subpassBeginInfo);
1692 vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelineProduceDynamicDensityMap);
1693 vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBufferDDM.get(), &vertexBufferOffset);
1694 vk.cmdDraw(*m_cmdBuffer, (deUint32)m_verticesDDM.size(), 1, 0, 0);
1695 RPS2::cmdEndRenderPass(vk, *m_cmdBuffer, &subpassEndInfo);
1696 }
1697
1698 // Render subsampled image
1699 const VkRenderPassBeginInfo renderPassBeginInfoProduceSubsampledImage
1700 {
1701 VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
1702 DE_NULL, // const void* pNext;
1703 *m_renderPassProduceSubsampledImage, // VkRenderPass renderPass;
1704 *m_framebufferProduceSubsampledImage, // VkFramebuffer framebuffer;
1705 makeRect2D(colorImageSize.width, colorImageSize.height), // VkRect2D renderArea;
1706 static_cast<deUint32>(attachmentClearValues.size()), // uint32_t clearValueCount;
1707 attachmentClearValues.data() // const VkClearValue* pClearValues;
1708 };
1709 RPS2::cmdBeginRenderPass(vk, *m_cmdBuffer, &renderPassBeginInfoProduceSubsampledImage, &subpassBeginInfo);
1710 vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelineProduceSubsampledImage);
1711 vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
1712 vk.cmdDraw(*m_cmdBuffer, (deUint32)m_vertices.size(), 1, 0, 0);
1713 if (testParams.makeCopy)
1714 {
1715 RPS2::cmdNextSubpass(vk, *m_cmdBuffer, &subpassBeginInfo, &subpassEndInfo);
1716 vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelineCopySubsampledImage);
1717 vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayoutOperateOnSubsampledImage, 0, 1, &m_descriptorSetOperateOnSubsampledImage.get(), 0, DE_NULL);
1718 vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
1719 vk.cmdDraw(*m_cmdBuffer, (deUint32)m_vertices.size(), 1, 0, 0);
1720 }
1721 RPS2::cmdEndRenderPass(vk, *m_cmdBuffer, &subpassEndInfo);
1722
1723 // Resample subsampled image
1724 if (testParams.subsampledLoads)
1725 {
1726 const VkRenderPassBeginInfo renderPassBeginInfoUpdateSubsampledImage
1727 {
1728 VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
1729 DE_NULL, // const void* pNext;
1730 *m_renderPassUpdateSubsampledImage, // VkRenderPass renderPass;
1731 *m_framebufferUpdateSubsampledImage, // VkFramebuffer framebuffer;
1732 makeRect2D(colorImageSize.width, colorImageSize.height), // VkRect2D renderArea;
1733 0u, // uint32_t clearValueCount;
1734 DE_NULL // const VkClearValue* pClearValues;
1735 };
1736 RPS2::cmdBeginRenderPass(vk, *m_cmdBuffer, &renderPassBeginInfoUpdateSubsampledImage, &subpassBeginInfo);
1737 vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelineUpdateSubsampledImage);
1738 vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayoutOperateOnSubsampledImage, 0, 1, &m_descriptorSetOperateOnSubsampledImage.get(), 0, DE_NULL);
1739 vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
1740 vk.cmdDraw(*m_cmdBuffer, (deUint32)m_vertices.size(), 1, 0, 0);
1741 RPS2::cmdEndRenderPass(vk, *m_cmdBuffer, &subpassEndInfo);
1742 }
1743
1744 // Copy subsampled image to normal image using sampler that is able to read from subsampled images
1745 // (subsampled image cannot be copied using vkCmdCopyImageToBuffer)
1746 const VkRenderPassBeginInfo renderPassBeginInfoOutputSubsampledImage
1747 {
1748 VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
1749 DE_NULL, // const void* pNext;
1750 *m_renderPassOutputSubsampledImage, // VkRenderPass renderPass;
1751 *m_framebufferOutputSubsampledImage, // VkFramebuffer framebuffer;
1752 makeRect2D(outputImageSize.width, outputImageSize.height), // VkRect2D renderArea;
1753 static_cast<deUint32>(attachmentClearValues.size()), // uint32_t clearValueCount;
1754 attachmentClearValues.data() // const VkClearValue* pClearValues;
1755 };
1756 RPS2::cmdBeginRenderPass(vk, *m_cmdBuffer, &renderPassBeginInfoOutputSubsampledImage, &subpassBeginInfo);
1757 vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelineOutputSubsampledImage);
1758 vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayoutOutputSubsampledImage, 0, 1, &m_descriptorSetOutputSubsampledImage.get(), 0, DE_NULL);
1759 vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBufferOutput.get(), &vertexBufferOffset);
1760 vk.cmdDraw(*m_cmdBuffer, (deUint32)m_verticesOutput.size(), 1, 0, 0);
1761 RPS2::cmdEndRenderPass(vk, *m_cmdBuffer, &subpassEndInfo);
1762
1763 endCommandBuffer(vk, *m_cmdBuffer);
1764 }
1765
iterate(void)1766 tcu::TestStatus FragmentDensityMapTestInstance::iterate (void)
1767 {
1768 const DeviceInterface& vk = m_context.getDeviceInterface();
1769 const VkDevice vkDevice = getDevice(m_context);
1770 const VkQueue queue = getDeviceQueue(vk, vkDevice, m_context.getUniversalQueueFamilyIndex(), 0);
1771
1772 submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get());
1773
1774 // approximations used when coarse reconstruction is specified are implementation defined
1775 if (m_testParams.coarseReconstruction)
1776 return tcu::TestStatus::pass("Pass");
1777
1778 return verifyImage();
1779 }
1780
1781 struct Vec4Sorter
1782 {
operator ()vkt::renderpass::__anonabc573560111::Vec4Sorter1783 bool operator()(const tcu::Vec4& lhs, const tcu::Vec4& rhs) const
1784 {
1785 if (lhs.x() != rhs.x())
1786 return lhs.x() < rhs.x();
1787 if (lhs.y() != rhs.y())
1788 return lhs.y() < rhs.y();
1789 if (lhs.z() != rhs.z())
1790 return lhs.z() < rhs.z();
1791 return lhs.w() < rhs.w();
1792 }
1793 };
1794
verifyImage(void)1795 tcu::TestStatus FragmentDensityMapTestInstance::verifyImage (void)
1796 {
1797 const DeviceInterface& vk = m_context.getDeviceInterface();
1798 const VkDevice vkDevice = getDevice(m_context);
1799 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1800 const VkQueue queue = getDeviceQueue(vk, vkDevice, queueFamilyIndex, 0);
1801 SimpleAllocator memAlloc (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
1802 tcu::UVec2 renderSize (m_renderSize.x(), m_renderSize.y());
1803 de::UniquePtr<tcu::TextureLevel> outputImage (pipeline::readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, memAlloc, *m_outputImage, VK_FORMAT_R8G8B8A8_UNORM, renderSize).release());
1804 const tcu::ConstPixelBufferAccess& outputAccess (outputImage->getAccess());
1805 tcu::TestLog& log (m_context.getTestContext().getLog());
1806
1807 // Log images
1808 log << tcu::TestLog::ImageSet("Result", "Result images")
1809 << tcu::TestLog::Image("Rendered", "Rendered output image", outputAccess)
1810 << tcu::TestLog::EndImageSet;
1811
1812 deUint32 estimatedColorCount = m_testParams.viewCount * m_testParams.fragmentArea.x() * m_testParams.fragmentArea.y();
1813 float densityMult = m_densityValue.x() * m_densityValue.y();
1814
1815 #if DRY_RUN_WITHOUT_FDM_EXTENSION
1816 estimatedColorCount = m_testParams.viewCount + 2;
1817 densityMult = 0.0f;
1818 #endif
1819
1820 // Create histogram of all image colors, check the value of inverted FragSizeEXT
1821 std::map<tcu::Vec4, deUint32, Vec4Sorter> colorCount;
1822 for (int y = 0; y < outputAccess.getHeight(); y++)
1823 {
1824 for (int x = 0; x < outputAccess.getWidth(); x++)
1825 {
1826 tcu::Vec4 outputColor = outputAccess.getPixel(x, y);
1827 float densityClamped = outputColor.z() * outputColor.w();
1828
1829 if ((densityClamped + 0.01) < densityMult)
1830 return tcu::TestStatus::fail("Wrong value of FragSizeEXT variable");
1831
1832 auto it = colorCount.find(outputColor);
1833 if (it == end(colorCount))
1834 it = colorCount.insert({ outputColor, 0u }).first;
1835 it->second++;
1836 }
1837 }
1838
1839 // Check if color count is the same as estimated one
1840 for (const auto& color : colorCount)
1841 {
1842 if (color.second > estimatedColorCount)
1843 return tcu::TestStatus::fail("Wrong color count");
1844 }
1845
1846 return tcu::TestStatus::pass("Pass");
1847 }
1848
1849 } // anonymous
1850
createChildren(tcu::TestCaseGroup * fdmTests)1851 static void createChildren (tcu::TestCaseGroup* fdmTests)
1852 {
1853 tcu::TestContext& testCtx = fdmTests->getTestContext();
1854
1855 const struct
1856 {
1857 std::string name;
1858 deUint32 viewCount;
1859 } views[] =
1860 {
1861 { "1_view", 1 },
1862 { "2_views", 2 },
1863 { "4_views", 4 },
1864 { "6_views", 6 },
1865 };
1866
1867 const struct
1868 {
1869 std::string name;
1870 bool makeCopy;
1871 } renders[] =
1872 {
1873 { "render", false },
1874 { "render_copy", true }
1875 };
1876
1877 const struct
1878 {
1879 std::string name;
1880 float renderSizeToDensitySize;
1881 } sizes[] =
1882 {
1883 { "divisible_density_size", 4.0f },
1884 { "non_divisible_density_size", 3.75f }
1885 };
1886
1887 const struct
1888 {
1889 std::string name;
1890 VkSampleCountFlagBits samples;
1891 } samples[] =
1892 {
1893 { "1_sample", VK_SAMPLE_COUNT_1_BIT },
1894 { "2_samples", VK_SAMPLE_COUNT_2_BIT },
1895 { "4_samples", VK_SAMPLE_COUNT_4_BIT },
1896 { "8_samples", VK_SAMPLE_COUNT_8_BIT }
1897 };
1898
1899 std::vector<tcu::UVec2> fragmentArea
1900 {
1901 { 1, 2 },
1902 { 2, 1 },
1903 { 2, 2 }
1904 };
1905
1906 for (const auto& view : views)
1907 {
1908 de::MovePtr<tcu::TestCaseGroup> viewGroup(new tcu::TestCaseGroup(testCtx, view.name.c_str(), ""));
1909 for (const auto& render : renders)
1910 {
1911 de::MovePtr<tcu::TestCaseGroup> renderGroup(new tcu::TestCaseGroup(testCtx, render.name.c_str(), ""));
1912 for (const auto& size : sizes)
1913 {
1914 de::MovePtr<tcu::TestCaseGroup> sizeGroup(new tcu::TestCaseGroup(testCtx, size.name.c_str(), ""));
1915 for (const auto& sample : samples)
1916 {
1917 de::MovePtr<tcu::TestCaseGroup> sampleGroup(new tcu::TestCaseGroup(testCtx, sample.name.c_str(), ""));
1918 for (const auto& area : fragmentArea)
1919 {
1920 std::stringstream str;
1921 str << "_" << area.x() << "_" << area.y();
1922
1923 TestParams params
1924 {
1925 false, // bool dynamicDensityMap;
1926 false, // bool deferredDensityMap;
1927 false, // bool nonSubsampledImages;
1928 false, // bool subsampledLoads;
1929 false, // bool coarseReconstruction;
1930 1, // deUint32 samplersCount;
1931 view.viewCount, // deUint32 viewCount;
1932 render.makeCopy, // bool makeCopy;
1933 size.renderSizeToDensitySize, // float renderMultiplier;
1934 sample.samples, // VkSampleCountFlagBits colorSamples;
1935 area, // tcu::UVec2 fragmentArea;
1936 { 16, 16 }, // tcu::UVec2 densityMapSize;
1937 VK_FORMAT_R8G8_UNORM // VkFormat densityMapFormat;
1938 };
1939
1940 sampleGroup->addChild(new FragmentDensityMapTest(testCtx, std::string("static_subsampled") + str.str(), "", params));
1941 params.deferredDensityMap = true;
1942 sampleGroup->addChild(new FragmentDensityMapTest(testCtx, std::string("deferred_subsampled") + str.str(), "", params));
1943 params.deferredDensityMap = false;
1944 params.dynamicDensityMap = true;
1945 sampleGroup->addChild(new FragmentDensityMapTest(testCtx, std::string("dynamic_subsampled") + str.str(), "", params));
1946
1947 // generate nonsubsampled tests just for single view and double view cases
1948 if (view.viewCount < 3)
1949 {
1950 params.nonSubsampledImages = true;
1951 sampleGroup->addChild(new FragmentDensityMapTest(testCtx, std::string("static_nonsubsampled") + str.str(), "", params));
1952 params.deferredDensityMap = true;
1953 sampleGroup->addChild(new FragmentDensityMapTest(testCtx, std::string("deferred_nonsubsampled") + str.str(), "", params));
1954 params.deferredDensityMap = false;
1955 params.dynamicDensityMap = true;
1956 sampleGroup->addChild(new FragmentDensityMapTest(testCtx, std::string("dynamic_nonsubsampled") + str.str(), "", params));
1957 }
1958 }
1959 sizeGroup->addChild(sampleGroup.release());
1960 }
1961 renderGroup->addChild(sizeGroup.release());
1962 }
1963 viewGroup->addChild(renderGroup.release());
1964 }
1965 fdmTests->addChild(viewGroup.release());
1966 }
1967
1968 const struct
1969 {
1970 std::string name;
1971 deUint32 count;
1972 } subsampledSamplers[] =
1973 {
1974 { "2_subsampled_samplers", 2 },
1975 { "4_subsampled_samplers", 4 },
1976 { "6_subsampled_samplers", 6 },
1977 { "8_subsampled_samplers", 8 }
1978 };
1979
1980 de::MovePtr<tcu::TestCaseGroup> propertiesGroup(new tcu::TestCaseGroup(testCtx, "properties", ""));
1981 for (const auto& sampler : subsampledSamplers)
1982 {
1983 TestParams params
1984 {
1985 false, // bool dynamicDensityMap;
1986 false, // bool deferredDensityMap;
1987 false, // bool nonSubsampledImages;
1988 false, // bool subsampledLoads;
1989 false, // bool coarseReconstruction;
1990 sampler.count, // deUint32 samplersCount;
1991 1, // deUint32 viewCount;
1992 false, // bool makeCopy;
1993 4.0f, // float renderMultiplier;
1994 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits colorSamples;
1995 { 2, 2 }, // tcu::UVec2 fragmentArea;
1996 { 16, 16 }, // tcu::UVec2 densityMapSize;
1997 VK_FORMAT_R8G8_UNORM // VkFormat densityMapFormat;
1998 };
1999 propertiesGroup->addChild(new FragmentDensityMapTest(testCtx, sampler.name, "", params));
2000 }
2001 TestParams params
2002 {
2003 false, // bool dynamicDensityMap;
2004 false, // bool deferredDensityMap;
2005 false, // bool nonSubsampledImages;
2006 true, // bool subsampledLoads;
2007 false, // bool coarseReconstruction;
2008 1, // deUint32 samplersCount;
2009 2, // deUint32 viewCount;
2010 false, // bool makeCopy;
2011 4.0f, // float renderMultiplier;
2012 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits colorSamples;
2013 { 1, 2 }, // tcu::UVec2 fragmentArea;
2014 { 16, 16 }, // tcu::UVec2 densityMapSize;
2015 VK_FORMAT_R8G8_UNORM // VkFormat densityMapFormat;
2016 };
2017 propertiesGroup->addChild(new FragmentDensityMapTest(testCtx, "subsampled_loads", "", params));
2018 params.subsampledLoads = false;
2019 params.coarseReconstruction = true;
2020 propertiesGroup->addChild(new FragmentDensityMapTest(testCtx, "subsampled_coarse_reconstruction", "", params));
2021 fdmTests->addChild(propertiesGroup.release());
2022 }
2023
cleanupGroup(tcu::TestCaseGroup * group)2024 static void cleanupGroup (tcu::TestCaseGroup* group)
2025 {
2026 DE_UNREF(group);
2027 // Destroy singleton objects.
2028 g_singletonDevice.clear();
2029 }
2030
createFragmentDensityMapTests(tcu::TestContext & testCtx)2031 tcu::TestCaseGroup* createFragmentDensityMapTests (tcu::TestContext& testCtx)
2032 {
2033 return createTestGroup(testCtx, "fragment_density_map", "VK_EXT_fragment_density_map and VK_EXT_fragment_density_map2 extensions tests", createChildren, cleanupGroup);
2034 }
2035
2036 } // renderpass
2037
2038 } // vkt
2039