diff --git a/android/pipelines/AndroidManifest.xml b/android/pipelines/AndroidManifest.xml index f28eb8a6..65a7b2b9 100644 --- a/android/pipelines/AndroidManifest.xml +++ b/android/pipelines/AndroidManifest.xml @@ -15,6 +15,7 @@ android:label="Pipelines" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:launchMode="singleTask" + android:screenOrientation="landscape" android:configChanges="orientation|screenSize|keyboardHidden"> diff --git a/android/pipelines/build.bat b/android/pipelines/build.bat deleted file mode 100644 index 598fe519..00000000 --- a/android/pipelines/build.bat +++ /dev/null @@ -1,23 +0,0 @@ -cd jni -call ndk-build -if %ERRORLEVEL% EQU 0 ( - echo ndk-build has failed, build cancelled - cd.. - - mkdir "assets\shaders\base" - xcopy "..\..\data\shaders\base\*.spv" "assets\shaders\base" /Y - - mkdir "assets\shaders\pipelines" - xcopy "..\..\data\shaders\pipelines\*.spv" "assets\shaders\pipelines" /Y - - mkdir "assets\models" - xcopy "..\..\data\models\treasure_smooth.dae" "assets\models" /Y - - mkdir "res\drawable" - xcopy "..\..\android\images\icon.png" "res\drawable" /Y - - call ant debug -Dout.final.file=vulkanPipelines.apk -) ELSE ( - echo error : ndk-build failed with errors! - cd.. -) diff --git a/android/pipelines/build.py b/android/pipelines/build.py new file mode 100644 index 00000000..fe18640c --- /dev/null +++ b/android/pipelines/build.py @@ -0,0 +1,48 @@ +import os +import shutil +import subprocess +import sys +import glob + +APK_NAME = "vulkanPipelines" +SHADER_DIR = "pipelines" +ASSETS_MODELS = ["treasure_smooth.dae"] + +if subprocess.call("ndk-build", shell=True) == 0: + print("Build successful") + + # Assets + if not os.path.exists("./assets"): + os.makedirs("./assets") + + # Shaders + # Base + if not os.path.exists("./assets/shaders/base"): + os.makedirs("./assets/shaders/base") + for file in glob.glob("../../data/shaders/base/*.spv"): + shutil.copy(file, "./assets/shaders/base") + # Sample + if not os.path.exists("./assets/shaders/%s" % SHADER_DIR): + os.makedirs("./assets/shaders/%s" % SHADER_DIR) + for file in glob.glob("../../data/shaders/%s/*.spv" %SHADER_DIR): + shutil.copy(file, "./assets/shaders/%s" % SHADER_DIR) + # Models + if not os.path.exists("./assets/models"): + os.makedirs("./assets/models") + for file in ASSETS_MODELS: + shutil.copy("../../data/models/%s" % file, "./assets/models") + + # Icon + if not os.path.exists("./res/drawable"): + os.makedirs("./res/drawable") + shutil.copy("../../android/images/icon.png", "./res/drawable") + + if subprocess.call("ant debug -Dout.final.file=%s.apk" % APK_NAME, shell=True) == 0: + if len(sys.argv) > 1: + if sys.argv[1] == "-deploy": + if subprocess.call("adb install -r %s.apk" % APK_NAME, shell=True) != 0: + print("Could not deploy to device!") + else: + print("Error during build process!") +else: + print("Error building project!") diff --git a/pipelines/pipelines.cpp b/pipelines/pipelines.cpp index 9ad9713e..4722d9b2 100644 --- a/pipelines/pipelines.cpp +++ b/pipelines/pipelines.cpp @@ -28,12 +28,6 @@ class VulkanExample: public VulkanExampleBase { public: - struct { - VkPipelineVertexInputStateCreateInfo inputState; - std::vector bindingDescriptions; - std::vector attributeDescriptions; - } vertices; - // Vertex layout for the models vks::VertexLayout vertexLayout = vks::VertexLayout({ vks::VERTEX_COMPONENT_POSITION, @@ -71,9 +65,6 @@ public: rotation = glm::vec3(-25.0f, 15.0f, 0.0f); enableTextOverlay = true; title = "Vulkan Example - Pipeline state objects"; - // Enable features for wireframe rendering and line width setting - enabledFeatures.fillModeNonSolid = VK_TRUE; - enabledFeatures.wideLines = VK_TRUE; } ~VulkanExample() @@ -94,6 +85,19 @@ public: uniformBuffer.destroy(); } + // Enable physical device features required for this example + virtual void getEnabledFeatures() + { + // Fill mode non solid is required for wireframe display + if (deviceFeatures.fillModeNonSolid) { + enabledFeatures.fillModeNonSolid = VK_TRUE; + // Wide lines must be present for line width > 1.0f + if (deviceFeatures.wideLines) { + enabledFeatures.wideLines = VK_TRUE; + } + }; + } + void buildCommandBuffers() { VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); @@ -143,7 +147,10 @@ public: viewport.x = (float)width / 3.0; vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.toon); - vkCmdSetLineWidth(drawCmdBuffers[i], 2.0f); + // Line width > 1.0f only if wide lines feature is supported + if (deviceFeatures.wideLines) { + vkCmdSetLineWidth(drawCmdBuffers[i], 2.0f); + } vkCmdDrawIndexed(drawCmdBuffers[i], models.cube.indexCount, 1, 0, 0, 0); if (deviceFeatures.fillModeNonSolid) @@ -166,55 +173,6 @@ public: models.cube.loadFromFile(getAssetPath() + "models/treasure_smooth.dae", vertexLayout, 1.0f, vulkanDevice, queue); } - void setupVertexDescriptions() - { - // Binding description - vertices.bindingDescriptions.resize(1); - vertices.bindingDescriptions[0] = - vks::initializers::vertexInputBindingDescription( - VERTEX_BUFFER_BIND_ID, - vertexLayout.stride(), - VK_VERTEX_INPUT_RATE_VERTEX); - - // Attribute descriptions - // Describes memory layout and shader positions - vertices.attributeDescriptions.resize(4); - // Location 0 : Position - vertices.attributeDescriptions[0] = - vks::initializers::vertexInputAttributeDescription( - VERTEX_BUFFER_BIND_ID, - 0, - VK_FORMAT_R32G32B32_SFLOAT, - 0); - // Location 1 : Color - vertices.attributeDescriptions[1] = - vks::initializers::vertexInputAttributeDescription( - VERTEX_BUFFER_BIND_ID, - 1, - VK_FORMAT_R32G32B32_SFLOAT, - sizeof(float) * 3); - // Location 3 : Texture coordinates - vertices.attributeDescriptions[2] = - vks::initializers::vertexInputAttributeDescription( - VERTEX_BUFFER_BIND_ID, - 2, - VK_FORMAT_R32G32_SFLOAT, - sizeof(float) * 6); - // Location 2 : Normal - vertices.attributeDescriptions[3] = - vks::initializers::vertexInputAttributeDescription( - VERTEX_BUFFER_BIND_ID, - 3, - VK_FORMAT_R32G32B32_SFLOAT, - sizeof(float) * 8); - - vertices.inputState = vks::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 = @@ -315,9 +273,7 @@ public: vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0); VkPipelineMultisampleStateCreateInfo multisampleState = - vks::initializers::pipelineMultisampleStateCreateInfo( - VK_SAMPLE_COUNT_1_BIT, - 0); + vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT); std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, @@ -325,24 +281,13 @@ public: VK_DYNAMIC_STATE_LINE_WIDTH, }; VkPipelineDynamicStateCreateInfo dynamicState = - vks::initializers::pipelineDynamicStateCreateInfo( - dynamicStateEnables.data(), - dynamicStateEnables.size(), - 0); + vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables); + + VkGraphicsPipelineCreateInfo pipelineCreateInfo = + vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass); std::array shaderStages; - // Phong shading pipeline - shaderStages[0] = loadShader(getAssetPath() + "shaders/pipelines/phong.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader(getAssetPath() + "shaders/pipelines/phong.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - - VkGraphicsPipelineCreateInfo pipelineCreateInfo = - vks::initializers::pipelineCreateInfo( - pipelineLayout, - renderPass, - 0); - - pipelineCreateInfo.pVertexInputState = &vertices.inputState; pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; pipelineCreateInfo.pRasterizationState = &rasterizationState; pipelineCreateInfo.pColorBlendState = &colorBlendState; @@ -353,6 +298,31 @@ public: pipelineCreateInfo.stageCount = shaderStages.size(); pipelineCreateInfo.pStages = shaderStages.data(); + // Shared vertex bindings and attributes used by all pipelines + + // Binding description + std::vector vertexInputBindings = { + vks::initializers::vertexInputBindingDescription(VERTEX_BUFFER_BIND_ID, vertexLayout.stride(), VK_VERTEX_INPUT_RATE_VERTEX), + }; + + // Attribute descriptions + std::vector vertexInputAttributes = { + vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID, 0, VK_FORMAT_R32G32B32_SFLOAT, 0), // Location 0: Position + vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID, 1, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3), // Location 1: Color + vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID, 2, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 6), // Location 2 : Texture coordinates + vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID, 3, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 8), // Location 3 : Normal + }; + + 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; + + // Create the graphics pipeline state objects + // We are using this pipeline as the base for the other pipelines (derivatives) // Pipeline derivatives can be used for pipelines that share most of their state // Depending on the implementation this may result in better performance for pipeline @@ -360,6 +330,9 @@ public: pipelineCreateInfo.flags = VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT; // Textured pipeline + // Phong shading pipeline + shaderStages[0] = loadShader(getAssetPath() + "shaders/pipelines/phong.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(getAssetPath() + "shaders/pipelines/phong.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.phong)); // All pipelines created after the base pipeline will be derivatives @@ -373,13 +346,12 @@ public: // Toon shading pipeline shaderStages[0] = loadShader(getAssetPath() + "shaders/pipelines/toon.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[1] = loadShader(getAssetPath() + "shaders/pipelines/toon.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.toon)); + // Pipeline for wire frame rendering // Non solid rendering is not a mandatory Vulkan feature if (deviceFeatures.fillModeNonSolid) { - // Pipeline for wire frame rendering rasterizationState.polygonMode = VK_POLYGON_MODE_LINE; shaderStages[0] = loadShader(getAssetPath() + "shaders/pipelines/wireframe.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[1] = loadShader(getAssetPath() + "shaders/pipelines/wireframe.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); @@ -432,7 +404,6 @@ public: { VulkanExampleBase::prepare(); loadAssets(); - setupVertexDescriptions(); prepareUniformBuffers(); setupDescriptorSetLayout(); preparePipelines(); @@ -459,6 +430,9 @@ public: textOverlay->addText("Phong shading pipeline",(float)width / 6.0f, height - 35.0f, VulkanTextOverlay::alignCenter); textOverlay->addText("Toon shading pipeline", (float)width / 2.0f, height - 35.0f, VulkanTextOverlay::alignCenter); textOverlay->addText("Wireframe pipeline", width - (float)width / 6.5f, height - 35.0f, VulkanTextOverlay::alignCenter); + if (!deviceFeatures.fillModeNonSolid) { + textOverlay->addText("Non solid fill modes not supported!", width - (float)width / 6.5f, (float)height / 2.0f - 7.5f, VulkanTextOverlay::alignCenter); + } } };