2
$\begingroup$

The biggest bottleneck of my code is fetching texture RGB values from memory.

My code looks something like this:

game loop{
    for every mesh{
        perform clipping;
        for every 3 verticies in mesh {
            draw triangle {
                interpolate texture coordinates;
                fetch texture RGB and place value in backbuffer;
            }
        }
    }
}

Fetching the texture RGB value from memory takes up so much time!!

I am not familiar with multithreading but I'm assuming there is some way to apply it here. Let me know what suggestions you have and how I should go about doing this!

$\endgroup$
7
  • $\begingroup$ How are you currently accessing memory? Can you share code for that? $\endgroup$
    – aces
    Commented Jul 20, 2017 at 3:58
  • $\begingroup$ This topic is big enough that books have been written on it. To get a good answer, you need to edit your question and make it more specific. But your software rasterizer will always be orders of magnitude slower than using OpenGL or DirectX. $\endgroup$
    – Dan Hulme
    Commented Jul 20, 2017 at 8:21
  • $\begingroup$ @aces The backbuffer I write to is the buffer of the screen. It is represented as 3 chars for RGB in sequential order. I call it "ibuffer". The texture RGB values are stored in an integer array where each integer is the chars RGBA. [code] *ibuffer = mesh->texture->intbuffer[(int)textureX + mesh->texture->width * (int)textureY]; [\code] The integer I copy from the texture to the backbuffer overwrites the R value of the next pixel in the back buffer. I do this so as to not use bitwise operations used to extract the RGB values from texture memory and store in backbuffer. $\endgroup$ Commented Jul 20, 2017 at 16:05
  • $\begingroup$ A minor optimisation would be to use powers of 2 for your texture size, so you can compute the offset using a logical shift. E.g. if you have a 256 pix wide texture you can compute the texel offset with "U + V << 8". Also pad your RGB structure to 4 bytes instead of 3 so the compiler can apply a similar optimisation to the array indirection. You can also apply texture wrapping trivially if power of 2 size e.g. (U & 255) + (V & 255) << 8 $\endgroup$
    – PaulHK
    Commented Jul 21, 2017 at 3:55
  • $\begingroup$ @PaulHK I will try that Paul. Compared to my original statement, I found if I access the same texel for all interpolated pixels (*ibuffer = mesh->texture->intbuffer[10000]), the program framerate increases by 3 to 4 times. Do you have any idea why? $\endgroup$ Commented Jul 21, 2017 at 16:42

2 Answers 2

5
$\begingroup$

It could be that you have to overcome a different bottleneck first.

Have you ever read Jim Blinn's "The Truth About Texture Mapping"? (I had a quick search to see if I could find a non-paywalled version but you may have better luck than me. Alternatively you might find a dead tree version of "Jim Blinn's Corner" in a library). Though this article is old and describes paging of texture data, it is still very relevant today.

Essentially, if your textures are large (i.e. too large to fit in the cache), in scan order, and they have been rotated when displayed on the polygons, you are very likely to be thrashing your cache and, as memory is an order or two of magnitude slower than the CPU, this will hurt performance.

To avoid the cache thrashing, textures are often stored in twiddled-order (that's what we called it in the early 90s but, more correctly, it'll be some variant of Morton order) or in a block order, which is what Blinn describes. This then makes texel/memory accesses far more coherent and the cache more effective.

$\endgroup$
2
  • 3
    $\begingroup$ Mip mapping is also a good strategy to improve cache coherence in texture mapping. $\endgroup$ Commented Jul 20, 2017 at 13:26
  • $\begingroup$ @Stefan Indeed. Texture aliasing is painful in multiple ways :-). There's a bit more on the subject here: computergraphics.stackexchange.com/questions/357/… $\endgroup$
    – Simon F
    Commented Jul 21, 2017 at 8:42
2
$\begingroup$

This is rather general programming question but parallelizing for loop (most common usage) in c++ is easy with openMP library. Basic example for parallelizing outer loop:

#pragma omp parallel for schedule(static, 1) num_threads(omp_get_num_procs())
for (int i = 0; i < size1; ++i)
{
    for (int j = 0; j < size2; ++j)
    {
        buffer[i*size1 + j] = ...
    }
}

But because of thread race situation below (incrementing array index) which would work in single thread wouldn't work in parallel:

int it = 0;
#pragma omp parallel for schedule(static, 1) num_threads(omp_get_num_procs())
for (int i = 0; i < size1; ++i)
{
    for (int j = 0; j < size2; ++j)
    {
        buffer[it++] = ...
    }
}

Also thing to consider is using SIMD instructions (Single Instruction Multiple Data) which optimize multiple operations to single CPU instruction:

#pragma omp parallel for simd schedule(static,10) 
for (i=0; i<N; i++) 
{ 
    a[i] = b[i] * c[i]; 
}

Some further info:

http://bisqwit.iki.fi/story/howto/openmp/

https://www.youtube.com/watch?v=Pc8DfEyAxzg

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.