Exemple #1
0
        public override void PreCommand(ICommandContext commandContext)
        {
            base.PreCommand(commandContext);

            buildTransaction = MicrothreadLocalDatabases.CreateTransaction(commandContext.GetOutputObjectsGroups());
            MicrothreadLocalDatabases.MountDatabase(buildTransaction);
        }
Exemple #2
0
        protected override void LoadContent()
        {
            // determine the adequate blend state to render the font
            adequateBlendState = Asset.Type.PremultiplyAlpha ? BlendStates.AlphaBlend : BlendStates.NonPremultiplied;

            // Load the texture (but don't use streaming so it will be fully loaded)
            texture = LoadAsset <Texture>(AssetItem.Location, ContentManagerLoaderSettings.StreamingDisabled);
            NotifyTextureLoaded?.Invoke();

            // Update the effect
            MicrothreadLocalDatabases.MountCommonDatabase();
            currentEffect.Parameters.Set(PreviewTextureParameters.Is3D, texture.ViewDimension == TextureDimension.Texture3D);

            // create texture views for cube textures.
            if (texture.ViewDimension == TextureDimension.TextureCube)
            {
                for (int i = 0; i < texture.ArraySize; i++)
                {
                    textureCubeViews[(TextureCubePreviewMode)i] = texture.ToTextureView(new TextureViewDescription {
                        ArraySlice = i, Type = ViewType.ArrayBand
                    });
                }
            }

            textureSourceRegion = new Rectangle(0, 0, TextureWidth, TextureHeight);

            // TODO: Return LDR or HDR depending on texture bits (16bits is most likely HDR)
            RenderingMode = RenderingMode.LDR;
        }
Exemple #3
0
 protected override void PostBuild()
 {
     base.PostBuild();
     if (mergeInCommonDatabase)
     {
         MicrothreadLocalDatabases.AddToSharedGroup(buildStep.OutputObjects);
     }
 }
Exemple #4
0
        /// <inheritdoc />
        protected override void Initialize()
        {
            // Database is needed by effect compiler cache
            MicrothreadLocalDatabases.MountCommonDatabase();

            base.Initialize();

            // TODO: the physics system should not be registered by default here!
            Physics.Simulation.DisableSimulation = true;
        }
Exemple #5
0
        private async Task ProcessPreviewRequestsTask()
        {
            while (IsRunning)
            {
                await Script.NextFrame();

                PreviewRequest request;
                lock (requestLock)
                {
                    request        = previewRequest;
                    previewRequest = null;
                }

                if (request != null)
                {
                    try
                    {
                        MicrothreadLocalDatabases.MountCommonDatabase();

                        Faulted = false;

                        previewScene.Children.Clear();

                        if (SceneSystem.GraphicsCompositor != request.GraphicsCompositor)
                        {
                            SceneSystem.GraphicsCompositor?.Dispose();
                            SceneSystem.GraphicsCompositor = request.GraphicsCompositor;
                        }

                        if (request.Scene != null)
                        {
                            previewScene.Children.Add(request.Scene);
                        }

                        request.RequestCompletion.SetResult(ResultStatus.Successful);
                    }
                    catch (Exception e)
                    {
                        // end the thumbnail build task
                        request.Logger.Error("An exception occurred while loading the preview scene.", e);
                        request.RequestCompletion.SetResult(ResultStatus.Failed);
                    }
                }

                if (previewScene.Children.Count != 0)
                {
                    var handler = UpdateSceneCallback;
                    if (handler != null)
                    {
                        var renderingMode = handler();
                    }
                }
            }
        }
