Tag: graphics

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

Pages: 1 2 3 ... 6 >

# VK_KHR_dedicated_allocation unofficial manual

22:36
Mon
16
Oct 2017

I wrote a short article that explains how to use Vulkan extenion "VK_KHR_dedicated_allocation". It may be interesting to you if you are a programmer and you code graphics using Vulkan.

Go to article: VK_KHR_dedicated_allocation unofficial manual

Comments | #graphics #vulkan Share

# Vulkan Memory Allocator 2.0.0-alpha.3

13:42
Wed
13
Sep 2017

I just published new version of Vulkan Memory Allocator 2.0.0-alpha.3. I'm quite happy with the quality of this code. Documentation is also updated, so if nothing else, please just go see User guide. I still marked it as "alpha" because I would like to ask for feedback and I may still change everything.

I would like to discuss proposed terminology. Naming things in code is a hard problem in general, and especially as English is not my native language, so please fill free to contact me and propose more elegant names to what I called: allocator, allocation, pool, block, stats, free range, used/unused bytes, own memory, persistently mapped memory, pointer to mapped data, lost allocation (becoming lost, making other lost), defragmentation, and used internally: suballocation, block vector.

Comments | #vulkan #productions #libraries #graphics Share

# How to Use Vulkan SDK with AppVeyor and Travis CI?

18:34
Mon
21
Aug 2017

AppVeyor and Travis CI are popular, free web services that provide continuous integration style build and testing environments for open source projects - for Windows and Linux, respectively. They are relatively easy to setup if your project is self-contained, but can be a little bit tricky if you need to install some additional dependencies. Today I successfully finished installing Vulkan SDK in these environments, to test Vulkan Memory Allocator project. Here is how to do it:

In AppVeyor I have everything configured on their website, so you can’t really see configuration file. To download Vulkan SDK, I used curl command which is available by default. It took me some time to find direct link to SDK file because Download page on vulkan.lunarg.com points to addresses like “https://vulkan.lunarg.com/sdk/home#sdk/downloadConfirm/1.0.51.0/windows/VulkanSDK-1.0.51.0-Installer.exe”, which is actually a web page full of JavaScript that eventually redirects to real file when opened in a web browser. Finally I found it. Then I entered following commands as Environment > Install script:

curl --silent --show-error --output VulkanSDK.exe https://vulkan.lunarg.com/sdk/download/1.0.51.0/windows/VulkanSDK-1.0.51.0-Installer.exe
.\VulkanSDK.exe /S

First command downloads and second one installs Vulkan SDK in silent mode. The SDK is installed to C:\VulkanSDK\1.0.51.0 directory.

Next I added an environmental variable in Environment > Environmental variables section:

name: VULKAN_SDK
value: c:\VulkanSDK\1.0.51.0

In my Visual Studio project settings, I added include directory "$(VULKAN_SDK)/Include" and library directory "$(VULKAN_SDK)/Lib". Then I could successfully #include <vulkan/vulkan.h> and link with vulkan-1.lib.

For Travis CI you can see my current configuration file as: .travis.yml. What I did here is I added few commands to install section. First there are some apt-get commands that install some additional libraries, which I took from Getting Started with the Vulkan SDK page:

sudo apt-get -qq update
sudo apt-get install -y libassimp-dev libglm-dev graphviz libxcb-dri3-0 libxcb-present0 libpciaccess0 cmake libpng-dev libxcb-dri3-dev libx11-dev libx11-xcb-dev libmirclient-dev libwayland-dev libxrandr-dev

Then I download and install Vulkan SDK. URL to real file is in the same format as for Windows. I used wget command for downloading. The file is a self-extracting archive that unpacks SDK content to following subdirectory of current directory: VulkanSDK/1.0.51.0/x86_64.

wget -O vulkansdk-linux-x86_64-1.0.51.0.run https://vulkan.lunarg.com/sdk/download/1.0.51.0/linux/vulkansdk-linux-x86_64-1.0.51.0.run
chmod ugo+x vulkansdk-linux-x86_64-1.0.51.0.run
./vulkansdk-linux-x86_64-1.0.51.0.run

Finally I issue a command that sets environmental variable pointing to the SDK, to have it available in the code just like on Windows:

