Tag: graphics

Entries for tag "graphics", ordered from most recent. Entry count: 55.

Pages: 1 2 3 ... 7 >

# Vulkan with DXGI - experiment results

Mon
19
Nov 2018

In my previous post, I’ve described a way to get GPU memory usage in Windows Vulkan app by using DXGI. This API, designed for Direct3D, seems to work with Vulkan as well. In this post I would like to share detailed results of my experiment on two different platforms with two graphics cards from different vendors. But before that, a disclaimer:

Read full entry > | Comments | #windows #graphics #directx #vulkan Share

# There is a way to query GPU memory usage in Vulkan - use DXGI

Thu
15
Nov 2018

In my GDC 2018 talk “Memory management in Vulkan and DX12” (slides freely available, video behind GDC Vault paywall) I said that in Direct3D 12 you can query for the exact amount of GPU memory used and available, while in Vulkan there is no way to do that, so I recommend to just query for memory capacity (VkMemoryHeap::​size) and limit your usage to around 80% of it. It turns out that I wasn’t quite right. If you code for Windows, there is a way to do this. I assumed that the mentioned function IDXGIAdapter3::​QueryVideoMemoryInfo is part of Direct3D 12 interface, while it is actually part of DirectX Graphics Infrastructure (DXGI). This is a more generic, higher level Windows API that allows you to enumerate adapters (graphics cards) installed in the system, query for their parameters and outputs (monitors) connected to them. Direct3D refers to this API, but it’s not the same.

Key question is: Can you use DXGI to query for GPU memory usage while doing graphics using Vulkan, not D3D11 or D3D12? Would it return some reasonable data and not all zeros? Short answer is: YES! I’ve made an experiment - I wrote a simple app that creates various Vulkan objects and queries DXGI for memory usage. Results look very promising. But before I move on to the details, here is a short primer of how to use this DXGI interface, for all non-DirectX developers:

1. Use C++ in Visual Studio. You may also use some other compiler for Windows or other programming language, but it will be probably harder to setup.

2. Install relatively new Windows SDK.

3. #include <dxgi1_4.h> and <atlbase.h>

4. Link with “dxgi.lib”.

5. Create Factory object:

IDXGIFactory4* dxgiFactory = nullptr;
CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory));

Don’t forget to release it at the end:

dxgiFactory->Release();

6. Write a loop to enumerate available adapters. Choose and remember suitable one.

IDXGIAdapter3* dxgiAdapter = nullptr;
IDXGIAdapter1* tmpDxgiAdapter = nullptr;
UINT adapterIndex = 0;
while(m_DxgiFactory->EnumAdapters1(adapterIndex, &tmpDxgiAdapter) != DXGI_ERROR_NOT_FOUND)
{
    DXGI_ADAPTER_DESC1 desc;
    tmpDxgiAdapter>GetDesc1(&desc);
    if(!dxgiAdapter && desc.Flags == 0)
    {
        tmpDxgiAdapter->QueryInterface(IID_PPV_ARGS(&dxgiAdapter));
    }
    tmpDxgiAdapter->Release();
    ++adapterIndex;
}

At the end, don’t forget to release it:

dxgiAdapter->Release();

Please note that using new version of DXGI interfaces like DXGIFactory4 and DXGIAdapter3 requires some relatively new version (I’m not sure which one) of both Windows SDK on developer’s side (otherwise it won’t compile) and updated Windows system on user’s side (otherwise function calls with fail with appropriate returned HRESULT).

7. To query for GPU memory usage at the moment, use this code:

DXGI_QUERY_VIDEO_MEMORY_INFO info = {};
dxgiAdapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &info);

There are two possible options:

Among members of the returned structure, the most interesting is CurrentUsage. It seems to precisely reflect the use of GPU memory - it increases when I allocate a new VkDeviceMemory object, as well as when I use some implicit memory by creating other Vulkan resources, like a swap chain, descriptor pools and descriptor sets, command pools and command buffers, query pools etc.

Other DXGI features for video memory - callback for budget change notification (IDXGIAdapter3::​RegisterVideoMemoryBudgetChangeNotificationEvent) and reservation (IDXGIAdapter3::​SetVideoMemoryReservation) may also work with Vulkan, but I didn’t check them.

As an example, on my system with GPU = AMD Radeon RX 580 8 GB and 16 GB of system RAM, on program startup and before any Vulkan or D3D initialization, DXGI reports following data:

