Archive for April, 2010

OpenGL Frame Rate


Calculating the frames per second in our Graphics application makes sense when we are displaying animation, which is simply a collection of images displayed rapidly and in sequence.When we watch a video\movie, the usual number of frames displayed in a second is 24. Our eyes can’t see all the 24 frames one by one in a single second, and that’s why we get the illusion of something moving, rotating, or growing in size.

In this post, we are going to create an OpenGL app that animates an object and calculates the frames per second for that animation.

FPS

To make this calculation, we need to find a way to keep track of the number of frames and time elapsed. The key here is to do the calculation in the GLUT idle function (callback function passed to glutIdleFunc), which is called only when our application is not busy doing something else (such as drawing the current frame). So every time the idle function is called, we increment the frame count, check the time elapsed, and if the time is greater than or equal to 1 second, we calculate the FPS.

//-------------------------------------------------------------------------
//  This function is called when OpenGL\GLUT is not working on
//  something else... It is mainly used for animation...
//
//  It's like the timers but time intervals are dependent on how busy
//  the app is, instead of having a constant value set by the user.
//-------------------------------------------------------------------------
void idle (void)
{
    //  Animate the object
    animateObject();

    //  Calculate FPS
    calculateFPS();

    //  Call display function (draw the current frame)
    glutPostRedisplay ();
}

As you can see in the code above, the idle function is animating the object, calculating the FPS, then triggering the display function (callback function passed to glutDisplayFunc) by calling glutPostRedisplay().

The display function would basically display the object and text showing the FPS value.

//-------------------------------------------------------------------------
//  This function is passed to glutDisplayFunc in order to display
//	OpenGL contents on the window.
//-------------------------------------------------------------------------
void display (void)
{
    glClear (GL_COLOR_BUFFER_BIT);

    drawObject();
    drawFPS();

    glutSwapBuffers ();
}

To get the time elapsed, we use the glutGet(GLUT_ELAPSED_TIME) function which will get the time passed in milliseconds since the program started or since it was last called. The implementation of calculateFPS would look like this:

//-------------------------------------------------------------------------
// Calculates the frames per second
//-------------------------------------------------------------------------
void calculateFPS()
{
    //  Increase frame count
    frameCount++;

    //  Get the number of milliseconds since glutInit called
    //  (or first call to glutGet(GLUT ELAPSED TIME)).
    currentTime = glutGet(GLUT_ELAPSED_TIME);

    //  Calculate time passed
    int timeInterval = currentTime - previousTime;

    if(timeInterval > 1000)
    {
        //  calculate the number of frames per second
        fps = frameCount / (timeInterval / 1000.0f);

        //  Set time
        previousTime = currentTime;

        //  Reset frame count
        frameCount = 0;
    }
}

Download full source code here. If you have any issues compiling or running the app, check out this section for details about compiling and running an OpenGL app that uses the GLUT library. Toby Howard has a different implementation that is not dependent on GLUT. You can find it here.

Memory Visualizer


“Memory Visualizer” is a program implemented in C++ using the OpenGL library. It allows you to browse and see the contents (in decimal, hex, char and binary formats) of every address in the process address space. It also color maps every byte in memory so we visually get an idea about the most common byte values. A lot of variables (x86-x64, physical vs. virtual memory, etc…) could affect the way we visualize memory, so they are described in detail in the sections that follow.

The implementation is simple, but it certainly helped me refresh my memory about computer memory. I hope it’ll do the same for you.

CPU Architecture

On an x86 machine, general-purpose registers (GPR) are 32-bit wide. Thus, a CPU register can refer to one of 2 ^ 32 possible addresses. Knowing that each address identifies a single byte of storage, on a 32-bit system, we can have a maximum of 4 GB of RAM (physical memory). On an x64 processor, GPRs are 64-bit wide, and thus it’s possible to refer to 2 ^ 64 locations (16 exbibytes). Although it’s possible to refer to that much memory, the largest RAM in the world by far is 2.5 TB ($4.7 million and 10,000 times the size of RAM in your PC. More details here).

