Path: blob/master/servers/rendering/renderer_canvas_render.h
10277 views
/**************************************************************************/1/* renderer_canvas_render.h */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#pragma once3132#include "servers/rendering/rendering_method.h"33#include "servers/rendering_server.h"3435class RendererCanvasRender {36public:37static RendererCanvasRender *singleton;3839enum CanvasRectFlags {40CANVAS_RECT_REGION = 1,41CANVAS_RECT_TILE = 2,42CANVAS_RECT_FLIP_H = 4,43CANVAS_RECT_FLIP_V = 8,44CANVAS_RECT_TRANSPOSE = 16,45CANVAS_RECT_CLIP_UV = 32,46CANVAS_RECT_IS_GROUP = 64,47CANVAS_RECT_MSDF = 128,48CANVAS_RECT_LCD = 256,49};5051struct Light {52bool enabled : 1;53bool on_interpolate_transform_list : 1;54bool interpolated : 1;55Color color;56Transform2D xform_curr;57Transform2D xform_prev;58float height;59float energy;60float scale;61int z_min;62int z_max;63int layer_min;64int layer_max;65int item_mask;66int item_shadow_mask;67float directional_distance;68RS::CanvasLightMode mode;69RS::CanvasLightBlendMode blend_mode;70RID texture;71Vector2 texture_offset;72RID canvas;73bool use_shadow;74int shadow_buffer_size;75RS::CanvasLightShadowFilter shadow_filter;76Color shadow_color;77float shadow_smooth;7879//void *texture_cache; // implementation dependent80Rect2 rect_cache;81Transform2D xform_cache;82float radius_cache; //used for shadow far plane83//Projection shadow_matrix_cache;8485Transform2D light_shader_xform;86//Vector2 light_shader_pos;8788Light *shadows_next_ptr = nullptr;89Light *filter_next_ptr = nullptr;90Light *next_ptr = nullptr;91Light *directional_next_ptr = nullptr;9293RID light_internal;94uint64_t version;9596int32_t render_index_cache;9798Light() {99version = 0;100enabled = true;101on_interpolate_transform_list = false;102interpolated = true;103color = Color(1, 1, 1);104shadow_color = Color(0, 0, 0, 0);105height = 0;106z_min = -1024;107z_max = 1024;108layer_min = 0;109layer_max = 0;110item_mask = 1;111scale = 1.0;112energy = 1.0;113item_shadow_mask = 1;114mode = RS::CANVAS_LIGHT_MODE_POINT;115blend_mode = RS::CANVAS_LIGHT_BLEND_MODE_ADD;116// texture_cache = nullptr;117next_ptr = nullptr;118directional_next_ptr = nullptr;119filter_next_ptr = nullptr;120use_shadow = false;121shadow_buffer_size = 2048;122shadow_filter = RS::CANVAS_LIGHT_FILTER_NONE;123shadow_smooth = 0.0;124render_index_cache = -1;125directional_distance = 10000.0;126}127};128129//easier wrap to avoid mistakes130131typedef uint64_t PolygonID;132virtual PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), int p_count = -1) = 0;133virtual void free_polygon(PolygonID p_polygon) = 0;134135//also easier to wrap to avoid mistakes136struct Polygon {137PolygonID polygon_id;138Rect2 rect_cache;139140_FORCE_INLINE_ void create(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), int p_count = -1) {141ERR_FAIL_COND(polygon_id != 0);142int count = p_count < 0 ? p_indices.size() : p_count * 3;143ERR_FAIL_COND(count > p_indices.size());144{145uint32_t pc = p_points.size();146const Vector2 *v2 = p_points.ptr();147rect_cache.position = *v2;148for (uint32_t i = 1; i < pc; i++) {149rect_cache.expand_to(v2[i]);150}151}152polygon_id = singleton->request_polygon(p_indices, p_points, p_colors, p_uvs, p_bones, p_weights, count);153}154155_FORCE_INLINE_ Polygon() { polygon_id = 0; }156_FORCE_INLINE_ ~Polygon() {157if (polygon_id) {158singleton->free_polygon(polygon_id);159}160}161};162163//item164165struct Item {166//commands are allocated in blocks of 4k to improve performance167//and cache coherence.168//blocks always grow but never shrink.169170struct CommandBlock {171enum {172MAX_SIZE = 4096173};174uint32_t usage;175uint8_t *memory = nullptr;176};177178struct Command {179enum Type {180TYPE_RECT,181TYPE_NINEPATCH,182TYPE_POLYGON,183TYPE_PRIMITIVE,184TYPE_MESH,185TYPE_MULTIMESH,186TYPE_PARTICLES,187TYPE_TRANSFORM,188TYPE_CLIP_IGNORE,189TYPE_ANIMATION_SLICE,190};191192Command *next = nullptr;193Type type;194virtual ~Command() {}195};196197struct CommandRect : public Command {198Rect2 rect;199Color modulate;200Rect2 source;201uint16_t flags;202float outline;203float px_range;204205RID texture;206207CommandRect() {208flags = 0;209outline = 0;210px_range = 1;211type = TYPE_RECT;212}213};214215struct CommandNinePatch : public Command {216Rect2 rect;217Rect2 source;218float margin[4];219bool draw_center;220Color color;221RS::NinePatchAxisMode axis_x;222RS::NinePatchAxisMode axis_y;223224RID texture;225226CommandNinePatch() {227draw_center = true;228type = TYPE_NINEPATCH;229}230};231232struct CommandPolygon : public Command {233RS::PrimitiveType primitive;234Polygon polygon;235236RID texture;237238CommandPolygon() {239type = TYPE_POLYGON;240}241};242243struct CommandPrimitive : public Command {244uint32_t point_count;245Vector2 points[4];246Vector2 uvs[4];247Color colors[4];248249RID texture;250251CommandPrimitive() {252type = TYPE_PRIMITIVE;253}254};255256struct CommandMesh : public Command {257RID mesh;258Transform2D transform;259Color modulate;260RID mesh_instance;261262RID texture;263264CommandMesh() { type = TYPE_MESH; }265~CommandMesh();266};267268struct CommandMultiMesh : public Command {269RID multimesh;270271RID texture;272273CommandMultiMesh() { type = TYPE_MULTIMESH; }274};275276struct CommandParticles : public Command {277RID particles;278RID texture;279280CommandParticles() { type = TYPE_PARTICLES; }281};282283struct CommandTransform : public Command {284Transform2D xform;285CommandTransform() { type = TYPE_TRANSFORM; }286};287288struct CommandClipIgnore : public Command {289bool ignore;290CommandClipIgnore() {291type = TYPE_CLIP_IGNORE;292ignore = false;293}294};295296struct CommandAnimationSlice : public Command {297double animation_length = 0;298double slice_begin = 0;299double slice_end = 0;300double offset = 0;301302CommandAnimationSlice() {303type = TYPE_ANIMATION_SLICE;304}305};306307struct ViewportRender {308RenderingServer *owner = nullptr;309void *udata = nullptr;310Rect2 rect;311};312313// For interpolation we store the current local xform,314// and the previous xform from the previous tick.315Transform2D xform_curr;316Transform2D xform_prev;317318bool clip : 1;319bool visible : 1;320bool behind : 1;321bool update_when_visible : 1;322bool on_interpolate_transform_list : 1;323bool interpolated : 1;324bool use_identity_transform : 1;325326struct CanvasGroup {327RS::CanvasGroupMode mode;328bool fit_empty;329float fit_margin;330bool blur_mipmaps;331float clear_margin;332};333334CanvasGroup *canvas_group = nullptr;335bool use_canvas_group = false;336int light_mask;337int z_final;338339mutable bool custom_rect;340mutable bool rect_dirty;341mutable Rect2 rect;342RID material;343RID skeleton;344345int32_t instance_allocated_shader_uniforms_offset = -1;346347Item *next = nullptr;348349struct CopyBackBuffer {350Rect2 rect;351Rect2 screen_rect;352bool full;353};354CopyBackBuffer *copy_back_buffer = nullptr;355356Color final_modulate;357Transform2D final_transform;358Rect2 final_clip_rect;359Item *final_clip_owner = nullptr;360Item *material_owner = nullptr;361Item *canvas_group_owner = nullptr;362ViewportRender *vp_render = nullptr;363bool distance_field;364bool light_masked;365bool repeat_source;366Point2 repeat_size;367int repeat_times = 1;368Item *repeat_source_item = nullptr;369370Rect2 global_rect_cache;371372const Rect2 &get_rect() const;373374Command *commands = nullptr;375Command *last_command = nullptr;376Vector<CommandBlock> blocks;377uint32_t current_block;378#ifdef DEBUG_ENABLED379mutable double debug_redraw_time = 0;380#endif381382template <typename T>383T *alloc_command() {384T *command = nullptr;385if (commands == nullptr) {386// As the most common use case of canvas items is to387// use only one command, the first is done with it's388// own allocation. The rest of them use blocks.389command = memnew(T);390command->next = nullptr;391commands = command;392last_command = command;393} else {394//Subsequent commands go into a block.395396while (true) {397if (unlikely(current_block == (uint32_t)blocks.size())) {398// If we need more blocks, we allocate them399// (they won't be freed until this CanvasItem is400// deleted, though).401CommandBlock cb;402cb.memory = (uint8_t *)memalloc(CommandBlock::MAX_SIZE);403cb.usage = 0;404blocks.push_back(cb);405}406407CommandBlock *c = &blocks.write[current_block];408size_t space_left = CommandBlock::MAX_SIZE - c->usage;409if (space_left < sizeof(T)) {410current_block++;411continue;412}413414//allocate block and add to the linked list415void *memory = c->memory + c->usage;416command = memnew_placement(memory, T);417command->next = nullptr;418last_command->next = command;419last_command = command;420c->usage += sizeof(T);421break;422}423}424425rect_dirty = true;426return command;427}428429void clear() {430// The first one is always allocated on heap431// the rest go in the blocks432Command *c = commands;433while (c) {434Command *n = c->next;435if (c == commands) {436memdelete(commands);437commands = nullptr;438} else {439c->~Command();440}441c = n;442}443{444uint32_t cbc = MIN((current_block + 1), (uint32_t)blocks.size());445CommandBlock *blockptr = blocks.ptrw();446for (uint32_t i = 0; i < cbc; i++) {447blockptr[i].usage = 0;448}449}450451last_command = nullptr;452commands = nullptr;453current_block = 0;454clip = false;455rect_dirty = true;456final_clip_owner = nullptr;457material_owner = nullptr;458light_masked = false;459}460461RS::CanvasItemTextureFilter texture_filter;462RS::CanvasItemTextureRepeat texture_repeat;463464Item() {465commands = nullptr;466last_command = nullptr;467current_block = 0;468light_mask = 1;469vp_render = nullptr;470next = nullptr;471final_clip_owner = nullptr;472canvas_group_owner = nullptr;473clip = false;474final_modulate = Color(1, 1, 1, 1);475visible = true;476rect_dirty = true;477custom_rect = false;478behind = false;479material_owner = nullptr;480copy_back_buffer = nullptr;481distance_field = false;482light_masked = false;483update_when_visible = false;484z_final = 0;485texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;486texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;487repeat_source = false;488on_interpolate_transform_list = false;489interpolated = true;490use_identity_transform = false;491}492virtual ~Item() {493clear();494for (int i = 0; i < blocks.size(); i++) {495memfree(blocks[i].memory);496}497if (copy_back_buffer) {498memdelete(copy_back_buffer);499}500}501};502503virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used, RenderingMethod::RenderInfo *r_render_info = nullptr) = 0;504505struct LightOccluderInstance {506bool enabled : 1;507bool on_interpolate_transform_list : 1;508bool interpolated : 1;509RID canvas;510RID polygon;511RID occluder;512Rect2 aabb_cache;513Transform2D xform_curr;514Transform2D xform_prev;515Transform2D xform_cache;516int light_mask;517bool sdf_collision;518RS::CanvasOccluderPolygonCullMode cull_cache;519520LightOccluderInstance *next = nullptr;521522LightOccluderInstance() {523enabled = true;524on_interpolate_transform_list = false;525interpolated = false;526sdf_collision = false;527next = nullptr;528light_mask = 1;529cull_cache = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;530}531};532533virtual RID light_create() = 0;534virtual void light_set_texture(RID p_rid, RID p_texture) = 0;535virtual void light_set_use_shadow(RID p_rid, bool p_enable) = 0;536virtual void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, const Rect2 &p_light_rect) = 0;537virtual void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) = 0;538539virtual void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) = 0;540541virtual RID occluder_polygon_create() = 0;542virtual void occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) = 0;543virtual void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) = 0;544virtual void set_shadow_texture_size(int p_size) = 0;545546virtual bool free(RID p_rid) = 0;547virtual void update() = 0;548549virtual void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) = 0;550virtual uint32_t get_pipeline_compilations(RS::PipelineSource p_source) = 0;551552RendererCanvasRender() {553ERR_FAIL_COND_MSG(singleton != nullptr, "A RendererCanvasRender singleton already exists.");554singleton = this;555}556virtual ~RendererCanvasRender() {557singleton = nullptr;558}559};560561562