trim excess ray count for the last time slice of batch Void UpdateExposureMap(int numRaysPerTimeSlice) Change the WriteOnly attribute on the ExposureMap field of the RaycastGatherJob struct to NativeDisableParallelForRestriction in order to remove Unity’s safeguard that limits the access to native arrays to only the index passed into the jobs’ Execute functions.Add an index field to the job strcuts to mark the beginning of the range of exposure map cells to process in each frame.Add a TimeSliceBaseIndex field (initialized to 0) to keep track of time slicing progress.Let’s modify our job structs so that they only process a portion of the exposure map in one frame. Go back to step 2 to start a new batch of work.Execute final processing logic when the last portion of the work is done.Advance the index as additional portion of the work is done in each time slice.Initialize the index at the start of a new batch of work.Declare an index (or iterator) that to keep track of the current progress of time slicing.Here is the pattern I usually use for time slicing: Now, let’s see how we can further reduce the CPU time spent on the raycast job with time slicing. The jobs run outside the span of the update function, freeing up the main thread and not stalling it. GatherJob.Schedule(NumCells, JobBatchSize, hRaycastJob) Var hSetupJob = setupJob.Schedule(NumCells, JobBatchSize) dispose of job data allocated from last frame wait for jobs from last frame to complete The jobs to set up raycasts, perform raycasts, and gather raycast results are kicked at the end of the update function and waited for completion at the start of the update function in the next frame. Recall our last iteration on the exposure map example. Can’t do it all in one frame? Then do it across multiple! It’s a simple but very effective idea. Texture streaming, seamless loading, etc., work that happens “in the background” without tanking a game’s frame rate. If you think about it, time slicing is everywhere. This is the core idea of time slicing, another optimization technique I picked up at work and one of my longtime favorites. What if the job takes too long to fit in a single frame? Or what if the job is just taking longer than we’d like? Then we can split the work across multiple frames. If the game cannot afford such latency, it’s still worth trying kicking the job early and gather the results later in the same frame. If the game can afford one-frame latency, then we can kick the job in one frame and gather the results in the next frame. This prevents the main thread from being stalled. The basic idea is: kick jobs to run on worker threads and gather the results later. In the previous tutorial, I used exposure avoidance as an example to demonstrate how to optimize computation with delayed result gathering. This post is part of my Game Programming Series. Source files and future updates are available on Patreon.
0 Comments
Leave a Reply. |