GLSL层卷积(先清理)

测试了《GPU编程之GLSL(五)——二维离散卷积》一文的程序,发现先运行哪个“clean.frag”,程序总运行时间更短,就以该文为模板来运行层卷积。

先把《glsl着色器实现多重纹理与帧缓冲对象(fbo)》一文的着色器出错提示部分复制过来(不然,将不能调试着色器)。


接口和前面相同,为了区别加一个G:

void conv_initG(int argc, char* argv[],int h,int w)
//核数据,核宽,输入维度,输出维度,偏置数据,输入数据,输出数据,是否激活
//核大小:kw * kw * 输入维度 * 输出维度。
//输入数据大小:wh * 输入维度。 输出数据大小:wh * 输出维度。
//加法结果在fbo中,中间不用读出,relu也在GLSL中完成
void conv_GLSL_层_add7G(float* kernel,int kw,int inNum,int outNum,float *bias,float *inData, float * &outData,bool active=true)


可以用前面的单个3x3卷积测试下:

	conv_initG(argc, argv,  h, w);
	conv_GLSL_层_add7G(kernel,kw,1,1,NULL,inData, outData, false);

或1x1:

	conv_initG(argc, argv,  h, w);
	conv_GLSL_层_add7G(kernel,1,1,1,NULL,inData, outData, false);


层卷积着色器和前面相同,全cpp:

//GPU编程之GLSL(五)——二维离散卷积

//本程序共分为7个文件:
//
//1个主程序文件,2个CTimer文件,2个CReader文件,2个着色器文件
//
// 
//
//两个CReader文件和2个着色器文件分别在前边的(二)和(四)中给出,这里就不详细解释了
//
// 
//
//首先我们来讲一下比较简单的文件——CTimer文件:
//
//主要是为了获取时间,以便比较程序性能

//接下来是主程序文件:
//
//共分为6大部分:初始化,准备纹理缓存,配置GLSL,绘制矩形,计时,读回结果
//
//1、初始化:包含对glut、GLEW、FBO的初始化
//
//2、准备纹理缓存:定义两块纹理,一块保存输入一块保存输出,简单生成数据传入输入数据的纹理缓存中
//
//3、配置GLSL:建立一个程序对象,一个着色器对象,贾周着色器程序文件,编译着色器对象以及添加、链接、启用程序对象,设置uniform变量
//
//4、绘制矩形:输出缓存yTexID与FBO关联(计算的结果需要写入保存输出数据的纹理缓存),激活已经保存有输入数据的纹理单元,设置显然对象,使矩形中的每一个像素都会被覆盖到,保证矩形与纹理图同一尺寸
//
//5、计时:glFinish()可以起到线程同步的作用,该函数是控制进入等待状态,直到所有调用的OpenGL命令都执行完成,它才返回。在计时器开始和结束的时候都要调用该函数以保证线程同步
//
//6、读回结果:将结果传回pfOutput缓存,最后完成清理工作
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <gl/glew.h>
#include <gl/glut.h>
#include "CReader.h"
#include "CTimer.h"
#pragma comment(lib, "glew32.lib")
 

 
using namespace std;
 
void initGLSL(void);
void initFBO(unsigned unWidth,unsigned unHeight);
void initGLUT(int argc,char** argv);
void createTextures(void);
void setupTexture(const GLuint texID);
void performComputation(void);
void transferFromTexture(float* data);
void transferToTexture(float* data,GLuint texID);
 
//纹理标识符
GLuint yTexID;
GLuint xTexID;
static GLuint textureN[64];    //多通道数据成为多纹理
static GLuint texture;    //结果加回纹理

 
//GLSL 变量                                          配置GLSL(一)
GLuint glslProgram;
GLuint fragmentShader;
GLuint outParam,inParam,radiusParam;
GLuint kernelParam;
 
//FBO标识符
GLuint fb;
 
