All Blog Entries

All blog entries, ordered from most recent. Entry count: 1111.

Pages: 1 2 3 ... 139 >

# D3D12 Memory Allocator 1.0.0

Mon
02
Sep 2019

Since 2017 I develop Vulkan Memory Allocator - a free, MIT-licensed C++ library that helps with GPU memory management for those who develop games or other graphics applications using Vulkan. Today we released a similar library for DirectX 12: D3D12 Memory Allocator, which I was preparing for some time. Because that's a project I do at my work at AMD rather than a personal project, I won't describe it in more details here, but just point to the official resources:

If you are interested in technical details and problems I had to consider during development or you want to write your own allocator for either Vulkan or Direct3D 12, you may also check my recent article: Differences in memory management between Direct3D 12 and Vulkan.

Comments | #libraries #directx #productions Share

# Most frequent questions on programming job interviews

Thu
29
Aug 2019

There are different questions that appear on job interviews. Good preparation to such interviews is an art on its own, just like making a good CV, and there are whole books and trainings about it. A potential employer usually asks for details of what is in your CV - your past experience (especially previous 1 or 2 jobs) and why did you leave your previous job. He may ask you to solve some algorithmic puzzles to test your general “intelligence”. He may even ask some ridiculous questions like “Try to estimate how many litres of paint is used every year to renovate buildings in London?”, believing that your response and your way of thinking will be some estimate of whether you will be a good employee. But most of the interviewers also ask some real, technical questions, checking your knowledge from the domain you will work with. Out of these, I observed few questions occurring most frequently. Here they are, together with a draft of the correct response:

1. About C++

1.1. What does inline keyword do? Answer: It means the function should be inlined by the compiler in each place where it is called instead of leaving the function call in the compiled code. It’s only a hint, modern compilers decide which functions to inline on their own.

1.2. What does virtual keyword do? How does it work? Answer: It lets you implement polymorphism when using class inheritance. When an object of a derived class is passed by a pointer or a reference to a base class, calling such a function will call the version from the derived class - the one that the passed object “really is”. It works thanks to each object having an additional, hidden pointer to the virtual function table, which dispatches calls to such functions to the appropriate version.

1.3. What does volatile keyword do? Answer: It tells the compiler that a variable marked with this modifier can change value out of its control (e.g. by a different thread, operating system, or hardware) so it should not optimize its access by caching its value in CPU registers, assume it won’t change for some period etc., but use it in its original location every time. Side note: This keyword is rarely used. It probably appears more frequently on job interviews than in a real code :)

1.4. What does mutable keyword do? Answer: It allows to change a class member variable marked with this modifier even if the member function and the current object is const. It might be useful e.g. to perform lazy evaluation - object is passed as const& and appears to be unchanged, but its methods GetSomething() calculates and caches the value of “something” on first call. Side note: This keyword is rarely used. It probably appears more frequently on job interviews than in a real code :)

2. About general programming

2.1. What is the difference between process and thread? Answer: Process is launched from a particular executable file. It has its own address space (memory heap is common for the whole process), handles to open files, network sockets etc., separated from other processes in the operating system. It comprises a main thread and may have several additional threads. Each thread shares the same code and memory heap, but it has its own stack, instruction pointer (the place in the code currently executed), and values of CPU registers.

2.2. What is a mutex? Answer: It’s a synchronization object that allows multiple threads to access a common resource safely. If only one thread can access the resource, the code accessing it (called a critical section) has to be surrounded by locking the mutex above it and unlocking the mutex below it. Then only one thread will be able to execute that code in any moment. Other threads have to wait.

2.3. What is a deadlock? How to prevent it? Answer: Deadlock is an error in multithreaded code occurring when two or more threads wait for each other and will never make progress. To prevent it, always remember to unlock your mutexes (even when doing early return, break, throwing exception etc.) Also, when locking multiple mutexes, always lock them in the same order, never like: thread 1 locking A then B, thread 2 locking B then A.

3. About graphics programming

3.1. Describe graphics pipeline in modern GPUs. Answer: Depending on how detailed you want to describe it, you can tell that data is processed through following stages: vertex fetch / input assembler (fetching vertices/triangles) --> vertex shader --> optional tessellation (hull shader aka tessellation control shader --> fixed tessellator --> domain shader aka tessellation evaluation shader) --> optional geometry shader --> triangle clipping and culling (incl. viewport culling, backface culling etc.) --> rasterizer (converting triangles to pixels) --> pixel shader aka fragment shader --> depth-stencil test --> writing to render targets with blending.

