Apply consistent code formatting across the repo. Add clang-format and pre-commit hooks.

This commit is contained in:
Rob Armstrong
2025-03-27 10:30:07 -07:00
parent 2cd58fbc9a
commit ceab6e8bcc
782 changed files with 107230 additions and 106548 deletions

View File

@@ -21,7 +21,7 @@ For Linux:
For Linux aarch64(L4T):
-- Install GLFW3 library using "sudo apt-get install libglfw3-dev" this will provide glfw3
-- 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"

View File

@@ -34,4 +34,3 @@ Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-d
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details)

View File

@@ -25,110 +25,114 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "SineWaveSimulation.h"
#include <algorithm>
#include <helper_cuda.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;
#include "SineWaveSimulation.h"
// 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;
}
__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));
: m_heightMap(nullptr)
, m_width(width)
, m_height(height)
{
}
int SineWaveSimulation::initCuda(uint8_t *vkDeviceUUID, size_t UUID_SIZE) {
int current_device = 0;
int device_count = 0;
int devices_prohibited = 0;
void SineWaveSimulation::initCudaLaunchConfig(int device)
{
cudaDeviceProp prop = {};
checkCudaErrors(cudaSetDevice(device));
checkCudaErrors(cudaGetDeviceProperties(&prop, device));
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceCount(&device_count));
// We don't need large block sizes, since there's not much inter-thread
// communication
m_threads = prop.warpSize;
if (device_count == 0) {
fprintf(stderr, "CUDA error: no devices supporting CUDA.\n");
exit(EXIT_FAILURE);
}
// 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;
// Find the GPU which is selected by Vulkan
while (current_device < device_count) {
cudaGetDeviceProperties(&deviceProp, current_device);
// 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));
}
if ((deviceProp.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);
int SineWaveSimulation::initCuda(uint8_t *vkDeviceUUID, size_t UUID_SIZE)
{
int current_device = 0;
int device_count = 0;
int devices_prohibited = 0;
return current_device;
}
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceCount(&device_count));
} else {
devices_prohibited++;
if (device_count == 0) {
fprintf(stderr, "CUDA error: no devices supporting CUDA.\n");
exit(EXIT_FAILURE);
}
current_device++;
}
// Find the GPU which is selected by Vulkan
while (current_device < device_count) {
cudaGetDeviceProperties(&deviceProp, current_device);
if (devices_prohibited == device_count) {
fprintf(stderr,
"CUDA error:"
" No Vulkan-CUDA Interop capable GPU found.\n");
exit(EXIT_FAILURE);
}
if ((deviceProp.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 -1;
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::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");
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");
}

View File

@@ -29,26 +29,28 @@
#ifndef __SINESIM_H__
#define __SINESIM_H__
#include <vector>
#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;
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);
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; }
size_t getWidth() const { return m_width; }
size_t getHeight() const { return m_height; }
};
#endif // __SINESIM_H__
#endif // __SINESIM_H__

File diff suppressed because it is too large Load Diff

View File

@@ -34,8 +34,8 @@
#include <vulkan/vulkan.h>
#ifdef _WIN64
#define NOMINMAX
#include <windows.h>
#include <vulkan/vulkan_win32.h>
#include <windows.h>
#endif /* _WIN64 */
/* remove _VK_TIMELINE_SEMAPHORE to use binary semaphores */
@@ -44,121 +44,122 @@
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();
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;
VkSemaphore m_vkPresentationSemaphore;
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];
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;
VkSemaphore m_vkPresentationSemaphore;
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();
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;
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 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();
void cleanupSwapChain();
void recreateSwapChain();
bool isSuitableDevice(VkPhysicalDevice dev) const;
static void resizeCallback(GLFWwindow* window, int width, int height);
bool isSuitableDevice(VkPhysicalDevice dev) const;
static void resizeCallback(GLFWwindow *window, int width, int height);
};
void readFile(std::istream& s, std::vector<char>& data);
void readFile(std::istream &s, std::vector<char> &data);
#endif /* __VULKANBASEAPP_H__ */