//“屏幕外窗口”的标识符,创建一个有效的OpenGL环境
GLuint glutWindowHandle;
 
//为OpenGL纹理准备的结构体,包含了纹理格式、内部格式等
struct structTextureParameters{
	GLenum texTarget;              //纹理类型
	GLenum texInternalFormat;      //内部格式
	GLenum texFormat;              //纹理格式
	char* shader_source;           //着色器源文件
}textureParameters;
 
//全局变量
float* pfInput;                     //输入数据

unsigned unWidth ;//= (unsigned)WIDTH;
unsigned unHeight;// = (unsigned)HEIGHT;
unsigned unSize;// = unWidth * unHeight;
 
void printShaderInfoLog(GLuint obj)
{
    int infologLength = 0;
    int charsWritten  = 0;
    char *infoLog;

 glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);

    if (infologLength > 0)
    {
        infoLog = (char *)malloc(infologLength);
        glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
  printf("%s\n",infoLog);
        free(infoLog);
    }
}

#define printOpenGLError() printOglError(__FILE__, __LINE__)

//输出错误相关信息
int printOglError(char *file, int line)
{
	GLenum glErr;
	int retCode = 0;
 
	glErr = glGetError();
	while (glErr != GL_NO_ERROR)
	{
		printf("glError in file %s @ line %d: %s\n", file, line, gluErrorString(glErr));
		retCode = 1;
		glErr = glGetError();
	}
	return retCode;
}


//输出opengl错误
void printInfoLog(GLhandleARB obj)
{
	int infologLength = 0;
	int charsWritten = 0;
	GLcharARB *infoLog;
	printOpenGLError();
 
	glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &infologLength);
	printOpenGLError();
 
	if(infologLength > 0)
	{
		infoLog = (GLcharARB*)malloc(infologLength);
		if(infoLog == NULL)
		{
			printf("ERROR: Could not allocate InfoLog buffer\n");
			exit(1);
		}
		glGetInfoLogARB(obj,infologLength,&charsWritten,infoLog);
		printf("InfoLog:\n%s\n\n",infoLog);
		free(infoLog);
	}
	printOpenGLError();
}


 
//初始化GLUT,创建的窗口是为有一个有效的OpenGL环境
void initGLUT(int argc,char **argv)
{
	glutInit(&argc,argv);
	glutWindowHandle = glutCreateWindow("GPGPU Tutorial");
}
 
//屏幕外渲染
void initFBO(unsigned unWidth,unsigned unHeight)
{
	//创建FBO,准备屏幕外帧缓存
	glGenFramebuffersEXT(1,&fb);
 
	//绑定屏幕外帧缓存,即避开了窗口系统默认的渲染目标
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
 
	//设置一个1:1等大的纹理元——像素映射
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0.0,unWidth,0.0,unHeight);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glViewport(0,0,unWidth,unHeight);
}
 
//初始化GLSL运行时组件,并创建着色器                     配置GLSL(三)
void initGLSL(void)                                     
{
	//建立程序对象
	glslProgram = glCreateProgram();
 
	//建立片段着色器对象
	fragmentShader = glCreateShader(GL_FRAGMENT_SHADER_ARB);
 
	//为着色器设置着色器程序文件
	const GLchar* source = textureParameters.shader_source;
	glShaderSource(fragmentShader, 1, &source, NULL);
 
	//编译着色器                              
	glCompileShader(fragmentShader);
	{
		GLint vertfragCompiled;
		glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &vertfragCompiled);
		 

		if (!vertfragCompiled )
		{
	 
			printf("编译出错了!!\n");
			printShaderInfoLog(fragmentShader);
		}
	}

 
	//把着色器与程序关联
	glAttachShader(glslProgram,fragmentShader);
 
	//链接到完整的程序,这里使用了默认功能的顶点着色器,用户也可以使用自定义的流经顶点着色器
	glLinkProgram(glslProgram);

	{
	GLint linked;
	//检查opengl错误
	glGetObjectParameterivARB(glslProgram, GL_OBJECT_LINK_STATUS_ARB, &linked);
 
	if(!linked)
	{
		printf("链接出错了!!\n");
		printInfoLog(glslProgram);
	}
	}
 
}
 
