Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't my small C loop print correctly to the frame buffer, but its unrolled version does?

I'm trying to write a simple C program that draws a 4x4 pixels white solid square at position (x, y) = (50, 50).

The idea is to write directly to the Linux frame buffer, which starts at the mapped memory fb->fp.

Now, the problem is that the following code is working well:

uint16_t color = 0xffff;

memcpy(fb->fp + (50+0) * fb->line_length + (50+0) * fb->bytes_per_pixel, &color, fb->bytes_per_pixel);
memcpy(fb->fp + (50+0) * fb->line_length + (50+1) * fb->bytes_per_pixel, &color, fb->bytes_per_pixel);
memcpy(fb->fp + (50+0) * fb->line_length + (50+2) * fb->bytes_per_pixel, &color, fb->bytes_per_pixel);
memcpy(fb->fp + (50+0) * fb->line_length + (50+3) * fb->bytes_per_pixel, &color, fb->bytes_per_pixel);

memcpy(fb->fp + (50+1) * fb->line_length + (50+0) * fb->bytes_per_pixel, &color, fb->bytes_per_pixel);
memcpy(fb->fp + (50+1) * fb->line_length + (50+1) * fb->bytes_per_pixel, &color, fb->bytes_per_pixel);
memcpy(fb->fp + (50+1) * fb->line_length + (50+2) * fb->bytes_per_pixel, &color, fb->bytes_per_pixel);
memcpy(fb->fp + (50+1) * fb->line_length + (50+3) * fb->bytes_per_pixel, &color, fb->bytes_per_pixel);

memcpy(fb->fp + (50+2) * fb->line_length + (50+0) * fb->bytes_per_pixel, &color, fb->bytes_per_pixel);
memcpy(fb->fp + (50+2) * fb->line_length + (50+1) * fb->bytes_per_pixel, &color, fb->bytes_per_pixel);
memcpy(fb->fp + (50+2) * fb->line_length + (50+2) * fb->bytes_per_pixel, &color, fb->bytes_per_pixel);
memcpy(fb->fp + (50+2) * fb->line_length + (50+3) * fb->bytes_per_pixel, &color, fb->bytes_per_pixel);

memcpy(fb->fp + (50+3) * fb->line_length + (50+0) * fb->bytes_per_pixel, &color, fb->bytes_per_pixel);
memcpy(fb->fp + (50+3) * fb->line_length + (50+1) * fb->bytes_per_pixel, &color, fb->bytes_per_pixel);
memcpy(fb->fp + (50+3) * fb->line_length + (50+2) * fb->bytes_per_pixel, &color, fb->bytes_per_pixel);
memcpy(fb->fp + (50+3) * fb->line_length + (50+3) * fb->bytes_per_pixel, &color, fb->bytes_per_pixel);

However, the following doesn't. It produces a 1x4 line instead of a 4x4 square.

uint16_t color = 0xffff;

int i = 0;
int j = 0;
for (; j < 4; j++) {
    for (; i < 4; i++) {

        int y_offset = 50 + j;
        int x_offset = 50 + i;

        memcpy(fb->fp + y_offset * fb->line_length + x_offset * fb->bytes_per_pixel, 
               &color, fb->bytes_per_pixel);
    }
}

As far as I can see, they should be equivalent. The assembly version I've got from the compiler doesn't look very easy to understand.

This runs in a ARM embedded Linux device. There's no X server or anything else writing to the frame buffer at this point.

fb->bytes_per_pixel equals 2.

I couldn't find any documentation on exactly how the frame buffer is mapped into memory. The offsets I've got are from random code I found on Google.

Maybe there is something wrong with these offsets. But at least the two codes should be equivalent, isn't it? Am I going crazy?

like image 805
Jardel Lucca Avatar asked Oct 29 '25 17:10

Jardel Lucca


1 Answers

Here is the problem:

for (; j < 4; j++) {
    for (; i < 4; i++) {
        //some code
    }
}

The outer for loop is expected to execute 4 times, which it must be because there is no conditional break; statement in the body. The inner for loop however needs a change. For the first iteration of outer for loop, inner for loop is executed 4 times as expected.
On the second iteration of outer for loop, the value of i is 4, the condition i>4 in inner for loop is false, so it doesn't execute. The same happens for all next iterations of outer for loop.

You can get over this by initialising i for each iteration of outer for loop.

Option 1:

for( ; j < 4; j++)
{
    for (i = 0; i < 4; i++)
    {
        // Some code
    }
}

Option 2:

for( ; j < 4; j++)
{
    for (; i < 4; i++)
    {
        // Some code
    }
    i = 0;
}

Option 3:

for( ; j < 4; j++)
{
    i = 0;
    for ( ; i < 4; i++)
    {
        // Some code
    }
}

Option 4: As suggested by David C. Rankin:

int j = 0;
// int i = 0;
for( ; j < 4; j++)
{
    int i = 0;
    for ( ; i < 4; i++)
    {
        // Some code
    }
}
like image 187
WedaPashi Avatar answered Oct 31 '25 06:10

WedaPashi