Fix eglBindAPI negative test am: 09784f8510 am: b7b2f00530 am: 03a8c9c6f8 am: 6e6f163...
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / pipeline / vktPipelineMultisampleInterpolationTests.cpp
1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*
20 * \file vktPipelineMultisampleInterpolationTests.cpp
21 * \brief Multisample Interpolation Tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktPipelineMultisampleInterpolationTests.hpp"
25 #include "vktPipelineMultisampleBaseResolve.hpp"
26 #include "vktPipelineMultisampleTestsUtil.hpp"
27 #include "vktPipelineMakeUtil.hpp"
28 #include "vkQueryUtil.hpp"
29 #include "tcuTestLog.hpp"
30 #include <vector>
31
32 namespace vkt
33 {
34 namespace pipeline
35 {
36 namespace multisample
37 {
38
39 using namespace vk;
40
41 struct VertexDataNdc
42 {
43         VertexDataNdc (const tcu::Vec4& posNdc) : positionNdc(posNdc) {}
44
45         tcu::Vec4 positionNdc;
46 };
47
48 struct VertexDataNdcScreen
49 {
50         VertexDataNdcScreen (const tcu::Vec4& posNdc, const tcu::Vec2& posScreen) : positionNdc(posNdc), positionScreen(posScreen) {}
51
52         tcu::Vec4 positionNdc;
53         tcu::Vec2 positionScreen;
54 };
55
56 struct VertexDataNdcBarycentric
57 {
58         VertexDataNdcBarycentric (const tcu::Vec4& posNdc, const tcu::Vec3& barCoord) : positionNdc(posNdc), barycentricCoord(barCoord) {}
59
60         tcu::Vec4 positionNdc;
61         tcu::Vec3 barycentricCoord;
62 };
63
64 bool checkForError (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS, const deUint32 errorCompNdx)
65 {
66         for (deUint32 z = 0u; z < imageRSInfo.extent.depth;  ++z)
67         for (deUint32 y = 0u; y < imageRSInfo.extent.height; ++y)
68         for (deUint32 x = 0u; x < imageRSInfo.extent.width;  ++x)
69         {
70                 const deUint32 errorComponent = dataRS.getPixelUint(x, y, z)[errorCompNdx];
71
72                 if (errorComponent > 0)
73                         return true;
74         }
75
76         return false;
77 }
78
79 template <typename CaseClassName>
80 class MSCase : public MultisampleCaseBase
81 {
82 public:
83                                                                 MSCase                  (tcu::TestContext&              testCtx,
84                                                                                                  const std::string&             name,
85                                                                                                  const ImageMSParams&   imageMSParams)
86                                                                 : MultisampleCaseBase(testCtx, name, imageMSParams) {}
87
88         void                                            init                    (void);
89         void                                            initPrograms    (vk::SourceCollections& programCollection) const;
90         TestInstance*                           createInstance  (Context&                               context) const;
91         static MultisampleCaseBase*     createCase              (tcu::TestContext&              testCtx,
92                                                                                                  const std::string&             name,
93                                                                                                  const ImageMSParams&   imageMSParams);
94 };
95
96 template <typename CaseClassName>
97 MultisampleCaseBase* MSCase<CaseClassName>::createCase (tcu::TestContext& testCtx, const std::string& name, const ImageMSParams& imageMSParams)
98 {
99         return new MSCase<CaseClassName>(testCtx, name, imageMSParams);
100 }
101
102 template <typename InstanceClassName>
103 class MSInstance : public MSInstanceBaseResolve
104 {
105 public:
106                                         MSInstance                              (Context&                                                       context,
107                                                                                          const ImageMSParams&                           imageMSParams)
108                                         : MSInstanceBaseResolve(context, imageMSParams) {}
109
110         VertexDataDesc  getVertexDataDescripton (void) const;
111         void                    uploadVertexData                (const Allocation&                                      vertexBufferAllocation,
112                                                                                          const VertexDataDesc&                          vertexDataDescripton) const;
113         tcu::TestStatus verifyImageData                 (const vk::VkImageCreateInfo&           imageRSInfo,
114                                                                                          const tcu::ConstPixelBufferAccess& dataRS) const;
115 };
116
117 class MSInstanceDistinctValues;
118
119 template<> MultisampleInstanceBase::VertexDataDesc MSInstance<MSInstanceDistinctValues>::getVertexDataDescripton (void) const
120 {
121         VertexDataDesc vertexDataDesc;
122
123         vertexDataDesc.verticesCount            = 3u;
124         vertexDataDesc.dataStride                       = sizeof(VertexDataNdc);
125         vertexDataDesc.dataSize                         = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
126         vertexDataDesc.primitiveTopology        = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
127
128         const VkVertexInputAttributeDescription vertexAttribPositionNdc =
129         {
130                 0u,                                                                             // deUint32     location;
131                 0u,                                                                             // deUint32     binding;
132                 VK_FORMAT_R32G32B32A32_SFLOAT,                  // VkFormat     format;
133                 DE_OFFSET_OF(VertexDataNdc, positionNdc),       // deUint32     offset;
134         };
135
136         vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
137
138         return vertexDataDesc;
139 }
140
141 template<> void MSInstance<MSInstanceDistinctValues>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
142 {
143         std::vector<VertexDataNdc> vertices;
144
145         vertices.push_back(VertexDataNdc(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f)));
146         vertices.push_back(VertexDataNdc(tcu::Vec4(-1.0f,  4.0f, 0.0f, 1.0f)));
147         vertices.push_back(VertexDataNdc(tcu::Vec4( 4.0f, -1.0f, 0.0f, 1.0f)));
148
149         deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
150 }
151
152 template<> tcu::TestStatus MSInstance<MSInstanceDistinctValues>::verifyImageData (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS) const
153 {
154         const deUint32 distinctValuesExpected = static_cast<deUint32>(m_imageMSParams.numSamples) + 1u;
155
156         std::vector<tcu::IVec4> distinctValues;
157
158         for (deUint32 z = 0u; z < imageRSInfo.extent.depth;      ++z)
159         for (deUint32 y = 0u; y < imageRSInfo.extent.height; ++y)
160         for (deUint32 x = 0u; x < imageRSInfo.extent.width;      ++x)
161         {
162                 const tcu::IVec4 pixel = dataRS.getPixelInt(x, y, z);
163
164                 if (std::find(distinctValues.begin(), distinctValues.end(), pixel) == distinctValues.end())
165                         distinctValues.push_back(pixel);
166         }
167
168         if (distinctValues.size() >= distinctValuesExpected)
169                 return tcu::TestStatus::pass("Passed");
170         else
171                 return tcu::TestStatus::fail("Expected numSamples+1 different colors in the output image");
172 }
173
174 class MSCaseSampleQualifierDistinctValues;
175
176 template<> void MSCase<MSCaseSampleQualifierDistinctValues>::init (void)
177 {
178         m_testCtx.getLog()
179                 << tcu::TestLog::Message
180                 << "Verifying that a sample qualified varying is given different values for different samples.\n"
181                 << "    Render full screen traingle with quadratic function defining red/green color pattern division.\n"
182                 << "    => Resulting image should contain n+1 different colors, where n = sample count.\n"
183                 << tcu::TestLog::EndMessage;
184
185         MultisampleCaseBase::init();
186 }
187
188 template<> void MSCase<MSCaseSampleQualifierDistinctValues>::initPrograms (vk::SourceCollections& programCollection) const
189 {
190         // Create vertex shader
191         std::ostringstream vs;
192
193         vs << "#version 440\n"
194                 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
195                 << "\n"
196                 << "layout(location = 0) out vec4 vs_out_position_ndc;\n"
197                 << "\n"
198                 << "out gl_PerVertex {\n"
199                 << "    vec4  gl_Position;\n"
200                 << "};\n"
201                 << "void main (void)\n"
202                 << "{\n"
203                 << "    gl_Position                     = vs_in_position_ndc;\n"
204                 << "    vs_out_position_ndc = vs_in_position_ndc;\n"
205                 << "}\n";
206
207         programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
208
209         // Create fragment shader
210         std::ostringstream fs;
211
212         fs << "#version 440\n"
213                 << "layout(location = 0) sample in vec4 fs_in_position_ndc;\n"
214                 << "\n"
215                 << "layout(location = 0) out vec4 fs_out_color;\n"
216                 << "\n"
217                 << "void main (void)\n"
218                 << "{\n"
219                 << "    if(fs_in_position_ndc.y < -2.0*pow(0.5*(fs_in_position_ndc.x + 1.0), 2.0) + 1.0)\n"
220                 << "            fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
221                 << "    else\n"
222                 << "            fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
223                 << "}\n";
224
225         programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
226 }
227
228 template<> TestInstance* MSCase<MSCaseSampleQualifierDistinctValues>::createInstance (Context& context) const
229 {
230         return new MSInstance<MSInstanceDistinctValues>(context, m_imageMSParams);
231 }
232
233 class MSCaseInterpolateAtSampleDistinctValues;
234
235 template<> void MSCase<MSCaseInterpolateAtSampleDistinctValues>::init (void)
236 {
237         m_testCtx.getLog()
238                 << tcu::TestLog::Message
239                 << "Verifying that a interpolateAtSample returns different values for different samples.\n"
240                 << "    Render full screen traingle with quadratic function defining red/green color pattern division.\n"
241                 << "    => Resulting image should contain n+1 different colors, where n = sample count.\n"
242                 << tcu::TestLog::EndMessage;
243
244         MultisampleCaseBase::init();
245 }
246
247 template<> void MSCase<MSCaseInterpolateAtSampleDistinctValues>::initPrograms (vk::SourceCollections& programCollection) const
248 {
249         // Create vertex shader
250         std::ostringstream vs;
251
252         vs << "#version 440\n"
253                 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
254                 << "\n"
255                 << "layout(location = 0) out vec4 vs_out_position_ndc;\n"
256                 << "\n"
257                 << "out gl_PerVertex {\n"
258                 << "    vec4  gl_Position;\n"
259                 << "};\n"
260                 << "void main (void)\n"
261                 << "{\n"
262                 << "    gl_Position                     = vs_in_position_ndc;\n"
263                 << "    vs_out_position_ndc = vs_in_position_ndc;\n"
264                 << "}\n";
265
266         programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
267
268         // Create fragment shader
269         std::ostringstream fs;
270
271         fs << "#version 440\n"
272                 << "layout(location = 0) in vec4 fs_in_position_ndc;\n"
273                 << "\n"
274                 << "layout(location = 0) out vec4 fs_out_color;\n"
275                 << "\n"
276                 << "void main (void)\n"
277                 << "{\n"
278                 << "    const vec4 position_ndc_at_sample = interpolateAtSample(fs_in_position_ndc, gl_SampleID);\n"
279                 << "    if(position_ndc_at_sample.y < -2.0*pow(0.5*(position_ndc_at_sample.x + 1.0), 2.0) + 1.0)\n"
280                 << "            fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
281                 << "    else\n"
282                 << "            fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
283                 << "}\n";
284
285         programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
286 }
287
288 template<> TestInstance* MSCase<MSCaseInterpolateAtSampleDistinctValues>::createInstance (Context& context) const
289 {
290         return new MSInstance<MSInstanceDistinctValues>(context, m_imageMSParams);
291 }
292
293 class MSInstanceInterpolateScreenPosition;
294
295 template<> MSInstanceBaseResolve::VertexDataDesc MSInstance<MSInstanceInterpolateScreenPosition>::getVertexDataDescripton (void) const
296 {
297         VertexDataDesc vertexDataDesc;
298
299         vertexDataDesc.verticesCount            = 4u;
300         vertexDataDesc.dataStride                       = sizeof(VertexDataNdcScreen);
301         vertexDataDesc.dataSize                         = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
302         vertexDataDesc.primitiveTopology        = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
303
304         const VkVertexInputAttributeDescription vertexAttribPositionNdc =
305         {
306                 0u,                                                                                             // deUint32     location;
307                 0u,                                                                                             // deUint32     binding;
308                 VK_FORMAT_R32G32B32A32_SFLOAT,                                  // VkFormat     format;
309                 DE_OFFSET_OF(VertexDataNdcScreen, positionNdc), // deUint32     offset;
310         };
311
312         vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
313
314         const VkVertexInputAttributeDescription vertexAttribPositionScreen =
315         {
316                 1u,                                                                                     // deUint32     location;
317                 0u,                                                                                     // deUint32     binding;
318                 VK_FORMAT_R32G32_SFLOAT,                                        // VkFormat     format;
319                 DE_OFFSET_OF(VertexDataNdcScreen, positionScreen),      // deUint32     offset;
320         };
321
322         vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionScreen);
323
324         return vertexDataDesc;
325 }
326
327 template<> void MSInstance<MSInstanceInterpolateScreenPosition>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
328 {
329         const tcu::UVec3 layerSize              = getLayerSize(IMAGE_TYPE_2D, m_imageMSParams.imageSize);
330         const float              screenSizeX    = static_cast<float>(layerSize.x());
331         const float              screenSizeY    = static_cast<float>(layerSize.y());
332
333         std::vector<VertexDataNdcScreen> vertices;
334
335         vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, 0.0f)));
336         vertices.push_back(VertexDataNdcScreen(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(screenSizeX, 0.0f)));
337         vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, screenSizeY)));
338         vertices.push_back(VertexDataNdcScreen(tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f), tcu::Vec2(screenSizeX, screenSizeY)));
339
340         deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
341 }
342
343 template<> tcu::TestStatus MSInstance<MSInstanceInterpolateScreenPosition>::verifyImageData (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS) const
344 {
345         if (checkForError(imageRSInfo, dataRS, 0))
346                 return tcu::TestStatus::fail("Failed");
347
348         return tcu::TestStatus::pass("Passed");
349 }
350
351 class MSCaseInterpolateAtSampleSingleSample;
352
353 template<> void MSCase<MSCaseInterpolateAtSampleSingleSample>::init (void)
354 {
355         m_testCtx.getLog()
356                 << tcu::TestLog::Message
357                 << "Verifying that using interpolateAtSample with multisample buffers not available returns sample evaluated at the center of the pixel.\n"
358                 << "    Interpolate varying containing screen space location.\n"
359                 << "    => fract(screen space location) should be (about) (0.5, 0.5)\n"
360                 << tcu::TestLog::EndMessage;
361
362         MultisampleCaseBase::init();
363 }
364
365 template<> void MSCase<MSCaseInterpolateAtSampleSingleSample>::initPrograms (vk::SourceCollections& programCollection) const
366 {
367         // Create vertex shader
368         std::ostringstream vs;
369
370         vs << "#version 440\n"
371                 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
372                 << "layout(location = 1) in vec2 vs_in_position_screen;\n"
373                 << "\n"
374                 << "layout(location = 0) out vec2 vs_out_position_screen;\n"
375                 << "\n"
376                 << "out gl_PerVertex {\n"
377                 << "    vec4  gl_Position;\n"
378                 << "};\n"
379                 << "void main (void)\n"
380                 << "{\n"
381                 << "    gl_Position                             = vs_in_position_ndc;\n"
382                 << "    vs_out_position_screen  = vs_in_position_screen;\n"
383                 << "}\n";
384
385         programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
386
387         // Create fragment shader
388         std::ostringstream fs;
389
390         fs << "#version 440\n"
391                 << "layout(location = 0) in vec2 fs_in_position_screen;\n"
392                 << "\n"
393                 << "layout(location = 0) out vec4 fs_out_color;\n"
394                 << "\n"
395                 << "void main (void)\n"
396                 << "{\n"
397                 << "    const float threshold                                   = 0.15625;\n"
398                 << "    const vec2  position_screen_at_sample   = interpolateAtSample(fs_in_position_screen, 0);\n"
399                 << "    const vec2  position_inside_pixel               = fract(position_screen_at_sample);\n"
400                 << "\n"
401                 << "    if (abs(position_inside_pixel.x - 0.5) <= threshold && abs(position_inside_pixel.y - 0.5) <= threshold)\n"
402                 << "            fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
403                 << "    else\n"
404                 << "            fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
405                 << "}\n";
406
407         programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
408 }
409
410 template<> TestInstance* MSCase<MSCaseInterpolateAtSampleSingleSample>::createInstance (Context& context) const
411 {
412         return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
413 }
414
415 class MSCaseInterpolateAtSampleIgnoresCentroid;
416
417 template<> void MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::init (void)
418 {
419         m_testCtx.getLog()
420                 << tcu::TestLog::Message
421                 << "Verifying that interpolateAtSample ignores centroid qualifier.\n"
422                 << "    Interpolate varying containing screen space location with centroid and sample qualifiers.\n"
423                 << "    => interpolateAtSample(screenSample, n) ~= interpolateAtSample(screenCentroid, n)\n"
424                 << tcu::TestLog::EndMessage;
425
426         MultisampleCaseBase::init();
427 }
428
429 template<> void MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::initPrograms (vk::SourceCollections& programCollection) const
430 {
431         // Create vertex shader
432         std::ostringstream vs;
433
434         vs << "#version 440\n"
435                 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
436                 << "layout(location = 1) in vec2 vs_in_position_screen;\n"
437                 << "\n"
438                 << "layout(location = 0) out vec2 vs_out_pos_screen_centroid;\n"
439                 << "layout(location = 1) out vec2 vs_out_pos_screen_fragment;\n"
440                 << "\n"
441                 << "out gl_PerVertex {\n"
442                 << "    vec4  gl_Position;\n"
443                 << "};\n"
444                 << "void main (void)\n"
445                 << "{\n"
446                 << "    gl_Position                                     = vs_in_position_ndc;\n"
447                 << "    vs_out_pos_screen_centroid      = vs_in_position_screen;\n"
448                 << "    vs_out_pos_screen_fragment      = vs_in_position_screen;\n"
449                 << "}\n";
450
451         programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
452
453         // Create fragment shader
454         std::ostringstream fs;
455
456         fs << "#version 440\n"
457                 << "layout(location = 0) centroid in vec2 fs_in_pos_screen_centroid;\n"
458                 << "layout(location = 1)                  in vec2 fs_in_pos_screen_fragment;\n"
459                 << "\n"
460                 << "layout(location = 0) out vec4 fs_out_color;\n"
461                 << "\n"
462                 << "void main (void)\n"
463                 << "{\n"
464                 << "    const float threshold = 0.0005;\n"
465                 << "\n"
466                 << "    const vec2 position_a  = interpolateAtSample(fs_in_pos_screen_centroid, gl_SampleID);\n"
467                 << "    const vec2 position_b  = interpolateAtSample(fs_in_pos_screen_fragment, gl_SampleID);\n"
468                 << "    const bool valuesEqual = all(lessThan(abs(position_a - position_b), vec2(threshold)));\n"
469                 << "\n"
470                 << "    if (valuesEqual)\n"
471                 << "            fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
472                 << "    else\n"
473                 << "            fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
474                 << "}\n";
475
476         programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
477 }
478
479 template<> TestInstance* MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::createInstance (Context& context) const
480 {
481         return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
482 }
483
484 class MSCaseInterpolateAtSampleConsistency;
485
486 template<> void MSCase<MSCaseInterpolateAtSampleConsistency>::init (void)
487 {
488         m_testCtx.getLog()
489                 << tcu::TestLog::Message
490                 << "Verifying that interpolateAtSample with the sample set to the current sampleID returns consistent values.\n"
491                 << "    Interpolate varying containing screen space location with centroid and sample qualifiers.\n"
492                 << "    => interpolateAtSample(screenCentroid, sampleID) = screenSample\n"
493                 << tcu::TestLog::EndMessage;
494
495         MultisampleCaseBase::init();
496 }
497
498 template<> void MSCase<MSCaseInterpolateAtSampleConsistency>::initPrograms (vk::SourceCollections& programCollection) const
499 {
500         // Create vertex shader
501         std::ostringstream vs;
502
503         vs << "#version 440\n"
504                 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
505                 << "layout(location = 1) in vec2 vs_in_position_screen;\n"
506                 << "\n"
507                 << "layout(location = 0) out vec2 vs_out_pos_screen_centroid;\n"
508                 << "layout(location = 1) out vec2 vs_out_pos_screen_sample;\n"
509                 << "\n"
510                 << "out gl_PerVertex {\n"
511                 << "    vec4  gl_Position;\n"
512                 << "};\n"
513                 << "void main (void)\n"
514                 << "{\n"
515                 << "    gl_Position                                     = vs_in_position_ndc;\n"
516                 << "    vs_out_pos_screen_centroid      = vs_in_position_screen;\n"
517                 << "    vs_out_pos_screen_sample        = vs_in_position_screen;\n"
518                 << "}\n";
519
520         programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
521
522         // Create fragment shader
523         std::ostringstream fs;
524
525         fs << "#version 440\n"
526                 << "layout(location = 0) centroid in vec2 fs_in_pos_screen_centroid;\n"
527                 << "layout(location = 1) sample   in vec2 fs_in_pos_screen_sample;\n"
528                 << "\n"
529                 << "layout(location = 0) out vec4 fs_out_color;\n"
530                 << "\n"
531                 << "void main (void)\n"
532                 << "{\n"
533                 << "    const float threshold = 0.15625;\n"
534                 << "\n"
535                 << "    const vec2  pos_interpolated_at_sample = interpolateAtSample(fs_in_pos_screen_centroid, gl_SampleID);\n"
536                 << "    const bool  valuesEqual                            = all(lessThan(abs(pos_interpolated_at_sample - fs_in_pos_screen_sample), vec2(threshold)));\n"
537                 << "\n"
538                 << "    if (valuesEqual)\n"
539                 << "            fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
540                 << "    else\n"
541                 << "            fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
542                 << "}\n";
543
544         programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
545 }
546
547 template<> TestInstance* MSCase<MSCaseInterpolateAtSampleConsistency>::createInstance (Context& context) const
548 {
549         return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
550 }
551
552 class MSCaseInterpolateAtCentroidConsistency;
553
554 template<> void MSCase<MSCaseInterpolateAtCentroidConsistency>::init (void)
555 {
556         m_testCtx.getLog()
557                 << tcu::TestLog::Message
558                 << "Verifying that interpolateAtCentroid does not return different values than a corresponding centroid qualified varying.\n"
559                 << "    Interpolate varying containing screen space location with sample and centroid qualifiers.\n"
560                 << "    => interpolateAtCentroid(screenSample) = screenCentroid\n"
561                 << tcu::TestLog::EndMessage;
562
563         MultisampleCaseBase::init();
564 }
565
566 template<> void MSCase<MSCaseInterpolateAtCentroidConsistency>::initPrograms (vk::SourceCollections& programCollection) const
567 {
568         // Create vertex shader
569         std::ostringstream vs;
570
571         vs << "#version 440\n"
572                 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
573                 << "layout(location = 1) in vec2 vs_in_position_screen;\n"
574                 << "\n"
575                 << "layout(location = 0) out vec2 vs_out_pos_screen_sample;\n"
576                 << "layout(location = 1) out vec2 vs_out_pos_screen_centroid;\n"
577                 << "\n"
578                 << "out gl_PerVertex {\n"
579                 << "    vec4  gl_Position;\n"
580                 << "};\n"
581                 << "void main (void)\n"
582                 << "{\n"
583                 << "    gl_Position                                     = vs_in_position_ndc;\n"
584                 << "    vs_out_pos_screen_sample        = vs_in_position_screen;\n"
585                 << "    vs_out_pos_screen_centroid      = vs_in_position_screen;\n"
586                 << "}\n";
587
588         programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
589
590         // Create fragment shader
591         std::ostringstream fs;
592
593         fs << "#version 440\n"
594                 << "layout(location = 0) sample   in vec2 fs_in_pos_screen_sample;\n"
595                 << "layout(location = 1) centroid in vec2 fs_in_pos_screen_centroid;\n"
596                 << "\n"
597                 << "layout(location = 0) out vec4 fs_out_color;\n"
598                 << "\n"
599                 << "void main (void)\n"
600                 << "{\n"
601                 << "    const float threshold = 0.0005;\n"
602                 << "\n"
603                 << "    const vec2 pos_interpolated_at_centroid = interpolateAtCentroid(fs_in_pos_screen_sample);\n"
604                 << "    const bool valuesEqual                                  = all(lessThan(abs(pos_interpolated_at_centroid - fs_in_pos_screen_centroid), vec2(threshold)));\n"
605                 << "\n"
606                 << "    if (valuesEqual)\n"
607                 << "            fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
608                 << "    else\n"
609                 << "            fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
610                 << "}\n";
611
612         programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
613 }
614
615 template<> TestInstance* MSCase<MSCaseInterpolateAtCentroidConsistency>::createInstance (Context& context) const
616 {
617         return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
618 }
619
620 class MSCaseInterpolateAtOffsetPixelCenter;
621
622 template<> void MSCase<MSCaseInterpolateAtOffsetPixelCenter>::init (void)
623 {
624         m_testCtx.getLog()
625                 << tcu::TestLog::Message
626                 << "Verifying that interpolateAtOffset returns value sampled at an offset from the center of the pixel.\n"
627                 << "    Interpolate varying containing screen space location.\n"
628                 << "    => interpolateAtOffset(screen, offset) should be \"varying value at the pixel center\" + offset"
629                 << tcu::TestLog::EndMessage;
630
631         MultisampleCaseBase::init();
632 }
633
634 template<> void MSCase<MSCaseInterpolateAtOffsetPixelCenter>::initPrograms (vk::SourceCollections& programCollection) const
635 {
636         // Create vertex shader
637         std::ostringstream vs;
638
639         vs << "#version 440\n"
640                 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
641                 << "layout(location = 1) in vec2 vs_in_position_screen;\n"
642                 << "\n"
643                 << "layout(location = 0) out vec2 vs_out_pos_screen;\n"
644                 << "layout(location = 1) out vec2 vs_out_offset;\n"
645                 << "\n"
646                 << "out gl_PerVertex {\n"
647                 << "    vec4  gl_Position;\n"
648                 << "};\n"
649                 << "void main (void)\n"
650                 << "{\n"
651                 << "    gl_Position                     = vs_in_position_ndc;\n"
652                 << "    vs_out_pos_screen       = vs_in_position_screen;\n"
653                 << "    vs_out_offset           = vs_in_position_ndc.xy * 0.5;\n"
654                 << "}\n";
655
656         programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
657
658         // Create fragment shader
659         std::ostringstream fs;
660
661         fs << "#version 440\n"
662                 << "layout(location = 0) in  vec2 fs_in_pos_screen;\n"
663                 << "layout(location = 1) in  vec2 fs_in_offset;\n"
664                 << "\n"
665                 << "layout(location = 0) out vec4 fs_out_color;\n"
666                 << "\n"
667                 << "void main (void)\n"
668                 << "{\n"
669                 << "    const vec2  frag_center = interpolateAtOffset(fs_in_pos_screen, vec2(0.0));\n"
670                 << "    const vec2  center_diff = abs(frag_center - fs_in_pos_screen);\n"
671                 << "    const float threshold   = 0.125;\n"
672                 << "    bool        valuesEqual = false;\n"
673                 << "\n"
674                 << "    if (all(lessThan(center_diff, vec2(0.5 + threshold)))) {\n"
675                 << "        const vec2 pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen, fs_in_offset);\n"
676                 << "        const vec2 reference_value            = frag_center + fs_in_offset;\n"
677                 << "\n"
678                 << "        valuesEqual = all(lessThan(abs(pos_interpolated_at_offset - reference_value), vec2(threshold)));\n"
679                 << "    }\n"
680                 << "\n"
681                 << "    if (valuesEqual)\n"
682                 << "        fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
683                 << "    else\n"
684                 << "        fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
685                 << "}\n";
686
687         programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
688 }
689
690 template<> TestInstance* MSCase<MSCaseInterpolateAtOffsetPixelCenter>::createInstance (Context& context) const
691 {
692         return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
693 }
694
695 class MSCaseInterpolateAtOffsetSamplePosition;
696
697 template<> void MSCase<MSCaseInterpolateAtOffsetSamplePosition>::init (void)
698 {
699         m_testCtx.getLog()
700                 << tcu::TestLog::Message
701                 << "Verifying that interpolateAtOffset of screen position with the offset of current sample position returns value "
702                 << "similar to screen position interpolated at sample.\n"
703                 << "    Interpolate varying containing screen space location with and without sample qualifier.\n"
704                 << "    => interpolateAtOffset(screenFragment, samplePosition - (0.5,0.5)) = screenSample"
705                 << tcu::TestLog::EndMessage;
706
707         MultisampleCaseBase::init();
708 }
709
710 template<> void MSCase<MSCaseInterpolateAtOffsetSamplePosition>::initPrograms (vk::SourceCollections& programCollection) const
711 {
712         // Create vertex shader
713         std::ostringstream vs;
714
715         vs << "#version 440\n"
716                 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
717                 << "layout(location = 1) in vec2 vs_in_position_screen;\n"
718                 << "\n"
719                 << "layout(location = 0) out vec2 vs_out_pos_screen_fragment;\n"
720                 << "layout(location = 1) out vec2 vs_out_pos_screen_sample;\n"
721                 << "\n"
722                 << "out gl_PerVertex {\n"
723                 << "    vec4  gl_Position;\n"
724                 << "};\n"
725                 << "void main (void)\n"
726                 << "{\n"
727                 << "    gl_Position                                     = vs_in_position_ndc;\n"
728                 << "    vs_out_pos_screen_fragment      = vs_in_position_screen;\n"
729                 << "    vs_out_pos_screen_sample        = vs_in_position_screen;\n"
730                 << "}\n";
731
732         programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
733
734         // Create fragment shader
735         std::ostringstream fs;
736
737         fs << "#version 440\n"
738                 << "layout(location = 0)                in vec2 fs_in_pos_screen_fragment;\n"
739                 << "layout(location = 1) sample in vec2 fs_in_pos_screen_sample;\n"
740                 << "\n"
741                 << "layout(location = 0) out vec4 fs_out_color;\n"
742                 << "\n"
743                 << "void main (void)\n"
744                 << "{\n"
745                 << "    const float threshold = 0.15625;\n"
746                 << "\n"
747                 << "    const vec2 offset                                         = gl_SamplePosition - vec2(0.5, 0.5);\n"
748                 << "    const vec2 pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen_fragment, offset);\n"
749                 << "    const bool valuesEqual                            = all(lessThan(abs(pos_interpolated_at_offset - fs_in_pos_screen_sample), vec2(threshold)));\n"
750                 << "\n"
751                 << "    if (valuesEqual)\n"
752                 << "            fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
753                 << "    else\n"
754                 << "            fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
755                 << "}\n";
756
757         programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
758 }
759
760 template<> TestInstance* MSCase<MSCaseInterpolateAtOffsetSamplePosition>::createInstance (Context& context) const
761 {
762         return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
763 }
764
765 class MSInstanceInterpolateBarycentricCoordinates;
766
767 template<> MSInstanceBaseResolve::VertexDataDesc MSInstance<MSInstanceInterpolateBarycentricCoordinates>::getVertexDataDescripton (void) const
768 {
769         VertexDataDesc vertexDataDesc;
770
771         vertexDataDesc.verticesCount            = 3u;
772         vertexDataDesc.dataStride                       = sizeof(VertexDataNdcBarycentric);
773         vertexDataDesc.dataSize                         = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
774         vertexDataDesc.primitiveTopology        = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
775
776         const VkVertexInputAttributeDescription vertexAttribPositionNdc =
777         {
778                 0u,                                                                                                                     // deUint32     location;
779                 0u,                                                                                                                     // deUint32     binding;
780                 VK_FORMAT_R32G32B32A32_SFLOAT,                                                          // VkFormat     format;
781                 DE_OFFSET_OF(VertexDataNdcBarycentric, positionNdc),            // deUint32     offset;
782         };
783
784         vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
785
786         const VkVertexInputAttributeDescription vertexAttrBarCoord =
787         {
788                 1u,                                                                                                                     // deUint32     location;
789                 0u,                                                                                                                     // deUint32     binding;
790                 VK_FORMAT_R32G32B32_SFLOAT,                                                                     // VkFormat     format;
791                 DE_OFFSET_OF(VertexDataNdcBarycentric, barycentricCoord),       // deUint32     offset;
792         };
793
794         vertexDataDesc.vertexAttribDescVec.push_back(vertexAttrBarCoord);
795
796         return vertexDataDesc;
797 }
798
799 template<> void MSInstance<MSInstanceInterpolateBarycentricCoordinates>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
800 {
801         // Create buffer storing vertex data
802         std::vector<VertexDataNdcBarycentric> vertices;
803
804         vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec3(0.0f, 0.0f, 1.0f)));
805         vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f), tcu::Vec3(1.0f, 0.0f, 0.0f)));
806         vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec3(0.0f, 1.0f, 0.0f)));
807
808         deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
809 }
810
811 template<> tcu::TestStatus MSInstance<MSInstanceInterpolateBarycentricCoordinates>::verifyImageData (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS) const
812 {
813         if (checkForError(imageRSInfo, dataRS, 0))
814                 return tcu::TestStatus::fail("Failed");
815
816         return tcu::TestStatus::pass("Passed");
817 }
818
819 class MSCaseCentroidQualifierInsidePrimitive;
820
821 template<> void MSCase<MSCaseCentroidQualifierInsidePrimitive>::init (void)
822 {
823         m_testCtx.getLog()
824                 << tcu::TestLog::Message
825                 << "Verifying that varying qualified with centroid is interpolated at location inside both the pixel and the primitive being processed.\n"
826                 << "    Interpolate triangle's barycentric coordinates with centroid qualifier.\n"
827                 << "    => After interpolation we expect barycentric.xyz >= 0.0 && barycentric.xyz <= 1.0\n"
828                 << tcu::TestLog::EndMessage;
829
830         MultisampleCaseBase::init();
831 }
832
833 template<> void MSCase<MSCaseCentroidQualifierInsidePrimitive>::initPrograms (vk::SourceCollections& programCollection) const
834 {
835         // Create vertex shader
836         std::ostringstream vs;
837
838         vs << "#version 440\n"
839                 << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
840                 << "layout(location = 1) in vec3 vs_in_barCoord;\n"
841                 << "\n"
842                 << "layout(location = 0) out vec3 vs_out_barCoord;\n"
843                 << "\n"
844                 << "out gl_PerVertex {\n"
845                 << "    vec4  gl_Position;\n"
846                 << "};\n"
847                 << "void main (void)\n"
848                 << "{\n"
849                 << "    gl_Position             = vs_in_position_ndc;\n"
850                 << "    vs_out_barCoord = vs_in_barCoord;\n"
851                 << "}\n";
852
853         programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
854
855         // Create fragment shader
856         std::ostringstream fs;
857
858         fs << "#version 440\n"
859                 << "layout(location = 0) centroid in vec3 fs_in_barCoord;\n"
860                 << "\n"
861                 << "layout(location = 0) out vec4 fs_out_color;\n"
862                 << "\n"
863                 << "void main (void)\n"
864                 << "{\n"
865                 << "    if( all(greaterThanEqual(fs_in_barCoord, vec3(0.0))) && all(lessThanEqual(fs_in_barCoord, vec3(1.0))) )\n"
866                 << "                    fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
867                 << "    else\n"
868                 << "                    fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
869                 << "}\n";
870
871         programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
872 }
873
874 template<> TestInstance* MSCase<MSCaseCentroidQualifierInsidePrimitive>::createInstance (Context& context) const
875 {
876         return new MSInstance<MSInstanceInterpolateBarycentricCoordinates>(context, m_imageMSParams);
877 }
878
879 } // multisample
880
881 tcu::TestCaseGroup* createMultisampleInterpolationTests (tcu::TestContext& testCtx)
882 {
883         de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "multisample_interpolation", "Multisample Interpolation"));
884
885         const tcu::UVec3 imageSizes[] =
886         {
887                 tcu::UVec3(128u, 128u, 1u),
888                 tcu::UVec3(137u, 191u, 1u),
889         };
890
891         const deUint32 sizesElemCount = static_cast<deUint32>(sizeof(imageSizes) / sizeof(tcu::UVec3));
892
893         const vk::VkSampleCountFlagBits imageSamples[] =
894         {
895                 vk::VK_SAMPLE_COUNT_2_BIT,
896                 vk::VK_SAMPLE_COUNT_4_BIT,
897                 vk::VK_SAMPLE_COUNT_8_BIT,
898                 vk::VK_SAMPLE_COUNT_16_BIT,
899                 vk::VK_SAMPLE_COUNT_32_BIT,
900                 vk::VK_SAMPLE_COUNT_64_BIT,
901         };
902
903         const deUint32 samplesElemCount = static_cast<deUint32>(sizeof(imageSamples) / sizeof(vk::VkSampleCountFlagBits));
904
905         de::MovePtr<tcu::TestCaseGroup> caseGroup(new tcu::TestCaseGroup(testCtx, "sample_interpolate_at_single_sample_", ""));
906
907         for (deUint32 imageSizeNdx = 0u; imageSizeNdx < sizesElemCount; ++imageSizeNdx)
908         {
909                 const tcu::UVec3        imageSize = imageSizes[imageSizeNdx];
910                 std::ostringstream      imageSizeStream;
911
912                 imageSizeStream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z();
913
914                 de::MovePtr<tcu::TestCaseGroup> sizeGroup(new tcu::TestCaseGroup(testCtx, imageSizeStream.str().c_str(), ""));
915
916                 sizeGroup->addChild(multisample::MSCase<multisample::MSCaseInterpolateAtSampleSingleSample>::createCase(testCtx, "samples_" + de::toString(1), multisample::ImageMSParams(vk::VK_SAMPLE_COUNT_1_BIT, imageSize)));
917
918                 caseGroup->addChild(sizeGroup.release());
919         }
920
921         testGroup->addChild(caseGroup.release());
922
923         testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleDistinctValues> >     (testCtx, "sample_interpolate_at_distinct_values",      imageSizes, sizesElemCount, imageSamples, samplesElemCount));
924         testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleIgnoresCentroid> >(testCtx, "sample_interpolate_at_ignores_centroid", imageSizes, sizesElemCount, imageSamples, samplesElemCount));
925         testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleConsistency> >        (testCtx, "sample_interpolate_at_consistency",          imageSizes, sizesElemCount, imageSamples, samplesElemCount));
926         testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleQualifierDistinctValues> >         (testCtx, "sample_qualifier_distinct_values",           imageSizes, sizesElemCount, imageSamples, samplesElemCount));
927         testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtCentroidConsistency> >      (testCtx, "centroid_interpolate_at_consistency",        imageSizes, sizesElemCount, imageSamples, samplesElemCount));
928         testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseCentroidQualifierInsidePrimitive> >      (testCtx, "centroid_qualifier_inside_primitive",        imageSizes, sizesElemCount, imageSamples, samplesElemCount));
929         testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetPixelCenter> >        (testCtx, "offset_interpolate_at_pixel_center",         imageSizes, sizesElemCount, imageSamples, samplesElemCount));
930         testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetSamplePosition> >     (testCtx, "offset_interpolate_at_sample_position",      imageSizes, sizesElemCount, imageSamples, samplesElemCount));
931
932         return testGroup.release();
933 }
934
935 } // pipeline
936 } // vkt