1 /*************************************************************************/
2 /* rasterizer_canvas_gles2.h */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30
31 #ifndef RASTERIZERCANVASGLES2_H
32 #define RASTERIZERCANVASGLES2_H
33
34 #include "rasterizer_canvas_base_gles2.h"
35
36 class RasterizerSceneGLES2;
37
38 class RasterizerCanvasGLES2 : public RasterizerCanvasBaseGLES2 {
39
40 // used to determine whether we use hardware transform (none)
41 // software transform all verts, or software transform just a translate
42 // (no rotate or scale)
43 enum TransformMode {
44 TM_NONE,
45 TM_ALL,
46 TM_TRANSLATE,
47 };
48
49 // pod versions of vector and color and RID, need to be 32 bit for vertex format
50 struct BatchVector2 {
51 float x, y;
setBatchVector252 void set(const Vector2 &p_o) {
53 x = p_o.x;
54 y = p_o.y;
55 }
toBatchVector256 void to(Vector2 &r_o) const {
57 r_o.x = x;
58 r_o.y = y;
59 }
60 };
61
62 struct BatchColor {
63 float r, g, b, a;
setBatchColor64 void set(const Color &p_c) {
65 r = p_c.r;
66 g = p_c.g;
67 b = p_c.b;
68 a = p_c.a;
69 }
70 bool operator==(const BatchColor &p_c) const {
71 return (r == p_c.r) && (g == p_c.g) && (b == p_c.b) && (a == p_c.a);
72 }
73 bool operator!=(const BatchColor &p_c) const { return (*this == p_c) == false; }
equalsBatchColor74 bool equals(const Color &p_c) const {
75 return (r == p_c.r) && (g == p_c.g) && (b == p_c.b) && (a == p_c.a);
76 }
get_dataBatchColor77 const float *get_data() const { return &r; }
78 String to_string() const;
79 };
80
81 struct BatchVertex {
82 // must be 32 bit pod
83 BatchVector2 pos;
84 BatchVector2 uv;
85 };
86
87 struct BatchVertexColored : public BatchVertex {
88 // must be 32 bit pod
89 BatchColor col;
90 };
91
92 struct Batch {
93 enum CommandType : uint32_t {
94 BT_DEFAULT,
95 BT_RECT,
96 };
97
98 CommandType type;
99 uint32_t first_command; // also item reference number
100 uint32_t num_commands;
101 uint32_t first_quad;
102 uint32_t batch_texture_id;
103 BatchColor color;
104 };
105
106 struct BatchTex {
107 enum TileMode : uint32_t {
108 TILE_OFF,
109 TILE_NORMAL,
110 TILE_FORCE_REPEAT,
111 };
112 RID RID_texture;
113 RID RID_normal;
114 TileMode tile_mode;
115 BatchVector2 tex_pixel_size;
116 uint32_t flags;
117 };
118
119 // items in a list to be sorted prior to joining
120 struct BSortItem {
121 // have a function to keep as pod, rather than operator
assignBSortItem122 void assign(const BSortItem &o) {
123 item = o.item;
124 z_index = o.z_index;
125 }
126 Item *item;
127 int z_index;
128 };
129
130 // batch item may represent 1 or more items
131 struct BItemJoined {
132 uint32_t first_item_ref;
133 uint32_t num_item_refs;
134
135 Rect2 bounding_rect;
136
137 // note the z_index may only be correct for the first of the joined item references
138 // this has implications for light culling with z ranged lights.
139 int16_t z_index;
140
141 // these are defined in RasterizerStorageGLES2::Shader::CanvasItem::BatchFlags
142 uint16_t flags;
143
144 // we are always splitting items with lots of commands,
145 // and items with unhandled primitives (default)
use_hardware_transformBItemJoined146 bool use_hardware_transform() const { return num_item_refs == 1; }
147 };
148
149 struct BItemRef {
150 Item *item;
151 Color final_modulate;
152 };
153
154 struct BLightRegion {
resetBLightRegion155 void reset() {
156 light_bitfield = 0;
157 shadow_bitfield = 0;
158 too_many_lights = false;
159 }
160 uint64_t light_bitfield;
161 uint64_t shadow_bitfield;
162 bool too_many_lights; // we can only do light region optimization if there are 64 or less lights
163 };
164
165 struct BatchData {
166 BatchData();
reset_flushBatchData167 void reset_flush() {
168 batches.reset();
169 batch_textures.reset();
170 vertices.reset();
171
172 total_quads = 0;
173 total_color_changes = 0;
174 }
175
176 GLuint gl_vertex_buffer;
177 GLuint gl_index_buffer;
178
179 uint32_t max_quads;
180 uint32_t vertex_buffer_size_units;
181 uint32_t vertex_buffer_size_bytes;
182 uint32_t index_buffer_size_units;
183 uint32_t index_buffer_size_bytes;
184
185 RasterizerArrayGLES2<BatchVertex> vertices;
186 RasterizerArrayGLES2<BatchVertexColored> vertices_colored;
187 RasterizerArrayGLES2<Batch> batches;
188 RasterizerArrayGLES2<Batch> batches_temp; // used for translating to colored vertex batches
189 RasterizerArray_non_pod_GLES2<BatchTex> batch_textures; // the only reason this is non-POD is because of RIDs
190
191 bool use_colored_vertices;
192
193 RasterizerArrayGLES2<BItemJoined> items_joined;
194 RasterizerArrayGLES2<BItemRef> item_refs;
195
196 // items are sorted prior to joining
197 RasterizerArrayGLES2<BSortItem> sort_items;
198
199 // counts
200 int total_quads;
201
202 // we keep a record of how many color changes caused new batches
203 // if the colors are causing an excessive number of batches, we switch
204 // to alternate batching method and add color to the vertex format.
205 int total_color_changes;
206
207 // if the shader is using MODULATE, we prevent baking color so the final_modulate can
208 // be read in the shader.
209 // if the shader is reading VERTEX, we prevent baking vertex positions with extra matrices etc
210 // to prevent the read position being incorrect.
211 // These flags are defined in RasterizerStorageGLES2::Shader::CanvasItem::BatchFlags
212 uint32_t joined_item_batch_flags;
213
214 // measured in pixels, recalculated each frame
215 float scissor_threshold_area;
216
217 // diagnose this frame, every nTh frame when settings_diagnose_frame is on
218 bool diagnose_frame;
219 String frame_string;
220 uint32_t next_diagnose_tick;
221 uint64_t diagnose_frame_number;
222
223 // whether to join items across z_indices - this can interfere with z ranged lights,
224 // so has to be disabled in some circumstances
225 bool join_across_z_indices;
226
227 // global settings
228 bool settings_use_batching; // the current use_batching (affected by flash)
229 bool settings_use_batching_original_choice; // the choice entered in project settings
230 bool settings_flash_batching; // for regression testing, flash between non-batched and batched renderer
231 bool settings_diagnose_frame; // print out batches to help optimize / regression test
232 int settings_max_join_item_commands;
233 float settings_colored_vertex_format_threshold;
234 int settings_batch_buffer_num_verts;
235 bool settings_scissor_lights;
236 float settings_scissor_threshold; // 0.0 to 1.0
237 int settings_item_reordering_lookahead;
238 bool settings_use_single_rect_fallback;
239 int settings_light_max_join_items;
240
241 // uv contraction
242 bool settings_uv_contract;
243 float settings_uv_contract_amount;
244
245 // only done on diagnose frame
reset_statsBatchData246 void reset_stats() {
247 stats_items_sorted = 0;
248 stats_light_items_joined = 0;
249 }
250
251 // frame stats (just for monitoring and debugging)
252 int stats_items_sorted;
253 int stats_light_items_joined;
254 } bdata;
255
256 struct RenderItemState {
RenderItemStateRenderItemState257 RenderItemState() { reset(); }
258 void reset();
259 Item *current_clip;
260 RasterizerStorageGLES2::Shader *shader_cache;
261 bool rebind_shader;
262 bool prev_use_skeleton;
263 int last_blend_mode;
264 RID canvas_last_material;
265 Color final_modulate;
266
267 // used for joining items only
268 BItemJoined *joined_item;
269 bool join_batch_break;
270 BLightRegion light_region;
271
272 // 'item group' is data over a single call to canvas_render_items
273 int item_group_z;
274 Color item_group_modulate;
275 Light *item_group_light;
276 Transform2D item_group_base_transform;
277 } _render_item_state;
278
279 struct FillState {
resetFillState280 void reset() {
281 // don't reset members that need to be preserved after flushing
282 // half way through a list of commands
283 curr_batch = 0;
284 batch_tex_id = -1;
285 texpixel_size = Vector2(1, 1);
286 contract_uvs = false;
287 }
288 Batch *curr_batch;
289 int batch_tex_id;
290 bool use_hardware_transform;
291 bool contract_uvs;
292 Vector2 texpixel_size;
293 Color final_modulate;
294 TransformMode transform_mode;
295 TransformMode orig_transform_mode;
296
297 // support for extra matrices
298 bool extra_matrix_sent; // whether sent on this item (in which case sofware transform can't be used untl end of item)
299 int transform_extra_command_number_p1; // plus one to allow fast checking against zero
300 Transform2D transform_combined; // final * extra
301 };
302
303 public:
304 virtual void canvas_render_items_begin(const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform);
305 virtual void canvas_render_items_end();
306 virtual void canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform);
307 virtual void canvas_begin();
308 virtual void canvas_end();
309
310 private:
311 // legacy codepath .. to remove after testing
312 void _canvas_render_item(Item *p_ci, RenderItemState &r_ris);
313 void _canvas_item_render_commands(Item *p_item, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES2::Material *p_material);
314
315 // high level batch funcs
316 void canvas_render_items_implementation(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform);
317 void render_joined_item(const BItemJoined &p_bij, RenderItemState &r_ris);
318 void record_items(Item *p_item_list, int p_z);
319 void join_items(Item *p_item_list, int p_z);
320 void join_sorted_items();
321 bool try_join_item(Item *p_ci, RenderItemState &r_ris, bool &r_batch_break);
322 void render_joined_item_commands(const BItemJoined &p_bij, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES2::Material *p_material, bool p_lit);
323 void render_batches(Item::Command *const *p_commands, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES2::Material *p_material);
324 bool prefill_joined_item(FillState &r_fill_state, int &r_command_start, Item *p_item, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES2::Material *p_material);
325 void flush_render_batches(Item *p_first_item, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES2::Material *p_material);
326
327 // low level batch funcs
328 void _batch_translate_to_colored();
329 int _batch_find_or_create_tex(const RID &p_texture, const RID &p_normal, bool p_tile, int p_previous_match);
330 RasterizerStorageGLES2::Texture *_get_canvas_texture(const RID &p_texture) const;
331 void _batch_upload_buffers();
332 void _batch_render_rects(const Batch &p_batch, RasterizerStorageGLES2::Material *p_material);
_batch_vertex_request_new()333 BatchVertex *_batch_vertex_request_new() { return bdata.vertices.request(); }
334 Batch *_batch_request_new(bool p_blank = true);
335
336 bool _detect_batch_break(Item *p_ci);
337 void _software_transform_vertex(BatchVector2 &r_v, const Transform2D &p_tr) const;
338 void _software_transform_vertex(Vector2 &r_v, const Transform2D &p_tr) const;
339 TransformMode _find_transform_mode(const Transform2D &p_tr) const;
340 void _prefill_default_batch(FillState &r_fill_state, int p_command_num, const Item &p_item);
341
342 // sorting
343 void sort_items();
344 bool sort_items_from(int p_start);
345 bool _sort_items_match(const BSortItem &p_a, const BSortItem &p_b) const;
346
347 // light scissoring
348 bool _light_find_intersection(const Rect2 &p_item_rect, const Transform2D &p_light_xform, const Rect2 &p_light_rect, Rect2 &r_cliprect) const;
349 bool _light_scissor_begin(const Rect2 &p_item_rect, const Transform2D &p_light_xform, const Rect2 &p_light_rect) const;
350 void _calculate_scissor_threshold_area();
351
352 // no need to compile these in in release, they are unneeded outside the editor and only add to executable size
353 #ifdef DEBUG_ENABLED
354 void diagnose_batches(Item::Command *const *p_commands);
355 String get_command_type_string(const Item::Command &p_command) const;
356 #endif
357
358 public:
359 void initialize();
360 RasterizerCanvasGLES2();
361 };
362
363 //////////////////////////////////////////////////////////////
364
365 // Default batches will not occur in software transform only items
366 // EXCEPT IN THE CASE OF SINGLE RECTS (and this may well not occur, check the logic in prefill_join_item TYPE_RECT)
367 // but can occur where transform commands have been sent during hardware batch
_prefill_default_batch(FillState & r_fill_state,int p_command_num,const Item & p_item)368 inline void RasterizerCanvasGLES2::_prefill_default_batch(FillState &r_fill_state, int p_command_num, const Item &p_item) {
369 if (r_fill_state.curr_batch->type == Batch::BT_DEFAULT) {
370 // don't need to flush an extra transform command?
371 if (!r_fill_state.transform_extra_command_number_p1) {
372 // another default command, just add to the existing batch
373 r_fill_state.curr_batch->num_commands++;
374 } else {
375 #if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED)
376 if (r_fill_state.transform_extra_command_number_p1 != p_command_num) {
377 WARN_PRINT_ONCE("_prefill_default_batch : transform_extra_command_number_p1 != p_command_num");
378 }
379 #endif
380 // if the first member of the batch is a transform we have to be careful
381 if (!r_fill_state.curr_batch->num_commands) {
382 // there can be leading useless extra transforms (sometimes happens with debug collision polys)
383 // we need to rejig the first_command for the first useful transform
384 r_fill_state.curr_batch->first_command += r_fill_state.transform_extra_command_number_p1 - 1;
385 }
386
387 // we do have a pending extra transform command to flush
388 // either the extra transform is in the prior command, or not, in which case we need 2 batches
389 r_fill_state.curr_batch->num_commands += 2;
390
391 r_fill_state.transform_extra_command_number_p1 = 0; // mark as sent
392 r_fill_state.extra_matrix_sent = true;
393
394 // the original mode should always be hardware transform ..
395 // test this assumption
396 //CRASH_COND(r_fill_state.orig_transform_mode != TM_NONE);
397 r_fill_state.transform_mode = r_fill_state.orig_transform_mode;
398
399 // do we need to restore anything else?
400 }
401 } else {
402 // end of previous different type batch, so start new default batch
403
404 // first consider whether there is a dirty extra matrix to send
405 if (r_fill_state.transform_extra_command_number_p1) {
406 // get which command the extra is in, and blank all the records as it no longer is stored CPU side
407 int extra_command = r_fill_state.transform_extra_command_number_p1 - 1; // plus 1 based
408 r_fill_state.transform_extra_command_number_p1 = 0;
409 r_fill_state.extra_matrix_sent = true;
410
411 // send the extra to the GPU in a batch
412 r_fill_state.curr_batch = _batch_request_new();
413 r_fill_state.curr_batch->type = Batch::BT_DEFAULT;
414 r_fill_state.curr_batch->first_command = extra_command;
415 r_fill_state.curr_batch->num_commands = 1;
416
417 // revert to the original transform mode
418 // e.g. go back to NONE if we were in hardware transform mode
419 r_fill_state.transform_mode = r_fill_state.orig_transform_mode;
420
421 // reset the original transform if we are going back to software mode,
422 // because the extra is now done on the GPU...
423 // (any subsequent extras are sent directly to the GPU, no deferring)
424 if (r_fill_state.orig_transform_mode != TM_NONE) {
425 r_fill_state.transform_combined = p_item.final_transform;
426 }
427
428 // can possibly combine batch with the next one in some cases
429 // this is more efficient than having an extra batch especially for the extra
430 if ((extra_command + 1) == p_command_num) {
431 r_fill_state.curr_batch->num_commands = 2;
432 return;
433 }
434 }
435
436 // start default batch
437 r_fill_state.curr_batch = _batch_request_new();
438 r_fill_state.curr_batch->type = Batch::BT_DEFAULT;
439 r_fill_state.curr_batch->first_command = p_command_num;
440 r_fill_state.curr_batch->num_commands = 1;
441 }
442 }
443
_software_transform_vertex(BatchVector2 & r_v,const Transform2D & p_tr)444 inline void RasterizerCanvasGLES2::_software_transform_vertex(BatchVector2 &r_v, const Transform2D &p_tr) const {
445 Vector2 vc(r_v.x, r_v.y);
446 vc = p_tr.xform(vc);
447 r_v.set(vc);
448 }
449
_software_transform_vertex(Vector2 & r_v,const Transform2D & p_tr)450 inline void RasterizerCanvasGLES2::_software_transform_vertex(Vector2 &r_v, const Transform2D &p_tr) const {
451 r_v = p_tr.xform(r_v);
452 }
453
_find_transform_mode(const Transform2D & p_tr)454 inline RasterizerCanvasGLES2::TransformMode RasterizerCanvasGLES2::_find_transform_mode(const Transform2D &p_tr) const {
455 // decided whether to do translate only for software transform
456 if ((p_tr.elements[0].x == 1.0) &&
457 (p_tr.elements[0].y == 0.0) &&
458 (p_tr.elements[1].x == 0.0) &&
459 (p_tr.elements[1].y == 1.0)) {
460 return TM_TRANSLATE;
461 }
462
463 return TM_ALL;
464 }
465
_sort_items_match(const BSortItem & p_a,const BSortItem & p_b)466 inline bool RasterizerCanvasGLES2::_sort_items_match(const BSortItem &p_a, const BSortItem &p_b) const {
467 const Item *a = p_a.item;
468 const Item *b = p_b.item;
469
470 if (b->commands.size() != 1)
471 return false;
472
473 // tested outside function
474 // if (a->commands.size() != 1)
475 // return false;
476
477 const Item::Command &cb = *b->commands[0];
478 if (cb.type != Item::Command::TYPE_RECT)
479 return false;
480
481 const Item::Command &ca = *a->commands[0];
482 // tested outside function
483 // if (ca.type != Item::Command::TYPE_RECT)
484 // return false;
485
486 const Item::CommandRect *rect_a = static_cast<const Item::CommandRect *>(&ca);
487 const Item::CommandRect *rect_b = static_cast<const Item::CommandRect *>(&cb);
488
489 if (rect_a->texture != rect_b->texture)
490 return false;
491
492 return true;
493 }
494
495 #endif // RASTERIZERCANVASGLES2_H
496