Exemple #6
0
        /// <summary>
        /// Load an asset to the preview.
        /// </summary>
        /// <typeparam name="TAssetType">The type of the asset to load</typeparam>
        /// <param name="url">The path to the asset to load</param>
        /// <param name="settings">The settings. If null, fallback to <see cref="ContentManagerLoaderSettings.Default" />.</param>
        /// <returns>The loaded asset</returns>
        public TAssetType LoadAsset <TAssetType>(string url, ContentManagerLoaderSettings settings = null) where TAssetType : class
        {
            TAssetType result = null;

            try
            {
                // This method can be invoked both from a script and from a regular task. In the second case, it will use the out-of-microthread database which need to be locked.
                // TODO: Ensure this method is always called from the preview game (it is not at least when a property is modified, currently), so we don't need to lock. Note: should be the case now, assume it is after GDC!
                if (Scheduler.CurrentMicroThread == null)
                {
                    Monitor.Enter(AssetBuilderService.OutOfMicrothreadDatabaseLock);
                }

                MicrothreadLocalDatabases.MountDatabase(OutputObjects.Yield());

                try
                {
                    result = Game.Content.Load <TAssetType>(url, settings);
                }
                finally
                {
                    if (Scheduler.CurrentMicroThread == null)
                    {
                        MicrothreadLocalDatabases.UnmountDatabase();
                    }
                }
            }
            catch (Exception e)
            {
                Builder.Logger.Error($"An exception was triggered when trying to load the entity [{url}] for the preview of asset item [{AssetItem.Location}].", e);
            }
            finally
            {
                if (Scheduler.CurrentMicroThread == null)
                {
                    Monitor.Exit(AssetBuilderService.OutOfMicrothreadDatabaseLock);
                }
            }
            return(result);
        }
Exemple #7
0
        public async Task <IDisposable> MountInCurrentMicroThread()
        {
            if (isDisposed)
            {
                throw new ObjectDisposedException(nameof(GameStudioDatabase));
            }
            if (Scheduler.CurrentMicroThread == null)
            {
                throw new InvalidOperationException("The database can only be mounted in a micro-thread.");
            }

            var lockObject = await databaseLock.LockAsync();

            // Return immediately if the database was disposed when waiting for the lock
            if (isDisposed)
            {
                return(lockObject);
            }

            MicrothreadLocalDatabases.MountDatabase(database.Yield());
            return(lockObject);
        }
Exemple #8
0
        public override void PostCommand(ICommandContext commandContext, ResultStatus status)
        {
            base.PostCommand(commandContext, status);

            if (status == ResultStatus.Successful)
            {
                // Save list of newly changed URLs in CommandResult.OutputObjects
                foreach (var entry in buildTransaction.GetTransactionIdMap())
                {
                    commandContext.RegisterOutput(entry.Key, entry.Value);
                }

                // Note: In case of remote process, the remote process will save the index map.
                // Alternative would be to not save it and just forward results to the master builder who would commit results locally.
                // Not sure which is the best.
                //
                // Anyway, current approach should be OK for now since the index map is "process-safe" (as long as we load new values as necessary).
                //contentIndexMap.Save();
            }

            MicrothreadLocalDatabases.UnmountDatabase();
        }
        public GameStudioBuilderService(SessionViewModel sessionViewModel, GameSettingsProviderService settingsProvider, string buildDirectory, bool createDebugTools = true)
            : base(buildDirectory)
        {
            this.createDebugTools = createDebugTools;
            if (createDebugTools)
            {
                assetBuilderServiceDebugPage   = EditorDebugTools.CreateLogDebugPage(GlobalLogger.GetLogger("AssetBuilderService"), "AssetBuilderService");
                effectCompilerServiceDebugPage = EditorDebugTools.CreateLogDebugPage(GlobalLogger.GetLogger("EffectCompilerCache"), "EffectCompilerCache");
            }

            SessionViewModel = sessionViewModel ?? throw new ArgumentNullException(nameof(sessionViewModel));

            var shaderImporter   = new XenkoShaderImporter();
            var shaderBuildSteps = shaderImporter.CreateSystemShaderBuildSteps(sessionViewModel);

            shaderBuildSteps.StepProcessed += ShaderBuildStepsStepProcessed;
            PushBuildUnit(new PrecompiledAssetBuildUnit(AssetBuildUnitIdentifier.Default, shaderBuildSteps, true));

            Database = new GameStudioDatabase(this, settingsProvider);

            const string shaderBundleUrl = "/binary/editor/EditorShadersD3D11.bundle";

            if (VirtualFileSystem.FileExists(shaderBundleUrl))
            {
                Builder.ObjectDatabase.BundleBackend.LoadBundleFromUrl("EditorShadersD3D11", Builder.ObjectDatabase.ContentIndexMap, shaderBundleUrl, true).Wait();
            }

            // Use a shared database for our shader system
            // TODO: Shaders compiled on main thread won't actually be visible to MicroThread build engine (contentIndexMap are separate).
            // It will still work and cache because EffectCompilerCache caches not only at the index map level, but also at the database level.
            // Later, we probably want to have a GetSharedDatabase() allowing us to mutate it (or merging our results back with IndexFileCommand.AddToSharedGroup()),
            // so that database created with MountDatabase also have all the newest shaders.
            taskScheduler = new EffectPriorityScheduler(ThreadPriority.BelowNormal, Math.Max(1, Environment.ProcessorCount / 2));
            TaskSchedulerSelector taskSchedulerSelector = (mixinTree, compilerParameters) => taskScheduler.GetOrCreatePriorityGroup(compilerParameters?.TaskPriority ?? 0);

            effectCompiler = (EffectCompilerBase)EffectSystem.CreateEffectCompiler(MicrothreadLocalDatabases.GetSharedDatabase(), taskSchedulerSelector: taskSchedulerSelector);

            StartPushNotificationsTask();
        }
