Beispiel #1
0
        protected override void BeforeDelete()
        {
            base.BeforeDelete();

            if (Render is MyRenderComponentPlanet)
            {
                (Render as MyRenderComponentPlanet).CancelAllRequests();
            }

            if (m_planetEnvironmentSectors != null)
            {
                foreach (var sector in m_planetEnvironmentSectors)
                {
                    sector.Value.CloseSector();
                    m_planetSectorsPool.Deallocate(sector.Value);
                }
            }
            if (m_physicsShapes != null)
            {
                foreach (var voxelMap in m_physicsShapes)
                {
                    MySession.Static.VoxelMaps.RemoveVoxelMap(voxelMap.Value);
                    voxelMap.Value.RemoveFromGamePruningStructure();
                }
            }

            MySession.Static.VoxelMaps.RemoveVoxelMap(this);
            Storage.DataProvider.ReleaseHeightMaps();

            m_storage = null;
        }
Beispiel #2
0
        protected override void BeforeDelete()
        {
            base.BeforeDelete();

            if (m_physicsShapes != null)
            {
                foreach (var voxelMap in m_physicsShapes)
                {
                    voxelMap.Value.Close();
                }
            }

            if (Render is MyRenderComponentPlanet)
            {
                (Render as MyRenderComponentPlanet).CancelAllRequests();
            }

            if (m_planetEnvironmentSectors != null)
            {
                foreach (var sector in m_planetEnvironmentSectors)
                {
                    sector.Value.CloseSector();
                    m_planetSectorsPool.Deallocate(sector.Value);
                }
            }

            m_storage = null;
            MySession.Static.VoxelMaps.RemoveVoxelMap(this);
        }
        public void Clear()
        {
            foreach (var entry in m_groups)
            {
                entry.Value.Clear();
                m_listAllocator.Deallocate(entry.Value);
            }
            m_groups.Clear();

            m_totalItemCounter  = 0;
            m_solvedItemCounter = 0;
        }
        protected override void OnComplete()
        {
            base.OnComplete();

            if (MyPrecalcComponent.Loaded && !m_isCancelled)
            {
                Debug.Assert(m_targetPhysics.RunningBatchTask == this);
                m_targetPhysics.OnBatchTaskComplete(m_newShapes);
            }

            foreach (var newShape in m_newShapes.Values)
            {
                if (!newShape.Base.IsZero)
                {
                    newShape.Base.RemoveReference();
                }
            }

            if (m_targetPhysics.RunningBatchTask == this)
            {
                m_targetPhysics.RunningBatchTask = null;
            }
            m_targetPhysics = null;
            CellBatch.Clear();
            m_newShapes.Clear();
            m_isCancelled = false;
            m_instancePool.Deallocate(this);
        }
 private void OnComplete()
 {
     m_args.CompletionCallback(m_args.Cell, m_result);
     m_args   = default(Args);
     m_result = null;
     m_instancePool.Deallocate(this);
 }
        protected override void OnComplete()
        {
            base.OnComplete();

            bool restartWork = false;
            if (MyPrecalcComponent.Loaded && !m_isCancelled && m_args.Storage != null)
            {
                // Update render even if results are not valid. Not updating may result in geometry staying the same for too long.
                if (IsValid)
                    MyRenderProxy.UpdateClipmapCell(m_args.ClipmapId, ref m_metadata, ref m_batches);
                else
                {
                    // recompute the whole things when results are not valid
                    restartWork = true;
                }
            }
            else
                Debug.Assert(m_isCancelled, "Clipmap request collector wont know this job finished!");

            if (!m_isCancelled)
            {
                m_args.RenderWorkTracker.Complete(m_args.WorkId);
            }
            m_batches.Clear();
            if (restartWork)
            {
                Start(m_args);
            }
            else
            {
                m_args = default(Args);
                m_instancePool.Deallocate(this);
            }
        }