void createTextures(void){
	//创建纹理,y保存输出数据,x保存输入数据
	glGenTextures(1, &yTexID);
	glGenTextures(1, &xTexID);
 
	//配置纹理
	setupTexture (yTexID);
	setupTexture (xTexID);
	transferToTexture(pfInput, xTexID);
 
	//设定映射参数  将纹理映射参数GL_MODULATE更改为GL_REPLACE
	//GL_MODULATE代表:把纹理元素的颜色乘以几何图元(进行光照计算之后)的颜色。
	//GL_REPLACE 代表:简单地覆盖掉纹理下面的结合图形的颜色。这样片段的颜色值将直接采用纹理的颜色。
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_REPLACE);
}
 
void setupTexture(const GLuint texID)
{
	//激活并绑定将要设置的纹理
	glBindTexture(textureParameters.texTarget,texID);
 
	//关闭滤波算法和边界以外的重复算法
	//使用GL_NEAREST的原因:将差值得到的纹理坐标和像素对齐,避免了因差值误差引起的误访问
	//使用GL_CLAMP  的原因:矩阵的边界元素在绘制的矩形尺寸大于纹理图时的处理方式
	                       //降低错误的发生并尽可能为发现错误提供方便
 
	glTexParameteri(textureParameters.texTarget,GL_TEXTURE_MIN_FILTER,GL_NEAREST);                   
	glTexParameteri(textureParameters.texTarget,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
	glTexParameteri(textureParameters.texTarget,GL_TEXTURE_WRAP_S,GL_CLAMP);
	glTexParameteri(textureParameters.texTarget,GL_TEXTURE_WRAP_T,GL_CLAMP);
 
	//定义纹理的数据类型为float
	glTexImage2D(textureParameters.texTarget,0,textureParameters.texInternalFormat,
		         unWidth,unHeight,0,textureParameters.texFormat,GL_FLOAT,0);
 
}
 
void performComputation(void)
{
	//关联输出缓存yTexID与FBO
	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,
		                      textureParameters.texTarget,yTexID,0);
 
	//将glslProgram设为当前程序对象
	glUseProgram(glslProgram);
 
	//将GL_TEXTURE0设为当前纹理单元
	glActiveTexture(GL_TEXTURE0);
 
	
 
	//同步线程,以便计时
	glFinish();
 
	//计时开始
	CTimer timer;
	long lTime = 0;
	timer.reset();
 
	//将设置写入纹理缓存的类型
	glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
 
	//将计算范围定义为同样包括矩形的内部
	glPolygonMode(GL_FRONT,GL_FILL);
 
	//用未归一化的纹理坐标设定计算范围
	glBegin(GL_QUADS);
	glTexCoord2f(0.0,0.0);
	glVertex2f(0.0,0.0);
	glTexCoord2f(unWidth,0.0);
	glVertex2f(unWidth,0.0);
	glTexCoord2f(unWidth,unHeight);
	glVertex2f(unWidth,unHeight);
	glTexCoord2f(0.0,unHeight);
	glVertex2f(0.0,unHeight);
	glEnd();
 
	//同步线程,终止计时
	glFinish();
	lTime = timer.getTime();
	cout<<"经过时间: "<<lTime<<" ms."<<endl;

	    

}
 
