1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 Advanced Micro Devices, Inc.
6 * Copyright (c) 2017 The Khronos Group Inc.
7 * Copyright (c) 2023 LunarG, Inc.
8 * Copyright (c) 2023 Nintendo
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *
22 *//*!
23 * \file
24 * \brief Tests for VK_EXT_sample_locations
25 *//*--------------------------------------------------------------------*/
26
27 #include "vktPipelineMultisampleSampleLocationsExtTests.hpp"
28 #include "vktPipelineSampleLocationsUtil.hpp"
29 #include "vktPipelineMakeUtil.hpp"
30 #include "vktTestCase.hpp"
31 #include "vktTestGroupUtil.hpp"
32 #include "vktTestCaseUtil.hpp"
33
34 #include "vkPlatform.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkQueryUtil.hpp"
37 #include "vkTypeUtil.hpp"
38 #include "vkRefUtil.hpp"
39 #include "vkBuilderUtil.hpp"
40 #include "vkPrograms.hpp"
41 #include "vkImageUtil.hpp"
42 #include "vkCmdUtil.hpp"
43 #include "vkObjUtil.hpp"
44
45 #include "deUniquePtr.hpp"
46 #include "deRandom.hpp"
47 #include "deMath.h"
48
49 #include "tcuTestLog.hpp"
50 #include "tcuImageCompare.hpp"
51 #include "tcuTextureUtil.hpp"
52 #include "tcuRGBA.hpp"
53 #include "tcuVectorUtil.hpp"
54
55 #include <string>
56 #include <vector>
57 #include <set>
58 #include <algorithm>
59
60 namespace vkt
61 {
62 namespace pipeline
63 {
64 namespace
65 {
66 using namespace vk;
67 using de::UniquePtr;
68 using de::MovePtr;
69 using tcu::Vec4;
70 using tcu::Vec2;
71 using tcu::UVec2;
72 using tcu::UVec4;
73 using tcu::RGBA;
74
75 static const deUint32 STENCIL_REFERENCE = 1u;
76 static const float DEPTH_CLEAR = 1.0f;
77 static const float DEPTH_REFERENCE = 0.5f;
78 static const Vec4 CLEAR_COLOR_0 = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
79 static const Vec4 CLEAR_COLOR_1 = Vec4(0.5f, 0.25f, 0.75f, 1.0f);
80 static const VkDeviceSize ZERO = 0u;
81
82 template<typename T>
dataOrNullPtr(const std::vector<T>& v)83 inline const T* dataOrNullPtr (const std::vector<T>& v)
84 {
85 return (v.empty() ? DE_NULL : &v[0]);
86 }
87
88 template<typename T>
dataOrNullPtr(std::vector<T>& v)89 inline T* dataOrNullPtr (std::vector<T>& v)
90 {
91 return (v.empty() ? DE_NULL : &v[0]);
92 }
93
94 template<typename T>
append(std::vector<T>& first, const std::vector<T>& second)95 inline void append (std::vector<T>& first, const std::vector<T>& second)
96 {
97 first.insert(first.end(), second.begin(), second.end());
98 }
99
100 //! Order a Vector by X, Y, Z, and W
101 template<typename VectorT>
102 struct LessThan
103 {
operator ()vkt::pipeline::__anon28238::LessThan104 bool operator()(const VectorT& v1, const VectorT& v2) const
105 {
106 for (int i = 0; i < VectorT::SIZE; ++i)
107 {
108 if (v1[i] == v2[i])
109 continue;
110 else
111 return v1[i] < v2[i];
112 }
113
114 return false;
115 }
116 };
117
118 //! Similar to the class in vktTestCaseUtil.hpp, but uses Arg0 directly rather than through a InstanceFunction1
119 template<typename Arg0>
120 class FunctionProgramsSimple1
121 {
122 public:
123 typedef void (*Function) (vk::SourceCollections& dst, Arg0 arg0);
FunctionProgramsSimple1(Function func)124 FunctionProgramsSimple1 (Function func) : m_func(func) {}
init(vk::SourceCollections& dst, const Arg0& arg0) const125 void init (vk::SourceCollections& dst, const Arg0& arg0) const { m_func(dst, arg0); }
126
127 private:
128 const Function m_func;
129 };
130
131 //! Convenience function to create a TestCase based on a freestanding initPrograms and a TestInstance implementation
132 template<typename Instance, typename Arg0>
addInstanceTestCaseWithPrograms(tcu::TestCaseGroup* group, const std::string& name, typename FunctionSupport1<Arg0>::Function checkSupport, typename FunctionProgramsSimple1<Arg0>::Function initPrograms, Arg0 arg0)133 void addInstanceTestCaseWithPrograms (tcu::TestCaseGroup* group,
134 const std::string& name,
135 typename FunctionSupport1<Arg0>::Function checkSupport,
136 typename FunctionProgramsSimple1<Arg0>::Function initPrograms,
137 Arg0 arg0)
138 {
139 group->addChild(new InstanceFactory1WithSupport<Instance, Arg0, FunctionSupport1<Arg0>, FunctionProgramsSimple1<Arg0> >(
140 group->getTestContext(), tcu::NODETYPE_SELF_VALIDATE, name, FunctionProgramsSimple1<Arg0>(initPrograms), arg0, typename FunctionSupport1<Arg0>::Args(checkSupport, arg0)));
141 }
142
checkSupportSampleLocations(Context& context)143 void checkSupportSampleLocations (Context& context)
144 {
145 context.requireDeviceFunctionality("VK_EXT_sample_locations");
146 }
147
getString(const VkSampleCountFlagBits sampleCount)148 std::string getString (const VkSampleCountFlagBits sampleCount)
149 {
150 std::ostringstream str;
151 str << "samples_" << static_cast<deUint32>(sampleCount);
152 return str.str();
153 }
154
isSupportedDepthStencilFormat(const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkFormat format)155 bool isSupportedDepthStencilFormat (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkFormat format)
156 {
157 VkFormatProperties formatProps;
158 vki.getPhysicalDeviceFormatProperties(physDevice, format, &formatProps);
159 return (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0;
160 }
161
findSupportedDepthStencilFormat(Context& context, const bool useDepth, const bool useStencil)162 VkFormat findSupportedDepthStencilFormat (Context& context, const bool useDepth, const bool useStencil)
163 {
164 const InstanceInterface& vki = context.getInstanceInterface();
165 const VkPhysicalDevice physDevice = context.getPhysicalDevice();
166
167 if (useDepth && !useStencil)
168 return VK_FORMAT_D16_UNORM; // must be supported
169
170 // One of these formats must be supported.
171
172 if (isSupportedDepthStencilFormat(vki, physDevice, VK_FORMAT_D24_UNORM_S8_UINT))
173 return VK_FORMAT_D24_UNORM_S8_UINT;
174
175 if (isSupportedDepthStencilFormat(vki, physDevice, VK_FORMAT_D32_SFLOAT_S8_UINT))
176 return VK_FORMAT_D32_SFLOAT_S8_UINT;
177
178 return VK_FORMAT_UNDEFINED;
179 }
180
checkFragmentShadingRateRequirements(Context& context, deUint32 sampleCount)181 void checkFragmentShadingRateRequirements(Context& context, deUint32 sampleCount)
182 {
183 const auto& vki = context.getInstanceInterface();
184 const auto physicalDevice = context.getPhysicalDevice();
185
186 context.requireDeviceFunctionality("VK_KHR_fragment_shading_rate");
187
188 if (!context.getFragmentShadingRateFeatures().pipelineFragmentShadingRate)
189 TCU_THROW(NotSupportedError, "pipelineFragmentShadingRate not supported");
190
191 // Fetch information about supported fragment shading rates
192 deUint32 supportedFragmentShadingRateCount = 0;
193 vki.getPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &supportedFragmentShadingRateCount, DE_NULL);
194
195 std::vector<vk::VkPhysicalDeviceFragmentShadingRateKHR> supportedFragmentShadingRates(supportedFragmentShadingRateCount,
196 {
197 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR,
198 DE_NULL,
199 vk::VK_SAMPLE_COUNT_1_BIT,
200 {1, 1}
201 });
202 vki.getPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &supportedFragmentShadingRateCount, supportedFragmentShadingRates.data());
203
204 bool requiredRateFound = false;
205 for (const auto& rate : supportedFragmentShadingRates)
206 {
207 if ((rate.fragmentSize.width == 2u) &&
208 (rate.fragmentSize.height == 2u) &&
209 (rate.sampleCounts & sampleCount))
210 {
211 requiredRateFound = true;
212 break;
213 }
214 }
215
216 if (!requiredRateFound)
217 TCU_THROW(NotSupportedError, "Required FragmentShadingRate not supported");
218 }
219
getImageAspectFlags(const VkFormat format)220 VkImageAspectFlags getImageAspectFlags (const VkFormat format)
221 {
222 const tcu::TextureFormat tcuFormat = mapVkFormat(format);
223
224 if (tcuFormat.order == tcu::TextureFormat::DS) return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
225 else if (tcuFormat.order == tcu::TextureFormat::D) return VK_IMAGE_ASPECT_DEPTH_BIT;
226 else if (tcuFormat.order == tcu::TextureFormat::S) return VK_IMAGE_ASPECT_STENCIL_BIT;
227
228 DE_FATAL("Format not handled");
229 return 0u;
230 }
231
getSampleLocationsPropertiesEXT(Context& context)232 VkPhysicalDeviceSampleLocationsPropertiesEXT getSampleLocationsPropertiesEXT (Context& context)
233 {
234 const InstanceInterface& vki = context.getInstanceInterface();
235 const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
236
237 VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationsProperties;
238 deMemset(&sampleLocationsProperties, 0, sizeof(sampleLocationsProperties));
239
240 sampleLocationsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT;
241 sampleLocationsProperties.pNext = DE_NULL;
242
243 VkPhysicalDeviceProperties2 properties =
244 {
245 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, // VkStructureType sType;
246 &sampleLocationsProperties, // void* pNext;
247 VkPhysicalDeviceProperties(), // VkPhysicalDeviceProperties properties;
248 };
249
250 vki.getPhysicalDeviceProperties2(physicalDevice, &properties);
251
252 return sampleLocationsProperties;
253 }
254
numSamplesPerPixel(const MultisamplePixelGrid& pixelGrid)255 inline deUint32 numSamplesPerPixel (const MultisamplePixelGrid& pixelGrid)
256 {
257 return static_cast<deUint32>(pixelGrid.samplesPerPixel());
258 }
259
makeEmptySampleLocationsInfo()260 inline VkSampleLocationsInfoEXT makeEmptySampleLocationsInfo ()
261 {
262 const VkSampleLocationsInfoEXT info =
263 {
264 VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT, // VkStructureType sType;
265 DE_NULL, // const void* pNext;
266 (VkSampleCountFlagBits)0, // VkSampleCountFlagBits sampleLocationsPerPixel;
267 makeExtent2D(0,0), // VkExtent2D sampleLocationGridSize;
268 0, // uint32_t sampleLocationsCount;
269 DE_NULL, // const VkSampleLocationEXT* pSampleLocations;
270 };
271 return info;
272 }
273
logPixelGrid(tcu::TestLog& log, const VkPhysicalDeviceSampleLocationsPropertiesEXT& sampleLocationsProperties, const MultisamplePixelGrid& pixelGrid)274 void logPixelGrid (tcu::TestLog& log, const VkPhysicalDeviceSampleLocationsPropertiesEXT& sampleLocationsProperties, const MultisamplePixelGrid& pixelGrid)
275 {
276 log << tcu::TestLog::Section("pixelGrid", "Multisample pixel grid configuration:")
277 << tcu::TestLog::Message << sampleLocationsProperties << tcu::TestLog::EndMessage
278 << tcu::TestLog::Message << "Specified grid size = " << pixelGrid.size() << tcu::TestLog::EndMessage;
279
280 for (deUint32 gridY = 0; gridY < pixelGrid.size().y(); ++gridY)
281 for (deUint32 gridX = 0; gridX < pixelGrid.size().x(); ++gridX)
282 {
283 log << tcu::TestLog::Message << "Pixel(" << gridX << ", " << gridY <<")" << tcu::TestLog::EndMessage;
284
285 for (deUint32 sampleNdx = 0; sampleNdx < numSamplesPerPixel(pixelGrid); ++sampleNdx)
286 {
287 const VkSampleLocationEXT& loc = pixelGrid.getSample(gridX, gridY, sampleNdx);
288 log << tcu::TestLog::Message << "* Sample(" << sampleNdx <<") = " << Vec2(loc.x, loc.y) << tcu::TestLog::EndMessage;
289 }
290 }
291
292 log << tcu::TestLog::Message << "Sample locations visualization" << tcu::TestLog::EndMessage;
293
294 {
295 const deUint32 height = deMinu32(1u << sampleLocationsProperties.sampleLocationSubPixelBits, 16u); // increase if you want more precision
296 const deUint32 width = 2 * height; // works well with a fixed-size font
297 std::vector<char> buffer (width * height);
298
299 for (deUint32 gridY = 0; gridY < pixelGrid.size().y(); ++gridY)
300 for (deUint32 gridX = 0; gridX < pixelGrid.size().x(); ++gridX)
301 {
302 std::fill(buffer.begin(), buffer.end(), '.');
303
304 for (deUint32 sampleNdx = 0; sampleNdx < numSamplesPerPixel(pixelGrid); ++sampleNdx)
305 {
306 const VkSampleLocationEXT& loc = pixelGrid.getSample(gridX, gridY, sampleNdx);
307 const deUint32 ndx = deMinu32(width - 1, static_cast<deUint32>(static_cast<float>(width) * loc.x)) +
308 deMinu32(height - 1, static_cast<deUint32>(static_cast<float>(height) * loc.y)) * width;
309 const deUint32 evenNdx = ndx - ndx % 2;
310
311 buffer[evenNdx ] = '[';
312 buffer[evenNdx + 1] = ']';
313 }
314
315 std::ostringstream str;
316 str << "Pixel(" << gridX << ", " << gridY <<")\n";
317
318 for (deUint32 lineNdx = 0; lineNdx < height; ++lineNdx)
319 {
320 str.write(&buffer[width * lineNdx], width);
321 str << "\n";
322 }
323
324 log << tcu::TestLog::Message << str.str() << tcu::TestLog::EndMessage;
325 }
326 }
327
328 log << tcu::TestLog::EndSection;
329 }
330
331 //! Place samples very close to each other
fillSampleLocationsPacked(MultisamplePixelGrid& grid, const deUint32 subPixelBits)332 void fillSampleLocationsPacked (MultisamplePixelGrid& grid, const deUint32 subPixelBits)
333 {
334 const deUint32 numLocations = 1u << subPixelBits;
335 const int offset[3] = { -1, 0, 1 };
336 de::Random rng (214);
337
338 for (deUint32 gridY = 0; gridY < grid.size().y(); ++gridY)
339 for (deUint32 gridX = 0; gridX < grid.size().x(); ++gridX)
340 {
341 // Will start placing from this location
342 const UVec2 baseLocationNdx (rng.getUint32() % numLocations,
343 rng.getUint32() % numLocations);
344 UVec2 locationNdx = baseLocationNdx;
345
346 std::set<UVec2, LessThan<UVec2> > takenLocationIndices;
347 for (deUint32 sampleNdx = 0; sampleNdx < numSamplesPerPixel(grid); /* no increment */)
348 {
349 if (takenLocationIndices.find(locationNdx) == takenLocationIndices.end())
350 {
351 const VkSampleLocationEXT location =
352 {
353 static_cast<float>(locationNdx.x()) / static_cast<float>(numLocations), // float x;
354 static_cast<float>(locationNdx.y()) / static_cast<float>(numLocations), // float y;
355 };
356
357 grid.setSample(gridX, gridY, sampleNdx, location);
358 takenLocationIndices.insert(locationNdx);
359
360 ++sampleNdx; // next sample
361 }
362
363 // Find next location by applying a small offset. Just keep iterating if a redundant location is chosen
364 locationNdx.x() = static_cast<deUint32>(deClamp32(locationNdx.x() + offset[rng.getUint32() % DE_LENGTH_OF_ARRAY(offset)], 0u, numLocations - 1));
365 locationNdx.y() = static_cast<deUint32>(deClamp32(locationNdx.y() + offset[rng.getUint32() % DE_LENGTH_OF_ARRAY(offset)], 0u, numLocations - 1));
366 }
367 }
368 }
369
370 //! Unorm/int compare, very low threshold as we are expecting near-exact values
compareGreenImage(tcu::TestLog& log, const char* name, const char* description, const tcu::ConstPixelBufferAccess& image)371 bool compareGreenImage (tcu::TestLog& log, const char* name, const char* description, const tcu::ConstPixelBufferAccess& image)
372 {
373 tcu::TextureLevel greenImage(image.getFormat(), image.getWidth(), image.getHeight());
374 tcu::clear(greenImage.getAccess(), tcu::RGBA::green().toIVec());
375 return tcu::intThresholdCompare(log, name, description, greenImage.getAccess(), image, tcu::UVec4(2u), tcu::COMPARE_LOG_RESULT);
376 }
377
378 //! Silent compare - no logging
intThresholdCompare(const tcu::ConstPixelBufferAccess& reference, const tcu::ConstPixelBufferAccess& result, const UVec4& threshold)379 bool intThresholdCompare (const tcu::ConstPixelBufferAccess& reference, const tcu::ConstPixelBufferAccess& result, const UVec4& threshold)
380 {
381 using namespace tcu;
382
383 int width = reference.getWidth();
384 int height = reference.getHeight();
385 int depth = reference.getDepth();
386 UVec4 maxDiff (0, 0, 0, 0);
387
388 TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
389
390 for (int z = 0; z < depth; z++)
391 {
392 for (int y = 0; y < height; y++)
393 {
394 for (int x = 0; x < width; x++)
395 {
396 IVec4 refPix = reference.getPixelInt(x, y, z);
397 IVec4 cmpPix = result.getPixelInt(x, y, z);
398 UVec4 diff = abs(refPix - cmpPix).cast<deUint32>();
399
400 maxDiff = max(maxDiff, diff);
401 }
402 }
403 }
404
405 return boolAll(lessThanEqual(maxDiff, threshold));
406 }
407
countUniqueColors(const tcu::ConstPixelBufferAccess& image)408 int countUniqueColors (const tcu::ConstPixelBufferAccess& image)
409 {
410 std::set<Vec4, LessThan<Vec4> > colors;
411
412 for (int y = 0; y < image.getHeight(); ++y)
413 for (int x = 0; x < image.getWidth(); ++x)
414 {
415 colors.insert(image.getPixel(x, y));
416 }
417
418 return static_cast<int>(colors.size());
419 }
420
makeImage(const DeviceInterface& vk, const VkDevice device, const VkImageCreateFlags flags, const VkFormat format, const UVec2& size, const VkSampleCountFlagBits samples, const VkImageUsageFlags usage)421 Move<VkImage> makeImage (const DeviceInterface& vk,
422 const VkDevice device,
423 const VkImageCreateFlags flags,
424 const VkFormat format,
425 const UVec2& size,
426 const VkSampleCountFlagBits samples,
427 const VkImageUsageFlags usage)
428 {
429 const VkImageCreateInfo imageParams =
430 {
431 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
432 DE_NULL, // const void* pNext;
433 flags, // VkImageCreateFlags flags;
434 VK_IMAGE_TYPE_2D, // VkImageType imageType;
435 format, // VkFormat format;
436 makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
437 1u, // deUint32 mipLevels;
438 1u, // deUint32 arrayLayers;
439 samples, // VkSampleCountFlagBits samples;
440 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
441 usage, // VkImageUsageFlags usage;
442 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
443 0u, // deUint32 queueFamilyIndexCount;
444 DE_NULL, // const deUint32* pQueueFamilyIndices;
445 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
446 };
447 return createImage(vk, device, &imageParams);
448 }
449
makeEvent(const DeviceInterface& vk, const VkDevice device)450 Move<VkEvent> makeEvent (const DeviceInterface& vk, const VkDevice device)
451 {
452 const VkEventCreateInfo createInfo =
453 {
454 VK_STRUCTURE_TYPE_EVENT_CREATE_INFO, // VkStructureType sType;
455 DE_NULL, // const void* pNext;
456 (VkEventCreateFlags)0, // VkEventCreateFlags flags;
457 };
458 return createEvent(vk, device, &createInfo);
459 }
460
461 //! Generate NDC space sample locations at each framebuffer pixel
462 //! Data is filled starting at pixel (0,0) and for each pixel there are numSamples locations
genFramebufferSampleLocations(const MultisamplePixelGrid& pixelGrid, const UVec2& gridSize, const UVec2& framebufferSize)463 std::vector<Vec2> genFramebufferSampleLocations (const MultisamplePixelGrid& pixelGrid, const UVec2& gridSize, const UVec2& framebufferSize)
464 {
465 std::vector<Vec2> locations;
466
467 for (deUint32 y = 0; y < framebufferSize.y(); ++y)
468 for (deUint32 x = 0; x < framebufferSize.x(); ++x)
469 for (deUint32 sampleNdx = 0; sampleNdx < numSamplesPerPixel(pixelGrid); ++sampleNdx)
470 {
471 const VkSampleLocationEXT& location = pixelGrid.getSample(x % gridSize.x(), y % gridSize.y(), sampleNdx);
472 const float globalX = location.x + static_cast<float>(x);
473 const float globalY = location.y + static_cast<float>(y);
474
475 // Transform to [-1, 1] space
476 locations.push_back(Vec2(-1.0f + 2.0f * (globalX / static_cast<float>(framebufferSize.x())),
477 -1.0f + 2.0f * (globalY / static_cast<float>(framebufferSize.y()))));
478 }
479
480 return locations;
481 }
482
483 struct PositionColor
484 {
485 tcu::Vec4 position;
486 tcu::Vec4 color;
487
PositionColorvkt::pipeline::__anon28238::PositionColor488 PositionColor (const tcu::Vec4& pos, const tcu::Vec4& col) : position(pos), color(col) {}
489 };
490
genVerticesFullQuad(const Vec4& color = Vec4(1.0f), const float z = 0.0f)491 std::vector<PositionColor> genVerticesFullQuad (const Vec4& color = Vec4(1.0f), const float z = 0.0f)
492 {
493 const PositionColor vertices[] =
494 {
495 PositionColor(Vec4( 1.0f, -1.0f, z, 1.0f), color),
496 PositionColor(Vec4(-1.0f, -1.0f, z, 1.0f), color),
497 PositionColor(Vec4(-1.0f, 1.0f, z, 1.0f), color),
498
499 PositionColor(Vec4(-1.0f, 1.0f, z, 1.0f), color),
500 PositionColor(Vec4( 1.0f, 1.0f, z, 1.0f), color),
501 PositionColor(Vec4( 1.0f, -1.0f, z, 1.0f), color),
502 };
503
504 return std::vector<PositionColor>(vertices, vertices + DE_LENGTH_OF_ARRAY(vertices));
505 }
506
507 //! Some abstract geometry with angled edges, to make multisampling visible.
genVerticesShapes(const Vec4& color = Vec4(1.0f), const float z = 0.0f)508 std::vector<PositionColor> genVerticesShapes (const Vec4& color = Vec4(1.0f), const float z = 0.0f)
509 {
510 std::vector<PositionColor> vertices;
511
512 const float numSteps = 16.0f;
513 const float angleStep = (2.0f * DE_PI) / numSteps;
514
515 for (float a = 0.0f; a <= 2.0f * DE_PI; a += angleStep)
516 {
517 vertices.push_back(PositionColor(Vec4(1.0f * deFloatCos(a), 1.0f * deFloatSin(a), z, 1.0f), color));
518 vertices.push_back(PositionColor(Vec4(0.1f * deFloatCos(a - angleStep), 0.1f * deFloatSin(a - angleStep), z, 1.0f), color));
519 vertices.push_back(PositionColor(Vec4(0.1f * deFloatCos(a + angleStep), 0.1f * deFloatSin(a + angleStep), z, 1.0f), color));
520 }
521
522 return vertices;
523 }
524
525 //! Stencil op that only allows drawing over the cleared area of an attachment.
stencilOpStateDrawOnce(void)526 inline VkStencilOpState stencilOpStateDrawOnce (void)
527 {
528 return makeStencilOpState(
529 VK_STENCIL_OP_KEEP, // stencil fail
530 VK_STENCIL_OP_ZERO, // depth & stencil pass
531 VK_STENCIL_OP_KEEP, // depth only fail
532 VK_COMPARE_OP_EQUAL, // compare op
533 ~0u, // compare mask
534 ~0u, // write mask
535 STENCIL_REFERENCE); // reference
536 }
537
538 //! Stencil op that simply increments the buffer with each passing test.
stencilOpStateIncrement(void)539 inline VkStencilOpState stencilOpStateIncrement(void)
540 {
541 return makeStencilOpState(
542 VK_STENCIL_OP_KEEP, // stencil fail
543 VK_STENCIL_OP_INCREMENT_AND_CLAMP, // depth & stencil pass
544 VK_STENCIL_OP_KEEP, // depth only fail
545 VK_COMPARE_OP_ALWAYS, // compare op
546 ~0u, // compare mask
547 ~0u, // write mask
548 STENCIL_REFERENCE); // reference
549 }
550
551 //! A few preconfigured vertex attribute configurations
552 enum VertexInputConfig
553 {
554 VERTEX_INPUT_NONE = 0u,
555 VERTEX_INPUT_VEC4,
556 VERTEX_INPUT_VEC4_VEC4,
557 };
558
559 //! Create a MSAA pipeline, with max per-sample shading
preparePipelineWrapper(GraphicsPipelineWrapper& gpw, const std::vector<VkDynamicState>& dynamicState, const PipelineLayoutWrapper& pipelineLayout, const VkRenderPass renderPass, const ShaderWrapper vertexModule, const ShaderWrapper fragmentModule, const deUint32 subpassIndex, const VkViewport& viewport, const VkRect2D scissor, const VkSampleCountFlagBits numSamples, const bool useSampleLocations, const VkSampleLocationsInfoEXT& sampleLocationsInfo, const bool useDepth, const bool useStencil, const VertexInputConfig vertexInputConfig, const VkPrimitiveTopology topology, const VkStencilOpState& stencilOpState, const bool useFragmentShadingRate)560 void preparePipelineWrapper (GraphicsPipelineWrapper& gpw,
561 const std::vector<VkDynamicState>& dynamicState,
562 const PipelineLayoutWrapper& pipelineLayout,
563 const VkRenderPass renderPass,
564 const ShaderWrapper vertexModule,
565 const ShaderWrapper fragmentModule,
566 const deUint32 subpassIndex,
567 const VkViewport& viewport,
568 const VkRect2D scissor,
569 const VkSampleCountFlagBits numSamples,
570 const bool useSampleLocations,
571 const VkSampleLocationsInfoEXT& sampleLocationsInfo,
572 const bool useDepth,
573 const bool useStencil,
574 const VertexInputConfig vertexInputConfig,
575 const VkPrimitiveTopology topology,
576 const VkStencilOpState& stencilOpState,
577 const bool useFragmentShadingRate)
578 {
579 std::vector<VkVertexInputBindingDescription> vertexInputBindingDescriptions;
580 std::vector<VkVertexInputAttributeDescription> vertexInputAttributeDescriptions;
581
582 const deUint32 sizeofVec4 = static_cast<deUint32>(sizeof(Vec4));
583
584 switch (vertexInputConfig)
585 {
586 case VERTEX_INPUT_NONE:
587 break;
588
589 case VERTEX_INPUT_VEC4:
590 vertexInputBindingDescriptions.push_back(makeVertexInputBindingDescription(0u, sizeofVec4, VK_VERTEX_INPUT_RATE_VERTEX));
591 vertexInputAttributeDescriptions.push_back(makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u));
592 break;
593
594 case VERTEX_INPUT_VEC4_VEC4:
595 vertexInputBindingDescriptions.push_back(makeVertexInputBindingDescription(0u, 2u * sizeofVec4, VK_VERTEX_INPUT_RATE_VERTEX));
596 vertexInputAttributeDescriptions.push_back(makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u));
597 vertexInputAttributeDescriptions.push_back(makeVertexInputAttributeDescription(1u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, sizeofVec4));
598 break;
599
600 default:
601 DE_FATAL("Vertex input config not supported");
602 break;
603 }
604
605 const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
606 {
607 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
608 DE_NULL, // const void* pNext;
609 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags;
610 static_cast<deUint32>(vertexInputBindingDescriptions.size()), // uint32_t vertexBindingDescriptionCount;
611 dataOrNullPtr(vertexInputBindingDescriptions), // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
612 static_cast<deUint32>(vertexInputAttributeDescriptions.size()), // uint32_t vertexAttributeDescriptionCount;
613 dataOrNullPtr(vertexInputAttributeDescriptions), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
614 };
615
616 const VkPipelineSampleLocationsStateCreateInfoEXT pipelineSampleLocationsCreateInfo =
617 {
618 VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT, // VkStructureType sType;
619 DE_NULL, // const void* pNext;
620 useSampleLocations, // VkBool32 sampleLocationsEnable;
621 sampleLocationsInfo, // VkSampleLocationsInfoEXT sampleLocationsInfo;
622 };
623
624 const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
625 {
626 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
627 &pipelineSampleLocationsCreateInfo, // const void* pNext;
628 (VkPipelineMultisampleStateCreateFlags)0, // VkPipelineMultisampleStateCreateFlags flags;
629 numSamples, // VkSampleCountFlagBits rasterizationSamples;
630 VK_TRUE, // VkBool32 sampleShadingEnable;
631 1.0f, // float minSampleShading;
632 DE_NULL, // const VkSampleMask* pSampleMask;
633 VK_FALSE, // VkBool32 alphaToCoverageEnable;
634 VK_FALSE // VkBool32 alphaToOneEnable;
635 };
636
637 VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
638 {
639 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
640 DE_NULL, // const void* pNext;
641 (VkPipelineDepthStencilStateCreateFlags)0, // VkPipelineDepthStencilStateCreateFlags flags;
642 useDepth, // VkBool32 depthTestEnable;
643 true, // VkBool32 depthWriteEnable;
644 VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
645 VK_FALSE, // VkBool32 depthBoundsTestEnable;
646 useStencil, // VkBool32 stencilTestEnable;
647 stencilOpState, // VkStencilOpState front;
648 stencilOpState, // VkStencilOpState back;
649 0.0f, // float minDepthBounds;
650 1.0f, // float maxDepthBounds;
651 };
652
653 const VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo =
654 {
655 VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
656 DE_NULL, // const void* pNext;
657 (VkPipelineDynamicStateCreateFlags)0, // VkPipelineDynamicStateCreateFlags flags;
658 static_cast<deUint32>(dynamicState.size()), // uint32_t dynamicStateCount;
659 dataOrNullPtr(dynamicState), // const VkDynamicState* pDynamicStates;
660 };
661
662 const VkPipelineColorBlendAttachmentState colorBlendAttachmentState
663 {
664 VK_FALSE, // VkBool32 blendEnable
665 VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcColorBlendFactor
666 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor
667 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp
668 VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcAlphaBlendFactor
669 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor
670 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp
671 VK_COLOR_COMPONENT_R_BIT // VkColorComponentFlags colorWriteMask
672 | VK_COLOR_COMPONENT_G_BIT
673 | VK_COLOR_COMPONENT_B_BIT
674 | VK_COLOR_COMPONENT_A_BIT
675 };
676
677 VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfoDefault = initVulkanStructure();
678 colorBlendStateCreateInfoDefault.attachmentCount = 1u;
679 colorBlendStateCreateInfoDefault.pAttachments = &colorBlendAttachmentState;
680
681 const std::vector<VkViewport> viewports { viewport };
682 const std::vector<VkRect2D> scissors { scissor };
683
684 VkPipelineFragmentShadingRateStateCreateInfoKHR shadingRateStateCreateInfo
685 {
686 VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR, // VkStructureType sType;
687 DE_NULL, // const void* pNext;
688 { 2, 2 }, // VkExtent2D fragmentSize;
689 { VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR, VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR }, // VkFragmentShadingRateCombinerOpKHR combinerOps[2];
690 };
691
692 gpw.setDefaultTopology(topology)
693 .setDynamicState(&dynamicStateCreateInfo)
694 .setDefaultRasterizationState()
695 .setupVertexInputState(&vertexInputStateInfo)
696 .setupPreRasterizationShaderState(viewports,
697 scissors,
698 pipelineLayout,
699 renderPass,
700 subpassIndex,
701 vertexModule,
702 nullptr, ShaderWrapper(), ShaderWrapper(), ShaderWrapper(), DE_NULL,
703 (useFragmentShadingRate ? &shadingRateStateCreateInfo : nullptr))
704 .setupFragmentShaderState(pipelineLayout,
705 renderPass,
706 subpassIndex,
707 fragmentModule,
708 &pipelineDepthStencilStateInfo,
709 &pipelineMultisampleStateInfo)
710 .setupFragmentOutputState(renderPass, subpassIndex, &colorBlendStateCreateInfoDefault, &pipelineMultisampleStateInfo)
711 .setMonolithicPipelineLayout(pipelineLayout)
712 .buildPipeline();
713 }
714
preparePipelineWrapperSinglePassColor(GraphicsPipelineWrapper& gpw, const std::vector<VkDynamicState>& dynamicState, const PipelineLayoutWrapper& pipelineLayout, const VkRenderPass renderPass, const ShaderWrapper vertexModule, const ShaderWrapper fragmentModule, const VkViewport& viewport, const VkRect2D scissor, const VkSampleCountFlagBits numSamples, const bool useSampleLocations, const VkSampleLocationsInfoEXT& sampleLocationsInfo, const VertexInputConfig vertexInputConfig, const VkPrimitiveTopology topology, const bool useFragmentShadingRate)715 void preparePipelineWrapperSinglePassColor (GraphicsPipelineWrapper& gpw,
716 const std::vector<VkDynamicState>& dynamicState,
717 const PipelineLayoutWrapper& pipelineLayout,
718 const VkRenderPass renderPass,
719 const ShaderWrapper vertexModule,
720 const ShaderWrapper fragmentModule,
721 const VkViewport& viewport,
722 const VkRect2D scissor,
723 const VkSampleCountFlagBits numSamples,
724 const bool useSampleLocations,
725 const VkSampleLocationsInfoEXT& sampleLocationsInfo,
726 const VertexInputConfig vertexInputConfig,
727 const VkPrimitiveTopology topology,
728 const bool useFragmentShadingRate)
729 {
730 preparePipelineWrapper(gpw, dynamicState, pipelineLayout, renderPass, vertexModule, fragmentModule,
731 /*subpass*/ 0u, viewport, scissor, numSamples, useSampleLocations, sampleLocationsInfo,
732 /*depth test*/ false, /*stencil test*/ false, vertexInputConfig, topology, stencilOpStateIncrement(), useFragmentShadingRate);
733 }
734
735 //! Utility to build and maintain render pass, framebuffer and related resources.
736 //! Use bake() before using the render pass.
737 class RenderTarget
738 {
739 public:
RenderTarget(void)740 RenderTarget (void)
741 {
742 nextSubpass();
743 }
744
745 //! Returns an attachment index that is used to reference this attachment later
addAttachment(const VkImage image, const VkImageView imageView, const VkAttachmentDescriptionFlags flags, const VkFormat format, const VkSampleCountFlagBits numSamples, const VkAttachmentLoadOp loadOp, const VkAttachmentStoreOp storeOp, const VkAttachmentLoadOp stencilLoadOp, const VkAttachmentStoreOp stencilStoreOp, const VkImageLayout initialLayout, const VkImageLayout finalLayout, const VkClearValue clearValue, const VkSampleLocationsInfoEXT* pInitialSampleLocations = DE_NULL)746 deUint32 addAttachment (const VkImage image,
747 const VkImageView imageView,
748 const VkAttachmentDescriptionFlags flags,
749 const VkFormat format,
750 const VkSampleCountFlagBits numSamples,
751 const VkAttachmentLoadOp loadOp,
752 const VkAttachmentStoreOp storeOp,
753 const VkAttachmentLoadOp stencilLoadOp,
754 const VkAttachmentStoreOp stencilStoreOp,
755 const VkImageLayout initialLayout,
756 const VkImageLayout finalLayout,
757 const VkClearValue clearValue,
758 const VkSampleLocationsInfoEXT* pInitialSampleLocations = DE_NULL)
759 {
760 const deUint32 index = static_cast<deUint32>(m_attachments.size());
761
762 m_images.push_back(image);
763 m_attachments.push_back(imageView);
764 m_attachmentDescriptions.push_back(makeAttachmentDescription(
765 flags, // VkAttachmentDescriptionFlags flags;
766 format, // VkFormat format;
767 numSamples, // VkSampleCountFlagBits samples;
768 loadOp, // VkAttachmentLoadOp loadOp;
769 storeOp, // VkAttachmentStoreOp storeOp;
770 stencilLoadOp, // VkAttachmentLoadOp stencilLoadOp;
771 stencilStoreOp, // VkAttachmentStoreOp stencilStoreOp;
772 initialLayout, // VkImageLayout initialLayout;
773 finalLayout // VkImageLayout finalLayout;
774 ));
775 m_clearValues.push_back(clearValue); // always add, even if unused
776
777 if (pInitialSampleLocations)
778 {
779 const VkAttachmentSampleLocationsEXT attachmentSampleLocations =
780 {
781 index, // uint32_t attachmentIndex;
782 *pInitialSampleLocations, // VkSampleLocationsInfoEXT sampleLocationsInfo;
783 };
784 m_attachmentSampleLocations.push_back(attachmentSampleLocations);
785 }
786
787 return index;
788 }
789
addSubpassColorAttachment(const deUint32 attachmentIndex, const VkImageLayout subpassLayout)790 void addSubpassColorAttachment (const deUint32 attachmentIndex, const VkImageLayout subpassLayout)
791 {
792 m_subpasses.back().colorAttachmentReferences.push_back(
793 makeAttachmentReference(attachmentIndex, subpassLayout));
794 m_subpasses.back().resolveAttachmentReferences.push_back(
795 makeAttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_UNDEFINED));
796 }
797
addSubpassColorAttachmentWithResolve(const deUint32 colorAttachmentIndex, const VkImageLayout colorSubpassLayout, const deUint32 resolveAttachmentIndex, const VkImageLayout resolveSubpassLayout, const VkSampleLocationsInfoEXT* pSampleLocations = DE_NULL)798 void addSubpassColorAttachmentWithResolve (const deUint32 colorAttachmentIndex, const VkImageLayout colorSubpassLayout, const deUint32 resolveAttachmentIndex, const VkImageLayout resolveSubpassLayout, const VkSampleLocationsInfoEXT* pSampleLocations = DE_NULL)
799 {
800 m_subpasses.back().colorAttachmentReferences.push_back(
801 makeAttachmentReference(colorAttachmentIndex, colorSubpassLayout));
802 m_subpasses.back().resolveAttachmentReferences.push_back(
803 makeAttachmentReference(resolveAttachmentIndex, resolveSubpassLayout));
804
805 if (pSampleLocations)
806 {
807 const VkSubpassSampleLocationsEXT subpassSampleLocations =
808 {
809 static_cast<deUint32>(m_subpasses.size() - 1), // uint32_t subpassIndex;
810 *pSampleLocations, // VkSampleLocationsInfoEXT sampleLocationsInfo;
811 };
812 m_subpassSampleLocations.push_back(subpassSampleLocations);
813 }
814 }
815
addSubpassDepthStencilAttachment(const deUint32 attachmentIndex, const VkImageLayout subpassLayout, const VkSampleLocationsInfoEXT* pSampleLocations = DE_NULL)816 void addSubpassDepthStencilAttachment (const deUint32 attachmentIndex, const VkImageLayout subpassLayout, const VkSampleLocationsInfoEXT* pSampleLocations = DE_NULL)
817 {
818 m_subpasses.back().depthStencilAttachmentReferences.push_back(
819 makeAttachmentReference(attachmentIndex, subpassLayout));
820
821 if (pSampleLocations)
822 {
823 const VkSubpassSampleLocationsEXT subpassSampleLocations =
824 {
825 static_cast<deUint32>(m_subpasses.size() - 1), // uint32_t subpassIndex;
826 *pSampleLocations, // VkSampleLocationsInfoEXT sampleLocationsInfo;
827 };
828 m_subpassSampleLocations.push_back(subpassSampleLocations);
829 }
830 }
831
addSubpassInputAttachment(const deUint32 attachmentIndex, const VkImageLayout subpassLayout)832 void addSubpassInputAttachment (const deUint32 attachmentIndex, const VkImageLayout subpassLayout)
833 {
834 m_subpasses.back().inputAttachmentReferences.push_back(
835 makeAttachmentReference(attachmentIndex, subpassLayout));
836 }
837
addSubpassPreserveAttachment(const deUint32 attachmentIndex)838 void addSubpassPreserveAttachment (const deUint32 attachmentIndex)
839 {
840 m_subpasses.back().preserveAttachmentReferences.push_back(attachmentIndex);
841 }
842
nextSubpass(void)843 void nextSubpass (void)
844 {
845 m_subpasses.push_back(SubpassDescription());
846 }
847
848 //! Create a RenderPass and Framebuffer based on provided attachments
bake(const DeviceInterface& vk, const VkDevice device, const PipelineConstructionType pipelineConstructionType, const UVec2& framebufferSize)849 void bake (const DeviceInterface& vk,
850 const VkDevice device,
851 const PipelineConstructionType pipelineConstructionType,
852 const UVec2& framebufferSize)
853 {
854 const deUint32 numSubpasses = static_cast<deUint32>(m_subpasses.size());
855
856 std::vector<VkSubpassDescription> subpassDescriptions;
857 std::vector<VkSubpassDependency> subpassDependencies;
858 for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx)
859 {
860 const SubpassDescription& sd = m_subpasses[subpassNdx];
861 const VkSubpassDescription description =
862 {
863 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags;
864 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
865 static_cast<deUint32>(sd.inputAttachmentReferences.size()), // deUint32 inputAttachmentCount;
866 dataOrNullPtr(sd.inputAttachmentReferences), // const VkAttachmentReference* pInputAttachments;
867 static_cast<deUint32>(sd.colorAttachmentReferences.size()), // deUint32 colorAttachmentCount;
868 dataOrNullPtr(sd.colorAttachmentReferences), // const VkAttachmentReference* pColorAttachments;
869 dataOrNullPtr(sd.resolveAttachmentReferences), // const VkAttachmentReference* pResolveAttachments;
870 dataOrNullPtr(sd.depthStencilAttachmentReferences), // const VkAttachmentReference* pDepthStencilAttachment;
871 static_cast<deUint32>(sd.preserveAttachmentReferences.size()), // deUint32 preserveAttachmentCount;
872 dataOrNullPtr(sd.preserveAttachmentReferences) // const deUint32* pPreserveAttachments;
873 };
874 subpassDescriptions.push_back(description);
875
876 // Add a very coarse dependency enforcing sequential ordering of subpasses
877 if (subpassNdx > 0)
878 {
879 static const VkAccessFlags accessAny = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
880 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
881 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
882 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
883 | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
884 const VkSubpassDependency dependency =
885 {
886 subpassNdx - 1, // uint32_t srcSubpass;
887 subpassNdx, // uint32_t dstSubpass;
888 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, // VkPipelineStageFlags srcStageMask;
889 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, // VkPipelineStageFlags dstStageMask;
890 accessAny, // VkAccessFlags srcAccessMask;
891 accessAny, // VkAccessFlags dstAccessMask;
892 (VkDependencyFlags)0, // VkDependencyFlags dependencyFlags;
893 };
894 subpassDependencies.push_back(dependency);
895 }
896 }
897 // add a final dependency to synchronize results for the copy commands that will follow the renderpass
898 const VkSubpassDependency finalDependency = {
899 numSubpasses - 1, // uint32_t srcSubpass;
900 VK_SUBPASS_EXTERNAL, // uint32_t dstSubpass;
901 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags srcStageMask;
902 VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags dstStageMask;
903 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask;
904 VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
905 (VkDependencyFlags)0, // VkDependencyFlags dependencyFlags;
906 };
907 subpassDependencies.push_back(finalDependency);
908
909 const VkRenderPassCreateInfo renderPassInfo =
910 {
911 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
912 DE_NULL, // const void* pNext;
913 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags;
914 static_cast<deUint32>(m_attachmentDescriptions.size()), // deUint32 attachmentCount;
915 dataOrNullPtr(m_attachmentDescriptions), // const VkAttachmentDescription* pAttachments;
916 static_cast<deUint32>(subpassDescriptions.size()), // deUint32 subpassCount;
917 dataOrNullPtr(subpassDescriptions), // const VkSubpassDescription* pSubpasses;
918 static_cast<deUint32>(subpassDependencies.size()), // deUint32 dependencyCount;
919 dataOrNullPtr(subpassDependencies) // const VkSubpassDependency* pDependencies;
920 };
921
922 m_renderPass = RenderPassWrapper(pipelineConstructionType, vk, device, &renderPassInfo);
923 m_renderPass.createFramebuffer(vk, device, static_cast<deUint32>(m_attachments.size()), dataOrNullPtr(m_images), dataOrNullPtr(m_attachments), framebufferSize.x(), framebufferSize.y());
924 }
925
getRenderPassWrapper(void) const926 const RenderPassWrapper& getRenderPassWrapper (void) const
927 {
928 return m_renderPass;
929 }
930
getRenderPass(void) const931 VkRenderPass getRenderPass (void) const
932 {
933 return *m_renderPass;
934 }
935
getFramebuffer(void) const936 VkFramebuffer getFramebuffer(void) const
937 {
938 return m_renderPass.getFramebuffer();
939 }
940
recordBeginRenderPass(const DeviceInterface& vk, const VkCommandBuffer cmdBuffer, const VkRect2D& renderArea, const VkSubpassContents subpassContents) const941 void recordBeginRenderPass (const DeviceInterface& vk,
942 const VkCommandBuffer cmdBuffer,
943 const VkRect2D& renderArea,
944 const VkSubpassContents subpassContents) const
945 {
946 const VkRenderPassSampleLocationsBeginInfoEXT renderPassSampleLocationsBeginInfo =
947 {
948 VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT, // VkStructureType sType;
949 DE_NULL, // const void* pNext;
950 static_cast<deUint32>(m_attachmentSampleLocations.size()), // uint32_t attachmentInitialSampleLocationsCount;
951 dataOrNullPtr(m_attachmentSampleLocations), // const VkAttachmentSampleLocationsEXT* pAttachmentInitialSampleLocations;
952 static_cast<deUint32>(m_subpassSampleLocations.size()), // uint32_t postSubpassSampleLocationsCount;
953 dataOrNullPtr(m_subpassSampleLocations), // const VkSubpassSampleLocationsEXT* pPostSubpassSampleLocations;
954 };
955 m_renderPass.begin(vk, cmdBuffer, renderArea, static_cast<deUint32>(m_clearValues.size()), dataOrNullPtr(m_clearValues), subpassContents, &renderPassSampleLocationsBeginInfo);
956 }
957
nextSubpass(const DeviceInterface& vk, const VkCommandBuffer cmdBuffer, const VkSubpassContents subpassContents) const958 void nextSubpass (const DeviceInterface& vk, const VkCommandBuffer cmdBuffer, const VkSubpassContents subpassContents) const
959 {
960 m_renderPass.nextSubpass(vk, cmdBuffer, subpassContents);
961 }
962
endRenderPass(const DeviceInterface& vk, const VkCommandBuffer cmdBuffer) const963 void endRenderPass (const DeviceInterface& vk, const VkCommandBuffer cmdBuffer) const
964 {
965 m_renderPass.end(vk, cmdBuffer);
966 }
967
968 private:
969 struct SubpassDescription
970 {
971 std::vector<VkAttachmentReference> inputAttachmentReferences;
972 std::vector<VkAttachmentReference> colorAttachmentReferences;
973 std::vector<VkAttachmentReference> resolveAttachmentReferences;
974 std::vector<VkAttachmentReference> depthStencilAttachmentReferences;
975 std::vector<deUint32> preserveAttachmentReferences;
976 };
977
978 std::vector<SubpassDescription> m_subpasses;
979 std::vector<VkImage> m_images;
980 std::vector<VkImageView> m_attachments;
981 std::vector<VkAttachmentDescription> m_attachmentDescriptions;
982 std::vector<VkClearValue> m_clearValues;
983 std::vector<VkAttachmentSampleLocationsEXT> m_attachmentSampleLocations;
984 std::vector<VkSubpassSampleLocationsEXT> m_subpassSampleLocations;
985 RenderPassWrapper m_renderPass;
986
987 // No copying allowed
988 RenderTarget (const RenderTarget&);
989 RenderTarget& operator=(const RenderTarget&);
990 };
991
recordImageBarrier(const DeviceInterface& vk, const VkCommandBuffer cmdBuffer, const VkImage image, const VkImageAspectFlags aspect, const VkPipelineStageFlags srcStageMask, const VkPipelineStageFlags dstStageMask, const VkAccessFlags srcAccessMask, const VkAccessFlags dstAccessMask, const VkImageLayout oldLayout, const VkImageLayout newLayout, const VkSampleLocationsInfoEXT* pSampleLocationsInfo = DE_NULL)992 void recordImageBarrier (const DeviceInterface& vk,
993 const VkCommandBuffer cmdBuffer,
994 const VkImage image,
995 const VkImageAspectFlags aspect,
996 const VkPipelineStageFlags srcStageMask,
997 const VkPipelineStageFlags dstStageMask,
998 const VkAccessFlags srcAccessMask,
999 const VkAccessFlags dstAccessMask,
1000 const VkImageLayout oldLayout,
1001 const VkImageLayout newLayout,
1002 const VkSampleLocationsInfoEXT* pSampleLocationsInfo = DE_NULL)
1003 {
1004 const VkImageMemoryBarrier barrier =
1005 {
1006 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1007 pSampleLocationsInfo, // const void* pNext;
1008 srcAccessMask, // VkAccessFlags srcAccessMask;
1009 dstAccessMask, // VkAccessFlags dstAccessMask;
1010 oldLayout, // VkImageLayout oldLayout;
1011 newLayout, // VkImageLayout newLayout;
1012 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1013 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1014 image, // VkImage image;
1015 makeImageSubresourceRange(aspect, 0u, 1u, 0u, 1u), // VkImageSubresourceRange subresourceRange;
1016 };
1017
1018 vk.cmdPipelineBarrier(cmdBuffer, srcStageMask, dstStageMask, (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
1019 }
1020
recordWaitEventWithImage(const DeviceInterface& vk, const VkCommandBuffer cmdBuffer, const VkEvent event, const VkImage image, const VkImageAspectFlags aspect, const VkPipelineStageFlags srcStageMask, const VkPipelineStageFlags dstStageMask, const VkAccessFlags srcAccessMask, const VkAccessFlags dstAccessMask, const VkImageLayout oldLayout, const VkImageLayout newLayout, const VkSampleLocationsInfoEXT* pSampleLocationsInfo = DE_NULL)1021 void recordWaitEventWithImage (const DeviceInterface& vk,
1022 const VkCommandBuffer cmdBuffer,
1023 const VkEvent event,
1024 const VkImage image,
1025 const VkImageAspectFlags aspect,
1026 const VkPipelineStageFlags srcStageMask,
1027 const VkPipelineStageFlags dstStageMask,
1028 const VkAccessFlags srcAccessMask,
1029 const VkAccessFlags dstAccessMask,
1030 const VkImageLayout oldLayout,
1031 const VkImageLayout newLayout,
1032 const VkSampleLocationsInfoEXT* pSampleLocationsInfo = DE_NULL)
1033 {
1034 const VkImageMemoryBarrier barrier =
1035 {
1036 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1037 pSampleLocationsInfo, // const void* pNext;
1038 srcAccessMask, // VkAccessFlags srcAccessMask;
1039 dstAccessMask, // VkAccessFlags dstAccessMask;
1040 oldLayout, // VkImageLayout oldLayout;
1041 newLayout, // VkImageLayout newLayout;
1042 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1043 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1044 image, // VkImage image;
1045 makeImageSubresourceRange(aspect, 0u, 1u, 0u, 1u), // VkImageSubresourceRange subresourceRange;
1046 };
1047
1048 vk.cmdWaitEvents(
1049 cmdBuffer, // VkCommandBuffer commandBuffer,
1050 1u, // uint32_t eventCount,
1051 &event, // const VkEvent* pEvents,
1052 srcStageMask, // VkPipelineStageFlags srcStageMask,
1053 dstStageMask, // VkPipelineStageFlags dstStageMask,
1054 0u, // uint32_t memoryBarrierCount,
1055 DE_NULL, // const VkMemoryBarrier* pMemoryBarriers,
1056 0u, // uint32_t bufferMemoryBarrierCount,
1057 DE_NULL, // const VkBufferMemoryBarrier* pBufferMemoryBarriers,
1058 1u, // uint32_t imageMemoryBarrierCount,
1059 &barrier); // const VkImageMemoryBarrier* pImageMemoryBarriers);
1060 }
1061
recordCopyImageToBuffer(const DeviceInterface& vk, const VkCommandBuffer cmdBuffer, const UVec2& imageSize, const VkImage srcImage, const VkBuffer dstBuffer)1062 void recordCopyImageToBuffer (const DeviceInterface& vk,
1063 const VkCommandBuffer cmdBuffer,
1064 const UVec2& imageSize,
1065 const VkImage srcImage,
1066 const VkBuffer dstBuffer)
1067 {
1068 // Resolve image -> host buffer
1069 {
1070 const VkBufferImageCopy region =
1071 {
1072 0ull, // VkDeviceSize bufferOffset;
1073 0u, // uint32_t bufferRowLength;
1074 0u, // uint32_t bufferImageHeight;
1075 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u), // VkImageSubresourceLayers imageSubresource;
1076 makeOffset3D(0, 0, 0), // VkOffset3D imageOffset;
1077 makeExtent3D(imageSize.x(), imageSize.y(), 1u), // VkExtent3D imageExtent;
1078 };
1079
1080 vk.cmdCopyImageToBuffer(cmdBuffer, srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstBuffer, 1u, ®ion);
1081 }
1082 // Buffer write barrier
1083 {
1084 const VkBufferMemoryBarrier barrier =
1085 {
1086 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
1087 DE_NULL, // const void* pNext;
1088 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
1089 VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
1090 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1091 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1092 dstBuffer, // VkBuffer buffer;
1093 0ull, // VkDeviceSize offset;
1094 VK_WHOLE_SIZE, // VkDeviceSize size;
1095 };
1096
1097 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
1098 0u, DE_NULL, 1u, &barrier, DE_NULL, 0u);
1099 }
1100 }
1101
recordClearAttachments(const DeviceInterface& vk, const VkCommandBuffer cmdBuffer, const deUint32 colorAttachment, const VkClearValue& colorClearValue, const VkImageAspectFlags depthStencilAspect, const VkClearValue& depthStencilClearValue, const VkRect2D& clearRect)1102 void recordClearAttachments (const DeviceInterface& vk,
1103 const VkCommandBuffer cmdBuffer,
1104 const deUint32 colorAttachment,
1105 const VkClearValue& colorClearValue,
1106 const VkImageAspectFlags depthStencilAspect,
1107 const VkClearValue& depthStencilClearValue,
1108 const VkRect2D& clearRect)
1109 {
1110 std::vector<VkClearAttachment> attachments;
1111
1112 const VkClearRect rect =
1113 {
1114 clearRect, // VkRect2D rect;
1115 0u, // uint32_t baseArrayLayer;
1116 1u, // uint32_t layerCount;
1117 };
1118
1119 // Clear color
1120 {
1121 const VkClearAttachment attachment =
1122 {
1123 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
1124 colorAttachment, // uint32_t colorAttachment;
1125 colorClearValue, // VkClearValue clearValue;
1126 };
1127 attachments.push_back(attachment);
1128 }
1129
1130 if ((depthStencilAspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0u)
1131 {
1132 const VkClearAttachment attachment =
1133 {
1134 depthStencilAspect, // VkImageAspectFlags aspectMask;
1135 VK_ATTACHMENT_UNUSED, // uint32_t colorAttachment;
1136 depthStencilClearValue, // VkClearValue clearValue;
1137 };
1138 attachments.push_back(attachment);
1139 }
1140
1141 vk.cmdClearAttachments(cmdBuffer, static_cast<deUint32>(attachments.size()), dataOrNullPtr(attachments), 1u, &rect);
1142 }
1143
1144 //! Suitable for executing in a render pass, no queries
beginSecondaryCommandBuffer(const DeviceInterface& vk, const VkCommandBuffer commandBuffer, const RenderPassWrapper& renderPass, const deUint32 subpass, const VkSampleCountFlagBits samples, const PipelineConstructionType pct)1145 void beginSecondaryCommandBuffer (const DeviceInterface& vk,
1146 const VkCommandBuffer commandBuffer,
1147 const RenderPassWrapper& renderPass,
1148 const deUint32 subpass,
1149 const VkSampleCountFlagBits samples,
1150 const PipelineConstructionType pct)
1151 {
1152 DE_UNREF(samples);
1153 DE_UNREF(pct);
1154 VkCommandBufferInheritanceInfo inheritanceInfo =
1155 {
1156 VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, // VkStructureType sType;
1157 DE_NULL, // const void* pNext;
1158 *renderPass, // VkRenderPass renderPass;
1159 subpass, // uint32_t subpass;
1160 renderPass.getFramebuffer(), // VkFramebuffer framebuffer;
1161 VK_FALSE, // VkBool32 occlusionQueryEnable;
1162 (VkQueryControlFlags)0, // VkQueryControlFlags queryFlags;
1163 (VkQueryPipelineStatisticFlags)0, // VkQueryPipelineStatisticFlags pipelineStatistics;
1164 };
1165
1166 const VkCommandBufferBeginInfo beginInfo =
1167 {
1168 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
1169 DE_NULL, // const void* pNext;
1170 (VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
1171 |VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT), // VkCommandBufferUsageFlags flags;
1172 &inheritanceInfo, // const VkCommandBufferInheritanceInfo* pInheritanceInfo;
1173 };
1174
1175 #ifndef CTS_USES_VULKANSC
1176 vk::VkCommandBufferInheritanceRenderingInfo inheritanceRenderingInfo = vk::initVulkanStructure();
1177 inheritanceRenderingInfo.flags = (VkRenderingFlags)0u;
1178 inheritanceRenderingInfo.viewMask = 0x0;
1179 inheritanceRenderingInfo.rasterizationSamples = samples;
1180 std::vector<vk::VkFormat> colorFormats;
1181 if (isConstructionTypeShaderObject(pct))
1182 {
1183 renderPass.fillInheritanceRenderingInfo(subpass, &colorFormats, &inheritanceRenderingInfo);
1184 inheritanceInfo.pNext = &inheritanceRenderingInfo;
1185 }
1186 #endif
1187
1188 VK_CHECK(vk.beginCommandBuffer(commandBuffer, &beginInfo));
1189 }
1190
1191 //! Verify results of a VkPhysicalDeviceSampleLocationsPropertiesEXT query with VkPhysicalDeviceProperties2KHR
testQuerySampleLocationProperties(Context& context)1192 tcu::TestStatus testQuerySampleLocationProperties (Context& context)
1193 {
1194 const VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationsProperties = getSampleLocationsPropertiesEXT(context);
1195
1196 context.getTestContext().getLog()
1197 << tcu::TestLog::Section("VkPhysicalDeviceSampleLocationsPropertiesEXT", "Query results")
1198 << tcu::TestLog::Message << sampleLocationsProperties << tcu::TestLog::EndMessage
1199 << tcu::TestLog::EndSection;
1200
1201 const VkSampleCountFlags allowedSampleCounts = (VK_SAMPLE_COUNT_2_BIT |
1202 VK_SAMPLE_COUNT_4_BIT |
1203 VK_SAMPLE_COUNT_8_BIT |
1204 VK_SAMPLE_COUNT_16_BIT |
1205 VK_SAMPLE_COUNT_32_BIT |
1206 VK_SAMPLE_COUNT_64_BIT);
1207
1208 if ((sampleLocationsProperties.sampleLocationSampleCounts & allowedSampleCounts) == 0)
1209 {
1210 return tcu::TestStatus::fail("VkPhysicalDeviceSampleLocationsPropertiesEXT: sampleLocationSampleCounts should specify at least one MSAA sample count");
1211 }
1212
1213 if (sampleLocationsProperties.maxSampleLocationGridSize.width == 0u ||
1214 sampleLocationsProperties.maxSampleLocationGridSize.height == 0u ||
1215 sampleLocationsProperties.maxSampleLocationGridSize.width > 16384u || // max not specified, but try to catch nonsense values like -1
1216 sampleLocationsProperties.maxSampleLocationGridSize.height > 16384u)
1217 {
1218 return tcu::TestStatus::fail("VkPhysicalDeviceSampleLocationsPropertiesEXT: maxSampleLocationGridSize must be at least (1,1) size");
1219 }
1220
1221 for (int i = 0; i < 2; ++i)
1222 {
1223 if (sampleLocationsProperties.sampleLocationCoordinateRange[i] < 0.0f ||
1224 sampleLocationsProperties.sampleLocationCoordinateRange[i] > 1.0f)
1225 {
1226 return tcu::TestStatus::fail("VkPhysicalDeviceSampleLocationsPropertiesEXT: sampleLocationCoordinateRange[] values must be in [0, 1] range");
1227 }
1228 }
1229
1230 if (sampleLocationsProperties.sampleLocationSubPixelBits == 0u ||
1231 sampleLocationsProperties.sampleLocationSubPixelBits > 64u) // max not specified, but try to catch nonsense values
1232 {
1233 return tcu::TestStatus::fail("VkPhysicalDeviceSampleLocationsPropertiesEXT: sampleLocationSubPixelBits should be greater than 0");
1234 }
1235
1236 return tcu::TestStatus::pass("Pass");
1237 }
1238
1239 //! Verify results of vkGetPhysicalDeviceMultisamplePropertiesEXT queries
testQueryMultisampleProperties(Context& context)1240 tcu::TestStatus testQueryMultisampleProperties (Context& context)
1241 {
1242 const InstanceInterface& vki = context.getInstanceInterface();
1243 const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
1244 tcu::TestLog& log = context.getTestContext().getLog();
1245
1246 const VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationsProperties = getSampleLocationsPropertiesEXT(context);
1247
1248 const VkSampleCountFlagBits sampleCountRange[] =
1249 {
1250 VK_SAMPLE_COUNT_1_BIT,
1251 VK_SAMPLE_COUNT_2_BIT,
1252 VK_SAMPLE_COUNT_4_BIT,
1253 VK_SAMPLE_COUNT_8_BIT,
1254 VK_SAMPLE_COUNT_16_BIT,
1255 VK_SAMPLE_COUNT_32_BIT,
1256 VK_SAMPLE_COUNT_64_BIT,
1257 };
1258
1259 bool allOk = true;
1260
1261 for (const VkSampleCountFlagBits* pLoopNumSamples = sampleCountRange; pLoopNumSamples < DE_ARRAY_END(sampleCountRange); ++pLoopNumSamples)
1262 {
1263 VkMultisamplePropertiesEXT multisampleProperties =
1264 {
1265 VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT, // VkStructureType sType;
1266 DE_NULL, // void* pNext;
1267 VkExtent2D(), // VkExtent2D maxSampleLocationGridSize;
1268 };
1269
1270 vki.getPhysicalDeviceMultisamplePropertiesEXT(physicalDevice, *pLoopNumSamples, &multisampleProperties);
1271
1272 log << tcu::TestLog::Section("getPhysicalDeviceMultisamplePropertiesEXT", "Query results")
1273 << tcu::TestLog::Message << "Sample count: " << *pLoopNumSamples << tcu::TestLog::EndMessage
1274 << tcu::TestLog::Message << multisampleProperties << tcu::TestLog::EndMessage;
1275
1276 const bool isSupportedSampleCount = (*pLoopNumSamples & sampleLocationsProperties.sampleLocationSampleCounts) != 0;
1277
1278 if (isSupportedSampleCount)
1279 {
1280 if (!(multisampleProperties.maxSampleLocationGridSize.width >= sampleLocationsProperties.maxSampleLocationGridSize.width &&
1281 multisampleProperties.maxSampleLocationGridSize.height >= sampleLocationsProperties.maxSampleLocationGridSize.height))
1282 {
1283 allOk = false;
1284 log << tcu::TestLog::Message
1285 << "FAIL: Grid size should be the same or larger than VkPhysicalDeviceSampleLocationsPropertiesEXT::maxSampleLocationGridSize"
1286 << tcu::TestLog::EndMessage;
1287 }
1288 }
1289 else
1290 {
1291 if (!(multisampleProperties.maxSampleLocationGridSize.width == 0u &&
1292 multisampleProperties.maxSampleLocationGridSize.height == 0u))
1293 {
1294 allOk = false;
1295 log << tcu::TestLog::Message << "FAIL: Expected (0, 0) grid size" << tcu::TestLog::EndMessage;
1296 }
1297 }
1298
1299 log << tcu::TestLog::EndSection;
1300 }
1301
1302 return allOk ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Some values were incorrect");
1303 }
1304
1305 // These tests only use a color attachment and focus on per-sample data
1306 namespace VerifySamples
1307 {
1308
1309 //! Data layout used in verify sample locations and interpolation cases
1310 namespace SampleDataSSBO
1311 {
1312
1313 static VkDeviceSize STATIC_SIZE = 6 * sizeof(deUint32);
1314
renderSize(void* const basePtr)1315 static UVec2& renderSize (void* const basePtr) { return *reinterpret_cast<UVec2*> (static_cast<deUint8*>(basePtr) + 0 * sizeof(deUint32)); }
gridSize(void* const basePtr)1316 static UVec2& gridSize (void* const basePtr) { return *reinterpret_cast<UVec2*> (static_cast<deUint8*>(basePtr) + 2 * sizeof(deUint32)); }
samplesPerPixel(void* const basePtr)1317 static deUint32& samplesPerPixel (void* const basePtr) { return *reinterpret_cast<deUint32*> (static_cast<deUint8*>(basePtr) + 4 * sizeof(deUint32)); }
1318
1319 template<typename T>
sampleData(void* const basePtr)1320 static T* sampleData (void* const basePtr) { DE_STATIC_ASSERT(sizeof(T) == sizeof(Vec2));
1321 return reinterpret_cast<T*> (static_cast<deUint8*>(basePtr) + STATIC_SIZE); }
1322
1323 } // SampleDataSSBO
1324
1325 enum TestOptionFlagBits
1326 {
1327 TEST_OPTION_DYNAMIC_STATE_BIT = 0x1, //!< Use dynamic pipeline state to pass in sample locations
1328 TEST_OPTION_CLOSELY_PACKED_BIT = 0x2, //!< Place samples as close as possible to each other
1329 TEST_OPTION_FRAGMENT_SHADING_RATE_BIT = 0x4, //!< Use VK_KHR_fragment_shading_rate
1330 TEST_OPTION_VARIABLE_SAMPLE_LOCATIONS_BIT = 0x8 //!< Use variable sample locations
1331 };
1332 typedef deUint32 TestOptionFlags;
1333
1334 struct TestParams
1335 {
1336 PipelineConstructionType pipelineConstructionType;
1337 VkSampleCountFlagBits numSamples;
1338 TestOptionFlags options;
1339 };
1340
checkSupportVerifyTests(Context& context, const TestParams params)1341 void checkSupportVerifyTests (Context& context, const TestParams params)
1342 {
1343 checkSupportSampleLocations(context);
1344
1345 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
1346
1347 if ((context.getDeviceProperties().limits.framebufferColorSampleCounts & params.numSamples) == 0u)
1348 TCU_THROW(NotSupportedError, "framebufferColorSampleCounts: sample count not supported");
1349
1350 if ((getSampleLocationsPropertiesEXT(context).sampleLocationSampleCounts & params.numSamples) == 0u)
1351 TCU_THROW(NotSupportedError, "VkPhysicalDeviceSampleLocationsPropertiesEXT: sample count not supported");
1352
1353 if (TEST_OPTION_FRAGMENT_SHADING_RATE_BIT & params.options)
1354 checkFragmentShadingRateRequirements(context, params.numSamples);
1355
1356 if (TEST_OPTION_VARIABLE_SAMPLE_LOCATIONS_BIT & params.options && !getSampleLocationsPropertiesEXT(context).variableSampleLocations)
1357 TCU_THROW(NotSupportedError, "VkPhysicalDeviceSampleLocationsPropertiesEXT: variableSampleLocations not supported");
1358
1359 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), params.pipelineConstructionType);
1360 }
1361
declareSampleDataSSBO(void)1362 std::string declareSampleDataSSBO (void)
1363 {
1364 std::ostringstream str;
1365 str << "layout(set = 0, binding = 0, std430) readonly buffer SampleData {\n" // make sure this matches SampleDataSSBO definition
1366 << " uvec2 renderSize;\n"
1367 << " uvec2 gridSize;\n"
1368 << " uint samplesPerPixel;\n"
1369 << " // padding 1-uint size;\n"
1370 << " vec2 data[];\n"
1371 << "} sb_data;\n";
1372 return str.str();
1373 }
1374
addProgramsVerifyLocationGeometry(SourceCollections& programCollection, const TestParams)1375 void addProgramsVerifyLocationGeometry (SourceCollections& programCollection, const TestParams)
1376 {
1377 // Vertex shader
1378 {
1379 std::ostringstream src;
1380 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1381 << "\n"
1382 << "layout(location = 0) in vec4 in_position;\n"
1383 << "\n"
1384 << "out gl_PerVertex {\n"
1385 << " vec4 gl_Position;\n"
1386 << "};\n"
1387 << "\n"
1388 << "void main(void)\n"
1389 << "{\n"
1390 << " gl_Position = in_position;\n"
1391 << "}\n";
1392
1393 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
1394 }
1395
1396 // Fragment shader
1397 {
1398 std::ostringstream src;
1399 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1400 << "\n"
1401 << "layout(location = 0) out vec4 o_color;\n"
1402 << "\n"
1403 << declareSampleDataSSBO()
1404 << "\n"
1405 << "void main(void)\n"
1406 << "{\n"
1407 << " uvec2 fragCoord = uvec2(gl_FragCoord.xy);\n"
1408 << " uint index = (fragCoord.y * sb_data.renderSize.x + fragCoord.x) * sb_data.samplesPerPixel + gl_SampleID;\n"
1409 << "\n"
1410 << " if (gl_PrimitiveID == index)\n"
1411 << " o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
1412 << " else\n"
1413 << " o_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
1414 << "}\n";
1415
1416 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
1417 }
1418 }
1419
addProgramsVerifyInterpolation(SourceCollections& programCollection, const TestParams)1420 void addProgramsVerifyInterpolation (SourceCollections& programCollection, const TestParams)
1421 {
1422 // Vertex shader
1423 {
1424 std::ostringstream src;
1425 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1426 << "\n"
1427 << "layout(location = 0) in vec4 in_position;\n"
1428 << "layout(location = 0) out vec2 o_position;\n"
1429 << "\n"
1430 << "out gl_PerVertex {\n"
1431 << " vec4 gl_Position;\n"
1432 << "};\n"
1433 << "\n"
1434 << "void main(void)\n"
1435 << "{\n"
1436 << " gl_Position = in_position;\n"
1437 << " o_position = in_position.xy;\n" // user-data that will be interpolated
1438 << "}\n";
1439
1440 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
1441 }
1442
1443 // Fragment shader
1444 {
1445 std::ostringstream src;
1446 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1447 << "\n"
1448 << "layout(location = 0) sample in vec2 in_value;\n"
1449 << "layout(location = 0) out vec4 o_color;\n"
1450 << "\n"
1451 << declareSampleDataSSBO()
1452 << "\n"
1453 << "void main(void)\n"
1454 << "{\n"
1455 << " uvec2 fragCoord = uvec2(gl_FragCoord.xy);\n"
1456 << " uint index = (fragCoord.y * sb_data.renderSize.x + fragCoord.x) * sb_data.samplesPerPixel + gl_SampleID;\n"
1457 << " vec2 diff = abs(sb_data.data[index] - in_value);\n"
1458 << " vec2 threshold = vec2(0.002);\n"
1459 << "\n"
1460 << " if (all(lessThan(diff, threshold)))\n"
1461 << " o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
1462 << " else\n"
1463 << " o_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
1464 << "}\n";
1465
1466 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
1467 }
1468 }
1469
1470 class TestBase : public TestInstance
1471 {
1472 public:
TestBase(Context& context, const TestParams params)1473 TestBase (Context& context, const TestParams params)
1474 : TestInstance (context)
1475 , m_params (params)
1476 , m_sampleLocationsProperties (getSampleLocationsPropertiesEXT(context))
1477 , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
1478 , m_numVertices (0)
1479 , m_currentGridNdx (0)
1480 {
1481 VkMultisamplePropertiesEXT multisampleProperties =
1482 {
1483 VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT, // VkStructureType sType;
1484 DE_NULL, // void* pNext;
1485 VkExtent2D(), // VkExtent2D maxSampleLocationGridSize;
1486 };
1487
1488 m_context.getInstanceInterface().getPhysicalDeviceMultisamplePropertiesEXT(m_context.getPhysicalDevice(), m_params.numSamples, &multisampleProperties);
1489
1490 // Generate grid size combinations
1491 for (deUint32 y = multisampleProperties.maxSampleLocationGridSize.height; y >= 1u; y >>= 1)
1492 for (deUint32 x = multisampleProperties.maxSampleLocationGridSize.width; x >= 1u; x >>= 1)
1493 {
1494 DE_ASSERT(multisampleProperties.maxSampleLocationGridSize.width % x == 0u);
1495 DE_ASSERT(multisampleProperties.maxSampleLocationGridSize.height % y == 0u);
1496 m_gridSizes.push_back(UVec2(x, y));
1497 }
1498 }
1499
iterate(void)1500 tcu::TestStatus iterate (void)
1501 {
1502 // Will be executed several times, for all possible pixel grid sizes
1503 if (!(currentGridSize().x() >= 1 && currentGridSize().y() >= 1))
1504 return tcu::TestStatus::fail("maxSampleLocationGridSize is invalid");
1505
1506 // Prepare the pixel grid
1507 {
1508 const deUint32 pixelGridRepetitions = 2; // just to make sure the pattern is consistently applied across the framebuffer
1509 m_renderSize = UVec2(pixelGridRepetitions * currentGridSize().x(),
1510 pixelGridRepetitions * currentGridSize().y());
1511 m_pixelGrid = MovePtr<MultisamplePixelGrid>(new MultisamplePixelGrid(currentGridSize(), m_params.numSamples));
1512
1513 if ((m_params.options & TEST_OPTION_CLOSELY_PACKED_BIT) != 0u)
1514 fillSampleLocationsPacked(*m_pixelGrid, m_sampleLocationsProperties.sampleLocationSubPixelBits);
1515 else
1516 fillSampleLocationsRandom(*m_pixelGrid, m_sampleLocationsProperties.sampleLocationSubPixelBits);
1517
1518 logPixelGrid (m_context.getTestContext().getLog(), m_sampleLocationsProperties, *m_pixelGrid);
1519 }
1520
1521 // Create images
1522 {
1523 const DeviceInterface& vk = m_context.getDeviceInterface();
1524 const VkDevice device = m_context.getDevice();
1525 Allocator& allocator = m_context.getDefaultAllocator();
1526
1527 // Images and staging buffers
1528
1529 m_colorImage = makeImage(vk, device, (VkImageCreateFlags)0, m_colorFormat, m_renderSize, m_params.numSamples, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
1530 m_colorImageAlloc = bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
1531 m_colorImageView = makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
1532
1533 m_resolveImage = makeImage(vk, device, (VkImageCreateFlags)0, m_colorFormat, m_renderSize, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1534 m_resolveImageAlloc = bindImage(vk, device, allocator, *m_resolveImage, MemoryRequirement::Any);
1535 m_resolveImageView = makeImageView(vk, device, *m_resolveImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
1536
1537 const VkDeviceSize colorBufferSize = m_renderSize.x() * m_renderSize.y() * tcu::getPixelSize(mapVkFormat(m_colorFormat));
1538 m_colorBuffer = makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
1539 m_colorBufferAlloc = bindBuffer(vk, device, allocator, *m_colorBuffer, MemoryRequirement::HostVisible);
1540 }
1541
1542 if (!testPixelGrid())
1543 return tcu::TestStatus::fail("Fail");
1544
1545 if (shrinkCurrentGrid())
1546 return tcu::TestStatus::incomplete();
1547 else
1548 return tcu::TestStatus::pass("Pass");
1549 }
1550
1551 protected:
1552 //! Return true if the test passed the current grid size
1553 virtual bool testPixelGrid (void) = 0;
1554
currentGridSize(void)1555 const UVec2& currentGridSize (void)
1556 {
1557 return m_gridSizes[m_currentGridNdx];
1558 }
1559
1560 //! Return false if the grid is already at (1, 1) size
shrinkCurrentGrid(void)1561 bool shrinkCurrentGrid (void)
1562 {
1563 if (m_gridSizes.size() <= m_currentGridNdx + 1)
1564 return false;
1565
1566 ++m_currentGridNdx;
1567 return true;
1568 }
1569
drawSinglePass(const VertexInputConfig vertexInputConfig)1570 void drawSinglePass (const VertexInputConfig vertexInputConfig)
1571 {
1572 DE_ASSERT(m_descriptorSetLayout);
1573
1574 const InstanceInterface& vki = m_context.getInstanceInterface();
1575 const DeviceInterface& vk = m_context.getDeviceInterface();
1576 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
1577 const VkDevice device = m_context.getDevice();
1578 const VkViewport viewport = makeViewport(m_renderSize);
1579 const VkRect2D renderArea = makeRect2D(m_renderSize);
1580 const VkRect2D scissor = makeRect2D(m_renderSize);
1581 const ShaderWrapper vertexModule (ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
1582 const ShaderWrapper fragmentModule (ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
1583 const PipelineLayoutWrapper pipelineLayout (m_params.pipelineConstructionType, vk, device, *m_descriptorSetLayout);
1584
1585 const bool useDynamicStateSampleLocations = ((m_params.options & TEST_OPTION_DYNAMIC_STATE_BIT) != 0u);
1586 const bool useFragmentShadingRate = ((m_params.options & TEST_OPTION_FRAGMENT_SHADING_RATE_BIT) != 0u);
1587 const VkSampleLocationsInfoEXT sampleLocationsInfo = makeSampleLocationsInfo(*m_pixelGrid);
1588
1589 RenderTarget rt;
1590
1591 rt.addAttachment(
1592 *m_colorImage, // VkImage image,
1593 *m_colorImageView, // VkImageView imageView,
1594 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
1595 m_colorFormat, // VkFormat format,
1596 m_params.numSamples, // VkSampleCountFlagBits numSamples,
1597 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
1598 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
1599 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
1600 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
1601 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
1602 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
1603 makeClearValueColor(CLEAR_COLOR_0)); // VkClearValue clearValue,
1604
1605 rt.addAttachment(
1606 *m_resolveImage, // VkImage image
1607 *m_resolveImageView, // VkImageView imageView,
1608 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
1609 m_colorFormat, // VkFormat format,
1610 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits numSamples,
1611 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp,
1612 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
1613 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
1614 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
1615 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
1616 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout finalLayout,
1617 VkClearValue()); // VkClearValue clearValue,
1618
1619 if (TEST_OPTION_VARIABLE_SAMPLE_LOCATIONS_BIT & m_params.options)
1620 {
1621 rt.addSubpassColorAttachmentWithResolve(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1622 1u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, &sampleLocationsInfo);
1623 }
1624 else
1625 {
1626 rt.addSubpassColorAttachmentWithResolve(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1627 1u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
1628 }
1629
1630 rt.bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
1631
1632 GraphicsPipelineWrapper pipeline(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
1633
1634 if (useDynamicStateSampleLocations)
1635 {
1636 std::vector<VkDynamicState> dynamicState;
1637 dynamicState.push_back(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
1638
1639 preparePipelineWrapperSinglePassColor(
1640 pipeline, dynamicState, pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule, viewport, scissor,
1641 m_params.numSamples, /*use sample locations*/ true, makeEmptySampleLocationsInfo(), vertexInputConfig, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, useFragmentShadingRate);
1642 }
1643 else
1644 {
1645 preparePipelineWrapperSinglePassColor(
1646 pipeline, std::vector<VkDynamicState>(), pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule, viewport, scissor,
1647 m_params.numSamples, /*use sample locations*/ true, sampleLocationsInfo, vertexInputConfig, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, useFragmentShadingRate);
1648 }
1649
1650 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
1651 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
1652
1653 beginCommandBuffer(vk, *cmdBuffer);
1654
1655 rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
1656
1657 vk.cmdBindVertexBuffers(*cmdBuffer, /*first binding*/ 0u, /*num bindings*/ 1u, &m_vertexBuffer.get(), /*offsets*/ &ZERO);
1658 pipeline.bind(*cmdBuffer);
1659
1660 if (useDynamicStateSampleLocations)
1661 vk.cmdSetSampleLocationsEXT(*cmdBuffer, &sampleLocationsInfo);
1662
1663 if (m_descriptorSet)
1664 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &m_descriptorSet.get(), 0u, DE_NULL);
1665
1666 vk.cmdDraw(*cmdBuffer, m_numVertices, 1u, 0u, 0u);
1667 rt.endRenderPass(vk, *cmdBuffer);
1668
1669 recordCopyImageToBuffer(vk, *cmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
1670
1671 endCommandBuffer(vk, *cmdBuffer);
1672 submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
1673
1674 invalidateAlloc(vk, device, *m_colorBufferAlloc);
1675 }
1676
createSampleDataBufferAndDescriptors(const VkDeviceSize bufferSize)1677 void createSampleDataBufferAndDescriptors (const VkDeviceSize bufferSize)
1678 {
1679 // Make sure the old descriptor set is destroyed before we destroy its pool
1680 m_descriptorSet = Move<VkDescriptorSet>();
1681
1682 const DeviceInterface& vk = m_context.getDeviceInterface();
1683 const VkDevice device = m_context.getDevice();
1684 Allocator& allocator = m_context.getDefaultAllocator();
1685
1686 m_sampleDataBuffer = makeBuffer(vk, device, bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1687 m_sampleDataBufferAlloc = bindBuffer(vk, device, allocator, *m_sampleDataBuffer, MemoryRequirement::HostVisible);
1688
1689 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
1690 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT)
1691 .build(vk, device);
1692
1693 m_descriptorPool = DescriptorPoolBuilder()
1694 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
1695 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1696
1697 m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
1698
1699 const VkDescriptorBufferInfo bufferDescriptorInfo = makeDescriptorBufferInfo(*m_sampleDataBuffer, 0ull, bufferSize);
1700 DescriptorSetUpdateBuilder()
1701 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferDescriptorInfo)
1702 .update(vk, device);
1703
1704 SampleDataSSBO::renderSize (m_sampleDataBufferAlloc->getHostPtr()) = m_renderSize;
1705 SampleDataSSBO::gridSize (m_sampleDataBufferAlloc->getHostPtr()) = m_pixelGrid->size();
1706 SampleDataSSBO::samplesPerPixel (m_sampleDataBufferAlloc->getHostPtr()) = m_pixelGrid->samplesPerPixel();
1707
1708 flushAlloc(vk, device, *m_sampleDataBufferAlloc);
1709 }
1710
1711 template<typename Vertex>
createVertexBuffer(const std::vector<Vertex>& vertices)1712 void createVertexBuffer (const std::vector<Vertex>& vertices)
1713 {
1714 const DeviceInterface& vk = m_context.getDeviceInterface();
1715 const VkDevice device = m_context.getDevice();
1716 Allocator& allocator = m_context.getDefaultAllocator();
1717 const VkDeviceSize vertexBufferSize = static_cast<VkDeviceSize>(vertices.size() * sizeof(vertices[0]));
1718
1719 m_numVertices = static_cast<deUint32>(vertices.size());
1720 m_vertexBuffer = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1721 m_vertexBufferAlloc = bindBuffer(vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
1722
1723 deMemcpy(m_vertexBufferAlloc->getHostPtr(), dataOrNullPtr(vertices), static_cast<std::size_t>(vertexBufferSize));
1724 flushAlloc(vk, device, *m_vertexBufferAlloc);
1725 }
1726
1727 const TestParams m_params;
1728 const VkPhysicalDeviceSampleLocationsPropertiesEXT m_sampleLocationsProperties;
1729 const VkFormat m_colorFormat;
1730 UVec2 m_renderSize;
1731 MovePtr<MultisamplePixelGrid> m_pixelGrid;
1732 deUint32 m_numVertices;
1733 Move<VkBuffer> m_vertexBuffer;
1734 MovePtr<Allocation> m_vertexBufferAlloc;
1735 Move<VkImage> m_colorImage;
1736 Move<VkImageView> m_colorImageView;
1737 MovePtr<Allocation> m_colorImageAlloc;
1738 Move<VkImage> m_resolveImage;
1739 Move<VkImageView> m_resolveImageView;
1740 MovePtr<Allocation> m_resolveImageAlloc;
1741 Move<VkBuffer> m_colorBuffer;
1742 MovePtr<Allocation> m_colorBufferAlloc;
1743 Move<VkBuffer> m_sampleDataBuffer;
1744 MovePtr<Allocation> m_sampleDataBufferAlloc;
1745 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
1746 Move<VkDescriptorPool> m_descriptorPool;
1747 Move<VkDescriptorSet> m_descriptorSet;
1748
1749 private:
1750 deUint32 m_currentGridNdx;
1751 std::vector<UVec2> m_gridSizes;
1752 };
1753
1754 //! Check that each custom sample has the expected position
1755 class VerifyLocationTest : public TestBase
1756 {
1757 public:
VerifyLocationTest(Context& context, const TestParams params)1758 VerifyLocationTest (Context& context, const TestParams params) : TestBase(context, params) {}
1759
testPixelGrid(void)1760 bool testPixelGrid (void)
1761 {
1762 // Create vertices
1763 {
1764 // For each sample location (in the whole framebuffer), create a sub-pixel triangle that contains it.
1765 // NDC viewport size is 2.0 in X and Y and NDC pixel width/height depends on the framebuffer resolution.
1766 const Vec2 pixelSize = Vec2(2.0f) / m_renderSize.cast<float>();
1767 const Vec2 offset = pixelSize / UVec2(1u << m_sampleLocationsProperties.sampleLocationSubPixelBits).cast<float>();
1768 std::vector<Vec4> vertices;
1769
1770 // Surround with a roughly centered triangle
1771 const float y1 = 0.5f * offset.y();
1772 const float y2 = 0.35f * offset.y();
1773 const float x1 = 0.5f * offset.x();
1774
1775 const std::vector<Vec2> locations = genFramebufferSampleLocations(*m_pixelGrid, m_pixelGrid->size(), m_renderSize);
1776 for (std::vector<Vec2>::const_iterator iter = locations.begin(); iter != locations.end(); ++iter)
1777 {
1778 vertices.push_back(Vec4(iter->x(), iter->y() - y1, 0.0f, 1.0f));
1779 vertices.push_back(Vec4(iter->x() - x1, iter->y() + y2, 0.0f, 1.0f));
1780 vertices.push_back(Vec4(iter->x() + x1, iter->y() + y2, 0.0f, 1.0f));
1781 }
1782
1783 createVertexBuffer(vertices);
1784 }
1785
1786 createSampleDataBufferAndDescriptors(SampleDataSSBO::STATIC_SIZE); // no per-sample data used
1787
1788 drawSinglePass(VERTEX_INPUT_VEC4); // sample locations are taken from the pixel grid
1789
1790 // Verify
1791
1792 const tcu::ConstPixelBufferAccess image (tcu::ConstPixelBufferAccess(mapVkFormat(m_colorFormat), tcu::IVec3(m_renderSize.x(), m_renderSize.y(), 1), m_colorBufferAlloc->getHostPtr()));
1793
1794 return compareGreenImage(m_context.getTestContext().getLog(), "resolve0", "Resolved test image", image);
1795 }
1796 };
1797
1798 //! Verify that vertex attributes are correctly interpolated at each custom sample location
1799 class VerifyInterpolationTest : public TestBase
1800 {
1801 public:
VerifyInterpolationTest(Context& context, const TestParams params)1802 VerifyInterpolationTest (Context& context, const TestParams params) : TestBase(context, params) {}
1803
testPixelGrid(void)1804 bool testPixelGrid (void)
1805 {
1806 createVertexBuffer(genVerticesFullQuad());
1807
1808 // Create sample data SSBO
1809 {
1810 const deUint32 numSamples = m_pixelGrid->samplesPerPixel();
1811 const deUint32 numDataEntries = numSamples * m_renderSize.x() * m_renderSize.y();
1812 const VkDeviceSize bufferSize = SampleDataSSBO::STATIC_SIZE + sizeof(Vec2) * numDataEntries;
1813
1814 createSampleDataBufferAndDescriptors(bufferSize);
1815
1816 Vec2* const pSampleData = SampleDataSSBO::sampleData<Vec2>(m_sampleDataBufferAlloc->getHostPtr());
1817 const std::vector<Vec2> locations = genFramebufferSampleLocations(*m_pixelGrid, m_pixelGrid->size(), m_renderSize);
1818
1819 // Fill SSBO with interpolated values (here: from -1.0 to 1.0 across the render area in both x and y)
1820 DE_ASSERT(locations.size() == numDataEntries);
1821 std::copy(locations.begin(), locations.end(), pSampleData);
1822
1823 flushAlloc(m_context.getDeviceInterface(), m_context.getDevice(), *m_sampleDataBufferAlloc);
1824 }
1825
1826 drawSinglePass(VERTEX_INPUT_VEC4_VEC4); // sample locations are taken from the pixel grid
1827
1828 // Verify
1829
1830 const tcu::ConstPixelBufferAccess image (tcu::ConstPixelBufferAccess(mapVkFormat(m_colorFormat), tcu::IVec3(m_renderSize.x(), m_renderSize.y(), 1), m_colorBufferAlloc->getHostPtr()));
1831
1832 return compareGreenImage(m_context.getTestContext().getLog(), "resolve0", "Resolved test image", image);
1833 }
1834 };
1835
1836 template<typename Test, typename ProgramsFunc>
addCases(tcu::TestCaseGroup* group, const VkSampleCountFlagBits numSamples, PipelineConstructionType pipelineConstructionType, bool useFragmentShadingRate, const ProgramsFunc initPrograms)1837 void addCases (tcu::TestCaseGroup* group, const VkSampleCountFlagBits numSamples, PipelineConstructionType pipelineConstructionType, bool useFragmentShadingRate, const ProgramsFunc initPrograms)
1838 {
1839 TestParams params;
1840 deMemset(¶ms, 0, sizeof(params));
1841
1842 params.pipelineConstructionType = pipelineConstructionType;
1843 params.numSamples = numSamples;
1844
1845 struct TestOptions
1846 {
1847 std::string testSuffix;
1848 TestOptionFlags testFlags;
1849
1850 };
1851
1852 TestOptions testOpts[] =
1853 {
1854 { "", useFragmentShadingRate ? (TestOptionFlags)TEST_OPTION_FRAGMENT_SHADING_RATE_BIT : (TestOptionFlags)0 | (TestOptionFlags)TEST_OPTION_VARIABLE_SAMPLE_LOCATIONS_BIT },
1855 { "_invariable", useFragmentShadingRate ? (TestOptionFlags)TEST_OPTION_FRAGMENT_SHADING_RATE_BIT : (TestOptionFlags)0 }
1856 };
1857
1858 for (const auto &options : testOpts)
1859 {
1860 params.options = options.testFlags;
1861
1862 addInstanceTestCaseWithPrograms<Test>(group, (getString(numSamples) + options.testSuffix).c_str(), checkSupportVerifyTests, initPrograms, params);
1863
1864 params.options |= (TestOptionFlags)TEST_OPTION_DYNAMIC_STATE_BIT;
1865 addInstanceTestCaseWithPrograms<Test>(group, (getString(numSamples) + "_dynamic" + options.testSuffix).c_str(), checkSupportVerifyTests, initPrograms, params);
1866
1867 params.options |= (TestOptionFlags)TEST_OPTION_CLOSELY_PACKED_BIT;
1868 addInstanceTestCaseWithPrograms<Test>(group, (getString(numSamples) + "_packed" + options.testSuffix).c_str(), checkSupportVerifyTests, initPrograms, params);
1869 }
1870 }
1871
1872 } // VerifySamples
1873
1874 // Draw tests with at least two "passes" where sample locations may change.
1875 // Test case is based on a combination of parameters defined below. Not all combinations are compatible.
1876 namespace Draw
1877 {
1878
1879 //! Options common to all test cases
1880 enum TestOptionFlagBits
1881 {
1882 TEST_OPTION_SAME_PATTERN_BIT = 1u << 0, //!< Use the same sample pattern for all operations
1883 TEST_OPTION_DYNAMIC_STATE_BIT = 1u << 1, //!< Use dynamic pipeline state to pass in sample locations
1884 TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT = 1u << 2, //!< Put drawing commands in a secondary buffer, including sample locations change (if dynamic)
1885 TEST_OPTION_GENERAL_LAYOUT_BIT = 1u << 3, //!< Transition the image to general layout at some point in rendering
1886 TEST_OPTION_WAIT_EVENTS_BIT = 1u << 4, //!< Use image memory barriers with vkCmdWaitEvents rather than vkCmdPipelineBarrier
1887 TEST_OPTION_FRAGMENT_SHADING_RATE_BIT = 1u << 5, //!< Use VK_KHR_fragment_shading_rate
1888 };
1889 typedef deUint32 TestOptionFlags;
1890
1891 //! Determines where draws/clears with custom samples occur in the test
1892 enum TestDrawIn
1893 {
1894 TEST_DRAW_IN_RENDER_PASSES = 0u, //!< Each operation in a separate render pass
1895 TEST_DRAW_IN_SUBPASSES, //!< Each operation in a separate subpass of the same render pass
1896 TEST_DRAW_IN_SAME_SUBPASS, //!< Each operation in the same subpass
1897 };
1898
1899 //! How a clear before the second pass will be done
1900 enum TestClears
1901 {
1902 TEST_CLEARS_NO_CLEAR = 0u, //!< Don't clear
1903 TEST_CLEARS_LOAD_OP_CLEAR, //!< Render pass attachment load clear
1904 TEST_CLEARS_CMD_CLEAR_ATTACHMENTS, //!< vkCmdClearAttachments within a subpass
1905 TEST_CLEARS_CMD_CLEAR_IMAGE, //!< vkCmdClear{Color|DepthStencil}Image outside a render pass
1906 };
1907
1908 //! What type of image will be verified with custom samples
1909 enum TestImageAspect
1910 {
1911 TEST_IMAGE_ASPECT_COLOR = 0u, //!< Color image
1912 TEST_IMAGE_ASPECT_DEPTH, //!< Depth aspect of an image (can be mixed format)
1913 TEST_IMAGE_ASPECT_STENCIL, //!< Stencil aspect of an image (can be mixed format)
1914 };
1915
1916 struct TestParams
1917 {
1918 PipelineConstructionType pipelineConstructionType;
1919 VkSampleCountFlagBits numSamples;
1920 TestOptionFlags options;
1921 TestDrawIn drawIn;
1922 TestClears clears;
1923 TestImageAspect imageAspect;
1924 };
1925
checkSupportDrawTests(Context& context, const TestParams params)1926 void checkSupportDrawTests (Context& context, const TestParams params)
1927 {
1928 checkSupportSampleLocations(context);
1929
1930 if ((context.getDeviceProperties().limits.framebufferColorSampleCounts & params.numSamples) == 0u)
1931 TCU_THROW(NotSupportedError, "framebufferColorSampleCounts: sample count not supported");
1932
1933 if ((getSampleLocationsPropertiesEXT(context).sampleLocationSampleCounts & params.numSamples) == 0u)
1934 TCU_THROW(NotSupportedError, "VkPhysicalDeviceSampleLocationsPropertiesEXT: sample count not supported");
1935
1936 // Are we allowed to modify the sample pattern within the same subpass?
1937 if (params.drawIn == TEST_DRAW_IN_SAME_SUBPASS && ((params.options & TEST_OPTION_SAME_PATTERN_BIT) == 0) && !getSampleLocationsPropertiesEXT(context).variableSampleLocations)
1938 TCU_THROW(NotSupportedError, "VkPhysicalDeviceSampleLocationsPropertiesEXT: variableSampleLocations not supported");
1939
1940 if (TEST_OPTION_FRAGMENT_SHADING_RATE_BIT & params.options)
1941 checkFragmentShadingRateRequirements(context, params.numSamples);
1942
1943 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), params.pipelineConstructionType);
1944
1945 #ifndef CTS_USES_VULKANSC
1946 if (TEST_OPTION_WAIT_EVENTS_BIT & params.options &&
1947 context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") && !context.getPortabilitySubsetFeatures().events)
1948 {
1949 TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Events are not supported by this implementation");
1950 }
1951 #endif // CTS_USES_VULKANSC
1952 }
1953
getString(const TestImageAspect aspect)1954 const char* getString (const TestImageAspect aspect)
1955 {
1956 switch (aspect)
1957 {
1958 case TEST_IMAGE_ASPECT_COLOR: return "color";
1959 case TEST_IMAGE_ASPECT_DEPTH: return "depth";
1960 case TEST_IMAGE_ASPECT_STENCIL: return "stencil";
1961 }
1962 DE_ASSERT(0);
1963 return DE_NULL;
1964 }
1965
getString(const TestDrawIn drawIn)1966 const char* getString (const TestDrawIn drawIn)
1967 {
1968 switch (drawIn)
1969 {
1970 case TEST_DRAW_IN_RENDER_PASSES: return "separate_renderpass";
1971 case TEST_DRAW_IN_SUBPASSES: return "separate_subpass";
1972 case TEST_DRAW_IN_SAME_SUBPASS: return "same_subpass";
1973 }
1974 DE_ASSERT(0);
1975 return DE_NULL;
1976 }
1977
getString(const TestClears clears)1978 const char* getString (const TestClears clears)
1979 {
1980 switch (clears)
1981 {
1982 case TEST_CLEARS_NO_CLEAR: return "no_clear";
1983 case TEST_CLEARS_LOAD_OP_CLEAR: return "load_op_clear";
1984 case TEST_CLEARS_CMD_CLEAR_ATTACHMENTS: return "clear_attachments";
1985 case TEST_CLEARS_CMD_CLEAR_IMAGE: return "clear_image";
1986 }
1987 DE_ASSERT(0);
1988 return DE_NULL;
1989 }
1990
getTestOptionFlagsString(const deUint32 flags)1991 std::string getTestOptionFlagsString (const deUint32 flags)
1992 {
1993 std::ostringstream str;
1994
1995 if ((flags & TEST_OPTION_SAME_PATTERN_BIT) != 0) str << (str.tellp() > 0 ? "_" : "") << "same_pattern";
1996 if ((flags & TEST_OPTION_DYNAMIC_STATE_BIT) != 0) str << (str.tellp() > 0 ? "_" : "") << "dynamic";
1997 if ((flags & TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT) != 0) str << (str.tellp() > 0 ? "_" : "") << "secondary_cmd_buf";
1998 if ((flags & TEST_OPTION_GENERAL_LAYOUT_BIT) != 0) str << (str.tellp() > 0 ? "_" : "") << "general_layout";
1999 if ((flags & TEST_OPTION_WAIT_EVENTS_BIT) != 0) str << (str.tellp() > 0 ? "_" : "") << "event";
2000
2001 return str.str();
2002 }
2003
initPrograms(SourceCollections& programCollection, const TestParams)2004 void initPrograms (SourceCollections& programCollection, const TestParams)
2005 {
2006 // Vertex shader
2007 {
2008 std::ostringstream src;
2009 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
2010 << "\n"
2011 << "layout(location = 0) in vec4 in_position;\n"
2012 << "layout(location = 1) in vec4 in_color;\n"
2013 << "layout(location = 0) out vec4 o_color;\n"
2014 << "\n"
2015 << "out gl_PerVertex {\n"
2016 << " vec4 gl_Position;\n"
2017 << "};\n"
2018 << "\n"
2019 << "void main(void)\n"
2020 << "{\n"
2021 << " gl_Position = in_position;\n"
2022 << " o_color = in_color;\n"
2023 << "\n"
2024 // We use instance index to draw the left shape (index = 0) or the right shape (index = 1).
2025 // Vertices are squished and moved to either half of the viewport.
2026 << " if (gl_InstanceIndex == 0)\n"
2027 << " gl_Position.x = 0.5 * (gl_Position.x - 1.0);\n"
2028 << " else if (gl_InstanceIndex == 1)\n"
2029 << " gl_Position.x = 0.5 * (gl_Position.x + 1.0);\n"
2030 << "}\n";
2031
2032 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
2033 }
2034
2035 // Fragment shader
2036 {
2037 std::ostringstream src;
2038 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
2039 << "\n"
2040 << "layout(location = 0) in vec4 in_color;\n"
2041 << "layout(location = 0) out vec4 o_color;\n"
2042 << "\n"
2043 << "void main(void)\n"
2044 << "{\n"
2045 << " o_color = in_color;\n"
2046 << "}\n";
2047
2048 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
2049 }
2050 }
2051
2052 //! Draw shapes using changing sample patterns. Add clears and other operations as necessary
2053 class DrawTest : public TestInstance
2054 {
2055 static const deUint32 NUM_PASSES = 2u;
2056
2057 public:
DrawTest(Context& context, const TestParams params)2058 DrawTest (Context& context, const TestParams params)
2059 : TestInstance (context)
2060 , m_params (params)
2061 , m_sampleLocationsProperties (getSampleLocationsPropertiesEXT(context))
2062 , m_renderSize (64, 32)
2063 , m_numVertices (0)
2064 , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
2065 , m_depthStencilFormat (VK_FORMAT_UNDEFINED)
2066 , m_depthStencilAspect (0)
2067 {
2068 VkMultisamplePropertiesEXT multisampleProperties =
2069 {
2070 VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT, // VkStructureType sType;
2071 DE_NULL, // void* pNext;
2072 VkExtent2D(), // VkExtent2D maxSampleLocationGridSize;
2073 };
2074
2075 // For this test always use the full pixel grid
2076
2077 m_context.getInstanceInterface().getPhysicalDeviceMultisamplePropertiesEXT(m_context.getPhysicalDevice(), m_params.numSamples, &multisampleProperties);
2078 m_gridSize.x() = multisampleProperties.maxSampleLocationGridSize.width;
2079 m_gridSize.y() = multisampleProperties.maxSampleLocationGridSize.height;
2080 }
2081
iterate(void)2082 tcu::TestStatus iterate (void)
2083 {
2084 // Requirements
2085 if (!(m_gridSize.x() >= 1 && m_gridSize.y() >= 1))
2086 return tcu::TestStatus::fail("maxSampleLocationGridSize is invalid");
2087
2088 // Images
2089 {
2090 const DeviceInterface& vk = m_context.getDeviceInterface();
2091 const VkDevice device = m_context.getDevice();
2092 Allocator& allocator = m_context.getDefaultAllocator();
2093 const VkImageUsageFlags colorImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2094
2095 m_colorImage = makeImage(vk, device, (VkImageCreateFlags)0, m_colorFormat, m_renderSize, m_params.numSamples, colorImageUsageFlags);
2096 m_colorImageAlloc = bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
2097 m_colorImageView = makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat,
2098 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
2099
2100 m_resolveImage = makeImage(vk, device, (VkImageCreateFlags)0, m_colorFormat, m_renderSize, VK_SAMPLE_COUNT_1_BIT, colorImageUsageFlags);
2101 m_resolveImageAlloc = bindImage(vk, device, allocator, *m_resolveImage, MemoryRequirement::Any);
2102 m_resolveImageView = makeImageView(vk, device, *m_resolveImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat,
2103 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
2104
2105 const VkDeviceSize colorBufferSize = m_renderSize.x() * m_renderSize.y() * tcu::getPixelSize(mapVkFormat(m_colorFormat));
2106 m_colorBuffer = makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
2107 m_colorBufferAlloc = bindBuffer(vk, device, allocator, *m_colorBuffer, MemoryRequirement::HostVisible);
2108
2109 if (m_params.imageAspect != TEST_IMAGE_ASPECT_COLOR)
2110 {
2111 const VkImageUsageFlags depthStencilImageUsageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2112
2113 m_depthStencilFormat = findSupportedDepthStencilFormat(m_context, useDepth(), useStencil());
2114 m_depthStencilAspect = (useDepth() ? VK_IMAGE_ASPECT_DEPTH_BIT : (VkImageAspectFlagBits)0) |
2115 (useStencil() ? VK_IMAGE_ASPECT_STENCIL_BIT : (VkImageAspectFlagBits)0);
2116 m_depthStencilImage = makeImage(vk, device, VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT,
2117 m_depthStencilFormat, m_renderSize, m_params.numSamples, depthStencilImageUsageFlags);
2118 m_depthStencilImageAlloc = bindImage(vk, device, allocator, *m_depthStencilImage, MemoryRequirement::Any);
2119 m_depthStencilImageView = makeImageView(vk, device, *m_depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, m_depthStencilFormat,
2120 makeImageSubresourceRange(m_depthStencilAspect, 0u, 1u, 0u, 1u));
2121 }
2122 }
2123
2124 // Vertices
2125 {
2126 const DeviceInterface& vk = m_context.getDeviceInterface();
2127 const VkDevice device = m_context.getDevice();
2128 Allocator& allocator = m_context.getDefaultAllocator();
2129
2130 std::vector<PositionColor> vertices;
2131
2132 if (useDepth())
2133 {
2134 append(vertices, genVerticesShapes (RGBA::black().toVec(), DEPTH_REFERENCE / 2.0f)); // mask above (z = 0.0 is nearest)
2135 append(vertices, genVerticesFullQuad(RGBA::white().toVec(), DEPTH_REFERENCE)); // fill below the mask, using the depth test
2136 }
2137 else if (useStencil())
2138 {
2139 append(vertices, genVerticesShapes (RGBA::black().toVec(), DEPTH_REFERENCE)); // first mask
2140 append(vertices, genVerticesFullQuad(RGBA::white().toVec(), DEPTH_REFERENCE / 2.0f)); // then fill the whole area, using the stencil test
2141 }
2142 else
2143 vertices = genVerticesShapes();
2144
2145 const VkDeviceSize vertexBufferSize = static_cast<VkDeviceSize>(vertices.size() * sizeof(vertices[0]));
2146
2147 m_numVertices = static_cast<deUint32>(vertices.size());
2148 m_vertexBuffer = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
2149 m_vertexBufferAlloc = bindBuffer(vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
2150
2151 deMemcpy(m_vertexBufferAlloc->getHostPtr(), dataOrNullPtr(vertices), static_cast<std::size_t>(vertexBufferSize));
2152 flushAlloc(vk, device, *m_vertexBufferAlloc);
2153 }
2154
2155 // Multisample pixel grids - set up two sample patterns for two draw passes
2156 {
2157 const deUint32 numGrids = (useSameSamplePattern() ? 1u : NUM_PASSES);
2158 m_pixelGrids.reserve(numGrids);
2159
2160 for (deUint32 passNdx = 0u; passNdx < numGrids; ++passNdx)
2161 {
2162 const deUint32 seed = 142u + 75u * passNdx;
2163 m_pixelGrids.push_back(MultisamplePixelGrid(m_gridSize, m_params.numSamples));
2164 fillSampleLocationsRandom(m_pixelGrids.back(), m_sampleLocationsProperties.sampleLocationSubPixelBits, seed);
2165 logPixelGrid (m_context.getTestContext().getLog(), m_sampleLocationsProperties, m_pixelGrids.back());
2166 }
2167 }
2168
2169 // Some test cases will not clear the left hand image, so we can use it directly
2170 const bool isClearCase = (m_params.clears != TEST_CLEARS_NO_CLEAR);
2171 const bool hasLeftSideImage = (!isClearCase ||
2172 (m_params.drawIn != TEST_DRAW_IN_RENDER_PASSES && m_params.clears != TEST_CLEARS_CMD_CLEAR_ATTACHMENTS));
2173
2174 // Render second pass reference image with the first pattern
2175 tcu::TextureLevel refImagePattern0;
2176 if (!useSameSamplePattern() && !hasLeftSideImage)
2177 {
2178 const tcu::TextureFormat colorFormat = mapVkFormat(m_colorFormat);
2179
2180 drawPatternChangeReference();
2181
2182 refImagePattern0.setStorage(colorFormat, m_renderSize.x(), m_renderSize.y());
2183 tcu::copy(refImagePattern0.getAccess(), tcu::ConstPixelBufferAccess(colorFormat, tcu::IVec3(m_renderSize.x(), m_renderSize.y(), 1), m_colorBufferAlloc->getHostPtr()));
2184 }
2185
2186 // Two-pass rendering
2187
2188 switch (m_params.drawIn)
2189 {
2190 case TEST_DRAW_IN_RENDER_PASSES: drawRenderPasses(); break;
2191 case TEST_DRAW_IN_SUBPASSES: drawSubpasses(); break;
2192 case TEST_DRAW_IN_SAME_SUBPASS: drawSameSubpass(); break;
2193
2194 default:
2195 DE_ASSERT(0);
2196 break;
2197 }
2198
2199 // Log the result
2200
2201 const tcu::ConstPixelBufferAccess image (tcu::ConstPixelBufferAccess(mapVkFormat(m_colorFormat), tcu::IVec3(m_renderSize.x(), m_renderSize.y(), 1), m_colorBufferAlloc->getHostPtr()));
2202
2203 m_context.getTestContext().getLog()
2204 << tcu::TestLog::ImageSet("Result", "Final result")
2205 << tcu::TestLog::Image("resolve0", "resolve0", image)
2206 << tcu::TestLog::EndImageSet;
2207
2208 // Verify result
2209 {
2210 DE_ASSERT((m_renderSize.x() % 2) == 0);
2211 DE_ASSERT((m_renderSize.y() % 2) == 0);
2212
2213 // Count colors in each image half separately, each half may have its own background color
2214 const int numBackgroundColors = 1;
2215 const int numExpectedColorsRight = numBackgroundColors + static_cast<int>(m_params.numSamples);
2216 const int numExpectedColorsLeft = (isClearCase ? numBackgroundColors : numExpectedColorsRight);
2217 const int numActualColorsLeft = countUniqueColors(tcu::getSubregion(image, 0, 0, m_renderSize.x()/2, m_renderSize.y()));
2218 const int numActualColorsRight = countUniqueColors(tcu::getSubregion(image, m_renderSize.x()/2, 0, m_renderSize.x()/2, m_renderSize.y()));
2219
2220 if (numActualColorsLeft != numExpectedColorsLeft || numActualColorsRight != numExpectedColorsRight)
2221 {
2222 std::ostringstream msg;
2223 msg << "Expected " << numExpectedColorsLeft << " unique colors, but got " << numActualColorsLeft;
2224
2225 if (numActualColorsLeft != numActualColorsRight)
2226 msg << " and " << numActualColorsRight;
2227
2228 m_context.getTestContext().getLog()
2229 << tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
2230
2231 return tcu::TestStatus::fail("Resolved image has incorrect pixels");
2232 }
2233
2234 if (hasLeftSideImage)
2235 {
2236 // Compare the left and the right half
2237 const bool match = intThresholdCompare(tcu::getSubregion(image, 0, 0, m_renderSize.x()/2, m_renderSize.y()),
2238 tcu::getSubregion(image, m_renderSize.x()/2, 0, m_renderSize.x()/2, m_renderSize.y()),
2239 UVec4(2u));
2240 if (useSameSamplePattern() && !match)
2241 return tcu::TestStatus::fail("Multisample pattern should be identical in both image halves");
2242 else if (!useSameSamplePattern() && match)
2243 return tcu::TestStatus::fail("Multisample pattern doesn't seem to change between left and right image halves");
2244 }
2245 else if (!useSameSamplePattern())
2246 {
2247 // Compare the right half with the previously rendered reference image -- patterns should be different
2248 bool match = intThresholdCompare(tcu::getSubregion(refImagePattern0.getAccess(), m_renderSize.x()/2, 0, m_renderSize.x()/2, m_renderSize.y()),
2249 tcu::getSubregion(image, m_renderSize.x()/2, 0, m_renderSize.x()/2, m_renderSize.y()),
2250 UVec4(2u));
2251
2252 if (match)
2253 return tcu::TestStatus::fail("Multisample pattern doesn't seem to change between passes");
2254 }
2255 }
2256
2257 return tcu::TestStatus::pass("Pass");
2258 }
2259
2260 protected:
useDepth(void) const2261 bool useDepth (void) const { return m_params.imageAspect == TEST_IMAGE_ASPECT_DEPTH; }
useStencil(void) const2262 bool useStencil (void) const { return m_params.imageAspect == TEST_IMAGE_ASPECT_STENCIL; }
useSameSamplePattern(void) const2263 bool useSameSamplePattern (void) const { return (m_params.options & TEST_OPTION_SAME_PATTERN_BIT) != 0u; }
useDynamicState(void) const2264 bool useDynamicState (void) const { return (m_params.options & TEST_OPTION_DYNAMIC_STATE_BIT) != 0u; }
useSecondaryCmdBuffer(void) const2265 bool useSecondaryCmdBuffer (void) const { return (m_params.options & TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT) != 0u; }
useGeneralLayout(void) const2266 bool useGeneralLayout (void) const { return (m_params.options & TEST_OPTION_GENERAL_LAYOUT_BIT) != 0u; }
useWaitEvents(void) const2267 bool useWaitEvents (void) const { return (m_params.options & TEST_OPTION_WAIT_EVENTS_BIT) != 0u; }
useFragmentShadingRate(void) const2268 bool useFragmentShadingRate (void) const { return (m_params.options & TEST_OPTION_FRAGMENT_SHADING_RATE_BIT) != 0u; }
2269
2270 //! Draw the second pass image, but with sample pattern from the first pass -- used to verify that the pattern is different
drawPatternChangeReference(void)2271 void drawPatternChangeReference (void)
2272 {
2273 const InstanceInterface& vki = m_context.getInstanceInterface();
2274 const DeviceInterface& vk = m_context.getDeviceInterface();
2275 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
2276 const VkDevice device = m_context.getDevice();
2277 const VkViewport viewport = makeViewport(m_renderSize);
2278 const VkRect2D renderArea = makeRect2D(m_renderSize);
2279 const VkRect2D scissor = makeRect2D(m_renderSize);
2280 const ShaderWrapper vertexModule (ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2281 const ShaderWrapper fragmentModule (ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
2282 const PipelineLayoutWrapper pipelineLayout (m_params.pipelineConstructionType, vk, device);
2283 const VkSampleLocationsInfoEXT sampleLocationsInfo = makeSampleLocationsInfo(m_pixelGrids[0]);
2284 const VkClearValue clearColor0 = (m_params.clears == TEST_CLEARS_NO_CLEAR ? makeClearValueColor(CLEAR_COLOR_0) : makeClearValueColor(CLEAR_COLOR_1));
2285
2286 RenderTarget rt;
2287
2288 rt.addAttachment(
2289 *m_colorImage, // VkImage image
2290 *m_colorImageView, // VkImageView imageView,
2291 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2292 m_colorFormat, // VkFormat format,
2293 m_params.numSamples, // VkSampleCountFlagBits numSamples,
2294 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
2295 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2296 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
2297 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
2298 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2299 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
2300 clearColor0); // VkClearValue clearValue,
2301
2302 rt.addAttachment(
2303 *m_resolveImage, // VkImage image
2304 *m_resolveImageView, // VkImageView imageView,
2305 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2306 m_colorFormat, // VkFormat format,
2307 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits numSamples,
2308 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp,
2309 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2310 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
2311 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
2312 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2313 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout finalLayout,
2314 VkClearValue()); // VkClearValue clearValue,
2315
2316 rt.addSubpassColorAttachmentWithResolve(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
2317 1u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
2318
2319 if (useDepth() || useStencil())
2320 {
2321 rt.addAttachment(
2322 *m_depthStencilImage, // VkImage image
2323 *m_depthStencilImageView, // VkImageView imageView,
2324 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2325 m_depthStencilFormat, // VkFormat format,
2326 m_params.numSamples, // VkSampleCountFlagBits numSamples,
2327 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
2328 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2329 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp,
2330 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp,
2331 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2332 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
2333 makeClearValueDepthStencil(DEPTH_CLEAR, STENCIL_REFERENCE), // VkClearValue clearValue,
2334 &sampleLocationsInfo); // VkSampleLocationsInfoEXT* pInitialSampleLocations
2335
2336 rt.addSubpassDepthStencilAttachment(2u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, &sampleLocationsInfo);
2337 }
2338
2339 rt.bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
2340
2341 GraphicsPipelineWrapper pipeline(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
2342 preparePipelineWrapper(pipeline, std::vector<VkDynamicState>(), pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule,
2343 /*subpass index*/ 0u, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, sampleLocationsInfo,
2344 useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate());
2345
2346 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
2347 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
2348 Move<VkCommandBuffer> secondaryCmdBuffer;
2349 VkCommandBuffer currentCmdBuffer = *cmdBuffer;
2350
2351 beginCommandBuffer(vk, currentCmdBuffer);
2352 rt.recordBeginRenderPass(vk, currentCmdBuffer, renderArea, (useSecondaryCmdBuffer() ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : VK_SUBPASS_CONTENTS_INLINE));
2353
2354 // For maximum consistency also use a secondary command buffer, if the two-pass path uses it
2355 if (useSecondaryCmdBuffer())
2356 {
2357 secondaryCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2358 currentCmdBuffer = *secondaryCmdBuffer;
2359
2360 beginSecondaryCommandBuffer(vk, currentCmdBuffer, rt.getRenderPassWrapper(), /*subpass*/ 0u, m_params.numSamples, m_params.pipelineConstructionType);
2361 }
2362
2363 vk.cmdBindVertexBuffers(currentCmdBuffer, /*first binding*/ 0u, /*num bindings*/ 1u, &m_vertexBuffer.get(), /*offsets*/ &ZERO);
2364 pipeline.bind(currentCmdBuffer);
2365
2366 // Draw the right shape only
2367 vk.cmdDraw(currentCmdBuffer, m_numVertices, /*instance count*/ 1u, /*first vertex*/ 0u, /*first instance*/ 1u);
2368
2369 if (useSecondaryCmdBuffer())
2370 {
2371 endCommandBuffer(vk, currentCmdBuffer);
2372 currentCmdBuffer = *cmdBuffer;
2373
2374 vk.cmdExecuteCommands(currentCmdBuffer, 1u, &secondaryCmdBuffer.get());
2375 }
2376
2377 rt.endRenderPass(vk, *cmdBuffer);
2378
2379 recordCopyImageToBuffer(vk, *cmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
2380
2381 endCommandBuffer(vk, *cmdBuffer);
2382 submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
2383
2384 invalidateAlloc(vk, device, *m_colorBufferAlloc);
2385 }
2386
2387 //! Draw two shapes with distinct sample patterns, each in its own render pass
drawRenderPasses(void)2388 void drawRenderPasses (void)
2389 {
2390 const InstanceInterface& vki = m_context.getInstanceInterface();
2391 const DeviceInterface& vk = m_context.getDeviceInterface();
2392 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
2393 const VkDevice device = m_context.getDevice();
2394 const VkViewport viewport = makeViewport(m_renderSize);
2395 const VkRect2D renderArea = makeRect2D(m_renderSize);
2396 const VkRect2D scissor = makeRect2D(m_renderSize);
2397 const ShaderWrapper vertexModule (ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2398 const ShaderWrapper fragmentModule (ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
2399 const PipelineLayoutWrapper pipelineLayout (m_params.pipelineConstructionType, vk, device);
2400 const VkClearValue clearColor0 = makeClearValueColor(CLEAR_COLOR_0);
2401 const VkClearValue clearColor1 = makeClearValueColor(CLEAR_COLOR_1);
2402 const VkClearValue clearDepthStencil0 = makeClearValueDepthStencil(DEPTH_CLEAR, STENCIL_REFERENCE);
2403 const VkSampleLocationsInfoEXT sampleLocationsInfo [NUM_PASSES] =
2404 {
2405 makeSampleLocationsInfo(m_pixelGrids[0]),
2406 makeSampleLocationsInfo(m_pixelGrids[useSameSamplePattern() ? 0 : 1]),
2407 };
2408 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
2409 Move<VkCommandBuffer> cmdBuffer [NUM_PASSES] =
2410 {
2411 makeCommandBuffer(vk, device, *cmdPool),
2412 makeCommandBuffer(vk, device, *cmdPool),
2413 };
2414 Move<VkCommandBuffer> secondaryCmdBuffer [NUM_PASSES];
2415 RenderTarget rt [NUM_PASSES];
2416 std::vector<GraphicsPipelineWrapper> pipelines;
2417 Move<VkEvent> event [2]; /*color and depth/stencil*/
2418
2419 // Layouts expected by the second render pass
2420 const VkImageLayout colorLayout1 = useGeneralLayout() && !(useDepth() || useStencil()) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2421 const VkImageLayout depthStencilLayout1 = useGeneralLayout() && (useDepth() || useStencil()) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2422
2423 // First render pass - no resolves
2424 {
2425 rt[0].addAttachment(
2426 *m_colorImage, // VkImage image
2427 *m_colorImageView, // VkImageView imageView,
2428 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2429 m_colorFormat, // VkFormat format,
2430 m_params.numSamples, // VkSampleCountFlagBits numSamples,
2431 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
2432 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2433 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
2434 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
2435 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2436 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
2437 clearColor0); // VkClearValue clearValue,
2438
2439 rt[0].addSubpassColorAttachment(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
2440
2441 if (useDepth() || useStencil())
2442 {
2443 rt[0].addAttachment(
2444 *m_depthStencilImage, // VkImage image
2445 *m_depthStencilImageView, // VkImageView imageView,
2446 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2447 m_depthStencilFormat, // VkFormat format,
2448 m_params.numSamples, // VkSampleCountFlagBits numSamples,
2449 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
2450 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2451 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp,
2452 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp,
2453 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2454 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
2455 clearDepthStencil0, // VkClearValue clearValue,
2456 &sampleLocationsInfo[0]); // VkSampleLocationsInfoEXT* pInitialSampleLocations
2457
2458 rt[0].addSubpassDepthStencilAttachment(1u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, &sampleLocationsInfo[0]);
2459 }
2460
2461 rt[0].bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
2462 }
2463
2464 // Second render pass
2465 {
2466 const VkAttachmentLoadOp loadOp = (m_params.clears == TEST_CLEARS_LOAD_OP_CLEAR ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD);
2467
2468 rt[1].addAttachment(
2469 *m_colorImage, // VkImage image
2470 *m_colorImageView, // VkImageView imageView,
2471 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2472 m_colorFormat, // VkFormat format,
2473 m_params.numSamples, // VkSampleCountFlagBits numSamples,
2474 loadOp, // VkAttachmentLoadOp loadOp,
2475 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2476 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
2477 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
2478 colorLayout1, // VkImageLayout initialLayout,
2479 colorLayout1, // VkImageLayout finalLayout,
2480 clearColor1); // VkClearValue clearValue,
2481
2482 rt[1].addAttachment(
2483 *m_resolveImage, // VkImage image
2484 *m_resolveImageView, // VkImageView imageView,
2485 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2486 m_colorFormat, // VkFormat format,
2487 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits numSamples,
2488 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp,
2489 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2490 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
2491 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
2492 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2493 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout finalLayout,
2494 VkClearValue()); // VkClearValue clearValue,
2495
2496 rt[1].addSubpassColorAttachmentWithResolve(0u, colorLayout1,
2497 1u, colorLayout1);
2498
2499 if (useDepth() || useStencil())
2500 {
2501 rt[1].addAttachment(
2502 *m_depthStencilImage, // VkImage image
2503 *m_depthStencilImageView, // VkImageView imageView,
2504 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2505 m_depthStencilFormat, // VkFormat format,
2506 m_params.numSamples, // VkSampleCountFlagBits numSamples,
2507 loadOp, // VkAttachmentLoadOp loadOp,
2508 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2509 loadOp, // VkAttachmentLoadOp stencilLoadOp,
2510 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp,
2511 depthStencilLayout1, // VkImageLayout initialLayout,
2512 depthStencilLayout1, // VkImageLayout finalLayout,
2513 clearDepthStencil0, // VkClearValue clearValue,
2514 &sampleLocationsInfo[1]); // VkSampleLocationsInfoEXT* pInitialSampleLocations
2515
2516 rt[1].addSubpassDepthStencilAttachment(2u, depthStencilLayout1, &sampleLocationsInfo[1]);
2517 }
2518
2519 rt[1].bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
2520 }
2521
2522 // Pipelines
2523 pipelines.reserve(NUM_PASSES);
2524 if (useDynamicState())
2525 {
2526 std::vector<VkDynamicState> dynamicState;
2527 dynamicState.push_back(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
2528
2529 for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
2530 {
2531 pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
2532 preparePipelineWrapper(pipelines.back(), dynamicState, pipelineLayout, rt[passNdx].getRenderPass(), vertexModule, fragmentModule,
2533 /*subpass index*/ 0u, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, makeEmptySampleLocationsInfo(),
2534 useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate());
2535 }
2536 }
2537 else for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
2538 {
2539 pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
2540 preparePipelineWrapper(pipelines.back(), std::vector<VkDynamicState>(), pipelineLayout, rt[passNdx].getRenderPass(), vertexModule, fragmentModule,
2541 /*subpass index*/ 0u, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, sampleLocationsInfo[passNdx],
2542 useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate());
2543 }
2544
2545 // Record secondary command buffers
2546
2547 if (useSecondaryCmdBuffer())
2548 {
2549 secondaryCmdBuffer[0] = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2550 secondaryCmdBuffer[1] = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2551
2552 // First render pass contents
2553 beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer[0], rt[0].getRenderPassWrapper(), /*subpass*/ 0u, m_params.numSamples, m_params.pipelineConstructionType);
2554 recordFirstPassContents(*secondaryCmdBuffer[0], pipelines[0], sampleLocationsInfo[0]);
2555 endCommandBuffer(vk, *secondaryCmdBuffer[0]);
2556
2557 // Second render pass contents
2558 beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer[1], rt[1].getRenderPassWrapper(), /*subpass*/ 0u, m_params.numSamples, m_params.pipelineConstructionType);
2559 recordSecondPassContents(*secondaryCmdBuffer[1], pipelines[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
2560 endCommandBuffer(vk, *secondaryCmdBuffer[1]);
2561 }
2562
2563 // Record primary command buffers
2564
2565 VkCommandBuffer currentCmdBuffer = *cmdBuffer[0];
2566 beginCommandBuffer(vk, currentCmdBuffer);
2567
2568 // First render pass
2569 if (useSecondaryCmdBuffer())
2570 {
2571 rt[0].recordBeginRenderPass(vk, currentCmdBuffer, renderArea, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
2572 vk.cmdExecuteCommands(currentCmdBuffer, 1u, &secondaryCmdBuffer[0].get());
2573 rt[0].endRenderPass(vk, currentCmdBuffer);
2574 }
2575 else
2576 {
2577 rt[0].recordBeginRenderPass(vk, currentCmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
2578 recordFirstPassContents(currentCmdBuffer, pipelines[0], sampleLocationsInfo[0]);
2579 rt[0].endRenderPass(vk, currentCmdBuffer);
2580 }
2581
2582 endCommandBuffer(vk, currentCmdBuffer);
2583
2584 // Record the second primary command buffer
2585 currentCmdBuffer = *cmdBuffer[1];
2586 beginCommandBuffer(vk, currentCmdBuffer);
2587
2588 if (m_params.clears == TEST_CLEARS_CMD_CLEAR_IMAGE)
2589 {
2590 {
2591 const VkImageLayout finalLayout = (useWaitEvents() ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : colorLayout1);
2592
2593 recordImageBarrier(vk, currentCmdBuffer, *m_colorImage,
2594 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspect,
2595 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask,
2596 VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags dstStageMask,
2597 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask,
2598 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask,
2599 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout,
2600 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); // VkImageLayout newLayout)
2601
2602 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
2603 vk.cmdClearColorImage(currentCmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor1.color, 1u, &subresourceRange);
2604
2605 recordImageBarrier(vk, currentCmdBuffer, *m_colorImage,
2606 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspect,
2607 VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags srcStageMask,
2608 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags dstStageMask,
2609 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask,
2610 (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
2611 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT), // VkAccessFlags dstAccessMask,
2612 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout,
2613 finalLayout); // VkImageLayout newLayout)
2614 }
2615
2616 if (useDepth() || useStencil())
2617 {
2618 const VkImageLayout finalLayout = (useWaitEvents() ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : depthStencilLayout1);
2619
2620 recordImageBarrier(vk, currentCmdBuffer, *m_depthStencilImage,
2621 getImageAspectFlags(m_depthStencilFormat), // VkImageAspectFlags aspect,
2622 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags srcStageMask,
2623 VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags dstStageMask,
2624 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask,
2625 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask,
2626 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout,
2627 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout)
2628 &sampleLocationsInfo[0]); // VkSampleLocationsInfoEXT
2629
2630 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(m_depthStencilAspect, 0u, 1u, 0u, 1u);
2631 vk.cmdClearDepthStencilImage(currentCmdBuffer, *m_depthStencilImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearDepthStencil0.depthStencil, 1u, &subresourceRange);
2632
2633 recordImageBarrier(vk, currentCmdBuffer, *m_depthStencilImage,
2634 getImageAspectFlags(m_depthStencilFormat), // VkImageAspectFlags aspect,
2635 VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags srcStageMask,
2636 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags dstStageMask,
2637 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask,
2638 (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
2639 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT), // VkAccessFlags dstAccessMask,
2640 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout,
2641 finalLayout, // VkImageLayout newLayout)
2642 &sampleLocationsInfo[0]); // VkSampleLocationsInfoEXT
2643 }
2644 }
2645 else if (!useWaitEvents())
2646 {
2647 // Barrier between the render passes
2648
2649 recordImageBarrier(vk, currentCmdBuffer, *m_colorImage,
2650 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspect,
2651 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask,
2652 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags dstStageMask,
2653 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask,
2654 (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
2655 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT), // VkAccessFlags dstAccessMask,
2656 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout,
2657 colorLayout1); // VkImageLayout newLayout)
2658
2659 if (useDepth() || useStencil())
2660 {
2661 recordImageBarrier(vk, currentCmdBuffer, *m_depthStencilImage,
2662 getImageAspectFlags(m_depthStencilFormat), // VkImageAspectFlags aspect,
2663 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags srcStageMask,
2664 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags dstStageMask,
2665 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask,
2666 (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
2667 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT), // VkAccessFlags dstAccessMask,
2668 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout,
2669 depthStencilLayout1); // VkImageLayout newLayout)
2670 }
2671 }
2672
2673 if (useWaitEvents())
2674 {
2675 // Use events to sync both render passes
2676 event[0] = makeEvent(vk, device);
2677 vk.cmdSetEvent(currentCmdBuffer, *event[0], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
2678
2679 recordWaitEventWithImage(vk, currentCmdBuffer, *event[0], *m_colorImage,
2680 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspect,
2681 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask,
2682 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags dstStageMask,
2683 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask,
2684 (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
2685 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT), // VkAccessFlags dstAccessMask,
2686 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout,
2687 colorLayout1); // VkImageLayout newLayout,
2688
2689 if (useDepth() || useStencil())
2690 {
2691 event[1] = makeEvent(vk, device);
2692 vk.cmdSetEvent(currentCmdBuffer, *event[1], VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
2693
2694 recordWaitEventWithImage(vk, currentCmdBuffer, *event[1], *m_depthStencilImage,
2695 getImageAspectFlags(m_depthStencilFormat), // VkImageAspectFlags aspect,
2696 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags srcStageMask,
2697 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags dstStageMask,
2698 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask,
2699 (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
2700 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT), // VkAccessFlags dstAccessMask,
2701 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout,
2702 depthStencilLayout1); // VkImageLayout newLayout,
2703 }
2704 }
2705
2706 // Second render pass
2707 if (useSecondaryCmdBuffer())
2708 {
2709 rt[1].recordBeginRenderPass(vk, currentCmdBuffer, renderArea, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
2710 vk.cmdExecuteCommands(currentCmdBuffer, 1u, &secondaryCmdBuffer[1].get());
2711 rt[1].endRenderPass(vk, currentCmdBuffer);
2712 }
2713 else
2714 {
2715 rt[1].recordBeginRenderPass(vk, currentCmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
2716 recordSecondPassContents(currentCmdBuffer, pipelines[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
2717 rt[1].endRenderPass(vk, currentCmdBuffer);
2718 }
2719
2720 // Resolve image -> host buffer
2721 recordCopyImageToBuffer(vk, currentCmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
2722
2723 endCommandBuffer(vk, currentCmdBuffer);
2724
2725 // Submit work
2726 {
2727 const Unique<VkFence> fence (createFence(vk, device));
2728 const VkCommandBuffer buffers [NUM_PASSES] =
2729 {
2730 *cmdBuffer[0],
2731 *cmdBuffer[1],
2732 };
2733
2734 const VkSubmitInfo submitInfo =
2735 {
2736 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
2737 DE_NULL, // const void* pNext;
2738 0u, // uint32_t waitSemaphoreCount;
2739 DE_NULL, // const VkSemaphore* pWaitSemaphores;
2740 DE_NULL, // const VkPipelineStageFlags* pWaitDstStageMask;
2741 DE_LENGTH_OF_ARRAY(buffers), // uint32_t commandBufferCount;
2742 buffers, // const VkCommandBuffer* pCommandBuffers;
2743 0u, // uint32_t signalSemaphoreCount;
2744 DE_NULL, // const VkSemaphore* pSignalSemaphores;
2745 };
2746 VK_CHECK(vk.queueSubmit(m_context.getUniversalQueue(), 1u, &submitInfo, *fence));
2747 VK_CHECK(vk.waitForFences(device, 1u, &fence.get(), DE_TRUE, ~0ull));
2748 }
2749
2750 invalidateAlloc(vk, device, *m_colorBufferAlloc);
2751 }
2752
recordFirstPassContents(const VkCommandBuffer cmdBuffer, const GraphicsPipelineWrapper& pipeline, const VkSampleLocationsInfoEXT& sampleLocationsInfo)2753 void recordFirstPassContents (const VkCommandBuffer cmdBuffer,
2754 const GraphicsPipelineWrapper& pipeline,
2755 const VkSampleLocationsInfoEXT& sampleLocationsInfo)
2756 {
2757 const DeviceInterface& vk = m_context.getDeviceInterface();
2758
2759 vk.cmdBindVertexBuffers(cmdBuffer, /*first binding*/ 0u, /*num bindings*/ 1u, &m_vertexBuffer.get(), /*offsets*/ &ZERO);
2760 pipeline.bind(cmdBuffer);
2761
2762 if (useDynamicState())
2763 vk.cmdSetSampleLocationsEXT(cmdBuffer, &sampleLocationsInfo);
2764
2765 if (m_params.clears == TEST_CLEARS_NO_CLEAR)
2766 vk.cmdDraw(cmdBuffer, m_numVertices, /*instance count*/ 1u, /*first vertex*/ 0u, /*first instance*/ 0u); // left shape only
2767 else
2768 vk.cmdDraw(cmdBuffer, m_numVertices, /*instance count*/ NUM_PASSES, /*first vertex*/ 0u, /*first instance*/ 0u); // both shapes
2769 }
2770
recordSecondPassContents(const VkCommandBuffer cmdBuffer, const GraphicsPipelineWrapper& pipeline, const VkSampleLocationsInfoEXT& sampleLocationsInfo, const VkClearValue& clearColor, const VkClearValue& clearDepthStencil, const VkRect2D& clearRect)2771 void recordSecondPassContents (const VkCommandBuffer cmdBuffer,
2772 const GraphicsPipelineWrapper& pipeline,
2773 const VkSampleLocationsInfoEXT& sampleLocationsInfo,
2774 const VkClearValue& clearColor,
2775 const VkClearValue& clearDepthStencil,
2776 const VkRect2D& clearRect)
2777 {
2778 const DeviceInterface& vk = m_context.getDeviceInterface();
2779
2780 vk.cmdBindVertexBuffers(cmdBuffer, /*first binding*/ 0u, /*num bindings*/ 1u, &m_vertexBuffer.get(), /*offsets*/ &ZERO);
2781 pipeline.bind(cmdBuffer);
2782
2783 if (m_params.clears == TEST_CLEARS_CMD_CLEAR_ATTACHMENTS)
2784 recordClearAttachments(vk, cmdBuffer, 0u, clearColor, m_depthStencilAspect, clearDepthStencil, clearRect);
2785
2786 if (useDynamicState())
2787 vk.cmdSetSampleLocationsEXT(cmdBuffer, &sampleLocationsInfo);
2788
2789 // Draw the right shape only
2790 vk.cmdDraw(cmdBuffer, m_numVertices, /*instance count*/ 1u, /*first vertex*/ 0u, /*first instance*/ 1u);
2791 }
2792
2793 //! Draw two shapes in two subpasses of the same render pass
drawSubpasses(void)2794 void drawSubpasses (void)
2795 {
2796 DE_ASSERT(m_params.clears != TEST_CLEARS_CMD_CLEAR_IMAGE); // not possible in a render pass
2797 DE_ASSERT(m_params.clears != TEST_CLEARS_LOAD_OP_CLEAR); // can't specify a load op for a subpass
2798 DE_ASSERT((m_params.options & TEST_OPTION_WAIT_EVENTS_BIT) == 0); // can't change layouts inside a subpass
2799
2800 const InstanceInterface& vki = m_context.getInstanceInterface();
2801 const DeviceInterface& vk = m_context.getDeviceInterface();
2802 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
2803 const VkDevice device = m_context.getDevice();
2804 const VkViewport viewport = makeViewport(m_renderSize);
2805 const VkRect2D renderArea = makeRect2D(m_renderSize);
2806 const VkRect2D scissor = makeRect2D(m_renderSize);
2807 const ShaderWrapper vertexModule (ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2808 const ShaderWrapper fragmentModule (ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
2809 const PipelineLayoutWrapper pipelineLayout (m_params.pipelineConstructionType, vk, device);
2810 const VkClearValue clearColor0 = makeClearValueColor(CLEAR_COLOR_0);
2811 const VkClearValue clearColor1 = makeClearValueColor(CLEAR_COLOR_1);
2812 const VkClearValue clearDepthStencil0 = makeClearValueDepthStencil(DEPTH_CLEAR, STENCIL_REFERENCE);
2813 const VkSampleLocationsInfoEXT sampleLocationsInfo [NUM_PASSES] =
2814 {
2815 makeSampleLocationsInfo(m_pixelGrids[0]),
2816 makeSampleLocationsInfo(m_pixelGrids[useSameSamplePattern() ? 0 : 1]),
2817 };
2818 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
2819 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
2820 Move<VkCommandBuffer> secondaryCmdBuffer [NUM_PASSES];
2821 RenderTarget rt;
2822 std::vector<GraphicsPipelineWrapper> pipelines;
2823 Move<VkEvent> event;
2824
2825 // Layouts used in the second subpass
2826 const VkImageLayout colorLayout1 = useGeneralLayout() && !(useDepth() || useStencil()) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2827 const VkImageLayout depthStencilLayout1 = useGeneralLayout() && (useDepth() || useStencil()) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2828
2829 // Prepare the render pass
2830 {
2831 rt.addAttachment(
2832 *m_colorImage, // VkImage image
2833 *m_colorImageView, // VkImageView imageView,
2834 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2835 m_colorFormat, // VkFormat format,
2836 m_params.numSamples, // VkSampleCountFlagBits numSamples,
2837 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
2838 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2839 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
2840 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
2841 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2842 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
2843 clearColor0); // VkClearValue clearValue,
2844
2845 rt.addAttachment(
2846 *m_resolveImage, // VkImage image
2847 *m_resolveImageView, // VkImageView imageView,
2848 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2849 m_colorFormat, // VkFormat format,
2850 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits numSamples,
2851 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp,
2852 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2853 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
2854 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
2855 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2856 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout finalLayout,
2857 VkClearValue()); // VkClearValue clearValue,
2858
2859 // First subpass
2860 rt.addSubpassColorAttachment(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
2861
2862 if (useDepth() || useStencil())
2863 {
2864 rt.addAttachment(
2865 *m_depthStencilImage, // VkImage image
2866 *m_depthStencilImageView, // VkImageView imageView,
2867 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2868 m_depthStencilFormat, // VkFormat format,
2869 m_params.numSamples, // VkSampleCountFlagBits numSamples,
2870 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
2871 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2872 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp,
2873 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp,
2874 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2875 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
2876 clearDepthStencil0, // VkClearValue clearValue,
2877 &sampleLocationsInfo[0]); // VkSampleLocationsInfoEXT* pInitialSampleLocations
2878
2879 rt.addSubpassDepthStencilAttachment(2u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, &sampleLocationsInfo[0]);
2880 }
2881
2882 // Second subpass
2883 rt.nextSubpass();
2884 rt.addSubpassColorAttachmentWithResolve(0u, colorLayout1,
2885 1u, colorLayout1);
2886
2887 if (useDepth() || useStencil())
2888 rt.addSubpassDepthStencilAttachment(2u, depthStencilLayout1, &sampleLocationsInfo[1]);
2889
2890 rt.bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
2891 }
2892
2893 // Pipelines
2894 pipelines.reserve(NUM_PASSES);
2895 if (useDynamicState())
2896 {
2897 std::vector<VkDynamicState> dynamicState;
2898 dynamicState.push_back(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
2899
2900 for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
2901 {
2902 pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
2903 preparePipelineWrapper(pipelines.back(), dynamicState, pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule,
2904 /*subpass*/ passNdx, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, makeEmptySampleLocationsInfo(),
2905 useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate());
2906 }
2907 }
2908 else for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
2909 {
2910 pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
2911 preparePipelineWrapper(pipelines.back(), std::vector<VkDynamicState>(), pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule,
2912 /*subpass*/ passNdx, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, sampleLocationsInfo[passNdx],
2913 useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate());
2914 }
2915
2916 // Record secondary command buffers
2917
2918 if (useSecondaryCmdBuffer())
2919 {
2920 secondaryCmdBuffer[0] = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2921 secondaryCmdBuffer[1] = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2922
2923 // First subpass contents
2924 beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer[0], rt.getRenderPassWrapper(), /*subpass*/ 0u, m_params.numSamples, m_params.pipelineConstructionType);
2925 recordFirstPassContents(*secondaryCmdBuffer[0], pipelines[0], sampleLocationsInfo[0]);
2926 endCommandBuffer(vk, *secondaryCmdBuffer[0]);
2927
2928 // Second subpass contents
2929 beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer[1], rt.getRenderPassWrapper(), /*subpass*/ 1u, m_params.numSamples, m_params.pipelineConstructionType);
2930 recordSecondPassContents(*secondaryCmdBuffer[1], pipelines[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
2931 endCommandBuffer(vk, *secondaryCmdBuffer[1]);
2932 }
2933
2934 // Record primary command buffer
2935
2936 beginCommandBuffer(vk, *cmdBuffer);
2937
2938 if (useSecondaryCmdBuffer())
2939 {
2940 rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
2941 vk.cmdExecuteCommands(*cmdBuffer, 1u, &secondaryCmdBuffer[0].get());
2942
2943 rt.nextSubpass(vk, *cmdBuffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
2944 vk.cmdExecuteCommands(*cmdBuffer, 1u, &secondaryCmdBuffer[1].get());
2945 }
2946 else
2947 {
2948 rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
2949 recordFirstPassContents(*cmdBuffer, pipelines[0], sampleLocationsInfo[0]);
2950
2951 rt.nextSubpass(vk, *cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
2952 recordSecondPassContents(*cmdBuffer, pipelines[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
2953 }
2954
2955 rt.endRenderPass(vk, *cmdBuffer);
2956
2957 // Resolve image -> host buffer
2958 recordCopyImageToBuffer(vk, *cmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
2959
2960 endCommandBuffer(vk, *cmdBuffer);
2961
2962 submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
2963 invalidateAlloc(vk, device, *m_colorBufferAlloc);
2964 }
2965
2966 //! Draw two shapes within the same subpass of a renderpass
drawSameSubpass(void)2967 void drawSameSubpass (void)
2968 {
2969 DE_ASSERT(m_params.clears != TEST_CLEARS_CMD_CLEAR_IMAGE); // not possible in a render pass
2970 DE_ASSERT(m_params.clears != TEST_CLEARS_LOAD_OP_CLEAR); // can't specify a load op for a subpass
2971 DE_ASSERT((m_params.options & TEST_OPTION_WAIT_EVENTS_BIT) == 0); // can't change layouts inside a subpass
2972 DE_ASSERT((m_params.options & TEST_OPTION_GENERAL_LAYOUT_BIT) == 0); // can't change layouts inside a subpass
2973
2974 const InstanceInterface& vki = m_context.getInstanceInterface();
2975 const DeviceInterface& vk = m_context.getDeviceInterface();
2976 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
2977 const VkDevice device = m_context.getDevice();
2978 const VkViewport viewport = makeViewport(m_renderSize);
2979 const VkRect2D renderArea = makeRect2D(m_renderSize);
2980 const VkRect2D scissor = makeRect2D(m_renderSize);
2981 const ShaderWrapper vertexModule (ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2982 const ShaderWrapper fragmentModule (ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
2983 const PipelineLayoutWrapper pipelineLayout (m_params.pipelineConstructionType, vk, device);
2984 const VkClearValue clearColor0 = makeClearValueColor(CLEAR_COLOR_0);
2985 const VkClearValue clearColor1 = makeClearValueColor(CLEAR_COLOR_1);
2986 const VkClearValue clearDepthStencil0 = makeClearValueDepthStencil(DEPTH_CLEAR, STENCIL_REFERENCE);
2987 const VkSampleLocationsInfoEXT sampleLocationsInfo [NUM_PASSES] =
2988 {
2989 makeSampleLocationsInfo(m_pixelGrids[0]),
2990 makeSampleLocationsInfo(m_pixelGrids[useSameSamplePattern() ? 0 : 1]),
2991 };
2992 const bool useFragmentShadingRate (TEST_OPTION_FRAGMENT_SHADING_RATE_BIT & m_params.options);
2993 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
2994 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
2995 Move<VkCommandBuffer> secondaryCmdBuffer;
2996 RenderTarget rt;
2997 std::vector<GraphicsPipelineWrapper> pipelines;
2998 Move<VkEvent> event;
2999
3000 // Prepare the render pass
3001 {
3002 rt.addAttachment(
3003 *m_colorImage, // VkImage image
3004 *m_colorImageView, // VkImageView imageView,
3005 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
3006 m_colorFormat, // VkFormat format,
3007 m_params.numSamples, // VkSampleCountFlagBits numSamples,
3008 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
3009 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
3010 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
3011 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
3012 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
3013 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
3014 clearColor0); // VkClearValue clearValue,
3015
3016 rt.addAttachment(
3017 *m_resolveImage, // VkImage image
3018 *m_resolveImageView, // VkImageView imageView,
3019 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
3020 m_colorFormat, // VkFormat format,
3021 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits numSamples,
3022 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp,
3023 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
3024 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
3025 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
3026 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
3027 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout finalLayout,
3028 VkClearValue()); // VkClearValue clearValue,
3029
3030 rt.addSubpassColorAttachmentWithResolve(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
3031 1u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
3032
3033 if (useDepth() || useStencil())
3034 {
3035 rt.addAttachment(
3036 *m_depthStencilImage, // VkImage image
3037 *m_depthStencilImageView, // VkImageView imageView,
3038 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
3039 m_depthStencilFormat, // VkFormat format,
3040 m_params.numSamples, // VkSampleCountFlagBits numSamples,
3041 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
3042 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
3043 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp,
3044 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp,
3045 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
3046 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
3047 clearDepthStencil0, // VkClearValue clearValue,
3048 &sampleLocationsInfo[0]); // VkSampleLocationsInfoEXT* pInitialSampleLocations
3049
3050 rt.addSubpassDepthStencilAttachment(2u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, &sampleLocationsInfo[0]);
3051 }
3052
3053 rt.bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
3054 }
3055
3056 // Pipelines
3057 pipelines.reserve(NUM_PASSES);
3058 if (useDynamicState())
3059 {
3060 std::vector<VkDynamicState> dynamicState;
3061 dynamicState.push_back(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
3062
3063 for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
3064 {
3065 pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
3066 preparePipelineWrapper(pipelines.back(), dynamicState, pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule,
3067 /*subpass*/ 0u, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, makeEmptySampleLocationsInfo(),
3068 useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate);
3069 }
3070 }
3071 else for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
3072 {
3073 pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_params.pipelineConstructionType);
3074 preparePipelineWrapper(pipelines.back(), std::vector<VkDynamicState>(), pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule,
3075 /*subpass*/ 0u, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, sampleLocationsInfo[passNdx],
3076 useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate);
3077 }
3078
3079 // Record secondary command buffers
3080
3081 if (useSecondaryCmdBuffer())
3082 {
3083 secondaryCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
3084
3085 beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer, rt.getRenderPassWrapper(), /*subpass*/ 0u, m_params.numSamples, m_params.pipelineConstructionType);
3086 recordFirstPassContents(*secondaryCmdBuffer, pipelines[0], sampleLocationsInfo[0]);
3087 recordSecondPassContents(*secondaryCmdBuffer, pipelines[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
3088 endCommandBuffer(vk, *secondaryCmdBuffer);
3089 }
3090
3091 // Record primary command buffer
3092
3093 beginCommandBuffer(vk, *cmdBuffer);
3094
3095 if (useSecondaryCmdBuffer())
3096 {
3097 rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
3098 vk.cmdExecuteCommands(*cmdBuffer, 1u, &secondaryCmdBuffer.get());
3099 }
3100 else
3101 {
3102 rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
3103 recordFirstPassContents(*cmdBuffer, pipelines[0], sampleLocationsInfo[0]);
3104 recordSecondPassContents(*cmdBuffer, pipelines[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
3105 }
3106
3107 rt.endRenderPass(vk, *cmdBuffer);
3108
3109 // Resolve image -> host buffer
3110 recordCopyImageToBuffer(vk, *cmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
3111
3112 endCommandBuffer(vk, *cmdBuffer);
3113
3114 submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
3115 invalidateAlloc(vk, device, *m_colorBufferAlloc);
3116 }
3117
3118 const TestParams m_params;
3119 const VkPhysicalDeviceSampleLocationsPropertiesEXT m_sampleLocationsProperties;
3120 const UVec2 m_renderSize;
3121 UVec2 m_gridSize;
3122 std::vector<MultisamplePixelGrid> m_pixelGrids;
3123 deUint32 m_numVertices;
3124 Move<VkBuffer> m_vertexBuffer;
3125 MovePtr<Allocation> m_vertexBufferAlloc;
3126 const VkFormat m_colorFormat;
3127 Move<VkImage> m_colorImage;
3128 Move<VkImageView> m_colorImageView;
3129 MovePtr<Allocation> m_colorImageAlloc;
3130 VkFormat m_depthStencilFormat;
3131 VkImageAspectFlags m_depthStencilAspect;
3132 Move<VkImage> m_depthStencilImage;
3133 Move<VkImageView> m_depthStencilImageView;
3134 MovePtr<Allocation> m_depthStencilImageAlloc;
3135 Move<VkImage> m_resolveImage;
3136 Move<VkImageView> m_resolveImageView;
3137 MovePtr<Allocation> m_resolveImageAlloc;
3138 Move<VkBuffer> m_colorBuffer;
3139 MovePtr<Allocation> m_colorBufferAlloc;
3140 };
3141
3142 } // Draw
3143
createTestsInGroup(tcu::TestCaseGroup* rootGroup, PipelineConstructionType pipelineConstructionType, bool useFragmentShadingRate)3144 void createTestsInGroup (tcu::TestCaseGroup* rootGroup, PipelineConstructionType pipelineConstructionType, bool useFragmentShadingRate)
3145 {
3146 // Queries
3147 if (!useFragmentShadingRate && (pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC))
3148 {
3149 MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(rootGroup->getTestContext(), "query"));
3150
3151 addFunctionCase(group.get(), "sample_locations_properties", checkSupportSampleLocations, testQuerySampleLocationProperties);
3152 addFunctionCase(group.get(), "multisample_properties", checkSupportSampleLocations, testQueryMultisampleProperties);
3153
3154 rootGroup->addChild(group.release());
3155 }
3156
3157 const VkSampleCountFlagBits sampleCountRange[] =
3158 {
3159 VK_SAMPLE_COUNT_2_BIT,
3160 VK_SAMPLE_COUNT_4_BIT,
3161 VK_SAMPLE_COUNT_8_BIT,
3162 VK_SAMPLE_COUNT_16_BIT,
3163 // There are no implementations that support 32 or 64 programmable samples currently
3164 };
3165
3166 // Verify custom sample locations and interpolation
3167 {
3168 using namespace VerifySamples;
3169
3170 MovePtr<tcu::TestCaseGroup> groupLocation (new tcu::TestCaseGroup(rootGroup->getTestContext(), "verify_location"));
3171 MovePtr<tcu::TestCaseGroup> groupInterpolation (new tcu::TestCaseGroup(rootGroup->getTestContext(), "verify_interpolation"));
3172
3173 for (const VkSampleCountFlagBits* pLoopNumSamples = sampleCountRange; pLoopNumSamples < DE_ARRAY_END(sampleCountRange); ++pLoopNumSamples)
3174 {
3175 addCases<VerifyLocationTest> (groupLocation.get(), *pLoopNumSamples, pipelineConstructionType, useFragmentShadingRate, addProgramsVerifyLocationGeometry);
3176 addCases<VerifyInterpolationTest>(groupInterpolation.get(), *pLoopNumSamples, pipelineConstructionType, useFragmentShadingRate, addProgramsVerifyInterpolation);
3177 }
3178
3179 rootGroup->addChild(groupLocation.release());
3180 rootGroup->addChild(groupInterpolation.release());
3181 }
3182
3183 // Draw with custom samples and various options
3184 {
3185 using namespace Draw;
3186
3187 const deUint32 globalOption = useFragmentShadingRate ? static_cast<deUint32>(TEST_OPTION_FRAGMENT_SHADING_RATE_BIT) : 0u;
3188 const deUint32 optionSets[] =
3189 {
3190 globalOption | TEST_OPTION_SAME_PATTERN_BIT,
3191 globalOption | 0u,
3192 globalOption | TEST_OPTION_DYNAMIC_STATE_BIT,
3193 globalOption | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3194 globalOption | TEST_OPTION_DYNAMIC_STATE_BIT | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3195 globalOption | TEST_OPTION_GENERAL_LAYOUT_BIT,
3196 globalOption | TEST_OPTION_GENERAL_LAYOUT_BIT | TEST_OPTION_DYNAMIC_STATE_BIT,
3197 globalOption | TEST_OPTION_GENERAL_LAYOUT_BIT | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3198 globalOption | TEST_OPTION_GENERAL_LAYOUT_BIT | TEST_OPTION_DYNAMIC_STATE_BIT | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3199 globalOption | TEST_OPTION_WAIT_EVENTS_BIT,
3200 globalOption | TEST_OPTION_WAIT_EVENTS_BIT | TEST_OPTION_GENERAL_LAYOUT_BIT,
3201 globalOption | TEST_OPTION_WAIT_EVENTS_BIT | TEST_OPTION_GENERAL_LAYOUT_BIT | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3202 };
3203
3204 const struct
3205 {
3206 TestDrawIn drawIn;
3207 TestClears clears;
3208 } drawClearSets[] =
3209 {
3210 { TEST_DRAW_IN_RENDER_PASSES, TEST_CLEARS_NO_CLEAR },
3211 { TEST_DRAW_IN_RENDER_PASSES, TEST_CLEARS_LOAD_OP_CLEAR },
3212 { TEST_DRAW_IN_RENDER_PASSES, TEST_CLEARS_CMD_CLEAR_ATTACHMENTS },
3213 { TEST_DRAW_IN_RENDER_PASSES, TEST_CLEARS_CMD_CLEAR_IMAGE },
3214 { TEST_DRAW_IN_SUBPASSES, TEST_CLEARS_NO_CLEAR },
3215 { TEST_DRAW_IN_SUBPASSES, TEST_CLEARS_CMD_CLEAR_ATTACHMENTS },
3216 { TEST_DRAW_IN_SAME_SUBPASS, TEST_CLEARS_NO_CLEAR },
3217 { TEST_DRAW_IN_SAME_SUBPASS, TEST_CLEARS_CMD_CLEAR_ATTACHMENTS },
3218 };
3219
3220 const TestImageAspect aspectRange[] =
3221 {
3222 TEST_IMAGE_ASPECT_COLOR,
3223 TEST_IMAGE_ASPECT_DEPTH,
3224 TEST_IMAGE_ASPECT_STENCIL,
3225 };
3226
3227 MovePtr<tcu::TestCaseGroup> drawGroup (new tcu::TestCaseGroup(rootGroup->getTestContext(), "draw"));
3228 for (const TestImageAspect* pLoopImageAspect = aspectRange; pLoopImageAspect != DE_ARRAY_END(aspectRange); ++pLoopImageAspect)
3229 {
3230 MovePtr<tcu::TestCaseGroup> aspectGroup (new tcu::TestCaseGroup(drawGroup->getTestContext(), getString(*pLoopImageAspect)));
3231 for (const VkSampleCountFlagBits* pLoopNumSamples = sampleCountRange; pLoopNumSamples < DE_ARRAY_END(sampleCountRange); ++pLoopNumSamples)
3232 {
3233 MovePtr<tcu::TestCaseGroup> samplesGroup (new tcu::TestCaseGroup(aspectGroup->getTestContext(), getString(*pLoopNumSamples).c_str()));
3234
3235 for (deUint32 loopDrawSetNdx = 0u; loopDrawSetNdx < DE_LENGTH_OF_ARRAY(drawClearSets); ++loopDrawSetNdx)
3236 for (const deUint32* pLoopOptions = optionSets; pLoopOptions != DE_ARRAY_END(optionSets); ++pLoopOptions)
3237 {
3238 const TestParams params
3239 {
3240 pipelineConstructionType, // PipelineConstructionType pipelineConstructionType;
3241 *pLoopNumSamples, // VkSampleCountFlagBits numSamples;
3242 *pLoopOptions, // TestOptionFlags options;
3243 drawClearSets[loopDrawSetNdx].drawIn, // TestDrawIn drawIn;
3244 drawClearSets[loopDrawSetNdx].clears, // TestClears clears;
3245 *pLoopImageAspect, // TestImageAspect imageAspect;
3246 };
3247
3248 // Filter out incompatible parameter combinations
3249 if (params.imageAspect != TEST_IMAGE_ASPECT_COLOR)
3250 {
3251 // If the sample pattern is changed, the D/S image must be cleared or the result is undefined
3252 if (((params.options & TEST_OPTION_SAME_PATTERN_BIT) == 0u) && (params.clears == TEST_CLEARS_NO_CLEAR))
3253 continue;
3254 }
3255
3256 // We are using events to change image layout and this is only allowed outside a render pass
3257 if (((params.options & TEST_OPTION_WAIT_EVENTS_BIT) != 0u) && (params.drawIn != TEST_DRAW_IN_RENDER_PASSES))
3258 continue;
3259
3260 // Can't change image layout inside a subpass
3261 if (((params.options & TEST_OPTION_GENERAL_LAYOUT_BIT) != 0u) && (params.drawIn == TEST_DRAW_IN_SAME_SUBPASS))
3262 continue;
3263
3264 std::ostringstream caseName;
3265 caseName << getString(params.drawIn) << "_"
3266 << getString(params.clears) << (params.options != 0 ? "_" : "")
3267 << getTestOptionFlagsString(params.options);
3268
3269 addInstanceTestCaseWithPrograms<DrawTest>(samplesGroup.get(), caseName.str().c_str(), checkSupportDrawTests, initPrograms, params);
3270 }
3271 aspectGroup->addChild(samplesGroup.release());
3272 }
3273 drawGroup->addChild(aspectGroup.release());
3274 }
3275 rootGroup->addChild(drawGroup.release());
3276 }
3277 }
3278
3279 } // anonymous ns
3280
createMultisampleSampleLocationsExtTests(tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType, bool useFragmentShadingRate)3281 tcu::TestCaseGroup* createMultisampleSampleLocationsExtTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType, bool useFragmentShadingRate)
3282 {
3283 return createTestGroup(testCtx, "sample_locations_ext", createTestsInGroup, pipelineConstructionType, useFragmentShadingRate);
3284 }
3285
3286 } // pipeline
3287 } // vkt
3288