diff --git a/src/main.cpp b/src/main.cpp
index 584ab2f..c23338d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -6,6 +6,7 @@
 #include <optional>
 #include <limits>
 #include <algorithm>
+#include <chrono>
 #include <random>
 
 #include <vulkan/vulkan.hpp>
@@ -102,6 +103,7 @@ private:
     vk::raii::Device m_device{ nullptr };
     vk::raii::Queue m_graphicsQueue{ nullptr };
     vk::raii::Queue m_presentQueue{ nullptr };
+    vk::raii::Queue m_computeQueue{ nullptr };
     vk::raii::SwapchainKHR m_swapChain{ nullptr };
     std::vector<vk::Image> m_swapChainImages;
     vk::Format m_swapChainImageFormat{};
@@ -109,10 +111,15 @@ private:
     std::vector<vk::raii::ImageView> m_swapChainImageViews;
     vk::raii::RenderPass m_renderPass{ nullptr };
     std::vector<vk::raii::Framebuffer> m_swapChainFramebuffers;
+    vk::raii::DescriptorSetLayout m_descriptorSetLayout{ nullptr };
+    vk::raii::DescriptorPool m_descriptorPool{ nullptr };
+    vk::raii::PipelineLayout m_computePipelineLayout{ nullptr };
+    vk::raii::Pipeline m_computePipeline{ nullptr };
     vk::raii::PipelineLayout m_pipelineLayout{ nullptr };
     vk::raii::Pipeline m_graphicsPipeline{ nullptr };
     vk::raii::CommandPool m_commandPool{ nullptr };
     std::vector<vk::raii::CommandBuffer> m_commandBuffers;
+    std::vector<vk::raii::CommandBuffer> m_computeCommandBuffers;
     std::vector<vk::raii::Semaphore> m_imageAvailableSemaphores;
     std::vector<vk::raii::Semaphore> m_renderFinishedSemaphores;
     std::vector<vk::raii::Fence> m_inFlightFences;
@@ -120,6 +127,9 @@ private:
     bool m_framebufferResized = false;
     vk::raii::DeviceMemory m_particleBufferMemory{ nullptr };
     vk::raii::Buffer m_particleBuffer{ nullptr };
+    std::vector<vk::raii::DescriptorSet> m_descriptorSets;
+    std::vector<vk::raii::Semaphore> m_computeFinishedSemaphores;
+    std::vector<vk::raii::Semaphore> m_graphicsFinishedSemaphores;
     /////////////////////////////////////////////////////////////
 
     /////////////////////////////////////////////////////////////
@@ -149,11 +159,16 @@ private:
         createImageViews();
         createRenderPass();
         createFramebuffers();
+        createDescriptorSetLayout();
+        createDescriptorPool();
+        createComputePipeline();
         createGraphicsPipeline();
         createCommandPool();
         createCommandBuffers();
+        createComputeCommandBuffers(); // 可以放在图形命令缓冲的下方或上方
         createSyncObjects();
         createParticleBuffer();
