Entries for tag "productions", ordered from most recent. Entry count: 130.
# Make Your Game Friendly for Graphics Debugging and Optimization - My Talk from Digital Dragons 2019
I've recently gave a talk at Digital Dragons conference in Kraków, Poland. It wasn't very technically advanced this time. Most of it should be understandable to everyone working on games - artists, programmers, producers... I've published slides on GPUOpen.com blog, along with slides my colleagues presented last month at other events across Europe. See: AMD at Digital Dragons and Vulkanised Conference.
# WinFontRender - my new library
Displaying text is a common problem in graphics applications where all you can do is to render textured quads. I've implemented my solution already back in 2007, as part of my old engine The Final Quest 7, which was my master thesis. I've recently come back to this code and improved it because I needed it for the personal project I now work on. Then I thought: Maybe it's a good idea to extract this code into a library? So here it is:
It does two things:
1. It renders characters of the font to a texture, tightly packed.
2. It calculates vertices needed to render given text.
Here are more details about the library:
# Vulkan Memory Allocator Survey March 2019
Are you a software developer, use Vulkan and the Vulkan Memory Allocator library (or at least considered using it)? If so, please spend a few minutes and help to shape the future of the library by participating in the survey:
Your feedback is greatly appreciated. The survey is anonymous - no personal data is collected like name, e-mail etc. All questions are optional.
# Global Game Jam 2019 - my impressions
Last weekend the 2019 edition of Global Game Jam took place - a worldwide event where teams od developers gather in different sites all around the world to make games during two days and two nights. There was a large site in my city (Warsaw) - PolyJam, but I decided to go to Gdańsk to participate it their local site called Hackerspace Game Jam together with my friends.
Theme this year was "what home means to you". As always, participants interpreted it very differently. Those who have families associated home with all kinds of troubles caused by the other residents. Pooplers - the game I liked the most - is about babies crawling around the house and pooping competitively to cover as much surface as possible with their specific color, while avoiding the mother :) Home Alone: Cat edition is about a cat that can destroy and drop stuff from the shelves, all in first person perspective. Kapeć Defender is about a man who throws slipper (pol. "kapeć") at the wife and other people to be able to just sit and watch TV. There were more sci-fi settings as well. I liked the game Gwiezdni Somsiedzi a lot. It is the only one with multiplayer over network. Players have to control satellites flying in space, catch asteroids and throw them at the other players. Another space game was Glop where players have to cooperatively control various devices on the surface of a planet to make it fly, as well as shoot at incoming obstacles.
Our team was a group of friends from the demoscene - 2 ex-Intel C++ developers and 2 DevOps currently working in a bank. Unfortunately we had no graphics artists. Although I would prefer to use Unity or Unreal Engine these days, we eventually decided to go the hard way and code in C++ using dxfw - the old framework developed by Krzysiek K., based on Direct3D 9. I had to remind myself this old technology before the jam, including all these
D3DRS_ fixed-function pipeline states and D3DX math library. By the way: If the last version of DirectX SDK for DX9 was released in June 2010, can we already consider it a retro platform, along with Atari and Amiga? ;)
We used FMOD library for playing sound and music and Gainput for handling input from gamepads. We started from having a ray-traced sphere, so we had to code all the game logic and rendering from scratch, including displaying characters, UI, collisions, etc. We've developed some of the logic in C++ and some in Squirrel, because we had this scripting language already integrated with the framework. I had no previous experience with Squirrel, so I had to learn it very quickly. After going through the documentation, I concluded that I love it! It looks like a great scripting language for simple applications. It's not perfect, e.g. it lacks vector and matrix types so necessary in game development (just like pretty much every other programming language except HLSL/GLSL), but I like its simplicity and syntax. It is very similar to Lua in its overall philosophy - dynamically typed, object oriented, and based on key-value arrays. The syntax is not that weird though. It seems to follow the "principle of least astonishment" - it's very similar to C++, arrays are indexed from 0, plus ending statements with a semicolon is optional - end of line also works.
Participating in an event such as GGJ is always an adventure and an opportunity for many new experiences - much better than just sitting on the Internet at home. During this jam I not only learned Squirrel as a new programming language, but I've also heard what is it like to work as a programmer at a bank, I've registered on Asana (a web service for organizing TODO lists, just like Trello which I used before), and of course I had an opportunity to practice quick and dirty programming, as opposed to code carefully thought out and tested, like it has to be done in a regular job.
Finally, the game we've made is here: LazerBugz. It is a twin-stick shooter happening on a spherical surface of a planet. The "home" is the cosmic base that you have to defend while shooting at alien bugs and going out to gather randomly placed gems. It supports local co-op for any number of players using Xbox gamepads or keyboard and mouse. Some screenshots and a photo of people playing our game:
There was a competition on our site. We didn't take any of the first 3 places. We just got mention among the games who received a good number of votes. The game that won was Clash of T-Rexes - kind of Pong with two dinosaurs standing on two planets.
Official photo gallery from the event: Hackerspace Game Jam 2019
# Debugging D3D12 driver crash
New generation, explcit graphics APIs (Vulkan and DirectX 12) are more efficient, involve less CPU overhead. Part of it is that they don't check most errors. In old APIs (Direct3D 9, OpenGL) every function call was validated internally, returned success of failure code, while driver crash indicated a bug in driver code. New APIs, on the other hand, rely on developer doing the right thing. Of course, some functions still return error code (especially ones that allocate memory or create some resource), but those that record commands into a command list just return
void. If you do something illegal, you can expect undefined behavior. You can use Validation Layers / Debug Layer to do some checks, but otherwise everything may work fine on some GPUs, you may get incorrect result, or you may experience driver crash or timeout (called "TDR"). Good thing is that (contrary to old Windows XP), crash inside graphics driver doesn't cause "blue screen of death" or machine restart. System just restarts graphics hardware and driver, while your program receives
DXGI_ERROR_DEVICE_REMOVED code from one of functions like
IDXGISwapChain::Present. Unfortunately, you then don't know which specific draw call or other command caused the crash.
NVIDIA proposed solution for that: they created NVIDIA Aftermath library. It lets you (among other things) record commands that write custom "marker" data to a buffer that survives driver crash, so you can later read it and see which command was successfully executed last. Unfortunately, this library works only with NVIDIA graphics cards.
Some time ago I showed a portable solution for Vulkan in my post: "Debugging Vulkan driver crash - equivalent of NVIDIA Aftermath". Now I'd like to present a solution for Direct3D 12. It turns out that this API also provides a standardized way to achieve this, in form of a method ID3D12GraphicsCommandList2::WriteBufferImmediate. One caveat: This new version of the interface requires:
I created a simple library that implements all the required logic under easy interface, which I called D3d12AfterCrash. You can find all the details and instruction for how to use it in file "D3d12AfterCrash.h".
I guess it would be better to allocate the buffer using WinAPI function
VirtualAlloc(NULL, bufferSize, MEM_COMMIT, PAGE_READWRITE), then call
ID3D12Device::CreatePlacedResource, but my simple way of just doing
ID3D12Device::CreateCommittedResource seems to work - buffer survives driver crash and preserves its content. I checked it on AMD as well as NVIDIA card.
Update 2019-01-28: Microsoft is releasing a new, more powerful API for analyzing reasons of driver/GPU crash, called Device Removed Extended Data (DRED).
# Vulkan Memory Allocator 2.1.0
Yesterday I merged changes in the code of Vulkan Memory Allocator that I've been working on for past few months to "master" branch, which I consider a major milestone, so I marked it as version 2.1.0-beta.1. There are many new features, including:
The release also includes many smaller bug fixes, improvements and additions. Everything is tested and documented. Yet I call it "beta" version, to encourage you to test it in your project and send me your feedback.
# str_view - null-termination-aware string-view class for C++
tl;dr I've written a small library, which I called "str_view - null-termination-aware string-view class for C++". You can find code and documentation on GitHub - sawickiap/str_view. Read on to see full story behind it...
Let me disclose my controversial beliefs: I like C++ STL. I think that any programming language needs to provide some built-in strings and containers to be called modern and suitable for developing large programs. But of course I'm aware that careless use of classes like
std::map makes program very slow due to large number of dynamic allocations.
What I value the most is RAII - the concept that memory is automatically freed whenever an object referenced by value is destroyed. That's why I use
std::unique_ptr all over the place in my personal code. Whenever I create and own an array, I use
std::vector, but when I just pass it to some other code for reading, I pass raw pointer and number of elements -
myVec.size(). Similarly, whenever I own and build a string, I use
std::string (or rather
std::wstring - I like Unicode), but when I pass it somewhere for reading, I use raw pointer.
There are multiple ways a string can be passed. One is pointer to first character and number of characters. Another one is pointer to first character and pointer to the next after last character - a pair of iterators, also called range. These two can be trivially converted between each other. Out of these, I prefer pointer + length, because I think that number of characters is slightly more often needed than pointer past the end.
But there is another way of passing strings common in C and C++ programs - just one pointer to a string that needs to be null-terminated. I think that null-terminated strings is one of the worst and the most stupid inventions in computer science. Not only it limits set of characters available to be used in string content by excluding
'\0', but it also makes calculation of string length O(n) time complexity. It also creates opportunity for security bugs. Still we have to deal with it because that's the format that most libraries expect.
I came up with an idea for a class that would encapsulate a reference to an externally-owned, immutable string, or a piece of thereof. Objects of such class could be used to pass strings to library functions instead of e.g. a pointer to null-terminated string or a pair of iterators. They can be then queried for
length(), indexed to access individual characters etc., as well as asked for a null-terminated copy using
c_str() method - similar to
Code like this already exists, e.g. C++17 introduces class
std::string_view. But my implementation has a twist that I'm quite happy with, which made me call my class "null-termination-aware". My
str_view class not only remembers pointer and length of the referred string, but also the way it was created to avoid unnecessary operations and lazily evaluate those that are requested.
c_str()trivially returns pointer to the original string.
length()trivially returns it.
c_str()creates a local, null-terminated copy of the string upon first call.
If you consider such class useful in your C++ code, see GitHub - sawickiap/str_view project for code (it's just a single header file), documentation, and extensive set of tests. I share this code for free, on MIT license. Feel free to contact me if you find any bugs or have any suggestions regarding this library.
# Human-friendly classification of Vulkan resources
In graphics programming we deal with different kinds of resources. Their specific types and names depend on graphics API. For example, in Direct3D 9 we have vertex buffers, index buffers, constant buffers, textures etc. OpenGL equivalent of constant buffer is uniform buffer object (UBO).
Vulkan has only two types of resources: buffers and images. This may be the only thing that is simpler in Vulkan than in other APIs :) When creating such resource, we specify usage flags that define how do we intend to use it. For example,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT means that a buffer may be used as vertex buffer.
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT means that an image may be used as color attachment (which is Vulkan name for “render target”).
Such flags may be combined together, so a single buffer can contain data to be used as vertex buffer, index buffer, and uniform buffer. I’m not 100% sure if this is guaranteed by the specification (theoretically some drivers could return disjoint sets of
VkMemoryRequirements::memoryTypeBits for different usage flags), but I think that every real implementation allows that. It means we cannot clearly classify buffers and images into categories. Despite that, I decided to develop a human-friendly classification of Vulkan resources into several categories, starting from most “special”, and ending with most “common/generic” ones. I propose following algorithm:
For buffers: // Buffer is used as source of data for fixed-function stage of graphics pipeline. // It’s indirect, vertex, or index buffer. if ((usage & (VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT)) != 0) return class0; // Buffer is accessed by shaders for load/store/atomic. // Aka “UAV” else if ((usage & (VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT)) != 0) return class1; // Buffer is accessed by shaders for reading uniform data. // Aka “constant buffer” else if ((usage & (VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT)) != 0) return class2; // Any other type of buffer. // Notice that VK_BUFFER_USAGE_TRANSFER_SRC_BIT and VK_BUFFER_USAGE_TRANSFER_DST_BIT // flags are intentionally ignored. else return class3; For images: // Image is used as depth/stencil “texture/surface”. if ((usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0) return class0; // Image is used as other type of attachment. // Aka “render target” else if ((usage & (VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) != 0) return class1; // Image is accessed by shaders for sampling. // Aka “texture” else if ((usage & VK_IMAGE_USAGE_SAMPLED_BIT) != 0) return class2; // Any other type of image. // Notice that VK_IMAGE_USAGE_TRANSFER_SRC_BIT and VK_IMAGE_USAGE_TRANSFER_DST_BIT // flags are intentionally ignored. else return class3;
I needed this because I wanted to introduce better coloring to VMA Dump Vis. Vulkan Memory Allocator (VMA) is a C++ library that simplifies GPU memory management in Vulkan applications. VMA Dump Vis is a Python script that can visualize JSON dump from this library on a picture. As I updated the library to remember usage flags of created resources, I wanted to use them to show more information on the picture. To do this, I defined following color scheme:
Example visualization of Vulkan memory in some game:
This color scheme is carefully designed. I based it on following principles:
VK_IMAGE_TILING_OPTIMALshould be used wherever possible, so those with
VK_IMAGE_TILING_LINEARare just marked with green. Images of unknown tiling have color between cyan and green.
You can already visualize your Vulkan memory with all these colors if you grab Vulkan Memory Allocator from development branch. I think that this classification of GPU resources and accompanying color scheme could also be useful for other graphics APIs.