The CPU architecture doesn’t directly affect the size of the virtual address in memory. It’s the targeted platform when compiling our C++ application that does have an impact on the way we are going to visualize memory. When compiling C++ using Visual Studio on a 64-bit Windows operating system, the code is built as a 32-bit application by default. However, we can still build 64-bit applications using Visual Studio (see section below). Using the sizeof operator (results in table below), we can clearly see that a pointer in a 32-bit C++ app has a size of 4 bytes (32 bits) while a pointer in a 64-bit app has a size of  8 bytes (64-bit).

So if we build our app as 32-bit, we’ll be able to browse virtual memory addresses ranging from address 0 to address 2^32 – 1.  Building that app as 64-bit, we can browse virtual memory addresses from 0 to 2^64 – 1.

Visual Studio X64

To build a 64-bit application in Visual Studio, go to Build \ Configuration Manager, in the “Active solution platform” drop-down, select <New…>. Select x64 in the “Type or select the new platform” drop-down. Click OK then rebuild your application. If you don’t see the “x64″ in the drop-down, check this page for installing Visual Studio 64-bit Components.

Physical Memory vs. Virtual Memory

Although physical memory is the actual location where data\code is stored, processes in an operating system don’t interact directly with physical memory. Instead, processes operate on virtual memory. Thus, our C++ program will reflect the virtual memory and not the physical memory. Here is a nice diagram that shows the relationship between virtual and physical address spaces.

A machine of 2 GB of RAM can actually have 4 GB of virtual memory. The extra memory is usually stored on a hard disk drive. Since I/O with a disk is much slower than volatile memory, new and active processes are located in RAM while other non-active processes reside on disk. Based on usage, virtual memory is swapped back and forth between RAM and hard drive to ensure most efficient execution possible. Thus, the total virtual space is limited by both the actual physical space and hard disk space.

Virtual memory is also dependent on the type of operating system installed on the machine. For example, on a 64-bit Windows Server R2 Enterprise, the virtual memory limit is 2 TB. On a 64-bit Windows 7 Ultimate, the limit is 192 GB. On a 64-bit Vista Ultimate, the limit is 128 GB. However, on a 32-bit Windows 7 Ultimate or Windows Vista Ultimate, the limit is 4 GB. In short, on a Windows Operating system, limits range between 2 GB and 2 TB based on the version of the OS. Full details available here.

Process Private Address Space

Although the total virtual address space can get up to 2 TB on Windows Server 2008 R2, this doesn’t mean that each process can take advantage of that much memory. The maximum amount of addressable memory a process can have is dependent on the Operating System and the way the program is compiled. By default, every process takes 2 GB of private address space on any Windows Operating System whatever the processor architecture is. However, a program can be flagged as large address aware during linkage, and in that case, a 32-bit process can take up to 3 GB on a 32-bit Windows (with 4GT enabled) and 4 GB on a 64-bit Windows, while a 64-bit process takes 8 TB on a 64-bit Windows. Full details available here.

Large Address Aware

To make a program large address aware in Visual Studio, go to Project \ Properties \ Configuration Properties \ Linker \ System. Set “Enable Large Addresses” to “Support Addresses Larger Than 2 Gigabytes (/LARGEADDRESSAWARE)”.

Access Violation

Every process has its own private address space. A process can’t read from the address space of another process. Thus, our Memory Visualizer C++ program will only be able to view the content of virtual memory addresses in its address space. If we try to access the contents of an address (except for shared memory) outside the process private address space, we will get an access violation exception.

Since in our program we can browse to any address (by changing the value of a pointer p) then view the contents of that address using *p, there is a very high possibility that we end up trying to view the contents outside our address space and thus get an access violation exception.

By default, in a project compiled with Visual C++, an access violation exception that happens inside a try\catch(…) block is not caught. The reason for this is that Visual C++ has two types of exception handling: Synchronous Exception Handling (/EHs) and Asynchronous Exception Handling (/EHa). The default Exception handling mechanism in Visual C++ 2005 (and later) is synchronous, which means it only handles exceptions thrown by a throw statement. Any hardware exceptions will not be caught by the synchronous model for performance reasons. To get the access violation exceptions caught, I had to change the exception handling model in my VS project to asynchronous. To do so, go to Project \ Properties \ Configuration Properties \ C/C++ \ Code Generation, and change “Enable C++ Exceptions” to “Yes With SEH Exceptions (/EHa)”.

