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