Beispiel #1
0
        public BitmapRenderBlock(Dictionary <string, Texture> textureDictionary, string texturePath, ChunkPool pool,
                                 RenderSettings renderSettings, IGraphicsApi <TImage> graphics, int chunkSize, int chunksPerDimension,
                                 ExecutionDataflowBlockOptions options)
        {
            int tileSize = chunksPerDimension * chunkSize;

            graphics.SetPoolDimensions(tileSize, tileSize);
            int chunkRenderedCounter = 0;
            ThreadLocal <RendererCombi <TImage> > renderCombi = new ThreadLocal <RendererCombi <TImage> >(() =>
                                                                                                          new RendererCombi <TImage>(textureDictionary, texturePath, renderSettings, graphics));

            Block = new TransformBlock <IEnumerable <ChunkAndData>, ImageInfo <TImage> >(chunkAndData =>
            {
                var b = graphics.GetPooledImage();
                {
                    var chunkList     = chunkAndData.ToList();
                    var firstX        = chunkList.First().C.X;
                    var firstZ        = chunkList.First().C.Z;
                    var chunkRenderer = renderCombi.Value.ChunkRenderer;

                    foreach (var chunk in chunkList)
                    {
                        var x = chunk.C.X % chunksPerDimension;
                        var z = chunk.C.Z % chunksPerDimension;
                        if (x < 0)
                        {
                            x += chunksPerDimension;
                        }
                        if (z < 0)
                        {
                            z += chunksPerDimension;
                        }
                        chunkRenderer.RenderChunk(b, chunk.C, x * chunkSize, z * chunkSize);

                        pool?.Return(chunk.C);
                    }


                    var fx = CoordHelpers.GetGroupedCoordinate(firstX, chunksPerDimension);
                    var fz = CoordHelpers.GetGroupedCoordinate(firstZ, chunksPerDimension);

                    Interlocked.Increment(ref processedCount);
                    Interlocked.Add(ref chunkRenderedCounter, chunkList.Count);

                    if (chunkRenderedCounter >= 32)
                    {
                        var v = chunkRenderedCounter;
                        ChunksRendered?.Invoke(this, new ChunksRenderedEventArgs(v));
                        Interlocked.Add(ref chunkRenderedCounter, -v);
                    }

                    return(new ImageInfo <TImage>()
                    {
                        Image = b, X = fx, Z = fz, Cd = chunkList.SelectMany(x => x.Cd)
                    });
                }
            }, options);
        }
