void CreateRenderGraph() { Dependency.Complete(); #if RENDERING_FORCE_DIRECT Assert.IsTrue(false, "Obsolete script define RENDERING_FORCE_DIRECT enabled. Use the RenderGraphConfig singleton to configure a render graph"); #endif if (!HasSingleton <RenderGraphConfig>()) { Entity eConfig = GetSingletonEntity <DisplayInfo>(); EntityManager.AddComponentData <RenderGraphConfig>(eConfig, RenderGraphConfig.Default); } RenderGraphConfig config = GetSingleton <RenderGraphConfig>(); if (!config.Equals(currentConfig) || eMainViewNode == Entity.Null) { RenderDebug.LogAlways("RenderGraphConfig changed, building a new render graph!"); DestroyRenderGraph(); // we should run the bgfx system here once, so textures are cleaned up and ready for re-use currentConfig = config; // we only build a default graph if there are no existing nodes - otherwise assume they are already built eMainViewNode = BuildRenderGraph(); CreateScreenToWorldChain(RenderPassType.Opaque, ScreenToWorldId.MainCamera); CreateScreenToWorldChain(RenderPassType.Sprites, ScreenToWorldId.Sprites); CreateScreenToWorldChain(RenderPassType.UI, ScreenToWorldId.UILayer); } // build light nodes for lights that have no node associated - need to do this always BuildAllLightNodes(eMainViewNode); }
protected override void OnUpdate() { if (!SceneService.AreStartupScenesLoaded(World)) { return; } #if DEBUG var countEntsStart = GetNumEntities(); #endif Entity eMainView = FindMainViewNode(); if (eMainView == Entity.Null) { // we only build a default graph if there are no existing nodes - otherwise assume they are already built RenderDebug.Log("Auto building default render graph"); eMainView = BuildDefaultRenderGraph(1920, 1080); } // build light nodes for lights that have no node associated BuildAllLightNodes(eMainView); #if DEBUG var countEntsEnd = GetNumEntities(); if (countEntsEnd != countEntsStart) { RenderDebug.LogFormatAlways("Render graph builder added entities (was {0}, now {1})", countEntsStart, countEntsEnd); } #endif //Disable Render graph builder system. We need to create it only once Enabled = false; }
public static unsafe bool SubmitTransientAlloc(RendererBGFXInstance *sys, bgfx.TransientIndexBuffer *tib, bgfx.TransientVertexBuffer *tvb, int nvertices, int nindices, bgfx.VertexLayout *layout) { if (!bgfx.alloc_transient_buffers(tvb, layout, (uint)nvertices, tib, (uint)nindices)) { #if DEBUG // TODO: throw or ignore draw? throw new InvalidOperationException("Out of transient bgfx memory!"); #else RenderDebug.LogFormat("Warning: Out of transient bgfx memory! Skipping draw call."); return(false); #endif } return(true); }
void BuildAllLightNodes(Entity eNodeOutput) { Assert.IsTrue(EntityManager.HasComponent <RenderNode>(eNodeOutput)); // go through all lights and create nodes Entities.WithoutBurst().WithStructuralChanges().ForEach((Entity eLight, ref Light l, ref ShadowmappedLight sl) => { if (sl.shadowMapRenderNode == Entity.Null) { // need a node Entity eNode = CreateNodeEntity(); sl.shadowMapRenderNode = eNode; EntityManager.AddComponent <RenderNode>(eNode); if (EntityManager.HasComponent <CascadeShadowmappedLight>(eLight)) { // need four passes in node for (int i = 0; i < 4; i++) { Entity ePass = EntityManager.CreateEntity(); AddShadowMapPass(eNode, ePass, eLight, i, sl.shadowMapResolution); } } else { Entity ePass = eNode; //why not stick everything on the same entity AddShadowMapPass(eNode, ePass, eLight, -1, sl.shadowMapResolution); } EntityManager.AddComponentData(eNode, new RenderNodeShadowMap { lightsource = eLight }); LinkNodes(eNodeOutput, eNode); RenderDebug.LogFormat("Build shadow map node {0}*{0}, input to {1}", sl.shadowMapResolution, eNodeOutput); World.TinyEnvironment().SetEntityName(eNode, "Auto generated: Shadow Map"); } // allocate the texture if needed if (sl.shadowMap == Entity.Null) { AddRenderToShadowMapForNode(sl.shadowMapRenderNode, sl.shadowMapResolution); var rtt = EntityManager.GetComponentData <RenderNodeTexture>(sl.shadowMapRenderNode); sl.shadowMap = rtt.depthTexture; Assert.IsTrue(sl.shadowMap != Entity.Null); } }).Run(); }
protected override void OnUpdate() { var bgfxinst = World.GetExistingSystem <RendererBGFXSystem>().InstancePointer(); if (!bgfxinst->m_initialized) { return; } // setup bgfx side Entities.WithoutBurst().ForEach((Entity e, ref RenderPass pass) => { if (pass.viewId == 0xffff) { RenderDebug.LogFormat("Render pass entity {0} on render node entity {1} is not referenced by the render graph. It should be deleted.", e, pass.inNode); Assert.IsTrue(false); return; } bool rtt = EntityManager.HasComponent <FramebufferBGFX>(pass.inNode); if (rtt) { pass.passFlags = RenderPassFlags.RenderToTexture; } else { pass.passFlags = 0; } // those could be more shared ... (that is, do all passes really need a copy of view & projection?) unsafe { fixed(float4x4 * viewp = &pass.viewTransform, projp = &pass.projectionTransform) { if (bgfxinst->m_homogeneousDepth && bgfxinst->m_originBottomLeft) // gl style { bgfx.set_view_transform(pass.viewId, viewp, projp); pass.passFlags &= ~RenderPassFlags.FlipCulling; } else // dx style { bool yflip = !bgfxinst->m_originBottomLeft && rtt; float4x4 adjustedProjection = RendererBGFXStatic.AdjustProjection(ref pass.projectionTransform, !bgfxinst->m_homogeneousDepth, yflip); bgfx.set_view_transform(pass.viewId, viewp, &adjustedProjection); if (yflip) { pass.passFlags |= RenderPassFlags.FlipCulling; } else { pass.passFlags &= ~RenderPassFlags.FlipCulling; } } // make a viewProjection pass.viewProjectionTransform = math.mul(pass.projectionTransform, pass.viewTransform); } } bgfx.set_view_mode(pass.viewId, (bgfx.ViewMode)pass.sorting); bgfx.set_view_rect(pass.viewId, pass.viewport.x, pass.viewport.y, pass.viewport.w, pass.viewport.h); bgfx.set_view_scissor(pass.viewId, pass.scissor.x, pass.scissor.y, pass.scissor.w, pass.scissor.h); bgfx.set_view_clear(pass.viewId, (ushort)pass.clearFlags, pass.clearRGBA, pass.clearDepth, pass.clearStencil); if (rtt) { var rttbgfx = EntityManager.GetComponentData <FramebufferBGFX>(pass.inNode); bgfx.set_view_frame_buffer(pass.viewId, rttbgfx.handle); } else { bgfx.set_view_frame_buffer(pass.viewId, new bgfx.FrameBufferHandle { idx = 0xffff }); } // touch it? needed? bgfx.touch(pass.viewId); }).Run(); }
protected override void OnUpdate() { var bgfxsys = World.GetExistingSystem <RendererBGFXSystem>(); if (!bgfxsys.Initialized) { return; } // make sure passes have viewid, transform, scissor rect and view rect set // reset alreadyAdded state // we expect < 100 or so passes, so the below code does not need to be crazy great Entities.ForEach((ref RenderNode rnode) => { rnode.alreadyAdded = false; }); Entities.ForEach((ref RenderPass pass) => { pass.viewId = 0xffff; }); // there SHOULD not be any passes around that are not referenced by the graph... // get all nodes, sort (bgfx issues in-order per view. a better api could use the render graph to issue without gpu // barriers where possible) // sort into eval order, assign pass viewId ushort nextViewId = 0; Entities.WithAll <RenderNodePrimarySurface>().ForEach((Entity eNode) => { RecAddPasses(eNode, ref nextViewId); }); Entities.WithAll <RenderPassAutoSizeToNode>().ForEach((Entity e, ref RenderPass pass) => { if (EntityManager.HasComponent <RenderNodePrimarySurface>(pass.inNode)) { var di = World.TinyEnvironment().GetConfigData <DisplayInfo>(); pass.viewport.x = 0; pass.viewport.y = 0; pass.viewport.w = (ushort)di.width; pass.viewport.h = (ushort)di.height; return; } if (EntityManager.HasComponent <RenderNodeTexture>(pass.inNode)) { var texRef = EntityManager.GetComponentData <RenderNodeTexture>(pass.inNode); pass.viewport = texRef.rect; } // TODO: add others like cubemap }); // auto update passes that are matched with a camera Entities.ForEach((Entity e, ref RenderPass pass, ref RenderPassUpdateFromCamera fromCam) => { Entity eCam = fromCam.camera; CameraMatrices camData = EntityManager.GetComponentData <CameraMatrices>(eCam); pass.viewTransform = camData.view; pass.projectionTransform = camData.projection; if (EntityManager.HasComponent <Frustum>(eCam)) { if (EntityManager.HasComponent <Frustum>(e)) { EntityManager.SetComponentData(e, EntityManager.GetComponentData <Frustum>(eCam)); } } else { if (EntityManager.HasComponent <Frustum>(e)) { EntityManager.SetComponentData(e, new Frustum()); } } }); // auto update passes that are matched with a light Entities.ForEach((Entity e, ref RenderPass pass, ref RenderPassUpdateFromLight fromLight) => { Entity eLight = fromLight.light; LightMatrices lightData = EntityManager.GetComponentData <LightMatrices>(eLight); pass.viewTransform = lightData.view; pass.projectionTransform = lightData.projection; if (EntityManager.HasComponent <Frustum>(eLight)) { if (EntityManager.HasComponent <Frustum>(e)) { EntityManager.SetComponentData(e, EntityManager.GetComponentData <Frustum>(eLight)); } } else { if (EntityManager.HasComponent <Frustum>(e)) { EntityManager.SetComponentData(e, new Frustum()); } } }); // set up extra pass data Entities.ForEach((Entity e, ref RenderPass pass) => { if (pass.viewId == 0xffff) { RenderDebug.LogFormat("Render pass entity {0} on render node entity {1} is not referenced by the render graph. It should be deleted.", e, pass.inNode); Assert.IsTrue(false); return; } bool rtt = EntityManager.HasComponent <FramebufferBGFX>(pass.inNode); // those could be more shared ... (that is, do all passes really need a copy of view & projection?) unsafe { fixed(float4x4 * viewp = &pass.viewTransform, projp = &pass.projectionTransform) { if (bgfxsys.m_homogeneousDepth && bgfxsys.m_originBottomLeft) // gl style { bgfx.set_view_transform(pass.viewId, viewp, projp); pass.flipCulling = 0; } else // dx style { bool yflip = !bgfxsys.m_originBottomLeft && rtt; float4x4 adjustedProjection = RendererBGFXSystem.AdjustProjection(ref pass.projectionTransform, !bgfxsys.m_homogeneousDepth, yflip); bgfx.set_view_transform(pass.viewId, viewp, &adjustedProjection); pass.flipCulling = yflip ? (byte)3 : (byte)0; } } } bgfx.set_view_mode(pass.viewId, (bgfx.ViewMode)pass.sorting); bgfx.set_view_rect(pass.viewId, pass.viewport.x, pass.viewport.y, pass.viewport.w, pass.viewport.h); bgfx.set_view_scissor(pass.viewId, pass.scissor.x, pass.scissor.y, pass.scissor.w, pass.scissor.h); bgfx.set_view_clear(pass.viewId, (ushort)pass.clearFlags, pass.clearRGBA, pass.clearDepth, pass.clearStencil); if (rtt) { var rttbgfx = EntityManager.GetComponentData <FramebufferBGFX>(pass.inNode); bgfx.set_view_frame_buffer(pass.viewId, rttbgfx.handle); } else { bgfx.set_view_frame_buffer(pass.viewId, new bgfx.FrameBufferHandle { idx = 0xffff }); } // touch it? needed? bgfx.touch(pass.viewId); }); }
protected override void OnUpdate() { if (!SceneService.AreStartupScenesLoaded(World)) { return; } #if DEBUG var countEntsStart = GetNumEntities(); #endif // gather all passes var q = GetEntityQuery(ComponentType.ReadOnly <RenderPass>()); m_allPasses = q.ToEntityArray(Allocator.TempJob); // go through lit renderers and assign lighting setup to them // create light // TEMP HACK var q2 = GetEntityQuery(ComponentType.ReadOnly <LightingBGFX>()); Entity eLighting = Entity.Null; if (q2.CalculateEntityCount() == 0) { eLighting = EntityManager.CreateEntity(); EntityManager.AddComponentData(eLighting, new LightingBGFX()); // add both ways lookup lighting setup <-> light var b1 = EntityManager.AddBuffer <LightToBGFXLightingSetup>(eLighting); Entities.WithAll <Light>().ForEach((Entity e) => { b1.Add(new LightToBGFXLightingSetup { e = e }); }); Entities.WithAll <Light>().ForEach((Entity e) => { var b = EntityManager.AddBuffer <LightToBGFXLightingSetup>(e); b.Add(new LightToBGFXLightingSetup { e = eLighting }); }); } else { var a = q2.ToEntityArray(Allocator.TempJob); Assert.IsTrue(a.Length == 1); eLighting = a[0]; a.Dispose(); } Entities.WithNone <LightingRef>().ForEach((Entity e, ref MeshRenderer rlmr, ref LitMeshReference meshRef) => { OptionalSetSharedComponent(e, new LightingRef { e = eLighting }); }); // EOH m_buildGroups = new NativeHashMap <BuildGroup, Entity>(256, Allocator.TempJob); // find existing groups and add them to builder Entities.WithAll <RenderGroup>().ForEach((Entity e, ref BuildGroup bg) => { m_buildGroups.Add(bg, e); }); // go through all known render types, and assign groups to them // assign groups to all renderers Entities.WithNone <RenderToPasses>().ForEach((Entity e, ref MeshRenderer rlmr) => { bool isTransparent = false; if (EntityManager.HasComponent <SimpleMeshReference>(e)) { if (EntityManager.HasComponent <SimpleMaterial>(rlmr.material)) { isTransparent = EntityManager.GetComponentData <SimpleMaterial>(rlmr.material).transparent; } else if (EntityManager.HasComponent <SimpleMaterialBGFX>(rlmr.material)) { var matBGFX = EntityManager.GetComponentData <SimpleMaterialBGFX>(rlmr.material); isTransparent = (matBGFX.state & (ulong)bgfx.StateFlags.WriteZ) != (ulong)bgfx.StateFlags.WriteZ; } } else if (EntityManager.HasComponent <LitMeshReference>(e)) { if (EntityManager.HasComponent <LitMaterial>(rlmr.material)) { isTransparent = EntityManager.GetComponentData <LitMaterial>(rlmr.material).transparent; } else if (EntityManager.HasComponent <LitMaterialBGFX>(rlmr.material)) { var matBGFX = EntityManager.GetComponentData <LitMaterialBGFX>(rlmr.material); isTransparent = (matBGFX.state & (ulong)bgfx.StateFlags.WriteZ) != (ulong)bgfx.StateFlags.WriteZ; } } CameraMask cameraMask = new CameraMask { mask = ulong.MaxValue }; if (EntityManager.HasComponent <CameraMask>(e)) { cameraMask = EntityManager.GetComponentData <CameraMask>(e); } ShadowMask shadowMask = new ShadowMask { mask = ulong.MaxValue }; if (EntityManager.HasComponent <ShadowMask>(e)) { shadowMask = EntityManager.GetComponentData <ShadowMask>(e); } Entity eGroup; if (isTransparent) { eGroup = FindOrCreateRenderGroup(new BuildGroup { passTypes = RenderPassType.Transparent, cameraMask = cameraMask, shadowMask = shadowMask }); } else { eGroup = FindOrCreateRenderGroup(new BuildGroup { passTypes = RenderPassType.Opaque | RenderPassType.ZOnly | RenderPassType.ShadowMap, cameraMask = cameraMask, shadowMask = shadowMask }); } OptionalSetSharedComponent(e, new RenderToPasses { e = eGroup }); }); Entities.WithNone <RenderToPasses>().ForEach((Entity e, ref GizmoLight rlgmr) => { ShadowMask shadowMask = new ShadowMask { mask = ulong.MaxValue }; CameraMask cameraMask = new CameraMask { mask = 0 }; Entity eGroup = FindOrCreateRenderGroup(new BuildGroup { passTypes = RenderPassType.Transparent, cameraMask = cameraMask, shadowMask = shadowMask }); OptionalSetSharedComponent(e, new RenderToPasses { e = eGroup }); }); m_buildGroups.Dispose(); m_allPasses.Dispose(); // TODO: remove any passes that are not referenced by anything #if DEBUG var countEntsEnd = GetNumEntities(); if (countEntsEnd != countEntsStart) { RenderDebug.LogFormatAlways("Render graph builder added entities (was {0}, now {1})", countEntsStart, countEntsEnd); } #endif }
protected void BuildAllLightNodes(Entity eNodeOutput) { Assert.IsTrue(EntityManager.HasComponent <RenderNode>(eNodeOutput)); // go through all lights and create nodes Entities.ForEach((Entity eLight, ref Light l, ref ShadowmappedLight sl) => { if (sl.shadowMapRenderNode == Entity.Null) { // need a node, with a pass Entity eNode = CreateNodeEntity(); EntityManager.AddComponent <RenderNode>(eNode); Entity ePass = eNode; //why not stick everything on the same entity! EntityManager.CreateEntity(); EntityManager.AddComponentData(ePass, new RenderPass { inNode = eNode, sorting = RenderPassSort.Unsorted, projectionTransform = float4x4.identity, viewTransform = float4x4.identity, passType = RenderPassType.ShadowMap, viewId = 0xffff, scissor = new RenderPassRect { x = 0, y = 0, w = 0, h = 0 }, viewport = new RenderPassRect { x = 0, y = 0, w = (ushort)sl.shadowMapResolution, h = (ushort)sl.shadowMapResolution }, #if SAFARI_WEBGL_WORKAROUND clearFlags = RenderPassClear.Depth | RenderPassClear.Color, #else clearFlags = RenderPassClear.Depth, #endif clearRGBA = 0, clearDepth = 1, clearStencil = 0 }); EntityManager.AddComponentData(ePass, new RenderPassUpdateFromLight { light = eLight }); EntityManager.AddComponentData(eNode, new RenderNodeShadowMap { lightsource = eLight, }); sl.shadowMapRenderNode = eNode; EntityManager.GetBuffer <RenderPassRef>(eNode).Add(new RenderPassRef { e = ePass }); LinkNodes(eNodeOutput, eNode); RenderDebug.LogFormat("Build shadow map node {0}*{0}, input to {1}", sl.shadowMapResolution, eNodeOutput); World.TinyEnvironment().SetEntityName(eNode, "Auto generated: Shadow Map"); } if (sl.shadowMap == Entity.Null) { AddRenderToShadowMapForNode(sl.shadowMapRenderNode, sl.shadowMapResolution, sl.shadowMapResolution); var rtt = EntityManager.GetComponentData <RenderNodeTexture>(sl.shadowMapRenderNode); sl.shadowMap = rtt.depthTexture; Assert.IsTrue(sl.shadowMap != Entity.Null); } }); }