PDA

View Full Version : Accessing frame buffer data through a socket



Benoit Leveau
November 10th, 2010, 11:25
[reposting in correct section]

Hi,

I'm trying to update a display shader from mental ray 3.6 to 3.8, and to use the native frame buffers instead of a custom frame buffer plugin.
So far, so good, but I have a problem.
I manage to receive the streams for all the frame buffers, using the socket number written in the stub files, but for some reason the data I receive for the color one is all black.
For all frame buffers, I manage to get the correct data and I can then send it to my display program.
The one for the color is a 4x8bit channel and all I receive are zeros. Anyone else had this problem?
Here is my read tile functions. It's called whenever I receive a "rect_data..." message on the socket, after I issued a stream_begin with all the ids I want to stream.



// read a bucket from ray via the socket, and send it to an external viewer
int read_rect_data(int sockfd, const char *buf, const bool output_shaders)
{
int size, fb_id, fb_type;
int xl, yl, xh, yh;
int width, height, comp, bits;

sscanf(buf, "rect_data: %d, %d %d %d %d, %d %d, %d %d %d %d",
&size,
&xl, &yl, &xh, &yh,
&fb_id, &fb_type,
&width, &height, &comp, &bits);

const int w = xh+1-xl;
const int h = yh+1-yl;
const int wh = w*h*sizeof(miColor);
if ( !tile_data || !packet_data || size > packet_size || wh > tile_size )
{
release_tile_data();
packet_size = size;
tile_size = wh;
packet_data = malloc(packet_size);
tile_data = (miColor*)malloc(tile_size);
}

const int n = get_packet(sockfd, (char*)packet_data, size);
if (n != size)
{
fprintf(stderr, "thing : dropped bucket %d %d %d %d\n", xl, xh, yl, yh);
return 0;
}


// interleave channels
miScalar *out = (miScalar*)tile_data;
if (bits == 32)
{
const unsigned int *in = (unsigned int*)packet_data;
for (int y=yh; y>=yl; --y)
{
for (int c=0; c<comp; ++c)
{
for (int x=0; x<w; ++x)
{
unsigned int i = ntohl(*in);
out[(w*(y-yl)+x)*4+c] = *((float*)&i);
++in;
}
}
}
}
else if (bits == 8)
{
const unsigned char *in = (unsigned char*)packet_data;
for (int y=yh; y>=yl; --y)
{
for (int c=0; c<comp; ++c)
{
for (int x=0; x<w; ++x)
{
out[(w*(y-yl)+x)*4+c] = (*in)/255.0f;
++in;
}
}
}
}
for (int c=comp; c<4; ++c)
{
for (int y=yh; y>=yl; --y)
{
for (int x=0; x<w; ++x)
{
out[(w*(y-yl)+x)*4+c] = 0.0f;
}
}
}

// send data to external viewer
return 0;
}


Any help appreciated,
Best,
Benoit

zee
November 11th, 2010, 16:22
Hi Benoit,

The code looks ok to me. maybe we have to break this down a little more.

If I understood you correctly the values you get in "*in" are all 0, right?

How many framebuffers do you have in this scene? Does a "rgba_fp" framebuffer work? Also you said "For all frame buffers, I manage to get the correct data and I can then send it to my display program." Does this mean the data for all the other frambuffers is not 0?

sorry for the many questions. :)

-Zee

Benoit Leveau
November 11th, 2010, 16:49
It's indeed 0s in the *in for the color, and meaningful values for other frame buffers.
I'm going to do a test with the rgba_fp.

I've tested with different numbers of frame buffers, and also with different numbers of frame buffer queried with stream_begin.

Have you succeeded in getting the color buffer from mentalray?

Benoit

zee
November 11th, 2010, 17:01
Yes, this is the way the new imf_disp gets the frambuffers for display. The way we do it is basically the same.
Btw I didn't see that the first time, but there is a for loop at the end, that sets everything in out to 0 again. I hope this is just a typo in the code here.

-Zee

Benoit Leveau
November 11th, 2010, 17:20
It's not a type, it does set all data to zero but using
for (int c=comp; c<4; ++c)
comp is equal to 4 when receiving the color data so it doesn't overwrite anything.
When receiving 1x32bit channels, then it's used.