export VULKAN_SDK=$TRAVIS_BUILD_DIR/VulkanSDK/1.0.51.0/x86_64

Then I needed to configure my project to search for include files in "$(VULKAN_SDK)/include" and library files in "$(VULKAN_SDK)/lib" (directory names are lowercase this time!). Finally I could #include <vulkan/vulkan.h> and link with libvulkan.so.

Comments | #graphics #vulkan Share

# Stencil Test Explained Using Code

20:11
Sun
20
Aug 2017

I must admit I never used stencil buffer in my personal code. I know it's there available in GPUs and all graphics APIs for years and it's useful for many things, but somehow I never had a need to use it. Recently I became aware that I don't fully understand it. There are many descriptions of stencil test on the Internet, but none of them definitely answered my questions in the way I would like them to be answered. I thought that a piece of pseudocode would explain it better than words, so here is my explanation of the stencil test.

Let's choose Direct3D 11 as our graphics API. Other APIs have similar sets of parameters. D3D11 offers following configuration parameters for stencil test:

Structure D3D11_DEPTH_STENCIL_DESC:

BOOL StencilEnable
UINT8 StencilReadMask
UINT8 StencilWriteMask
D3D11_DEPTH_STENCILOP_DESC FrontFace
D3D11_DEPTH_STENCILOP_DESC BackFace

Structure D3D11_DEPTH_STENCILOP_DESC:

D3D11_STENCIL_OP StencilFailOp
D3D11_STENCIL_OP StencilDepthFailOp
D3D11_STENCIL_OP StencilPassOp
D3D11_COMPARISON_FUNC StencilFunc

Parameter passed to ID3D11DeviceContext::OMSetDepthStencilState method:

UINT StencilRef

How do they work? If you render pixel (x, y) and you have current value of stencil buffer available as:

UINT8 Stencil[x, y]

Then pseudocode for stencil test and write could look like below. First, one of two sets of parameters is selected depending on whether current primitive is front-facing or back-facing:

if(StencilEnable)
{
    if(primitive has no front and back face, e.g. points, lines)
      StencilOpDesc = FrontFace
    else
    {
       if(primitive is front facing)
          StencilOpDesc = FrontFace
       else
          StencilOpDesc = BackFace
   }

Then, a test is performed:

    StencilTestPassed =
       (StencilRef & StencilReadMask) StencilOpDesc.StencilFunc
       (Stencil[x, y] & StencilReadMask)

StencilOpDesc.StencilFunc is a comparison operator that can be one of possible enum values: D3D11_COMPARISON_NEVER, LESS, EQUAL, LESS_EQUAL, GREATER, NOT_EQUAL, GREATER_EQUAL, ALWAYS. I think this is quite self-explanatory.

Notice how StencilRef is on the left side of comparison operator and current stencil buffer value is on the right.

Both StencilRef and current stencil buffer value are ANDed with StencilReadMask before comparison.

Next, based on the result of this test, as well as result of depth-test aka Z-test (which is out of scope of this article), an operation is selected:

    if(StencilTestPassed)
    {
       if(DepthTestPassed)
          Op = StencilOpDesc.SencilPassOp
       else
          Op = StencilOpDesc.StencilDepthFailOp
    }
    else
        Op = StencilOpDesc.StencilFailOp

Op is another enum that controls a new value to be written to stencil buffer. It can be one of:

    switch(Op)
    {
    case D3D11_STENCIL_OP_KEEP: NewValue = Stencil[x, y]
    case D3D11_STENCIL_OP_ZERO: NewValue = 0
    case D3D11_STENCIL_OP_REPLACE: NewValue = StencilRef
    case D3D11_STENCIL_OP_INCR_SAT: NewValue = min(Stencil[x, y] + 1, 0xFF)
    case D3D11_STENCIL_OP_DECR_SAT: NewValue = max(Stencil[x, y] - 1, 0)
    case D3D11_STENCIL_OP_INVERT: NewValue = ~Stencil[x, y]
    case D3D11_STENCIL_OP_INCR: NewValue = Stencil[x, y] + 1 // with 8-bit wrap-around
    case D3D11_STENCIL_OP_DECR: NewValue = Stencil[x, y] - 1 // with 8-bit wrap-around
    }

Finally, the new value is written to the stencil buffer. Notice how only those bits are changed that are included in StencilWriteMask. Others remain unchanged.

    Stencil[x, y] =
       (Stencil[x, y] & ~StencilWriteMask) |
       (NewValue & StencilWriteMask)
}

