目的
opengl虽然老,但是算上opengl es,应该是应用最广泛的显卡api。用compute shader做计算,可以一定程度上摆脱N卡的限制,也摆脱windows和linux,mac等平台的限制。
计算着色器应该没有完全榨干硬件的性能,但是也取得了可观的并行性。
compute shader的并发模型
compute shader把并发任务拆成了一个三维的工作组,即一个并发任务可以有三个维度,我理解是为了方便索引。然后每个工作组下可以定义多个工作项,也有三个维度。工作组和工作项的区别在于,一个工作组的不同工作项可以共享变量,用share关键字即可,他们之间可以相互协同,类似于线程,可以完成比较复杂的工作。而工作组之间类似于进程,不方便共享,更独立。
一个shader只实现一个工作项的逻辑,工作项数目由shader指定,似乎不能动态设置,而工作项数目由api指定,可以动态设置。
计算着色器中的内置变量来进行索引:
假设一个任务有 (10,5,3)个工作组,每个工作组有(2,3,4)个工作项
- gl_WorkGroupSize:全局工作组数量。三维数组(10,5,3)
- gl_NumGroupSize: 每个工作组的工作项数,三维数组,即(2,3,4)
- gl_WorkGroupID:当前工作组的全局ID。三维数组 ,范围是([0-9],[0-4],[0-2])
- gl_LocalInvocationID:当前工作项的局部ID。三维数组,范围是([0-1],[0-2],[0-3])
- gl_GlobalInvocationID:当前工作项的全局ID。三维数组,相当于gl_WorkGroupID和gl_LocalInvocationID拉平的id:
- 比如第(5,2,1)工作组的第(1,2,1)个工作项的gl_GlobalInvocationID = (52+1, 23+2, 1*4+1) = (11,8,5)
- gl_LocalInvocationIndex:当前工作项的线性索引。一个数,相当于拉成一维来进行唯一索引,即上一项进一步拉平
性能测试
比较cpu单核性能和集成显卡,我的pc参数如下:
windows11 专业版
cpu 13th Gen Intel® Core™ i5-1340P 1.90 GHz
显卡 Intel® Iris® Xe Graphics
测试 10002000的矩阵和20001000的矩阵相乘,这个显卡很垃圾
代码
#include <iostream>
#include <string>
#include <vector>
#include <random>
#include <chrono>
#include "glad/glad.h"
#include "GLFW/glfw3.h"
#include "img_util.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
std::string loadShaderSource(const std::string& shaderPath) {
FILE* file = fopen(shaderPath.c_str(), "r");
std::vector<char> res;
if (file == NULL) {
std::cout << "open shader file error:" << shaderPath << std::endl;
return "";
}
// 计算大小
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
if (fileSize > 0) {
res.resize(fileSize);
long readSize = fread(res.data(), sizeof(char), fileSize, file);
if (readSize > fileSize) {
std::cout << "read shader file error:" << shaderPath
<< "fileSize: " << fileSize << ",readSize: " << readSize
<< " ,content: " << std::string(res.begin()