<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Programming on BlueHour</title>
    <link>https://keqing996.github.io/categories/programming/</link>
    <description>Recent content in Programming on BlueHour</description>
    <generator>Hugo</generator>
    <language>en</language>
    <lastBuildDate>Sat, 27 Sep 2025 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://keqing996.github.io/categories/programming/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Notes on Developing Vulkan on Mac</title>
      <link>https://keqing996.github.io/posts/programming/20250927_vulkanonapple/</link>
      <pubDate>Sat, 27 Sep 2025 00:00:00 +0000</pubDate>
      <guid>https://keqing996.github.io/posts/programming/20250927_vulkanonapple/</guid>
      <description>&lt;h1 id=&#34;setup-environment-on-macos&#34;&gt;Setup environment on MacOS&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;First, install the Vulkan SDK. I recommend downloading the latest version from the &lt;a href=&#34;https://vulkan.lunarg.com/sdk/home#mac&#34;&gt;LunarG website&lt;/a&gt;. The default install path is usually &lt;strong&gt;/Users/$USER/VulkanSDK/version-number&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The SDK includes a script named &lt;strong&gt;setup-env.sh&lt;/strong&gt; for setting environment variables, so you need to run it every time your shell starts.&lt;/li&gt;
&lt;li&gt;Open your shell config file, such as &lt;sub&gt;/.zshrc for zsh or &lt;/sub&gt;/.bash_profile for bash, and add the following line. This gives every new shell session the corresponding Vulkan environment variables, and CMake can also find Vulkan through find_package.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Note: replace this path with your actual VulkanSDK installation path&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt; /Users/USER/VulkanSDK/1.3.xxx.x/setup-env.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;moltenvk&#34;&gt;MoltenVK&lt;/h1&gt;
&lt;p&gt;Apple&amp;rsquo;s native graphics API is Metal, and there is no native Vulkan implementation on macOS. So you need MoltenVK to translate Vulkan calls into Metal calls. If you installed the Vulkan SDK, MoltenVK is already included. One extra thing to watch out for: when creating Vulkan-related contexts, there are three places you need to configure.&lt;/p&gt;</description>
    </item>
    <item>
      <title>C#, Java, and Cpp Communication in Unity</title>
      <link>https://keqing996.github.io/posts/programming/20240912_unityjavaandjni/</link>
      <pubDate>Thu, 12 Sep 2024 00:00:00 +0000</pubDate>
      <guid>https://keqing996.github.io/posts/programming/20240912_unityjavaandjni/</guid>
      <description>&lt;p&gt;This post covers four things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How C# calls Java functions in Unity.&lt;/li&gt;
&lt;li&gt;How Java calls C++ through JNI.&lt;/li&gt;
&lt;li&gt;How C++ under JNI calls Java.&lt;/li&gt;
&lt;li&gt;How Java calls Unity&amp;rsquo;s C#.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;csharp-call-java&#34;&gt;CSharp Call Java&lt;/h2&gt;
&lt;p&gt;Use Unity&amp;rsquo;s &lt;code&gt;AndroidJavaObject&lt;/code&gt;, and pass the Java class object into the constructor. The format is the package name followed by the class name.&lt;/p&gt;
&lt;p&gt;For example, in Java:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;com.example.jni&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;ExampleJavaClass&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Function with no return value&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;TestFuncVoid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* ... */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Function with a return value&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;TestFuncInt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* ... */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In CSharp, write it like this:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Cross-Compiling C&#43;&#43; for Android Without Android Studio</title>
      <link>https://keqing996.github.io/posts/programming/20231217_crosscompileandroidcpp/</link>
      <pubDate>Sun, 17 Dec 2023 00:00:00 +0000</pubDate>
      <guid>https://keqing996.github.io/posts/programming/20231217_crosscompileandroidcpp/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://github.com/keqing996/AndroidCppCrossCompile&#34;&gt;AndroidCppCrossCompile&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Android Studio has quite a few bugs, and the C++ development experience is not exactly great. A lot of the time, when we need to do JNI development or pure C++ development, we do not really want to do it inside Android Studio. So we need an environment for cross-compiling C++ programs for Android without relying on Android Studio.&lt;/p&gt;
&lt;p&gt;Next, I will use CMake to build the whole workflow. First, the preparation: you must download the NDK, because we need to use the NDK toolchain. The version I use here is r23c.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Using Arm64 Assembly on Android</title>
      <link>https://keqing996.github.io/posts/programming/20231016_arm64onandroid/</link>
      <pubDate>Mon, 16 Oct 2023 00:00:00 +0000</pubDate>
      <guid>https://keqing996.github.io/posts/programming/20231016_arm64onandroid/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://github.com/keqing996/AndroidCppWithAsm&#34;&gt;AndroidAsm&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;First, create an Android Studio JNI project. By default, the project will generate a C++ file that calls a native function from the Java side to display a string.&lt;/p&gt;
&lt;p&gt;The function generated on the Cpp side uses static binding, so the function name is extremely long and not very pleasant to look at. Let&amp;rsquo;s change it to dynamic binding first. Start by renaming that verbose function.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C++&#34; data-lang=&#34;C++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;JNIEXPORT&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;jstring&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;JNICALL&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;StringFromJNI&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;JNIEnv&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;jclass&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;clazz&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hello&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Hello World From JNI&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NewStringUTF&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hello&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c_str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, implement dynamic binding. Add a function called JniOnLoad to the Cpp file, and load the native function from the Java side inside this function.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Lock-Free Programming</title>
      <link>https://keqing996.github.io/posts/programming/20230421_lockfree/</link>
      <pubDate>Fri, 21 Apr 2023 00:00:00 +0000</pubDate>
      <guid>https://keqing996.github.io/posts/programming/20230421_lockfree/</guid>
      <description>&lt;h1 id=&#34;lock-free-programming&#34;&gt;Lock-Free Programming&lt;/h1&gt;
&lt;p&gt;The goal of lock-free programming is not to make synchronization &amp;ldquo;free&amp;rdquo;. It is to avoid as much of the extra overhead of traditional locks as possible in highly concurrent scenarios.&lt;/p&gt;
&lt;p&gt;In a multithreaded environment, the most common and simplest synchronization tool is still a lock. For example, many implementations of &lt;code&gt;std::mutex&lt;/code&gt; try to stay in user space when there is no contention. But once contention becomes heavy, threads may block, wake up, and context switch, and performance can drop sharply. Even when the kernel is not involved, locks can still introduce cache synchronization, pipeline stalls, and scheduling overhead.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Getting Started with OpenGL Using SFML</title>
      <link>https://keqing996.github.io/posts/programming/20211022_openglwithsfml/</link>
      <pubDate>Fri, 22 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://keqing996.github.io/posts/programming/20211022_openglwithsfml/</guid>
      <description>&lt;p&gt;If you have ever taught yourself OpenGL, you probably remember the pain of pulling in a whole pile of libraries. GLEW and GLUT in particular are awkward to use. SFML makes opening a window very simple, and for anyone learning OpenGL, I think it can completely replace GLUT. So in this post I will use SFML to create the window, then write a casual OpenGL example: a simple forward renderer using the Phong model.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