Now as we have all this explained in a very strict way using code, let me answer doubts I had before understanding this, in form of a FAQ.

Q: Are there no separate flags to enable stencil test and stencil write?

A: No. There is only one flag StencilEnable to enable all this functionality.

Q: So how to use only one and not the other?

A: You can find specific set of settings to do that.

To perform only stencil test and not write, set StencilEnable to true, StencilFunc to the comparison function you need and set all *Op to KEEP or alternatively set StencilWriteMask to 0 to disable any modifications to stencil buffer.

To perform only stencil write and not stencil test, set StencilEnable to true, all *Op and StencilWriteMask to values you need and set StencilFunc to ALWAYS to make the stencil test always passing.

Q: Is the StencilRef value also masked by StencilReadMask?

A: Yes. As you can see in the code, it is also ANDed with StencilReadMask, just as the previous value from stencil buffer. You don't need to provide it "pre-masked". (Comparison to "premultipled alpha" comes to my mind...)

In other words, we could say that only bits indicated by StencilReadMask from both sides participate in comparison.

Q: What are stencil value bits replaced to in REPLACE Op mode?

A: They are replaced with StencilRef value - the same that was used in comparison.

Q: Why is it the same StencilRef value as used for comparison, not separate one?

A: I don't know. There is separate StencilReadMask and StencilWriteMask. They could have provided separate "StencilReadRef" and "StencilWriteRef" - but for some reason the didn't :P

Q: What value is incremented/decremented when Op in INCR*, DECR*?

A: It's the original value read from stencil buffer, not masked or shifted in relation to StencilReadMask or StencilWriteMask. Which means it doesn't make much sense to use these ops if your StencilWriteMask looks like e.g. 0xF0 - masks out least significant bits.

Q: Is depth buffer updated when stencil test fails?

A: No. Failing stencil test means that the pixel is discarded, so Z-buffer is not updated and color is not written or blended to render targets.

On the other hand, failing Z-test can cause stencil buffer to be updated when you use StencilDepthFailOp other than KEEP.

If I misunderstood something and some of the information in this article is wrong, please let me know by e-mail or comment below.

Comments | #directx #graphics Share

# Understanding Vulkan objects

18:27
Mon
07
Aug 2017

An important part of learning the Vulkan® API – just like any other API – is to understand what types of objects are defined in it, what they represent and how they relate to each other. To help with this, we’ve created a diagram that shows all of the Vulkan objects and some of their relationships, especially the order in which you create one from another.

Read more: Understanding Vulkan objects @ GPUOpen

Comments | #graphics #vulkan Share

# Slavic Game Jam 2017 and my talk

12:40
Wed
26
Jul 2017

There are many game jams all around the world. Global Game Jam is probably the biggest and most popular one, but it is a global event that happens at different sites. This weekend Slavic Game Jam takes place - the biggest game jam in Eastern Europe, happening in just one site in Warsaw, Poland.

I will be there not only as a participant, but I will also give a talk, because AMD is a sponsor of the event. My talk will be on Friday at 2 PM. Its title is "Rendering in Your Game - Debugging and Profiling". I will provide some basic information and show some tools useful for analyzing performance of a game, including live demo. This information may be useful no matter if you develop your own engine or use existing one like Unity or Unreal. If you have a ticket for the event (tickets are already sold out), I invite you to come on Friday earlier than for the official start of the jam.

Comments | #teaching #events #competitions #graphics Share

# Vulkan Memory Allocator - a library on GPUOpen & GitHub

13:03
Tue
11
Jul 2017

Vulkan is hard. One of the difficulties is the responsibility of a developer to manually manage GPU memory. Various GPU vendors expose various set of memory heaps and types and you need to choose right ones. It is also recommended to allocate larger memory blocks and assign parts of them to individual buffers and images. Now there is a library that simplifies these tasks - a one that I developed as part of my job duties. It has just been announced on GPUOpen blog and published on GitHub:

It is a single-header C++ library with a simple C Vulkan-style interface documented using Doxygen-style comments. It is available on MIT license.

Comments | #graphics #vulkan Share

