Merge branch 'master' into slang_shaders
This commit is contained in:
commit
fc42739429
7 changed files with 589 additions and 0 deletions
|
|
@ -446,6 +446,10 @@ Vulkan is an extensible api with lots of functionality added by extensions. Thes
|
|||
|
||||
Shows usage of the VK_KHR_dynamic_rendering extension, which simplifies the rendering setup by no longer requiring render pass objects or framebuffers.
|
||||
|
||||
- [Dynamic rendering with multi sampling (VK_KHR_dynamic_rendering)](examples/dynamicrenderingmultisampling/)
|
||||
|
||||
Based on the dynamic rendering sample, this sample shows how to do implement multi sampling with dynamic rendering.
|
||||
|
||||
- [Graphics pipeline library (VK_EXT_graphics_pipeline_library)](./examples/graphicspipelinelibrary)
|
||||
|
||||
Uses the graphics pipeline library extensions to improve run-time pipeline creation. Instead of creating the whole pipeline at once, this sample pre builds shared pipeline parts like like vertex input state and fragment output state. These are then used to create full pipelines at runtime, reducing build times and possible hick-ups.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
cmake_minimum_required(VERSION 3.4.1 FATAL_ERROR)
|
||||
|
||||
set(NAME dynamicrenderingmultisampling)
|
||||
|
||||
set(SRC_DIR ../../../examples/${NAME})
|
||||
set(BASE_DIR ../../../base)
|
||||
set(EXTERNAL_DIR ../../../external)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -DVK_USE_PLATFORM_ANDROID_KHR -DVK_NO_PROTOTYPES")
|
||||
|
||||
file(GLOB EXAMPLE_SRC "${SRC_DIR}/*.cpp")
|
||||
|
||||
add_library(native-lib SHARED ${EXAMPLE_SRC})
|
||||
|
||||
add_library(native-app-glue STATIC ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
|
||||
|
||||
add_subdirectory(../base ${CMAKE_SOURCE_DIR}/../base)
|
||||
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")
|
||||
|
||||
include_directories(${BASE_DIR})
|
||||
include_directories(${EXTERNAL_DIR})
|
||||
include_directories(${EXTERNAL_DIR}/glm)
|
||||
include_directories(${EXTERNAL_DIR}/imgui)
|
||||
include_directories(${EXTERNAL_DIR}/tinygltf)
|
||||
include_directories(${ANDROID_NDK}/sources/android/native_app_glue)
|
||||
|
||||
target_link_libraries(
|
||||
native-lib
|
||||
native-app-glue
|
||||
libbase
|
||||
android
|
||||
log
|
||||
z
|
||||
)
|
||||
65
android/examples/dynamicrenderingmultisampling/build.gradle
Normal file
65
android/examples/dynamicrenderingmultisampling/build.gradle
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply from: '../gradle/outputfilename.gradle'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
defaultConfig {
|
||||
applicationId "de.saschawillems.vulkanDynamicrenderingmulitsampling"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
ndk {
|
||||
abiFilters rootProject.ext.abiFilters
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags "-std=c++14"
|
||||
arguments "-DANDROID_STL=c++_shared", '-DANDROID_TOOLCHAIN=clang'
|
||||
}
|
||||
}
|
||||
}
|
||||
sourceSets {
|
||||
main.assets.srcDirs = ['assets']
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path "CMakeLists.txt"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task copyTask {
|
||||
copy {
|
||||
from '../../common/res/drawable'
|
||||
into "src/main/res/drawable"
|
||||
include 'icon.png'
|
||||
}
|
||||
|
||||
copy {
|
||||
from rootProject.ext.shaderPath + 'glsl/base'
|
||||
into 'assets/shaders/glsl/base'
|
||||
include '*.spv'
|
||||
}
|
||||
|
||||
copy {
|
||||
from rootProject.ext.shaderPath + 'glsl/dynamicrendering'
|
||||
into 'assets/shaders/glsl/dynamicrendering'
|
||||
include '*.*'
|
||||
}
|
||||
|
||||
copy {
|
||||
from rootProject.ext.assetPath + 'models'
|
||||
into 'assets/models'
|
||||
include 'voyager.gltf'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
preBuild.dependsOn copyTask
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:label="Vulkan dynamic rendering with multi sampling"
|
||||
android:icon="@drawable/icon"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
|
||||
<activity android:name="de.saschawillems.vulkanSample.VulkanActivity"
|
||||
android:screenOrientation="landscape"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:exported="true">
|
||||
<meta-data android:name="android.app.lib_name"
|
||||
android:value="native-lib" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.gamepad" android:required="false" />
|
||||
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (C) 2018 by Sascha Willems - www.saschawillems.de
|
||||
*
|
||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
package de.saschawillems.vulkanSample;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.NativeActivity;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
public class VulkanActivity extends NativeActivity {
|
||||
|
||||
static {
|
||||
// Load native library
|
||||
System.loadLibrary("native-lib");
|
||||
}
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
// Use a semaphore to create a modal dialog
|
||||
|
||||
private final Semaphore semaphore = new Semaphore(0, true);
|
||||
|
||||
public void showAlert(final String message)
|
||||
{
|
||||
final VulkanActivity activity = this;
|
||||
|
||||
ApplicationInfo applicationInfo = activity.getApplicationInfo();
|
||||
final String applicationName = applicationInfo.nonLocalizedLabel.toString();
|
||||
|
||||
this.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity, android.R.style.Theme_Material_Dialog_Alert);
|
||||
builder.setTitle(applicationName);
|
||||
builder.setMessage(message);
|
||||
builder.setPositiveButton("Close", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
semaphore.release();
|
||||
}
|
||||
});
|
||||
builder.setCancelable(false);
|
||||
AlertDialog dialog = builder.create();
|
||||
dialog.show();
|
||||
}
|
||||
});
|
||||
try {
|
||||
semaphore.acquire();
|
||||
}
|
||||
catch (InterruptedException e) { }
|
||||
}
|
||||
}
|
||||
|
|
@ -109,6 +109,7 @@ set(EXAMPLES
|
|||
displacement
|
||||
distancefieldfonts
|
||||
dynamicrendering
|
||||
dynamicrenderingmultisampling
|
||||
dynamicstate
|
||||
dynamicuniformbuffer
|
||||
gears
|
||||
|
|
|
|||
|
|
@ -0,0 +1,402 @@
|
|||
/*
|
||||
* Vulkan Example - Using Multi sampling with VK_KHR_dynamic_rendering
|
||||
*
|
||||
* Copyright (C) 2025 by Sascha Willems - www.saschawillems.de
|
||||
*
|
||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "vulkanexamplebase.h"
|
||||
#include "VulkanglTFModel.h"
|
||||
|
||||
class VulkanExample : public VulkanExampleBase
|
||||
{
|
||||
public:
|
||||
PFN_vkCmdBeginRenderingKHR vkCmdBeginRenderingKHR{ VK_NULL_HANDLE };
|
||||
PFN_vkCmdEndRenderingKHR vkCmdEndRenderingKHR{ VK_NULL_HANDLE };
|
||||
|
||||
VkPhysicalDeviceDynamicRenderingFeaturesKHR enabledDynamicRenderingFeaturesKHR{};
|
||||
|
||||
vkglTF::Model model;
|
||||
|
||||
const VkSampleCountFlagBits multiSampleCount = VK_SAMPLE_COUNT_4_BIT;
|
||||
|
||||
struct UniformData {
|
||||
glm::mat4 projection;
|
||||
glm::mat4 modelView;
|
||||
glm::vec4 viewPos;
|
||||
} uniformData;
|
||||
vks::Buffer uniformBuffer;
|
||||
|
||||
VkPipeline pipeline{ VK_NULL_HANDLE };
|
||||
VkPipelineLayout pipelineLayout{ VK_NULL_HANDLE };
|
||||
VkDescriptorSet descriptorSet{ VK_NULL_HANDLE };
|
||||
VkDescriptorSetLayout descriptorSetLayout{ VK_NULL_HANDLE };
|
||||
|
||||
// Intermediate images used for multi sampling
|
||||
struct Image {
|
||||
VkImage image{ VK_NULL_HANDLE };
|
||||
VkImageView view{ VK_NULL_HANDLE };
|
||||
VkDeviceMemory memory{ VK_NULL_HANDLE };
|
||||
};
|
||||
Image renderImage;
|
||||
Image depthStencilRenderImage;
|
||||
|
||||
VulkanExample() : VulkanExampleBase()
|
||||
{
|
||||
title = "Multi sampling with dynamic rendering";
|
||||
camera.type = Camera::CameraType::lookat;
|
||||
camera.setPosition(glm::vec3(0.0f, 0.0f, -10.0f));
|
||||
camera.setRotation(glm::vec3(-7.5f, 72.0f, 0.0f));
|
||||
camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 256.0f);
|
||||
settings.overlay = false;
|
||||
|
||||
enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
||||
|
||||
// The sample uses the extension (instead of Vulkan 1.2, where dynamic rendering is core)
|
||||
enabledDeviceExtensions.push_back(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
|
||||
enabledDeviceExtensions.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
|
||||
enabledDeviceExtensions.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
|
||||
enabledDeviceExtensions.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
|
||||
enabledDeviceExtensions.push_back(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
|
||||
|
||||
// in addition to the extension, the feature needs to be explicitly enabled too by chaining the extension structure into device creation
|
||||
enabledDynamicRenderingFeaturesKHR.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR;
|
||||
enabledDynamicRenderingFeaturesKHR.dynamicRendering = VK_TRUE;
|
||||
|
||||
deviceCreatepNextChain = &enabledDynamicRenderingFeaturesKHR;
|
||||
}
|
||||
|
||||
~VulkanExample()
|
||||
{
|
||||
if (device) {
|
||||
vkDestroyPipeline(device, pipeline, nullptr);
|
||||
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
||||
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
|
||||
uniformBuffer.destroy();
|
||||
vkDestroyImage(device, renderImage.image, nullptr);
|
||||
vkDestroyImageView(device, renderImage.view, nullptr);
|
||||
vkFreeMemory(device, renderImage.memory, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void setupRenderPass() override
|
||||
{
|
||||
// With VK_KHR_dynamic_rendering we no longer need a render pass, so we can skip the sample base render pass setup
|
||||
renderPass = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void setupFrameBuffer() override
|
||||
{
|
||||
// With VK_KHR_dynamic_rendering we no longer need a frame buffer, so we can so skip the sample base framebuffer setup
|
||||
// For multi sampling we need intermediate images that are then resolved to the final presentation image
|
||||
vkDestroyImage(device, renderImage.image, nullptr);
|
||||
vkDestroyImageView(device, renderImage.view, nullptr);
|
||||
vkFreeMemory(device, renderImage.memory, nullptr);
|
||||
VkImageCreateInfo renderImageCI = vks::initializers::imageCreateInfo();
|
||||
renderImageCI.imageType = VK_IMAGE_TYPE_2D;
|
||||
renderImageCI.format = swapChain.colorFormat;
|
||||
renderImageCI.extent = { width, height, 1 };
|
||||
renderImageCI.mipLevels = 1;
|
||||
renderImageCI.arrayLayers = 1;
|
||||
renderImageCI.samples = multiSampleCount;
|
||||
renderImageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
renderImageCI.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
renderImageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
VK_CHECK_RESULT(vkCreateImage(device, &renderImageCI, nullptr, &renderImage.image));
|
||||
VkMemoryRequirements memReqs{};
|
||||
vkGetImageMemoryRequirements(device, renderImage.image, &memReqs);
|
||||
VkMemoryAllocateInfo memAllloc{};
|
||||
memAllloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
memAllloc.allocationSize = memReqs.size;
|
||||
memAllloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllloc, nullptr, &renderImage.memory));
|
||||
VK_CHECK_RESULT(vkBindImageMemory(device, renderImage.image, renderImage.memory, 0));
|
||||
VkImageViewCreateInfo imageViewCI = vks::initializers::imageViewCreateInfo();
|
||||
imageViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
imageViewCI.image = renderImage.image;
|
||||
imageViewCI.format = swapChain.colorFormat;
|
||||
imageViewCI.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
||||
VK_CHECK_RESULT(vkCreateImageView(device, &imageViewCI, nullptr, &renderImage.view));
|
||||
}
|
||||
|
||||
// We need to override the default depth/stencil setup to create a depth image that supports multi sampling
|
||||
void setupDepthStencil() override
|
||||
{
|
||||
VkImageCreateInfo imageCI{};
|
||||
imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageCI.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageCI.format = depthFormat;
|
||||
imageCI.extent = { width, height, 1 };
|
||||
imageCI.mipLevels = 1;
|
||||
imageCI.arrayLayers = 1;
|
||||
imageCI.samples = multiSampleCount;
|
||||
imageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageCI.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &depthStencil.image));
|
||||
VkMemoryRequirements memReqs{};
|
||||
vkGetImageMemoryRequirements(device, depthStencil.image, &memReqs);
|
||||
VkMemoryAllocateInfo memAllloc{};
|
||||
memAllloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
memAllloc.allocationSize = memReqs.size;
|
||||
memAllloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllloc, nullptr, &depthStencil.memory));
|
||||
VK_CHECK_RESULT(vkBindImageMemory(device, depthStencil.image, depthStencil.memory, 0));
|
||||
VkImageViewCreateInfo depthImageViewCI{};
|
||||
depthImageViewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
depthImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
depthImageViewCI.image = depthStencil.image;
|
||||
depthImageViewCI.format = depthFormat;
|
||||
depthImageViewCI.subresourceRange.baseMipLevel = 0;
|
||||
depthImageViewCI.subresourceRange.levelCount = 1;
|
||||
depthImageViewCI.subresourceRange.baseArrayLayer = 0;
|
||||
depthImageViewCI.subresourceRange.layerCount = 1;
|
||||
depthImageViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
// Stencil aspect should only be set on depth + stencil formats (VK_FORMAT_D16_UNORM_S8_UINT..VK_FORMAT_D32_SFLOAT_S8_UINT
|
||||
if (depthFormat >= VK_FORMAT_D16_UNORM_S8_UINT) {
|
||||
depthImageViewCI.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
VK_CHECK_RESULT(vkCreateImageView(device, &depthImageViewCI, nullptr, &depthStencil.view));
|
||||
}
|
||||
|
||||
// Enable physical device features required for this example
|
||||
virtual void getEnabledFeatures()
|
||||
{
|
||||
// Enable anisotropic filtering if supported
|
||||
if (deviceFeatures.samplerAnisotropy) {
|
||||
enabledFeatures.samplerAnisotropy = VK_TRUE;
|
||||
};
|
||||
}
|
||||
|
||||
void loadAssets()
|
||||
{
|
||||
const uint32_t glTFLoadingFlags = vkglTF::FileLoadingFlags::PreTransformVertices | vkglTF::FileLoadingFlags::PreMultiplyVertexColors | vkglTF::FileLoadingFlags::FlipY;
|
||||
model.loadFromFile(getAssetPath() + "models/voyager.gltf", vulkanDevice, queue, glTFLoadingFlags);
|
||||
}
|
||||
|
||||
void buildCommandBuffers()
|
||||
{
|
||||
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
|
||||
|
||||
for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
|
||||
{
|
||||
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
|
||||
|
||||
// With dynamic rendering there are no subpass dependencies, so we need to take care of proper layout transitions by using barriers
|
||||
// This set of barriers prepares the color and depth images for output
|
||||
vks::tools::insertImageMemoryBarrier(
|
||||
drawCmdBuffers[i],
|
||||
renderImage.image,
|
||||
0,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_GENERAL,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
|
||||
vks::tools::insertImageMemoryBarrier(
|
||||
drawCmdBuffers[i],
|
||||
depthStencil.image,
|
||||
0,
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
VkImageSubresourceRange{ VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 0, 1 });
|
||||
|
||||
// New structures are used to define the attachments used in dynamic rendering
|
||||
VkRenderingAttachmentInfoKHR colorAttachment{};
|
||||
colorAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
|
||||
colorAttachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
colorAttachment.clearValue.color = { 0.0f,0.0f,0.0f,0.0f };
|
||||
// When multi sampling is used, we use intermediate images to render and resolve to the swap chain images
|
||||
colorAttachment.imageView = renderImage.view;
|
||||
colorAttachment.resolveMode = VK_RESOLVE_MODE_AVERAGE_BIT;
|
||||
colorAttachment.resolveImageView = swapChain.imageViews[i];
|
||||
colorAttachment.resolveImageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
// A single depth stencil attachment info can be used, but they can also be specified separately.
|
||||
// When both are specified separately, the only requirement is that the image view is identical.
|
||||
VkRenderingAttachmentInfoKHR depthStencilAttachment{};
|
||||
depthStencilAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
|
||||
depthStencilAttachment.imageView = depthStencil.view;
|
||||
depthStencilAttachment.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
depthStencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
depthStencilAttachment.clearValue.depthStencil = { 1.0f, 0 };
|
||||
|
||||
VkRenderingInfoKHR renderingInfo{};
|
||||
renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR;
|
||||
renderingInfo.renderArea = { 0, 0, width, height };
|
||||
renderingInfo.layerCount = 1;
|
||||
renderingInfo.colorAttachmentCount = 1;
|
||||
renderingInfo.pColorAttachments = &colorAttachment;
|
||||
renderingInfo.pDepthAttachment = &depthStencilAttachment;
|
||||
renderingInfo.pStencilAttachment = &depthStencilAttachment;
|
||||
|
||||
// Begin dynamic rendering
|
||||
vkCmdBeginRenderingKHR(drawCmdBuffers[i], &renderingInfo);
|
||||
|
||||
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);
|
||||
|
||||
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
|
||||
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
|
||||
model.draw(drawCmdBuffers[i], vkglTF::RenderFlags::BindImages, pipelineLayout);
|
||||
|
||||
drawUI(drawCmdBuffers[i]);
|
||||
|
||||
// End dynamic rendering
|
||||
vkCmdEndRenderingKHR(drawCmdBuffers[i]);
|
||||
|
||||
// This set of barriers prepares the color image for presentation, we don't need to care for the depth image
|
||||
vks::tools::insertImageMemoryBarrier(
|
||||
drawCmdBuffers[i],
|
||||
swapChain.images[i],
|
||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
0,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||
VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
|
||||
|
||||
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void setupDescriptors()
|
||||
{
|
||||
// Pool
|
||||
std::vector<VkDescriptorPoolSize> poolSizes = {
|
||||
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
|
||||
};
|
||||
VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 1);
|
||||
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool));
|
||||
// Layout
|
||||
const std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = {
|
||||
// Binding 0 : Vertex shader uniform buffer
|
||||
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));
|
||||
// Set
|
||||
VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1);
|
||||
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet));
|
||||
std::vector<VkWriteDescriptorSet> writeDescriptorSets = {
|
||||
// Binding 0 : Vertex shader uniform buffer
|
||||
vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffer.descriptor),
|
||||
};
|
||||
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr);
|
||||
}
|
||||
|
||||
void preparePipelines()
|
||||
{
|
||||
// Layout
|
||||
// Uses set 0 for passing vertex shader ubo and set 1 for fragment shader images (taken from glTF model)
|
||||
const std::vector<VkDescriptorSetLayout> setLayouts = {
|
||||
descriptorSetLayout,
|
||||
vkglTF::descriptorSetLayoutImage,
|
||||
};
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), 2);
|
||||
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
|
||||
|
||||
// Pipeline
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE);
|
||||
VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_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(multiSampleCount, 0);
|
||||
std::vector<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
|
||||
VkPipelineDynamicStateCreateInfo dynamicState = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables);
|
||||
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages{};
|
||||
|
||||
// We no longer need to set a renderpass for the pipeline create info
|
||||
VkGraphicsPipelineCreateInfo pipelineCI = vks::initializers::pipelineCreateInfo();
|
||||
pipelineCI.layout = pipelineLayout;
|
||||
pipelineCI.pInputAssemblyState = &inputAssemblyState;
|
||||
pipelineCI.pRasterizationState = &rasterizationState;
|
||||
pipelineCI.pColorBlendState = &colorBlendState;
|
||||
pipelineCI.pMultisampleState = &multisampleState;
|
||||
pipelineCI.pViewportState = &viewportState;
|
||||
pipelineCI.pDepthStencilState = &depthStencilState;
|
||||
pipelineCI.pDynamicState = &dynamicState;
|
||||
pipelineCI.stageCount = static_cast<uint32_t>(shaderStages.size());
|
||||
pipelineCI.pStages = shaderStages.data();
|
||||
pipelineCI.pVertexInputState = vkglTF::Vertex::getPipelineVertexInputState({ vkglTF::VertexComponent::Position, vkglTF::VertexComponent::Normal, vkglTF::VertexComponent::UV });
|
||||
|
||||
// New create info to define color, depth and stencil attachments at pipeline create time
|
||||
VkPipelineRenderingCreateInfoKHR pipelineRenderingCreateInfo{};
|
||||
pipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR;
|
||||
pipelineRenderingCreateInfo.colorAttachmentCount = 1;
|
||||
pipelineRenderingCreateInfo.pColorAttachmentFormats = &swapChain.colorFormat;
|
||||
pipelineRenderingCreateInfo.depthAttachmentFormat = depthFormat;
|
||||
pipelineRenderingCreateInfo.stencilAttachmentFormat = depthFormat;
|
||||
// Chain into the pipeline creat einfo
|
||||
pipelineCI.pNext = &pipelineRenderingCreateInfo;
|
||||
|
||||
shaderStages[0] = loadShader(getShadersPath() + "dynamicrendering/texture.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
|
||||
shaderStages[1] = loadShader(getShadersPath() + "dynamicrendering/texture.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, 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, &uniformBuffer, sizeof(uniformData), &uniformData));
|
||||
VK_CHECK_RESULT(uniformBuffer.map());
|
||||
updateUniformBuffers();
|
||||
}
|
||||
|
||||
void updateUniformBuffers()
|
||||
{
|
||||
uniformData.projection = camera.matrices.perspective;
|
||||
uniformData.modelView = camera.matrices.view;
|
||||
uniformData.viewPos = camera.viewPos;
|
||||
memcpy(uniformBuffer.mapped, &uniformData, sizeof(uniformData));
|
||||
}
|
||||
|
||||
void prepare()
|
||||
{
|
||||
VulkanExampleBase::prepare();
|
||||
|
||||
// Since we use an extension, we need to expliclity load the function pointers for extension related Vulkan commands
|
||||
vkCmdBeginRenderingKHR = reinterpret_cast<PFN_vkCmdBeginRenderingKHR>(vkGetDeviceProcAddr(device, "vkCmdBeginRenderingKHR"));
|
||||
vkCmdEndRenderingKHR = reinterpret_cast<PFN_vkCmdEndRenderingKHR>(vkGetDeviceProcAddr(device, "vkCmdEndRenderingKHR"));
|
||||
|
||||
loadAssets();
|
||||
prepareUniformBuffers();
|
||||
setupDescriptors();
|
||||
preparePipelines();
|
||||
buildCommandBuffers();
|
||||
prepared = true;
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
VulkanExampleBase::prepareFrame();
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
|
||||
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
|
||||
VulkanExampleBase::submitFrame();
|
||||
}
|
||||
|
||||
virtual void render()
|
||||
{
|
||||
if (!prepared)
|
||||
return;
|
||||
updateUniformBuffers();
|
||||
draw();
|
||||
}
|
||||
};
|
||||
|
||||
VULKAN_EXAMPLE_MAIN()
|
||||
Loading…
Add table
Add a link
Reference in a new issue