+        createDescriptorSets();
     }
 
     void mainLoop() {
@@ -273,9 +288,10 @@ private:
         // std::vector<vk::QueueFamilyProperties>
         const auto queueFamilies = physicalDevice.getQueueFamilyProperties();
         for (int i = 0; const auto& queueFamily : queueFamilies) {
-            if (queueFamily.queueFlags & vk::QueueFlagBits::eGraphics) {
-                indices.graphicsFamily = i;
-            }
+            if ((queueFamily.queueFlags & vk::QueueFlagBits::eGraphics) &&
+                (queueFamily.queueFlags & vk::QueueFlagBits::eCompute)
+            ) indices.graphicsFamily = i;
+
             if(physicalDevice.getSurfaceSupportKHR(i, m_surface)){
                 indices.presentFamily = i;
             }
@@ -352,6 +368,7 @@ private:
         m_device = m_physicalDevice.createDevice( createInfo );
         m_graphicsQueue = m_device.getQueue( graphics.value(), 0 );
         m_presentQueue = m_device.getQueue( present.value(), 0 );
+        m_computeQueue = m_device.getQueue( graphics.value(), 0 );
     }
     /////////////////////////////////////////////////////////////
 
@@ -662,6 +679,8 @@ private:
             m_imageAvailableSemaphores.emplace_back( m_device, semaphoreInfo );
             m_renderFinishedSemaphores.emplace_back( m_device,  semaphoreInfo );
             m_inFlightFences.emplace_back( m_device , fenceInfo );
+            m_computeFinishedSemaphores.emplace_back( m_device, semaphoreInfo );
+            m_graphicsFinishedSemaphores.emplace_back( m_device, semaphoreInfo );
         }
     }
     void drawFrame() {
@@ -681,16 +700,49 @@ private:
 
         m_device.resetFences( *m_inFlightFences[m_currentFrame] );
 
+        m_computeCommandBuffers[m_currentFrame].reset();
+        recordComputeCommandBuffer(m_computeCommandBuffers[m_currentFrame]);
+
+        static bool firstTime = true;
+
+        // 设置提交信息，并在任务完成时发送信号量
+        vk::SubmitInfo computeSubmitInfo;
+        computeSubmitInfo.setCommandBuffers( *m_computeCommandBuffers[m_currentFrame] );
+        computeSubmitInfo.setSignalSemaphores( *m_computeFinishedSemaphores[m_currentFrame] );
+        if (!firstTime) { // 如果不是第一次，则等待上一次绘制完成
+            computeSubmitInfo.setWaitSemaphores( *m_graphicsFinishedSemaphores[ (m_currentFrame+MAX_FRAMES_IN_FLIGHT-1)%MAX_FRAMES_IN_FLIGHT ] );
+            // 在计算着色器等待上一次渲染完成
+            constexpr vk::PipelineStageFlags pipelineStage = vk::PipelineStageFlagBits::eComputeShader;
+            computeSubmitInfo.setWaitDstStageMask( pipelineStage );
+        } else {
+            firstTime = false;
+        }
+        m_computeQueue.submit(computeSubmitInfo);
+
+
         m_commandBuffers[m_currentFrame].reset();
         recordCommandBuffer(m_commandBuffers[m_currentFrame], imageIndex);
 
         vk::SubmitInfo submitInfo;
-        submitInfo.setWaitSemaphores( *m_imageAvailableSemaphores[m_currentFrame] );
-        std::array<vk::PipelineStageFlags,1> waitStages = { vk::PipelineStageFlagBits::eColorAttachmentOutput };
+        // 渲染需要等待图像可用和本次计算完成
+        const std::array<vk::Semaphore,2> waitSemaphores = {
+            m_computeFinishedSemaphores[m_currentFrame],
+            m_imageAvailableSemaphores[m_currentFrame]
+        };
+        submitInfo.setWaitSemaphores( waitSemaphores );
+        constexpr std::array<vk::PipelineStageFlags,2> waitStages = {
+            vk::PipelineStageFlagBits::eVertexInput,
+            vk::PipelineStageFlagBits::eColorAttachmentOutput
+        };
         submitInfo.setWaitDstStageMask( waitStages );
         submitInfo.setCommandBuffers( *m_commandBuffers[m_currentFrame] );
 
-        submitInfo.setSignalSemaphores( *m_renderFinishedSemaphores[m_currentFrame] );
+        // 设置信号量，表示图形渲染完成。renderFinished 提供给呈现呈现，graphicsFinished提供给计算管线
+        const std::array<vk::Semaphore,2> signalSemaphores = {
+            m_renderFinishedSemaphores[m_currentFrame],
+            m_graphicsFinishedSemaphores[m_currentFrame]
+        };
+        submitInfo.setSignalSemaphores( signalSemaphores );
         m_graphicsQueue.submit(submitInfo, m_inFlightFences[m_currentFrame]);
 
         vk::PresentInfoKHR presentInfo;
@@ -831,6 +883,7 @@ private:
         stagingBufferMemory.unmapMemory();
 
         createBuffer(bufferSize,
+            vk::BufferUsageFlagBits::eStorageBuffer | // 添加存储缓冲区标志
             vk::BufferUsageFlagBits::eTransferDst |
             vk::BufferUsageFlagBits::eVertexBuffer,
             vk::MemoryPropertyFlagBits::eDeviceLocal,
@@ -841,6 +894,139 @@ private:
         copyBuffer(stagingBuffer, m_particleBuffer, bufferSize);
     }
     /////////////////////////////////////////////////////////////
+
+    /////////////////////////////////////////////////////////////
+    /// 获取时间差
+    static float getDeltaTime() {
+        static auto lastTime = std::chrono::steady_clock::now();
+        const auto currentTime = std::chrono::steady_clock::now();
+        const float res =  std::chrono::duration<float, std::chrono::milliseconds::period>(currentTime - lastTime).count();
+        lastTime = currentTime;
+        return res;
+    }
+    /////////////////////////////////////////////////////////////
+    /// 描述符
+    void createDescriptorSetLayout() {
+        vk::DescriptorSetLayoutBinding layoutBinding; // Storage Buffer 粒子数据
+        layoutBinding.binding = 0;
+        layoutBinding.descriptorCount = 1;
+        layoutBinding.descriptorType = vk::DescriptorType::eStorageBuffer; // 存储缓冲区
+        layoutBinding.stageFlags = vk::ShaderStageFlagBits::eCompute; // 计算着色器
+        vk::DescriptorSetLayoutCreateInfo layoutInfo;
+        layoutInfo.setBindings( layoutBinding );
+        m_descriptorSetLayout = m_device.createDescriptorSetLayout( layoutInfo );
+    }
+    void createDescriptorPool() {
+        vk::DescriptorPoolSize poolSize;
+        poolSize.type = vk::DescriptorType::eStorageBuffer; // 存储缓冲区
+        poolSize.descriptorCount = 1;
+
+        vk::DescriptorPoolCreateInfo poolInfo;
+        // raii 封装需要使用 eFreeDescriptorSet 标志位
+        poolInfo.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet;
+        poolInfo.maxSets = 1;
+        poolInfo.setPoolSizes( poolSize );
+
+        m_descriptorPool = m_device.createDescriptorPool( poolInfo );
+    }
+    void createDescriptorSets() {
+        vk::DescriptorSetAllocateInfo allocInfo;
+        allocInfo.setDescriptorPool( m_descriptorPool );
+        allocInfo.setSetLayouts( *m_descriptorSetLayout ); // 需要至少一次 * 显式转换
+
+        // 此描述符集数组仅单个元素
+        m_descriptorSets = m_device.allocateDescriptorSets( allocInfo );
+
+        vk::DescriptorBufferInfo particleBufferInfo;
+        // 绑定上一个缓冲区
+        particleBufferInfo.buffer = m_particleBuffer;
+        particleBufferInfo.offset = 0;
+        particleBufferInfo.range = sizeof(Particle) * PARTICLE_COUNT;
+
+        vk::WriteDescriptorSet descriptorWrite;
+        descriptorWrite.dstSet = m_descriptorSets.at(0);
+        descriptorWrite.dstBinding = 0;
+        descriptorWrite.descriptorType = vk::DescriptorType::eStorageBuffer; // 存储缓冲区类型
+        descriptorWrite.setBufferInfo( particleBufferInfo );
+
+        m_device.updateDescriptorSets(descriptorWrite, nullptr);
+    }
+    /////////////////////////////////////////////////////////////
+
+    /////////////////////////////////////////////////////////////
+    /// 计算管线
+    void createComputePipeline() {
+
+        // 推送常量配置
+        vk::PushConstantRange pushConstantRange;
+        pushConstantRange.stageFlags = vk::ShaderStageFlagBits::eCompute; // 计算着色器阶段
+        pushConstantRange.offset = 0; // 偏移量
+        pushConstantRange.size = sizeof(float); // 大小为 float
+
+        // 创建管线布局
+        vk::PipelineLayoutCreateInfo pipelineLayoutInfo;
+        pipelineLayoutInfo.setPushConstantRanges( pushConstantRange ); // 设置推送常量范围
+        pipelineLayoutInfo.setSetLayouts( *m_descriptorSetLayout ); // 设置描述符布局
+        m_computePipelineLayout = m_device.createPipelineLayout(pipelineLayoutInfo);
+
+        // 读取并创建着色器模块
+        const auto computeShaderCode = readFile("shaders/compute.comp.spv");
+        vk::raii::ShaderModule computeShaderModule = createShaderModule(computeShaderCode);
+
+        // 设置计算着色器阶段信息
+        vk::PipelineShaderStageCreateInfo computeShaderStageInfo;
+        computeShaderStageInfo.stage = vk::ShaderStageFlagBits::eCompute;
+        computeShaderStageInfo.module = computeShaderModule;
+        computeShaderStageInfo.pName = "main";
+
+        // 创建计算管线
+        vk::ComputePipelineCreateInfo computePipelineInfo;
+        computePipelineInfo.stage = computeShaderStageInfo;
+        computePipelineInfo.layout = m_computePipelineLayout;
+        m_computePipeline = m_device.createComputePipeline(nullptr, computePipelineInfo);
+    }
+    /////////////////////////////////////////////////////////////
+
+    /////////////////////////////////////////////////////////////
+    /// 命令录制
+    void createComputeCommandBuffers() {
+        vk::CommandBufferAllocateInfo allocInfo;
+        allocInfo.commandPool = m_commandPool;
+        allocInfo.level = vk::CommandBufferLevel::ePrimary;
+        allocInfo.commandBufferCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
+
+        m_computeCommandBuffers = m_device.allocateCommandBuffers(allocInfo);
+    }
+    void recordComputeCommandBuffer(const vk::raii::CommandBuffer& commandBuffer) {
+        constexpr vk::CommandBufferBeginInfo beginInfo;
+        commandBuffer.begin(beginInfo);
+
+        // 绑定计算管线
+        commandBuffer.bindPipeline(vk::PipelineBindPoint::eCompute, m_computePipeline);
+
+        // 绑定描述符集
+        commandBuffer.bindDescriptorSets(
+            vk::PipelineBindPoint::eCompute,
+            m_computePipelineLayout,
+            0,
+            *m_descriptorSets.at(0),
+            nullptr
+        );
+
+        const float deltaTime = getDeltaTime(); // 获取时间差
+        commandBuffer.pushConstants<float>(
+            m_computePipelineLayout,
+            vk::ShaderStageFlagBits::eCompute, // 计算着色器阶段
+            0, // 偏移量
+            deltaTime
+        );
+
+        // 调用计算着色器
+        commandBuffer.dispatch((PARTICLE_COUNT + 255) / 256, 1, 1);
+        commandBuffer.end();
+    }
+    /////////////////////////////////////////////////////////////
+
 };
 
 int main() {