Local:
 Budget=7252479180 CurrentUsage=0
 AvailableForReservation=3839547801 CurrentReservation=0
Nonlocal:
 Budget=7699177267 CurrentUsage=0
 AvailableForReservation=4063454668 CurrentReservation=0

8. You may want to choose correct DXGI adapter to match the physical device used in Vulkan. Even on the system with just one discrete GPU there are two adapters reported, one of them being software renderer. I exclude it by comparing desc.Flags == 0, which means this is a real, hardware-accelerated GPU, not DXGI_ADAPTER_FLAG_REMOTE or DXGI_ADAPTER_FLAG_SOFTWARE.

Good news is that even when there are more such adapters in the system, there is a way to match them between DXGI and Vulkan. Both APIs return something called Locally Unique Identifier (LUID). In DXGI it’s in DXGI_ADAPTER_DESC1::​AdapterLuid. In Vulkan it’s in VkPhysicalDeviceIDProperties::​deviceLUID. They are of different types - two 32-bit numbers versus array of bytes, but it seems that simple, raw memory compare works correctly. So the way to find DXGI adapter matching Vulkan physical device is:

// After obtaining VkPhysicalDevice of your choice:
VkPhysicalDeviceIDProperties physDeviceIDProps = {
    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES };
VkPhysicalDeviceProperties2 physDeviceProps = {
    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 };
physDeviceProps.pNext = &physDeviceIDProps;
vkGetPhysicalDeviceProperties2(physicalDevice, &physDeviceProps);

// While enumerating DXGI adapters, replace condition:
// if(!dxgiAdapter && desc.Flags == 0)
// With this:
if(memcmp(&desc.AdapterLuid, physDeviceIDProps.deviceLUID, VK_LUID_SIZE) == 0)

Please note that function vkGetPhysicalDeviceProperties2 requires Vulkan 1.1, so set VkApplicationInfo::​apiVersion = VK_API_VERSION_1_1. Otherwise the call results in “Access Violation” error.

In my next blog post, I present detailed results of my experiment with DXGI used with Vulkan application, tested on 2 different GPUs.

Comments | #windows #graphics #vulkan #directx Share

# Scaling is everywhere, pixel-perfect is the past

Thu
04
Oct 2018

Long time ago, when computers were slow and screen resolutions were low, everything had to be pixel-perfect. For example, Atari 2600 game console could display only 160x192 pixels. During that time, game characters and all the graphics had to be drawn pixel by pixel, to include all the intended details, like Mario's moustache. This is known as pixel art.



Source: The Evolution of Mario

Years later, with higher screen resolutions, game sprites could be drawn using different methods, or even rendered from 3D models, but icons and other GUI elements were still prepared to be shown pixel-by-pixel. Same applied to web pages.

Nowadays, even GUI icons are scaled. They can be enlarged smoothly and they can be displayed on various monitors, where 4K monitor has 4x more pixels than FullHD. Setting desktop DPI scaling other than 100% scales all the apps in Windows. Modern web pages created according to "responsive design" principles have to look good on all kinds of devices, from little smartphones to huge monitors. Scaling is everywhere.

When programmable cellphones first appeared, making apps and games for them was like going back in time. Just like on retro platforms and first PCs, screens had very low resolutions and pixel art was the way to go when drawing game characters. Now mobile games have to work on all sorts of smartphones, many of them having resolutions like our PC monitors - FullHD or even higher.

What seems like the last relic of pixel-perfection is the rendering of 3D scenes. Since the introduction of 3D graphics, we tend to rasterize and shade our triangles in the same resolution as the image to be displayed on screen, which is ideally equal to native resolution of the monitor. Otherwise, every gamer who cares about image quality would call it looking bad. Or wouldn't he?

Some things can be rendered in lower resolution. There are games that render the layer with alpha-blended, translucent objects (especially particle effects like fire, smoke, clouds) to a 4x smaller texture and then upscale it while compositing with main, opaque geometry. Such elements tend not to have too many high-frequency (small) details anyway, so quality degradation due to lower resolution is not very noticeable, while smaller number of pixels that need to be shaded and blended saves a lot of rendering time.