3.2. What’s the difference between forward and deferred shading? Answer: In traditional forward shading, each object is rendered already shaded by each affecting light. In deferred shading, objects are rendered only once, with their parameters stored in intermediate render targets called G-buffer - like albedo color (taken straight from color texture), normal, depth (allows to reconstruct full position), material parameters (like roughness and metalness in case of PBR). Then separate screen-space passes use these data to apply shading from particular lights. One could say forward shading has complexity of O*L, where O is a number of objects and L is a number of lights, while deferred shading has O+L, which is better for a large number of lights. But deferred shading has its drawbacks: heavy G-buffers consume lots of bandwidth, the algorithm doesn’t work well with translucent objects, MSAA, or using different materials.

There are many more questions you may meet on programming job interview, whether from the topics described above (e.g. from advanced C++ - what is RAII, what is SFINAE), or any other topics important for a specific position, but from my experience those mentioned above are especially frequent, so preparing good answers to them may be the best investment of your time before the interview.

Comments | #career Share

# Differences in memory management between Direct3D 12 and Vulkan

Fri
26
Jul 2019

Since July 2017 I develop Vulkan Memory Allocator (VMA) – a C++ library that helps with memory management in games and other applications using Vulkan. But because I deal with both Vulkan and DirectX 12 in my everyday work, I think it’s a good idea to compare them.

This is an article about a very specific topic. It may be useful to you if you are a programmer working with both graphics APIs – Direct3D 12 and Vulkan. These two APIs offer a similar set of features and performance. Both are the new generation, explicit, low-level interfaces to the modern graphics hardware (GPUs), so we could compare them back-to-back to show similarities and differences, e.g. in naming things. For example, ID3D12CommandQueue::ExecuteCommandLists function has Vulkan equivalent in form of vkQueueSubmit function. However, this article focuses on just one aspect – memory management, which means the rules and limitation of GPU memory allocation and the creation of resources – images (textures, render targets, depth-stencil surfaces etc.) and buffers (vertex buffers, index buffers, constant/uniform buffers etc.) Chapters below describe pretty much all the aspects of memory management that differ between the two APIs.

Read full article »

Comments | #vulkan #directx #gpu Share

# Slavic Game Jam 2019 and our project

Thu
25
Jul 2019

Over the last weekend I took part in Slavic Game Jam 2019 in Warsaw, Poland. (See website, Facebook event, games at itch.io). It was a big one - over 200 participants, many of them coming from different countries all around Europe. The event started on Thursday with a session of talks in 2 parallel tracks. In the evening there was a pre-party in VooDoo club, with electronic music played from GameBoys and live visuals. The jam started on Friday with the announcement of the theme which was "growth". As always, this was just an inspiration, so participants were free to make any kinds of games.

During the event there was food provided, as well as fruits and vegetables, coffee, and ice cream - all for free, included in the ticket price. Also during the event there was "HydePark" organized in a separate room - something like a small Slot Art Festival where people could reserve time slots to organize their events of any kind - like a talk, a workshop, playing video games, or playing some instruments. It made me wonder if people could come to SGJ, not make any game and still enjoy themselves all the time!

The official communication between the organizers and participants happened on a designated Discord server. Organizers kept us informed about everything what's important by posting announcements to @everyone. And there was a lot happening. For example, they asked us to deliver an exactly 3-second video from our games, from which they later assembled this showreel. They were also making quality photos and posting them during the jam on the Facebook event.

The deadline for games was on Sunday midday. What's interesting is that SGJ was non competitive this time. There were no presentations of the games on stage, no voting or judging by any jury, no winners or prizes. Instead of that, everyone needed to prepare their game to be played by others at their desk. I liked that. I think it might even feel somewhat like preparing a booth at some game expo if taken seriously. Finally, as every good party has a before- and after-party, so in the evening we went to a bar :)

To summarize, I think that in some way it's quite easy to organize a (normal) game jam. You need not invite speakers like for a conference. You need not provide any hardware, as people will bring their own laptops. All you need to do is to have some venue booked for a weekend, and some marketing to invite people to come. Possibly that's why there are so many of such events. My friend once said that taking part in game jams can become a lifestyle - you can go to one almost every week. But SGJ was different. There was so much happening and it was so well organized that I'm sure it required enormous work from everyone involved. Congratulations to the entire crew, KNTG Polygon group from Warsaw University of Technology, volunteers and others!

Regarding the games created during the jam, I could see most of them were developed using Unity. Other technologies were used as well. There were few mobile games, few board games... I couldn't see many VR games. I was developing a game in a team of two, together with my friend Thomas Pendragon - just two programmers. We were planning to use Unreal but we eventually used Unity. We ended up making this game: see entry at itch.io (including binary download for Windows and MacOS).

