summaryrefslogtreecommitdiff
path: root/Runtime/Camera/RenderLoops/RenderLoopPrivate.cpp
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-08-14 22:50:43 +0800
committerchai <chaifix@163.com>2019-08-14 22:50:43 +0800
commit15740faf9fe9fe4be08965098bbf2947e096aeeb (patch)
treea730ec236656cc8cab5b13f088adfaed6bb218fb /Runtime/Camera/RenderLoops/RenderLoopPrivate.cpp
+Unity Runtime codeHEADmaster
Diffstat (limited to 'Runtime/Camera/RenderLoops/RenderLoopPrivate.cpp')
-rw-r--r--Runtime/Camera/RenderLoops/RenderLoopPrivate.cpp469
1 files changed, 469 insertions, 0 deletions
diff --git a/Runtime/Camera/RenderLoops/RenderLoopPrivate.cpp b/Runtime/Camera/RenderLoops/RenderLoopPrivate.cpp
new file mode 100644
index 0000000..823c8fa
--- /dev/null
+++ b/Runtime/Camera/RenderLoops/RenderLoopPrivate.cpp
@@ -0,0 +1,469 @@
+#include "UnityPrefix.h"
+#include "RenderLoopPrivate.h"
+#include "RenderLoop.h"
+#include "Runtime/Camera/UnityScene.h"
+#include "Runtime/Camera/Camera.h"
+#include "Runtime/Camera/ShadowCulling.h"
+#include "Runtime/Camera/RenderSettings.h"
+#include "Runtime/Camera/ImageFilters.h"
+#include "Runtime/Camera/CameraUtil.h"
+#include "Runtime/Graphics/Transform.h"
+#include "Runtime/Camera/BaseRenderer.h"
+#include "Runtime/Shaders/Material.h"
+#include "Runtime/Camera/Renderqueue.h"
+#include "Runtime/Graphics/RenderTexture.h"
+#include "Runtime/Shaders/GraphicsCaps.h"
+#include "Runtime/GfxDevice/GfxDevice.h"
+#include "Runtime/Misc/BuildSettings.h"
+#include "Runtime/Profiler/Profiler.h"
+#include "Runtime/Profiler/ExternalGraphicsProfiler.h"
+#include "Runtime/GfxDevice/GfxDeviceConfigure.h"
+#include "Runtime/Shaders/Shader.h"
+#include "External/shaderlab/Library/intshader.h"
+#include "Runtime/Graphics/RenderBufferManager.h"
+#include "External/shaderlab/Library/shaderlab.h"
+#include "ReplacementRenderLoop.h"
+
+#if UNITY_EDITOR
+ #include "Editor/Src/EditorUserBuildSettings.h"
+#endif
+
+PROFILER_INFORMATION(gRenderPrepareObjects, "Render.Prepare", kProfilerRender)
+PROFILER_INFORMATION(gRenderOpaque, "Render.OpaqueGeometry", kProfilerRender)
+PROFILER_INFORMATION(gRenderTransparent, "Render.TransparentGeometry", kProfilerRender)
+PROFILER_INFORMATION(gPrePassFwdDepthTex, "RenderPrePass.FwdObjectsIntoDepth", kProfilerRender)
+PROFILER_INFORMATION(gPrePassFwdDepthNormalsTex, "RenderPrePass.FwdObjectsIntoDepthNormals", kProfilerRender)
+PROFILER_INFORMATION(gCameraResolveProfile, "Camera.AAResolve", kProfilerRender)
+
+
+namespace ShaderLab { void ClearGrabPassFrameState (); } // pass.cpp
+
+
+struct RenderLoop {
+public:
+ RenderLoop (Camera& camera);
+ ~RenderLoop ();
+
+ void PrepareFrame (bool dontRenderRenderables, bool renderingShaderReplace);
+
+public:
+ RenderLoopContext m_Context;
+ ShadowCullData m_ShadowCullData;
+ RenderObjectDataContainer m_Objects[kPartCount];
+ ImageFilters m_ImageFilters;
+
+ enum { kMaxCreatedTempBuffers = 8 };
+ RenderTexture* m_TempBuffers[kMaxCreatedTempBuffers];
+ int m_TempBufferCount;
+};
+
+
+RenderLoop* CreateRenderLoop (Camera& camera)
+{
+ return new RenderLoop(camera);
+}
+
+void DeleteRenderLoop (RenderLoop* loop)
+{
+ delete loop;
+}
+
+ImageFilters& GetRenderLoopImageFilters (RenderLoop& loop)
+{
+ return loop.m_ImageFilters;
+}
+
+
+RenderLoop::RenderLoop(Camera& camera)
+{
+ m_Context.m_Camera = &camera;
+ m_Context.m_RenderLoop = this;
+
+ for (int i = 0; i < kMaxCreatedTempBuffers; ++i) {
+ m_TempBuffers[i] = NULL;
+ }
+ m_TempBufferCount = 0;
+}
+
+RenderLoop::~RenderLoop()
+{
+ Assert (m_TempBufferCount == 0);
+}
+
+inline float MultiplyPointZ (const Matrix4x4f& m, const Vector3f& v)
+{
+ return m.m_Data[2] * v.x + m.m_Data[6] * v.y + m.m_Data[10] * v.z + m.m_Data[14];
+}
+
+// Both distances become smaller (more negative) when moving forward from the camera.
+// outDistanceForSort is for sorting only, and it can be square of the actual distance, and so on.
+// outDistnaceAlongView is projection of the center along camera's view.
+static void EvaluateObjectDepth (const RenderLoopContext& ctx, const TransformInfo& info, float& outDistanceForSort, float& outDistanceAlongView)
+{
+ Vector3f center = info.worldAABB.GetCenter();
+ if (ctx.m_SortOrthographic)
+ {
+ const float d = MultiplyPointZ (ctx.m_CurCameraMatrix, center);
+ outDistanceForSort = d;
+ outDistanceAlongView = d;
+ }
+ else
+ {
+ outDistanceAlongView = MultiplyPointZ (ctx.m_CurCameraMatrix, center);
+ center -= ctx.m_CurCameraPos;
+ outDistanceForSort = -SqrMagnitude(center);
+ }
+
+ // A distance of NaN can cause inconsistent sorting results, if input order is inconsistent.
+ Assert(IsFinite(outDistanceForSort));
+ Assert(IsFinite(outDistanceAlongView));
+}
+
+
+void RenderLoop::PrepareFrame (bool dontRenderRenderables, bool renderingShaderReplace)
+{
+ Camera& camera = *m_Context.m_Camera;
+ m_Context.m_CurCameraMatrix = camera.GetWorldToCameraMatrix();
+ m_Context.m_CurCameraPos = camera.GetComponent(Transform).GetPosition();
+ m_Context.m_CameraViewport = camera.GetRenderRectangle();
+ switch (camera.GetSortMode())
+ {
+ case Camera::kSortPerspective: m_Context.m_SortOrthographic = false; break;
+ case Camera::kSortOrthographic: m_Context.m_SortOrthographic = true; break;
+ default: m_Context.m_SortOrthographic = camera.GetOrthographic(); break;
+ }
+ m_Context.m_DontRenderRenderables = dontRenderRenderables;
+ m_Context.m_RenderingShaderReplace = renderingShaderReplace;
+
+ for (int i = 0; i < kPartCount; ++i)
+ m_Objects[i].resize_uninitialized(0);
+
+ #if DEBUGMODE
+ for (int i = 0; i < kMaxCreatedTempBuffers; ++i) {
+ Assert (m_TempBuffers[i] == NULL);
+ }
+ #endif
+ m_TempBufferCount = 0;
+}
+
+
+static RenderTexture* ResolveScreenToTextureIfNeeded (RenderLoop& loop, bool forceIntoRT, bool beforeOpaqueImageFx)
+{
+ // If we use screen to composite image effects, resolve screen into the render texture now
+ bool usingScreenToComposite = loop.m_ImageFilters.HasImageFilter() && loop.m_Context.m_Camera->GetUsesScreenForCompositing(forceIntoRT);
+ RenderTexture* rt = NULL;
+ if (usingScreenToComposite)
+ {
+ // Do a screen to RT resolve here.
+ rt = beforeOpaqueImageFx ? loop.m_ImageFilters.GetTargetBeforeOpaque () : loop.m_ImageFilters.GetTargetAfterOpaque (forceIntoRT, usingScreenToComposite);
+ if (!rt)
+ return NULL;
+
+ PROFILER_AUTO_GFX(gCameraResolveProfile, loop.m_Context.m_Camera)
+ GPU_AUTO_SECTION(kGPUSectionPostProcess);
+
+ // We should insert proper discard/clear/... on backbuffer when doing MSAA
+ // resolved off it. However that's for the future (case 549705),
+ // for now just silence the RT unresolve warning.
+ GetGfxDevice().IgnoreNextUnresolveOnCurrentRenderTarget();
+
+ Rectf r = loop.m_Context.m_Camera->GetPhysicalViewportRect();
+ int rect[4];
+ RectfToViewport( r, rect );
+ Assert (rect[2] == rt->GetGLWidth() && rect[3] == rt->GetGLHeight());
+ rt->GrabPixels (rect[0], rect[1], rect[2], rect[3]);
+
+ // D3D and GL use different notions of how Y texture coordinates go.
+ // In effect, we have to flip any sampling from the first texture in the image filters
+ // stack on D3D.
+ rt->CorrectVerticalTexelSize(false);
+ }
+
+ return rt;
+}
+
+
+void RenderImageFilters (RenderLoop& loop, RenderTexture* targetTexture, bool afterOpaque)
+{
+ bool forceIntoRT = loop.m_Context.m_Camera->CalculateNeedsToRenderIntoRT();
+ ResolveScreenToTextureIfNeeded (loop, forceIntoRT, afterOpaque);
+ bool usingScreenToComposite = loop.m_ImageFilters.HasImageFilter() && loop.m_Context.m_Camera->GetUsesScreenForCompositing(forceIntoRT);
+ loop.m_ImageFilters.DoRender (targetTexture, forceIntoRT, afterOpaque, usingScreenToComposite, loop.m_Context.m_Camera->GetUsingHDR());
+ if (afterOpaque && !usingScreenToComposite)
+ loop.m_Context.m_Camera->SetCurrentTargetTexture (loop.m_ImageFilters.GetTargetAfterOpaque(forceIntoRT,usingScreenToComposite));
+}
+
+
+static void UpdateCameraDepthTextures (Camera& camera, RenderTexture* rtDepth, RenderTexture* rtDepthNormals, RenderObjectDataContainer& objects, bool depthWasCopied, bool skipDepthTexture, bool afterOpaque)
+{
+ if (!rtDepth || objects.size() == 0)
+ return;
+
+ // use depth buffer from final target
+ RenderTexture* rtFinal = camera.GetCurrentTargetTexture();
+ Assert (rtFinal);
+ RenderSurfaceHandle rtSurfaceDepth = rtFinal->GetDepthSurfaceHandle();
+
+ int renderFlags = Camera::kRenderFlagSetRenderTarget;
+ if (!afterOpaque)
+ renderFlags |= Camera::kRenderFlagSetRenderTargetFinal;
+
+ if (!skipDepthTexture && gGraphicsCaps.hasStencilInDepthTexture && (camera.GetDepthTextureMode() & Camera::kDepthTexDepthBit))
+ {
+ Shader* shader = GetCameraDepthTextureShader ();
+ if (shader)
+ {
+ PROFILER_AUTO_GFX(gPrePassFwdDepthTex, &camera);
+ // If we did separate pass or depth resolve in deferred to work around depth+stencil texture bugs,
+ // render into the copy in that case.
+ if (depthWasCopied)
+ {
+ RenderTexture::SetActive (rtDepth);
+ }
+ else
+ {
+ RenderSurfaceHandle rtSurfaceColor = rtDepth->GetColorSurfaceHandle();
+ RenderTexture::SetActive (1, &rtSurfaceColor, rtSurfaceDepth, rtDepth);
+ }
+
+ RenderSceneShaderReplacement (objects, shader, "RenderType");
+ camera.SetupRender (renderFlags);
+ }
+ }
+
+ if (rtDepthNormals && (camera.GetDepthTextureMode() & Camera::kDepthTexDepthNormalsBit))
+ {
+ Shader* shader = GetCameraDepthNormalsTextureShader ();
+ if (shader)
+ {
+ PROFILER_AUTO_GFX(gPrePassFwdDepthNormalsTex, &camera);
+ RenderSurfaceHandle rtSurfaceColor = rtDepthNormals->GetColorSurfaceHandle();
+ RenderTexture::SetActive (1, &rtSurfaceColor, rtSurfaceDepth, rtDepthNormals);
+
+ RenderSceneShaderReplacement (objects, shader, "RenderType");
+ camera.SetupRender (renderFlags);
+ }
+ }
+}
+
+bool gInsideRenderLoop = false;
+void StartRenderLoop()
+{
+ Assert (!gInsideRenderLoop);
+ gInsideRenderLoop = true;
+}
+void EndRenderLoop()
+{
+ Assert (gInsideRenderLoop);
+ gInsideRenderLoop = false;
+}
+bool IsInsideRenderLoop()
+{
+ return gInsideRenderLoop;
+}
+
+void DoRenderLoop (
+ RenderLoop& loop,
+ RenderingPath renderPath,
+ CullResults& contents,
+ bool dontRenderRenderables)
+{
+ Assert (loop.m_TempBufferCount == 0);
+ Assert (contents.shadowCullData);
+
+ loop.m_Context.m_ShadowCullData = contents.shadowCullData;
+ loop.m_Context.m_CullResults = &contents;
+
+ // save wireframe state, restore at exit
+ SetAndRestoreWireframeMode saveAndRestoreWireframe;
+
+ const bool licenseAllowsStaticBatching = GetBuildSettings().hasAdvancedVersion;
+ Camera& camera = *loop.m_Context.m_Camera;
+
+ Shader* replacementShader = contents.shaderReplaceData.replacementShader;
+ const bool replacementTagSet = contents.shaderReplaceData.replacementTagSet;
+ const int replacementTagID = contents.shaderReplaceData.replacementTagID;
+
+
+ {
+ PROFILER_AUTO(gRenderPrepareObjects, &camera);
+
+ loop.PrepareFrame (dontRenderRenderables, replacementShader);
+
+ const bool useOldRenderQueueLogic = !IS_CONTENT_NEWER_OR_SAME (kUnityVersion4_2_a1);
+
+ // sort out objects into opaque & alpha parts
+ VisibleNodes::iterator itEnd = contents.nodes.end();
+ for (VisibleNodes::iterator it = contents.nodes.begin(); it != itEnd; ++it)
+ {
+ if (!IsFinite(it->invScale))
+ continue;
+
+ BaseRenderer* renderer = it->renderer;
+
+ float distanceForSort, distanceAlongView;
+ EvaluateObjectDepth (loop.m_Context, *it, distanceForSort, distanceAlongView);
+ distanceForSort -= renderer->GetSortingFudge ();
+ distanceAlongView = -distanceAlongView; // make that so increases with distance
+
+ const int matCount = renderer->GetMaterialCount();
+ const int batchIndex = (licenseAllowsStaticBatching)? renderer->GetStaticBatchIndex(): 0;
+ const UInt16 lightmapIndex = renderer->GetLightmapIndex();
+
+ for (int mi = 0; mi < matCount; ++mi)
+ {
+ Material* mat = renderer->GetMaterial (mi);
+ if( mat == NULL )
+ mat = Material::GetDefault();
+ Shader* shader = mat->GetShader();
+
+ int usedSubshaderIndex = -1;
+ if (replacementShader)
+ {
+ if (replacementTagSet)
+ {
+ int subshaderTypeID = shader->GetShaderLabShader()->GetTag (replacementTagID, true);
+ if (subshaderTypeID < 0)
+ continue; // skip rendering
+ usedSubshaderIndex = replacementShader->GetSubShaderWithTagValue (replacementTagID, subshaderTypeID);
+ if (usedSubshaderIndex == -1)
+ continue; // skip rendering
+ }
+ else
+ {
+ usedSubshaderIndex = 0;
+ }
+ }
+
+ const int matIndex = renderer->GetSubsetIndex(mi);
+
+ // Figure out rendering queue to use
+ int queueIndex = mat->GetCustomRenderQueue(); // any per-material overriden queue takes priority
+ if (queueIndex < 0)
+ {
+ // When no shader replacement or old content, take queue from the shader
+ if (!replacementShader || useOldRenderQueueLogic)
+ {
+ queueIndex = shader->GetShaderLabShader()->GetRenderQueue();
+ }
+ // Otherwise take from replacement shader
+ else
+ {
+ queueIndex = replacementShader->GetShaderLabShader()->GetRenderQueue(usedSubshaderIndex);
+ }
+ }
+
+ RenderPart part;
+ if (queueIndex <= kGeometryQueueIndexMax)
+ part = kPartOpaque;
+ else
+ part = kPartAfterOpaque;
+
+ RenderObjectData& odata = loop.m_Objects[part].push_back ();
+ DebugAssertIf (!mat);
+ odata.material = mat;
+ odata.queueIndex = queueIndex;
+ odata.subsetIndex = matIndex;
+ odata.subShaderIndex = usedSubshaderIndex;
+ odata.sourceMaterialIndex = (UInt16)mi;
+ odata.lightmapIndex = lightmapIndex;
+ odata.staticBatchIndex = batchIndex;
+ odata.distance = distanceForSort;
+ odata.distanceAlongView = distanceAlongView;
+ odata.visibleNode = &*it;
+ odata.shader = replacementShader ? replacementShader : shader;
+ odata.globalLayeringData = renderer->GetGlobalLayeringData();
+ }
+ }
+ }
+
+ // want linear lighting?
+ bool linearLighting = GetActiveColorSpace() == kLinearColorSpace;
+
+ // opaque: deferred or forward
+ RenderTexture *rtDepth = NULL, *rtDepthNormals = NULL;
+ bool prepassDepthWasCopied = false;
+ {
+ PROFILER_AUTO_GFX(gRenderOpaque, &camera);
+
+ loop.m_Context.m_RenderQueueStart = kQueueIndexMin; loop.m_Context.m_RenderQueueEnd = kGeometryQueueIndexMax+1;
+ if (renderPath == kRenderPathPrePass)
+ {
+ #if GFX_SUPPORTS_RENDERLOOP_PREPASS
+ RenderTexture *rtShadowMap = NULL;
+ RenderObjectDataContainer remainingObjects;
+ DoPrePassRenderLoop (loop.m_Context, loop.m_Objects[kPartOpaque], remainingObjects, rtDepth, rtDepthNormals, rtShadowMap, contents.activeLights, linearLighting, &prepassDepthWasCopied);
+ if (remainingObjects.size() != 0)
+ {
+ // Objects/shaders that don't handle deferred: render with forward path, and pass main shadowmap to it
+ // Also disable dynamic batching of those objects. They are already rendered into
+ // the depth buffer, and dynamic batching would make them be rendered at slightly
+ // different positions, failing depth test at places.
+ DoForwardShaderRenderLoop (loop.m_Context, remainingObjects, true, true, rtShadowMap, contents.activeLights, linearLighting, false);
+
+ UpdateCameraDepthTextures (camera, rtDepth, rtDepthNormals, remainingObjects, prepassDepthWasCopied, true, true);
+ }
+ #else
+ ErrorString ("Pre-pass rendering loop should never happen on this platform!");
+ #endif
+ }
+ else if (renderPath == kRenderPathForward)
+ {
+ DoForwardShaderRenderLoop (loop.m_Context, loop.m_Objects[kPartOpaque], true, false, NULL, contents.activeLights, linearLighting, true);
+ }
+ else
+ {
+ DoForwardVertexRenderLoop (loop.m_Context, loop.m_Objects[kPartOpaque], true, contents.activeLights, linearLighting, true);
+ }
+ }
+
+ // render skybox after opaque (sRGB conversions needed if using linear rendering)
+ {
+ GetGfxDevice().SetSRGBWrite(linearLighting);
+ camera.RenderSkybox();
+ GetGfxDevice().SetSRGBWrite(false);
+ }
+
+ RenderImageFilters (loop, camera.GetTargetTexture(), true);
+
+ // after opaque: forward
+ {
+ PROFILER_AUTO_GFX(gRenderTransparent, &camera);
+
+ loop.m_Context.m_RenderQueueStart = kGeometryQueueIndexMax+1; loop.m_Context.m_RenderQueueEnd = kQueueIndexMax;
+ if (renderPath != kRenderPathVertex)
+ {
+ DoForwardShaderRenderLoop (loop.m_Context, loop.m_Objects[kPartAfterOpaque], false, false, NULL, contents.activeLights, linearLighting, false);
+ }
+ else
+ {
+ DoForwardVertexRenderLoop (loop.m_Context, loop.m_Objects[kPartAfterOpaque], false, contents.activeLights, linearLighting, false);
+ }
+
+ UpdateCameraDepthTextures (camera, rtDepth, rtDepthNormals, loop.m_Objects[kPartAfterOpaque], prepassDepthWasCopied, false, false);
+ }
+
+ loop.m_Context.m_ShadowCullData = NULL;
+ loop.m_Context.m_CullResults = NULL;
+}
+
+void CleanupAfterRenderLoop (RenderLoop& loop)
+{
+ Assert (loop.m_TempBufferCount >= 0 && loop.m_TempBufferCount < RenderLoop::kMaxCreatedTempBuffers);
+ RenderBufferManager& rbm = GetRenderBufferManager();
+ for (int i = 0; i < loop.m_TempBufferCount; ++i) {
+ Assert (loop.m_TempBuffers[i]);
+ rbm.ReleaseTempBuffer (loop.m_TempBuffers[i]);
+ loop.m_TempBuffers[i] = NULL;
+ }
+ loop.m_TempBufferCount = 0;
+ ShaderLab::ClearGrabPassFrameState();
+}
+
+void AddRenderLoopTempBuffer (RenderLoop* loop, RenderTexture* rt)
+{
+ Assert (loop && rt);
+ Assert (loop->m_TempBufferCount < RenderLoop::kMaxCreatedTempBuffers);
+
+ loop->m_TempBuffers[loop->m_TempBufferCount++] = rt;
+}