alpha值计算 qcolor_高性能计算主要是研究什么的?

384d11826110f5259f330f63b29ff633.gif

478f11d3bc2610e0f5abaaf5b7ac9119.png

计算的概念

计算在数学上的概念: 计算是一种行为,通过已知量的可能的组合,获得新的量。计算的本质是集合之间的映射。

个人粗浅直白的理解是: 输入一个或多个数据,经过处理,输出一个或多个数据。如 1 + 2 就是一个计算,输入 2 个数据,输出 1 个数据 3

那到这里就会有很多疑问,在计算机上:

  • 高性能计算的概念是什么?

  • 全部的普通计算都能转成高性能计算实现么?如果不是的话,那哪些类型的计算可以呢?

  • 我们需要做哪些事情,来实现高性能计算?

  • Android框架或者是否存在第三方库为我们做了相关的工作

高性能计算的概念

高性能计算:通常使用很多处理器(作为单个机器的一部分)或者某一集群中组织的几台计算机(作为单个计算资源操作)的计算系统和环境。

在移动端,我们可以认为是通过同时启用移动设备的 CPUGPU 构成的异构计算资源,进行协同计算。

计算模型类型

从数据流和指令的角度把计算模型分为4类(费林分类法)

  1. 单指令单数据流 (SISD): 非并行计算的模型,典型例子就是单核 CPU,所有数据都被一个处理器顺次处理,某一时刻只能使用一个指令。

  2. 单指令多数据流 (SIMD): 指多个不同的数据同时被相同的执行、指令集或者算法处理,是 GPU 的计算模型。

  3. 多指令单数据流 (MISD): 在同一个数据流上执行不同的指令。

  4. 多指令多数据流 (MIMD): 是多核CPU的计算模型。

本文内容讨论的高性能计算则主要是在 SIMD 的基础上讨论,但这里并不需要严格按照 SIMD,只需要计算流程中的一部分内容符合 SIMD 我们就认为该实现过程就是一个高性能计算。

知道了计算模型的类型,我们就能知道并不是所有的计算类型都能实现为高性能计算。只有满足以下要求的算法(或者算法中的部分满足,其他部分通过CPU协调)才能够比较好的实现为高性能计算。

  1. 每个数据(数据包)都需要经过相同的流程来处理

  2. 数据之间并没有相干性,即某些数据的计算不依赖另外一些数据的计算结果

  3. 数据量庞大

8903111a542f13f0bfb32992a3851b5e.png

如何实现高性能计算

这里首先了解的是图形显示流程,常用的通用计算也正是基于这个显示流程做修改而实现的。这里以OpenGL ES为例,其他的如Direct3D、CG的流程大体也相同。

OpenGL ES 2.0可编程渲染管线:

f349434176ef4219c26e30b904df2811.png

其中的顶点着色器片元着色器的处理过程,程序猿可以自行编写,且是分别在 GPU 中的顶点处理器和片元处理器(或者统一处理器)计算。

知道了这个流程,我们可以很容易联想到:

  1. 我们的高性能计算的主要算法过程是在 顶点着色器片元着色器 中处理的,一般都是 片元着色器

  2. 这个流程是用于显示,输入是顶点和纹理等数据,输出是帧缓冲,很明显并不是我们所需要的,因此我们还需要修改流程。

修改后的计算流程图:

ab14a63e65b8a77fa677b4a4abedb46e.png

其中 {{ }} 显示的部分并不是我们关心的内容,我们的程序会经过这几步骤,但逻辑上一般并不用生效。

31aa997ea8ab83f835886eec67dcb8b1.png

这里的处理过程还是很模糊,对比一下上面的常规计算 (普通计算左,高性能计算右):

  1. 输入 int 数组 → 输入纹理数据

  2. for 循环语句 → 片段着色器

  3. 返回int数组 → 渲染到纹理(具体对应帧缓存对象 FBO),并读取

  4. 调用 → 绘制矩形

  5. 数组处理范围 → 坐标

为了保证我们输出到纹理的数据是完整正确的,另外需要注意的是:

  1. 绘制的矩形应该与投影平面平行,即正对摄像机

  2. 使用正交投影

  3. 矩形和纹理等大

  4. 视口和纹理图等大

    6de7fa730b517e5975860864b01f46a7.png

性能提升效果

前面介绍了这么多,但终究只是理论介绍,我们并没有看到使用高性能计算究竟提升了多少。

写一个非常简单的图像处理的算法 (因为使用图像暂时效果比较明显,表达也比较容易,所以这里使用的是图像显示的 Demo,并不是说高性能计算只能用于显示相关)

