diff --git a/Samples/simpleVulkan/Build_instructions.txt b/Samples/simpleVulkan/Build_instructions.txt index 7e4e5a2f..dc71e3d4 100644 --- a/Samples/simpleVulkan/Build_instructions.txt +++ b/Samples/simpleVulkan/Build_instructions.txt @@ -19,8 +19,17 @@ For Linux: -- Install "libxcb1-dev" and "xorg-dev" as GLFW3 is depended on it -- Add Vulkan and GLFW3 libraries directories to LD_LIBRARY_PATH + For Linux aarch64(L4T): -- Install GLFW3 library using "sudo apt-get install libglfw3-dev" this will provide glfw3 -- install above will also provide libvulkan-dev as dependencies -- Add Vulkan and GLFW3 libraries directories to LD_LIBRARY_PATH --- Pass path to vulkan sdk while building 'make VULKAN_SDK_PATH=', VULKAN_SDK_PATH in this scenario is typically "/usr" \ No newline at end of file +-- Pass path to vulkan sdk while building 'make VULKAN_SDK_PATH=', VULKAN_SDK_PATH in this scenario is typically "/usr" + + +For Shader changes: +-- Update the sinewave.vert and/or sinewave.frag shader source file as required +-- Use the glslc shader compiler from the installed Vulkan SDK's bin directory to compile shaders as: + glslc sinewave.vert -o vert.spv + glslc sinewave.frag -o frag.spv +** Make sure to add glslc's path in your PATH environment variable ** diff --git a/Samples/simpleVulkan/frag.spv b/Samples/simpleVulkan/frag.spv new file mode 100644 index 00000000..cb13e606 Binary files /dev/null and b/Samples/simpleVulkan/frag.spv differ diff --git a/Samples/simpleVulkan/main.cpp b/Samples/simpleVulkan/main.cpp index 3277cb7b..117d16c7 100644 --- a/Samples/simpleVulkan/main.cpp +++ b/Samples/simpleVulkan/main.cpp @@ -92,9 +92,9 @@ class VulkanCudaSineWave : public VulkanBaseApp { } // Add our compiled vulkan shader files char *vertex_shader_path = - sdkFindFilePath("sinewave.vert", execution_path.c_str()); + sdkFindFilePath("vert.spv", execution_path.c_str()); char *fragment_shader_path = - sdkFindFilePath("sinewave.frag", execution_path.c_str()); + 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( diff --git a/Samples/simpleVulkan/vert.spv b/Samples/simpleVulkan/vert.spv new file mode 100644 index 00000000..58454bf4 Binary files /dev/null and b/Samples/simpleVulkan/vert.spv differ diff --git a/Samples/simpleVulkanMMAP/Build_instructions.txt b/Samples/simpleVulkanMMAP/Build_instructions.txt new file mode 100644 index 00000000..a6c2df23 --- /dev/null +++ b/Samples/simpleVulkanMMAP/Build_instructions.txt @@ -0,0 +1,35 @@ +For Windows: +Follow these steps once you have installed Vulkan SDK for Windows from https://www.lunarg.com/vulkan-sdk/ +-- Install GLFW3 library at suitable location +-- Open the simpleVulkan VS project file. +To add the GLFW3 library path +-- Right click on Project name "simpleVulkan" click on "Properties" +-- In Property pages window go to Linker -> General. Here in "Additional Libraries Directories" edit and add path to glfw3dll.lib +To add the GLFW3 headers path +-- Right click on Project name "simpleVulkan" click on "Properties" +-- In Property pages window go to "VC++ Directories" section. Here in "Include Directories" edit and add path to GLFW3 headers include directory location. +** Make sure to add path to glfw3.dll in your PATH environment variable** + + +For Linux: +-- Install the Vulkan SDK from https://www.lunarg.com/vulkan-sdk/ and follow environment setup instructions. +-- Install GLFW3 library through your OS package repository. For example: apt-get for Ubuntu and dnf for RHEL/CentOS. Below is for Ubuntu: + sudo apt-get install libglfw3 + sudo apt-get install libglfw3-dev +-- Install "libxcb1-dev" and "xorg-dev" as GLFW3 is depended on it +-- Add Vulkan and GLFW3 libraries directories to LD_LIBRARY_PATH + + +For Linux aarch64(L4T): +-- Install GLFW3 library using "sudo apt-get install libglfw3-dev" this will provide glfw3 +-- install above will also provide libvulkan-dev as dependencies +-- Add Vulkan and GLFW3 libraries directories to LD_LIBRARY_PATH +-- Pass path to vulkan sdk while building 'make VULKAN_SDK_PATH=', VULKAN_SDK_PATH in this scenario is typically "/usr" + + +For Shader changes: +-- Update the montecarlo.vert and/or montecarlo.frag shader source file as required +-- Use the glslc shader compiler from the installed Vulkan SDK's bin directory to compile shaders as: + glslc montecarlo.vert -o vert.spv + glslc montecarlo.frag -o frag.spv +** Make sure to add glslc's path in your PATH environment variable ** diff --git a/Samples/simpleVulkanMMAP/MonteCarloPi.cu b/Samples/simpleVulkanMMAP/MonteCarloPi.cu index bb275cf2..08ebdb24 100644 --- a/Samples/simpleVulkanMMAP/MonteCarloPi.cu +++ b/Samples/simpleVulkanMMAP/MonteCarloPi.cu @@ -25,9 +25,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - /* - * See: https://www.piday.org/million/ - */ +/* + * See: https://www.piday.org/million/ + */ #include "MonteCarloPi.h" #include @@ -37,15 +37,16 @@ #define ROUND_UP_TO_GRANULARITY(x, n) (((x + n - 1) / n) * n) - // `ipcHandleTypeFlag` specifies the platform specific handle type this sample - // uses for importing and exporting memory allocation. On Linux this sample - // specifies the type as CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR meaning that - // file descriptors will be used. On Windows this sample specifies the type as - // CU_MEM_HANDLE_TYPE_WIN32 meaning that NT HANDLEs will be used. The - // ipcHandleTypeFlag variable is a convenience variable and is passed by value - // to individual requests. +// `ipcHandleTypeFlag` specifies the platform specific handle type this sample +// uses for importing and exporting memory allocation. On Linux this sample +// specifies the type as CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR meaning that +// file descriptors will be used. On Windows this sample specifies the type as +// CU_MEM_HANDLE_TYPE_WIN32 meaning that NT HANDLEs will be used. The +// ipcHandleTypeFlag variable is a convenience variable and is passed by value +// to individual requests. #if defined(__linux__) -CUmemAllocationHandleType ipcHandleTypeFlag = CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR; +CUmemAllocationHandleType ipcHandleTypeFlag = + CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR; #else CUmemAllocationHandleType ipcHandleTypeFlag = CU_MEM_HANDLE_TYPE_WIN32; #endif @@ -53,223 +54,248 @@ CUmemAllocationHandleType ipcHandleTypeFlag = CU_MEM_HANDLE_TYPE_WIN32; // Windows-specific LPSECURITYATTRIBUTES void getDefaultSecurityDescriptor(CUmemAllocationProp *prop) { #if defined(__linux__) - return; + return; #elif defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) - static const char sddl[] = "D:P(OA;;GARCSDWDWOCCDCLCSWLODTWPRPCRFA;;;WD)"; - static OBJECT_ATTRIBUTES objAttributes; - static bool objAttributesConfigured = false; + static const char sddl[] = "D:P(OA;;GARCSDWDWOCCDCLCSWLODTWPRPCRFA;;;WD)"; + static OBJECT_ATTRIBUTES objAttributes; + static bool objAttributesConfigured = false; - if (!objAttributesConfigured) { - PSECURITY_DESCRIPTOR secDesc; - BOOL result = ConvertStringSecurityDescriptorToSecurityDescriptorA( - sddl, SDDL_REVISION_1, &secDesc, NULL); - if (result == 0) { - printf("IPC failure: getDefaultSecurityDescriptor Failed! (%d)\n", - GetLastError()); - } - - InitializeObjectAttributes(&objAttributes, NULL, 0, NULL, secDesc); - - objAttributesConfigured = true; + if (!objAttributesConfigured) { + PSECURITY_DESCRIPTOR secDesc; + BOOL result = ConvertStringSecurityDescriptorToSecurityDescriptorA( + sddl, SDDL_REVISION_1, &secDesc, NULL); + if (result == 0) { + printf("IPC failure: getDefaultSecurityDescriptor Failed! (%d)\n", + GetLastError()); } - prop->win32HandleMetaData = &objAttributes; - return; + InitializeObjectAttributes(&objAttributes, NULL, 0, NULL, secDesc); + + objAttributesConfigured = true; + } + + prop->win32HandleMetaData = &objAttributes; + return; #endif } -__global__ void monte_carlo_kernel(vec2 *xyVector, float *pointsInsideCircle, float *numPointsInCircle, unsigned int numPoints, float time) -{ - const size_t stride = gridDim.x * blockDim.x; - size_t tid = blockIdx.x * blockDim.x + threadIdx.x; - float count = 0.0f; +__global__ void monte_carlo_kernel(vec2 *xyVector, float *pointsInsideCircle, + float *numPointsInCircle, + unsigned int numPoints, float time) { + const size_t stride = gridDim.x * blockDim.x; + size_t tid = blockIdx.x * blockDim.x + threadIdx.x; + float count = 0.0f; - curandState rgnState; - curand_init((unsigned long long)time, tid, 0, &rgnState); + curandState rgnState; + curand_init((unsigned long long)time, tid, 0, &rgnState); - for (; tid < numPoints; tid += stride) { - float x = curand_uniform(&rgnState); - float y = curand_uniform(&rgnState); - x = (2.0f * x) - 1.0f; - y = (2.0f * y) - 1.0f; - xyVector[tid][0] = x; - xyVector[tid][1] = y; + for (; tid < numPoints; tid += stride) { + float x = curand_uniform(&rgnState); + float y = curand_uniform(&rgnState); + x = (2.0f * x) - 1.0f; + y = (2.0f * y) - 1.0f; + xyVector[tid][0] = x; + xyVector[tid][1] = y; - // Compute the distance of this point form the center(0, 0) - float dist = sqrtf((x*x) + (y*y)); + // Compute the distance of this point form the center(0, 0) + float dist = sqrtf((x * x) + (y * y)); - // If distance is less than the radius of the unit circle, the point lies in the circle. - pointsInsideCircle[tid] = (dist <= 1.0f); - count += (dist <= 1.0f); - } - atomicAdd(numPointsInCircle, count); + // If distance is less than the radius of the unit circle, the point lies in + // the circle. + pointsInsideCircle[tid] = (dist <= 1.0f); + count += (dist <= 1.0f); + } + atomicAdd(numPointsInCircle, count); } -MonteCarloPiSimulation::MonteCarloPiSimulation(size_t num_points) : - m_xyVector(nullptr), - m_pointsInsideCircle(nullptr), - m_totalPointsInsideCircle(0), - m_totalPointsSimulated(0), - m_numPoints(num_points) -{ +MonteCarloPiSimulation::MonteCarloPiSimulation(size_t num_points) + : m_xyVector(nullptr), + m_pointsInsideCircle(nullptr), + m_totalPointsInsideCircle(0), + m_totalPointsSimulated(0), + m_numPoints(num_points) {} + +MonteCarloPiSimulation::~MonteCarloPiSimulation() { + if (m_numPointsInCircle) { + checkCudaErrors(cudaFree(m_numPointsInCircle)); + m_numPointsInCircle = nullptr; + } + if (m_hostNumPointsInCircle) { + checkCudaErrors(cudaFreeHost(m_hostNumPointsInCircle)); + m_hostNumPointsInCircle = nullptr; + } + + cleanupSimulationAllocations(); } -MonteCarloPiSimulation::~MonteCarloPiSimulation() -{ - if (m_numPointsInCircle) { - checkCudaErrors(cudaFree(m_numPointsInCircle)); - m_numPointsInCircle = nullptr; - } - if (m_hostNumPointsInCircle) { - checkCudaErrors(cudaFreeHost(m_hostNumPointsInCircle)); - m_hostNumPointsInCircle = nullptr; - } +void MonteCarloPiSimulation::initSimulation(int cudaDevice, + cudaStream_t stream) { + m_cudaDevice = cudaDevice; + getIdealExecutionConfiguration(); - cleanupSimulationAllocations(); + // Allocate a position buffer that contains random location of the points in + // XY cartesian plane. + // Allocate a bitmap buffer which holds information of whether a point in the + // position buffer is inside the unit circle or not. + setupSimulationAllocations(); + + checkCudaErrors( + cudaMalloc((float **)&m_numPointsInCircle, sizeof(*m_numPointsInCircle))); + checkCudaErrors(cudaMallocHost((float **)&m_hostNumPointsInCircle, + sizeof(*m_hostNumPointsInCircle))); } -void MonteCarloPiSimulation::initSimulation(int cudaDevice, cudaStream_t stream) -{ - m_cudaDevice = cudaDevice; - getIdealExecutionConfiguration(); +void MonteCarloPiSimulation::stepSimulation(float time, cudaStream_t stream) { + checkCudaErrors(cudaMemsetAsync(m_numPointsInCircle, 0, + sizeof(*m_numPointsInCircle), stream)); - // Allocate a position buffer that contains random location of the points in XY cartesian plane. - // Allocate a bitmap buffer which holds information of whether a point in the position buffer is inside the unit circle or not. - setupSimulationAllocations(); + monte_carlo_kernel<<>>( + m_xyVector, m_pointsInsideCircle, m_numPointsInCircle, m_numPoints, time); + getLastCudaError("Failed to launch CUDA simulation"); - checkCudaErrors(cudaMalloc((float **)&m_numPointsInCircle, sizeof(*m_numPointsInCircle))); - checkCudaErrors(cudaMallocHost((float **)&m_hostNumPointsInCircle, sizeof(*m_hostNumPointsInCircle))); + checkCudaErrors(cudaMemcpyAsync(m_hostNumPointsInCircle, m_numPointsInCircle, + sizeof(*m_numPointsInCircle), + cudaMemcpyDeviceToHost, stream)); + + // Queue up a stream callback to compute and print the PI value. + checkCudaErrors( + cudaLaunchHostFunc(stream, this->computePiCallback, (void *)this)); } -void MonteCarloPiSimulation::stepSimulation(float time, cudaStream_t stream) -{ - - checkCudaErrors(cudaMemsetAsync(m_numPointsInCircle, 0, sizeof(*m_numPointsInCircle), stream)); - - monte_carlo_kernel << < m_blocks, m_threads, 0, stream >> > (m_xyVector, m_pointsInsideCircle, m_numPointsInCircle, m_numPoints, time); - getLastCudaError("Failed to launch CUDA simulation"); - - checkCudaErrors(cudaMemcpyAsync(m_hostNumPointsInCircle, m_numPointsInCircle, sizeof(*m_numPointsInCircle), cudaMemcpyDeviceToHost, stream)); - - // Queue up a stream callback to compute and print the PI value. - checkCudaErrors(cudaLaunchHostFunc(stream, this->computePiCallback, (void *)this)); +void MonteCarloPiSimulation::computePiCallback(void *args) { + MonteCarloPiSimulation *cbData = (MonteCarloPiSimulation *)args; + cbData->m_totalPointsInsideCircle += *(cbData->m_hostNumPointsInCircle); + cbData->m_totalPointsSimulated += cbData->m_numPoints; + double piValue = 4.0 * ((double)cbData->m_totalPointsInsideCircle / + (double)cbData->m_totalPointsSimulated); + printf("Approximate Pi value for %zd data points: %lf \n", + cbData->m_totalPointsSimulated, piValue); } -void MonteCarloPiSimulation::computePiCallback(void *args) -{ - MonteCarloPiSimulation *cbData = (MonteCarloPiSimulation *)args; - cbData->m_totalPointsInsideCircle += *(cbData->m_hostNumPointsInCircle); - cbData->m_totalPointsSimulated += cbData->m_numPoints; - double piValue = 4.0 * ((double)cbData->m_totalPointsInsideCircle / (double)cbData->m_totalPointsSimulated); - printf("Approximate Pi value for %zd data points: %lf \n", cbData->m_totalPointsSimulated, piValue); +void MonteCarloPiSimulation::getIdealExecutionConfiguration() { + int warpSize = 0; + int multiProcessorCount = 0; + + checkCudaErrors(cudaSetDevice(m_cudaDevice)); + checkCudaErrors( + cudaDeviceGetAttribute(&warpSize, cudaDevAttrWarpSize, m_cudaDevice)); + + // We don't need large block sizes, since there's not much inter-thread + // communication + m_threads = warpSize; + + // Use the occupancy calculator and fill the gpu as best as we can + checkCudaErrors(cudaOccupancyMaxActiveBlocksPerMultiprocessor( + &m_blocks, monte_carlo_kernel, warpSize, 0)); + + checkCudaErrors(cudaDeviceGetAttribute( + &multiProcessorCount, cudaDevAttrMultiProcessorCount, m_cudaDevice)); + m_blocks *= multiProcessorCount; + + // Go ahead and the clamp the blocks to the minimum needed for this + // height/width + m_blocks = + std::min(m_blocks, (int)((m_numPoints + m_threads - 1) / m_threads)); } -void MonteCarloPiSimulation::getIdealExecutionConfiguration() -{ - int warpSize = 0; - int multiProcessorCount = 0; +void MonteCarloPiSimulation::setupSimulationAllocations() { + CUdeviceptr d_ptr = 0U; + size_t granularity = 0; + CUmemGenericAllocationHandle cudaPositionHandle, cudaInCircleHandle; - checkCudaErrors(cudaSetDevice(m_cudaDevice)); - checkCudaErrors(cudaDeviceGetAttribute(&warpSize, cudaDevAttrWarpSize, m_cudaDevice)); + CUmemAllocationProp allocProp = {}; + allocProp.type = CU_MEM_ALLOCATION_TYPE_PINNED; + allocProp.location.type = CU_MEM_LOCATION_TYPE_DEVICE; + allocProp.location.id = m_cudaDevice; + allocProp.win32HandleMetaData = NULL; + allocProp.requestedHandleTypes = ipcHandleTypeFlag; - // We don't need large block sizes, since there's not much inter-thread communication - m_threads = warpSize; + // Windows-specific LPSECURITYATTRIBUTES is required when + // CU_MEM_HANDLE_TYPE_WIN32 is used. The security attribute defines the scope + // of which exported allocations may be tranferred to other processes. For all + // other handle types, pass NULL. + getDefaultSecurityDescriptor(&allocProp); - // Use the occupancy calculator and fill the gpu as best as we can - checkCudaErrors(cudaOccupancyMaxActiveBlocksPerMultiprocessor(&m_blocks, monte_carlo_kernel, warpSize, 0)); + // Get the recommended granularity for m_cudaDevice. + checkCudaErrors(cuMemGetAllocationGranularity( + &granularity, &allocProp, CU_MEM_ALLOC_GRANULARITY_RECOMMENDED)); - checkCudaErrors(cudaDeviceGetAttribute(&multiProcessorCount, cudaDevAttrMultiProcessorCount, m_cudaDevice)); - m_blocks *= multiProcessorCount; + size_t xyPositionVecSize = m_numPoints * sizeof(*m_xyVector); + size_t inCircleVecSize = m_numPoints * sizeof(*m_pointsInsideCircle); - // Go ahead and the clamp the blocks to the minimum needed for this height/width - m_blocks = std::min(m_blocks, (int)((m_numPoints + m_threads - 1) / m_threads)); + size_t xyPositionSize = + ROUND_UP_TO_GRANULARITY(xyPositionVecSize, granularity); + size_t inCircleSize = ROUND_UP_TO_GRANULARITY(inCircleVecSize, granularity); + m_totalAllocationSize = (xyPositionSize + inCircleSize); + + // Reserve the required contiguous VA space for the allocations + checkCudaErrors( + cuMemAddressReserve(&d_ptr, m_totalAllocationSize, granularity, 0U, 0)); + + // Create the allocations as a pinned allocation on this device. + // Create an allocation to store all the positions of points on the xy plane + // and a second allocation which stores information if the corresponding + // position is inside the unit circle or not. + checkCudaErrors( + cuMemCreate(&cudaPositionHandle, xyPositionSize, &allocProp, 0)); + checkCudaErrors( + cuMemCreate(&cudaInCircleHandle, inCircleSize, &allocProp, 0)); + + // Export the allocation to a platform-specific handle. The type of handle + // requested here must match the requestedHandleTypes field in the prop + // structure passed to cuMemCreate. The handle obtained here will be passed to + // vulkan to import the allocation. + checkCudaErrors(cuMemExportToShareableHandle( + (void *)&m_posShareableHandle, cudaPositionHandle, ipcHandleTypeFlag, 0)); + checkCudaErrors( + cuMemExportToShareableHandle((void *)&m_inCircleShareableHandle, + cudaInCircleHandle, ipcHandleTypeFlag, 0)); + + CUdeviceptr va_position = d_ptr; + CUdeviceptr va_InCircle = va_position + xyPositionSize; + m_pointsInsideCircle = (float *)va_InCircle; + m_xyVector = (vec2 *)va_position; + + // Assign the chunk to the appropriate VA range + checkCudaErrors( + cuMemMap(va_position, xyPositionSize, 0, cudaPositionHandle, 0)); + checkCudaErrors( + cuMemMap(va_InCircle, inCircleSize, 0, cudaInCircleHandle, 0)); + + // Release the handles for the allocation. Since the allocation is currently + // mapped to a VA range with a previous call to cuMemMap the actual freeing of + // memory allocation will happen on an eventual call to cuMemUnmap. Thus the + // allocation will be kept live until it is unmapped. + checkCudaErrors(cuMemRelease(cudaPositionHandle)); + checkCudaErrors(cuMemRelease(cudaInCircleHandle)); + + CUmemAccessDesc accessDescriptor = {}; + accessDescriptor.location.id = m_cudaDevice; + accessDescriptor.location.type = CU_MEM_LOCATION_TYPE_DEVICE; + accessDescriptor.flags = CU_MEM_ACCESS_FLAGS_PROT_READWRITE; + + // Apply the access descriptor to the whole VA range. Essentially enables + // Read-Write access to the range. + checkCudaErrors( + cuMemSetAccess(d_ptr, m_totalAllocationSize, &accessDescriptor, 1)); } -void MonteCarloPiSimulation::setupSimulationAllocations() -{ - CUdeviceptr d_ptr = 0U; - size_t granularity = 0; - CUmemGenericAllocationHandle cudaPositionHandle, cudaInCircleHandle; +void MonteCarloPiSimulation::cleanupSimulationAllocations() { + if (m_xyVector && m_pointsInsideCircle) { + // Unmap the mapped virtual memory region + // Since the handles to the mapped backing stores have already been released + // by cuMemRelease, and these are the only/last mappings referencing them, + // The backing stores will be freed. + checkCudaErrors(cuMemUnmap((CUdeviceptr)m_xyVector, m_totalAllocationSize)); - CUmemAllocationProp allocProp = { }; - allocProp.type = CU_MEM_ALLOCATION_TYPE_PINNED; - allocProp.location.type = CU_MEM_LOCATION_TYPE_DEVICE; - allocProp.location.id = m_cudaDevice; - allocProp.win32HandleMetaData = NULL; - allocProp.requestedHandleTypes = ipcHandleTypeFlag; + checkIpcErrors(ipcCloseShareableHandle(m_posShareableHandle)); + checkIpcErrors(ipcCloseShareableHandle(m_inCircleShareableHandle)); - // Windows-specific LPSECURITYATTRIBUTES is required when - // CU_MEM_HANDLE_TYPE_WIN32 is used. The security attribute defines the scope - // of which exported allocations may be tranferred to other processes. For all - // other handle types, pass NULL. - getDefaultSecurityDescriptor(&allocProp); + // Free the virtual address region. + checkCudaErrors( + cuMemAddressFree((CUdeviceptr)m_xyVector, m_totalAllocationSize)); - // Get the recommended granularity for m_cudaDevice. - checkCudaErrors(cuMemGetAllocationGranularity(&granularity, &allocProp, CU_MEM_ALLOC_GRANULARITY_RECOMMENDED)); - - size_t xyPositionVecSize = m_numPoints * sizeof(*m_xyVector); - size_t inCircleVecSize = m_numPoints * sizeof(*m_pointsInsideCircle); - - size_t xyPositionSize = ROUND_UP_TO_GRANULARITY(xyPositionVecSize, granularity); - size_t inCircleSize = ROUND_UP_TO_GRANULARITY(inCircleVecSize, granularity); - m_totalAllocationSize = (xyPositionSize + inCircleSize); - - // Reserve the required contiguous VA space for the allocations - checkCudaErrors(cuMemAddressReserve(&d_ptr, m_totalAllocationSize, granularity, 0U, 0)); - - // Create the allocations as a pinned allocation on this device. - // Create an allocation to store all the positions of points on the xy plane and a second - // allocation which stores information if the corresponding position is inside the unit circle or not. - checkCudaErrors(cuMemCreate(&cudaPositionHandle, xyPositionSize, &allocProp, 0)); - checkCudaErrors(cuMemCreate(&cudaInCircleHandle, inCircleSize, &allocProp, 0)); - - // Export the allocation to a platform-specific handle. The type of handle - // requested here must match the requestedHandleTypes field in the prop - // structure passed to cuMemCreate. The handle obtained here will be passed to vulkan - // to import the allocation. - checkCudaErrors(cuMemExportToShareableHandle((void *)&m_posShareableHandle, cudaPositionHandle, ipcHandleTypeFlag, 0)); - checkCudaErrors(cuMemExportToShareableHandle((void *)&m_inCircleShareableHandle, cudaInCircleHandle, ipcHandleTypeFlag, 0)); - - CUdeviceptr va_position = d_ptr; - CUdeviceptr va_InCircle = va_position + xyPositionSize; - m_pointsInsideCircle = (float *)va_InCircle; - m_xyVector = (vec2 *)va_position; - - // Assign the chunk to the appropriate VA range - checkCudaErrors(cuMemMap(va_position, xyPositionSize, 0, cudaPositionHandle, 0)); - checkCudaErrors(cuMemMap(va_InCircle, inCircleSize, 0, cudaInCircleHandle, 0)); - - // Release the handles for the allocation. Since the allocation is currently mapped to a VA range - // with a previous call to cuMemMap the actual freeing of memory allocation will happen on an eventual call to - // cuMemUnmap. Thus the allocation will be kept live until it is unmapped. - checkCudaErrors(cuMemRelease(cudaPositionHandle)); - checkCudaErrors(cuMemRelease(cudaInCircleHandle)); - - CUmemAccessDesc accessDescriptor = {}; - accessDescriptor.location.id = m_cudaDevice; - accessDescriptor.location.type = CU_MEM_LOCATION_TYPE_DEVICE; - accessDescriptor.flags = CU_MEM_ACCESS_FLAGS_PROT_READWRITE; - - // Apply the access descriptor to the whole VA range. Essentially enables Read-Write access to the range. - checkCudaErrors(cuMemSetAccess(d_ptr, m_totalAllocationSize, &accessDescriptor, 1)); -} - -void MonteCarloPiSimulation::cleanupSimulationAllocations() -{ - if (m_xyVector && m_pointsInsideCircle) { - // Unmap the mapped virtual memory region - // Since the handles to the mapped backing stores have already been released - // by cuMemRelease, and these are the only/last mappings referencing them, - // The backing stores will be freed. - checkCudaErrors(cuMemUnmap((CUdeviceptr)m_xyVector, m_totalAllocationSize)); - - checkIpcErrors(ipcCloseShareableHandle(m_posShareableHandle)); - checkIpcErrors(ipcCloseShareableHandle(m_inCircleShareableHandle)); - - // Free the virtual address region. - checkCudaErrors(cuMemAddressFree((CUdeviceptr)m_xyVector, m_totalAllocationSize)); - - m_xyVector = nullptr; - m_pointsInsideCircle = nullptr; - } + m_xyVector = nullptr; + m_pointsInsideCircle = nullptr; + } } diff --git a/Samples/simpleVulkanMMAP/MonteCarloPi.h b/Samples/simpleVulkanMMAP/MonteCarloPi.h index 09f0854a..a82ca2e1 100644 --- a/Samples/simpleVulkanMMAP/MonteCarloPi.h +++ b/Samples/simpleVulkanMMAP/MonteCarloPi.h @@ -39,62 +39,57 @@ typedef float vec2[2]; -class MonteCarloPiSimulation -{ - size_t m_numPoints; +class MonteCarloPiSimulation { + size_t m_numPoints; - // Pointers to Cuda allocated buffers which are imported and used by vulkan as vertex buffer - vec2 *m_xyVector; - float *m_pointsInsideCircle; + // Pointers to Cuda allocated buffers which are imported and used by vulkan as + // vertex buffer + vec2 *m_xyVector; + float *m_pointsInsideCircle; - // Pointers to device and host allocated memories storing number of points that are inside the unit circle - float *m_numPointsInCircle; - float *m_hostNumPointsInCircle; + // Pointers to device and host allocated memories storing number of points + // that are inside the unit circle + float *m_numPointsInCircle; + float *m_hostNumPointsInCircle; - int m_blocks, m_threads; + int m_blocks, m_threads; - // Total size of allocations created by cuMemMap Apis. This size is the sum of sizes of - // m_xyVector and m_pointsInsideCircle buffers. - size_t m_totalAllocationSize; + // Total size of allocations created by cuMemMap Apis. This size is the sum of + // sizes of m_xyVector and m_pointsInsideCircle buffers. + size_t m_totalAllocationSize; - // Shareable Handles(a file descriptor on Linux and NT Handle on Windows), used for sharing cuda - // allocated memory with Vulkan - ShareableHandle m_posShareableHandle, m_inCircleShareableHandle; + // Shareable Handles(a file descriptor on Linux and NT Handle on Windows), + // used for sharing cuda + // allocated memory with Vulkan + ShareableHandle m_posShareableHandle, m_inCircleShareableHandle; - // Cuda Device corresponding to the Vulkan Physical device - int m_cudaDevice; + // Cuda Device corresponding to the Vulkan Physical device + int m_cudaDevice; - // Track and accumulate total points that have been simulated since start of the sample. - // The idea is to get a closer approximation to PI with time. - size_t m_totalPointsInsideCircle; - size_t m_totalPointsSimulated; + // Track and accumulate total points that have been simulated since start of + // the sample. The idea is to get a closer approximation to PI with time. + size_t m_totalPointsInsideCircle; + size_t m_totalPointsSimulated; - void setupSimulationAllocations(); - void cleanupSimulationAllocations(); - void getIdealExecutionConfiguration(); + void setupSimulationAllocations(); + void cleanupSimulationAllocations(); + void getIdealExecutionConfiguration(); -public: - MonteCarloPiSimulation(size_t num_points); - ~MonteCarloPiSimulation(); - void initSimulation(int cudaDevice, cudaStream_t stream = 0); - void stepSimulation(float time, cudaStream_t stream = 0); - static void computePiCallback(void *args); + public: + MonteCarloPiSimulation(size_t num_points); + ~MonteCarloPiSimulation(); + void initSimulation(int cudaDevice, cudaStream_t stream = 0); + void stepSimulation(float time, cudaStream_t stream = 0); + static void computePiCallback(void *args); - size_t getNumPoints() const { - return m_numPoints; - } + size_t getNumPoints() const { return m_numPoints; } - float getNumPointsInCircle() const { - return *m_hostNumPointsInCircle; - } - - ShareableHandle &getPositionShareableHandle() { - return m_posShareableHandle; - } - ShareableHandle &getInCircleShareableHandle() { - return m_inCircleShareableHandle; - } + float getNumPointsInCircle() const { return *m_hostNumPointsInCircle; } + ShareableHandle &getPositionShareableHandle() { return m_posShareableHandle; } + ShareableHandle &getInCircleShareableHandle() { + return m_inCircleShareableHandle; + } }; -#endif // __PISIM_H__ +#endif // __PISIM_H__ diff --git a/Samples/simpleVulkanMMAP/VulkanBaseApp.cpp b/Samples/simpleVulkanMMAP/VulkanBaseApp.cpp index dc665bdc..d470394d 100644 --- a/Samples/simpleVulkanMMAP/VulkanBaseApp.cpp +++ b/Samples/simpleVulkanMMAP/VulkanBaseApp.cpp @@ -25,11 +25,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - /* - * This file contains basic cross-platform setup paths in working with Vulkan - * and rendering window. It is largely based off of tutorials provided here: - * https://vulkan-tutorial.com/ - */ +/* + * This file contains basic cross-platform setup paths in working with Vulkan + * and rendering window. It is largely based off of tutorials provided here: + * https://vulkan-tutorial.com/ +*/ #include #include @@ -56,1673 +56,1786 @@ #define countof(x) (sizeof(x) / sizeof(*(x))) #endif -static const char *validationLayers[] = { "VK_LAYER_KHRONOS_validation" }; +static const char *validationLayers[] = {"VK_LAYER_KHRONOS_validation"}; static const size_t MAX_FRAMES_IN_FLIGHT = 5; -void VulkanBaseApp::resizeCallback(GLFWwindow *window, int width, int height) -{ - VulkanBaseApp *app = reinterpret_cast(glfwGetWindowUserPointer(window)); - app->m_framebufferResized = true; +void VulkanBaseApp::resizeCallback(GLFWwindow *window, int width, int height) { + VulkanBaseApp *app = + reinterpret_cast(glfwGetWindowUserPointer(window)); + app->m_framebufferResized = true; } -static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *pUserData) -{ - std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl; +static VKAPI_ATTR VkBool32 VKAPI_CALL +debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, + void *pUserData) { + std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl; - return VK_FALSE; + return VK_FALSE; } -VulkanBaseApp::VulkanBaseApp(const std::string& appName, bool enableValidation) : - m_appName(appName), - m_enableValidation(enableValidation), - m_instance(VK_NULL_HANDLE), - m_window(nullptr), - m_debugMessenger(VK_NULL_HANDLE), - m_surface(VK_NULL_HANDLE), - m_physicalDevice(VK_NULL_HANDLE), - m_device(VK_NULL_HANDLE), - m_graphicsQueue(VK_NULL_HANDLE), - m_presentQueue(VK_NULL_HANDLE), - m_swapChain(VK_NULL_HANDLE), - m_swapChainImages(), - m_swapChainFormat(), - m_swapChainExtent(), - m_swapChainImageViews(), - m_shaderFiles(), - m_renderPass(), - m_pipelineLayout(VK_NULL_HANDLE), - m_graphicsPipeline(VK_NULL_HANDLE), - m_swapChainFramebuffers(), - m_commandPool(VK_NULL_HANDLE), - m_commandBuffers(), - m_imageAvailableSemaphores(), - m_renderFinishedSemaphores(), - m_inFlightFences(), - m_uniformBuffers(), - m_uniformMemory(), - m_descriptorSetLayout(VK_NULL_HANDLE), - m_descriptorPool(VK_NULL_HANDLE), - m_descriptorSets(), - m_depthImage(VK_NULL_HANDLE), - m_depthImageMemory(VK_NULL_HANDLE), - m_depthImageView(VK_NULL_HANDLE), - m_currentFrame(0), - m_framebufferResized(false) -{ -} +VulkanBaseApp::VulkanBaseApp(const std::string &appName, bool enableValidation) + : m_appName(appName), + m_enableValidation(enableValidation), + m_instance(VK_NULL_HANDLE), + m_window(nullptr), + m_debugMessenger(VK_NULL_HANDLE), + m_surface(VK_NULL_HANDLE), + m_physicalDevice(VK_NULL_HANDLE), + m_device(VK_NULL_HANDLE), + m_graphicsQueue(VK_NULL_HANDLE), + m_presentQueue(VK_NULL_HANDLE), + m_swapChain(VK_NULL_HANDLE), + m_swapChainImages(), + m_swapChainFormat(), + m_swapChainExtent(), + m_swapChainImageViews(), + m_shaderFiles(), + m_renderPass(), + m_pipelineLayout(VK_NULL_HANDLE), + m_graphicsPipeline(VK_NULL_HANDLE), + m_swapChainFramebuffers(), + m_commandPool(VK_NULL_HANDLE), + m_commandBuffers(), + m_imageAvailableSemaphores(), + m_renderFinishedSemaphores(), + m_inFlightFences(), + m_uniformBuffers(), + m_uniformMemory(), + m_descriptorSetLayout(VK_NULL_HANDLE), + m_descriptorPool(VK_NULL_HANDLE), + m_descriptorSets(), + m_depthImage(VK_NULL_HANDLE), + m_depthImageMemory(VK_NULL_HANDLE), + m_depthImageView(VK_NULL_HANDLE), + m_currentFrame(0), + m_framebufferResized(false) {} -VkExternalSemaphoreHandleTypeFlagBits VulkanBaseApp::getDefaultSemaphoreHandleType() -{ +VkExternalSemaphoreHandleTypeFlagBits +VulkanBaseApp::getDefaultSemaphoreHandleType() { #ifdef _WIN64 - return IsWindows8OrGreater() ? - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT : - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT; + return IsWindows8OrGreater() + ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT + : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT; #else - return VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; + return VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; #endif } -VkExternalMemoryHandleTypeFlagBits VulkanBaseApp::getDefaultMemHandleType() -{ +VkExternalMemoryHandleTypeFlagBits VulkanBaseApp::getDefaultMemHandleType() { #ifdef _WIN64 - return IsWindows8Point1OrGreater() ? - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT : - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT; + return IsWindows8Point1OrGreater() + ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT + : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT; #else - return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; #endif } -VulkanBaseApp::~VulkanBaseApp() -{ - cleanupSwapChain(); +VulkanBaseApp::~VulkanBaseApp() { + cleanupSwapChain(); - if (m_descriptorSetLayout != VK_NULL_HANDLE) { - vkDestroyDescriptorSetLayout(m_device, m_descriptorSetLayout, nullptr); - } + if (m_descriptorSetLayout != VK_NULL_HANDLE) { + vkDestroyDescriptorSetLayout(m_device, m_descriptorSetLayout, nullptr); + } - for (size_t i = 0; i < m_renderFinishedSemaphores.size(); i++) { - vkDestroySemaphore(m_device, m_renderFinishedSemaphores[i], nullptr); - vkDestroySemaphore(m_device, m_imageAvailableSemaphores[i], nullptr); - vkDestroyFence(m_device, m_inFlightFences[i], nullptr); - } - if (m_commandPool != VK_NULL_HANDLE) { - vkDestroyCommandPool(m_device, m_commandPool, nullptr); - } + for (size_t i = 0; i < m_renderFinishedSemaphores.size(); i++) { + vkDestroySemaphore(m_device, m_renderFinishedSemaphores[i], nullptr); + vkDestroySemaphore(m_device, m_imageAvailableSemaphores[i], nullptr); + vkDestroyFence(m_device, m_inFlightFences[i], nullptr); + } + if (m_commandPool != VK_NULL_HANDLE) { + vkDestroyCommandPool(m_device, m_commandPool, nullptr); + } - if (m_device != VK_NULL_HANDLE) { - vkDestroyDevice(m_device, nullptr); - } + if (m_device != VK_NULL_HANDLE) { + vkDestroyDevice(m_device, nullptr); + } - if (m_enableValidation) { - PFN_vkDestroyDebugUtilsMessengerEXT func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(m_instance, "vkDestroyDebugUtilsMessengerEXT"); - if (func != nullptr) { - func(m_instance, m_debugMessenger, nullptr); - } + if (m_enableValidation) { + PFN_vkDestroyDebugUtilsMessengerEXT func = + (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr( + m_instance, "vkDestroyDebugUtilsMessengerEXT"); + if (func != nullptr) { + func(m_instance, m_debugMessenger, nullptr); } + } - if (m_surface != VK_NULL_HANDLE) { - vkDestroySurfaceKHR(m_instance, m_surface, nullptr); - } + if (m_surface != VK_NULL_HANDLE) { + vkDestroySurfaceKHR(m_instance, m_surface, nullptr); + } - if (m_instance != VK_NULL_HANDLE) { - vkDestroyInstance(m_instance, nullptr); - } + if (m_instance != VK_NULL_HANDLE) { + vkDestroyInstance(m_instance, nullptr); + } - if (m_window) { - glfwDestroyWindow(m_window); - } + if (m_window) { + glfwDestroyWindow(m_window); + } - glfwTerminate(); + glfwTerminate(); } -void VulkanBaseApp::init() -{ - initWindow(); - initVulkan(); +void VulkanBaseApp::init() { + initWindow(); + initVulkan(); } -VkCommandBuffer VulkanBaseApp::beginSingleTimeCommands() -{ - VkCommandBufferAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandPool = m_commandPool; - allocInfo.commandBufferCount = 1; +VkCommandBuffer VulkanBaseApp::beginSingleTimeCommands() { + VkCommandBufferAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandPool = m_commandPool; + allocInfo.commandBufferCount = 1; - VkCommandBuffer commandBuffer; - vkAllocateCommandBuffers(m_device, &allocInfo, &commandBuffer); + VkCommandBuffer commandBuffer; + vkAllocateCommandBuffers(m_device, &allocInfo, &commandBuffer); - VkCommandBufferBeginInfo beginInfo = {}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + VkCommandBufferBeginInfo beginInfo = {}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(commandBuffer, &beginInfo); + vkBeginCommandBuffer(commandBuffer, &beginInfo); - return commandBuffer; + return commandBuffer; } -void VulkanBaseApp::endSingleTimeCommands(VkCommandBuffer commandBuffer) -{ - vkEndCommandBuffer(commandBuffer); +void VulkanBaseApp::endSingleTimeCommands(VkCommandBuffer commandBuffer) { + vkEndCommandBuffer(commandBuffer); - VkSubmitInfo submitInfo = {}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &commandBuffer; + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; - vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); - vkQueueWaitIdle(m_graphicsQueue); + vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); + vkQueueWaitIdle(m_graphicsQueue); - vkFreeCommandBuffers(m_device, m_commandPool, 1, &commandBuffer); + vkFreeCommandBuffers(m_device, m_commandPool, 1, &commandBuffer); } -void VulkanBaseApp::initWindow() -{ - glfwInit(); +void VulkanBaseApp::initWindow() { + glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); - m_window = glfwCreateWindow(1280, 800, m_appName.c_str(), nullptr, nullptr); - glfwSetWindowUserPointer(m_window, this); - glfwSetFramebufferSizeCallback(m_window, resizeCallback); + m_window = glfwCreateWindow(1280, 800, m_appName.c_str(), nullptr, nullptr); + glfwSetWindowUserPointer(m_window, this); + glfwSetFramebufferSizeCallback(m_window, resizeCallback); } - -std::vector VulkanBaseApp::getRequiredExtensions() const -{ - return std::vector(); +std::vector VulkanBaseApp::getRequiredExtensions() const { + return std::vector(); } -std::vector VulkanBaseApp::getRequiredDeviceExtensions() const -{ - return std::vector(); +std::vector VulkanBaseApp::getRequiredDeviceExtensions() const { + return std::vector(); } -void VulkanBaseApp::initVulkan() -{ - createInstance(); - createSurface(); - createDevice(); - createSwapChain(); - createImageViews(); - createRenderPass(); - createDescriptorSetLayout(); - createGraphicsPipeline(); - createCommandPool(); - createDepthResources(); - createFramebuffers(); - initVulkanApp(); - createUniformBuffers(); - createDescriptorPool(); - createDescriptorSets(); - createCommandBuffers(); - createSyncObjects(); +void VulkanBaseApp::initVulkan() { + createInstance(); + createSurface(); + createDevice(); + createSwapChain(); + createImageViews(); + createRenderPass(); + createDescriptorSetLayout(); + createGraphicsPipeline(); + createCommandPool(); + createDepthResources(); + createFramebuffers(); + initVulkanApp(); + createUniformBuffers(); + createDescriptorPool(); + createDescriptorSets(); + createCommandBuffers(); + createSyncObjects(); } #ifdef _WIN64 -class WindowsSecurityAttributes -{ -protected: - SECURITY_ATTRIBUTES m_winSecurityAttributes; - PSECURITY_DESCRIPTOR m_winPSecurityDescriptor; +class WindowsSecurityAttributes { + protected: + SECURITY_ATTRIBUTES m_winSecurityAttributes; + PSECURITY_DESCRIPTOR m_winPSecurityDescriptor; -public: - WindowsSecurityAttributes(); - SECURITY_ATTRIBUTES *operator&(); - ~WindowsSecurityAttributes(); + public: + WindowsSecurityAttributes(); + SECURITY_ATTRIBUTES *operator&(); + ~WindowsSecurityAttributes(); }; -WindowsSecurityAttributes::WindowsSecurityAttributes() -{ - m_winPSecurityDescriptor = (PSECURITY_DESCRIPTOR)calloc(1, SECURITY_DESCRIPTOR_MIN_LENGTH + 2 * sizeof(void **)); - if (!m_winPSecurityDescriptor) { - throw std::runtime_error("Failed to allocate memory for security descriptor"); - } +WindowsSecurityAttributes::WindowsSecurityAttributes() { + m_winPSecurityDescriptor = (PSECURITY_DESCRIPTOR)calloc( + 1, SECURITY_DESCRIPTOR_MIN_LENGTH + 2 * sizeof(void **)); + if (!m_winPSecurityDescriptor) { + throw std::runtime_error( + "Failed to allocate memory for security descriptor"); + } - PSID *ppSID = (PSID *)((PBYTE)m_winPSecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); - PACL *ppACL = (PACL *)((PBYTE)ppSID + sizeof(PSID *)); + PSID *ppSID = (PSID *)((PBYTE)m_winPSecurityDescriptor + + SECURITY_DESCRIPTOR_MIN_LENGTH); + PACL *ppACL = (PACL *)((PBYTE)ppSID + sizeof(PSID *)); - InitializeSecurityDescriptor(m_winPSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); + InitializeSecurityDescriptor(m_winPSecurityDescriptor, + SECURITY_DESCRIPTOR_REVISION); - SID_IDENTIFIER_AUTHORITY sidIdentifierAuthority = SECURITY_WORLD_SID_AUTHORITY; - AllocateAndInitializeSid(&sidIdentifierAuthority, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, ppSID); + SID_IDENTIFIER_AUTHORITY sidIdentifierAuthority = + SECURITY_WORLD_SID_AUTHORITY; + AllocateAndInitializeSid(&sidIdentifierAuthority, 1, SECURITY_WORLD_RID, 0, 0, + 0, 0, 0, 0, 0, ppSID); - EXPLICIT_ACCESS explicitAccess; - ZeroMemory(&explicitAccess, sizeof(EXPLICIT_ACCESS)); - explicitAccess.grfAccessPermissions = STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL; - explicitAccess.grfAccessMode = SET_ACCESS; - explicitAccess.grfInheritance = INHERIT_ONLY; - explicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID; - explicitAccess.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; - explicitAccess.Trustee.ptstrName = (LPTSTR)* ppSID; + EXPLICIT_ACCESS explicitAccess; + ZeroMemory(&explicitAccess, sizeof(EXPLICIT_ACCESS)); + explicitAccess.grfAccessPermissions = + STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL; + explicitAccess.grfAccessMode = SET_ACCESS; + explicitAccess.grfInheritance = INHERIT_ONLY; + explicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID; + explicitAccess.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + explicitAccess.Trustee.ptstrName = (LPTSTR)*ppSID; - SetEntriesInAcl(1, &explicitAccess, NULL, ppACL); + SetEntriesInAcl(1, &explicitAccess, NULL, ppACL); - SetSecurityDescriptorDacl(m_winPSecurityDescriptor, TRUE, *ppACL, FALSE); + SetSecurityDescriptorDacl(m_winPSecurityDescriptor, TRUE, *ppACL, FALSE); - m_winSecurityAttributes.nLength = sizeof(m_winSecurityAttributes); - m_winSecurityAttributes.lpSecurityDescriptor = m_winPSecurityDescriptor; - m_winSecurityAttributes.bInheritHandle = TRUE; + m_winSecurityAttributes.nLength = sizeof(m_winSecurityAttributes); + m_winSecurityAttributes.lpSecurityDescriptor = m_winPSecurityDescriptor; + m_winSecurityAttributes.bInheritHandle = TRUE; } -SECURITY_ATTRIBUTES * -WindowsSecurityAttributes::operator&() -{ - return &m_winSecurityAttributes; +SECURITY_ATTRIBUTES *WindowsSecurityAttributes::operator&() { + return &m_winSecurityAttributes; } -WindowsSecurityAttributes::~WindowsSecurityAttributes() -{ - PSID *ppSID = (PSID *)((PBYTE)m_winPSecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); - PACL *ppACL = (PACL *)((PBYTE)ppSID + sizeof(PSID *)); +WindowsSecurityAttributes::~WindowsSecurityAttributes() { + PSID *ppSID = (PSID *)((PBYTE)m_winPSecurityDescriptor + + SECURITY_DESCRIPTOR_MIN_LENGTH); + PACL *ppACL = (PACL *)((PBYTE)ppSID + sizeof(PSID *)); - if (*ppSID) { - FreeSid(*ppSID); - } - if (*ppACL) { - LocalFree(*ppACL); - } - free(m_winPSecurityDescriptor); + if (*ppSID) { + FreeSid(*ppSID); + } + if (*ppACL) { + LocalFree(*ppACL); + } + free(m_winPSecurityDescriptor); } #endif /* _WIN64 */ - -static VkFormat findSupportedFormat(VkPhysicalDevice physicalDevice, const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features) -{ - for (VkFormat format : candidates) { - VkFormatProperties props; - vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &props); - if (tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures & features) == features) { - return format; - } - else if (tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features) { - return format; - } +static VkFormat findSupportedFormat(VkPhysicalDevice physicalDevice, + const std::vector &candidates, + VkImageTiling tiling, + VkFormatFeatureFlags features) { + for (VkFormat format : candidates) { + VkFormatProperties props; + vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &props); + if (tiling == VK_IMAGE_TILING_LINEAR && + (props.linearTilingFeatures & features) == features) { + return format; + } else if (tiling == VK_IMAGE_TILING_OPTIMAL && + (props.optimalTilingFeatures & features) == features) { + return format; } - throw std::runtime_error("Failed to find supported format!"); + } + throw std::runtime_error("Failed to find supported format!"); } -static uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties) -{ - VkPhysicalDeviceMemoryProperties memProperties; - vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties); - for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) { - if (typeFilter & (1 << i) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) { - return i; - } +static uint32_t findMemoryType(VkPhysicalDevice physicalDevice, + uint32_t typeFilter, + VkMemoryPropertyFlags properties) { + VkPhysicalDeviceMemoryProperties memProperties; + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties); + for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) { + if (typeFilter & (1 << i) && + (memProperties.memoryTypes[i].propertyFlags & properties) == + properties) { + return i; } - return ~0; + } + return ~0; } -static bool supportsValidationLayers() -{ - std::vector availableLayers; - uint32_t layerCount; +static bool supportsValidationLayers() { + std::vector availableLayers; + uint32_t layerCount; - vkEnumerateInstanceLayerProperties(&layerCount, nullptr); - availableLayers.resize(layerCount); - vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); + vkEnumerateInstanceLayerProperties(&layerCount, nullptr); + availableLayers.resize(layerCount); + vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); - for (const char * layerName : validationLayers) { - bool layerFound = false; + for (const char *layerName : validationLayers) { + bool layerFound = false; - for (const auto & layerProperties : availableLayers) { - if (strcmp(layerName, layerProperties.layerName) == 0) { - layerFound = true; - break; - } - } - - if (!layerFound) { - return false; - } + for (const auto &layerProperties : availableLayers) { + if (strcmp(layerName, layerProperties.layerName) == 0) { + layerFound = true; + break; + } } - return true; + if (!layerFound) { + return false; + } + } + + return true; } -void VulkanBaseApp::createInstance() -{ - if (m_enableValidation && !supportsValidationLayers()) { - throw std::runtime_error("Validation requested, but not supported!"); - } +void VulkanBaseApp::createInstance() { + if (m_enableValidation && !supportsValidationLayers()) { + throw std::runtime_error("Validation requested, but not supported!"); + } - VkApplicationInfo appInfo = {}; - appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.pApplicationName = m_appName.c_str(); - appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); - appInfo.pEngineName = "No Engine"; - appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); - appInfo.apiVersion = VK_API_VERSION_1_0; + VkApplicationInfo appInfo = {}; + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.pApplicationName = m_appName.c_str(); + appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.pEngineName = "No Engine"; + appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.apiVersion = VK_API_VERSION_1_0; - VkInstanceCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - createInfo.pApplicationInfo = &appInfo; + VkInstanceCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + createInfo.pApplicationInfo = &appInfo; - std::vector exts = getRequiredExtensions(); + std::vector exts = getRequiredExtensions(); - { - uint32_t glfwExtensionCount = 0; - const char **glfwExtensions; + { + uint32_t glfwExtensionCount = 0; + const char **glfwExtensions; - glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); + glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); - exts.insert(exts.begin(), glfwExtensions, glfwExtensions + glfwExtensionCount); - - if (m_enableValidation) { - exts.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - } - } - - createInfo.enabledExtensionCount = static_cast(exts.size()); - createInfo.ppEnabledExtensionNames = exts.data(); - VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {}; - if (m_enableValidation) { - createInfo.enabledLayerCount = static_cast(countof(validationLayers)); - createInfo.ppEnabledLayerNames = validationLayers; - - debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - debugCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - debugCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; - debugCreateInfo.pfnUserCallback = debugCallback; - - createInfo.pNext = &debugCreateInfo; - } - else { - createInfo.enabledLayerCount = 0; - createInfo.pNext = nullptr; - } - - if (vkCreateInstance(&createInfo, nullptr, &m_instance) != VK_SUCCESS) { - throw std::runtime_error("Failed to create Vulkan instance!"); - } + exts.insert(exts.begin(), glfwExtensions, + glfwExtensions + glfwExtensionCount); if (m_enableValidation) { - PFN_vkCreateDebugUtilsMessengerEXT func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(m_instance, "vkCreateDebugUtilsMessengerEXT"); - if (func == nullptr || func(m_instance, &debugCreateInfo, nullptr, &m_debugMessenger) != VK_SUCCESS) { - throw std::runtime_error("Failed to set up debug messenger!"); - } + exts.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); } + } + + createInfo.enabledExtensionCount = static_cast(exts.size()); + createInfo.ppEnabledExtensionNames = exts.data(); + VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {}; + if (m_enableValidation) { + createInfo.enabledLayerCount = + static_cast(countof(validationLayers)); + createInfo.ppEnabledLayerNames = validationLayers; + + debugCreateInfo.sType = + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + debugCreateInfo.messageSeverity = + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + debugCreateInfo.messageType = + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + debugCreateInfo.pfnUserCallback = debugCallback; + + createInfo.pNext = &debugCreateInfo; + } else { + createInfo.enabledLayerCount = 0; + createInfo.pNext = nullptr; + } + + if (vkCreateInstance(&createInfo, nullptr, &m_instance) != VK_SUCCESS) { + throw std::runtime_error("Failed to create Vulkan instance!"); + } + + if (m_enableValidation) { + PFN_vkCreateDebugUtilsMessengerEXT func = + (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr( + m_instance, "vkCreateDebugUtilsMessengerEXT"); + if (func == nullptr || + func(m_instance, &debugCreateInfo, nullptr, &m_debugMessenger) != + VK_SUCCESS) { + throw std::runtime_error("Failed to set up debug messenger!"); + } + } } -void VulkanBaseApp::createSurface() -{ - if (glfwCreateWindowSurface(m_instance, m_window, nullptr, &m_surface) != VK_SUCCESS) { - throw std::runtime_error("failed to create window surface!"); - } +void VulkanBaseApp::createSurface() { + if (glfwCreateWindowSurface(m_instance, m_window, nullptr, &m_surface) != + VK_SUCCESS) { + throw std::runtime_error("failed to create window surface!"); + } } -static bool findGraphicsQueueIndicies(VkPhysicalDevice device, VkSurfaceKHR surface, uint32_t& graphicsFamily, uint32_t& presentFamily) -{ - uint32_t queueFamilyCount = 0; +static bool findGraphicsQueueIndicies(VkPhysicalDevice device, + VkSurfaceKHR surface, + uint32_t &graphicsFamily, + uint32_t &presentFamily) { + uint32_t queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); - std::vector queueFamilies(queueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data()); + std::vector queueFamilies(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, + queueFamilies.data()); - graphicsFamily = presentFamily = ~0; + graphicsFamily = presentFamily = ~0; - for (uint32_t i = 0; i < queueFamilyCount; i++) { - - if (queueFamilies[i].queueCount > 0) { - if (graphicsFamily == ~0 && queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { - graphicsFamily = i; - } - uint32_t presentSupport = 0; - vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport); - if (presentFamily == ~0 && presentSupport) { - presentFamily = i; - } - if (presentFamily != ~0 && graphicsFamily != ~0) { - break; - } - } + for (uint32_t i = 0; i < queueFamilyCount; i++) { + if (queueFamilies[i].queueCount > 0) { + if (graphicsFamily == ~0 && + queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { + graphicsFamily = i; + } + uint32_t presentSupport = 0; + vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport); + if (presentFamily == ~0 && presentSupport) { + presentFamily = i; + } + if (presentFamily != ~0 && graphicsFamily != ~0) { + break; + } } + } - return graphicsFamily != ~0 && presentFamily != ~0; + return graphicsFamily != ~0 && presentFamily != ~0; } -static bool hasAllExtensions(VkPhysicalDevice device, const std::vector& deviceExtensions) -{ - uint32_t extensionCount; - vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr); - std::vector availableExtensions(extensionCount); - vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data()); +static bool hasAllExtensions( + VkPhysicalDevice device, + const std::vector &deviceExtensions) { + uint32_t extensionCount; + vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, + nullptr); + std::vector availableExtensions(extensionCount); + vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, + availableExtensions.data()); - std::set requiredExtensions(deviceExtensions.begin(), deviceExtensions.end()); + std::set requiredExtensions(deviceExtensions.begin(), + deviceExtensions.end()); - for (const auto & extension : availableExtensions) { - requiredExtensions.erase(extension.extensionName); - } + for (const auto &extension : availableExtensions) { + requiredExtensions.erase(extension.extensionName); + } - return requiredExtensions.empty(); + return requiredExtensions.empty(); } -static void getSwapChainProperties(VkPhysicalDevice device, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR& capabilities, std::vector& formats, std::vector& presentModes) -{ - vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &capabilities); - uint32_t formatCount; - vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr); - if (formatCount != 0) { - formats.resize(formatCount); - vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, formats.data()); - } - uint32_t presentModeCount; - vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr); - if (presentModeCount != 0) { - presentModes.resize(presentModeCount); - vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, presentModes.data()); - } +static void getSwapChainProperties( + VkPhysicalDevice device, VkSurfaceKHR surface, + VkSurfaceCapabilitiesKHR &capabilities, + std::vector &formats, + std::vector &presentModes) { + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &capabilities); + uint32_t formatCount; + vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr); + if (formatCount != 0) { + formats.resize(formatCount); + vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, + formats.data()); + } + uint32_t presentModeCount; + vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, + nullptr); + if (presentModeCount != 0) { + presentModes.resize(presentModeCount); + vkGetPhysicalDeviceSurfacePresentModesKHR( + device, surface, &presentModeCount, presentModes.data()); + } } -bool VulkanBaseApp::isSuitableDevice(VkPhysicalDevice dev) const -{ - bool isSuitable = false; - uint32_t graphicsQueueIndex, presentQueueIndex; - std::vector deviceExtensions = getRequiredDeviceExtensions(); - VkSurfaceCapabilitiesKHR caps; - std::vector formats; - std::vector presentModes; - deviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); - getSwapChainProperties(dev, m_surface, caps, formats, presentModes); +bool VulkanBaseApp::isSuitableDevice(VkPhysicalDevice dev) const { + bool isSuitable = false; + uint32_t graphicsQueueIndex, presentQueueIndex; + std::vector deviceExtensions = getRequiredDeviceExtensions(); + VkSurfaceCapabilitiesKHR caps; + std::vector formats; + std::vector presentModes; + deviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + getSwapChainProperties(dev, m_surface, caps, formats, presentModes); - VkPhysicalDeviceIDPropertiesKHR vkPhysicalDeviceIDPropertiesKHR = {}; - vkPhysicalDeviceIDPropertiesKHR.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR; - vkPhysicalDeviceIDPropertiesKHR.pNext = NULL; + VkPhysicalDeviceIDPropertiesKHR vkPhysicalDeviceIDPropertiesKHR = {}; + vkPhysicalDeviceIDPropertiesKHR.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR; + vkPhysicalDeviceIDPropertiesKHR.pNext = NULL; - VkPhysicalDeviceProperties2KHR vkPhysicalDeviceProperties2KHR = {}; - vkPhysicalDeviceProperties2KHR.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; - vkPhysicalDeviceProperties2KHR.pNext = &vkPhysicalDeviceIDPropertiesKHR; + VkPhysicalDeviceProperties2KHR vkPhysicalDeviceProperties2KHR = {}; + vkPhysicalDeviceProperties2KHR.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; + vkPhysicalDeviceProperties2KHR.pNext = &vkPhysicalDeviceIDPropertiesKHR; - vkGetPhysicalDeviceProperties2(dev, &vkPhysicalDeviceProperties2KHR); + vkGetPhysicalDeviceProperties2(dev, &vkPhysicalDeviceProperties2KHR); - isSuitable = hasAllExtensions(dev, deviceExtensions) - && isDeviceCompatible(vkPhysicalDeviceIDPropertiesKHR.deviceUUID, (size_t)VK_UUID_SIZE) - && !formats.empty() && !presentModes.empty() - && findGraphicsQueueIndicies(dev, m_surface, graphicsQueueIndex, presentQueueIndex); + isSuitable = hasAllExtensions(dev, deviceExtensions) && + isDeviceCompatible(vkPhysicalDeviceIDPropertiesKHR.deviceUUID, + (size_t)VK_UUID_SIZE) && + !formats.empty() && !presentModes.empty() && + findGraphicsQueueIndicies(dev, m_surface, graphicsQueueIndex, + presentQueueIndex); - if (isSuitable) { - memcpy((void *)m_deviceUUID, vkPhysicalDeviceIDPropertiesKHR.deviceUUID, sizeof(m_deviceUUID)); - } + if (isSuitable) { + memcpy((void *)m_deviceUUID, vkPhysicalDeviceIDPropertiesKHR.deviceUUID, + sizeof(m_deviceUUID)); + } - return isSuitable; + return isSuitable; } bool VulkanBaseApp::isVkPhysicalDeviceUuid(void *Uuid) { - return !memcmp((void *)m_deviceUUID, Uuid, (size_t)VK_UUID_SIZE); + return !memcmp((void *)m_deviceUUID, Uuid, (size_t)VK_UUID_SIZE); } -void VulkanBaseApp::createDevice() -{ - { - uint32_t deviceCount = 0; - vkEnumeratePhysicalDevices(m_instance, &deviceCount, nullptr); - if (deviceCount == 0) { - throw std::runtime_error("Failed to find Vulkan capable GPUs!"); - } - std::vector phyDevs(deviceCount); - vkEnumeratePhysicalDevices(m_instance, &deviceCount, phyDevs.data()); - std::vector::iterator it = std::find_if(phyDevs.begin(), phyDevs.end(), - std::bind(&VulkanBaseApp::isSuitableDevice, this, std::placeholders::_1)); - if (it == phyDevs.end()) { - printf("\nNo suitable device found! Waiving Execution\n"); - exit(EXIT_WAIVED); - } - m_physicalDevice = *it; +void VulkanBaseApp::createDevice() { + { + uint32_t deviceCount = 0; + vkEnumeratePhysicalDevices(m_instance, &deviceCount, nullptr); + if (deviceCount == 0) { + throw std::runtime_error("Failed to find Vulkan capable GPUs!"); } - - uint32_t graphicsQueueIndex, presentQueueIndex; - findGraphicsQueueIndicies(m_physicalDevice, m_surface, graphicsQueueIndex, presentQueueIndex); - - std::vector queueCreateInfos; - std::set uniqueFamilyIndices = { graphicsQueueIndex, presentQueueIndex }; - - float queuePriority = 1.0f; - - for (uint32_t queueFamily : uniqueFamilyIndices) { - VkDeviceQueueCreateInfo queueCreateInfo = {}; - queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfo.queueFamilyIndex = graphicsQueueIndex; - queueCreateInfo.queueCount = 1; - queueCreateInfo.pQueuePriorities = &queuePriority; - queueCreateInfos.push_back(queueCreateInfo); + std::vector phyDevs(deviceCount); + vkEnumeratePhysicalDevices(m_instance, &deviceCount, phyDevs.data()); + std::vector::iterator it = + std::find_if(phyDevs.begin(), phyDevs.end(), + std::bind(&VulkanBaseApp::isSuitableDevice, this, + std::placeholders::_1)); + if (it == phyDevs.end()) { + printf("\nNo suitable device found! Waiving Execution\n"); + exit(EXIT_WAIVED); } + m_physicalDevice = *it; + } - VkPhysicalDeviceFeatures deviceFeatures = {}; - deviceFeatures.fillModeNonSolid = true; + uint32_t graphicsQueueIndex, presentQueueIndex; + findGraphicsQueueIndicies(m_physicalDevice, m_surface, graphicsQueueIndex, + presentQueueIndex); - VkDeviceCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + std::vector queueCreateInfos; + std::set uniqueFamilyIndices = {graphicsQueueIndex, + presentQueueIndex}; - createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); + float queuePriority = 1.0f; - createInfo.pEnabledFeatures = &deviceFeatures; + for (uint32_t queueFamily : uniqueFamilyIndices) { + VkDeviceQueueCreateInfo queueCreateInfo = {}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = graphicsQueueIndex; + queueCreateInfo.queueCount = 1; + queueCreateInfo.pQueuePriorities = &queuePriority; + queueCreateInfos.push_back(queueCreateInfo); + } - std::vector deviceExtensions = getRequiredDeviceExtensions(); - deviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + VkPhysicalDeviceFeatures deviceFeatures = {}; + deviceFeatures.fillModeNonSolid = true; - createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); - createInfo.ppEnabledExtensionNames = deviceExtensions.data(); + VkDeviceCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - if (m_enableValidation) { - createInfo.enabledLayerCount = static_cast(countof(validationLayers)); - createInfo.ppEnabledLayerNames = validationLayers; - } - else { - createInfo.enabledLayerCount = 0; - } + createInfo.pQueueCreateInfos = queueCreateInfos.data(); + createInfo.queueCreateInfoCount = + static_cast(queueCreateInfos.size()); - if (vkCreateDevice(m_physicalDevice, &createInfo, nullptr, &m_device) != VK_SUCCESS) { - throw std::runtime_error("failed to create logical device!"); - } + createInfo.pEnabledFeatures = &deviceFeatures; - vkGetDeviceQueue(m_device, graphicsQueueIndex, 0, &m_graphicsQueue); - vkGetDeviceQueue(m_device, presentQueueIndex, 0, &m_presentQueue); + std::vector deviceExtensions = getRequiredDeviceExtensions(); + deviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + + createInfo.enabledExtensionCount = + static_cast(deviceExtensions.size()); + createInfo.ppEnabledExtensionNames = deviceExtensions.data(); + + if (m_enableValidation) { + createInfo.enabledLayerCount = + static_cast(countof(validationLayers)); + createInfo.ppEnabledLayerNames = validationLayers; + } else { + createInfo.enabledLayerCount = 0; + } + + if (vkCreateDevice(m_physicalDevice, &createInfo, nullptr, &m_device) != + VK_SUCCESS) { + throw std::runtime_error("failed to create logical device!"); + } + + vkGetDeviceQueue(m_device, graphicsQueueIndex, 0, &m_graphicsQueue); + vkGetDeviceQueue(m_device, presentQueueIndex, 0, &m_presentQueue); } -static VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) -{ - if (availableFormats.size() == 1 && availableFormats[0].format == VK_FORMAT_UNDEFINED) { - return { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }; - } +static VkSurfaceFormatKHR chooseSwapSurfaceFormat( + const std::vector &availableFormats) { + if (availableFormats.size() == 1 && + availableFormats[0].format == VK_FORMAT_UNDEFINED) { + return {VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}; + } - for (const auto & availableFormat : availableFormats) { - if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - return availableFormat; - } + for (const auto &availableFormat : availableFormats) { + if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && + availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + return availableFormat; } + } - return availableFormats[0]; + return availableFormats[0]; } -static VkPresentModeKHR chooseSwapPresentMode(const std::vector& availablePresentModes) -{ - VkPresentModeKHR bestMode = VK_PRESENT_MODE_FIFO_KHR; +static VkPresentModeKHR chooseSwapPresentMode( + const std::vector &availablePresentModes) { + VkPresentModeKHR bestMode = VK_PRESENT_MODE_FIFO_KHR; - for (const auto & availablePresentMode : availablePresentModes) { - if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) { - return availablePresentMode; - } - else if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) { - bestMode = availablePresentMode; - } + for (const auto &availablePresentMode : availablePresentModes) { + if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) { + return availablePresentMode; + } else if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) { + bestMode = availablePresentMode; } + } - return bestMode; + return bestMode; } -static VkExtent2D chooseSwapExtent(GLFWwindow *window, const VkSurfaceCapabilitiesKHR& capabilities) -{ - if (capabilities.currentExtent.width != std::numeric_limits::max()) { - return capabilities.currentExtent; - } - else { - int width, height; - glfwGetFramebufferSize(window, &width, &height); - VkExtent2D actualExtent = { static_cast(width), static_cast(height) }; - - actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); - actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); - - return actualExtent; - } -} - -void VulkanBaseApp::createSwapChain() -{ - VkSurfaceCapabilitiesKHR capabilities; - VkSurfaceFormatKHR format; - VkPresentModeKHR presentMode; - VkExtent2D extent; - uint32_t imageCount; - - { - std::vector formats; - std::vector presentModes; - - getSwapChainProperties(m_physicalDevice, m_surface, capabilities, formats, presentModes); - format = chooseSwapSurfaceFormat(formats); - presentMode = chooseSwapPresentMode(presentModes); - extent = chooseSwapExtent(m_window, capabilities); - imageCount = capabilities.minImageCount + 1; - if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) { - imageCount = capabilities.maxImageCount; - } - } - - VkSwapchainCreateInfoKHR createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - createInfo.surface = m_surface; - - createInfo.minImageCount = imageCount; - createInfo.imageFormat = format.format; - createInfo.imageColorSpace = format.colorSpace; - createInfo.imageExtent = extent; - createInfo.imageArrayLayers = 1; - createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - - uint32_t queueFamilyIndices[2]; - findGraphicsQueueIndicies(m_physicalDevice, m_surface, queueFamilyIndices[0], queueFamilyIndices[1]); - - if (queueFamilyIndices[0] != queueFamilyIndices[1]) { - createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; - createInfo.queueFamilyIndexCount = countof(queueFamilyIndices); - createInfo.pQueueFamilyIndices = queueFamilyIndices; - } - else { - createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - } - - createInfo.preTransform = capabilities.currentTransform; - createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - createInfo.presentMode = presentMode; - createInfo.clipped = VK_TRUE; - - createInfo.oldSwapchain = VK_NULL_HANDLE; - - if (vkCreateSwapchainKHR(m_device, &createInfo, nullptr, &m_swapChain) != VK_SUCCESS) { - throw std::runtime_error("failed to create swap chain!"); - } - - vkGetSwapchainImagesKHR(m_device, m_swapChain, &imageCount, nullptr); - m_swapChainImages.resize(imageCount); - vkGetSwapchainImagesKHR(m_device, m_swapChain, &imageCount, m_swapChainImages.data()); - - m_swapChainFormat = format.format; - m_swapChainExtent = extent; -} - -static VkImageView createImageView(VkDevice dev, VkImage image, VkFormat format, VkImageAspectFlags aspectFlags) -{ - VkImageView imageView; - VkImageViewCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - createInfo.image = image; - createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - createInfo.format = format; - createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.subresourceRange.aspectMask = aspectFlags; - createInfo.subresourceRange.baseMipLevel = 0; - createInfo.subresourceRange.levelCount = 1; - createInfo.subresourceRange.baseArrayLayer = 0; - createInfo.subresourceRange.layerCount = 1; - if (vkCreateImageView(dev, &createInfo, nullptr, &imageView) != VK_SUCCESS) { - throw std::runtime_error("Failed to create image views!"); - } - - return imageView; -} - -static void createImage(VkPhysicalDevice physicalDevice, VkDevice device, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) -{ - VkImageCreateInfo imageInfo = {}; - imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent.width = width; - imageInfo.extent.height = height; - imageInfo.extent.depth = 1; - imageInfo.mipLevels = 1; - imageInfo.arrayLayers = 1; - imageInfo.format = format; - imageInfo.tiling = tiling; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.usage = usage; - imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - if (vkCreateImage(device, &imageInfo, nullptr, &image) != VK_SUCCESS) { - throw std::runtime_error("failed to create image!"); - } - - VkMemoryRequirements memRequirements; - vkGetImageMemoryRequirements(device, image, &memRequirements); - - VkMemoryAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.allocationSize = memRequirements.size; - allocInfo.memoryTypeIndex = findMemoryType(physicalDevice, memRequirements.memoryTypeBits, properties); - - if (vkAllocateMemory(device, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate image memory!"); - } - - vkBindImageMemory(device, image, imageMemory, 0); -} - -void VulkanBaseApp::createImageViews() -{ - m_swapChainImageViews.resize(m_swapChainImages.size()); - - for (uint32_t i = 0; i < m_swapChainImages.size(); i++) { - m_swapChainImageViews[i] = createImageView(m_device, m_swapChainImages[i], m_swapChainFormat, VK_IMAGE_ASPECT_COLOR_BIT); - } -} - -void VulkanBaseApp::createRenderPass() -{ - VkAttachmentDescription colorAttachment = {}; - colorAttachment.format = m_swapChainFormat; - colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; - // Set up the render pass to preserve the contents of the attachment while rendering. - // By doing this the points already rendered are not cleared and thus displays growing number of - // points with time eventhough the number of points rendered per frame is constant - colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - - VkAttachmentReference colorAttachmentRef = {}; - colorAttachmentRef.attachment = 0; - colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkAttachmentDescription depthAttachment = {}; - depthAttachment.format = findSupportedFormat(m_physicalDevice, - { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT }, - VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); - depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; - depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - VkAttachmentReference depthAttachmentRef = {}; - depthAttachmentRef.attachment = 1; - depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &colorAttachmentRef; - subpass.pDepthStencilAttachment = &depthAttachmentRef; - - - VkSubpassDependency dependency = {}; - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.srcAccessMask = 0; - dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - - VkAttachmentDescription attachments[] = { colorAttachment, depthAttachment }; - VkRenderPassCreateInfo renderPassInfo = {}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderPassInfo.attachmentCount = countof(attachments); - renderPassInfo.pAttachments = attachments; - renderPassInfo.subpassCount = 1; - renderPassInfo.pSubpasses = &subpass; - renderPassInfo.dependencyCount = 1; - renderPassInfo.pDependencies = &dependency; - - if (vkCreateRenderPass(m_device, &renderPassInfo, nullptr, &m_renderPass) != VK_SUCCESS) { - throw std::runtime_error("failed to create render pass!"); - } -} - -void VulkanBaseApp::createDescriptorSetLayout() -{ - VkDescriptorSetLayoutBinding uboLayoutBinding = {}; - uboLayoutBinding.binding = 0; - uboLayoutBinding.descriptorCount = 1; - uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - uboLayoutBinding.pImmutableSamplers = nullptr; - uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - - VkDescriptorSetLayoutCreateInfo layoutInfo = {}; - layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layoutInfo.bindingCount = 1; - layoutInfo.pBindings = &uboLayoutBinding; - - if (vkCreateDescriptorSetLayout(m_device, &layoutInfo, nullptr, &m_descriptorSetLayout) != VK_SUCCESS) { - throw std::runtime_error("failed to create descriptor set layout!"); - } -} - -VkShaderModule createShaderModule(VkDevice device, const char *filename) -{ - std::vector shaderContents; - std::ifstream shaderFile(filename, std::ios_base::in | std::ios_base::binary); - VkShaderModuleCreateInfo createInfo = {}; - VkShaderModule shaderModule; - - if (!shaderFile.good()) { - throw std::runtime_error("Failed to load shader contents"); - } - readFile(shaderFile, shaderContents); - - createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - createInfo.codeSize = shaderContents.size(); - createInfo.pCode = reinterpret_cast(shaderContents.data()); - - if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { - throw std::runtime_error("Failed to create shader module!"); - } - - return shaderModule; -} - -void VulkanBaseApp::getVertexDescriptions(std::vector& bindingDesc, std::vector& attribDesc) -{ -} - -void VulkanBaseApp::getAssemblyStateInfo(VkPipelineInputAssemblyStateCreateInfo& info) -{ - -} - -void VulkanBaseApp::createGraphicsPipeline() -{ - std::vector shaderStageInfos(m_shaderFiles.size()); - for (size_t i = 0; i < m_shaderFiles.size(); i++) { - shaderStageInfos[i] = {}; - shaderStageInfos[i].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - shaderStageInfos[i].stage = m_shaderFiles[i].first; - shaderStageInfos[i].module = createShaderModule(m_device, m_shaderFiles[i].second.c_str()); - shaderStageInfos[i].pName = "main"; - } - - VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; - - std::vector vertexBindingDescriptions; - std::vector vertexAttributeDescriptions; - - getVertexDescriptions(vertexBindingDescriptions, vertexAttributeDescriptions); - - vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertexInputInfo.vertexBindingDescriptionCount = static_cast(vertexBindingDescriptions.size()); - vertexInputInfo.pVertexBindingDescriptions = vertexBindingDescriptions.data(); - vertexInputInfo.vertexAttributeDescriptionCount = static_cast(vertexAttributeDescriptions.size()); - vertexInputInfo.pVertexAttributeDescriptions = vertexAttributeDescriptions.data(); - - VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; - getAssemblyStateInfo(inputAssembly); - - VkViewport viewport = {}; - viewport.x = 0.0f; - viewport.y = 0.0f; - viewport.width = (float)m_swapChainExtent.width; - viewport.height = (float)m_swapChainExtent.height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - VkRect2D scissor = {}; - scissor.offset = { 0, 0 }; - scissor.extent = m_swapChainExtent; - - VkPipelineViewportStateCreateInfo viewportState = {}; - viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportState.viewportCount = 1; - viewportState.pViewports = &viewport; - viewportState.scissorCount = 1; - viewportState.pScissors = &scissor; - - VkPipelineRasterizationStateCreateInfo rasterizer = {}; - rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizer.depthClampEnable = VK_FALSE; - rasterizer.rasterizerDiscardEnable = VK_FALSE; - rasterizer.polygonMode = VK_POLYGON_MODE_POINT; - rasterizer.lineWidth = 1.0f; - rasterizer.cullMode = VK_CULL_MODE_NONE; - rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; - rasterizer.depthBiasEnable = VK_FALSE; - - VkPipelineMultisampleStateCreateInfo multisampling = {}; - multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling.sampleShadingEnable = VK_FALSE; - multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - multisampling.minSampleShading = 1.0f; // Optional - multisampling.pSampleMask = nullptr; // Optional - multisampling.alphaToCoverageEnable = VK_FALSE; // Optional - multisampling.alphaToOneEnable = VK_FALSE; // Optional - - VkPipelineDepthStencilStateCreateInfo depthStencil = {}; - depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depthStencil.depthTestEnable = VK_TRUE; - depthStencil.depthWriteEnable = VK_TRUE; - depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; - depthStencil.depthBoundsTestEnable = VK_FALSE; - depthStencil.stencilTestEnable = VK_FALSE; - - VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; - colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - colorBlendAttachment.blendEnable = VK_FALSE; - - VkPipelineColorBlendStateCreateInfo colorBlending = {}; - colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlending.logicOpEnable = VK_FALSE; - colorBlending.logicOp = VK_LOGIC_OP_COPY; - colorBlending.attachmentCount = 1; - colorBlending.pAttachments = &colorBlendAttachment; - colorBlending.blendConstants[0] = 0.0f; - colorBlending.blendConstants[1] = 0.0f; - colorBlending.blendConstants[2] = 0.0f; - colorBlending.blendConstants[3] = 0.0f; - - VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; - pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutInfo.setLayoutCount = 1; // Optional - pipelineLayoutInfo.pSetLayouts = &m_descriptorSetLayout; // Optional - pipelineLayoutInfo.pushConstantRangeCount = 0; // Optional - pipelineLayoutInfo.pPushConstantRanges = nullptr; // Optional - - if (vkCreatePipelineLayout(m_device, &pipelineLayoutInfo, nullptr, &m_pipelineLayout) != VK_SUCCESS) { - throw std::runtime_error("failed to create pipeline layout!"); - } - - VkGraphicsPipelineCreateInfo pipelineInfo = {}; - pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineInfo.stageCount = static_cast(shaderStageInfos.size()); - pipelineInfo.pStages = shaderStageInfos.data(); - - pipelineInfo.pVertexInputState = &vertexInputInfo; - pipelineInfo.pInputAssemblyState = &inputAssembly; - pipelineInfo.pViewportState = &viewportState; - pipelineInfo.pRasterizationState = &rasterizer; - pipelineInfo.pMultisampleState = &multisampling; - pipelineInfo.pDepthStencilState = &depthStencil; // Optional - pipelineInfo.pColorBlendState = &colorBlending; - pipelineInfo.pDynamicState = nullptr; // Optional - - pipelineInfo.layout = m_pipelineLayout; - - pipelineInfo.renderPass = m_renderPass; - pipelineInfo.subpass = 0; - - pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; // Optional - pipelineInfo.basePipelineIndex = -1; // Optional - - if (vkCreateGraphicsPipelines(m_device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &m_graphicsPipeline) != VK_SUCCESS) { - throw std::runtime_error("failed to create graphics pipeline!"); - } - - for (size_t i = 0; i < shaderStageInfos.size(); i++) { - vkDestroyShaderModule(m_device, shaderStageInfos[i].module, nullptr); - } -} - -void VulkanBaseApp::createFramebuffers() -{ - m_swapChainFramebuffers.resize(m_swapChainImageViews.size()); - for (size_t i = 0; i < m_swapChainImageViews.size(); i++) { - VkImageView attachments[] = { - m_swapChainImageViews[i], - m_depthImageView - }; - - VkFramebufferCreateInfo framebufferInfo = {}; - framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferInfo.renderPass = m_renderPass; - framebufferInfo.attachmentCount = countof(attachments); - framebufferInfo.pAttachments = attachments; - framebufferInfo.width = m_swapChainExtent.width; - framebufferInfo.height = m_swapChainExtent.height; - framebufferInfo.layers = 1; - - if (vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &m_swapChainFramebuffers[i]) != VK_SUCCESS) { - throw std::runtime_error("failed to create framebuffer!"); - } - } -} - -void VulkanBaseApp::createCommandPool() -{ - VkCommandPoolCreateInfo poolInfo = {}; - uint32_t graphicsIndex, presentIndex; - - findGraphicsQueueIndicies(m_physicalDevice, m_surface, graphicsIndex, presentIndex); - - poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - poolInfo.queueFamilyIndex = graphicsIndex; - poolInfo.flags = 0; // Optional - - if (vkCreateCommandPool(m_device, &poolInfo, nullptr, &m_commandPool) != VK_SUCCESS) { - throw std::runtime_error("Failed to create command pool!"); - } -} - -static void transitionImageLayout(VulkanBaseApp *app, VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout) -{ - VkCommandBuffer commandBuffer = app->beginSingleTimeCommands(); - - VkImageMemoryBarrier barrier = {}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.oldLayout = oldLayout; - barrier.newLayout = newLayout; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = image; - - if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - - if (format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT) { - barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - } - } - else { - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - } - - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - - VkPipelineStageFlags sourceStage; - VkPipelineStageFlags destinationStage; - - if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { - barrier.srcAccessMask = 0; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - - sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - - sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { - barrier.srcAccessMask = 0; - barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - - sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - } - else { - throw std::invalid_argument("unsupported layout transition!"); - } - - vkCmdPipelineBarrier( - commandBuffer, - sourceStage, destinationStage, - 0, - 0, nullptr, - 0, nullptr, - 1, &barrier - ); - - app->endSingleTimeCommands(commandBuffer); -} - -void VulkanBaseApp::createDepthResources() -{ - VkFormat depthFormat = findSupportedFormat(m_physicalDevice, - { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT }, - VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); - createImage(m_physicalDevice, m_device, m_swapChainExtent.width, m_swapChainExtent.height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_depthImage, m_depthImageMemory); - m_depthImageView = createImageView(m_device, m_depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT); - transitionImageLayout(this, m_depthImage, depthFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); -} - -void VulkanBaseApp::createUniformBuffers() -{ - VkDeviceSize size = getUniformSize(); - if (size > 0) { - m_uniformBuffers.resize(m_swapChainImages.size()); - m_uniformMemory.resize(m_swapChainImages.size()); - for (size_t i = 0; i < m_uniformBuffers.size(); i++) { - createBuffer(getUniformSize(), - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - m_uniformBuffers[i], m_uniformMemory[i]); - } - } -} - -void VulkanBaseApp::createDescriptorPool() -{ - VkDescriptorPoolSize poolSize = {}; - poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - poolSize.descriptorCount = static_cast(m_swapChainImages.size()); - VkDescriptorPoolCreateInfo poolInfo = {}; - poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - poolInfo.poolSizeCount = 1; - poolInfo.pPoolSizes = &poolSize; - poolInfo.maxSets = static_cast(m_swapChainImages.size());; - if (vkCreateDescriptorPool(m_device, &poolInfo, nullptr, &m_descriptorPool) != VK_SUCCESS) { - throw std::runtime_error("failed to create descriptor pool!"); - } -} - -void VulkanBaseApp::createDescriptorSets() -{ - std::vector layouts(m_swapChainImages.size(), m_descriptorSetLayout); - VkDescriptorSetAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocInfo.descriptorPool = m_descriptorPool; - allocInfo.descriptorSetCount = static_cast(m_swapChainImages.size()); - allocInfo.pSetLayouts = layouts.data(); - m_descriptorSets.resize(m_swapChainImages.size()); - - if (vkAllocateDescriptorSets(m_device, &allocInfo, m_descriptorSets.data()) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate descriptor sets!"); - } - - VkDescriptorBufferInfo bufferInfo = {}; - bufferInfo.offset = 0; - bufferInfo.range = VK_WHOLE_SIZE; - VkWriteDescriptorSet descriptorWrite = {}; - descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrite.dstBinding = 0; - descriptorWrite.dstArrayElement = 0; - descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptorWrite.descriptorCount = 1; - descriptorWrite.pBufferInfo = &bufferInfo; - descriptorWrite.pImageInfo = nullptr; // Optional - descriptorWrite.pTexelBufferView = nullptr; // Optional - - for (size_t i = 0; i < m_swapChainImages.size(); i++) { - bufferInfo.buffer = m_uniformBuffers[i]; - descriptorWrite.dstSet = m_descriptorSets[i]; - vkUpdateDescriptorSets(m_device, 1, &descriptorWrite, 0, nullptr); - } -} - -void VulkanBaseApp::createCommandBuffers() -{ - m_commandBuffers.resize(m_swapChainFramebuffers.size()); - VkCommandBufferAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.commandPool = m_commandPool; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandBufferCount = (uint32_t)m_commandBuffers.size(); - - if (vkAllocateCommandBuffers(m_device, &allocInfo, m_commandBuffers.data()) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate command buffers!"); - } - - for (size_t i = 0; i < m_commandBuffers.size(); i++) { - VkCommandBufferBeginInfo beginInfo = {}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; - beginInfo.pInheritanceInfo = nullptr; // Optional - - if (vkBeginCommandBuffer(m_commandBuffers[i], &beginInfo) != VK_SUCCESS) { - throw std::runtime_error("failed to begin recording command buffer!"); - } - - VkRenderPassBeginInfo renderPassInfo = {}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = m_renderPass; - renderPassInfo.framebuffer = m_swapChainFramebuffers[i]; - - renderPassInfo.renderArea.offset = { 0, 0 }; - renderPassInfo.renderArea.extent = m_swapChainExtent; - - VkClearValue clearColors[2]; - clearColors[0].color = { 0.0f, 0.0f, 0.0f, 1.0f }; - clearColors[1].depthStencil = { 1.0f, 0 }; - renderPassInfo.clearValueCount = countof(clearColors); - renderPassInfo.pClearValues = clearColors; - - vkCmdBeginRenderPass(m_commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - - vkCmdBindPipeline(m_commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - - vkCmdBindDescriptorSets(m_commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descriptorSets[i], 0, nullptr); - - fillRenderingCommandBuffer(m_commandBuffers[i]); - - vkCmdEndRenderPass(m_commandBuffers[i]); - - if (vkEndCommandBuffer(m_commandBuffers[i]) != VK_SUCCESS) { - throw std::runtime_error("failed to record command buffer!"); - } - } -} - -void VulkanBaseApp::createSyncObjects() -{ - VkSemaphoreCreateInfo semaphoreInfo = {}; - semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - VkFenceCreateInfo fenceInfo = {}; - fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - - m_inFlightFences.resize(MAX_FRAMES_IN_FLIGHT); - m_imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT); - m_renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT); - - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - if (vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_imageAvailableSemaphores[i]) != VK_SUCCESS) { - throw std::runtime_error("Failed to create image available semaphore!"); - } - if (vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_renderFinishedSemaphores[i]) != VK_SUCCESS) { - throw std::runtime_error("Failed to create image available semaphore!"); - } - if (vkCreateFence(m_device, &fenceInfo, nullptr, &m_inFlightFences[i]) != VK_SUCCESS) { - throw std::runtime_error("Failed to create image available semaphore!"); - } - } -} - -void VulkanBaseApp::getWaitFrameSemaphores(std::vector& wait, std::vector& waitStages) const -{ -} - -void VulkanBaseApp::getSignalFrameSemaphores(std::vector& signal) const -{ -} - -VkDeviceSize VulkanBaseApp::getUniformSize() const -{ - return VkDeviceSize(0); -} - -void VulkanBaseApp::updateUniformBuffer(uint32_t imageIndex, size_t frame) -{ -} - -void VulkanBaseApp::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) -{ - VkBufferCreateInfo bufferInfo = {}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = size; - bufferInfo.usage = usage; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - if (vkCreateBuffer(m_device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { - throw std::runtime_error("failed to create buffer!"); - } - - VkMemoryRequirements memRequirements; - vkGetBufferMemoryRequirements(m_device, buffer, &memRequirements); - - VkMemoryAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.allocationSize = memRequirements.size; - allocInfo.memoryTypeIndex = findMemoryType(m_physicalDevice, memRequirements.memoryTypeBits, properties); - - if (vkAllocateMemory(m_device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate buffer memory!"); - } - - vkBindBufferMemory(m_device, buffer, bufferMemory, 0); -} - -void VulkanBaseApp::createExternalBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkExternalMemoryHandleTypeFlagsKHR extMemHandleType, VkBuffer& buffer, VkDeviceMemory& bufferMemory) -{ - VkBufferCreateInfo bufferInfo = {}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = size; - bufferInfo.usage = usage; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - if (vkCreateBuffer(m_device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { - throw std::runtime_error("failed to create buffer!"); - } - - VkMemoryRequirements memRequirements; - vkGetBufferMemoryRequirements(m_device, buffer, &memRequirements); - -#ifdef _WIN64 - WindowsSecurityAttributes winSecurityAttributes; - - VkExportMemoryWin32HandleInfoKHR vulkanExportMemoryWin32HandleInfoKHR = {}; - vulkanExportMemoryWin32HandleInfoKHR.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR; - vulkanExportMemoryWin32HandleInfoKHR.pNext = NULL; - vulkanExportMemoryWin32HandleInfoKHR.pAttributes = &winSecurityAttributes; - vulkanExportMemoryWin32HandleInfoKHR.dwAccess = DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE; - vulkanExportMemoryWin32HandleInfoKHR.name = (LPCWSTR)NULL; -#endif - VkExportMemoryAllocateInfoKHR vulkanExportMemoryAllocateInfoKHR = {}; - vulkanExportMemoryAllocateInfoKHR.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR; -#ifdef _WIN64 - vulkanExportMemoryAllocateInfoKHR.pNext = extMemHandleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR ? &vulkanExportMemoryWin32HandleInfoKHR : NULL; - vulkanExportMemoryAllocateInfoKHR.handleTypes = extMemHandleType; -#else - vulkanExportMemoryAllocateInfoKHR.pNext = NULL; - vulkanExportMemoryAllocateInfoKHR.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; -#endif - VkMemoryAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.pNext = &vulkanExportMemoryAllocateInfoKHR; - allocInfo.allocationSize = memRequirements.size; - allocInfo.memoryTypeIndex = findMemoryType(m_physicalDevice, memRequirements.memoryTypeBits, properties); - - if (vkAllocateMemory(m_device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) { - throw std::runtime_error("failed to allocate external buffer memory!"); - } - - vkBindBufferMemory(m_device, buffer, bufferMemory, 0); -} - -void *VulkanBaseApp::getMemHandle(VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagBits handleType) -{ -#ifdef _WIN64 - HANDLE handle = 0; - - VkMemoryGetWin32HandleInfoKHR vkMemoryGetWin32HandleInfoKHR = {}; - vkMemoryGetWin32HandleInfoKHR.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; - vkMemoryGetWin32HandleInfoKHR.pNext = NULL; - vkMemoryGetWin32HandleInfoKHR.memory = memory; - vkMemoryGetWin32HandleInfoKHR.handleType = handleType; - - PFN_vkGetMemoryWin32HandleKHR fpGetMemoryWin32HandleKHR; - fpGetMemoryWin32HandleKHR = (PFN_vkGetMemoryWin32HandleKHR)vkGetDeviceProcAddr(m_device, "vkGetMemoryWin32HandleKHR"); - if (!fpGetMemoryWin32HandleKHR) { - throw std::runtime_error("Failed to retrieve vkGetMemoryWin32HandleKHR!"); - } - if (fpGetMemoryWin32HandleKHR(m_device, &vkMemoryGetWin32HandleInfoKHR, &handle) != VK_SUCCESS) { - throw std::runtime_error("Failed to retrieve handle for buffer!"); - } - return (void *)handle; -#else - int fd = -1; - - VkMemoryGetFdInfoKHR vkMemoryGetFdInfoKHR = {}; - vkMemoryGetFdInfoKHR.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; - vkMemoryGetFdInfoKHR.pNext = NULL; - vkMemoryGetFdInfoKHR.memory = memory; - vkMemoryGetFdInfoKHR.handleType = handleType; - - PFN_vkGetMemoryFdKHR fpGetMemoryFdKHR; - fpGetMemoryFdKHR = (PFN_vkGetMemoryFdKHR)vkGetDeviceProcAddr(m_device, "vkGetMemoryFdKHR"); - if (!fpGetMemoryFdKHR) { - throw std::runtime_error("Failed to retrieve vkGetMemoryWin32HandleKHR!"); - } - if (fpGetMemoryFdKHR(m_device, &vkMemoryGetFdInfoKHR, &fd) != VK_SUCCESS) { - throw std::runtime_error("Failed to retrieve handle for buffer!"); - } - return (void *)(uintptr_t)fd; -#endif /* _WIN64 */ -} - -void *VulkanBaseApp::getSemaphoreHandle(VkSemaphore semaphore, VkExternalSemaphoreHandleTypeFlagBits handleType) -{ -#ifdef _WIN64 - HANDLE handle; - - VkSemaphoreGetWin32HandleInfoKHR semaphoreGetWin32HandleInfoKHR = {}; - semaphoreGetWin32HandleInfoKHR.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR; - semaphoreGetWin32HandleInfoKHR.pNext = NULL; - semaphoreGetWin32HandleInfoKHR.semaphore = semaphore; - semaphoreGetWin32HandleInfoKHR.handleType = handleType; - - PFN_vkGetSemaphoreWin32HandleKHR fpGetSemaphoreWin32HandleKHR; - fpGetSemaphoreWin32HandleKHR = (PFN_vkGetSemaphoreWin32HandleKHR)vkGetDeviceProcAddr(m_device, "vkGetSemaphoreWin32HandleKHR"); - if (!fpGetSemaphoreWin32HandleKHR) { - throw std::runtime_error("Failed to retrieve vkGetMemoryWin32HandleKHR!"); - } - if (fpGetSemaphoreWin32HandleKHR(m_device, &semaphoreGetWin32HandleInfoKHR, &handle) != VK_SUCCESS) { - throw std::runtime_error("Failed to retrieve handle for buffer!"); - } - - return (void *)handle; -#else - int fd; - - VkSemaphoreGetFdInfoKHR semaphoreGetFdInfoKHR = {}; - semaphoreGetFdInfoKHR.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR; - semaphoreGetFdInfoKHR.pNext = NULL; - semaphoreGetFdInfoKHR.semaphore = semaphore; - semaphoreGetFdInfoKHR.handleType = handleType; - - PFN_vkGetSemaphoreFdKHR fpGetSemaphoreFdKHR; - fpGetSemaphoreFdKHR = (PFN_vkGetSemaphoreFdKHR)vkGetDeviceProcAddr(m_device, "vkGetSemaphoreFdKHR"); - if (!fpGetSemaphoreFdKHR) { - throw std::runtime_error("Failed to retrieve vkGetMemoryWin32HandleKHR!"); - } - if (fpGetSemaphoreFdKHR(m_device, &semaphoreGetFdInfoKHR, &fd) != VK_SUCCESS) { - throw std::runtime_error("Failed to retrieve handle for buffer!"); - } - - return (void *)(uintptr_t)fd; -#endif -} - -void VulkanBaseApp::createExternalSemaphore(VkSemaphore& semaphore, VkExternalSemaphoreHandleTypeFlagBits handleType) -{ - VkSemaphoreCreateInfo semaphoreInfo = {}; - semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - VkExportSemaphoreCreateInfoKHR exportSemaphoreCreateInfo = {}; - exportSemaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR; - -#ifdef _WIN64 - WindowsSecurityAttributes winSecurityAttributes; - - VkExportSemaphoreWin32HandleInfoKHR exportSemaphoreWin32HandleInfoKHR = {}; - exportSemaphoreWin32HandleInfoKHR.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR; - exportSemaphoreWin32HandleInfoKHR.pNext = NULL; - exportSemaphoreWin32HandleInfoKHR.pAttributes = &winSecurityAttributes; - exportSemaphoreWin32HandleInfoKHR.dwAccess = DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE; - exportSemaphoreWin32HandleInfoKHR.name = (LPCWSTR)NULL; - exportSemaphoreCreateInfo.pNext = (handleType & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT) ? &exportSemaphoreWin32HandleInfoKHR : NULL; -#else - exportSemaphoreCreateInfo.pNext = NULL; -#endif - exportSemaphoreCreateInfo.handleTypes = handleType; - semaphoreInfo.pNext = &exportSemaphoreCreateInfo; - - if (vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &semaphore) != VK_SUCCESS) { - throw std::runtime_error("failed to create synchronization objects for a CUDA-Vulkan!"); - } -} - -void VulkanBaseApp::importExternalBuffer(void *handle, VkExternalMemoryHandleTypeFlagBits handleType, size_t size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& memory) -{ - VkBufferCreateInfo bufferInfo = {}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = size; - bufferInfo.usage = usage; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - if (vkCreateBuffer(m_device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { - throw std::runtime_error("failed to create buffer!"); - } - - VkMemoryRequirements memRequirements; - vkGetBufferMemoryRequirements(m_device, buffer, &memRequirements); - -#ifdef _WIN64 - VkImportMemoryWin32HandleInfoKHR handleInfo = {}; - handleInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR; - handleInfo.pNext = NULL; - handleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; - handleInfo.handle = handle; - handleInfo.name = NULL; -#else - VkImportMemoryFdInfoKHR handleInfo = {}; - handleInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; - handleInfo.pNext = NULL; - handleInfo.fd = (int)(uintptr_t)handle; - handleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; -#endif /* _WIN64 */ - - VkMemoryAllocateInfo memAllocation = {}; - memAllocation.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memAllocation.pNext = (void *)&handleInfo; - memAllocation.allocationSize = size; - memAllocation.memoryTypeIndex = findMemoryType(m_physicalDevice, memRequirements.memoryTypeBits, properties); - - if (vkAllocateMemory(m_device, &memAllocation, nullptr, &memory) != VK_SUCCESS) { - throw std::runtime_error("Failed to import allocation!"); - } - - vkBindBufferMemory(m_device, buffer, memory, 0); -} - -void VulkanBaseApp::copyBuffer(VkBuffer dst, VkBuffer src, VkDeviceSize size) -{ - - VkCommandBuffer commandBuffer = beginSingleTimeCommands(); - - VkBufferCopy copyRegion = {}; - copyRegion.size = size; - vkCmdCopyBuffer(commandBuffer, src, dst, 1, ©Region); - - endSingleTimeCommands(commandBuffer); -} - -void VulkanBaseApp::drawFrame() -{ - size_t currentFrameIdx = m_currentFrame % MAX_FRAMES_IN_FLIGHT; - vkWaitForFences(m_device, 1, &m_inFlightFences[currentFrameIdx], VK_TRUE, std::numeric_limits::max()); - - uint32_t imageIndex; - VkResult result = vkAcquireNextImageKHR(m_device, m_swapChain, std::numeric_limits::max(), m_imageAvailableSemaphores[currentFrameIdx], VK_NULL_HANDLE, &imageIndex); - if (result == VK_ERROR_OUT_OF_DATE_KHR) { - recreateSwapChain(); - } - else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { - throw std::runtime_error("Failed to acquire swap chain image!"); - } - - updateUniformBuffer(imageIndex, m_currentFrame); - - VkSubmitInfo submitInfo = {}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - - std::vector waitSemaphores; - std::vector waitStages; - - waitSemaphores.push_back(m_imageAvailableSemaphores[currentFrameIdx]); - waitStages.push_back(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - getWaitFrameSemaphores(waitSemaphores, waitStages); - - submitInfo.waitSemaphoreCount = (uint32_t)waitSemaphores.size(); - submitInfo.pWaitSemaphores = waitSemaphores.data(); - submitInfo.pWaitDstStageMask = waitStages.data(); - - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &m_commandBuffers[imageIndex]; - - std::vector signalSemaphores; - getSignalFrameSemaphores(signalSemaphores); - signalSemaphores.push_back(m_renderFinishedSemaphores[currentFrameIdx]); - submitInfo.signalSemaphoreCount = (uint32_t)signalSemaphores.size(); - submitInfo.pSignalSemaphores = signalSemaphores.data(); - - vkResetFences(m_device, 1, &m_inFlightFences[currentFrameIdx]); - - if (vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, m_inFlightFences[currentFrameIdx]) != VK_SUCCESS) { - throw std::runtime_error("failed to submit draw command buffer!"); - } - - VkPresentInfoKHR presentInfo = {}; - presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - presentInfo.waitSemaphoreCount = 1; - presentInfo.pWaitSemaphores = &m_renderFinishedSemaphores[currentFrameIdx]; - - VkSwapchainKHR swapChains[] = { m_swapChain }; - presentInfo.swapchainCount = 1; - presentInfo.pSwapchains = swapChains; - presentInfo.pImageIndices = &imageIndex; - - result = vkQueuePresentKHR(m_presentQueue, &presentInfo); - if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || m_framebufferResized) { - recreateSwapChain(); - m_framebufferResized = false; - } - else if (result != VK_SUCCESS) { - throw std::runtime_error("Failed to acquire swap chain image!"); - } - - m_currentFrame++; -} - -void VulkanBaseApp::cleanupSwapChain() -{ - - if (m_depthImageView != VK_NULL_HANDLE) { - vkDestroyImageView(m_device, m_depthImageView, nullptr); - } - if (m_depthImage != VK_NULL_HANDLE) { - vkDestroyImage(m_device, m_depthImage, nullptr); - } - if (m_depthImageMemory != VK_NULL_HANDLE) { - vkFreeMemory(m_device, m_depthImageMemory, nullptr); - } - - for (size_t i = 0; i < m_uniformBuffers.size(); i++) { - vkDestroyBuffer(m_device, m_uniformBuffers[i], nullptr); - vkFreeMemory(m_device, m_uniformMemory[i], nullptr); - } - - if (m_descriptorPool != VK_NULL_HANDLE) { - vkDestroyDescriptorPool(m_device, m_descriptorPool, nullptr); - } - - for (size_t i = 0; i < m_swapChainFramebuffers.size(); i++) { - vkDestroyFramebuffer(m_device, m_swapChainFramebuffers[i], nullptr); - } - - if (m_graphicsPipeline != VK_NULL_HANDLE) { - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - } - - if (m_pipelineLayout != VK_NULL_HANDLE) { - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - } - - if (m_renderPass != VK_NULL_HANDLE) { - vkDestroyRenderPass(m_device, m_renderPass, nullptr); - } - - for (size_t i = 0; i < m_swapChainImageViews.size(); i++) { - vkDestroyImageView(m_device, m_swapChainImageViews[i], nullptr); - } - - if (m_swapChain != VK_NULL_HANDLE) { - vkDestroySwapchainKHR(m_device, m_swapChain, nullptr); - } -} - -void VulkanBaseApp::recreateSwapChain() -{ +static VkExtent2D chooseSwapExtent( + GLFWwindow *window, const VkSurfaceCapabilitiesKHR &capabilities) { + if (capabilities.currentExtent.width != + std::numeric_limits::max()) { + return capabilities.currentExtent; + } else { int width, height; + glfwGetFramebufferSize(window, &width, &height); + VkExtent2D actualExtent = {static_cast(width), + static_cast(height)}; + actualExtent.width = std::max( + capabilities.minImageExtent.width, + std::min(capabilities.maxImageExtent.width, actualExtent.width)); + actualExtent.height = std::max( + capabilities.minImageExtent.height, + std::min(capabilities.maxImageExtent.height, actualExtent.height)); + + return actualExtent; + } +} + +void VulkanBaseApp::createSwapChain() { + VkSurfaceCapabilitiesKHR capabilities; + VkSurfaceFormatKHR format; + VkPresentModeKHR presentMode; + VkExtent2D extent; + uint32_t imageCount; + + { + std::vector formats; + std::vector presentModes; + + getSwapChainProperties(m_physicalDevice, m_surface, capabilities, formats, + presentModes); + format = chooseSwapSurfaceFormat(formats); + presentMode = chooseSwapPresentMode(presentModes); + extent = chooseSwapExtent(m_window, capabilities); + imageCount = capabilities.minImageCount + 1; + if (capabilities.maxImageCount > 0 && + imageCount > capabilities.maxImageCount) { + imageCount = capabilities.maxImageCount; + } + } + + VkSwapchainCreateInfoKHR createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.surface = m_surface; + + createInfo.minImageCount = imageCount; + createInfo.imageFormat = format.format; + createInfo.imageColorSpace = format.colorSpace; + createInfo.imageExtent = extent; + createInfo.imageArrayLayers = 1; + createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + uint32_t queueFamilyIndices[2]; + findGraphicsQueueIndicies(m_physicalDevice, m_surface, queueFamilyIndices[0], + queueFamilyIndices[1]); + + if (queueFamilyIndices[0] != queueFamilyIndices[1]) { + createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + createInfo.queueFamilyIndexCount = countof(queueFamilyIndices); + createInfo.pQueueFamilyIndices = queueFamilyIndices; + } else { + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + } + + createInfo.preTransform = capabilities.currentTransform; + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + createInfo.presentMode = presentMode; + createInfo.clipped = VK_TRUE; + + createInfo.oldSwapchain = VK_NULL_HANDLE; + + if (vkCreateSwapchainKHR(m_device, &createInfo, nullptr, &m_swapChain) != + VK_SUCCESS) { + throw std::runtime_error("failed to create swap chain!"); + } + + vkGetSwapchainImagesKHR(m_device, m_swapChain, &imageCount, nullptr); + m_swapChainImages.resize(imageCount); + vkGetSwapchainImagesKHR(m_device, m_swapChain, &imageCount, + m_swapChainImages.data()); + + m_swapChainFormat = format.format; + m_swapChainExtent = extent; +} + +static VkImageView createImageView(VkDevice dev, VkImage image, VkFormat format, + VkImageAspectFlags aspectFlags) { + VkImageView imageView; + VkImageViewCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = image; + createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + createInfo.format = format; + createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.subresourceRange.aspectMask = aspectFlags; + createInfo.subresourceRange.baseMipLevel = 0; + createInfo.subresourceRange.levelCount = 1; + createInfo.subresourceRange.baseArrayLayer = 0; + createInfo.subresourceRange.layerCount = 1; + if (vkCreateImageView(dev, &createInfo, nullptr, &imageView) != VK_SUCCESS) { + throw std::runtime_error("Failed to create image views!"); + } + + return imageView; +} + +static void createImage(VkPhysicalDevice physicalDevice, VkDevice device, + uint32_t width, uint32_t height, VkFormat format, + VkImageTiling tiling, VkImageUsageFlags usage, + VkMemoryPropertyFlags properties, VkImage &image, + VkDeviceMemory &imageMemory) { + VkImageCreateInfo imageInfo = {}; + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.extent.width = width; + imageInfo.extent.height = height; + imageInfo.extent.depth = 1; + imageInfo.mipLevels = 1; + imageInfo.arrayLayers = 1; + imageInfo.format = format; + imageInfo.tiling = tiling; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.usage = usage; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + if (vkCreateImage(device, &imageInfo, nullptr, &image) != VK_SUCCESS) { + throw std::runtime_error("failed to create image!"); + } + + VkMemoryRequirements memRequirements; + vkGetImageMemoryRequirements(device, image, &memRequirements); + + VkMemoryAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = findMemoryType( + physicalDevice, memRequirements.memoryTypeBits, properties); + + if (vkAllocateMemory(device, &allocInfo, nullptr, &imageMemory) != + VK_SUCCESS) { + throw std::runtime_error("failed to allocate image memory!"); + } + + vkBindImageMemory(device, image, imageMemory, 0); +} + +void VulkanBaseApp::createImageViews() { + m_swapChainImageViews.resize(m_swapChainImages.size()); + + for (uint32_t i = 0; i < m_swapChainImages.size(); i++) { + m_swapChainImageViews[i] = + createImageView(m_device, m_swapChainImages[i], m_swapChainFormat, + VK_IMAGE_ASPECT_COLOR_BIT); + } +} + +void VulkanBaseApp::createRenderPass() { + VkAttachmentDescription colorAttachment = {}; + colorAttachment.format = m_swapChainFormat; + colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + // Set up the render pass to preserve the contents of the attachment while + // rendering. By doing this the points already rendered are not cleared and + // thus displays growing number of points with time eventhough the number of + // points rendered per frame is constant + colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + VkAttachmentReference colorAttachmentRef = {}; + colorAttachmentRef.attachment = 0; + colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkAttachmentDescription depthAttachment = {}; + depthAttachment.format = findSupportedFormat( + m_physicalDevice, {VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, + VK_FORMAT_D24_UNORM_S8_UINT}, + VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); + depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + depthAttachment.finalLayout = + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkAttachmentReference depthAttachmentRef = {}; + depthAttachmentRef.attachment = 1; + depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorAttachmentRef; + subpass.pDepthStencilAttachment = &depthAttachmentRef; + + VkSubpassDependency dependency = {}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.srcAccessMask = 0; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + + VkAttachmentDescription attachments[] = {colorAttachment, depthAttachment}; + VkRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.attachmentCount = countof(attachments); + renderPassInfo.pAttachments = attachments; + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = &subpass; + renderPassInfo.dependencyCount = 1; + renderPassInfo.pDependencies = &dependency; + + if (vkCreateRenderPass(m_device, &renderPassInfo, nullptr, &m_renderPass) != + VK_SUCCESS) { + throw std::runtime_error("failed to create render pass!"); + } +} + +void VulkanBaseApp::createDescriptorSetLayout() { + VkDescriptorSetLayoutBinding uboLayoutBinding = {}; + uboLayoutBinding.binding = 0; + uboLayoutBinding.descriptorCount = 1; + uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + uboLayoutBinding.pImmutableSamplers = nullptr; + uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + + VkDescriptorSetLayoutCreateInfo layoutInfo = {}; + layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layoutInfo.bindingCount = 1; + layoutInfo.pBindings = &uboLayoutBinding; + + if (vkCreateDescriptorSetLayout(m_device, &layoutInfo, nullptr, + &m_descriptorSetLayout) != VK_SUCCESS) { + throw std::runtime_error("failed to create descriptor set layout!"); + } +} + +VkShaderModule createShaderModule(VkDevice device, const char *filename) { + std::vector shaderContents; + std::ifstream shaderFile(filename, std::ios_base::in | std::ios_base::binary); + VkShaderModuleCreateInfo createInfo = {}; + VkShaderModule shaderModule; + + if (!shaderFile.good()) { + throw std::runtime_error("Failed to load shader contents"); + } + readFile(shaderFile, shaderContents); + + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = shaderContents.size(); + createInfo.pCode = reinterpret_cast(shaderContents.data()); + + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != + VK_SUCCESS) { + throw std::runtime_error("Failed to create shader module!"); + } + + return shaderModule; +} + +void VulkanBaseApp::getVertexDescriptions( + std::vector &bindingDesc, + std::vector &attribDesc) {} + +void VulkanBaseApp::getAssemblyStateInfo( + VkPipelineInputAssemblyStateCreateInfo &info) {} + +void VulkanBaseApp::createGraphicsPipeline() { + std::vector shaderStageInfos( + m_shaderFiles.size()); + for (size_t i = 0; i < m_shaderFiles.size(); i++) { + shaderStageInfos[i] = {}; + shaderStageInfos[i].sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStageInfos[i].stage = m_shaderFiles[i].first; + shaderStageInfos[i].module = + createShaderModule(m_device, m_shaderFiles[i].second.c_str()); + shaderStageInfos[i].pName = "main"; + } + + VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; + + std::vector vertexBindingDescriptions; + std::vector vertexAttributeDescriptions; + + getVertexDescriptions(vertexBindingDescriptions, vertexAttributeDescriptions); + + vertexInputInfo.sType = + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputInfo.vertexBindingDescriptionCount = + static_cast(vertexBindingDescriptions.size()); + vertexInputInfo.pVertexBindingDescriptions = vertexBindingDescriptions.data(); + vertexInputInfo.vertexAttributeDescriptionCount = + static_cast(vertexAttributeDescriptions.size()); + vertexInputInfo.pVertexAttributeDescriptions = + vertexAttributeDescriptions.data(); + + VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; + getAssemblyStateInfo(inputAssembly); + + VkViewport viewport = {}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = (float)m_swapChainExtent.width; + viewport.height = (float)m_swapChainExtent.height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor = {}; + scissor.offset = {0, 0}; + scissor.extent = m_swapChainExtent; + + VkPipelineViewportStateCreateInfo viewportState = {}; + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportState.viewportCount = 1; + viewportState.pViewports = &viewport; + viewportState.scissorCount = 1; + viewportState.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = VK_POLYGON_MODE_POINT; + rasterizer.lineWidth = 1.0f; + rasterizer.cullMode = VK_CULL_MODE_NONE; + rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; + rasterizer.depthBiasEnable = VK_FALSE; + + VkPipelineMultisampleStateCreateInfo multisampling = {}; + multisampling.sType = + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.sampleShadingEnable = VK_FALSE; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampling.minSampleShading = 1.0f; // Optional + multisampling.pSampleMask = nullptr; // Optional + multisampling.alphaToCoverageEnable = VK_FALSE; // Optional + multisampling.alphaToOneEnable = VK_FALSE; // Optional + + VkPipelineDepthStencilStateCreateInfo depthStencil = {}; + depthStencil.sType = + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencil.depthTestEnable = VK_TRUE; + depthStencil.depthWriteEnable = VK_TRUE; + depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; + depthStencil.depthBoundsTestEnable = VK_FALSE; + depthStencil.stencilTestEnable = VK_FALSE; + + VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; + colorBlendAttachment.colorWriteMask = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + colorBlendAttachment.blendEnable = VK_FALSE; + + VkPipelineColorBlendStateCreateInfo colorBlending = {}; + colorBlending.sType = + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlending.logicOpEnable = VK_FALSE; + colorBlending.logicOp = VK_LOGIC_OP_COPY; + colorBlending.attachmentCount = 1; + colorBlending.pAttachments = &colorBlendAttachment; + colorBlending.blendConstants[0] = 0.0f; + colorBlending.blendConstants[1] = 0.0f; + colorBlending.blendConstants[2] = 0.0f; + colorBlending.blendConstants[3] = 0.0f; + + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.setLayoutCount = 1; // Optional + pipelineLayoutInfo.pSetLayouts = &m_descriptorSetLayout; // Optional + pipelineLayoutInfo.pushConstantRangeCount = 0; // Optional + pipelineLayoutInfo.pPushConstantRanges = nullptr; // Optional + + if (vkCreatePipelineLayout(m_device, &pipelineLayoutInfo, nullptr, + &m_pipelineLayout) != VK_SUCCESS) { + throw std::runtime_error("failed to create pipeline layout!"); + } + + VkGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineInfo.stageCount = static_cast(shaderStageInfos.size()); + pipelineInfo.pStages = shaderStageInfos.data(); + + pipelineInfo.pVertexInputState = &vertexInputInfo; + pipelineInfo.pInputAssemblyState = &inputAssembly; + pipelineInfo.pViewportState = &viewportState; + pipelineInfo.pRasterizationState = &rasterizer; + pipelineInfo.pMultisampleState = &multisampling; + pipelineInfo.pDepthStencilState = &depthStencil; // Optional + pipelineInfo.pColorBlendState = &colorBlending; + pipelineInfo.pDynamicState = nullptr; // Optional + + pipelineInfo.layout = m_pipelineLayout; + + pipelineInfo.renderPass = m_renderPass; + pipelineInfo.subpass = 0; + + pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; // Optional + pipelineInfo.basePipelineIndex = -1; // Optional + + if (vkCreateGraphicsPipelines(m_device, VK_NULL_HANDLE, 1, &pipelineInfo, + nullptr, &m_graphicsPipeline) != VK_SUCCESS) { + throw std::runtime_error("failed to create graphics pipeline!"); + } + + for (size_t i = 0; i < shaderStageInfos.size(); i++) { + vkDestroyShaderModule(m_device, shaderStageInfos[i].module, nullptr); + } +} + +void VulkanBaseApp::createFramebuffers() { + m_swapChainFramebuffers.resize(m_swapChainImageViews.size()); + for (size_t i = 0; i < m_swapChainImageViews.size(); i++) { + VkImageView attachments[] = {m_swapChainImageViews[i], m_depthImageView}; + + VkFramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = m_renderPass; + framebufferInfo.attachmentCount = countof(attachments); + framebufferInfo.pAttachments = attachments; + framebufferInfo.width = m_swapChainExtent.width; + framebufferInfo.height = m_swapChainExtent.height; + framebufferInfo.layers = 1; + + if (vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, + &m_swapChainFramebuffers[i]) != VK_SUCCESS) { + throw std::runtime_error("failed to create framebuffer!"); + } + } +} + +void VulkanBaseApp::createCommandPool() { + VkCommandPoolCreateInfo poolInfo = {}; + uint32_t graphicsIndex, presentIndex; + + findGraphicsQueueIndicies(m_physicalDevice, m_surface, graphicsIndex, + presentIndex); + + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.queueFamilyIndex = graphicsIndex; + poolInfo.flags = 0; // Optional + + if (vkCreateCommandPool(m_device, &poolInfo, nullptr, &m_commandPool) != + VK_SUCCESS) { + throw std::runtime_error("Failed to create command pool!"); + } +} + +static void transitionImageLayout(VulkanBaseApp *app, VkImage image, + VkFormat format, VkImageLayout oldLayout, + VkImageLayout newLayout) { + VkCommandBuffer commandBuffer = app->beginSingleTimeCommands(); + + VkImageMemoryBarrier barrier = {}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.oldLayout = oldLayout; + barrier.newLayout = newLayout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = image; + + if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + + if (format == VK_FORMAT_D32_SFLOAT_S8_UINT || + format == VK_FORMAT_D24_UNORM_S8_UINT) { + barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + } else { + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + + VkPipelineStageFlags sourceStage; + VkPipelineStageFlags destinationStage; + + if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && + newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { + barrier.srcAccessMask = 0; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + + sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && + newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + } else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && + newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { + barrier.srcAccessMask = 0; + barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + + sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + } else { + throw std::invalid_argument("unsupported layout transition!"); + } + + vkCmdPipelineBarrier(commandBuffer, sourceStage, destinationStage, 0, 0, + nullptr, 0, nullptr, 1, &barrier); + + app->endSingleTimeCommands(commandBuffer); +} + +void VulkanBaseApp::createDepthResources() { + VkFormat depthFormat = findSupportedFormat( + m_physicalDevice, {VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, + VK_FORMAT_D24_UNORM_S8_UINT}, + VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); + createImage(m_physicalDevice, m_device, m_swapChainExtent.width, + m_swapChainExtent.height, depthFormat, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_depthImage, + m_depthImageMemory); + m_depthImageView = createImageView(m_device, m_depthImage, depthFormat, + VK_IMAGE_ASPECT_DEPTH_BIT); + transitionImageLayout(this, m_depthImage, depthFormat, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); +} + +void VulkanBaseApp::createUniformBuffers() { + VkDeviceSize size = getUniformSize(); + if (size > 0) { + m_uniformBuffers.resize(m_swapChainImages.size()); + m_uniformMemory.resize(m_swapChainImages.size()); + for (size_t i = 0; i < m_uniformBuffers.size(); i++) { + createBuffer(getUniformSize(), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + m_uniformBuffers[i], m_uniformMemory[i]); + } + } +} + +void VulkanBaseApp::createDescriptorPool() { + VkDescriptorPoolSize poolSize = {}; + poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + poolSize.descriptorCount = static_cast(m_swapChainImages.size()); + VkDescriptorPoolCreateInfo poolInfo = {}; + poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + poolInfo.poolSizeCount = 1; + poolInfo.pPoolSizes = &poolSize; + poolInfo.maxSets = static_cast(m_swapChainImages.size()); + ; + if (vkCreateDescriptorPool(m_device, &poolInfo, nullptr, &m_descriptorPool) != + VK_SUCCESS) { + throw std::runtime_error("failed to create descriptor pool!"); + } +} + +void VulkanBaseApp::createDescriptorSets() { + std::vector layouts(m_swapChainImages.size(), + m_descriptorSetLayout); + VkDescriptorSetAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocInfo.descriptorPool = m_descriptorPool; + allocInfo.descriptorSetCount = + static_cast(m_swapChainImages.size()); + allocInfo.pSetLayouts = layouts.data(); + m_descriptorSets.resize(m_swapChainImages.size()); + + if (vkAllocateDescriptorSets(m_device, &allocInfo, m_descriptorSets.data()) != + VK_SUCCESS) { + throw std::runtime_error("failed to allocate descriptor sets!"); + } + + VkDescriptorBufferInfo bufferInfo = {}; + bufferInfo.offset = 0; + bufferInfo.range = VK_WHOLE_SIZE; + VkWriteDescriptorSet descriptorWrite = {}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstBinding = 0; + descriptorWrite.dstArrayElement = 0; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pBufferInfo = &bufferInfo; + descriptorWrite.pImageInfo = nullptr; // Optional + descriptorWrite.pTexelBufferView = nullptr; // Optional + + for (size_t i = 0; i < m_swapChainImages.size(); i++) { + bufferInfo.buffer = m_uniformBuffers[i]; + descriptorWrite.dstSet = m_descriptorSets[i]; + vkUpdateDescriptorSets(m_device, 1, &descriptorWrite, 0, nullptr); + } +} + +void VulkanBaseApp::createCommandBuffers() { + m_commandBuffers.resize(m_swapChainFramebuffers.size()); + VkCommandBufferAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = m_commandPool; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandBufferCount = (uint32_t)m_commandBuffers.size(); + + if (vkAllocateCommandBuffers(m_device, &allocInfo, m_commandBuffers.data()) != + VK_SUCCESS) { + throw std::runtime_error("failed to allocate command buffers!"); + } + + for (size_t i = 0; i < m_commandBuffers.size(); i++) { + VkCommandBufferBeginInfo beginInfo = {}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + beginInfo.pInheritanceInfo = nullptr; // Optional + + if (vkBeginCommandBuffer(m_commandBuffers[i], &beginInfo) != VK_SUCCESS) { + throw std::runtime_error("failed to begin recording command buffer!"); + } + + VkRenderPassBeginInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = m_renderPass; + renderPassInfo.framebuffer = m_swapChainFramebuffers[i]; + + renderPassInfo.renderArea.offset = {0, 0}; + renderPassInfo.renderArea.extent = m_swapChainExtent; + + VkClearValue clearColors[2]; + clearColors[0].color = {0.0f, 0.0f, 0.0f, 1.0f}; + clearColors[1].depthStencil = {1.0f, 0}; + renderPassInfo.clearValueCount = countof(clearColors); + renderPassInfo.pClearValues = clearColors; + + vkCmdBeginRenderPass(m_commandBuffers[i], &renderPassInfo, + VK_SUBPASS_CONTENTS_INLINE); + + vkCmdBindPipeline(m_commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, + m_graphicsPipeline); + + vkCmdBindDescriptorSets(m_commandBuffers[i], + VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, + 0, 1, &m_descriptorSets[i], 0, nullptr); + + fillRenderingCommandBuffer(m_commandBuffers[i]); + + vkCmdEndRenderPass(m_commandBuffers[i]); + + if (vkEndCommandBuffer(m_commandBuffers[i]) != VK_SUCCESS) { + throw std::runtime_error("failed to record command buffer!"); + } + } +} + +void VulkanBaseApp::createSyncObjects() { + VkSemaphoreCreateInfo semaphoreInfo = {}; + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + VkFenceCreateInfo fenceInfo = {}; + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + m_inFlightFences.resize(MAX_FRAMES_IN_FLIGHT); + m_imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT); + m_renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT); + + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + if (vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, + &m_imageAvailableSemaphores[i]) != VK_SUCCESS) { + throw std::runtime_error("Failed to create image available semaphore!"); + } + if (vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, + &m_renderFinishedSemaphores[i]) != VK_SUCCESS) { + throw std::runtime_error("Failed to create image available semaphore!"); + } + if (vkCreateFence(m_device, &fenceInfo, nullptr, &m_inFlightFences[i]) != + VK_SUCCESS) { + throw std::runtime_error("Failed to create image available semaphore!"); + } + } +} + +void VulkanBaseApp::getWaitFrameSemaphores( + std::vector &wait, + std::vector &waitStages) const {} + +void VulkanBaseApp::getSignalFrameSemaphores( + std::vector &signal) const {} + +VkDeviceSize VulkanBaseApp::getUniformSize() const { return VkDeviceSize(0); } + +void VulkanBaseApp::updateUniformBuffer(uint32_t imageIndex, size_t frame) {} + +void VulkanBaseApp::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, + VkMemoryPropertyFlags properties, + VkBuffer &buffer, + VkDeviceMemory &bufferMemory) { + VkBufferCreateInfo bufferInfo = {}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = size; + bufferInfo.usage = usage; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + if (vkCreateBuffer(m_device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { + throw std::runtime_error("failed to create buffer!"); + } + + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(m_device, buffer, &memRequirements); + + VkMemoryAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = findMemoryType( + m_physicalDevice, memRequirements.memoryTypeBits, properties); + + if (vkAllocateMemory(m_device, &allocInfo, nullptr, &bufferMemory) != + VK_SUCCESS) { + throw std::runtime_error("failed to allocate buffer memory!"); + } + + vkBindBufferMemory(m_device, buffer, bufferMemory, 0); +} + +void VulkanBaseApp::createExternalBuffer( + VkDeviceSize size, VkBufferUsageFlags usage, + VkMemoryPropertyFlags properties, + VkExternalMemoryHandleTypeFlagsKHR extMemHandleType, VkBuffer &buffer, + VkDeviceMemory &bufferMemory) { + VkBufferCreateInfo bufferInfo = {}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = size; + bufferInfo.usage = usage; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VkExternalMemoryBufferCreateInfo externalMemoryBufferInfo = {}; + externalMemoryBufferInfo.sType = + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO; + externalMemoryBufferInfo.handleTypes = extMemHandleType; + bufferInfo.pNext = &externalMemoryBufferInfo; + + if (vkCreateBuffer(m_device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { + throw std::runtime_error("failed to create buffer!"); + } + + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(m_device, buffer, &memRequirements); + +#ifdef _WIN64 + WindowsSecurityAttributes winSecurityAttributes; + + VkExportMemoryWin32HandleInfoKHR vulkanExportMemoryWin32HandleInfoKHR = {}; + vulkanExportMemoryWin32HandleInfoKHR.sType = + VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + vulkanExportMemoryWin32HandleInfoKHR.pNext = NULL; + vulkanExportMemoryWin32HandleInfoKHR.pAttributes = &winSecurityAttributes; + vulkanExportMemoryWin32HandleInfoKHR.dwAccess = + DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE; + vulkanExportMemoryWin32HandleInfoKHR.name = (LPCWSTR)NULL; +#endif + VkExportMemoryAllocateInfoKHR vulkanExportMemoryAllocateInfoKHR = {}; + vulkanExportMemoryAllocateInfoKHR.sType = + VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR; +#ifdef _WIN64 + vulkanExportMemoryAllocateInfoKHR.pNext = + extMemHandleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR + ? &vulkanExportMemoryWin32HandleInfoKHR + : NULL; + vulkanExportMemoryAllocateInfoKHR.handleTypes = extMemHandleType; +#else + vulkanExportMemoryAllocateInfoKHR.pNext = NULL; + vulkanExportMemoryAllocateInfoKHR.handleTypes = + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; +#endif + VkMemoryAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.pNext = &vulkanExportMemoryAllocateInfoKHR; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = findMemoryType( + m_physicalDevice, memRequirements.memoryTypeBits, properties); + + if (vkAllocateMemory(m_device, &allocInfo, nullptr, &bufferMemory) != + VK_SUCCESS) { + throw std::runtime_error("failed to allocate external buffer memory!"); + } + + vkBindBufferMemory(m_device, buffer, bufferMemory, 0); +} + +void *VulkanBaseApp::getMemHandle( + VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagBits handleType) { +#ifdef _WIN64 + HANDLE handle = 0; + + VkMemoryGetWin32HandleInfoKHR vkMemoryGetWin32HandleInfoKHR = {}; + vkMemoryGetWin32HandleInfoKHR.sType = + VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; + vkMemoryGetWin32HandleInfoKHR.pNext = NULL; + vkMemoryGetWin32HandleInfoKHR.memory = memory; + vkMemoryGetWin32HandleInfoKHR.handleType = handleType; + + PFN_vkGetMemoryWin32HandleKHR fpGetMemoryWin32HandleKHR; + fpGetMemoryWin32HandleKHR = + (PFN_vkGetMemoryWin32HandleKHR)vkGetDeviceProcAddr( + m_device, "vkGetMemoryWin32HandleKHR"); + if (!fpGetMemoryWin32HandleKHR) { + throw std::runtime_error("Failed to retrieve vkGetMemoryWin32HandleKHR!"); + } + if (fpGetMemoryWin32HandleKHR(m_device, &vkMemoryGetWin32HandleInfoKHR, + &handle) != VK_SUCCESS) { + throw std::runtime_error("Failed to retrieve handle for buffer!"); + } + return (void *)handle; +#else + int fd = -1; + + VkMemoryGetFdInfoKHR vkMemoryGetFdInfoKHR = {}; + vkMemoryGetFdInfoKHR.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; + vkMemoryGetFdInfoKHR.pNext = NULL; + vkMemoryGetFdInfoKHR.memory = memory; + vkMemoryGetFdInfoKHR.handleType = handleType; + + PFN_vkGetMemoryFdKHR fpGetMemoryFdKHR; + fpGetMemoryFdKHR = + (PFN_vkGetMemoryFdKHR)vkGetDeviceProcAddr(m_device, "vkGetMemoryFdKHR"); + if (!fpGetMemoryFdKHR) { + throw std::runtime_error("Failed to retrieve vkGetMemoryWin32HandleKHR!"); + } + if (fpGetMemoryFdKHR(m_device, &vkMemoryGetFdInfoKHR, &fd) != VK_SUCCESS) { + throw std::runtime_error("Failed to retrieve handle for buffer!"); + } + return (void *)(uintptr_t)fd; +#endif /* _WIN64 */ +} + +void *VulkanBaseApp::getSemaphoreHandle( + VkSemaphore semaphore, VkExternalSemaphoreHandleTypeFlagBits handleType) { +#ifdef _WIN64 + HANDLE handle; + + VkSemaphoreGetWin32HandleInfoKHR semaphoreGetWin32HandleInfoKHR = {}; + semaphoreGetWin32HandleInfoKHR.sType = + VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR; + semaphoreGetWin32HandleInfoKHR.pNext = NULL; + semaphoreGetWin32HandleInfoKHR.semaphore = semaphore; + semaphoreGetWin32HandleInfoKHR.handleType = handleType; + + PFN_vkGetSemaphoreWin32HandleKHR fpGetSemaphoreWin32HandleKHR; + fpGetSemaphoreWin32HandleKHR = + (PFN_vkGetSemaphoreWin32HandleKHR)vkGetDeviceProcAddr( + m_device, "vkGetSemaphoreWin32HandleKHR"); + if (!fpGetSemaphoreWin32HandleKHR) { + throw std::runtime_error("Failed to retrieve vkGetMemoryWin32HandleKHR!"); + } + if (fpGetSemaphoreWin32HandleKHR(m_device, &semaphoreGetWin32HandleInfoKHR, + &handle) != VK_SUCCESS) { + throw std::runtime_error("Failed to retrieve handle for buffer!"); + } + + return (void *)handle; +#else + int fd; + + VkSemaphoreGetFdInfoKHR semaphoreGetFdInfoKHR = {}; + semaphoreGetFdInfoKHR.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR; + semaphoreGetFdInfoKHR.pNext = NULL; + semaphoreGetFdInfoKHR.semaphore = semaphore; + semaphoreGetFdInfoKHR.handleType = handleType; + + PFN_vkGetSemaphoreFdKHR fpGetSemaphoreFdKHR; + fpGetSemaphoreFdKHR = (PFN_vkGetSemaphoreFdKHR)vkGetDeviceProcAddr( + m_device, "vkGetSemaphoreFdKHR"); + if (!fpGetSemaphoreFdKHR) { + throw std::runtime_error("Failed to retrieve vkGetMemoryWin32HandleKHR!"); + } + if (fpGetSemaphoreFdKHR(m_device, &semaphoreGetFdInfoKHR, &fd) != + VK_SUCCESS) { + throw std::runtime_error("Failed to retrieve handle for buffer!"); + } + + return (void *)(uintptr_t)fd; +#endif +} + +void VulkanBaseApp::createExternalSemaphore( + VkSemaphore &semaphore, VkExternalSemaphoreHandleTypeFlagBits handleType) { + VkSemaphoreCreateInfo semaphoreInfo = {}; + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + VkExportSemaphoreCreateInfoKHR exportSemaphoreCreateInfo = {}; + exportSemaphoreCreateInfo.sType = + VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR; + +#ifdef _WIN64 + WindowsSecurityAttributes winSecurityAttributes; + + VkExportSemaphoreWin32HandleInfoKHR exportSemaphoreWin32HandleInfoKHR = {}; + exportSemaphoreWin32HandleInfoKHR.sType = + VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR; + exportSemaphoreWin32HandleInfoKHR.pNext = NULL; + exportSemaphoreWin32HandleInfoKHR.pAttributes = &winSecurityAttributes; + exportSemaphoreWin32HandleInfoKHR.dwAccess = + DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE; + exportSemaphoreWin32HandleInfoKHR.name = (LPCWSTR)NULL; + exportSemaphoreCreateInfo.pNext = + (handleType & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT) + ? &exportSemaphoreWin32HandleInfoKHR + : NULL; +#else + exportSemaphoreCreateInfo.pNext = NULL; +#endif + exportSemaphoreCreateInfo.handleTypes = handleType; + semaphoreInfo.pNext = &exportSemaphoreCreateInfo; + + if (vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &semaphore) != + VK_SUCCESS) { + throw std::runtime_error( + "failed to create synchronization objects for a CUDA-Vulkan!"); + } +} + +void VulkanBaseApp::importExternalBuffer( + void *handle, VkExternalMemoryHandleTypeFlagBits handleType, size_t size, + VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, + VkBuffer &buffer, VkDeviceMemory &memory) { + VkBufferCreateInfo bufferInfo = {}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = size; + bufferInfo.usage = usage; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VkExternalMemoryBufferCreateInfo externalMemoryBufferInfo = {}; + externalMemoryBufferInfo.sType = + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO; + externalMemoryBufferInfo.handleTypes = + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + bufferInfo.pNext = &externalMemoryBufferInfo; + + if (vkCreateBuffer(m_device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { + throw std::runtime_error("failed to create buffer!"); + } + + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(m_device, buffer, &memRequirements); + +#ifdef _WIN64 + VkImportMemoryWin32HandleInfoKHR handleInfo = {}; + handleInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + handleInfo.pNext = NULL; + handleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + handleInfo.handle = handle; + handleInfo.name = NULL; +#else + VkImportMemoryFdInfoKHR handleInfo = {}; + handleInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; + handleInfo.pNext = NULL; + handleInfo.fd = (int)(uintptr_t)handle; + handleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; +#endif /* _WIN64 */ + + VkMemoryAllocateInfo memAllocation = {}; + memAllocation.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memAllocation.pNext = (void *)&handleInfo; + memAllocation.allocationSize = memRequirements.size; + memAllocation.memoryTypeIndex = findMemoryType( + m_physicalDevice, memRequirements.memoryTypeBits, properties); + + if (vkAllocateMemory(m_device, &memAllocation, nullptr, &memory) != + VK_SUCCESS) { + throw std::runtime_error("Failed to import allocation!"); + } + + vkBindBufferMemory(m_device, buffer, memory, 0); +} + +void VulkanBaseApp::copyBuffer(VkBuffer dst, VkBuffer src, VkDeviceSize size) { + VkCommandBuffer commandBuffer = beginSingleTimeCommands(); + + VkBufferCopy copyRegion = {}; + copyRegion.size = size; + vkCmdCopyBuffer(commandBuffer, src, dst, 1, ©Region); + + endSingleTimeCommands(commandBuffer); +} + +void VulkanBaseApp::drawFrame() { + size_t currentFrameIdx = m_currentFrame % MAX_FRAMES_IN_FLIGHT; + vkWaitForFences(m_device, 1, &m_inFlightFences[currentFrameIdx], VK_TRUE, + std::numeric_limits::max()); + + uint32_t imageIndex; + VkResult result = vkAcquireNextImageKHR( + m_device, m_swapChain, std::numeric_limits::max(), + m_imageAvailableSemaphores[currentFrameIdx], VK_NULL_HANDLE, &imageIndex); + if (result == VK_ERROR_OUT_OF_DATE_KHR) { + recreateSwapChain(); + } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { + throw std::runtime_error("Failed to acquire swap chain image!"); + } + + updateUniformBuffer(imageIndex, m_currentFrame); + + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + + std::vector waitSemaphores; + std::vector waitStages; + + waitSemaphores.push_back(m_imageAvailableSemaphores[currentFrameIdx]); + waitStages.push_back(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + getWaitFrameSemaphores(waitSemaphores, waitStages); + + submitInfo.waitSemaphoreCount = (uint32_t)waitSemaphores.size(); + submitInfo.pWaitSemaphores = waitSemaphores.data(); + submitInfo.pWaitDstStageMask = waitStages.data(); + + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &m_commandBuffers[imageIndex]; + + std::vector signalSemaphores; + getSignalFrameSemaphores(signalSemaphores); + signalSemaphores.push_back(m_renderFinishedSemaphores[currentFrameIdx]); + submitInfo.signalSemaphoreCount = (uint32_t)signalSemaphores.size(); + submitInfo.pSignalSemaphores = signalSemaphores.data(); + + vkResetFences(m_device, 1, &m_inFlightFences[currentFrameIdx]); + + if (vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, + m_inFlightFences[currentFrameIdx]) != VK_SUCCESS) { + throw std::runtime_error("failed to submit draw command buffer!"); + } + + VkPresentInfoKHR presentInfo = {}; + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.waitSemaphoreCount = 1; + presentInfo.pWaitSemaphores = &m_renderFinishedSemaphores[currentFrameIdx]; + + VkSwapchainKHR swapChains[] = {m_swapChain}; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = swapChains; + presentInfo.pImageIndices = &imageIndex; + + result = vkQueuePresentKHR(m_presentQueue, &presentInfo); + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || + m_framebufferResized) { + recreateSwapChain(); + m_framebufferResized = false; + } else if (result != VK_SUCCESS) { + throw std::runtime_error("Failed to acquire swap chain image!"); + } + + m_currentFrame++; +} + +void VulkanBaseApp::cleanupSwapChain() { + if (m_depthImageView != VK_NULL_HANDLE) { + vkDestroyImageView(m_device, m_depthImageView, nullptr); + } + if (m_depthImage != VK_NULL_HANDLE) { + vkDestroyImage(m_device, m_depthImage, nullptr); + } + if (m_depthImageMemory != VK_NULL_HANDLE) { + vkFreeMemory(m_device, m_depthImageMemory, nullptr); + } + + for (size_t i = 0; i < m_uniformBuffers.size(); i++) { + vkDestroyBuffer(m_device, m_uniformBuffers[i], nullptr); + vkFreeMemory(m_device, m_uniformMemory[i], nullptr); + } + + if (m_descriptorPool != VK_NULL_HANDLE) { + vkDestroyDescriptorPool(m_device, m_descriptorPool, nullptr); + } + + for (size_t i = 0; i < m_swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(m_device, m_swapChainFramebuffers[i], nullptr); + } + + if (m_graphicsPipeline != VK_NULL_HANDLE) { + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + } + + if (m_pipelineLayout != VK_NULL_HANDLE) { + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + } + + if (m_renderPass != VK_NULL_HANDLE) { + vkDestroyRenderPass(m_device, m_renderPass, nullptr); + } + + for (size_t i = 0; i < m_swapChainImageViews.size(); i++) { + vkDestroyImageView(m_device, m_swapChainImageViews[i], nullptr); + } + + if (m_swapChain != VK_NULL_HANDLE) { + vkDestroySwapchainKHR(m_device, m_swapChain, nullptr); + } +} + +void VulkanBaseApp::recreateSwapChain() { + int width, height; + + glfwGetFramebufferSize(m_window, &width, &height); + while (width == 0 || height == 0) { + glfwWaitEvents(); glfwGetFramebufferSize(m_window, &width, &height); - while (width == 0 || height == 0) { - glfwWaitEvents(); - glfwGetFramebufferSize(m_window, &width, &height); - } + } - vkDeviceWaitIdle(m_device); + vkDeviceWaitIdle(m_device); - cleanupSwapChain(); + cleanupSwapChain(); - createSwapChain(); - createImageViews(); - createRenderPass(); - createGraphicsPipeline(); - createDepthResources(); - createFramebuffers(); - createUniformBuffers(); - createDescriptorPool(); - createDescriptorSets(); - createCommandBuffers(); + createSwapChain(); + createImageViews(); + createRenderPass(); + createGraphicsPipeline(); + createDepthResources(); + createFramebuffers(); + createUniformBuffers(); + createDescriptorPool(); + createDescriptorSets(); + createCommandBuffers(); } -void VulkanBaseApp::mainLoop() -{ - while (!glfwWindowShouldClose(m_window)) { - glfwPollEvents(); - drawFrame(); - } - vkDeviceWaitIdle(m_device); +void VulkanBaseApp::mainLoop() { + while (!glfwWindowShouldClose(m_window)) { + glfwPollEvents(); + drawFrame(); + } + vkDeviceWaitIdle(m_device); } -void readFile(std::istream& s, std::vector& data) -{ - s.seekg(0, std::ios_base::end); - data.resize(s.tellg()); - s.clear(); - s.seekg(0, std::ios_base::beg); - s.read(data.data(), data.size()); +void readFile(std::istream &s, std::vector &data) { + s.seekg(0, std::ios_base::end); + data.resize(s.tellg()); + s.clear(); + s.seekg(0, std::ios_base::beg); + s.read(data.data(), data.size()); } diff --git a/Samples/simpleVulkanMMAP/VulkanBaseApp.h b/Samples/simpleVulkanMMAP/VulkanBaseApp.h index 5c80dc8d..a1054b1a 100644 --- a/Samples/simpleVulkanMMAP/VulkanBaseApp.h +++ b/Samples/simpleVulkanMMAP/VulkanBaseApp.h @@ -40,101 +40,119 @@ 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); - bool isVkPhysicalDeviceUuid(void *Uuid); - 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; - uint8_t m_deviceUUID[VK_UUID_SIZE]; - VkDevice m_device; - VkQueue m_graphicsQueue; - VkQueue m_presentQueue; - VkSwapchainKHR m_swapChain; - std::vector m_swapChainImages; - VkFormat m_swapChainFormat; - VkExtent2D m_swapChainExtent; - std::vector m_swapChainImageViews; - std::vector > m_shaderFiles; - VkRenderPass m_renderPass; - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - std::vector m_swapChainFramebuffers; - VkCommandPool m_commandPool; - std::vector m_commandBuffers; - std::vector m_imageAvailableSemaphores; - std::vector m_renderFinishedSemaphores; - std::vector m_inFlightFences; - std::vector m_uniformBuffers; - std::vector m_uniformMemory; - VkDescriptorSetLayout m_descriptorSetLayout; - VkDescriptorPool m_descriptorPool; - std::vector m_descriptorSets; +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); + bool isVkPhysicalDeviceUuid(void* Uuid); + 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(); - VkImage m_depthImage; - VkDeviceMemory m_depthImageMemory; - VkImageView m_depthImageView; - size_t m_currentFrame; - bool m_framebufferResized; + protected: + const std::string m_appName; + const bool m_enableValidation; + VkInstance m_instance; + VkDebugUtilsMessengerEXT m_debugMessenger; + VkSurfaceKHR m_surface; + VkPhysicalDevice m_physicalDevice; + uint8_t m_deviceUUID[VK_UUID_SIZE]; + VkDevice m_device; + VkQueue m_graphicsQueue; + VkQueue m_presentQueue; + VkSwapchainKHR m_swapChain; + std::vector m_swapChainImages; + VkFormat m_swapChainFormat; + VkExtent2D m_swapChainExtent; + std::vector m_swapChainImageViews; + std::vector > m_shaderFiles; + VkRenderPass m_renderPass; + VkPipelineLayout m_pipelineLayout; + VkPipeline m_graphicsPipeline; + std::vector m_swapChainFramebuffers; + VkCommandPool m_commandPool; + std::vector m_commandBuffers; + std::vector m_imageAvailableSemaphores; + std::vector m_renderFinishedSemaphores; + std::vector m_inFlightFences; + std::vector m_uniformBuffers; + std::vector m_uniformMemory; + VkDescriptorSetLayout m_descriptorSetLayout; + VkDescriptorPool m_descriptorPool; + std::vector m_descriptorSets; - virtual void initVulkanApp() {} - virtual void fillRenderingCommandBuffer(VkCommandBuffer& buffer) {} - virtual std::vector getRequiredExtensions() const; - virtual std::vector getRequiredDeviceExtensions() const; - virtual void getVertexDescriptions(std::vector& bindingDesc, std::vector& attribDesc); - virtual void getAssemblyStateInfo(VkPipelineInputAssemblyStateCreateInfo& info); - virtual void getWaitFrameSemaphores(std::vector& wait, std::vector< VkPipelineStageFlags>& waitStages) const; - virtual void getSignalFrameSemaphores(std::vector& signal) const; - virtual VkDeviceSize getUniformSize() const; - virtual void updateUniformBuffer(uint32_t imageIndex, size_t globalFrame); - virtual void drawFrame(); -private: - GLFWwindow *m_window; + VkImage m_depthImage; + VkDeviceMemory m_depthImageMemory; + VkImageView m_depthImageView; + size_t m_currentFrame; + bool m_framebufferResized; - 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(); + virtual void initVulkanApp() {} + virtual void fillRenderingCommandBuffer(VkCommandBuffer& buffer) {} + virtual std::vector getRequiredExtensions() const; + virtual std::vector getRequiredDeviceExtensions() const; + virtual void getVertexDescriptions( + std::vector& bindingDesc, + std::vector& attribDesc); + virtual void getAssemblyStateInfo( + VkPipelineInputAssemblyStateCreateInfo& info); + virtual void getWaitFrameSemaphores( + std::vector& wait, + std::vector& waitStages) const; + virtual void getSignalFrameSemaphores(std::vector& signal) const; + virtual VkDeviceSize getUniformSize() const; + virtual void updateUniformBuffer(uint32_t imageIndex, size_t globalFrame); + virtual void drawFrame(); - void cleanupSwapChain(); - void recreateSwapChain(); + private: + GLFWwindow* m_window; - bool isSuitableDevice(VkPhysicalDevice dev) const; - static void resizeCallback(GLFWwindow *window, int width, int height); + void initWindow(); + void initVulkan(); + void createInstance(); + void createSurface(); + void createDevice(); + void createSwapChain(); + void createImageViews(); + void createRenderPass(); + void createDescriptorSetLayout(); + void createGraphicsPipeline(); + void createFramebuffers(); + void createCommandPool(); + void createDepthResources(); + void createUniformBuffers(); + void createDescriptorPool(); + void createDescriptorSets(); + void createCommandBuffers(); + void createSyncObjects(); + + void cleanupSwapChain(); + void recreateSwapChain(); + + bool isSuitableDevice(VkPhysicalDevice dev) const; + static void resizeCallback(GLFWwindow* window, int width, int height); }; void readFile(std::istream& s, std::vector& data); diff --git a/Samples/simpleVulkanMMAP/VulkanCudaInterop.h b/Samples/simpleVulkanMMAP/VulkanCudaInterop.h index a16ddab5..a3413cd2 100644 --- a/Samples/simpleVulkanMMAP/VulkanCudaInterop.h +++ b/Samples/simpleVulkanMMAP/VulkanCudaInterop.h @@ -35,41 +35,48 @@ #include bool isDeviceCompatible(void *Uuid, size_t size) { + int cudaDevice = cudaInvalidDeviceId; + int deviceCount; + checkCudaErrors(cudaGetDeviceCount(&deviceCount)); - int cudaDevice = cudaInvalidDeviceId; - int deviceCount; - checkCudaErrors(cudaGetDeviceCount(&deviceCount)); - - for (int i = 0; i < deviceCount; ++i) { - cudaDeviceProp devProp = { }; - checkCudaErrors(cudaGetDeviceProperties(&devProp, i)); - if (!memcmp(&devProp.uuid, Uuid, size)) { - cudaDevice = i; - break; - } - } - if (cudaDevice == cudaInvalidDeviceId) { - return false; + for (int i = 0; i < deviceCount; ++i) { + cudaDeviceProp devProp = {}; + checkCudaErrors(cudaGetDeviceProperties(&devProp, i)); + if (!memcmp(&devProp.uuid, Uuid, size)) { + cudaDevice = i; + break; } + } + if (cudaDevice == cudaInvalidDeviceId) { + return false; + } - int deviceSupportsHandle = 0; - int attributeVal = 0; - int deviceComputeMode = 0; + int deviceSupportsHandle = 0; + int attributeVal = 0; + int deviceComputeMode = 0; - checkCudaErrors(cuDeviceGetAttribute(&deviceComputeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, cudaDevice)); - checkCudaErrors(cuDeviceGetAttribute(&attributeVal, CU_DEVICE_ATTRIBUTE_VIRTUAL_ADDRESS_MANAGEMENT_SUPPORTED, cudaDevice)); + checkCudaErrors(cuDeviceGetAttribute( + &deviceComputeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, cudaDevice)); + checkCudaErrors(cuDeviceGetAttribute( + &attributeVal, CU_DEVICE_ATTRIBUTE_VIRTUAL_ADDRESS_MANAGEMENT_SUPPORTED, + cudaDevice)); #if defined(__linux__) - checkCudaErrors(cuDeviceGetAttribute(&deviceSupportsHandle, CU_DEVICE_ATTRIBUTE_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR_SUPPORTED, cudaDevice)); + checkCudaErrors(cuDeviceGetAttribute( + &deviceSupportsHandle, + CU_DEVICE_ATTRIBUTE_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR_SUPPORTED, + cudaDevice)); #else - checkCudaErrors(cuDeviceGetAttribute(&deviceSupportsHandle, CU_DEVICE_ATTRIBUTE_HANDLE_TYPE_WIN32_HANDLE_SUPPORTED, cudaDevice)); + checkCudaErrors(cuDeviceGetAttribute( + &deviceSupportsHandle, + CU_DEVICE_ATTRIBUTE_HANDLE_TYPE_WIN32_HANDLE_SUPPORTED, cudaDevice)); #endif - if ((deviceComputeMode != CU_COMPUTEMODE_DEFAULT) || !attributeVal || !deviceSupportsHandle) { - return false; - } - return true; + if ((deviceComputeMode != CU_COMPUTEMODE_DEFAULT) || !attributeVal || + !deviceSupportsHandle) { + return false; + } + return true; } -#endif // __VKCUDA_H__ - +#endif // __VKCUDA_H__ diff --git a/Samples/simpleVulkanMMAP/frag.spv b/Samples/simpleVulkanMMAP/frag.spv new file mode 100644 index 00000000..cb13e606 Binary files /dev/null and b/Samples/simpleVulkanMMAP/frag.spv differ diff --git a/Samples/simpleVulkanMMAP/main.cpp b/Samples/simpleVulkanMMAP/main.cpp index 53c05952..409722b1 100644 --- a/Samples/simpleVulkanMMAP/main.cpp +++ b/Samples/simpleVulkanMMAP/main.cpp @@ -25,11 +25,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - /* - * This sample demonstrates CUDA Interop with Vulkan using cuMemMap APIs. - * Allocating device memory and updating values in those allocations are performed by CUDA - * and the contents of the allocation are visualized by Vulkan. - */ +/* + * This sample demonstrates CUDA Interop with Vulkan using cuMemMap APIs. + * Allocating device memory and updating values in those allocations are + * performed by CUDA and the contents of the allocation are visualized by + * Vulkan. + */ #include "VulkanBaseApp.h" @@ -55,25 +56,23 @@ std::string execution_path; -class VulkanCudaPi : public VulkanBaseApp -{ - typedef struct UniformBufferObject_st { - float frame; - } UniformBufferObject; +class VulkanCudaPi : public VulkanBaseApp { + typedef struct UniformBufferObject_st { float frame; } UniformBufferObject; - VkBuffer m_inCircleBuffer, m_xyPositionBuffer; - VkDeviceMemory m_inCircleMemory, m_xyPositionMemory; - VkSemaphore m_vkWaitSemaphore, m_vkSignalSemaphore; - MonteCarloPiSimulation m_sim; - UniformBufferObject m_ubo; - cudaStream_t m_stream; - cudaExternalSemaphore_t m_cudaWaitSemaphore, m_cudaSignalSemaphore; - using chrono_tp = std::chrono::time_point; - chrono_tp m_lastTime; - size_t m_lastFrame; -public: - VulkanCudaPi(size_t num_points) : - VulkanBaseApp("simpleVulkanMMAP", ENABLE_VALIDATION), + VkBuffer m_inCircleBuffer, m_xyPositionBuffer; + VkDeviceMemory m_inCircleMemory, m_xyPositionMemory; + VkSemaphore m_vkWaitSemaphore, m_vkSignalSemaphore; + MonteCarloPiSimulation m_sim; + UniformBufferObject m_ubo; + cudaStream_t m_stream; + cudaExternalSemaphore_t m_cudaWaitSemaphore, m_cudaSignalSemaphore; + using chrono_tp = std::chrono::time_point; + chrono_tp m_lastTime; + size_t m_lastFrame; + + public: + VulkanCudaPi(size_t num_points) + : VulkanBaseApp("simpleVulkanMMAP", ENABLE_VALIDATION), m_inCircleBuffer(VK_NULL_HANDLE), m_xyPositionBuffer(VK_NULL_HANDLE), m_inCircleMemory(VK_NULL_HANDLE), @@ -86,232 +85,268 @@ public: m_cudaWaitSemaphore(), m_cudaSignalSemaphore(), m_lastFrame(0) { + // 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)); + } - // Add our compiled vulkan shader files - char* vertex_shader_path = sdkFindFilePath("montecarlo.vert", execution_path.c_str()); - char* fragment_shader_path = sdkFindFilePath("montecarlo.frag", 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)); + ~VulkanCudaPi() { + if (m_stream) { + // Make sure there's no pending work before we start tearing down + checkCudaErrors(cudaStreamSynchronize(m_stream)); + checkCudaErrors(cudaStreamDestroy(m_stream)); } - ~VulkanCudaPi() { - if (m_stream) { - // Make sure there's no pending work before we start tearing down - checkCudaErrors(cudaStreamSynchronize(m_stream)); - checkCudaErrors(cudaStreamDestroy(m_stream)); - } + 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_xyPositionBuffer != VK_NULL_HANDLE) { + vkDestroyBuffer(m_device, m_xyPositionBuffer, nullptr); + } + if (m_xyPositionMemory != VK_NULL_HANDLE) { + vkFreeMemory(m_device, m_xyPositionMemory, nullptr); + } + if (m_inCircleBuffer != VK_NULL_HANDLE) { + vkDestroyBuffer(m_device, m_inCircleBuffer, nullptr); + } + if (m_inCircleMemory != VK_NULL_HANDLE) { + vkFreeMemory(m_device, m_inCircleMemory, nullptr); + } + } - 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_xyPositionBuffer != VK_NULL_HANDLE) { - vkDestroyBuffer(m_device, m_xyPositionBuffer, nullptr); - } - if (m_xyPositionMemory != VK_NULL_HANDLE) { - vkFreeMemory(m_device, m_xyPositionMemory, nullptr); - } - if (m_inCircleBuffer != VK_NULL_HANDLE) { - vkDestroyBuffer(m_device, m_inCircleBuffer, nullptr); - } - if (m_inCircleMemory != VK_NULL_HANDLE) { - vkFreeMemory(m_device, m_inCircleMemory, nullptr); - } + void fillRenderingCommandBuffer(VkCommandBuffer& commandBuffer) { + VkBuffer vertexBuffers[] = {m_inCircleBuffer, m_xyPositionBuffer}; + VkDeviceSize offsets[] = {0, 0}; + vkCmdBindVertexBuffers(commandBuffer, 0, + sizeof(vertexBuffers) / sizeof(vertexBuffers[0]), + vertexBuffers, offsets); + vkCmdDraw(commandBuffer, (uint32_t)(m_sim.getNumPoints()), 1, 0, 0); + } + + void getVertexDescriptions( + std::vector& bindingDesc, + std::vector& 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& wait, + std::vector& 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& 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() { + const size_t nVerts = m_sim.getNumPoints(); + + // Obtain cuda device id for the device corresponding to the Vulkan physical + // device + int deviceCount; + int cudaDevice = cudaInvalidDeviceId; + checkCudaErrors(cudaGetDeviceCount(&deviceCount)); + for (int dev = 0; dev < deviceCount; ++dev) { + cudaDeviceProp devProp = {}; + checkCudaErrors(cudaGetDeviceProperties(&devProp, dev)); + if (isVkPhysicalDeviceUuid(&devProp.uuid)) { + cudaDevice = dev; + break; + } + } + if (cudaDevice == cudaInvalidDeviceId) { + throw std::runtime_error("No Suitable device found!"); } - void fillRenderingCommandBuffer(VkCommandBuffer& commandBuffer) { - VkBuffer vertexBuffers[] = { m_inCircleBuffer, m_xyPositionBuffer }; - VkDeviceSize offsets[] = { 0, 0 }; - vkCmdBindVertexBuffers(commandBuffer, 0, sizeof(vertexBuffers) / sizeof(vertexBuffers[0]), vertexBuffers, offsets); - vkCmdDraw(commandBuffer, (uint32_t)(m_sim.getNumPoints()), 1, 0, 0); + // On the corresponding cuda device, create the cuda stream we'll using + checkCudaErrors(cudaSetDevice(cudaDevice)); + checkCudaErrors( + cudaStreamCreateWithFlags(&m_stream, cudaStreamNonBlocking)); + m_sim.initSimulation(cudaDevice, m_stream); + + importExternalBuffer( + (void*)(uintptr_t)m_sim.getPositionShareableHandle(), + getDefaultMemHandleType(), nVerts * sizeof(vec2), + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_xyPositionBuffer, + m_xyPositionMemory); + + importExternalBuffer( + (void*)(uintptr_t)m_sim.getInCircleShareableHandle(), + getDefaultMemHandleType(), nVerts * sizeof(float), + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_inCircleBuffer, + m_inCircleMemory); + + // 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()); + } + + void importCudaExternalSemaphore( + cudaExternalSemaphore_t& cudaSem, VkSemaphore& vkSem, + VkExternalSemaphoreHandleTypeFlagBits handleType) { + cudaExternalSemaphoreHandleDesc externalSemaphoreHandleDesc = {}; + + 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; + } else { + throw std::runtime_error("Unknown handle type requested!"); } - void getVertexDescriptions(std::vector& bindingDesc, std::vector& 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& 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& 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() { - const size_t nVerts = m_sim.getNumPoints(); - - // Obtain cuda device id for the device corresponding to the Vulkan physical device - int deviceCount; - int cudaDevice = cudaInvalidDeviceId; - checkCudaErrors(cudaGetDeviceCount(&deviceCount)); - for (int dev = 0; dev < deviceCount; ++dev) { - cudaDeviceProp devProp = { }; - checkCudaErrors(cudaGetDeviceProperties(&devProp, dev)); - if (isVkPhysicalDeviceUuid(&devProp.uuid)) { - cudaDevice = dev; - break; - } - } - if (cudaDevice == cudaInvalidDeviceId) { - throw std::runtime_error("No Suitable device found!"); - } - - // On the corresponding cuda device, create the cuda stream we'll using - checkCudaErrors(cudaSetDevice(cudaDevice)); - checkCudaErrors(cudaStreamCreateWithFlags(&m_stream, cudaStreamNonBlocking)); - m_sim.initSimulation(cudaDevice, m_stream); - - importExternalBuffer((void *)(uintptr_t)m_sim.getPositionShareableHandle(), getDefaultMemHandleType(), nVerts * sizeof(vec2), - VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_xyPositionBuffer, m_xyPositionMemory); - - importExternalBuffer((void *)(uintptr_t)m_sim.getInCircleShareableHandle(), getDefaultMemHandleType(), nVerts * sizeof(float), - VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_inCircleBuffer, m_inCircleMemory); - - // 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()); - } - - void importCudaExternalSemaphore(cudaExternalSemaphore_t& cudaSem, VkSemaphore& vkSem, VkExternalSemaphoreHandleTypeFlagBits handleType) { - cudaExternalSemaphoreHandleDesc externalSemaphoreHandleDesc = {}; - - 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; - } - 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)); - } + checkCudaErrors( + cudaImportExternalSemaphore(&cudaSem, &externalSemaphoreHandleDesc)); + } - VkDeviceSize getUniformSize() const { - return sizeof(UniformBufferObject); - } + VkDeviceSize getUniformSize() const { return sizeof(UniformBufferObject); } - void updateUniformBuffer(uint32_t imageIndex, size_t globalFrame) { - m_ubo.frame = (float)globalFrame; - 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]); - } + void updateUniformBuffer(uint32_t imageIndex, size_t globalFrame) { + m_ubo.frame = (float)globalFrame; + 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 getRequiredExtensions() const { - std::vector 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 getRequiredExtensions() const { + std::vector extensions; + extensions.push_back(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME); + extensions.push_back(VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME); + extensions.push_back(VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME); + extensions.push_back( + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + return extensions; + } - std::vector getRequiredDeviceExtensions() const { - std::vector extensions; + std::vector getRequiredDeviceExtensions() const { + std::vector extensions; - extensions.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME); - extensions.push_back(VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME); + extensions.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME); + extensions.push_back(VK_KHR_EXTERNAL_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; + 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( + currentTime - startTime) + .count(); + + if (m_currentFrame == 0) { + m_lastTime = startTime; } - void drawFrame() { - static chrono_tp startTime = std::chrono::high_resolution_clock::now(); + cudaExternalSemaphoreWaitParams waitParams = {}; + waitParams.flags = 0; + waitParams.params.fence.value = 0; - chrono_tp currentTime = std::chrono::high_resolution_clock::now(); - float time = std::chrono::duration(currentTime - startTime).count(); + cudaExternalSemaphoreSignalParams signalParams = {}; + signalParams.flags = 0; + signalParams.params.fence.value = 0; - if (m_currentFrame == 0) { - m_lastTime = startTime; - } + // Have vulkan draw the current frame... + VulkanBaseApp::drawFrame(); + // 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); - cudaExternalSemaphoreWaitParams waitParams = {}; - waitParams.flags = 0; - waitParams.params.fence.value = 0; - - cudaExternalSemaphoreSignalParams signalParams = {}; - signalParams.flags = 0; - signalParams.params.fence.value = 0; - - // Have vulkan draw the current frame... - VulkanBaseApp::drawFrame(); - // 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)); - } + // Signal vulkan to continue with the updated buffers + checkCudaErrors(cudaSignalExternalSemaphoresAsync( + &m_cudaSignalSemaphore, &signalParams, 1, m_stream)); + } }; -int main(int argc, char **argv) -{ - execution_path = argv[0]; - VulkanCudaPi app(NUM_SIMULATION_POINTS); - app.init(); - app.mainLoop(); - return 0; +int main(int argc, char** argv) { + execution_path = argv[0]; + VulkanCudaPi app(NUM_SIMULATION_POINTS); + app.init(); + app.mainLoop(); + return 0; } diff --git a/Samples/simpleVulkanMMAP/vert.spv b/Samples/simpleVulkanMMAP/vert.spv new file mode 100644 index 00000000..2a8fe1ae Binary files /dev/null and b/Samples/simpleVulkanMMAP/vert.spv differ diff --git a/Samples/vulkanImageCUDA/Build_instructions.txt b/Samples/vulkanImageCUDA/Build_instructions.txt index 9b3ada8d..48ce584a 100644 --- a/Samples/vulkanImageCUDA/Build_instructions.txt +++ b/Samples/vulkanImageCUDA/Build_instructions.txt @@ -19,8 +19,17 @@ For Linux: -- Install "libxcb1-dev" and "xorg-dev" as GLFW3 is depended on it -- Add Vulkan and GLFW3 libraries directories to LD_LIBRARY_PATH + For Linux aarch64(L4T): -- Install GLFW3 library using "sudo apt-get install libglfw3-dev" this will provide glfw3 -- install above will also provide libvulkan-dev as dependencies -- Add Vulkan and GLFW3 libraries directories to LD_LIBRARY_PATH --- Pass path to vulkan sdk while building 'make VULKAN_SDK_PATH=', VULKAN_SDK_PATH in this scenario is typically "/usr" \ No newline at end of file +-- Pass path to vulkan sdk while building 'make VULKAN_SDK_PATH=', VULKAN_SDK_PATH in this scenario is typically "/usr" + + +For Shader changes: +-- Update the shader.vert and/or shader.frag shader source file as required +-- Use the glslc shader compiler from the installed Vulkan SDK's bin directory to compile shaders as: + glslc shader.vert -o vert.spv + glslc shader.frag -o frag.spv +** Make sure to add glslc's path in your PATH environment variable ** diff --git a/Samples/vulkanImageCUDA/frag.spv b/Samples/vulkanImageCUDA/frag.spv new file mode 100644 index 00000000..823e9c69 Binary files /dev/null and b/Samples/vulkanImageCUDA/frag.spv differ diff --git a/Samples/vulkanImageCUDA/vert.spv b/Samples/vulkanImageCUDA/vert.spv new file mode 100644 index 00000000..ac9df527 Binary files /dev/null and b/Samples/vulkanImageCUDA/vert.spv differ diff --git a/Samples/vulkanImageCUDA/vulkanImageCUDA.cu b/Samples/vulkanImageCUDA/vulkanImageCUDA.cu index c709b74e..8dca17d2 100644 --- a/Samples/vulkanImageCUDA/vulkanImageCUDA.cu +++ b/Samples/vulkanImageCUDA/vulkanImageCUDA.cu @@ -69,7 +69,7 @@ const std::vector validationLayers = { "VK_LAYER_KHRONOS_validation"}; #ifdef NDEBUG -const bool enableValidationLayers = false; +const bool enableValidationLayers = true; #else const bool enableValidationLayers = false; #endif @@ -494,7 +494,7 @@ class vulkanImageCUDA { unsigned int* image_data = NULL; unsigned int imageWidth, imageHeight; - unsigned int mipLevels; + unsigned int mipLevels = 1; size_t totalImageMemSize; // CUDA objects @@ -630,6 +630,9 @@ class vulkanImageCUDA { vkDestroyBuffer(device, vertexBuffer, nullptr); vkFreeMemory(device, vertexBufferMemory, nullptr); + vkDestroySemaphore(device, cudaUpdateVkSemaphore, nullptr); + vkDestroySemaphore(device, vkUpdateCudaSemaphore, nullptr); + for (size_t i = 0; i < MAX_FRAMES; i++) { vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr); vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr); @@ -686,7 +689,7 @@ class vulkanImageCUDA { appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); appInfo.pEngineName = "No Engine"; appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); - appInfo.apiVersion = VK_API_VERSION_1_0; + appInfo.apiVersion = VK_API_VERSION_1_1; VkInstanceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; @@ -905,6 +908,7 @@ class vulkanImageCUDA { } VkPhysicalDeviceFeatures deviceFeatures = {}; + deviceFeatures.samplerAnisotropy = VK_TRUE; VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; @@ -1078,8 +1082,8 @@ class vulkanImageCUDA { } void createGraphicsPipeline() { - auto vertShaderCode = readFile("shader.vert"); - auto fragShaderCode = readFile("shader.frag"); + auto vertShaderCode = readFile("vert.spv"); + auto fragShaderCode = readFile("frag.spv"); VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); @@ -1268,7 +1272,7 @@ class vulkanImageCUDA { // VK_FORMAT_R8G8B8A8_UNORM changed to VK_FORMAT_R8G8B8A8_UINT createImage( - imageWidth, imageHeight, VK_FORMAT_R8G8B8A8_UINT, + imageWidth, imageHeight, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, @@ -1280,9 +1284,6 @@ class vulkanImageCUDA { copyBufferToImage(stagingBuffer, textureImage, static_cast(imageWidth), static_cast(imageHeight)); - transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_UINT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); vkDestroyBuffer(device, stagingBuffer, nullptr); vkFreeMemory(device, stagingBufferMemory, nullptr); @@ -1523,8 +1524,13 @@ class vulkanImageCUDA { vkExternalMemImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO; vkExternalMemImageCreateInfo.pNext = NULL; +#ifdef _WIN64 + vkExternalMemImageCreateInfo.handleTypes = + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; +#else vkExternalMemImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; +#endif imageInfo.pNext = &vkExternalMemImageCreateInfo; @@ -2147,7 +2153,7 @@ class vulkanImageCUDA { if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS || vkCreateSemaphore(device, &semaphoreInfo, nullptr, - &renderFinishedSemaphores[i]) != VK_SUCCESS || + &renderFinishedSemaphores[i]) != VK_SUCCESS || vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) { throw std::runtime_error( @@ -2201,7 +2207,6 @@ class vulkanImageCUDA { throw std::runtime_error( "failed to create synchronization objects for a CUDA-Vulkan!"); } - } void updateUniformBuffer() { @@ -2333,8 +2338,8 @@ class vulkanImageCUDA { submitInfo.signalSemaphoreCount = 2; submitInfo.pSignalSemaphores = signalSemaphores; - if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]) != - VK_SUCCESS) { + if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, + inFlightFences[currentFrame]) != VK_SUCCESS) { throw std::runtime_error("failed to submit draw command buffer!"); } } @@ -2360,8 +2365,8 @@ class vulkanImageCUDA { submitInfo.signalSemaphoreCount = 2; submitInfo.pSignalSemaphores = signalSemaphores; - if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]) != - VK_SUCCESS) { + if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, + inFlightFences[currentFrame]) != VK_SUCCESS) { throw std::runtime_error("failed to submit draw command buffer!"); } }