/// <inheritdoc/> public override void Prepare(RenderThreadContext context) { // Assign descriptor sets to each render node var resourceGroupPool = ((RootEffectRenderFeature)RootRenderFeature).ResourceGroupPool; for (int renderNodeIndex = 0; renderNodeIndex < RootRenderFeature.RenderNodes.Count; renderNodeIndex++) { var renderNodeReference = new RenderNodeReference(renderNodeIndex); var renderNode = RootRenderFeature.RenderNodes[renderNodeIndex]; var renderMesh = (RenderMesh)renderNode.RenderObject; // Ignore fallback effects if (renderNode.RenderEffect.State != RenderEffectState.Normal) { continue; } // Collect materials and create associated MaterialInfo (includes reflection) first time // TODO: We assume same material will generate same ResourceGroup (i.e. same resources declared in same order) // Need to offer some protection if this invariant is violated (or support it if it can actually happen in real scenario) var material = renderMesh.Material; var materialInfo = renderMesh.MaterialInfo; var materialParameters = material.Parameters; if (!UpdateMaterial(RenderSystem, context, materialInfo, perMaterialDescriptorSetSlot.Index, renderNode.RenderEffect, materialParameters)) { continue; } var descriptorSetPoolOffset = ((RootEffectRenderFeature)RootRenderFeature).ComputeResourceGroupOffset(renderNodeReference); resourceGroupPool[descriptorSetPoolOffset + perMaterialDescriptorSetSlot.Index] = materialInfo.Resources; } }
/// <inheritdoc/> public override void Prepare(RenderThreadContext context) { var renderViewObjectInfoData = RootRenderFeature.RenderData.GetData(renderViewObjectInfoKey); var resourceGroupPool = ((RootEffectRenderFeature)RootRenderFeature).ResourceGroupPool; for (int renderNodeIndex = 0; renderNodeIndex < RootRenderFeature.RenderNodes.Count; renderNodeIndex++) { var renderNodeReference = new RenderNodeReference(renderNodeIndex); var renderNode = RootRenderFeature.RenderNodes[renderNodeIndex]; var renderViewObjectInfo = renderViewObjectInfoData[renderNode.ViewObjectNode]; if (renderViewObjectInfo == null) { continue; } // Ignore fallback effects if (renderNode.RenderEffect.State != RenderEffectState.Normal) { continue; } if (!PrepareLightParameterEntry(context, renderViewObjectInfo, renderNode.RenderEffect)) { continue; } var resourceGroupPoolOffset = ((RootEffectRenderFeature)RootRenderFeature).ComputeResourceGroupOffset(renderNodeReference); resourceGroupPool[resourceGroupPoolOffset + perLightingDescriptorSetSlot.Index] = renderViewObjectInfo.Resources; } }
/// <param name="context"></param> /// <inheritdoc/> public override void PrepareEffectPermutationsImpl(RenderThreadContext context) { var renderEffects = RenderData.GetData(RenderEffectKey); foreach (var renderObject in RenderObjects) { var staticObjectNode = renderObject.StaticObjectNode; for (int i = 0; i < EffectPermutationSlotCount; ++i) { var staticEffectObjectNode = staticObjectNode * EffectPermutationSlotCount + i; var renderEffect = renderEffects[staticEffectObjectNode]; var renderSkybox = (RenderSkybox)renderObject; // Skip effects not used during this frame if (renderEffect == null || !renderEffect.IsUsedDuringThisFrame(RenderSystem)) { continue; } var parameters = renderSkybox.Background == SkyboxBackground.Irradiance ? renderSkybox.Skybox.DiffuseLightingParameters : renderSkybox.Skybox.Parameters; var shader = parameters.Get(SkyboxKeys.Shader); if (shader == null) { renderEffect.EffectValidator.ShouldSkip = true; } renderEffect.EffectValidator.ValidateParameter(SkyboxKeys.Shader, shader); } } transformRenderFeature.PrepareEffectPermutations(context); }
/// <inheritdoc/> public override void PrepareEffectPermutationsImpl(RenderThreadContext context) { base.PrepareEffectPermutationsImpl(context); var renderEffects = RenderData.GetData(renderEffectKey); int effectSlotCount = EffectPermutationSlotCount; // Update existing materials foreach (var material in allMaterialInfos) { material.Key.Setup(RenderSystem.RenderContextOld); } foreach (var renderObject in RenderObjects) { var staticObjectNode = renderObject.StaticObjectNode; var renderParticleEmitter = (RenderParticleEmitter)renderObject; var material = renderParticleEmitter.ParticleEmitter.Material; var materialInfo = renderParticleEmitter.ParticleMaterialInfo; for (int i = 0; i < effectSlotCount; ++i) { var staticEffectObjectNode = staticObjectNode * effectSlotCount + i; var renderEffect = renderEffects[staticEffectObjectNode]; // Skip effects not used during this frame if (renderEffect == null || !renderEffect.IsUsedDuringThisFrame(RenderSystem)) { continue; } if (materialInfo == null || materialInfo.Material != material) { // First time this material is initialized, let's create associated info if (!allMaterialInfos.TryGetValue(material, out materialInfo)) { materialInfo = new ParticleMaterialInfo(material); allMaterialInfos.Add(material, materialInfo); } renderParticleEmitter.ParticleMaterialInfo = materialInfo; // Update new materials material.Setup(RenderSystem.RenderContextOld); } // TODO: Iterate PermuatationParameters automatically? material.ValidateEffect(RenderSystem.RenderContextOld, ref renderEffect.EffectValidator); } } }
void SinglePassPreRender() { if (needInitPropertyId) { id_unity_StereoCameraProjection = Shader.PropertyToID("unity_StereoCameraProjection"); id_unity_StereoCameraInvProjection = Shader.PropertyToID("unity_StereoCameraInvProjection"); id_unity_StereoMatrixP = Shader.PropertyToID("unity_StereoMatrixP"); id_unity_StereoCameraToWorld = Shader.PropertyToID("unity_StereoCameraToWorld"); id_unity_StereoWorldToCamera = Shader.PropertyToID("unity_StereoWorldToCamera"); id_unity_StereoWorldSpaceCameraPos = Shader.PropertyToID("unity_StereoWorldSpaceCameraPos"); id_unity_StereoMatrixV = Shader.PropertyToID("unity_StereoMatrixV"); id_unity_StereoMatrixInvV = Shader.PropertyToID("unity_StereoMatrixInvV"); id_unity_StereoMatrixVP = Shader.PropertyToID("unity_StereoMatrixVP"); id_unity_StereoScaleOffset = Shader.PropertyToID("unity_StereoScaleOffset"); needInitPropertyId = false; } var texturepool = WaveVR_Render.Instance.textureManager.both; RenderThreadContext.IssueUpdateConfig(RTSOUpdateConfig, (uint)texturepool.currentPtr, (uint)texturepool.currentDepthPtr, cam.allowMSAA ? QualitySettings.antiAliasing : 0); // TODO The matrix process here is too slow and cause many GL.Allocate(). //Unity will not handle these Stereo shader variables for us, so we have to set it all by ourselves Shader.SetGlobalMatrixArray(id_unity_StereoCameraProjection, unity_StereoMatrixP); Shader.SetGlobalMatrixArray(id_unity_StereoCameraInvProjection, unity_StereoMatrixInvP); Shader.SetGlobalMatrixArray(id_unity_StereoMatrixP, unity_StereoMatrixP); //Since eyes are moving, so below variables need to re-calculate every frame. Matrix4x4 world2Camera = cam.worldToCameraMatrix; // View matrix Matrix4x4 camera2World = cam.cameraToWorldMatrix; M4Multiply(ref unity_StereoCameraToWorld[0], ref camera2World, ref eyesOffsetMatrix[0]); M4Multiply(ref unity_StereoCameraToWorld[1], ref camera2World, ref eyesOffsetMatrix[1]); M4Multiply(ref unity_StereoWorldToCamera[0], ref eyesOffsetMatrixInv[0], ref world2Camera); M4Multiply(ref unity_StereoWorldToCamera[1], ref eyesOffsetMatrixInv[1], ref world2Camera); // TODO Need to know if this can help set shader... //SetStereoViewAndCullingMatrix(unity_StereoWorldToCamera[0], unity_StereoWorldToCamera[1]); // Put later than SetStereoViewMatrix() to avoid be overrided. Shader.SetGlobalMatrixArray(id_unity_StereoCameraToWorld, unity_StereoCameraToWorld); Shader.SetGlobalMatrixArray(id_unity_StereoWorldToCamera, unity_StereoWorldToCamera); //So the camera positons Vector4 campos = cam.transform.position; V4Add(ref stereoWorldSpaceCameraPos[0], ref campos, ref eyesOffset[0]); V4Add(ref stereoWorldSpaceCameraPos[1], ref campos, ref eyesOffset[1]); Shader.SetGlobalVectorArray(id_unity_StereoWorldSpaceCameraPos, stereoWorldSpaceCameraPos); //camera.worldToCameraMatrix is the view matrix Shader.SetGlobalMatrixArray(id_unity_StereoMatrixV, unity_StereoWorldToCamera); Shader.SetGlobalMatrixArray(id_unity_StereoMatrixInvV, unity_StereoCameraToWorld); //MatrixVP is the value UNITY_MATRIX_VP used in shader M4Multiply(ref unity_StereoMatrixVP[0], ref unity_StereoMatrixP[0], ref unity_StereoWorldToCamera[0]); M4Multiply(ref unity_StereoMatrixVP[1], ref unity_StereoMatrixP[1], ref unity_StereoWorldToCamera[1]); Shader.SetGlobalMatrixArray(id_unity_StereoMatrixVP, unity_StereoMatrixVP); Shader.SetGlobalVectorArray(id_unity_StereoScaleOffset, unity_StereoScaleOffset); PrepareCommandBuffers(); }
public void CopyTo(RenderThreadContext dest) { dest.antialiasing = antialiasing; dest.textureId = textureId; dest.depthId = depthId; }
private unsafe bool PrepareLightParameterEntry(RenderThreadContext context, LightParametersPermutationEntry lightParameterEntry, RenderEffect renderEffect) { var lightShadersPermutation = lightParameterEntry.ShaderPermutationEntry; // Create layout for new light shader permutations if (lightShadersPermutation.PerLightingLayout == null || lightShadersPermutation.PerLightingLayout.Hash != renderEffect.Reflection.ResourceGroupDescriptions[perLightingDescriptorSetSlot.Index].Hash) { var resourceGroupDescription = renderEffect.Reflection.ResourceGroupDescriptions[perLightingDescriptorSetSlot.Index]; if (resourceGroupDescription.DescriptorSetLayout == null) { return(false); } var parameterCollectionLayout = lightShadersPermutation.ParameterCollectionLayout = new ParameterCollectionLayout(); parameterCollectionLayout.ProcessResources(resourceGroupDescription.DescriptorSetLayout); lightShadersPermutation.ResourceCount = parameterCollectionLayout.ResourceCount; // Process PerLighting cbuffer (if any) if (resourceGroupDescription.ConstantBufferReflection != null) { lightShadersPermutation.ConstantBufferReflection = resourceGroupDescription.ConstantBufferReflection; parameterCollectionLayout.ProcessConstantBuffer(resourceGroupDescription.ConstantBufferReflection); } lightShadersPermutation.PerLightingLayout = ResourceGroupLayout.New(RenderSystem.GraphicsDevice, resourceGroupDescription, renderEffect.Effect.Bytecode); } // Assign layout to new parameter permutations var parameters = lightParameterEntry.Parameters; if (parameters.Layout != lightShadersPermutation.ParameterCollectionLayout) { // TODO GRAPHICS REFACTOR should we recompute or store the parameter layout? parameters.UpdateLayout(lightShadersPermutation.ParameterCollectionLayout); } // Do we need to allocate resources? if (lightParameterEntry.LastFrameUsed == RenderSystem.FrameCounter) { return(true); } lightParameterEntry.LastFrameUsed = RenderSystem.FrameCounter; // Set values foreach (var lightGroup in lightParameterEntry.DirectLightGroupDatas) { lightGroup.ApplyParameters(parameters); } foreach (var lightGroup in lightParameterEntry.EnvironmentLightDatas) { lightGroup.ApplyParameters(parameters); } context.ResourceGroupAllocator.PrepareResourceGroup(lightShadersPermutation.PerLightingLayout, BufferPoolAllocationType.UsedMultipleTime, lightParameterEntry.Resources); // Set resource bindings in PerLighting resource set for (int resourceSlot = 0; resourceSlot < lightShadersPermutation.ResourceCount; ++resourceSlot) { lightParameterEntry.Resources.DescriptorSet.SetValue(resourceSlot, parameters.ObjectValues[resourceSlot]); } // Process PerMaterial cbuffer if (lightShadersPermutation.ConstantBufferReflection != null) { var mappedCB = lightParameterEntry.Resources.ConstantBuffer.Data; fixed(byte *dataValues = parameters.DataValues) Utilities.CopyMemory(mappedCB, (IntPtr)dataValues, lightParameterEntry.Resources.ConstantBuffer.Size); } return(true); }
/// <param name="context"></param> /// <inheritdoc/> public override void PrepareEffectPermutations(RenderThreadContext context) { var renderEffects = RootRenderFeature.RenderData.GetData(renderEffectKey); int effectSlotCount = ((RootEffectRenderFeature)RootRenderFeature).EffectPermutationSlotCount; var renderViewObjectInfoData = RootRenderFeature.RenderData.GetData(renderViewObjectInfoKey); var shadowMapEffectSlot = ShadowMapRenderStage != null ? ((RootEffectRenderFeature)RootRenderFeature).GetEffectPermutationSlot(ShadowMapRenderStage) : EffectPermutationSlot.Invalid; foreach (var view in RenderSystem.Views) { if (view.GetType() != typeof(RenderView)) { continue; } RenderViewLightData renderViewData; if (!renderViewDatas.TryGetValue(view, out renderViewData)) { continue; } var viewFeature = view.Features[RootRenderFeature.Index]; foreach (var renderPerViewNodeReference in viewFeature.ViewObjectNodes) { var renderPerViewNode = RootRenderFeature.GetViewObjectNode(renderPerViewNodeReference); var renderMesh = (RenderMesh)renderPerViewNode.RenderObject; if (!renderMesh.Material.IsLightDependent) { continue; } var staticObjectNode = renderMesh.StaticObjectNode; for (int i = 0; i < effectSlotCount; ++i) { // Don't apply lighting for shadow casters if (i == shadowMapEffectSlot.Index) { continue; } var staticEffectObjectNode = staticObjectNode * effectSlotCount + i; var renderEffect = renderEffects[staticEffectObjectNode]; // Skip effects not used during this frame if (renderEffect == null || !renderEffect.IsUsedDuringThisFrame(RenderSystem)) { continue; } var renderModel = renderMesh.RenderModel; var modelComponent = renderModel.ModelComponent; var isShadowReceiver = renderMesh.IsShadowReceiver && modelComponent.IsShadowReceiver; // TODO GRAPHICS REFACTOR: Shader permutations can be collected per-object. Only parameter permutations need to be per-view-object. var renderObjectInfo = PreparePermutationEntryForRendering(renderViewData, isShadowReceiver, ref modelComponent.BoundingBox, modelComponent.Entity.Group, i); renderObjectInfo.ApplyEffectPermutations(renderEffect); renderViewObjectInfoData[renderPerViewNodeReference] = renderObjectInfo; if (renderObjectInfo == null) { continue; } renderEffect.EffectValidator.ValidateParameter(LightingKeys.DirectLightGroups, renderObjectInfo.ShaderPermutationEntry.DirectLightShaders); renderEffect.EffectValidator.ValidateParameter(LightingKeys.EnvironmentLights, renderObjectInfo.ShaderPermutationEntry.EnvironmentLightShaders); } } } }
/// <inheritdoc/> public override unsafe void Prepare(RenderThreadContext context) { base.Prepare(context); for (int renderNodeIndex = 0; renderNodeIndex < RenderNodes.Count; renderNodeIndex++) { var renderNodeReference = new RenderNodeReference(renderNodeIndex); var renderNode = RenderNodes[renderNodeIndex]; var renderSkybox = (RenderSkybox)renderNode.RenderObject; var sourceParameters = renderSkybox.Background == SkyboxBackground.Irradiance ? renderSkybox.Skybox.DiffuseLightingParameters : renderSkybox.Skybox.Parameters; var skyboxInfo = renderSkybox.SkyboxInfo; if (skyboxInfo == null || skyboxInfo.Skybox != renderSkybox.Skybox) { skyboxInfo = renderSkybox.SkyboxInfo = new SkyboxInfo(renderSkybox.Skybox); } var parameters = skyboxInfo.ParameterCollection; var renderEffect = renderNode.RenderEffect; if (renderEffect.State != RenderEffectState.Normal) { continue; } // TODO GRAPHICS REFACTOR current system is not really safe with multiple renderers (parameters come from Skybox which is shared but ResourceGroupLayout from RenderSkybox is per RenderNode) if (skyboxInfo.ResourceGroupLayout == null || skyboxInfo.ResourceGroupLayout.Hash != renderEffect.Reflection.ResourceGroupDescriptions[perLightingDescriptorSetSlot.Index].Hash) { var resourceGroupDescription = renderEffect.Reflection.ResourceGroupDescriptions[perLightingDescriptorSetSlot.Index]; var parameterCollectionLayout = skyboxInfo.ParameterCollectionLayout = new ParameterCollectionLayout(); parameterCollectionLayout.ProcessResources(resourceGroupDescription.DescriptorSetLayout); // Find material cbuffer if (resourceGroupDescription.ConstantBufferReflection != null) { parameterCollectionLayout.ProcessConstantBuffer(resourceGroupDescription.ConstantBufferReflection); } //skyboxInfo.RotationParameter = parameters.GetAccessor(SkyboxKeys.Rotation); //skyboxInfo.SkyMatrixParameter = parameters.GetAccessor(SkyboxKeys.SkyMatrix); // TODO: Cache that skyboxInfo.ResourceGroupLayout = ResourceGroupLayout.New(RenderSystem.GraphicsDevice, resourceGroupDescription, renderEffect.Effect.Bytecode); parameters.UpdateLayout(parameterCollectionLayout); if (renderSkybox.Background == SkyboxBackground.Irradiance) { skyboxInfo.ParameterCollectionCopier = new ParameterCollection.Copier(parameters, sourceParameters, ".skyboxColor"); } else { skyboxInfo.ParameterCollectionCopier = new ParameterCollection.Copier(parameters, sourceParameters); } } skyboxInfo.ParameterCollectionCopier.Copy(); // Setup the intensity parameters.Set(SkyboxKeys.Intensity, renderSkybox.Intensity); // Update SkyMatrix Matrix skyMatrix; Matrix.RotationQuaternion(ref renderSkybox.Rotation, out skyMatrix); parameters.Set(SkyboxKeys.SkyMatrix, ref skyMatrix); // Update MatrixTransform // TODO: Use default values? var matrixTransformOffset = renderNode.RenderEffect.Reflection.PerDrawLayout.GetConstantBufferOffset(this.matrixTransform); if (matrixTransformOffset != -1) { var mappedCB = renderNode.Resources.ConstantBuffer.Data + matrixTransformOffset; Matrix.Translation(0.0f, 0.0f, 1.0f, out *(Matrix *)(byte *)mappedCB); } var descriptorSetPoolOffset = ComputeResourceGroupOffset(renderNodeReference); context.ResourceGroupAllocator.PrepareResourceGroup(skyboxInfo.ResourceGroupLayout, BufferPoolAllocationType.UsedMultipleTime, skyboxInfo.Resources); ResourceGroupPool[descriptorSetPoolOffset + perLightingDescriptorSetSlot.Index] = skyboxInfo.Resources; var descriptorSet = skyboxInfo.Resources.DescriptorSet; // Set resource bindings in PerLighting resource set for (int resourceSlot = 0; resourceSlot < parameters.Layout.ResourceCount; ++resourceSlot) { descriptorSet.SetValue(resourceSlot, parameters.ObjectValues[resourceSlot]); } // Process PerLighting cbuffer if (skyboxInfo.Resources.ConstantBuffer.Size > 0) { var mappedCB = skyboxInfo.Resources.ConstantBuffer.Data; fixed(byte *dataValues = parameters.DataValues) Utilities.CopyMemory(mappedCB, (IntPtr)dataValues, skyboxInfo.Resources.ConstantBuffer.Size); } } transformRenderFeature.Prepare(context); }
/// <param name="context"></param> /// <inheritdoc/> public override void PrepareEffectPermutations(RenderThreadContext context) { var renderEffects = RootRenderFeature.RenderData.GetData(renderEffectKey); var tessellationStates = RootRenderFeature.RenderData.GetData(tessellationStateKey); int effectSlotCount = ((RootEffectRenderFeature)RootRenderFeature).EffectPermutationSlotCount; foreach (var renderObject in RootRenderFeature.RenderObjects) { var staticObjectNode = renderObject.StaticObjectNode; var renderMesh = (RenderMesh)renderObject; var material = renderMesh.Material; var materialInfo = renderMesh.MaterialInfo; // Material use first 16 bits var materialHashCode = material != null ? (uint)material.GetHashCode() : 0; renderObject.StateSortKey = (renderObject.StateSortKey & 0x0000FFFF) | (materialHashCode << 16); var tessellationState = tessellationStates[staticObjectNode]; // Update draw data if tessellation is active if (material.TessellationMethod != XenkoTessellationMethod.None) { var tessellationMeshDraw = tessellationState.MeshDraw; if (tessellationState.Method != material.TessellationMethod) { tessellationState.Method = material.TessellationMethod; var oldMeshDraw = renderMesh.ActiveMeshDraw; tessellationMeshDraw = new MeshDraw { VertexBuffers = oldMeshDraw.VertexBuffers, IndexBuffer = oldMeshDraw.IndexBuffer, DrawCount = oldMeshDraw.DrawCount, StartLocation = oldMeshDraw.StartLocation, PrimitiveType = tessellationState.Method.GetPrimitiveType(), }; // adapt the primitive type and index buffer to the tessellation used if (tessellationState.Method.PerformsAdjacentEdgeAverage()) { renderMeshesToGenerateAEN.Add(renderMesh); } else { // Not using AEN tessellation anymore, dispose AEN indices if they were generated Utilities.Dispose(ref tessellationState.GeneratedIndicesAEN); } tessellationState.MeshDraw = tessellationMeshDraw; // Save back new state tessellationStates[staticObjectNode] = tessellationState; // Reset pipeline states for (int i = 0; i < effectSlotCount; ++i) { var staticEffectObjectNode = staticObjectNode * effectSlotCount + i; var renderEffect = renderEffects[staticEffectObjectNode]; if (renderEffect != null) { renderEffect.PipelineState = null; } } } renderMesh.ActiveMeshDraw = tessellationState.MeshDraw; } else if (tessellationState.GeneratedIndicesAEN != null) { // Not using tessellation anymore, dispose AEN indices if they were generated Utilities.Dispose(ref tessellationState.GeneratedIndicesAEN); } for (int i = 0; i < effectSlotCount; ++i) { var staticEffectObjectNode = staticObjectNode * effectSlotCount + i; var renderEffect = renderEffects[staticEffectObjectNode]; // Skip effects not used during this frame if (renderEffect == null || !renderEffect.IsUsedDuringThisFrame(RenderSystem)) { continue; } if (materialInfo == null || materialInfo.Material != material) { // First time this material is initialized, let's create associated info if (!allMaterialInfos.TryGetValue(material, out materialInfo)) { materialInfo = new MaterialInfo(material); allMaterialInfos.Add(material, materialInfo); } renderMesh.MaterialInfo = materialInfo; } if (materialInfo.CullMode != material.CullMode) { materialInfo.CullMode = material.CullMode; renderEffect.PipelineState = null; } var isMaterialParametersChanged = materialInfo.MaterialParameters != material.Parameters; if (isMaterialParametersChanged || // parameter fast reload? materialInfo.PermutationCounter != material.Parameters.PermutationCounter) { materialInfo.VertexStageSurfaceShaders = material.Parameters.Get(MaterialKeys.VertexStageSurfaceShaders); materialInfo.VertexStageStreamInitializer = material.Parameters.Get(MaterialKeys.VertexStageStreamInitializer); materialInfo.DomainStageSurfaceShaders = material.Parameters.Get(MaterialKeys.DomainStageSurfaceShaders); materialInfo.DomainStageStreamInitializer = material.Parameters.Get(MaterialKeys.DomainStageStreamInitializer); materialInfo.TessellationShader = material.Parameters.Get(MaterialKeys.TessellationShader); materialInfo.PixelStageSurfaceShaders = material.Parameters.Get(MaterialKeys.PixelStageSurfaceShaders); materialInfo.PixelStageStreamInitializer = material.Parameters.Get(MaterialKeys.PixelStageStreamInitializer); materialInfo.HasNormalMap = material.Parameters.Get(MaterialKeys.HasNormalMap); materialInfo.MaterialParameters = material.Parameters; materialInfo.ParametersChanged = isMaterialParametersChanged; materialInfo.PermutationCounter = material.Parameters.PermutationCounter; } // VS if (materialInfo.VertexStageSurfaceShaders != null) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.VertexStageSurfaceShaders, materialInfo.VertexStageSurfaceShaders); } if (materialInfo.VertexStageStreamInitializer != null) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.VertexStageStreamInitializer, materialInfo.VertexStageStreamInitializer); } // DS if (materialInfo.DomainStageSurfaceShaders != null) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.DomainStageSurfaceShaders, materialInfo.DomainStageSurfaceShaders); } if (materialInfo.DomainStageStreamInitializer != null) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.DomainStageStreamInitializer, materialInfo.DomainStageStreamInitializer); } // Tessellation if (materialInfo.TessellationShader != null) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.TessellationShader, materialInfo.TessellationShader); } // PS if (materialInfo.PixelStageSurfaceShaders != null) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.PixelStageSurfaceShaders, materialInfo.PixelStageSurfaceShaders); } if (materialInfo.PixelStageStreamInitializer != null) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.PixelStageStreamInitializer, materialInfo.PixelStageStreamInitializer); } if (materialInfo.HasNormalMap) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.HasNormalMap, materialInfo.HasNormalMap); } } } }
public static unsafe bool UpdateMaterial(RenderSystem renderSystem, RenderThreadContext context, MaterialInfoBase materialInfo, int materialSlotIndex, RenderEffect renderEffect, ParameterCollection materialParameters) { // Check if encountered first time this frame if (materialInfo.LastFrameUsed == renderSystem.FrameCounter) { return(true); } // First time we use the material with a valid effect, let's update layouts if (materialInfo.PerMaterialLayout == null || materialInfo.PerMaterialLayout.Hash != renderEffect.Reflection.ResourceGroupDescriptions[materialSlotIndex].Hash) { var resourceGroupDescription = renderEffect.Reflection.ResourceGroupDescriptions[materialSlotIndex]; if (resourceGroupDescription.DescriptorSetLayout == null) { return(false); } materialInfo.PerMaterialLayout = ResourceGroupLayout.New(renderSystem.GraphicsDevice, resourceGroupDescription, renderEffect.Effect.Bytecode); var parameterCollectionLayout = materialInfo.ParameterCollectionLayout = new ParameterCollectionLayout(); parameterCollectionLayout.ProcessResources(resourceGroupDescription.DescriptorSetLayout); materialInfo.ResourceCount = parameterCollectionLayout.ResourceCount; // Process material cbuffer (if any) if (resourceGroupDescription.ConstantBufferReflection != null) { materialInfo.ConstantBufferReflection = resourceGroupDescription.ConstantBufferReflection; parameterCollectionLayout.ProcessConstantBuffer(resourceGroupDescription.ConstantBufferReflection); } materialInfo.ParametersChanged = true; } // If the parameters collection instance changed, we need to update it if (materialInfo.ParametersChanged) { materialInfo.ParameterCollection.UpdateLayout(materialInfo.ParameterCollectionLayout); materialInfo.ParameterCollectionCopier = new ParameterCollection.Copier(materialInfo.ParameterCollection, materialParameters); materialInfo.ParametersChanged = false; } // Mark this material as used during this frame materialInfo.LastFrameUsed = renderSystem.FrameCounter; // Copy back to ParameterCollection // TODO GRAPHICS REFACTOR directly copy to resource group? materialInfo.ParameterCollectionCopier.Copy(); // Allocate resource groups context.ResourceGroupAllocator.PrepareResourceGroup(materialInfo.PerMaterialLayout, BufferPoolAllocationType.UsedMultipleTime, materialInfo.Resources); // Set resource bindings in PerMaterial resource set for (int resourceSlot = 0; resourceSlot < materialInfo.ResourceCount; ++resourceSlot) { materialInfo.Resources.DescriptorSet.SetValue(resourceSlot, materialInfo.ParameterCollection.ObjectValues[resourceSlot]); } // Process PerMaterial cbuffer if (materialInfo.ConstantBufferReflection != null) { var mappedCB = materialInfo.Resources.ConstantBuffer.Data; fixed(byte *dataValues = materialInfo.ParameterCollection.DataValues) Utilities.CopyMemory(mappedCB, (IntPtr)dataValues, materialInfo.Resources.ConstantBuffer.Size); } return(true); }
/// <inheritdoc/> public override unsafe void Prepare(RenderThreadContext context) { // Reset pipeline states if necessary for (int renderNodeIndex = 0; renderNodeIndex < RenderNodes.Count; renderNodeIndex++) { var renderNode = RenderNodes[renderNodeIndex]; var renderParticleEmitter = (RenderParticleEmitter)renderNode.RenderObject; if (renderParticleEmitter.ParticleEmitter.VertexBuilder.IsBufferDirty) { // Reset pipeline state, so input layout is regenerated if (renderNode.RenderEffect != null) { renderNode.RenderEffect.PipelineState = null; } } } foreach (var renderObject in RenderObjects) { var renderParticleEmitter = (RenderParticleEmitter)renderObject; renderParticleEmitter.ParticleEmitter.PrepareForDraw(); var materialInfo = (ParticleMaterialInfo)renderParticleEmitter.ParticleMaterialInfo; // Handle vertex element changes if (renderParticleEmitter.ParticleEmitter.VertexBuilder.IsBufferDirty) { // Create new buffers renderParticleEmitter.ParticleEmitter.VertexBuilder.RecreateBuffers(RenderSystem.GraphicsDevice); } // TODO: ParticleMaterial should set this up materialInfo?.Material.Parameters.Set(ParticleBaseKeys.ColorScale, renderParticleEmitter.RenderParticleSystem.ParticleSystemComponent.Color); } base.Prepare(context); // Assign descriptor sets to each render node var resourceGroupPool = ResourceGroupPool; for (int renderNodeIndex = 0; renderNodeIndex < RenderNodes.Count; renderNodeIndex++) { var renderNodeReference = new RenderNodeReference(renderNodeIndex); var renderNode = RenderNodes[renderNodeIndex]; var renderParticleEmitter = (RenderParticleEmitter)renderNode.RenderObject; // Ignore fallback effects if (renderNode.RenderEffect.State != RenderEffectState.Normal) { continue; } // Collect materials and create associated MaterialInfo (includes reflection) first time // TODO: We assume same material will generate same ResourceGroup (i.e. same resources declared in same order) // Need to offer some protection if this invariant is violated (or support it if it can actually happen in real scenario) var material = renderParticleEmitter.ParticleEmitter.Material; var materialInfo = renderParticleEmitter.ParticleMaterialInfo; var materialParameters = material.Parameters; if (!MaterialRenderFeature.UpdateMaterial(RenderSystem, context, materialInfo, perMaterialDescriptorSetSlot.Index, renderNode.RenderEffect, materialParameters)) { continue; } var descriptorSetPoolOffset = ComputeResourceGroupOffset(renderNodeReference); resourceGroupPool[descriptorSetPoolOffset + perMaterialDescriptorSetSlot.Index] = materialInfo.Resources; } // Per view // TODO: Transform sub render feature? for (int index = 0; index < RenderSystem.Views.Count; index++) { var view = RenderSystem.Views[index]; var viewFeature = view.Features[Index]; // TODO GRAPHICS REFACTOR: Happens in several places Matrix.Multiply(ref view.View, ref view.Projection, out view.ViewProjection); // Copy ViewProjection to PerFrame cbuffer foreach (var viewLayout in viewFeature.Layouts) { var viewProjectionOffset = viewLayout.GetConstantBufferOffset(this.view); if (viewProjectionOffset == -1) { continue; } var resourceGroup = viewLayout.Entries[view.Index].Resources; var mappedCB = resourceGroup.ConstantBuffer.Data; var perView = (Matrix *)((byte *)mappedCB + viewProjectionOffset); * perView = view.ViewProjection; } } }