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