Exemple #1
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 #2
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();
        }
Exemple #3
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);
        }