Exemple #10
0
        /// <inheritdoc />
        protected override async Task LoadContent()
        {
            await base.LoadContent();

            // mount the common database in this micro-thread to have access to the built effects, etc.
            MicrothreadLocalDatabases.MountCommonDatabase();

            // Create fallback effect to use when material is still loading
            fallbackColorMaterial = Material.New(GraphicsDevice, new MaterialDescriptor
            {
                Attributes =
                {
                    Diffuse      = new MaterialDiffuseMapFeature(new ComputeTextureColor()),
                    DiffuseModel = new MaterialDiffuseLambertModelFeature()
                }
            });

            fallbackTextureMaterial = Material.New(GraphicsDevice, new MaterialDescriptor
            {
                Attributes =
                {
                    Diffuse           = new MaterialDiffuseMapFeature(new ComputeTextureColor {
                        FallbackValue = null
                    }),                                                                                        // Do not use fallback value, we want a DiffuseMap
                    DiffuseModel      = new MaterialDiffuseLambertModelFeature()
                }
            });

            // Listen to all Renderer Initialized to plug dynamic effect compilation
            RenderContext.GetShared(Services).RendererInitialized += SceneGameRendererInitialized;
            // Update the marker render target setter viewport
            //OnClientSizeChanged(this, EventArgs.Empty);

            // Initialize the services
            var initialized = new List <IEditorGameService>();

            foreach (var service in EditorServices.OrderByDependency())
            {
                // Check that the current service dependencies have been initialized
                foreach (var dependency in service.Dependencies)
                {
                    if (!initialized.Any(x => dependency.IsInstanceOfType(x)))
                    {
                        throw new InvalidOperationException($"The service [{service.GetType().Name}] requires a service of type [{dependency.Name}] to be initialized first.");
                    }
                }
                if (await service.InitializeService(this))
                {
                    initialized.Add(service);
                }

                var mouseService = service as EditorGameMouseServiceBase;
                mouseService?.RegisterMouseServices(EditorServices);
            }

            // TODO: Maybe define this scene default graphics compositor as an asset?
            var defaultGraphicsCompositor = GraphicsCompositorHelper.CreateDefault(true, EditorGraphicsCompositorHelper.EditorForwardShadingEffect);

            // Add UI (engine doesn't depend on it)
            defaultGraphicsCompositor.RenderFeatures.Add(new UIRenderFeature
            {
                RenderStageSelectors =
                {
                    new SimpleGroupToRenderStageSelector
                    {
                        RenderStage = defaultGraphicsCompositor.RenderStages.First(x => x.Name == "Transparent"),
                        EffectName  = "Test",
                        RenderGroup = GizmoBase.DefaultGroupMask
                    }
                }
            });

            // Make the game switch to this graphics compositor
            UpdateGraphicsCompositor(defaultGraphicsCompositor);

            gameContentLoadedTaskSource.SetResult(true);
        }
