Ejemplo n.º 1
0
        /// <summary>
        /// Registers the given view on this thread.
        /// </summary>
        internal void RegisterView(IInputEnabledView view)
        {
            view.EnsureNotNull(nameof(view));

            m_commandQueue.Enqueue(() =>
            {
                List <IInputHandler> inputHandlers = InputHandlerFactory.CreateInputHandlersForView(view);
                if (inputHandlers == null)
                {
                    return;
                }
                if (inputHandlers.Count == 0)
                {
                    return;
                }

                // Deregister old input handlers if necessary
                if (m_viewInputHandlers.ContainsKey(view))
                {
                    List <IInputHandler> oldList = m_viewInputHandlers[view];
                    foreach (IInputHandler actOldInputHanlder in oldList)
                    {
                        actOldInputHanlder.Stop();
                    }
                    m_viewInputHandlers.Remove(view);
                }

                // Register new ones
                m_viewInputHandlers[view] = inputHandlers;
                foreach (IInputHandler actInputHandler in inputHandlers)
                {
                    actInputHandler.Start(view);
                }
            });
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Waits until the given object is visible.
        /// </summary>
        /// <param name="sceneObjects">The scene objects to check for.</param>
        /// <param name="viewInfo">The view on which to check for visibility.</param>
        /// <param name="cancelToken">The cancellation token.</param>
        public Task WaitUntilVisibleAsync(IEnumerable <SceneObject> sceneObjects, ViewInformation viewInfo, CancellationToken cancelToken = default(CancellationToken))
        {
            sceneObjects.EnsureNotNull(nameof(sceneObjects));
            viewInfo.EnsureNotNull(nameof(viewInfo));

            TaskCompletionSource <object> taskComplSource = new TaskCompletionSource <object>();

            // Define the poll action (polling is done inside scene update
            Action pollAction = null;

            pollAction = () =>
            {
                if (AreAllObjectsVisible(sceneObjects, viewInfo))
                {
                    taskComplSource.SetResult(null);
                }
                else if (cancelToken.IsCancellationRequested)
                {
                    taskComplSource.SetCanceled();
                }
                else
                {
                    m_asyncInvokesBeforeUpdate.Enqueue(pollAction);
                }
            };

            // Register first call of the polling action
            m_asyncInvokesBeforeUpdate.Enqueue(pollAction);

            return(taskComplSource.Task);
        }
        /// <summary>
        /// Attaches the given component to this scene.
        /// </summary>
        /// <param name="component">The component to be attached.</param>
        /// <param name="sourceView">The view which attaches the component.</param>
        internal void AttachComponent(SceneComponentBase component, ViewInformation sourceView)
        {
            component.EnsureNotNull(nameof(component));
            if (component.IsViewSpecific)
            {
                sourceView.EnsureNotNull(nameof(sourceView));
            }

            m_componentRequests.Enqueue(new SceneComponentRequest()
            {
                RequestType       = SceneComponentRequestType.Attach,
                Component         = component,
                CorrespondingView = component.IsViewSpecific ? sourceView : null
            });
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Gets all gathered InputFrames.
        /// </summary>
        internal void QueryForCurrentFrames(List <InputFrame> targetList)
        {
            // Do first recover all old frames
            m_recoveredInputFrames.Enqueue(targetList);
            targetList.Clear();

            // Enqueue new frames
            m_gatheredInputFrames.DequeueAll(targetList);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Awaits next render.
        /// </summary>
        public Task AwaitRenderAsync()
        {
            if (!this.IsOperational)
            {
                return(Task.Delay(100));
            }

            TaskCompletionSource <object> result = new TaskCompletionSource <object>();

            m_renderAwaitors.Enqueue(result);

            return(result.Task);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Performs the given action beside rendering process.
        /// (given action gets called by update thread while render threads are rendering.)
        /// </summary>
        /// <param name="actionToInvoke">The action to be invoked.</param>
        public Task PerformBesideRenderingAsync(Action actionToInvoke)
        {
            actionToInvoke.EnsureNotNull(nameof(actionToInvoke));

            TaskCompletionSource <bool> taskCompletionSource = new TaskCompletionSource <bool>();

            m_asyncInvokesUpdateBesideRendering.Enqueue(() =>
            {
                try
                {
                    actionToInvoke();

                    taskCompletionSource.TrySetResult(true);
                }
                catch (Exception ex)
                {
                    taskCompletionSource.TrySetException(ex);
                }
            });

            return(taskCompletionSource.Task);
        }
Ejemplo n.º 7
0
        protected override void OnTick(EventArgs eArgs)
        {
            base.OnTick(eArgs);

            if (!GraphicsCore.IsInitialized)
            {
                return;
            }

            // Query for all input handlers on first tick
            if (m_globalInputHandlers == null)
            {
                m_globalInputHandlers = InputHandlerFactory.CreateInputHandlersForGlobal();
                foreach (IInputHandler actInputHandler in m_globalInputHandlers)
                {
                    actInputHandler.Start(null);
                }
            }

            // Execute all commands within the command queue
            if (m_commandQueue.Count > 0)
            {
                Action actCommand = null;
                while (m_commandQueue.Dequeue(out actCommand))
                {
                    actCommand();
                }
            }

            // Gather all input data
            int expectedStateCount = m_lastInputFrame != null ? m_lastInputFrame.CountStates : 6;

            // Create new InputFrame object or reuse an old one
            InputFrame newInputFrame = null;

            if (m_recoveredInputFrames.Dequeue(out newInputFrame))
            {
                newInputFrame.Reset(expectedStateCount, SINGLE_FRAME_DURATION);
            }
            else
            {
                newInputFrame = new InputFrame(expectedStateCount, SINGLE_FRAME_DURATION);
            }

            // Gather all input states
            foreach (IInputHandler actInputHandler in m_globalInputHandlers)
            {
                foreach (InputStateBase actInputState in actInputHandler.GetInputStates())
                {
                    actInputState.EnsureNotNull(nameof(actInputState));

                    newInputFrame.AddCopyOfState(actInputState, null);
                }
            }
            foreach (KeyValuePair <IInputEnabledView, List <IInputHandler> > actViewSpecificHandlers in m_viewInputHandlers)
            {
                RenderLoop renderLoop = actViewSpecificHandlers.Key.RenderLoop;
                if (renderLoop == null)
                {
                    continue;
                }

                foreach (IInputHandler actInputHandler in actViewSpecificHandlers.Value)
                {
                    foreach (InputStateBase actInputState in actInputHandler.GetInputStates())
                    {
                        actInputState.EnsureNotNull(nameof(actInputState));

                        newInputFrame.AddCopyOfState(actInputState, renderLoop.ViewInformation);
                    }
                }
            }

            // Store the generated InputFrame
            m_lastInputFrame = newInputFrame;
            m_gatheredInputFrames.Enqueue(newInputFrame);

            // Ensure that we hold input frames for a maximum time range of a second
            //  (older input is obsolete)
            while (m_gatheredInputFrames.Count > Constants.INPUT_FRAMES_PER_SECOND)
            {
                InputFrame dummyFrame = null;
                m_gatheredInputFrames.Dequeue(out dummyFrame);
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Renders all given scenes using the different devices and performs "UpdateBesideRendering" step.
        /// </summary>
        /// <param name="registeredRenderLoops">The registered render loops on the current pass.</param>
        /// <param name="scenesToRender">All scenes to be updated / rendered.</param>
        /// <param name="devicesInUse">The rendering devices that are in use.</param>
        /// <param name="updateState">Current global update state.</param>
        private void RenderAndUpdateBeside(
            List <RenderLoop> registeredRenderLoops, List <Scene> scenesToRender, List <EngineDevice> devicesInUse, UpdateState updateState)
        {
            using (var perfToken = m_host.BeginMeasureActivityDuration(Constants.PERF_GLOBAL_RENDER_AND_UPDATE_BESIDE))
            {
                ThreadSaveQueue <RenderLoop> invalidRenderLoops = new ThreadSaveQueue <RenderLoop>();

                // Trigger all tasks for 'Update' pass
                Parallel.For(0, devicesInUse.Count + scenesToRender.Count, (actTaskIndex) =>
                {
                    if (actTaskIndex < devicesInUse.Count)
                    {
                        // Render all targets for the current device
                        EngineDevice actDevice = devicesInUse[actTaskIndex];
                        using (var perfTokenInner = m_host.BeginMeasureActivityDuration(string.Format(Constants.PERF_GLOBAL_RENDER_DEVICE, actDevice.AdapterDescription)))
                        {
                            for (int loop = 0; loop < registeredRenderLoops.Count; loop++)
                            {
                                RenderLoop actRenderLoop = registeredRenderLoops[loop];
                                try
                                {
                                    if (actRenderLoop.Device == actDevice)
                                    {
                                        actRenderLoop.Render();
                                    }
                                }
                                catch (Exception)
                                {
                                    // Mark this renderloop as invalid
                                    invalidRenderLoops.Enqueue(actRenderLoop);
                                }
                            }
                        }
                    }
                    else
                    {
                        // Perform updates beside rendering for the current scene
                        int sceneIndex = actTaskIndex - devicesInUse.Count;
                        using (var perfTokenInner = m_host.BeginMeasureActivityDuration(string.Format(Constants.PERF_GLOBAL_UPDATE_BESIDE, sceneIndex)))
                        {
                            Scene actScene = scenesToRender[sceneIndex];
                            SceneRelatedUpdateState actUpdateState = actScene.CachedUpdateState;

                            actUpdateState.OnStartSceneUpdate(actScene, updateState, null);
                            actScene.UpdateBesideRender(actUpdateState);
                        }
                    }
                });

                // Handle all invalid render loops
                if (invalidRenderLoops.HasAny())
                {
                    foreach (var actRenderLoop in invalidRenderLoops.DequeueAll())
                    {
                        DeregisterRenderLoop(actRenderLoop);
                    }
                }

                // Reset camera changed flags
                foreach (RenderLoop actRenderLoop in registeredRenderLoops)
                {
                    actRenderLoop.Camera.StateChanged = false;
                }
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Updates the scene's and prepares all views for rendering.
        /// </summary>
        /// <param name="renderingRenderLoops">The registered render loops on the current pass.</param>
        /// <param name="scenesToRender">All scenes to be updated / rendered.</param>
        /// <param name="devicesInUse">The rendering devices that are in use.</param>
        /// <param name="inputFrames">All InputFrames gathered during last render.</param>
        /// <param name="updateState">Current global update state.</param>
        private async Task UpdateAndPrepareRendering(List <RenderLoop> renderingRenderLoops, List <Scene> scenesToRender, List <EngineDevice> devicesInUse, IEnumerable <InputFrame> inputFrames, UpdateState updateState)
        {
            using (var perfToken = m_host.BeginMeasureActivityDuration(Constants.PERF_GLOBAL_UPDATE_AND_PREPARE))
            {
                List <Action> additionalContinuationActions     = new List <Action>();
                object        additionalContinuationActionsLock = new object();

                // Trigger all tasks for preparing views
                List <Task <List <Action> > > prepareRenderTasks = new List <Task <List <Action> > >(renderingRenderLoops.Count);
                for (int actDeviceIndex = 0; actDeviceIndex < devicesInUse.Count; actDeviceIndex++)
                {
                    EngineDevice actDevice = devicesInUse[actDeviceIndex];
                    for (int loop = 0; loop < renderingRenderLoops.Count; loop++)
                    {
                        RenderLoop actRenderLoop = renderingRenderLoops[loop];
                        if (actRenderLoop.Device == actDevice)
                        {
                            // Call prepare render and wait for the answer
                            //  => Error handling is a bit tricky..
                            //     Errors are catched by the continuation action
                            var actTask = actRenderLoop.PrepareRenderAsync();
                            prepareRenderTasks.Add(actTask.ContinueWith((givenTask) =>
                            {
                                if (!givenTask.IsFaulted)
                                {
                                    return(givenTask.Result);
                                }
                                else
                                {
                                    // Deregister this RenderLoop
                                    lock (additionalContinuationActionsLock)
                                    {
                                        additionalContinuationActions.Add(() =>
                                        {
                                            this.DeregisterRenderLoop(actRenderLoop);
                                            renderingRenderLoops.Remove(actRenderLoop);
                                        });
                                    }

                                    return(new List <Action>());
                                }
                            }));
                        }
                    }
                }

                // Handle initial configuration of render loops (=> No current device)
                for (int loop = 0; loop < renderingRenderLoops.Count; loop++)
                {
                    RenderLoop actRenderLoop = renderingRenderLoops[loop];
                    if (actRenderLoop.Device == null)
                    {
                        try
                        {
                            Task <List <Action> > actPrepareRenderTask = actRenderLoop.PrepareRenderAsync();
                            await actPrepareRenderTask;

                            lock (additionalContinuationActionsLock)
                            {
                                additionalContinuationActions.AddRange(actPrepareRenderTask.Result);
                            }
                        }
                        catch (Exception)
                        {
                            // Deregister this RenderLoop
                            lock (additionalContinuationActionsLock)
                            {
                                additionalContinuationActions.Add(() =>
                                {
                                    this.DeregisterRenderLoop(actRenderLoop);
                                    renderingRenderLoops.Remove(actRenderLoop);
                                });
                            }
                        }
                    }
                }

                // Update all scenes
                ThreadSaveQueue <Exception> exceptionsDuringUpdate = new ThreadSaveQueue <Exception>();
                Parallel.For(0, scenesToRender.Count, (actTaskIndex) =>
                {
                    try
                    {
                        using (var perfToken2 = m_host.BeginMeasureActivityDuration(
                                   string.Format(Constants.PERF_GLOBAL_UPDATE_SCENE, actTaskIndex)))
                        {
                            Scene actScene = scenesToRender[actTaskIndex];
                            SceneRelatedUpdateState actUpdateState = actScene.CachedUpdateState;

                            actUpdateState.OnStartSceneUpdate(actScene, updateState, inputFrames);

                            actScene.Update(actUpdateState);
                        }
                    }
                    catch (Exception ex)
                    {
                        exceptionsDuringUpdate.Enqueue(ex);
                    }
                });

                // Await synchronizations with the view(s)
                if (prepareRenderTasks.Count > 0)
                {
                    await Task.WhenAll(prepareRenderTasks.ToArray());
                }

                // Throw exceptions if any occurred during scene update
                //  => This would be a fatal exception, so throw up to main loop
                if (exceptionsDuringUpdate.HasAny())
                {
                    throw new AggregateException("Error(s) during Scene update!", exceptionsDuringUpdate.DequeueAll().ToArray());
                }

                // Trigger all continuation actions returned by the previously executed prepare tasks
                foreach (var actPrepareTasks in prepareRenderTasks)
                {
                    if (actPrepareTasks.IsFaulted || actPrepareTasks.IsCanceled)
                    {
                        continue;
                    }
                    foreach (Action actContinuationAction in actPrepareTasks.Result)
                    {
                        actContinuationAction();
                    }
                }
                foreach (var actAction in additionalContinuationActions)
                {
                    actAction();
                }

                // Reset all dummy flags before rendering
                foreach (var actRenderLoop in renderingRenderLoops)
                {
                    actRenderLoop.ResetFlagsBeforeRendering();
                }

                // Unload all derigistered RenderLoops
                await UpdateRenderLoopRegistrationsAsync(renderingRenderLoops);
            }
        }