View File

@@ -30,114 +30,155 @@
// 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) {
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];
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) {
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];
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) {
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;
for (i = 0; i < 3; ++i)
r[i] = v[i] * s;
}
static inline float vec3_mul_inner(vec3 const a, vec3 const b) {
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];
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) {
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) {
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) {
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];
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) {
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];
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) {
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];
for (i = 0; i < 4; ++i)
r[i] = a[i] - b[i];
}
static inline void vec4_scale(vec4 r, vec4 v, float s) {
static inline void vec4_scale(vec4 r, vec4 v, float s)
{
int i;
for (i = 0; i < 4; ++i) r[i] = v[i] * s;
for (i = 0; i < 4; ++i)
r[i] = v[i] * s;
}
static inline float vec4_mul_inner(vec4 a, vec4 b) {
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];
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) {
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) {
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) {
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];
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) {
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;
for (j = 0; j < 4; ++j)
M[i][j] = i == j ? 1.f : 0.f;
}
static inline void mat4x4_dup(mat4x4 M, mat4x4 N) {
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];
for (j = 0; j < 4; ++j)
M[i][j] = N[i][j];
}
static inline void mat4x4_row(vec4 r, mat4x4 M, int i) {
static inline void mat4x4_row(vec4 r, mat4x4 M, int i)
{
int k;
for (k = 0; k < 4; ++k) r[k] = M[k][i];
for (k = 0; k < 4; ++k)
r[k] = M[k][i];
}
static inline void mat4x4_col(vec4 r, mat4x4 M, int 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];
for (k = 0; k < 4; ++k)
r[k] = M[i][k];
}
static inline void mat4x4_transpose(mat4x4 M, mat4x4 N) {
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];
for (i = 0; i < 4; ++i)
M[i][j] = N[j][i];
}
static inline void mat4x4_add(mat4x4 M, mat4x4 a, mat4x4 b) {
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]);
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) {
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]);
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) {
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);
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) {
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);
@@ -146,45 +187,54 @@ static inline void mat4x4_scale_aniso(mat4x4 M, mat4x4 a, float x, float y, floa
M[3][i] = a[3][i];
}
}
static inline void mat4x4_mul(mat4x4 M, mat4x4 a, mat4x4 b) {
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];
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) {
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];
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) {
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) {
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;
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) {
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;
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) {
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};
vec3 u = {x, y, z};
if (vec3_len(u) > 1e-4) {
vec3_norm(u, u);
@@ -205,29 +255,34 @@ static inline void mat4x4_rotate(mat4x4 R, mat4x4 M, float x, float y, float z,
T[3][3] = 1.;
mat4x4_mul(R, M, T);
} else {
}
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);
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);
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);
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) {
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];
@@ -267,10 +322,11 @@ static inline void mat4x4_invert(mat4x4 T, mat4x4 M) {
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) {
static inline void mat4x4_orthonormalize(mat4x4 R, mat4x4 M)
{
mat4x4_dup(R, M);
float s = 1.;
vec3 h;
vec3 h;
vec3_norm(R[2], R[2]);
@@ -290,7 +346,8 @@ static inline void mat4x4_orthonormalize(mat4x4 R, mat4x4 M) {
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) {
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;
@@ -305,7 +362,8 @@ static inline void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t,
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) {
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;
@@ -320,7 +378,8 @@ static inline void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, fl
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) {
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));
@@ -345,7 +404,8 @@ static inline void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float
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) {
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: */
@@ -386,20 +446,26 @@ static inline void mat4x4_look_at(mat4x4 m, vec3 eye, vec3 center, vec3 up) {
mat4x4_translate_in_place(m, -eye[0], -eye[1], -eye[2]);
}
typedef float quat[4];
static inline void quat_identity(quat q) {
typedef float quat[4];
static inline void quat_identity(quat q)
{
q[0] = q[1] = q[2] = 0.f;
q[3] = 1.f;
q[3] = 1.f;
}
static inline void quat_add(quat r, quat a, quat b) {
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];
for (i = 0; i < 4; ++i)
r[i] = a[i] + b[i];
}
static inline void quat_sub(quat r, quat a, quat b) {
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];
for (i = 0; i < 4; ++i)
r[i] = a[i] - b[i];
}
static inline void quat_mul(quat r, quat p, quat q) {
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]);
@@ -408,23 +474,30 @@ static inline void quat_mul(quat r, quat p, quat q) {
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) {
static inline void quat_scale(quat r, quat v, float s)
{
int i;
for (i = 0; i < 4; ++i) r[i] = v[i] * s;
for (i = 0; i < 4; ++i)
r[i] = v[i] * s;
}
static inline float quat_inner_product(quat a, quat b) {
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];
int i;
for (i = 0; i < 4; ++i)
p += b[i] * a[i];
return p;
}
static inline void quat_conj(quat r, quat q) {
static inline void quat_conj(quat r, quat q)
{
int i;
for (i = 0; i < 3; ++i) r[i] = -q[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) {
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);
@@ -432,11 +505,12 @@ static inline void quat_mul_vec3(vec3 r, quat q, vec3 v) {
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];
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;
@@ -458,10 +532,11 @@ static inline void mat4x4_from_quat(mat4x4 M, quat q) {
M[2][3] = 0.f;
M[3][0] = M[3][1] = M[3][2] = 0.f;
M[3][3] = 1.f;
M[3][3] = 1.f;
}
static inline void mat4x4o_mul_quat(mat4x4 R, mat4x4 M, quat q) {
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]);
@@ -469,18 +544,20 @@ static inline void mat4x4o_mul_quat(mat4x4 R, mat4x4 M, quat q) {
quat_mul_vec3(R[2], q, M[2]);
R[3][0] = R[3][1] = R[3][2] = 0.f;
R[3][3] = 1.f;
R[3][3] = 1.f;
}
static inline void quat_from_mat4x4(quat q, mat4x4 M) {
static inline void quat_from_mat4x4(quat q, mat4x4 M)
{
float r = 0.f;
int i;
int i;
int perm[] = {0, 1, 2, 0, 1};
int *p = perm;
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;
if (m < r)
continue;
m = r;
p = &perm[i];
}

View File

@@ -25,20 +25,18 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "VulkanBaseApp.h"
#include <iostream>
#include <iomanip>
#include <chrono>
#include <algorithm>
#include "linmath.h"
#include <chrono>
#include <iomanip>
#include <iostream>
#include "SineWaveSimulation.h"
#include <helper_cuda.h>
#include "VulkanBaseApp.h"
#include "helper_cuda.h"
#include "linmath.h"
typedef float vec2[2];
std::string execution_path;
std::string execution_path;
#ifndef NDEBUG
#define ENABLE_VALIDATION (false)
@@ -46,498 +44,483 @@ std::string execution_path;
#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);
class VulkanCudaSineWave : public VulkanBaseApp
{
typedef struct UniformBufferObject_st
{
// 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);
mat4x4 modelViewProj;
} UniformBufferObject;
vkMapMemory(m_device, stagingMemory, 0, stagingSz, 0, &stagingBase);
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;
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;
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!");
}
}
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);
// 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
// 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());
if (m_vkTimelineSemaphore != VK_NULL_HANDLE) {
checkCudaErrors(cudaDestroyExternalSemaphore(m_cudaTimelineSemaphore));
vkDestroySemaphore(m_device, m_vkTimelineSemaphore, nullptr);
}
#endif /* _VK_TIMELINE_SEMAPHORE */
}
void importCudaExternalMemory(void **cudaPtr, cudaExternalMemory_t &cudaMem,
VkDeviceMemory &vkMem, VkDeviceSize size,
VkExternalMemoryHandleTypeFlagBits handleType) {
cudaExternalMemoryHandleDesc externalMemoryHandleDesc = {};
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 (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!");
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);
}
}
externalMemoryHandleDesc.size = size;
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);
externalMemoryHandleDesc.handle.win32.handle = (HANDLE)getMemHandle(vkMem, handleType);
#else
externalMemoryHandleDesc.handle.fd =
(int)(uintptr_t)getMemHandle(vkMem, handleType);
externalMemoryHandleDesc.handle.fd = (int)(uintptr_t)getMemHandle(vkMem, handleType);
#endif
checkCudaErrors(
cudaImportExternalMemory(&cudaMem, &externalMemoryHandleDesc));
checkCudaErrors(cudaImportExternalMemory(&cudaMem, &externalMemoryHandleDesc));
cudaExternalMemoryBufferDesc externalMemBufferDesc = {};
externalMemBufferDesc.offset = 0;
externalMemBufferDesc.size = size;
externalMemBufferDesc.flags = 0;
cudaExternalMemoryBufferDesc externalMemBufferDesc = {};
externalMemBufferDesc.offset = 0;
externalMemBufferDesc.size = size;
externalMemBufferDesc.flags = 0;
checkCudaErrors(cudaExternalMemoryGetMappedBuffer(cudaPtr, cudaMem,
&externalMemBufferDesc));
}
checkCudaErrors(cudaExternalMemoryGetMappedBuffer(cudaPtr, cudaMem, &externalMemBufferDesc));
}
void importCudaExternalSemaphore(
cudaExternalSemaphore_t &cudaSem, VkSemaphore &vkSem,
VkExternalSemaphoreHandleTypeFlagBits handleType) {
cudaExternalSemaphoreHandleDesc externalSemaphoreHandleDesc = {};
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;
}
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;
}
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!");
}
else {
throw std::runtime_error("Unknown handle type requested!");
}
#ifdef _WIN64
externalSemaphoreHandleDesc.handle.win32.handle =
(HANDLE)getSemaphoreHandle(vkSem, handleType);
externalSemaphoreHandleDesc.handle.win32.handle = (HANDLE)getSemaphoreHandle(vkSem, handleType);
#else
externalSemaphoreHandleDesc.handle.fd =
(int)(uintptr_t)getSemaphoreHandle(vkSem, handleType);
externalSemaphoreHandleDesc.handle.fd = (int)(uintptr_t)getSemaphoreHandle(vkSem, handleType);
#endif
externalSemaphoreHandleDesc.flags = 0;
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);
checkCudaErrors(cudaImportExternalSemaphore(&cudaSem, &externalSemaphoreHandleDesc));
}
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]);
}
VkDeviceSize getUniformSize() const { return sizeof(UniformBufferObject); }
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;
}
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};
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);
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);
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);
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;
return extensions;
}
float frame_time =
std::chrono::duration<float, std::chrono::seconds::period>(currentTime -
m_lastTime)
.count();
void drawFrame()
{
static chrono_tp startTime = std::chrono::high_resolution_clock::now();
// Have vulkan draw the current frame...
VulkanBaseApp::drawFrame();
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;
static uint64_t waitValue = 1;
static uint64_t signalValue = 2;
cudaExternalSemaphoreWaitParams waitParams = {};
waitParams.flags = 0;
waitParams.params.fence.value = waitValue;
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));
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;
waitValue += 2;
signalValue += 2;
#else
cudaExternalSemaphoreWaitParams waitParams = {};
waitParams.flags = 0;
waitParams.params.fence.value = 0;
cudaExternalSemaphoreWaitParams waitParams = {};
waitParams.flags = 0;
waitParams.params.fence.value = 0;
cudaExternalSemaphoreSignalParams signalParams = {};
signalParams.flags = 0;
signalParams.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));
// 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;
// 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;
int main(int argc, char **argv)
{
execution_path = argv[0];
VulkanCudaSineWave app((1ULL << 8ULL), (1ULL << 8ULL));
app.init();
app.mainLoop();
return 0;
}