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