The Visualization

With all those memory concepts finally sorted out, we can now get to visualizing it.

  1. A virtual memory address refers to one byte in memory. Thus, we should declare the address pointer as follows:
    unsigned char *currentAddress;
  2. Start with an address inside our process. We can get the address of any primitive type or array declared (stack) or the address of anything initialized on the heap with malloc or new. I chose the address of the argc argument to the main method.
    start_Address = (unsigned char *)&argc;
  3. Show the content of up to 24 addresses at a time.
    for (currentAddress = top_entry; currentAddress < top_entry + 24; currentAddress++)
    {
        //  Code to display current address and its contents
    }
  4. In case an access violation happens while trying to access the contents of an address, show the ‘?’ value in all formats.
    bool av = false;
    try
    {
        currentValue = *currentAddress;
    }
    catch(...)
    {
        av = true;
    }
    
    if(av)
    {
        //  draw '?'
    }
    else
    {
        //  draw currentValue
    }
  5. An address is displayed in hexadecimal. Contents of an address (a byte) is displayed in decimal (value between 0 and 255), as ASCII character (GLUT capable of displaying letters, digits, and few symbols), in hexadecimal format and binary format.
  6. Based on the value of address content, a color is used. More details about color mapping below.

Usage

Color Mapping

The content of an address (a  byte) can have a value ranging from 0 to 255 (in decimal format). We need to assign a color for each of those values ranging from black to white. The RGB system accepts 256 different values for each of the color components red, green and blue. With 256 values for each color components, the number of possible colors that can be generated is 256 ^ 3 (permutation with repetition). The challenge here is to meaningfully map 16,777,216 possible colors to 256 colors only.

Color Lookup Table (CLUT)

A color look-up table (CLUT) is a mechanism used to transform a range of input colors into another range of colors. In our case, we want to transform the 16,777,216 range to a 256 range. We will try to generate more than one color table and see where the visualization looks best.

Gray Scale

We will start with the simplest color table. A color looks gray if all the R, G, and B components are equal. When R = G = B = 0, the color is black. As we increase the value of the color components, the color will get lighter (dark gray) and lighter (gray) and lighter (light gray) until it becomes white with R = G = B = 255.

for(i = 0; i < 256; i++)
{
    gray[i][0] = i;        //  R
    gray[i][1] = i;        //  G
    gray[i][2] = i;        //  B
}

RB

To keep things simple, let’s remove one variable out of the equation. So as if the green component doesn’t exist, think of a way to combine the red and blue components to give a feeling of moving from red to blue as we move from 0 to 255.

For color 0, use (255, 0, 0), for color 1, use (254, 0, 1), …, for color n use (255 – n, 0, n), … for color 255 use (0, 0, 255).

for(i = 0; i < 256; i++)
{
    rb[i][0] = 255 - i;  //  R
    rb[i][1] = 0;        //  G
    rb[i][2] = i;        //  B
}

RGB

Let’s say that now we would like to put back the green color into the color scale. We can do so by splitting the scale in half. 0 to 127 will represent the move from red to green and 128 to 255 will represent the move from green to blue.

Color 0 is (255, 0, 0), Color 1 is (253, 2, 0), Color n (where n < 128) is (255 – 2n, 2n, 0). Color 128 is (0, 255, 0), Color 129 is (0, 253, 2) and color n (where n >= 128) is (0, 255 – 2n, 2n).

for(i = 0; i < 128; i++)
{
    rgb[i][0] = 255 - 2 * i;  //  R
    rgb[i][1] = 2 * i;        //  G
    rgb[i][2] = 0;            //  B
}

for(; i < 256; i++)
{
    rgb[i][0] = 0;            //  R
    rgb[i][1] = 255 - 2 * i;  //  G
    rgb[i][2] = 2 * i;        //  B
}

Rainbow

