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); }
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); }