PDA

View Full Version : how can I convert pixels from glReadPixels to texture



dongdongmaomao
09-10-2016, 05:58 AM
For example, a texture is rendered by two shaders (vs1, fs1). And I want to use other shaders (vs2, fs2) for further processing based on the first shaders' output. I have read a document for this in www.nxp.com/files/32bit/doc/app_note/AN4629.pdf. It is called shaders chain and FBO (frame buffer object) will be adopted in this article. However, no detail is reported in the article. In my code, the output of the first two shaders is correct, and I think the texture has been rendered in offscreen. The output pixels will be read with "glReadPixels" command, and convert them to a new texture followed by second shaders (vs2, fs2). The related part is emphasized in my code. However, the result is not correct. What is wrong?
#include <GL/glew.h>
#include <GLUT/GLUT.h>
//#include <GLES2/gl2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Dataset_shader {
GLuint program;
GLint locSampler;
GLint locVertices;
GLint locTexcoord;
GLint locTransformMat;
GLint locProjMat;
GLint locWidthStep;
GLint locHeightStep;
GLint locWidthHeightStep;
GLint locWidthNegativeHeightStep;
GLuint texture;
};
Dataset_shader program1;
Dataset_shader program2;


/* Storage For One Texture ( NEW ) */
struct FrameBufferObject {
GLuint m_hTexture;
GLuint m_hFrameBuffer;
GLuint m_hRenderBuffer;
int m_nWidth;
int m_nHeight;
};
FrameBufferObject g_pOffscreenFBO;

GLfloat vertices[][3] = {


/* Top Right Of The Quad (Top) */
//{ 1.0f, 1.0f, -1.0f},
/* Top Left Of The Quad (Top) */
//{-1.0f, 1.0f, -1.0f},
/* Bottom Right Of The Quad (Top) */
//{ 1.0f, 1.0f, 1.0f},
/* Bottom Left Of The Quad (Top) */
//{-1.0f, 1.0f, 1.0f},

/* Top Right Of The Quad (Bottom) */
{1.0f,-1.0f,1.0f},
/* Top Left Of The Quad (Bottom) */
{-1.0f, -1.0f,1.0f},
/* Bottom Right Of The Quad (Bottom) */
{1.0f,-1.0f,-1.0f},
/* Bottom Left Of The Quad (Bottom) */
{-1.0f,-1.0f,-1.0f},

/* Top Right Of The Quad (Front) */
{1.0f,1.0f,1.0f},
/* Top Left Of The Quad (Front) */
{-1.0f,1.0f,1.0f},
/* Bottom Right Of The Quad (Front) */
{1.0f,-1.0f,1.0f},
/* Bottom Left Of The Quad (Front) */
{-1.0f,-1.0f,1.0f},

/* Top Right Of The Quad (Back) */
{1.0f,-1.0f,-1.0f},
/* Top Left Of The Quad (Back) */
{-1.0f,-1.0f,-1.0f},
/* Bottom Right Of The Quad (Back) */
{1.0f, 1.0f, -1.0f},
/* Bottom Left Of The Quad (Back) */
{-1.0f,1.0f,-1.0f},

/* Top Right Of The Quad (Left) */
{-1.0f,1.0f,1.0f},
/* Top Left Of The Quad (Left) */
{-1.0f,1.0f, -1.0f},
/* Bottom Right Of The Quad (Left) */
{-1.0f,-1.0f,1.0f},
/* Bottom Left Of The Quad (Left) */
{-1.0f,-1.0f,-1.0f},

/* Top Right Of The Quad (Right) */
{1.0f,1.0f,-1.0f},
/* Top Left Of The Quad (Right) */
{1.0f,1.0f,1.0f},
/* Bottom Right Of The Quad (Right) */
{1.0f,-1.0f,-1.0f},
/* Bottom Left Of The Quad (Right) */
{1.0f,-1.0f,1.0f},
};