Benoit

Benoit Leveau
November 17th, 2010, 12:15
Hi,

How do you use the 'comp' information in the imf_disp code? Maybe it's what's wrong in my code.

Benoit

zee
November 17th, 2010, 13:30
Hey,

we don't use the comp value from the rect_data output at all. It is clear how many components there are from the framebuffer listing. Did you check if comp delivers you the right value? Try fixing it to 4 if you know that a rgba buffer is pressent. Maybe also check if scanf assigns all the values. The line might be incomplete.

I hope this helps.
-Zee

Benoit Leveau
November 17th, 2010, 15:56
Hi,

I was about to mention another problem, which is that the colors in the Normal passes are incorrect (G and B channels are swapped) but I've just used imf_disp to see the exact differences and I noticed the following behavior during rendering:
- the beauty pass is all black.
- the normal pass colors are also incorrect (swapped channels).
At the end of the render, when the EXR file is written to disk, imf_disp refreshes and correctly displays the beauty and the normal.

So, it looks like all my problems are actually caused by what mental ray is sending, and not from my code.

Benoit

zee
November 17th, 2010, 16:20
Hi,

The beauty pass is an output shader that writes to a user buffer. That means that the tiles that are send while rendering are black. The primary buffer (the non user rgba buffer) should show the values, though.

I will look into the normal pass. That doesn't sound right. Thx a lot.

could you send me your framebuffer statement in the camera? Then I could tell you what you should expect.

-Zee

Benoit Leveau
November 17th, 2010, 16:26
I attached the mi file for my test scene.

The beauty pass I'm refering to is actually the "mayaColor" one that's created automatically by Maya in the scene. It displays as MAIN in the layer menu of imf_disp, and is black during rendering and correct after render has finished.

Thanks,
Benoit

Benoit Leveau
November 23rd, 2010, 11:54
Any luck into looking at the scene I sent you? I'm still trying to display the primary buffer but as the same problem appears with imf_disp I'm not really optimistic :/

Thanks,
Benoit

Benoit Leveau
November 23rd, 2010, 17:50
Interestingly, if I launch imf_disp from mental ray 3.6.52.7 (linux 64bit), the image displays fine during and after render.
When launching imf_disp from mental ray 3.8.2.10b (linux 64bit), the image is black during render then fine at the end.
Any idea?

Benoit

zee
November 23rd, 2010, 18:25
Hi Benoit,

the version of imf_disp in 3.8 is a new implementation that handles multiple frambuffers. you can only disply one frambuffer with the version of 3.6.

Regarding your issues:
Unfortunately I could not reproduce the black image issue. Does it exist as well if you only use one framebuffer, that is only the rgba primary framebuffer mayaColor?

All the other framebuffers supplied in the mi file are user frambuffers handled by the maya shaders.

I hope this helps,
Zee

steve
November 23rd, 2010, 19:17
Hi Benoit,
this sounds more like an image update / timing problem. Does the behavior change if you disable OpenGL for display with --disable-gl ?

Benoit Leveau
November 24th, 2010, 13:04
I just realized you probably meant to listen to the first socket indicated in the stub file to get the primary color. I've always listened to the second socket for frame buffers until now.
I'm trying now by listening at the first socket, which is probably what imf_disp for mr3.6 was doing and it's why it's working in this version?

Do you have a snippet of code for listening on the first socket?
I can't get my code to receive these 5-integer packets? The data looks a bit random to me.

From "Programming mental ray":
"The protocol used to send data to a file descriptor or to a socket are identical. Data is sent in packets. Each packet consists of a header, followed by optional image data. The header consists of five integers in network byte order (big-endian, high byte first): one packet type code followed by four parameters."

Thanks,
Benoit

Benoit Leveau
November 24th, 2010, 17:33
Do you have a snippet of code for listening on the first socket?
I can't get my code to receive these 5-integer packets? The data looks a bit random to me.


Ok, I found what I was doing wrong...I wasn't properly converting the network byte order to the host byte order.

I'm now able to retrieve the primary color data during rendering, so my problem is fixed :)

Thanks for your help!
Benoit