Blog

# DirectX 12 Agility SDK 1.716.0-preview Explained

Sun
02
Feb 2025

On January 30th 2025 Microsoft released a new version of DirectX 12 Agility SDK: 1.615.0 (D3D12SDKVersion = 615) and 1.716.0-preview (D3D12SDKVersion = 716). The main article announcing this release is: AgilitySDK 1.716.0-preview and 1.615-retail. Files are available to download from DirectX 12 Agility SDK Downloads, as always, in form of .nupkg files (which are really ZIP archives).

I can see several interesting additions in the new SDK, so in this article I am going to describe them and delve into details of some of them. This way, I aim to consolidate information that is scattered across multiple Microsoft pages and provide links to all of them. The article is intended for advanced programmers who use DirectX 12 and are interested in the latest developments of the API and its surrounding ecosystem, including features that are currently in preview mode and will be included in future retail versions.

 

 

 

Comments | #directx #rendering Share

# Global Game Jam 2025 and First Impressions from Godot

Wed
29
Jan 2025

Last weekend, 24-26 January 2025 I participated in Global Game Jam, and, more specifically, PolyJam 2025 - a site in Warsaw, Poland. In this post I'll share the game we've made (including the full source code) and describe my first impressions of the Godot Engine, which we used for development.

We made a simple 2D pixel-art game with mechanics similar to Overcooked. It was designed for 2 to 4 players in co-op mode, using keyboard and gamepads.

Entry of the game at globalgamejam.org

GitHub repository with the source code

A side note: The theme of GGJ 2025 was "Bubble". Many teams created games about bubbles in water, while others interpreted it more creatively. For example, the game Startup Panic: The Grind Never Stops featured minigames like drawing graphs or typing buzzwords such as "Machine Learning" to convince investors to fund your startup – an obvious bubble 🙂 Our game, on the other hand, focused on taking care of babies and fulfilling their needs so they could grow up successfully. In Polish, the word for "bubbles" is "bąbelki", but it’s also informally used to refer to babies. Deliberately misspelled as "bombelki", it is a wordplay that makes sense and fits the theme in Polish.

My previous game jam was exactly two years ago. Before that jam, I had learned a bit of the Cocos Creator and used it to develop my game, mainly to try something new. I described my impressions in this post: Impressions After Global Game Jam 2023. This time, I took a similar approach and I started learning Godot engine about three weeks before the jam. Having some experience with Unity and Unreal Engine, my first impressions of Godot have been very positive. Despite being an open-source project, it doesn’t have that typical "open-source feeling" of being buggy, unfinished, or inconvenient to use. Quite the opposite! Here are the things I especially like about the engine:

I like that it’s small, lightweight, and easy to set up. All you need to do is download a 55 MB archive, unpack it, and you’re ready to start developing. This is because it’s a portable executable that doesn’t require any installation. The only time you need to download additional files (over 1 GB) is when you’re preparing to create a build for a specific platform.

I also appreciate how simple the core ideas of the engine are:

  • No distinction between scenes and prefabs: When laying out an entire game level, we create a scene. Similarly, when designing a character (like the player or an enemy) with its graphics, physical collision shape, accompanying script code, and so on, we also create a scene. Scenes can be instantiated within other scenes, functioning as prefabs.
  • No distinction between sub-nodes and components: When we want to add an object as a child of another object to inherit its transform, we create a sub-node in the scene tree. Likewise, when we want an object to have visual elements (by adding a 2D sprite or 3D model), physical collisions with a specific shape, or the ability to play a sound, we also add sub-nodes of the appropriate types.

I’m not sure if this approach is optimal in terms of performance or whether it’s as well-optimized as the full Entity Component System (ECS) that some other engines use. However, I believe a good engine should be designed like this one – with a simple and intuitive interface, while handling performance optimizations seamlessly under the hood.

I also appreciate the idea that the editor is built using the same GUI controls available for game development. This approach provides access to a wide range of advanced controls: not just buttons and labels, but also movable splitters, multi-line text editors, tree views, and more. They can all be skinned with custom colors and textures.

Similarly, files saved by the engine are text files in the INI-like format with sections like [SectionName] and key-value pairs like Name = Value. Unlike binary files, XML, or JSON, these files are very convenient to merge when conflicts arise after two developers modify the same file. The same format is also available and recommended for use in games, such as for saving settings.