void performComputationG(void)
{
	
 
 
	//将设置写入纹理缓存的类型
	glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
 
	//将计算范围定义为同样包括矩形的内部
	glPolygonMode(GL_FRONT,GL_FILL);
 
	//用未归一化的纹理坐标设定计算范围
	glBegin(GL_QUADS);
	glTexCoord2f(0.0,0.0);
	glVertex2f(0.0,0.0);
	glTexCoord2f(unWidth,0.0);
	glVertex2f(unWidth,0.0);
	glTexCoord2f(unWidth,unHeight);
	glVertex2f(unWidth,unHeight);
	glTexCoord2f(0.0,unHeight);
	glVertex2f(0.0,unHeight);
	glEnd();
 

	    

}
 
//将数据从当前的纹理缓存传至主存储器
void transferFromTexture(float* data)
{
	glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
	glReadPixels(0,0,unWidth,unHeight,textureParameters.texFormat,GL_FLOAT,data);
}
 
//将数据传送至纹理缓存,请注意在使用硬件加速时,ATI和NVIDIA显卡的区别
void transferToTexture(float* data, GLuint texID)
{
	glBindTexture(textureParameters.texTarget,texID);
	glTexSubImage2D(textureParameters.texTarget,0,0,0,unWidth,unHeight,
		            textureParameters.texFormat,GL_FLOAT,data);
	
}

float * _0Data;
float* pfOutput;
void conv_initG(int argc, char* argv[],int h,int w)
{
	printf("\n为 GLSL 运行作准备...\n");
	unWidth =w;
	unHeight=h;
	unSize = unWidth * unHeight;//数据总数
		
	float * _0Data= new float[unWidth * unHeight];
	memset(_0Data, 0,unWidth * unHeight*sizeof(float));//清零

	pfInput=_0Data;

	pfOutput = new float[unSize];


	//确定纹理参数
	textureParameters.texTarget         = GL_TEXTURE_RECTANGLE_ARB;
	textureParameters.texInternalFormat = GL_R32F;
	textureParameters.texFormat         = GL_RED;


	//初始化GLUT和GLEW
	initGLUT(argc,argv);
	glewInit();
 
	//初始化FBO
	initFBO(unWidth, unHeight);
 
	//为输入、输出数据创建纹理缓存
	createTextures();
 
	//初始化CReader
	CReader reader;
	//安全起见,先清除输入纹理缓存                配置GLSL(二)
	textureParameters.shader_source = reader.textFileRead("clean.frag");
	initGLSL();
	performComputation();//计时
 
		
	//计算二维离散卷积
	textureParameters.shader_source = reader.textFileRead("convolution.h");
	//textureParameters.shader_source = reader.textFileRead("convolution - 1.h");

	initGLSL();
		
	//关联输出缓存yTexID与FBO
	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,
		                      textureParameters.texTarget,yTexID,0);
 
	//将glslProgram设为当前程序对象
	glUseProgram(glslProgram);
 


}

void LoadinToTextures(float *pTexData,int num)
{
	glGenTextures( num, textureN );
	for(int i=0;i<num;++i)
	{
		setupTexture(textureN[i]);
		transferToTexture(pTexData+i* unHeight * unWidth,textureN[i]);
	}

	
}

//加法纹理
void initaddG()
{

	if(texture == 0)
	{
		//设置输出纹理的参数
		glGenTextures( 1, &texture );
		setupTexture(  texture );
		transferToTexture( _0Data, texture );
 
	}
	else
	{
		transferToTexture( _0Data, texture );
	}

}

#include <time.h>
void relu(float *res,int len);


