private unsafe static void OnSystemStarting()
 {
     // Lock here because this method is called from a triggered public event
     using (RenderStateBarrier.AcquirePermit(withLock: staticMutationLock)) {
         CreateDeviceIfNecessary();
     }
 }
Beispiel #2
0
        /// <summary>
        /// Attempts to set the hardware that will be used for rendering by the system. You do not need to call this method before
        /// starting the system: Reasonable defaults will be selected for you.
        /// </summary>
        /// <param name="gpuIndex">The <see cref="GraphicsProcessingUnit.Index">index</see> slot of the gpu to use.</param>
        /// <param name="displayIndex">The <see cref="OutputDisplay.Index">index</see> slot of the output to use.</param>
        /// <exception cref="ArgumentOutOfRangeException">Thrown if </exception>
        /// <exception cref="InvalidOperationException">Thrown if you attempt to set the hardware while the
        /// <see cref="LosgapSystem">system</see> is running (you must stop the system to change the hardware).</exception>
        /// <seealso cref="SetHardware(Ophidian.Losgap.Rendering.GraphicsProcessingUnit,Ophidian.Losgap.Rendering.OutputDisplay)"/>
        public static void SetHardware(int gpuIndex, int displayGPUIndex, int?displayIndex)
        {
            using (RenderStateBarrier.AcquirePermit(withLock: staticMutationLock)) {
                if (installedGPUs == null)
                {
                    throw new InvalidOperationException("Can not set hardware before module has been added.");
                }
                if (LosgapSystem.IsRunning)
                {
                    throw new InvalidOperationException("Can not set hardware while system is running.");
                }
                if (gpuIndex >= installedGPUs.Length || gpuIndex < 0)
                {
                    throw new ArgumentOutOfRangeException("gpuIndex");
                }
                if (displayIndex == null)
                {
                    displayIndex = 0;
                }

                selectedGPUIndex       = gpuIndex;
                selectedOutputGPUIndex = displayGPUIndex;
                selectedOutputIndex    = displayIndex;

                Logger.Log("Selected GPU set to " + SelectedGPU);
                Logger.Log("Selected output GPU set to " + SelectedOutputGPU);
                Logger.Log("Selected output set to " + SelectedOutputDisplay);
            }
        }
 /// <summary>
 /// Remove all <see cref="RenderPass"/>es from the pipeline.
 /// </summary>
 public static void ClearPasses()
 {
     using (RenderStateBarrier.AcquirePermit(withLock: staticMutationLock)) {
         activePasses.Clear();
     }
     Logger.Log("Removed all render passes.");
 }
        /// <summary>
        /// Removes a previously-added <see cref="RenderPass"/> from the renderer. The pass will no longer be executed on each frame.
        /// </summary>
        /// <param name="renderPass">The pass to remove. Must not be null, and must currently be added.</param>
        public static void RemoveRenderPass(RenderPass renderPass)
        {
            if (renderPass == null)
            {
                throw new ArgumentNullException("renderPass");
            }

            using (RenderStateBarrier.AcquirePermit(withLock: staticMutationLock)) {
                if (!activePasses.Remove(renderPass))
                {
                    throw new InvalidOperationException("Render pass not currently added.");
                }
                Logger.Log("Removed " + renderPass + ".");
            }
        }
        /// <summary>
        /// Add a new <see cref="RenderPass"/> to the renderer. The pass will be executed on each frame, after all previously-added
        /// passes. You can insert the new pass ahead of others in the list instead using <see cref="InsertRenderPass"/>.
        /// </summary>
        /// <param name="renderPass">The render pass to add. Must not be null or already added.</param>
        public static void AddRenderPass(RenderPass renderPass)
        {
            if (renderPass == null)
            {
                throw new ArgumentNullException("renderPass");
            }

            lock (staticMutationLock) {
                if (activePasses.Contains(renderPass))
                {
                    throw new InvalidOperationException("Render pass already added.");
                }
                using (RenderStateBarrier.AcquirePermit()) activePasses.Add(renderPass);
                Logger.Log("Added " + renderPass + ".");
            }
        }
        private unsafe static void CreateDeviceIfNecessary()
        {
            using (RenderStateBarrier.AcquirePermit()) {
                // Create device
                if (device == DeviceHandle.NULL)
                {
                    Logger.Debug("Creating device...");
                    DeviceHandle outDeviceHandle;
                    InteropBool  outSupportsMT;

                    InteropUtils.CallNative(
                        NativeMethods.DeviceFactory_CreateDevice,
                        SelectedGPU.Index,
                        SelectedOutputGPU.Index,
                        SelectedOutputDisplay.Index,
                        (IntPtr)(&outDeviceHandle),
                        (IntPtr)(&outSupportsMT)
                        ).ThrowOnFailure();

                    Device = outDeviceHandle;
                    deviceSupportsMTRendering = outSupportsMT;
                    if (!deviceSupportsMTRendering)
                    {
                        Logger.Warn("Selected adapter/device does not support multithreaded command lists. " +
                                    "Multithreaded rendering will be disabled, resulting in a potentially significant performance penalty. " +
                                    "You are strongly recommended to upgrade your graphics drivers to the latest version.");
                    }
                }

                // Create thread-local device context wrapper
                if (threadLocalDeviceContext == null)
                {
                    Logger.Debug("Creating thread-local device context wrapper...");
                    threadLocalDeviceContext = new ThreadLocal <DeviceContextHandle>(CreateThreadLocalDeviceContext, true);
                }
            }
        }
        private unsafe static void OnSystemExited()
        {
            // Lock here because this method is called from a triggered public event
            using (RenderStateBarrier.AcquirePermit(withLock: staticMutationLock)) {
                // Close windows
                Logger.Debug("Closing windows...");
                HashSet <Window> openWindowsCopy = new HashSet <Window>();
                Window.OpenWindows.CopyTo(openWindowsCopy);
                foreach (Window window in openWindowsCopy)
                {
                    window.Close();
                }

                // Destroy device contexts
                Logger.Debug("Destroying device contexts...");
                threadLocalDeviceContext.Values.ForEach(dc => InteropUtils.CallNative(NativeMethods.ContextFactory_ReleaseContext, dc));
                threadLocalDeviceContext = null;

                // Destroy device
                Logger.Debug("Destroying device...");
                InteropUtils.CallNative(NativeMethods.DeviceFactory_ReleaseDevice, Device).ThrowOnFailure();
                Device = DeviceHandle.NULL;
            }
        }
        /// <summary>
        /// Inserts a new <see cref="RenderPass"/> in to the rendering pipeline, to be executed on each frame before <paramref name="insertionKey"/>.
        /// </summary>
        /// <param name="renderPass">The pass to add. Must not be null or already added.</param>
        /// <param name="insertionKey">The already-added pass to insert <paramref name="renderPass"/> in front of. Must not be null, and must
        /// currently be added.</param>
        public static void InsertRenderPass(RenderPass renderPass, RenderPass insertionKey)
        {
            if (renderPass == null)
            {
                throw new ArgumentNullException("renderPass");
            }
            if (insertionKey == null)
            {
                throw new ArgumentNullException("insertionKey");
            }

            lock (staticMutationLock) {
                if (activePasses.Contains(renderPass))
                {
                    throw new InvalidOperationException("Render pass already added.");
                }
                else if (!activePasses.Contains(insertionKey))
                {
                    throw new InvalidOperationException("Insertion key pass not currently added.");
                }
                using (RenderStateBarrier.AcquirePermit()) activePasses.Insert(activePasses.IndexOf(insertionKey), renderPass);
                Logger.Log("Added " + renderPass + ".");
            }
        }
        //private static readonly Dictionary<RenderPass, int> passCountDict = new Dictionary<RenderPass, int>();
        //private static readonly Dictionary<RenderPass, double> passTimeDict = new Dictionary<RenderPass, double>();
        //private static readonly Stopwatch timer = Stopwatch.StartNew();

        unsafe void ILosgapModule.PipelineIterate(ParallelizationProvider parallelizationProvider, long deltaMs)
        {
#if CODE_ANALYSIS // Required because for some reason we can't ignore this one in source. Justification: parallelizationProvider will never be null.
            if (parallelizationProvider == null)
            {
                throw new ArgumentNullException("parallelizationProvider");
            }
#endif
            openWindowCopySpace.Clear();
            for (int i = 0; i < Window.OpenWindows.Count; ++i)
            {
                openWindowCopySpace.Add(Window.OpenWindows[i]);
            }
            foreach (var win in openWindowCopySpace)
            {
                win.HydrateMessagePump();
                if (!win.IsClosed)
                {
                    win.Clear();                                // If check because HydrateMessagePump can close the window
                }
            }

            RenderStateBarrier.FreezeMutations();
            bool singleThreadedModeEnabled = parallelizationProvider.ForceSingleThreadedMode;
            try {
                if (!MtRenderingSupported)
                {
                    parallelizationProvider.ForceSingleThreadedMode = true;
                }
                for (int p = 0; p < activePasses.Count; ++p)
                {
                    RenderPass currentPass = activePasses[p];
                    if (!currentPass.IsEnabled)
                    {
                        continue;
                    }
                    if (!currentPass.IsValid)
                    {
                        Logger.Debug(currentPass + " will be skipped as it not in a valid configuration.");
                        continue;
                    }

                    //var timeBefore = timer.Elapsed;
                    currentPass.OnPrePass();
                    currentPass.Execute(parallelizationProvider);
                    currentPass.OnPostPass();
                    //if (!passCountDict.ContainsKey(currentPass)) {
                    //	passCountDict.Add(currentPass, 0);
                    //	passTimeDict.Add(currentPass, 0d);
                    //}
                    //passTimeDict[currentPass] += (timer.Elapsed - timeBefore).TotalMilliseconds;
                    //if (++passCountDict[currentPass] == 1000) {
                    //	Logger.Log("Pass '" + currentPass + "' avg time = " + (passTimeDict[currentPass] / 1000d) + "ms");
                    //	passCountDict[currentPass] = 0;
                    //	passTimeDict[currentPass] = 0d;
                    //}
                }
            }
            finally {
                parallelizationProvider.ForceSingleThreadedMode = singleThreadedModeEnabled;
                RenderStateBarrier.UnfreezeMutations();
            }
        }