But that's not the full story. Regardless of resolution, antialiasing is, and always will be, necessary to blur jaggy edges. Ideal solution for it is known as Super Sampling Anti-Aliasing (SSAA), which is nothing else but rendering the scene in higher resolution and then downscaling it to e.g. average 2x2 rendered pixels into a single output pixel. It could be done by a game, or introduced by graphics driver. AMD has this feature in driver under the name "Virtual Super Resolution".

This of course is a slow method, because rendering 4x more pixels requires a lot of computations and memory bandwidth. Various methods exist that provide more efficient antialiasing. Multisample Anti-Aliasing (MSAA), which is supported by GPUs in hardware, lets you shade a pixel (calculate RGB color in a pixel shader) only once, but store it in multiple per-pixel samples, depending on the shape of the edge being rendered. Numerous screen-space postprocessing algorithms exist that intelligently blur already rendered image to smooth the edges, e.g. FXAA, MLAA.

This interchangeability between rendering in higher resolution and higher quality antialiasing, as well as the possibility to do some filtering of the rendered image, is probably best exploited by the engine behind Call of Duty. Jorge Jimenez (Graphics R&D Technical Director at Activision Blizzard) explained it in his talks: "Dynamic temporal antialiasing and upsampling in Call of Duty" (Digital Dragons 2017), "Dynamic Temporal Antialiasing in Call of Duty: Infinite Warfare" (SIGGRAPH 2017). They dynamically scale rendering resolution depending on current game load to maintain sufficient framerate. The scene is then scaled to screen resolution. Their technique "combines dynamic resolution with temporal upsampling". Such techniques are especially useful where high FPS and smooth gameplay is important, even at the expense of graphics quality - in fast-paced games, professional e-sport, and VR.

Screen resolutions become higher, but performance of GPUs don't necessarily scale at the same rate. Single-pixel details are harder to notice. That's why it can make sense to render at resolutions even smaller than output resolution and then interpolate missing pixels. Of course, no interpolation algorithm is perfect and using just bilinear filter would look horrible. That's why techniques are being developed which try to minimize quality loss in this process, e.g. temporal methods (that use image from the previous frame), checkerboard rendering, or new Deep Learning Super Sampling (DLSS) from NVIDIA.

It also makes sense to shade pixels at lower rate in some parts of the image where details are hard to notice, e.g. where the player is not looking (peripheral vision in VR, especially if eye tracking is available), objects are moving fast (based on screen-space motion vectors) or where there are not many high-frequency details (based on analysis of the previous frame). Shading per pixel or per sample is just one option. NVIDIA cards support techniques like Multi-Res Shading or their latest invention - Variable Rate Shading (VFR), where helper texture can locally control shading rate from once per 16 pixels all the way to 8 times per pixel.

Finally, the rate of shading (lighting calculation) can be completely decoupled from the rate of rendering of the final image (rasterization) and done in different space, at different framerate or even completely asynchronously. This is known as Object-Space Shading/Texture-Space Shading. It has successfully been used by Oxide Games in their Ashes of the Singularity and may soon become more widespread.

I think we could say that scaling is everywhere, pixel-perfect is the past. It is not necessarily a bad thing. If the goal of advancements in 3D rendering in games is to look photorealistically like movies, then we should realize that movies are never pixel-perfect - there is always scaling and filtering involved at various stages. Even at the very beginning, camera sensors have some pattern of R, G, B pixels that must be interpolated to fit them into (RGB) triplets.

