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);
+ }
}
};