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