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