xgamedev.net Blog

website·Indexed 29 days ago

https://xgamedev.net

A technical blog focusing on game development and C# programming. Topics include C# Source Generator performance profiling using MSBuildStructuredLog and JetBrains dotTrace, Roslyn, URP, 2D glow effects, and binary serialization.

Tokens
5.2K
Snippets
17
Records
27
Agent score
50%

What's inside xgamedev.net

  1. Overview of JEngine Hot Update Framework

    JEngine is an open-source, plug-and-play hot update framework developed for the Unity engine.
    # Source: https://github.com/JasonXuDeveloper/JEngine
  2. High-performance C# libraries by JasonXuDeveloper

    A collection of specialized C# libraries focusing on low-level optimization and systems architecture:

    • Nino: A high-performance binary serialization library.
    • Miku: A high-throughput, multi-threaded TCP networking library.
    • EasyEcs: An easy-to-use, multi-threaded asynchronous Entity Component System (ECS) library.
    - Nino: https://github.com/JasonXuDeveloper/Nino
    - Miku: https://github.com/JasonXuDeveloper/Miku
    - EasyEcs: https://github.com/JasonXuDeveloper/EasyEcs
  3. Writer LLM Agent for long-form novels

    Writer is an experimental LLM Agent project designed to write long-form novels while addressing common Large Language Model issues, such as hallucinations.
    # Source: https://github.com/JasonXuDeveloper/Writer
  4. Optimize C# Source Generator performance

    To prevent build slowdowns and improve the developer experience, apply the following optimization strategies to your Source Generators:

    • Use Incremental Source Generators: Introduced in Roslyn 4.0+, these only regenerate code when necessary, significantly reducing overhead.
    • Cache Expensive Operations: Store results for symbol lookups, type checking, and syntax tree parsing to avoid redundant processing.
    • Minimize String Allocations: Use Span<char> and ReadOnlySpan<char> for slicing, StringBuilder for complex construction, and DefaultInterpolatedStringHandler for interpolation.
    • Reduce Diagnostics: Only report diagnostics when absolutely necessary, as they introduce performance overhead.
    • Avoid Inefficient Patterns: Replace heavy LINQ queries with for loops and batch file I/O operations or use in-memory alternatives.
  5. Profile C# Source Generator performance using MSBuildStructuredLog and dotTrace

    To identify performance bottlenecks in a C# Source Generator that are slowing down the build process, you can profile the execution of the C# compiler (csc). The process involves manually invoking csc to compile a project that utilizes the target Source Generator and using JetBrains dotTrace to analyze the compilation process. This allows developers to see the execution time of individual functions within the Source Generator itself.
  6. Analyze Source Generator performance results in dotTrace

    After profiling the compilation process, use the following dotTrace views to identify bottlenecks in the Source Generator:

    • Call Tree: Examine the hierarchical structure of method calls. Double-clicking a function allows you to view decompiled source code to identify specific optimization opportunities.
    • Hot Spots: Identify methods consuming the most time.
    • Timeline: Visualize when methods were executed.

    Focus on methods with high Total Time (including child calls) and high Own Time (time spent in the method itself), as well as expensive I/O operations or excessive string allocations.

  7. Extract C# compiler (csc) arguments from binlog

    Use MSBuildStructuredLog to retrieve the full command line arguments used by the C# compiler for a specific project:

    1. Open the msbuild.binlog file in MSBuildStructuredLog (File → Open Log File).
    2. Search for csc in the left search box.
    3. Select the Csc task corresponding to the target project you wish to profile.
    4. Double-click CommandLineArguments in the right panel to view and copy the full content.

    These arguments include source files, referenced assemblies, Source Generator configurations, and compiler options.

  8. Implement a 2D Glow Effect Shader in Unity URP

    Create a fragment shader for 2D weapons or sprites that supports transparency, custom color blending, and SRP Batcher optimization. The shader allows rendering a specific region of a texture atlas and applying a 'breathing' glow effect based on time and alpha thresholds.
    Shader "Unlit/Fx"
    {
        Properties
        {
            _SrcTexture ("原图", 2D) = "clear" {}
            _Rect ("图片信息", Vector) = (0, 0, 0, 0)
            [Toggle(GLOW)] _GLOW ("发光", Float) = 0
            _Color ("特效颜色", Vector) = (0, 0, 0, 0)
            _Speed ("特效速度", Float) = 0
            _Range ("特效范围", Float) = 0
            _Alpha ("透明度", Range(0, 1)) = 1
            [Enum(UnityEngine.Rendering.BlendMode)]_Src("_Src",Int)=5
            [Enum(UnityEngine.Rendering.BlendMode)]_Dst("_Dst",Int)= 10
        }
        SubShader
        {
            Tags
            {
                "RenderType" = "Transparent"
                "Queue" = "Transparent"
                "RenderPipeline" = "UniversalPipeline"
            }
    
            ZWrite Off
            Blend [_Src][_Dst]
    
            Pass
            {
                HLSLPROGRAM
                #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
    
                CBUFFER_START(UnityPerMaterial)
                    float _Speed;
                    float _Range;
                    float _Alpha;
                    float4 _Rect;
                    float4 _SrcTexture_TexelSize;
                    float4 _Color;
                CBUFFER_END
    
                TEXTURE2D_FLOAT(_SrcTexture);
                SAMPLER(sampler_SrcTexture);
    
                #pragma vertex vert
                #pragma fragment frag
    
                struct Attributes
                {
                    float4 positionOS : POSITION;
                    float4 uv : TEXCOORD0;
                };
    
                struct Varyings
                {
                    float4 positionCS : SV_POSITION;
                    float2 uv : TEXCOORD0;
                };
    
                Varyings vert(Attributes IN)
                {
                    Varyings OUT;
                    OUT.positionCS = TransformObjectToHClip(IN.positionOS.xyz);
                    
                    // Calculate UV based on _Rect (x, y, width, height)
                    float4 cur_pixel = float4(IN.uv.x * _Rect.z, IN.uv.y * _Rect.w, 0, 0);
                    float x = (_Rect.x + cur_pixel.x) * _SrcTexture_TexelSize.x;
                    float y = (_SrcTexture_TexelSize.w - _Rect.y - _Rect.w + cur_pixel.y) * _SrcTexture_TexelSize.y;
    
                    OUT.uv = float2(x, y);
                    return OUT;
                }
    
                half4 frag(Varyings IN) : SV_Target
                {
                    half4 ret = SAMPLE_TEXTURE2D(_SrcTexture, sampler_SrcTexture, IN.uv.xy);
                    
                    // Glow logic
                    half v = (cos(_Time.y * _Speed) + 1);
                    v = step(_Range, ret.a);
                    half4 c = _Color;
                    c.rgb *= v;
                    
                    return ret; // Note: Final blending logic is continued in subsequent parts of the source
                }
                ENDHLSL
            }
        }
    }
  9. Profile C# Source Generator performance using dotTrace and MSBuildStructuredLog

    To identify performance bottlenecks in a C# Source Generator that are slowing down the build process, you can profile the execution of the C# compiler (csc). The process involves manually invoking csc to compile a project that utilizes the target Source Generator and using JetBrains dotTrace to analyze the compilation process. This approach allows developers to see the execution time of individual functions within the Source Generator itself to pinpoint specific performance issues.
  10. Create a compiler response file for Source Generator profiling

    To profile a Source Generator, you must capture the exact compiler arguments used during a build. Create a response file (e.g., compile.rsp) in the project directory containing the .csproj file. This file must be saved with UTF-8 encoding. Paste only the compiler arguments starting from /noconfig through to the end of the command line.
    /noconfig
    /nowarn:1701,1702
    /fullpaths
    /define:DEBUG;TRACE
    /reference:path/to/reference1.dll
    /reference:path/to/reference2.dll
    ... (all other compiler arguments)
  11. Create a compiler response file (.rsp)

    Because compiler command line arguments are often too long for a standard shell command, they should be saved into a response file (.rsp).

    From the extracted CommandLineArguments, identify the part starting from /noconfig to the end of the string. Save this specific segment into a text file with a .rsp extension. This file can then be passed to the compiler using the @ symbol.

    # Example of the full command structure:
    /usr/local/share/dotnet/dotnet exec "/usr/local/share/dotnet/sdk/9.0.303/Roslyn/bincore/csc.dll" /noconfig /unsafe- /checked- /nowarn:...
    
    # The part to save in the .rsp file:
    /noconfig /unsafe- /checked- /nowarn:...
  12. Profile C# Source Generator performance

    To identify performance bottlenecks within a C# Source Generator, you can manually invoke the C# compiler (csc) to compile a project that utilizes the generator. By profiling this specific compilation process with JetBrains dotTrace, you can analyze the execution time of individual functions within the Source Generator itself.