From 34ca943ac598cf2bd0987951f22157ea1898a9cc Mon Sep 17 00:00:00 2001 From: saschawillems Date: Mon, 26 Dec 2016 19:08:03 +0100 Subject: [PATCH] Started work on specialization constants example --- .../shaders/specializationconstants/uber.frag | 70 +++ .../specializationconstants/uber.frag.spv | Bin 0 -> 4656 bytes .../shaders/specializationconstants/uber.vert | 41 ++ .../specializationconstants/uber.vert.spv | Bin 0 -> 3100 bytes .../specializationconstants.cpp | 460 ++++++++++++++++++ .../specializationconstants.vcxproj | 99 ++++ .../specializationconstants.vcxproj.filters | 53 ++ vulkanExamples.sln | 6 + 8 files changed, 729 insertions(+) create mode 100644 data/shaders/specializationconstants/uber.frag create mode 100644 data/shaders/specializationconstants/uber.frag.spv create mode 100644 data/shaders/specializationconstants/uber.vert create mode 100644 data/shaders/specializationconstants/uber.vert.spv create mode 100644 specializationconstants/specializationconstants.cpp create mode 100644 specializationconstants/specializationconstants.vcxproj create mode 100644 specializationconstants/specializationconstants.vcxproj.filters diff --git a/data/shaders/specializationconstants/uber.frag b/data/shaders/specializationconstants/uber.frag new file mode 100644 index 00000000..a5c3b79f --- /dev/null +++ b/data/shaders/specializationconstants/uber.frag @@ -0,0 +1,70 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (binding = 1) uniform sampler2D samplerColormap; +layout (binding = 2) uniform sampler2D samplerDiscard; + +layout (location = 0) in vec3 inNormal; +layout (location = 1) in vec3 inColor; +layout (location = 2) in vec2 inUV; +layout (location = 3) in vec3 inViewVec; +layout (location = 4) in vec3 inLightVec; + +layout (location = 0) out vec4 outFragColor; + +// We use this constant to control the flow of the shader depending on the +// lighting model selected at pipeline creation time +layout (constant_id = 0) const int LIGHTING_MODEL = 0; + +void main() +{ + switch (LIGHTING_MODEL) { + case 0: // Phong + { + vec3 ambient = inColor * vec3(0.25); + vec3 N = normalize(inNormal); + vec3 L = normalize(inLightVec); + vec3 V = normalize(inViewVec); + vec3 R = reflect(-L, N); + vec3 diffuse = max(dot(N, L), 0.0) * inColor; + vec3 specular = pow(max(dot(R, V), 0.0), 32.0) * vec3(0.75); + outFragColor = vec4(ambient + diffuse * 1.75 + specular, 1.0); + break; + } + case 1: // Toon + { + + vec3 N = normalize(inNormal); + vec3 L = normalize(inLightVec); + float intensity = dot(N,L); + vec3 color; + if (intensity > 0.98) + color = inColor * 1.5; + else if (intensity > 0.9) + color = inColor * 1.0; + else if (intensity > 0.5) + color = inColor * 0.6; + else if (intensity > 0.25) + color = inColor * 0.4; + else + color = inColor * 0.2; + outFragColor.rgb = color; + break; + } + case 2: // Textured + { + vec4 color = texture(samplerColormap, inUV).rrra; + vec3 ambient = color.rgb * vec3(0.25) * inColor; + vec3 N = normalize(inNormal); + vec3 L = normalize(inLightVec); + vec3 V = normalize(inViewVec); + vec3 R = reflect(-L, N); + vec3 diffuse = max(dot(N, L), 0.0) * color.rgb; + float specular = pow(max(dot(R, V), 0.0), 32.0) * color.a; + outFragColor = vec4(ambient + diffuse + vec3(specular), 1.0); + break; + } + } +} \ No newline at end of file diff --git a/data/shaders/specializationconstants/uber.frag.spv b/data/shaders/specializationconstants/uber.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..7ec71a38133cab2758c777997c296b58a0ac9575 GIT binary patch literal 4656 zcmZ9OcXO0g6o;>D5(}{)2qG%MhKiyh*wBQcVu^q#*o{lF2@A<4?r!Xku{Z2pEZBSR zWk$!p@jK|Ju#Gc5&%5uzm)y+ZoZs)1dv1B}Qkru3?kVlY-yZ4b)Ed*$6mUvYQ%9y( z^>_?t)Oo&xtmXv;> zNL$)7t?KPtzHUWdqcT>mmz$No#-{Q>rQSEXadV}=+1ND(SG6|OH(ag_jhBZieTx^J zI9Bf8lG>?M>_faSbCgFmRx7n;=C`+MZRP0jXdPTiGr_BocK+)+%lvI=K6;=!I5^&@Wb>T> zZj4p>$A`;xOt_A0uSUn4=hn+ZttKmO)~Ggb&SKlrmFWI# zh1P6K6T9G!bPu>u9vK_1)U!E8%41oaXH>1NcR3l}ivEA^O6f^(^zaOJtA|p09=o*% zrL+w@*1H|MxZZcclh^x`T&tI}tBwA0eITV(^z0q+emTURn|m!M_N>GXv3E`E`HMXZ zu{Txh9W2JX2cC^Xzjz)J_1z2Oy`%c=vluTnUjKCdRnN)QMVgArQdo2 zugvg7kNIn`-5+a)e?9hjzu(d`gVXRn27fhnN`_+?>kn+ zzGX$cZ4%yI!1m*tX8a%Q-c+>XAMSx%;61QCpFI)xdoRR&mOqPq_FLT_@q50P-4`E_ zbAH3!)b^TqJVl zVMmTWb3AkT$T=L_I(Ou2I|5rS{6}KjTPM5ZT8~1kxe75>zjeJk`XcXWZ1VyigY7&| zvuA!I$0EkaTU+ip#M<)ueaj;Mcx?Cl(R|MrV#}H1{PWRr5$}I~>?!a`*seY1UxaOp ze9V6`cFeEe`NOv)_qhh+d{?8F)3ALboqqtBdPw0z`TjBTC3>#&W9 zGra`c7nsL|=-?ea~KPKwp+~>(RamSD+n#6R+=b4 zyBcxcE75Z9mo?3|PV~`-UF@R_mb(tIkAAenKJ;xw1`+FMM;`; %vxi~lbkh2eK zns1%xV+gz0M-?o$39*kYXor31+l-7N*3phWhOvu%)WC8hNbHB4eOS|c>qH-8*u_4s z2g^-I?4yBp*oVG4awB3L?dYS4UF_oqu-rHjeaP8|HO;q9ab> z6xZeY#IfIMaohuS%y%ocXCyuyeH*eAS;N;QzCGuRYeU+R4y1(GkFmyBe=6Gb?1i@8 zUFds}dvbgq`a$FY8&{%<(n0b=KzpkNXB&E+lfl zg)?7&{N8?tE$;~Kdu%!PAh;iL&b^P{nnc$Q^EgI@igQ=2ZD^= literal 0 HcmV?d00001 diff --git a/data/shaders/specializationconstants/uber.vert b/data/shaders/specializationconstants/uber.vert new file mode 100644 index 00000000..293173bf --- /dev/null +++ b/data/shaders/specializationconstants/uber.vert @@ -0,0 +1,41 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec3 inNormal; +layout (location = 2) in vec2 inUV; +layout (location = 3) in vec3 inColor; + +layout (binding = 0) uniform UBO +{ + mat4 projection; + mat4 model; + vec4 lightPos; +} ubo; + +layout (location = 0) out vec3 outNormal; +layout (location = 1) out vec3 outColor; +layout (location = 2) out vec2 outUV; +layout (location = 3) out vec3 outViewVec; +layout (location = 4) out vec3 outLightVec; + +out gl_PerVertex +{ + vec4 gl_Position; +}; + +void main() +{ + outNormal = inNormal; + outColor = inColor; + outUV = inUV; + gl_Position = ubo.projection * ubo.model * vec4(inPos.xyz, 1.0); + + vec4 pos = ubo.model * vec4(inPos, 1.0); + outNormal = mat3(ubo.model) * inNormal; + vec3 lPos = mat3(ubo.model) * ubo.lightPos.xyz; + outLightVec = lPos - pos.xyz; + outViewVec = -pos.xyz; +} \ No newline at end of file diff --git a/data/shaders/specializationconstants/uber.vert.spv b/data/shaders/specializationconstants/uber.vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..d6215eb52551e53c836505862df1c915a76646cd GIT binary patch literal 3100 zcmZXVeOFXf6vnT>kYrhAqP^K5m6b(gXqKsfDO8hy#`NAez-_oV%&>-G)qlBGpP)Wc zpQ?XatKaY5yX}UDwLSZJ&U5zJXYVuD(UIvVlH>?~N0VMsj1$QSI7yBrY}YM$ZGF^287vpmEE{xR%n>^Sxu_B{3ib{e+^4nuhZ(bd!2)JCvDALoZV}0K1gar zs^(IIF`xdy@J@fQ+wS7anP1j>MCF|MqPyAe_6N9dV|o5rub{-<13&t!3b4&a{>e<2shuDW`rJ zeblIy@&>9ku$c~?}ywe@QciK%vcvn{1U$74ESYcV->NB-pK{;8S&Qap=XHgVcf4?`tFG{ zrtv*9>SIqM2k-J0mLv~v82>#y^Nl;bk8f|p=6J2dYK-sx>zKp+cbL^{aefOw^1EO9 z#xo!L@0&7S;Nm-*B$s*Z?z0{aHGjkS8&GR*eiJ-P?Ad-7#Mi*iPhq~7>+JSjiDS+G z1$-;6`G&-<+51zNeRs|GAzt9*I`b4}&F!6fYkdxr56x@%YNoN!ypAvbCvn{K2IfBb z$mvb|^Vk|1Yx_1P=LqfszTA-t_fE-KuT^etec#30uikb0{0DJeo54I^jXB%*S3)HRkF& zkc(We;vdfS6FB)bDr;?TU~(~npN9y($g$8bRCx0Y{bI?hbp(GC-#GHsIGy4s)3l9P8>8*_~QZQ&bVo&ED0Di{6!8DB2q zckunaMf`1iIn5FAe=pxh24@U)#!s2$BHjc1YP>F3PIE-O-^y?LE}R-;?J$e~L3IWD E7cD2k9{>OV literal 0 HcmV?d00001 diff --git a/specializationconstants/specializationconstants.cpp b/specializationconstants/specializationconstants.cpp new file mode 100644 index 00000000..a460b08d --- /dev/null +++ b/specializationconstants/specializationconstants.cpp @@ -0,0 +1,460 @@ +/* +* Vulkan Example - Shader specialization constants +* +* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de +* +* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +*/ + +#include +#include +#include +#include +#include + +#define GLM_FORCE_RADIANS +#define GLM_FORCE_DEPTH_ZERO_TO_ONE +#include +#include + +#include +#include "vulkanexamplebase.h" +#include "vulkanbuffer.hpp" + +#define VERTEX_BUFFER_BIND_ID 0 +#define ENABLE_VALIDATION false + +// Vertex layout for this example +std::vector vertexLayout = +{ + vkMeshLoader::VERTEX_LAYOUT_POSITION, + vkMeshLoader::VERTEX_LAYOUT_NORMAL, + vkMeshLoader::VERTEX_LAYOUT_UV, + vkMeshLoader::VERTEX_LAYOUT_COLOR +}; + +class VulkanExample: public VulkanExampleBase +{ +public: + struct { + VkPipelineVertexInputStateCreateInfo inputState; + std::vector bindingDescriptions; + std::vector attributeDescriptions; + } vertices; + + struct { + vkMeshLoader::MeshBuffer cube; + } meshes; + + struct { + vkTools::VulkanTexture colormap; + } textures; + + vk::Buffer uniformBuffer; + + // Same uniform buffer layout as shader + struct UBOVS { + glm::mat4 projection; + glm::mat4 modelView; + glm::vec4 lightPos = glm::vec4(0.0f, -2.0f, 1.0f, 0.0f); + } uboVS; + + VkPipelineLayout pipelineLayout; + VkDescriptorSet descriptorSet; + VkDescriptorSetLayout descriptorSetLayout; + + struct { + VkPipeline phong; + VkPipeline toon; + VkPipeline textured; + } pipelines; + + VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) + { + zoom = -2.1f; + rotation = glm::vec3(-41.25f, -90.0f, 0.0f); + enableTextOverlay = true; + title = "Vulkan Example - Specialization constants"; + + camera.type = Camera::CameraType::lookat; + camera.setPerspective(60.0f, ((float)width / 3.0f) / (float)height, 0.1f, 512.0f); + camera.setRotation(glm::vec3(-40.0f, -90.0f, 0.0f)); + camera.setTranslation(glm::vec3(0.0f, 0.0f, -2.0f)); + } + + ~VulkanExample() + { + vkDestroyPipeline(device, pipelines.phong, nullptr); + vkDestroyPipeline(device, pipelines.textured, nullptr); + vkDestroyPipeline(device, pipelines.toon, nullptr); + + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + + vkMeshLoader::freeMeshBufferResources(device, &meshes.cube); + + textureLoader->destroyTexture(textures.colormap); + + uniformBuffer.destroy(); + } + + void buildCommandBuffers() + { + VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo(); + + VkClearValue clearValues[2]; + clearValues[0].color = defaultClearColor; + clearValues[1].depthStencil = { 1.0f, 0 }; + + VkRenderPassBeginInfo renderPassBeginInfo = vkTools::initializers::renderPassBeginInfo(); + renderPassBeginInfo.renderPass = renderPass; + renderPassBeginInfo.renderArea.offset.x = 0; + renderPassBeginInfo.renderArea.offset.y = 0; + renderPassBeginInfo.renderArea.extent.width = width; + renderPassBeginInfo.renderArea.extent.height = height; + renderPassBeginInfo.clearValueCount = 2; + renderPassBeginInfo.pClearValues = clearValues; + + for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) + { + // Set target frame buffer + renderPassBeginInfo.framebuffer = frameBuffers[i]; + + VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); + + vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + VkViewport viewport = vkTools::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); + vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); + + VkRect2D scissor = vkTools::initializers::rect2D(width, height, 0, 0); + vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); + + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL); + + VkDeviceSize offsets[1] = { 0 }; + vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &meshes.cube.vertices.buf, offsets); + vkCmdBindIndexBuffer(drawCmdBuffers[i], meshes.cube.indices.buf, 0, VK_INDEX_TYPE_UINT32); + + // Left + viewport.width = (float)width / 3.0; + vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.phong); + + vkCmdDrawIndexed(drawCmdBuffers[i], meshes.cube.indexCount, 1, 0, 0, 0); + + // Center + viewport.x = (float)width / 3.0; + vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.toon); + vkCmdDrawIndexed(drawCmdBuffers[i], meshes.cube.indexCount, 1, 0, 0, 0); + + // Right + viewport.x = (float)width / 3.0 + (float)width / 3.0; + vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.textured); + vkCmdDrawIndexed(drawCmdBuffers[i], meshes.cube.indexCount, 1, 0, 0, 0); + + vkCmdEndRenderPass(drawCmdBuffers[i]); + + VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i])); + } + } + + void loadAssets() + { + loadMesh(getAssetPath() + "models/color_teapot_spheres.X", &meshes.cube, vertexLayout, 0.1f); + textureLoader->loadTexture(getAssetPath() + "textures/metalplate_nomips_rgba.ktx", VK_FORMAT_R8G8B8A8_UNORM, &textures.colormap); + } + + void setupVertexDescriptions() + { + // Binding description + vertices.bindingDescriptions.resize(1); + vertices.bindingDescriptions[0] = + vkTools::initializers::vertexInputBindingDescription( + VERTEX_BUFFER_BIND_ID, + vkMeshLoader::vertexSize(vertexLayout), + VK_VERTEX_INPUT_RATE_VERTEX); + + // Attribute descriptions + // Describes memory layout and shader positions + vertices.attributeDescriptions.resize(4); + // Location 0 : Position + vertices.attributeDescriptions[0] = + vkTools::initializers::vertexInputAttributeDescription( + VERTEX_BUFFER_BIND_ID, + 0, + VK_FORMAT_R32G32B32_SFLOAT, + 0); + // Location 1 : Color + vertices.attributeDescriptions[1] = + vkTools::initializers::vertexInputAttributeDescription( + VERTEX_BUFFER_BIND_ID, + 1, + VK_FORMAT_R32G32B32_SFLOAT, + sizeof(float) * 3); + // Location 3 : Texture coordinates + vertices.attributeDescriptions[2] = + vkTools::initializers::vertexInputAttributeDescription( + VERTEX_BUFFER_BIND_ID, + 2, + VK_FORMAT_R32G32_SFLOAT, + sizeof(float) * 6); + // Location 2 : Normal + vertices.attributeDescriptions[3] = + vkTools::initializers::vertexInputAttributeDescription( + VERTEX_BUFFER_BIND_ID, + 3, + VK_FORMAT_R32G32B32_SFLOAT, + sizeof(float) * 8); + + vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo(); + vertices.inputState.vertexBindingDescriptionCount = vertices.bindingDescriptions.size(); + vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data(); + vertices.inputState.vertexAttributeDescriptionCount = vertices.attributeDescriptions.size(); + vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data(); + } + + void setupDescriptorPool() + { + std::vector poolSizes = + { + vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), + vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1) + }; + + VkDescriptorPoolCreateInfo descriptorPoolInfo = + vkTools::initializers::descriptorPoolCreateInfo( + poolSizes.size(), + poolSizes.data(), + 1); + + VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); + } + + void setupDescriptorSetLayout() + { + std::vector setLayoutBindings ={ + vkTools::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0), + vkTools::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1), + }; + + VkDescriptorSetLayoutCreateInfo descriptorLayout = + vkTools::initializers::descriptorSetLayoutCreateInfo( + setLayoutBindings.data(), + setLayoutBindings.size()); + + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); + + VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = + vkTools::initializers::pipelineLayoutCreateInfo( + &descriptorSetLayout, + 1); + + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout)); + } + + void setupDescriptorSet() + { + VkDescriptorSetAllocateInfo allocInfo = + vkTools::initializers::descriptorSetAllocateInfo( + descriptorPool, + &descriptorSetLayout, + 1); + + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); + + std::vector writeDescriptorSets = { + vkTools::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffer.descriptor), + vkTools::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &textures.colormap.descriptor), + }; + + vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL); + } + + void preparePipelines() + { + VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = + vkTools::initializers::pipelineInputAssemblyStateCreateInfo( + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + 0, + VK_FALSE); + + VkPipelineRasterizationStateCreateInfo rasterizationState = + vkTools::initializers::pipelineRasterizationStateCreateInfo( + VK_POLYGON_MODE_FILL, + VK_CULL_MODE_NONE, + VK_FRONT_FACE_CLOCKWISE, + 0); + + VkPipelineColorBlendAttachmentState blendAttachmentState = + vkTools::initializers::pipelineColorBlendAttachmentState( + 0xf, + VK_FALSE); + + VkPipelineColorBlendStateCreateInfo colorBlendState = + vkTools::initializers::pipelineColorBlendStateCreateInfo( + 1, + &blendAttachmentState); + + VkPipelineDepthStencilStateCreateInfo depthStencilState = + vkTools::initializers::pipelineDepthStencilStateCreateInfo( + VK_TRUE, + VK_TRUE, + VK_COMPARE_OP_LESS_OR_EQUAL); + + VkPipelineViewportStateCreateInfo viewportState = + vkTools::initializers::pipelineViewportStateCreateInfo(1, 1, 0); + + VkPipelineMultisampleStateCreateInfo multisampleState = + vkTools::initializers::pipelineMultisampleStateCreateInfo( + VK_SAMPLE_COUNT_1_BIT, + 0); + + std::vector dynamicStateEnables = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_LINE_WIDTH, + }; + VkPipelineDynamicStateCreateInfo dynamicState = + vkTools::initializers::pipelineDynamicStateCreateInfo( + dynamicStateEnables.data(), + dynamicStateEnables.size(), + 0); + + std::array shaderStages; + + VkGraphicsPipelineCreateInfo pipelineCreateInfo = + vkTools::initializers::pipelineCreateInfo( + pipelineLayout, + renderPass, + 0); + + pipelineCreateInfo.pVertexInputState = &vertices.inputState; + pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; + pipelineCreateInfo.pRasterizationState = &rasterizationState; + pipelineCreateInfo.pColorBlendState = &colorBlendState; + pipelineCreateInfo.pMultisampleState = &multisampleState; + pipelineCreateInfo.pViewportState = &viewportState; + pipelineCreateInfo.pDepthStencilState = &depthStencilState; + pipelineCreateInfo.pDynamicState = &dynamicState; + pipelineCreateInfo.stageCount = static_cast(shaderStages.size()); + pipelineCreateInfo.pStages = shaderStages.data(); + + // Prepare specialization data + + // Host data to take specialization constants from + struct SpecializationData { + uint32_t lightingModel; + } specializationData; + + // Each shader constant of a shader stage corresponds to one map entry + std::array specializationMapEntries; + // Shader bindings based on specialization constants are marked by the new "constant_id" layout qualifier: + // layout (constant_id = 0) const int LIGHTING_MODEL = 0; + + // Map entry for the lighting model to be used by the fragment shader + specializationMapEntries[0].constantID = 0; + specializationMapEntries[0].size = sizeof(specializationData.lightingModel); + specializationMapEntries[0].offset = 0; + + // Prepare specialization info block for the shader stage + VkSpecializationInfo specializationInfo{}; + specializationInfo.dataSize = sizeof(specializationData); + specializationInfo.mapEntryCount = static_cast(specializationMapEntries.size()); + specializationInfo.pMapEntries = specializationMapEntries.data(); + specializationInfo.pData = &specializationData; + + // Create pipelines + // All pipelines will use the same "uber" shader and specialization constants to change branching and parameters of that shader + shaderStages[0] = loadShader(getAssetPath() + "shaders/specializationconstants/uber.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(getAssetPath() + "shaders/specializationconstants/uber.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + // Specialization info is assigned is part of the shader stage (modul) and must be set after creating the module and before creating the pipeline + shaderStages[1].pSpecializationInfo = &specializationInfo; + + // Solid phong shading + specializationData.lightingModel = 0; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.phong)); + + // Phong and textured + specializationData.lightingModel = 1; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.toon)); + + // Textured discard + specializationData.lightingModel = 2; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.textured)); + } + + // Prepare and initialize uniform buffer containing shader uniforms + void prepareUniformBuffers() + { + // Create the vertex shader uniform buffer block + VK_CHECK_RESULT(vulkanDevice->createBuffer( + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &uniformBuffer, + sizeof(uboVS))); + + // Map persistent + VK_CHECK_RESULT(uniformBuffer.map()); + + updateUniformBuffers(); + } + + void updateUniformBuffers() + { + uboVS.projection = glm::perspective(glm::radians(60.0f), (float)(width / 3.0f) / (float)height, 0.1f, 256.0f); + + glm::mat4 viewMatrix = glm::translate(glm::mat4(), glm::vec3(0.0f, 0.0f, zoom)); + + uboVS.modelView = viewMatrix * glm::translate(glm::mat4(), cameraPos); + uboVS.modelView = glm::rotate(uboVS.modelView, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f)); + uboVS.modelView = glm::rotate(uboVS.modelView, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f)); + uboVS.modelView = glm::rotate(uboVS.modelView, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f)); + + uboVS.projection = camera.matrices.perspective; + uboVS.modelView = camera.matrices.view; + + memcpy(uniformBuffer.mapped, &uboVS, sizeof(uboVS)); + } + + void draw() + { + VulkanExampleBase::prepareFrame(); + + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); + + VulkanExampleBase::submitFrame(); + } + + void prepare() + { + VulkanExampleBase::prepare(); + loadAssets(); + setupVertexDescriptions(); + prepareUniformBuffers(); + setupDescriptorSetLayout(); + preparePipelines(); + setupDescriptorPool(); + setupDescriptorSet(); + buildCommandBuffers(); + prepared = true; + } + + virtual void render() + { + if (!prepared) + return; + draw(); + } + + virtual void viewChanged() + { + updateUniformBuffers(); + } +}; + +VULKAN_EXAMPLE_MAIN() \ No newline at end of file diff --git a/specializationconstants/specializationconstants.vcxproj b/specializationconstants/specializationconstants.vcxproj new file mode 100644 index 00000000..684dcf68 --- /dev/null +++ b/specializationconstants/specializationconstants.vcxproj @@ -0,0 +1,99 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {00F600D2-DF0E-4F07-B722-633F7C4B2F65} + Win32Proj + 8.1 + + + + Application + true + v140 + + + Application + false + v140 + + + + + + + + + + + + + true + $(SolutionDir)\bin\ + $(SolutionDir)\bin\intermediate\$(ProjectName)\$(ConfigurationName) + + + true + $(SolutionDir)\bin\ + $(SolutionDir)\bin\intermediate\$(ProjectName)\$(ConfigurationName) + + + + WIN32;_DEBUG;_WINDOWS;VK_USE_PLATFORM_WIN32_KHR;_USE_MATH_DEFINES;NOMINMAX;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + ProgramDatabase + Disabled + ..\base;..\external\glm;..\external\gli;..\external\assimp;..\external;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + true + Windows + ..\libs\vulkan\vulkan-1.lib;..\libs\assimp\assimp.lib;%(AdditionalDependencies) + + + + + WIN32;NDEBUG;_WINDOWS;VK_USE_PLATFORM_WIN32_KHR;_USE_MATH_DEFINES;NOMINMAX;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + ProgramDatabase + ..\base;..\external\glm;..\external\gli;..\external\assimp;..\external;%(AdditionalIncludeDirectories) + + + true + Windows + true + true + ..\libs\vulkan\vulkan-1.lib;..\libs\assimp\assimp.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/specializationconstants/specializationconstants.vcxproj.filters b/specializationconstants/specializationconstants.vcxproj.filters new file mode 100644 index 00000000..1f725253 --- /dev/null +++ b/specializationconstants/specializationconstants.vcxproj.filters @@ -0,0 +1,53 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {b5352d42-8278-45c5-979c-2aa01853e035} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Shaders + + + Shaders + + + \ No newline at end of file diff --git a/vulkanExamples.sln b/vulkanExamples.sln index 246bf836..b61cf998 100644 --- a/vulkanExamples.sln +++ b/vulkanExamples.sln @@ -132,6 +132,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "screenshot", "screenshot\sc EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dynamicuniformbuffer", "dynamicuniformbuffer\dynamicuniformbuffer.vcxproj", "{3DB2A9C4-50BC-4390-A94F-F7F724238101}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "specializationconstants", "specializationconstants\specializationconstants.vcxproj", "{00F600D2-DF0E-4F07-B722-633F7C4B2F65}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -322,6 +324,10 @@ Global {3DB2A9C4-50BC-4390-A94F-F7F724238101}.Debug|x64.Build.0 = Debug|x64 {3DB2A9C4-50BC-4390-A94F-F7F724238101}.Release|x64.ActiveCfg = Release|x64 {3DB2A9C4-50BC-4390-A94F-F7F724238101}.Release|x64.Build.0 = Release|x64 + {00F600D2-DF0E-4F07-B722-633F7C4B2F65}.Debug|x64.ActiveCfg = Debug|x64 + {00F600D2-DF0E-4F07-B722-633F7C4B2F65}.Debug|x64.Build.0 = Debug|x64 + {00F600D2-DF0E-4F07-B722-633F7C4B2F65}.Release|x64.ActiveCfg = Release|x64 + {00F600D2-DF0E-4F07-B722-633F7C4B2F65}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE