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