Rendering Loop

With multi-threaded rendering, the traditional rendering loop is split up into two pieces: the advance/input processing logic executed by the advance thread and the render-thread loop that executes drawing commands such “draw frame”. Scaleform 4.0 APIs accommodate multi-threading by defining GFx::MovieDisplayHandle that can be safely passed to the rendering thread. The GFx::Movie object itself should not be passed to the rendering thread since it is not inherently thread-safe and no longer contains the Display method.

The general movie rendering process can be broken down into the following steps:

  1. Initialization. After GFx::Movie is created by GFx::MovieDef::CreateInstance, the user configures it by setting the viewport, obtaining the display handle and passing it to the render thread.
  2. Main thread processing loop. On every frame, the user handles input and calls Advance to perform timeline and ActionScript processing. It is important that the Advance call be the last call after any Invoke/DirectAccess API modifications to the movie, as that is where the scene snapshot is taken for the frame. After Advance, the movie submits a Scaleform draw frame request to the render thread.
  3. Rendering. Once the render thread receives a draw frame request, it “grabs” the most recently captured snapshot for the MovieDisplayHandle and renders it on screen.

The following reference demonstrates these steps in detail.

//------------------------------------------------------------------------
// 1. Movie Initialization

Ptr<GFx::Movie>          pMovie = ...;
GFx::MovieDisplayHandle  hMovieDisplay;

// Configure viewport after movie creation and grab the
// display handle.
pMovie->SetViewport(width, height, 0,0, width, height);
hMovieDisplay = pMovie->GetDisplayHandle();

// Pass the handle to render thread; this is engine-specific. In Scaleform Player,
// this is done by queuing up an internal function call.
pRenderThread->AddDisplayHandle(hMovieDisplay);


//------------------------------------------------------------------------
// 2. Processing loop

// Handle input and processing on the main thread. Movie callbacks
// such as ExternalInterface are also called here from Advance.
float deltaT = ...;
pMovie->HandleEvent(...);
pMovie->Advance(deltaT);

// Wait for previous frame rendering to complete and queue up
// a draw frame request.
pRenderThread->WaitForOutstandingDrawFrame();
pRenderThread->DrawFrame();


//------------------------------------------------------------------------
// 3. Rendering – Render thread DrawFrame logic
Ptr<Render::HAL> pHAL = ...;

pHAL->BeginFrame();
bool hasData = hMovieDisplay.NextCapture(pHAL->GetContextNotify());
if (hasData)
    pHAL->Display(hMovieDisplay);
pHAL->EndFrame();

While most of the logic is self-explanatory, a couple of details stand out: