1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2014 The Android Open Source Project
6 * Copyright (c) 2016 The Khronos Group Inc.
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * \brief Tessellation Geometry Interaction - Point Size
23 *//*--------------------------------------------------------------------*/
25 #include "vktTessellationGeometryPassthroughTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTessellationUtil.hpp"
29 #include "tcuTestLog.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkBuilderUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkImageUtil.hpp"
37 #include "deUniquePtr.hpp"
44 namespace tessellation
59 FLAG_VERTEX_SET = 1u << 0, // !< set gl_PointSize in vertex shader
60 FLAG_TESSELLATION_EVALUATION_SET = 1u << 1, // !< set gl_PointSize in tessellation evaluation shader
61 FLAG_TESSELLATION_ADD = 1u << 2, // !< read and add to gl_PointSize in tessellation shader pair
62 FLAG_GEOMETRY_SET = 1u << 3, // !< set gl_PointSize in geometry shader
63 FLAG_GEOMETRY_ADD = 1u << 4, // !< read and add to gl_PointSize in geometry shader
65 typedef deUint32 Flags;
67 void checkPointSizeRequirements (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const int maxPointSize)
69 const VkPhysicalDeviceProperties properties = getPhysicalDeviceProperties(vki, physDevice);
70 if (maxPointSize > static_cast<int>(properties.limits.pointSizeRange[1]))
71 throw tcu::NotSupportedError("Test requires point size " + de::toString(maxPointSize));
72 // Point size granularity must be 1.0 at most, so no need to check it for this test.
75 int getExpectedPointSize (const Flags flags)
80 if (flags & FLAG_GEOMETRY_SET)
82 else if (flags & FLAG_GEOMETRY_ADD)
86 if (flags & FLAG_TESSELLATION_EVALUATION_SET)
88 else if (flags & FLAG_TESSELLATION_ADD)
92 if (flags & FLAG_VERTEX_SET)
100 inline bool isTessellationStage (const Flags flags)
102 return (flags & (FLAG_TESSELLATION_EVALUATION_SET | FLAG_TESSELLATION_ADD)) != 0;
105 inline bool isGeometryStage (const Flags flags)
107 return (flags & (FLAG_GEOMETRY_SET | FLAG_GEOMETRY_ADD)) != 0;
110 bool verifyImage (tcu::TestLog& log, const tcu::ConstPixelBufferAccess image, const int expectedSize)
112 log << tcu::TestLog::Message << "Verifying rendered point size. Expecting " << expectedSize << " pixels." << tcu::TestLog::EndMessage;
114 bool resultAreaFound = false;
115 tcu::IVec4 resultArea;
116 const tcu::Vec4 black(0.0, 0.0, 0.0, 1.0);
118 // Find rasterization output area
120 for (int y = 0; y < image.getHeight(); ++y)
121 for (int x = 0; x < image.getWidth(); ++x)
122 if (image.getPixel(x, y) != black)
124 if (!resultAreaFound)
127 resultArea = tcu::IVec4(x, y, x + 1, y + 1);
128 resultAreaFound = true;
133 resultArea.x() = de::min(resultArea.x(), x);
134 resultArea.y() = de::min(resultArea.y(), y);
135 resultArea.z() = de::max(resultArea.z(), x+1);
136 resultArea.w() = de::max(resultArea.w(), y+1);
140 if (!resultAreaFound)
142 log << tcu::TestLog::Message << "Verification failed, could not find any point fragments." << tcu::TestLog::EndMessage;
146 const tcu::IVec2 pointSize = resultArea.swizzle(2,3) - resultArea.swizzle(0, 1);
148 if (pointSize.x() != pointSize.y())
150 log << tcu::TestLog::Message << "ERROR! Rasterized point is not a square. Point size was " << pointSize << tcu::TestLog::EndMessage;
154 if (pointSize.x() != expectedSize)
156 log << tcu::TestLog::Message << "ERROR! Point size invalid, expected " << expectedSize << ", got " << pointSize.x() << tcu::TestLog::EndMessage;
163 void initPrograms (vk::SourceCollections& programCollection, const Flags flags)
167 std::ostringstream src;
168 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
170 << "void main (void)\n"
172 << " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n";
174 if (flags & FLAG_VERTEX_SET)
175 src << " gl_PointSize = 2.0;\n";
179 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
184 std::ostringstream src;
185 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
186 << "layout(location = 0) out mediump vec4 fragColor;\n"
188 << "void main (void)\n"
190 << " fragColor = vec4(1.0);\n"
193 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
196 if (isTessellationStage(flags))
198 // Tessellation control shader
200 std::ostringstream src;
201 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
202 << "#extension GL_EXT_tessellation_shader : require\n"
203 << "#extension GL_EXT_tessellation_point_size : require\n"
204 << "layout(vertices = 1) out;\n"
206 << "void main (void)\n"
208 << " gl_TessLevelOuter[0] = 3.0;\n"
209 << " gl_TessLevelOuter[1] = 3.0;\n"
210 << " gl_TessLevelOuter[2] = 3.0;\n"
211 << " gl_TessLevelInner[0] = 3.0;\n"
213 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n";
215 if (flags & FLAG_TESSELLATION_ADD)
216 src << " // pass as is to eval\n"
217 << " gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n";
221 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
224 // Tessellation evaluation shader
226 std::ostringstream src;
227 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
228 << "#extension GL_EXT_tessellation_shader : require\n"
229 << "#extension GL_EXT_tessellation_point_size : require\n"
230 << "layout(triangles, point_mode) in;\n"
232 << "void main (void)\n"
234 << " // hide all but one vertex\n"
235 << " if (gl_TessCoord.x < 0.99)\n"
236 << " gl_Position = vec4(-2.0, 0.0, 0.0, 1.0);\n"
238 << " gl_Position = gl_in[0].gl_Position;\n";
240 if (flags & FLAG_TESSELLATION_ADD)
242 << " // add to point size\n"
243 << " gl_PointSize = gl_in[0].gl_PointSize + 2.0;\n";
244 else if (flags & FLAG_TESSELLATION_EVALUATION_SET)
246 << " // set point size\n"
247 << " gl_PointSize = 4.0;\n";
251 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
255 if (isGeometryStage(flags))
258 std::ostringstream src;
259 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
260 << "#extension GL_EXT_geometry_shader : require\n"
261 << "#extension GL_EXT_geometry_point_size : require\n"
262 << "layout(points) in;\n"
263 << "layout(points, max_vertices = 1) out;\n"
265 << "void main (void)\n"
267 << " gl_Position = gl_in[0].gl_Position;\n";
269 if (flags & FLAG_GEOMETRY_SET)
270 src << " gl_PointSize = 6.0;\n";
271 else if (flags & FLAG_GEOMETRY_ADD)
272 src << " gl_PointSize = gl_in[0].gl_PointSize + 2.0;\n";
275 << " EmitVertex();\n"
278 programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
282 tcu::TestStatus test (Context& context, const Flags flags)
284 const int expectedPointSize = getExpectedPointSize(flags);
286 const InstanceInterface& vki = context.getInstanceInterface();
287 const VkPhysicalDevice physDevice = context.getPhysicalDevice();
289 requireFeatures (vki, physDevice, FEATURE_TESSELLATION_SHADER | FEATURE_GEOMETRY_SHADER | FEATURE_SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE);
290 checkPointSizeRequirements(vki, physDevice, expectedPointSize);
293 tcu::TestLog& log = context.getTestContext().getLog();
295 if (flags & FLAG_VERTEX_SET)
296 log << tcu::TestLog::Message << "Setting point size in vertex shader to 2.0." << tcu::TestLog::EndMessage;
297 if (flags & FLAG_TESSELLATION_EVALUATION_SET)
298 log << tcu::TestLog::Message << "Setting point size in tessellation evaluation shader to 4.0." << tcu::TestLog::EndMessage;
299 if (flags & FLAG_TESSELLATION_ADD)
300 log << tcu::TestLog::Message << "Reading point size in tessellation control shader and adding 2.0 to it in evaluation." << tcu::TestLog::EndMessage;
301 if (flags & FLAG_GEOMETRY_SET)
302 log << tcu::TestLog::Message << "Setting point size in geometry shader to 6.0." << tcu::TestLog::EndMessage;
303 if (flags & FLAG_GEOMETRY_ADD)
304 log << tcu::TestLog::Message << "Reading point size in geometry shader and adding 2.0." << tcu::TestLog::EndMessage;
307 const DeviceInterface& vk = context.getDeviceInterface();
308 const VkDevice device = context.getDevice();
309 const VkQueue queue = context.getUniversalQueue();
310 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
311 Allocator& allocator = context.getDefaultAllocator();
315 const tcu::IVec2 renderSize = tcu::IVec2(RENDER_SIZE, RENDER_SIZE);
316 const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
317 const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
318 const Image colorAttachmentImage (vk, device, allocator,
319 makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
320 MemoryRequirement::Any);
322 // Color output buffer
324 const VkDeviceSize colorBufferSizeBytes = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
325 const Buffer colorBuffer (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
329 const Unique<VkImageView> colorAttachmentView(makeImageView (vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
330 const Unique<VkRenderPass> renderPass (makeRenderPass (vk, device, colorFormat));
331 const Unique<VkFramebuffer> framebuffer (makeFramebuffer (vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y(), 1u));
332 const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayoutWithoutDescriptors(vk, device));
333 const Unique<VkCommandPool> cmdPool (makeCommandPool (vk, device, queueFamilyIndex));
334 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer (vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
336 GraphicsPipelineBuilder pipelineBuilder;
339 .setPrimitiveTopology (VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
340 .setRenderSize (renderSize)
341 .setPatchControlPoints (1)
342 .setShader (vk, device, VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get("vert"), DE_NULL)
343 .setShader (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get("frag"), DE_NULL);
345 if (isTessellationStage(flags))
347 .setShader (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, context.getBinaryCollection().get("tesc"), DE_NULL)
348 .setShader (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, context.getBinaryCollection().get("tese"), DE_NULL);
350 if (isGeometryStage(flags))
352 .setShader (vk, device, VK_SHADER_STAGE_GEOMETRY_BIT, context.getBinaryCollection().get("geom"), DE_NULL);
354 const Unique<VkPipeline> pipeline(pipelineBuilder.build(vk, device, *pipelineLayout, *renderPass));
358 beginCommandBuffer(vk, *cmdBuffer);
361 const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
362 (VkAccessFlags)0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
363 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
364 *colorAttachmentImage, colorImageSubresourceRange);
366 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
367 0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
372 const VkRect2D renderArea = {
374 makeExtent2D(renderSize.x(), renderSize.y()),
376 const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
378 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
381 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
383 vk.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u);
384 endRenderPass(vk, *cmdBuffer);
386 // Copy render result to a host-visible buffer
388 const VkImageMemoryBarrier colorAttachmentPreCopyBarrier = makeImageMemoryBarrier(
389 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
390 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
391 *colorAttachmentImage, colorImageSubresourceRange);
393 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
394 0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentPreCopyBarrier);
397 const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeExtent3D(renderSize.x(), renderSize.y(), 1), makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
398 vk.cmdCopyImageToBuffer(*cmdBuffer, *colorAttachmentImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, ©Region);
401 const VkBufferMemoryBarrier postCopyBarrier = makeBufferMemoryBarrier(
402 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *colorBuffer, 0ull, colorBufferSizeBytes);
404 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
405 0u, DE_NULL, 1u, &postCopyBarrier, 0u, DE_NULL);
408 endCommandBuffer(vk, *cmdBuffer);
409 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
413 const Allocation& alloc = colorBuffer.getAllocation();
414 invalidateMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), colorBufferSizeBytes);
415 tcu::ConstPixelBufferAccess image(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, alloc.getHostPtr());
417 tcu::TestLog& log = context.getTestContext().getLog();
418 log << tcu::LogImage("color0", "", image);
420 if (verifyImage(log, image, expectedPointSize))
421 return tcu::TestStatus::pass("OK");
423 return tcu::TestStatus::fail("Didn't render expected point");
427 std::string getTestCaseName (const Flags flags)
429 std::ostringstream buf;
431 // join per-bit descriptions into a single string with '_' separator
432 if (flags & FLAG_VERTEX_SET) buf << "vertex_set";
433 if (flags & FLAG_TESSELLATION_EVALUATION_SET) buf << ((flags & (FLAG_TESSELLATION_EVALUATION_SET-1)) ? ("_") : ("")) << "evaluation_set";
434 if (flags & FLAG_TESSELLATION_ADD) buf << ((flags & (FLAG_TESSELLATION_ADD-1)) ? ("_") : ("")) << "control_pass_eval_add";
435 if (flags & FLAG_GEOMETRY_SET) buf << ((flags & (FLAG_GEOMETRY_SET-1)) ? ("_") : ("")) << "geometry_set";
436 if (flags & FLAG_GEOMETRY_ADD) buf << ((flags & (FLAG_GEOMETRY_ADD-1)) ? ("_") : ("")) << "geometry_add";
441 std::string getTestCaseDescription (const Flags flags)
443 std::ostringstream buf;
445 // join per-bit descriptions into a single string with ", " separator
446 if (flags & FLAG_VERTEX_SET) buf << "set point size in vertex shader";
447 if (flags & FLAG_TESSELLATION_EVALUATION_SET) buf << ((flags & (FLAG_TESSELLATION_EVALUATION_SET-1)) ? (", ") : ("")) << "set point size in tessellation evaluation shader";
448 if (flags & FLAG_TESSELLATION_ADD) buf << ((flags & (FLAG_TESSELLATION_ADD-1)) ? (", ") : ("")) << "add to point size in tessellation shader";
449 if (flags & FLAG_GEOMETRY_SET) buf << ((flags & (FLAG_GEOMETRY_SET-1)) ? (", ") : ("")) << "set point size in geometry shader";
450 if (flags & FLAG_GEOMETRY_ADD) buf << ((flags & (FLAG_GEOMETRY_ADD-1)) ? (", ") : ("")) << "add to point size in geometry shader";
457 //! Ported from dEQP-GLES31.functional.tessellation_geometry_interaction.point_size.*
458 //! with the exception of the default 1.0 point size cases (not valid in Vulkan).
459 tcu::TestCaseGroup* createGeometryPointSizeTests (tcu::TestContext& testCtx)
461 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "point_size", "Test point size"));
463 static const Flags caseFlags[] =
466 FLAG_TESSELLATION_EVALUATION_SET,
468 FLAG_VERTEX_SET | FLAG_TESSELLATION_EVALUATION_SET,
469 FLAG_VERTEX_SET | FLAG_GEOMETRY_SET,
470 FLAG_VERTEX_SET | FLAG_TESSELLATION_EVALUATION_SET | FLAG_GEOMETRY_SET,
471 FLAG_VERTEX_SET | FLAG_TESSELLATION_ADD | FLAG_GEOMETRY_ADD,
474 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(caseFlags); ++ndx)
476 const std::string name = getTestCaseName (caseFlags[ndx]);
477 const std::string desc = getTestCaseDescription(caseFlags[ndx]);
479 addFunctionCaseWithPrograms(group.get(), name, desc, initPrograms, test, caseFlags[ndx]);
482 return group.release();