Then, there is GDScript - a custom scripting language. While Godot also offers a separate version that supports C# and even has a binding to Rust, GDScript is the native way of implementing game logic. I like it a lot. Some people compare it to Python, but it’s not a fork or extension of Python; it’s a completely separate language. The syntax shares similarities with Python, such as using indentation instead of braces {} to define scopes. However, GDScript includes many features that Python lacks, specifically tailored for convenient and efficient game development.

One such feature is an interesting mix of dynamic and static typing. By default, variables can have dynamic types (referred to as "variant"), but there are ways to define a static type for a variable. In such cases, assigning a value of a different type results in an error – a feature that Python lacks.

var a = 0.1
a = "Text" # OK - dynamic type.
var b: float
b = 0.1
b = "Text" # Error! b must be a number.
var c := 0.1
c = "Text" # Error! c must be a number.

Another great feature is the inclusion of vector types for 2D, 3D, or 4D vectors of floats or integers. These types are both convenient and intuitive to use – they are passed by value (creating an implicit copy) and are mutable, meaning you can modify individual xyzw components. This is something that Python cannot easily replicate: in Python, tuples are immutable, while lists and custom classes are passed by reference. As a result, assigning or passing them as function parameters in Python makes the new variable refer to the original object. In GDScript, on the other hand:

var a := Vector2(1.0, 2.0)
var b := a # Made a copy.
b.x = 3.0  # Can modify a single component.
print(a)   # Prints (1, 2).

I really appreciate the extra language features that are clearly designed for game development. For example, the @export attribute before a variable exposes it to the Inspector as a property of a specific type, making it available for visual editing. The $NodeName syntax allows you to reference other nodes in the scene, and it supports file system-like paths, such as using / to navigate down the hierarchy and .. to go up. For instance, you can write something like $../AudioPlayers/HitAudioPlayer.play().

I also like how easy it is to animate any property of any object using paths like the one shown above. This can be done using a dedicated AnimationPlayer node, which provides a full sequencer experience with a timeline. Alternatively, you can dynamically change properties over time using a temporary Tween object. For example, the following code changes the font color of a label to a transparent color over 0.5 seconds, using a specific easing function selected from the many available options (check out the Godot tweening cheat sheet for more details):

create_tween().tween_property(addition_label.label_settings, ^":font_color", transparent_color, 0.5).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_IN)

I really appreciate the documentation. All core language features, as well as the classes and functions available in the standard library, seem to be well-documented. The documentation is not only available online but also integrated into the editor (just press F1), allowing you to open documentation tabs alongside your script code tabs.

I also like the debugger. Being able to debug the code I write is incredibly important to me, and Godot delivers a full debugging experience. It allows you to pause the game (automatically pausing when an error occurs), inspect the call stack, view variable values, explore the current scene tree, and more.

That said, I’m sure Godot isn’t perfect. For me, it was just a one-month adventure, so I’ve only described my first impressions. There must be reasons why AAA games aren’t commonly made in this engine. It likely has some rough edges and missing features. I only worked with 2D graphics, but I can see it supports 3D graphics with a Forward+ renderer and PBR materials. While it could potentially be used for 3D projects, I’m certain it’s not as powerful as Unreal Engine in that regard. I also encountered some serious technical issues with the engine during the game jam, but I’ll describe those in separate blog posts to make them easier to find for anyone searching the Internet for a solution.

I also don’t know much about Godot’s performance. The game we made was very simple. If we had thousands of objects on the scene to render and complex logic to calculate every frame, performance would become a critical factor. Doing some work in every object every frame using _process function is surely an anti-pattern and it runs serially on a single thread. However, I can see that GDScript also supports multithreading – another feature that sets it apart from Python.

To summarize, I now believe that Godot is a great engine at least for game jams and fast prototyping.

Comments | #godot #events #competitions #ggj #productions Share

# Thoughts Beyond C++

Mon
30
Dec 2024

Earlier this month, Timothy Lottes published a document on Google Docs called “Fixing the GPU”, where he describes many ideas about how programming compute shaders on the GPU could be improved. It might be an interesting read for those advanced enough to understand it. The document is open for suggestions and comments, and there are few comments there already.