Then they are often encoded using chroma subsampling (like 4:2:2) and compressed using some video compression codecs. Interpolation and filtering may be involved at many stages of processing, e.g. frame rate conversion, deinterlace, noise reduction, or finally, sharpening commonly applied by modern smart TVs (which I'm very allergic to, but there must be some reason behind it). Recorded videos are never pixel perfect. Rendered 3D games don't have to be as well.

Comments | #graphics Share

# Debugging D3D12 driver crash

Wed
12
Sep 2018

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 ID3D12Device3::​OpenExistingHeapFromAddress and 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.

Comments | #directx #graphics #libraries #productions Share

# Vulkan Memory Allocator 2.1.0

Tue
28
Aug 2018

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.

Comments | #vulkan #libraries #productions #graphics Share

# Vulkan API - my talk at Warsaw University of Technology

Mon
16
Apr 2018

On Wednesday 16 April, around 8 PM, at Warsaw University of Technology, during weekly meeting of KNTG Polygon, I will give a talk about "Vulkan API" (in Polish). Come if you want to hear about new generation of graphics APIs, see how Vulkan API looks like, what tools are there to support it, what are advantages and disadvantages of using such API and finally decide whethere learning Vulkan is a good idea for you.

Event on Facebook: https://www.facebook.com/events/185314825611839/

Slides:
Vulkan API.pdf
Vulkan API.pptx

Comments | #graphics #gpu #vulkan #teaching Share

# Debugging Vulkan driver crash - equivalent of NVIDIA Aftermath

Wed
28
Mar 2018

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 buffer 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 VK_ERROR_DEVICE_LOST code from one of functions like vkQueueSubmit. 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 and only in D3D11 and D3D12.

I was looking for similar solution for Vulkan. When I saw that Vulkan can "import" external memory, I thought that maybe I could use function vkCmdFillBuffer to write immediate value to such buffer and this way implement the same logic. I then started experimenting with extensions: VK_KHR_get_physical_device_properties_2, VK_KHR_external_memory_capabilities, VK_KHR_external_memory, VK_KHR_external_memory_win32, VK_KHR_dedicated_allocation. I was basically trying to somehow allocate a piece of system memory and import it to Vulkan to write to it as Vulkan buffer. I tried many things: CreateFileMapping + MapViewOfFile, HeapCreate + HeapAlloc and other ways, with various flags, but nothing worked for me. I also couldn't find any description or sample code of how these extensions could be used in Windows to import some system memory as Vulkan buffer.

Everything changed when I learned that creating normal device memory and buffer inside Vulkan is enough! It survives driver crash, so its content can be read later via mapped pointer. No extensions required. I don't think this is guaranteed by specification, but it seems to work on both AMD and NVIDIA cards. So my current solution to write makers that survive driver crash in Vulkan is:

  1. Call vkAllocateMemory to allocate VkDeviceMemory from memory type that has HOST_VISIBLE + HOST_COHERENT flags. (This is system RAM. Spec guarantees that you can always find such type.)
  2. Map the memory using vkMapMemory to get raw CPU pointer to its data.
  3. Call vkCreateBuffer to create VkBuffer with VK_BUFFER_USAGE_TRANSFER_DST_BIT and bind it to that memory using vkBindBufferMemory.
  4. While recording commands to VkCommandBuffer, use vkCmdFillBuffer to write immediate data with your custom "markers" to the buffer.
  5. If everything goes right, don't forget to vkDestroyBuffer and vkFreeMemory during shutdown.
  6. If you experience driver crash (receive VK_ERROR_DEVICE_LOST), read data under the pointer to see what marker values were successfully written last and deduce which one of your commands might cause the crash.

There is also a new extension available on latest AMD drivers: VK_AMD_buffer_marker. It adds just one function: vkCmdWriteBufferMarkerAMD. It works similar to beforementioned vkCmdFillBuffer, but it adds two good things that let you write your markers with much better granularity:

I created a simple library that implements all this logic under easy interface, which I called "Vulkan AfterCrash". All you need to use it is just this single file: VulkanAfterCrash.h.

Update 4 April 2018: In GDC 2018 talk "Aftermath: Advances in GPU Crash Debugging (Presented by NVIDIA)", Alex Dunn announced that a Vulkan extension from NVIDIA will also be available, called VK_NV_device_diagnostic_checkpoints, but I can see it's not publicly accessible yet.

Update 1 August 2018: Documentation for extension VK_NV_device_diagnostic_checkpoints has been published in Vulkan version 1.1.82.

Update 12 September 2018: I've created similar, portable library for Direct3D 12 - see blog post "Debugging D3D12 driver crash".

Comments | #vulkan #graphics #libraries #productions Share

# Vulkan Memory Allocator 2.0.0

Mon
26
Mar 2018

At Game Developers Conference (GDC) last week I released final version 2.0.0 of Vulkan Memory Allocator library. It is now well documented and thanks to contributions from open source community it compiles and works on Windows, Linux, Android, and MacOS. Together with it I released VMA Dump Vis - a Python script that visualizes Vulkan memory on a picture. From now on I will continue incremental development on "development" branch and occasionally merge to "master". Feel free to contact me if you have any feedback, suggestions or if you find a bug.

Comments | #vulkan #libraries #productions #graphics Share

Pages: 1 2 3 ... 7 >

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