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
32namespace vkt
33{
34namespace pipeline
35{
36namespace multisample
37{
38
39using namespace vk;
40
41struct VertexDataNdc
42{
43	VertexDataNdc (const tcu::Vec4& posNdc) : positionNdc(posNdc) {}
44
45	tcu::Vec4 positionNdc;
46};
47
48struct 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
56struct 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
64bool 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
79template <typename CaseClassName>
80class MSCase : public MultisampleCaseBase
81{
82public:
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
96template <typename CaseClassName>
97MultisampleCaseBase* MSCase<CaseClassName>::createCase (tcu::TestContext& testCtx, const std::string& name, const ImageMSParams& imageMSParams)
98{
99	return new MSCase<CaseClassName>(testCtx, name, imageMSParams);
100}
101
102template <typename InstanceClassName>
103class MSInstance : public MSInstanceBaseResolve
104{
105public:
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
117class MSInstanceDistinctValues;
118
119template<> 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
141template<> 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
152template<> 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
174class MSCaseSampleQualifierDistinctValues;
175
176template<> 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
188template<> 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
228template<> TestInstance* MSCase<MSCaseSampleQualifierDistinctValues>::createInstance (Context& context) const
229{
230	if (!context.getDeviceFeatures().sampleRateShading)
231		TCU_THROW(NotSupportedError, "sampleRateShading support required");
232	return new MSInstance<MSInstanceDistinctValues>(context, m_imageMSParams);
233}
234
235class MSCaseInterpolateAtSampleDistinctValues;
236
237template<> void MSCase<MSCaseInterpolateAtSampleDistinctValues>::init (void)
238{
239	m_testCtx.getLog()
240		<< tcu::TestLog::Message
241		<< "Verifying that a interpolateAtSample returns different values for different samples.\n"
242		<< "	Render full screen traingle with quadratic function defining red/green color pattern division.\n"
243		<< "	=> Resulting image should contain n+1 different colors, where n = sample count.\n"
244		<< tcu::TestLog::EndMessage;
245
246	MultisampleCaseBase::init();
247}
248
249template<> void MSCase<MSCaseInterpolateAtSampleDistinctValues>::initPrograms (vk::SourceCollections& programCollection) const
250{
251	// Create vertex shader
252	std::ostringstream vs;
253
254	vs << "#version 440\n"
255		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
256		<< "\n"
257		<< "layout(location = 0) out vec4 vs_out_position_ndc;\n"
258		<< "\n"
259		<< "out gl_PerVertex {\n"
260		<< "	vec4  gl_Position;\n"
261		<< "};\n"
262		<< "void main (void)\n"
263		<< "{\n"
264		<< "	gl_Position			= vs_in_position_ndc;\n"
265		<< "	vs_out_position_ndc = vs_in_position_ndc;\n"
266		<< "}\n";
267
268	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
269
270	// Create fragment shader
271	std::ostringstream fs;
272
273	fs << "#version 440\n"
274		<< "layout(location = 0) in vec4 fs_in_position_ndc;\n"
275		<< "\n"
276		<< "layout(location = 0) out vec4 fs_out_color;\n"
277		<< "\n"
278		<< "void main (void)\n"
279		<< "{\n"
280		<< "	const vec4 position_ndc_at_sample = interpolateAtSample(fs_in_position_ndc, gl_SampleID);\n"
281		<< "	if(position_ndc_at_sample.y < -2.0*pow(0.5*(position_ndc_at_sample.x + 1.0), 2.0) + 1.0)\n"
282		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
283		<< "	else\n"
284		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
285		<< "}\n";
286
287	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
288}
289
290template<> TestInstance* MSCase<MSCaseInterpolateAtSampleDistinctValues>::createInstance (Context& context) const
291{
292	if (!context.getDeviceFeatures().sampleRateShading)
293		TCU_THROW(NotSupportedError, "sampleRateShading support required");
294
295	return new MSInstance<MSInstanceDistinctValues>(context, m_imageMSParams);
296}
297
298class MSInstanceInterpolateScreenPosition;
299
300template<> MSInstanceBaseResolve::VertexDataDesc MSInstance<MSInstanceInterpolateScreenPosition>::getVertexDataDescripton (void) const
301{
302	VertexDataDesc vertexDataDesc;
303
304	vertexDataDesc.verticesCount		= 4u;
305	vertexDataDesc.dataStride			= sizeof(VertexDataNdcScreen);
306	vertexDataDesc.dataSize				= vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
307	vertexDataDesc.primitiveTopology	= VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
308
309	const VkVertexInputAttributeDescription vertexAttribPositionNdc =
310	{
311		0u,												// deUint32	location;
312		0u,												// deUint32	binding;
313		VK_FORMAT_R32G32B32A32_SFLOAT,					// VkFormat	format;
314		DE_OFFSET_OF(VertexDataNdcScreen, positionNdc),	// deUint32	offset;
315	};
316
317	vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
318
319	const VkVertexInputAttributeDescription vertexAttribPositionScreen =
320	{
321		1u,											// deUint32	location;
322		0u,											// deUint32	binding;
323		VK_FORMAT_R32G32_SFLOAT,					// VkFormat	format;
324		DE_OFFSET_OF(VertexDataNdcScreen, positionScreen),	// deUint32	offset;
325	};
326
327	vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionScreen);
328
329	return vertexDataDesc;
330}
331
332template<> void MSInstance<MSInstanceInterpolateScreenPosition>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
333{
334	const tcu::UVec3 layerSize		= getLayerSize(IMAGE_TYPE_2D, m_imageMSParams.imageSize);
335	const float		 screenSizeX	= static_cast<float>(layerSize.x());
336	const float		 screenSizeY	= static_cast<float>(layerSize.y());
337
338	std::vector<VertexDataNdcScreen> vertices;
339
340	vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, 0.0f)));
341	vertices.push_back(VertexDataNdcScreen(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec2(screenSizeX, 0.0f)));
342	vertices.push_back(VertexDataNdcScreen(tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, screenSizeY)));
343	vertices.push_back(VertexDataNdcScreen(tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f), tcu::Vec2(screenSizeX, screenSizeY)));
344
345	deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
346}
347
348template<> tcu::TestStatus MSInstance<MSInstanceInterpolateScreenPosition>::verifyImageData (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS) const
349{
350	if (checkForError(imageRSInfo, dataRS, 0))
351		return tcu::TestStatus::fail("Failed");
352
353	return tcu::TestStatus::pass("Passed");
354}
355
356class MSCaseInterpolateAtSampleSingleSample;
357
358template<> void MSCase<MSCaseInterpolateAtSampleSingleSample>::init (void)
359{
360	m_testCtx.getLog()
361		<< tcu::TestLog::Message
362		<< "Verifying that using interpolateAtSample with multisample buffers not available returns sample evaluated at the center of the pixel.\n"
363		<< "	Interpolate varying containing screen space location.\n"
364		<< "	=> fract(screen space location) should be (about) (0.5, 0.5)\n"
365		<< tcu::TestLog::EndMessage;
366
367	MultisampleCaseBase::init();
368}
369
370template<> void MSCase<MSCaseInterpolateAtSampleSingleSample>::initPrograms (vk::SourceCollections& programCollection) const
371{
372	// Create vertex shader
373	std::ostringstream vs;
374
375	vs << "#version 440\n"
376		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
377		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
378		<< "\n"
379		<< "layout(location = 0) out vec2 vs_out_position_screen;\n"
380		<< "\n"
381		<< "out gl_PerVertex {\n"
382		<< "	vec4  gl_Position;\n"
383		<< "};\n"
384		<< "void main (void)\n"
385		<< "{\n"
386		<< "	gl_Position				= vs_in_position_ndc;\n"
387		<< "	vs_out_position_screen	= vs_in_position_screen;\n"
388		<< "}\n";
389
390	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
391
392	// Create fragment shader
393	std::ostringstream fs;
394
395	fs << "#version 440\n"
396		<< "layout(location = 0) in vec2 fs_in_position_screen;\n"
397		<< "\n"
398		<< "layout(location = 0) out vec4 fs_out_color;\n"
399		<< "\n"
400		<< "void main (void)\n"
401		<< "{\n"
402		<< "	const float threshold					= 0.15625;\n"
403		<< "	const vec2  position_screen_at_sample	= interpolateAtSample(fs_in_position_screen, 0);\n"
404		<< "	const vec2  position_inside_pixel		= fract(position_screen_at_sample);\n"
405		<< "\n"
406		<< "	if (abs(position_inside_pixel.x - 0.5) <= threshold && abs(position_inside_pixel.y - 0.5) <= threshold)\n"
407		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
408		<< "	else\n"
409		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
410		<< "}\n";
411
412	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
413}
414
415template<> TestInstance* MSCase<MSCaseInterpolateAtSampleSingleSample>::createInstance (Context& context) const
416{
417	if (!context.getDeviceFeatures().sampleRateShading)
418		TCU_THROW(NotSupportedError, "sampleRateShading support required");
419
420	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
421}
422
423class MSCaseInterpolateAtSampleIgnoresCentroid;
424
425template<> void MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::init (void)
426{
427	m_testCtx.getLog()
428		<< tcu::TestLog::Message
429		<< "Verifying that interpolateAtSample ignores centroid qualifier.\n"
430		<< "	Interpolate varying containing screen space location with centroid and sample qualifiers.\n"
431		<< "	=> interpolateAtSample(screenSample, n) ~= interpolateAtSample(screenCentroid, n)\n"
432		<< tcu::TestLog::EndMessage;
433
434	MultisampleCaseBase::init();
435}
436
437template<> void MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::initPrograms (vk::SourceCollections& programCollection) const
438{
439	// Create vertex shader
440	std::ostringstream vs;
441
442	vs << "#version 440\n"
443		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
444		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
445		<< "\n"
446		<< "layout(location = 0) out vec2 vs_out_pos_screen_centroid;\n"
447		<< "layout(location = 1) out vec2 vs_out_pos_screen_fragment;\n"
448		<< "\n"
449		<< "out gl_PerVertex {\n"
450		<< "	vec4  gl_Position;\n"
451		<< "};\n"
452		<< "void main (void)\n"
453		<< "{\n"
454		<< "	gl_Position					= vs_in_position_ndc;\n"
455		<< "	vs_out_pos_screen_centroid	= vs_in_position_screen;\n"
456		<< "	vs_out_pos_screen_fragment	= vs_in_position_screen;\n"
457		<< "}\n";
458
459	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
460
461	// Create fragment shader
462	std::ostringstream fs;
463
464	fs << "#version 440\n"
465		<< "layout(location = 0) centroid in vec2 fs_in_pos_screen_centroid;\n"
466		<< "layout(location = 1)		  in vec2 fs_in_pos_screen_fragment;\n"
467		<< "\n"
468		<< "layout(location = 0) out vec4 fs_out_color;\n"
469		<< "\n"
470		<< "void main (void)\n"
471		<< "{\n"
472		<< "	const float threshold = 0.0005;\n"
473		<< "\n"
474		<< "	const vec2 position_a  = interpolateAtSample(fs_in_pos_screen_centroid, gl_SampleID);\n"
475		<< "	const vec2 position_b  = interpolateAtSample(fs_in_pos_screen_fragment, gl_SampleID);\n"
476		<< "	const bool valuesEqual = all(lessThan(abs(position_a - position_b), vec2(threshold)));\n"
477		<< "\n"
478		<< "	if (valuesEqual)\n"
479		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
480		<< "	else\n"
481		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
482		<< "}\n";
483
484	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
485}
486
487template<> TestInstance* MSCase<MSCaseInterpolateAtSampleIgnoresCentroid>::createInstance (Context& context) const
488{
489	if (!context.getDeviceFeatures().sampleRateShading)
490		TCU_THROW(NotSupportedError, "sampleRateShading support required");
491
492	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
493}
494
495class MSCaseInterpolateAtSampleConsistency;
496
497template<> void MSCase<MSCaseInterpolateAtSampleConsistency>::init (void)
498{
499	m_testCtx.getLog()
500		<< tcu::TestLog::Message
501		<< "Verifying that interpolateAtSample with the sample set to the current sampleID returns consistent values.\n"
502		<< "	Interpolate varying containing screen space location with centroid and sample qualifiers.\n"
503		<< "	=> interpolateAtSample(screenCentroid, sampleID) = screenSample\n"
504		<< tcu::TestLog::EndMessage;
505
506	MultisampleCaseBase::init();
507}
508
509template<> void MSCase<MSCaseInterpolateAtSampleConsistency>::initPrograms (vk::SourceCollections& programCollection) const
510{
511	// Create vertex shader
512	std::ostringstream vs;
513
514	vs << "#version 440\n"
515		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
516		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
517		<< "\n"
518		<< "layout(location = 0) out vec2 vs_out_pos_screen_centroid;\n"
519		<< "layout(location = 1) out vec2 vs_out_pos_screen_sample;\n"
520		<< "\n"
521		<< "out gl_PerVertex {\n"
522		<< "	vec4  gl_Position;\n"
523		<< "};\n"
524		<< "void main (void)\n"
525		<< "{\n"
526		<< "	gl_Position					= vs_in_position_ndc;\n"
527		<< "	vs_out_pos_screen_centroid	= vs_in_position_screen;\n"
528		<< "	vs_out_pos_screen_sample	= vs_in_position_screen;\n"
529		<< "}\n";
530
531	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
532
533	// Create fragment shader
534	std::ostringstream fs;
535
536	fs << "#version 440\n"
537		<< "layout(location = 0) centroid in vec2 fs_in_pos_screen_centroid;\n"
538		<< "layout(location = 1) sample   in vec2 fs_in_pos_screen_sample;\n"
539		<< "\n"
540		<< "layout(location = 0) out vec4 fs_out_color;\n"
541		<< "\n"
542		<< "void main (void)\n"
543		<< "{\n"
544		<< "	const float threshold = 0.15625;\n"
545		<< "\n"
546		<< "	const vec2  pos_interpolated_at_sample = interpolateAtSample(fs_in_pos_screen_centroid, gl_SampleID);\n"
547		<< "	const bool  valuesEqual				   = all(lessThan(abs(pos_interpolated_at_sample - fs_in_pos_screen_sample), vec2(threshold)));\n"
548		<< "\n"
549		<< "	if (valuesEqual)\n"
550		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
551		<< "	else\n"
552		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
553		<< "}\n";
554
555	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
556}
557
558template<> TestInstance* MSCase<MSCaseInterpolateAtSampleConsistency>::createInstance (Context& context) const
559{
560	if (!context.getDeviceFeatures().sampleRateShading)
561		TCU_THROW(NotSupportedError, "sampleRateShading support required");
562
563	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
564}
565
566class MSCaseInterpolateAtCentroidConsistency;
567
568template<> void MSCase<MSCaseInterpolateAtCentroidConsistency>::init (void)
569{
570	m_testCtx.getLog()
571		<< tcu::TestLog::Message
572		<< "Verifying that interpolateAtCentroid does not return different values than a corresponding centroid qualified varying.\n"
573		<< "	Interpolate varying containing screen space location with sample and centroid qualifiers.\n"
574		<< "	=> interpolateAtCentroid(screenSample) = screenCentroid\n"
575		<< tcu::TestLog::EndMessage;
576
577	MultisampleCaseBase::init();
578}
579
580template<> void MSCase<MSCaseInterpolateAtCentroidConsistency>::initPrograms (vk::SourceCollections& programCollection) const
581{
582	// Create vertex shader
583	std::ostringstream vs;
584
585	vs << "#version 440\n"
586		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
587		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
588		<< "\n"
589		<< "layout(location = 0) out vec2 vs_out_pos_screen_sample;\n"
590		<< "layout(location = 1) out vec2 vs_out_pos_screen_centroid;\n"
591		<< "\n"
592		<< "out gl_PerVertex {\n"
593		<< "	vec4  gl_Position;\n"
594		<< "};\n"
595		<< "void main (void)\n"
596		<< "{\n"
597		<< "	gl_Position					= vs_in_position_ndc;\n"
598		<< "	vs_out_pos_screen_sample	= vs_in_position_screen;\n"
599		<< "	vs_out_pos_screen_centroid	= vs_in_position_screen;\n"
600		<< "}\n";
601
602	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
603
604	// Create fragment shader
605	std::ostringstream fs;
606
607	fs << "#version 440\n"
608		<< "layout(location = 0) sample   in vec2 fs_in_pos_screen_sample;\n"
609		<< "layout(location = 1) centroid in vec2 fs_in_pos_screen_centroid;\n"
610		<< "\n"
611		<< "layout(location = 0) out vec4 fs_out_color;\n"
612		<< "\n"
613		<< "void main (void)\n"
614		<< "{\n"
615		<< "	const float threshold = 0.0005;\n"
616		<< "\n"
617		<< "	const vec2 pos_interpolated_at_centroid = interpolateAtCentroid(fs_in_pos_screen_sample);\n"
618		<< "	const bool valuesEqual					= all(lessThan(abs(pos_interpolated_at_centroid - fs_in_pos_screen_centroid), vec2(threshold)));\n"
619		<< "\n"
620		<< "	if (valuesEqual)\n"
621		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
622		<< "	else\n"
623		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
624		<< "}\n";
625
626	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
627}
628
629template<> TestInstance* MSCase<MSCaseInterpolateAtCentroidConsistency>::createInstance (Context& context) const
630{
631	if (!context.getDeviceFeatures().sampleRateShading)
632		TCU_THROW(NotSupportedError, "sampleRateShading support required");
633
634	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
635}
636
637class MSCaseInterpolateAtOffsetPixelCenter;
638
639template<> void MSCase<MSCaseInterpolateAtOffsetPixelCenter>::init (void)
640{
641	m_testCtx.getLog()
642		<< tcu::TestLog::Message
643		<< "Verifying that interpolateAtOffset returns value sampled at an offset from the center of the pixel.\n"
644		<< "	Interpolate varying containing screen space location.\n"
645		<< "	=> interpolateAtOffset(screen, offset) should be \"varying value at the pixel center\" + offset"
646		<< tcu::TestLog::EndMessage;
647
648	MultisampleCaseBase::init();
649}
650
651template<> void MSCase<MSCaseInterpolateAtOffsetPixelCenter>::initPrograms (vk::SourceCollections& programCollection) const
652{
653	// Create vertex shader
654	std::ostringstream vs;
655
656	vs << "#version 440\n"
657		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
658		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
659		<< "\n"
660		<< "layout(location = 0) out vec2 vs_out_pos_screen;\n"
661		<< "layout(location = 1) out vec2 vs_out_offset;\n"
662		<< "\n"
663		<< "out gl_PerVertex {\n"
664		<< "	vec4  gl_Position;\n"
665		<< "};\n"
666		<< "void main (void)\n"
667		<< "{\n"
668		<< "	gl_Position			= vs_in_position_ndc;\n"
669		<< "	vs_out_pos_screen	= vs_in_position_screen;\n"
670		<< "	vs_out_offset		= vs_in_position_ndc.xy * 0.5;\n"
671		<< "}\n";
672
673	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
674
675	// Create fragment shader
676	std::ostringstream fs;
677
678	fs << "#version 440\n"
679		<< "layout(location = 0) in  vec2 fs_in_pos_screen;\n"
680		<< "layout(location = 1) in  vec2 fs_in_offset;\n"
681		<< "\n"
682		<< "layout(location = 0) out vec4 fs_out_color;\n"
683		<< "\n"
684		<< "void main (void)\n"
685		<< "{\n"
686		<< "    const vec2  frag_center = interpolateAtOffset(fs_in_pos_screen, vec2(0.0));\n"
687		<< "    const vec2  center_diff = abs(frag_center - fs_in_pos_screen);\n"
688		<< "    const float threshold   = 0.125;\n"
689		<< "    bool        valuesEqual = false;\n"
690		<< "\n"
691		<< "    if (all(lessThan(center_diff, vec2(0.5 + threshold)))) {\n"
692		<< "        const vec2 pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen, fs_in_offset);\n"
693		<< "        const vec2 reference_value            = frag_center + fs_in_offset;\n"
694		<< "\n"
695		<< "        valuesEqual = all(lessThan(abs(pos_interpolated_at_offset - reference_value), vec2(threshold)));\n"
696		<< "    }\n"
697		<< "\n"
698		<< "    if (valuesEqual)\n"
699		<< "        fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
700		<< "    else\n"
701		<< "        fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
702		<< "}\n";
703
704	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
705}
706
707template<> TestInstance* MSCase<MSCaseInterpolateAtOffsetPixelCenter>::createInstance (Context& context) const
708{
709	if (!context.getDeviceFeatures().sampleRateShading)
710		TCU_THROW(NotSupportedError, "sampleRateShading support required");
711
712	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
713}
714
715class MSCaseInterpolateAtOffsetSamplePosition;
716
717template<> void MSCase<MSCaseInterpolateAtOffsetSamplePosition>::init (void)
718{
719	m_testCtx.getLog()
720		<< tcu::TestLog::Message
721		<< "Verifying that interpolateAtOffset of screen position with the offset of current sample position returns value "
722		<< "similar to screen position interpolated at sample.\n"
723		<< "	Interpolate varying containing screen space location with and without sample qualifier.\n"
724		<< "	=> interpolateAtOffset(screenFragment, samplePosition - (0.5,0.5)) = screenSample"
725		<< tcu::TestLog::EndMessage;
726
727	MultisampleCaseBase::init();
728}
729
730template<> void MSCase<MSCaseInterpolateAtOffsetSamplePosition>::initPrograms (vk::SourceCollections& programCollection) const
731{
732	// Create vertex shader
733	std::ostringstream vs;
734
735	vs << "#version 440\n"
736		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
737		<< "layout(location = 1) in vec2 vs_in_position_screen;\n"
738		<< "\n"
739		<< "layout(location = 0) out vec2 vs_out_pos_screen_fragment;\n"
740		<< "layout(location = 1) out vec2 vs_out_pos_screen_sample;\n"
741		<< "\n"
742		<< "out gl_PerVertex {\n"
743		<< "	vec4  gl_Position;\n"
744		<< "};\n"
745		<< "void main (void)\n"
746		<< "{\n"
747		<< "	gl_Position					= vs_in_position_ndc;\n"
748		<< "	vs_out_pos_screen_fragment	= vs_in_position_screen;\n"
749		<< "	vs_out_pos_screen_sample	= vs_in_position_screen;\n"
750		<< "}\n";
751
752	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
753
754	// Create fragment shader
755	std::ostringstream fs;
756
757	fs << "#version 440\n"
758		<< "layout(location = 0)		in vec2 fs_in_pos_screen_fragment;\n"
759		<< "layout(location = 1) sample in vec2 fs_in_pos_screen_sample;\n"
760		<< "\n"
761		<< "layout(location = 0) out vec4 fs_out_color;\n"
762		<< "\n"
763		<< "void main (void)\n"
764		<< "{\n"
765		<< "	const float threshold = 0.15625;\n"
766		<< "\n"
767		<< "	const vec2 offset					  = gl_SamplePosition - vec2(0.5, 0.5);\n"
768		<< "	const vec2 pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen_fragment, offset);\n"
769		<< "	const bool valuesEqual				  = all(lessThan(abs(pos_interpolated_at_offset - fs_in_pos_screen_sample), vec2(threshold)));\n"
770		<< "\n"
771		<< "	if (valuesEqual)\n"
772		<< "		fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
773		<< "	else\n"
774		<< "		fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
775		<< "}\n";
776
777	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
778}
779
780template<> TestInstance* MSCase<MSCaseInterpolateAtOffsetSamplePosition>::createInstance (Context& context) const
781{
782	if (!context.getDeviceFeatures().sampleRateShading)
783		TCU_THROW(NotSupportedError, "sampleRateShading support required");
784
785	return new MSInstance<MSInstanceInterpolateScreenPosition>(context, m_imageMSParams);
786}
787
788class MSInstanceInterpolateBarycentricCoordinates;
789
790template<> MSInstanceBaseResolve::VertexDataDesc MSInstance<MSInstanceInterpolateBarycentricCoordinates>::getVertexDataDescripton (void) const
791{
792	VertexDataDesc vertexDataDesc;
793
794	vertexDataDesc.verticesCount		= 3u;
795	vertexDataDesc.dataStride			= sizeof(VertexDataNdcBarycentric);
796	vertexDataDesc.dataSize				= vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
797	vertexDataDesc.primitiveTopology	= VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
798
799	const VkVertexInputAttributeDescription vertexAttribPositionNdc =
800	{
801		0u,															// deUint32	location;
802		0u,															// deUint32	binding;
803		VK_FORMAT_R32G32B32A32_SFLOAT,								// VkFormat	format;
804		DE_OFFSET_OF(VertexDataNdcBarycentric, positionNdc),		// deUint32	offset;
805	};
806
807	vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
808
809	const VkVertexInputAttributeDescription vertexAttrBarCoord =
810	{
811		1u,															// deUint32	location;
812		0u,															// deUint32	binding;
813		VK_FORMAT_R32G32B32_SFLOAT,									// VkFormat	format;
814		DE_OFFSET_OF(VertexDataNdcBarycentric, barycentricCoord),	// deUint32	offset;
815	};
816
817	vertexDataDesc.vertexAttribDescVec.push_back(vertexAttrBarCoord);
818
819	return vertexDataDesc;
820}
821
822template<> void MSInstance<MSInstanceInterpolateBarycentricCoordinates>::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
823{
824	// Create buffer storing vertex data
825	std::vector<VertexDataNdcBarycentric> vertices;
826
827	vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec3(0.0f, 0.0f, 1.0f)));
828	vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f), tcu::Vec3(1.0f, 0.0f, 0.0f)));
829	vertices.push_back(VertexDataNdcBarycentric(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec3(0.0f, 1.0f, 0.0f)));
830
831	deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
832}
833
834template<> tcu::TestStatus MSInstance<MSInstanceInterpolateBarycentricCoordinates>::verifyImageData (const vk::VkImageCreateInfo& imageRSInfo, const tcu::ConstPixelBufferAccess& dataRS) const
835{
836	if (checkForError(imageRSInfo, dataRS, 0))
837		return tcu::TestStatus::fail("Failed");
838
839	return tcu::TestStatus::pass("Passed");
840}
841
842class MSCaseCentroidQualifierInsidePrimitive;
843
844template<> void MSCase<MSCaseCentroidQualifierInsidePrimitive>::init (void)
845{
846	m_testCtx.getLog()
847		<< tcu::TestLog::Message
848		<< "Verifying that varying qualified with centroid is interpolated at location inside both the pixel and the primitive being processed.\n"
849		<< "	Interpolate triangle's barycentric coordinates with centroid qualifier.\n"
850		<< "	=> After interpolation we expect barycentric.xyz >= 0.0 && barycentric.xyz <= 1.0\n"
851		<< tcu::TestLog::EndMessage;
852
853	MultisampleCaseBase::init();
854}
855
856template<> void MSCase<MSCaseCentroidQualifierInsidePrimitive>::initPrograms (vk::SourceCollections& programCollection) const
857{
858	// Create vertex shader
859	std::ostringstream vs;
860
861	vs << "#version 440\n"
862		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
863		<< "layout(location = 1) in vec3 vs_in_barCoord;\n"
864		<< "\n"
865		<< "layout(location = 0) out vec3 vs_out_barCoord;\n"
866		<< "\n"
867		<< "out gl_PerVertex {\n"
868		<< "	vec4  gl_Position;\n"
869		<< "};\n"
870		<< "void main (void)\n"
871		<< "{\n"
872		<< "	gl_Position		= vs_in_position_ndc;\n"
873		<< "	vs_out_barCoord = vs_in_barCoord;\n"
874		<< "}\n";
875
876	programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
877
878	// Create fragment shader
879	std::ostringstream fs;
880
881	fs << "#version 440\n"
882		<< "layout(location = 0) centroid in vec3 fs_in_barCoord;\n"
883		<< "\n"
884		<< "layout(location = 0) out vec4 fs_out_color;\n"
885		<< "\n"
886		<< "void main (void)\n"
887		<< "{\n"
888		<< "	if( all(greaterThanEqual(fs_in_barCoord, vec3(0.0))) && all(lessThanEqual(fs_in_barCoord, vec3(1.0))) )\n"
889		<< "			fs_out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
890		<< "	else\n"
891		<< "			fs_out_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
892		<< "}\n";
893
894	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
895}
896
897template<> TestInstance* MSCase<MSCaseCentroidQualifierInsidePrimitive>::createInstance (Context& context) const
898{
899	return new MSInstance<MSInstanceInterpolateBarycentricCoordinates>(context, m_imageMSParams);
900}
901
902} // multisample
903
904tcu::TestCaseGroup* createMultisampleInterpolationTests (tcu::TestContext& testCtx)
905{
906	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "multisample_interpolation", "Multisample Interpolation"));
907
908	const tcu::UVec3 imageSizes[] =
909	{
910		tcu::UVec3(128u, 128u, 1u),
911		tcu::UVec3(137u, 191u, 1u),
912	};
913
914	const deUint32 sizesElemCount = static_cast<deUint32>(sizeof(imageSizes) / sizeof(tcu::UVec3));
915
916	const vk::VkSampleCountFlagBits imageSamples[] =
917	{
918		vk::VK_SAMPLE_COUNT_2_BIT,
919		vk::VK_SAMPLE_COUNT_4_BIT,
920		vk::VK_SAMPLE_COUNT_8_BIT,
921		vk::VK_SAMPLE_COUNT_16_BIT,
922		vk::VK_SAMPLE_COUNT_32_BIT,
923		vk::VK_SAMPLE_COUNT_64_BIT,
924	};
925
926	const deUint32 samplesElemCount = static_cast<deUint32>(sizeof(imageSamples) / sizeof(vk::VkSampleCountFlagBits));
927
928	de::MovePtr<tcu::TestCaseGroup> caseGroup(new tcu::TestCaseGroup(testCtx, "sample_interpolate_at_single_sample_", ""));
929
930	for (deUint32 imageSizeNdx = 0u; imageSizeNdx < sizesElemCount; ++imageSizeNdx)
931	{
932		const tcu::UVec3	imageSize = imageSizes[imageSizeNdx];
933		std::ostringstream	imageSizeStream;
934
935		imageSizeStream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z();
936
937		de::MovePtr<tcu::TestCaseGroup> sizeGroup(new tcu::TestCaseGroup(testCtx, imageSizeStream.str().c_str(), ""));
938
939		sizeGroup->addChild(multisample::MSCase<multisample::MSCaseInterpolateAtSampleSingleSample>::createCase(testCtx, "samples_" + de::toString(1), multisample::ImageMSParams(vk::VK_SAMPLE_COUNT_1_BIT, imageSize)));
940
941		caseGroup->addChild(sizeGroup.release());
942	}
943
944	testGroup->addChild(caseGroup.release());
945
946	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleDistinctValues> >	(testCtx, "sample_interpolate_at_distinct_values",	imageSizes, sizesElemCount, imageSamples, samplesElemCount));
947	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleIgnoresCentroid> >(testCtx, "sample_interpolate_at_ignores_centroid",	imageSizes, sizesElemCount, imageSamples, samplesElemCount));
948	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtSampleConsistency> >	(testCtx, "sample_interpolate_at_consistency",		imageSizes, sizesElemCount, imageSamples, samplesElemCount));
949	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseSampleQualifierDistinctValues> >		(testCtx, "sample_qualifier_distinct_values",		imageSizes, sizesElemCount, imageSamples, samplesElemCount));
950	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtCentroidConsistency> >	(testCtx, "centroid_interpolate_at_consistency",	imageSizes, sizesElemCount, imageSamples, samplesElemCount));
951	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseCentroidQualifierInsidePrimitive> >	(testCtx, "centroid_qualifier_inside_primitive",	imageSizes, sizesElemCount, imageSamples, samplesElemCount));
952	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetPixelCenter> >	(testCtx, "offset_interpolate_at_pixel_center",		imageSizes, sizesElemCount, imageSamples, samplesElemCount));
953	testGroup->addChild(makeMSGroup<multisample::MSCase<multisample::MSCaseInterpolateAtOffsetSamplePosition> >	(testCtx, "offset_interpolate_at_sample_position",	imageSizes, sizesElemCount, imageSamples, samplesElemCount));
954
955	return testGroup.release();
956}
957
958} // pipeline
959} // vkt
960