Exemple #11
0
        private BuildResultCode BuildSlave()
        {
            // Mount build path
            ((FileSystemProvider)VirtualFileSystem.ApplicationData).ChangeBasePath(builderOptions.BuildDirectory);

            VirtualFileSystem.CreateDirectory(VirtualFileSystem.ApplicationDatabasePath);

            // Open WCF channel with master builder
            var namedPipeBinding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
            {
                SendTimeout = TimeSpan.FromSeconds(300.0), MaxReceivedMessageSize = int.MaxValue
            };
            var processBuilderRemote = ChannelFactory <IProcessBuilderRemote> .CreateChannel(namedPipeBinding, new EndpointAddress(builderOptions.SlavePipe));

            try
            {
                RegisterRemoteLogger(processBuilderRemote);

                // Make sure to laod all assemblies containing serializers
                // TODO: Review how costly it is to do so, and possibily find a way to restrict what needs to be loaded (i.e. only app plugins?)
                foreach (var assemblyLocation in processBuilderRemote.GetAssemblyContainerLoadedAssemblies())
                {
                    AssemblyContainer.Default.LoadAssemblyFromPath(assemblyLocation, builderOptions.Logger);
                }

                // Create scheduler
                var scheduler = new Scheduler();

                var status = ResultStatus.NotProcessed;

                // Schedule command
                string buildPath = builderOptions.BuildDirectory;

                Builder.OpenObjectDatabase(buildPath, VirtualFileSystem.ApplicationDatabaseIndexName);

                var         logger      = builderOptions.Logger;
                MicroThread microthread = scheduler.Add(async() =>
                {
                    // Deserialize command and parameters
                    Command command = processBuilderRemote.GetCommandToExecute();

                    // Run command
                    var inputHashes    = FileVersionTracker.GetDefault();
                    var builderContext = new BuilderContext(inputHashes, null);

                    var commandContext = new RemoteCommandContext(processBuilderRemote, command, builderContext, logger);
                    MicrothreadLocalDatabases.MountDatabase(commandContext.GetOutputObjectsGroups());
                    command.PreCommand(commandContext);
                    status = await command.DoCommand(commandContext);
                    command.PostCommand(commandContext, status);

                    // Returns result to master builder
                    processBuilderRemote.RegisterResult(commandContext.ResultEntry);
                });

                while (true)
                {
                    scheduler.Run();

                    // Exit loop if no more micro threads
                    lock (scheduler.MicroThreads)
                    {
                        if (!scheduler.MicroThreads.Any())
                        {
                            break;
                        }
                    }

                    Thread.Sleep(0);
                }

                // Rethrow any exception that happened in microthread
                if (microthread.Exception != null)
                {
                    builderOptions.Logger.Fatal(microthread.Exception.ToString());
                    return(BuildResultCode.BuildError);
                }

                if (status == ResultStatus.Successful || status == ResultStatus.NotTriggeredWasSuccessful)
                {
                    return(BuildResultCode.Successful);
                }

                return(BuildResultCode.BuildError);
            }
            finally
            {
                // Close WCF channel
                // ReSharper disable SuspiciousTypeConversion.Global
                ((IClientChannel)processBuilderRemote).Close();
                // ReSharper restore SuspiciousTypeConversion.Global
            }
        }