Beispiel #7
0
 protected override void OnComplete()
 {
     base.OnComplete();
     if (((MySession.Static != null) == MySession.Static.GetComponent <MyPrecalcComponent>().Loaded) && !this.m_isCancelled)
     {
         this.m_targetPhysics.OnBatchTaskComplete(this.m_newShapes, this.Lod);
     }
     foreach (HkBvCompressedMeshShape shape in this.m_newShapes.Values)
     {
         HkShape shape2 = shape.Base;
         if (!shape2.IsZero)
         {
             shape.Base.RemoveReference();
         }
     }
     if (ReferenceEquals(this.m_targetPhysics.RunningBatchTask[this.Lod], this))
     {
         this.m_targetPhysics.RunningBatchTask[this.Lod] = null;
     }
     this.m_targetPhysics = null;
     this.CellBatch.Clear();
     this.m_newShapes.Clear();
     this.m_isCancelled = false;
     m_instancePool.Deallocate(this);
 }
 private void OnComplete()
 {
     ProfilerShort.Begin("MyOreDetectorComponent - OnComplete");
     m_args.CompletionCallback(m_args.Cell, m_result);
     m_args   = default(Args);
     m_result = null;
     m_instancePool.Deallocate(this);
     ProfilerShort.End();
 }
Beispiel #9
0
        protected override void OnComplete()
        {
            base.OnComplete();
            System.Diagnostics.Debug.Assert(m_clonedShapes.Count > 0);
            if (MyDestructionData.Static != null && MyDestructionData.Static.BlockShapePool != null)
            {
                MyDestructionData.Static.BlockShapePool.EnqueShapes(m_args.DefId, m_clonedShapes);
            }

            m_clonedShapes.Clear();
            m_args.Tracker.Complete(m_args.DefId);
            m_args       = default(Args);
            m_isCanceled = false;
            m_instancePool.Deallocate(this);
        }
        protected override void OnComplete()
        {
            base.OnComplete();

            bool restartWork = false;

            if (MyPrecalcComponent.Loaded && !m_isCancelled && m_args.Storage != null)
            {
                // Update render even if results are not valid. Not updating may result in geometry staying the same for too long.
                MyRenderProxy.UpdateClipmapCell(
                    m_args.ClipmapId,
                    m_args.Cell,
                    m_batches,
                    m_positionOffset,
                    m_positionScale,
                    m_localBoundingBox);
                if (!IsValid)
                {
                    // recompute the whole things when results are not valid
                    restartWork = true;
                }
            }

            if (!m_isCancelled)
            {
                m_args.RenderWorkTracker.Complete(m_args.WorkId);
            }
            m_batches.Clear();
            if (restartWork)
            {
                Start(m_args);
            }
            else
            {
                m_args = default(Args);
                m_instancePool.Deallocate(this);
            }
        }
        protected override void OnComplete()
        {
            base.OnComplete();

            if (MyPrecalcComponent.Loaded && !m_isCancelled)
            {
                m_args.TargetPhysics.OnTaskComplete(m_args.GeometryCell, m_result);
            }

            if (!m_isCancelled)
            {
                m_args.Tracker.Complete(m_args.GeometryCell);
            }

            if (!m_result.Base.IsZero)
            {
                m_result.Base.RemoveReference();
            }

            m_args        = default(Args);
            m_isCancelled = false;
            m_result      = (HkBvCompressedMeshShape)HkShape.Empty;
            m_instancePool.Deallocate(this);
        }
 protected void RemoveTriangle(MyNavigationTriangle tri)
 {
     m_mesh.RemoveFace(tri.Index);
     m_triPool.Deallocate(tri);
 }
 internal static void Release(MySingleInstance instance)
 {
     instance.ReleaseLodProxies();
     m_objectPool.Deallocate(instance);
 }
