mirror of
https://github.com/NVIDIA/cuda-samples.git
synced 2026-10-25 22:28:17 +08:00
Apply consistent code formatting across the repo. Add clang-format and pre-commit hooks.
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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
@@ -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__ */
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user