当前位置:   article > 正文

UE4阴影初始化【3】_ue4 wholescene split

ue4 wholescene split

FSceneRenderer::InitDynamicShadows()

        CreateWholeSceneProjectedShadow()

  1. void FSceneRenderer::CreateWholeSceneProjectedShadow(
  2. FLightSceneInfo* LightSceneInfo,
  3. uint32& InOutNumPointShadowCachesUpdatedThisFrame,
  4. uint32& InOutNumSpotShadowCachesUpdatedThisFrame)
  5. {
  6. SCOPE_CYCLE_COUNTER(STAT_CreateWholeSceneProjectedShadow);
  7. FVisibleLightInfo& VisibleLightInfo = VisibleLightInfos[LightSceneInfo->Id];
  8. // early out if shadow resoluion scale is zero
  9. if (CVarResolutionScaleZeroDisablesSm.GetValueOnRenderThread() != 0 && LightSceneInfo->Proxy->GetShadowResolutionScale() <= 0.0f)
  10. {
  11. return;
  12. }
  13. // Try to create a whole-scene projected shadow initializer for the light.
  14. TArray<FWholeSceneProjectedShadowInitializer, TInlineAllocator<6> > ProjectedShadowInitializers;
  15. if (LightSceneInfo->Proxy->GetWholeSceneProjectedShadowInitializer(ViewFamily, ProjectedShadowInitializers))
  16. {
  17. FSceneRenderTargets& SceneContext_ConstantsOnly = FSceneRenderTargets::Get_FrameConstantsOnly();
  18. checkSlow(ProjectedShadowInitializers.Num() > 0);
  19. // Shadow resolution constants.
  20. const uint32 ShadowBorder = ProjectedShadowInitializers[0].bOnePassPointLightShadow ? 0 : SHADOW_BORDER;
  21. const uint32 EffectiveDoubleShadowBorder = ShadowBorder * 2;
  22. const uint32 MinShadowResolution = FMath::Max<int32>(0, CVarMinShadowResolution.GetValueOnRenderThread());
  23. const int32 MaxShadowResolutionSetting = GetCachedScalabilityCVars().MaxShadowResolution;
  24. const FIntPoint ShadowBufferResolution = SceneContext_ConstantsOnly.GetShadowDepthTextureResolution();
  25. const uint32 MaxShadowResolution = FMath::Min(MaxShadowResolutionSetting, ShadowBufferResolution.X) - EffectiveDoubleShadowBorder;
  26. const uint32 MaxShadowResolutionY = FMath::Min(MaxShadowResolutionSetting, ShadowBufferResolution.Y) - EffectiveDoubleShadowBorder;
  27. const uint32 ShadowFadeResolution = FMath::Max<int32>(0, CVarShadowFadeResolution.GetValueOnRenderThread());
  28. // Compute the maximum resolution required for the shadow by any view. Also keep track of the unclamped resolution for fading.
  29. float MaxDesiredResolution = 0;
  30. TArray<float, TInlineAllocator<2> > FadeAlphas;
  31. float MaxFadeAlpha = 0;
  32. bool bStaticSceneOnly = false;
  33. bool bAnyViewIsSceneCapture = false;
  34. for(int32 ViewIndex = 0, ViewCount = Views.Num(); ViewIndex < ViewCount; ++ViewIndex)
  35. {
  36. const FViewInfo& View = Views[ViewIndex];
  37. const float ScreenRadius = LightSceneInfo->Proxy->GetEffectiveScreenRadius(View.ShadowViewMatrices);
  38. // Determine the amount of shadow buffer resolution needed for this view.
  39. float UnclampedResolution = 1.0f;
  40. switch (LightSceneInfo->Proxy->GetLightType())
  41. {
  42. case LightType_Point:
  43. UnclampedResolution = ScreenRadius * CVarShadowTexelsPerPixelPointlight.GetValueOnRenderThread();
  44. break;
  45. case LightType_Spot:
  46. UnclampedResolution = ScreenRadius * CVarShadowTexelsPerPixelSpotlight.GetValueOnRenderThread();
  47. break;
  48. case LightType_Rect:
  49. UnclampedResolution = ScreenRadius * CVarShadowTexelsPerPixelRectlight.GetValueOnRenderThread();
  50. break;
  51. default:
  52. // directional lights are not handled here
  53. checkf(false, TEXT("Unexpected LightType %d appears in CreateWholeSceneProjectedShadow %s"),
  54. (int32)LightSceneInfo->Proxy->GetLightType(),
  55. *LightSceneInfo->Proxy->GetComponentName().ToString());
  56. }
  57. // Compute FadeAlpha before ShadowResolutionScale contribution (artists want to modify the softness of the shadow, not change the fade ranges)
  58. const float FadeAlpha = CalculateShadowFadeAlpha( UnclampedResolution, ShadowFadeResolution, MinShadowResolution ) * LightSceneInfo->Proxy->GetShadowAmount();
  59. MaxFadeAlpha = FMath::Max(MaxFadeAlpha, FadeAlpha);
  60. FadeAlphas.Add(FadeAlpha);
  61. const float ShadowResolutionScale = LightSceneInfo->Proxy->GetShadowResolutionScale();
  62. float ClampedResolution = UnclampedResolution;
  63. if (ShadowResolutionScale > 1.0f)
  64. {
  65. // Apply ShadowResolutionScale before the MaxShadowResolution clamp if raising the resolution
  66. ClampedResolution *= ShadowResolutionScale;
  67. }
  68. ClampedResolution = FMath::Min<float>(ClampedResolution, MaxShadowResolution);
  69. if (ShadowResolutionScale <= 1.0f)
  70. {
  71. // Apply ShadowResolutionScale after the MaxShadowResolution clamp if lowering the resolution
  72. // Artists want to modify the softness of the shadow with ShadowResolutionScale
  73. ClampedResolution *= ShadowResolutionScale;
  74. }
  75. MaxDesiredResolution = FMath::Max(
  76. MaxDesiredResolution,
  77. FMath::Max<float>(
  78. ClampedResolution,
  79. FMath::Min<float>(MinShadowResolution, ShadowBufferResolution.X - EffectiveDoubleShadowBorder)
  80. )
  81. );
  82. bStaticSceneOnly = bStaticSceneOnly || View.bStaticSceneOnly;
  83. bAnyViewIsSceneCapture = bAnyViewIsSceneCapture || View.bIsSceneCapture;
  84. }
  85. if (MaxFadeAlpha > 1.0f / 256.0f)
  86. {
  87. Scene->FlushAsyncLightPrimitiveInteractionCreation();
  88. for (int32 ShadowIndex = 0, ShadowCount = ProjectedShadowInitializers.Num(); ShadowIndex < ShadowCount; ShadowIndex++)
  89. {
  90. FWholeSceneProjectedShadowInitializer& ProjectedShadowInitializer = ProjectedShadowInitializers[ShadowIndex];
  91. // Round down to the nearest power of two so that resolution changes are always doubling or halving the resolution, which increases filtering stability
  92. // Use the max resolution if the desired resolution is larger than that
  93. // FMath::CeilLogTwo(MaxDesiredResolution + 1.0f) instead of FMath::CeilLogTwo(MaxDesiredResolution) because FMath::CeilLogTwo takes
  94. // an uint32 as argument and this causes MaxDesiredResolution get truncated. For example, if MaxDesiredResolution is 256.1f,
  95. // FMath::CeilLogTwo returns 8 but the next line of code expects a 9 to work correctly
  96. int32 RoundedDesiredResolution = FMath::Max<int32>((1 << (FMath::CeilLogTwo(MaxDesiredResolution + 1.0f) - 1)) - ShadowBorder * 2, 1);
  97. int32 SizeX = MaxDesiredResolution >= MaxShadowResolution ? MaxShadowResolution : RoundedDesiredResolution;
  98. int32 SizeY = MaxDesiredResolution >= MaxShadowResolutionY ? MaxShadowResolutionY : RoundedDesiredResolution;
  99. if (ProjectedShadowInitializer.bOnePassPointLightShadow)
  100. {
  101. // Round to a resolution that is supported for one pass point light shadows
  102. SizeX = SizeY = SceneContext_ConstantsOnly.GetCubeShadowDepthZResolution(SceneContext_ConstantsOnly.GetCubeShadowDepthZIndex(MaxDesiredResolution));
  103. }
  104. int32 NumShadowMaps = 1;
  105. EShadowDepthCacheMode CacheMode[2] = { SDCM_Uncached, SDCM_Uncached };
  106. if (!bAnyViewIsSceneCapture && !ProjectedShadowInitializer.bRayTracedDistanceField)
  107. {
  108. FIntPoint ShadowMapSize(SizeX + ShadowBorder * 2, SizeY + ShadowBorder * 2);
  109. ComputeWholeSceneShadowCacheModes(
  110. LightSceneInfo,
  111. ProjectedShadowInitializer.bOnePassPointLightShadow,
  112. ViewFamily.CurrentRealTime,
  113. MaxDesiredResolution,
  114. FIntPoint(MaxShadowResolution, MaxShadowResolutionY),
  115. Scene,
  116. // Below are in-out or out parameters. They can change
  117. ProjectedShadowInitializer,
  118. ShadowMapSize,
  119. InOutNumPointShadowCachesUpdatedThisFrame,
  120. InOutNumSpotShadowCachesUpdatedThisFrame,
  121. NumShadowMaps,
  122. CacheMode);
  123. SizeX = ShadowMapSize.X - ShadowBorder * 2;
  124. SizeY = ShadowMapSize.Y - ShadowBorder * 2;
  125. }
  126. for (int32 CacheModeIndex = 0; CacheModeIndex < NumShadowMaps; CacheModeIndex++)
  127. {
  128. // Create the projected shadow info.
  129. FProjectedShadowInfo* ProjectedShadowInfo = new(FMemStack::Get(), 1, 16) FProjectedShadowInfo;
  130. ProjectedShadowInfo->SetupWholeSceneProjection(
  131. LightSceneInfo,
  132. NULL,
  133. ProjectedShadowInitializer,
  134. SizeX,
  135. SizeY,
  136. ShadowBorder,
  137. false // no RSM
  138. );
  139. ProjectedShadowInfo->CacheMode = CacheMode[CacheModeIndex];
  140. ProjectedShadowInfo->FadeAlphas = FadeAlphas;
  141. VisibleLightInfo.MemStackProjectedShadows.Add(ProjectedShadowInfo);
  142. if (ProjectedShadowInitializer.bOnePassPointLightShadow)
  143. {
  144. const static FVector CubeDirections[6] =
  145. {
  146. FVector(-1, 0, 0),
  147. FVector(1, 0, 0),
  148. FVector(0, -1, 0),
  149. FVector(0, 1, 0),
  150. FVector(0, 0, -1),
  151. FVector(0, 0, 1)
  152. };
  153. const static FVector UpVectors[6] =
  154. {
  155. FVector(0, 1, 0),
  156. FVector(0, 1, 0),
  157. FVector(0, 0, -1),
  158. FVector(0, 0, 1),
  159. FVector(0, 1, 0),
  160. FVector(0, 1, 0)
  161. };
  162. const FLightSceneProxy& LightProxy = *(ProjectedShadowInfo->GetLightSceneInfo().Proxy);
  163. const FMatrix FaceProjection = FPerspectiveMatrix(PI / 4.0f, 1, 1, 1, LightProxy.GetRadius());
  164. // Light projection and bounding volume is set up relative to the light position
  165. // the view pre-translation (relative to light) is added later, when rendering & sampling.
  166. const FVector LightPosition = ProjectedShadowInitializer.WorldToLight.GetOrigin();
  167. ProjectedShadowInfo->OnePassShadowViewMatrices.Empty(6);
  168. ProjectedShadowInfo->OnePassShadowViewProjectionMatrices.Empty(6);
  169. const FMatrix ScaleMatrix = FScaleMatrix(FVector(1, -1, 1));
  170. // fill in the caster frustum with the far plane from every face
  171. ProjectedShadowInfo->CasterFrustum.Planes.Empty();
  172. for (int32 FaceIndex = 0; FaceIndex < 6; FaceIndex++)
  173. {
  174. // Create a view projection matrix for each cube face
  175. const FMatrix WorldToLightMatrix = FLookFromMatrix(LightPosition, CubeDirections[FaceIndex], UpVectors[FaceIndex]) * ScaleMatrix;
  176. ProjectedShadowInfo->OnePassShadowViewMatrices.Add(WorldToLightMatrix);
  177. const FMatrix ShadowViewProjectionMatrix = WorldToLightMatrix * FaceProjection;
  178. ProjectedShadowInfo->OnePassShadowViewProjectionMatrices.Add(ShadowViewProjectionMatrix);
  179. // Add plane representing cube face to bounding volume
  180. ProjectedShadowInfo->CasterFrustum.Planes.Add(FPlane(CubeDirections[FaceIndex], LightProxy.GetRadius()));
  181. }
  182. ProjectedShadowInfo->CasterFrustum.Init();
  183. }
  184. // Ray traced shadows use the GPU managed distance field object buffers, no CPU culling should be used
  185. if (!ProjectedShadowInfo->bRayTracedDistanceField)
  186. {
  187. // Build light-view convex hulls for shadow caster culling
  188. FLightViewFrustumConvexHulls LightViewFrustumConvexHulls;
  189. if (CacheMode[CacheModeIndex] != SDCM_StaticPrimitivesOnly)
  190. {
  191. FVector const& LightOrigin = LightSceneInfo->Proxy->GetOrigin();
  192. BuildLightViewFrustumConvexHulls(LightOrigin, Views, LightViewFrustumConvexHulls);
  193. }
  194. bool bCastCachedShadowFromMovablePrimitives = GCachedShadowsCastFromMovablePrimitives || LightSceneInfo->Proxy->GetForceCachedShadowsForMovablePrimitives();
  195. if (CacheMode[CacheModeIndex] != SDCM_StaticPrimitivesOnly
  196. && (CacheMode[CacheModeIndex] != SDCM_MovablePrimitivesOnly || bCastCachedShadowFromMovablePrimitives))
  197. {
  198. // Add all the shadow casting primitives affected by the light to the shadow's subject primitive list.
  199. for (FLightPrimitiveInteraction* Interaction = LightSceneInfo->GetDynamicInteractionOftenMovingPrimitiveList(false);
  200. Interaction;
  201. Interaction = Interaction->GetNextPrimitive())
  202. {
  203. if (Interaction->HasShadow()
  204. // If the primitive only wants to cast a self shadow don't include it in whole scene shadows.
  205. && !Interaction->CastsSelfShadowOnly()
  206. && (!bStaticSceneOnly || Interaction->GetPrimitiveSceneInfo()->Proxy->HasStaticLighting()))
  207. {
  208. FBoxSphereBounds const& Bounds = Interaction->GetPrimitiveSceneInfo()->Proxy->GetBounds();
  209. if (IntersectsConvexHulls(LightViewFrustumConvexHulls, Bounds))
  210. {
  211. ProjectedShadowInfo->AddSubjectPrimitive(Interaction->GetPrimitiveSceneInfo(), &Views, FeatureLevel, false);
  212. }
  213. }
  214. }
  215. }
  216. if (CacheMode[CacheModeIndex] != SDCM_MovablePrimitivesOnly)
  217. {
  218. // Add all the shadow casting primitives affected by the light to the shadow's subject primitive list.
  219. for (FLightPrimitiveInteraction* Interaction = LightSceneInfo->GetDynamicInteractionStaticPrimitiveList(false);
  220. Interaction;
  221. Interaction = Interaction->GetNextPrimitive())
  222. {
  223. if (Interaction->HasShadow()
  224. // If the primitive only wants to cast a self shadow don't include it in whole scene shadows.
  225. && !Interaction->CastsSelfShadowOnly()
  226. && (!bStaticSceneOnly || Interaction->GetPrimitiveSceneInfo()->Proxy->HasStaticLighting()))
  227. {
  228. FBoxSphereBounds const& Bounds = Interaction->GetPrimitiveSceneInfo()->Proxy->GetBounds();
  229. if (IntersectsConvexHulls(LightViewFrustumConvexHulls, Bounds))
  230. {
  231. ProjectedShadowInfo->AddSubjectPrimitive(Interaction->GetPrimitiveSceneInfo(), &Views, FeatureLevel, false);
  232. }
  233. }
  234. }
  235. }
  236. }
  237. bool bRenderShadow = true;
  238. if (CacheMode[CacheModeIndex] == SDCM_StaticPrimitivesOnly)
  239. {
  240. const bool bHasStaticPrimitives = ProjectedShadowInfo->HasSubjectPrims();
  241. bRenderShadow = bHasStaticPrimitives;
  242. FCachedShadowMapData& CachedShadowMapData = Scene->CachedShadowMaps.FindChecked(ProjectedShadowInfo->GetLightSceneInfo().Id);
  243. CachedShadowMapData.bCachedShadowMapHasPrimitives = bHasStaticPrimitives;
  244. }
  245. if (bRenderShadow)
  246. {
  247. VisibleLightInfo.AllProjectedShadows.Add(ProjectedShadowInfo);
  248. }
  249. }
  250. }
  251. }
  252. }
  253. }

  1. void FProjectedShadowInfo::AddSubjectPrimitive(FPrimitiveSceneInfo* PrimitiveSceneInfo, TArray<FViewInfo>* ViewArray, ERHIFeatureLevel::Type FeatureLevel, bool bRecordShadowSubjectsForMobileShading)
  2. {
  3. // Ray traced shadows use the GPU managed distance field object buffers, no CPU culling should be used
  4. check(!bRayTracedDistanceField);
  5. if (!ReceiverPrimitives.Contains(PrimitiveSceneInfo)
  6. // Far cascade only casts from primitives marked for it
  7. && (!CascadeSettings.bFarShadowCascade || PrimitiveSceneInfo->Proxy->CastsFarShadow()))
  8. {
  9. const FPrimitiveSceneProxy* Proxy = PrimitiveSceneInfo->Proxy;
  10. TArray<FViewInfo*, TInlineAllocator<1> > Views;
  11. const bool bWholeSceneDirectionalShadow = IsWholeSceneDirectionalShadow();
  12. if (bWholeSceneDirectionalShadow)
  13. {
  14. Views.Add(DependentView);
  15. }
  16. else
  17. {
  18. checkf(ViewArray,
  19. TEXT("bWholeSceneShadow=%d, CascadeSettings.ShadowSplitIndex=%d, bDirectionalLight=%s"),
  20. bWholeSceneShadow ? TEXT("true") : TEXT("false"),
  21. CascadeSettings.ShadowSplitIndex,
  22. bDirectionalLight ? TEXT("true") : TEXT("false"));
  23. for (int32 ViewIndex = 0; ViewIndex < ViewArray->Num(); ViewIndex++)
  24. {
  25. Views.Add(&(*ViewArray)[ViewIndex]);
  26. }
  27. }
  28. bool bOpaque = false;
  29. bool bTranslucentRelevance = false;
  30. bool bShadowRelevance = false;
  31. uint32 ViewMask = 0;
  32. int32 PrimitiveId = PrimitiveSceneInfo->GetIndex();
  33. for (int32 ViewIndex = 0, Num = Views.Num(); ViewIndex < Num; ViewIndex++)
  34. {
  35. FViewInfo& CurrentView = *Views[ViewIndex];
  36. FPrimitiveViewRelevance& ViewRelevance = CurrentView.PrimitiveViewRelevanceMap[PrimitiveId];
  37. if (!ViewRelevance.bInitializedThisFrame)
  38. {
  39. if( CurrentView.IsPerspectiveProjection() )
  40. {
  41. // Compute the distance between the view and the primitive.
  42. float DistanceSquared = (Proxy->GetBounds().Origin - CurrentView.ShadowViewMatrices.GetViewOrigin()).SizeSquared();
  43. bool bIsDistanceCulled = CurrentView.IsDistanceCulled(
  44. DistanceSquared,
  45. Proxy->GetMinDrawDistance(),
  46. Proxy->GetMaxDrawDistance(),
  47. PrimitiveSceneInfo
  48. );
  49. if( bIsDistanceCulled )
  50. {
  51. continue;
  52. }
  53. }
  54. // Respect HLOD visibility which can hide child LOD primitives
  55. if (CurrentView.ViewState &&
  56. CurrentView.ViewState->HLODVisibilityState.IsValidPrimitiveIndex(PrimitiveId) &&
  57. CurrentView.ViewState->HLODVisibilityState.IsNodeForcedHidden(PrimitiveId))
  58. {
  59. continue;
  60. }
  61. if ((CurrentView.ShowOnlyPrimitives.IsSet() &&
  62. !CurrentView.ShowOnlyPrimitives->Contains(PrimitiveSceneInfo->Proxy->GetPrimitiveComponentId())) ||
  63. CurrentView.HiddenPrimitives.Contains(PrimitiveSceneInfo->Proxy->GetPrimitiveComponentId()))
  64. {
  65. continue;
  66. }
  67. // Compute the subject primitive's view relevance since it wasn't cached
  68. // Update the main view's PrimitiveViewRelevanceMap
  69. ViewRelevance = PrimitiveSceneInfo->Proxy->GetViewRelevance(&CurrentView);
  70. ViewMask |= (1 << ViewIndex);
  71. }
  72. bOpaque |= ViewRelevance.bOpaque || ViewRelevance.bMasked;
  73. bTranslucentRelevance |= ViewRelevance.HasTranslucency() && !ViewRelevance.bMasked;
  74. bShadowRelevance |= ViewRelevance.bShadowRelevance;
  75. }
  76. if (bShadowRelevance)
  77. {
  78. // Update the primitive component's last render time. Allows the component to update when using bCastWhenHidden.
  79. const float CurrentWorldTime = Views[0]->Family->CurrentWorldTime;
  80. PrimitiveSceneInfo->UpdateComponentLastRenderTime(CurrentWorldTime, /*bUpdateLastRenderTimeOnScreen=*/false);
  81. if (PrimitiveSceneInfo->NeedsUniformBufferUpdate())
  82. {
  83. for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
  84. {
  85. // Main view visible primitives are processed on parallel tasks, updating uniform buffer them here will cause a race condition.
  86. check(!Views[ViewIndex]->PrimitiveVisibilityMap[PrimitiveSceneInfo->GetIndex()]);
  87. }
  88. PrimitiveSceneInfo->ConditionalUpdateUniformBuffer(FRHICommandListExecutor::GetImmediateCommandList());
  89. }
  90. if (PrimitiveSceneInfo->NeedsUpdateStaticMeshes())
  91. {
  92. // Need to defer to next InitViews, as main view visible primitives are processed on parallel tasks and calling
  93. // CacheMeshDrawCommands may resize CachedDrawLists/CachedMeshDrawCommandStateBuckets causing a crash.
  94. PrimitiveSceneInfo->BeginDeferredUpdateStaticMeshesWithoutVisibilityCheck();
  95. }
  96. }
  97. if (bOpaque && bShadowRelevance)
  98. {
  99. const FBoxSphereBounds& Bounds = Proxy->GetBounds();
  100. bool bDrawingStaticMeshes = false;
  101. if (PrimitiveSceneInfo->StaticMeshes.Num() > 0)
  102. {
  103. for (int32 ViewIndex = 0, ViewCount = Views.Num(); ViewIndex < ViewCount; ViewIndex++)
  104. {
  105. FViewInfo& CurrentView = *Views[ViewIndex];
  106. const float DistanceSquared = ( Bounds.Origin - CurrentView.ShadowViewMatrices.GetViewOrigin() ).SizeSquared();
  107. if (bWholeSceneShadow)
  108. {
  109. const float LODScaleSquared = FMath::Square(CurrentView.LODDistanceFactor);
  110. const bool bDrawShadowDepth = FMath::Square(Bounds.SphereRadius) > FMath::Square(GMinScreenRadiusForShadowCaster) * DistanceSquared * LODScaleSquared;
  111. if( !bDrawShadowDepth )
  112. {
  113. // cull object if it's too small to be considered as shadow caster
  114. continue;
  115. }
  116. }
  117. // Update visibility for meshes which weren't visible in the main views or were visible with static relevance
  118. if (!CurrentView.PrimitiveVisibilityMap[PrimitiveId] || CurrentView.PrimitiveViewRelevanceMap[PrimitiveId].bStaticRelevance)
  119. {
  120. bDrawingStaticMeshes |= ShouldDrawStaticMeshes(CurrentView, PrimitiveSceneInfo);
  121. }
  122. }
  123. }
  124. if (bDrawingStaticMeshes)
  125. {
  126. if (bRecordShadowSubjectsForMobileShading)
  127. {
  128. DependentView->VisibleLightInfos[GetLightSceneInfo().Id].MobileCSMSubjectPrimitives.AddSubjectPrimitive(PrimitiveSceneInfo, PrimitiveId);
  129. }
  130. }
  131. else
  132. {
  133. // Add the primitive to the subject primitive list.
  134. DynamicSubjectPrimitives.Add(PrimitiveSceneInfo);
  135. if (bRecordShadowSubjectsForMobileShading)
  136. {
  137. DependentView->VisibleLightInfos[GetLightSceneInfo().Id].MobileCSMSubjectPrimitives.AddSubjectPrimitive(PrimitiveSceneInfo, PrimitiveId);
  138. }
  139. }
  140. }
  141. // Add translucent shadow casting primitives to SubjectTranslucentPrimitives
  142. if (bTranslucentRelevance && bShadowRelevance)
  143. {
  144. SubjectTranslucentPrimitives.Add(PrimitiveSceneInfo);
  145. }
  146. }
  147. }
  1. bool FProjectedShadowInfo::ShouldDrawStaticMeshes(FViewInfo& InCurrentView, FPrimitiveSceneInfo* InPrimitiveSceneInfo)
  2. {
  3. bool WholeSceneDirectionalShadow = IsWholeSceneDirectionalShadow();
  4. bool bDrawingStaticMeshes = false;
  5. int32 PrimitiveId = InPrimitiveSceneInfo->GetIndex();
  6. {
  7. const int32 ForcedLOD = (InCurrentView.Family->EngineShowFlags.LOD) ? (GetCVarForceLODShadow() != -1 ? GetCVarForceLODShadow() : GetCVarForceLOD()) : -1;
  8. const FLODMask* VisibilePrimitiveLODMask = nullptr;
  9. if (InCurrentView.PrimitivesLODMask[PrimitiveId].ContainsLOD(MAX_int8)) // only calculate it if it's not set
  10. {
  11. FLODMask ViewLODToRender;
  12. float MeshScreenSizeSquared = 0;
  13. const int8 CurFirstLODIdx = InPrimitiveSceneInfo->Proxy->GetCurrentFirstLODIdx_RenderThread();
  14. const FBoxSphereBounds& Bounds = InPrimitiveSceneInfo->Proxy->GetBounds();
  15. const float LODScale = InCurrentView.LODDistanceFactor * GetCachedScalabilityCVars().StaticMeshLODDistanceScale;
  16. ViewLODToRender = ComputeLODForMeshes(InPrimitiveSceneInfo->StaticMeshRelevances, InCurrentView, Bounds.Origin, Bounds.SphereRadius, ForcedLOD, MeshScreenSizeSquared, CurFirstLODIdx, LODScale);
  17. InCurrentView.PrimitivesLODMask[PrimitiveId] = ViewLODToRender;
  18. }
  19. VisibilePrimitiveLODMask = &InCurrentView.PrimitivesLODMask[PrimitiveId];
  20. check(VisibilePrimitiveLODMask != nullptr);
  21. FLODMask ShadowLODToRender = *VisibilePrimitiveLODMask;
  22. // Use lowest LOD for PreShadow
  23. if (bReflectiveShadowmap || (bPreShadow && GPreshadowsForceLowestLOD))
  24. {
  25. int8 LODToRenderScan = -MAX_int8;
  26. FLODMask LODToRender;
  27. for (int32 Index = 0; Index < InPrimitiveSceneInfo->StaticMeshRelevances.Num(); Index++)
  28. {
  29. LODToRenderScan = FMath::Max<int8>(InPrimitiveSceneInfo->StaticMeshRelevances[Index].LODIndex, LODToRenderScan);
  30. }
  31. if (LODToRenderScan != -MAX_int8)
  32. {
  33. ShadowLODToRender.SetLOD(LODToRenderScan);
  34. }
  35. }
  36. if (CascadeSettings.bFarShadowCascade)
  37. {
  38. extern ENGINE_API int32 GFarShadowStaticMeshLODBias;
  39. int8 LODToRenderScan = ShadowLODToRender.DitheredLODIndices[0] + GFarShadowStaticMeshLODBias;
  40. for (int32 Index = InPrimitiveSceneInfo->StaticMeshRelevances.Num() - 1; Index >= 0; Index--)
  41. {
  42. if (LODToRenderScan == InPrimitiveSceneInfo->StaticMeshRelevances[Index].LODIndex)
  43. {
  44. ShadowLODToRender.SetLOD(LODToRenderScan);
  45. break;
  46. }
  47. }
  48. }
  49. if (WholeSceneDirectionalShadow)
  50. {
  51. // Don't cache if it requires per view per mesh state for distance cull fade.
  52. const bool bIsPrimitiveDistanceCullFading = InCurrentView.PotentiallyFadingPrimitiveMap[InPrimitiveSceneInfo->GetIndex()];
  53. const bool bCanCache = !bIsPrimitiveDistanceCullFading && !InPrimitiveSceneInfo->NeedsUpdateStaticMeshes();
  54. for (int32 MeshIndex = 0; MeshIndex < InPrimitiveSceneInfo->StaticMeshRelevances.Num(); MeshIndex++)
  55. {
  56. const FStaticMeshBatchRelevance& StaticMeshRelevance = InPrimitiveSceneInfo->StaticMeshRelevances[MeshIndex];
  57. const FStaticMeshBatch& StaticMesh = InPrimitiveSceneInfo->StaticMeshes[MeshIndex];
  58. if ((StaticMeshRelevance.CastShadow || (bSelfShadowOnly && StaticMeshRelevance.bUseForDepthPass)) && ShadowLODToRender.ContainsLOD(StaticMeshRelevance.LODIndex))
  59. {
  60. if (GetShadowDepthType() == CSMShadowDepthType && bCanCache)
  61. {
  62. AddCachedMeshDrawCommandsForPass(
  63. PrimitiveId,
  64. InPrimitiveSceneInfo,
  65. StaticMeshRelevance,
  66. StaticMesh,
  67. InPrimitiveSceneInfo->Scene,
  68. EMeshPass::CSMShadowDepth,
  69. ShadowDepthPassVisibleCommands,
  70. SubjectMeshCommandBuildRequests,
  71. NumSubjectMeshCommandBuildRequestElements);
  72. }
  73. else
  74. {
  75. NumSubjectMeshCommandBuildRequestElements += StaticMeshRelevance.NumElements;
  76. SubjectMeshCommandBuildRequests.Add(&StaticMesh);
  77. }
  78. bDrawingStaticMeshes = true;
  79. }
  80. }
  81. }
  82. else
  83. {
  84. for (int32 MeshIndex = 0; MeshIndex < InPrimitiveSceneInfo->StaticMeshRelevances.Num(); MeshIndex++)
  85. {
  86. const FStaticMeshBatchRelevance& StaticMeshRelevance = InPrimitiveSceneInfo->StaticMeshRelevances[MeshIndex];
  87. const FStaticMeshBatch& StaticMesh = InPrimitiveSceneInfo->StaticMeshes[MeshIndex];
  88. if ((StaticMeshRelevance.CastShadow || (bSelfShadowOnly && StaticMeshRelevance.bUseForDepthPass)) && ShadowLODToRender.ContainsLOD(StaticMeshRelevance.LODIndex))
  89. {
  90. NumSubjectMeshCommandBuildRequestElements += StaticMeshRelevance.NumElements;
  91. SubjectMeshCommandBuildRequests.Add(&StaticMesh);
  92. bDrawingStaticMeshes = true;
  93. }
  94. }
  95. }
  96. }
  97. return bDrawingStaticMeshes;
  98. }

  1. void FProjectedShadowInfo::AddCachedMeshDrawCommandsForPass(
  2. int32 PrimitiveIndex,
  3. const FPrimitiveSceneInfo* InPrimitiveSceneInfo,
  4. const FStaticMeshBatchRelevance& RESTRICT StaticMeshRelevance,
  5. const FStaticMeshBatch& StaticMesh,
  6. const FScene* Scene,
  7. EMeshPass::Type PassType,
  8. FMeshCommandOneFrameArray& VisibleMeshCommands,
  9. TArray<const FStaticMeshBatch*, SceneRenderingAllocator>& MeshCommandBuildRequests,
  10. int32& NumMeshCommandBuildRequestElements)
  11. {
  12. const EShadingPath ShadingPath = Scene->GetShadingPath();
  13. const bool bUseCachedMeshCommand = UseCachedMeshDrawCommands()
  14. && !!(FPassProcessorManager::GetPassFlags(ShadingPath, PassType) & EMeshPassFlags::CachedMeshCommands)
  15. && StaticMeshRelevance.bSupportsCachingMeshDrawCommands;
  16. if (bUseCachedMeshCommand)
  17. {
  18. const int32 StaticMeshCommandInfoIndex = StaticMeshRelevance.GetStaticMeshCommandInfoIndex(PassType);
  19. if (StaticMeshCommandInfoIndex >= 0)
  20. {
  21. const FCachedMeshDrawCommandInfo& CachedMeshDrawCommand = InPrimitiveSceneInfo->StaticMeshCommandInfos[StaticMeshCommandInfoIndex];
  22. const FCachedPassMeshDrawList& SceneDrawList = Scene->CachedDrawLists[PassType];
  23. const FMeshDrawCommand* MeshDrawCommand = CachedMeshDrawCommand.StateBucketId >= 0
  24. ? &Scene->CachedMeshDrawCommandStateBuckets[PassType].GetByElementId(CachedMeshDrawCommand.StateBucketId).Key
  25. : &SceneDrawList.MeshDrawCommands[CachedMeshDrawCommand.CommandIndex];
  26. FVisibleMeshDrawCommand NewVisibleMeshDrawCommand;
  27. NewVisibleMeshDrawCommand.Setup(
  28. MeshDrawCommand,
  29. PrimitiveIndex,
  30. PrimitiveIndex,
  31. CachedMeshDrawCommand.StateBucketId,
  32. CachedMeshDrawCommand.MeshFillMode,
  33. CachedMeshDrawCommand.MeshCullMode,
  34. CachedMeshDrawCommand.SortKey);
  35. VisibleMeshCommands.Add(NewVisibleMeshDrawCommand);
  36. }
  37. }
  38. else
  39. {
  40. NumMeshCommandBuildRequestElements += StaticMeshRelevance.NumElements;
  41. MeshCommandBuildRequests.Add(&StaticMesh);
  42. }
  43. }
  1. FORCEINLINE_DEBUGGABLE void Setup(
  2. const FMeshDrawCommand* InMeshDrawCommand,
  3. int32 InDrawPrimitiveId,
  4. int32 InScenePrimitiveId,
  5. int32 InStateBucketId,
  6. ERasterizerFillMode InMeshFillMode,
  7. ERasterizerCullMode InMeshCullMode,
  8. FMeshDrawCommandSortKey InSortKey)
  9. {
  10. MeshDrawCommand = InMeshDrawCommand;
  11. DrawPrimitiveId = InDrawPrimitiveId;
  12. ScenePrimitiveId = InScenePrimitiveId;
  13. PrimitiveIdBufferOffset = -1;
  14. StateBucketId = InStateBucketId;
  15. MeshFillMode = InMeshFillMode;
  16. MeshCullMode = InMeshCullMode;
  17. SortKey = InSortKey;
  18. }
  1. class FMeshDrawCommand
  2. {
  3. public:
  4. /**
  5. * Resource bindings
  6. */
  7. FMeshDrawShaderBindings ShaderBindings;
  8. FVertexInputStreamArray VertexStreams;
  9. FRHIIndexBuffer* IndexBuffer;
  10. /**
  11. * PSO
  12. */
  13. FGraphicsMinimalPipelineStateId CachedPipelineId;
  14. /**
  15. * Draw command parameters
  16. */
  17. uint32 FirstIndex;
  18. uint32 NumPrimitives;
  19. uint32 NumInstances;
  20. union
  21. {
  22. struct
  23. {
  24. uint32 BaseVertexIndex;
  25. uint32 NumVertices;
  26. } VertexParams;
  27. struct
  28. {
  29. FRHIVertexBuffer* Buffer;
  30. uint32 Offset;
  31. } IndirectArgs;
  32. };
  33. int8 PrimitiveIdStreamIndex;
  34. /** Non-pipeline state */
  35. uint8 StencilRef;
  36. FMeshDrawCommand() {};
  37. FMeshDrawCommand(FMeshDrawCommand&& Other) = default;
  38. FMeshDrawCommand(const FMeshDrawCommand& Other) = default;
  39. FMeshDrawCommand& operator=(const FMeshDrawCommand& Other) = default;
  40. FMeshDrawCommand& operator=(FMeshDrawCommand&& Other) = default;
  41. bool MatchesForDynamicInstancing(const FMeshDrawCommand& Rhs) const
  42. {
  43. return CachedPipelineId == Rhs.CachedPipelineId
  44. && StencilRef == Rhs.StencilRef
  45. && ShaderBindings.MatchesForDynamicInstancing(Rhs.ShaderBindings)
  46. && VertexStreams == Rhs.VertexStreams
  47. && PrimitiveIdStreamIndex == Rhs.PrimitiveIdStreamIndex
  48. && IndexBuffer == Rhs.IndexBuffer
  49. && FirstIndex == Rhs.FirstIndex
  50. && NumPrimitives == Rhs.NumPrimitives
  51. && NumInstances == Rhs.NumInstances
  52. && ((NumPrimitives > 0 && VertexParams.BaseVertexIndex == Rhs.VertexParams.BaseVertexIndex && VertexParams.NumVertices == Rhs.VertexParams.NumVertices)
  53. || (NumPrimitives == 0 && IndirectArgs.Buffer == Rhs.IndirectArgs.Buffer && IndirectArgs.Offset == Rhs.IndirectArgs.Offset));
  54. }
  55. uint32 GetDynamicInstancingHash() const
  56. {
  57. //add and initialize any leftover padding within the struct to avoid unstable keys
  58. struct FHashKey
  59. {
  60. uint32 IndexBuffer;
  61. uint32 VertexBuffers = 0;
  62. uint32 VertexStreams = 0;
  63. uint32 PipelineId;
  64. uint32 DynamicInstancingHash;
  65. uint32 FirstIndex;
  66. uint32 NumPrimitives;
  67. uint32 NumInstances;
  68. uint32 IndirectArgsBufferOrBaseVertexIndex;
  69. uint32 NumVertices;
  70. uint32 StencilRefAndPrimitiveIdStreamIndex;
  71. static inline uint32 PointerHash(const void* Key)
  72. {
  73. #if PLATFORM_64BITS
  74. // Ignoring the lower 4 bits since they are likely zero anyway.
  75. // Higher bits are more significant in 64 bit builds.
  76. return reinterpret_cast<UPTRINT>(Key) >> 4;
  77. #else
  78. return reinterpret_cast<UPTRINT>(Key);
  79. #endif
  80. };
  81. static inline uint32 HashCombine(uint32 A, uint32 B)
  82. {
  83. return A ^ (B + 0x9e3779b9 + (A << 6) + (A >> 2));
  84. }
  85. } HashKey;
  86. HashKey.PipelineId = CachedPipelineId.GetId();
  87. HashKey.StencilRefAndPrimitiveIdStreamIndex = StencilRef | (PrimitiveIdStreamIndex << 8);
  88. HashKey.DynamicInstancingHash = ShaderBindings.GetDynamicInstancingHash();
  89. for (int index = 0; index < VertexStreams.Num(); index++)
  90. {
  91. const FVertexInputStream& VertexInputStream = VertexStreams[index];
  92. const uint32 StreamIndex = VertexInputStream.StreamIndex;
  93. const uint32 Offset = VertexInputStream.Offset;
  94. uint32 Packed = (StreamIndex << 28) | Offset;
  95. HashKey.VertexStreams = FHashKey::HashCombine(HashKey.VertexStreams, Packed);
  96. HashKey.VertexBuffers = FHashKey::HashCombine(HashKey.VertexBuffers, FHashKey::PointerHash(VertexInputStream.VertexBuffer));
  97. }
  98. HashKey.IndexBuffer = FHashKey::PointerHash(IndexBuffer);
  99. HashKey.FirstIndex = FirstIndex;
  100. HashKey.NumPrimitives = NumPrimitives;
  101. HashKey.NumInstances = NumInstances;
  102. if (NumPrimitives > 0)
  103. {
  104. HashKey.IndirectArgsBufferOrBaseVertexIndex = VertexParams.BaseVertexIndex;
  105. HashKey.NumVertices = VertexParams.NumVertices;
  106. }
  107. else
  108. {
  109. HashKey.IndirectArgsBufferOrBaseVertexIndex = FHashKey::PointerHash(IndirectArgs.Buffer);
  110. HashKey.NumVertices = IndirectArgs.Offset;
  111. }
  112. return uint32(CityHash64((char*)&HashKey, sizeof(FHashKey)));
  113. }
  114. /** Sets shaders on the mesh draw command and allocates room for the shader bindings. */
  115. RENDERER_API void SetShaders(FRHIVertexDeclaration* VertexDeclaration, const FMeshProcessorShaders& Shaders, FGraphicsMinimalPipelineStateInitializer& PipelineState);
  116. inline void SetStencilRef(uint32 InStencilRef)
  117. {
  118. StencilRef = InStencilRef;
  119. // Verify no overflow
  120. checkSlow((uint32)StencilRef == InStencilRef);
  121. }
  122. /** Called when the mesh draw command is complete. */
  123. RENDERER_API void SetDrawParametersAndFinalize(
  124. const FMeshBatch& MeshBatch,
  125. int32 BatchElementIndex,
  126. FGraphicsMinimalPipelineStateId PipelineId,
  127. const FMeshProcessorShaders* ShadersForDebugging);
  128. void Finalize(FGraphicsMinimalPipelineStateId PipelineId, const FMeshProcessorShaders* ShadersForDebugging)
  129. {
  130. CachedPipelineId = PipelineId;
  131. ShaderBindings.Finalize(ShadersForDebugging);
  132. }
  133. /** Submits commands to the RHI Commandlist to draw the MeshDrawCommand. */
  134. static void SubmitDraw(
  135. const FMeshDrawCommand& RESTRICT MeshDrawCommand,
  136. const FGraphicsMinimalPipelineStateSet& GraphicsMinimalPipelineStateSet,
  137. FRHIVertexBuffer* ScenePrimitiveIdsBuffer,
  138. int32 PrimitiveIdOffset,
  139. uint32 InstanceFactor,
  140. FRHICommandList& CommandList,
  141. class FMeshDrawCommandStateCache& RESTRICT StateCache);
  142. FORCENOINLINE friend uint32 GetTypeHash( const FMeshDrawCommand& Other )
  143. {
  144. return Other.CachedPipelineId.GetId();
  145. }
  146. #if MESH_DRAW_COMMAND_DEBUG_DATA
  147. RENDERER_API void SetDebugData(const FPrimitiveSceneProxy* PrimitiveSceneProxy, const FMaterial* Material, const FMaterialRenderProxy* MaterialRenderProxy, const FMeshProcessorShaders& UntypedShaders, const FVertexFactory* VertexFactory);
  148. #else
  149. void SetDebugData(const FPrimitiveSceneProxy* PrimitiveSceneProxy, const FMaterial* Material, const FMaterialRenderProxy* MaterialRenderProxy, const FMeshProcessorShaders& UntypedShaders, const FVertexFactory* VertexFactory){}
  150. #endif
  151. SIZE_T GetAllocatedSize() const
  152. {
  153. return ShaderBindings.GetAllocatedSize() + VertexStreams.GetAllocatedSize();
  154. }
  155. SIZE_T GetDebugDataSize() const
  156. {
  157. #if MESH_DRAW_COMMAND_DEBUG_DATA
  158. return sizeof(DebugData);
  159. #endif
  160. return 0;
  161. }
  162. #if MESH_DRAW_COMMAND_DEBUG_DATA
  163. void ClearDebugPrimitiveSceneProxy() const
  164. {
  165. DebugData.PrimitiveSceneProxyIfNotUsingStateBuckets = nullptr;
  166. }
  167. private:
  168. mutable FMeshDrawCommandDebugData DebugData;
  169. #endif
  170. };