# Vulkan Bits and Pieces: Synchronization in a Frame

21:15
Mon
15
May 2017

One of the things that you must implement when using Vulkan is basic structure of a rendering frame, which consists of filling a command buffer, submitting it to a command queue, acquiring image from swap chain and finally presenting it (order not preserved here). Things happen in parallel, as GPU works asynchronously to the CPU, so you must explicitly synchronize all these things. In this post I’d like to present basic structure of the rendering frame, with all necessary synchronization.

There are actually two objects that we must take care of simultaneously. First is command buffer. One time it is being filled on the CPU by using vkBeginCommandBuffer, vkEndCommandBuffer and everything in between (like starting render passes and posting all the vkCmd* commands). Another time (after being submitted to a queue using vkQueueSubmit) it waits for execution or it is being executed on the GPU. These things cannot happen at the same time, so we need synchronization. Because it’s a GPU-to-CPU synchronization, we use fence for that. It’s better to have multiple command buffers and all these synchronization objects, stored in array and used in a round-robin fashion (with help of index variable) because this way one can be filled while the other one is consumed at the same time.

Second object is an image acquired from the swapchain. One time it is being rendered to during command buffer execution. Another time it is presented on the screen. Again, we need to synchronize it so these states happen in a sequence. Because it’s a GPU-to-GPU synchronization, we use semaphores for that. There are multiple images as well because swapchain consists of several of them (not necessarily used in round-robin fashion, we need to obtain index of a new image using vkAcquireNextImageKHR function, so there is separate imageIndex).

Having following objects already initialized:

VkDevice g_Device;
VkQueue g_GraphicsQueue;
VkSwapchainKHR g_Swapchain;
VkImageView g_SwapchainImageViews[MAX_SWAPCHAIN_IMAGES];

const uint32_t COUNT = 2;
uint32_t g_NextIndex = 0;
VkCommandBuffer g_CmdBuf[COUNT];
VkFence g_CmdBufExecutedFences[COUNT]; // Create with VK_FENCE_CREATE_SIGNALED_BIT.
VkSemaphore g_ImageAvailableSemaphores[COUNT];
VkSemaphore g_RenderFinishedSemaphores[COUNT];

Structure of a frame may look like this:

uint32_t index = (g_NextIndex++) % COUNT;
VkCommandBuffer cmdBuf = g_CmdBuf[index];

vkWaitForFences(g_Device, 1, &g_CmdBufExecutedFences[index], VK_TRUE, UINT64_MAX);

VkCommandBufferBeginInfo cmdBufBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuf, &cmdBufBeginInfo);

// Post some rendering commands to cmdBuf.

uint32_t imageIndex;
vkAcquireNextImageKHR(g_Device, g_Swapchain, UINT64_MAX, g_ImageAvailableSemaphores[index], VK_NULL_HANDLE, &imageIndex);

// Post those rendering commands that render to final backbuffer:
// g_SwapchainImageViews[imageIndex]

vkEndCommandBuffer(cmdBuf);

vkResetFences(g_Device, 1, &g_CmdBufExecutedFences[index]);

VkPipelineStageFlags submitWaitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT;
VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = &g_ImageAvailableSemaphores[index];
submitInfo.pWaitDstStageMask = &submitWaitStage;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &cmdBuf;
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &g_RenderFinishedSemaphores[index];
vkQueueSubmit(g_GraphicsQueue, 1, &submitInfo, g_CmdBufExecutedFences[index]);

VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = &g_RenderFinishedSemaphores[index];
presentInfo.swapChainCount = 1;
presentInfo.pSwapchains = &g_Swapchain;
presentInfo.pImageIndices = &imageIndex;
vkQueuePresentKHR(g_GraphicsQueue, &presentInfo);

At least that’s what I currently believe is the correct and efficient way. If you think I’m wrong, please leave a comment or write me an e-mail.

That’s just one aspect of using Vulkan. There are still more things to do before you can even render your first triangle, like transitioning swapchain image layout between VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL and VK_IMAGE_LAYOUT_PRESENT_SRC_KHR.

Comments | #vulkan #graphics Share

Pages: 1 2 3 ... 6 >

STAT NO AD
[Stat] [STAT NO AD] [Download] [Dropbox] [pub] [Mirror]
Copyright © 2004-2017