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