On a different topic, 25 November I attended Code::Dive conference in Wrocław, Poland. It was mostly dedicated to programming in C++ language. I usually attend conferences about game development, so it was an interesting experience for me. Big thanks to Tomasz Łopuszański from Programista magazine for inviting me there! It was great to see Bjarne Stroustrup and Herb Sutter live, among other good speakers. By the way, recordings from the talks are available on YouTube.

Those two events inspired me to write down my thoughts – my personal “wishlist” about programming languages, from the perspective of someone interesting in games and real-time graphics programming. I gathered my opinions about things I like and dislike in C++ and some ideas about how a new, better language could look like. It is less about a specific syntax to propose and more about high-level ideas. You can find it under the following shortened address, but it is really a document at Google Docs. Comments are welcome.

» “Thoughts Beyond C++” «

Of course I am aware of Rust, D, Circle, Carbon, and other programming languages that share the same goal of replacing C++. I just wanted to write down my own thoughts about this topic.

Comments | #c++ #compilers #productions Share

# FP8 data type - all values in a table

Tue
24
Sep 2024

Floating-point numbers are a great invention. Thanks to dedicating separate bits to the sign, exponent, and mantissa (also called significand), they can represent a wide range of numbers on a limited number of bits - numbers that are positive or negative, very large or very small (close to zero), integer or fractional.

In programming, we typically use double-precision (64b) or single-precision (32b) numbers. These are the data types available in programming languages (like double and float in C/C++) and supported by processors, which can perform calculations on them efficiently. Those of you who deal with graphics programming using graphics APIs like OpenGL, DirectX, or Vulkan, may know that some GPUs also support 16-bit floating-point type, also known as half-float.

Such 16b "half" type obviously has limited precision and range compared to the "single" or "double" version. Because of these limitations, I am reserved in recommending them to use in graphics. I summarized capabilities and limits of these 3 types in a table in my old "Floating-Point Formats Cheatsheet".

Now, as artificial intelligence (AI) / machine learning (ML) is a popular topic, programmers use low precision numbers in this domain. When I learned that floating-point formats based only on 8 bits were proposed, I immediately thought: 256 possible value is little enough that they could be all visualized in a 16x16 table! I developed a script that generates such tables, and so I invite you to take a look at my new article:

"FP8 data type - all values in a table"

Comments | #math #artificial intelligence Share

# How to do a good code review - a new article

Mon
19
Aug 2024

Today I would like to present my new, comprehensive article: "How to do a good code review". I can be helpful to any programmer no matter what programming language they use. Conducting good code reviews is a skill worth mastering. In this article, we will discuss the advantages and disadvantages of this process and explore the types of projects where it is most beneficial. We will consider the best approach to take when reviewing code, how to effectively carry out the process, which aspects of the code to focus on, and finally – how to write comments on the code in a way that benefits the project. The goal is to ensure that the review process serves as an opportunity for fruitful communication among team members rather than a source of conflict.

The article was first published few months ago in Polish in issue 112 (March/April 2024) of the Programista magazine. Now I have a right to show it publicly for free, so I share it in two language versions:

I wasn't active on my blog in the past months because I took some time for vacation, but also because I'm now learning about machine learning. I may be late to the party, but I recognize that machine learning algorithms are useful tools in many applications. As people learn the basics, the often feel an urge to teach others about it. Some good reads authored by game/graphics developers are: "Machine Learning for Game Devs" by Alan Wolfe and "Crash Course in Deep Learning (for Computer Graphics)" by Jakub Boksansky. I don't want to duplicate their work, so I will only blog about it when I have something unique to show.

Comments | #productions #software engineering Share

# Shapes and forms of DX12 root signatures

Tue
14
May 2024

This article is for you if you are a programmer using Direct3D 12. We will talk about a specific part of the API: root signatures. I will provide a comprehensive description of various formats in which they can be specified, stored, and ways to convert between them. The difficulty of this article is intermediate. You are expected to know at least some basics of D3D12. I think that advanced developers will can also learn something new, as some of the topics shown here are not what we typically use in a day-to-day development with D3D12.

Tools of the trade