算法基本流程是:

  • 读入一张图片

  • 光顺处理下,即将每个像素点和周围的8个像素点的颜色做一个平均,并将均值赋值给中间像素点

  • 将各个像素点置灰,即将每个像素点的rgb值求和并取平均值

  • 调整亮度,即将每个像素点的颜色的各通道值乘以0.9

  • 将像素数组取出设置给bitmap,并设置给ImageView

常规计算 ( java 代码) 实现

public class ImageGrayUtil {
// 给出最终求和时的加权因子(为调整亮度)
public static final float scaleFactor = 0.9f;
public static Bitmap apply(Context context, Bitmap sentBitmap) {
Bitmap bitmap = sentBitmap.copy(Bitmap.Config.ARGB_8888, true);
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int[] pix = new int[w * h];
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
// 卷积内核中各个位置的值
float kernalValue = 1.0f/9.0f;
float k00 = kernalValue;
float k10 = kernalValue;
float k20 = kernalValue;
float k01 = kernalValue;
float k11 = kernalValue;
float k21 = kernalValue;
float k02 = kernalValue;
float k12 = kernalValue;
float k22 = kernalValue;
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
// 获取卷积内核中各个元素对应像素的颜色值
int[] p00 = mutiply(getARGB(pix, w, h, i - 1, j - 1), k00);
int[] p10 = mutiply(getARGB(pix, w, h, i, j - 1), k10);
int[] p20 = mutiply(getARGB(pix, w, h, i + 1, j - 1), k20);
int[] p01 = mutiply(getARGB(pix, w, h, i - 1, j), k01);
int[] p11 = mutiply(getARGB(pix, w, h, i, j), k11);
int[] p21 = mutiply(getARGB(pix, w, h, i + 1, j), k21);
int[] p02 = mutiply(getARGB(pix, w, h, i - 1, j + 1), k02);
int[] p12 = mutiply(getARGB(pix, w, h, i, j + 1), k12);
int[] p22 = mutiply(getARGB(pix, w, h, i + 1, j + 1), k22);
int[] pixARGB = add(p00, p10, p20, p01, p11, p21, p02, p12, p22);
setColor(pix, w, h, i, j, uniform(toGray(pixARGB)));
}
}
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
return bitmap;
}
// 获取颜色各通道值
private static int[] argbFromColor(@ColorInt int color) {
int[] argb = new int[4];
argb[0] = Color.alpha(color);
argb[1] = Color.red(color);
argb[2] = Color.green(color);
argb[3] = Color.blue(color);
return argb;
}
private static int getColor(int[] pix, int w, int h, int x, int y) {
if (x < 0 || x > w - 1) return 0;
if (y < 0 || y > h - 1) return 0;
return pix[y * w + x];
}
private static int[] setColor(int[] pix, int w, int h, int x, int y, int[] argb) {
if (x < 0 || x > w - 1) return pix;
if (y < 0 || y > h - 1) return pix;
pix[y * w + x] = Color.argb(argb[0], argb[1], argb[2], argb[3]);
return pix;
}
// 获取颜色置灰,排除alpha通道
private static int[] toGray(int[] argb) {
int v = 0;
for (int i=1; i v += argb[i];
}
v /= 3;
return new int[]{v, v, v, v};
}
// 获取颜色各通道值
private static int[] getARGB(int[] pix, int w, int h, int x, int y) {
int color = getColor(pix, w, h, x, y);
return argbFromColor(color);
}
// 将数组的各元素和factor相乘
private static int[] mutiply(int[] argb, float factor) {
for (int i = 0; i < argb.length; i++) {
argb[i] = (int) (argb[i] * factor);
}
return argb;
}
// 将数组相加
private static int[] add(int[]... argbs) {
int[] result = new int[4];
for (int i = 0; i < argbs.length; i++) {
for (int j = 0; j < 4; j++) {
result[j] += argbs[i][j];
}
}
return result;
}
// 将颜色各通道值限制在0-255之间
private static int[] uniform(int[] argb) {
argb[0] = 255;
for (int i = 0; i < argb.length; i++) {
if (argb[i] < 0) argb[i] = 0;
if (argb[i] > 255) argb[i] = 255;
argb[i] *= scaleFactor;
}
return argb;
}
}

在系统 5.1.1 的 Nexus 5 手机,对 142KB 的正方形 png 图片做处理,实现结果如下:

55b92b55f625a05bcfafbe441d8baad8.png

说明:

上面的图片是输入图片,下面的图片是输出图片,显示的处理时间是 4234.676ms

高性能计算实现

片元处理器代码 gray_blur_f.glsl (用于处理数据) 如下:

precision mediump float;//给出默认的浮点精度
varying vec2 vTexCoord;//从顶点着色器传递过来的纹理坐标
uniform sampler2D sTexture;//纹理内容数据
uniform vec2 uPxD; // pixel delta values

