Hi,
so after a long weekend of tests, i just got a nice solution to make GPU shader tasks and upload the results.
Thanking this thread to inspire me ideas, the trick was to “codify” a 640x480 gray image into a 320x240 RGBA one.
In the GPU the process is going into 640x480 RGBA textures, but to upload the result into the CPU, i apply a shader that makes in the first quarter of the image all the info for the resulting gray image.
Then, i decodify that image in a simple loop.
Here are the shaders, functions and example:
void rgba_to_gray(unsigned char *src_rgba, unsigned char *dest){
// converts from a codified RGBA image that contains a w*2,h*2
// gray image, to that original GRAY image (w*2,h*2)
// used with the shader gray2RGBA.frag .
// dest and src_rgba are size w*h*4, where w and h are the sizes of the rgba image,
// i.e, half the sizes of the GRAY image.
int w = width;
int h = height;
int w2 = w/2;
int h2 = h/2;
unsigned char r,g,b,a;
int k,x,y;
for (int i=0; i<w2*h2; i++) {
k=4*i;
x = i % w2;
y = i / w2;
r = src_rgba[k];
g = src_rgba[k+1];
b = src_rgba[k+2];
a = src_rgba[k+3];
// decodify the image::
dest[x+w*y] = r; // dest[x,y] = r;
dest[x+w*y + w2 ] = g; // dest[x+w2,y] = g;
dest[x+w*y + w*h2 ] = b;//dest[i+ w*h] = b; // dest[x,y+h2] = b;
dest[x+w*y + w2 + w*h2 ] = a; //dest[i+ w + w*h] = a; // dest[x+w2,y+h2] = a;
}
}
The shader ::
/*
// transform a RGBA image into a w/2, h/2 GRAY image
// the rule will be:
// R channel is for the pixels x [0,w/2] y [0,h/2].
// G channel is for the pixels x [w/2,w] y [0,h/2].
// B channel is for the pixels x [0,w/2] y [h/2,h].
// A channel is for the pixels x [w/2,w] y [h/2,h].
// we will upload the result drawing the fbo into a w/2,h/2 RGBA image.
// then looping through those pixels we recover a GRAY pixels vector w,h.
*/
uniform sampler2DRect tex;
uniform float width;
uniform float height;
vec4 vr = vec4(1,0,0,0);
vec4 vg = vec4(0,1,0,0);
vec4 vb = vec4(0,0,1,0);
vec4 va = vec4(0,0,0,1);
vec4 gray_to_rgba(vec2 pos){
float w = width;
float h = height;
float h2 = h/2.;
float w2 = w/2.;
vec2 pos_g = vec2(w2,0);
vec2 pos_b = vec2(0,h2);
vec2 pos_a = vec2(w2,h2);
float cr = texture2DRect(tex, pos).r;
float cg = texture2DRect(tex, pos + pos_g).r;
float cb = texture2DRect(tex, pos + pos_b).r;
float ca = texture2DRect(tex, pos + pos_a).r;
vec4 col = vec4(cr,cg,cb,ca);
//vec4 col = vec4(cr,cg,cb,1);
//vec4 col = vec4(0,0,0,ca);
return(col);
}
void main()
{
vec2 pos = gl_TexCoord[0].xy;
float h2 = height/2.;
float w2 = width/2.;
if( pos.x <w2 && pos.y <h2){
gl_FragColor = gray_to_rgba(pos);
}
else
gl_FragColor = vec4(0.,0.,0.,1.);
}
An example on how to use it:
void do_grey_rgb(){
fbo_grey.begin();
ofClear(0,1); // we clear the fbo.
ofDisableAlphaBlending(); // IMPORTANT !!!
// drawing here the image from the camera (grey-scaled):
fbo_dest.draw(0,0);
s_grey.begin(); // shader to codify the image as RGBA, using only w/2, h/2..
s_grey.setUniform1f("width", width);
s_grey.setUniform1f("height", height);
int w = width;
int h = height;
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex3f(0, 0, 0);
glTexCoord2f(w, 0); glVertex3f(w, 0, 0);
glTexCoord2f(w, h); glVertex3f(w, h, 0);
glTexCoord2f(0,h); glVertex3f(0,h, 0);
glEnd();
s_grey.end(); // shader's end.
fbo_grey.end();
// this next fbo is half the size ::
// we use this one to draw only 1/4 of the previous fbo.
// it is the only needed info.
fbo_small.begin();
ofClear(0,1); // we clear the fbo.
ofDisableAlphaBlending();
fbo_grey.draw(0,0);
fbo_small.end();
// when the camera gots a new frame, then upload the image from GPU:
if(newFrame) {
fbo_small.readToPixels(image_fbo);
image_fbo.update();
// this will un-codify the image and make one full size grey image.
rgba_to_gray(image_fbo.getPixels(),image_fbo_grey.getPixels());
image_fbo_grey.update();
// image_fbo_grey contains the result...
}
}
Hope this helps…
Now i can make 60fps (NO, THAT WAS NOT THE CASE…see below) with extensive GPU work on images from my Ps3…
Soon some source code…