I will use C++ as the programming language. Wherever possible, I will also try to use standalone command-line tools instead of writing a custom code. To repeat my experiments demonstrated in this article, you will need two of these:

  • dxc.exe - the HLSL shader compiler from Microsoft. If you have a development environment installed (like Microsoft Visual Studio and Windows SDK), you already have it in your system, located in a path like "c:\Program Files (x86)\Windows Kits\10\bin\10.0.20348.0\x64\dxc.exe" and added to the system PATH environmental variable, so you can open Command Prompt and just type "dxc" to use it.
  • rga.exe - Radeon GPU Analyzer, which is part of Radeon Developer Tool Suite. You can find the download link on page Radeon™ GPU Analyzer - AMD GPUOpen. It is an offline shader compiler that can also compile HLSL code, but on top of that it can create the full Pipeline State Object (PSO) and output the AMD GPU ISA (assembly code), among many other features. Note that you don't need an AMD graphics card to use it. It comes with the shader compiler bundled for the "offline" mode, so it works regardless of what GPU you have.

You don't need to know the command-line syntax of these tools to understand the article. I will describe everything step-by-step.

Warning about DXC: If you also have Vulkan SDK installed, very likely your PATH environmental variable points to "dxc.exe" in that SDK instead of Windows SDK, which can cause problems. To check this, type command: where dxc. If you find Vulkan SDK listed first, make sure you call "dxc.exe" from Windows SDK, e.g. by explicitly specifying full path to the executable file.

Warning about RGA: If you want to repeat command-line experiments presented here, make sure to use Radeon GPU Analyzer in the latest version, at least 2.9.1. In older versions, the commands I present wouldn't work.

Shader compilation

A side note about shader compilation: Native CPU code, like the one we create when compiling our C++ programs, is saved in .exe files. I contains instructions in a common format called x86, which is sent directly to CPU for execution. It works regardless if you have an AMD or Intel processor in your computer, because they comply to the same standard. With programs written for the GPU (which we call shaders), things are different. Every GPU vendor (AMD, Nvidia, Intel) has its own instruction set, necessitating a two-step process for shader compilation:

  1. As graphics programmers, we write shaders in high-level languages like HLSL or GLSL. We then compile them using a shader compiler like "dxc.exe" to a binary format. It is actually an intermediate format common to all GPU vendors, defined by Microsoft for Direct3D (called DXIL) or by Khronos for Vulkan (called SPIR-V). We are encouraged to compile our shaders offline and only ship these compiled binaries to end users.
  2. When our application uses a graphics API (like Direct3D 12, Vulkan) and creates a pipeline state object (PSO), it specifies these shaders as inputs. This intermediate code then goes to the graphics driver, which performs second stage of the compilation - translates it to instructions valid for the specific GPU (also called Instruction Set Architecture - ISA). We typically don't see this assembly code and we never write it directly, although inspecting it can be useful for optimizations. Nvidia's ISA is secret, but AMD and Intel publish documents describing theirs. RGA tool mentioned below can show the AMD ISA.

What is a root signature?

In Direct3D 12, a root signature is a data structure that describes resource bindings used by a pipeline on all the shader stages. Let's see an example. Let's work with file "Shader1.hlsl": a very simple HLSL code that contains 2 entry points: function VsMain for vertex shader and function PsMain for pixel shader:

struct VsInput
{
 float3 pos : POSITION;
 float2 tex_coord : TEXCOORD;
};
struct VsOutput
{
 float4 pos : SV_Position;
 float2 tex_coord : TEXCOORD;
};

struct VsConstants
{
 float4x4 model_view_proj;
};
ConstantBuffer<VsConstants> vs_constant_buffer : register(b4);

VsOutput VsMain(VsInput i)
{
 VsOutput o;
 o.pos = mul(float4(i.pos, 1.0), vs_constant_buffer.model_view_proj);
 o.tex_coord = i.tex_coord;
 return o;
}

Texture2D<float4> color_texture : register(t0);
SamplerState color_sampler : register(s0);

float4 PsMain(VsOutput i) : SV_Target
{
 return color_texture.Sample(color_sampler, i.tex_coord);
}

I assume you already know that a shader is a program executed on a GPU that processes a single vertex or pixel with clearly defined inputs and outputs. To perform the work, it can also reach out to video memory to access additional resources, like buffers and textures. In the code shown above:

  • Vertex shader declares and uses a constant buffer, bound to slot b4. It contains a model-view-projection 4x4 matrix. Vertex position, extended to 4D (known as homogeneous coordinates) is multiplied by this matrix. Texture coordinates are passed as-is from the input to the output.
  • Pixel shader declares a texture bound to slot t0 and a sampler bound to slot s0. It uses them to sample a color from this texture at given texture coordinates and returns this color, to be written to a render target.

A root signature is a data structure that describes what I said above - what resources should be bound to the pipeline at individual shader stages. In this specific example, it will be a constant buffer at register b4, a texture at t0, and a sampler at s0. It can also be shown in form of a table:

Root param index Register Shader stage
0 b4 VS
1 t0 PS
2 s0 PS

I am simplifying things here, because this article is not about teaching you the basics of root signatures. For more information about them, you can check:

To prepare for our experiments, let's compile the shaders shown above using commands:

dxc -T vs_6_0 -E VsMain -Fo Shader1.vs.bin Shader1.hlsl
dxc -T ps_6_0 -E PsMain -Fo Shader1.ps.bin Shader1.hlsl

Note that a single HLSL source file can contain multiple functions (VsMain, PsMain). When we compile it, we need to specify one function as an entry point. For example, the first command compiles "Shader1.hlsl" file using VsMain function as the entry point (-E parameter) treated as a vertex shader in Shader Model 6.0 (-T parameter). Similarly, the second command compiles PsMain function as a pixel shader. Compiled shaders are saved in two separate files: "Shader1.vs.bin" and "Shader1.ps.bin".

 

 

 

Comments | #directx #rendering Share

# Debugging third-party apps in Visual Studio

Mon
29
Apr 2024

If you are a programmer coding mostly in C++ for Windows, as I do, you likely use Microsoft Visual Studio as the IDE, including its code editor and debugger. When using Visual Studio for development, we typically compile, launch, and debug the code we developed. However, Visual Studio can also be used for debugging third-party executables. Having neither debug symbols (.pdb files) nor the source code of the application will result in a limited debugging experience, but it can still be useful in some cases. In this article, I will share a few tips and tricks for using the Visual Studio debugger to debug external .exe files.

I think this article is suitable for programmers with all levels of experience, also for beginners. We won't be looking at the x86 assembly code, I promise! 😀 All the screenshots are made with Visual Studio 2022 version 17.9.6 on Windows 10.

 

 

 

Comments | #c++ #visual studio Share

# What does software have to do with the linen industry?

Thu
28
Mar 2024

Technological advancements don't come out of nowhere. They are a sum of many small steps. Video games added interactivity to films displayed on a screen, so we call them "video games". Film, in turn, is a successor of theater, which dates back to the ancient times. No wonder that when we make modern games e.g. using Unreal Engine, we use concepts from the theater and film, like an "actor", "scene", "camera", "light".

What inspired me to write this blog post was my visit at Linen Industry Museum in Żyrardów, a city located not far from Warsaw, Poland. Formerly an industrial hub, Żyrardów now houses a museum dedicated to showcasing the rich history of the linen industry through a collection of preserved machinery and artifacts.

Probably the most interesting for us programmers is the Jacquard machine, which used punched cards to program the pattern to be created on a textile. Punched cards like this later became the medium of storing programs for the first computers. For that machine, it wasn't yet programming in terms of Turing-completeness, but it surely was a digital code that controlled the machine.

It should be no surprise that in modern computer science, we use the term "thread", which comes from the textile industry. Nvidia also uses the term "warp", which is another word from that industry. We can think of a modern GPU as a machine like this one below. There are a lot of threads running in parallel. Each thread produces one pixel of a certain color. Our role as graphics programmers is to make this machine run fast, with no jams, and make sure the correct pattern is produced on the fabric on the computer screen.

So many threads! 😀

(All photos are taken by me in the beforementioned Linen Industry Museum in Żyrardów. If you happen to drive around Warsaw in Poland, make sure to visit it!)

Comments | #history Share

Older entries >

Pinboard Bookmarks

Blog Tags

Mastodon

[Download] [Dropbox] [pub] [Mirror] [Privacy policy]
Copyright © 2004-2025