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::__anon8cdc224e0111::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_KHR, // 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::__anon8cdc224e0111::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
makeGraphicsPipeline(const DeviceInterface & vk,const VkDevice device,const std::vector<VkDynamicState> & dynamicState,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const VkShaderModule vertexModule,const VkShaderModule fragmentModule,const deUint32 subpassIndex,const VkViewport & viewport,const VkRect2D scissor,const VkSampleCountFlagBits numSamples,const bool useSampleLocations,const VkSampleLocationsInfoEXT & sampleLocationsInfo,const bool useDepth,const bool useStencil,const VertexInputConfig vertexInputConfig,const VkPrimitiveTopology topology,const VkStencilOpState & stencilOpState,const bool useFragmentShadingRate)559 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface& vk,
560 const VkDevice device,
561 const std::vector<VkDynamicState>& dynamicState,
562 const VkPipelineLayout pipelineLayout,
563 const VkRenderPass renderPass,
564 const VkShaderModule vertexModule,
565 const VkShaderModule fragmentModule,
566 const deUint32 subpassIndex,
567 const VkViewport& viewport,
568 const VkRect2D scissor,
569 const VkSampleCountFlagBits numSamples,
570 const bool useSampleLocations,
571 const VkSampleLocationsInfoEXT& sampleLocationsInfo,
572 const bool useDepth,
573 const bool useStencil,
574 const VertexInputConfig vertexInputConfig,
575 const VkPrimitiveTopology topology,
576 const VkStencilOpState& stencilOpState,
577 const bool useFragmentShadingRate)
578 {
579 std::vector<VkVertexInputBindingDescription> vertexInputBindingDescriptions;
580 std::vector<VkVertexInputAttributeDescription> vertexInputAttributeDescriptions;
581
582 const deUint32 sizeofVec4 = static_cast<deUint32>(sizeof(Vec4));
583
584 switch (vertexInputConfig)
585 {
586 case VERTEX_INPUT_NONE:
587 break;
588
589 case VERTEX_INPUT_VEC4:
590 vertexInputBindingDescriptions.push_back(makeVertexInputBindingDescription(0u, sizeofVec4, VK_VERTEX_INPUT_RATE_VERTEX));
591 vertexInputAttributeDescriptions.push_back(makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u));
592 break;
593
594 case VERTEX_INPUT_VEC4_VEC4:
595 vertexInputBindingDescriptions.push_back(makeVertexInputBindingDescription(0u, 2u * sizeofVec4, VK_VERTEX_INPUT_RATE_VERTEX));
596 vertexInputAttributeDescriptions.push_back(makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u));
597 vertexInputAttributeDescriptions.push_back(makeVertexInputAttributeDescription(1u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, sizeofVec4));
598 break;
599
600 default:
601 DE_FATAL("Vertex input config not supported");
602 break;
603 }
604
605 const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
606 {
607 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
608 DE_NULL, // const void* pNext;
609 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags;
610 static_cast<deUint32>(vertexInputBindingDescriptions.size()), // uint32_t vertexBindingDescriptionCount;
611 dataOrNullPtr(vertexInputBindingDescriptions), // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
612 static_cast<deUint32>(vertexInputAttributeDescriptions.size()), // uint32_t vertexAttributeDescriptionCount;
613 dataOrNullPtr(vertexInputAttributeDescriptions), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
614 };
615
616 const VkPipelineSampleLocationsStateCreateInfoEXT pipelineSampleLocationsCreateInfo =
617 {
618 VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT, // VkStructureType sType;
619 DE_NULL, // const void* pNext;
620 useSampleLocations, // VkBool32 sampleLocationsEnable;
621 sampleLocationsInfo, // VkSampleLocationsInfoEXT sampleLocationsInfo;
622 };
623
624 const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
625 {
626 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
627 &pipelineSampleLocationsCreateInfo, // const void* pNext;
628 (VkPipelineMultisampleStateCreateFlags)0, // VkPipelineMultisampleStateCreateFlags flags;
629 numSamples, // VkSampleCountFlagBits rasterizationSamples;
630 VK_TRUE, // VkBool32 sampleShadingEnable;
631 1.0f, // float minSampleShading;
632 DE_NULL, // const VkSampleMask* pSampleMask;
633 VK_FALSE, // VkBool32 alphaToCoverageEnable;
634 VK_FALSE // VkBool32 alphaToOneEnable;
635 };
636
637 VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
638 {
639 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
640 DE_NULL, // const void* pNext;
641 (VkPipelineDepthStencilStateCreateFlags)0, // VkPipelineDepthStencilStateCreateFlags flags;
642 useDepth, // VkBool32 depthTestEnable;
643 true, // VkBool32 depthWriteEnable;
644 VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
645 VK_FALSE, // VkBool32 depthBoundsTestEnable;
646 useStencil, // VkBool32 stencilTestEnable;
647 stencilOpState, // VkStencilOpState front;
648 stencilOpState, // VkStencilOpState back;
649 0.0f, // float minDepthBounds;
650 1.0f, // float maxDepthBounds;
651 };
652
653 const VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo =
654 {
655 VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
656 DE_NULL, // const void* pNext;
657 (VkPipelineDynamicStateCreateFlags)0, // VkPipelineDynamicStateCreateFlags flags;
658 static_cast<deUint32>(dynamicState.size()), // uint32_t dynamicStateCount;
659 dataOrNullPtr(dynamicState), // const VkDynamicState* pDynamicStates;
660 };
661
662 std::vector<VkPipelineShaderStageCreateInfo> pipelineShaderStageParams(2, {
663 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType
664 DE_NULL, // const void* pNext
665 0u, // VkPipelineShaderStageCreateFlags flags
666 VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage
667 vertexModule, // VkShaderModule module
668 "main", // const char* pName
669 DE_NULL // const VkSpecializationInfo* pSpecializationInfo
670 });
671
672 pipelineShaderStageParams[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
673 pipelineShaderStageParams[1].module = fragmentModule;
674
675 const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo
676 {
677 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType
678 DE_NULL, // const void* pNext
679 0u, // VkPipelineInputAssemblyStateCreateFlags flags
680 topology, // VkPrimitiveTopology topology
681 VK_FALSE // VkBool32 primitiveRestartEnable
682 };
683
684 const VkPipelineViewportStateCreateInfo viewportStateCreateInfo
685 {
686 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType
687 DE_NULL, // const void* pNext
688 (VkPipelineViewportStateCreateFlags)0, // VkPipelineViewportStateCreateFlags flags
689 1u, // deUint32 viewportCount
690 &viewport, // const VkViewport* pViewports
691 1u, // deUint32 scissorCount
692 &scissor // const VkRect2D* pScissors
693 };
694
695 const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfoDefault
696 {
697 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType
698 DE_NULL, // const void* pNext
699 0u, // VkPipelineRasterizationStateCreateFlags flags
700 VK_FALSE, // VkBool32 depthClampEnable
701 VK_FALSE, // VkBool32 rasterizerDiscardEnable
702 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode
703 VK_CULL_MODE_NONE, // VkCullModeFlags cullMode
704 VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace
705 VK_FALSE, // VkBool32 depthBiasEnable
706 0.0f, // float depthBiasConstantFactor
707 0.0f, // float depthBiasClamp
708 0.0f, // float depthBiasSlopeFactor
709 1.0f // float lineWidth
710 };
711
712 const VkPipelineColorBlendAttachmentState colorBlendAttachmentState
713 {
714 VK_FALSE, // VkBool32 blendEnable
715 VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcColorBlendFactor
716 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor
717 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp
718 VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcAlphaBlendFactor
719 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor
720 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp
721 VK_COLOR_COMPONENT_R_BIT // VkColorComponentFlags colorWriteMask
722 | VK_COLOR_COMPONENT_G_BIT
723 | VK_COLOR_COMPONENT_B_BIT
724 | VK_COLOR_COMPONENT_A_BIT
725 };
726
727 VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfoDefault = initVulkanStructure();
728 colorBlendStateCreateInfoDefault.attachmentCount = 1u;
729 colorBlendStateCreateInfoDefault.pAttachments = &colorBlendAttachmentState;
730
731 VkPipelineFragmentShadingRateStateCreateInfoKHR shadingRateStateCreateInfo
732 {
733 VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR, // VkStructureType sType;
734 DE_NULL, // const void* pNext;
735 { 2, 2 }, // VkExtent2D fragmentSize;
736 { VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR, VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR }, // VkFragmentShadingRateCombinerOpKHR combinerOps[2];
737 };
738
739 const VkGraphicsPipelineCreateInfo pipelineCreateInfo
740 {
741 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType
742 useFragmentShadingRate ? &shadingRateStateCreateInfo : DE_NULL, // const void* pNext
743 0u, // VkPipelineCreateFlags flags
744 (deUint32)pipelineShaderStageParams.size(), // deUint32 stageCount
745 &pipelineShaderStageParams[0], // const VkPipelineShaderStageCreateInfo* pStages
746 &vertexInputStateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState
747 &inputAssemblyStateCreateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState
748 DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState
749 &viewportStateCreateInfo, // const VkPipelineViewportStateCreateInfo* pViewportState
750 &rasterizationStateCreateInfoDefault, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState
751 &pipelineMultisampleStateInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState
752 &pipelineDepthStencilStateInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState
753 &colorBlendStateCreateInfoDefault, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState
754 &dynamicStateCreateInfo, // const VkPipelineDynamicStateCreateInfo* pDynamicState
755 pipelineLayout, // VkPipelineLayout layout
756 renderPass, // VkRenderPass renderPass
757 subpassIndex, // deUint32 subpass
758 DE_NULL, // VkPipeline basePipelineHandle
759 0 // deInt32 basePipelineIndex;
760 };
761
762 return createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
763 }
764
makeGraphicsPipelineSinglePassColor(const DeviceInterface & vk,const VkDevice device,const std::vector<VkDynamicState> & dynamicState,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const VkShaderModule vertexModule,const VkShaderModule fragmentModule,const VkViewport & viewport,const VkRect2D scissor,const VkSampleCountFlagBits numSamples,const bool useSampleLocations,const VkSampleLocationsInfoEXT & sampleLocationsInfo,const VertexInputConfig vertexInputConfig,const VkPrimitiveTopology topology,const bool useFragmentShadingRate)765 inline Move<VkPipeline> makeGraphicsPipelineSinglePassColor (const DeviceInterface& vk,
766 const VkDevice device,
767 const std::vector<VkDynamicState>& dynamicState,
768 const VkPipelineLayout pipelineLayout,
769 const VkRenderPass renderPass,
770 const VkShaderModule vertexModule,
771 const VkShaderModule fragmentModule,
772 const VkViewport& viewport,
773 const VkRect2D scissor,
774 const VkSampleCountFlagBits numSamples,
775 const bool useSampleLocations,
776 const VkSampleLocationsInfoEXT& sampleLocationsInfo,
777 const VertexInputConfig vertexInputConfig,
778 const VkPrimitiveTopology topology,
779 const bool useFragmentShadingRate)
780 {
781 return makeGraphicsPipeline(vk, device, dynamicState, pipelineLayout, renderPass, vertexModule, fragmentModule,
782 /*subpass*/ 0u, viewport, scissor, numSamples, useSampleLocations, sampleLocationsInfo,
783 /*depth test*/ false, /*stencil test*/ false, vertexInputConfig, topology, stencilOpStateIncrement(), useFragmentShadingRate);
784 }
785
786 //! Utility to build and maintain render pass, framebuffer and related resources.
787 //! Use bake() before using the render pass.
788 class RenderTarget
789 {
790 public:
RenderTarget(void)791 RenderTarget (void)
792 {
793 nextSubpass();
794 }
795
796 //! 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)797 deUint32 addAttachment (const VkImageView imageView,
798 const VkAttachmentDescriptionFlags flags,
799 const VkFormat format,
800 const VkSampleCountFlagBits numSamples,
801 const VkAttachmentLoadOp loadOp,
802 const VkAttachmentStoreOp storeOp,
803 const VkAttachmentLoadOp stencilLoadOp,
804 const VkAttachmentStoreOp stencilStoreOp,
805 const VkImageLayout initialLayout,
806 const VkImageLayout finalLayout,
807 const VkClearValue clearValue,
808 const VkSampleLocationsInfoEXT* pInitialSampleLocations = DE_NULL)
809 {
810 const deUint32 index = static_cast<deUint32>(m_attachments.size());
811
812 m_attachments.push_back(imageView);
813 m_attachmentDescriptions.push_back(makeAttachmentDescription(
814 flags, // VkAttachmentDescriptionFlags flags;
815 format, // VkFormat format;
816 numSamples, // VkSampleCountFlagBits samples;
817 loadOp, // VkAttachmentLoadOp loadOp;
818 storeOp, // VkAttachmentStoreOp storeOp;
819 stencilLoadOp, // VkAttachmentLoadOp stencilLoadOp;
820 stencilStoreOp, // VkAttachmentStoreOp stencilStoreOp;
821 initialLayout, // VkImageLayout initialLayout;
822 finalLayout // VkImageLayout finalLayout;
823 ));
824 m_clearValues.push_back(clearValue); // always add, even if unused
825
826 if (pInitialSampleLocations)
827 {
828 const VkAttachmentSampleLocationsEXT attachmentSampleLocations =
829 {
830 index, // uint32_t attachmentIndex;
831 *pInitialSampleLocations, // VkSampleLocationsInfoEXT sampleLocationsInfo;
832 };
833 m_attachmentSampleLocations.push_back(attachmentSampleLocations);
834 }
835
836 return index;
837 }
838
addSubpassColorAttachment(const deUint32 attachmentIndex,const VkImageLayout subpassLayout)839 void addSubpassColorAttachment (const deUint32 attachmentIndex, const VkImageLayout subpassLayout)
840 {
841 m_subpasses.back().colorAttachmentReferences.push_back(
842 makeAttachmentReference(attachmentIndex, subpassLayout));
843 m_subpasses.back().resolveAttachmentReferences.push_back(
844 makeAttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_UNDEFINED));
845 }
846
addSubpassColorAttachmentWithResolve(const deUint32 colorAttachmentIndex,const VkImageLayout colorSubpassLayout,const deUint32 resolveAttachmentIndex,const VkImageLayout resolveSubpassLayout)847 void addSubpassColorAttachmentWithResolve (const deUint32 colorAttachmentIndex, const VkImageLayout colorSubpassLayout, const deUint32 resolveAttachmentIndex, const VkImageLayout resolveSubpassLayout)
848 {
849 m_subpasses.back().colorAttachmentReferences.push_back(
850 makeAttachmentReference(colorAttachmentIndex, colorSubpassLayout));
851 m_subpasses.back().resolveAttachmentReferences.push_back(
852 makeAttachmentReference(resolveAttachmentIndex, resolveSubpassLayout));
853 }
854
addSubpassDepthStencilAttachment(const deUint32 attachmentIndex,const VkImageLayout subpassLayout,const VkSampleLocationsInfoEXT * pSampleLocations=DE_NULL)855 void addSubpassDepthStencilAttachment (const deUint32 attachmentIndex, const VkImageLayout subpassLayout, const VkSampleLocationsInfoEXT* pSampleLocations = DE_NULL)
856 {
857 m_subpasses.back().depthStencilAttachmentReferences.push_back(
858 makeAttachmentReference(attachmentIndex, subpassLayout));
859
860 if (pSampleLocations)
861 {
862 const VkSubpassSampleLocationsEXT subpassSampleLocations =
863 {
864 static_cast<deUint32>(m_subpasses.size() - 1), // uint32_t subpassIndex;
865 *pSampleLocations, // VkSampleLocationsInfoEXT sampleLocationsInfo;
866 };
867 m_subpassSampleLocations.push_back(subpassSampleLocations);
868 }
869 }
870
addSubpassInputAttachment(const deUint32 attachmentIndex,const VkImageLayout subpassLayout)871 void addSubpassInputAttachment (const deUint32 attachmentIndex, const VkImageLayout subpassLayout)
872 {
873 m_subpasses.back().inputAttachmentReferences.push_back(
874 makeAttachmentReference(attachmentIndex, subpassLayout));
875 }
876
addSubpassPreserveAttachment(const deUint32 attachmentIndex)877 void addSubpassPreserveAttachment (const deUint32 attachmentIndex)
878 {
879 m_subpasses.back().preserveAttachmentReferences.push_back(attachmentIndex);
880 }
881
nextSubpass(void)882 void nextSubpass (void)
883 {
884 m_subpasses.push_back(SubpassDescription());
885 }
886
887 //! Create a RenderPass and Framebuffer based on provided attachments
bake(const DeviceInterface & vk,const VkDevice device,const UVec2 & framebufferSize)888 void bake (const DeviceInterface& vk,
889 const VkDevice device,
890 const UVec2& framebufferSize)
891 {
892 DE_ASSERT(!m_renderPass);
893 const deUint32 numSubpasses = static_cast<deUint32>(m_subpasses.size());
894
895 std::vector<VkSubpassDescription> subpassDescriptions;
896 std::vector<VkSubpassDependency> subpassDependencies;
897 for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx)
898 {
899 const SubpassDescription& sd = m_subpasses[subpassNdx];
900 const VkSubpassDescription description =
901 {
902 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags;
903 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
904 static_cast<deUint32>(sd.inputAttachmentReferences.size()), // deUint32 inputAttachmentCount;
905 dataOrNullPtr(sd.inputAttachmentReferences), // const VkAttachmentReference* pInputAttachments;
906 static_cast<deUint32>(sd.colorAttachmentReferences.size()), // deUint32 colorAttachmentCount;
907 dataOrNullPtr(sd.colorAttachmentReferences), // const VkAttachmentReference* pColorAttachments;
908 dataOrNullPtr(sd.resolveAttachmentReferences), // const VkAttachmentReference* pResolveAttachments;
909 dataOrNullPtr(sd.depthStencilAttachmentReferences), // const VkAttachmentReference* pDepthStencilAttachment;
910 static_cast<deUint32>(sd.preserveAttachmentReferences.size()), // deUint32 preserveAttachmentCount;
911 dataOrNullPtr(sd.preserveAttachmentReferences) // const deUint32* pPreserveAttachments;
912 };
913 subpassDescriptions.push_back(description);
914
915 // Add a very coarse dependency enforcing sequential ordering of subpasses
916 if (subpassNdx > 0)
917 {
918 static const VkAccessFlags accessAny = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
919 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
920 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
921 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
922 | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
923 const VkSubpassDependency dependency =
924 {
925 subpassNdx - 1, // uint32_t srcSubpass;
926 subpassNdx, // uint32_t dstSubpass;
927 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, // VkPipelineStageFlags srcStageMask;
928 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, // VkPipelineStageFlags dstStageMask;
929 accessAny, // VkAccessFlags srcAccessMask;
930 accessAny, // VkAccessFlags dstAccessMask;
931 (VkDependencyFlags)0, // VkDependencyFlags dependencyFlags;
932 };
933 subpassDependencies.push_back(dependency);
934 }
935 }
936 // add a final dependency to synchronize results for the copy commands that will follow the renderpass
937 const VkSubpassDependency finalDependency = {
938 numSubpasses - 1, // uint32_t srcSubpass;
939 VK_SUBPASS_EXTERNAL, // uint32_t dstSubpass;
940 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags srcStageMask;
941 VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags dstStageMask;
942 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask;
943 VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
944 (VkDependencyFlags)0, // VkDependencyFlags dependencyFlags;
945 };
946 subpassDependencies.push_back(finalDependency);
947
948 const VkRenderPassCreateInfo renderPassInfo =
949 {
950 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
951 DE_NULL, // const void* pNext;
952 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags;
953 static_cast<deUint32>(m_attachmentDescriptions.size()), // deUint32 attachmentCount;
954 dataOrNullPtr(m_attachmentDescriptions), // const VkAttachmentDescription* pAttachments;
955 static_cast<deUint32>(subpassDescriptions.size()), // deUint32 subpassCount;
956 dataOrNullPtr(subpassDescriptions), // const VkSubpassDescription* pSubpasses;
957 static_cast<deUint32>(subpassDependencies.size()), // deUint32 dependencyCount;
958 dataOrNullPtr(subpassDependencies) // const VkSubpassDependency* pDependencies;
959 };
960
961 m_renderPass = createRenderPass(vk, device, &renderPassInfo);
962 m_framebuffer = makeFramebuffer (vk, device, *m_renderPass, static_cast<deUint32>(m_attachments.size()), dataOrNullPtr(m_attachments), framebufferSize.x(), framebufferSize.y());
963 }
964
getRenderPass(void) const965 VkRenderPass getRenderPass (void) const
966 {
967 DE_ASSERT(m_renderPass);
968 return *m_renderPass;
969 }
970
getFramebuffer(void) const971 VkFramebuffer getFramebuffer (void) const
972 {
973 DE_ASSERT(m_framebuffer);
974 return *m_framebuffer;
975 }
976
recordBeginRenderPass(const DeviceInterface & vk,const VkCommandBuffer cmdBuffer,const VkRect2D & renderArea,const VkSubpassContents subpassContents) const977 void recordBeginRenderPass (const DeviceInterface& vk,
978 const VkCommandBuffer cmdBuffer,
979 const VkRect2D& renderArea,
980 const VkSubpassContents subpassContents) const
981 {
982 DE_ASSERT(m_renderPass);
983 DE_ASSERT(m_framebuffer);
984
985 const VkRenderPassSampleLocationsBeginInfoEXT renderPassSampleLocationsBeginInfo =
986 {
987 VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT, // VkStructureType sType;
988 DE_NULL, // const void* pNext;
989 static_cast<deUint32>(m_attachmentSampleLocations.size()), // uint32_t attachmentInitialSampleLocationsCount;
990 dataOrNullPtr(m_attachmentSampleLocations), // const VkAttachmentSampleLocationsEXT* pAttachmentInitialSampleLocations;
991 static_cast<deUint32>(m_subpassSampleLocations.size()), // uint32_t postSubpassSampleLocationsCount;
992 dataOrNullPtr(m_subpassSampleLocations), // const VkSubpassSampleLocationsEXT* pPostSubpassSampleLocations;
993 };
994
995 const VkRenderPassBeginInfo renderPassBeginInfo =
996 {
997 VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
998 &renderPassSampleLocationsBeginInfo, // const void* pNext;
999 *m_renderPass, // VkRenderPass renderPass;
1000 *m_framebuffer, // VkFramebuffer framebuffer;
1001 renderArea, // VkRect2D renderArea;
1002 static_cast<deUint32>(m_clearValues.size()), // uint32_t clearValueCount;
1003 dataOrNullPtr(m_clearValues), // const VkClearValue* pClearValues;
1004 };
1005 vk.cmdBeginRenderPass(cmdBuffer, &renderPassBeginInfo, subpassContents);
1006 }
1007
1008 private:
1009 struct SubpassDescription
1010 {
1011 std::vector<VkAttachmentReference> inputAttachmentReferences;
1012 std::vector<VkAttachmentReference> colorAttachmentReferences;
1013 std::vector<VkAttachmentReference> resolveAttachmentReferences;
1014 std::vector<VkAttachmentReference> depthStencilAttachmentReferences;
1015 std::vector<deUint32> preserveAttachmentReferences;
1016 };
1017
1018 std::vector<SubpassDescription> m_subpasses;
1019 std::vector<VkImageView> m_attachments;
1020 std::vector<VkAttachmentDescription> m_attachmentDescriptions;
1021 std::vector<VkClearValue> m_clearValues;
1022 std::vector<VkAttachmentSampleLocationsEXT> m_attachmentSampleLocations;
1023 std::vector<VkSubpassSampleLocationsEXT> m_subpassSampleLocations;
1024 Move<VkRenderPass> m_renderPass;
1025 Move<VkFramebuffer> m_framebuffer;
1026
1027 // No copying allowed
1028 RenderTarget (const RenderTarget&);
1029 RenderTarget& operator=(const RenderTarget&);
1030 };
1031
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)1032 void recordImageBarrier (const DeviceInterface& vk,
1033 const VkCommandBuffer cmdBuffer,
1034 const VkImage image,
1035 const VkImageAspectFlags aspect,
1036 const VkPipelineStageFlags srcStageMask,
1037 const VkPipelineStageFlags dstStageMask,
1038 const VkAccessFlags srcAccessMask,
1039 const VkAccessFlags dstAccessMask,
1040 const VkImageLayout oldLayout,
1041 const VkImageLayout newLayout,
1042 const VkSampleLocationsInfoEXT* pSampleLocationsInfo = DE_NULL)
1043 {
1044 const VkImageMemoryBarrier barrier =
1045 {
1046 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1047 pSampleLocationsInfo, // const void* pNext;
1048 srcAccessMask, // VkAccessFlags srcAccessMask;
1049 dstAccessMask, // VkAccessFlags dstAccessMask;
1050 oldLayout, // VkImageLayout oldLayout;
1051 newLayout, // VkImageLayout newLayout;
1052 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1053 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1054 image, // VkImage image;
1055 makeImageSubresourceRange(aspect, 0u, 1u, 0u, 1u), // VkImageSubresourceRange subresourceRange;
1056 };
1057
1058 vk.cmdPipelineBarrier(cmdBuffer, srcStageMask, dstStageMask, (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
1059 }
1060
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)1061 void recordWaitEventWithImage (const DeviceInterface& vk,
1062 const VkCommandBuffer cmdBuffer,
1063 const VkEvent event,
1064 const VkImage image,
1065 const VkImageAspectFlags aspect,
1066 const VkPipelineStageFlags srcStageMask,
1067 const VkPipelineStageFlags dstStageMask,
1068 const VkAccessFlags srcAccessMask,
1069 const VkAccessFlags dstAccessMask,
1070 const VkImageLayout oldLayout,
1071 const VkImageLayout newLayout,
1072 const VkSampleLocationsInfoEXT* pSampleLocationsInfo = DE_NULL)
1073 {
1074 const VkImageMemoryBarrier barrier =
1075 {
1076 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1077 pSampleLocationsInfo, // const void* pNext;
1078 srcAccessMask, // VkAccessFlags srcAccessMask;
1079 dstAccessMask, // VkAccessFlags dstAccessMask;
1080 oldLayout, // VkImageLayout oldLayout;
1081 newLayout, // VkImageLayout newLayout;
1082 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1083 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1084 image, // VkImage image;
1085 makeImageSubresourceRange(aspect, 0u, 1u, 0u, 1u), // VkImageSubresourceRange subresourceRange;
1086 };
1087
1088 vk.cmdWaitEvents(
1089 cmdBuffer, // VkCommandBuffer commandBuffer,
1090 1u, // uint32_t eventCount,
1091 &event, // const VkEvent* pEvents,
1092 srcStageMask, // VkPipelineStageFlags srcStageMask,
1093 dstStageMask, // VkPipelineStageFlags dstStageMask,
1094 0u, // uint32_t memoryBarrierCount,
1095 DE_NULL, // const VkMemoryBarrier* pMemoryBarriers,
1096 0u, // uint32_t bufferMemoryBarrierCount,
1097 DE_NULL, // const VkBufferMemoryBarrier* pBufferMemoryBarriers,
1098 1u, // uint32_t imageMemoryBarrierCount,
1099 &barrier); // const VkImageMemoryBarrier* pImageMemoryBarriers);
1100 }
1101
recordCopyImageToBuffer(const DeviceInterface & vk,const VkCommandBuffer cmdBuffer,const UVec2 & imageSize,const VkImage srcImage,const VkBuffer dstBuffer)1102 void recordCopyImageToBuffer (const DeviceInterface& vk,
1103 const VkCommandBuffer cmdBuffer,
1104 const UVec2& imageSize,
1105 const VkImage srcImage,
1106 const VkBuffer dstBuffer)
1107 {
1108 // Resolve image -> host buffer
1109 {
1110 const VkBufferImageCopy region =
1111 {
1112 0ull, // VkDeviceSize bufferOffset;
1113 0u, // uint32_t bufferRowLength;
1114 0u, // uint32_t bufferImageHeight;
1115 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u), // VkImageSubresourceLayers imageSubresource;
1116 makeOffset3D(0, 0, 0), // VkOffset3D imageOffset;
1117 makeExtent3D(imageSize.x(), imageSize.y(), 1u), // VkExtent3D imageExtent;
1118 };
1119
1120 vk.cmdCopyImageToBuffer(cmdBuffer, srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstBuffer, 1u, ®ion);
1121 }
1122 // Buffer write barrier
1123 {
1124 const VkBufferMemoryBarrier barrier =
1125 {
1126 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
1127 DE_NULL, // const void* pNext;
1128 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
1129 VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
1130 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1131 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1132 dstBuffer, // VkBuffer buffer;
1133 0ull, // VkDeviceSize offset;
1134 VK_WHOLE_SIZE, // VkDeviceSize size;
1135 };
1136
1137 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
1138 0u, DE_NULL, 1u, &barrier, DE_NULL, 0u);
1139 }
1140 }
1141
recordClearAttachments(const DeviceInterface & vk,const VkCommandBuffer cmdBuffer,const deUint32 colorAttachment,const VkClearValue & colorClearValue,const VkImageAspectFlags depthStencilAspect,const VkClearValue & depthStencilClearValue,const VkRect2D & clearRect)1142 void recordClearAttachments (const DeviceInterface& vk,
1143 const VkCommandBuffer cmdBuffer,
1144 const deUint32 colorAttachment,
1145 const VkClearValue& colorClearValue,
1146 const VkImageAspectFlags depthStencilAspect,
1147 const VkClearValue& depthStencilClearValue,
1148 const VkRect2D& clearRect)
1149 {
1150 std::vector<VkClearAttachment> attachments;
1151
1152 const VkClearRect rect =
1153 {
1154 clearRect, // VkRect2D rect;
1155 0u, // uint32_t baseArrayLayer;
1156 1u, // uint32_t layerCount;
1157 };
1158
1159 // Clear color
1160 {
1161 const VkClearAttachment attachment =
1162 {
1163 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
1164 colorAttachment, // uint32_t colorAttachment;
1165 colorClearValue, // VkClearValue clearValue;
1166 };
1167 attachments.push_back(attachment);
1168 }
1169
1170 if ((depthStencilAspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0u)
1171 {
1172 const VkClearAttachment attachment =
1173 {
1174 depthStencilAspect, // VkImageAspectFlags aspectMask;
1175 VK_ATTACHMENT_UNUSED, // uint32_t colorAttachment;
1176 depthStencilClearValue, // VkClearValue clearValue;
1177 };
1178 attachments.push_back(attachment);
1179 }
1180
1181 vk.cmdClearAttachments(cmdBuffer, static_cast<deUint32>(attachments.size()), dataOrNullPtr(attachments), 1u, &rect);
1182 }
1183
1184 //! 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)1185 void beginSecondaryCommandBuffer (const DeviceInterface& vk,
1186 const VkCommandBuffer commandBuffer,
1187 const VkRenderPass renderPass,
1188 const deUint32 subpass,
1189 const VkFramebuffer framebuffer)
1190 {
1191 const VkCommandBufferInheritanceInfo inheritanceInfo =
1192 {
1193 VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, // VkStructureType sType;
1194 DE_NULL, // const void* pNext;
1195 renderPass, // VkRenderPass renderPass;
1196 subpass, // uint32_t subpass;
1197 framebuffer, // VkFramebuffer framebuffer;
1198 VK_FALSE, // VkBool32 occlusionQueryEnable;
1199 (VkQueryControlFlags)0, // VkQueryControlFlags queryFlags;
1200 (VkQueryPipelineStatisticFlags)0, // VkQueryPipelineStatisticFlags pipelineStatistics;
1201 };
1202 const VkCommandBufferBeginInfo beginInfo =
1203 {
1204 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
1205 DE_NULL, // const void* pNext;
1206 (VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
1207 |VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT), // VkCommandBufferUsageFlags flags;
1208 &inheritanceInfo, // const VkCommandBufferInheritanceInfo* pInheritanceInfo;
1209 };
1210 VK_CHECK(vk.beginCommandBuffer(commandBuffer, &beginInfo));
1211 }
1212
1213 //! Verify results of a VkPhysicalDeviceSampleLocationsPropertiesEXT query with VkPhysicalDeviceProperties2KHR
testQuerySampleLocationProperties(Context & context)1214 tcu::TestStatus testQuerySampleLocationProperties (Context& context)
1215 {
1216 const VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationsProperties = getSampleLocationsPropertiesEXT(context);
1217
1218 context.getTestContext().getLog()
1219 << tcu::TestLog::Section("VkPhysicalDeviceSampleLocationsPropertiesEXT", "Query results")
1220 << tcu::TestLog::Message << sampleLocationsProperties << tcu::TestLog::EndMessage
1221 << tcu::TestLog::EndSection;
1222
1223 const VkSampleCountFlags allowedSampleCounts = (VK_SAMPLE_COUNT_2_BIT |
1224 VK_SAMPLE_COUNT_4_BIT |
1225 VK_SAMPLE_COUNT_8_BIT |
1226 VK_SAMPLE_COUNT_16_BIT |
1227 VK_SAMPLE_COUNT_32_BIT |
1228 VK_SAMPLE_COUNT_64_BIT);
1229
1230 if ((sampleLocationsProperties.sampleLocationSampleCounts & allowedSampleCounts) == 0)
1231 {
1232 return tcu::TestStatus::fail("VkPhysicalDeviceSampleLocationsPropertiesEXT: sampleLocationSampleCounts should specify at least one MSAA sample count");
1233 }
1234
1235 if (sampleLocationsProperties.maxSampleLocationGridSize.width == 0u ||
1236 sampleLocationsProperties.maxSampleLocationGridSize.height == 0u ||
1237 sampleLocationsProperties.maxSampleLocationGridSize.width > 16384u || // max not specified, but try to catch nonsense values like -1
1238 sampleLocationsProperties.maxSampleLocationGridSize.height > 16384u)
1239 {
1240 return tcu::TestStatus::fail("VkPhysicalDeviceSampleLocationsPropertiesEXT: maxSampleLocationGridSize must be at least (1,1) size");
1241 }
1242
1243 for (int i = 0; i < 2; ++i)
1244 {
1245 if (sampleLocationsProperties.sampleLocationCoordinateRange[i] < 0.0f ||
1246 sampleLocationsProperties.sampleLocationCoordinateRange[i] > 1.0f)
1247 {
1248 return tcu::TestStatus::fail("VkPhysicalDeviceSampleLocationsPropertiesEXT: sampleLocationCoordinateRange[] values must be in [0, 1] range");
1249 }
1250 }
1251
1252 if (sampleLocationsProperties.sampleLocationSubPixelBits == 0u ||
1253 sampleLocationsProperties.sampleLocationSubPixelBits > 64u) // max not specified, but try to catch nonsense values
1254 {
1255 return tcu::TestStatus::fail("VkPhysicalDeviceSampleLocationsPropertiesEXT: sampleLocationSubPixelBits should be greater than 0");
1256 }
1257
1258 return tcu::TestStatus::pass("Pass");
1259 }
1260
1261 //! Verify results of vkGetPhysicalDeviceMultisamplePropertiesEXT queries
testQueryMultisampleProperties(Context & context)1262 tcu::TestStatus testQueryMultisampleProperties (Context& context)
1263 {
1264 const InstanceInterface& vki = context.getInstanceInterface();
1265 const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
1266 tcu::TestLog& log = context.getTestContext().getLog();
1267
1268 const VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationsProperties = getSampleLocationsPropertiesEXT(context);
1269
1270 const VkSampleCountFlagBits sampleCountRange[] =
1271 {
1272 VK_SAMPLE_COUNT_1_BIT,
1273 VK_SAMPLE_COUNT_2_BIT,
1274 VK_SAMPLE_COUNT_4_BIT,
1275 VK_SAMPLE_COUNT_8_BIT,
1276 VK_SAMPLE_COUNT_16_BIT,
1277 VK_SAMPLE_COUNT_32_BIT,
1278 VK_SAMPLE_COUNT_64_BIT,
1279 };
1280
1281 bool allOk = true;
1282
1283 for (const VkSampleCountFlagBits* pLoopNumSamples = sampleCountRange; pLoopNumSamples < DE_ARRAY_END(sampleCountRange); ++pLoopNumSamples)
1284 {
1285 VkMultisamplePropertiesEXT multisampleProperties =
1286 {
1287 VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT, // VkStructureType sType;
1288 DE_NULL, // void* pNext;
1289 VkExtent2D(), // VkExtent2D maxSampleLocationGridSize;
1290 };
1291
1292 vki.getPhysicalDeviceMultisamplePropertiesEXT(physicalDevice, *pLoopNumSamples, &multisampleProperties);
1293
1294 log << tcu::TestLog::Section("getPhysicalDeviceMultisamplePropertiesEXT", "Query results")
1295 << tcu::TestLog::Message << "Sample count: " << *pLoopNumSamples << tcu::TestLog::EndMessage
1296 << tcu::TestLog::Message << multisampleProperties << tcu::TestLog::EndMessage;
1297
1298 const bool isSupportedSampleCount = (*pLoopNumSamples & sampleLocationsProperties.sampleLocationSampleCounts) != 0;
1299
1300 if (isSupportedSampleCount)
1301 {
1302 if (!(multisampleProperties.maxSampleLocationGridSize.width >= sampleLocationsProperties.maxSampleLocationGridSize.width &&
1303 multisampleProperties.maxSampleLocationGridSize.height >= sampleLocationsProperties.maxSampleLocationGridSize.height))
1304 {
1305 allOk = false;
1306 log << tcu::TestLog::Message
1307 << "FAIL: Grid size should be the same or larger than VkPhysicalDeviceSampleLocationsPropertiesEXT::maxSampleLocationGridSize"
1308 << tcu::TestLog::EndMessage;
1309 }
1310 }
1311 else
1312 {
1313 if (!(multisampleProperties.maxSampleLocationGridSize.width == 0u &&
1314 multisampleProperties.maxSampleLocationGridSize.height == 0u))
1315 {
1316 allOk = false;
1317 log << tcu::TestLog::Message << "FAIL: Expected (0, 0) grid size" << tcu::TestLog::EndMessage;
1318 }
1319 }
1320
1321 log << tcu::TestLog::EndSection;
1322 }
1323
1324 return allOk ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Some values were incorrect");
1325 }
1326
1327 // These tests only use a color attachment and focus on per-sample data
1328 namespace VerifySamples
1329 {
1330
1331 //! Data layout used in verify sample locations and interpolation cases
1332 namespace SampleDataSSBO
1333 {
1334
1335 static VkDeviceSize STATIC_SIZE = 6 * sizeof(deUint32);
1336
renderSize(void * const basePtr)1337 static UVec2& renderSize (void* const basePtr) { return *reinterpret_cast<UVec2*> (static_cast<deUint8*>(basePtr) + 0 * sizeof(deUint32)); }
gridSize(void * const basePtr)1338 static UVec2& gridSize (void* const basePtr) { return *reinterpret_cast<UVec2*> (static_cast<deUint8*>(basePtr) + 2 * sizeof(deUint32)); }
samplesPerPixel(void * const basePtr)1339 static deUint32& samplesPerPixel (void* const basePtr) { return *reinterpret_cast<deUint32*> (static_cast<deUint8*>(basePtr) + 4 * sizeof(deUint32)); }
1340
1341 template<typename T>
sampleData(void * const basePtr)1342 static T* sampleData (void* const basePtr) { DE_STATIC_ASSERT(sizeof(T) == sizeof(Vec2));
1343 return reinterpret_cast<T*> (static_cast<deUint8*>(basePtr) + STATIC_SIZE); }
1344
1345 } // SampleDataSSBO
1346
1347 enum TestOptionFlagBits
1348 {
1349 TEST_OPTION_DYNAMIC_STATE_BIT = 0x1, //!< Use dynamic pipeline state to pass in sample locations
1350 TEST_OPTION_CLOSELY_PACKED_BIT = 0x2, //!< Place samples as close as possible to each other
1351 TEST_OPTION_FRAGMENT_SHADING_RATE_BIT = 0x4, //!< Use VK_KHR_fragment_shading_rate
1352
1353 };
1354 typedef deUint32 TestOptionFlags;
1355
1356 struct TestParams
1357 {
1358 VkSampleCountFlagBits numSamples;
1359 TestOptionFlags options;
1360 };
1361
checkSupportVerifyTests(Context & context,const TestParams params)1362 void checkSupportVerifyTests (Context& context, const TestParams params)
1363 {
1364 checkSupportSampleLocations(context);
1365
1366 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
1367
1368 if ((context.getDeviceProperties().limits.framebufferColorSampleCounts & params.numSamples) == 0u)
1369 TCU_THROW(NotSupportedError, "framebufferColorSampleCounts: sample count not supported");
1370
1371 if ((getSampleLocationsPropertiesEXT(context).sampleLocationSampleCounts & params.numSamples) == 0u)
1372 TCU_THROW(NotSupportedError, "VkPhysicalDeviceSampleLocationsPropertiesEXT: sample count not supported");
1373
1374 if (TEST_OPTION_FRAGMENT_SHADING_RATE_BIT & params.options)
1375 checkFragmentShadingRateRequirements(context, params.numSamples);
1376 }
1377
declareSampleDataSSBO(void)1378 std::string declareSampleDataSSBO (void)
1379 {
1380 std::ostringstream str;
1381 str << "layout(set = 0, binding = 0, std430) readonly buffer SampleData {\n" // make sure this matches SampleDataSSBO definition
1382 << " uvec2 renderSize;\n"
1383 << " uvec2 gridSize;\n"
1384 << " uint samplesPerPixel;\n"
1385 << " // padding 1-uint size;\n"
1386 << " vec2 data[];\n"
1387 << "} sb_data;\n";
1388 return str.str();
1389 }
1390
addProgramsVerifyLocationGeometry(SourceCollections & programCollection,const TestParams)1391 void addProgramsVerifyLocationGeometry (SourceCollections& programCollection, const TestParams)
1392 {
1393 // Vertex shader
1394 {
1395 std::ostringstream src;
1396 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1397 << "\n"
1398 << "layout(location = 0) in vec4 in_position;\n"
1399 << "\n"
1400 << "out gl_PerVertex {\n"
1401 << " vec4 gl_Position;\n"
1402 << "};\n"
1403 << "\n"
1404 << "void main(void)\n"
1405 << "{\n"
1406 << " gl_Position = in_position;\n"
1407 << "}\n";
1408
1409 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
1410 }
1411
1412 // Fragment shader
1413 {
1414 std::ostringstream src;
1415 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1416 << "\n"
1417 << "layout(location = 0) out vec4 o_color;\n"
1418 << "\n"
1419 << declareSampleDataSSBO()
1420 << "\n"
1421 << "void main(void)\n"
1422 << "{\n"
1423 << " uvec2 fragCoord = uvec2(gl_FragCoord.xy);\n"
1424 << " uint index = (fragCoord.y * sb_data.renderSize.x + fragCoord.x) * sb_data.samplesPerPixel + gl_SampleID;\n"
1425 << "\n"
1426 << " if (gl_PrimitiveID == index)\n"
1427 << " o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
1428 << " else\n"
1429 << " o_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
1430 << "}\n";
1431
1432 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
1433 }
1434 }
1435
addProgramsVerifyInterpolation(SourceCollections & programCollection,const TestParams)1436 void addProgramsVerifyInterpolation (SourceCollections& programCollection, const TestParams)
1437 {
1438 // Vertex shader
1439 {
1440 std::ostringstream src;
1441 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1442 << "\n"
1443 << "layout(location = 0) in vec4 in_position;\n"
1444 << "layout(location = 0) out vec2 o_position;\n"
1445 << "\n"
1446 << "out gl_PerVertex {\n"
1447 << " vec4 gl_Position;\n"
1448 << "};\n"
1449 << "\n"
1450 << "void main(void)\n"
1451 << "{\n"
1452 << " gl_Position = in_position;\n"
1453 << " o_position = in_position.xy;\n" // user-data that will be interpolated
1454 << "}\n";
1455
1456 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
1457 }
1458
1459 // Fragment shader
1460 {
1461 std::ostringstream src;
1462 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1463 << "\n"
1464 << "layout(location = 0) sample in vec2 in_value;\n"
1465 << "layout(location = 0) out vec4 o_color;\n"
1466 << "\n"
1467 << declareSampleDataSSBO()
1468 << "\n"
1469 << "void main(void)\n"
1470 << "{\n"
1471 << " uvec2 fragCoord = uvec2(gl_FragCoord.xy);\n"
1472 << " uint index = (fragCoord.y * sb_data.renderSize.x + fragCoord.x) * sb_data.samplesPerPixel + gl_SampleID;\n"
1473 << " vec2 diff = abs(sb_data.data[index] - in_value);\n"
1474 << " vec2 threshold = vec2(0.002);\n"
1475 << "\n"
1476 << " if (all(lessThan(diff, threshold)))\n"
1477 << " o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
1478 << " else\n"
1479 << " o_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
1480 << "}\n";
1481
1482 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
1483 }
1484 }
1485
1486 class TestBase : public TestInstance
1487 {
1488 public:
TestBase(Context & context,const TestParams params)1489 TestBase (Context& context, const TestParams params)
1490 : TestInstance (context)
1491 , m_params (params)
1492 , m_sampleLocationsProperties (getSampleLocationsPropertiesEXT(context))
1493 , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
1494 , m_numVertices (0)
1495 , m_currentGridNdx (0)
1496 {
1497 VkMultisamplePropertiesEXT multisampleProperties =
1498 {
1499 VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT, // VkStructureType sType;
1500 DE_NULL, // void* pNext;
1501 VkExtent2D(), // VkExtent2D maxSampleLocationGridSize;
1502 };
1503
1504 m_context.getInstanceInterface().getPhysicalDeviceMultisamplePropertiesEXT(m_context.getPhysicalDevice(), m_params.numSamples, &multisampleProperties);
1505
1506 // Generate grid size combinations
1507 for (deUint32 y = multisampleProperties.maxSampleLocationGridSize.height; y >= 1u; y >>= 1)
1508 for (deUint32 x = multisampleProperties.maxSampleLocationGridSize.width; x >= 1u; x >>= 1)
1509 {
1510 DE_ASSERT(multisampleProperties.maxSampleLocationGridSize.width % x == 0u);
1511 DE_ASSERT(multisampleProperties.maxSampleLocationGridSize.height % y == 0u);
1512 m_gridSizes.push_back(UVec2(x, y));
1513 }
1514 }
1515
iterate(void)1516 tcu::TestStatus iterate (void)
1517 {
1518 // Will be executed several times, for all possible pixel grid sizes
1519 if (!(currentGridSize().x() >= 1 && currentGridSize().y() >= 1))
1520 return tcu::TestStatus::fail("maxSampleLocationGridSize is invalid");
1521
1522 // Prepare the pixel grid
1523 {
1524 const deUint32 pixelGridRepetitions = 2; // just to make sure the pattern is consistently applied across the framebuffer
1525 m_renderSize = UVec2(pixelGridRepetitions * currentGridSize().x(),
1526 pixelGridRepetitions * currentGridSize().y());
1527 m_pixelGrid = MovePtr<MultisamplePixelGrid>(new MultisamplePixelGrid(currentGridSize(), m_params.numSamples));
1528
1529 if ((m_params.options & TEST_OPTION_CLOSELY_PACKED_BIT) != 0u)
1530 fillSampleLocationsPacked(*m_pixelGrid, m_sampleLocationsProperties.sampleLocationSubPixelBits);
1531 else
1532 fillSampleLocationsRandom(*m_pixelGrid, m_sampleLocationsProperties.sampleLocationSubPixelBits);
1533
1534 logPixelGrid (m_context.getTestContext().getLog(), m_sampleLocationsProperties, *m_pixelGrid);
1535 }
1536
1537 // Create images
1538 {
1539 const DeviceInterface& vk = m_context.getDeviceInterface();
1540 const VkDevice device = m_context.getDevice();
1541 Allocator& allocator = m_context.getDefaultAllocator();
1542
1543 // Images and staging buffers
1544
1545 m_colorImage = makeImage(vk, device, (VkImageCreateFlags)0, m_colorFormat, m_renderSize, m_params.numSamples, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
1546 m_colorImageAlloc = bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
1547 m_colorImageView = makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
1548
1549 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);
1550 m_resolveImageAlloc = bindImage(vk, device, allocator, *m_resolveImage, MemoryRequirement::Any);
1551 m_resolveImageView = makeImageView(vk, device, *m_resolveImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
1552
1553 const VkDeviceSize colorBufferSize = m_renderSize.x() * m_renderSize.y() * tcu::getPixelSize(mapVkFormat(m_colorFormat));
1554 m_colorBuffer = makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
1555 m_colorBufferAlloc = bindBuffer(vk, device, allocator, *m_colorBuffer, MemoryRequirement::HostVisible);
1556 }
1557
1558 if (!testPixelGrid())
1559 return tcu::TestStatus::fail("Fail");
1560
1561 if (shrinkCurrentGrid())
1562 return tcu::TestStatus::incomplete();
1563 else
1564 return tcu::TestStatus::pass("Pass");
1565 }
1566
1567 protected:
1568 //! Return true if the test passed the current grid size
1569 virtual bool testPixelGrid (void) = 0;
1570
currentGridSize(void)1571 const UVec2& currentGridSize (void)
1572 {
1573 return m_gridSizes[m_currentGridNdx];
1574 }
1575
1576 //! Return false if the grid is already at (1, 1) size
shrinkCurrentGrid(void)1577 bool shrinkCurrentGrid (void)
1578 {
1579 if (m_gridSizes.size() <= m_currentGridNdx + 1)
1580 return false;
1581
1582 ++m_currentGridNdx;
1583 return true;
1584 }
1585
drawSinglePass(const VertexInputConfig vertexInputConfig)1586 void drawSinglePass (const VertexInputConfig vertexInputConfig)
1587 {
1588 DE_ASSERT(m_descriptorSetLayout);
1589
1590 const DeviceInterface& vk = m_context.getDeviceInterface();
1591 const VkDevice device = m_context.getDevice();
1592 const VkViewport viewport = makeViewport(m_renderSize);
1593 const VkRect2D renderArea = makeRect2D(m_renderSize);
1594 const VkRect2D scissor = makeRect2D(m_renderSize);
1595 const Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
1596 const Unique<VkShaderModule> fragmentModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
1597 const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *m_descriptorSetLayout));
1598
1599 const bool useDynamicStateSampleLocations = ((m_params.options & TEST_OPTION_DYNAMIC_STATE_BIT) != 0u);
1600 const bool useFragmentShadingRate = ((m_params.options & TEST_OPTION_FRAGMENT_SHADING_RATE_BIT) != 0u);
1601 const VkSampleLocationsInfoEXT sampleLocationsInfo = makeSampleLocationsInfo(*m_pixelGrid);
1602
1603 RenderTarget rt;
1604
1605 rt.addAttachment(
1606 *m_colorImageView, // VkImageView imageView,
1607 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
1608 m_colorFormat, // VkFormat format,
1609 m_params.numSamples, // VkSampleCountFlagBits numSamples,
1610 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
1611 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
1612 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
1613 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
1614 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
1615 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
1616 makeClearValueColor(CLEAR_COLOR_0)); // VkClearValue clearValue,
1617
1618 rt.addAttachment(
1619 *m_resolveImageView, // VkImageView imageView,
1620 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
1621 m_colorFormat, // VkFormat format,
1622 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits numSamples,
1623 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp,
1624 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
1625 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
1626 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
1627 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
1628 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout finalLayout,
1629 VkClearValue()); // VkClearValue clearValue,
1630
1631 rt.addSubpassColorAttachmentWithResolve(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1632 1u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
1633
1634 rt.bake(vk, device, m_renderSize);
1635
1636 Move<VkPipeline> pipeline;
1637
1638 if (useDynamicStateSampleLocations)
1639 {
1640 std::vector<VkDynamicState> dynamicState;
1641 dynamicState.push_back(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
1642
1643 pipeline = makeGraphicsPipelineSinglePassColor(
1644 vk, device, dynamicState, *pipelineLayout, rt.getRenderPass(), *vertexModule, *fragmentModule, viewport, scissor,
1645 m_params.numSamples, /*use sample locations*/ true, makeEmptySampleLocationsInfo(), vertexInputConfig, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, useFragmentShadingRate);
1646 }
1647 else
1648 {
1649 pipeline = makeGraphicsPipelineSinglePassColor(
1650 vk, device, std::vector<VkDynamicState>(), *pipelineLayout, rt.getRenderPass(), *vertexModule, *fragmentModule, viewport, scissor,
1651 m_params.numSamples, /*use sample locations*/ true, sampleLocationsInfo, vertexInputConfig, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, useFragmentShadingRate);
1652 }
1653
1654 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
1655 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
1656
1657 beginCommandBuffer(vk, *cmdBuffer);
1658
1659 rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
1660
1661 vk.cmdBindVertexBuffers(*cmdBuffer, /*first binding*/ 0u, /*num bindings*/ 1u, &m_vertexBuffer.get(), /*offsets*/ &ZERO);
1662 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1663
1664 if (useDynamicStateSampleLocations)
1665 vk.cmdSetSampleLocationsEXT(*cmdBuffer, &sampleLocationsInfo);
1666
1667 if (m_descriptorSet)
1668 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &m_descriptorSet.get(), 0u, DE_NULL);
1669
1670 vk.cmdDraw(*cmdBuffer, m_numVertices, 1u, 0u, 0u);
1671 endRenderPass(vk, *cmdBuffer);
1672
1673 recordCopyImageToBuffer(vk, *cmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
1674
1675 endCommandBuffer(vk, *cmdBuffer);
1676 submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
1677
1678 invalidateAlloc(vk, device, *m_colorBufferAlloc);
1679 }
1680
createSampleDataBufferAndDescriptors(const VkDeviceSize bufferSize)1681 void createSampleDataBufferAndDescriptors (const VkDeviceSize bufferSize)
1682 {
1683 // Make sure the old descriptor set is destroyed before we destroy its pool
1684 m_descriptorSet = Move<VkDescriptorSet>();
1685
1686 const DeviceInterface& vk = m_context.getDeviceInterface();
1687 const VkDevice device = m_context.getDevice();
1688 Allocator& allocator = m_context.getDefaultAllocator();
1689
1690 m_sampleDataBuffer = makeBuffer(vk, device, bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1691 m_sampleDataBufferAlloc = bindBuffer(vk, device, allocator, *m_sampleDataBuffer, MemoryRequirement::HostVisible);
1692
1693 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
1694 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT)
1695 .build(vk, device);
1696
1697 m_descriptorPool = DescriptorPoolBuilder()
1698 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
1699 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1700
1701 m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
1702
1703 const VkDescriptorBufferInfo bufferDescriptorInfo = makeDescriptorBufferInfo(*m_sampleDataBuffer, 0ull, bufferSize);
1704 DescriptorSetUpdateBuilder()
1705 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferDescriptorInfo)
1706 .update(vk, device);
1707
1708 SampleDataSSBO::renderSize (m_sampleDataBufferAlloc->getHostPtr()) = m_renderSize;
1709 SampleDataSSBO::gridSize (m_sampleDataBufferAlloc->getHostPtr()) = m_pixelGrid->size();
1710 SampleDataSSBO::samplesPerPixel (m_sampleDataBufferAlloc->getHostPtr()) = m_pixelGrid->samplesPerPixel();
1711
1712 flushAlloc(vk, device, *m_sampleDataBufferAlloc);
1713 }
1714
1715 template<typename Vertex>
createVertexBuffer(const std::vector<Vertex> & vertices)1716 void createVertexBuffer (const std::vector<Vertex>& vertices)
1717 {
1718 const DeviceInterface& vk = m_context.getDeviceInterface();
1719 const VkDevice device = m_context.getDevice();
1720 Allocator& allocator = m_context.getDefaultAllocator();
1721 const VkDeviceSize vertexBufferSize = static_cast<VkDeviceSize>(vertices.size() * sizeof(vertices[0]));
1722
1723 m_numVertices = static_cast<deUint32>(vertices.size());
1724 m_vertexBuffer = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1725 m_vertexBufferAlloc = bindBuffer(vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
1726
1727 deMemcpy(m_vertexBufferAlloc->getHostPtr(), dataOrNullPtr(vertices), static_cast<std::size_t>(vertexBufferSize));
1728 flushAlloc(vk, device, *m_vertexBufferAlloc);
1729 }
1730
1731 const TestParams m_params;
1732 const VkPhysicalDeviceSampleLocationsPropertiesEXT m_sampleLocationsProperties;
1733 const VkFormat m_colorFormat;
1734 UVec2 m_renderSize;
1735 MovePtr<MultisamplePixelGrid> m_pixelGrid;
1736 deUint32 m_numVertices;
1737 Move<VkBuffer> m_vertexBuffer;
1738 MovePtr<Allocation> m_vertexBufferAlloc;
1739 Move<VkImage> m_colorImage;
1740 Move<VkImageView> m_colorImageView;
1741 MovePtr<Allocation> m_colorImageAlloc;
1742 Move<VkImage> m_resolveImage;
1743 Move<VkImageView> m_resolveImageView;
1744 MovePtr<Allocation> m_resolveImageAlloc;
1745 Move<VkBuffer> m_colorBuffer;
1746 MovePtr<Allocation> m_colorBufferAlloc;
1747 Move<VkBuffer> m_sampleDataBuffer;
1748 MovePtr<Allocation> m_sampleDataBufferAlloc;
1749 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
1750 Move<VkDescriptorPool> m_descriptorPool;
1751 Move<VkDescriptorSet> m_descriptorSet;
1752
1753 private:
1754 deUint32 m_currentGridNdx;
1755 std::vector<UVec2> m_gridSizes;
1756 };
1757
1758 //! Check that each custom sample has the expected position
1759 class VerifyLocationTest : public TestBase
1760 {
1761 public:
VerifyLocationTest(Context & context,const TestParams params)1762 VerifyLocationTest (Context& context, const TestParams params) : TestBase(context, params) {}
1763
testPixelGrid(void)1764 bool testPixelGrid (void)
1765 {
1766 // Create vertices
1767 {
1768 // For each sample location (in the whole framebuffer), create a sub-pixel triangle that contains it.
1769 // NDC viewport size is 2.0 in X and Y and NDC pixel width/height depends on the framebuffer resolution.
1770 const Vec2 pixelSize = Vec2(2.0f) / m_renderSize.cast<float>();
1771 const Vec2 offset = pixelSize / UVec2(1u << m_sampleLocationsProperties.sampleLocationSubPixelBits).cast<float>();
1772 std::vector<Vec4> vertices;
1773
1774 // Surround with a roughly centered triangle
1775 const float y1 = 0.5f * offset.y();
1776 const float y2 = 0.35f * offset.y();
1777 const float x1 = 0.5f * offset.x();
1778
1779 const std::vector<Vec2> locations = genFramebufferSampleLocations(*m_pixelGrid, m_pixelGrid->size(), m_renderSize);
1780 for (std::vector<Vec2>::const_iterator iter = locations.begin(); iter != locations.end(); ++iter)
1781 {
1782 vertices.push_back(Vec4(iter->x(), iter->y() - y1, 0.0f, 1.0f));
1783 vertices.push_back(Vec4(iter->x() - x1, iter->y() + y2, 0.0f, 1.0f));
1784 vertices.push_back(Vec4(iter->x() + x1, iter->y() + y2, 0.0f, 1.0f));
1785 }
1786
1787 createVertexBuffer(vertices);
1788 }
1789
1790 createSampleDataBufferAndDescriptors(SampleDataSSBO::STATIC_SIZE); // no per-sample data used
1791
1792 drawSinglePass(VERTEX_INPUT_VEC4); // sample locations are taken from the pixel grid
1793
1794 // Verify
1795
1796 const tcu::ConstPixelBufferAccess image (tcu::ConstPixelBufferAccess(mapVkFormat(m_colorFormat), tcu::IVec3(m_renderSize.x(), m_renderSize.y(), 1), m_colorBufferAlloc->getHostPtr()));
1797
1798 return compareGreenImage(m_context.getTestContext().getLog(), "resolve0", "Resolved test image", image);
1799 }
1800 };
1801
1802 //! Verify that vertex attributes are correctly interpolated at each custom sample location
1803 class VerifyInterpolationTest : public TestBase
1804 {
1805 public:
VerifyInterpolationTest(Context & context,const TestParams params)1806 VerifyInterpolationTest (Context& context, const TestParams params) : TestBase(context, params) {}
1807
testPixelGrid(void)1808 bool testPixelGrid (void)
1809 {
1810 createVertexBuffer(genVerticesFullQuad());
1811
1812 // Create sample data SSBO
1813 {
1814 const deUint32 numSamples = m_pixelGrid->samplesPerPixel();
1815 const deUint32 numDataEntries = numSamples * m_renderSize.x() * m_renderSize.y();
1816 const VkDeviceSize bufferSize = SampleDataSSBO::STATIC_SIZE + sizeof(Vec2) * numDataEntries;
1817
1818 createSampleDataBufferAndDescriptors(bufferSize);
1819
1820 Vec2* const pSampleData = SampleDataSSBO::sampleData<Vec2>(m_sampleDataBufferAlloc->getHostPtr());
1821 const std::vector<Vec2> locations = genFramebufferSampleLocations(*m_pixelGrid, m_pixelGrid->size(), m_renderSize);
1822
1823 // Fill SSBO with interpolated values (here: from -1.0 to 1.0 across the render area in both x and y)
1824 DE_ASSERT(locations.size() == numDataEntries);
1825 std::copy(locations.begin(), locations.end(), pSampleData);
1826
1827 flushAlloc(m_context.getDeviceInterface(), m_context.getDevice(), *m_sampleDataBufferAlloc);
1828 }
1829
1830 drawSinglePass(VERTEX_INPUT_VEC4_VEC4); // sample locations are taken from the pixel grid
1831
1832 // Verify
1833
1834 const tcu::ConstPixelBufferAccess image (tcu::ConstPixelBufferAccess(mapVkFormat(m_colorFormat), tcu::IVec3(m_renderSize.x(), m_renderSize.y(), 1), m_colorBufferAlloc->getHostPtr()));
1835
1836 return compareGreenImage(m_context.getTestContext().getLog(), "resolve0", "Resolved test image", image);
1837 }
1838 };
1839
1840 template<typename Test, typename ProgramsFunc>
addCases(tcu::TestCaseGroup * group,const VkSampleCountFlagBits numSamples,bool useFragmentShadingRate,const ProgramsFunc initPrograms)1841 void addCases (tcu::TestCaseGroup* group, const VkSampleCountFlagBits numSamples, bool useFragmentShadingRate, const ProgramsFunc initPrograms)
1842 {
1843 TestParams params;
1844 deMemset(¶ms, 0, sizeof(params));
1845
1846 params.numSamples = numSamples;
1847 params.options = useFragmentShadingRate ? (TestOptionFlags)TEST_OPTION_FRAGMENT_SHADING_RATE_BIT : (TestOptionFlags)0;
1848
1849 addInstanceTestCaseWithPrograms<Test>(group, getString(numSamples).c_str(), "", checkSupportVerifyTests, initPrograms, params);
1850
1851 params.options |= (TestOptionFlags)TEST_OPTION_DYNAMIC_STATE_BIT;
1852 addInstanceTestCaseWithPrograms<Test>(group, (getString(numSamples) + "_dynamic").c_str(), "", checkSupportVerifyTests, initPrograms, params);
1853
1854 params.options |= (TestOptionFlags)TEST_OPTION_CLOSELY_PACKED_BIT;
1855 addInstanceTestCaseWithPrograms<Test>(group, (getString(numSamples) + "_packed").c_str(), "", checkSupportVerifyTests, initPrograms, params);
1856 }
1857
1858 } // VerifySamples
1859
1860 // Draw tests with at least two "passes" where sample locations may change.
1861 // Test case is based on a combination of parameters defined below. Not all combinations are compatible.
1862 namespace Draw
1863 {
1864
1865 //! Options common to all test cases
1866 enum TestOptionFlagBits
1867 {
1868 TEST_OPTION_SAME_PATTERN_BIT = 1u << 0, //!< Use the same sample pattern for all operations
1869 TEST_OPTION_DYNAMIC_STATE_BIT = 1u << 1, //!< Use dynamic pipeline state to pass in sample locations
1870 TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT = 1u << 2, //!< Put drawing commands in a secondary buffer, including sample locations change (if dynamic)
1871 TEST_OPTION_GENERAL_LAYOUT_BIT = 1u << 3, //!< Transition the image to general layout at some point in rendering
1872 TEST_OPTION_WAIT_EVENTS_BIT = 1u << 4, //!< Use image memory barriers with vkCmdWaitEvents rather than vkCmdPipelineBarrier
1873 TEST_OPTION_FRAGMENT_SHADING_RATE_BIT = 1u << 5, //!< Use VK_KHR_fragment_shading_rate
1874 };
1875 typedef deUint32 TestOptionFlags;
1876
1877 //! Determines where draws/clears with custom samples occur in the test
1878 enum TestDrawIn
1879 {
1880 TEST_DRAW_IN_RENDER_PASSES = 0u, //!< Each operation in a separate render pass
1881 TEST_DRAW_IN_SUBPASSES, //!< Each operation in a separate subpass of the same render pass
1882 TEST_DRAW_IN_SAME_SUBPASS, //!< Each operation in the same subpass
1883 };
1884
1885 //! How a clear before the second pass will be done
1886 enum TestClears
1887 {
1888 TEST_CLEARS_NO_CLEAR = 0u, //!< Don't clear
1889 TEST_CLEARS_LOAD_OP_CLEAR, //!< Render pass attachment load clear
1890 TEST_CLEARS_CMD_CLEAR_ATTACHMENTS, //!< vkCmdClearAttachments within a subpass
1891 TEST_CLEARS_CMD_CLEAR_IMAGE, //!< vkCmdClear{Color|DepthStencil}Image outside a render pass
1892 };
1893
1894 //! What type of image will be verified with custom samples
1895 enum TestImageAspect
1896 {
1897 TEST_IMAGE_ASPECT_COLOR = 0u, //!< Color image
1898 TEST_IMAGE_ASPECT_DEPTH, //!< Depth aspect of an image (can be mixed format)
1899 TEST_IMAGE_ASPECT_STENCIL, //!< Stencil aspect of an image (can be mixed format)
1900 };
1901
1902 struct TestParams
1903 {
1904 VkSampleCountFlagBits numSamples;
1905 TestOptionFlags options;
1906 TestDrawIn drawIn;
1907 TestClears clears;
1908 TestImageAspect imageAspect;
1909 };
1910
checkSupportDrawTests(Context & context,const TestParams params)1911 void checkSupportDrawTests (Context& context, const TestParams params)
1912 {
1913 checkSupportSampleLocations(context);
1914
1915 if ((context.getDeviceProperties().limits.framebufferColorSampleCounts & params.numSamples) == 0u)
1916 TCU_THROW(NotSupportedError, "framebufferColorSampleCounts: sample count not supported");
1917
1918 if ((getSampleLocationsPropertiesEXT(context).sampleLocationSampleCounts & params.numSamples) == 0u)
1919 TCU_THROW(NotSupportedError, "VkPhysicalDeviceSampleLocationsPropertiesEXT: sample count not supported");
1920
1921 // Are we allowed to modify the sample pattern within the same subpass?
1922 if (params.drawIn == TEST_DRAW_IN_SAME_SUBPASS && ((params.options & TEST_OPTION_SAME_PATTERN_BIT) == 0) && !getSampleLocationsPropertiesEXT(context).variableSampleLocations)
1923 TCU_THROW(NotSupportedError, "VkPhysicalDeviceSampleLocationsPropertiesEXT: variableSampleLocations not supported");
1924
1925 if (TEST_OPTION_FRAGMENT_SHADING_RATE_BIT & params.options)
1926 checkFragmentShadingRateRequirements(context, params.numSamples);
1927
1928 if (TEST_OPTION_WAIT_EVENTS_BIT & params.options &&
1929 context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") && !context.getPortabilitySubsetFeatures().events)
1930 {
1931 TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Events are not supported by this implementation");
1932 }
1933 }
1934
getString(const TestImageAspect aspect)1935 const char* getString (const TestImageAspect aspect)
1936 {
1937 switch (aspect)
1938 {
1939 case TEST_IMAGE_ASPECT_COLOR: return "color";
1940 case TEST_IMAGE_ASPECT_DEPTH: return "depth";
1941 case TEST_IMAGE_ASPECT_STENCIL: return "stencil";
1942 }
1943 DE_ASSERT(0);
1944 return DE_NULL;
1945 }
1946
getString(const TestDrawIn drawIn)1947 const char* getString (const TestDrawIn drawIn)
1948 {
1949 switch (drawIn)
1950 {
1951 case TEST_DRAW_IN_RENDER_PASSES: return "separate_renderpass";
1952 case TEST_DRAW_IN_SUBPASSES: return "separate_subpass";
1953 case TEST_DRAW_IN_SAME_SUBPASS: return "same_subpass";
1954 }
1955 DE_ASSERT(0);
1956 return DE_NULL;
1957 }
1958
getString(const TestClears clears)1959 const char* getString (const TestClears clears)
1960 {
1961 switch (clears)
1962 {
1963 case TEST_CLEARS_NO_CLEAR: return "no_clear";
1964 case TEST_CLEARS_LOAD_OP_CLEAR: return "load_op_clear";
1965 case TEST_CLEARS_CMD_CLEAR_ATTACHMENTS: return "clear_attachments";
1966 case TEST_CLEARS_CMD_CLEAR_IMAGE: return "clear_image";
1967 }
1968 DE_ASSERT(0);
1969 return DE_NULL;
1970 }
1971
getTestOptionFlagsString(const deUint32 flags)1972 std::string getTestOptionFlagsString (const deUint32 flags)
1973 {
1974 std::ostringstream str;
1975
1976 if ((flags & TEST_OPTION_SAME_PATTERN_BIT) != 0) str << (str.tellp() > 0 ? "_" : "") << "same_pattern";
1977 if ((flags & TEST_OPTION_DYNAMIC_STATE_BIT) != 0) str << (str.tellp() > 0 ? "_" : "") << "dynamic";
1978 if ((flags & TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT) != 0) str << (str.tellp() > 0 ? "_" : "") << "secondary_cmd_buf";
1979 if ((flags & TEST_OPTION_GENERAL_LAYOUT_BIT) != 0) str << (str.tellp() > 0 ? "_" : "") << "general_layout";
1980 if ((flags & TEST_OPTION_WAIT_EVENTS_BIT) != 0) str << (str.tellp() > 0 ? "_" : "") << "event";
1981
1982 return str.str();
1983 }
1984
initPrograms(SourceCollections & programCollection,const TestParams)1985 void initPrograms (SourceCollections& programCollection, const TestParams)
1986 {
1987 // Vertex shader
1988 {
1989 std::ostringstream src;
1990 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1991 << "\n"
1992 << "layout(location = 0) in vec4 in_position;\n"
1993 << "layout(location = 1) in vec4 in_color;\n"
1994 << "layout(location = 0) out vec4 o_color;\n"
1995 << "\n"
1996 << "out gl_PerVertex {\n"
1997 << " vec4 gl_Position;\n"
1998 << "};\n"
1999 << "\n"
2000 << "void main(void)\n"
2001 << "{\n"
2002 << " gl_Position = in_position;\n"
2003 << " o_color = in_color;\n"
2004 << "\n"
2005 // We use instance index to draw the left shape (index = 0) or the right shape (index = 1).
2006 // Vertices are squished and moved to either half of the viewport.
2007 << " if (gl_InstanceIndex == 0)\n"
2008 << " gl_Position.x = 0.5 * (gl_Position.x - 1.0);\n"
2009 << " else if (gl_InstanceIndex == 1)\n"
2010 << " gl_Position.x = 0.5 * (gl_Position.x + 1.0);\n"
2011 << "}\n";
2012
2013 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
2014 }
2015
2016 // Fragment shader
2017 {
2018 std::ostringstream src;
2019 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
2020 << "\n"
2021 << "layout(location = 0) in vec4 in_color;\n"
2022 << "layout(location = 0) out vec4 o_color;\n"
2023 << "\n"
2024 << "void main(void)\n"
2025 << "{\n"
2026 << " o_color = in_color;\n"
2027 << "}\n";
2028
2029 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
2030 }
2031 }
2032
2033 //! Draw shapes using changing sample patterns. Add clears and other operations as necessary
2034 class DrawTest : public TestInstance
2035 {
2036 static const deUint32 NUM_PASSES = 2u;
2037
2038 public:
DrawTest(Context & context,const TestParams params)2039 DrawTest (Context& context, const TestParams params)
2040 : TestInstance (context)
2041 , m_params (params)
2042 , m_sampleLocationsProperties (getSampleLocationsPropertiesEXT(context))
2043 , m_renderSize (64, 32)
2044 , m_numVertices (0)
2045 , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM)
2046 , m_depthStencilFormat (VK_FORMAT_UNDEFINED)
2047 , m_depthStencilAspect (0)
2048 {
2049 VkMultisamplePropertiesEXT multisampleProperties =
2050 {
2051 VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT, // VkStructureType sType;
2052 DE_NULL, // void* pNext;
2053 VkExtent2D(), // VkExtent2D maxSampleLocationGridSize;
2054 };
2055
2056 // For this test always use the full pixel grid
2057
2058 m_context.getInstanceInterface().getPhysicalDeviceMultisamplePropertiesEXT(m_context.getPhysicalDevice(), m_params.numSamples, &multisampleProperties);
2059 m_gridSize.x() = multisampleProperties.maxSampleLocationGridSize.width;
2060 m_gridSize.y() = multisampleProperties.maxSampleLocationGridSize.height;
2061 }
2062
iterate(void)2063 tcu::TestStatus iterate (void)
2064 {
2065 // Requirements
2066 if (!(m_gridSize.x() >= 1 && m_gridSize.y() >= 1))
2067 return tcu::TestStatus::fail("maxSampleLocationGridSize is invalid");
2068
2069 // Images
2070 {
2071 const DeviceInterface& vk = m_context.getDeviceInterface();
2072 const VkDevice device = m_context.getDevice();
2073 Allocator& allocator = m_context.getDefaultAllocator();
2074 const VkImageUsageFlags colorImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2075
2076 m_colorImage = makeImage(vk, device, (VkImageCreateFlags)0, m_colorFormat, m_renderSize, m_params.numSamples, colorImageUsageFlags);
2077 m_colorImageAlloc = bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
2078 m_colorImageView = makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat,
2079 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
2080
2081 m_resolveImage = makeImage(vk, device, (VkImageCreateFlags)0, m_colorFormat, m_renderSize, VK_SAMPLE_COUNT_1_BIT, colorImageUsageFlags);
2082 m_resolveImageAlloc = bindImage(vk, device, allocator, *m_resolveImage, MemoryRequirement::Any);
2083 m_resolveImageView = makeImageView(vk, device, *m_resolveImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat,
2084 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
2085
2086 const VkDeviceSize colorBufferSize = m_renderSize.x() * m_renderSize.y() * tcu::getPixelSize(mapVkFormat(m_colorFormat));
2087 m_colorBuffer = makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
2088 m_colorBufferAlloc = bindBuffer(vk, device, allocator, *m_colorBuffer, MemoryRequirement::HostVisible);
2089
2090 if (m_params.imageAspect != TEST_IMAGE_ASPECT_COLOR)
2091 {
2092 const VkImageUsageFlags depthStencilImageUsageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2093
2094 m_depthStencilFormat = findSupportedDepthStencilFormat(m_context, useDepth(), useStencil());
2095 m_depthStencilAspect = (useDepth() ? VK_IMAGE_ASPECT_DEPTH_BIT : (VkImageAspectFlagBits)0) |
2096 (useStencil() ? VK_IMAGE_ASPECT_STENCIL_BIT : (VkImageAspectFlagBits)0);
2097 m_depthStencilImage = makeImage(vk, device, VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT,
2098 m_depthStencilFormat, m_renderSize, m_params.numSamples, depthStencilImageUsageFlags);
2099 m_depthStencilImageAlloc = bindImage(vk, device, allocator, *m_depthStencilImage, MemoryRequirement::Any);
2100 m_depthStencilImageView = makeImageView(vk, device, *m_depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, m_depthStencilFormat,
2101 makeImageSubresourceRange(m_depthStencilAspect, 0u, 1u, 0u, 1u));
2102 }
2103 }
2104
2105 // Vertices
2106 {
2107 const DeviceInterface& vk = m_context.getDeviceInterface();
2108 const VkDevice device = m_context.getDevice();
2109 Allocator& allocator = m_context.getDefaultAllocator();
2110
2111 std::vector<PositionColor> vertices;
2112
2113 if (useDepth())
2114 {
2115 append(vertices, genVerticesShapes (RGBA::black().toVec(), DEPTH_REFERENCE / 2.0f)); // mask above (z = 0.0 is nearest)
2116 append(vertices, genVerticesFullQuad(RGBA::white().toVec(), DEPTH_REFERENCE)); // fill below the mask, using the depth test
2117 }
2118 else if (useStencil())
2119 {
2120 append(vertices, genVerticesShapes (RGBA::black().toVec(), DEPTH_REFERENCE)); // first mask
2121 append(vertices, genVerticesFullQuad(RGBA::white().toVec(), DEPTH_REFERENCE / 2.0f)); // then fill the whole area, using the stencil test
2122 }
2123 else
2124 vertices = genVerticesShapes();
2125
2126 const VkDeviceSize vertexBufferSize = static_cast<VkDeviceSize>(vertices.size() * sizeof(vertices[0]));
2127
2128 m_numVertices = static_cast<deUint32>(vertices.size());
2129 m_vertexBuffer = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
2130 m_vertexBufferAlloc = bindBuffer(vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
2131
2132 deMemcpy(m_vertexBufferAlloc->getHostPtr(), dataOrNullPtr(vertices), static_cast<std::size_t>(vertexBufferSize));
2133 flushAlloc(vk, device, *m_vertexBufferAlloc);
2134 }
2135
2136 // Multisample pixel grids - set up two sample patterns for two draw passes
2137 {
2138 const deUint32 numGrids = (useSameSamplePattern() ? 1u : NUM_PASSES);
2139 m_pixelGrids.reserve(numGrids);
2140
2141 for (deUint32 passNdx = 0u; passNdx < numGrids; ++passNdx)
2142 {
2143 const deUint32 seed = 142u + 75u * passNdx;
2144 m_pixelGrids.push_back(MultisamplePixelGrid(m_gridSize, m_params.numSamples));
2145 fillSampleLocationsRandom(m_pixelGrids.back(), m_sampleLocationsProperties.sampleLocationSubPixelBits, seed);
2146 logPixelGrid (m_context.getTestContext().getLog(), m_sampleLocationsProperties, m_pixelGrids.back());
2147 }
2148 }
2149
2150 // Some test cases will not clear the left hand image, so we can use it directly
2151 const bool isClearCase = (m_params.clears != TEST_CLEARS_NO_CLEAR);
2152 const bool hasLeftSideImage = (!isClearCase ||
2153 (m_params.drawIn != TEST_DRAW_IN_RENDER_PASSES && m_params.clears != TEST_CLEARS_CMD_CLEAR_ATTACHMENTS));
2154
2155 // Render second pass reference image with the first pattern
2156 tcu::TextureLevel refImagePattern0;
2157 if (!useSameSamplePattern() && !hasLeftSideImage)
2158 {
2159 const tcu::TextureFormat colorFormat = mapVkFormat(m_colorFormat);
2160
2161 drawPatternChangeReference();
2162
2163 refImagePattern0.setStorage(colorFormat, m_renderSize.x(), m_renderSize.y());
2164 tcu::copy(refImagePattern0.getAccess(), tcu::ConstPixelBufferAccess(colorFormat, tcu::IVec3(m_renderSize.x(), m_renderSize.y(), 1), m_colorBufferAlloc->getHostPtr()));
2165 }
2166
2167 // Two-pass rendering
2168
2169 switch (m_params.drawIn)
2170 {
2171 case TEST_DRAW_IN_RENDER_PASSES: drawRenderPasses(); break;
2172 case TEST_DRAW_IN_SUBPASSES: drawSubpasses(); break;
2173 case TEST_DRAW_IN_SAME_SUBPASS: drawSameSubpass(); break;
2174
2175 default:
2176 DE_ASSERT(0);
2177 break;
2178 }
2179
2180 // Log the result
2181
2182 const tcu::ConstPixelBufferAccess image (tcu::ConstPixelBufferAccess(mapVkFormat(m_colorFormat), tcu::IVec3(m_renderSize.x(), m_renderSize.y(), 1), m_colorBufferAlloc->getHostPtr()));
2183
2184 m_context.getTestContext().getLog()
2185 << tcu::TestLog::ImageSet("Result", "Final result")
2186 << tcu::TestLog::Image("resolve0", "resolve0", image)
2187 << tcu::TestLog::EndImageSet;
2188
2189 // Verify result
2190 {
2191 DE_ASSERT((m_renderSize.x() % 2) == 0);
2192 DE_ASSERT((m_renderSize.y() % 2) == 0);
2193
2194 // Count colors in each image half separately, each half may have its own background color
2195 const int numBackgroundColors = 1;
2196 const int numExpectedColorsRight = numBackgroundColors + static_cast<int>(m_params.numSamples);
2197 const int numExpectedColorsLeft = (isClearCase ? numBackgroundColors : numExpectedColorsRight);
2198 const int numActualColorsLeft = countUniqueColors(tcu::getSubregion(image, 0, 0, m_renderSize.x()/2, m_renderSize.y()));
2199 const int numActualColorsRight = countUniqueColors(tcu::getSubregion(image, m_renderSize.x()/2, 0, m_renderSize.x()/2, m_renderSize.y()));
2200
2201 if (numActualColorsLeft != numExpectedColorsLeft || numActualColorsRight != numExpectedColorsRight)
2202 {
2203 std::ostringstream msg;
2204 msg << "Expected " << numExpectedColorsLeft << " unique colors, but got " << numActualColorsLeft;
2205
2206 if (numActualColorsLeft != numActualColorsRight)
2207 msg << " and " << numActualColorsRight;
2208
2209 m_context.getTestContext().getLog()
2210 << tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
2211
2212 return tcu::TestStatus::fail("Resolved image has incorrect pixels");
2213 }
2214
2215 if (hasLeftSideImage)
2216 {
2217 // Compare the left and the right half
2218 const bool match = intThresholdCompare(tcu::getSubregion(image, 0, 0, m_renderSize.x()/2, m_renderSize.y()),
2219 tcu::getSubregion(image, m_renderSize.x()/2, 0, m_renderSize.x()/2, m_renderSize.y()),
2220 UVec4(2u));
2221 if (useSameSamplePattern() && !match)
2222 return tcu::TestStatus::fail("Multisample pattern should be identical in both image halves");
2223 else if (!useSameSamplePattern() && match)
2224 return tcu::TestStatus::fail("Multisample pattern doesn't seem to change between left and right image halves");
2225 }
2226 else if (!useSameSamplePattern())
2227 {
2228 // Compare the right half with the previously rendered reference image -- patterns should be different
2229 bool match = intThresholdCompare(tcu::getSubregion(refImagePattern0.getAccess(), m_renderSize.x()/2, 0, m_renderSize.x()/2, m_renderSize.y()),
2230 tcu::getSubregion(image, m_renderSize.x()/2, 0, m_renderSize.x()/2, m_renderSize.y()),
2231 UVec4(2u));
2232
2233 if (match)
2234 return tcu::TestStatus::fail("Multisample pattern doesn't seem to change between passes");
2235 }
2236 }
2237
2238 return tcu::TestStatus::pass("Pass");
2239 }
2240
2241 protected:
useDepth(void) const2242 bool useDepth (void) const { return m_params.imageAspect == TEST_IMAGE_ASPECT_DEPTH; }
useStencil(void) const2243 bool useStencil (void) const { return m_params.imageAspect == TEST_IMAGE_ASPECT_STENCIL; }
useSameSamplePattern(void) const2244 bool useSameSamplePattern (void) const { return (m_params.options & TEST_OPTION_SAME_PATTERN_BIT) != 0u; }
useDynamicState(void) const2245 bool useDynamicState (void) const { return (m_params.options & TEST_OPTION_DYNAMIC_STATE_BIT) != 0u; }
useSecondaryCmdBuffer(void) const2246 bool useSecondaryCmdBuffer (void) const { return (m_params.options & TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT) != 0u; }
useGeneralLayout(void) const2247 bool useGeneralLayout (void) const { return (m_params.options & TEST_OPTION_GENERAL_LAYOUT_BIT) != 0u; }
useWaitEvents(void) const2248 bool useWaitEvents (void) const { return (m_params.options & TEST_OPTION_WAIT_EVENTS_BIT) != 0u; }
useFragmentShadingRate(void) const2249 bool useFragmentShadingRate (void) const { return (m_params.options & TEST_OPTION_FRAGMENT_SHADING_RATE_BIT) != 0u; }
2250
2251 //! Draw the second pass image, but with sample pattern from the first pass -- used to verify that the pattern is different
drawPatternChangeReference(void)2252 void drawPatternChangeReference (void)
2253 {
2254 const DeviceInterface& vk = m_context.getDeviceInterface();
2255 const VkDevice device = m_context.getDevice();
2256 const VkViewport viewport = makeViewport(m_renderSize);
2257 const VkRect2D renderArea = makeRect2D(m_renderSize);
2258 const VkRect2D scissor = makeRect2D(m_renderSize);
2259 const Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2260 const Unique<VkShaderModule> fragmentModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
2261 const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device));
2262 const VkSampleLocationsInfoEXT sampleLocationsInfo = makeSampleLocationsInfo(m_pixelGrids[0]);
2263 const VkClearValue clearColor0 = (m_params.clears == TEST_CLEARS_NO_CLEAR ? makeClearValueColor(CLEAR_COLOR_0) : makeClearValueColor(CLEAR_COLOR_1));
2264
2265 RenderTarget rt;
2266
2267 rt.addAttachment(
2268 *m_colorImageView, // VkImageView imageView,
2269 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2270 m_colorFormat, // VkFormat format,
2271 m_params.numSamples, // VkSampleCountFlagBits numSamples,
2272 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
2273 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2274 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
2275 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
2276 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2277 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
2278 clearColor0); // VkClearValue clearValue,
2279
2280 rt.addAttachment(
2281 *m_resolveImageView, // VkImageView imageView,
2282 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2283 m_colorFormat, // VkFormat format,
2284 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits numSamples,
2285 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp,
2286 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2287 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
2288 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
2289 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2290 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout finalLayout,
2291 VkClearValue()); // VkClearValue clearValue,
2292
2293 rt.addSubpassColorAttachmentWithResolve(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
2294 1u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
2295
2296 if (useDepth() || useStencil())
2297 {
2298 rt.addAttachment(
2299 *m_depthStencilImageView, // VkImageView imageView,
2300 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2301 m_depthStencilFormat, // VkFormat format,
2302 m_params.numSamples, // VkSampleCountFlagBits numSamples,
2303 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
2304 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2305 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp,
2306 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp,
2307 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2308 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
2309 makeClearValueDepthStencil(DEPTH_CLEAR, STENCIL_REFERENCE), // VkClearValue clearValue,
2310 &sampleLocationsInfo); // VkSampleLocationsInfoEXT* pInitialSampleLocations
2311
2312 rt.addSubpassDepthStencilAttachment(2u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, &sampleLocationsInfo);
2313 }
2314
2315 rt.bake(vk, device, m_renderSize);
2316
2317 const Unique<VkPipeline> pipeline(makeGraphicsPipeline(
2318 vk, device, std::vector<VkDynamicState>(), *pipelineLayout, rt.getRenderPass(), *vertexModule, *fragmentModule,
2319 /*subpass index*/ 0u, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, sampleLocationsInfo,
2320 useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate()));
2321
2322 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
2323 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
2324 Move<VkCommandBuffer> secondaryCmdBuffer;
2325 VkCommandBuffer currentCmdBuffer = *cmdBuffer;
2326
2327 beginCommandBuffer(vk, currentCmdBuffer);
2328 rt.recordBeginRenderPass(vk, currentCmdBuffer, renderArea, (useSecondaryCmdBuffer() ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : VK_SUBPASS_CONTENTS_INLINE));
2329
2330 // For maximum consistency also use a secondary command buffer, if the two-pass path uses it
2331 if (useSecondaryCmdBuffer())
2332 {
2333 secondaryCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2334 currentCmdBuffer = *secondaryCmdBuffer;
2335
2336 beginSecondaryCommandBuffer(vk, currentCmdBuffer, rt.getRenderPass(), /*subpass*/ 0u, rt.getFramebuffer());
2337 }
2338
2339 vk.cmdBindVertexBuffers(currentCmdBuffer, /*first binding*/ 0u, /*num bindings*/ 1u, &m_vertexBuffer.get(), /*offsets*/ &ZERO);
2340 vk.cmdBindPipeline(currentCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
2341
2342 // Draw the right shape only
2343 vk.cmdDraw(currentCmdBuffer, m_numVertices, /*instance count*/ 1u, /*first vertex*/ 0u, /*first instance*/ 1u);
2344
2345 if (useSecondaryCmdBuffer())
2346 {
2347 endCommandBuffer(vk, currentCmdBuffer);
2348 currentCmdBuffer = *cmdBuffer;
2349
2350 vk.cmdExecuteCommands(currentCmdBuffer, 1u, &secondaryCmdBuffer.get());
2351 }
2352
2353 endRenderPass(vk, *cmdBuffer);
2354
2355 recordCopyImageToBuffer(vk, *cmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
2356
2357 endCommandBuffer(vk, *cmdBuffer);
2358 submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
2359
2360 invalidateAlloc(vk, device, *m_colorBufferAlloc);
2361 }
2362
2363 //! Draw two shapes with distinct sample patterns, each in its own render pass
drawRenderPasses(void)2364 void drawRenderPasses (void)
2365 {
2366 const DeviceInterface& vk = m_context.getDeviceInterface();
2367 const VkDevice device = m_context.getDevice();
2368 const VkViewport viewport = makeViewport(m_renderSize);
2369 const VkRect2D renderArea = makeRect2D(m_renderSize);
2370 const VkRect2D scissor = makeRect2D(m_renderSize);
2371 const Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2372 const Unique<VkShaderModule> fragmentModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
2373 const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device));
2374 const VkClearValue clearColor0 = makeClearValueColor(CLEAR_COLOR_0);
2375 const VkClearValue clearColor1 = makeClearValueColor(CLEAR_COLOR_1);
2376 const VkClearValue clearDepthStencil0 = makeClearValueDepthStencil(DEPTH_CLEAR, STENCIL_REFERENCE);
2377 const VkSampleLocationsInfoEXT sampleLocationsInfo [NUM_PASSES] =
2378 {
2379 makeSampleLocationsInfo(m_pixelGrids[0]),
2380 makeSampleLocationsInfo(m_pixelGrids[useSameSamplePattern() ? 0 : 1]),
2381 };
2382 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
2383 Move<VkCommandBuffer> cmdBuffer [NUM_PASSES] =
2384 {
2385 makeCommandBuffer(vk, device, *cmdPool),
2386 makeCommandBuffer(vk, device, *cmdPool),
2387 };
2388 Move<VkCommandBuffer> secondaryCmdBuffer [NUM_PASSES];
2389 RenderTarget rt [NUM_PASSES];
2390 Move<VkPipeline> pipeline [NUM_PASSES];
2391 Move<VkEvent> event [2]; /*color and depth/stencil*/
2392
2393 // Layouts expected by the second render pass
2394 const VkImageLayout colorLayout1 = useGeneralLayout() && !(useDepth() || useStencil()) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2395 const VkImageLayout depthStencilLayout1 = useGeneralLayout() && (useDepth() || useStencil()) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2396
2397 // First render pass - no resolves
2398 {
2399 rt[0].addAttachment(
2400 *m_colorImageView, // VkImageView imageView,
2401 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2402 m_colorFormat, // VkFormat format,
2403 m_params.numSamples, // VkSampleCountFlagBits numSamples,
2404 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
2405 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2406 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
2407 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
2408 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2409 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
2410 clearColor0); // VkClearValue clearValue,
2411
2412 rt[0].addSubpassColorAttachment(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
2413
2414 if (useDepth() || useStencil())
2415 {
2416 rt[0].addAttachment(
2417 *m_depthStencilImageView, // VkImageView imageView,
2418 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2419 m_depthStencilFormat, // VkFormat format,
2420 m_params.numSamples, // VkSampleCountFlagBits numSamples,
2421 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
2422 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2423 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp,
2424 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp,
2425 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2426 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
2427 clearDepthStencil0, // VkClearValue clearValue,
2428 &sampleLocationsInfo[0]); // VkSampleLocationsInfoEXT* pInitialSampleLocations
2429
2430 rt[0].addSubpassDepthStencilAttachment(1u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, &sampleLocationsInfo[0]);
2431 }
2432
2433 rt[0].bake(vk, device, m_renderSize);
2434 }
2435
2436 // Second render pass
2437 {
2438 const VkAttachmentLoadOp loadOp = (m_params.clears == TEST_CLEARS_LOAD_OP_CLEAR ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD);
2439
2440 rt[1].addAttachment(
2441 *m_colorImageView, // VkImageView imageView,
2442 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2443 m_colorFormat, // VkFormat format,
2444 m_params.numSamples, // VkSampleCountFlagBits numSamples,
2445 loadOp, // VkAttachmentLoadOp loadOp,
2446 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2447 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
2448 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
2449 colorLayout1, // VkImageLayout initialLayout,
2450 colorLayout1, // VkImageLayout finalLayout,
2451 clearColor1); // VkClearValue clearValue,
2452
2453 rt[1].addAttachment(
2454 *m_resolveImageView, // VkImageView imageView,
2455 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2456 m_colorFormat, // VkFormat format,
2457 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits numSamples,
2458 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp,
2459 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2460 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
2461 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
2462 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2463 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout finalLayout,
2464 VkClearValue()); // VkClearValue clearValue,
2465
2466 rt[1].addSubpassColorAttachmentWithResolve(0u, colorLayout1,
2467 1u, colorLayout1);
2468
2469 if (useDepth() || useStencil())
2470 {
2471 rt[1].addAttachment(
2472 *m_depthStencilImageView, // VkImageView imageView,
2473 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2474 m_depthStencilFormat, // VkFormat format,
2475 m_params.numSamples, // VkSampleCountFlagBits numSamples,
2476 loadOp, // VkAttachmentLoadOp loadOp,
2477 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2478 loadOp, // VkAttachmentLoadOp stencilLoadOp,
2479 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp,
2480 depthStencilLayout1, // VkImageLayout initialLayout,
2481 depthStencilLayout1, // VkImageLayout finalLayout,
2482 clearDepthStencil0, // VkClearValue clearValue,
2483 &sampleLocationsInfo[1]); // VkSampleLocationsInfoEXT* pInitialSampleLocations
2484
2485 rt[1].addSubpassDepthStencilAttachment(2u, depthStencilLayout1, &sampleLocationsInfo[1]);
2486 }
2487
2488 rt[1].bake(vk, device, m_renderSize);
2489 }
2490
2491 // Pipelines
2492
2493 if (useDynamicState())
2494 {
2495 std::vector<VkDynamicState> dynamicState;
2496 dynamicState.push_back(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
2497
2498 for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
2499 {
2500 pipeline[passNdx] = makeGraphicsPipeline(
2501 vk, device, dynamicState, *pipelineLayout, rt[passNdx].getRenderPass(), *vertexModule, *fragmentModule,
2502 /*subpass index*/ 0u, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, makeEmptySampleLocationsInfo(),
2503 useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate());
2504 }
2505 }
2506 else for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
2507 {
2508 pipeline[passNdx] = makeGraphicsPipeline(
2509 vk, device, std::vector<VkDynamicState>(), *pipelineLayout, rt[passNdx].getRenderPass(), *vertexModule, *fragmentModule,
2510 /*subpass index*/ 0u, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, sampleLocationsInfo[passNdx],
2511 useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate());
2512 }
2513
2514 // Record secondary command buffers
2515
2516 if (useSecondaryCmdBuffer())
2517 {
2518 secondaryCmdBuffer[0] = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2519 secondaryCmdBuffer[1] = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2520
2521 // First render pass contents
2522 beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer[0], rt[0].getRenderPass(), /*subpass*/ 0u, rt[0].getFramebuffer());
2523 recordFirstPassContents(*secondaryCmdBuffer[0], *pipeline[0], sampleLocationsInfo[0]);
2524 endCommandBuffer(vk, *secondaryCmdBuffer[0]);
2525
2526 // Second render pass contents
2527 beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer[1], rt[1].getRenderPass(), /*subpass*/ 0u, rt[1].getFramebuffer());
2528 recordSecondPassContents(*secondaryCmdBuffer[1], *pipeline[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
2529 endCommandBuffer(vk, *secondaryCmdBuffer[1]);
2530 }
2531
2532 // Record primary command buffers
2533
2534 VkCommandBuffer currentCmdBuffer = *cmdBuffer[0];
2535 beginCommandBuffer(vk, currentCmdBuffer);
2536
2537 // First render pass
2538 if (useSecondaryCmdBuffer())
2539 {
2540 rt[0].recordBeginRenderPass(vk, currentCmdBuffer, renderArea, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
2541 vk.cmdExecuteCommands(currentCmdBuffer, 1u, &secondaryCmdBuffer[0].get());
2542 endRenderPass(vk, currentCmdBuffer);
2543 }
2544 else
2545 {
2546 rt[0].recordBeginRenderPass(vk, currentCmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
2547 recordFirstPassContents(currentCmdBuffer, *pipeline[0], sampleLocationsInfo[0]);
2548 endRenderPass(vk, currentCmdBuffer);
2549 }
2550
2551 endCommandBuffer(vk, currentCmdBuffer);
2552
2553 // Record the second primary command buffer
2554 currentCmdBuffer = *cmdBuffer[1];
2555 beginCommandBuffer(vk, currentCmdBuffer);
2556
2557 if (m_params.clears == TEST_CLEARS_CMD_CLEAR_IMAGE)
2558 {
2559 {
2560 const VkImageLayout finalLayout = (useWaitEvents() ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : colorLayout1);
2561
2562 recordImageBarrier(vk, currentCmdBuffer, *m_colorImage,
2563 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspect,
2564 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask,
2565 VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags dstStageMask,
2566 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask,
2567 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask,
2568 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout,
2569 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); // VkImageLayout newLayout)
2570
2571 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
2572 vk.cmdClearColorImage(currentCmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor1.color, 1u, &subresourceRange);
2573
2574 recordImageBarrier(vk, currentCmdBuffer, *m_colorImage,
2575 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspect,
2576 VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags srcStageMask,
2577 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags dstStageMask,
2578 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask,
2579 (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
2580 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT), // VkAccessFlags dstAccessMask,
2581 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout,
2582 finalLayout); // VkImageLayout newLayout)
2583 }
2584
2585 if (useDepth() || useStencil())
2586 {
2587 const VkImageLayout finalLayout = (useWaitEvents() ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : depthStencilLayout1);
2588
2589 recordImageBarrier(vk, currentCmdBuffer, *m_depthStencilImage,
2590 getImageAspectFlags(m_depthStencilFormat), // VkImageAspectFlags aspect,
2591 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags srcStageMask,
2592 VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags dstStageMask,
2593 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask,
2594 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask,
2595 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout,
2596 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout)
2597 &sampleLocationsInfo[0]); // VkSampleLocationsInfoEXT
2598
2599 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(m_depthStencilAspect, 0u, 1u, 0u, 1u);
2600 vk.cmdClearDepthStencilImage(currentCmdBuffer, *m_depthStencilImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearDepthStencil0.depthStencil, 1u, &subresourceRange);
2601
2602 recordImageBarrier(vk, currentCmdBuffer, *m_depthStencilImage,
2603 getImageAspectFlags(m_depthStencilFormat), // VkImageAspectFlags aspect,
2604 VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags srcStageMask,
2605 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags dstStageMask,
2606 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask,
2607 (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
2608 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT), // VkAccessFlags dstAccessMask,
2609 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout,
2610 finalLayout, // VkImageLayout newLayout)
2611 &sampleLocationsInfo[0]); // VkSampleLocationsInfoEXT
2612 }
2613 }
2614 else if (!useWaitEvents())
2615 {
2616 // Barrier between the render passes
2617
2618 recordImageBarrier(vk, currentCmdBuffer, *m_colorImage,
2619 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspect,
2620 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask,
2621 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags dstStageMask,
2622 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask,
2623 (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
2624 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT), // VkAccessFlags dstAccessMask,
2625 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout,
2626 colorLayout1); // VkImageLayout newLayout)
2627
2628 if (useDepth() || useStencil())
2629 {
2630 recordImageBarrier(vk, currentCmdBuffer, *m_depthStencilImage,
2631 getImageAspectFlags(m_depthStencilFormat), // VkImageAspectFlags aspect,
2632 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags srcStageMask,
2633 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags dstStageMask,
2634 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask,
2635 (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
2636 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT), // VkAccessFlags dstAccessMask,
2637 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout,
2638 depthStencilLayout1); // VkImageLayout newLayout)
2639 }
2640 }
2641
2642 if (useWaitEvents())
2643 {
2644 // Use events to sync both render passes
2645 event[0] = makeEvent(vk, device);
2646 vk.cmdSetEvent(currentCmdBuffer, *event[0], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
2647
2648 recordWaitEventWithImage(vk, currentCmdBuffer, *event[0], *m_colorImage,
2649 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspect,
2650 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask,
2651 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags dstStageMask,
2652 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask,
2653 (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
2654 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT), // VkAccessFlags dstAccessMask,
2655 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout,
2656 colorLayout1); // VkImageLayout newLayout,
2657
2658 if (useDepth() || useStencil())
2659 {
2660 event[1] = makeEvent(vk, device);
2661 vk.cmdSetEvent(currentCmdBuffer, *event[1], VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
2662
2663 recordWaitEventWithImage(vk, currentCmdBuffer, *event[1], *m_depthStencilImage,
2664 getImageAspectFlags(m_depthStencilFormat), // VkImageAspectFlags aspect,
2665 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags srcStageMask,
2666 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags dstStageMask,
2667 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask,
2668 (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
2669 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT), // VkAccessFlags dstAccessMask,
2670 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout,
2671 depthStencilLayout1); // VkImageLayout newLayout,
2672 }
2673 }
2674
2675 // Second render pass
2676 if (useSecondaryCmdBuffer())
2677 {
2678 rt[1].recordBeginRenderPass(vk, currentCmdBuffer, renderArea, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
2679 vk.cmdExecuteCommands(currentCmdBuffer, 1u, &secondaryCmdBuffer[1].get());
2680 endRenderPass(vk, currentCmdBuffer);
2681 }
2682 else
2683 {
2684 rt[1].recordBeginRenderPass(vk, currentCmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
2685 recordSecondPassContents(currentCmdBuffer, *pipeline[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
2686 endRenderPass(vk, currentCmdBuffer);
2687 }
2688
2689 // Resolve image -> host buffer
2690 recordCopyImageToBuffer(vk, currentCmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
2691
2692 endCommandBuffer(vk, currentCmdBuffer);
2693
2694 // Submit work
2695 {
2696 const Unique<VkFence> fence (createFence(vk, device));
2697 const VkCommandBuffer buffers [NUM_PASSES] =
2698 {
2699 *cmdBuffer[0],
2700 *cmdBuffer[1],
2701 };
2702
2703 const VkSubmitInfo submitInfo =
2704 {
2705 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
2706 DE_NULL, // const void* pNext;
2707 0u, // uint32_t waitSemaphoreCount;
2708 DE_NULL, // const VkSemaphore* pWaitSemaphores;
2709 DE_NULL, // const VkPipelineStageFlags* pWaitDstStageMask;
2710 DE_LENGTH_OF_ARRAY(buffers), // uint32_t commandBufferCount;
2711 buffers, // const VkCommandBuffer* pCommandBuffers;
2712 0u, // uint32_t signalSemaphoreCount;
2713 DE_NULL, // const VkSemaphore* pSignalSemaphores;
2714 };
2715 VK_CHECK(vk.queueSubmit(m_context.getUniversalQueue(), 1u, &submitInfo, *fence));
2716 VK_CHECK(vk.waitForFences(device, 1u, &fence.get(), DE_TRUE, ~0ull));
2717 }
2718
2719 invalidateAlloc(vk, device, *m_colorBufferAlloc);
2720 }
2721
recordFirstPassContents(const VkCommandBuffer cmdBuffer,const VkPipeline pipeline,const VkSampleLocationsInfoEXT & sampleLocationsInfo)2722 void recordFirstPassContents (const VkCommandBuffer cmdBuffer,
2723 const VkPipeline pipeline,
2724 const VkSampleLocationsInfoEXT& sampleLocationsInfo)
2725 {
2726 const DeviceInterface& vk = m_context.getDeviceInterface();
2727
2728 vk.cmdBindVertexBuffers(cmdBuffer, /*first binding*/ 0u, /*num bindings*/ 1u, &m_vertexBuffer.get(), /*offsets*/ &ZERO);
2729 vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
2730
2731 if (useDynamicState())
2732 vk.cmdSetSampleLocationsEXT(cmdBuffer, &sampleLocationsInfo);
2733
2734 if (m_params.clears == TEST_CLEARS_NO_CLEAR)
2735 vk.cmdDraw(cmdBuffer, m_numVertices, /*instance count*/ 1u, /*first vertex*/ 0u, /*first instance*/ 0u); // left shape only
2736 else
2737 vk.cmdDraw(cmdBuffer, m_numVertices, /*instance count*/ NUM_PASSES, /*first vertex*/ 0u, /*first instance*/ 0u); // both shapes
2738 }
2739
recordSecondPassContents(const VkCommandBuffer cmdBuffer,const VkPipeline pipeline,const VkSampleLocationsInfoEXT & sampleLocationsInfo,const VkClearValue & clearColor,const VkClearValue & clearDepthStencil,const VkRect2D & clearRect)2740 void recordSecondPassContents (const VkCommandBuffer cmdBuffer,
2741 const VkPipeline pipeline,
2742 const VkSampleLocationsInfoEXT& sampleLocationsInfo,
2743 const VkClearValue& clearColor,
2744 const VkClearValue& clearDepthStencil,
2745 const VkRect2D& clearRect)
2746 {
2747 const DeviceInterface& vk = m_context.getDeviceInterface();
2748
2749 vk.cmdBindVertexBuffers(cmdBuffer, /*first binding*/ 0u, /*num bindings*/ 1u, &m_vertexBuffer.get(), /*offsets*/ &ZERO);
2750 vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
2751
2752 if (m_params.clears == TEST_CLEARS_CMD_CLEAR_ATTACHMENTS)
2753 recordClearAttachments(vk, cmdBuffer, 0u, clearColor, m_depthStencilAspect, clearDepthStencil, clearRect);
2754
2755 if (useDynamicState())
2756 vk.cmdSetSampleLocationsEXT(cmdBuffer, &sampleLocationsInfo);
2757
2758 // Draw the right shape only
2759 vk.cmdDraw(cmdBuffer, m_numVertices, /*instance count*/ 1u, /*first vertex*/ 0u, /*first instance*/ 1u);
2760 }
2761
2762 //! Draw two shapes in two subpasses of the same render pass
drawSubpasses(void)2763 void drawSubpasses (void)
2764 {
2765 DE_ASSERT(m_params.clears != TEST_CLEARS_CMD_CLEAR_IMAGE); // not possible in a render pass
2766 DE_ASSERT(m_params.clears != TEST_CLEARS_LOAD_OP_CLEAR); // can't specify a load op for a subpass
2767 DE_ASSERT((m_params.options & TEST_OPTION_WAIT_EVENTS_BIT) == 0); // can't change layouts inside a subpass
2768
2769 const DeviceInterface& vk = m_context.getDeviceInterface();
2770 const VkDevice device = m_context.getDevice();
2771 const VkViewport viewport = makeViewport(m_renderSize);
2772 const VkRect2D renderArea = makeRect2D(m_renderSize);
2773 const VkRect2D scissor = makeRect2D(m_renderSize);
2774 const Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2775 const Unique<VkShaderModule> fragmentModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
2776 const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device));
2777 const VkClearValue clearColor0 = makeClearValueColor(CLEAR_COLOR_0);
2778 const VkClearValue clearColor1 = makeClearValueColor(CLEAR_COLOR_1);
2779 const VkClearValue clearDepthStencil0 = makeClearValueDepthStencil(DEPTH_CLEAR, STENCIL_REFERENCE);
2780 const VkSampleLocationsInfoEXT sampleLocationsInfo [NUM_PASSES] =
2781 {
2782 makeSampleLocationsInfo(m_pixelGrids[0]),
2783 makeSampleLocationsInfo(m_pixelGrids[useSameSamplePattern() ? 0 : 1]),
2784 };
2785 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
2786 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
2787 Move<VkCommandBuffer> secondaryCmdBuffer [NUM_PASSES];
2788 RenderTarget rt;
2789 Move<VkPipeline> pipeline [NUM_PASSES];
2790 Move<VkEvent> event;
2791
2792 // Layouts used in the second subpass
2793 const VkImageLayout colorLayout1 = useGeneralLayout() && !(useDepth() || useStencil()) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2794 const VkImageLayout depthStencilLayout1 = useGeneralLayout() && (useDepth() || useStencil()) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2795
2796 // Prepare the render pass
2797 {
2798 rt.addAttachment(
2799 *m_colorImageView, // VkImageView imageView,
2800 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2801 m_colorFormat, // VkFormat format,
2802 m_params.numSamples, // VkSampleCountFlagBits numSamples,
2803 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
2804 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2805 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
2806 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
2807 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2808 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
2809 clearColor0); // VkClearValue clearValue,
2810
2811 rt.addAttachment(
2812 *m_resolveImageView, // VkImageView imageView,
2813 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2814 m_colorFormat, // VkFormat format,
2815 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits numSamples,
2816 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp,
2817 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2818 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
2819 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
2820 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2821 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout finalLayout,
2822 VkClearValue()); // VkClearValue clearValue,
2823
2824 // First subpass
2825 rt.addSubpassColorAttachment(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
2826
2827 if (useDepth() || useStencil())
2828 {
2829 rt.addAttachment(
2830 *m_depthStencilImageView, // VkImageView imageView,
2831 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2832 m_depthStencilFormat, // VkFormat format,
2833 m_params.numSamples, // VkSampleCountFlagBits numSamples,
2834 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
2835 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2836 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp,
2837 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp,
2838 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2839 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
2840 clearDepthStencil0, // VkClearValue clearValue,
2841 &sampleLocationsInfo[0]); // VkSampleLocationsInfoEXT* pInitialSampleLocations
2842
2843 rt.addSubpassDepthStencilAttachment(2u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, &sampleLocationsInfo[0]);
2844 }
2845
2846 // Second subpass
2847 rt.nextSubpass();
2848 rt.addSubpassColorAttachmentWithResolve(0u, colorLayout1,
2849 1u, colorLayout1);
2850
2851 if (useDepth() || useStencil())
2852 rt.addSubpassDepthStencilAttachment(2u, depthStencilLayout1, &sampleLocationsInfo[1]);
2853
2854 rt.bake(vk, device, m_renderSize);
2855 }
2856
2857 // Pipelines
2858
2859 if (useDynamicState())
2860 {
2861 std::vector<VkDynamicState> dynamicState;
2862 dynamicState.push_back(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
2863
2864 for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
2865 {
2866 pipeline[passNdx] = makeGraphicsPipeline(
2867 vk, device, dynamicState, *pipelineLayout, rt.getRenderPass(), *vertexModule, *fragmentModule,
2868 /*subpass*/ passNdx, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, makeEmptySampleLocationsInfo(),
2869 useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate());
2870 }
2871 }
2872 else for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
2873 {
2874 pipeline[passNdx] = makeGraphicsPipeline(
2875 vk, device, std::vector<VkDynamicState>(), *pipelineLayout, rt.getRenderPass(), *vertexModule, *fragmentModule,
2876 /*subpass*/ passNdx, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, sampleLocationsInfo[passNdx],
2877 useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate());
2878 }
2879
2880 // Record secondary command buffers
2881
2882 if (useSecondaryCmdBuffer())
2883 {
2884 secondaryCmdBuffer[0] = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2885 secondaryCmdBuffer[1] = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2886
2887 // First subpass contents
2888 beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer[0], rt.getRenderPass(), /*subpass*/ 0u, rt.getFramebuffer());
2889 recordFirstPassContents(*secondaryCmdBuffer[0], *pipeline[0], sampleLocationsInfo[0]);
2890 endCommandBuffer(vk, *secondaryCmdBuffer[0]);
2891
2892 // Second subpass contents
2893 beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer[1], rt.getRenderPass(), /*subpass*/ 1u, rt.getFramebuffer());
2894 recordSecondPassContents(*secondaryCmdBuffer[1], *pipeline[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
2895 endCommandBuffer(vk, *secondaryCmdBuffer[1]);
2896 }
2897
2898 // Record primary command buffer
2899
2900 beginCommandBuffer(vk, *cmdBuffer);
2901
2902 if (useSecondaryCmdBuffer())
2903 {
2904 rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
2905 vk.cmdExecuteCommands(*cmdBuffer, 1u, &secondaryCmdBuffer[0].get());
2906
2907 vk.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
2908 vk.cmdExecuteCommands(*cmdBuffer, 1u, &secondaryCmdBuffer[1].get());
2909 }
2910 else
2911 {
2912 rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
2913 recordFirstPassContents(*cmdBuffer, *pipeline[0], sampleLocationsInfo[0]);
2914
2915 vk.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
2916 recordSecondPassContents(*cmdBuffer, *pipeline[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
2917 }
2918
2919 endRenderPass(vk, *cmdBuffer);
2920
2921 // Resolve image -> host buffer
2922 recordCopyImageToBuffer(vk, *cmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
2923
2924 endCommandBuffer(vk, *cmdBuffer);
2925
2926 submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
2927 invalidateAlloc(vk, device, *m_colorBufferAlloc);
2928 }
2929
2930 //! Draw two shapes within the same subpass of a renderpass
drawSameSubpass(void)2931 void drawSameSubpass (void)
2932 {
2933 DE_ASSERT(m_params.clears != TEST_CLEARS_CMD_CLEAR_IMAGE); // not possible in a render pass
2934 DE_ASSERT(m_params.clears != TEST_CLEARS_LOAD_OP_CLEAR); // can't specify a load op for a subpass
2935 DE_ASSERT((m_params.options & TEST_OPTION_WAIT_EVENTS_BIT) == 0); // can't change layouts inside a subpass
2936 DE_ASSERT((m_params.options & TEST_OPTION_GENERAL_LAYOUT_BIT) == 0); // can't change layouts inside a subpass
2937
2938 const DeviceInterface& vk = m_context.getDeviceInterface();
2939 const VkDevice device = m_context.getDevice();
2940 const VkViewport viewport = makeViewport(m_renderSize);
2941 const VkRect2D renderArea = makeRect2D(m_renderSize);
2942 const VkRect2D scissor = makeRect2D(m_renderSize);
2943 const Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2944 const Unique<VkShaderModule> fragmentModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
2945 const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device));
2946 const VkClearValue clearColor0 = makeClearValueColor(CLEAR_COLOR_0);
2947 const VkClearValue clearColor1 = makeClearValueColor(CLEAR_COLOR_1);
2948 const VkClearValue clearDepthStencil0 = makeClearValueDepthStencil(DEPTH_CLEAR, STENCIL_REFERENCE);
2949 const VkSampleLocationsInfoEXT sampleLocationsInfo [NUM_PASSES] =
2950 {
2951 makeSampleLocationsInfo(m_pixelGrids[0]),
2952 makeSampleLocationsInfo(m_pixelGrids[useSameSamplePattern() ? 0 : 1]),
2953 };
2954 const bool useFragmentShadingRate (TEST_OPTION_FRAGMENT_SHADING_RATE_BIT & m_params.options);
2955 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
2956 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
2957 Move<VkCommandBuffer> secondaryCmdBuffer;
2958 RenderTarget rt;
2959 Move<VkPipeline> pipeline [NUM_PASSES];
2960 Move<VkEvent> event;
2961
2962 // Prepare the render pass
2963 {
2964 rt.addAttachment(
2965 *m_colorImageView, // VkImageView imageView,
2966 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2967 m_colorFormat, // VkFormat format,
2968 m_params.numSamples, // VkSampleCountFlagBits numSamples,
2969 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
2970 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2971 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
2972 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
2973 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2974 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
2975 clearColor0); // VkClearValue clearValue,
2976
2977 rt.addAttachment(
2978 *m_resolveImageView, // VkImageView imageView,
2979 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2980 m_colorFormat, // VkFormat format,
2981 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits numSamples,
2982 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp,
2983 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
2984 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp,
2985 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp,
2986 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
2987 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout finalLayout,
2988 VkClearValue()); // VkClearValue clearValue,
2989
2990 rt.addSubpassColorAttachmentWithResolve(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
2991 1u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
2992
2993 if (useDepth() || useStencil())
2994 {
2995 rt.addAttachment(
2996 *m_depthStencilImageView, // VkImageView imageView,
2997 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags,
2998 m_depthStencilFormat, // VkFormat format,
2999 m_params.numSamples, // VkSampleCountFlagBits numSamples,
3000 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp,
3001 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp,
3002 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp,
3003 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp,
3004 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout,
3005 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout,
3006 clearDepthStencil0, // VkClearValue clearValue,
3007 &sampleLocationsInfo[0]); // VkSampleLocationsInfoEXT* pInitialSampleLocations
3008
3009 rt.addSubpassDepthStencilAttachment(2u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, &sampleLocationsInfo[0]);
3010 }
3011
3012 rt.bake(vk, device, m_renderSize);
3013 }
3014
3015 // Pipelines
3016
3017 if (useDynamicState())
3018 {
3019 std::vector<VkDynamicState> dynamicState;
3020 dynamicState.push_back(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
3021
3022 for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
3023 {
3024 pipeline[passNdx] = makeGraphicsPipeline(
3025 vk, device, dynamicState, *pipelineLayout, rt.getRenderPass(), *vertexModule, *fragmentModule,
3026 /*subpass*/ 0u, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, makeEmptySampleLocationsInfo(),
3027 useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate);
3028 }
3029 }
3030 else for (deUint32 passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
3031 {
3032 pipeline[passNdx] = makeGraphicsPipeline(
3033 vk, device, std::vector<VkDynamicState>(), *pipelineLayout, rt.getRenderPass(), *vertexModule, *fragmentModule,
3034 /*subpass*/ 0u, viewport, scissor, m_params.numSamples, /*use sample locations*/ true, sampleLocationsInfo[passNdx],
3035 useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate);
3036 }
3037
3038 // Record secondary command buffers
3039
3040 if (useSecondaryCmdBuffer())
3041 {
3042 secondaryCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
3043
3044 beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer, rt.getRenderPass(), /*subpass*/ 0u, rt.getFramebuffer());
3045 recordFirstPassContents(*secondaryCmdBuffer, *pipeline[0], sampleLocationsInfo[0]);
3046 recordSecondPassContents(*secondaryCmdBuffer, *pipeline[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
3047 endCommandBuffer(vk, *secondaryCmdBuffer);
3048 }
3049
3050 // Record primary command buffer
3051
3052 beginCommandBuffer(vk, *cmdBuffer);
3053
3054 if (useSecondaryCmdBuffer())
3055 {
3056 rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
3057 vk.cmdExecuteCommands(*cmdBuffer, 1u, &secondaryCmdBuffer.get());
3058 }
3059 else
3060 {
3061 rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
3062 recordFirstPassContents(*cmdBuffer, *pipeline[0], sampleLocationsInfo[0]);
3063 recordSecondPassContents(*cmdBuffer, *pipeline[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0, scissor);
3064 }
3065
3066 endRenderPass(vk, *cmdBuffer);
3067
3068 // Resolve image -> host buffer
3069 recordCopyImageToBuffer(vk, *cmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
3070
3071 endCommandBuffer(vk, *cmdBuffer);
3072
3073 submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
3074 invalidateAlloc(vk, device, *m_colorBufferAlloc);
3075 }
3076
3077 const TestParams m_params;
3078 const VkPhysicalDeviceSampleLocationsPropertiesEXT m_sampleLocationsProperties;
3079 const UVec2 m_renderSize;
3080 UVec2 m_gridSize;
3081 std::vector<MultisamplePixelGrid> m_pixelGrids;
3082 deUint32 m_numVertices;
3083 Move<VkBuffer> m_vertexBuffer;
3084 MovePtr<Allocation> m_vertexBufferAlloc;
3085 const VkFormat m_colorFormat;
3086 Move<VkImage> m_colorImage;
3087 Move<VkImageView> m_colorImageView;
3088 MovePtr<Allocation> m_colorImageAlloc;
3089 VkFormat m_depthStencilFormat;
3090 VkImageAspectFlags m_depthStencilAspect;
3091 Move<VkImage> m_depthStencilImage;
3092 Move<VkImageView> m_depthStencilImageView;
3093 MovePtr<Allocation> m_depthStencilImageAlloc;
3094 Move<VkImage> m_resolveImage;
3095 Move<VkImageView> m_resolveImageView;
3096 MovePtr<Allocation> m_resolveImageAlloc;
3097 Move<VkBuffer> m_colorBuffer;
3098 MovePtr<Allocation> m_colorBufferAlloc;
3099 };
3100
3101 } // Draw
3102
createTestsInGroup(tcu::TestCaseGroup * rootGroup,bool useFragmentShadingRate)3103 void createTestsInGroup (tcu::TestCaseGroup* rootGroup, bool useFragmentShadingRate)
3104 {
3105 // Queries
3106 if (!useFragmentShadingRate)
3107 {
3108 MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(rootGroup->getTestContext(), "query", ""));
3109
3110 addFunctionCase(group.get(), "sample_locations_properties", "", checkSupportSampleLocations, testQuerySampleLocationProperties);
3111 addFunctionCase(group.get(), "multisample_properties", "", checkSupportSampleLocations, testQueryMultisampleProperties);
3112
3113 rootGroup->addChild(group.release());
3114 }
3115
3116 const VkSampleCountFlagBits sampleCountRange[] =
3117 {
3118 VK_SAMPLE_COUNT_2_BIT,
3119 VK_SAMPLE_COUNT_4_BIT,
3120 VK_SAMPLE_COUNT_8_BIT,
3121 VK_SAMPLE_COUNT_16_BIT,
3122 // There are no implementations that support 32 or 64 programmable samples currently
3123 };
3124
3125 // Verify custom sample locations and interpolation
3126 {
3127 using namespace VerifySamples;
3128
3129 MovePtr<tcu::TestCaseGroup> groupLocation (new tcu::TestCaseGroup(rootGroup->getTestContext(), "verify_location", ""));
3130 MovePtr<tcu::TestCaseGroup> groupInterpolation (new tcu::TestCaseGroup(rootGroup->getTestContext(), "verify_interpolation", ""));
3131
3132 for (const VkSampleCountFlagBits* pLoopNumSamples = sampleCountRange; pLoopNumSamples < DE_ARRAY_END(sampleCountRange); ++pLoopNumSamples)
3133 {
3134 addCases<VerifyLocationTest> (groupLocation.get(), *pLoopNumSamples, useFragmentShadingRate, addProgramsVerifyLocationGeometry);
3135 addCases<VerifyInterpolationTest>(groupInterpolation.get(), *pLoopNumSamples, useFragmentShadingRate, addProgramsVerifyInterpolation);
3136 }
3137
3138 rootGroup->addChild(groupLocation.release());
3139 rootGroup->addChild(groupInterpolation.release());
3140 }
3141
3142 // Draw with custom samples and various options
3143 {
3144 using namespace Draw;
3145
3146 const deUint32 globalOption = useFragmentShadingRate ? static_cast<deUint32>(TEST_OPTION_FRAGMENT_SHADING_RATE_BIT) : 0u;
3147 const deUint32 optionSets[] =
3148 {
3149 globalOption | TEST_OPTION_SAME_PATTERN_BIT,
3150 globalOption | 0u,
3151 globalOption | TEST_OPTION_DYNAMIC_STATE_BIT,
3152 globalOption | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3153 globalOption | TEST_OPTION_DYNAMIC_STATE_BIT | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3154 globalOption | TEST_OPTION_GENERAL_LAYOUT_BIT,
3155 globalOption | TEST_OPTION_GENERAL_LAYOUT_BIT | TEST_OPTION_DYNAMIC_STATE_BIT,
3156 globalOption | TEST_OPTION_GENERAL_LAYOUT_BIT | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3157 globalOption | TEST_OPTION_GENERAL_LAYOUT_BIT | TEST_OPTION_DYNAMIC_STATE_BIT | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3158 globalOption | TEST_OPTION_WAIT_EVENTS_BIT,
3159 globalOption | TEST_OPTION_WAIT_EVENTS_BIT | TEST_OPTION_GENERAL_LAYOUT_BIT,
3160 globalOption | TEST_OPTION_WAIT_EVENTS_BIT | TEST_OPTION_GENERAL_LAYOUT_BIT | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3161 };
3162
3163 const struct
3164 {
3165 TestDrawIn drawIn;
3166 TestClears clears;
3167 } drawClearSets[] =
3168 {
3169 { TEST_DRAW_IN_RENDER_PASSES, TEST_CLEARS_NO_CLEAR },
3170 { TEST_DRAW_IN_RENDER_PASSES, TEST_CLEARS_LOAD_OP_CLEAR },
3171 { TEST_DRAW_IN_RENDER_PASSES, TEST_CLEARS_CMD_CLEAR_ATTACHMENTS },
3172 { TEST_DRAW_IN_RENDER_PASSES, TEST_CLEARS_CMD_CLEAR_IMAGE },
3173 { TEST_DRAW_IN_SUBPASSES, TEST_CLEARS_NO_CLEAR },
3174 { TEST_DRAW_IN_SUBPASSES, TEST_CLEARS_CMD_CLEAR_ATTACHMENTS },
3175 { TEST_DRAW_IN_SAME_SUBPASS, TEST_CLEARS_NO_CLEAR },
3176 { TEST_DRAW_IN_SAME_SUBPASS, TEST_CLEARS_CMD_CLEAR_ATTACHMENTS },
3177 };
3178
3179 const TestImageAspect aspectRange[] =
3180 {
3181 TEST_IMAGE_ASPECT_COLOR,
3182 TEST_IMAGE_ASPECT_DEPTH,
3183 TEST_IMAGE_ASPECT_STENCIL,
3184 };
3185
3186 MovePtr<tcu::TestCaseGroup> drawGroup (new tcu::TestCaseGroup(rootGroup->getTestContext(), "draw", ""));
3187 for (const TestImageAspect* pLoopImageAspect = aspectRange; pLoopImageAspect != DE_ARRAY_END(aspectRange); ++pLoopImageAspect)
3188 {
3189 MovePtr<tcu::TestCaseGroup> aspectGroup (new tcu::TestCaseGroup(drawGroup->getTestContext(), getString(*pLoopImageAspect), ""));
3190 for (const VkSampleCountFlagBits* pLoopNumSamples = sampleCountRange; pLoopNumSamples < DE_ARRAY_END(sampleCountRange); ++pLoopNumSamples)
3191 {
3192 MovePtr<tcu::TestCaseGroup> samplesGroup (new tcu::TestCaseGroup(aspectGroup->getTestContext(), getString(*pLoopNumSamples).c_str(), ""));
3193
3194 for (deUint32 loopDrawSetNdx = 0u; loopDrawSetNdx < DE_LENGTH_OF_ARRAY(drawClearSets); ++loopDrawSetNdx)
3195 for (const deUint32* pLoopOptions = optionSets; pLoopOptions != DE_ARRAY_END(optionSets); ++pLoopOptions)
3196 {
3197 const TestParams params =
3198 {
3199 *pLoopNumSamples, // VkSampleCountFlagBits numSamples;
3200 *pLoopOptions, // TestOptionFlags options;
3201 drawClearSets[loopDrawSetNdx].drawIn, // TestDrawIn drawIn;
3202 drawClearSets[loopDrawSetNdx].clears, // TestClears clears;
3203 *pLoopImageAspect, // TestImageAspect imageAspect;
3204 };
3205
3206 // Filter out incompatible parameter combinations
3207 if (params.imageAspect != TEST_IMAGE_ASPECT_COLOR)
3208 {
3209 // If the sample pattern is changed, the D/S image must be cleared or the result is undefined
3210 if (((params.options & TEST_OPTION_SAME_PATTERN_BIT) == 0u) && (params.clears == TEST_CLEARS_NO_CLEAR))
3211 continue;
3212 }
3213
3214 // We are using events to change image layout and this is only allowed outside a render pass
3215 if (((params.options & TEST_OPTION_WAIT_EVENTS_BIT) != 0u) && (params.drawIn != TEST_DRAW_IN_RENDER_PASSES))
3216 continue;
3217
3218 // Can't change image layout inside a subpass
3219 if (((params.options & TEST_OPTION_GENERAL_LAYOUT_BIT) != 0u) && (params.drawIn == TEST_DRAW_IN_SAME_SUBPASS))
3220 continue;
3221
3222 std::ostringstream caseName;
3223 caseName << getString(params.drawIn) << "_"
3224 << getString(params.clears) << (params.options != 0 ? "_" : "")
3225 << getTestOptionFlagsString(params.options);
3226
3227 addInstanceTestCaseWithPrograms<DrawTest>(samplesGroup.get(), caseName.str().c_str(), "", checkSupportDrawTests, initPrograms, params);
3228 }
3229 aspectGroup->addChild(samplesGroup.release());
3230 }
3231 drawGroup->addChild(aspectGroup.release());
3232 }
3233 rootGroup->addChild(drawGroup.release());
3234 }
3235 }
3236
3237 } // anonymous ns
3238
createMultisampleSampleLocationsExtTests(tcu::TestContext & testCtx,bool useFragmentShadingRate)3239 tcu::TestCaseGroup* createMultisampleSampleLocationsExtTests (tcu::TestContext& testCtx, bool useFragmentShadingRate)
3240 {
3241 return createTestGroup(testCtx, "sample_locations_ext", "Test a graphics pipeline with user-defined sample locations", createTestsInGroup, useFragmentShadingRate);
3242 }
3243
3244 } // pipeline
3245 } // vkt
3246