Advertisement Jump to content
  • Advertisement

Cararasu

Member
  • Content Count

    13
  • Joined

  • Last visited

Community Reputation

165 Neutral

About Cararasu

  • Rank
    Member

Personal Information

  • Role
    Programmer
  • Interests
    DevOps
    Education
    Programming

Social

  • Github
    Cararasu
  1. Hi! Yes, this happens because the normals are facing outwards. And when rendering the graphics card does not distinguish in what way the triangle faces, if you do not use culling. In the fragment shader, you could access the built-in variable gl_FrontFacing and flip the normal if you are rendering a back-face. I'm not quite sure why you would want to do that because you can not see the inside facing triangles. What typically happens is that inwards facing triangles are not rendered at all. If you enable back-face culling every triangle that presents its back-face is not rendered. You are probably familiar with the effect that if the camera enters an object you can look through. That is backface culling in action. This is done to save GPU time as only the winding order of the triangle needs to be calculated and then it is discarded before rasterization happens.
  2. Are you sure about that? I just tried it with GCC 7.3.0 and Clang 6.0.0 and both compiled a test program without complaints. MSVC in comparison reports an error.
  3. The problem is most likely that you are allocating more memory on the stack than the stack has space. On what operating system are you executing the program and what compiler do you use? On Windows with MSVC you should have by default 1MB of stack-memory. With GCC you should have at least 1MB. You are allocating 128*(128*12 + 128*16?) bytes -> ~460KB, if I am correct about the size of the TPlane<float>. This should in theory fit but by the fact that your program crashes it seems like you are going over the limit. To fix it you can make the stack bigger. This is possible with compiler options but I would not recommend it. It's better to just use dynamic allocation via new. The overhead caused by memory allocation is being easily exceeded by any operation you perform over all that data and you do not risk crashes because of using too much stack-memory.
  4. First of all, do you have the validation layer enabled? It helps a lot when debugging Vulkan errors. I let it run on my system and a few things came up: You forgot to set the type of the VkShaderModuleCreateInfo: shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; And you are not setting the subpass-index in the VkGraphicsPipelineCreateInfo so it defaults to 0, which is probably what you want but you should set it explicitly just to be sure. graphicsPipelineCreateInfo[0].subpass = ??; Additionally, you are not setting the pDepthStencilState. You should definitely set this if you are actually using a depth/stencil attachment in the subpass. Without any information on how the RenderPass was created, it's hard to tell if that is the main problem.
  5. Cararasu

    Moving On From the "Vulkan Tutorial"

    Hi! I do not know of a more in depth vulkan tutorial but here: https://github.com/SaschaWillems/Vulkan is a pretty nice collection of implemented rendering techniques in Vulkan. I will address the UBO issue and a bit on how you might want to use them. There quite a lot of possibilities for how you can update and use data on the GPU and the whole process is not quite trivial. Push-constants are a good idea for when you have a small amount of data that you need to pass. You need to update them when recording the command buffer. They are meant for frequently changing data during the whole rendering process. The disadvantage is that the data has to be defined at recording time. That means if you change the data you have to rerecord the command buffer. UBO updates via vkCmdUpdateBuffer. This is similar to push-constants as data is saved in the command buffer and cannot change between different submissions. Also in the specs, it states that you should not update a large amount of data this way because the data is saved in the command buffer. The problem with this approach is you can not call vkCmdUpdateBuffer inside of a renderpass so using it to update per-mesh data is not possible. UBO updates via staging buffer. This is the most complicated one because you need to manage the staging buffers yourself. Basically, you write into a mapped buffer and then as part of the rendering command you can transfer the data from the staging buffer to the UBO. Mapping UBO buffers directly is typically not possible or recommended for dedicated GPUs. So how do you update pass the data to the actual shader? There are 3 ways I can think of the top of my head: Update the push-constants between draw calls Bind a different descriptor set between calls Pass the data via a vertexbuffer as per-instance data and not per-vertex data So how do you pass per-mesh data specifically? Again there are a number of ways Pass everything with push-constants Pass everything via per-index vertexbuffer Pass everything via UBOs Use an index from the push-constants to access the UBO Use an index from the per-index data to access the UBO ... You can also pass the data using SSBOs or Textures and use some way of passing an index. The choice is yours😉 In a simple tutorial that might be the case but VkRenderPass objects can be used with multiple Shaders. What you might mean is the VkPipeline object which refers to a specific set of shaders. Here https://gpuopen.com/understanding-vulkan-objects/ the author goes over the important Vulkan objects and describes them. The clearing of attachment is not needed for every renderpass. The depth buffer should probably only be cleared once per frame. The color attachment you probably don't need to clear if you decide to completely overwrite the texture in the renderpass. It completely depends on what you are doing and trying to achieve. Tbh I don't really know why this option exists at every renderpass, because you can do it explicitly in the command buffer as well. Anyway, this is basically the same as glClearColor. just implicitly at the start of the renderpass and yes you can disable it with VK_ATTACHMENT_LOAD_OP_DONT_CARE or VK_ATTACHMENT_LOAD_OP_LOAD depending on your needs when you create the renderpass.
  6. Cararasu

    Texture mapping acts weird on some images.

    Well if you use 4 channels then the size of one row is always divisible by 4 so there can be no issue because of weird line-sizes. An issue might appear if the data pointer returned by "stbi_load" is not divisible by 4. I do not know if stb guarantees a certain alignment, but I would be very surprised if you ever get a pointer that is not at least divisible by 4. So yeah you should be safe when always using 4 channels. Additionally, I think most hardware does not store RGB images tightly. They will leave space for a fourth value because of (surprise surprise) 4-byte alignment. That means you do not lose anything in terms of GPU-memory when using RGBA over RBG. I am not 100% certain about this, so if there is anyone who has more in-depth knowledge feel free to enlighten me😉
  7. Cararasu

    Texture mapping acts weird on some images.

    No that's not OpenGL ES. I just looked it up and it seems that the 4-byte alignment rule also affects normal OpenGL even though it is not mentioned directly in the description of glTexImage2D. The problem seems to be a common one. They even put it inside the common mistakes section of the OpenGL-wiki: https://www.khronos.org/opengl/wiki/Common_Mistakes#Texture_upload_and_pixel_reads To fix the issue either make sure that the alignment of each row is always 4 bytes. or call glPixelStorei(GL_UNPACK_ALIGNMENT, 1) before glTexImage2D. The problem with changing the alignment rules is that uploading the texture can be slower than if the alignment is not 4-bytes.
  8. Cararasu

    Texture mapping acts weird on some images.

    Are you by any chance using OpenGL ES? In that case, take a look at the documentation of glTexImage2D. Especially the sentence That means after every row the pointer is rounded up to be divisible by 4. The images from the explosion are exactly 480 pixels wide. Every pixel has 3 color values, which means 480*3 = 1440 bytes, which is divisible by 4. So no adjustment. The image of the arrows is 115 pixels wide. This makes 115*3 = 345 bytes per line. OpenGL will then pad it by 3 bytes effectively skipping 1 pixel. So the second line will look 1 pixel shifted. The third line will look 2 pixels shifted. I have already mentioned it but I think you have missed it. If you look at the rendered image you will see 93 pixels missing from the last line, which is the height of the image. If you load an image with 4 components the size of each line is trivially divisible by 4 which means no adjustments. Curiously enough this alignment of rows seems to be only part of the OpenGL ES standard and not the normal OpenGL.
  9. Cararasu

    Texture mapping acts weird on some images.

    It looks to me that you are not filling the whole memory of the image on the GPU. If you look closely at the rendered image you will notice at the last pixel-line that some pixels are missing. The amount seems to be about the same as the height of your image, which would mean the width is one pixel too wide. Your image loading code seems alright on first glance so that is strange. I do not think that the problem is that you are loading an RGBA image and treating it as RGB. This would create a different effect as the image is fully opaque. In this case, every pixel in the black area would be I think either red, green or blue.
  10. Hello Everyone! A few days ago I had a very interesting problem in one of my projects and I want to share the weirdness that happened. A little bit of background: I am writing a renderer in Vulkan, which runs on both Windows and Linux. Most of the time I develope on Windows on my desktop PC but sometimes when I am away I switch to my Laptop with Ubuntu 18.04 LTS. Last week I turned on my Laptop and started programming. Everything was fine the program ran well and no error was shown. Not even from the Vulkan validation layer. When I exited the program suddenly my OS froze. No response at all. No keystroke/key-combination was recognized, the mouse did not move, nothing. The only thing that worked was pressing the good old power-button and killing the system. When rebooting everything worked fine again. So I continued programming. I changed a few things and restarted my program. After ~3 times the same freeze happened again. This pattern repeated a few times. Sometimes it worked sometimes my system would freeze on closing the window. It was quite strange, as this should not really happen. So I went looking for a solution. My first thought was looking into log files to maybe track down the problem. /var/log/syslog would stop writing the moment the system freezes. There are a bunch of null bytes in the file but that seems to be normal in case of a crash. kernel.log and Xorg.0.log are the same. No entry the moment the system freezes. My next thought was maybe the driver is at fault. I had a Nvidia GTX 950M with the nvidia-410 driver. I kicked out the driver and installed the version 396. Reboot and my program still freezes everything on exit. Same with driver version 415. At this point, I tried nailing down where the freeze happened by enabling all logging messages in my program. To make it faster I also switched from debug-build to release build. I ran my program and it exited fine. I tried a bunch of times and there was no crash, no error, and no freezing. That was strange so I switched back to my debug-build and it froze the system. One reboot later I just rebuild the whole program instead of doing an incremental build and since then I had no freezes at all. WTF? How? So that was 3 hours of debugging that confused the hell out of me. Even if one of the object files was broken in some way it should not lock up the whole OS that way. I have no idea what the problem was and my complete rebuild deleted all object files so I can not recreate the behavior. So yeah, that was one of the 2 ways I brought down my OS with this project, which I wanted to share.😉
  11. You can load the Library manually with the LoadLibraryA/LoadLibraryW function. With the handle of the loaded library, you can get a pointer to your function with GetProcAddress. All three are located in Kernel32.dll. More information you can find in the Windows-documentation: https://docs.microsoft.com/de-at/windows/desktop/Dlls/using-run-time-dynamic-linking The difference between the LoadLibraryA and LoadLibraryW function is how the library-filename is encoded. The A-version takes regular ASCII characters and the W-version takes wchar_t which is a 2-byte character.
  12. As far as I can tell Raspberries all support OpenGL ES 2.0. I do not think there are drivers that natively support OpenGL 3.0 for their graphics chips themselves. But in case you want the functionality without worrying about performance you can always get Mesa-library which falls back to software rendering in case features are is not supported. https://www.mesa3d.org/
  13. Cararasu

    Int vs. Float Graphics Programming

    Incidentally I thought about the same question for the last few days. The following answer is what I came up with: While it is true that there are only 3 integer values between -1 and 1 it is still possible to get a much higher resolution. Just think of UNORM and SNORM. UNORM means integers are normalized values in the range [0,1] and SNORM in the range [-1, 1]. e.g.: Using this you can subdivide the range into 2^32 parts with a 32-bit integer and not just 3. The big problem is that with this you can not represent values outside of the range. Therefore representing positions with U/SNORM integers does not make much sense. As you are restricted to a very narrow range. Another more sensible way would be to split one distance unit into smaller ones. For example, you can split one meter into 1 million parts. That will create a very fine-grained grid of possible positions. Snapping to the grid will not really be noticeable. With 32-bit numbers, you get a very big grid(40km x 40km) and with 64-bit integers it is quite enormous(10^10km x 10^10km). At first glance that sounds fine. The problems with integers are that you want it to be fine-grained, but you still want to be able to calculate with them. The bigger the numbers the bigger the problems. Take floating-point numbers as an example: Adding a very low number to a very large number may lead to no change at all to the large number. Nonetheless, floating-point numbers work well if you are careful. While floating-point numbers get inaccurate if there is a large discrepancy between the 2 numbers, integers freak out completely if you multiply 2 large numbers. Let's explain with a little example: With the previously defined grid let us calculate the distance between 2 points. The difference vector is (1*10^6, 2*10^6, 0) which corresponds to (1 meter, 2 meters, 0 meters). We now have to calculate the square root of 10^6^2 + 2*10^6^2 + 0. This results in the square root of 3*10^12. 10^12 is approximately 2^40 which cannot be represented in a 32-bit number and therefore gets cut of after 32-bits and the resulting square root gets some completely unpredictable value. This effectively limits us to 16-bit values which are not very accurate. If there is ever the need to multiply 3 numbers of that scale then we already need 60-bits to represent it which already nearly overflows in a 64-bit integer and our points are just a few meters apart nearly at the center of the world. With bigger numbers the problem gets only worse. A 1km distance means a squared value of approximately 2^60. 10km means 2^66. Switching to 64-bit values helps a bit but that only gives us safe values up to 32-bit. Another possibility is to cast up to 128-bit numbers for each calculation and cast back down to 64-bit at the end. This could work but 64-bit multiplication is already not easy(is there a 64-bit multiplication instruction on x86-64? I have not found any. Not even in the SSE instructions) and 128-bit calculations are even more complicated. Especially on 32-bit systems. 128-bit multiplication is probably still faster than a double precision floating point multiplication, but for every multiplication we might overflow our value which might spell disaster. TLDR: I would say the problems in floating point calculations is the lack of precision which is not so bad. Problems in integer calculations are completely wrong results because of overflows which is very bad.
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!