const GLfloat texcoords[][2] = {


/* Top Face */
{0.0f,0.0f},
{1.0f,0.0f},
{0.0f,1.0f},
{1.0f,1.0f},
/* Bottom Face */
{1.0f,1.0f},
{0.0f,1.0f},
{0.0f,0.0f},
{1.0f,0.0f},

/* Front Face */

{1.0f,1.0f},
{0.0f,1.0f},
{1.0f,0.0f},
{0.0f,0.0f},

/* Back Face */
{1.0f,0.0f},
{0.0f,0.0f},
{1.0f,1.0f},
{0.0f,1.0f},
/*left face*/
{1.0f,1.0f},
{0.0f,1.0f},
{1.0f,0.0f},
{0.0f,0.0f},

/* Right face */
{1.0f,0.0f},
{0.0f,0.0f},
{1.0f,1.0f},
{0.0f,1.0f},


};

// Start with an identity matrix.
GLfloat transformMatrix[16] =
{
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};

const int screen_w=1280,screen_h=720;
const int pixel_w = 1280, pixel_h = 720;
//YUV file
FILE *infile = NULL;
unsigned char buf[pixel_w*pixel_h*3/2];

void DestroyFBO(FrameBufferObject* pFBO) {
glDeleteTextures(1, &(pFBO->m_hTexture));
glDeleteFramebuffers(1, &(pFBO->m_hFrameBuffer));
glDeleteRenderbuffers(1, &(pFBO->m_hRenderBuffer));
delete pFBO;
}

void EndFBO(void)
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// glViewport(0, 0, pixel_w, pixel_h);
}

bool CreateFBO(FrameBufferObject* pFBO)
{
pFBO->m_nWidth = pixel_w;
pFBO->m_nHeight = pixel_h;
pFBO->m_hTexture = program1.texture;
glGenFramebuffers(1, &(pFBO->m_hFrameBuffer));
glBindFramebuffer(GL_FRAMEBUFFER, pFBO->m_hFrameBuffer);
glGenRenderbuffers(1, &(pFBO->m_hRenderBuffer));
glBindRenderbuffer(GL_RENDERBUFFER, pFBO->m_hRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, pFBO->m_nWidth, pFBO->m_nHeight);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pFBO->m_hTexture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, pFBO->m_hRenderBuffer);
if(GL_FRAMEBUFFER_COMPLETE != glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
return GL_FALSE;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
return GL_TRUE;
}

