overv / vulkantutorial Goto Github PK
View Code? Open in Web Editor NEWTutorial for the Vulkan graphics and compute API
Home Page: https://vulkan-tutorial.com
License: Creative Commons Attribution Share Alike 4.0 International
Tutorial for the Vulkan graphics and compute API
Home Page: https://vulkan-tutorial.com
License: Creative Commons Attribution Share Alike 4.0 International
It appears there is an issue in Visual Studio 2017 when exporting C++ templates.
It seems that Visual Studio doesn't include the files added through Add
-> New Item...
, I'm not sure if this is intended behaviour or not. A quick workaround I've found is to drag and drop the main.cpp
file into the project rather than adding files through that system. Exporting the template should then work as one would expect.
Perhaps this could be noted in the tutorial in the Template Export
section.
There is currently only one uniform buffer that is updated before each drawFrame
call while multiple frames may be in-flight. The code should probably be changed to use a uniform buffer per frame.
vulkan-tutorial.com uses an invalid security certificate.
The certificate expired on June 24, 2017 at 10:01 PM. The current time is June 24, 2017 at 10:36 PM.
Error code: SEC_ERROR_EXPIRED_CERTIFICATE
According to Vulkan specs, VK_EXT_debug_utils
is the "proper" extension to use for validation layers and VK_EXT_debug_report
will no longer be developed further. I think it would be a good idea to mention that in the tutorial and replace current implementation to make use of the new structures.
There are two known issues in the current drawing and presentation logic of the tutorial:
I will research other samples and reference code to correct these and update the tutorial + code.
The glfwGetFramebufferSize
function should be used instead of glfwGetWindowSize
.
See: https://vulkan-tutorial.com/Drawing_a_triangle/Swap_chain_recreation#comment-3943716852
The code snippets on the website are not colored in Firefox Quantum.
Although MoltenVK fixes this in an upcoming release, it appears that there are other platforms that also don't trigger invalid/out-of-date swap chain notifications after resizes. The tutorial should be updated to have an extra check for the window resize event.
#76, #22 are symptoms of a deeper problem -- the tutorial code has no bound on the number of frames the app may run ahead of the driver.
There is no guarantee of backpressure from any of vkQueueSubmit
/vkQueuePresentKHR
/vkAcquireNextImageKHR
- the examples are just getting lucky because most implementations /do/ provide some in one of the WSI calls.
All samples after "re-creation surface" have this bug.
If collapse window - programm terminated with error "failed to create swap chain"
Windows 7x64, VS 2017
The website automatically generate links for any references to vkSomething
functions and VkSomething
structs, but this doesn't work for certain functions that are not included in the Khronos reference, like VkSurfaceKHR
. These should be blacklisted to not have broken links created from them, which confuses users.
Your website claims that only cards that support OpenGL 4.3 or later will be supported by Vulkan. But I recall that the presentations claimed that OpenGL 4.1 hardware would be the minimum.
I feel that one thing that's still missing from the tutorial to make it complete is a chapter on how to implement multisampling in existing code. Given that the reader made it past mipmapping, adding multisampling won't be that difficult and as of today it's basically a minimum feature to have in a renderer/game engine.
What do you think? If it sounds interesting (and nobody else is working on it to your knowledge) I'd be happy to contribute.
I've done the tutorial until "hello_triangle.cpp" and I've found that the process memory slowly grows and seems like there's no drop-down period. Could you please check it out? I'm not sure if somebody out there face the issue like me.
The swap_chain_creation.cpp as well as my own implementation following your tutorial up to this point reliably freezes my machine if I interact in any way with the window (moving, resizing, closing etc.). Additionally I get a "validation layer: vkDeviceWaitIdle: returned VK_ERROR_DEVICE_LOST, indicating that the logical device has been lost" error when terminating the application.
Note that SashaWillems basic triangle example works fine.
Hello @Overv,
Thanks for the great tutorial.
I noticed a point that could be improved.
In @SaschaWillems examples, the staging image is a staging buffer, I then asked the question on ##vulkan (irc) and @baldurk (creator of renderdoc) answered to me:
staging VkBuffers are the way to go. You can use your own packing/padding layout (so you can memcpy directly from a file for example) as you don't have to respect the implementation's image layout, and most image formats won't allow you to create a linear image anyway
His explanation is very good, it would be great to update the tutorial and to use a staging buffer.
What do you think about that ?
You are loading an image from the CPU.
If you want to use it in the GPU (through a command buffer), the spec says :
For host writes to be seen by subsequent command buffer operations, a pipeline barrier from a source of VK_ACCESS_HOST_WRITE_BIT and VK_PIPELINE_STAGE_HOST_BIT to a destination of the relevant device pipeline stages and access types must be performed. Note that such a barrier is performed implicitly upon each command buffer submission, so an explicit barrier is only rarely needed
As I understand, it performs a kind of a global memory barrier with :
srcStage = VK_PIPELINE_STAGE_HOST_BIT;
srcAccess = VK_ACCESS_HOST_WRITE_BIT;
dstStage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
dstAccess = VK_ACCESS_MEMORY_READ_BIT;
Since this memory barrier is performed implicity, you do not need the barrier to use the image inside a commandBuffer.
However, you still need to transition your image from the LAYOUT_PREINITIALIZED to the LAYOUT_TRANSFER_SRC.
Since the execution barrier was done as we saw above, we do not need an another, but we still need an image memory barrier to transition the image. I will do it like that /
oldLayout = PREINITIALIZED;
newLayout = TRANSFER_SRC;
srcStage = TOP_OF_PIPE; // Since it could be
srcAccess = 0;
dstStage = TRANSFER;
dstAccess = VK_ACCESS_TRANSFER_READ_BIT; // Since you can use this "cache" before, it is better to make memory visible IMHO
Put srcAccess
to 0 will lead to validation layer warning. I post an issu here
For the image with memory that resides on GPU side (you called it textureImage I think), you can do:
oldLayout = UNDEFINED; // obvious
newLayout = TRANSFER_DST;
srcStage = TOP_OF_PIPE;
srcAccess = 0;
dstStage = TRANSFER;
dstAccess = 0; // TRANSFER_WRITE is not useful IMHO since you do not need memory visibility
After, you can make the copy !
After the copy is done, you must transition the textureImage's layout to SHADER_READ_ONLY_OPTIMAL;
When the transfer is done? After TRANSFER stage
Before which stage it must be done? Before the FRAGMENT_SHADER (if you use it only in the fragment shader), but I'd go for ALL_GRAPHICS or ALL_COMMANDS (to use it in the computeShader).
So the barrier should be something like that :
oldLayout = TRANSFER_DST;
newLayout = SHADER_READ_ONLY;
srcStage = TRANSFER;
srcAccess = TRANSFER_WRITE; // Make the memory available
dstStage = ALL_COMMANDS; FRAGMENT_SHADER; // It is up to you;
dstAccess = SHADER_READ; // Make the memory visible for shader reads !
It is where I think you must correct it.
IMHO you must as well use barrier when you use buffers ! But in my opinion you just need one and only one barrier for buffers (to make the memory visible after the transfer :))
IMHO, TOP_OF_PIPE for barrier is not a good idea.
I tryed to make that clear on my website.
I hope I did not forget anything.
@vazgriz Could you add an explanation for why createImage
in createTextureImage
changes from:
createImage(texWidth, texHeight, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage, textureImageMemory);
to:
createImage(texWidth, texHeight, mipLevels, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage, textureImageMemory);
The chapter currently doesn't explicitly mention why the extra flags are added. It should mention that they are needed for the generateMipmaps
operations.
There is a problem on your website https://vulkan-tutorial.com/ where some pages have problem with resource loading and fails to present properly. The following errors are caused by:
<!-- hightlight.js -->
<script src="//vulkan-tutorial.com/Uniform_buffers/themes/daux/js/highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
The script fails to load and the function call prevents the pages to load as expected.
Could u prefix the files in code with index numbers so they are ordered. Thanks.
vulkan, glfw and glm installed from a package:
$ g++ -DNDEBUG -lvulkan -lglfw -std=c++11 hello_triangle.cpp
hello_triangle.cpp: In member function ‘bool HelloTriangleApplication::checkValidationLayerSupport()’:
hello_triangle.cpp:823:64: error: ‘strcmp’ was not declared in this scope
if (strcmp(layerName, layerProperties.layerName) == 0) {
^
adding #include <string.h>
does compile it.
This is on ArchLinux, gcc-6.1.1, vulkan-headers-1.0.21, vulkan-intel 12.0.1 (mesa), glfw-x11 3.2-4, glm 0.9.7.5-1
VulkanTutorial/code/15_hello_triangle.cpp
Line 647 in 343c0a0
Should be wrapped in an if(enableValidationLayers)
check, as the memory leak is only present when validation layers are enabled.
(Also affects other examples after this one)
In the "Images" chapter of the Texture Mapping section, the createImage
function creates an image with an initial layout of VK_IMAGE_LAYOUT_PREINITIALIZED
. The reason given for this is so that the contents of the image are preserved by the first transition. However, data is not placed into the image before the first transition in any part of the tutorial. I think this was left over from when the tutorial used a staging image to transfer the texture, but since it uses a staging buffer now, VK_IMAGE_LAYOUT_PREINITIALIZED
is not necessary.
For reference, section 11.4 of the spec says
VK_IMAGE_LAYOUT_PREINITIALIZED does not support device access.
...
Currently, VK_IMAGE_LAYOUT_PREINITIALIZED is only useful with VK_IMAGE_TILING_LINEAR images because there is not a standard layout defined for VK_IMAGE_TILING_OPTIMAL images.
VK_IMAGE_TILING_LINEAR
is also never used.
Your tutorial is fantastic and well written. I'm actually using it to learn Vulkan with Java, translating everything as I go. The Java game development / LWJGL community could use a tutorial like yours, but rather than making yet another tutorial, when so much of the content is the same, I was hoping you might be willing to accept contributions to your tutorial to expand it to cover Java.
As a proof of concept, I forked your tutorial and started incorporating Java elements into it to see how it would turn out. I've got the code ported so far to the swap chain chapter, and I've edited 00 and 01 of the text.
master...tthelin:master
Are you interested in the idea? If so I'd keep going, clean things up, and send over pull requests as I make progress. I'm open to how you'd like the content done.
Hi, please consider rewriting the tutorial using plain C (optionally with the use of C++ RAII) to keep the focus of the learner on Vulkan and away from C++ issues.
For example this code fragment from the Base Code chapter is not exception safe...
void run() {
initVulkan();
mainLoop();
cleanup();
}
The call to cleanup() will be skipped if initVulkan() or mainLoop() throws an exception.
Exceptions are a C++ specific thing. It is just a distraction while learning Vulkan.
The table in Section 6.1.3, specifies what pipeline stage each access mask can be accessed in. For example, when dstAccessMask
is VK_ACCESS_TRANSFER_WRITE_BIT
, dstStageMask
must be VK_PIPELINE_STAGE_TRANSFER_BIT
. The current function always uses VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
for the source and dest stage.
The easiest way to correct this would be choosing the source and dest stages alongside the access masks
VkPipelineStageFlags source;
VkPipelineStageFlags dest;
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
source = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dest = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
...
vkCmdPipelineBarrier(
commandBuffer,
source, dest,
0,
0, nullptr,
0, nullptr,
1, &barrier
);
I have a freescale i.MX6 dev board, the OS of it is linux, and the dev board has a LCD(7 inch).
On https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers, the link for vkCreateDebugReportCallbackEXT to the Khronos documentation results in a 404.
It tries to point to https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkCreateDebugReportCallbackEXT.html
I dont see any *EXT documentation in the file listing there, and correspondingly, it seems that all *EXT links are broken.
In the chapter "Vertex input description" you declared the vertex attribute as
layout(location = 0) in vec2 inPosition;
so to use it, you had to cast it to vec4, like this
gl_Position = vec4(inPosition, 0.0, 1.0);
Later in the chapter "Depth buffering" you had to change this to
layout(location = 0) in vec3 inPosition;
...
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0);
All this does not make sense.
Vulkan specification says
If the format does not include G, B, or A components, then those are filled with (0,0,1) as needed (using either 1.0f or integer 1 based on the format) for attributes that are not 64-bit data types. The number of components in the vertex shader input variable need not exactly match the number of components in the format. If the vertex shader has fewer components, the extra components are discarded.
Therefore, if you declare a vertex attribute, like this
layout(location = 0) in vec4 inPosition;
you do not need to cast it to vec4, whatever the format.
So this cast here just adds an extra operation. And forces us to recompile the shader when changing the format of the vertices.
While it is good practice to abstract away memory management like this, the VDeleter template class is a completely distinct concept from Vulkan. This tutorial series would be much easier to follow if memory management was explicitly done, not abstracted away.
The code exists to be read, and understood, not elegant and functional. This is a case where elegance hides the functionality.
The reader is here to learn about the Vulkan API, and nothing else.
By encapsulating the memory management, the reader has an unnecessary knowledge dependency. He or she must drop everything, and learn how this new template class works and will be used in the future before they can do what they came for: learn Vulkan.
To make matters worse, if the reader wants to use their own abstraction for memory management, they still have to figure out what VDeleter is doing in every subsequent tutorial.
Don't abstract away any memory management.
Yes.
It is also good teaching.
No.
More code does not equate to more confusing code.
Vulkan is inherently verbose. The reader is expecting to write a lot of code.
Almost definitely.
Make a separate tutorial about it! That would be a helpful resource to anyone who hasn't already done something similar. Like I said before,
The reader is here to learn about the Vulkan API.
Common abstractions for handling memory are great to know, but they aren't Vulkan.
At the last paragraph:
Now run your program and you'll see that all of the hard work has finally paid off! We are already getting quite close to seeing the that triangle pop up on the screen. In the next couple of chapters we'll set up the actual framebuffers from the swap chain images and prepare the drawing commands.
Would have opened a PR but I was not sure which variant you meant/prefer.
Also, I find that this paragraph is a little misleading, I thought I should have seen something on my screen, and this comment thought too.
You should make more clear that we're not done yet ;)
I just noticed that the shader files are missing.
The recreateSwapChain
function needs to handle a window with a zero size properly. Proposed code:
void recreateSwapChain() {
int width = 0, height = 0;
while (width == 0 || height == 0) {
glfwGetWindowSize(window, &width, &height);
glfwWaitEvents();
}
...
}
There's also a possible issue with fences:
https://vulkan-tutorial.com/Drawing_a_triangle/Swap_chain_recreation#comment-3943645739
In Setup of Rendering And Presentation
void mainLoop() {
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
drawFrame();
}
glfwDestroyWindow(window);
}
Should not include glfwDestroyWindow. glfwDestroyWindow is part of cleanup in the tutorial and code examples.
Hey,
Great tutorial! but i just wanted to check
Im not getting this error which im presuming is incorrect? ive put my version on gist here: https://gist.github.com/johnfg10/41d31da51db2a6c7f2aca0f7c10ac7ea
thanks in advance,
John
The code listing in the pdf version of the tutorial, the code goes out of the page. For example, in pages 32 and 33.
There should probably be more checking around this.
As described here: https://vulkan-tutorial.com/Generating_Mipmaps#comment-3942171741
You are making a subpass dependency between "before the renderpass" and the subpass 0.
As you wrote your dependency, it can be understandable like "I am waiting for the presentation finish to read".
However, presentation engine is asynchronous and synchronisation for it should be done via Semaphore. Moreover semaphores make memory available and visible :
This semaphore signal operation defines the first half of a memory dependency, guaranteeing that all memory accesses defined by the submitted queue operations in the batch are made available, and that those queue operations have completed execution.
A semaphore wait operation defines the second half of a memory dependency for the semaphores being waited on. This half of the memory dependency guarantees that the first half has completed execution, and also guarantees that all available memory accesses are made visible to the queue operations in the batch.
The semaphore we are talking about is the semaphore that you use inside the vkAcquireNextImageKHR
.
The presentation engine may not have finished reading from the image at the
time it is acquired, so the application must use semaphore and/or fence to ensure that the image layout and contents
are not modified until the presentation engine reads have completed.
So, to me you do not need to use a dependency since the layout transition is performed by the renderpass itself, and the memory dependencies / execution dependencies are performed by the semaphore.
There are dozens of cpp file under the code directory.
I might have missed something, but I can't find any support for building them into executables.
I've seen the Development Environment chapter, but I think this is missing actual ready to go build scripts.
I've been using the pdf version of this guide, Getting to the rotating rectangle example shows several fatal mistakes in the pdf that are not present in the html guide;
ubo.model = glm::rotate(glm::mat4(), time * glm::radians(90.0f) ...
you need to specify that matf(1.0f), ... otherwise you see nothing.
There's also no VDeleter, what's up with that?
Your hello triangle builds fine, the window opens but doesn't get filled with black and I get this error.
validation layer: SPIR-V module not valid: Invalid SPIR-V magic number.
I've tried google, but found nothing. I'll keep looking.
Antergos Linux 4.7.0-1-ARCH
glinfo :
GL_VERSION: 4.5.0 NVIDIA 367.35
GL_RENDERER: GeForce GTX 970/PCIe/SSE2
GL_VENDOR: NVIDIA Corporation
First of all, thank you for great vulkan tutorial!
Secondary, develop
branch of TinyObjLoader is now merged into master
, thus please update the information of TinyObjLoader in Loading models section(https://vulkan-tutorial.com/Loading_models) to point to the master
branch.
In the tutorial noted, we create the instance and store the result in one line of code:
VkResult result = vkCreateInstance(&createInfo, nullptr, &instance);
And then immediately ignore the result (apparently this is the new preferred method?) and create the instance again:
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
I assume that either the first part should no longer exist, or the second part should revert to if (result != VK_SUCCESS) {
The second GDC talk, "More on Vulkan and SPIR-V: The Future of High-Performance Graphics", has been posted to YouTube on the khronosgroup channel.
Tutorial should probably have an explicit check.
See: https://vulkan-tutorial.com/Drawing_a_triangle/Swap_chain_recreation#comment-3943926258
In figuring out how to statically generate the tutorial, I came across several performance issues where the static files are still trying to reach out to the internet, but with a bad assumption that "//" as a URL prefix would always work (it doesn't when protocol is file:) It takes about ~10s for Chrome to give up on trying to resolve the bad URL for each one of these.
The discuss thread is one of them (loading google analytics and the special font are the others, but you can turn those off via config files).
The disqus thread is part of the patch into the daux theme so it's not so simple.
If we put in "local file detection" as part of the disqus loading code we fix the problem as it'll only load when served from a web server
If you want me to make a formal pull request I can, but basically this is the change to fix the issue (it needs to be incorporated into daux.patch though)
diff --git a/templates/content.php b/templates/content.php
index 82e79cd..03017b7 100644
--- a/templates/content.php
+++ b/templates/content.php
@@ -26,6 +26,7 @@
<div id="disqus_thread"></div>
<script>
+ if (document.location.host) {
var disqus_config = function() {
var path = location.pathname;
if (path == '/') path = '/Introduction';
@@ -38,6 +39,7 @@
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
+ }
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
</article>
As I'm following the tutorial (part 3 creating the VDeleter 00_Setup/00_Base_code) and I noticed the assignment operator isn't checking for self assignment.
Is this the intention or not, or am I missing something?
The link on VulkanTutorial/00_Introduction.md
in the second to last paragraph of the About section is broken.
I think it would be worth while putting CMake in place of Make for this section. If your version of CMake isn't too old (at least 3.7) CMake already comes with a module FindVulkan.cmake. Creating a CMake project can then look pretty simple.
cmake_minimum_required(VERSION 3.7)
project(vulkan_tut)
set(CMAKE_CXX_STANDARD 14)
set(SOURCE_FILES main.cpp)
add_executable(vulkan_tut ${SOURCE_FILES})
find_package(PkgConfig REQUIRED)
pkg_search_module(GLFW REQUIRED glfw3)
include_directories(${GLFW_INCLUDE_DIRS})
find_package(Vulkan REQUIRED)
find_package(glm REQUIRED)
target_link_libraries(vulkan_tut ${GLFW_LIBRARIES} ${Vulkan_LIBRARIES})
If you're for some reason stuck with an old version of CMake, glfw3 actually comes with its own FindVulkan.cmake.
I'm getting this error:
$ g++ -DNDEBUG -lvulkan -lglfw -std=c++11 descriptor_layout.cpp
$ ./a.out
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted (core dumped)
seems code uses push_back of on-stack variables
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.