Release Type: Official Release
Version: 4.4 beta 4
Platform(s): Windows
Describe the bug
When I reload scripts after changing them in the IDE, the Game Studio crashes.
To Reproduce
This started when I created a split screen renderer and used it in my graphics compositor.
[DataContract]
public class SplitScreenRenderer : SceneRendererBase
{
/// <summary>
/// Gets or sets the camera.
/// </summary>
/// <value>The camera.</value>
/// <userdoc>The camera to use to render the scene.</userdoc>
public required SceneCameraSlot LeftCamera { get; init; }
public required SceneCameraSlot RightCamera { get; init; }
public required ISceneRenderer ForwardRenderer { get; init; }
public required ISceneRenderer DebugRenderer { get; init; }
[Range(0.0f, 1.0f)]
public float SplitPosition { get; set; } = 0.5f;
[Range(0.0f, 1.0f)]
public float SeparatorWidth { get; set; } = 0f;
public Vector4 SeparatorColor { get; set; } = new Vector4(0, 0, 0, 1);
#nullable disable
private SceneCameraRenderer leftCameraRenderer;
private SceneCameraRenderer rightCameraRenderer;
private RenderTextureSceneRenderer leftRenderTextureSceneRenderer;
private RenderTextureSceneRenderer rightRenderTextureSceneRenderer;
private SceneRendererCollection leftRendererCollection;
private SceneRendererCollection rightRendererCollection;
private SplitScreenCompositeEffect compositeEffect;
#nullable restore
protected override void InitializeCore()
{
compositeEffect = ToLoadAndUnload(new SplitScreenCompositeEffect()); // hooks lifecycle into the renderer
leftRendererCollection = ToLoadAndUnload(new SceneRendererCollection()
{
Children = { ForwardRenderer, DebugRenderer }
});
rightRendererCollection = ToLoadAndUnload(new SceneRendererCollection()
{
Children = { ForwardRenderer, DebugRenderer }
});
Texture leftRenderTexture = Texture.New2D(GraphicsDevice, 1, 1, PixelFormat.R8G8B8A8_UNorm_SRgb, TextureFlags.ShaderResource | TextureFlags.RenderTarget);
Texture rightRenderTexture = Texture.New2D(GraphicsDevice, 1, 1, PixelFormat.R8G8B8A8_UNorm_SRgb, TextureFlags.ShaderResource | TextureFlags.RenderTarget);
leftRenderTextureSceneRenderer = ToLoadAndUnload(new RenderTextureSceneRenderer()
{
RenderTexture = leftRenderTexture,
Child = leftRendererCollection,
});
rightRenderTextureSceneRenderer = ToLoadAndUnload(new RenderTextureSceneRenderer()
{
RenderTexture = rightRenderTexture,
Child = rightRendererCollection,
});
leftCameraRenderer = ToLoadAndUnload(new SceneCameraRenderer()
{
Camera = LeftCamera,
Child = leftRenderTextureSceneRenderer,
});
rightCameraRenderer = ToLoadAndUnload(new SceneCameraRenderer()
{
Camera = RightCamera,
Child = rightRenderTextureSceneRenderer,
});
}
protected override void CollectCore(RenderContext context)
{
leftCameraRenderer.Collect(context);
rightCameraRenderer.Collect(context);
}
protected override void DrawCore(RenderContext context, RenderDrawContext drawContext)
{
// Reallocate offscreen targets matching the output size if needed
// TODO: We currently render twice as many pixels as we need to, since we render the left and right cameras at full resolution.
// We could optimize this by rendering at half resolution, but that requires changes to the shader.
var outputTarget = drawContext.CommandList.RenderTarget;
MaybeReplaceTexture(leftRenderTextureSceneRenderer, GraphicsDevice, outputTarget.Width, outputTarget.Height, outputTarget.Format);
MaybeReplaceTexture(rightRenderTextureSceneRenderer, GraphicsDevice, outputTarget.Width, outputTarget.Height, outputTarget.Format);
leftCameraRenderer.Draw(drawContext);
rightCameraRenderer.Draw(drawContext);
DrawCompositeEffect(drawContext);
}
private void DrawCompositeEffect(RenderDrawContext drawContext)
{
compositeEffect.CameraATexture = leftRenderTextureSceneRenderer.RenderTexture;
compositeEffect.CameraBTexture = rightRenderTextureSceneRenderer.RenderTexture;
compositeEffect.SplitPosition = SplitPosition;
compositeEffect.SeparatorWidth = SeparatorWidth;
compositeEffect.SeparatorColor = SeparatorColor;
compositeEffect.Draw(drawContext);
}
private static void MaybeReplaceTexture(RenderTextureSceneRenderer renderer, GraphicsDevice graphicsDevice, int width, int height, PixelFormat format)
{
var texture = renderer.RenderTexture;
if (texture.Width != width || texture.Height != height || texture.Format != format)
{
texture.Dispose();
renderer.RenderTexture = Texture.New2D(graphicsDevice, width, height, format, TextureFlags.ShaderResource | TextureFlags.RenderTarget);
}
}
}
public class SplitScreenCompositeEffect : ImageEffectShader
{
public SplitScreenCompositeEffect() : base("SplitScreenComposite") { }
#nullable disable
public Texture CameraATexture { get; set; }
public Texture CameraBTexture { get; set; }
public float SplitPosition { get; set; } = 0.5f;
public float SeparatorWidth { get; set; } = 0f;
public Vector4 SeparatorColor { get; set; } = new Vector4(0, 0, 0, 1);
#nullable restore
protected override void UpdateParameters()
{
base.UpdateParameters();
Parameters.Set(SplitScreenCompositeKeys.SplitPosition, SplitPosition);
Parameters.Set(SplitScreenCompositeKeys.SeparatorWidth, SeparatorWidth);
Parameters.Set(SplitScreenCompositeKeys.SeparatorColor, SeparatorColor);
}
protected override void DrawCore(RenderDrawContext context)
{
SetInput(0, CameraATexture);
SetInput(1, CameraBTexture);
base.DrawCore(context);
}
}
namespace GraphicsTest.Compositing
{
shader SplitScreenComposite : ImageEffectShader
{
stage float SplitPosition = 0.5f;
stage float SeparatorWidth = 0.0f;
stage float4 SeparatorColor = float4(0, 0, 0, 1);
stage override float4 Shading()
{
float leftEdge_X = SplitPosition - SeparatorWidth * 0.5f;
float rightEdge_X = SplitPosition + SeparatorWidth * 0.5f;
float2 uv = streams.TexCoord;
float screen_X = uv.x;
float camA_X = saturate(screen_X - (0.5f * leftEdge_X) + 0.5f);
float camB_X = saturate(screen_X + (0.5f * rightEdge_X) - 0.5f);
float4 camA = Texture0.Sample(Sampler, float2(camA_X, uv.y));
float4 camB = Texture1.Sample(Sampler, float2(camB_X, uv.y));
float4 temp = lerp(camA, SeparatorColor, step(leftEdge_X, uv.x));
return lerp(temp, camB, step(rightEdge_X, uv.x));
}
};
}
Expected behavior
Reload scripts should work the same as it did before I created this class.
Log and callstacks
Exception: ArgumentException: No serializer available for type GraphicsTest.Compositing.SplitScreenRenderer
at Stride.Core.Serialization.MemberReuseSerializer`1.Serialize(T& obj, ArchiveMode mode, SerializationStream stream) in /_/sources/core/Stride.Core/Serialization/MemberSerializerGenerated.cs:line 1183
at Stride.Core.DataSerializers.StrideAssetsRendering_GraphicsCompositorAssetSerializer.Serialize(GraphicsCompositorAsset& obj, ArchiveMode mode, SerializationStream stream)
at Stride.Core.Serialization.DataSerializer`1.Serialize(Object& obj, ArchiveMode mode, SerializationStream stream) in /_/sources/core/Stride.Core/Serialization/DataSerializer.cs:line 80
at Stride.Core.Serialization.MemberReuseSerializer`1.SerializeExtended(T& obj, ArchiveMode mode, SerializationStream stream, DataSerializer`1 dataSerializer) in /_/sources/core/Stride.Core/Serialization/MemberSerializerGenerated.cs:line 1429
at Stride.Core.Assets.AssetCloner..ctor(Object value, AssetClonerFlags flags, IEnumerable`1 externalIdentifiables) in /_/sources/assets/Stride.Core.Assets/AssetCloner.cs:line 73
at Stride.Core.Assets.Analysis.AssetDependencyManager.Session_AssetDirtyChanged(AssetItem asset, Boolean oldValue, Boolean newValue) in /_/sources/assets/Stride.Core.Assets/Analysis/AssetDependencyManager.cs:line 519
at Stride.Core.Presentation.ViewModels.DirtiableEditableViewModel.UpdateDirtiness(Boolean value) in /_/sources/presentation/Stride.Core.Presentation/ViewModels/DirtiableEditableViewModel.cs:line 47
at Stride.Core.Presentation.Dirtiables.DirtiableManager.UpdateDirtiables(HashSet`1 dirtiables) in /_/sources/presentation/Stride.Core.Presentation/Dirtiables/DirtiableManager.cs:line 121
at Stride.Core.Presentation.Dirtiables.DirtiableManager.TransactionCompleted(Object sender, TransactionEventArgs e) in /_/sources/presentation/Stride.Core.Presentation/Dirtiables/DirtiableManager.cs:line 138
at Stride.Core.Transactions.TransactionStack.CompleteTransaction(Transaction transaction) in /_/sources/core/Stride.Core.Design/Transactions/TransactionStack.cs:line 202
at Stride.Core.Transactions.TransactionStack.CompleteTransaction(Transaction transaction) in /_/sources/core/Stride.Core.Design/Transactions/TransactionStack.cs:line 134
at Stride.Core.Transactions.Transaction.Dispose() in /_/sources/core/Stride.Core.Design/Transactions/Transaction.cs:line 45
at Stride.GameStudio.ViewModels.DebuggingViewModel.ReloadAssemblies() in /_/sources/editor/Stride.GameStudio/ViewModels/DebuggingViewModel.cs:line 397
at Stride.GameStudio.ViewModels.DebuggingViewModel.ReloadAssemblies()
at Stride.Core.Presentation.Commands.AnonymousTaskCommand.<>c__DisplayClass0_0.<<-ctor>b__0>d.MoveNext() in /_/sources/presentation/Stride.Core.Presentation/Commands/AnonymousCommand.cs:line 84
--- End of stack trace from previous location ---
at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__124_0(Object state)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
Report.txt
Additional context
This happens every time I try to reload scripts, not just the first time.
Release Type: Official Release
Version: 4.4 beta 4
Platform(s): Windows
Describe the bug
When I reload scripts after changing them in the IDE, the Game Studio crashes.
To Reproduce
This started when I created a split screen renderer and used it in my graphics compositor.
Expected behavior
Reload scripts should work the same as it did before I created this class.
Log and callstacks
Report.txt
Additional context
This happens every time I try to reload scripts, not just the first time.