Beispiel #2
0
        public void RenderInitialLevel()
        {
            World.ChunkPool         = new ChunkPool();
            graphics.DefaultQuality = FileQuality;


            var keysByXZ = AllWorldKeys.Where(c => c.X <= XMax && c.X >= XMin && c.Z <= ZMax && c.Z >= ZMin)
                           .GroupBy(x => x.XZ);

            Console.Write("Grouping subchunks... ");
            List <GroupedChunkSubKeys> chunkKeys = new List <GroupedChunkSubKeys>();

            foreach (var chunkGroup in keysByXZ)
            {
                chunkKeys.Add(new GroupedChunkSubKeys(chunkGroup));
            }

            Console.WriteLine(chunkKeys.Count);

            var t = Math.Max(1, this.RenderSettings.MaxNumberOfThreads);

            var tsave = FileFormat == "webp" ? t : 2;

            var getOptions = new ExecutionDataflowBlockOptions()
            {
                BoundedCapacity = 2 * t, EnsureOrdered = false, MaxDegreeOfParallelism = 1
            };
            var bitmapOptions = new ExecutionDataflowBlockOptions()
            {
                BoundedCapacity = 2 * t, EnsureOrdered = false, MaxDegreeOfParallelism = t
            };
            var saveOptions = new ExecutionDataflowBlockOptions()
            {
                BoundedCapacity = 2 * t, EnsureOrdered = false, MaxDegreeOfParallelism = tsave
            };
            var dbOptions = new ExecutionDataflowBlockOptions()
            {
                BoundedCapacity = 2 * t, EnsureOrdered = false, MaxDegreeOfParallelism = 1
            };
            var groupedToTiles = chunkKeys.GroupBy(x => x.Subchunks.First().Value.GetXZGroup(ChunksPerDimension))
                                 .ToList();

            Console.WriteLine($"Grouped by {ChunksPerDimension} to {groupedToTiles.Count} tiles");
            var average = groupedToTiles.Average(x => x.Count());

            Console.WriteLine($"Average of {average:0.0} chunks per tile");

            var getDataBlock = new GetDataBlock(World, renderedSubchunks, getOptions, ForceOverwrite);
            //var createChunkBlock = new CreateDataBlock(World, chunkCreatorOptions);
            //var bitmapBlock = new BitmapRenderBlock<TImage>(TextureDictionary, TexturePath, World.ChunkPool, RenderSettings, graphics, ChunkSize, ChunksPerDimension, bitmapOptions);

            var createAndRender = new CreateChunkAndRenderBlock <TImage>(World, TextureDictionary, TexturePath, RenderSettings, graphics, ChunkSize, ChunksPerDimension, bitmapOptions);

            var saveBitmapBlock = new SaveBitmapBlock <TImage>(isUpdate ? pathToMapUpdate : pathToMap, NewInitialZoomLevel, FileFormat, saveOptions, graphics);

            var batchBlock = new BatchBlock <IEnumerable <SubChunkData> >(128, new GroupingDataflowBlockOptions()
            {
                BoundedCapacity = 128 * 8, EnsureOrdered = false
            });

            // Todo, put in own class
            var inserts = 0;
            var updates = 0;
            var r       = new Random();
            var dbBLock = new ActionBlock <IEnumerable <IEnumerable <SubChunkData> > >(data =>
            {
                if (data == null)
                {
                    return;
                }

                var datas = data.Where(x => x != null).SelectMany(x => x).ToList();
                try
                {
                    /*
                     * if (r.Next(100) == 0)
                     * {
                     *  throw new ArgumentOutOfRangeException("Test Error in dbBLock");
                     * }*/

                    var toInsert = datas.Where(x => x.FoundInDb == false)
                                   .Select(x => new Checksum {
                        Crc32 = x.Crc32, LevelDbKey = x.Key, Profile = Profile
                    }).ToList();

                    if (toInsert.Count > 0)
                    {
                        db.BulkInsert(toInsert);
                        inserts += toInsert.Count;
                    }

                    var toUpdate = datas.Where(x => x.FoundInDb).Select(x => new Checksum()
                    {
                        Id = x.ForeignDbId, Crc32 = x.Crc32, LevelDbKey = x.Key, Profile = Profile
                    }).ToList();
                    if (toUpdate.Count > 0)
                    {
                        db.BulkUpdate(toUpdate);
                        updates += toUpdate.Count;
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error in CreateChunkAndRenderBlock: " + ex.Message);
                }
            }, dbOptions);

            createAndRender.ChunksRendered += (sender, args) => ChunksRendered?.Invoke(sender, args);

            getDataBlock.Block.LinkTo(createAndRender.Block, new DataflowLinkOptions()
            {
                PropagateCompletion = true,
            });
            createAndRender.Block.LinkTo(saveBitmapBlock.Block, new DataflowLinkOptions()
            {
                PropagateCompletion = true
            });
            saveBitmapBlock.Block.LinkTo(batchBlock, new DataflowLinkOptions()
            {
                PropagateCompletion = true
            });
            batchBlock.LinkTo(dbBLock, new DataflowLinkOptions {
                PropagateCompletion = true
            });
            //saveBitmapBlock.Block.LinkTo(dbBLock, new DataflowLinkOptions() {PropagateCompletion = true});

            int postCount = 0;

            foreach (var groupedToTile in groupedToTiles)
            {
                if (getDataBlock.Block.Post(groupedToTile))
                {
                    postCount++;
                    continue;
                }

                postCount++;
                getDataBlock.Block.SendAsync(groupedToTile).Wait();
                if (postCount > 1000)
                {
                    postCount = 0;
                    Console.WriteLine($"\nQueue Stat: GetData {getDataBlock.InputCount} Render {createAndRender.InputCount} Save {saveBitmapBlock.InputCount} Db {dbBLock.InputCount}");
                }
            }

            Console.WriteLine("Post complete");

            getDataBlock.Block.Complete();
            while (!dbBLock.Completion.Wait(1000))
            {
                Console.WriteLine($"\nQueue Stat: GetData {getDataBlock.InputCount} Render {createAndRender.InputCount} Save {saveBitmapBlock.InputCount} Db {dbBLock.InputCount}");
            }
            Console.WriteLine("DbUpdate complete");


            Console.WriteLine($"\n{inserts}, {updates}");
            Console.WriteLine($"\n{getDataBlock.ProcessedCount} {createAndRender.ProcessedCount}  {saveBitmapBlock.ProcessedCount}");
        }
        public CreateChunkAndRenderBlock(
            World world,
            Dictionary <string, Texture> textureDictionary,
            string texturePath,
            RenderSettings renderSettings,
            IGraphicsApi <TImage> graphics,
            int chunkSize, int chunksPerDimension,
            ExecutionDataflowBlockOptions options)
        {
            int tileSize = chunksPerDimension * chunkSize;

            graphics.SetPoolDimensions(tileSize, tileSize);
            int chunkRenderedCounter = 0;
            var renderCombiPool      = new GenericPool <RendererCombi <TImage> >(() => new RendererCombi <TImage>(textureDictionary, texturePath, renderSettings, graphics));

            Block = new TransformBlock <IEnumerable <ChunkData>, ImageInfo <TImage> >(chunkDatas =>
            {
                RendererCombi <TImage> chunkRenderer = null;
                try
                {
                    var b = graphics.GetPooledImage(); // pooled
                    //var b = graphics.CreateEmptyImage(tileSize, tileSize);

                    chunkRenderer = renderCombiPool.Get();
                    var firstX    = -1;
                    var firstZ    = -1;

                    var count         = 0;
                    var chunkDataList = chunkDatas.ToList();
                    foreach (var chunkData in chunkDataList)
                    {
                        var chunk = world.GetChunk(chunkData.X, chunkData.Z, chunkData);

                        if (firstX == -1)
                        {
                            firstX = chunkData.X;
                        }
                        if (firstZ == -1)
                        {
                            firstZ = chunkData.Z;
                        }

                        var x = chunk.X % chunksPerDimension;
                        var z = chunk.Z % chunksPerDimension;
                        if (x < 0)
                        {
                            x += chunksPerDimension;
                        }
                        if (z < 0)
                        {
                            z += chunksPerDimension;
                        }
                        chunkRenderer.ChunkRenderer.RenderChunk(b, chunk, x * chunkSize, z * chunkSize);

                        world.ChunkPool?.Return(chunk);
                        count++;
                    }


                    var fx = CoordHelpers.GetGroupedCoordinate(firstX, chunksPerDimension);
                    var fz = CoordHelpers.GetGroupedCoordinate(firstZ, chunksPerDimension);

                    Interlocked.Increment(ref processedCount);
                    Interlocked.Add(ref chunkRenderedCounter, count);

                    if (chunkRenderedCounter >= 128)
                    {
                        var v = chunkRenderedCounter;
                        ChunksRendered?.Invoke(this, new ChunksRenderedEventArgs(v));
                        Interlocked.Add(ref chunkRenderedCounter, -v);
                    }

                    /*if (r.Next(100) == 0)
                     * {
                     *  throw new ArgumentOutOfRangeException("Test Error in CreateChunkAndRender");
                     * }*/



                    return(new ImageInfo <TImage>()
                    {
                        Image = b,
                        X = fx,
                        Z = fz,
                        Cd = chunkDataList.SelectMany(x => x.SubChunks)
                    });
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error in CreateChunkAndRenderBlock: " + ex.Message);
                    return(null);
                }
                finally
                {
                    if (chunkRenderer != null)
                    {
                        renderCombiPool.Return(chunkRenderer);
                    }
                }
            }, options);
        }