mirror of
https://github.com/NVIDIA/cuda-samples.git
synced 2026-10-13 00:08:26 +08:00
CUDA 13.2 samples update (#432)
- Added Python samples for CUDA Python 1.0 release - Renamed top-level `Samples` directory to `cpp` to accommodate Python samples.
This commit is contained in:
18
cpp/5_Domain_Specific/simpleVulkan/.vscode/c_cpp_properties.json
vendored
Normal file
18
cpp/5_Domain_Specific/simpleVulkan/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/../../../Common"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/local/cuda/bin/nvcc",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "gnu++14",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"configurationProvider": "ms-vscode.makefile-tools"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
7
cpp/5_Domain_Specific/simpleVulkan/.vscode/extensions.json
vendored
Normal file
7
cpp/5_Domain_Specific/simpleVulkan/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"nvidia.nsight-vscode-edition",
|
||||
"ms-vscode.cpptools",
|
||||
"ms-vscode.makefile-tools"
|
||||
]
|
||||
}
|
||||
35
cpp/5_Domain_Specific/simpleVulkan/Build_instructions.txt
Normal file
35
cpp/5_Domain_Specific/simpleVulkan/Build_instructions.txt
Normal file
@@ -0,0 +1,35 @@
|
||||
For Windows:
|
||||
Follow these steps once you have installed Vulkan SDK for Windows from https://www.lunarg.com/vulkan-sdk/
|
||||
-- Install GLFW3 library at suitable location
|
||||
-- Open the simpleVulkan VS project file.
|
||||
To add the GLFW3 library path
|
||||
-- Right click on Project name "simpleVulkan" click on "Properties"
|
||||
-- In Property pages window go to Linker -> General. Here in "Additional Libraries Directories" edit and add path to glfw3dll.lib
|
||||
To add the GLFW3 headers path
|
||||
-- Right click on Project name "simpleVulkan" click on "Properties"
|
||||
-- In Property pages window go to "VC++ Directories" section. Here in "Include Directories" edit and add path to GLFW3 headers include directory location.
|
||||
** Make sure to add path to glfw3.dll in your PATH environment variable**
|
||||
|
||||
|
||||
For Linux:
|
||||
-- Install the Vulkan SDK from https://www.lunarg.com/vulkan-sdk/ and follow environment setup instructions.
|
||||
-- Install GLFW3 library through your OS package repository. For example: apt-get for Ubuntu and dnf for RHEL/CentOS. Below is for Ubuntu:
|
||||
sudo apt-get install libglfw3
|
||||
sudo apt-get install libglfw3-dev
|
||||
-- Install "libxcb1-dev" and "xorg-dev" as GLFW3 is depended on it
|
||||
-- Add Vulkan and GLFW3 libraries directories to LD_LIBRARY_PATH
|
||||
|
||||
|
||||
For Linux aarch64(L4T):
|
||||
-- Install GLFW3 library using "sudo apt-get install libglfw3-dev" this will provide glfw3
|
||||
-- install above will also provide libvulkan-dev as dependencies
|
||||
-- Add Vulkan and GLFW3 libraries directories to LD_LIBRARY_PATH
|
||||
-- Pass path to vulkan sdk while building 'make VULKAN_SDK_PATH=<PATH_TO_VULKAN_SDK>', VULKAN_SDK_PATH in this scenario is typically "/usr"
|
||||
|
||||
|
||||
For Shader changes:
|
||||
-- Update the sinewave.vert and/or sinewave.frag shader source file as required
|
||||
-- Use the glslc shader compiler from the installed Vulkan SDK's bin directory to compile shaders as:
|
||||
glslc sinewave.vert -o vert.spv
|
||||
glslc sinewave.frag -o frag.spv
|
||||
** Make sure to add glslc's path in your PATH environment variable **
|
||||
114
cpp/5_Domain_Specific/simpleVulkan/CMakeLists.txt
Normal file
114
cpp/5_Domain_Specific/simpleVulkan/CMakeLists.txt
Normal file
@@ -0,0 +1,114 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
|
||||
|
||||
project(simpleVulkan LANGUAGES C CXX CUDA)
|
||||
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(CMAKE_CUDA_ARCHITECTURES 75 80 86 87 89 90 100 110 120)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
|
||||
if(ENABLE_CUDA_DEBUG)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
|
||||
else()
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
|
||||
endif()
|
||||
|
||||
# Include directories and libraries
|
||||
include_directories(../../../Common)
|
||||
|
||||
find_package(Vulkan)
|
||||
find_package(OpenGL)
|
||||
|
||||
|
||||
# Include the check_include_file macro
|
||||
include(CheckIncludeFile)
|
||||
|
||||
# Check for the GLFW/glfw3.h header
|
||||
check_include_file("GLFW/glfw3.h" HAVE_GLFW3_H)
|
||||
|
||||
# Check for SUSE Linux
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
file(READ "/etc/os-release" OS_RELEASE_CONTENTS)
|
||||
if(OS_RELEASE_CONTENTS MATCHES "ID=[^ ]*suse[^ ]*")
|
||||
message(STATUS "SUSE Linux detected")
|
||||
set(SUSE_LINUX TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Find GLFW header and lib for Windows and SUSE Linux
|
||||
if(WIN32 OR CMAKE_CROSSCOMPILING OR SUSE_LINUX)
|
||||
set(GLFW_INCLUDE_DIRS "${GLFW_INCLUDE_DIR}" "${CMAKE_INCLUDE_PATH}")
|
||||
find_file(GLFW3_H "GLFW/glfw3.h" PATHS ${GLFW_INCLUDE_DIRS})
|
||||
find_library(GLFW3_LIB
|
||||
NAMES glfw3 glfw
|
||||
PATHS "${GLFW_LIB_DIR}"
|
||||
PATH_SUFFIXES lib lib64)
|
||||
if(GLFW3_H AND GLFW3_LIB)
|
||||
message(STATUS "Found GLFW/glfw3.h and GLFW library.")
|
||||
set(HAVE_GLFW3_H 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Source file
|
||||
if(${Vulkan_FOUND})
|
||||
if(${OPENGL_FOUND})
|
||||
if(${HAVE_GLFW3_H})
|
||||
# Add target for simpleVulkan
|
||||
add_executable(simpleVulkan main.cpp SineWaveSimulation.cu VulkanBaseApp.cpp)
|
||||
|
||||
target_compile_options(simpleVulkan PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
|
||||
|
||||
target_compile_features(simpleVulkan PRIVATE cxx_std_17 cuda_std_17)
|
||||
|
||||
set_target_properties(simpleVulkan PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
|
||||
|
||||
target_include_directories(simpleVulkan PUBLIC
|
||||
${Vulkan_INCLUDE_DIRS}
|
||||
${CUDAToolkit_INCLUDE_DIRS}
|
||||
)
|
||||
target_link_libraries(simpleVulkan
|
||||
${Vulkan_LIBRARIES}
|
||||
OpenGL::GL
|
||||
)
|
||||
if(WIN32 OR CMAKE_CROSSCOMPILING OR SUSE_LINUX)
|
||||
target_include_directories(simpleVulkan PUBLIC
|
||||
${GLFW_INCLUDE_DIRS}
|
||||
)
|
||||
target_link_libraries(simpleVulkan
|
||||
${GLFW3_LIB}
|
||||
)
|
||||
else()
|
||||
target_link_libraries(simpleVulkan
|
||||
glfw
|
||||
)
|
||||
endif()
|
||||
# Need to add X11 for SUSE Linux explicitly
|
||||
if(SUSE_LINUX)
|
||||
target_link_libraries(simpleVulkan
|
||||
X11
|
||||
)
|
||||
endif()
|
||||
add_custom_command(TARGET simpleVulkan POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/sinewave.frag
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/sinewave.vert
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vert.spv
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/frag.spv
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
else()
|
||||
message(STATUS "glfw3 not found - will not build sample 'simpleVulkan'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "OpenGL not found - will not build sample 'simpleVulkan'")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Vulkan not found - will not build sample 'simpleVulkan'")
|
||||
endif()
|
||||
|
||||
# Include installation configuration
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
|
||||
setup_samples_install()
|
||||
36
cpp/5_Domain_Specific/simpleVulkan/README.md
Normal file
36
cpp/5_Domain_Specific/simpleVulkan/README.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# simpleVulkan - Vulkan CUDA Interop Sinewave
|
||||
|
||||
## Description
|
||||
|
||||
This sample demonstrates Vulkan CUDA Interop. CUDA imports the Vulkan vertex buffer and operates on it to create sinewave, and synchronizes with Vulkan through vulkan semaphores imported by CUDA. This sample depends on Vulkan SDK, GLFW3 libraries, for building this sample please refer to "Build_instructions.txt" provided in this sample's directory
|
||||
|
||||
## Key Concepts
|
||||
|
||||
Graphics Interop, CUDA Vulkan Interop, Data Parallel Algorithms
|
||||
|
||||
## Supported SM Architectures
|
||||
|
||||
[SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](https://developer.nvidia.com/cuda-gpus) [SM 5.3 ](https://developer.nvidia.com/cuda-gpus) [SM 6.0 ](https://developer.nvidia.com/cuda-gpus) [SM 6.1 ](https://developer.nvidia.com/cuda-gpus) [SM 7.0 ](https://developer.nvidia.com/cuda-gpus) [SM 7.2 ](https://developer.nvidia.com/cuda-gpus) [SM 7.5 ](https://developer.nvidia.com/cuda-gpus) [SM 8.0 ](https://developer.nvidia.com/cuda-gpus) [SM 8.6 ](https://developer.nvidia.com/cuda-gpus) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus)
|
||||
|
||||
## Supported OSes
|
||||
|
||||
Linux, Windows
|
||||
|
||||
## Supported CPU Architecture
|
||||
|
||||
x86_64, aarch64
|
||||
|
||||
## CUDA APIs involved
|
||||
|
||||
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html)
|
||||
cudaStreamCreateWithFlags, cudaExternalMemoryGetMappedBuffer, cudaSignalSemaphore, cudaWaitExternalSemaphoresAsync, cudaVertMem, cudaImportExternalSemaphore, cudaWaitSemaphore, cudaHeightMap, cudaSetDevice, cudaGetDeviceCount, cudaSignalExternalSemaphoresAsync, cudaTimelineSemaphore, cudaStreamSynchronize, cudaDestroyExternalMemory, cudaOccupancyMaxActiveBlocksPerMultiprocessor, cudaImportExternalMemory, cudaGetDeviceProperties, cudaDestroyExternalSemaphore
|
||||
|
||||
## Dependencies needed to build/run
|
||||
[X11](../../../README.md#x11), [VULKAN](../../../README.md#vulkan), [GLFW](../../../README.md#glfw)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
|
||||
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
|
||||
|
||||
## References (for more details)
|
||||
140
cpp/5_Domain_Specific/simpleVulkan/SineWaveSimulation.cu
Normal file
140
cpp/5_Domain_Specific/simpleVulkan/SineWaveSimulation.cu
Normal file
@@ -0,0 +1,140 @@
|
||||
/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <helper_cuda.h>
|
||||
|
||||
#include "SineWaveSimulation.h"
|
||||
|
||||
__global__ void sinewave(float *heightMap, unsigned int width, unsigned int height, float time)
|
||||
{
|
||||
const float freq = 4.0f;
|
||||
const size_t stride = gridDim.x * blockDim.x;
|
||||
|
||||
// Iterate through the entire array in a way that is
|
||||
// independent of the grid configuration
|
||||
for (size_t tid = blockIdx.x * blockDim.x + threadIdx.x; tid < width * height; tid += stride) {
|
||||
// Calculate the x, y coordinates
|
||||
const size_t y = tid / width;
|
||||
const size_t x = tid - y * width;
|
||||
// Normalize x, y to [0,1]
|
||||
const float u = ((2.0f * x) / width) - 1.0f;
|
||||
const float v = ((2.0f * y) / height) - 1.0f;
|
||||
// Calculate the new height value
|
||||
const float w = 0.5f * sinf(u * freq + time) * cosf(v * freq + time);
|
||||
// Store this new height value
|
||||
heightMap[tid] = w;
|
||||
}
|
||||
}
|
||||
|
||||
SineWaveSimulation::SineWaveSimulation(size_t width, size_t height)
|
||||
: m_heightMap(nullptr)
|
||||
, m_width(width)
|
||||
, m_height(height)
|
||||
{
|
||||
}
|
||||
|
||||
void SineWaveSimulation::initCudaLaunchConfig(int device)
|
||||
{
|
||||
cudaDeviceProp prop = {};
|
||||
checkCudaErrors(cudaSetDevice(device));
|
||||
checkCudaErrors(cudaGetDeviceProperties(&prop, device));
|
||||
|
||||
// We don't need large block sizes, since there's not much inter-thread
|
||||
// communication
|
||||
m_threads = prop.warpSize;
|
||||
|
||||
// Use the occupancy calculator and fill the gpu as best as we can
|
||||
checkCudaErrors(cudaOccupancyMaxActiveBlocksPerMultiprocessor(&m_blocks, sinewave, prop.warpSize, 0));
|
||||
m_blocks *= prop.multiProcessorCount;
|
||||
|
||||
// Go ahead and the clamp the blocks to the minimum needed for this
|
||||
// height/width
|
||||
m_blocks = std::min(m_blocks, (int)((m_width * m_height + m_threads - 1) / m_threads));
|
||||
}
|
||||
|
||||
int SineWaveSimulation::initCuda(uint8_t *vkDeviceUUID, size_t UUID_SIZE)
|
||||
{
|
||||
int current_device = 0;
|
||||
int device_count = 0;
|
||||
int devices_prohibited = 0;
|
||||
|
||||
cudaDeviceProp deviceProp;
|
||||
checkCudaErrors(cudaGetDeviceCount(&device_count));
|
||||
|
||||
if (device_count == 0) {
|
||||
fprintf(stderr, "CUDA error: no devices supporting CUDA.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Find the GPU which is selected by Vulkan
|
||||
while (current_device < device_count) {
|
||||
cudaGetDeviceProperties(&deviceProp, current_device);
|
||||
int computeMode;
|
||||
checkCudaErrors(cudaDeviceGetAttribute(&computeMode, cudaDevAttrComputeMode, current_device));
|
||||
|
||||
if ((computeMode != cudaComputeModeProhibited)) {
|
||||
// Compare the cuda device UUID with vulkan UUID
|
||||
int ret = memcmp((void *)&deviceProp.uuid, vkDeviceUUID, UUID_SIZE);
|
||||
if (ret == 0) {
|
||||
checkCudaErrors(cudaSetDevice(current_device));
|
||||
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, current_device));
|
||||
printf("GPU Device %d: \"%s\" with compute capability %d.%d\n\n",
|
||||
current_device,
|
||||
deviceProp.name,
|
||||
deviceProp.major,
|
||||
deviceProp.minor);
|
||||
|
||||
return current_device;
|
||||
}
|
||||
}
|
||||
else {
|
||||
devices_prohibited++;
|
||||
}
|
||||
|
||||
current_device++;
|
||||
}
|
||||
|
||||
if (devices_prohibited == device_count) {
|
||||
fprintf(stderr,
|
||||
"CUDA error:"
|
||||
" No Vulkan-CUDA Interop capable GPU found.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
SineWaveSimulation::~SineWaveSimulation() { m_heightMap = NULL; }
|
||||
|
||||
void SineWaveSimulation::initSimulation(float *heights) { m_heightMap = heights; }
|
||||
|
||||
void SineWaveSimulation::stepSimulation(float time, cudaStream_t stream)
|
||||
{
|
||||
sinewave<<<m_blocks, m_threads, 0, stream>>>(m_heightMap, m_width, m_height, time);
|
||||
getLastCudaError("Failed to launch CUDA simulation");
|
||||
}
|
||||
56
cpp/5_Domain_Specific/simpleVulkan/SineWaveSimulation.h
Normal file
56
cpp/5_Domain_Specific/simpleVulkan/SineWaveSimulation.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef __SINESIM_H__
|
||||
#define __SINESIM_H__
|
||||
|
||||
#include <cuda_runtime_api.h>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
#include "linmath.h"
|
||||
|
||||
class SineWaveSimulation
|
||||
{
|
||||
float *m_heightMap;
|
||||
size_t m_width, m_height;
|
||||
int m_blocks, m_threads;
|
||||
|
||||
public:
|
||||
SineWaveSimulation(size_t width, size_t height);
|
||||
~SineWaveSimulation();
|
||||
void initSimulation(float *heightMap);
|
||||
void stepSimulation(float time, cudaStream_t stream = 0);
|
||||
void initCudaLaunchConfig(int device);
|
||||
int initCuda(uint8_t *vkDeviceUUID, size_t UUID_SIZE);
|
||||
|
||||
size_t getWidth() const { return m_width; }
|
||||
size_t getHeight() const { return m_height; }
|
||||
};
|
||||
|
||||
#endif // __SINESIM_H__
|
||||
1906
cpp/5_Domain_Specific/simpleVulkan/VulkanBaseApp.cpp
Normal file
1906
cpp/5_Domain_Specific/simpleVulkan/VulkanBaseApp.cpp
Normal file
File diff suppressed because it is too large
Load Diff
168
cpp/5_Domain_Specific/simpleVulkan/VulkanBaseApp.h
Normal file
168
cpp/5_Domain_Specific/simpleVulkan/VulkanBaseApp.h
Normal file
@@ -0,0 +1,168 @@
|
||||
/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef __VULKANBASEAPP_H__
|
||||
#define __VULKANBASEAPP_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <vulkan/vulkan.h>
|
||||
#ifdef _WIN64
|
||||
#define NOMINMAX
|
||||
// Add windows.h to the include path
|
||||
#include <windows.h>
|
||||
// Add vulkan_win32.h to the include path
|
||||
#include <vulkan/vulkan_win32.h>
|
||||
#endif /* _WIN64 */
|
||||
|
||||
/* remove _VK_TIMELINE_SEMAPHORE to use binary semaphores */
|
||||
// use vulkan timeline semaphore
|
||||
#define _VK_TIMELINE_SEMAPHORE
|
||||
|
||||
struct GLFWwindow;
|
||||
|
||||
class VulkanBaseApp
|
||||
{
|
||||
public:
|
||||
VulkanBaseApp(const std::string &appName, bool enableValidation = false);
|
||||
static VkExternalSemaphoreHandleTypeFlagBits getDefaultSemaphoreHandleType();
|
||||
static VkExternalMemoryHandleTypeFlagBits getDefaultMemHandleType();
|
||||
virtual ~VulkanBaseApp();
|
||||
void init();
|
||||
void *getMemHandle(VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagBits handleType);
|
||||
void *getSemaphoreHandle(VkSemaphore semaphore, VkExternalSemaphoreHandleTypeFlagBits handleType);
|
||||
void createExternalSemaphore(VkSemaphore &semaphore, VkExternalSemaphoreHandleTypeFlagBits handleType);
|
||||
void createBuffer(VkDeviceSize size,
|
||||
VkBufferUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties,
|
||||
VkBuffer &buffer,
|
||||
VkDeviceMemory &bufferMemory);
|
||||
void createExternalBuffer(VkDeviceSize size,
|
||||
VkBufferUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties,
|
||||
VkExternalMemoryHandleTypeFlagsKHR extMemHandleType,
|
||||
VkBuffer &buffer,
|
||||
VkDeviceMemory &bufferMemory);
|
||||
void importExternalBuffer(void *handle,
|
||||
VkExternalMemoryHandleTypeFlagBits handleType,
|
||||
size_t size,
|
||||
VkBufferUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties,
|
||||
VkBuffer &buffer,
|
||||
VkDeviceMemory &memory);
|
||||
void copyBuffer(VkBuffer dst, VkBuffer src, VkDeviceSize size);
|
||||
VkCommandBuffer beginSingleTimeCommands();
|
||||
void endSingleTimeCommands(VkCommandBuffer commandBuffer);
|
||||
void mainLoop();
|
||||
|
||||
protected:
|
||||
const std::string m_appName;
|
||||
const bool m_enableValidation;
|
||||
VkInstance m_instance;
|
||||
VkDebugUtilsMessengerEXT m_debugMessenger;
|
||||
VkSurfaceKHR m_surface;
|
||||
VkPhysicalDevice m_physicalDevice;
|
||||
VkDevice m_device;
|
||||
VkQueue m_graphicsQueue;
|
||||
VkQueue m_presentQueue;
|
||||
VkSwapchainKHR m_swapChain;
|
||||
std::vector<VkImage> m_swapChainImages;
|
||||
VkFormat m_swapChainFormat;
|
||||
VkExtent2D m_swapChainExtent;
|
||||
std::vector<VkImageView> m_swapChainImageViews;
|
||||
std::vector<std::pair<VkShaderStageFlagBits, std::string>> m_shaderFiles;
|
||||
VkRenderPass m_renderPass;
|
||||
VkPipelineLayout m_pipelineLayout;
|
||||
VkPipeline m_graphicsPipeline;
|
||||
std::vector<VkFramebuffer> m_swapChainFramebuffers;
|
||||
VkCommandPool m_commandPool;
|
||||
std::vector<VkCommandBuffer> m_commandBuffers;
|
||||
std::vector<VkSemaphore> m_imageAvailableSemaphores;
|
||||
std::vector<VkSemaphore> m_renderFinishedSemaphores;
|
||||
std::vector<VkFence> m_inFlightFences;
|
||||
std::vector<VkBuffer> m_uniformBuffers;
|
||||
std::vector<VkDeviceMemory> m_uniformMemory;
|
||||
std::vector<VkSemaphore> m_vkImageAcquiredSemaphores;
|
||||
std::vector<VkSemaphore> m_vkRenderCompleteSemaphores;
|
||||
VkSemaphore m_vkTimelineSemaphore;
|
||||
VkDescriptorSetLayout m_descriptorSetLayout;
|
||||
VkDescriptorPool m_descriptorPool;
|
||||
std::vector<VkDescriptorSet> m_descriptorSets;
|
||||
VkImage m_depthImage;
|
||||
VkDeviceMemory m_depthImageMemory;
|
||||
VkImageView m_depthImageView;
|
||||
size_t m_currentFrame;
|
||||
bool m_framebufferResized;
|
||||
uint8_t m_vkDeviceUUID[VK_UUID_SIZE];
|
||||
|
||||
virtual void initVulkanApp() {}
|
||||
virtual void fillRenderingCommandBuffer(VkCommandBuffer &buffer) {}
|
||||
virtual std::vector<const char *> getRequiredExtensions() const;
|
||||
virtual std::vector<const char *> getRequiredDeviceExtensions() const;
|
||||
virtual void getVertexDescriptions(std::vector<VkVertexInputBindingDescription> &bindingDesc,
|
||||
std::vector<VkVertexInputAttributeDescription> &attribDesc);
|
||||
virtual void getAssemblyStateInfo(VkPipelineInputAssemblyStateCreateInfo &info);
|
||||
virtual void getWaitFrameSemaphores(std::vector<VkSemaphore> &wait,
|
||||
std::vector<VkPipelineStageFlags> &waitStages) const;
|
||||
virtual void getSignalFrameSemaphores(std::vector<VkSemaphore> &signal) const;
|
||||
virtual VkDeviceSize getUniformSize() const;
|
||||
virtual void updateUniformBuffer(uint32_t imageIndex);
|
||||
virtual void drawFrame();
|
||||
|
||||
private:
|
||||
GLFWwindow *m_window;
|
||||
|
||||
void initWindow();
|
||||
void initVulkan();
|
||||
void createInstance();
|
||||
void createSurface();
|
||||
void createDevice();
|
||||
void createSwapChain();
|
||||
void createImageViews();
|
||||
void createRenderPass();
|
||||
void createDescriptorSetLayout();
|
||||
void createGraphicsPipeline();
|
||||
void createFramebuffers();
|
||||
void createCommandPool();
|
||||
void createDepthResources();
|
||||
void createUniformBuffers();
|
||||
void createDescriptorPool();
|
||||
void createDescriptorSets();
|
||||
void createCommandBuffers();
|
||||
void createSyncObjects();
|
||||
|
||||
void cleanupSwapChain();
|
||||
void recreateSwapChain();
|
||||
|
||||
bool isSuitableDevice(VkPhysicalDevice dev) const;
|
||||
static void resizeCallback(GLFWwindow *window, int width, int height);
|
||||
};
|
||||
|
||||
void readFile(std::istream &s, std::vector<char> &data);
|
||||
|
||||
#endif /* __VULKANBASEAPP_H__ */
|
||||
BIN
cpp/5_Domain_Specific/simpleVulkan/frag.spv
Normal file
BIN
cpp/5_Domain_Specific/simpleVulkan/frag.spv
Normal file
Binary file not shown.
579
cpp/5_Domain_Specific/simpleVulkan/linmath.h
Normal file
579
cpp/5_Domain_Specific/simpleVulkan/linmath.h
Normal file
@@ -0,0 +1,579 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
* Copyright (c) 2015-2016 Valve Corporation
|
||||
* Copyright (c) 2015-2016 LunarG, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Relicensed from the WTFPL (http://www.wtfpl.net/faq/).
|
||||
*/
|
||||
|
||||
#ifndef LINMATH_H
|
||||
#define LINMATH_H
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
// Converts degrees to radians.
|
||||
#define degreesToRadians(angleDegrees) (angleDegrees * M_PI / 180.0)
|
||||
|
||||
// Converts radians to degrees.
|
||||
#define radiansToDegrees(angleRadians) (angleRadians * 180.0 / M_PI)
|
||||
|
||||
typedef float vec3[3];
|
||||
static inline void vec3_add(vec3 r, vec3 const a, vec3 const b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 3; ++i)
|
||||
r[i] = a[i] + b[i];
|
||||
}
|
||||
static inline void vec3_sub(vec3 r, vec3 const a, vec3 const b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 3; ++i)
|
||||
r[i] = a[i] - b[i];
|
||||
}
|
||||
static inline void vec3_scale(vec3 r, vec3 const v, float const s)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 3; ++i)
|
||||
r[i] = v[i] * s;
|
||||
}
|
||||
static inline float vec3_mul_inner(vec3 const a, vec3 const b)
|
||||
{
|
||||
float p = 0.f;
|
||||
int i;
|
||||
for (i = 0; i < 3; ++i)
|
||||
p += b[i] * a[i];
|
||||
return p;
|
||||
}
|
||||
static inline void vec3_mul_cross(vec3 r, vec3 const a, vec3 const b)
|
||||
{
|
||||
r[0] = a[1] * b[2] - a[2] * b[1];
|
||||
r[1] = a[2] * b[0] - a[0] * b[2];
|
||||
r[2] = a[0] * b[1] - a[1] * b[0];
|
||||
}
|
||||
static inline float vec3_len(vec3 const v) { return sqrtf(vec3_mul_inner(v, v)); }
|
||||
static inline void vec3_norm(vec3 r, vec3 const v)
|
||||
{
|
||||
float k = 1.f / vec3_len(v);
|
||||
vec3_scale(r, v, k);
|
||||
}
|
||||
static inline void vec3_reflect(vec3 r, vec3 const v, vec3 const n)
|
||||
{
|
||||
float p = 2.f * vec3_mul_inner(v, n);
|
||||
int i;
|
||||
for (i = 0; i < 3; ++i)
|
||||
r[i] = v[i] - p * n[i];
|
||||
}
|
||||
|
||||
typedef float vec4[4];
|
||||
static inline void vec4_add(vec4 r, vec4 const a, vec4 const b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
r[i] = a[i] + b[i];
|
||||
}
|
||||
static inline void vec4_sub(vec4 r, vec4 const a, vec4 const b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
r[i] = a[i] - b[i];
|
||||
}
|
||||
static inline void vec4_scale(vec4 r, vec4 v, float s)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
r[i] = v[i] * s;
|
||||
}
|
||||
static inline float vec4_mul_inner(vec4 a, vec4 b)
|
||||
{
|
||||
float p = 0.f;
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
p += b[i] * a[i];
|
||||
return p;
|
||||
}
|
||||
static inline void vec4_mul_cross(vec4 r, vec4 a, vec4 b)
|
||||
{
|
||||
r[0] = a[1] * b[2] - a[2] * b[1];
|
||||
r[1] = a[2] * b[0] - a[0] * b[2];
|
||||
r[2] = a[0] * b[1] - a[1] * b[0];
|
||||
r[3] = 1.f;
|
||||
}
|
||||
static inline float vec4_len(vec4 v) { return sqrtf(vec4_mul_inner(v, v)); }
|
||||
static inline void vec4_norm(vec4 r, vec4 v)
|
||||
{
|
||||
float k = 1.f / vec4_len(v);
|
||||
vec4_scale(r, v, k);
|
||||
}
|
||||
static inline void vec4_reflect(vec4 r, vec4 v, vec4 n)
|
||||
{
|
||||
float p = 2.f * vec4_mul_inner(v, n);
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
r[i] = v[i] - p * n[i];
|
||||
}
|
||||
|
||||
typedef vec4 mat4x4[4];
|
||||
static inline void mat4x4_identity(mat4x4 M)
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; i < 4; ++i)
|
||||
for (j = 0; j < 4; ++j)
|
||||
M[i][j] = i == j ? 1.f : 0.f;
|
||||
}
|
||||
static inline void mat4x4_dup(mat4x4 M, mat4x4 N)
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; i < 4; ++i)
|
||||
for (j = 0; j < 4; ++j)
|
||||
M[i][j] = N[i][j];
|
||||
}
|
||||
static inline void mat4x4_row(vec4 r, mat4x4 M, int i)
|
||||
{
|
||||
int k;
|
||||
for (k = 0; k < 4; ++k)
|
||||
r[k] = M[k][i];
|
||||
}
|
||||
static inline void mat4x4_col(vec4 r, mat4x4 M, int i)
|
||||
{
|
||||
int k;
|
||||
for (k = 0; k < 4; ++k)
|
||||
r[k] = M[i][k];
|
||||
}
|
||||
static inline void mat4x4_transpose(mat4x4 M, mat4x4 N)
|
||||
{
|
||||
int i, j;
|
||||
for (j = 0; j < 4; ++j)
|
||||
for (i = 0; i < 4; ++i)
|
||||
M[i][j] = N[j][i];
|
||||
}
|
||||
static inline void mat4x4_add(mat4x4 M, mat4x4 a, mat4x4 b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
vec4_add(M[i], a[i], b[i]);
|
||||
}
|
||||
static inline void mat4x4_sub(mat4x4 M, mat4x4 a, mat4x4 b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
vec4_sub(M[i], a[i], b[i]);
|
||||
}
|
||||
static inline void mat4x4_scale(mat4x4 M, mat4x4 a, float k)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
vec4_scale(M[i], a[i], k);
|
||||
}
|
||||
static inline void mat4x4_scale_aniso(mat4x4 M, mat4x4 a, float x, float y, float z)
|
||||
{
|
||||
int i;
|
||||
vec4_scale(M[0], a[0], x);
|
||||
vec4_scale(M[1], a[1], y);
|
||||
vec4_scale(M[2], a[2], z);
|
||||
for (i = 0; i < 4; ++i) {
|
||||
M[3][i] = a[3][i];
|
||||
}
|
||||
}
|
||||
static inline void mat4x4_mul(mat4x4 M, mat4x4 a, mat4x4 b)
|
||||
{
|
||||
int k, r, c;
|
||||
for (c = 0; c < 4; ++c)
|
||||
for (r = 0; r < 4; ++r) {
|
||||
M[c][r] = 0.f;
|
||||
for (k = 0; k < 4; ++k)
|
||||
M[c][r] += a[k][r] * b[c][k];
|
||||
}
|
||||
}
|
||||
static inline void mat4x4_mul_vec4(vec4 r, mat4x4 M, vec4 v)
|
||||
{
|
||||
int i, j;
|
||||
for (j = 0; j < 4; ++j) {
|
||||
r[j] = 0.f;
|
||||
for (i = 0; i < 4; ++i)
|
||||
r[j] += M[i][j] * v[i];
|
||||
}
|
||||
}
|
||||
static inline void mat4x4_translate(mat4x4 T, float x, float y, float z)
|
||||
{
|
||||
mat4x4_identity(T);
|
||||
T[3][0] = x;
|
||||
T[3][1] = y;
|
||||
T[3][2] = z;
|
||||
}
|
||||
static inline void mat4x4_translate_in_place(mat4x4 M, float x, float y, float z)
|
||||
{
|
||||
vec4 t = {x, y, z, 0};
|
||||
vec4 r;
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
mat4x4_row(r, M, i);
|
||||
M[3][i] += vec4_mul_inner(r, t);
|
||||
}
|
||||
}
|
||||
static inline void mat4x4_from_vec3_mul_outer(mat4x4 M, vec3 a, vec3 b)
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; i < 4; ++i)
|
||||
for (j = 0; j < 4; ++j)
|
||||
M[i][j] = i < 3 && j < 3 ? a[i] * b[j] : 0.f;
|
||||
}
|
||||
static inline void mat4x4_rotate(mat4x4 R, mat4x4 M, float x, float y, float z, float angle)
|
||||
{
|
||||
float s = sinf(angle);
|
||||
float c = cosf(angle);
|
||||
vec3 u = {x, y, z};
|
||||
|
||||
if (vec3_len(u) > 1e-4) {
|
||||
vec3_norm(u, u);
|
||||
mat4x4 T;
|
||||
mat4x4_from_vec3_mul_outer(T, u, u);
|
||||
|
||||
mat4x4 S = {{0, u[2], -u[1], 0}, {-u[2], 0, u[0], 0}, {u[1], -u[0], 0, 0}, {0, 0, 0, 0}};
|
||||
mat4x4_scale(S, S, s);
|
||||
|
||||
mat4x4 C;
|
||||
mat4x4_identity(C);
|
||||
mat4x4_sub(C, C, T);
|
||||
|
||||
mat4x4_scale(C, C, c);
|
||||
|
||||
mat4x4_add(T, T, C);
|
||||
mat4x4_add(T, T, S);
|
||||
|
||||
T[3][3] = 1.;
|
||||
mat4x4_mul(R, M, T);
|
||||
}
|
||||
else {
|
||||
mat4x4_dup(R, M);
|
||||
}
|
||||
}
|
||||
static inline void mat4x4_rotate_X(mat4x4 Q, mat4x4 M, float angle)
|
||||
{
|
||||
float s = sinf(angle);
|
||||
float c = cosf(angle);
|
||||
mat4x4 R = {{1.f, 0.f, 0.f, 0.f}, {0.f, c, s, 0.f}, {0.f, -s, c, 0.f}, {0.f, 0.f, 0.f, 1.f}};
|
||||
mat4x4_mul(Q, M, R);
|
||||
}
|
||||
static inline void mat4x4_rotate_Y(mat4x4 Q, mat4x4 M, float angle)
|
||||
{
|
||||
float s = sinf(angle);
|
||||
float c = cosf(angle);
|
||||
mat4x4 R = {{c, 0.f, s, 0.f}, {0.f, 1.f, 0.f, 0.f}, {-s, 0.f, c, 0.f}, {0.f, 0.f, 0.f, 1.f}};
|
||||
mat4x4_mul(Q, M, R);
|
||||
}
|
||||
static inline void mat4x4_rotate_Z(mat4x4 Q, mat4x4 M, float angle)
|
||||
{
|
||||
float s = sinf(angle);
|
||||
float c = cosf(angle);
|
||||
mat4x4 R = {{c, s, 0.f, 0.f}, {-s, c, 0.f, 0.f}, {0.f, 0.f, 1.f, 0.f}, {0.f, 0.f, 0.f, 1.f}};
|
||||
mat4x4_mul(Q, M, R);
|
||||
}
|
||||
static inline void mat4x4_invert(mat4x4 T, mat4x4 M)
|
||||
{
|
||||
float s[6];
|
||||
float c[6];
|
||||
s[0] = M[0][0] * M[1][1] - M[1][0] * M[0][1];
|
||||
s[1] = M[0][0] * M[1][2] - M[1][0] * M[0][2];
|
||||
s[2] = M[0][0] * M[1][3] - M[1][0] * M[0][3];
|
||||
s[3] = M[0][1] * M[1][2] - M[1][1] * M[0][2];
|
||||
s[4] = M[0][1] * M[1][3] - M[1][1] * M[0][3];
|
||||
s[5] = M[0][2] * M[1][3] - M[1][2] * M[0][3];
|
||||
|
||||
c[0] = M[2][0] * M[3][1] - M[3][0] * M[2][1];
|
||||
c[1] = M[2][0] * M[3][2] - M[3][0] * M[2][2];
|
||||
c[2] = M[2][0] * M[3][3] - M[3][0] * M[2][3];
|
||||
c[3] = M[2][1] * M[3][2] - M[3][1] * M[2][2];
|
||||
c[4] = M[2][1] * M[3][3] - M[3][1] * M[2][3];
|
||||
c[5] = M[2][2] * M[3][3] - M[3][2] * M[2][3];
|
||||
|
||||
/* Assumes it is invertible */
|
||||
float idet = 1.0f / (s[0] * c[5] - s[1] * c[4] + s[2] * c[3] + s[3] * c[2] - s[4] * c[1] + s[5] * c[0]);
|
||||
|
||||
T[0][0] = (M[1][1] * c[5] - M[1][2] * c[4] + M[1][3] * c[3]) * idet;
|
||||
T[0][1] = (-M[0][1] * c[5] + M[0][2] * c[4] - M[0][3] * c[3]) * idet;
|
||||
T[0][2] = (M[3][1] * s[5] - M[3][2] * s[4] + M[3][3] * s[3]) * idet;
|
||||
T[0][3] = (-M[2][1] * s[5] + M[2][2] * s[4] - M[2][3] * s[3]) * idet;
|
||||
|
||||
T[1][0] = (-M[1][0] * c[5] + M[1][2] * c[2] - M[1][3] * c[1]) * idet;
|
||||
T[1][1] = (M[0][0] * c[5] - M[0][2] * c[2] + M[0][3] * c[1]) * idet;
|
||||
T[1][2] = (-M[3][0] * s[5] + M[3][2] * s[2] - M[3][3] * s[1]) * idet;
|
||||
T[1][3] = (M[2][0] * s[5] - M[2][2] * s[2] + M[2][3] * s[1]) * idet;
|
||||
|
||||
T[2][0] = (M[1][0] * c[4] - M[1][1] * c[2] + M[1][3] * c[0]) * idet;
|
||||
T[2][1] = (-M[0][0] * c[4] + M[0][1] * c[2] - M[0][3] * c[0]) * idet;
|
||||
T[2][2] = (M[3][0] * s[4] - M[3][1] * s[2] + M[3][3] * s[0]) * idet;
|
||||
T[2][3] = (-M[2][0] * s[4] + M[2][1] * s[2] - M[2][3] * s[0]) * idet;
|
||||
|
||||
T[3][0] = (-M[1][0] * c[3] + M[1][1] * c[1] - M[1][2] * c[0]) * idet;
|
||||
T[3][1] = (M[0][0] * c[3] - M[0][1] * c[1] + M[0][2] * c[0]) * idet;
|
||||
T[3][2] = (-M[3][0] * s[3] + M[3][1] * s[1] - M[3][2] * s[0]) * idet;
|
||||
T[3][3] = (M[2][0] * s[3] - M[2][1] * s[1] + M[2][2] * s[0]) * idet;
|
||||
}
|
||||
static inline void mat4x4_orthonormalize(mat4x4 R, mat4x4 M)
|
||||
{
|
||||
mat4x4_dup(R, M);
|
||||
float s = 1.;
|
||||
vec3 h;
|
||||
|
||||
vec3_norm(R[2], R[2]);
|
||||
|
||||
s = vec3_mul_inner(R[1], R[2]);
|
||||
vec3_scale(h, R[2], s);
|
||||
vec3_sub(R[1], R[1], h);
|
||||
vec3_norm(R[2], R[2]);
|
||||
|
||||
s = vec3_mul_inner(R[1], R[2]);
|
||||
vec3_scale(h, R[2], s);
|
||||
vec3_sub(R[1], R[1], h);
|
||||
vec3_norm(R[1], R[1]);
|
||||
|
||||
s = vec3_mul_inner(R[0], R[1]);
|
||||
vec3_scale(h, R[1], s);
|
||||
vec3_sub(R[0], R[0], h);
|
||||
vec3_norm(R[0], R[0]);
|
||||
}
|
||||
|
||||
static inline void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t, float n, float f)
|
||||
{
|
||||
M[0][0] = 2.f * n / (r - l);
|
||||
M[0][1] = M[0][2] = M[0][3] = 0.f;
|
||||
|
||||
M[1][1] = 2.f * n / (t - b);
|
||||
M[1][0] = M[1][2] = M[1][3] = 0.f;
|
||||
|
||||
M[2][0] = (r + l) / (r - l);
|
||||
M[2][1] = (t + b) / (t - b);
|
||||
M[2][2] = -(f + n) / (f - n);
|
||||
M[2][3] = -1.f;
|
||||
|
||||
M[3][2] = -2.f * (f * n) / (f - n);
|
||||
M[3][0] = M[3][1] = M[3][3] = 0.f;
|
||||
}
|
||||
static inline void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, float n, float f)
|
||||
{
|
||||
M[0][0] = 2.f / (r - l);
|
||||
M[0][1] = M[0][2] = M[0][3] = 0.f;
|
||||
|
||||
M[1][1] = 2.f / (t - b);
|
||||
M[1][0] = M[1][2] = M[1][3] = 0.f;
|
||||
|
||||
M[2][2] = -2.f / (f - n);
|
||||
M[2][0] = M[2][1] = M[2][3] = 0.f;
|
||||
|
||||
M[3][0] = -(r + l) / (r - l);
|
||||
M[3][1] = -(t + b) / (t - b);
|
||||
M[3][2] = -(f + n) / (f - n);
|
||||
M[3][3] = 1.f;
|
||||
}
|
||||
static inline void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float n, float f)
|
||||
{
|
||||
/* NOTE: Degrees are an unhandy unit to work with.
|
||||
* linmath.h uses radians for everything! */
|
||||
float const a = (float)(1.f / tan(y_fov / 2.f));
|
||||
|
||||
m[0][0] = a / aspect;
|
||||
m[0][1] = 0.f;
|
||||
m[0][2] = 0.f;
|
||||
m[0][3] = 0.f;
|
||||
|
||||
m[1][0] = 0.f;
|
||||
m[1][1] = a;
|
||||
m[1][2] = 0.f;
|
||||
m[1][3] = 0.f;
|
||||
|
||||
m[2][0] = 0.f;
|
||||
m[2][1] = 0.f;
|
||||
m[2][2] = -((f + n) / (f - n));
|
||||
m[2][3] = -1.f;
|
||||
|
||||
m[3][0] = 0.f;
|
||||
m[3][1] = 0.f;
|
||||
m[3][2] = -((2.f * f * n) / (f - n));
|
||||
m[3][3] = 0.f;
|
||||
}
|
||||
static inline void mat4x4_look_at(mat4x4 m, vec3 eye, vec3 center, vec3 up)
|
||||
{
|
||||
/* Adapted from Android's OpenGL Matrix.java. */
|
||||
/* See the OpenGL GLUT documentation for gluLookAt for a description */
|
||||
/* of the algorithm. We implement it in a straightforward way: */
|
||||
|
||||
/* TODO: The negation of of can be spared by swapping the order of
|
||||
* operands in the following cross products in the right way. */
|
||||
vec3 f;
|
||||
vec3_sub(f, center, eye);
|
||||
vec3_norm(f, f);
|
||||
|
||||
vec3 s;
|
||||
vec3_mul_cross(s, f, up);
|
||||
vec3_norm(s, s);
|
||||
|
||||
vec3 t;
|
||||
vec3_mul_cross(t, s, f);
|
||||
|
||||
m[0][0] = s[0];
|
||||
m[0][1] = t[0];
|
||||
m[0][2] = -f[0];
|
||||
m[0][3] = 0.f;
|
||||
|
||||
m[1][0] = s[1];
|
||||
m[1][1] = t[1];
|
||||
m[1][2] = -f[1];
|
||||
m[1][3] = 0.f;
|
||||
|
||||
m[2][0] = s[2];
|
||||
m[2][1] = t[2];
|
||||
m[2][2] = -f[2];
|
||||
m[2][3] = 0.f;
|
||||
|
||||
m[3][0] = 0.f;
|
||||
m[3][1] = 0.f;
|
||||
m[3][2] = 0.f;
|
||||
m[3][3] = 1.f;
|
||||
|
||||
mat4x4_translate_in_place(m, -eye[0], -eye[1], -eye[2]);
|
||||
}
|
||||
|
||||
typedef float quat[4];
|
||||
static inline void quat_identity(quat q)
|
||||
{
|
||||
q[0] = q[1] = q[2] = 0.f;
|
||||
q[3] = 1.f;
|
||||
}
|
||||
static inline void quat_add(quat r, quat a, quat b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
r[i] = a[i] + b[i];
|
||||
}
|
||||
static inline void quat_sub(quat r, quat a, quat b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
r[i] = a[i] - b[i];
|
||||
}
|
||||
static inline void quat_mul(quat r, quat p, quat q)
|
||||
{
|
||||
vec3 w;
|
||||
vec3_mul_cross(r, p, q);
|
||||
vec3_scale(w, p, q[3]);
|
||||
vec3_add(r, r, w);
|
||||
vec3_scale(w, q, p[3]);
|
||||
vec3_add(r, r, w);
|
||||
r[3] = p[3] * q[3] - vec3_mul_inner(p, q);
|
||||
}
|
||||
static inline void quat_scale(quat r, quat v, float s)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
r[i] = v[i] * s;
|
||||
}
|
||||
static inline float quat_inner_product(quat a, quat b)
|
||||
{
|
||||
float p = 0.f;
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
p += b[i] * a[i];
|
||||
return p;
|
||||
}
|
||||
static inline void quat_conj(quat r, quat q)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 3; ++i)
|
||||
r[i] = -q[i];
|
||||
r[3] = q[3];
|
||||
}
|
||||
#define quat_norm vec4_norm
|
||||
static inline void quat_mul_vec3(vec3 r, quat q, vec3 v)
|
||||
{
|
||||
quat v_ = {v[0], v[1], v[2], 0.f};
|
||||
|
||||
quat_conj(r, q);
|
||||
quat_norm(r, r);
|
||||
quat_mul(r, v_, r);
|
||||
quat_mul(r, q, r);
|
||||
}
|
||||
static inline void mat4x4_from_quat(mat4x4 M, quat q)
|
||||
{
|
||||
float a = q[3];
|
||||
float b = q[0];
|
||||
float c = q[1];
|
||||
float d = q[2];
|
||||
float a2 = a * a;
|
||||
float b2 = b * b;
|
||||
float c2 = c * c;
|
||||
float d2 = d * d;
|
||||
|
||||
M[0][0] = a2 + b2 - c2 - d2;
|
||||
M[0][1] = 2.f * (b * c + a * d);
|
||||
M[0][2] = 2.f * (b * d - a * c);
|
||||
M[0][3] = 0.f;
|
||||
|
||||
M[1][0] = 2 * (b * c - a * d);
|
||||
M[1][1] = a2 - b2 + c2 - d2;
|
||||
M[1][2] = 2.f * (c * d + a * b);
|
||||
M[1][3] = 0.f;
|
||||
|
||||
M[2][0] = 2.f * (b * d + a * c);
|
||||
M[2][1] = 2.f * (c * d - a * b);
|
||||
M[2][2] = a2 - b2 - c2 + d2;
|
||||
M[2][3] = 0.f;
|
||||
|
||||
M[3][0] = M[3][1] = M[3][2] = 0.f;
|
||||
M[3][3] = 1.f;
|
||||
}
|
||||
|
||||
static inline void mat4x4o_mul_quat(mat4x4 R, mat4x4 M, quat q)
|
||||
{
|
||||
/* XXX: The way this is written only works for othogonal matrices. */
|
||||
/* TODO: Take care of non-orthogonal case. */
|
||||
quat_mul_vec3(R[0], q, M[0]);
|
||||
quat_mul_vec3(R[1], q, M[1]);
|
||||
quat_mul_vec3(R[2], q, M[2]);
|
||||
|
||||
R[3][0] = R[3][1] = R[3][2] = 0.f;
|
||||
R[3][3] = 1.f;
|
||||
}
|
||||
static inline void quat_from_mat4x4(quat q, mat4x4 M)
|
||||
{
|
||||
float r = 0.f;
|
||||
int i;
|
||||
|
||||
int perm[] = {0, 1, 2, 0, 1};
|
||||
int *p = perm;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
float m = M[i][i];
|
||||
if (m < r)
|
||||
continue;
|
||||
m = r;
|
||||
p = &perm[i];
|
||||
}
|
||||
|
||||
r = sqrtf(1.f + M[p[0]][p[0]] - M[p[1]][p[1]] - M[p[2]][p[2]]);
|
||||
|
||||
if (r < 1e-6) {
|
||||
q[0] = 1.f;
|
||||
q[1] = q[2] = q[3] = 0.f;
|
||||
return;
|
||||
}
|
||||
|
||||
q[0] = r / 2.f;
|
||||
q[1] = (M[p[0]][p[1]] - M[p[1]][p[0]]) / (2.f * r);
|
||||
q[2] = (M[p[2]][p[0]] - M[p[0]][p[2]]) / (2.f * r);
|
||||
q[3] = (M[p[2]][p[1]] - M[p[1]][p[2]]) / (2.f * r);
|
||||
}
|
||||
|
||||
#endif
|
||||
526
cpp/5_Domain_Specific/simpleVulkan/main.cpp
Normal file
526
cpp/5_Domain_Specific/simpleVulkan/main.cpp
Normal file
@@ -0,0 +1,526 @@
|
||||
/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
#include "SineWaveSimulation.h"
|
||||
#include "VulkanBaseApp.h"
|
||||
#include "helper_cuda.h"
|
||||
#include "linmath.h"
|
||||
|
||||
typedef float vec2[2];
|
||||
std::string execution_path;
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define ENABLE_VALIDATION (false)
|
||||
#else
|
||||
#define ENABLE_VALIDATION (true)
|
||||
#endif
|
||||
|
||||
class VulkanCudaSineWave : public VulkanBaseApp
|
||||
{
|
||||
typedef struct UniformBufferObject_st
|
||||
{
|
||||
mat4x4 modelViewProj;
|
||||
} UniformBufferObject;
|
||||
|
||||
VkBuffer m_heightBuffer, m_xyBuffer, m_indexBuffer;
|
||||
VkDeviceMemory m_heightMemory, m_xyMemory, m_indexMemory;
|
||||
UniformBufferObject m_ubo;
|
||||
VkSemaphore m_vkWaitSemaphore, m_vkSignalSemaphore;
|
||||
SineWaveSimulation m_sim;
|
||||
cudaStream_t m_stream;
|
||||
cudaExternalSemaphore_t m_cudaWaitSemaphore, m_cudaSignalSemaphore, m_cudaTimelineSemaphore;
|
||||
cudaExternalMemory_t m_cudaVertMem;
|
||||
float *m_cudaHeightMap;
|
||||
using chrono_tp = std::chrono::time_point<std::chrono::high_resolution_clock>;
|
||||
chrono_tp m_lastTime;
|
||||
size_t m_lastFrame;
|
||||
|
||||
public:
|
||||
VulkanCudaSineWave(size_t width, size_t height)
|
||||
: VulkanBaseApp("vulkanCudaSineWave", ENABLE_VALIDATION)
|
||||
, m_heightBuffer(VK_NULL_HANDLE)
|
||||
, m_xyBuffer(VK_NULL_HANDLE)
|
||||
, m_indexBuffer(VK_NULL_HANDLE)
|
||||
, m_heightMemory(VK_NULL_HANDLE)
|
||||
, m_xyMemory(VK_NULL_HANDLE)
|
||||
, m_indexMemory(VK_NULL_HANDLE)
|
||||
, m_ubo()
|
||||
, m_sim(width, height)
|
||||
, m_stream(0)
|
||||
, m_vkWaitSemaphore(VK_NULL_HANDLE)
|
||||
, m_vkSignalSemaphore(VK_NULL_HANDLE)
|
||||
, m_cudaWaitSemaphore()
|
||||
, m_cudaSignalSemaphore()
|
||||
, m_cudaTimelineSemaphore()
|
||||
, m_cudaVertMem()
|
||||
, m_cudaHeightMap(nullptr)
|
||||
, m_lastFrame(0)
|
||||
{
|
||||
// Our index buffer can only index 32-bits of the vertex buffer
|
||||
if ((width * height) > (1ULL << 32ULL)) {
|
||||
throw std::runtime_error("Requested height and width is too large for this sample!");
|
||||
}
|
||||
// Add our compiled vulkan shader files
|
||||
char *vertex_shader_path = sdkFindFilePath("vert.spv", execution_path.c_str());
|
||||
char *fragment_shader_path = sdkFindFilePath("frag.spv", execution_path.c_str());
|
||||
m_shaderFiles.push_back(std::make_pair(VK_SHADER_STAGE_VERTEX_BIT, vertex_shader_path));
|
||||
m_shaderFiles.push_back(std::make_pair(VK_SHADER_STAGE_FRAGMENT_BIT, fragment_shader_path));
|
||||
}
|
||||
~VulkanCudaSineWave()
|
||||
{
|
||||
// Make sure there's no pending work before we start tearing down
|
||||
checkCudaErrors(cudaStreamSynchronize(m_stream));
|
||||
|
||||
#ifdef _VK_TIMELINE_SEMAPHORE
|
||||
if (m_vkTimelineSemaphore != VK_NULL_HANDLE) {
|
||||
checkCudaErrors(cudaDestroyExternalSemaphore(m_cudaTimelineSemaphore));
|
||||
vkDestroySemaphore(m_device, m_vkTimelineSemaphore, nullptr);
|
||||
}
|
||||
#endif /* _VK_TIMELINE_SEMAPHORE */
|
||||
|
||||
if (m_vkSignalSemaphore != VK_NULL_HANDLE) {
|
||||
checkCudaErrors(cudaDestroyExternalSemaphore(m_cudaSignalSemaphore));
|
||||
vkDestroySemaphore(m_device, m_vkSignalSemaphore, nullptr);
|
||||
}
|
||||
if (m_vkWaitSemaphore != VK_NULL_HANDLE) {
|
||||
checkCudaErrors(cudaDestroyExternalSemaphore(m_cudaWaitSemaphore));
|
||||
vkDestroySemaphore(m_device, m_vkWaitSemaphore, nullptr);
|
||||
}
|
||||
|
||||
if (m_xyBuffer != VK_NULL_HANDLE) {
|
||||
vkDestroyBuffer(m_device, m_xyBuffer, nullptr);
|
||||
}
|
||||
if (m_xyMemory != VK_NULL_HANDLE) {
|
||||
vkFreeMemory(m_device, m_xyMemory, nullptr);
|
||||
}
|
||||
|
||||
if (m_heightBuffer != VK_NULL_HANDLE) {
|
||||
vkDestroyBuffer(m_device, m_heightBuffer, nullptr);
|
||||
}
|
||||
if (m_heightMemory != VK_NULL_HANDLE) {
|
||||
vkFreeMemory(m_device, m_heightMemory, nullptr);
|
||||
}
|
||||
if (m_cudaHeightMap) {
|
||||
checkCudaErrors(cudaDestroyExternalMemory(m_cudaVertMem));
|
||||
}
|
||||
|
||||
if (m_indexBuffer != VK_NULL_HANDLE) {
|
||||
vkDestroyBuffer(m_device, m_indexBuffer, nullptr);
|
||||
}
|
||||
if (m_indexMemory != VK_NULL_HANDLE) {
|
||||
vkFreeMemory(m_device, m_indexMemory, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void fillRenderingCommandBuffer(VkCommandBuffer &commandBuffer)
|
||||
{
|
||||
VkBuffer vertexBuffers[] = {m_heightBuffer, m_xyBuffer};
|
||||
VkDeviceSize offsets[] = {0, 0};
|
||||
vkCmdBindVertexBuffers(
|
||||
commandBuffer, 0, sizeof(vertexBuffers) / sizeof(vertexBuffers[0]), vertexBuffers, offsets);
|
||||
vkCmdBindIndexBuffer(commandBuffer, m_indexBuffer, 0, VK_INDEX_TYPE_UINT32);
|
||||
vkCmdDrawIndexed(commandBuffer, (uint32_t)((m_sim.getWidth() - 1) * (m_sim.getHeight() - 1) * 6), 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
void getVertexDescriptions(std::vector<VkVertexInputBindingDescription> &bindingDesc,
|
||||
std::vector<VkVertexInputAttributeDescription> &attribDesc)
|
||||
{
|
||||
bindingDesc.resize(2);
|
||||
attribDesc.resize(2);
|
||||
|
||||
bindingDesc[0].binding = 0;
|
||||
bindingDesc[0].stride = sizeof(float);
|
||||
bindingDesc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
|
||||
bindingDesc[1].binding = 1;
|
||||
bindingDesc[1].stride = sizeof(vec2);
|
||||
bindingDesc[1].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
|
||||
attribDesc[0].binding = 0;
|
||||
attribDesc[0].location = 0;
|
||||
attribDesc[0].format = VK_FORMAT_R32_SFLOAT;
|
||||
attribDesc[0].offset = 0;
|
||||
|
||||
attribDesc[1].binding = 1;
|
||||
attribDesc[1].location = 1;
|
||||
attribDesc[1].format = VK_FORMAT_R32G32_SFLOAT;
|
||||
attribDesc[1].offset = 0;
|
||||
}
|
||||
|
||||
void getAssemblyStateInfo(VkPipelineInputAssemblyStateCreateInfo &info)
|
||||
{
|
||||
info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||
info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
info.primitiveRestartEnable = VK_FALSE;
|
||||
}
|
||||
|
||||
void getWaitFrameSemaphores(std::vector<VkSemaphore> &wait, std::vector<VkPipelineStageFlags> &waitStages) const
|
||||
{
|
||||
if (m_currentFrame != 0) {
|
||||
// Have vulkan wait until cuda is done with the vertex buffer before
|
||||
// rendering, We don't do this on the first frame, as the wait semaphore
|
||||
// hasn't been initialized yet
|
||||
wait.push_back(m_vkWaitSemaphore);
|
||||
// We want to wait until all the pipeline commands are complete before
|
||||
// letting cuda work
|
||||
waitStages.push_back(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
void getSignalFrameSemaphores(std::vector<VkSemaphore> &signal) const
|
||||
{
|
||||
// Add this semaphore for vulkan to signal once the vertex buffer is ready
|
||||
// for cuda to modify
|
||||
signal.push_back(m_vkSignalSemaphore);
|
||||
}
|
||||
|
||||
void initVulkanApp()
|
||||
{
|
||||
int cuda_device = -1;
|
||||
|
||||
// Select cuda device where vulkan is running.
|
||||
cuda_device = m_sim.initCuda(m_vkDeviceUUID, VK_UUID_SIZE);
|
||||
if (cuda_device == -1) {
|
||||
printf("Error: No CUDA-Vulkan interop capable device found\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
m_sim.initCudaLaunchConfig(cuda_device);
|
||||
|
||||
// Create the cuda stream we'll be using
|
||||
checkCudaErrors(cudaStreamCreateWithFlags(&m_stream, cudaStreamNonBlocking));
|
||||
|
||||
const size_t nVerts = m_sim.getWidth() * m_sim.getHeight();
|
||||
const size_t nInds = (m_sim.getWidth() - 1) * (m_sim.getHeight() - 1) * 6;
|
||||
|
||||
// Create the height map cuda will write to
|
||||
createExternalBuffer(nVerts * sizeof(float),
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
getDefaultMemHandleType(),
|
||||
m_heightBuffer,
|
||||
m_heightMemory);
|
||||
|
||||
// Create the vertex buffer that will hold the xy coordinates for the grid
|
||||
createBuffer(nVerts * sizeof(vec2),
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
m_xyBuffer,
|
||||
m_xyMemory);
|
||||
|
||||
// Create the index buffer that references from both buffers above
|
||||
createBuffer(nInds * sizeof(uint32_t),
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
m_indexBuffer,
|
||||
m_indexMemory);
|
||||
|
||||
// Import the height map into cuda and retrieve a device pointer to use
|
||||
importCudaExternalMemory((void **)&m_cudaHeightMap,
|
||||
m_cudaVertMem,
|
||||
m_heightMemory,
|
||||
nVerts * sizeof(*m_cudaHeightMap),
|
||||
getDefaultMemHandleType());
|
||||
// Set the height map to use in the simulation
|
||||
m_sim.initSimulation(m_cudaHeightMap);
|
||||
|
||||
{
|
||||
// Set up the initial values for the vertex buffers with Vulkan
|
||||
void *stagingBase;
|
||||
VkBuffer stagingBuffer;
|
||||
VkDeviceMemory stagingMemory;
|
||||
VkDeviceSize stagingSz = std::max(nVerts * sizeof(vec2), nInds * sizeof(uint32_t));
|
||||
createBuffer(stagingSz,
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||
stagingBuffer,
|
||||
stagingMemory);
|
||||
|
||||
vkMapMemory(m_device, stagingMemory, 0, stagingSz, 0, &stagingBase);
|
||||
|
||||
memset(stagingBase, 0, nVerts * sizeof(float));
|
||||
copyBuffer(m_heightBuffer, stagingBuffer, nVerts * sizeof(float));
|
||||
|
||||
for (size_t y = 0; y < m_sim.getHeight(); y++) {
|
||||
for (size_t x = 0; x < m_sim.getWidth(); x++) {
|
||||
vec2 *stagedVert = (vec2 *)stagingBase;
|
||||
stagedVert[y * m_sim.getWidth() + x][0] = (2.0f * x) / (m_sim.getWidth() - 1) - 1;
|
||||
stagedVert[y * m_sim.getWidth() + x][1] = (2.0f * y) / (m_sim.getHeight() - 1) - 1;
|
||||
}
|
||||
}
|
||||
copyBuffer(m_xyBuffer, stagingBuffer, nVerts * sizeof(vec2));
|
||||
|
||||
{
|
||||
uint32_t *indices = (uint32_t *)stagingBase;
|
||||
for (size_t y = 0; y < m_sim.getHeight() - 1; y++) {
|
||||
for (size_t x = 0; x < m_sim.getWidth() - 1; x++) {
|
||||
indices[0] = (uint32_t)((y + 0) * m_sim.getWidth() + (x + 0));
|
||||
indices[1] = (uint32_t)((y + 1) * m_sim.getWidth() + (x + 0));
|
||||
indices[2] = (uint32_t)((y + 0) * m_sim.getWidth() + (x + 1));
|
||||
indices[3] = (uint32_t)((y + 1) * m_sim.getWidth() + (x + 0));
|
||||
indices[4] = (uint32_t)((y + 1) * m_sim.getWidth() + (x + 1));
|
||||
indices[5] = (uint32_t)((y + 0) * m_sim.getWidth() + (x + 1));
|
||||
indices += 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
copyBuffer(m_indexBuffer, stagingBuffer, nInds * sizeof(uint32_t));
|
||||
|
||||
vkUnmapMemory(m_device, stagingMemory);
|
||||
vkDestroyBuffer(m_device, stagingBuffer, nullptr);
|
||||
vkFreeMemory(m_device, stagingMemory, nullptr);
|
||||
}
|
||||
|
||||
#ifdef _VK_TIMELINE_SEMAPHORE
|
||||
// Create the timeline semaphore to sync cuda and vulkan access to vertex
|
||||
// buffer
|
||||
createExternalSemaphore(m_vkTimelineSemaphore, getDefaultSemaphoreHandleType());
|
||||
// Import the timeline semaphore cuda will use to sync cuda and vulkan
|
||||
// access to vertex buffer
|
||||
importCudaExternalSemaphore(m_cudaTimelineSemaphore, m_vkTimelineSemaphore, getDefaultSemaphoreHandleType());
|
||||
#else
|
||||
// Create the semaphore vulkan will signal when it's done with the vertex
|
||||
// buffer
|
||||
createExternalSemaphore(m_vkSignalSemaphore, getDefaultSemaphoreHandleType());
|
||||
// Create the semaphore vulkan will wait for before using the vertex buffer
|
||||
createExternalSemaphore(m_vkWaitSemaphore, getDefaultSemaphoreHandleType());
|
||||
// Import the semaphore cuda will use -- vulkan's signal will be cuda's wait
|
||||
importCudaExternalSemaphore(m_cudaWaitSemaphore, m_vkSignalSemaphore, getDefaultSemaphoreHandleType());
|
||||
// Import the semaphore cuda will use -- cuda's signal will be vulkan's wait
|
||||
importCudaExternalSemaphore(m_cudaSignalSemaphore, m_vkWaitSemaphore, getDefaultSemaphoreHandleType());
|
||||
#endif /* _VK_TIMELINE_SEMAPHORE */
|
||||
}
|
||||
|
||||
void importCudaExternalMemory(void **cudaPtr,
|
||||
cudaExternalMemory_t &cudaMem,
|
||||
VkDeviceMemory &vkMem,
|
||||
VkDeviceSize size,
|
||||
VkExternalMemoryHandleTypeFlagBits handleType)
|
||||
{
|
||||
cudaExternalMemoryHandleDesc externalMemoryHandleDesc = {};
|
||||
|
||||
if (handleType & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT) {
|
||||
externalMemoryHandleDesc.type = cudaExternalMemoryHandleTypeOpaqueWin32;
|
||||
}
|
||||
else if (handleType & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT) {
|
||||
externalMemoryHandleDesc.type = cudaExternalMemoryHandleTypeOpaqueWin32Kmt;
|
||||
}
|
||||
else if (handleType & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) {
|
||||
externalMemoryHandleDesc.type = cudaExternalMemoryHandleTypeOpaqueFd;
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Unknown handle type requested!");
|
||||
}
|
||||
|
||||
externalMemoryHandleDesc.size = size;
|
||||
|
||||
#ifdef _WIN64
|
||||
externalMemoryHandleDesc.handle.win32.handle = (HANDLE)getMemHandle(vkMem, handleType);
|
||||
#else
|
||||
externalMemoryHandleDesc.handle.fd = (int)(uintptr_t)getMemHandle(vkMem, handleType);
|
||||
#endif
|
||||
|
||||
checkCudaErrors(cudaImportExternalMemory(&cudaMem, &externalMemoryHandleDesc));
|
||||
|
||||
cudaExternalMemoryBufferDesc externalMemBufferDesc = {};
|
||||
externalMemBufferDesc.offset = 0;
|
||||
externalMemBufferDesc.size = size;
|
||||
externalMemBufferDesc.flags = 0;
|
||||
|
||||
checkCudaErrors(cudaExternalMemoryGetMappedBuffer(cudaPtr, cudaMem, &externalMemBufferDesc));
|
||||
}
|
||||
|
||||
void importCudaExternalSemaphore(cudaExternalSemaphore_t &cudaSem,
|
||||
VkSemaphore &vkSem,
|
||||
VkExternalSemaphoreHandleTypeFlagBits handleType)
|
||||
{
|
||||
cudaExternalSemaphoreHandleDesc externalSemaphoreHandleDesc = {};
|
||||
|
||||
#ifdef _VK_TIMELINE_SEMAPHORE
|
||||
if (handleType & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT) {
|
||||
externalSemaphoreHandleDesc.type = cudaExternalSemaphoreHandleTypeTimelineSemaphoreWin32;
|
||||
}
|
||||
else if (handleType & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT) {
|
||||
externalSemaphoreHandleDesc.type = cudaExternalSemaphoreHandleTypeTimelineSemaphoreWin32;
|
||||
}
|
||||
else if (handleType & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) {
|
||||
externalSemaphoreHandleDesc.type = cudaExternalSemaphoreHandleTypeTimelineSemaphoreFd;
|
||||
}
|
||||
#else
|
||||
if (handleType & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT) {
|
||||
externalSemaphoreHandleDesc.type = cudaExternalSemaphoreHandleTypeOpaqueWin32;
|
||||
}
|
||||
else if (handleType & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT) {
|
||||
externalSemaphoreHandleDesc.type = cudaExternalSemaphoreHandleTypeOpaqueWin32Kmt;
|
||||
}
|
||||
else if (handleType & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) {
|
||||
externalSemaphoreHandleDesc.type = cudaExternalSemaphoreHandleTypeOpaqueFd;
|
||||
}
|
||||
#endif /* _VK_TIMELINE_SEMAPHORE */
|
||||
else {
|
||||
throw std::runtime_error("Unknown handle type requested!");
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
externalSemaphoreHandleDesc.handle.win32.handle = (HANDLE)getSemaphoreHandle(vkSem, handleType);
|
||||
#else
|
||||
externalSemaphoreHandleDesc.handle.fd = (int)(uintptr_t)getSemaphoreHandle(vkSem, handleType);
|
||||
#endif
|
||||
|
||||
externalSemaphoreHandleDesc.flags = 0;
|
||||
|
||||
checkCudaErrors(cudaImportExternalSemaphore(&cudaSem, &externalSemaphoreHandleDesc));
|
||||
}
|
||||
|
||||
VkDeviceSize getUniformSize() const { return sizeof(UniformBufferObject); }
|
||||
|
||||
void updateUniformBuffer(uint32_t imageIndex)
|
||||
{
|
||||
{
|
||||
mat4x4 view, proj;
|
||||
vec3 eye = {1.75f, 1.75f, 1.25f};
|
||||
vec3 center = {0.0f, 0.0f, -0.25f};
|
||||
vec3 up = {0.0f, 0.0f, 1.0f};
|
||||
|
||||
mat4x4_perspective(proj,
|
||||
(float)degreesToRadians(45.0f),
|
||||
m_swapChainExtent.width / (float)m_swapChainExtent.height,
|
||||
0.1f,
|
||||
10.0f);
|
||||
proj[1][1] *= -1.0f; // Flip y axis
|
||||
|
||||
mat4x4_look_at(view, eye, center, up);
|
||||
mat4x4_mul(m_ubo.modelViewProj, proj, view);
|
||||
}
|
||||
|
||||
void *data;
|
||||
vkMapMemory(m_device, m_uniformMemory[imageIndex], 0, getUniformSize(), 0, &data);
|
||||
memcpy(data, &m_ubo, sizeof(m_ubo));
|
||||
vkUnmapMemory(m_device, m_uniformMemory[imageIndex]);
|
||||
}
|
||||
|
||||
std::vector<const char *> getRequiredExtensions() const
|
||||
{
|
||||
std::vector<const char *> extensions;
|
||||
extensions.push_back(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME);
|
||||
extensions.push_back(VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME);
|
||||
return extensions;
|
||||
}
|
||||
|
||||
std::vector<const char *> getRequiredDeviceExtensions() const
|
||||
{
|
||||
std::vector<const char *> extensions;
|
||||
extensions.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME);
|
||||
extensions.push_back(VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME);
|
||||
extensions.push_back(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME);
|
||||
#ifdef _WIN64
|
||||
extensions.push_back(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
|
||||
extensions.push_back(VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME);
|
||||
#else
|
||||
extensions.push_back(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
|
||||
extensions.push_back(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME);
|
||||
#endif /* _WIN64 */
|
||||
return extensions;
|
||||
}
|
||||
|
||||
void drawFrame()
|
||||
{
|
||||
static chrono_tp startTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
chrono_tp currentTime = std::chrono::high_resolution_clock::now();
|
||||
float time = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - startTime).count();
|
||||
|
||||
if (m_currentFrame == 0) {
|
||||
m_lastTime = startTime;
|
||||
}
|
||||
|
||||
float frame_time = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - m_lastTime).count();
|
||||
|
||||
// Have vulkan draw the current frame...
|
||||
VulkanBaseApp::drawFrame();
|
||||
|
||||
#ifdef _VK_TIMELINE_SEMAPHORE
|
||||
static uint64_t waitValue = 1;
|
||||
static uint64_t signalValue = 2;
|
||||
|
||||
cudaExternalSemaphoreWaitParams waitParams = {};
|
||||
waitParams.flags = 0;
|
||||
waitParams.params.fence.value = waitValue;
|
||||
|
||||
cudaExternalSemaphoreSignalParams signalParams = {};
|
||||
signalParams.flags = 0;
|
||||
signalParams.params.fence.value = signalValue;
|
||||
// Wait for vulkan to complete it's work
|
||||
checkCudaErrors(cudaWaitExternalSemaphoresAsync(&m_cudaTimelineSemaphore, &waitParams, 1, m_stream));
|
||||
// Now step the simulation
|
||||
m_sim.stepSimulation(time, m_stream);
|
||||
// Signal vulkan to continue with the updated buffers
|
||||
checkCudaErrors(cudaSignalExternalSemaphoresAsync(&m_cudaTimelineSemaphore, &signalParams, 1, m_stream));
|
||||
|
||||
waitValue += 2;
|
||||
signalValue += 2;
|
||||
#else
|
||||
cudaExternalSemaphoreWaitParams waitParams = {};
|
||||
waitParams.flags = 0;
|
||||
waitParams.params.fence.value = 0;
|
||||
|
||||
cudaExternalSemaphoreSignalParams signalParams = {};
|
||||
signalParams.flags = 0;
|
||||
signalParams.params.fence.value = 0;
|
||||
|
||||
// Wait for vulkan to complete it's work
|
||||
checkCudaErrors(cudaWaitExternalSemaphoresAsync(&m_cudaWaitSemaphore, &waitParams, 1, m_stream));
|
||||
// Now step the simulation
|
||||
m_sim.stepSimulation(time, m_stream);
|
||||
// Signal vulkan to continue with the updated buffers
|
||||
checkCudaErrors(cudaSignalExternalSemaphoresAsync(&m_cudaSignalSemaphore, &signalParams, 1, m_stream));
|
||||
#endif /* _VK_TIMELINE_SEMAPHORE */
|
||||
|
||||
// Output a naive measurement of the frames per second every five seconds
|
||||
if (frame_time > 5) {
|
||||
std::cout << "Average FPS (over " << std::fixed << std::setprecision(2) << frame_time
|
||||
<< " seconds): " << std::fixed << std::setprecision(2)
|
||||
<< ((m_currentFrame - m_lastFrame) / frame_time) << std::endl;
|
||||
m_lastFrame = m_currentFrame;
|
||||
m_lastTime = currentTime;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
execution_path = argv[0];
|
||||
VulkanCudaSineWave app((1ULL << 8ULL), (1ULL << 8ULL));
|
||||
app.init();
|
||||
app.mainLoop();
|
||||
return 0;
|
||||
}
|
||||
38
cpp/5_Domain_Specific/simpleVulkan/sinewave.frag
Normal file
38
cpp/5_Domain_Specific/simpleVulkan/sinewave.frag
Normal file
@@ -0,0 +1,38 @@
|
||||
/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#version 450
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
|
||||
layout(location = 0) in vec3 fragColor;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
outColor = vec4(fragColor, 1.0);
|
||||
}
|
||||
43
cpp/5_Domain_Specific/simpleVulkan/sinewave.vert
Normal file
43
cpp/5_Domain_Specific/simpleVulkan/sinewave.vert
Normal file
@@ -0,0 +1,43 @@
|
||||
/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#version 450
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
|
||||
layout(binding = 0) uniform UniformBufferObject {
|
||||
mat4 modelViewProj;
|
||||
} ubo;
|
||||
|
||||
layout(location = 0) in float height;
|
||||
layout(location = 1) in vec2 xyPos;
|
||||
|
||||
layout(location = 0) out vec3 fragColor;
|
||||
|
||||
void main() {
|
||||
gl_Position = ubo.modelViewProj * vec4(xyPos.xy, height, 1.0f);
|
||||
fragColor = vec3(0.0f, (height + 0.5f), 0.0f);
|
||||
}
|
||||
BIN
cpp/5_Domain_Specific/simpleVulkan/vert.spv
Normal file
BIN
cpp/5_Domain_Specific/simpleVulkan/vert.spv
Normal file
Binary file not shown.
Reference in New Issue
Block a user