MeshPassProcessor.cpp

  1. void FCachedPassMeshDrawListContext::FinalizeCommand(
  2. const FMeshBatch& MeshBatch,
  3. int32 BatchElementIndex,
  4. int32 DrawPrimitiveId,
  5. int32 ScenePrimitiveId,
  6. ERasterizerFillMode MeshFillMode,
  7. ERasterizerCullMode MeshCullMode,
  8. FMeshDrawCommandSortKey SortKey,
  9. const FGraphicsMinimalPipelineStateInitializer& PipelineState,
  10. const FMeshProcessorShaders* ShadersForDebugging,
  11. FMeshDrawCommand& MeshDrawCommand)
  12. {
  13. // disabling this by default as it incurs a high cost in perf captures due to sheer volume. Recommendation is to re-enable locally if you need to profile this particular code.
  14. // QUICK_SCOPE_CYCLE_COUNTER(STAT_FinalizeCachedMeshDrawCommand);
  15. FGraphicsMinimalPipelineStateId PipelineId = FGraphicsMinimalPipelineStateId::GetPersistentId(PipelineState);
  16. MeshDrawCommand.SetDrawParametersAndFinalize(MeshBatch, BatchElementIndex, PipelineId, ShadersForDebugging);
  17. if (UseGPUScene(GMaxRHIShaderPlatform, GMaxRHIFeatureLevel))
  18. {
  19. Experimental::FHashElementId SetId;
  20. auto hash = CachedMeshDrawCommandStateBuckets.ComputeHash(MeshDrawCommand);
  21. {
  22. FScopeLock Lock(&CachedMeshDrawCommandLock);
  23. #if UE_BUILD_DEBUG
  24. FMeshDrawCommand MeshDrawCommandDebug = FMeshDrawCommand(MeshDrawCommand);
  25. check(MeshDrawCommandDebug.ShaderBindings.GetDynamicInstancingHash() == MeshDrawCommand.ShaderBindings.GetDynamicInstancingHash());
  26. check(MeshDrawCommandDebug.GetDynamicInstancingHash() == MeshDrawCommand.GetDynamicInstancingHash());
  27. #endif
  28. SetId = CachedMeshDrawCommandStateBuckets.FindOrAddIdByHash(hash, MeshDrawCommand, FMeshDrawCommandCount());
  29. CachedMeshDrawCommandStateBuckets.GetByElementId(SetId).Value.Num++;
  30. #if MESH_DRAW_COMMAND_DEBUG_DATA
  31. if (CachedMeshDrawCommandStateBuckets.GetByElementId(SetId).Value.Num == 1)
  32. {
  33. MeshDrawCommand.ClearDebugPrimitiveSceneProxy(); //When using State Buckets multiple PrimitiveSceneProxies use the same MeshDrawCommand, so The PrimitiveSceneProxy pointer can't be stored.
  34. }
  35. #endif
  36. }
  37. check(CommandInfo.StateBucketId == -1);
  38. CommandInfo.StateBucketId = SetId.GetIndex();
  39. check(CommandInfo.CommandIndex == -1);
  40. }
  41. else
  42. {
  43. check(CommandInfo.CommandIndex == -1);
  44. FScopeLock Lock(&CachedMeshDrawCommandLock);
  45. // Only one FMeshDrawCommand supported per FStaticMesh in a pass
  46. // Allocate at lowest free index so that 'r.DoLazyStaticMeshUpdate' can shrink the TSparseArray more effectively
  47. CommandInfo.CommandIndex = CachedDrawLists.MeshDrawCommands.EmplaceAtLowestFreeIndex(CachedDrawLists.LowestFreeIndexSearchStart, MeshDrawCommand);
  48. }
  49. CommandInfo.SortKey = SortKey;
  50. CommandInfo.MeshFillMode = MeshFillMode;
  51. CommandInfo.MeshCullMode = MeshCullMode;
  52. }
  1. void FMeshDrawCommand::SetDrawParametersAndFinalize(
  2. const FMeshBatch& MeshBatch,
  3. int32 BatchElementIndex,
  4. FGraphicsMinimalPipelineStateId PipelineId,
  5. const FMeshProcessorShaders* ShadersForDebugging)
  6. {
  7. const FMeshBatchElement& BatchElement = MeshBatch.Elements[BatchElementIndex];
  8. check(!BatchElement.IndexBuffer || (BatchElement.IndexBuffer && BatchElement.IndexBuffer->IsInitialized() && BatchElement.IndexBuffer->IndexBufferRHI));
  9. checkSlow(!BatchElement.bIsInstanceRuns);
  10. IndexBuffer = BatchElement.IndexBuffer ? BatchElement.IndexBuffer->IndexBufferRHI.GetReference() : nullptr;
  11. FirstIndex = BatchElement.FirstIndex;
  12. NumPrimitives = BatchElement.NumPrimitives;
  13. NumInstances = BatchElement.NumInstances;
  14. if (NumPrimitives > 0)
  15. {
  16. VertexParams.BaseVertexIndex = BatchElement.BaseVertexIndex;
  17. VertexParams.NumVertices = BatchElement.MaxVertexIndex - BatchElement.MinVertexIndex + 1;
  18. checkf(!BatchElement.IndirectArgsBuffer, TEXT("FMeshBatchElement::NumPrimitives must be set to 0 when a IndirectArgsBuffer is used"));
  19. }
  20. else
  21. {
  22. checkf(BatchElement.IndirectArgsBuffer, TEXT("It is only valid to set BatchElement.NumPrimitives == 0 when a IndirectArgsBuffer is used"));
  23. IndirectArgs.Buffer = BatchElement.IndirectArgsBuffer;
  24. IndirectArgs.Offset = BatchElement.IndirectArgsOffset;
  25. }
  26. Finalize(PipelineId, ShadersForDebugging);
  27. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/91463
推荐阅读
相关标签
  

闽ICP备14008679号