void parameter_config1(Dataset_shader* shaders) {
shaders->locVertices = glGetAttribLocation(shaders->program, "vPosition");
shaders->locTexcoord = glGetAttribLocation(shaders->program, "my_Texcoor");
// Transform Matrix is uniform for all vertices here.
shaders->locTransformMat = glGetUniformLocation(shaders->program, "u_TransMatrix");
shaders->locProjMat = glGetUniformLocation(shaders->program, "g_matProj");
shaders->locSampler = glGetUniformLocation(shaders->program, "my_Sampler");
shaders->locWidthStep = glGetUniformLocation(shaders->program, "widthStep");
shaders->locHeightStep = glGetUniformLocation(shaders->program, "heightStep");
shaders->locWidthHeightStep = glGetUniformLocation(shaders->program, "widthHeightStep");
shaders->locWidthNegativeHeightStep = glGetUniformLocation(shaders->program, "widthNegativeHeightStep");
// enable vertex arrays to push the data.
glEnableVertexAttribArray(shaders->locVertices);
glEnableVertexAttribArray(shaders->locTexcoord);
// set data in the arrays.
glVertexAttribPointer(shaders->locVertices, 3, GL_FLOAT, GL_FALSE, 0, &vertices[0][0]);
glVertexAttribPointer(shaders->locTexcoord, 2, GL_FLOAT, GL_FALSE, 0, &texcoords[0][0]);
glGenTextures(1, &(shaders->texture));
glBindTexture(GL_TEXTURE_2D, shaders->texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (CreateFBO(&g_pOffscreenFBO) != GL_TRUE) {
DestroyFBO(&g_pOffscreenFBO);
}
}

void parameter_config2(Dataset_shader* shaders) {
shaders->locVertices = glGetAttribLocation(shaders->program, "vPosition");
shaders->locTexcoord = glGetAttribLocation(shaders->program, "my_Texcoor");
// Transform Matrix is uniform for all vertices here.
shaders->locSampler = glGetUniformLocation(shaders->program, "my_Sampler");
// enable vertex arrays to push the data.
glEnableVertexAttribArray(shaders->locVertices);
glEnableVertexAttribArray(shaders->locTexcoord);
// set data in the arrays.
glVertexAttribPointer(shaders->locVertices, 3, GL_FLOAT, GL_FALSE, 0, &vertices[0][0]);
glVertexAttribPointer(shaders->locTexcoord, 2, GL_FLOAT, GL_FALSE, 0, &texcoords[0][0]);
glGenTextures(1, &(shaders->texture));
glBindTexture(GL_TEXTURE_2D, shaders->texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}

void parameter_set1(Dataset_shader shaders) {
GLfloat widthStep[2];
GLfloat heightStep[2];
GLfloat widthHeightStep[2];
GLfloat widthNegativeHeightStep[2];
widthStep[0]= (GLfloat) (1.0/pixel_w);
widthStep[1]= (GLfloat) (0.0);
heightStep[0]= (GLfloat) (0.0);
heightStep[1]= (GLfloat) (1.0/pixel_h);
widthHeightStep[0]= (GLfloat) (1.0/pixel_w);
widthHeightStep[1]= (GLfloat) (1.0/pixel_h);
widthNegativeHeightStep[0]= (GLfloat) (1.0/pixel_w);
widthNegativeHeightStep[1]= (GLfloat) (-1.0/pixel_h);
glUniformMatrix4fv(shaders.locTransformMat, 1, GL_FALSE, transformMatrix);
glUniformMatrix4fv(shaders.locProjMat, 1, GL_FALSE, transformMatrix);
glUniform2fv(shaders.locWidthStep, 1, &widthStep[0]);
glUniform2fv(shaders.locHeightStep, 1, &heightStep[0]);
glUniform2fv(shaders.locWidthHeightStep, 1, &widthHeightStep[0]);
glUniform2fv(shaders.locWidthNegativeHeightStep, 1, &widthNegativeHeightStep[0]);
glUniform1i(shaders.locSampler, 0);
glBindTexture(GL_TEXTURE_2D, shaders.texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, pixel_w, pixel_h, 0, GL_RED, GL_UNSIGNED_BYTE, buf);
}

void parameter_set2(Dataset_shader shaders) {
GLubyte *rawPositionPixels;
rawPositionPixels = (GLubyte*)malloc(pixel_w * pixel_h * 4 * sizeof(GLubyte));
glReadPixels(0, 0, pixel_w, pixel_h, GL_RGBA, GL_UNSIGNED_BYTE, rawPositionPixels);
glUniform1i(shaders.locSampler, 0);
glBindTexture(GL_TEXTURE_2D, shaders.texture);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, pixel_w, pixel_h, 0);
}

void display(void){
if (fread(buf, 1, pixel_w*pixel_h*3/2, infile) != pixel_w*pixel_h*3/2){
// Loop
fseek(infile, 0, SEEK_SET);
fread(buf, 1, pixel_w*pixel_h*3/2, infile);
}
//Clear
glBindRenderbuffer(GL_RENDERBUFFER, g_pOffscreenFBO.m_hRenderBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, g_pOffscreenFBO.m_hFrameBuffer);
glClearColor(1.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program1.program);
parameter_set1(program1);
// Draw
glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);

glClear(GL_COLOR_BUFFER_BIT);
parameter_set2(program2);
EndFBO();
glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
// Show
//Double
glutSwapBuffers();
//DestroyFBO(g_pOffscreenFBO);

//Single
//glFlush();
}

void timeFunc(int value){
display();
// Timer: 40ms
glutTimerFunc(40, timeFunc, 0);
}