The conventional 7 colors of a rainbow are red, orange, yellow, green, blue and violet. See Roygbiv.

for(i = 0; i < 64; i++)
{
    roygbv[i][0] = 255;
    roygbv[i][1] = i * 4;
    roygbv[i][2] = 0;
}

for(; i < 128; i++)
{
    roygbv[i][0] = 255 - (i * 4);
    roygbv[i][1] = 255;
    roygbv[i][2] = 0;
}

for(; i < 192; i++)
{
    roygbv[i][0] = 0;
    roygbv[i][1] = 255 - (i * 4);
    roygbv[i][2] = i * 4;
}

for(; i < 256; i++)
{
    roygbv[i][0] = i * 4;
    roygbv[i][1] = 0;
    roygbv[i][2] = 255;
}

Hot

Hot is the transition from black to red to yellow to white.
for(i = 0; i < 85; i++)
{
    hot[i][0] = i * 3;
    hot[i][1] = 0;
    hot[i][2] = 0;
}

for(; i < 170; i++)
{
    hot[i][0] = 255;
    hot[i][1] = (i - 85) * 3;
    hot[i][2] = 0;
}

for(; i < 256; i++)
{
    hot[i][0] = 255;
    hot[i][1] = 255;
    hot[i][2] = (i - 170) * 3;
}

Cold

Cold is the transition from cyan to magenta.

for(i = 0; i < 256; i++)
{
    cold[i][0] = i;
    cold[i][1] = 255 - i;
    cold[i][2] = 255;
}

Random

Generate random numbers for the R, G, and B components.
for(i = 0; i < 256; i++)
{
    random[i][0] = rand() % 256;
    random[i][1] = rand() % 256;
    random[i][2] = rand() % 256;
}

Source Code

To run the app, download the exe from here. The complete source code is available here. If you have any issues compiling or running the app, check out this section for details about compiling and running an OpenGL app that uses the GLUT library.

Xml Editor Control


If you have a Windows Forms application that involves Xml editing or viewing, you can use this control to save yourself the effort of formatting the Xml content. For now, only syntax highlighting is implemented. I expect to add more features in the future like spacing, grouping, intellisense, etc…

Usage

Simply add the files (XmlToken.cs, XmlTokenizer.cs, XmlEditor.cs, XmlEditor.designer.cs) to your project then drag and drop the XmlEditor control from the Toolbox into your Windows Form.

The XmlEditor control currently has three public properties. Use AllowXmlFormatting to enable or disable formatting on the Xml content in the editor. The ReadOnly property tells whether or not to allow the user to change the text. The Text property sets or gets the text of the Xml editor.

Here is how the control looks like when AllowXmlFormatting = true and ReadOnly = false (default values):

Implementation

To color the Xml string, we have to split it into multiple tokens, then color each token based on its type. I have identified the following token types (based on syntax highlighting behavior in Visual Studio 2008):

  • A “Value” is anything between double quotes
  • A “Comment” is anything that starts with <!– and ends with –> (or starts with <!– and is never closed with –>)
  • An “Element” is any letter or digit that falls between < and a space or >
  • An “Attribute” is any letter or digit that falls after a < followed by space and not closed by >
  • An “Escape” is anything that starts with & and ends with ; (For example &quote;)
  • A “SpecialChar” is any character that is not a letter or a digit
  • A “None” is anything else

The Tokenize() public static method of the XmlTokenizer class does the job of splitting a string into Xml tokens.

An XmlToken object is a representation of an Xml token with details about the exact text of that token, its location in the string and its type.

Here is the code in the XmlEditor control that does the syntax highlighting:

List<XmlToken> tokens = XmlTokenizer.Tokenize(xmlEditor.Text);

foreach (XmlToken token in tokens)
{
    xmlEditor.Select(token.Index, token.Text.Length);

    switch (token.Type)
    {
        case XmlTokenType.Attribute:
            xmlEditor.SelectionColor = Color.Red;
            break;
        case XmlTokenType.Comment:
            xmlEditor.SelectionColor = Color.DarkGreen;
            break;

        //  and so on for the other token types
    }
}

Download source and exe.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: