本篇是这个系列的第二篇,上一篇我们了解到GPU如何基于SM的计算单元和Wrap调度器来实现并行计算,并通过CPU和GPU协作,来实现CUDA的编程,那么这些GPU的并行计算都是用于什么的呢?其实早期SM主要用于3D游戏的着色器渲染,用于实现更炫酷,更逼真的光影效果,随着AIGC在这些年的爆火,GPU并行计算的可编程性在AI框架和CUDA编程的双重推动下,成为AI算子的一个实现方式。
这个话题会从「什么是着色器?3D模型渲染为什么要转换成三角形且使用着色器来实现 -->什么是GLSL,其与CPU是如何配合实现的 --> 一个简单的着色器demo实现3D正方体渲染 --> 为什么说向量运算是AI模型训练和推理的基础?它对并行计算有什么要求 --> 如何基于CUDA实现一次向量计算」这几个维度来介绍如何基于GPU实现着色器和向量计算的。


着色器(Shader)是运行在GPU上的小程序,用于实现图形渲染管线中的特定阶段计算。它取代了传统图形处理中固定的渲染流程,使开发者能够自定义渲染效果,实现更丰富的视觉体验。
3D模型在渲染前必须转换为三角形,这是因为:
使用着色器实现渲染的优势在于:
不管是游戏中的人物、场景、正方体,还是工业建模的复杂曲面,在送入 GPU 渲染前,一定会被拆解为无数个三角形的拼接组合。这不是人为规定的标准,而是图形学原理 + GPU 硬件设计的双重最优解,也是唯一解,核心原因有 3 点,优先级从高到低,缺一不可:

这个问题的答案,本质是「GPU 的核心能力是并行计算,而着色器是 GPU 并行计算在图形渲染上的唯一落地形式」,也是 CPU 与 GPU 的核心能力差异体现,核心原因有 3 点:
GLSL(OpenGL着色器语言)是用于编写着色器的编程语言,是OpenGL图形API的一部分,也是目前最通用、跨平台的着色器语言(适配 OpenGL/Vulkan,兼容绝大多数 GPU),我们日常开发的着色器程序,90% 都是基于 GLSL 编写的。它是一种类似C的高级语言,专为GPU着色器编程设计。
GLSL与CPU的协作流程:
三者分工的核心总结
CPU = 总指挥 + 后勤保障:负责串行调度、数据准备、配置管理、指令发送,不做任何密集计算;
GLSL = GPU 的并行计算代码:是运行在 GPU 上的「并行小程序」,负责实现渲染的核心计算逻辑;
GPU = 超级并行计算工人:负责执行 GLSL 代码,完成海量顶点 / 像素的并行计算,依靠 SM+Warp 发挥极致算力;
三者的协作,本质是「CPU 的串行优势」与「GPU 的并行优势」的完美结合,也是所有 GPU 编程(包括 CUDA)的核心思想。
这个示例展示了如何通过GLSL着色器实现3D正方体渲染。CPU负责设置渲染状态和数据,GPU则通过着色器执行顶点变换和像素着色.
// main.cpp - 完整的旋转彩色立方体#include<GL/glew.h>#include<GLFW/glfw3.h>#include<glm/glm.hpp>#include<glm/gtc/matrix_transform.hpp>#include<glm/gtc/type_ptr.hpp>#include<iostream>#include<vector>// 着色器源代码constchar* vertexShaderSource = R"(#version 460 corelayout(location = 0) in vec3 aPos;layout(location = 1) in vec3 aColor;out vec3 vertexColor;uniform mat4 model;uniform mat4 view;uniform mat4 projection;void main() { gl_Position = projection * view * model * vec4(aPos, 1.0); vertexColor = aColor;})";constchar* fragmentShaderSource = R"(#version 460 corein vec3 vertexColor;out vec4 FragColor;void main() { FragColor = vec4(vertexColor, 1.0);})";// 立方体数据:36个顶点(12个三角形 * 3个顶点)float vertices[] = {// 位置 // 颜色// 前平面 (红色)-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,// 后平面 (绿色)-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f,0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f,// 左平面 (蓝色)-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,// 右平面 (黄色)0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f,// 上平面 (品红色)-0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f,-0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f,-0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 1.0f,// 下平面 (青色)-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f,0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f,0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 1.0f,0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f};// 编译着色器辅助函数GLuint compileShader(GLenum type, constchar* source){ GLuint shader = glCreateShader(type);glShaderSource(shader, 1, &source, NULL);glCompileShader(shader);// 检查编译错误 GLint success;glGetShaderiv(shader, GL_COMPILE_STATUS, &success);if (!success) {char infoLog[512];glGetShaderInfoLog(shader, 512, NULL, infoLog); std::cout << "着色器编译错误: " << infoLog << std::endl; }return shader;}intmain(){// 初始化GLFWif (!glfwInit()) return-1;// 创建窗口 GLFWwindow* window = glfwCreateWindow(800, 600, "3D立方体Demo", NULL, NULL);if (!window) {glfwTerminate();return-1; }glfwMakeContextCurrent(window);// 初始化GLEWif (glewInit() != GLEW_OK) { std::cout << "GLEW初始化失败" << std::endl;return-1; }// 启用深度测试glEnable(GL_DEPTH_TEST);// 编译链接着色器 GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource); GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource); GLuint shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);// 清理着色器对象glDeleteShader(vertexShader);glDeleteShader(fragmentShader);// 创建顶点缓冲区和顶点数组对象 GLuint VBO, VAO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 位置属性glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);// 颜色属性glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(1);// 解绑glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);// 渲染循环while (!glfwWindowShouldClose(window)) {// 清除缓冲glClearColor(0.1f, 0.1f, 0.1f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 使用着色器程序glUseProgram(shaderProgram);// 创建变换矩阵float time = glfwGetTime();// 模型矩阵:旋转 glm::mat4 model = glm::mat4(1.0f); model = glm::rotate(model, time * glm::radians(50.0f), glm::vec3(0.5f, 1.0f, 0.0f));// 视图矩阵:摄像机位置 glm::mat4 view = glm::mat4(1.0f); view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));// 投影矩阵:透视投影 glm::mat4 projection = glm::perspective( glm::radians(45.0f), // 视野800.0f / 600.0f, // 宽高比0.1f, // 近平面100.0f// 远平面 );// 传递矩阵给着色器 GLint modelLoc = glGetUniformLocation(shaderProgram, "model"); GLint viewLoc = glGetUniformLocation(shaderProgram, "view"); GLint projLoc = glGetUniformLocation(shaderProgram, "projection");glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));// 绘制立方体glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 36);// 交换缓冲并检查事件glfwSwapBuffers(window);glfwPollEvents(); }// 清理资源glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteProgram(shaderProgram);glfwTerminate();return0;}向量运算是AI模型训练和推理的核心,原因如下:
这些要求与GPU的架构完美匹配,使得GPU成为AI计算的理想平台。
CUDA是NVIDIA开发的并行计算平台,它允许开发者利用GPU的并行计算能力来加速计算密集型任务。

以下是一个简单的向量点积公式CUDA实现:dot=∑i=0N−1A[i]∗B[i],是 AI 模型中最核心的运算之一 —— 注意力分数、卷积运算、全连接层,本质都是向量点积的组合。
#include<iostream>#include<vector>#include<cuda_runtime.h>// CUDA核函数:并行计算向量元素的乘积,存入临时数组__global__ voidvecDotKernel(constfloat* A, constfloat* B, float* temp, int N){int idx = blockIdx.x * blockDim.x + threadIdx.x;if (idx < N) { temp[idx] = A[idx] * B[idx]; // 并行计算逐元素乘积 }}// CPU主机端函数:调度GPU计算+最终求和floatvecDot(const std::vector<float>& h_A, const std::vector<float>& h_B, int N){int dataSize = N * sizeof(float);float *d_A, *d_B, *d_temp;std::vector<float> h_temp(N, 0.0f);float dotResult = 0.0f;// 分配显存+拷贝数据cudaMalloc((void**)&d_A, dataSize);cudaMalloc((void**)&d_B, dataSize);cudaMalloc((void**)&d_temp, dataSize);cudaMemcpy(d_A, h_A.data(), dataSize, cudaMemcpyHostToDevice);cudaMemcpy(d_B, h_B.data(), dataSize, cudaMemcpyHostToDevice);// 启动核函数int blockSize = 32;int gridSize = (N + blockSize - 1) / blockSize; vecDotKernel<<<gridSize, blockSize>>>(d_A, d_B, d_temp, N);// 拷贝乘积结果回CPU+求和cudaMemcpy(h_temp.data(), d_temp, dataSize, cudaMemcpyDeviceToHost);for (int i = 0; i < N; ++i) { dotResult += h_temp[i]; }// 释放显存cudaFree(d_A);cudaFree(d_B);cudaFree(d_temp);return dotResult;}// 主函数:测试向量点积intmain(){constint vecDim = 1024;std::vector<float> h_A(vecDim, 1.0f);std::vector<float> h_B(vecDim, 2.0f);float dot = vecDot(h_A, h_B, vecDim); std::cout << "向量点积的最终结果:" << dot << std::endl; // 预期:1024*2=2048return0;}这个CUDA程序展示了如何利用GPU的并行计算能力高效地执行向量运算: