All blog entries, ordered from most recent. Entry count: 1173.
# 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.
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:
PATH
environmental variable, so you can open Command Prompt and just type "dxc" to use it.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.
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:
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:
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!)
# 20 years of my blog
Tue
13
Feb 2024
Believe it or not, today marks the 20th anniversary of my blog. Exactly on February 13th, 2004, I've published my first entry, which is still online: "Nareszcie w Sieci". It was Friday 13th, but I said there that I don't believe in bad luck, and apparently I was right. Today, I would like to take this opportunity to look back and to write a few words about this website.
This wasn't my first or last venture on the Internet. Even before I launched this page, together with my friends from the neighborhood in my home town Częstochowa, still as teenagers, we formed a group that we called "ProgrameX". We had a website where we published various applications, games, articles, and art. We even created and shared custom Windows cursors and screensavers. I mentioned it in my past article: "Internet in Poland - My History". By the way, we all ended up earning M.Sc. degrees in computer science and now work in the IT field. Greetings to Grzesiek, Damian, and Tomek! I was also actively involved in the Polish Internet game developers community known as "Warsztat" (eng. "Workshop"), and over the years I became a moderator and then an administrator of it. That website doesn't exist anymore. Its last address was warsztat.gd.
At first, I was blogging in Polish, as I didn't feel confident writing in English. Only in June 2009 I officially switched to English. Over these 20 years, I gathered more than a thousand of entries. This one is 1168th. I know I could be ashamed of the old ones and I should remove them, their links and images probably don't work any more, but I still keep them, because I think some of them may provide useful knowledge. I like educating people and I know there are always more beginners than advanced programmers in each area, so what now seems obvious to me may be an interesting and new finding for someone else. I've only included a disclaimer for older entries, acknowledging that they may not reflect my current knowledge and beliefs.
# Calculating checksums of multiple files in PowerShell
Sat
27
Jan 2024
Today I would like to share with you a small script that I developed some time ago and I use regularly since then. It calculates hashes (checksums) for multiple files and saves them to a text file. It is written in PowerShell.
A bit of background: While working with games, I often need to move large amounts of data. Packages of 150 GB or more are not uncommon. When copying, uploading, downloading them, how to make sure not a single bit has changed? A solution is obviously to calculate some checksum and compare it between the source and the destination location. If the checksums don't match, it would be beneficial to avoid transferring the entire package again. Thus, packing it into multiple files (a multi-part .7z archive) is a good idea. This, however, requires a convenient way to calculate checksums of multiple files at once.
My script is actually just a single line:
$ExtractName = @{l='Name';e={Split-Path $_.Path -Leaf}}; Get-FileHash -Path INPUT_MASK | Select-Object -Property Hash, $ExtractName > OUTPUT_FILE
To use it:
Example PowerShell session:
PS C:\Users\Adam Sawicki> cd E:\tmp\checksum_test\
PS E:\tmp\checksum_test> $ExtractName = @{l='Name';e={Split-Path $_.Path -Leaf}}; Get-FileHash -Path Archive.7z.* | Select-Object -Property Hash, $ExtractName > Checksums.txt
PS E:\tmp\checksum_test>
If input files are large, it may take few minutes to execute. After it is complete, the output file "Checksums.txt" may look like this:
Hash Name
---- ----
CBBABFB5529ACFB6AD67502F37444B9273A9B5BB7AF70EFA0FF1F1EC99B70895 Archive.7z.001
185D73ECBCECB9302981C97D0DDFC4B96198103436F23DB593EA9BAFBF997DAC Archive.7z.002
086640842CC34114B898D2E19270DCE427AC89D64BCD9E8E3D8D955D69588402 Archive.7z.003
BE536C66854530236DA924B1CAED44D0880D28AAA66420F6EBE5F363435BEB4F Archive.7z.004
You can then execute the same script on the destination machine of your transfer and compare files and checksums to make sure they match.
# How to programmatically check graphics driver version
Sat
16
Dec 2023
This article is for you if you are a graphics programmer who develops for Windows using Direct3D 11, 12, or Vulkan, and you want to fetch the version of the graphics driver currently installed in your user's system programmatically. If you are in a hurry, you can jump straight to the recommended solution in section "DXGI way" below. However, because this topic is non-trivial, I invite you to read the entire article, where I explain it comprehensively.
Comments | #rendering #directx #vulkan #windows #winapi Share