Beispiel #14
0
        /**
         * Scan sectors arround entities in planet and update them accordingly.
         */
        private void UpdateSectors(bool serial, ref BoundingBoxD box)
        {
            // Prepare sectors for update
            foreach (var sp in m_planetEnvironmentSectors)
            {
                sp.Value.PrepareForUpdate();
            }

            // Find all entities, spawn physics arround ships and players, spawn graphics arround cameras

            ProfilerShort.Begin("Update Sectors");
            MyGamePruningStructure.GetTopMostEntitiesInBox(ref box, m_entities, MyEntityQueryType.Dynamic);

            foreach (var entity in m_entities)
            {
                // entity is MyPlanet || entity is MyVoxelMap || entity is MyEnvironmentItems should all be static
                // If any of that changes keep in mind they must be skipped
                // It is also important to avoid adding physics where there are no clusters, otherwise the entities won't get activated properly.
                if (entity.MarkedForClose || entity.Physics == null || entity.Physics.IsStatic)
                {
                    continue;
                }

                Vector3 position   = entity.PositionComp.GetPosition() - WorldMatrix.Translation;
                double  distanceSq = position.LengthSquared();

                var predictionOffset = ComputePredictionOffset(entity);

                if (CanSpawnFlora && RUN_SECTORS && distanceSq >= Ranges.PLANET_PHYSICS_SCAN_MIN && distanceSq <= Ranges.PLANET_PHYSICS_SCAN_MAX)
                {
                    ProfilerShort.Begin("EntitySpawn");
                    position += predictionOffset;

                    MyPlanetSectorId sectId;
                    GetSectorIdAt(position, out sectId);

                    MyPlanetEnvironmentSector sector;
                    if (!m_planetEnvironmentSectors.TryGetValue(sectId, out sector) || !sector.HasEntity)
                    {
                        ForEachSector(position, SECTOR_PHYSICS_EXTENT + SECTOR_KEEP_INFLATE, SectorPhysicsDelegate);
                    }
                    if ((sector != null || m_planetEnvironmentSectors.TryGetValue(sectId, out sector)) && !sector.ShouldClose)
                    {
                        // Make sure other entities in same sector do not cause new scans.
                        sector.HasEntity = true;
                    }
                    ProfilerShort.End();
                }
            }

            if (CanSpawnFlora && RUN_SECTORS)
            {
                ProfilerShort.Begin("MainCameraSpawn");
                Vector3D position   = MySector.MainCamera.Position - WorldMatrix.Translation;
                double   distanceSq = position.LengthSquared();

                if (distanceSq > Ranges.PLANET_GRAPHICS_SCAN_MIN && distanceSq < Ranges.PLANET_GRAPHICS_SCAN_MAX)
                {
                    ForEachSector(position, SECTOR_LOD1_EXTENT + SECTOR_KEEP_INFLATE, SectorGraphicsDelegate);
                }
                ProfilerShort.End();

                // Remove sectors marked for removal and enqueue sectors with pending operations.

                ProfilerShort.Begin("Recycle Sectors");
                m_sectorsToRemove.Clear();
                foreach (var sp in m_planetEnvironmentSectors)
                {
                    var sector = sp.Value;
                    using (sector.AcquireStatusLock())
                    {
                        sector.EvaluateOperations();

                        if (sector.ShouldClose)
                        {
                            if ((sector.PendingOperations & MyPlanetEnvironmentSector.SERIAL_OPERATIONS_MASK) != 0)
                            {
                                // This will close the sector here if necessary.
                                sector.DoSerialWork(false);
                            }
                            Debug.Assert(sector.IsClosed);
                            m_planetSectorsPool.Deallocate(sector);
                            m_sectorsToRemove.Add(sp.Key);
                        }
                        else if (sector.ParallelPending)
                        {
                            if (!sector.IsQueuedParallel && sector.ParallelPending)
                            {
                                sector.IsQueuedParallel = true;
                                SectorsToWorkParallel.Enqueue(sector);
                            }
                        }
                        else if (sector.SerialPending && !sector.IsQueuedSerial)
                        {
                            SectorsToWorkSerial.Enqueue(sector);
                            sector.IsQueuedSerial = true;
                        }
                    }
                }

                // Remove from the dictionary all the sectors that were closed
                foreach (var sector in m_sectorsToRemove)
                {
                    m_planetEnvironmentSectors.Remove(sector);
                }
                ProfilerShort.End();

                ProfilerShort.Begin("Schedule Tasks");
                // Lastly we start the sectors worker if any work is left in the queue.
                if (!m_sectorsWorking)
                {
                    if (SectorsToWorkParallel.Count > 0)
                    {
                        m_sectorsWorking = true;

                        if (serial)
                        {
                            ParallelWorkCallback();
                            SerialWorkCallback();
                        }
                        else
                        {
                            Parallel.Start(m_parallelWorkDelegate, m_serialWorkDelegate);
                        }
                    }
                    else
                    {
                        SerialWorkCallback();
                    }
                }
                ProfilerShort.End();
            }

            ProfilerShort.End();

            WrapCounters();
        }
        private bool AddCell(Vector3I cellPos)
        {
            MyCellCoord coord = new MyCellCoord(NAVMESH_LOD, cellPos);

            var geometry = m_voxelMap.Storage.Geometry;

            MyVoxelGeometry.CellData data = geometry.GetCell(ref coord);
            if (data == null)
            {
                m_processedCells.Add(ref cellPos);
                m_higherLevelHelper.AddExplored(ref cellPos);
                return(false);
            }

            ulong packedCoord = coord.PackId64();

            List <DebugDrawEdge> debugEdgesList = new List <DebugDrawEdge>();

            m_debugCellEdges[packedCoord] = debugEdgesList;

            MyVoxelPathfinding.CellId cellId = new MyVoxelPathfinding.CellId()
            {
                VoxelMap = m_voxelMap, Pos = cellPos
            };

            MyTrace.Send(TraceWindow.Ai, "Adding cell " + cellPos);

            m_connectionHelper.ClearCell();
            m_vertexMapping.Init(data.VoxelVerticesCount);

            // Prepare list of possibly intersecting cube grids for voxel-grid navmesh intersection testing
            Vector3D     bbMin  = m_voxelMap.PositionLeftBottomCorner + (m_cellSize * (new Vector3D(-0.125) + cellPos));
            Vector3D     bbMax  = m_voxelMap.PositionLeftBottomCorner + (m_cellSize * (Vector3D.One + cellPos));
            BoundingBoxD cellBB = new BoundingBoxD(bbMin, bbMax);

            m_tmpGridList.Clear();
            m_navmeshCoordinator.PrepareVoxelTriangleTests(cellBB, m_tmpGridList);

            Vector3D voxelMapCenter     = m_voxelMap.PositionComp.GetPosition();
            Vector3  centerDisplacement = voxelMapCenter - m_voxelMap.PositionLeftBottomCorner;

            // This is needed for correct edge classification - to tell, whether the edges are inner or outer edges of the cell
            ProfilerShort.Begin("Triangle preprocessing");
            for (int i = 0; i < data.VoxelTrianglesCount; i++)
            {
                short a = data.VoxelTriangles[i].VertexIndex0;
                short b = data.VoxelTriangles[i].VertexIndex1;
                short c = data.VoxelTriangles[i].VertexIndex2;

                Vector3 aPos, bPos, cPos;
                Vector3 vert;
                data.GetUnpackedPosition(a, out vert);
                aPos = vert - centerDisplacement;
                data.GetUnpackedPosition(b, out vert);
                bPos = vert - centerDisplacement;
                data.GetUnpackedPosition(c, out vert);
                cPos = vert - centerDisplacement;

                bool invalidTriangle = false;
                if ((bPos - aPos).LengthSquared() <= MyVoxelConnectionHelper.OUTER_EDGE_EPSILON_SQ)
                {
                    m_vertexMapping.Union(a, b);
                    invalidTriangle = true;
                }
                if ((cPos - aPos).LengthSquared() <= MyVoxelConnectionHelper.OUTER_EDGE_EPSILON_SQ)
                {
                    m_vertexMapping.Union(a, c);
                    invalidTriangle = true;
                }
                if ((cPos - bPos).LengthSquared() <= MyVoxelConnectionHelper.OUTER_EDGE_EPSILON_SQ)
                {
                    m_vertexMapping.Union(b, c);
                    invalidTriangle = true;
                }

                if (invalidTriangle)
                {
                    continue;
                }

                m_connectionHelper.PreprocessInnerEdge(a, b);
                m_connectionHelper.PreprocessInnerEdge(b, c);
                m_connectionHelper.PreprocessInnerEdge(c, a);
            }
            ProfilerShort.End();

            ProfilerShort.Begin("Free face sorting");
            // Ensure that the faces have increasing index numbers
            Mesh.SortFreeFaces();
            ProfilerShort.End();

            m_higherLevelHelper.OpenNewCell(coord);

            ProfilerShort.Begin("Adding triangles");
            for (int i = 0; i < data.VoxelTrianglesCount; i++)
            {
                short a    = data.VoxelTriangles[i].VertexIndex0;
                short b    = data.VoxelTriangles[i].VertexIndex1;
                short c    = data.VoxelTriangles[i].VertexIndex2;
                short setA = (short)m_vertexMapping.Find(a);
                short setB = (short)m_vertexMapping.Find(b);
                short setC = (short)m_vertexMapping.Find(c);

                if (setA == setB || setB == setC || setA == setC)
                {
                    continue;
                }

                Vector3 aPos, bPos, cPos;
                Vector3 vert;
                data.GetUnpackedPosition(setA, out vert);
                aPos = vert - centerDisplacement;
                data.GetUnpackedPosition(setB, out vert);
                bPos = vert - centerDisplacement;
                data.GetUnpackedPosition(setC, out vert);
                cPos = vert - centerDisplacement;

                if (MyFakes.NAVMESH_PRESUMES_DOWNWARD_GRAVITY)
                {
                    Vector3 normal = (cPos - aPos).Cross(bPos - aPos);
                    normal.Normalize();
                    if (normal.Dot(ref Vector3.Up) <= Math.Cos(MathHelper.ToRadians(54.0f)))
                    {
                        continue;
                    }
                }

                Vector3D aTformed = aPos + voxelMapCenter;
                Vector3D bTformed = bPos + voxelMapCenter;
                Vector3D cTformed = cPos + voxelMapCenter;

                bool intersecting = false;
                m_tmpLinkCandidates.Clear();
                m_navmeshCoordinator.TestVoxelNavmeshTriangle(ref aTformed, ref bTformed, ref cTformed, m_tmpGridList, m_tmpLinkCandidates, out intersecting);
                if (intersecting)
                {
                    m_tmpLinkCandidates.Clear();
                    continue;
                }

                if (!m_connectionHelper.IsInnerEdge(a, b))
                {
                    debugEdgesList.Add(new DebugDrawEdge(aTformed, bTformed));
                }
                if (!m_connectionHelper.IsInnerEdge(b, c))
                {
                    debugEdgesList.Add(new DebugDrawEdge(bTformed, cTformed));
                }
                if (!m_connectionHelper.IsInnerEdge(c, a))
                {
                    debugEdgesList.Add(new DebugDrawEdge(cTformed, aTformed));
                }

                int edgeAB   = m_connectionHelper.TryGetAndRemoveEdgeIndex(b, a, ref bPos, ref aPos);
                int edgeBC   = m_connectionHelper.TryGetAndRemoveEdgeIndex(c, b, ref cPos, ref bPos);
                int edgeCA   = m_connectionHelper.TryGetAndRemoveEdgeIndex(a, c, ref aPos, ref cPos);
                int formerAB = edgeAB;
                int formerBC = edgeBC;
                int formerCA = edgeCA;

                ProfilerShort.Begin("AddTriangle");
                var tri = AddTriangle(ref aPos, ref bPos, ref cPos, ref edgeAB, ref edgeBC, ref edgeCA);
                ProfilerShort.End();

                CheckMeshConsistency();

                m_higherLevelHelper.AddTriangle(tri.Index);

                if (formerAB == -1)
                {
                    m_connectionHelper.AddEdgeIndex(a, b, ref aPos, ref bPos, edgeAB);
                }
                if (formerBC == -1)
                {
                    m_connectionHelper.AddEdgeIndex(b, c, ref bPos, ref cPos, edgeBC);
                }
                if (formerCA == -1)
                {
                    m_connectionHelper.AddEdgeIndex(c, a, ref cPos, ref aPos, edgeCA);
                }

                // TODO: Instead of this, just add the tri into a list of tris that want to connect with the link candidates
                //m_navmeshCoordinator.TryAddVoxelNavmeshLinks(tri, cellId, m_tmpLinkCandidates);
                foreach (var candidate in m_tmpLinkCandidates)
                {
                    List <MyNavigationPrimitive> primitives = null;
                    if (!m_tmpCubeLinkCandidates.TryGetValue(candidate, out primitives))
                    {
                        primitives = m_primitiveListPool.Allocate();
                        m_tmpCubeLinkCandidates.Add(candidate, primitives);
                    }

                    primitives.Add(tri);
                }
                m_tmpLinkCandidates.Clear();
            }
            ProfilerShort.End();

            m_tmpGridList.Clear();
            m_connectionHelper.ClearCell();
            m_vertexMapping.Clear();

            Debug.Assert(!m_processedCells.Contains(ref cellPos));
            m_processedCells.Add(ref cellPos);
            m_higherLevelHelper.AddExplored(ref cellPos);

            // Find connected components in the current cell's subgraph of the navigation mesh
            m_higherLevelHelper.ProcessCellComponents();
            m_higherLevelHelper.CloseCell();

            // Create navmesh links using the navmesh coordinator, taking into consideration the high level components
            m_navmeshCoordinator.TryAddVoxelNavmeshLinks2(cellId, m_tmpCubeLinkCandidates);
            m_navmeshCoordinator.UpdateVoxelNavmeshCellHighLevelLinks(cellId);

            foreach (var candidate in m_tmpCubeLinkCandidates)
            {
                candidate.Value.Clear();
                m_primitiveListPool.Deallocate(candidate.Value);
            }
            m_tmpCubeLinkCandidates.Clear();

            return(true);
        }