Exemple #12
0
        private BuildResultCode BuildSlave()
        {
            // Mount build path
            ((FileSystemProvider)VirtualFileSystem.ApplicationData).ChangeBasePath(builderOptions.BuildDirectory);

            VirtualFileSystem.CreateDirectory(VirtualFileSystem.ApplicationDatabasePath);

            // Open ServiceWire Client Channel
            using (var client = new NpClient <IProcessBuilderRemote>(new NpEndPoint(builderOptions.SlavePipe), new StrideServiceWireSerializer()))
            {
                RegisterRemoteLogger(client);

                // Make sure to laod all assemblies containing serializers
                // TODO: Review how costly it is to do so, and possibily find a way to restrict what needs to be loaded (i.e. only app plugins?)
                foreach (var assemblyLocation in client.Proxy.GetAssemblyContainerLoadedAssemblies())
                {
                    AssemblyContainer.Default.LoadAssemblyFromPath(assemblyLocation, builderOptions.Logger);
                }

                // Create scheduler
                var scheduler = new Scheduler();

                var status = ResultStatus.NotProcessed;

                // Schedule command
                string buildPath = builderOptions.BuildDirectory;

                Builder.OpenObjectDatabase(buildPath, VirtualFileSystem.ApplicationDatabaseIndexName);

                var         logger      = builderOptions.Logger;
                MicroThread microthread = scheduler.Add(async() =>
                {
                    // Deserialize command and parameters
                    Command command = client.Proxy.GetCommandToExecute();

                    // Run command
                    var inputHashes    = FileVersionTracker.GetDefault();
                    var builderContext = new BuilderContext(inputHashes, null);

                    var commandContext = new RemoteCommandContext(client.Proxy, command, builderContext, logger);
                    MicrothreadLocalDatabases.MountDatabase(commandContext.GetOutputObjectsGroups());
                    command.PreCommand(commandContext);
                    status = await command.DoCommand(commandContext);
                    command.PostCommand(commandContext, status);

                    // Returns result to master builder
                    client.Proxy.RegisterResult(commandContext.ResultEntry);
                });

                while (true)
                {
                    scheduler.Run();

                    // Exit loop if no more micro threads
                    lock (scheduler.MicroThreads)
                    {
                        if (!scheduler.MicroThreads.Any())
                        {
                            break;
                        }
                    }

                    Thread.Sleep(0);
                }

                // Rethrow any exception that happened in microthread
                if (microthread.Exception != null)
                {
                    builderOptions.Logger.Fatal(microthread.Exception.ToString());
                    return(BuildResultCode.BuildError);
                }

                if (status == ResultStatus.Successful || status == ResultStatus.NotTriggeredWasSuccessful)
                {
                    return(BuildResultCode.Successful);
                }

                return(BuildResultCode.BuildError);
            }
        }
        private async Task Execute()
        {
            MicrothreadLocalDatabases.MountCommonDatabase();

            while (game.IsRunning)
            {
                await game.Script.NextFrame();

                if (IsActive)
                {
                    // TODO: code largely duplicated in EditorGameMaterialHighlightService. Factorize!

                    var screenSize = new Vector2(game.GraphicsDevice.Presenter.BackBuffer.Width, game.GraphicsDevice.Presenter.BackBuffer.Height);

                    if (game.Input.IsMouseButtonPressed(MouseButton.Left))
                    {
                        mouseMoveAccumulator = Vector2.Zero;
                    }
                    mouseMoveAccumulator += new Vector2(Math.Abs(game.Input.MouseDelta.X * screenSize.X), Math.Abs(game.Input.MouseDelta.Y * screenSize.Y));

                    if (IsMouseAvailable && game.Input.IsMouseButtonReleased(MouseButton.Left) && !game.Input.IsMouseButtonDown(MouseButton.Right))
                    {
                        if (mouseMoveAccumulator.Length() >= TransformationGizmo.TransformationStartPixelThreshold)
                        {
                            continue;
                        }

                        var addToSelection = game.Input.IsKeyDown(Keys.LeftCtrl) || game.Input.IsKeyDown(Keys.RightCtrl);

                        var entityUnderMouse = Gizmos.GetContentEntityUnderMouse();

                        if (entityUnderMouse == null)
                        {
                            var entityPicked = Pick();
                            entityUnderMouse = entityPicked.Entity;
                        }

                        // Ctrl + click on an empty area: do nothing
                        if (entityUnderMouse == null && addToSelection)
                        {
                            continue;
                        }

                        // Click on an empty area: clear selection
                        if (entityUnderMouse == null)
                        {
                            Clear();
                        }
                        // Click on an entity: select this entity
                        else if (!addToSelection)
                        {
                            Set(entityUnderMouse);
                        }
                        // Ctrl + click on an already selected entity: unselect this entity
                        else if (Contains(entityUnderMouse))
                        {
                            Remove(entityUnderMouse);
                        }
                        // Ctrl + click on an entity: add this entity to the selection
                        else
                        {
                            Add(entityUnderMouse);
                        }
                    }
                }
            }
        }
        protected override Task <bool> Initialize(EditorServiceGame editorGame)
        {
            game        = (EntityHierarchyEditorGame)editorGame;
            editorScene = game.EditorScene;

            var transformMainGizmoRenderStage        = new RenderStage("TransformGizmoOpaque", "Main");
            var transformTransparentGizmoRenderStage = new RenderStage("TransformGizmoTransparent", "Main")
            {
                SortMode = new BackToFrontSortMode()
            };

            game.EditorSceneSystem.GraphicsCompositor.RenderStages.Add(transformMainGizmoRenderStage);
            game.EditorSceneSystem.GraphicsCompositor.RenderStages.Add(transformTransparentGizmoRenderStage);

            var meshRenderFeature = game.EditorSceneSystem.GraphicsCompositor.RenderFeatures.OfType <MeshRenderFeature>().First();

            // Reset all stages for TransformationGrizmoGroup
            meshRenderFeature.RenderStageSelectors.Add(new SimpleGroupToRenderStageSelector
            {
                RenderGroup = TransformationGizmo.TransformationGizmoGroupMask,
            });
            meshRenderFeature.RenderStageSelectors.Add(new MeshTransparentRenderStageSelector
            {
                EffectName             = EditorGraphicsCompositorHelper.EditorForwardShadingEffect,
                RenderGroup            = TransformationGizmo.TransformationGizmoGroupMask,
                OpaqueRenderStage      = transformMainGizmoRenderStage,
                TransparentRenderStage = transformTransparentGizmoRenderStage,
            });
            meshRenderFeature.PipelineProcessors.Add(new MeshPipelineProcessor {
                TransparentRenderStage = transformTransparentGizmoRenderStage
            });

            var editorCompositor = (EditorTopLevelCompositor)game.EditorSceneSystem.GraphicsCompositor.Game;

            editorCompositor.PostGizmoCompositors.Add(new ClearRenderer {
                ClearFlags = ClearRendererFlags.DepthOnly
            });
            editorCompositor.PostGizmoCompositors.Add(new SingleStageRenderer {
                RenderStage = transformMainGizmoRenderStage, Name = "Transform Opaque Gizmos"
            });
            editorCompositor.PostGizmoCompositors.Add(new SingleStageRenderer {
                RenderStage = transformTransparentGizmoRenderStage, Name = "Transform Transparent Gizmos"
            });

            TranslationGizmo = new TranslationGizmo();
            RotationGizmo    = new RotationGizmo();
            ScaleGizmo       = new ScaleGizmo();
            TranslationGizmo.TransformationEnded += OnGizmoTransformationFinished;
            ScaleGizmo.TransformationEnded       += OnGizmoTransformationFinished;
            RotationGizmo.TransformationEnded    += OnGizmoTransformationFinished;

            transformationGizmos.Add(TranslationGizmo);
            transformationGizmos.Add(RotationGizmo);
            transformationGizmos.Add(ScaleGizmo);

            Services.Get <IEditorGameEntitySelectionService>().SelectionUpdated += UpdateModifiedEntitiesList;

            // Initialize and add the Gizmo entities to the gizmo scene
            MicrothreadLocalDatabases.MountCommonDatabase();

            // initialize the gizmo
            foreach (var gizmo in transformationGizmos)
            {
                gizmo.Initialize(game.Services, editorScene);
            }

            // Deactivate all transformation gizmo by default
            foreach (var gizmo in transformationGizmos)
            {
                gizmo.IsEnabled = false;
            }

            // set the default active transformation gizmo
            ActiveTransformationGizmo = TranslationGizmo;

            // Start update script (with priority 1 so that it happens after UpdateModifiedEntitiesList is called -- which usually happens from a EditorGameComtroller.PostAction() which has a default priority 0)
            game.Script.AddTask(Update, 1);
            return(Task.FromResult(true));
        }