In our game, you need to "grow" your city by creating a balanced number of places of 5 types (red for building, green for park, blue for water, yellow for airport, gray for road). The city visualization on the left is just eye-candy. You play a tile-matching game like Candy Crush Saga, but with one twist. In the bottom-center there is a Tetris-like indicator that goes up every time you make a match of some color. When all colors are matched, the bottom row is cleared - like in Tetris. If any color goes all the way to the top, you lose, so you need to consider which colors do you match to keep a good balance. That makes the game more strategic. Points are calculated for every match - more if you match 4 or 5 in a row or if something else is matched in the same move. How many points can you reach? The record during the jam was above 1000.

Thomas gave initial idea and designed the game. He did some coding (like the city building on the left), composed the music, added sound effects, made some graphics in Blender, and assembled the rest from some assets. I coded the core logic of the matching game, the whole UI, and juicing, like particle effects and animations.

As a post-mortem of this little project, here is the list of what went right:

What went wrong?

Comments | #productions #competitions #unity #events Share

# Make Your Game Friendly for Graphics Debugging and Optimization - My Talk from Digital Dragons 2019

Fri
07
Jun 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.

Comments | #productions #graphics #games #teaching Share

# Remote programming job is usually not an option

Fri
10
May 2019

Every programmer these days receives lots of job offers from recruiters, especially if having profile on LinkedIn. Some people make fun of it. I used to ignore or reject them, telling that “sorry, I’m not looking for a new job at the moment, I’m happy with my current one”. For some time I started to do something different - I tell them that I’m not interested in relocation to California/​London/​Germany/​Iceland/​South Korea/​wherever and ask if I can work remotely. The answer is usually “no”.

This is contrary to a popular belief that programmers can often work from home. I have a remote job now, but this one is unique and I know such job is hard to find. Maybe it’s more frequent when someone develops web pages, mobile apps, or other small programs that a single person can make. A freelancer hunting for specific projects and tasks may have an opportunity to work from anywhere in the world. But if you want to work in a team of many programmers developing a large and complex project, they usually expect you to be full time on site.

You can come from any place in the world and have a great coding talent. You can study solid computer science at your local university or even learn by yourself from the Internet. But it’s unlikely you can make a world-class career or take part in state-of-the-art, innovative projects while staying in your small home town. For that you have to move to one of these technology hubs, like Silicon Valley. This is despite the developments in telecoferencing, Skype, Slack, etc.

Here are screenshots of 12 chats I had with recruiters on LinkedIn since the beginning of this year. I told them I don’t want to relocate and asked them if I could work remotely. 11 of them said “no”. Only 1 said it’s possible.

Comments | #career Share

# Vulkan: Long way to access data

Thu
18
Apr 2019

If you want to access some GPU memory in a shader, there are multiple levels of indirection that you need to go through. Understanding them is an important part of learning Vulkan API. Here is an explanation of this whole path.

Let’s take texture sampling as an example. We will start from shader code and go from there back to GPU memory where pixels of the texture are stored. If you write your shaders in GLSL language, you can use texture function to do sampling. You need to provide name of a sampler, as well as texture coordinates.

vec4 sampledColor = texture(sampler1, texCoords);

Earlier in the shader, the sampler needs to be defined. Together with this definition you need to provide index of a slot where this sampler and texture will be bound when the shader executes. Binding resources to slots under different numbers is a concept that exists in various graphics APIs for some time already. In Vulkan there are actually two numbers: index of a descriptor set and index of specific binding in that set. Sampler definition in GLSL may look like this:

layout(set=0, binding=1) uniform sampler2D sampler1;

What you bind to this slot is not the texture itself, but so-called descriptor. Descriptors are grouped into descriptor sets – objects of type VkDescriptorSet. They are allocated out of VkDescriptorPool (which we ignore here for simplicity) and they must comply with some VkDescriptorSetLayout. When defining layout of a descriptor set, you may specify that binding number 1 will contain combined image sampler. (This is just an example way of doing this. There are other possibilities, like descriptors of type: sampled image, sampler, storage image etc.)

VkDescriptorSetLayoutBinding binding1 = {};
binding1.binding = 1;
binding1.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
binding1.descriptorCount = 1;
binding1.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;

VkDescriptorSetLayoutCreateInfo layoutInfo = {
    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
layoutInfo.bindingCount = 1;
layoutInfo.pBindings = &binding1;

VkDescriptorSetLayout descriptorSetLayout1;
vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout1);