void main() {

   // 给出卷积内核中各个元素对应像素相对于待处理像素的纹理坐标偏移量    vec2 offset0=vec2(-1.0,-1.0); vec2 offset1=vec2(0.0,-1.0); vec2 offset2=vec2(1.0,-1.0);

   vec2 offset3=vec2(-1.0,0.0); vec2 offset4=vec2(0.0,0.0); vec2 offset5=vec2(1.0,0.0);

   vec2 offset6=vec2(-1.0,1.0); vec2 offset7=vec2(0.0,1.0); vec2 offset8=vec2(1.0,1.0);


// 给出最终求和时的加权因子(为调整亮度)
const float scaleFactor = 0.9;

   //卷积内核中各个位置的值

    float kernelValue = 1.0/9.0;

  float kernelValue0 = kernelValue; float kernelValue1 = kernelValue; float kernelValue2 = kernelValue;

  float kernelValue3 = kernelValue; float kernelValue4 = kernelValue; float kernelValue5 = kernelValue;

  float kernelValue6 = kernelValue; float kernelValue7 = kernelValue; float kernelValue8 = kernelValue;


// 获取卷积内核中各个元素对应像素的颜色值
vec4 p00 = texture2D(sTexture, vTexCoord + offset0.xy * uPxD.xy) * kernelValue0;
vec4 p10 = texture2D(sTexture, vTexCoord + offset1.xy * uPxD.xy) * kernelValue1;
vec4 p20 = texture2D(sTexture, vTexCoord + offset2.xy * uPxD.xy) * kernelValue2;
vec4 p01 = texture2D(sTexture, vTexCoord + offset3.xy * uPxD.xy) * kernelValue3;
vec4 p11 = texture2D(sTexture, vTexCoord + offset4.xy * uPxD.xy) * kernelValue4;
vec4 p21 = texture2D(sTexture, vTexCoord + offset5.xy * uPxD.xy) * kernelValue5;
vec4 p02 = texture2D(sTexture, vTexCoord + offset6.xy * uPxD.xy) * kernelValue6;
vec4 p12 = texture2D(sTexture, vTexCoord + offset7.xy * uPxD.xy) * kernelValue7;
vec4 p22 = texture2D(sTexture, vTexCoord + offset8.xy * uPxD.xy) * kernelValue8;
//颜色求和
vec4 clr = p00 + p01 + p02 +
p10 + p11 + p12 +
p20 + p21 + p22;
// 灰度化
float hd = (clr.r + clr.g + clr.b) / 3.0;
//进行亮度加权后将最终颜色传递给管线
gl_FragColor = vec4(hd) * scaleFactor;
}

java 代码 (用于读取数据并生成 bitmap) 如下:

public Bitmap saveFrameBufferToBitmap(int w, int h) {
resultBm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
IntBuffer ib = ByteBuffer.allocateDirect((int) (w * h * 4))
.order(ByteOrder.nativeOrder()).asIntBuffer();
// IntBuffer ibt = ByteBuffer.allocateDirect((int) (w * h * 4))
// .order(ByteOrder.nativeOrder()).asIntBuffer();
ib.rewind();
// ibt.rewind();
// 强制刷新数据至纹理缓冲区
GLES20.glFinish();
// 从纹理缓冲区读取数据
GLES20.glReadPixels(0, 0, w, h, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ib);
// 数据上下翻转
// 删除使用java代码上下翻转图片,而是在前面设置纹理坐标的时候,修改转向,实现上下翻转
// 可以节省大量的时间
// for (int i = 0; i < h; i++) {
// for (int j = 0; j < w; j++) {
// ibt.put((h - i - 1) * w + j, ib.get(i * w + j));
// }
// }
resultBm.copyPixelsFromBuffer(ib);
return resultBm
}

在系统 5.1.1 的 Nexus 5 手机,对 142KB 的方形 png 图片做处理,实现结果如下:

6134dc7c45d38275ce63b8dacb6205c3.png

说明:

上面的图片是输入图片,下面的图片是输出图片,显示的处理时间是257.13364ms

这里的时间并不仅仅包含片元处理器的代码执行时间,也已经包括从纹理缓存对象中读取数据并生成Bitmap的时间,读取数据的时间也会占用比较多的时间

054c15c03c0b19d75cb89d5ed02e0a50.gif

海普森(Hipeson)——专注计算&助力科研

面向各大高校、科研院所、企事业单位,提供高性能计算产品解决方案

2d3b6e9532d5e6a5d868e29fc92eabd2.png647f8379be895acc8cecc663de565e99.png

a7d26b3cee35d00f73dccc837941506b.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值