Search code examples
c++multithreadingopenmpraytracing

Increment shared loop counter in OpenMP for progress reporting


I want to keep track of total pixels and rays processed by a long running raytracing process. If I update the shared variables every iteration, the process will slow down noticeably because of synchronization. I'd like to keep track of the progress and still get accurate count results at the end. Is there a way to do this with OpenMP for loops?

Here's some code of the loop in question:

void Raytracer::trace(RenderTarget& renderTarget, const Scene& scene, std::atomic<int>& sharedPixelCount, std::atomic<int>& sharedRayCount)
{
    int width = renderTarget.getWidth();
    int height = renderTarget.getHeight();
    int totalPixelCount = width * height;

    #pragma omp parallel for schedule(dynamic, 4096)
    for (int i = 0; i < totalPixelCount; ++i)
    {
        int x = i % width;
        int y = i / width;

        Ray rayToScene = scene.camera.getRay(x, y);
        shootRay(rayToScene, scene, sharedRayCount); // will increment sharedRayCount
        renderTarget.setPixel(x, y, rayToScene.color.clamped());

        ++sharedPixelCount;
    }
}

Solution

  • Here's an example on how to do it:

    void Raytracer::trace(RenderTarget& renderTarget, const Scene& scene, std::atomic<int>& sharedPixelCount, std::atomic<int>& sharedRayCount)
    {
        int width = renderTarget.getWidth();
        int height = renderTarget.getHeight();
        int totalPixelCount = width * height;
        int rayCount = 0;
        int previousRayCount = 0;
    
        #pragma omp parallel for schedule(dynamic, 1000) reduction(+:rayCount) firstprivate(previousRayCount)
        for (int i = 0; i < totalPixelCount; ++i)
        {
            int x = i % width;
            int y = i / width;
    
            Ray rayToScene = scene.camera.getRay(x, y);
            shootRay(rayToScene, scene, rayCount);
            renderTarget.setPixel(x, y, rayToScene.color.clamped());
    
            if ((i + 1) % 100 == 0)
            {
                sharedPixelCount += 100;
                sharedRayCount += (rayCount - previousRayCount);
                previousRayCount = rayCount;
            }
        }
    
        sharedPixelCount = totalPixelCount;
        sharedRayCount = rayCount;
    }
    

    It won't be 100% accurate while the loop is running, but the error is negligible. At the end exact values will be reported.