Optimizing Pseudo 3D Rendering // Code Review

Поделиться
HTML-код
  • Опубликовано: 27 ноя 2024

Комментарии • 134

  • @TheCherno
    @TheCherno  28 дней назад +19

    Thanks for watching! Did you follow along with the exercise and try and find issues yourself? What did you find? 👇
    Also don't forget you can try everything Brilliant has to offer-free-for a full 30 days, visit brilliant.org/TheCherno . You’ll also get 20% off an annual premium subscription.

  • @vlauderlauders741
    @vlauderlauders741 28 дней назад +475

    I sign the petition to see this game running on GPU

  • @marco_martin
    @marco_martin 28 дней назад +158

    I would ABSOLUTELY like it if you could run that code on the GPU

  • @DesyncX
    @DesyncX 28 дней назад +94

    Yes please, make this run on the gpu; maybe even increase the resolution to full screen and compare the results.

  • @xxdeadmonkxx
    @xxdeadmonkxx 28 дней назад +43

    Recommended settings for that game:
    CPU: Intel Core i3 8100
    GPU: Yes

  • @ABaumstumpf
    @ABaumstumpf 28 дней назад +72

    Some of your assumptions are completely wrong - like with the sin/cos values:
    Recalculating those values would be significantly slower but the compiler can see that they are identical and will not redo the work all the time. On the other hand explicitly storing those intermediate values has no chance of being a cold memory read as they would only be used right after getting calculated.
    With the memory access in different parts of the array: Nah, that really isn't a problem. Going backwards for the sky is likely far worse - but without an actual isolated benchmark there is no way of saying what is going on.
    And what really is slow is setting every single pixel with the SDL_RenderDrawPoint - this is extremely slow. The Function is doing renderer-setups, checks, allocations and a lot more for every single pixel. Use your own pixel-buffer and then send in the whole thing at once will be much much faster.

    • @xeridea
      @xeridea 28 дней назад +1

      If they were locally cached the values would not be cold. I was thinking it would be cached once before rendering then fetching each frame. They may end up being prefetched though, so would still be in cache.
      Can CPUs detect reverse loop offsets and prefetch?
      I was thinking the same thing about drawing pixels. There is going to be a massive overhead individually drawing pixels. I am surprised he didn't mention that. Perhaps I will compare.

    • @ABaumstumpf
      @ABaumstumpf 28 дней назад +2

      @@xeridea "Can CPUs detect reverse loop offsets and prefetch?"
      Can? pretty sure - yes. But as there are other things going on it is still better to avoid that.
      I have seen instances where the branch-predictor managed to get better than chance performance on data that was basically random, and memory-prefetch for lists.

    • @streamdx
      @streamdx 28 дней назад +3

      Yep! Cherno missed the elephant in the room this time! )

    • @jlewwis1995
      @jlewwis1995 28 дней назад +2

      If the values are stored on the stack they would basically never be in cold memory right? Because the CPU is accessing the stack all the time when you call functions, push function arguments to the stack, write to a stack allocated buffer, etc. So the area of memory that contains the stack would be in the CPU cache most of the time wouldn't it since it's being used constantly?

    • @bobjones304
      @bobjones304 28 дней назад +2

      Doesn't the complier just inline them?

  • @stendaneel4879
    @stendaneel4879 28 дней назад +45

    9:34 Make the raytracing series run in a shader, it would be really cool to see how you would implement it. Maybe another cool video idea would be compute shaders with vulkan, or a vulkan series in general, kind of like the opengl series.

    • @mertcanzafer5446
      @mertcanzafer5446 28 дней назад +3

      +1

    • @emomaxd2462
      @emomaxd2462 28 дней назад +4

      or maybe running ray tracing with CUDA that gives a lot more low-level control

    • @pyropoops139
      @pyropoops139 24 дня назад

      @@emomaxd2462opencl would probably be a better bet no? but i think an opengl shader would be the best bet as it is the closest to practical application in game engines

  • @Jellow2202
    @Jellow2202 28 дней назад +24

    lerp is available in the standard library since C++20 as std::lerp in

  • @oskardeeream1846
    @oskardeeream1846 28 дней назад +21

    You should do a collaboration video with one lone coder :D that would be awesome.

  • @RequiDev
    @RequiDev 28 дней назад +3

    15:30 While you're right in most cases, that caching does come with the cost of memory and reading from the memory, in this specific case its just a constant that not only never changes, it can be computed at compile-time and will very very likely just live directly inside the instruction as an immediate operand. Compilers are very smart.

  • @OlxinosEtenn
    @OlxinosEtenn 28 дней назад +3

    17:40 - 20:20
    It's not *that* bad since it's almost sequential.
    Also, 19:25 suggests that reading an array in reverse is always bad, which is wrong (it might not be what was meant, but it's very easy to interpret it like that).
    I made a small program to illustrate that but youtube dislikes comments with links and ate it (so I'm reposting my comment without that, I hope I'm not being a bother). The takeaway was that:
    - going through an array sequentially or in reverse (sequentially but backwards) doesn't noticeably change performance
    - reversing the order of rows (like in the video) or columns causes a small performance hit (about +5% time spent on my machine with x=y=10000 and a loop body consisting of a single addition), possibly not noticeable if the loop body does as much work as the one shown in the video
    - iterating over x in the outer loop and y in the inner loop however causes a massive performance hit (about +900% time spent, same context as above), that's the main thing to avoid if possible
    - random accesses is even worse (about +1500% time spent, same context as above)

  • @oliverdowning1543
    @oliverdowning1543 28 дней назад +2

    I did actually do, for a project a few months ago, this exact code as a GLSL fragment shader. It's quite fun as a project.

  • @mohamedyusuf4777
    @mohamedyusuf4777 27 дней назад +1

    I love these code review series. Keep up the good work.

  • @Steven-tw7iz
    @Steven-tw7iz 28 дней назад +5

    I would love to see you convert this loop to use SSE/AVX intrinsics to really start to use the power of modern CPUs, not enough people really know or understand about that stuff

  • @Waffle4569
    @Waffle4569 28 дней назад +6

    6:12 When std::chrono is such a cumbersome namespace that you need to make a wrapper around it.

    • @mjthebest7294
      @mjthebest7294 28 дней назад +2

      just like pretty much the entire standard library

  • @mr.anderson5077
    @mr.anderson5077 28 дней назад +4

    Please teach multi threading on such scenarios and offloading stuff on the multiple cpu cores

  • @juanmacias5922
    @juanmacias5922 28 дней назад

    This was really cool, I hope you continue the code review series. :D

  • @matsv201
    @matsv201 28 дней назад +2

    I would say for caching you would want a mix of function.
    The issue is that a typical modern CPU do about 4 instruction per cycle, but every instruction takes anywhere between about 4 and 15 cycles to do.
    If you feed the result from one instruction that take a lot of cycles to do into a other one, it have to wait for it to catch up.
    The shedular often do a good work of this for short issues, but if you do a loop, that may not be possible.
    So inside the loop you would want a good mix of cach calls, floats and other instruction mix. The more mix you have, the faster it will execute.
    Of cause in this case, if you want it to do it quickly, you would really want to use the SIMD function
    Its also worth saying that the L1 cache is typically fairly small, but its instant. Like typically 32kB of L1 cach. If you do something like a 256 bit simd you really would want to do no more than 100 of them in cache at any one time, preferably quite a bit less.
    I i would speculate that a resonable aproch would be to set up a calculation for a block of simd and run it for 20-30 sets at the time, then rework them, and during the rework set up the next block, allowing it to draw form memory while its calculating the old work

  • @TheMaginor
    @TheMaginor 28 дней назад +4

    You would probably speed up a lot using SSE on the inner x loop too (can be combined with threading). The compiler may not be able to do that on its own since it can't know if the rows are aligned or have lengths that are multiples of 4. The texture lookups could not be vectorized, but the math could. Could probably even vectorize the rgba unpacking (it is just bit shifting).

  • @someidiot6359
    @someidiot6359 28 дней назад +3

    Do you think you could make a video explaining the cache and how to optimize for it?

  • @user-sl6gn1ss8p
    @user-sl6gn1ss8p 28 дней назад +4

    Makes entire screen white
    "Well, yes, looks much better"

  • @mspeir
    @mspeir 28 дней назад +1

    Heck yeah! I'd love to see that rewritten on a GPU. In fact, I was thinking of how to rewrite it as a shader as you were going through it.

  • @SuperCamelFunTime
    @SuperCamelFunTime 28 дней назад +1

    Please do make a video on leveraging the GPU as much as possible. It would be great if you can go into particle emitter calculations on GPU as well.

  • @arcoute9108
    @arcoute9108 28 дней назад +1

    Mode 7 rendering is cool and was first implemented with hardware in the SNES

  • @ciCCapROSTi
    @ciCCapROSTi 27 дней назад

    +1 for the GPU video, especially if you can make it simple in your usual style. I last used a GPU when OpenGL was still properly pipelining, no shaders, so that's like 2 decades out of date knowledge.

  • @mjthebest7294
    @mjthebest7294 28 дней назад +14

    Raytracing series comeback when?

  • @mr.anderson5077
    @mr.anderson5077 28 дней назад +1

    Hey @TheCherno
    I request you to please make a tutorial on running the exit screen rendering on GPU.
    I would love to see you deploy this workload on iGPU if your on intel or amd or use dGPU like Nvidia. May be we can dive into some CUDA programming too if needed in future or raw CPP is fine for now.
    Also include this idea to utilise the same with your ray tracing examples.
    Netizens please hit the like button below if you feel the same.

  • @ZackLivestone
    @ZackLivestone 28 дней назад

    I want to see more like this in the future

  • @AlexSmolyankin
    @AlexSmolyankin 27 дней назад

    Really cool video. Now I'm waiting the video about bringing that code to the GPU.

  • @xeridea
    @xeridea 28 дней назад +2

    Caching can be good if only done on code that is looped a lot, and small to keep within the CPU cache, unless if operations are really expensive then larger cache would be fine.
    AFAIK, looping backwards may not necessarily be horrible because prefetchers can detect offsets and fetch accordingly, but forward is still likely better.
    I would say a big slowdown is calling a function to draw each pixel. You could just save everything to a buffer, then do the 1 draw.

  • @lptimey
    @lptimey 28 дней назад +2

    15:50 give that some of these don’t ever change. Wy even cache them if you could precalculate them with your compiler with a const_expr I think

  • @Kazyek
    @Kazyek 27 дней назад

    15:52 The cost of "caching" mainly depend about where you put it and how to retrieve it. A HashMap for example, while being the most awesome data structure ever, involve quite a bit of math to retrieve a value from a given key. In THIS specific case though, since the variable doesn't depend on anything else at the moment, you'd probably simply keep it in the same struct alongside the fWorldA and fFoVHalf that you're already accessing, so it would be in a very similar place in memory, no expensive math to retrieve, and the relative cost of trigonometry function on the sum of two variable in a struct is definitely higher than retrieving a single variable in that same struct.

  • @anon_y_mousse
    @anon_y_mousse 20 дней назад

    One tiny hint, if you have to specially handle an iteration because of an initial zero value, it's better to have that code before the loop and then start the loop at one. It'd be nice if the compiler would always recognize what's happening and do that for you, but it's also significantly more clear if you do it yourself.

  • @christianlett
    @christianlett 28 дней назад +1

    From what I could see in the video (I've not got the source code so can't be sure), the values pre-trig functions could all be constexpr. In C++26, the trig functions will also be constexpr. But the first thing I saw was the sin and cos calculations were each repeated 4 times, so I'd start there. Good observations re memory caching and memory access in the inner loop.

  • @SueDoeNym-b4d
    @SueDoeNym-b4d 19 дней назад

    19:39 The CPU fetches memory as fixed lines. It basically divides the whole address range into fixed lines of (usually) 64 bytes. When a particular address is accessed, its whole line will be fetched, some of which could be behind it.
    Suddenly looping backwards may result in some waste, as a line may have been loaded going forward that doesn't get fully utilised, but the difference would be imperceptible.

  • @Xoduz85
    @Xoduz85 27 дней назад

    Yes yes yes, please make a video on how to take this code and transform it into a GPU version :D
    Keep on making these awesome videos, they're great!!

  • @empireempire3545
    @empireempire3545 28 дней назад +1

    9:40 DO IT, There is always need for GPU coding tutorials!

  • @MWPSBCID
    @MWPSBCID 28 дней назад +3

    I would like to see you do this on the GPU

  • @bronkolie
    @bronkolie 24 дня назад

    creating this exact look in GPU would be really interesting

  • @zeusdeux
    @zeusdeux 28 дней назад +3

    Just here upvoting all “let’s get this on the GPU” comments

  • @anonanon6596
    @anonanon6596 28 дней назад +4

    I would actually love to see you review a code of javidx9 himself.
    Like his pixel game engine or any other project he has shown in his videos.

  • @theairaccumulator7144
    @theairaccumulator7144 28 дней назад +6

    when i wrote a raytracer in js caching everything made it like 350x faster LMFAO (don't ask why i was writing a raytracer in js)

  • @SoederHouse
    @SoederHouse 27 дней назад

    Now we just need Cherno and olc to collaborate on an light weight engine and the world would be a little more perfect.

  • @an1n-dya
    @an1n-dya 28 дней назад +2

    Could we please have the return of the ray tracing series? 🙏🙏

  • @frankreeser4400
    @frankreeser4400 28 дней назад +1

    Good video! Thanks. Please make the GPU (imported original code) video! :)

  • @FarisEdits
    @FarisEdits 28 дней назад

    I LOVE THIS KIND OF VIDEOS

  • @LoopSkaify
    @LoopSkaify 27 дней назад

    YES I WANT THAT!

  • @Lunastela64
    @Lunastela64 23 дня назад

    I'd love to see a video where you make something like this run on the GPU please :)

  • @MatrixHound_Dungeon
    @MatrixHound_Dungeon 28 дней назад +1

    Yes make a video on how to run this on a GPU. Thanks!

  • @Rob_III
    @Rob_III 27 дней назад

    Although you split ground and sky rendering into two loops, you didn't change the sky accessing memory "backwards"; I think that would've made a big(er) change in performance than just splitting the two into two separate loops.

  • @debsarkar4893
    @debsarkar4893 28 дней назад +2

    9:45 I would absolutely love to see how u take code like this run it on a GPU

  • @awesomeguy11000
    @awesomeguy11000 28 дней назад +1

    I'm surprised you didn't make an rgba32 backbuffer and format the loaded textures as rgba32, then you could avoid all function calling overhead and copy pixels directly from source to destination buffer. SDL uses the GPU behind the scenes so setting up render state and issuing a draw call for each pixel has a much higher overhead than performing all of the work in the CPU and flushing the buffer at the end.

  • @TheJonatanMr
    @TheJonatanMr 28 дней назад +3

    Petition to continue the ray tracing

  • @linavabai8470
    @linavabai8470 28 дней назад +4

    Yes, GPU it, please

  • @denravonska
    @denravonska 28 дней назад

    It would be interesting to see if making all those constants const or locking them to an anonymous namespace will make a difference.

  • @furyzenblade3558
    @furyzenblade3558 28 дней назад +1

    9:37 Yess

  • @ralph_d_youtuber8298
    @ralph_d_youtuber8298 28 дней назад

    I feel like if u still wanted the cosf to be there for easy reading. Then put it in a const scope. So it can just be calculated at compile time. Why cache the compiler can inline the results for u😊.

  • @BadMemoryAccess
    @BadMemoryAccess 28 дней назад

    lmao, last week I wrote a Cacher class which held cached values and the relevant recomputing functions ... granted, my cached computations were actually costly, not just arithmetic operations and trig (there was noticable lag without caching)

  • @whoshotdk
    @whoshotdk 25 дней назад

    I’m more interested in how you’d multi-thread the rendering of this than seeing it run on a GPU, which I think would just be a ton of boilerplate code and a fragment shader that looks very similar to the existing code (I could be wrong!). I guess multi-threading would introduce concepts like synchronicity? I.e how do you avoid tearing effects if different cores are spitting out pixels at different rates? Mostly guessing here, I’m new to C++ myself and am strictly a single-thread guy right now.

  • @gsestream
    @gsestream 28 дней назад

    there is the maf, and there is the code. math is interesting, code is boring maintenance. or just do post processing filtering like FXA. or TAA, or MSAA or just super sampling anti-alias from higher resolution down.

  • @Redeam.
    @Redeam. 24 дня назад

    When new "The Cherno's Adventures in Minecraft"?

  • @Doogle41
    @Doogle41 23 дня назад

    These magic scribbles are well and good but where do I get a cool hoodie like Cherno's?

  • @ringo2715
    @ringo2715 28 дней назад

    Just for clarity, javidx9 has migrated development of console game engine to pixel game engine which does use the GPU.

  • @brendandower9021
    @brendandower9021 27 дней назад

    Yes please.

  • @adamagrest8215
    @adamagrest8215 28 дней назад +1

    Baited my comment :) Please show us running this on GPU

  • @ThunderSphun
    @ThunderSphun 28 дней назад +1

    please convert this code to a shader, i have been waiting for something like this since i finished the raytrace series

  • @GEKKOGAMES_RETRO
    @GEKKOGAMES_RETRO 28 дней назад

    yes me too 🤟🏻

  • @saurabhmehta7681
    @saurabhmehta7681 28 дней назад +1

    Its called Skyward Scammer because you scam Gonzo, the guy running after you, and fly into the sky after taking his money. You're welcome

  • @shawnbucholtz8082
    @shawnbucholtz8082 28 дней назад +1

    13:55 ........ me too.

  • @Diamonddrake
    @Diamonddrake 28 дней назад

    Does this mean looping through an array backwards is a cache miss party?

  • @Jurasebastian
    @Jurasebastian 27 дней назад

    Is following idea good? i have 1MB memory fragment in which i have many memory fragments i want to access many times, my idea is to copy all of those fragments to one smaller buffer that will fit into cpu cache and then do calculations on that memory? it will be probably faster even i add extra allocation at beginning and end assuming i access memory like milion of times

  • @mr.anderson5077
    @mr.anderson5077 28 дней назад +1

    Anybody know what tool does Cherno uses to draw stuff on the screen kindly drop a comment

  • @cacticrown
    @cacticrown 22 дня назад

    do you only review c++ code?

  • @luizgarciaaa
    @luizgarciaaa 28 дней назад

    Pleeeeeaze do it!!!

  • @bobjones304
    @bobjones304 28 дней назад

    If it is the same calculation, why not just inline it?

  • @axjb2428
    @axjb2428 27 дней назад

    I would love to see you to port that code to GPU =)

  • @ralphyreece4687
    @ralphyreece4687 28 дней назад

    My code is a mess of AI for stuff like SDL and structures, a ton of copy and pasting, and hundreds of if statements.

  • @jouniosmala9921
    @jouniosmala9921 28 дней назад +2

    My memories of pseudo 3D was mostly with a system having 8Mhz but some memory of pseudo 3D with 1Mhz CPU. The performance of that thing is horrendous when considering that.

  • @R_eal-G_rude
    @R_eal-G_rude 28 дней назад

    Cool

  • @mirabilis
    @mirabilis 27 дней назад

    Super Mario Kart!

  • @adrien8768
    @adrien8768 24 дня назад

    Lets go GPU video

  • @timmygilbert4102
    @timmygilbert4102 28 дней назад

    gpu gpu GPU GPU ❤

  • @Markus-fw4px
    @Markus-fw4px 28 дней назад

    speed to 0.75, then it's watchable 😅

  • @ericisconfused
    @ericisconfused 28 дней назад

    GPU! GPU!

  • @casdf7
    @casdf7 27 дней назад

    I want this game running at 1000 fps on a gpu

  • @codinghuman9954
    @codinghuman9954 27 дней назад +1

    MOAR GPU VIDS PLS!!!!!!!!!!!!!!!

  • @NintendoJimmy
    @NintendoJimmy 28 дней назад

    GPU!

  • @ShivamKumarPal-nc3nx
    @ShivamKumarPal-nc3nx 24 дня назад

    cpu to gpu code

  • @dj10schannel
    @dj10schannel 28 дней назад

    🧐

  • @Tyler-z8r
    @Tyler-z8r 28 дней назад

    Absolutely port this code to run on discrete graphics hardware! I have no idea how to do that!

  • @andrewdunbar828
    @andrewdunbar828 28 дней назад

    This is a pseudo comment

  • @defini7
    @defini7 28 дней назад

    That code was originally designed for rendering in Windows Command Prompt so it was not expected to be run on GPU

  • @pfqniet
    @pfqniet 28 дней назад

    13:30 I feel incredibly called out LMAO - I was exactly the same way 10 years ago and now I am "Future Me" and have to deal with "Past Me" being all clever and stuff. Help...

  • @kingofbattleonline
    @kingofbattleonline 27 дней назад

    очень понравилось, еще видосов с этим движком про оптимизацию.

  • @KeithKazamaFlick
    @KeithKazamaFlick 28 дней назад

    javidx9 & ChiliTomatoNoodle