//核数据,核宽,输入维度,输出维度,偏置数据,输入数据,输出数据,是否激活
//核大小:kw * kw * 输入维度 * 输出维度。
//输入数据大小:wh * 输入维度。 输出数据大小:wh * 输出维度。
//加法结果在fbo中,中间不用读出,relu也在GLSL中完成
void conv_GLSL_层_add7G(float* kernel,int kw,int inNum,int outNum,float *bias,float *inData, float * &outData,bool active=true)
{
//可以不是7个
#define CONV_NUM 7

	//7个纹理用于卷积,1个纹理用于加法

	//printf("核宽:%d,输入维度:%d,输出维度:%d\n",kw,inNum,outNum);
	//加载全部输入通道到多纹理
	LoadinToTextures(inData,inNum);

	initaddG();

	//最大 7个9x9 核
	//float kernel648[648]={0.0f};

	clock_t start_t, end_t;//计算时间
	double total_t;
 
	start_t = clock();


	int wh=unHeight * unWidth;
	outData=new float[wh*outNum];
	memset(outData, 0, wh*outNum*sizeof(float));//清零



	float *out=outData;

	float *in=inData;
	float * kernel_s=kernel;//当前核


	for(int k=0;k<outNum;++k)
	{
		//一次实现7个卷积
		int kNum=(inNum<CONV_NUM)?inNum:CONV_NUM;
		for(int i=0;i<inNum;i+=CONV_NUM)
		{
				
			//最多7核
			if((kNum==CONV_NUM) && (i+CONV_NUM>inNum))//余数
				kNum= inNum % CONV_NUM;

				
		 
			if ( glslProgram <= 0 )
				printf("Failed to run shader.\n");
			else{
				char txt[255];
				//传送纹理 Texture0--- Texture7
				for(int j=0;j<kNum;++j)
				{
					sprintf_s(txt,255,"Texture%d\0",j);
					glActiveTexture( GL_TEXTURE0 +j);
					glBindTexture(textureParameters.texTarget,textureN[i+j]);
					glUniform1i( glGetUniformLocation( glslProgram, txt ),  j);  
					//printf("%s.\n",txt);
				}
					
				//激活 纹理
				sprintf_s(txt,255,"Texture%d\0",kNum);
				glActiveTexture( GL_TEXTURE0 +kNum);
				glBindTexture(textureParameters.texTarget,texture);
				glUniform1i( glGetUniformLocation( glslProgram, txt ),  kNum);  
				//printf("%s.\n",txt);

				glUniform1i( glGetUniformLocation( glslProgram, "kw" ), kw );   //核宽
				glUniform1i( glGetUniformLocation( glslProgram, "kNum" ), kNum );   //核1--8个

				glUniform1fv( glGetUniformLocation( glslProgram, "kernel"),kw*kw*kNum,kernel_s);//核数据
				kernel_s+=kw*kw*kNum;
				//加偏置
				if(i+CONV_NUM>=inNum && bias!=NULL)
				{
					glUniform1f( glGetUniformLocation( glslProgram, "bias"),bias[k]);//偏置数据
					if(active)
						glUniform1i( glGetUniformLocation( glslProgram, "active"),1);//激活
					else
						glUniform1i( glGetUniformLocation( glslProgram, "active"),0);//激活
				}
				else
				{
					glUniform1f( glGetUniformLocation( glslProgram, "bias"),0.0f);//无偏置 
					glUniform1i( glGetUniformLocation( glslProgram, "active"),0);//激活
				}
			}
		 
			performComputationG();
		 



			//取出数据
			if(i+kNum==inNum)
			{
				//p++;
				transferFromTexture( pfOutput );
				memcpy(out,pfOutput,wh*sizeof(float));
				//清0
				glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texture );
				glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_R32F, unWidth, unHeight, 0,GL_RED,GL_FLOAT,_0Data ); 
			}
			else
			{
				//结果转到 texture 中
				glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texture );
	            glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, 0, 0, unWidth, unHeight);   

			}

			end_t = clock();
	   
		   total_t = (double)(end_t - start_t) / CLOCKS_PER_SEC;
		   if(total_t>1.0){
				printf("%d/%d\n",k,outNum);
				start_t = clock();
		   }
		}
		out+=wh;
	}

	//清理
	for(int i=0;i<64;++i)
	{
		if(	textureN[i] !=0)
		{
			//删除纹理
			glDeleteTextures(1,textureN+i);
			textureN[i]=0;
		}
	}
		

}



结束。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值