diff --git a/Vulkan/Vulkan_Sample/Vulkan.xcodeproj/project.pbxproj b/Vulkan/Vulkan_Sample/Vulkan.xcodeproj/project.pbxproj index 6b5b7b6..f8fc27e 100644 --- a/Vulkan/Vulkan_Sample/Vulkan.xcodeproj/project.pbxproj +++ b/Vulkan/Vulkan_Sample/Vulkan.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ B0272D7128B4C609002D3602 /* deferredmutisampling.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B0272D7028B4C609002D3602 /* deferredmutisampling.cpp */; }; B0272D7628B4E294002D3602 /* deferredshadows.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B0272D7528B4E294002D3602 /* deferredshadows.cpp */; }; B0272D8128B71F82002D3602 /* ssao.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B0272D7A28B70A45002D3602 /* ssao.cpp */; }; + B0272D8628B899F9002D3602 /* computershader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B0272D8428B899F9002D3602 /* computershader.cpp */; }; B066A145286213A600763515 /* assets in CopyFiles */ = {isa = PBXBuildFile; fileRef = B066A1422862125900763515 /* assets */; }; B066DE1E28A4FF5D00726A95 /* thread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B066DE1D28A4FF5D00726A95 /* thread.cpp */; }; B066DE2328A5074600726A95 /* multithread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B066DE2128A5074600726A95 /* multithread.cpp */; }; @@ -111,6 +112,8 @@ B0272D7528B4E294002D3602 /* deferredshadows.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = deferredshadows.cpp; sourceTree = ""; }; B0272D7928B70A45002D3602 /* ssao.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssao.h; sourceTree = ""; }; B0272D7A28B70A45002D3602 /* ssao.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ssao.cpp; sourceTree = ""; }; + B0272D8428B899F9002D3602 /* computershader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = computershader.cpp; sourceTree = ""; }; + B0272D8528B899F9002D3602 /* computershader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = computershader.h; sourceTree = ""; }; B066A1422862125900763515 /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; path = assets; sourceTree = ""; }; B066DE1C28A4FF5D00726A95 /* thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = thread.h; sourceTree = ""; }; B066DE1D28A4FF5D00726A95 /* thread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = thread.cpp; sourceTree = ""; }; @@ -308,6 +311,15 @@ path = ssao; sourceTree = ""; }; + B0272D8328B899F9002D3602 /* computershader */ = { + isa = PBXGroup; + children = ( + B0272D8428B899F9002D3602 /* computershader.cpp */, + B0272D8528B899F9002D3602 /* computershader.h */, + ); + path = computershader; + sourceTree = ""; + }; B066DE2028A5074600726A95 /* multithread */ = { isa = PBXGroup; children = ( @@ -737,6 +749,7 @@ B0E13A182861729300D1D2B6 /* sample */ = { isa = PBXGroup; children = ( + B0272D8328B899F9002D3602 /* computershader */, B0272D7828B70A45002D3602 /* ssao */, B0272D7328B4E294002D3602 /* deferredshadows */, B0272D6E28B4C609002D3602 /* deferredmutisampling */, @@ -888,6 +901,7 @@ B066DE5C28ACD54300726A95 /* svpng.c in Sources */, B0B5D0C5287ECA78003A175D /* specializationconstants.cpp in Sources */, B0B5D01F2875293B003A175D /* ui.cpp in Sources */, + B0272D8628B899F9002D3602 /* computershader.cpp in Sources */, B0B5D10B288A7935003A175D /* separatevertexattributes.cpp in Sources */, B0B5D0BA287D50A3003A175D /* dynamicuniformbuffer.cpp in Sources */, B0B5D09728783317003A175D /* gltfModel.cpp in Sources */, diff --git a/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/edgedetect.comp b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/edgedetect.comp new file mode 100644 index 0000000..5c70178 --- /dev/null +++ b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/edgedetect.comp @@ -0,0 +1,44 @@ +#version 450 + +layout (local_size_x = 16, local_size_y = 16) in; +layout (binding = 0, rgba8) uniform readonly image2D inputImage; +layout (binding = 1, rgba8) uniform image2D resultImage; + +float conv(in float[9] kernel, in float[9] data, in float denom, in float offset) +{ + float res = 0.0; + for (int i=0; i<9; ++i) + { + res += kernel[i] * data[i]; + } + return clamp(res/denom + offset, 0.0, 1.0); +} + +struct ImageData +{ + float avg[9]; +} imageData; + +void main() +{ + // Fetch neighbouring texels + int n = -1; + for (int i=-1; i<2; ++i) + { + for(int j=-1; j<2; ++j) + { + n++; + vec3 rgb = imageLoad(inputImage, ivec2(gl_GlobalInvocationID.x + i, gl_GlobalInvocationID.y + j)).rgb; + imageData.avg[n] = (rgb.r + rgb.g + rgb.b) / 3.0; + } + } + + float[9] kernel; + kernel[0] = -1.0/8.0; kernel[1] = -1.0/8.0; kernel[2] = -1.0/8.0; + kernel[3] = -1.0/8.0; kernel[4] = 1.0; kernel[5] = -1.0/8.0; + kernel[6] = -1.0/8.0; kernel[7] = -1.0/8.0; kernel[8] = -1.0/8.0; + + vec4 res = vec4(vec3(conv(kernel, imageData.avg, 0.1, 0.0)), 1.0); + + imageStore(resultImage, ivec2(gl_GlobalInvocationID.xy), res); +} diff --git a/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/edgedetect.comp.spv b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/edgedetect.comp.spv new file mode 100644 index 0000000..66a32b3 Binary files /dev/null and b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/edgedetect.comp.spv differ diff --git a/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/emboss.comp b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/emboss.comp new file mode 100644 index 0000000..4402d7c --- /dev/null +++ b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/emboss.comp @@ -0,0 +1,44 @@ +#version 450 + +layout (local_size_x = 16, local_size_y = 16) in; +layout (binding = 0, rgba8) uniform readonly image2D inputImage; +layout (binding = 1, rgba8) uniform image2D resultImage; + +float conv(in float[9] kernel, in float[9] data, in float denom, in float offset) +{ + float res = 0.0; + for (int i=0; i<9; ++i) + { + res += kernel[i] * data[i]; + } + return clamp(res/denom + offset, 0.0, 1.0); +} + +struct ImageData +{ + float avg[9]; +} imageData; + +void main() +{ + // Fetch neighbouring texels + int n = -1; + for (int i=-1; i<2; ++i) + { + for(int j=-1; j<2; ++j) + { + n++; + vec3 rgb = imageLoad(inputImage, ivec2(gl_GlobalInvocationID.x + i, gl_GlobalInvocationID.y + j)).rgb; + imageData.avg[n] = (rgb.r + rgb.g + rgb.b) / 3.0; + } + } + + float[9] kernel; + kernel[0] = -1.0; kernel[1] = 0.0; kernel[2] = 0.0; + kernel[3] = 0.0; kernel[4] = -1.0; kernel[5] = 0.0; + kernel[6] = 0.0; kernel[7] = 0.0; kernel[8] = 2.0; + + vec4 res = vec4(vec3(conv(kernel, imageData.avg, 1.0, 0.50)), 1.0); + + imageStore(resultImage, ivec2(gl_GlobalInvocationID.xy), res); +} \ No newline at end of file diff --git a/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/emboss.comp.spv b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/emboss.comp.spv new file mode 100644 index 0000000..88cc8d7 Binary files /dev/null and b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/emboss.comp.spv differ diff --git a/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/sharpen.comp b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/sharpen.comp new file mode 100644 index 0000000..f94c8e9 --- /dev/null +++ b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/sharpen.comp @@ -0,0 +1,53 @@ +#version 450 + +layout (local_size_x = 16, local_size_y = 16) in; +layout (binding = 0, rgba8) uniform readonly image2D inputImage; +layout (binding = 1, rgba8) uniform image2D resultImage; + +float conv(in float[9] kernel, in float[9] data, in float denom, in float offset) +{ + float res = 0.0; + for (int i=0; i<9; ++i) + { + res += kernel[i] * data[i]; + } + return clamp(res/denom + offset, 0.0, 1.0); +} + +struct ImageData +{ + float r[9]; + float g[9]; + float b[9]; +} imageData; + +void main() +{ + + // Fetch neighbouring texels + int n = -1; + for (int i=-1; i<2; ++i) + { + for(int j=-1; j<2; ++j) + { + n++; + vec3 rgb = imageLoad(inputImage, ivec2(gl_GlobalInvocationID.x + i, gl_GlobalInvocationID.y + j)).rgb; + imageData.r[n] = rgb.r; + imageData.g[n] = rgb.g; + imageData.b[n] = rgb.b; + } + } + + float[9] kernel; + kernel[0] = -1.0; kernel[1] = -1.0; kernel[2] = -1.0; + kernel[3] = -1.0; kernel[4] = 9.0; kernel[5] = -1.0; + kernel[6] = -1.0; kernel[7] = -1.0; kernel[8] = -1.0; + + vec4 res = vec4( + conv(kernel, imageData.r, 1.0, 0.0), + conv(kernel, imageData.g, 1.0, 0.0), + conv(kernel, imageData.b, 1.0, 0.0), + 1.0); + + imageStore(resultImage, ivec2(gl_GlobalInvocationID.xy), res); +} \ No newline at end of file diff --git a/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/sharpen.comp.spv b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/sharpen.comp.spv new file mode 100644 index 0000000..f023b76 Binary files /dev/null and b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/sharpen.comp.spv differ diff --git a/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/texture.frag b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/texture.frag new file mode 100644 index 0000000..108e89b --- /dev/null +++ b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/texture.frag @@ -0,0 +1,12 @@ +#version 450 + +layout (binding = 1) uniform sampler2D samplerColor; + +layout (location = 0) in vec2 inUV; + +layout (location = 0) out vec4 outFragColor; + +void main() +{ + outFragColor = texture(samplerColor, inUV); +} \ No newline at end of file diff --git a/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/texture.frag.spv b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/texture.frag.spv new file mode 100644 index 0000000..401a743 Binary files /dev/null and b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/texture.frag.spv differ diff --git a/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/texture.vert b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/texture.vert new file mode 100644 index 0000000..7548607 --- /dev/null +++ b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/texture.vert @@ -0,0 +1,23 @@ +#version 450 + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec2 inUV; + +layout (binding = 0) uniform UBO +{ + mat4 projection; + mat4 model; +} ubo; + +layout (location = 0) out vec2 outUV; + +out gl_PerVertex +{ + vec4 gl_Position; +}; + +void main() +{ + outUV = inUV; + gl_Position = ubo.projection * ubo.model * vec4(inPos.xyz, 1.0); +} diff --git a/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/texture.vert.spv b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/texture.vert.spv new file mode 100644 index 0000000..f72d601 Binary files /dev/null and b/Vulkan/Vulkan_Sample/Vulkan/assets/shaders/computeshader/texture.vert.spv differ diff --git a/Vulkan/Vulkan_Sample/Vulkan/assets/textures/vulkan_11_rgba.ktx b/Vulkan/Vulkan_Sample/Vulkan/assets/textures/vulkan_11_rgba.ktx new file mode 100644 index 0000000..4b6fb52 Binary files /dev/null and b/Vulkan/Vulkan_Sample/Vulkan/assets/textures/vulkan_11_rgba.ktx differ diff --git a/Vulkan/Vulkan_Sample/Vulkan/common/application.cpp b/Vulkan/Vulkan_Sample/Vulkan/common/application.cpp index 3527264..3e07f2c 100644 --- a/Vulkan/Vulkan_Sample/Vulkan/common/application.cpp +++ b/Vulkan/Vulkan_Sample/Vulkan/common/application.cpp @@ -64,6 +64,7 @@ void Application::init() Tools::m_deviceEnabledFeatures = m_deviceEnabledFeatures; Tools::m_deviceProperties = m_deviceProperties; Tools::m_graphicsQueue = m_graphicsQueue; + Tools::m_computerQueue = m_computerQueue; createCommandPool(); Tools::m_commandPool = m_commandPool; @@ -155,7 +156,7 @@ void Application::render() vkResetFences(m_device, 1, &m_inFlightFences[m_currentFrame]); vkAcquireNextImageKHR(m_device, m_swapchainKHR, UINT64_MAX, m_imageAvailableSemaphores[m_currentFrame], VK_NULL_HANDLE, &m_imageIndex); - + VkCommandBuffer commandBuffer = m_commandBuffers[m_imageIndex]; beginRenderCommandAndPass(commandBuffer, m_imageIndex); recordRenderCommand(commandBuffer); @@ -370,18 +371,21 @@ void Application::createLogicDeivce() m_familyIndices = findQueueFamilyIndices(); uint32_t graphicsFamily = m_familyIndices.graphicsFamily.value(); uint32_t presentFamily = m_familyIndices.presentFamily.value(); + uint32_t computerFamily = m_familyIndices.computerFamily.value(); + std::vector familyIndexs = {}; + familyIndexs.push_back(graphicsFamily); - if ( graphicsFamily == presentFamily ) + if(presentFamily != graphicsFamily) { - familyIndexs.push_back(graphicsFamily); - } - else - { - familyIndexs.push_back(graphicsFamily); familyIndexs.push_back(presentFamily); } + if((computerFamily != graphicsFamily) && (computerFamily != presentFamily)) + { + familyIndexs.push_back(computerFamily); + } + std::vector queueCreateInfos; for(uint32_t index : familyIndexs) { @@ -412,6 +416,7 @@ void Application::createLogicDeivce() vkGetDeviceQueue(m_device, graphicsFamily, 0, &m_graphicsQueue); vkGetDeviceQueue(m_device, presentFamily, 0, &m_presentQueue); + vkGetDeviceQueue(m_device, computerFamily, 0, &m_computerQueue); } void Application::createSwapchain() @@ -679,13 +684,13 @@ void Application::createCommandBuffers() { m_commandBuffers.resize(m_framebuffers.size()); - VkCommandBufferAllocateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - createInfo.commandPool = m_commandPool; - createInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - createInfo.commandBufferCount = static_cast(m_commandBuffers.size()); + VkCommandBufferAllocateInfo allocateInfo = {}; + allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocateInfo.commandPool = m_commandPool; + allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocateInfo.commandBufferCount = static_cast(m_commandBuffers.size()); - if( vkAllocateCommandBuffers(m_device, &createInfo, m_commandBuffers.data()) != VK_SUCCESS ) + if( vkAllocateCommandBuffers(m_device, &allocateInfo, m_commandBuffers.data()) != VK_SUCCESS ) { throw std::runtime_error("failed to create command buffer!"); } @@ -786,10 +791,15 @@ QueueFamilyIndices Application::findQueueFamilyIndices() uint32_t i = 0; for(auto properties : queueFamilyProperties) { - if( properties.queueFlags & VK_QUEUE_GRAPHICS_BIT ) + if( properties.queueFlags & VK_QUEUE_GRAPHICS_BIT) { indices.graphicsFamily = i; } + + if( properties.queueFlags & VK_QUEUE_COMPUTE_BIT) + { + indices.computerFamily = i; + } VkBool32 supported; vkGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, i, m_surfaceKHR, &supported); @@ -798,7 +808,7 @@ QueueFamilyIndices Application::findQueueFamilyIndices() indices.presentFamily = i; } - if(indices.graphicsFamily.has_value() && indices.presentFamily.has_value()) + if(indices.isComplete()) { break; } diff --git a/Vulkan/Vulkan_Sample/Vulkan/common/application.h b/Vulkan/Vulkan_Sample/Vulkan/common/application.h index 559ff22..f256c13 100644 --- a/Vulkan/Vulkan_Sample/Vulkan/common/application.h +++ b/Vulkan/Vulkan_Sample/Vulkan/common/application.h @@ -12,9 +12,10 @@ struct QueueFamilyIndices { std::optional graphicsFamily; std::optional presentFamily; + std::optional computerFamily; bool isComplete(){ - return graphicsFamily.has_value() && presentFamily.has_value(); + return graphicsFamily.has_value() && presentFamily.has_value() && computerFamily.has_value(); } }; @@ -32,7 +33,7 @@ class Application void run(); void loop(); void logic(); - void render(); + virtual void render(); virtual void betweenInitAndLoop(); virtual void updateRenderData(); void beginRenderCommandAndPass(const VkCommandBuffer commandBuffer, int frameBufferIndex); @@ -97,6 +98,7 @@ class Application VkPhysicalDevice m_physicalDevice; VkDevice m_device; QueueFamilyIndices m_familyIndices; + VkQueue m_computerQueue; VkQueue m_graphicsQueue; VkQueue m_presentQueue; diff --git a/Vulkan/Vulkan_Sample/Vulkan/common/texture.cpp b/Vulkan/Vulkan_Sample/Vulkan/common/texture.cpp index 1835582..ab4bfd9 100644 --- a/Vulkan/Vulkan_Sample/Vulkan/common/texture.cpp +++ b/Vulkan/Vulkan_Sample/Vulkan/common/texture.cpp @@ -130,7 +130,7 @@ void Texture::fillTextrue(Texture* texture, void* buffer, VkDeviceSize bufferSiz stagingBuffer, stagingMemory); Tools::mapMemory(stagingMemory, bufferSize, buffer); Tools::createImageAndMemoryThenBind(texture->m_fromat, texture->m_width, texture->m_height, texture->m_mipLevels, texture->m_layerCount, - VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_TILING_OPTIMAL, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, texture->m_image, texture->m_imageMemory); @@ -318,7 +318,7 @@ void Texture::fillTextrue(Texture* texture, ktxTexture* ktxTexture, VkQueue tran } Tools::createImageAndMemoryThenBind(texture->m_fromat, texture->m_width, texture->m_height, texture->m_mipLevels, layerCount, - VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_TILING_OPTIMAL, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, texture->m_image, texture->m_imageMemory, flags); @@ -540,7 +540,7 @@ Texture* Texture::loadTextrue2D(std::string fileName, VkQueue transferQueue, VkF } Tools::createImageAndMemoryThenBind(format, newTexture->m_width, newTexture->m_height, newTexture->m_mipLevels, layerCount, - VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_TILING_OPTIMAL, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, newTexture->m_image, newTexture->m_imageMemory, flags); diff --git a/Vulkan/Vulkan_Sample/Vulkan/common/tools.cpp b/Vulkan/Vulkan_Sample/Vulkan/common/tools.cpp index 77edc19..5163dc0 100644 --- a/Vulkan/Vulkan_Sample/Vulkan/common/tools.cpp +++ b/Vulkan/Vulkan_Sample/Vulkan/common/tools.cpp @@ -7,6 +7,7 @@ VkPhysicalDevice Tools::m_physicalDevice = VK_NULL_HANDLE; VkDevice Tools::m_device = VK_NULL_HANDLE; VkQueue Tools::m_graphicsQueue = VK_NULL_HANDLE; +VkQueue Tools::m_computerQueue = VK_NULL_HANDLE; VkCommandPool Tools::m_commandPool = VK_NULL_HANDLE; VkPhysicalDeviceFeatures Tools::m_deviceEnabledFeatures = {}; VkPhysicalDeviceProperties Tools::m_deviceProperties = {}; @@ -165,8 +166,10 @@ void Tools::createImageAndMemoryThenBind(VkFormat format, uint32_t width, uint32 createInfo.tiling = tiling; createInfo.usage = usage; createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - createInfo.queueFamilyIndexCount = 0; - createInfo.pQueueFamilyIndices = nullptr; + std::vector queueFamilyIndices; + queueFamilyIndices.push_back(0); + createInfo.queueFamilyIndexCount = static_cast(queueFamilyIndices.size()); + createInfo.pQueueFamilyIndices = queueFamilyIndices.data(); createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; if( vkCreateImage(m_device, &createInfo, nullptr, &image) != VK_SUCCESS ) diff --git a/Vulkan/Vulkan_Sample/Vulkan/common/tools.h b/Vulkan/Vulkan_Sample/Vulkan/common/tools.h index 1915ee5..e2fbf93 100644 --- a/Vulkan/Vulkan_Sample/Vulkan/common/tools.h +++ b/Vulkan/Vulkan_Sample/Vulkan/common/tools.h @@ -50,6 +50,7 @@ class Tools static VkPhysicalDevice m_physicalDevice; static VkDevice m_device; static VkQueue m_graphicsQueue; + static VkQueue m_computerQueue; static VkPhysicalDeviceFeatures m_deviceEnabledFeatures; static VkPhysicalDeviceProperties m_deviceProperties; static VkCommandPool m_commandPool; diff --git a/Vulkan/Vulkan_Sample/Vulkan/main.cpp b/Vulkan/Vulkan_Sample/Vulkan/main.cpp index f66620d..b33512b 100644 --- a/Vulkan/Vulkan_Sample/Vulkan/main.cpp +++ b/Vulkan/Vulkan_Sample/Vulkan/main.cpp @@ -38,6 +38,7 @@ #include "sample/deferredmutisampling/deferredmutisampling.h" #include "sample/deferredshadows/deferredshadows.h" #include "sample/ssao/ssao.h" +#include "sample/computershader/computershader.h" int main(int argc, const char * argv[]) { @@ -80,8 +81,9 @@ int main(int argc, const char * argv[]) // Deferred app("deferred"); // DeferredMutiSampling app("deferredmutisampling"); // DeferredShadows app("deferredshadows"); +// DeferredSsao app("ssao"); - DeferredSsao app("ssao"); + ComputerShader app("computershader"); try { app.run(); diff --git a/Vulkan/Vulkan_Sample/Vulkan/sample/computershader/computershader.cpp b/Vulkan/Vulkan_Sample/Vulkan/sample/computershader/computershader.cpp new file mode 100644 index 0000000..b81ee17 --- /dev/null +++ b/Vulkan/Vulkan_Sample/Vulkan/sample/computershader/computershader.cpp @@ -0,0 +1,509 @@ + +#include "computershader.h" + +ComputerShader::ComputerShader(std::string title) : Application(title) +{ +} + +ComputerShader::~ComputerShader() +{} + +void ComputerShader::init() +{ + Application::init(); + + prepareVertex(); + prepareUniform(); + prepareTextureTarget(); + prepareDescriptorSetLayoutAndPipelineLayout(); + prepareDescriptorSetAndWrite(); + + createComputePipeline(); + createGraphicsPipeline(); +} + +void ComputerShader::initCamera() +{ + m_camera.setPosition(glm::vec3(0.0f, 0.0f, -2.5f)); + m_camera.setRotation(glm::vec3(0.0f)); + m_camera.setPerspective(60.0f, (float)m_width / (float)m_height, 1.0f, 256.0f); +} + +void ComputerShader::clear() +{ + vkDestroyPipeline(m_device, m_computerPipeline, nullptr); + vkDestroyCommandPool(m_device, m_computerCommandPool, nullptr); + vkDestroyPipelineLayout(m_device, m_computerPipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_computerDescriptorSetLayout, nullptr); + vkDestroySemaphore(m_device, m_computerSemaphore, nullptr); + vkDestroySemaphore(m_device, m_graphicsSemaphore, nullptr); + + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + vkFreeMemory(m_device, m_uniformMemory, nullptr); + vkDestroyBuffer(m_device, m_uniformBuffer, nullptr); + vkFreeMemory(m_device, m_vertexMemory, nullptr); + vkDestroyBuffer(m_device, m_vertexBuffer, nullptr); + vkFreeMemory(m_device, m_indexMemory, nullptr); + vkDestroyBuffer(m_device, m_indexBuffer, nullptr); + + m_pTexture->clear(); + m_pComputerTarget->clear(); + delete m_pTexture; + delete m_pComputerTarget; + Application::clear(); +} + +void ComputerShader::prepareVertex() +{ + std::vector vertexs = + { + { { 1.0f, 1.0f, 0.0f }, { 1.0f, 1.0f } }, + { { -1.0f, 1.0f, 0.0f }, { 0.0f, 1.0f } }, + { { -1.0f, -1.0f, 0.0f }, { 0.0f, 0.0f } }, + { { 1.0f, -1.0f, 0.0f }, { 1.0f, 0.0f } } + }; + + std::vector indexs = {0, 1, 2, 2, 3, 0}; + + m_vertexInputBindDes.clear(); + m_vertexInputBindDes.push_back(Tools::getVertexInputBindingDescription(0, sizeof(Vertex))); + + m_vertexInputAttrDes.clear(); + m_vertexInputAttrDes.push_back(Tools::getVertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, position))); + m_vertexInputAttrDes.push_back(Tools::getVertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, uv))); + + VkDeviceSize vertexSize = vertexs.size() * sizeof(Vertex); + VkDeviceSize indexSize = indexs.size() * sizeof(uint32_t); + + VkBuffer vertexStageBuffer; + VkDeviceMemory vertexStageMemory; + Tools::createBufferAndMemoryThenBind(vertexSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + vertexStageBuffer, vertexStageMemory); + Tools::mapMemory(vertexStageMemory, vertexSize, vertexs.data()); + Tools::createBufferAndMemoryThenBind(vertexSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_vertexBuffer, m_vertexMemory); + + VkBuffer indexStageBuffer; + VkDeviceMemory indexStageMemory; + Tools::createBufferAndMemoryThenBind(indexSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + indexStageBuffer, indexStageMemory); + Tools::mapMemory(indexStageMemory, indexSize, indexs.data()); + Tools::createBufferAndMemoryThenBind(indexSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_indexBuffer, m_indexMemory); + + + VkCommandBuffer cmd = Tools::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); + + VkBufferCopy vertexCopy = {}; + vertexCopy.srcOffset = 0; + vertexCopy.dstOffset = 0; + vertexCopy.size = vertexSize; + vkCmdCopyBuffer(cmd, vertexStageBuffer, m_vertexBuffer, 1, &vertexCopy); + + VkBufferCopy indexCopy = {}; + indexCopy.srcOffset = 0; + indexCopy.dstOffset = 0; + indexCopy.size = indexSize; + vkCmdCopyBuffer(cmd, indexStageBuffer, m_indexBuffer, 1, &indexCopy); + + Tools::flushCommandBuffer(cmd, m_graphicsQueue, true); + + vkFreeMemory(m_device, vertexStageMemory, nullptr); + vkDestroyBuffer(m_device, vertexStageBuffer, nullptr); + vkFreeMemory(m_device, indexStageMemory, nullptr); + vkDestroyBuffer(m_device, indexStageBuffer, nullptr); +} + +void ComputerShader::prepareUniform() +{ + VkDeviceSize uniformSize = sizeof(Uniform); + + Tools::createBufferAndMemoryThenBind(uniformSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + m_uniformBuffer, m_uniformMemory); + + Uniform mvp = {}; + mvp.projectionMatrix = m_camera.m_projMat; + mvp.viewMatrix = m_camera.m_viewMat; + Tools::mapMemory(m_uniformMemory, sizeof(Uniform), &mvp); +} + +void ComputerShader::prepareTextureTarget() +{ + m_pTexture = Texture::loadTextrue2D(Tools::getTexturePath() + "vulkan_11_rgba.ktx", m_graphicsQueue, VK_FORMAT_R8G8B8A8_UNORM, TextureCopyRegion::Nothing, VK_IMAGE_LAYOUT_GENERAL); + + m_pComputerTarget = new Texture(); + m_pComputerTarget->m_fromat = VK_FORMAT_R8G8B8A8_UNORM; + m_pComputerTarget->m_imageLayout = VK_IMAGE_LAYOUT_GENERAL; + m_pComputerTarget->m_width = m_pTexture->m_width; + m_pComputerTarget->m_height = m_pTexture->m_height; + m_pComputerTarget->m_layerCount = 1; + m_pComputerTarget->m_mipLevels = 1; + + Tools::createImageAndMemoryThenBind(m_pComputerTarget->m_fromat, m_pComputerTarget->m_width, m_pComputerTarget->m_height, m_pComputerTarget->m_mipLevels, m_pComputerTarget->m_layerCount, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_TILING_OPTIMAL, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_pComputerTarget->m_image, m_pComputerTarget->m_imageMemory); + + VkCommandBuffer cmd = Tools::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); + + Tools::setImageLayout(cmd, m_pComputerTarget->m_image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_IMAGE_ASPECT_COLOR_BIT); + Tools::flushCommandBuffer(cmd, m_graphicsQueue, true); + vkDeviceWaitIdle(m_device); + + Tools::createImageView(m_pComputerTarget->m_image, m_pComputerTarget->m_fromat, VK_IMAGE_ASPECT_COLOR_BIT, m_pComputerTarget->m_mipLevels, m_pComputerTarget->m_layerCount, m_pComputerTarget->m_imageView); + Tools::createTextureSampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT, m_pComputerTarget->m_mipLevels, m_pComputerTarget->m_sampler); +} + +void ComputerShader::prepareDescriptorSetLayoutAndPipelineLayout() +{ + { + std::array bindings = {}; + bindings[0] = Tools::getDescriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT, 0); + bindings[1] = Tools::getDescriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT, 1); + VkDescriptorSetLayoutCreateInfo createInfo = Tools::getDescriptorSetLayoutCreateInfo(bindings.data(), 2); + vkCreateDescriptorSetLayout(m_device, &createInfo, nullptr, &m_computerDescriptorSetLayout); + createPipelineLayout(&m_computerDescriptorSetLayout, 1, m_computerPipelineLayout); + } + + { + std::array bindings = {}; + bindings[0] = Tools::getDescriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0); + bindings[1] = Tools::getDescriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1); + createDescriptorSetLayout(bindings.data(), static_cast(bindings.size())); + createPipelineLayout(); + } +} + +void ComputerShader::prepareDescriptorSetAndWrite() +{ + std::array poolSizes; + poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + poolSizes[0].descriptorCount = 2; + poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + poolSizes[1].descriptorCount = 2; + poolSizes[2].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + poolSizes[2].descriptorCount = 2; + + createDescriptorPool(poolSizes.data(), static_cast(poolSizes.size()), 3); + + { + createDescriptorSet(&m_descriptorSetLayout, 1, m_preComputerDescriptorSet); + + VkDescriptorBufferInfo bufferInfo = {}; + bufferInfo.offset = 0; + bufferInfo.range = sizeof(Uniform); + bufferInfo.buffer = m_uniformBuffer; + + VkDescriptorImageInfo imageInfo = m_pTexture->getDescriptorImageInfo(); + + std::array writes = {}; + writes[0] = Tools::getWriteDescriptorSet(m_preComputerDescriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &bufferInfo); + writes[1] = Tools::getWriteDescriptorSet(m_preComputerDescriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &imageInfo); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); + } + + { + createDescriptorSet(&m_descriptorSetLayout, 1, m_postComputerDescriptorSet); + VkDescriptorBufferInfo bufferInfo = {}; + bufferInfo.offset = 0; + bufferInfo.range = sizeof(Uniform); + bufferInfo.buffer = m_uniformBuffer; + + VkDescriptorImageInfo imageInfo = m_pComputerTarget->getDescriptorImageInfo(); + + std::array writes = {}; + writes[0] = Tools::getWriteDescriptorSet(m_postComputerDescriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &bufferInfo); + writes[1] = Tools::getWriteDescriptorSet(m_postComputerDescriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &imageInfo); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); + } + + { + createDescriptorSet(&m_computerDescriptorSetLayout, 1, m_computerDescriptorSet); + + VkDescriptorImageInfo imageInfo1 = {}; + imageInfo1.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + imageInfo1.imageView = m_pTexture->m_imageView; + imageInfo1.sampler = VK_NULL_HANDLE; + + VkDescriptorImageInfo imageInfo2 = {}; + imageInfo2.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + imageInfo2.imageView = m_pComputerTarget->m_imageView; + imageInfo2.sampler = VK_NULL_HANDLE; + + std::array writes = {}; + writes[0] = Tools::getWriteDescriptorSet(m_computerDescriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 0, &imageInfo1); + writes[1] = Tools::getWriteDescriptorSet(m_computerDescriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, &imageInfo2); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); + } +} + +void ComputerShader::createComputePipeline() +{ + { + std::vector shaderNames = { "emboss", "edgedetect", "sharpen" }; + VkShaderModule compModule = Tools::createShaderModule( Tools::getShaderPath() + "computeshader/" + shaderNames[0] + ".comp.spv"); + VkPipelineShaderStageCreateInfo stageInfo = Tools::getPipelineShaderStageCreateInfo(compModule, VK_SHADER_STAGE_COMPUTE_BIT); + + VkComputePipelineCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + createInfo.stage = stageInfo; + createInfo.layout = m_computerPipelineLayout; + VK_CHECK_RESULT(vkCreateComputePipelines(m_device, m_pipelineCache, 1, &createInfo, nullptr, &m_computerPipeline)); + vkDestroyShaderModule(m_device, compModule, nullptr); + } + + { + VkCommandPoolCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + createInfo.queueFamilyIndex = m_familyIndices.computerFamily.value(); + VK_CHECK_RESULT(vkCreateCommandPool(m_device, &createInfo, nullptr, &m_computerCommandPool)); + } + + // Semaphore for compute & graphics sync + { + VkSemaphoreCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + createInfo.flags = 0; + VK_CHECK_RESULT(vkCreateSemaphore(m_device, &createInfo, nullptr, &m_graphicsSemaphore)); + + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &m_graphicsSemaphore; + VK_CHECK_RESULT(vkQueueSubmit(m_computerQueue, 1, &submitInfo, VK_NULL_HANDLE)); + VK_CHECK_RESULT(vkQueueWaitIdle(m_computerQueue)); + } + + { + VkSemaphoreCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + createInfo.flags = 0; + VK_CHECK_RESULT(vkCreateSemaphore(m_device, &createInfo, nullptr, &m_computerSemaphore)); + } + + // command buffer + { + VkCommandBufferAllocateInfo allocateInfo = {}; + allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocateInfo.commandPool = m_computerCommandPool; + allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocateInfo.commandBufferCount = 1; + VK_CHECK_RESULT(vkAllocateCommandBuffers(m_device, &allocateInfo, &m_computerCommandBuffer)); + + VkCommandBufferBeginInfo beginInfo = {}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + beginInfo.pInheritanceInfo = nullptr; + VK_CHECK_RESULT(vkBeginCommandBuffer(m_computerCommandBuffer, &beginInfo)); + + vkCmdBindPipeline(m_computerCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, m_computerPipeline); + vkCmdBindDescriptorSets(m_computerCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, m_computerPipelineLayout, 0, 1, &m_computerDescriptorSet, 0, nullptr); + vkCmdDispatch(m_computerCommandBuffer, m_pComputerTarget->m_width/16, m_pComputerTarget->m_height/16, 1); + vkEndCommandBuffer(m_computerCommandBuffer); + } +} + +void ComputerShader::createGraphicsPipeline() +{ + VkShaderModule vertModule = Tools::createShaderModule( Tools::getShaderPath() + "computeshader/texture.vert.spv"); + VkShaderModule fragModule = Tools::createShaderModule( Tools::getShaderPath() + "computeshader/texture.frag.spv"); + + VkPipelineShaderStageCreateInfo vertShader = Tools::getPipelineShaderStageCreateInfo(vertModule, VK_SHADER_STAGE_VERTEX_BIT); + VkPipelineShaderStageCreateInfo fragShader = Tools::getPipelineShaderStageCreateInfo(fragModule, VK_SHADER_STAGE_FRAGMENT_BIT); + + VkPipelineVertexInputStateCreateInfo vertexInput = {}; + vertexInput.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInput.vertexBindingDescriptionCount = static_cast(m_vertexInputBindDes.size()); + vertexInput.pVertexBindingDescriptions = m_vertexInputBindDes.data(); + vertexInput.vertexAttributeDescriptionCount = static_cast(m_vertexInputAttrDes.size()); + vertexInput.pVertexAttributeDescriptions = m_vertexInputAttrDes.data(); + + VkPipelineInputAssemblyStateCreateInfo inputAssembly = Tools::getPipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_FALSE); + + VkPipelineViewportStateCreateInfo viewport = {}; + viewport.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport.flags = 0; + viewport.viewportCount = 1; + viewport.pViewports = nullptr; + viewport.scissorCount = 1; + viewport.pScissors = nullptr; + + std::vector dynamicStates = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR + }; + + VkPipelineDynamicStateCreateInfo dynamic = Tools::getPipelineDynamicStateCreateInfo(dynamicStates); + VkPipelineRasterizationStateCreateInfo rasterization = Tools::getPipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE); + VkPipelineMultisampleStateCreateInfo multisample = Tools::getPipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT); + VkPipelineDepthStencilStateCreateInfo depthStencil = Tools::getPipelineDepthStencilStateCreateInfo(VK_FALSE, VK_FALSE, VK_COMPARE_OP_LESS_OR_EQUAL); + + VkPipelineColorBlendAttachmentState colorBlendAttachment = Tools::getPipelineColorBlendAttachmentState(VK_FALSE, VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT); + VkPipelineColorBlendStateCreateInfo colorBlend = Tools::getPipelineColorBlendStateCreateInfo(1, &colorBlendAttachment); + + std::vector shaderStages; + shaderStages.push_back(vertShader); + shaderStages.push_back(fragShader); + + VkGraphicsPipelineCreateInfo createInfo = Tools::getGraphicsPipelineCreateInfo(shaderStages, m_pipelineLayout, m_renderPass); + + createInfo.pVertexInputState = &vertexInput; + createInfo.pInputAssemblyState = &inputAssembly; + createInfo.pTessellationState = nullptr; + createInfo.pViewportState = &viewport; + createInfo.pRasterizationState = &rasterization; + createInfo.pMultisampleState = &multisample; + createInfo.pDepthStencilState = &depthStencil; + createInfo.pColorBlendState = &colorBlend; + createInfo.pDynamicState = &dynamic; + createInfo.subpass = 0; + + if( vkCreateGraphicsPipelines(m_device, m_pipelineCache, 1, &createInfo, nullptr, &m_graphicsPipeline) != VK_SUCCESS ) + { + throw std::runtime_error("failed to create graphics pipeline!"); + } + + vkDestroyShaderModule(m_device, vertModule, nullptr); + vkDestroyShaderModule(m_device, fragModule, nullptr); +} + +void ComputerShader::updateRenderData() +{ + +} + +void ComputerShader::recordRenderCommand(const VkCommandBuffer commandBuffer) +{ +// VkViewport viewport = Tools::getViewport(-m_swapchainExtent.width*0.25, 0, m_swapchainExtent.width, m_swapchainExtent.height); + VkViewport viewport = Tools::getViewport(0, 0, m_swapchainExtent.width, m_swapchainExtent.height); + VkRect2D scissor; + scissor.offset = {0, 0}; + scissor.extent = m_swapchainExtent; + + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); + vkCmdSetViewport(commandBuffer, 0, 1, &viewport); + vkCmdSetScissor(commandBuffer, 0, 1, &scissor); + + VkDeviceSize offset = {0}; + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_vertexBuffer, &offset); + vkCmdBindIndexBuffer(commandBuffer, m_indexBuffer, 0, VK_INDEX_TYPE_UINT32); + + // left + viewport.x = -(float)m_swapchainExtent.width*0.25; + vkCmdSetViewport(commandBuffer, 0, 1, &viewport); + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_preComputerDescriptorSet, 0, nullptr); + vkCmdDrawIndexed(commandBuffer, 6, 1, 0, 0, 0); + + // right + viewport.x = (float)m_swapchainExtent.width*0.25; + vkCmdSetViewport(commandBuffer, 0, 1, &viewport); + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_postComputerDescriptorSet, 0, nullptr); + vkCmdDrawIndexed(commandBuffer, 6, 1, 0, 0, 0); +} + +void ComputerShader::createOtherRenderPass(const VkCommandBuffer& commandBuffer) +{ + // Image memory barrier to make sure that compute shader writes are finished before sampling from the texture + VkImageMemoryBarrier imageMemoryBarrier = {}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + // We won't be changing the layout of the image + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + imageMemoryBarrier.image = m_pComputerTarget->m_image; + imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; + imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + vkCmdPipelineBarrier( commandBuffer, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + 0, + 0, nullptr, + 0, nullptr, + 1, &imageMemoryBarrier); +} + +void ComputerShader::render() +{ + updateRenderData(); + + if(m_pUi) + { + m_pUi->updateRenderData(); + } + + // fence需要手动重置为未发出的信号 + vkWaitForFences(m_device, 1, &m_inFlightFences[m_currentFrame], VK_TRUE, UINT64_MAX); + vkResetFences(m_device, 1, &m_inFlightFences[m_currentFrame]); + + { + // 这里放computer command + VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &m_computerCommandBuffer; + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = &m_graphicsSemaphore; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &m_computerSemaphore; + submitInfo.pWaitDstStageMask = &waitStageMask; + VK_CHECK_RESULT(vkQueueSubmit(m_computerQueue, 1, &submitInfo, VK_NULL_HANDLE)); + } + + vkAcquireNextImageKHR(m_device, m_swapchainKHR, UINT64_MAX, m_imageAvailableSemaphores[m_currentFrame], VK_NULL_HANDLE, &m_imageIndex); + + VkCommandBuffer commandBuffer = m_commandBuffers[m_imageIndex]; + beginRenderCommandAndPass(commandBuffer, m_imageIndex); + recordRenderCommand(commandBuffer); + + if(m_pUi) + { + m_pUi->recordRenderCommand(commandBuffer); + } + + endRenderCommandAndPass(commandBuffer); + + + VkSemaphore graphicsWaitSemaphores[] = { m_computerSemaphore, m_imageAvailableSemaphores[m_currentFrame] }; + VkSemaphore graphicsSignalSemaphores[] = { m_graphicsSemaphore, m_renderFinishedSemaphores[m_currentFrame] }; + + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.waitSemaphoreCount = 2; + submitInfo.pWaitSemaphores = graphicsWaitSemaphores; + VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; + submitInfo.pWaitDstStageMask = waitStages; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + submitInfo.signalSemaphoreCount = 2; + submitInfo.pSignalSemaphores = graphicsSignalSemaphores; + + //在命令缓冲区结束后需要发起的fence + if(vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, m_inFlightFences[m_currentFrame]) != VK_SUCCESS) + { + throw std::runtime_error("failed to queue submit!"); + } + + queueResult(); + + VkPresentInfoKHR presentInfo = {}; + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.waitSemaphoreCount = 1; + presentInfo.pWaitSemaphores = &m_renderFinishedSemaphores[m_currentFrame]; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = &m_swapchainKHR; + presentInfo.pImageIndices = &m_imageIndex; + presentInfo.pResults = nullptr; + + if(vkQueuePresentKHR(m_presentQueue, &presentInfo) != VK_SUCCESS) + { + throw std::runtime_error("failed to queue present!"); + } + + m_currentFrame = (m_currentFrame + 1) % m_swapchainImageCount; +} diff --git a/Vulkan/Vulkan_Sample/Vulkan/sample/computershader/computershader.h b/Vulkan/Vulkan_Sample/Vulkan/sample/computershader/computershader.h new file mode 100644 index 0000000..1df69ff --- /dev/null +++ b/Vulkan/Vulkan_Sample/Vulkan/sample/computershader/computershader.h @@ -0,0 +1,69 @@ + +#pragma once + +#include "common/application.h" +#include "common/texture.h" + +class ComputerShader : public Application +{ +public: + + struct Vertex { + float position[3]; + float uv[2]; + }; + + struct Uniform { + glm::mat4 projectionMatrix; + glm::mat4 viewMatrix; + }; + + ComputerShader(std::string title); + virtual ~ComputerShader(); + + virtual void init(); + virtual void initCamera(); + virtual void clear(); + virtual void render(); + + virtual void updateRenderData(); + virtual void recordRenderCommand(const VkCommandBuffer commandBuffer); + virtual void createOtherRenderPass(const VkCommandBuffer& commandBuffer); + +protected: + void prepareVertex(); + void prepareUniform(); + void prepareTextureTarget(); + void prepareDescriptorSetLayoutAndPipelineLayout(); + void prepareDescriptorSetAndWrite(); + void createGraphicsPipeline(); + void createComputePipeline(); + +protected: + VkPipeline m_graphicsPipeline; + //顶点绑定和顶点描述 + std::vector m_vertexInputBindDes; + std::vector m_vertexInputAttrDes; + + VkBuffer m_vertexBuffer; + VkDeviceMemory m_vertexMemory; + VkBuffer m_indexBuffer; + VkDeviceMemory m_indexMemory; + VkBuffer m_uniformBuffer; + VkDeviceMemory m_uniformMemory; + + Texture* m_pTexture; + Texture* m_pComputerTarget; + + VkDescriptorSet m_preComputerDescriptorSet; + VkDescriptorSet m_postComputerDescriptorSet; + + VkPipeline m_computerPipeline; + VkCommandPool m_computerCommandPool; + VkCommandBuffer m_computerCommandBuffer; + VkPipelineLayout m_computerPipelineLayout; + VkDescriptorSetLayout m_computerDescriptorSetLayout; + VkDescriptorSet m_computerDescriptorSet; + VkSemaphore m_computerSemaphore; + VkSemaphore m_graphicsSemaphore; +}; diff --git a/Vulkan/Vulkan_Sample/screenshots/39_computeShader.png b/Vulkan/Vulkan_Sample/screenshots/39_computeShader.png new file mode 100644 index 0000000..fd487b8 Binary files /dev/null and b/Vulkan/Vulkan_Sample/screenshots/39_computeShader.png differ