Exemple #15
0
        /// <summary>
        /// The micro-thread in charge of processing the thumbnail build requests and creating the thumbnails.
        /// </summary>
        private ResultStatus ProcessThumbnailRequests(ThumbnailBuildRequest request)
        {
            var status = ResultStatus.Successful;

            // Global lock so that only one rendering happens at the same time
            lock (lockObject)
            {
                try
                {
                    lock (AssetBuilderService.OutOfMicrothreadDatabaseLock)
                    {
                        MicrothreadLocalDatabases.MountCommonDatabase();

                        // set the master output
                        var renderTarget = GraphicsContext.Allocator.GetTemporaryTexture2D(request.Size.X, request.Size.Y, request.ColorSpace == ColorSpace.Linear ? PixelFormat.R8G8B8A8_UNorm_SRgb : PixelFormat.R8G8B8A8_UNorm, TextureFlags.ShaderResource | TextureFlags.RenderTarget);
                        var depthStencil = GraphicsContext.Allocator.GetTemporaryTexture2D(request.Size.X, request.Size.Y, PixelFormat.D24_UNorm_S8_UInt, TextureFlags.DepthStencil);

                        try
                        {
                            // Fake presenter
                            // TODO GRAPHICS REFACTOR: Try to remove that
                            GraphicsDevice.Presenter = new RenderTargetGraphicsPresenter(GraphicsDevice, renderTarget, depthStencil.ViewFormat);

                            // Always clear the state of the GraphicsDevice to make sure a scene doesn't start with a wrong setup
                            GraphicsCommandList.ClearState();

                            // Setup the color space when rendering a thumbnail
                            GraphicsDevice.ColorSpace = request.ColorSpace;

                            // render the thumbnail
                            thumbnailScene.Children.Add(request.Scene);

                            // Store the graphics compositor to use, so we can dispose it when disposing this ThumbnailGenerator
                            thumbnailGraphicsCompositors.Add(request.GraphicsCompositor);
                            sceneSystem.GraphicsCompositor = request.GraphicsCompositor;

                            // Render once to setup render processors
                            // TODO GRAPHICS REFACTOR: Should not require two rendering
                            GraphicsContext.ResourceGroupAllocator.Reset(GraphicsContext.CommandList);
                            gameSystems.Draw(nullGameTime);

                            // Draw
                            gameSystems.Update(nullGameTime);
                            GraphicsContext.ResourceGroupAllocator.Reset(GraphicsContext.CommandList);
                            gameSystems.Draw(nullGameTime);

                            // write the thumbnail to the file
                            using (var thumbnailImage = renderTarget.GetDataAsImage(GraphicsCommandList))
                                using (var outputImageStream = request.FileProvider.OpenStream(request.Url, VirtualFileMode.Create, VirtualFileAccess.Write))
                                {
                                    request.PostProcessThumbnail?.Invoke(thumbnailImage);

                                    ThumbnailBuildHelper.ApplyThumbnailStatus(thumbnailImage, request.DependencyBuildStatus);

                                    thumbnailImage.Save(outputImageStream, ImageFileType.Png);

                                    request.Logger.Info($"Thumbnail creation successful [{request.Url}] to ({thumbnailImage.Description.Width}x{thumbnailImage.Description.Height},{thumbnailImage.Description.Format})");
                                }
                        }
                        finally
                        {
                            // Cleanup the scene
                            thumbnailScene.Children.Clear();
                            sceneSystem.GraphicsCompositor = null;

                            GraphicsContext.Allocator.ReleaseReference(depthStencil);
                            GraphicsContext.Allocator.ReleaseReference(renderTarget);
                        }

                        MicrothreadLocalDatabases.UnmountDatabase();
                    }
                }
                catch (Exception e)
                {
                    status = ResultStatus.Failed;
                    request.Logger.Error("An exception occurred while processing thumbnail request.", e);
                }
            }

            return(status);
        }
