From a17e3924b34ab229dd7f0d83ddaec9d6c09ec7f6 Mon Sep 17 00:00:00 2001 From: saschawillems Date: Sun, 12 Nov 2017 14:19:01 +0100 Subject: [PATCH] Added pipeline statistics query example --- CMakeLists.txt | 1 + android/pipelinestatistics/.gitignore | 10 + .../pipelinestatistics/AndroidManifest.xml | 28 + android/pipelinestatistics/example.json | 15 + data/shaders/pipelinestatistics/scene.frag | 19 + .../shaders/pipelinestatistics/scene.frag.spv | Bin 0 -> 1484 bytes data/shaders/pipelinestatistics/scene.tesc | 30 ++ .../shaders/pipelinestatistics/scene.tesc.spv | Bin 0 -> 2680 bytes data/shaders/pipelinestatistics/scene.tese | 24 + .../shaders/pipelinestatistics/scene.tese.spv | Bin 0 -> 3028 bytes data/shaders/pipelinestatistics/scene.vert | 41 ++ .../shaders/pipelinestatistics/scene.vert.spv | Bin 0 -> 3156 bytes pipelinestatistics/pipelinestatistics.cpp | 492 ++++++++++++++++++ 13 files changed, 660 insertions(+) create mode 100644 android/pipelinestatistics/.gitignore create mode 100644 android/pipelinestatistics/AndroidManifest.xml create mode 100644 android/pipelinestatistics/example.json create mode 100644 data/shaders/pipelinestatistics/scene.frag create mode 100644 data/shaders/pipelinestatistics/scene.frag.spv create mode 100644 data/shaders/pipelinestatistics/scene.tesc create mode 100644 data/shaders/pipelinestatistics/scene.tesc.spv create mode 100644 data/shaders/pipelinestatistics/scene.tese create mode 100644 data/shaders/pipelinestatistics/scene.tese.spv create mode 100644 data/shaders/pipelinestatistics/scene.vert create mode 100644 data/shaders/pipelinestatistics/scene.vert.spv create mode 100644 pipelinestatistics/pipelinestatistics.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 31165e34..a93ae182 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -177,6 +177,7 @@ set(EXAMPLES pbribl pbrtexture pipelines + pipelinestatistics pushconstants radialblur raytracing diff --git a/android/pipelinestatistics/.gitignore b/android/pipelinestatistics/.gitignore new file mode 100644 index 00000000..7a5d249c --- /dev/null +++ b/android/pipelinestatistics/.gitignore @@ -0,0 +1,10 @@ +/assets/ +/res/ +/bin/ +/libs/ +/obj/ +/build.xml +/local.properties +/project.properties +/proguard-project.txt +*.apk \ No newline at end of file diff --git a/android/pipelinestatistics/AndroidManifest.xml b/android/pipelinestatistics/AndroidManifest.xml new file mode 100644 index 00000000..7e73dc1a --- /dev/null +++ b/android/pipelinestatistics/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/android/pipelinestatistics/example.json b/android/pipelinestatistics/example.json new file mode 100644 index 00000000..ee6eebfd --- /dev/null +++ b/android/pipelinestatistics/example.json @@ -0,0 +1,15 @@ +{ + "apkname": "vulkanPipelinestatistics", + "directories": { + "shaders": "pipelinestatistics" + }, + "assets": { + "models": [ + "cube.obj", + "geosphere.obj", + "teapot.dae", + "torusknot.obj", + "venus.fbx" + ] + } +} \ No newline at end of file diff --git a/data/shaders/pipelinestatistics/scene.frag b/data/shaders/pipelinestatistics/scene.frag new file mode 100644 index 00000000..43f18f5f --- /dev/null +++ b/data/shaders/pipelinestatistics/scene.frag @@ -0,0 +1,19 @@ +#version 450 + +layout (location = 0) in vec3 inNormal; +layout (location = 1) in vec3 inColor; +layout (location = 2) in vec3 inViewVec; +layout (location = 3) in vec3 inLightVec; + +layout (location = 0) out vec4 outFragColor; + +void main() +{ + 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), 8.0) * vec3(0.75); + outFragColor = vec4(diffuse + specular, 0.5); +} \ No newline at end of file diff --git a/data/shaders/pipelinestatistics/scene.frag.spv b/data/shaders/pipelinestatistics/scene.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..17d51ad6f12d282a0e695f5369648904a801569b GIT binary patch literal 1484 zcmYk5+fGwa5QdkOA_5ACf@i6CLa?3yF-FlC<)$GX67Cx)xD#kifp}?r0k3=_pUN8( zzi)L zwH#>7WExAu?Al?w=;|29Cb1c;ftfT#jxiJi)u@ot9}cLaR&(q4&fwd^>ij&b=x+7; zhwTF(N{#v{wKA^fIz_it?0-Gp?(7Ww=kaZqetRgo+ePPlcIW(Aw9nZ;oUXF(7JGXq zM;&~_x!2U z_9FN0a%UrVj&kP|`7=Zr*C5+`@hoVBeIA=5-dW1^&%;OA)in7SyJyQ^mfRlIg4<)2 z+oODmc+b9xxgx#+uKE|VH@%JcrOe-KER${BWlSy1zMF8*_Pg8XBX;kgZXLO^P>XX{ zz^simzJRkZ*JaFKlsdb)&cOE*cb5BJs@(Tc<-Uh1_f1r}Z$SQv^W7&f=QvT`@hsSx zyw6%nuj$Gj)FWpK?5rba8XP(L%&|}P$hiRadqmDfaOCJS$GfOU&K%ftew4jl0;`4p zGT7cGxQTbUf_dg9W~_eCbtd{E?;6;=;Mc*{`JMj}gLi9;x@X5b_3ZnY@7lK%`M1Cg z>=*g=v4E+~W7hW@s73r8ussF83-<0&{~p*F^{8*%sITAp;d@Z}yrXf8SoHD`?7KC_ zUi|)QQTqwl{(?UR8}qZg%QLVs>YvK_tb)~Dp{;?{>@l?GrRE#|$Yh%A>zMh*>-WE4 NU;an*{o{mn>_0X&N*DkD literal 0 HcmV?d00001 diff --git a/data/shaders/pipelinestatistics/scene.tesc b/data/shaders/pipelinestatistics/scene.tesc new file mode 100644 index 00000000..60693281 --- /dev/null +++ b/data/shaders/pipelinestatistics/scene.tesc @@ -0,0 +1,30 @@ +#version 450 + +layout (vertices = 3) out; + +layout (location = 0) in vec3 inNormal[]; +layout (location = 1) in vec3 inColor[]; +layout (location = 2) in vec3 inViewVec[]; +layout (location = 3) in vec3 inLightVec[]; + +layout (location = 0) out vec3 outNormal[3]; +layout (location = 1) out vec3 outColor[3]; +layout (location = 2) out vec3 outViewVec[3]; +layout (location = 3) out vec3 outLightVec[3]; + +void main(void) +{ + if (gl_InvocationID == 0) + { + gl_TessLevelInner[0] = 2.0; + gl_TessLevelOuter[0] = 1.0; + gl_TessLevelOuter[1] = 1.0; + gl_TessLevelOuter[2] = 1.0; + } + + gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; + outNormal[gl_InvocationID] = inNormal[gl_InvocationID]; + outColor[gl_InvocationID] = inColor[gl_InvocationID]; + outViewVec[gl_InvocationID] = inViewVec[gl_InvocationID]; + outLightVec[gl_InvocationID] = inLightVec[gl_InvocationID]; +} \ No newline at end of file diff --git a/data/shaders/pipelinestatistics/scene.tesc.spv b/data/shaders/pipelinestatistics/scene.tesc.spv new file mode 100644 index 0000000000000000000000000000000000000000..d68bc835b4b8c8369794d446ab42915a508695b7 GIT binary patch literal 2680 zcmZ{m>uwxH5Jo%p?mA$|Jr0);HiWyu;gWC4Uq-gS?2mg~0milj0X#sx-JZ`!+`7(n_E+b-d@V@v@q1mcJIp1!wPY z%fs@gm2y1Uu6Bxj&hyFb4Tt-jXY^TtkM<_^+e`C}|G%EZU3KkNPvVF5BzIU(a)_k& zI}0v-S71I{F?C=*Q!$@kVA^8NvwfJ)IQecf@&q@8$yH()V84 zzIUQ;EqUL=w!fZz>&kl<^5J_A`t~629fW_HDB~`|%4?q`ribn$*6ic+v8iqG8`<~1 zEtM;`XiYH%QF9&emah-+}8R=6x4! zY=d>u0=B)1n^*sG#;p5(w#}`71#L}z&wmZ=`J(TSu*IV9>zNZbzrM2{@i(xIkA6PI zwjXih^?f(QtbaS(?$N)4HkW?nU&&bPzl-1GZ0h^&xF>kuoi^{g)8>75xU9yQjm#f`ax{v2`E%w-LIW1_|YyItdc_M^rFd}mKQYHVPO zM~yGBomX>NL*JOFv5DQT@pbm2#umQwD;_nz!4{7i-(oxS=CX#qG5<34*OC7K3{1*8 literal 0 HcmV?d00001 diff --git a/data/shaders/pipelinestatistics/scene.tese b/data/shaders/pipelinestatistics/scene.tese new file mode 100644 index 00000000..39f020d2 --- /dev/null +++ b/data/shaders/pipelinestatistics/scene.tese @@ -0,0 +1,24 @@ +#version 450 + +layout (triangles) in; + +layout (location = 0) in vec3 inNormal[]; +layout (location = 1) in vec3 inColor[]; +layout (location = 2) in vec3 inViewVec[]; +layout (location = 3) in vec3 inLightVec[]; + +layout (location = 0) out vec3 outNormal; +layout (location = 1) out vec3 outColor; +layout (location = 2) out vec3 outViewVec; +layout (location = 3) out vec3 outLightVec; + +void main(void) +{ + gl_Position = (gl_TessCoord.x * gl_in[2].gl_Position) + + (gl_TessCoord.y * gl_in[1].gl_Position) + + (gl_TessCoord.z * gl_in[0].gl_Position); + outNormal = gl_TessCoord.x*inNormal[2] + gl_TessCoord.y*inNormal[1] + gl_TessCoord.z*inNormal[0]; + outViewVec = gl_TessCoord.x*inViewVec[2] + gl_TessCoord.y*inViewVec[1] + gl_TessCoord.z*inViewVec[0]; + outLightVec = gl_TessCoord.x*inLightVec[2] + gl_TessCoord.y*inLightVec[1] + gl_TessCoord.z*inLightVec[0]; + outColor = inColor[0]; +} \ No newline at end of file diff --git a/data/shaders/pipelinestatistics/scene.tese.spv b/data/shaders/pipelinestatistics/scene.tese.spv new file mode 100644 index 0000000000000000000000000000000000000000..1a6233c4c52fb60a45f99b92e2003772a4d9976f GIT binary patch literal 3028 zcmZ{k>vj}X5QSTk;UWrw2zWspjNkeQ~TbEcBqMgwL|x^2+l3 zaI`Uh?)(`u_SI2$W!e60hU_ex#NFUrwM z@kef6#MC0T)GzK|D~6-Bay=i%oQtss{r))Cp+Dc*$9{Zwa&G6t;Zju%HiAFW@c-#k z-ly&-=~MnueHwdIpT_>b&*}P1(5VlqL${t!^lg!Ey_%MLDKw&hsO0wa9;4 z&DWbe&$B4URGsJflDAxJ-W!={JK_MN-}@N#Uj)lX{g=SjpTpAnC-99${gYrh z_iwkFFN3?7vCw=KtfuD}ny-Q7L-Q0^P4!aE*YS;o<{Mx+_lM>@SY2ako@PCR`TMcf z6(+53Ui9=9cyi9?;N;Em_i_>QZa8QA_8z^B$=i?qJ1ytlsC@}MIpcTX}jhTezZtC%t8 zc$QTzw6B9F=lBtvygAPC6U^UGI>+Uf5A7THa_)`VH^Gy0{1i?;YTp7|JDuZa`0`Qv zbFiFyx7#_cfYme>dbh#qrT6p;eEHB@1*@0N@k@O9(EAE3=ibo!8my)<=h$PF3+->g zYR_Wv8~F|_AKE{F{nn&&yn`Xiii1V7x@YHa&rc18Yf~34 zp4Z|~FY;CwcP0`9Doi&Y7RlqL)W2oXd4>kXN3E20yK&-ejfQYK=dzn zhPTT8)^ZnK%y^yNE>vO0$8M(VmVH>Tu_|AuS3}B2z`NyYs~o5wEuKccb8~^tnia3# zcE8+guMRsU)dy~GTjg52`&*}dA3kvF?snEUhE>Em<_WN!m9oljubp14wC=OW_sf2F zZP&h0yaCqQ8Enjyy}^*Wn%IeX%9YJjYonM#-p=eASY8EN@7`^-`%CTqu>HF})+X*z zR}MN=GxqD;J@TJ(Z!-w%au>{Q-d2{{s}<&Mz?SG(sF-Db?&37$QFaf?&PUlDrNp?q}e;ht$qF&kB#KPX4X&-ubrr!9@-`JA*k8+#eZ}b$uk8z7B zpHBM}3)~pTk?qA@n?u>TiycQk$vqC4^IVcoC0YMx;I%bo)aYKq-g@dCJ-B|FPTYs} z>iZ_Q^AOWl+3!d!a=iub(f&NQI{l61?(9$9HE!o5W-MjDr(2c;kh=->CMNn7wxH!6Wt$h~JC0?$N(}))VsCOtx14 z9;m;Hz4sH4Z{-@%oQZPi4#WFS)cJmtZ;;JhJqx*Ccc{I4dkzv0{}h+QnW@Sf1;Zgw?s4)l6Om z(_ee__U~N9qyN|7_xArfn0WMm4&MIt@y)#r`7V8nVe?MH|HQ_9ybI|k9=%*hIM*(A zF=2TxmlBrG?L9F4wO60d?J}}8YZJNNhZpw*_5r+Dp6g1&^0|EoroZ;;oty7ZJmxkH z@7!VrzMC7+G!!$r39nz|pMe+i1ojcUSYFe|2^-;#ck>Cn{@Sb0`=3QNw>H){$Neef z_ilaGuUy;J?|vS6@7})v6Oa0D!RPfaAd7jT{uaDgUjJgk^7_97(_ee_dHuJM&8>~K z`fZEFtiOWaTk9P#@kPGKCigdxSe(GW1qi&Zv9|v%!>u#yzfZWfp1^;AH;#B7=f@1s z)c`y?^pOdULRRZ@ +#include +#include +#include +#include + +#define GLM_FORCE_RADIANS +#define GLM_FORCE_DEPTH_ZERO_TO_ONE +#include +#include + +#include +#include "vulkanexamplebase.h" +#include "VulkanBuffer.hpp" +#include "VulkanModel.hpp" + +#define ENABLE_VALIDATION false +#define OBJ_DIM 0.05f + +class VulkanExample : public VulkanExampleBase +{ +public: + // Vertex layout for the models + vks::VertexLayout vertexLayout = vks::VertexLayout({ + vks::VERTEX_COMPONENT_POSITION, + vks::VERTEX_COMPONENT_NORMAL, + vks::VERTEX_COMPONENT_COLOR, + }); + + struct Models { + std::vector objects; + int32_t objectIndex = 3; + std::vector names; + } models; + + struct UniformBuffers { + vks::Buffer VS; + } uniformBuffers; + + struct UBOVS { + glm::mat4 projection; + glm::mat4 modelview; + glm::vec4 lightPos = glm::vec4(-10.0f, -10.0f, 10.0f, 1.0f); + } uboVS; + + VkPipeline pipeline = VK_NULL_HANDLE; + + int32_t cullMode = VK_CULL_MODE_BACK_BIT; + bool blending = false; + bool discard = false; + bool wireframe = false; + bool tessellation = false; + + VkPipelineLayout pipelineLayout; + VkDescriptorSet descriptorSet; + VkDescriptorSetLayout descriptorSetLayout; + + VkQueryPool queryPool; + + // Vector for storing pipeline statistics results + std::vector pipelineStats; + std::vector pipelineStatNames; + + int32_t gridSize = 3; + + VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) + { + title = "Pipeline statistics"; + camera.type = Camera::CameraType::firstperson; + camera.setPosition(glm::vec3(-4.0f, 3.0f, -3.75f)); + camera.setRotation(glm::vec3(-15.25f, -46.5f, 0.0f)); + camera.movementSpeed = 4.0f; + camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 256.0f); + camera.rotationSpeed = 0.25f; + settings.overlay = true; + } + + ~VulkanExample() + { + vkDestroyPipeline(device, pipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + vkDestroyQueryPool(device, queryPool, nullptr); + uniformBuffers.VS.destroy(); + for (auto& model : models.objects) { + model.destroy(); + } + } + + virtual void getEnabledFeatures() + { + // Support for pipeline statistics is optional + if (deviceFeatures.pipelineStatisticsQuery) { + enabledFeatures.pipelineStatisticsQuery = VK_TRUE; + } + else { + vks::tools::exitFatal("Selected GPU does not support pipeline statistics!", "Feature not supported"); + } + if (deviceFeatures.fillModeNonSolid) { + enabledFeatures.fillModeNonSolid = VK_TRUE; + } + if (deviceFeatures.tessellationShader) { + enabledFeatures.tessellationShader = VK_TRUE; + } + } + + // Setup a query pool for storing pipeline statistics + void setupQueryPool() + { + pipelineStatNames = { + "Input assembly vertex count ", + "Input assembly primitives count ", + "Vertex shader invocations ", + "Clipping stage primitives processed", + "Clipping stage primtives output ", + "Fragment shader invocations " + }; + if (deviceFeatures.tessellationShader) { + pipelineStatNames.push_back("Tess. control shader patches "); + pipelineStatNames.push_back("Tess. eval. shader invocations "); + } + pipelineStats.resize(pipelineStatNames.size()); + + VkQueryPoolCreateInfo queryPoolInfo = {}; + queryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; + // This query pool will store pipeline statistics + queryPoolInfo.queryType = VK_QUERY_TYPE_PIPELINE_STATISTICS; + // Pipeline counters to be returned for this pool + queryPoolInfo.pipelineStatistics = + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT | + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT | + VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT | + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT | + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT | + VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT; + if (deviceFeatures.tessellationShader) { + queryPoolInfo.pipelineStatistics |= + VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT | + VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT; + } + queryPoolInfo.queryCount = deviceFeatures.tessellationShader ? 8 : 6; + VK_CHECK_RESULT(vkCreateQueryPool(device, &queryPoolInfo, NULL, &queryPool)); + } + + // Retrieves the results of the pipeline statistics query submitted to the command buffer + void getQueryResults() + { + uint32_t count = static_cast(pipelineStats.size()); + vkGetQueryPoolResults( + device, + queryPool, + 0, + 1, + count * sizeof(uint64_t), + pipelineStats.data(), + sizeof(uint64_t), + VK_QUERY_RESULT_64_BIT); + } + + void buildCommandBuffers() + { + VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); + + VkClearValue clearValues[2]; + clearValues[0].color = defaultClearColor; + clearValues[1].depthStencil = { 1.0f, 0 }; + + VkRenderPassBeginInfo renderPassBeginInfo = vks::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) { + renderPassBeginInfo.framebuffer = frameBuffers[i]; + + VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); + + // Reset timestamp query pool + vkCmdResetQueryPool(drawCmdBuffers[i], queryPool, 0, static_cast(pipelineStats.size())); + + vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); + vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); + + VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0); + vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); + + VkDeviceSize offsets[1] = { 0 }; + + // Start capture of pipeline statistics + vkCmdBeginQuery(drawCmdBuffers[i], queryPool, 0, VK_QUERY_CONTROL_PRECISE_BIT); + + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL); + vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &models.objects[models.objectIndex].vertices.buffer, offsets); + vkCmdBindIndexBuffer(drawCmdBuffers[i], models.objects[models.objectIndex].indices.buffer, 0, VK_INDEX_TYPE_UINT32); + + for (int32_t y = 0; y < gridSize; y++) { + for (int32_t x = 0; x < gridSize; x++) { + glm::vec3 pos = glm::vec3(float(x - (gridSize / 2.0f)) * 2.5f, 0.0f, float(y - (gridSize / 2.0f)) * 2.5f); + vkCmdPushConstants(drawCmdBuffers[i], pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::vec3), &pos); + vkCmdDrawIndexed(drawCmdBuffers[i], models.objects[models.objectIndex].indexCount, 1, 0, 0, 0); + } + } + + // End capture of pipeline statistics + vkCmdEndQuery(drawCmdBuffers[i], queryPool, 0); + + vkCmdEndRenderPass(drawCmdBuffers[i]); + + VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i])); + } + } + + void draw() + { + VulkanExampleBase::prepareFrame(); + + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); + + // Read query results for displaying in next frame + getQueryResults(); + + VulkanExampleBase::submitFrame(); + } + + void loadAssets() + { + // Objects + std::vector filenames = { "geosphere.obj", "teapot.dae", "torusknot.obj", "venus.fbx" }; + for (auto file : filenames) { + vks::Model model; + model.loadFromFile(getAssetPath() + "models/" + file, vertexLayout, OBJ_DIM * (file == "venus.fbx" ? 3.0f : 1.0f), vulkanDevice, queue); + models.objects.push_back(model); + } + models.names = { "Sphere", "Teapot", "Torusknot", "Venus" }; + } + + void setupDescriptorPool() + { + std::vector poolSizes = { + vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3) + }; + VkDescriptorPoolCreateInfo descriptorPoolInfo = + vks::initializers::descriptorPoolCreateInfo(poolSizes, 3); + VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); + } + + void setupDescriptorSetLayout() + { + std::vector setLayoutBindings = { + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0) + }; + VkDescriptorSetLayoutCreateInfo descriptorLayout = + vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = + vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); + VkPushConstantRange pushConstantRange = vks::initializers::pushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, sizeof(glm::vec3), 0); + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange; + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); + } + + void setupDescriptorSets() + { + VkDescriptorSetAllocateInfo allocInfo = + vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1); + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); + std::vector writeDescriptorSets = { + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.VS.descriptor) + }; + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); + } + + void preparePipelines() + { + if (pipeline != VK_NULL_HANDLE) { + vkDestroyPipeline(device, pipeline, nullptr); + } + + VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = + vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); + + VkPipelineRasterizationStateCreateInfo rasterizationState = + vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, cullMode, VK_FRONT_FACE_CLOCKWISE, 0); + + VkPipelineColorBlendAttachmentState blendAttachmentState = + vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); + + VkPipelineColorBlendStateCreateInfo colorBlendState = + vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState); + + VkPipelineDepthStencilStateCreateInfo depthStencilState = + vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL); + + VkPipelineViewportStateCreateInfo viewportState = + vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0); + + VkPipelineMultisampleStateCreateInfo multisampleState = + vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT, 0); + + std::vector dynamicStateEnables = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR + }; + VkPipelineDynamicStateCreateInfo dynamicState = + vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables.data(), static_cast(dynamicStateEnables.size()), 0); + + VkGraphicsPipelineCreateInfo pipelineCreateInfo = + vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass, 0); + + VkPipelineTessellationStateCreateInfo tessellationState = + vks::initializers::pipelineTessellationStateCreateInfo(3); + + pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; + pipelineCreateInfo.pRasterizationState = &rasterizationState; + pipelineCreateInfo.pColorBlendState = &colorBlendState; + pipelineCreateInfo.pMultisampleState = &multisampleState; + pipelineCreateInfo.pViewportState = &viewportState; + pipelineCreateInfo.pDepthStencilState = &depthStencilState; + pipelineCreateInfo.pDynamicState = &dynamicState; + + // Vertex bindings and attributes + std::vector vertexInputBindings = { + vks::initializers::vertexInputBindingDescription(0, vertexLayout.stride(), VK_VERTEX_INPUT_RATE_VERTEX) + }; + + std::vector vertexInputAttributes = { + vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0), // Location 0 : Position + vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3), // Location 1 : Normal + vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 6) // Location 3 : Color + }; + + VkPipelineVertexInputStateCreateInfo vertexInputState = vks::initializers::pipelineVertexInputStateCreateInfo(); + vertexInputState.vertexBindingDescriptionCount = static_cast(vertexInputBindings.size()); + vertexInputState.pVertexBindingDescriptions = vertexInputBindings.data(); + vertexInputState.vertexAttributeDescriptionCount = static_cast(vertexInputAttributes.size()); + vertexInputState.pVertexAttributeDescriptions = vertexInputAttributes.data(); + + pipelineCreateInfo.pVertexInputState = &vertexInputState; + + if (blending) { + blendAttachmentState.blendEnable = VK_TRUE; + blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; + blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; + depthStencilState.depthWriteEnable = VK_FALSE; + } + + if (discard) { + rasterizationState.rasterizerDiscardEnable = VK_TRUE; + } + + if (wireframe) { + rasterizationState.polygonMode = VK_POLYGON_MODE_LINE; + } + + std::vector shaderStages; + shaderStages.resize(tessellation ? 4 : 2); + shaderStages[0] = loadShader(getAssetPath() + "shaders/pipelinestatistics/scene.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(getAssetPath() + "shaders/pipelinestatistics/scene.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + + if (tessellation) { + inputAssemblyState.topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; + pipelineCreateInfo.pTessellationState = &tessellationState; + shaderStages[2] = loadShader(getAssetPath() + "shaders/pipelinestatistics/scene.tesc.spv", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT); + shaderStages[3] = loadShader(getAssetPath() + "shaders/pipelinestatistics/scene.tese.spv", VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT); + } + + pipelineCreateInfo.stageCount = static_cast(shaderStages.size()); + pipelineCreateInfo.pStages = shaderStages.data(); + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipeline)); + } + + // Prepare and initialize uniform buffer containing shader uniforms + void prepareUniformBuffers() + { + VK_CHECK_RESULT(vulkanDevice->createBuffer( + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &uniformBuffers.VS, + sizeof(uboVS))); + + // Map persistent + VK_CHECK_RESULT(uniformBuffers.VS.map()); + + updateUniformBuffers(); + } + + void updateUniformBuffers() + { + uboVS.projection = camera.matrices.perspective; + uboVS.modelview = camera.matrices.view; + memcpy(uniformBuffers.VS.mapped, &uboVS, sizeof(uboVS)); + } + + void prepare() + { + VulkanExampleBase::prepare(); + loadAssets(); + setupQueryPool(); + prepareUniformBuffers(); + setupDescriptorSetLayout(); + preparePipelines(); + setupDescriptorPool(); + setupDescriptorSets(); + buildCommandBuffers(); + prepared = true; + } + + virtual void render() + { + if (!prepared) + return; + draw(); + } + + virtual void viewChanged() + { + updateUniformBuffers(); + } + + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) + { + if (overlay->header("Settings")) { + if (overlay->comboBox("Object type", &models.objectIndex, models.names)) { + updateUniformBuffers(); + buildCommandBuffers(); + } + if (overlay->sliderInt("Grid size", &gridSize, 1, 10)) { + buildCommandBuffers(); + } + std::vector cullModeNames = { "None", "Front", "Back", "Back and front" }; + if (overlay->comboBox("Cull mode", &cullMode, cullModeNames)) { + preparePipelines(); + buildCommandBuffers(); + } + if (overlay->checkBox("Blending", &blending)) { + preparePipelines(); + buildCommandBuffers(); + } + if (deviceFeatures.fillModeNonSolid) { + if (overlay->checkBox("Wireframe", &wireframe)) { + preparePipelines(); + buildCommandBuffers(); + } + } + if (deviceFeatures.tessellationShader) { + if (overlay->checkBox("Tessellation", &tessellation)) { + preparePipelines(); + buildCommandBuffers(); + } + } + if (overlay->checkBox("Discard", &discard)) { + preparePipelines(); + buildCommandBuffers(); + } + } + if (!pipelineStats.empty()) { + if (overlay->header("Pipeline statistics")) { + for (auto i = 0; i < pipelineStats.size(); i++) { + std::string caption = pipelineStatNames[i] + ": %d"; + overlay->text(caption.c_str(), pipelineStats[i]); + } + } + } + } + +}; + +VULKAN_EXAMPLE_MAIN() \ No newline at end of file