Beispiel #16
0
 internal void DeallocateFrustum(BoundingFrustumD frustum)
 {
     m_frustumPool.Deallocate(frustum);
 }
Beispiel #17
0
        internal void RecordCommandLists(MyCullQuery processedCullQuery, Queue <CommandList> outCommandLists)
        {
            ProfilerShort.Begin("PrepareWork");

            ProfilerShort.Begin("Init");
            Debug.Assert(m_workList.Count == 0, "Work list not cleared after use!");

            foreach (List <MyRenderCullResultFlat> cullResults in m_passElements)
            {
                cullResults.Clear();
                m_sortListPool.Deallocate(cullResults);
            }
            m_passElements.Clear();
            m_passElements2.Clear();

            for (int renderPassIndex = 0; renderPassIndex < processedCullQuery.Size; ++renderPassIndex)
            {
                if (!MyRender11.DeferredContextsEnabled)
                {
                    processedCullQuery.RenderingPasses[renderPassIndex].SetImmediate(true);
                }

                m_passElements.Add(m_sortListPool.Allocate());
                m_passElements2.Add(null);
            }

            ProfilerShort.BeginNextBlock("Flatten");
            for (int i = 0; i < processedCullQuery.Size; ++i)
            {
                m_affectedQueueIds.SetSize(0);
                var frustumQuery = processedCullQuery.FrustumCullQueries[i];

                for (int renderPassIndex = 0; renderPassIndex < processedCullQuery.Size; renderPassIndex++)
                {
                    if ((processedCullQuery.RenderingPasses[renderPassIndex].ProcessingMask & frustumQuery.Bitmask) > 0)
                    {
                        m_affectedQueueIds.Add(renderPassIndex);
                    }
                }

                var cullProxies = frustumQuery.List;
                var queryType   = frustumQuery.Type;

                foreach (MyCullProxy cullProxy in cullProxies)
                {
                    var renderableProxies = cullProxy.RenderableProxies;
                    if (renderableProxies == null)
                    {
                        continue;
                    }

                    for (int proxyIndex = 0; proxyIndex < renderableProxies.Length; ++proxyIndex)
                    {
                        var flag = renderableProxies[proxyIndex].DrawSubmesh.Flags;
                        if (queryType == MyFrustumEnum.MainFrustum)
                        {
                            if ((flag & MyDrawSubmesh.MySubmeshFlags.Gbuffer) != MyDrawSubmesh.MySubmeshFlags.Gbuffer)
                            {
                                continue;
                            }
                        }
                        else if (queryType == MyFrustumEnum.ShadowCascade || queryType == MyFrustumEnum.ShadowProjection)
                        {
                            if ((flag & MyDrawSubmesh.MySubmeshFlags.Depth) != MyDrawSubmesh.MySubmeshFlags.Depth)
                            {
                                continue;
                            }
                        }

                        MyRenderableProxy renderableProxy = renderableProxies[proxyIndex];
                        ulong             sortKey         = cullProxy.SortingKeys[proxyIndex];

                        for (int queueIndex = 0; queueIndex < m_affectedQueueIds.Count; ++queueIndex)
                        {
                            var queueId = m_affectedQueueIds[queueIndex];
                            var item    = new MyRenderCullResultFlat
                            {
                                SortKey     = sortKey,
                                RenderProxy = renderableProxy,
                            };

                            m_passElements[queueId].Add(item);
                        }
                    }
                }

                // proxy 2
                var list2 = frustumQuery.List2;

                // flatten and sort
                m_flattenedKeys.SetSize(0);
                m_indirectionList.SetSize(0);
                m_location.SetSize(0);

                int indirectionCounter = 0;
                for (int list2Index = 0; list2Index < list2.Count; ++list2Index)
                {
                    for (int sortKeyIndex = 0; sortKeyIndex < list2[list2Index].SortingKeys.Length; sortKeyIndex++)
                    {
                        m_flattenedKeys.Add(list2[list2Index].SortingKeys[sortKeyIndex]);
                        m_indirectionList.Add(indirectionCounter++);
                        m_location.Add(MyTuple.Create(list2Index, sortKeyIndex));
                    }
                }

                MyRenderableProxy_2[] flattenedProxies = null;

                if (indirectionCounter > 0)
                {
                    flattenedProxies = new MyRenderableProxy_2[indirectionCounter];
                }

                m_sortingKeysComparer.Values = m_flattenedKeys;
                m_indirectionList.Sort(0, m_indirectionList.Count, m_sortingKeysComparer);

                if (flattenedProxies != null)
                {
                    for (int e = 0; e < indirectionCounter; e++)
                    {
                        var l = m_location[m_indirectionList[e]];
                        flattenedProxies[e] = list2[l.Item1].Proxies[l.Item2];
                    }
                }

                for (int l = 0; l < m_affectedQueueIds.Count; l++)
                {
                    m_passElements2[m_affectedQueueIds[l]] = flattenedProxies;
                }
            }
            ProfilerShort.BeginNextBlock("Sort");
            foreach (var flatCullResults in m_passElements)
            {
                foreach (MyRenderCullResultFlat element in flatCullResults)
                {
                    List <MyRenderCullResultFlat> sortList;
                    if (m_tmpSortListDictionary.TryGetValue(element.SortKey, out sortList))
                    {
                        sortList.Add(element);
                    }
                    else
                    {
                        sortList = m_sortListPool.Allocate();
                        sortList.Add(element);
                        m_tmpSortListDictionary.Add(element.SortKey, sortList);
                    }
                }
                flatCullResults.Clear();
                foreach (var sortList in m_tmpSortListDictionary.Values)
                {
                    flatCullResults.AddList(sortList);
                    sortList.SetSize(0);
                    m_sortListPool.Deallocate(sortList);
                }
                m_tmpSortListDictionary.Clear();
            }

            int jobsNum = GetRenderingThreadsNum();

            // always amortize this path
            ProfilerShort.BeginNextBlock("WorkAmortization");

            //passElements.RemoveAll(x => x.Count == 0);

            int workSum = 0;

            foreach (var list in m_passElements)
            {
                workSum += list.Count;
            }

            int batchWork = (workSum + jobsNum - 1) / jobsNum;

            Debug.Assert(m_subworks.Count == 0);

            int work = 0;

            for (int passElementIndex = 0; passElementIndex < m_passElements.Count; ++passElementIndex)
            {
                var flatCullResults = m_passElements[passElementIndex];
                if (flatCullResults.Count == 0)
                {
                    MyObjectPoolManager.Deallocate(processedCullQuery.RenderingPasses[passElementIndex]);
                    processedCullQuery.RenderingPasses[passElementIndex] = null;
                    if (m_passElements2[passElementIndex] == null || m_passElements2[passElementIndex].Length == 0)
                    {
                        continue;
                    }
                }

                if (processedCullQuery.RenderingPasses[passElementIndex] == null)
                {
                    continue;
                }

                int passBegin = 0;

                if (m_passElements2[passElementIndex] != null && m_passElements2[passElementIndex].Length > 0)
                {
                    m_subworks.Add(new MyRenderingWorkItem
                    {
                        Pass  = processedCullQuery.RenderingPasses[passElementIndex].Fork(),
                        List2 = m_passElements2[passElementIndex]
                    });
                }

                while (passBegin < flatCullResults.Count)
                {
                    int toTake = Math.Min(flatCullResults.Count - passBegin, batchWork - work);

                    var workItem = new MyRenderingWorkItem
                    {
                        Renderables = flatCullResults,
                        Begin       = passBegin,
                        End         = passBegin + toTake
                    };

                    if (toTake < flatCullResults.Count && workItem.End != workItem.Renderables.Count)
                    {
                        workItem.Pass = processedCullQuery.RenderingPasses[passElementIndex].Fork();
                    }
                    else
                    {
                        workItem.Pass = processedCullQuery.RenderingPasses[passElementIndex];
                        processedCullQuery.RenderingPasses[passElementIndex] = null;    // Consume the pass so it doesn't get cleaned up later with the cull query, but instead with the work item
                    }

                    m_subworks.Add(workItem);

                    passBegin += toTake;
                    work      += toTake;

                    Debug.Assert(work <= batchWork);
                    if (work != batchWork)
                    {
                        continue;
                    }

                    if (MyRender11.DeferredContextsEnabled)
                    {
                        var renderWork = MyObjectPoolManager.Allocate <MyRenderingWorkRecordCommands>();
                        renderWork.Init(MyRenderContextPool.AcquireRC(), m_subworks);
                        m_workList.Add(renderWork);
                    }
                    else
                    {
                        var renderWork = MyObjectPoolManager.Allocate <MyRenderingWorkRecordCommands>();
                        renderWork.Init(m_subworks);
                        m_workList.Add(renderWork);
                    }

                    work = 0;

                    m_subworks.Clear();
                }
            }
            if (m_subworks.Count > 0)
            {
                if (MyRender11.DeferredContextsEnabled)
                {
                    var renderWork = MyObjectPoolManager.Allocate <MyRenderingWorkRecordCommands>();
                    renderWork.Init(MyRenderContextPool.AcquireRC(), m_subworks);
                    m_workList.Add(renderWork);
                }
                else
                {
                    var renderWork = MyObjectPoolManager.Allocate <MyRenderingWorkRecordCommands>();
                    renderWork.Init(m_subworks);
                    m_workList.Add(renderWork);
                }
                m_subworks.Clear();
            }

            ProfilerShort.End();

            ProfilerShort.End();

            DoRecordingWork(outCommandLists);

            foreach (var renderWork in m_workList)
            {
                MyObjectPoolManager.Deallocate(renderWork);
            }
            m_workList.Clear();
        }