VkDescriptorSetAllocateInfo setAllocInfo = {
    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
setAllocInfo.descriptorPool = descriptorPool1; // You need to have that already.
setAllocInfo.descriptorSetCount = 1;
setAllocInfo.pSetLayouts = &descriptorSetLayout1;

VkDescriptorSet descriptorSet1;
vkAllocateDescriptorSets(device, &setAllocInfo, &descriptorSet1);

When you have descriptor set layout created, as well as descriptor set based on it allocated, you need to bind the descriptor set as current one under set index 0 in the command buffer that you fill before you can issue a draw call that will use our shader. Function vkCmdBindDescriptorSets is defined for this purpose:

vkCmdBindDescriptorSets(
    commandBuffer1,
    VK_PIPELINE_BIND_POINT_GRAPHICS,
    descriptorSetLayout1,
    0, // firstSet
    1, // descriptorSetCount
    &descriptorSet1,
    0, // dynamicOffsetCount
    nullptr); // pDynamicOffsets

How do you setup the descriptor to point to a specific texture? There are multiple ways to do that. The most basic one is to use vkUpdateDescriptorSets function:

VkDescriptorImageInfo imageInfo = {};
imageInfo.sampler = sampler1;
imageInfo.imageView = imageView1;
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;

VkWriteDescriptorSet descriptorWrite = {
    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
descriptorWrite.dstSet = descriptorSet1;
descriptorWrite.dstBinding = 1;
descriptorWrite.descriptorCount = 1;
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptorWrite.pImageInfo = &imageInfo;

vkUpdateDescriptorSets(
    device,
    1, // descriptorWriteCount
    &descriptorWrite, // pDescriptorWrites
    0, // descriptorCopyCount
    nullptr); // pDescriptorCopies

Please note that this function doesn’t record a command to any command buffer. Descriptor update happens immediately. That’s why you need to do it before you submit your command buffer for execution on GPU and you need to keep this descriptor set alive and unchanged until the command buffer finishes execution.

There are other ways to update a descriptor set. You can e.g. use last two parameters of vkUpdateDescriptorSets function to copy descriptors (which is not recommended for performance reasons), as well as to use some extensions, e.g.: VK_KHR_push_descriptor, VK_KHR_descriptor_update_template.

What we write as value of the descriptor is reference to objects: imageView1 and sampler1. Let’s ignore the sampler and just focus on imageView1. This is an object of type VkImageView. Like in Direct3D 11, an image view is a simple object that encapsulates reference to an image along with a set of additional parameters that let you “view” the image in a certain way, e.g. limit access to a range of mipmap levels, array layers, or reinterpret it as different format.

VkImageViewCreateInfo viewInfo = {
    VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
viewInfo.image = image1;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;

VkImageView imageView1;
vkCreateImageView(device, &viewInfo, nullptr, &imageView1);

As you can see, image view object holds reference to image1. This is an object of type VkImage that represents actual resource, commonly called “texture” in other APIs. It is created from a rich set of parameters, like width, height, pixel format, number of mipmap levels etc.

VkImageCreateInfo imageInfo = {
    VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent.width = 1024;
imageInfo.extent.height = 1024;
imageInfo.depth = 1;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
iamgeInfo.usage =
    VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;

VkImage image1;
vkCreateImage(device, &imageInfo, nullptr, &image1);

It’s not all yet. Unlike previous generation graphics APIs (Direct3D 9 or 11, OpenGL), image or buffer object doesn’t automatically allocate backing memory for its data. You need to do it on your own. What you actually need to do is to first query the image for memory requirements (required size and alignment), then allocate memory block for it and finally bind those two together. Only then the image is usable as a means of accessing the memory, interpreted as colorful pixels of a 2D picture.

VkMemoryRequirements memReq;
vkGetImageMemoryRequirements(device, image1, &memReq);

VkMemoryAllocateInfo allocInfo = {
    VK_STRUTURE_TYPE_MEMORY_ALLOCATE_INFO };
allocInfo.allocationSize = memReq.size;
allocInfo.memoryTypeIndex = 0; // You need to find appropriate index!

VkDeviceMemory memory1;
vkAllocateMemory(device, &allocInfo, nullptr, &memory1);

vkBindImageMemory(
    device,
    image1,
    memory1,
    0); // memoryOffset

In production quality code you should of course check for error codes, e.g. when your allocation fails because you run out of memory. You should also avoid allocating separate memory blocks for each of your images and buffers. It is necessary to allocate bigger memory blocks and manage them manually, assigning parts of them to your resources. You can use last parameter of the binding function to provide offset in bytes from the start of a memory block. You can also simplify this part by using existing library: Vulkan Memory Allocator.

Comments | #graphics #vulkan Share

# WinFontRender - my new library

Thu
14
Mar 2019

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:

» WinFontRender - small single-header C++ library that renders Windows fonts in graphics applications

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:

Comments | #graphics #libraries #productions Share

Pages: 1 2 3 ... 139 >

STAT NO AD
[Stat] [STAT NO AD] [Download] [Dropbox] [pub] [Mirror] [Privacy policy]
Copyright © 2004-2019