From acf2d4cf96ea26df5335e63f06e54ce8904c7b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 31 Jul 2023 18:18:48 +0200 Subject: [PATCH 1/2] Proposal for the multi-camera, multi-franebuffer batch renderer support. --- src/esp/gfx_batch/Renderer.h | 258 +++++++++++++++++++++++++++++------ 1 file changed, 213 insertions(+), 45 deletions(-) diff --git a/src/esp/gfx_batch/Renderer.h b/src/esp/gfx_batch/Renderer.h index a25ce7a2b5..ca8144f790 100644 --- a/src/esp/gfx_batch/Renderer.h +++ b/src/esp/gfx_batch/Renderer.h @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace esp { @@ -39,6 +40,41 @@ typedef Corrade::Containers::EnumSet RendererFlags; CORRADE_ENUMSET_OPERATORS(RendererFlags) +/** +@brief Output rendered by a particular batch camera + +@see @ref RendererBatchCameraOutputs, @ref RendererBatchCamera, + @ref RendererConfiguration::setBatchCameras() +*/ +enum class RendererBatchCameraOutput { + Color = 1 << 0, /**< Color buffer */ + Depth = 1 << 1, /**< Depth buffer */ + Semantic = 1 << 2 /**< Semantic buffer */ +}; + +/** +@brief Buffers rendered by a particular batch camera + +@see @ref RendererBatchCamera, @ref RendererConfiguration::setBatchCameras() +*/ +typedef Corrade::Containers::EnumSet RendererBatchCameraOutputs; + +CORRADE_ENUMSET_OPERATORS(RendererBatchCameraOutputs) + +/** +@brief Batch camera setup + +@see @ref RendererConfiguration::setBatchCameras() +*/ +struct RendererBatchCamera { + /** @brief Outputs rendered by the batch camera */ + RendererBatchCameraOutputs outputs; + /** @brief Tile size, in pixels */ + Magnum::Vector2i tileSize; + /** @brief Tile count */ + Magnum::Vector2i tileCount; +}; + class Renderer; /** @@ -61,25 +97,48 @@ struct RendererConfiguration { RendererConfiguration& setFlags(RendererFlags flags); /** - * @brief Set tile size and count - * - * By default there's a single @cpp {128, 128} @ce tile, corresponding to a - * single rendered scene. Tiles are organized in the framebuffer in a grid - * and @p tileCount implies an upper bound on number of scenes rendered. To - * avoid hitting GPU limits with large tile counts and/or sizes, it's best to - * aim for the total framebuffer size given by @cpp tileSize*tileCount @ce to - * be a power-of-two square. On the other hand, having tiles organized in a - * single column may make it easier for external libraries to consume the - * data tile-by-tile, as there's no row stride to account for. - * - * Scenes that are empty are not rendered at all, so it's fine to have unused - * tiles, they only occupy space in the output framebuffer. For example, if - * you want 13 scenes, set @p tileCount to @cpp {4, 4} @ce and ignore the - * last 3. - * @see @ref Renderer::tileSize(), @ref Renderer::tileCount() + * @brief Set batch camera properties + * + * For each batch camera there's one framebuffer with tiles organized in a + * grid and @ref RendererBatchCamera::tileCount implies an upper bound on + * number of scenes rendered by that particular camera. To avoid hitting GPU + * limits with large tile counts and/or sizes, it's best to aim for the total + * framebuffer size given by @cpp tileSize*tileCount @ce to be a power-of-two + * square. On the other hand, having tiles organized in a single column may + * make it easier for external libraries to consume the data tile-by-tile, as + * there's no row stride to account for. + * + * Assigning of scenes to particular cameras is done in + * @ref setSceneCameraAssignment(). Tiles that are empty are not rendered at + * all, so it's fine to have unused tiles, they only occupy space in given + * camera's framebuffer. For example, if you need a particular camera to + * render 13 scenes, set its @ref RendererBatchCamera::tileCount to + * @cpp {4, 4} @ce and ignore the last 3. + * + * By default there's a single color + depth batch camera with a single + * @cpp {128, 128} @ce tile, corresponding to a single rendered scene. + * @see @ref Renderer::batchCameraCount(), @ref Renderer::tileSize(), + * @ref Renderer::tileCount() */ - RendererConfiguration& setTileSizeCount(const Magnum::Vector2i& tileSize, - const Magnum::Vector2i& tileCount); + RendererConfiguration& setBatchCameras(Corrade::Containers::ArrayView cameras); + /** @overload */ + RendererConfiguration& setBatchCameras(std::initializer_list cameras); + + /** + * @brief Set scene count and camera assignment + * + * Size of the first dimension is the total scene count, which will become + * @ref Renderer::sceneCount(). The second dimension is expected to be + * contiguous and have the same size as camera count passed to + * @ref setBatchCameras(). A bit set at position @cpp [i, j] @ce means scene + * `i` will be shown in camera `j`. The total count of bits set for a + * particular camera is expected to not exceed the total tile count set for + * that camera in @ref setBatchCameras(). + * + * By default, each scene gets assigned to all cameras, i.e. as if this + * function was called with @p assignment being all ones. + */ + RendererConfiguration& setSceneCameraAssignment(const Corrade::Containers::StridedBitArrayView2D& assignment); /** * @brief Set max light count per draw @@ -191,6 +250,30 @@ standalone operation use the @ref RendererStandalone subclass instead, which manages the OpenGL context and a framebuffer on its own. Apart from the context and framebuffer, the high-level usage is same for both. +@section gfx_batch-Renderer-terms Terms used + +- **Model file** is a regular glTF, OBJ, PLY, ... model, with no restrictions + on its contents. The whole file is treated as a single *node heirarchy*. +- **Composite file** is a set of regular *model files* brought together into a + single file with various optimizations applied. Often it's a single + *composite mesh* together with a single *composite texture*. The original + model files form *node hierarchies* in the composite file and are referenced + using string identifiers. +- **Node hierarchy** is a hierarchy of nodes with meshes, materials or lights + attached. It's referenced using a string identifier in a *composite file*, + using a filename in a model and using a numeric ID when added to a *scene*. +- **Scene** is a set of *node hierarchies* added either from *model files* or + *composite files*. +- **Batch camera** has a framebuffer with various *batch camera outputs* + attached and renders a grid of *scenes* assigned to it. All tiles in the grid + have the same size and each is a single *camera*. +- **Batch camera output** is a color, depth or semantic buffer to which a + *batch camera* renders. +- **Camera** is associated with a particular *scene* and *batch camera*. Its + output size is given by the *batch camera*, contains a projection and a + transformation matrix and a mask of *node hierarchies* that it should render + for given *scene*. + @section gfx_batch-Renderer-usage Usage The renderer gets constructed using a @ref RendererConfiguration with desired @@ -457,30 +540,74 @@ class Renderer { */ RendererFlags flags() const; + /** + * @brief Total batch camera count + * + * See @ref sceneBatchCameras() for an information about what scenes is given + * batch camera rendering. By default there's a single batch camera. + */ + Magnum::UnsignedInt batchCameraCount() const; + + /** + * @brief Outputs enabled for given batch camera + * @param batchCameraId Batch camera ID, expected to be less than + * @ref batchCameraCount() + */ + RendererBatchCameraOutputs batchCameraOutputs(Magnum::UnsignedInt batchCameraId) const; + /** * @brief Tile size + * @param batchCameraId Batch camera ID, expected to be less than + * @ref batchCameraCount() * * The default tile size is @cpp {128, 128} @ce. * @see @ref RendererConfiguration::setTileSizeCount() */ - Magnum::Vector2i tileSize() const; + Magnum::Vector2i tileSize(Magnum::UnsignedInt batchCameraId) const; /** * @brief Tile count + * @param batchCameraId Batch camera ID, expected to be less than + * @ref batchCameraCount() * * By default there's a single tile. * @see @ref RendererConfiguration::setTileSizeCount() */ - Magnum::Vector2i tileCount() const; + Magnum::Vector2i tileCount(Magnum::UnsignedInt batchCameraId) const; /** - * @brief Scene count + * @brief Total scene count * - * Same as the @ref Magnum::Math::Vector::product() "product()" of - * @ref tileCount(). Empty scenes are not rendered, they only occupy space in - * the output framebuffer. + * See @ref sceneBatchCameras() for an information about what batch cameras + * is given scene included in and @ref sceneBatchCameraIndex() for the tile + * index in given batch camera. By default there's a single scene. */ - std::size_t sceneCount() const; + Magnum::UnsignedInt sceneCount() const; + + /** + * @brief Batch cameras which render given scene + * @param sceneId Scene ID, expected to be less than + * @ref sceneCount() + * + * The returned view has a size equal to @ref batchCameraCount(), with bits + * set for each batch camera that includes @p sceneId. By default there's a + * single scene rendered by a single camera, so this function returns a + * single bit that's set. + */ + Corrade::Containers::BitArrayView sceneBatchCameras(Magnum::UnsignedInt sceneId) const; + + /** + * @brief Tile index at which given scene is rendered in given batch camera + * @param sceneId Scene ID, expected to be less than + * @ref sceneCount() + * @param batchCameraId Batch camera ID, expected to be less than + * @ref batchCameraCount() + * + * The @ref sceneBatchCameras() for given @p sceneId is expected to include + * @p batchCameraId. By default there's a single scene rendered by a single + * camera, so this function returns @cpp {0, 0} @ce. + */ + Magnum::Vector2i sceneBatchCameraIndex(Magnum::UnsignedInt sceneId, Magnum::UnsignedInt batchCameraId); /** * @brief Max light count @@ -568,11 +695,16 @@ class Renderer { * @brief Add a mesh hierarchy * @param sceneId Scene ID, expected to be less than * @ref sceneCount() + * @param cameras Camears to include the hierarchy in * @param name *Node hierarchy template* name, added with * @ref addFile() earlier * @param bakeTransformation Transformation to bake into the hierarchy * @return ID of the newly added node * + * Size of the @p cameras view is expected to be the same as + * @ref batchCameraCount(), bits that are zero in @ref sceneBatchCameras() + * for given @p sceneId are expected to be zero in @p cameras as well. + * * The returned ID can be subsequently used to update transformations via * @ref transformations(). The returned IDs are *not* contiguous, the gaps * correspond to number of child nodes in the hierarchy. @@ -585,17 +717,31 @@ class Renderer { */ std::size_t addNodeHierarchy(Magnum::UnsignedInt sceneId, Corrade::Containers::StringView name, + Corrade::Containers::BitArrayView cameras, const Magnum::Matrix4& bakeTransformation = {}); #else /* To avoid having to include Matrix4 in the header */ std::size_t addNodeHierarchy(Magnum::UnsignedInt sceneId, Corrade::Containers::StringView name, + Corrade::Containers::BitArrayView cameras, const Magnum::Matrix4& bakeTransformation); std::size_t addNodeHierarchy(Magnum::UnsignedInt sceneId, - Corrade::Containers::StringView name); + Corrade::Containers::StringView name, + Corrade::Containers::BitArrayView cameras); #endif - std::size_t addEmptyNode(Magnum::UnsignedInt sceneId); + /** + * @brief Add an empty node + * @param sceneId Scene ID, expected to be less than + * @ref sceneCount() + * @param cameras Camears to include the node in + * + * Size of the @p cameras view is expected to be the same as + * @ref batchCameraCount(), bits that are zero in @ref sceneBatchCameras() + * for given @p sceneId are expected to be zero in @p cameras as well. + */ + std::size_t addEmptyNode(Magnum::UnsignedInt sceneId, + Corrade::Containers::BitArrayView cameras); /** * @brief Add a light @@ -606,8 +752,8 @@ class Renderer { * @param type Light type. Can't be changed after adding the * light. * - * Expects that @ref maxLightCount() isn't @cpp 0 @ce. If @p type is - * @ref RendererLightType::Directional, a negative + * The light is used for all cameras that the @p nodeId is included in. If + * @p type is @ref RendererLightType::Directional, a negative * @ref Magnum::Matrix4::backwards() is taken from @p nodeId transformation * as the direction, if @p type is @ref RendererLightType::Point, * @ref Magnum::Matrix4::translation() is taken from @p nodeId transformation @@ -641,28 +787,45 @@ class Renderer { /** * @brief Get the combined projection and view matrices of a camera - * (read-only) - * @param sceneId Scene ID, expected to be less than @ref sceneCount() + * @param sceneId Scene ID, expected to be less than + * @ref sceneCount() + * @param batchCameraId Batch camera ID, expected to be less than + * @ref batchCameraCount() + * + * The @ref sceneBatchCameras() for given @p sceneId is expected to include + * @p batchCameraId. */ - Magnum::Matrix4 camera(Magnum::UnsignedInt sceneId) const; + Magnum::Matrix4 camera(Magnum::UnsignedInt sceneId, + Magnum::UnsignedInt batchCameraId) const; /** - * @brief Get the depth unprojection parameters of a camera (read-only) - * @param sceneId Scene ID, expected to be less than @ref sceneCount() + * @brief Get the depth unprojection parameters of a camera + * @param sceneId Scene ID, expected to be less than + * @ref sceneCount() + * @param batchCameraId Batch camera ID, expected to be less than + * @ref batchCameraCount() + * + * The @ref sceneBatchCameras() for given @p sceneId is expected to include + * @p batchCameraId. */ - Magnum::Vector2 cameraDepthUnprojection(Magnum::UnsignedInt sceneId) const; + Magnum::Vector2 cameraDepthUnprojection(Magnum::UnsignedInt sceneId, + Magnum::UnsignedInt batchCameraId) const; /** * @brief Set the camera projection and view matrices - * @param sceneId Scene ID, expected to be less than @ref sceneCount() - * @param view View matrix of the camera (inverse transform) - * @param projection Projection matrix of the camera - * - * Also computes the camera unprojection. - * Modifications to the transformation are taken into account in the next - * @ref draw(). + * @param sceneId Scene ID, expected to be less than + * @ref sceneCount() + * @param batchCameraId Batch camera ID, expected to be less than + * @ref batchCameraCount() + * @param view View matrix of the camera (inverse transform) + * @param projection Projection matrix of the camera + * + * The @ref sceneBatchCameras() for given @p sceneId is expected to include + * @p batchCameraId. Also computes the camera unprojection. Modifications to + * the transformation are taken into account in the next @ref draw(). */ void updateCamera(Magnum::UnsignedInt sceneId, + Magnum::UnsignedInt batchCameraId, const Magnum::Matrix4& projection, const Magnum::Matrix4& view); @@ -714,12 +877,17 @@ class Renderer { Magnum::UnsignedInt sceneId); /** - * @brief Draw all scenes into provided framebuffer + * @brief Draw all scenes associated with given batch camera into provided framebuffer + * @param batchCameraId Batch camera ID, expected to be less than + * @ref batchCameraCount() * * The @p framebuffer is expected to have a size at least as larger as the - * product of @ref tileSize() and @ref tileCount(). + * product of @ref tileSize() and @ref tileCount() and contain attachments + * for all @ref batchCameraOutputs() for given @p batchCameraId. You can use + * @ref sceneBatchCameraIndex() to query tile index for a particular scene in + * the output. */ - void draw(Magnum::GL::AbstractFramebuffer& framebuffer); + void draw(Magnum::UnsignedInt batchCameraId, Magnum::GL::AbstractFramebuffer& framebuffer); /** * @brief Scene stats From 6b3f1f16792995104e3bdcd1fbefcef126317a31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 31 Jul 2023 18:37:56 +0200 Subject: [PATCH 2/2] Replace some words with some other words. --- src/esp/gfx_batch/Renderer.h | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/esp/gfx_batch/Renderer.h b/src/esp/gfx_batch/Renderer.h index ca8144f790..789fd690a0 100644 --- a/src/esp/gfx_batch/Renderer.h +++ b/src/esp/gfx_batch/Renderer.h @@ -109,8 +109,8 @@ struct RendererConfiguration { * there's no row stride to account for. * * Assigning of scenes to particular cameras is done in - * @ref setSceneCameraAssignment(). Tiles that are empty are not rendered at - * all, so it's fine to have unused tiles, they only occupy space in given + * @ref setSceneBatchCameras(). Tiles that are empty are not rendered at all, + * so it's fine to have unused tiles, they only occupy space in given * camera's framebuffer. For example, if you need a particular camera to * render 13 scenes, set its @ref RendererBatchCamera::tileCount to * @cpp {4, 4} @ce and ignore the last 3. @@ -125,20 +125,20 @@ struct RendererConfiguration { RendererConfiguration& setBatchCameras(std::initializer_list cameras); /** - * @brief Set scene count and camera assignment + * @brief Set scene count and scene to batch camera assignment * * Size of the first dimension is the total scene count, which will become - * @ref Renderer::sceneCount(). The second dimension is expected to be - * contiguous and have the same size as camera count passed to - * @ref setBatchCameras(). A bit set at position @cpp [i, j] @ce means scene - * `i` will be shown in camera `j`. The total count of bits set for a - * particular camera is expected to not exceed the total tile count set for - * that camera in @ref setBatchCameras(). + * @ref Renderer::sceneCount(). The second dimension then becomes + * @ref Renderer::sceneBatchCameras(), is expected to be contiguous and have + * the same size as camera count passed to @ref setBatchCameras(). A bit set + * at position @cpp [i, j] @ce means scene `i` will be shown in camera `j`. + * The total count of bits set for a particular camera is expected to not + * exceed the total tile count set for that camera in @ref setBatchCameras(). * * By default, each scene gets assigned to all cameras, i.e. as if this * function was called with @p assignment being all ones. */ - RendererConfiguration& setSceneCameraAssignment(const Corrade::Containers::StridedBitArrayView2D& assignment); + RendererConfiguration& setSceneBatchCameras(const Corrade::Containers::StridedBitArrayView2D& cameras); /** * @brief Set max light count per draw @@ -263,16 +263,17 @@ and framebuffer, the high-level usage is same for both. attached. It's referenced using a string identifier in a *composite file*, using a filename in a model and using a numeric ID when added to a *scene*. - **Scene** is a set of *node hierarchies* added either from *model files* or - *composite files*. + *composite files*. A single scene can appear in multiple *batch cameras*, + rendered by multiple *cameras*. - **Batch camera** has a framebuffer with various *batch camera outputs* attached and renders a grid of *scenes* assigned to it. All tiles in the grid have the same size and each is a single *camera*. - **Batch camera output** is a color, depth or semantic buffer to which a *batch camera* renders. -- **Camera** is associated with a particular *scene* and *batch camera*. Its - output size is given by the *batch camera*, contains a projection and a - transformation matrix and a mask of *node hierarchies* that it should render - for given *scene*. +- **Camera** is what a *batch camera* uses to render a particular *scene*. Its + output size is given by the *batch camera* tile size, contains a projection + and a transformation matrix and a mask of *node hierarchies* that it should + render from given *scene*. @section gfx_batch-Renderer-usage Usage