.. _doc_gpu_optimization: GPU optimization ================ Introduction ~~~~~~~~~~~~ The demand for new graphics features and progress almost guarantees that you will encounter graphics bottlenecks. Some of these can be on the CPU side, for instance in calculations inside the Godot engine to prepare objects for rendering. Bottlenecks can also occur on the CPU in the graphics driver, which sorts instructions to pass to the GPU, and in the transfer of these instructions. And finally, bottlenecks also occur on the GPU itself. Where bottlenecks occur in rendering is highly hardware-specific. Mobile GPUs in particular may struggle with scenes that run easily on desktop. Understanding and investigating GPU bottlenecks is slightly different to the situation on the CPU. This is because, often, you can only change performance indirectly by changing the instructions you give to the GPU. Also, it may be more difficult to take measurements. In many cases, the only way of measuring performance is by examining changes in the time spent rendering each frame. Draw calls, state changes, and APIs =================================== .. note:: The following section is not relevant to end-users, but is useful to provide background information that is relevant in later sections. Godot sends instructions to the GPU via a graphics API (OpenGL, OpenGL ES or Vulkan). The communication and driver activity involved can be quite costly, especially in OpenGL and OpenGL ES. If we can provide these instructions in a way that is preferred by the driver and GPU, we can greatly increase performance. Nearly every API command in OpenGL requires a certain amount of validation to make sure the GPU is in the correct state. Even seemingly simple commands can lead to a flurry of behind-the-scenes housekeeping. Therefore, the goal is to reduce these instructions to a bare minimum and group together similar objects as much as possible so they can be rendered together, or with the minimum number of these expensive state changes. 2D batching ~~~~~~~~~~~ In 2D, the costs of treating each item individually can be prohibitively high - there can easily be thousands of them on the screen. This is why 2D *batching* is used. Multiple similar items are grouped together and rendered in a batch, via a single draw call, rather than making a separate draw call for each item. In addition, this means state changes, material and texture changes can be kept to a minimum. For more information on 2D batching, see `doc_batching`. 3D batching ~~~~~~~~~~~ In 3D, we still aim to minimize draw calls and state changes. However, it can be more difficult to batch together several objects into a single draw call. 3D meshes tend to comprise hundreds or thousands of triangles, and combining large meshes in real-time is prohibitively expensive. The costs of joining them quickly exceeds any benefits as the number of triangles grows per mesh. A much better alternative is to **join meshes ahead of time** (static meshes in relation to each other). This can either be done by artists, or programmatically within Godot. There is also a cost to batching together objects in 3D. Several objects rendered as one cannot be individually culled. An entire city that is off-screen will still be rendered if it is joined to a single blade of grass that is on screen. Thus, you should always take objects' location and culling into account when attempting to batch 3D objects together. Despite this, the benefits of joining static objects often outweigh other considerations, especially for large numbers of distant or low-poly objects. For more information on 3D specific optimizations, see `doc_optimizing_3d_performance`. Reuse Shaders and Materials ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Godot renderer is a little different to what is out there. It's designed to minimize GPU state changes as much as possible. `SpatialMaterial