Simulant  21.12-1292
A portable game engine for Windows, OSX, Linux, Dreamcast, and PSP
render_queue.h
1 /* * Copyright (c) 2011-2017 Luke Benstead https://simulant-engine.appspot.com
2  *
3  * This file is part of Simulant.
4  *
5  * Simulant is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * Simulant is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with Simulant. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #pragma once
20 
21 #include <list>
22 #include <set>
23 
24 #include "../../generic/containers/contiguous_map.h"
25 
26 #include "../../core/aligned_allocator.h"
27 #include "../../macros.h"
28 #include "../../threads/shared_mutex.h"
29 #include "../../types.h"
30 
31 namespace smlt {
32 
33 class MaterialPass;
34 class Renderer;
35 struct Renderable;
36 class Light;
37 class StageNode;
38 
39 namespace batcher {
40 
41 /* Remember! Render group keys are for *sorting* only. Priority, pass, and
42 is_blended are the only values you
43  * can rely on to be accurate, the others are capped or limited in some way. We
44 order in the following way:
45  *
46  * - RenderPriority. This is the highest level ordering, renderables with
47 different priorities are basically in different "queues"
48  * - Pass. This is the material pass number, the lower the pass number, the
49 earlier it is rendered
50  * - is_blended. This is 0 if the object is opaque or 1 if it's translucent.
51 This impacts the next value.
52  * - distance to camera. Stored as an unsigned 10-bit minifloat, with 5
53 exponent bits and 5 mantissa bits. If the object is blended, this is the
54 max-storable float minus the distance to camera)
55  * - Precedence. This is a value that allows you to tweak the order of objects
56 */
57 
59  union {
60  struct alignas(alignof(uint32_t)) {
61  // Texture ID of the base color texture. This is used
62  // to minimize texture changes, if you have a lot of
63  // textures this will lose its value
64  unsigned texture : 10;
65 
66  // This allows 7 levels of tweaking the
67  unsigned precedence : 3;
68 
69  // Float10 value for the distance to camera. If is_blended is true
70  // then this will be Float10::max_value - value
71  unsigned distance_to_camera : 10;
72 
73  unsigned is_blended : 1;
74 
75  unsigned pass : 2; // Max material passes is 4
76 
77  // Min/max priority is -/+ 25, but we store as 0 - 50.
78  unsigned priority : 6;
79  } __attribute__((packed)) s;
80  uint32_t i;
81  };
82 };
83 
84 static_assert(sizeof(RenderGroupKey::s) == 4,
85  "Render group key has unexpected size");
86 
87 struct RenderGroup {
88  /* A sort key, generated from priority and material properties, this
89  * may differ per-renderer */
90  RenderGroupKey sort_key;
91 
92  bool operator<(const RenderGroup& rhs) const {
93  return sort_key.i < rhs.sort_key.i;
94  }
95 
96  bool operator==(const RenderGroup& rhs) const {
97  return sort_key.i == rhs.sort_key.i;
98  }
99 
100  bool operator!=(const RenderGroup& rhs) const {
101  return !(*this == rhs);
102  }
103 };
104 
105 RenderGroupKey generate_render_group_key(
106  const RenderPriority priority, const uint8_t pass, const bool is_blended,
107  const float distance_to_camera, int16_t precedence, uint16_t texture_id);
108 
110 public:
111  virtual ~RenderGroupFactory() {}
112 
113  /* Initialize a render group based on the provided arguments
114  * Returns the group's sort_key */
115  virtual RenderGroupKey prepare_render_group(
116  RenderGroup* group, const Renderable* renderable,
117  const MaterialPass* material_pass, const RenderPriority priority,
118  const uint8_t pass_number, const bool is_blended,
119  const float distance_to_camera, uint16_t texture_id) = 0;
120 };
121 
122 typedef uint32_t Pass;
123 typedef uint32_t Iteration;
124 
125 class RenderQueue;
126 
128 public:
129  virtual ~RenderQueueVisitor() {}
130 
131  virtual void start_traversal(const RenderQueue& queue, uint64_t frame_id, StageNode* stage) = 0;
132 
133  virtual void change_render_group(const RenderGroup* prev, const RenderGroup* next) = 0;
134 
135  virtual void change_material_pass(const MaterialPass* prev, const MaterialPass* next) = 0;
136  virtual void apply_lights(const LightPtr* lights, const uint8_t count) = 0;
137 
138  virtual void visit(const Renderable*, const MaterialPass*, Iteration) = 0;
139  virtual void end_traversal(const RenderQueue& queue, StageNode* stage) = 0;
140 };
141 
142 
144 public:
146  queue_(queue) {}
147 
148  void watch(AssetID material_id, Renderable* renderable);
149  void unwatch(Renderable* renderable);
150 
151 private:
152  RenderQueue* queue_;
153 
154  /*
155  * We store a list of all the renderables that need to be reinserted if a material changes
156  */
157  std::unordered_map<AssetID, std::set<Renderable*>> renderables_by_material_;
158 
159  /*
160  * We store connections to material update signals, when all renderables are removed
161  * for a particular material, we disconnect the signal
162  */
163  std::unordered_map<AssetID, sig::connection> material_update_conections_;
164 
165  void on_material_changed(AssetID material);
166 };
167 
168 
169 class RenderQueue {
170 public:
171  typedef std::function<void (bool, const RenderGroup*, Renderable*, MaterialPass*, Light*, Iteration)> TraverseCallback;
172 
173  RenderQueue();
174 
175  void reset(StageNode* stage, RenderGroupFactory* render_group_factory, CameraPtr camera);
176 
177  void insert_renderable(Renderable&& renderable); // IMPORTANT, must update RenderGroups if they exist already
178  void clear();
179 
180  void traverse(RenderQueueVisitor* callback, uint64_t frame_id) const;
181 
182  std::size_t renderable_count() const {
183  return render_queue_.size();
184  }
185 
186  Renderable* renderable(std::size_t idx);
187 
188 private:
189  // std::map is ordered, so by using the RenderGroup as the key we
190  // minimize GL state changes (e.g. if a RenderGroupImpl orders by AssetID, then ShaderID
191  // then we'll see (TexID(1), ShaderID(1)), (TexID(1), ShaderID(2)) for example meaning the
192  // texture doesn't change even if the shader does
194 
195  StageNode* stage_node_ = nullptr;
196  RenderGroupFactory* render_group_factory_ = nullptr;
197  CameraPtr camera_;
198 
199  SortedRenderables render_queue_;
200 
201  void clean_empty_batches();
202 
203  mutable thread::Mutex queue_lock_;
204 };
205 
206 }
207 }
smlt
Definition: animation.cpp:25
smlt::batcher::MaterialChangeWatcher
Definition: render_queue.h:143
smlt::Light
Definition: light.h:34
smlt::batcher::RenderGroupKey
Definition: render_queue.h:58
smlt::batcher::RenderQueue
Definition: render_queue.h:169
smlt::batcher::RenderQueueVisitor
Definition: render_queue.h:127
smlt::Camera
Definition: camera.h:17
smlt::MaterialPass
Definition: material.h:46
smlt::StageNode
Definition: stage_node.h:442
smlt::batcher::RenderGroup
Definition: render_queue.h:87
smlt::batcher::RenderGroupFactory
Definition: render_queue.h:109
smlt::Renderable
Definition: renderable.h:67
smlt::thread::Mutex
Definition: mutex.h:35
smlt::ContiguousMultiMap< RenderGroup, Renderable >