Exemple #16
0
        private BuildResultCode BuildSlave()
        {
            // Mount build path
            ((FileSystemProvider)VirtualFileSystem.ApplicationData).ChangeBasePath(builderOptions.BuildDirectory);

            PrepareDatabases();

            VirtualFileSystem.CreateDirectory(VirtualFileSystem.ApplicationDatabasePath);

            // Open WCF channel with master builder
            var namedPipeBinding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
            {
                SendTimeout = TimeSpan.FromSeconds(300.0)
            };
            var processBuilderRemote = ChannelFactory <IProcessBuilderRemote> .CreateChannel(namedPipeBinding, new EndpointAddress(builderOptions.SlavePipe));

            try
            {
                RegisterRemoteLogger(processBuilderRemote);

                // Create scheduler
                var scheduler = new Scheduler();

                var status = ResultStatus.NotProcessed;

                // Schedule command
                string buildPath    = builderOptions.BuildDirectory;
                string buildProfile = builderOptions.BuildProfile;

                Builder.OpenObjectDatabase(buildPath, VirtualFileSystem.ApplicationDatabaseIndexName);

                var         logger      = builderOptions.Logger;
                MicroThread microthread = scheduler.Add(async() =>
                {
                    // Deserialize command and parameters
                    Command command = processBuilderRemote.GetCommandToExecute();
                    BuildParameterCollection parameters = processBuilderRemote.GetBuildParameters();

                    // Run command
                    var inputHashes    = FileVersionTracker.GetDefault();
                    var builderContext = new BuilderContext(buildPath, buildProfile, inputHashes, parameters, 0, null);

                    var commandContext = new RemoteCommandContext(processBuilderRemote, command, builderContext, logger);
                    MicrothreadLocalDatabases.MountDatabase(commandContext.GetOutputObjectsGroups());
                    command.PreCommand(commandContext);
                    status = await command.DoCommand(commandContext);
                    command.PostCommand(commandContext, status);

                    // Returns result to master builder
                    processBuilderRemote.RegisterResult(commandContext.ResultEntry);
                });

                while (true)
                {
                    scheduler.Run();

                    // Exit loop if no more micro threads
                    lock (scheduler.MicroThreads)
                    {
                        if (!scheduler.MicroThreads.Any())
                        {
                            break;
                        }
                    }

                    Thread.Sleep(0);
                }

                // Rethrow any exception that happened in microthread
                if (microthread.Exception != null)
                {
                    builderOptions.Logger.Fatal(microthread.Exception.ToString());
                    return(BuildResultCode.BuildError);
                }

                if (status == ResultStatus.Successful || status == ResultStatus.NotTriggeredWasSuccessful)
                {
                    return(BuildResultCode.Successful);
                }

                return(BuildResultCode.BuildError);
            }
            finally
            {
                // Close WCF channel
                // ReSharper disable SuspiciousTypeConversion.Global
                ((IClientChannel)processBuilderRemote).Close();
                // ReSharper restore SuspiciousTypeConversion.Global
            }
        }