OptixPathTracer Sample (7.6): how resize_dirty works?

I am trying to create a custom test renderer based on the OptixPathTracer Sample mainly to figure out how the optix pipeline works. Now I am focused on the handleResize function. I am not sure how it actually handles the resize event.
There is a global variable resize_dirty which is initialized false

bool resize_dirty = false;

then in windowSizeCallback we get the signal when user changes the window size:

Params* params = static_cast<Params*>( glfwGetWindowUserPointer( window ) );
params->width  = res_x;
params->height = res_y;
camera_changed = true;
resize_dirty   = true;

and handleResize function (which is called by the updateState function ) handles the resize event:

void handleResize( sutil::CUDAOutputBuffer<uchar4>& output_buffer, Params& params )
{
    if( !resize_dirty )
        return;
    resize_dirty = false;

    output_buffer.resize( params.width, params.height );

    // Realloc accumulation buffer
    CUDA_CHECK( cudaFree( reinterpret_cast<void*>( params.accum_buffer ) ) );
    CUDA_CHECK( cudaMalloc(
                reinterpret_cast<void**>( &params.accum_buffer ),
                params.width * params.height * sizeof( float4 )
                ) );
}

Now the pathtracer renderer main loop goes like this:

 do
 {
                    updateState( output_buffer, state.params );
                    launchSubframe( output_buffer, state );
                    displaySubframe( output_buffer, gl_display, window );
                    sutil::displayStats( state_update_time, render_time, display_time );
while( !glfwWindowShouldClose( window ) );

My main question is that how come there is not sync issue here. What if the user resizes the window at a moment where the loop has already executed the updatestate function?
Another question is if there is a sample in Optix with non-dirty resize?

Thanks!!

My main question is that how come there is not sync issue here. What if the user resizes the window at a moment where the loop has already executed the updateState function?

Have you stepped through the launchSubframe() and displaySubframe() functions?
If yes, you should have seen that there is a CUDA_SYNC_CHECK(); macro which is calling a cudaDeviceSynchronize();

That means although the optixLaunch() call is asynchronous, means it does work on the GPU while the CPU is free to continue, that cudaDeviceSynchronize() will wait until all CUDA kernels launched before have finished.
So you cannot reach the windowSizeCallback() function until CUDA is finished with its asynchronous work in a single-threaded application.

Additionally all cudaFree() and cudaMalloc() calls are synchronous and need to wait on currently running CUDA kernels in the same context to finish their work anyway.

All remaining functions are also called one after the other because the whole application is single-threaded.

Another question is if there is a sample in Optix with non-dirty resize?

Not when there is a window which can be resized.

My more advanced OptiX examples are decoupling the window client resolution from the rendering and display texture resolution. Means you can resize your window as much as you want, the ray tracer will not resize its current rendering resolution. (But again, since the examples are single-threaded, that window resize will hardly happen in parallel.) Just the display routine to the OpenGL back buffer needs to track the current window client size to adjust its projection to fit the texture blit into the window.

When actually resizing the rendering resolution inside the GUI, that change is also deferred to the next rendering call so it’s not possible to resize the buffers currently in use while the CUDA kernels are working on them. This is a very usual mechanism.

See comments here:
https://github.com/NVIDIA/OptiX_Apps/blob/master/apps/rtigo12/src/Device.cpp#L308