char *textFileRead(char * filename)
{
char *s = (char *)malloc(8000);
memset(s, 0, 8000);
FILE *infile = fopen(filename, "rb");
int len = fread(s, 1, 8000, infile);
fclose(infile);
s[len] = 0;
return s;
}

//Init Shader
GLuint InitShaders(char *vertice_shader, char *frag_shader)
{
GLint vertCompiled, fragCompiled, linked;

GLint v, f;
const char *vs,*fs;
//Shader: step1
v = glCreateShader(GL_VERTEX_SHADER);
f = glCreateShader(GL_FRAGMENT_SHADER);
//Get source code
vs = textFileRead(vertice_shader);
fs = textFileRead(frag_shader);
//Shader: step2
glShaderSource(v, 1, &vs,NULL);
glShaderSource(f, 1, &fs,NULL);
//Shader: step3
glCompileShader(v);
//Debug
glGetShaderiv(v, GL_COMPILE_STATUS, &vertCompiled);
if (GL_FALSE == vertCompiled) {
GLint logLen;
//得到编译日志长度
glGetShaderiv(v,GL_INFO_LOG_LENGTH,&logLen);
if (logLen > 0) {
char *log = (char *)malloc(logLen);
GLsizei written;
//得到日志信息并输出
glGetShaderInfoLog(v,logLen,&written,log);
printf("vertex shader compile log : %s", log);
free(log);//释放空间
}
}
glCompileShader(f);
glGetShaderiv(f, GL_COMPILE_STATUS, &fragCompiled);
glGetShaderiv(f, GL_COMPILE_STATUS, &fragCompiled);
if (GL_FALSE == fragCompiled) {
GLint logLen;
//得到编译日志长度
glGetShaderiv(f,GL_INFO_LOG_LENGTH,&logLen);
if (logLen > 0) {
char *log = (char *)malloc(logLen);
GLsizei written;
//得到日志信息并输出
glGetShaderInfoLog(f,logLen,&written,log);
printf("frag shader compile log : %s", log);
free(log);//释放空间
}
}

//Program: Step1
GLuint p = glCreateProgram();
//Program: Step2
glAttachShader(p,v);
glAttachShader(p,f);

//Program: Step3
glLinkProgram(p);
//Debug
glGetProgramiv(p, GL_LINK_STATUS, &linked);
if (!linked)
{
printf("%d: Link failed.\n", __LINE__);
// Retrieve error buffer size.
GLint errorBufSize, errorLength;
glGetShaderiv(p, GL_INFO_LOG_LENGTH, &errorBufSize);

char * infoLog = (char*)malloc(errorBufSize * sizeof (char) + 1);
if (!infoLog)
{
// Retrieve error.
glGetProgramInfoLog(p, errorBufSize, &errorLength, infoLog);
infoLog[errorBufSize + 1] = '\0';
fprintf(stderr, "%s", infoLog);

free(infoLog);
}

exit(1);
}
//Program: Step4
//glUseProgram(p);
return p;
}



int main(int argc, char* argv[])
{
//Open YUV420P file
if((infile=fopen("rawvideo.yuv", "rb"))==NULL){
printf("cannot open this file\n");
return -1;
}

//Init GLUT
glutInit(&argc, argv);
//GLUT_DOUBLE
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA /*| GLUT_STENCIL | GLUT_DEPTH*/);
glutInitWindowPosition(100, 100);
glutInitWindowSize(screen_w, screen_h);
glutCreateWindow("Simplest Video Play OpenGL");
printf("Version: %s\n", glGetString(GL_VERSION));
GLenum l = glewInit();
if( GLEW_OK != l )
{
printf("Error initializing GLEW: %s",glewGetErrorString(l));
}
glutDisplayFunc(&display);
glutTimerFunc(40, timeFunc, 0);
program1.program = InitShaders("vs1.vert", "fs1.frag");
program2.program = InitShaders("vs2.vert", "fs2.frag");
parameter_config1(&program1);
parameter_config2(&program2);
// Begin!
glutMainLoop();

return 0;
}