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