1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2014 The Android Open Source Project
6 * Copyright (c) 2016 The Khronos Group Inc.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Tessellation Utilities
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktTessellationUtil.hpp"
26 #include "vkTypeUtil.hpp"
27 #include "vkCmdUtil.hpp"
28 #include "deMath.h"
29
30 namespace vkt
31 {
32 namespace tessellation
33 {
34
35 using namespace vk;
36
makeImageCreateInfo(const tcu::IVec2& size, const VkFormat format, const VkImageUsageFlags usage, const deUint32 numArrayLayers)37 VkImageCreateInfo makeImageCreateInfo (const tcu::IVec2& size, const VkFormat format, const VkImageUsageFlags usage, const deUint32 numArrayLayers)
38 {
39 const VkImageCreateInfo imageInfo =
40 {
41 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
42 DE_NULL, // const void* pNext;
43 (VkImageCreateFlags)0, // VkImageCreateFlags flags;
44 VK_IMAGE_TYPE_2D, // VkImageType imageType;
45 format, // VkFormat format;
46 makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
47 1u, // uint32_t mipLevels;
48 numArrayLayers, // uint32_t arrayLayers;
49 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
50 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
51 usage, // VkImageUsageFlags usage;
52 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
53 0u, // uint32_t queueFamilyIndexCount;
54 DE_NULL, // const uint32_t* pQueueFamilyIndices;
55 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
56 };
57 return imageInfo;
58 }
59
makeRenderPassWithoutAttachments(const DeviceInterface& vk, const VkDevice device)60 Move<VkRenderPass> makeRenderPassWithoutAttachments (const DeviceInterface& vk,
61 const VkDevice device)
62 {
63 const VkAttachmentReference unusedAttachment =
64 {
65 VK_ATTACHMENT_UNUSED, // deUint32 attachment;
66 VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout layout;
67 };
68
69 const VkSubpassDescription subpassDescription =
70 {
71 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags;
72 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
73 0u, // deUint32 inputAttachmentCount;
74 DE_NULL, // const VkAttachmentReference* pInputAttachments;
75 0u, // deUint32 colorAttachmentCount;
76 DE_NULL, // const VkAttachmentReference* pColorAttachments;
77 DE_NULL, // const VkAttachmentReference* pResolveAttachments;
78 &unusedAttachment, // const VkAttachmentReference* pDepthStencilAttachment;
79 0u, // deUint32 preserveAttachmentCount;
80 DE_NULL // const deUint32* pPreserveAttachments;
81 };
82
83 const VkRenderPassCreateInfo renderPassInfo =
84 {
85 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
86 DE_NULL, // const void* pNext;
87 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags;
88 0u, // deUint32 attachmentCount;
89 DE_NULL, // const VkAttachmentDescription* pAttachments;
90 1u, // deUint32 subpassCount;
91 &subpassDescription, // const VkSubpassDescription* pSubpasses;
92 0u, // deUint32 dependencyCount;
93 DE_NULL // const VkSubpassDependency* pDependencies;
94 };
95
96 return createRenderPass(vk, device, &renderPassInfo);
97 }
98
setShader(const DeviceInterface& vk, const VkDevice device, const VkShaderStageFlagBits stage, const ProgramBinary& binary, const VkSpecializationInfo* specInfo)99 GraphicsPipelineBuilder& GraphicsPipelineBuilder::setShader (const DeviceInterface& vk,
100 const VkDevice device,
101 const VkShaderStageFlagBits stage,
102 const ProgramBinary& binary,
103 const VkSpecializationInfo* specInfo)
104 {
105 VkShaderModule module;
106 switch (stage)
107 {
108 case (VK_SHADER_STAGE_VERTEX_BIT):
109 DE_ASSERT(m_vertexShaderModule.get() == DE_NULL);
110 m_vertexShaderModule = createShaderModule(vk, device, binary, (VkShaderModuleCreateFlags)0);
111 module = *m_vertexShaderModule;
112 break;
113
114 case (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT):
115 DE_ASSERT(m_tessControlShaderModule.get() == DE_NULL);
116 m_tessControlShaderModule = createShaderModule(vk, device, binary, (VkShaderModuleCreateFlags)0);
117 module = *m_tessControlShaderModule;
118 break;
119
120 case (VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT):
121 DE_ASSERT(m_tessEvaluationShaderModule.get() == DE_NULL);
122 m_tessEvaluationShaderModule = createShaderModule(vk, device, binary, (VkShaderModuleCreateFlags)0);
123 module = *m_tessEvaluationShaderModule;
124 break;
125
126 case (VK_SHADER_STAGE_GEOMETRY_BIT):
127 DE_ASSERT(m_geometryShaderModule.get() == DE_NULL);
128 m_geometryShaderModule = createShaderModule(vk, device, binary, (VkShaderModuleCreateFlags)0);
129 module = *m_geometryShaderModule;
130 break;
131
132 case (VK_SHADER_STAGE_FRAGMENT_BIT):
133 DE_ASSERT(m_fragmentShaderModule.get() == DE_NULL);
134 m_fragmentShaderModule = createShaderModule(vk, device, binary, (VkShaderModuleCreateFlags)0);
135 module = *m_fragmentShaderModule;
136 break;
137
138 default:
139 DE_FATAL("Invalid shader stage");
140 return *this;
141 }
142
143 const VkPipelineShaderStageCreateInfo pipelineShaderStageInfo =
144 {
145 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
146 DE_NULL, // const void* pNext;
147 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
148 stage, // VkShaderStageFlagBits stage;
149 module, // VkShaderModule module;
150 "main", // const char* pName;
151 specInfo, // const VkSpecializationInfo* pSpecializationInfo;
152 };
153
154 m_shaderStageFlags |= stage;
155 m_shaderStages.push_back(pipelineShaderStageInfo);
156
157 return *this;
158 }
159
setVertexInputSingleAttribute(const VkFormat vertexFormat, const deUint32 stride)160 GraphicsPipelineBuilder& GraphicsPipelineBuilder::setVertexInputSingleAttribute (const VkFormat vertexFormat, const deUint32 stride)
161 {
162 const VkVertexInputBindingDescription bindingDesc =
163 {
164 0u, // uint32_t binding;
165 stride, // uint32_t stride;
166 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
167 };
168 const VkVertexInputAttributeDescription attributeDesc =
169 {
170 0u, // uint32_t location;
171 0u, // uint32_t binding;
172 vertexFormat, // VkFormat format;
173 0u, // uint32_t offset;
174 };
175
176 m_vertexInputBindings.clear();
177 m_vertexInputBindings.push_back(bindingDesc);
178
179 m_vertexInputAttributes.clear();
180 m_vertexInputAttributes.push_back(attributeDesc);
181
182 return *this;
183 }
184
185 template<typename T>
dataPointer(const std::vector<T>& vec)186 inline const T* dataPointer (const std::vector<T>& vec)
187 {
188 return (vec.size() != 0 ? &vec[0] : DE_NULL);
189 }
190
build(const DeviceInterface& vk, const VkDevice device, const VkPipelineLayout pipelineLayout, const VkRenderPass renderPass)191 Move<VkPipeline> GraphicsPipelineBuilder::build (const DeviceInterface& vk,
192 const VkDevice device,
193 const VkPipelineLayout pipelineLayout,
194 const VkRenderPass renderPass)
195 {
196 const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
197 {
198 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
199 DE_NULL, // const void* pNext;
200 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags;
201 static_cast<deUint32>(m_vertexInputBindings.size()), // uint32_t vertexBindingDescriptionCount;
202 dataPointer(m_vertexInputBindings), // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
203 static_cast<deUint32>(m_vertexInputAttributes.size()), // uint32_t vertexAttributeDescriptionCount;
204 dataPointer(m_vertexInputAttributes), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
205 };
206
207 const VkPrimitiveTopology topology = (m_shaderStageFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST
208 : m_primitiveTopology;
209 const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
210 {
211 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
212 DE_NULL, // const void* pNext;
213 (VkPipelineInputAssemblyStateCreateFlags)0, // VkPipelineInputAssemblyStateCreateFlags flags;
214 topology, // VkPrimitiveTopology topology;
215 VK_FALSE, // VkBool32 primitiveRestartEnable;
216 };
217
218 const VkPipelineTessellationDomainOriginStateCreateInfo tessellationDomainOriginStateInfo =
219 {
220 VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO,
221 DE_NULL,
222 (!m_tessellationDomainOrigin ? VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT : *m_tessellationDomainOrigin)
223 };
224 const VkPipelineTessellationStateCreateInfo pipelineTessellationStateInfo =
225 {
226 VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType;
227 (!m_tessellationDomainOrigin ? DE_NULL : &tessellationDomainOriginStateInfo),
228 (VkPipelineTessellationStateCreateFlags)0, // VkPipelineTessellationStateCreateFlags flags;
229 m_patchControlPoints, // uint32_t patchControlPoints;
230 };
231
232 const VkViewport viewport = makeViewport(m_renderSize);
233 const VkRect2D scissor = makeRect2D(m_renderSize);
234
235 const bool haveRenderSize = m_renderSize.x() > 0 && m_renderSize.y() > 0;
236
237 const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
238 {
239 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
240 DE_NULL, // const void* pNext;
241 (VkPipelineViewportStateCreateFlags)0, // VkPipelineViewportStateCreateFlags flags;
242 1u, // uint32_t viewportCount;
243 haveRenderSize ? &viewport : DE_NULL, // const VkViewport* pViewports;
244 1u, // uint32_t scissorCount;
245 haveRenderSize ? &scissor : DE_NULL, // const VkRect2D* pScissors;
246 };
247
248 const bool isRasterizationDisabled = ((m_shaderStageFlags & VK_SHADER_STAGE_FRAGMENT_BIT) == 0);
249 const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
250 {
251 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
252 DE_NULL, // const void* pNext;
253 (VkPipelineRasterizationStateCreateFlags)0, // VkPipelineRasterizationStateCreateFlags flags;
254 VK_FALSE, // VkBool32 depthClampEnable;
255 isRasterizationDisabled, // VkBool32 rasterizerDiscardEnable;
256 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
257 m_cullModeFlags, // VkCullModeFlags cullMode;
258 m_frontFace, // VkFrontFace frontFace;
259 VK_FALSE, // VkBool32 depthBiasEnable;
260 0.0f, // float depthBiasConstantFactor;
261 0.0f, // float depthBiasClamp;
262 0.0f, // float depthBiasSlopeFactor;
263 1.0f, // float lineWidth;
264 };
265
266 const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
267 {
268 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
269 DE_NULL, // const void* pNext;
270 (VkPipelineMultisampleStateCreateFlags)0, // VkPipelineMultisampleStateCreateFlags flags;
271 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
272 VK_FALSE, // VkBool32 sampleShadingEnable;
273 0.0f, // float minSampleShading;
274 DE_NULL, // const VkSampleMask* pSampleMask;
275 VK_FALSE, // VkBool32 alphaToCoverageEnable;
276 VK_FALSE // VkBool32 alphaToOneEnable;
277 };
278
279 const VkStencilOpState stencilOpState = makeStencilOpState(
280 VK_STENCIL_OP_KEEP, // stencil fail
281 VK_STENCIL_OP_KEEP, // depth & stencil pass
282 VK_STENCIL_OP_KEEP, // depth only fail
283 VK_COMPARE_OP_NEVER, // compare op
284 0u, // compare mask
285 0u, // write mask
286 0u); // reference
287
288 const VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
289 {
290 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
291 DE_NULL, // const void* pNext;
292 (VkPipelineDepthStencilStateCreateFlags)0, // VkPipelineDepthStencilStateCreateFlags flags;
293 VK_FALSE, // VkBool32 depthTestEnable;
294 VK_FALSE, // VkBool32 depthWriteEnable;
295 VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
296 VK_FALSE, // VkBool32 depthBoundsTestEnable;
297 VK_FALSE, // VkBool32 stencilTestEnable;
298 stencilOpState, // VkStencilOpState front;
299 stencilOpState, // VkStencilOpState back;
300 0.0f, // float minDepthBounds;
301 1.0f, // float maxDepthBounds;
302 };
303
304 const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
305 const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState =
306 {
307 m_blendEnable, // VkBool32 blendEnable;
308 VK_BLEND_FACTOR_SRC_ALPHA, // VkBlendFactor srcColorBlendFactor;
309 VK_BLEND_FACTOR_ONE, // VkBlendFactor dstColorBlendFactor;
310 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
311 VK_BLEND_FACTOR_SRC_ALPHA, // VkBlendFactor srcAlphaBlendFactor;
312 VK_BLEND_FACTOR_ONE, // VkBlendFactor dstAlphaBlendFactor;
313 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
314 colorComponentsAll, // VkColorComponentFlags colorWriteMask;
315 };
316
317 const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
318 {
319 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
320 DE_NULL, // const void* pNext;
321 (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags;
322 VK_FALSE, // VkBool32 logicOpEnable;
323 VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
324 1u, // deUint32 attachmentCount;
325 &pipelineColorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
326 { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4];
327 };
328
329 std::vector<VkDynamicState> dynamicStates;
330 if (!haveRenderSize && !isRasterizationDisabled)
331 {
332 dynamicStates.push_back(VK_DYNAMIC_STATE_VIEWPORT);
333 dynamicStates.push_back(VK_DYNAMIC_STATE_SCISSOR);
334 }
335
336 const VkPipelineDynamicStateCreateInfo pipelineDynamicStateInfo =
337 {
338 VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
339 DE_NULL, // const void* pNext;
340 0, // VkPipelineDynamicStateCreateFlags flags;
341 static_cast<deUint32>(dynamicStates.size()), // uint32_t dynamicStateCount;
342 (dynamicStates.empty() ? DE_NULL : &dynamicStates[0]), // const VkDynamicState* pDynamicStates;
343 };
344
345 const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
346 {
347 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
348 DE_NULL, // const void* pNext;
349 (VkPipelineCreateFlags)0, // VkPipelineCreateFlags flags;
350 static_cast<deUint32>(m_shaderStages.size()), // deUint32 stageCount;
351 &m_shaderStages[0], // const VkPipelineShaderStageCreateInfo* pStages;
352 &vertexInputStateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
353 &pipelineInputAssemblyStateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
354 (m_shaderStageFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ? &pipelineTessellationStateInfo : DE_NULL), // const VkPipelineTessellationStateCreateInfo* pTessellationState;
355 (isRasterizationDisabled ? DE_NULL : &pipelineViewportStateInfo), // const VkPipelineViewportStateCreateInfo* pViewportState;
356 &pipelineRasterizationStateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
357 (isRasterizationDisabled ? DE_NULL : &pipelineMultisampleStateInfo), // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
358 (isRasterizationDisabled ? DE_NULL : &pipelineDepthStencilStateInfo), // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
359 (isRasterizationDisabled ? DE_NULL : &pipelineColorBlendStateInfo), // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
360 (dynamicStates.empty() ? DE_NULL : &pipelineDynamicStateInfo), // const VkPipelineDynamicStateCreateInfo* pDynamicState;
361 pipelineLayout, // VkPipelineLayout layout;
362 renderPass, // VkRenderPass renderPass;
363 0u, // deUint32 subpass;
364 DE_NULL, // VkPipeline basePipelineHandle;
365 0, // deInt32 basePipelineIndex;
366 };
367
368 return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
369 }
370
getClampedTessLevel(const SpacingMode mode, const float tessLevel)371 float getClampedTessLevel (const SpacingMode mode, const float tessLevel)
372 {
373 switch (mode)
374 {
375 case SPACINGMODE_EQUAL: return de::max(1.0f, tessLevel);
376 case SPACINGMODE_FRACTIONAL_ODD: return de::max(1.0f, tessLevel);
377 case SPACINGMODE_FRACTIONAL_EVEN: return de::max(2.0f, tessLevel);
378 default:
379 DE_ASSERT(false);
380 return 0.0f;
381 }
382 }
383
getRoundedTessLevel(const SpacingMode mode, const float clampedTessLevel)384 int getRoundedTessLevel (const SpacingMode mode, const float clampedTessLevel)
385 {
386 static const int minimumMaxTessGenLevel = 64; //!< Minimum maxTessellationGenerationLevel defined by the spec.
387
388 int result = (int)deFloatCeil(clampedTessLevel);
389
390 switch (mode)
391 {
392 case SPACINGMODE_EQUAL: break;
393 case SPACINGMODE_FRACTIONAL_ODD: result += 1 - result % 2; break;
394 case SPACINGMODE_FRACTIONAL_EVEN: result += result % 2; break;
395 default:
396 DE_ASSERT(false);
397 }
398 DE_ASSERT(de::inRange<int>(result, 1, minimumMaxTessGenLevel));
399 DE_UNREF(minimumMaxTessGenLevel);
400
401 return result;
402 }
403
getClampedRoundedTessLevel(const SpacingMode mode, const float tessLevel)404 int getClampedRoundedTessLevel (const SpacingMode mode, const float tessLevel)
405 {
406 return getRoundedTessLevel(mode, getClampedTessLevel(mode, tessLevel));
407 }
408
getClampedRoundedTriangleTessLevels(const SpacingMode spacingMode, const float* innerSrc, const float* outerSrc, int* innerDst, int* outerDst)409 void getClampedRoundedTriangleTessLevels (const SpacingMode spacingMode,
410 const float* innerSrc,
411 const float* outerSrc,
412 int* innerDst,
413 int* outerDst)
414 {
415 innerDst[0] = getClampedRoundedTessLevel(spacingMode, innerSrc[0]);
416 for (int i = 0; i < 3; i++)
417 outerDst[i] = getClampedRoundedTessLevel(spacingMode, outerSrc[i]);
418 }
419
getClampedRoundedQuadTessLevels(const SpacingMode spacingMode, const float* innerSrc, const float* outerSrc, int* innerDst, int* outerDst)420 void getClampedRoundedQuadTessLevels (const SpacingMode spacingMode,
421 const float* innerSrc,
422 const float* outerSrc,
423 int* innerDst,
424 int* outerDst)
425 {
426 for (int i = 0; i < 2; i++)
427 innerDst[i] = getClampedRoundedTessLevel(spacingMode, innerSrc[i]);
428 for (int i = 0; i < 4; i++)
429 outerDst[i] = getClampedRoundedTessLevel(spacingMode, outerSrc[i]);
430 }
431
getClampedRoundedIsolineTessLevels(const SpacingMode spacingMode, const float* outerSrc, int* outerDst)432 void getClampedRoundedIsolineTessLevels (const SpacingMode spacingMode,
433 const float* outerSrc,
434 int* outerDst)
435 {
436 outerDst[0] = getClampedRoundedTessLevel(SPACINGMODE_EQUAL, outerSrc[0]);
437 outerDst[1] = getClampedRoundedTessLevel(spacingMode, outerSrc[1]);
438 }
439
numOuterTessellationLevels(const TessPrimitiveType primType)440 int numOuterTessellationLevels (const TessPrimitiveType primType)
441 {
442 switch (primType)
443 {
444 case TESSPRIMITIVETYPE_TRIANGLES: return 3;
445 case TESSPRIMITIVETYPE_QUADS: return 4;
446 case TESSPRIMITIVETYPE_ISOLINES: return 2;
447 default:
448 DE_ASSERT(false);
449 return 0;
450 }
451 }
452
isPatchDiscarded(const TessPrimitiveType primitiveType, const float* outerLevels)453 bool isPatchDiscarded (const TessPrimitiveType primitiveType, const float* outerLevels)
454 {
455 const int numOuterLevels = numOuterTessellationLevels(primitiveType);
456 for (int i = 0; i < numOuterLevels; i++)
457 if (outerLevels[i] <= 0.0f)
458 return true;
459 return false;
460 }
461
getTessellationLevelsString(const TessLevels& tessLevels, const TessPrimitiveType primitiveType)462 std::string getTessellationLevelsString (const TessLevels& tessLevels, const TessPrimitiveType primitiveType)
463 {
464 std::ostringstream str;
465 switch (primitiveType)
466 {
467 case TESSPRIMITIVETYPE_ISOLINES:
468 str << "inner: { }, "
469 << "outer: { " << tessLevels.outer[0] << ", " << tessLevels.outer[1] << " }";
470 break;
471
472 case TESSPRIMITIVETYPE_TRIANGLES:
473 str << "inner: { " << tessLevels.inner[0] << " }, "
474 << "outer: { " << tessLevels.outer[0] << ", " << tessLevels.outer[1] << ", " << tessLevels.outer[2] << " }";
475 break;
476
477 case TESSPRIMITIVETYPE_QUADS:
478 str << "inner: { " << tessLevels.inner[0] << ", " << tessLevels.inner[1] << " }, "
479 << "outer: { " << tessLevels.outer[0] << ", " << tessLevels.outer[1] << ", " << tessLevels.outer[2] << ", " << tessLevels.outer[3] << " }";
480 break;
481
482 default:
483 DE_ASSERT(false);
484 }
485
486 return str.str();
487 }
488
489 //! Assumes array sizes inner[2] and outer[4].
getTessellationLevelsString(const float* inner, const float* outer)490 std::string getTessellationLevelsString (const float* inner, const float* outer)
491 {
492 const TessLevels tessLevels =
493 {
494 { inner[0], inner[1] },
495 { outer[0], outer[1], outer[2], outer[3] }
496 };
497 return getTessellationLevelsString(tessLevels, TESSPRIMITIVETYPE_QUADS);
498 }
499
500 // \note The tessellation coordinates generated by this function could break some of the rules given in the spec
501 // (e.g. it may not exactly hold that u+v+w == 1.0f, or [uvw] + (1.0f-[uvw]) == 1.0f).
generateReferenceTriangleTessCoords(const SpacingMode spacingMode, const int inner, const int outer0, const int outer1, const int outer2)502 std::vector<tcu::Vec3> generateReferenceTriangleTessCoords (const SpacingMode spacingMode,
503 const int inner,
504 const int outer0,
505 const int outer1,
506 const int outer2)
507 {
508 std::vector<tcu::Vec3> tessCoords;
509
510 if (inner == 1)
511 {
512 if (outer0 == 1 && outer1 == 1 && outer2 == 1)
513 {
514 tessCoords.push_back(tcu::Vec3(1.0f, 0.0f, 0.0f));
515 tessCoords.push_back(tcu::Vec3(0.0f, 1.0f, 0.0f));
516 tessCoords.push_back(tcu::Vec3(0.0f, 0.0f, 1.0f));
517 return tessCoords;
518 }
519 else
520 return generateReferenceTriangleTessCoords(spacingMode, spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
521 outer0, outer1, outer2);
522 }
523 else
524 {
525 for (int i = 0; i < outer0; i++) { const float v = (float)i / (float)outer0; tessCoords.push_back(tcu::Vec3( 0.0f, v, 1.0f - v)); }
526 for (int i = 0; i < outer1; i++) { const float v = (float)i / (float)outer1; tessCoords.push_back(tcu::Vec3(1.0f - v, 0.0f, v)); }
527 for (int i = 0; i < outer2; i++) { const float v = (float)i / (float)outer2; tessCoords.push_back(tcu::Vec3( v, 1.0f - v, 0.0f)); }
528
529 const int numInnerTriangles = inner/2;
530 for (int innerTriangleNdx = 0; innerTriangleNdx < numInnerTriangles; innerTriangleNdx++)
531 {
532 const int curInnerTriangleLevel = inner - 2*(innerTriangleNdx+1);
533
534 if (curInnerTriangleLevel == 0)
535 tessCoords.push_back(tcu::Vec3(1.0f/3.0f));
536 else
537 {
538 const float minUVW = (float)(2 * (innerTriangleNdx + 1)) / (float)(3 * inner);
539 const float maxUVW = 1.0f - 2.0f*minUVW;
540 const tcu::Vec3 corners[3] =
541 {
542 tcu::Vec3(maxUVW, minUVW, minUVW),
543 tcu::Vec3(minUVW, maxUVW, minUVW),
544 tcu::Vec3(minUVW, minUVW, maxUVW)
545 };
546
547 for (int i = 0; i < curInnerTriangleLevel; i++)
548 {
549 const float f = (float)i / (float)curInnerTriangleLevel;
550 for (int j = 0; j < 3; j++)
551 tessCoords.push_back((1.0f - f)*corners[j] + f*corners[(j+1)%3]);
552 }
553 }
554 }
555
556 return tessCoords;
557 }
558 }
559
560 // \note The tessellation coordinates generated by this function could break some of the rules given in the spec
561 // (e.g. it may not exactly hold that [uv] + (1.0f-[uv]) == 1.0f).
generateReferenceQuadTessCoords(const SpacingMode spacingMode, const int inner0, const int inner1, const int outer0, const int outer1, const int outer2, const int outer3)562 std::vector<tcu::Vec3> generateReferenceQuadTessCoords (const SpacingMode spacingMode,
563 const int inner0,
564 const int inner1,
565 const int outer0,
566 const int outer1,
567 const int outer2,
568 const int outer3)
569 {
570 std::vector<tcu::Vec3> tessCoords;
571
572 if (inner0 == 1 || inner1 == 1)
573 {
574 if (inner0 == 1 && inner1 == 1 && outer0 == 1 && outer1 == 1 && outer2 == 1 && outer3 == 1)
575 {
576 tessCoords.push_back(tcu::Vec3(0.0f, 0.0f, 0.0f));
577 tessCoords.push_back(tcu::Vec3(1.0f, 0.0f, 0.0f));
578 tessCoords.push_back(tcu::Vec3(0.0f, 1.0f, 0.0f));
579 tessCoords.push_back(tcu::Vec3(1.0f, 1.0f, 0.0f));
580 return tessCoords;
581 }
582 else
583 return generateReferenceQuadTessCoords(spacingMode, inner0 > 1 ? inner0 : spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
584 inner1 > 1 ? inner1 : spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
585 outer0, outer1, outer2, outer3);
586 }
587 else
588 {
589 for (int i = 0; i < outer0; i++) { const float v = (float)i / (float)outer0; tessCoords.push_back(tcu::Vec3( 0.0f, v, 0.0f)); }
590 for (int i = 0; i < outer1; i++) { const float v = (float)i / (float)outer1; tessCoords.push_back(tcu::Vec3(1.0f - v, 0.0f, 0.0f)); }
591 for (int i = 0; i < outer2; i++) { const float v = (float)i / (float)outer2; tessCoords.push_back(tcu::Vec3( 1.0f, 1.0f - v, 0.0f)); }
592 for (int i = 0; i < outer3; i++) { const float v = (float)i / (float)outer3; tessCoords.push_back(tcu::Vec3( v, 1.0f, 0.0f)); }
593
594 for (int innerVtxY = 0; innerVtxY < inner1-1; innerVtxY++)
595 for (int innerVtxX = 0; innerVtxX < inner0-1; innerVtxX++)
596 tessCoords.push_back(tcu::Vec3((float)(innerVtxX + 1) / (float)inner0,
597 (float)(innerVtxY + 1) / (float)inner1,
598 0.0f));
599
600 return tessCoords;
601 }
602 }
603
604 // \note The tessellation coordinates generated by this function could break some of the rules given in the spec
605 // (e.g. it may not exactly hold that [uv] + (1.0f-[uv]) == 1.0f).
generateReferenceIsolineTessCoords(const int outer0, const int outer1)606 std::vector<tcu::Vec3> generateReferenceIsolineTessCoords (const int outer0, const int outer1)
607 {
608 std::vector<tcu::Vec3> tessCoords;
609
610 for (int y = 0; y < outer0; y++)
611 for (int x = 0; x < outer1+1; x++)
612 tessCoords.push_back(tcu::Vec3((float)x / (float)outer1,
613 (float)y / (float)outer0,
614 0.0f));
615
616 return tessCoords;
617 }
618
referencePointModePrimitiveCount(const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const float* innerLevels, const float* outerLevels)619 static int referencePointModePrimitiveCount (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const float* innerLevels, const float* outerLevels)
620 {
621 if (isPatchDiscarded(primitiveType, outerLevels))
622 return 0;
623
624 switch (primitiveType)
625 {
626 case TESSPRIMITIVETYPE_TRIANGLES:
627 {
628 int inner;
629 int outer[3];
630 getClampedRoundedTriangleTessLevels(spacingMode, innerLevels, outerLevels, &inner, &outer[0]);
631 return static_cast<int>(generateReferenceTriangleTessCoords(spacingMode, inner, outer[0], outer[1], outer[2]).size());
632 }
633
634 case TESSPRIMITIVETYPE_QUADS:
635 {
636 int inner[2];
637 int outer[4];
638 getClampedRoundedQuadTessLevels(spacingMode, innerLevels, outerLevels, &inner[0], &outer[0]);
639 return static_cast<int>(generateReferenceQuadTessCoords(spacingMode, inner[0], inner[1], outer[0], outer[1], outer[2], outer[3]).size());
640 }
641
642 case TESSPRIMITIVETYPE_ISOLINES:
643 {
644 int outer[2];
645 getClampedRoundedIsolineTessLevels(spacingMode, &outerLevels[0], &outer[0]);
646 return static_cast<int>(generateReferenceIsolineTessCoords(outer[0], outer[1]).size());
647 }
648
649 default:
650 DE_ASSERT(false);
651 return 0;
652 }
653 }
654
referenceTriangleNonPointModePrimitiveCount(const SpacingMode spacingMode, const int inner, const int outer0, const int outer1, const int outer2)655 static int referenceTriangleNonPointModePrimitiveCount (const SpacingMode spacingMode, const int inner, const int outer0, const int outer1, const int outer2)
656 {
657 if (inner == 1)
658 {
659 if (outer0 == 1 && outer1 == 1 && outer2 == 1)
660 return 1;
661 else
662 return referenceTriangleNonPointModePrimitiveCount(spacingMode, spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
663 outer0, outer1, outer2);
664 }
665 else
666 {
667 int result = outer0 + outer1 + outer2;
668
669 const int numInnerTriangles = inner/2;
670 for (int innerTriangleNdx = 0; innerTriangleNdx < numInnerTriangles; innerTriangleNdx++)
671 {
672 const int curInnerTriangleLevel = inner - 2*(innerTriangleNdx+1);
673
674 if (curInnerTriangleLevel == 1)
675 result += 4;
676 else
677 result += 2*3*curInnerTriangleLevel;
678 }
679
680 return result;
681 }
682 }
683
referenceQuadNonPointModePrimitiveCount(const SpacingMode spacingMode, const int inner0, const int inner1, const int outer0, const int outer1, const int outer2, const int outer3)684 static int referenceQuadNonPointModePrimitiveCount (const SpacingMode spacingMode, const int inner0, const int inner1, const int outer0, const int outer1, const int outer2, const int outer3)
685 {
686 if (inner0 == 1 || inner1 == 1)
687 {
688 if (inner0 == 1 && inner1 == 1 && outer0 == 1 && outer1 == 1 && outer2 == 1 && outer3 == 1)
689 return 2;
690 else
691 return referenceQuadNonPointModePrimitiveCount(spacingMode, inner0 > 1 ? inner0 : spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
692 inner1 > 1 ? inner1 : spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
693 outer0, outer1, outer2, outer3);
694 }
695 else
696 return 2*(inner0-2)*(inner1-2) + 2*(inner0-2) + 2*(inner1-2) + outer0+outer1+outer2+outer3;
697 }
698
referenceIsolineNonPointModePrimitiveCount(const int outer0, const int outer1)699 static inline int referenceIsolineNonPointModePrimitiveCount (const int outer0, const int outer1)
700 {
701 return outer0*outer1;
702 }
703
referenceNonPointModePrimitiveCount(const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const float* innerLevels, const float* outerLevels)704 static int referenceNonPointModePrimitiveCount (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const float* innerLevels, const float* outerLevels)
705 {
706 if (isPatchDiscarded(primitiveType, outerLevels))
707 return 0;
708
709 switch (primitiveType)
710 {
711 case TESSPRIMITIVETYPE_TRIANGLES:
712 {
713 int inner;
714 int outer[3];
715 getClampedRoundedTriangleTessLevels(spacingMode, innerLevels, outerLevels, &inner, &outer[0]);
716 return referenceTriangleNonPointModePrimitiveCount(spacingMode, inner, outer[0], outer[1], outer[2]);
717 }
718
719 case TESSPRIMITIVETYPE_QUADS:
720 {
721 int inner[2];
722 int outer[4];
723 getClampedRoundedQuadTessLevels(spacingMode, innerLevels, outerLevels, &inner[0], &outer[0]);
724 return referenceQuadNonPointModePrimitiveCount(spacingMode, inner[0], inner[1], outer[0], outer[1], outer[2], outer[3]);
725 }
726
727 case TESSPRIMITIVETYPE_ISOLINES:
728 {
729 int outer[2];
730 getClampedRoundedIsolineTessLevels(spacingMode, &outerLevels[0], &outer[0]);
731 return referenceIsolineNonPointModePrimitiveCount(outer[0], outer[1]);
732 }
733
734 default:
735 DE_ASSERT(false);
736 return 0;
737 }
738 }
739
numVerticesPerPrimitive(const TessPrimitiveType primitiveType, const bool usePointMode)740 int numVerticesPerPrimitive (const TessPrimitiveType primitiveType, const bool usePointMode)
741 {
742 if (usePointMode)
743 return 1;
744
745 switch (primitiveType)
746 {
747 case TESSPRIMITIVETYPE_TRIANGLES: return 3;
748 case TESSPRIMITIVETYPE_QUADS: return 3; // quads are composed of two triangles
749 case TESSPRIMITIVETYPE_ISOLINES: return 2;
750 default:
751 DE_ASSERT(false);
752 return 0;
753 }
754 }
755
referencePrimitiveCount(const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* innerLevels, const float* outerLevels)756 int referencePrimitiveCount (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* innerLevels, const float* outerLevels)
757 {
758 return usePointMode ? referencePointModePrimitiveCount (primitiveType, spacingMode, innerLevels, outerLevels)
759 : referenceNonPointModePrimitiveCount (primitiveType, spacingMode, innerLevels, outerLevels);
760 }
761
762 //! In point mode this should return the number of unique vertices, while in non-point mode the maximum theoretical number of verticies.
763 //! Actual implementation will likely return a much smaller number because the shader isn't required to be run for duplicate coordinates.
referenceVertexCount(const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* innerLevels, const float* outerLevels)764 int referenceVertexCount (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* innerLevels, const float* outerLevels)
765 {
766 return referencePrimitiveCount(primitiveType, spacingMode, usePointMode, innerLevels, outerLevels)
767 * numVerticesPerPrimitive(primitiveType, usePointMode);
768 }
769
requireFeatures(const InstanceInterface& vki, const VkPhysicalDevice physDevice, const FeatureFlags flags)770 void requireFeatures (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const FeatureFlags flags)
771 {
772 const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice);
773
774 if (((flags & FEATURE_TESSELLATION_SHADER) != 0) && !features.tessellationShader)
775 throw tcu::NotSupportedError("Tessellation shader not supported");
776
777 if (((flags & FEATURE_GEOMETRY_SHADER) != 0) && !features.geometryShader)
778 throw tcu::NotSupportedError("Geometry shader not supported");
779
780 if (((flags & FEATURE_SHADER_FLOAT_64) != 0) && !features.shaderFloat64)
781 throw tcu::NotSupportedError("Double-precision floats not supported");
782
783 if (((flags & FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS) != 0) && !features.vertexPipelineStoresAndAtomics)
784 throw tcu::NotSupportedError("SSBO and image writes not supported in vertex pipeline");
785
786 if (((flags & FEATURE_FRAGMENT_STORES_AND_ATOMICS) != 0) && !features.fragmentStoresAndAtomics)
787 throw tcu::NotSupportedError("SSBO and image writes not supported in fragment shader");
788
789 if (((flags & FEATURE_SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE) != 0) && !features.shaderTessellationAndGeometryPointSize)
790 throw tcu::NotSupportedError("Tessellation and geometry shaders don't support PointSize built-in");
791 }
792
793 } // tessellation
794 } // vkt
795