Unified GLES2 / GLES3 Batching
Batching is mostly separated into a common template which can be used with multiple backends (GLES2 and GLES3 here). Only necessary specifics are in the backend files. Batching is extended to cover more primitives.
This commit is contained in:
parent
2dc8ed2925
commit
c2290dbedd
28 changed files with 7314 additions and 4484 deletions
|
@ -1062,6 +1062,10 @@
|
||||||
<member name="rendering/limits/time/time_rollover_secs" type="float" setter="" getter="" default="3600">
|
<member name="rendering/limits/time/time_rollover_secs" type="float" setter="" getter="" default="3600">
|
||||||
Shaders have a time variable that constantly increases. At some point, it needs to be rolled back to zero to avoid precision errors on shader animations. This setting specifies when (in seconds).
|
Shaders have a time variable that constantly increases. At some point, it needs to be rolled back to zero to avoid precision errors on shader animations. This setting specifies when (in seconds).
|
||||||
</member>
|
</member>
|
||||||
|
<member name="rendering/quality/2d/ninepatch_mode" type="int" setter="" getter="" default="0">
|
||||||
|
Choose between default mode where corner scalings are preserved matching the artwork, and scaling mode.
|
||||||
|
Not available in GLES3 when [member rendering/batching/options/use_batching] is off.
|
||||||
|
</member>
|
||||||
<member name="rendering/quality/2d/use_nvidia_rect_flicker_workaround" type="bool" setter="" getter="" default="false">
|
<member name="rendering/quality/2d/use_nvidia_rect_flicker_workaround" type="bool" setter="" getter="" default="false">
|
||||||
Some NVIDIA GPU drivers have a bug which produces flickering issues for the [code]draw_rect[/code] method, especially as used in [TileMap]. Refer to [url=https://github.com/godotengine/godot/issues/9913]GitHub issue 9913[/url] for details.
|
Some NVIDIA GPU drivers have a bug which produces flickering issues for the [code]draw_rect[/code] method, especially as used in [TileMap]. Refer to [url=https://github.com/godotengine/godot/issues/9913]GitHub issue 9913[/url] for details.
|
||||||
If [code]true[/code], this option enables a "safe" code path for such NVIDIA GPUs at the cost of performance. This option affects GLES2 and GLES3 rendering, but only on desktop platforms.
|
If [code]true[/code], this option enables a "safe" code path for such NVIDIA GPUs at the cost of performance. This option affects GLES2 and GLES3 rendering, but only on desktop platforms.
|
||||||
|
@ -1070,6 +1074,10 @@
|
||||||
If [code]true[/code], forces snapping of polygons to pixels in 2D rendering. May help in some pixel art styles.
|
If [code]true[/code], forces snapping of polygons to pixels in 2D rendering. May help in some pixel art styles.
|
||||||
Consider using the project setting [member rendering/batching/precision/uv_contract] to prevent artifacts.
|
Consider using the project setting [member rendering/batching/precision/uv_contract] to prevent artifacts.
|
||||||
</member>
|
</member>
|
||||||
|
<member name="rendering/quality/2d/use_software_skinning" type="bool" setter="" getter="" default="true">
|
||||||
|
If [code]true[/code], performs 2d skinning on the CPU rather than the GPU. This provides greater compatibility with a wide range of hardware, and also may be faster in some circumstances.
|
||||||
|
Currently only available when [member rendering/batching/options/use_batching] is active.
|
||||||
|
</member>
|
||||||
<member name="rendering/quality/depth/hdr" type="bool" setter="" getter="" default="true">
|
<member name="rendering/quality/depth/hdr" type="bool" setter="" getter="" default="true">
|
||||||
If [code]true[/code], allocates the main framebuffer with high dynamic range. High dynamic range allows the use of [Color] values greater than 1.
|
If [code]true[/code], allocates the main framebuffer with high dynamic range. High dynamic range allows the use of [Color] values greater than 1.
|
||||||
[b]Note:[/b] Only available on the GLES3 backend.
|
[b]Note:[/b] Only available on the GLES3 backend.
|
||||||
|
|
|
@ -26,6 +26,7 @@ SConscript("winmidi/SCsub")
|
||||||
if env["platform"] != "server":
|
if env["platform"] != "server":
|
||||||
SConscript("gles3/SCsub")
|
SConscript("gles3/SCsub")
|
||||||
SConscript("gles2/SCsub")
|
SConscript("gles2/SCsub")
|
||||||
|
SConscript("gles_common/SCsub")
|
||||||
SConscript("gl_context/SCsub")
|
SConscript("gl_context/SCsub")
|
||||||
else:
|
else:
|
||||||
SConscript("dummy/SCsub")
|
SConscript("dummy/SCsub")
|
||||||
|
|
|
@ -56,7 +56,12 @@ void RasterizerCanvasBaseGLES2::canvas_begin() {
|
||||||
|
|
||||||
// always start with light_angle unset
|
// always start with light_angle unset
|
||||||
state.using_light_angle = false;
|
state.using_light_angle = false;
|
||||||
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_LIGHT_ANGLE, false);
|
state.using_large_vertex = false;
|
||||||
|
state.using_modulate = false;
|
||||||
|
|
||||||
|
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_ATTRIB_LIGHT_ANGLE, false);
|
||||||
|
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_ATTRIB_MODULATE, false);
|
||||||
|
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_ATTRIB_LARGE_VERTEX, false);
|
||||||
state.canvas_shader.bind();
|
state.canvas_shader.bind();
|
||||||
|
|
||||||
int viewport_x, viewport_y, viewport_width, viewport_height;
|
int viewport_x, viewport_y, viewport_width, viewport_height;
|
||||||
|
@ -160,13 +165,23 @@ void RasterizerCanvasBaseGLES2::draw_generic_textured_rect(const Rect2 &p_rect,
|
||||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerCanvasBaseGLES2::_set_texture_rect_mode(bool p_texture_rect, bool p_light_angle) {
|
void RasterizerCanvasBaseGLES2::_set_texture_rect_mode(bool p_texture_rect, bool p_light_angle, bool p_modulate, bool p_large_vertex) {
|
||||||
// always set this directly (this could be state checked)
|
// always set this directly (this could be state checked)
|
||||||
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, p_texture_rect);
|
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, p_texture_rect);
|
||||||
|
|
||||||
if (state.using_light_angle != p_light_angle) {
|
if (state.using_light_angle != p_light_angle) {
|
||||||
state.using_light_angle = p_light_angle;
|
state.using_light_angle = p_light_angle;
|
||||||
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_LIGHT_ANGLE, p_light_angle);
|
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_ATTRIB_LIGHT_ANGLE, p_light_angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.using_modulate != p_modulate) {
|
||||||
|
state.using_modulate = p_modulate;
|
||||||
|
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_ATTRIB_MODULATE, p_modulate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.using_large_vertex != p_large_vertex) {
|
||||||
|
state.using_large_vertex = p_large_vertex;
|
||||||
|
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_ATTRIB_LARGE_VERTEX, p_large_vertex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1024,10 +1039,4 @@ void RasterizerCanvasBaseGLES2::finalize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
RasterizerCanvasBaseGLES2::RasterizerCanvasBaseGLES2() {
|
RasterizerCanvasBaseGLES2::RasterizerCanvasBaseGLES2() {
|
||||||
#ifdef GLES_OVER_GL
|
|
||||||
use_nvidia_rect_workaround = GLOBAL_GET("rendering/quality/2d/use_nvidia_rect_flicker_workaround");
|
|
||||||
#else
|
|
||||||
// Not needed (a priori) on GLES devices
|
|
||||||
use_nvidia_rect_workaround = false;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,13 +31,14 @@
|
||||||
#ifndef RASTERIZERCANVASBASEGLES2_H
|
#ifndef RASTERIZERCANVASBASEGLES2_H
|
||||||
#define RASTERIZERCANVASBASEGLES2_H
|
#define RASTERIZERCANVASBASEGLES2_H
|
||||||
|
|
||||||
#include "rasterizer_array_gles2.h"
|
#include "drivers/gles_common/rasterizer_array.h"
|
||||||
#include "rasterizer_storage_gles2.h"
|
#include "rasterizer_storage_gles2.h"
|
||||||
#include "servers/visual/rasterizer.h"
|
#include "servers/visual/rasterizer.h"
|
||||||
|
|
||||||
#include "shaders/canvas.glsl.gen.h"
|
#include "shaders/canvas.glsl.gen.h"
|
||||||
#include "shaders/lens_distorted.glsl.gen.h"
|
#include "shaders/lens_distorted.glsl.gen.h"
|
||||||
|
|
||||||
|
#include "drivers/gles_common/rasterizer_storage_common.h"
|
||||||
#include "shaders/canvas_shadow.glsl.gen.h"
|
#include "shaders/canvas_shadow.glsl.gen.h"
|
||||||
|
|
||||||
class RasterizerCanvasBaseGLES2 : public RasterizerCanvas {
|
class RasterizerCanvasBaseGLES2 : public RasterizerCanvas {
|
||||||
|
@ -77,7 +78,11 @@ public:
|
||||||
LensDistortedShaderGLES2 lens_shader;
|
LensDistortedShaderGLES2 lens_shader;
|
||||||
|
|
||||||
bool using_texture_rect;
|
bool using_texture_rect;
|
||||||
|
|
||||||
bool using_light_angle;
|
bool using_light_angle;
|
||||||
|
bool using_modulate;
|
||||||
|
bool using_large_vertex;
|
||||||
|
|
||||||
bool using_ninepatch;
|
bool using_ninepatch;
|
||||||
bool using_skeleton;
|
bool using_skeleton;
|
||||||
|
|
||||||
|
@ -102,8 +107,6 @@ public:
|
||||||
|
|
||||||
RasterizerStorageGLES2 *storage;
|
RasterizerStorageGLES2 *storage;
|
||||||
|
|
||||||
bool use_nvidia_rect_workaround;
|
|
||||||
|
|
||||||
void _set_uniforms();
|
void _set_uniforms();
|
||||||
|
|
||||||
virtual RID light_internal_create();
|
virtual RID light_internal_create();
|
||||||
|
@ -131,7 +134,7 @@ public:
|
||||||
virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow);
|
virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow);
|
||||||
|
|
||||||
RasterizerStorageGLES2::Texture *_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map);
|
RasterizerStorageGLES2::Texture *_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map);
|
||||||
void _set_texture_rect_mode(bool p_texture_rect, bool p_light_angle = false);
|
void _set_texture_rect_mode(bool p_texture_rect, bool p_light_angle = false, bool p_modulate = false, bool p_large_vertex = false);
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
void finalize();
|
void finalize();
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -31,297 +31,14 @@
|
||||||
#ifndef RASTERIZERCANVASGLES2_H
|
#ifndef RASTERIZERCANVASGLES2_H
|
||||||
#define RASTERIZERCANVASGLES2_H
|
#define RASTERIZERCANVASGLES2_H
|
||||||
|
|
||||||
|
#include "drivers/gles_common/rasterizer_canvas_batcher.h"
|
||||||
#include "rasterizer_canvas_base_gles2.h"
|
#include "rasterizer_canvas_base_gles2.h"
|
||||||
|
|
||||||
class RasterizerSceneGLES2;
|
class RasterizerSceneGLES2;
|
||||||
|
|
||||||
class RasterizerCanvasGLES2 : public RasterizerCanvasBaseGLES2 {
|
class RasterizerCanvasGLES2 : public RasterizerCanvasBaseGLES2, public RasterizerCanvasBatcher<RasterizerCanvasGLES2, RasterizerStorageGLES2> {
|
||||||
|
|
||||||
// used to determine whether we use hardware transform (none)
|
friend class RasterizerCanvasBatcher<RasterizerCanvasGLES2, RasterizerStorageGLES2>;
|
||||||
// software transform all verts, or software transform just a translate
|
|
||||||
// (no rotate or scale)
|
|
||||||
enum TransformMode {
|
|
||||||
TM_NONE,
|
|
||||||
TM_ALL,
|
|
||||||
TM_TRANSLATE,
|
|
||||||
};
|
|
||||||
|
|
||||||
// pod versions of vector and color and RID, need to be 32 bit for vertex format
|
|
||||||
struct BatchVector2 {
|
|
||||||
float x, y;
|
|
||||||
void set(const Vector2 &p_o) {
|
|
||||||
x = p_o.x;
|
|
||||||
y = p_o.y;
|
|
||||||
}
|
|
||||||
void to(Vector2 &r_o) const {
|
|
||||||
r_o.x = x;
|
|
||||||
r_o.y = y;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BatchColor {
|
|
||||||
float r, g, b, a;
|
|
||||||
void set(const Color &p_c) {
|
|
||||||
r = p_c.r;
|
|
||||||
g = p_c.g;
|
|
||||||
b = p_c.b;
|
|
||||||
a = p_c.a;
|
|
||||||
}
|
|
||||||
bool operator==(const BatchColor &p_c) const {
|
|
||||||
return (r == p_c.r) && (g == p_c.g) && (b == p_c.b) && (a == p_c.a);
|
|
||||||
}
|
|
||||||
bool operator!=(const BatchColor &p_c) const { return (*this == p_c) == false; }
|
|
||||||
bool equals(const Color &p_c) const {
|
|
||||||
return (r == p_c.r) && (g == p_c.g) && (b == p_c.b) && (a == p_c.a);
|
|
||||||
}
|
|
||||||
const float *get_data() const { return &r; }
|
|
||||||
String to_string() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BatchVertex {
|
|
||||||
// must be 32 bit pod
|
|
||||||
BatchVector2 pos;
|
|
||||||
BatchVector2 uv;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BatchVertexColored : public BatchVertex {
|
|
||||||
// must be 32 bit pod
|
|
||||||
BatchColor col;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BatchVertexLightAngled : public BatchVertexColored {
|
|
||||||
// must be pod
|
|
||||||
float light_angle;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Batch {
|
|
||||||
enum CommandType : uint32_t {
|
|
||||||
BT_DEFAULT,
|
|
||||||
BT_RECT,
|
|
||||||
};
|
|
||||||
|
|
||||||
CommandType type;
|
|
||||||
uint32_t first_command; // also item reference number
|
|
||||||
uint32_t num_commands;
|
|
||||||
uint32_t first_quad;
|
|
||||||
uint32_t batch_texture_id;
|
|
||||||
BatchColor color;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BatchTex {
|
|
||||||
enum TileMode : uint32_t {
|
|
||||||
TILE_OFF,
|
|
||||||
TILE_NORMAL,
|
|
||||||
TILE_FORCE_REPEAT,
|
|
||||||
};
|
|
||||||
RID RID_texture;
|
|
||||||
RID RID_normal;
|
|
||||||
TileMode tile_mode;
|
|
||||||
BatchVector2 tex_pixel_size;
|
|
||||||
uint32_t flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
// items in a list to be sorted prior to joining
|
|
||||||
struct BSortItem {
|
|
||||||
// have a function to keep as pod, rather than operator
|
|
||||||
void assign(const BSortItem &o) {
|
|
||||||
item = o.item;
|
|
||||||
z_index = o.z_index;
|
|
||||||
}
|
|
||||||
Item *item;
|
|
||||||
int z_index;
|
|
||||||
};
|
|
||||||
|
|
||||||
// batch item may represent 1 or more items
|
|
||||||
struct BItemJoined {
|
|
||||||
uint32_t first_item_ref;
|
|
||||||
uint32_t num_item_refs;
|
|
||||||
|
|
||||||
Rect2 bounding_rect;
|
|
||||||
|
|
||||||
// note the z_index may only be correct for the first of the joined item references
|
|
||||||
// this has implications for light culling with z ranged lights.
|
|
||||||
int16_t z_index;
|
|
||||||
|
|
||||||
// these are defined in RasterizerStorageGLES2::Shader::CanvasItem::BatchFlags
|
|
||||||
uint16_t flags;
|
|
||||||
|
|
||||||
// we are always splitting items with lots of commands,
|
|
||||||
// and items with unhandled primitives (default)
|
|
||||||
bool use_hardware_transform() const { return num_item_refs == 1; }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BItemRef {
|
|
||||||
Item *item;
|
|
||||||
Color final_modulate;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BLightRegion {
|
|
||||||
void reset() {
|
|
||||||
light_bitfield = 0;
|
|
||||||
shadow_bitfield = 0;
|
|
||||||
too_many_lights = false;
|
|
||||||
}
|
|
||||||
uint64_t light_bitfield;
|
|
||||||
uint64_t shadow_bitfield;
|
|
||||||
bool too_many_lights; // we can only do light region optimization if there are 64 or less lights
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BatchData {
|
|
||||||
BatchData();
|
|
||||||
void reset_flush() {
|
|
||||||
batches.reset();
|
|
||||||
batch_textures.reset();
|
|
||||||
|
|
||||||
vertices.reset();
|
|
||||||
light_angles.reset();
|
|
||||||
|
|
||||||
total_quads = 0;
|
|
||||||
total_color_changes = 0;
|
|
||||||
use_light_angles = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint gl_vertex_buffer;
|
|
||||||
GLuint gl_index_buffer;
|
|
||||||
|
|
||||||
uint32_t max_quads;
|
|
||||||
uint32_t vertex_buffer_size_units;
|
|
||||||
uint32_t vertex_buffer_size_bytes;
|
|
||||||
uint32_t index_buffer_size_units;
|
|
||||||
uint32_t index_buffer_size_bytes;
|
|
||||||
|
|
||||||
// small vertex FVF type - pos and UV.
|
|
||||||
// This will always be written to initially, but can be translated
|
|
||||||
// to larger FVFs if necessary.
|
|
||||||
RasterizerArrayGLES2<BatchVertex> vertices;
|
|
||||||
|
|
||||||
// extra data which can be stored during prefilling, for later translation to larger FVFs
|
|
||||||
RasterizerArrayGLES2<float> light_angles;
|
|
||||||
|
|
||||||
// instead of having a different buffer for each vertex FVF type
|
|
||||||
// we have a special array big enough for the biggest FVF
|
|
||||||
// which can have a changeable unit size, and reuse it.
|
|
||||||
RasterizerUnitArrayGLES2 unit_vertices;
|
|
||||||
|
|
||||||
RasterizerArrayGLES2<Batch> batches;
|
|
||||||
RasterizerArrayGLES2<Batch> batches_temp; // used for translating to colored vertex batches
|
|
||||||
RasterizerArray_non_pod_GLES2<BatchTex> batch_textures; // the only reason this is non-POD is because of RIDs
|
|
||||||
|
|
||||||
// flexible vertex format.
|
|
||||||
// all verts have pos and UV.
|
|
||||||
// some have color, some light angles etc.
|
|
||||||
bool use_colored_vertices;
|
|
||||||
bool use_light_angles;
|
|
||||||
|
|
||||||
RasterizerArrayGLES2<BItemJoined> items_joined;
|
|
||||||
RasterizerArrayGLES2<BItemRef> item_refs;
|
|
||||||
|
|
||||||
// items are sorted prior to joining
|
|
||||||
RasterizerArrayGLES2<BSortItem> sort_items;
|
|
||||||
|
|
||||||
// counts
|
|
||||||
int total_quads;
|
|
||||||
|
|
||||||
// we keep a record of how many color changes caused new batches
|
|
||||||
// if the colors are causing an excessive number of batches, we switch
|
|
||||||
// to alternate batching method and add color to the vertex format.
|
|
||||||
int total_color_changes;
|
|
||||||
|
|
||||||
// if the shader is using MODULATE, we prevent baking color so the final_modulate can
|
|
||||||
// be read in the shader.
|
|
||||||
// if the shader is reading VERTEX, we prevent baking vertex positions with extra matrices etc
|
|
||||||
// to prevent the read position being incorrect.
|
|
||||||
// These flags are defined in RasterizerStorageGLES2::Shader::CanvasItem::BatchFlags
|
|
||||||
uint32_t joined_item_batch_flags;
|
|
||||||
|
|
||||||
// measured in pixels, recalculated each frame
|
|
||||||
float scissor_threshold_area;
|
|
||||||
|
|
||||||
// diagnose this frame, every nTh frame when settings_diagnose_frame is on
|
|
||||||
bool diagnose_frame;
|
|
||||||
String frame_string;
|
|
||||||
uint32_t next_diagnose_tick;
|
|
||||||
uint64_t diagnose_frame_number;
|
|
||||||
|
|
||||||
// whether to join items across z_indices - this can interfere with z ranged lights,
|
|
||||||
// so has to be disabled in some circumstances
|
|
||||||
bool join_across_z_indices;
|
|
||||||
|
|
||||||
// global settings
|
|
||||||
bool settings_use_batching; // the current use_batching (affected by flash)
|
|
||||||
bool settings_use_batching_original_choice; // the choice entered in project settings
|
|
||||||
bool settings_flash_batching; // for regression testing, flash between non-batched and batched renderer
|
|
||||||
bool settings_diagnose_frame; // print out batches to help optimize / regression test
|
|
||||||
int settings_max_join_item_commands;
|
|
||||||
float settings_colored_vertex_format_threshold;
|
|
||||||
int settings_batch_buffer_num_verts;
|
|
||||||
bool settings_scissor_lights;
|
|
||||||
float settings_scissor_threshold; // 0.0 to 1.0
|
|
||||||
int settings_item_reordering_lookahead;
|
|
||||||
bool settings_use_single_rect_fallback;
|
|
||||||
int settings_light_max_join_items;
|
|
||||||
|
|
||||||
// uv contraction
|
|
||||||
bool settings_uv_contract;
|
|
||||||
float settings_uv_contract_amount;
|
|
||||||
|
|
||||||
// only done on diagnose frame
|
|
||||||
void reset_stats() {
|
|
||||||
stats_items_sorted = 0;
|
|
||||||
stats_light_items_joined = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// frame stats (just for monitoring and debugging)
|
|
||||||
int stats_items_sorted;
|
|
||||||
int stats_light_items_joined;
|
|
||||||
} bdata;
|
|
||||||
|
|
||||||
struct RenderItemState {
|
|
||||||
RenderItemState() { reset(); }
|
|
||||||
void reset();
|
|
||||||
Item *current_clip;
|
|
||||||
RasterizerStorageGLES2::Shader *shader_cache;
|
|
||||||
bool rebind_shader;
|
|
||||||
bool prev_use_skeleton;
|
|
||||||
int last_blend_mode;
|
|
||||||
RID canvas_last_material;
|
|
||||||
Color final_modulate;
|
|
||||||
|
|
||||||
// used for joining items only
|
|
||||||
BItemJoined *joined_item;
|
|
||||||
bool join_batch_break;
|
|
||||||
BLightRegion light_region;
|
|
||||||
|
|
||||||
// 'item group' is data over a single call to canvas_render_items
|
|
||||||
int item_group_z;
|
|
||||||
Color item_group_modulate;
|
|
||||||
Light *item_group_light;
|
|
||||||
Transform2D item_group_base_transform;
|
|
||||||
} _render_item_state;
|
|
||||||
|
|
||||||
struct FillState {
|
|
||||||
void reset() {
|
|
||||||
// don't reset members that need to be preserved after flushing
|
|
||||||
// half way through a list of commands
|
|
||||||
curr_batch = 0;
|
|
||||||
batch_tex_id = -1;
|
|
||||||
texpixel_size = Vector2(1, 1);
|
|
||||||
contract_uvs = false;
|
|
||||||
}
|
|
||||||
Batch *curr_batch;
|
|
||||||
int batch_tex_id;
|
|
||||||
bool use_hardware_transform;
|
|
||||||
bool contract_uvs;
|
|
||||||
Vector2 texpixel_size;
|
|
||||||
Color final_modulate;
|
|
||||||
TransformMode transform_mode;
|
|
||||||
TransformMode orig_transform_mode;
|
|
||||||
|
|
||||||
// support for extra matrices
|
|
||||||
bool extra_matrix_sent; // whether sent on this item (in which case software transform can't be used untl end of item)
|
|
||||||
int transform_extra_command_number_p1; // plus one to allow fast checking against zero
|
|
||||||
Transform2D transform_combined; // final * extra
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void canvas_render_items_begin(const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform);
|
virtual void canvas_render_items_begin(const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform);
|
||||||
|
@ -332,598 +49,27 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// legacy codepath .. to remove after testing
|
// legacy codepath .. to remove after testing
|
||||||
void _canvas_render_item(Item *p_ci, RenderItemState &r_ris);
|
void _legacy_canvas_render_item(Item *p_ci, RenderItemState &r_ris);
|
||||||
void _canvas_item_render_commands(Item *p_item, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES2::Material *p_material);
|
|
||||||
|
|
||||||
// high level batch funcs
|
// high level batch funcs
|
||||||
void canvas_render_items_implementation(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform);
|
void canvas_render_items_implementation(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform);
|
||||||
void render_joined_item(const BItemJoined &p_bij, RenderItemState &r_ris);
|
void render_joined_item(const BItemJoined &p_bij, RenderItemState &r_ris);
|
||||||
void record_items(Item *p_item_list, int p_z);
|
|
||||||
void join_items(Item *p_item_list, int p_z);
|
|
||||||
void join_sorted_items();
|
|
||||||
bool try_join_item(Item *p_ci, RenderItemState &r_ris, bool &r_batch_break);
|
bool try_join_item(Item *p_ci, RenderItemState &r_ris, bool &r_batch_break);
|
||||||
void render_joined_item_commands(const BItemJoined &p_bij, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES2::Material *p_material, bool p_lit);
|
|
||||||
void render_batches(Item::Command *const *p_commands, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES2::Material *p_material);
|
void render_batches(Item::Command *const *p_commands, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES2::Material *p_material);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
void flush_render_batches(Item *p_first_item, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES2::Material *p_material);
|
|
||||||
|
|
||||||
// low level batch funcs
|
// low level batch funcs
|
||||||
int _batch_find_or_create_tex(const RID &p_texture, const RID &p_normal, bool p_tile, int p_previous_match);
|
|
||||||
RasterizerStorageGLES2::Texture *_get_canvas_texture(const RID &p_texture) const;
|
|
||||||
void _batch_upload_buffers();
|
void _batch_upload_buffers();
|
||||||
void _batch_render_rects(const Batch &p_batch, RasterizerStorageGLES2::Material *p_material);
|
void _batch_render_rects(const Batch &p_batch, RasterizerStorageGLES2::Material *p_material);
|
||||||
BatchVertex *_batch_vertex_request_new() { return bdata.vertices.request(); }
|
void _batch_render_polys(const Batch &p_batch, RasterizerStorageGLES2::Material *p_material);
|
||||||
Batch *_batch_request_new(bool p_blank = true);
|
void _batch_render_lines(const Batch &p_batch, RasterizerStorageGLES2::Material *p_material, bool p_anti_alias);
|
||||||
|
|
||||||
bool _detect_batch_break(Item *p_ci);
|
// funcs used from rasterizer_canvas_batcher template
|
||||||
void _software_transform_vertex(BatchVector2 &r_v, const Transform2D &p_tr) const;
|
void gl_enable_scissor(int p_x, int p_y, int p_width, int p_height) const;
|
||||||
void _software_transform_vertex(Vector2 &r_v, const Transform2D &p_tr) const;
|
void gl_disable_scissor() const;
|
||||||
TransformMode _find_transform_mode(const Transform2D &p_tr) const;
|
|
||||||
void _prefill_default_batch(FillState &r_fill_state, int p_command_num, const Item &p_item);
|
|
||||||
|
|
||||||
// sorting
|
|
||||||
void sort_items();
|
|
||||||
bool sort_items_from(int p_start);
|
|
||||||
bool _sort_items_match(const BSortItem &p_a, const BSortItem &p_b) const;
|
|
||||||
|
|
||||||
// light scissoring
|
|
||||||
bool _light_find_intersection(const Rect2 &p_item_rect, const Transform2D &p_light_xform, const Rect2 &p_light_rect, Rect2 &r_cliprect) const;
|
|
||||||
bool _light_scissor_begin(const Rect2 &p_item_rect, const Transform2D &p_light_xform, const Rect2 &p_light_rect) const;
|
|
||||||
void _calculate_scissor_threshold_area();
|
|
||||||
|
|
||||||
// no need to compile these in in release, they are unneeded outside the editor and only add to executable size
|
|
||||||
#ifdef DEBUG_ENABLED
|
|
||||||
void diagnose_batches(Item::Command *const *p_commands);
|
|
||||||
String get_command_type_string(const Item::Command &p_command) const;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void initialize();
|
void initialize();
|
||||||
RasterizerCanvasGLES2();
|
RasterizerCanvasGLES2();
|
||||||
|
|
||||||
private:
|
|
||||||
template <bool SEND_LIGHT_ANGLES>
|
|
||||||
bool prefill_rect(Item::CommandRect *rect, FillState &r_fill_state, int &r_command_start, int command_num, int command_count, Item::Command *const *commands, Item *p_item, bool multiply_final_modulate);
|
|
||||||
|
|
||||||
template <class BATCH_VERTEX_TYPE, bool INCLUDE_LIGHT_ANGLES>
|
|
||||||
void _translate_batches_to_larger_FVF();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default batches will not occur in software transform only items
|
|
||||||
// EXCEPT IN THE CASE OF SINGLE RECTS (and this may well not occur, check the logic in prefill_join_item TYPE_RECT)
|
|
||||||
// but can occur where transform commands have been sent during hardware batch
|
|
||||||
inline void RasterizerCanvasGLES2::_prefill_default_batch(FillState &r_fill_state, int p_command_num, const Item &p_item) {
|
|
||||||
if (r_fill_state.curr_batch->type == Batch::BT_DEFAULT) {
|
|
||||||
// don't need to flush an extra transform command?
|
|
||||||
if (!r_fill_state.transform_extra_command_number_p1) {
|
|
||||||
// another default command, just add to the existing batch
|
|
||||||
r_fill_state.curr_batch->num_commands++;
|
|
||||||
} else {
|
|
||||||
#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED)
|
|
||||||
if (r_fill_state.transform_extra_command_number_p1 != p_command_num) {
|
|
||||||
WARN_PRINT_ONCE("_prefill_default_batch : transform_extra_command_number_p1 != p_command_num");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// if the first member of the batch is a transform we have to be careful
|
|
||||||
if (!r_fill_state.curr_batch->num_commands) {
|
|
||||||
// there can be leading useless extra transforms (sometimes happens with debug collision polys)
|
|
||||||
// we need to rejig the first_command for the first useful transform
|
|
||||||
r_fill_state.curr_batch->first_command += r_fill_state.transform_extra_command_number_p1 - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we do have a pending extra transform command to flush
|
|
||||||
// either the extra transform is in the prior command, or not, in which case we need 2 batches
|
|
||||||
r_fill_state.curr_batch->num_commands += 2;
|
|
||||||
|
|
||||||
r_fill_state.transform_extra_command_number_p1 = 0; // mark as sent
|
|
||||||
r_fill_state.extra_matrix_sent = true;
|
|
||||||
|
|
||||||
// the original mode should always be hardware transform ..
|
|
||||||
// test this assumption
|
|
||||||
//CRASH_COND(r_fill_state.orig_transform_mode != TM_NONE);
|
|
||||||
r_fill_state.transform_mode = r_fill_state.orig_transform_mode;
|
|
||||||
|
|
||||||
// do we need to restore anything else?
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// end of previous different type batch, so start new default batch
|
|
||||||
|
|
||||||
// first consider whether there is a dirty extra matrix to send
|
|
||||||
if (r_fill_state.transform_extra_command_number_p1) {
|
|
||||||
// get which command the extra is in, and blank all the records as it no longer is stored CPU side
|
|
||||||
int extra_command = r_fill_state.transform_extra_command_number_p1 - 1; // plus 1 based
|
|
||||||
r_fill_state.transform_extra_command_number_p1 = 0;
|
|
||||||
r_fill_state.extra_matrix_sent = true;
|
|
||||||
|
|
||||||
// send the extra to the GPU in a batch
|
|
||||||
r_fill_state.curr_batch = _batch_request_new();
|
|
||||||
r_fill_state.curr_batch->type = Batch::BT_DEFAULT;
|
|
||||||
r_fill_state.curr_batch->first_command = extra_command;
|
|
||||||
r_fill_state.curr_batch->num_commands = 1;
|
|
||||||
|
|
||||||
// revert to the original transform mode
|
|
||||||
// e.g. go back to NONE if we were in hardware transform mode
|
|
||||||
r_fill_state.transform_mode = r_fill_state.orig_transform_mode;
|
|
||||||
|
|
||||||
// reset the original transform if we are going back to software mode,
|
|
||||||
// because the extra is now done on the GPU...
|
|
||||||
// (any subsequent extras are sent directly to the GPU, no deferring)
|
|
||||||
if (r_fill_state.orig_transform_mode != TM_NONE) {
|
|
||||||
r_fill_state.transform_combined = p_item.final_transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
// can possibly combine batch with the next one in some cases
|
|
||||||
// this is more efficient than having an extra batch especially for the extra
|
|
||||||
if ((extra_command + 1) == p_command_num) {
|
|
||||||
r_fill_state.curr_batch->num_commands = 2;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// start default batch
|
|
||||||
r_fill_state.curr_batch = _batch_request_new();
|
|
||||||
r_fill_state.curr_batch->type = Batch::BT_DEFAULT;
|
|
||||||
r_fill_state.curr_batch->first_command = p_command_num;
|
|
||||||
r_fill_state.curr_batch->num_commands = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void RasterizerCanvasGLES2::_software_transform_vertex(BatchVector2 &r_v, const Transform2D &p_tr) const {
|
|
||||||
Vector2 vc(r_v.x, r_v.y);
|
|
||||||
vc = p_tr.xform(vc);
|
|
||||||
r_v.set(vc);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void RasterizerCanvasGLES2::_software_transform_vertex(Vector2 &r_v, const Transform2D &p_tr) const {
|
|
||||||
r_v = p_tr.xform(r_v);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline RasterizerCanvasGLES2::TransformMode RasterizerCanvasGLES2::_find_transform_mode(const Transform2D &p_tr) const {
|
|
||||||
// decided whether to do translate only for software transform
|
|
||||||
if ((p_tr.elements[0].x == 1.0) &&
|
|
||||||
(p_tr.elements[0].y == 0.0) &&
|
|
||||||
(p_tr.elements[1].x == 0.0) &&
|
|
||||||
(p_tr.elements[1].y == 1.0)) {
|
|
||||||
return TM_TRANSLATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TM_ALL;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool RasterizerCanvasGLES2::_sort_items_match(const BSortItem &p_a, const BSortItem &p_b) const {
|
|
||||||
const Item *a = p_a.item;
|
|
||||||
const Item *b = p_b.item;
|
|
||||||
|
|
||||||
if (b->commands.size() != 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// tested outside function
|
|
||||||
// if (a->commands.size() != 1)
|
|
||||||
// return false;
|
|
||||||
|
|
||||||
const Item::Command &cb = *b->commands[0];
|
|
||||||
if (cb.type != Item::Command::TYPE_RECT)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const Item::Command &ca = *a->commands[0];
|
|
||||||
// tested outside function
|
|
||||||
// if (ca.type != Item::Command::TYPE_RECT)
|
|
||||||
// return false;
|
|
||||||
|
|
||||||
const Item::CommandRect *rect_a = static_cast<const Item::CommandRect *>(&ca);
|
|
||||||
const Item::CommandRect *rect_b = static_cast<const Item::CommandRect *>(&cb);
|
|
||||||
|
|
||||||
if (rect_a->texture != rect_b->texture)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
|
||||||
// TEMPLATE FUNCS
|
|
||||||
|
|
||||||
// Translation always involved adding color to the FVF, which enables
|
|
||||||
// joining of batches that have different colors.
|
|
||||||
// There is a trade off. Non colored verts are smaller so work faster, but
|
|
||||||
// there comes a point where it is better to just use colored verts to avoid lots of
|
|
||||||
// batches.
|
|
||||||
// In addition this can optionally add light angles to the FVF, necessary for normal mapping.
|
|
||||||
template <class BATCH_VERTEX_TYPE, bool INCLUDE_LIGHT_ANGLES>
|
|
||||||
void RasterizerCanvasGLES2::_translate_batches_to_larger_FVF() {
|
|
||||||
|
|
||||||
// zeros the size and sets up how big each unit is
|
|
||||||
bdata.unit_vertices.prepare(sizeof(BATCH_VERTEX_TYPE));
|
|
||||||
bdata.batches_temp.reset();
|
|
||||||
|
|
||||||
// As the vertices_colored and batches_temp are 'mirrors' of the non-colored version,
|
|
||||||
// the sizes should be equal, and allocations should never fail. Hence the use of debug
|
|
||||||
// asserts to check program flow, these should not occur at runtime unless the allocation
|
|
||||||
// code has been altered.
|
|
||||||
#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED)
|
|
||||||
CRASH_COND(bdata.unit_vertices.max_size() != bdata.vertices.max_size());
|
|
||||||
CRASH_COND(bdata.batches_temp.max_size() != bdata.batches.max_size());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Color curr_col(-1.0, -1.0, -1.0, -1.0);
|
|
||||||
|
|
||||||
Batch *dest_batch = 0;
|
|
||||||
|
|
||||||
const float *source_light_angles = &bdata.light_angles[0];
|
|
||||||
|
|
||||||
// translate the batches into vertex colored batches
|
|
||||||
for (int n = 0; n < bdata.batches.size(); n++) {
|
|
||||||
const Batch &source_batch = bdata.batches[n];
|
|
||||||
|
|
||||||
// does source batch use light angles?
|
|
||||||
const BatchTex &btex = bdata.batch_textures[source_batch.batch_texture_id];
|
|
||||||
bool source_batch_uses_light_angles = btex.RID_normal != RID();
|
|
||||||
|
|
||||||
bool needs_new_batch = true;
|
|
||||||
|
|
||||||
if (dest_batch) {
|
|
||||||
if (dest_batch->type == source_batch.type) {
|
|
||||||
if (source_batch.type == Batch::BT_RECT) {
|
|
||||||
if (dest_batch->batch_texture_id == source_batch.batch_texture_id) {
|
|
||||||
// add to previous batch
|
|
||||||
dest_batch->num_commands += source_batch.num_commands;
|
|
||||||
needs_new_batch = false;
|
|
||||||
|
|
||||||
// create the colored verts (only if not default)
|
|
||||||
int first_vert = source_batch.first_quad * 4;
|
|
||||||
int end_vert = 4 * (source_batch.first_quad + source_batch.num_commands);
|
|
||||||
|
|
||||||
for (int v = first_vert; v < end_vert; v++) {
|
|
||||||
const BatchVertex &bv = bdata.vertices[v];
|
|
||||||
BATCH_VERTEX_TYPE *cv = (BatchVertexLightAngled *)bdata.unit_vertices.request();
|
|
||||||
#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED)
|
|
||||||
CRASH_COND(!cv);
|
|
||||||
#endif
|
|
||||||
cv->pos = bv.pos;
|
|
||||||
cv->uv = bv.uv;
|
|
||||||
cv->col = source_batch.color;
|
|
||||||
|
|
||||||
if (INCLUDE_LIGHT_ANGLES) {
|
|
||||||
// this is required to allow compilation with non light angle vertex.
|
|
||||||
// it should be compiled out.
|
|
||||||
BatchVertexLightAngled *lv = (BatchVertexLightAngled *)cv;
|
|
||||||
if (source_batch_uses_light_angles)
|
|
||||||
lv->light_angle = *source_light_angles++;
|
|
||||||
else
|
|
||||||
lv->light_angle = 0.0f; // dummy, unused in vertex shader (could possibly be left uninitialized, but probably bad idea)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // textures match
|
|
||||||
} else {
|
|
||||||
// default
|
|
||||||
// we can still join, but only under special circumstances
|
|
||||||
// does this ever happen? not sure at this stage, but left for future expansion
|
|
||||||
uint32_t source_last_command = source_batch.first_command + source_batch.num_commands;
|
|
||||||
if (source_last_command == dest_batch->first_command) {
|
|
||||||
dest_batch->num_commands += source_batch.num_commands;
|
|
||||||
needs_new_batch = false;
|
|
||||||
} // if the commands line up exactly
|
|
||||||
}
|
|
||||||
} // if both batches are the same type
|
|
||||||
|
|
||||||
} // if dest batch is valid
|
|
||||||
|
|
||||||
if (needs_new_batch) {
|
|
||||||
dest_batch = bdata.batches_temp.request();
|
|
||||||
#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED)
|
|
||||||
CRASH_COND(!dest_batch);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
*dest_batch = source_batch;
|
|
||||||
|
|
||||||
// create the colored verts (only if not default)
|
|
||||||
if (source_batch.type != Batch::BT_DEFAULT) {
|
|
||||||
int first_vert = source_batch.first_quad * 4;
|
|
||||||
int end_vert = 4 * (source_batch.first_quad + source_batch.num_commands);
|
|
||||||
|
|
||||||
for (int v = first_vert; v < end_vert; v++) {
|
|
||||||
const BatchVertex &bv = bdata.vertices[v];
|
|
||||||
BATCH_VERTEX_TYPE *cv = (BatchVertexLightAngled *)bdata.unit_vertices.request();
|
|
||||||
#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED)
|
|
||||||
CRASH_COND(!cv);
|
|
||||||
#endif
|
|
||||||
cv->pos = bv.pos;
|
|
||||||
cv->uv = bv.uv;
|
|
||||||
cv->col = source_batch.color;
|
|
||||||
|
|
||||||
if (INCLUDE_LIGHT_ANGLES) {
|
|
||||||
// this is required to allow compilation with non light angle vertex.
|
|
||||||
// it should be compiled out.
|
|
||||||
BatchVertexLightAngled *lv = (BatchVertexLightAngled *)cv;
|
|
||||||
if (source_batch_uses_light_angles)
|
|
||||||
lv->light_angle = *source_light_angles++;
|
|
||||||
else
|
|
||||||
lv->light_angle = 0.0f; // dummy, unused in vertex shader (could possibly be left uninitialized, but probably bad idea)
|
|
||||||
} // if using light angles
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy the temporary batches to the master batch list (this could be avoided but it makes the code cleaner)
|
|
||||||
bdata.batches.copy_from(bdata.batches_temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// return true if buffer full up, else return false
|
|
||||||
template <bool SEND_LIGHT_ANGLES>
|
|
||||||
bool RasterizerCanvasGLES2::prefill_rect(Item::CommandRect *rect, FillState &r_fill_state, int &r_command_start, int command_num, int command_count, Item::Command *const *commands, Item *p_item, bool multiply_final_modulate) {
|
|
||||||
bool change_batch = false;
|
|
||||||
|
|
||||||
// conditions for creating a new batch
|
|
||||||
if (r_fill_state.curr_batch->type != Batch::BT_RECT) {
|
|
||||||
change_batch = true;
|
|
||||||
|
|
||||||
// check for special case if there is only a single or small number of rects,
|
|
||||||
// in which case we will use the legacy default rect renderer
|
|
||||||
// because it is faster for single rects
|
|
||||||
|
|
||||||
// we only want to do this if not a joined item with more than 1 item,
|
|
||||||
// because joined items with more than 1, the command * will be incorrect
|
|
||||||
// NOTE - this is assuming that use_hardware_transform means that it is a non-joined item!!
|
|
||||||
// If that assumption is incorrect this will go horribly wrong.
|
|
||||||
if (bdata.settings_use_single_rect_fallback && r_fill_state.use_hardware_transform) {
|
|
||||||
bool is_single_rect = false;
|
|
||||||
int command_num_next = command_num + 1;
|
|
||||||
if (command_num_next < command_count) {
|
|
||||||
Item::Command *command_next = commands[command_num_next];
|
|
||||||
if ((command_next->type != Item::Command::TYPE_RECT) && (command_next->type != Item::Command::TYPE_TRANSFORM)) {
|
|
||||||
is_single_rect = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
is_single_rect = true;
|
|
||||||
}
|
|
||||||
// if it is a rect on its own, do exactly the same as the default routine
|
|
||||||
if (is_single_rect) {
|
|
||||||
_prefill_default_batch(r_fill_state, command_num, *p_item);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} // if use hardware transform
|
|
||||||
}
|
|
||||||
|
|
||||||
Color col = rect->modulate;
|
|
||||||
if (multiply_final_modulate) {
|
|
||||||
col *= r_fill_state.final_modulate;
|
|
||||||
}
|
|
||||||
|
|
||||||
// instead of doing all the texture preparation for EVERY rect,
|
|
||||||
// we build a list of texture combinations and do this once off.
|
|
||||||
// This means we have a potentially rather slow step to identify which texture combo
|
|
||||||
// using the RIDs.
|
|
||||||
int old_batch_tex_id = r_fill_state.batch_tex_id;
|
|
||||||
r_fill_state.batch_tex_id = _batch_find_or_create_tex(rect->texture, rect->normal_map, rect->flags & CANVAS_RECT_TILE, old_batch_tex_id);
|
|
||||||
|
|
||||||
//r_fill_state.use_light_angles = send_light_angles;
|
|
||||||
if (SEND_LIGHT_ANGLES)
|
|
||||||
bdata.use_light_angles = true;
|
|
||||||
|
|
||||||
// try to create vertices BEFORE creating a batch,
|
|
||||||
// because if the vertex buffer is full, we need to finish this
|
|
||||||
// function, draw what we have so far, and then start a new set of batches
|
|
||||||
|
|
||||||
// request FOUR vertices at a time, this is more efficient
|
|
||||||
BatchVertex *bvs = bdata.vertices.request(4);
|
|
||||||
if (!bvs) {
|
|
||||||
// run out of space in the vertex buffer .. finish this function and draw what we have so far
|
|
||||||
// return where we got to
|
|
||||||
r_command_start = command_num;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// conditions for creating a new batch
|
|
||||||
if (old_batch_tex_id != r_fill_state.batch_tex_id) {
|
|
||||||
change_batch = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we need to treat color change separately because we need to count these
|
|
||||||
// to decide whether to switch on the fly to colored vertices.
|
|
||||||
if (!r_fill_state.curr_batch->color.equals(col)) {
|
|
||||||
change_batch = true;
|
|
||||||
bdata.total_color_changes++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (change_batch) {
|
|
||||||
// put the tex pixel size in a local (less verbose and can be a register)
|
|
||||||
const BatchTex &batchtex = bdata.batch_textures[r_fill_state.batch_tex_id];
|
|
||||||
batchtex.tex_pixel_size.to(r_fill_state.texpixel_size);
|
|
||||||
|
|
||||||
if (bdata.settings_uv_contract) {
|
|
||||||
r_fill_state.contract_uvs = (batchtex.flags & VS::TEXTURE_FLAG_FILTER) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// need to preserve texpixel_size between items
|
|
||||||
r_fill_state.texpixel_size = r_fill_state.texpixel_size;
|
|
||||||
|
|
||||||
// open new batch (this should never fail, it dynamically grows)
|
|
||||||
r_fill_state.curr_batch = _batch_request_new(false);
|
|
||||||
|
|
||||||
r_fill_state.curr_batch->type = Batch::BT_RECT;
|
|
||||||
r_fill_state.curr_batch->color.set(col);
|
|
||||||
r_fill_state.curr_batch->batch_texture_id = r_fill_state.batch_tex_id;
|
|
||||||
r_fill_state.curr_batch->first_command = command_num;
|
|
||||||
r_fill_state.curr_batch->num_commands = 1;
|
|
||||||
r_fill_state.curr_batch->first_quad = bdata.total_quads;
|
|
||||||
} else {
|
|
||||||
// we could alternatively do the count when closing a batch .. perhaps more efficient
|
|
||||||
r_fill_state.curr_batch->num_commands++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// fill the quad geometry
|
|
||||||
Vector2 mins = rect->rect.position;
|
|
||||||
|
|
||||||
if (r_fill_state.transform_mode == TM_TRANSLATE) {
|
|
||||||
_software_transform_vertex(mins, r_fill_state.transform_combined);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2 maxs = mins + rect->rect.size;
|
|
||||||
|
|
||||||
// just aliases
|
|
||||||
BatchVertex *bA = &bvs[0];
|
|
||||||
BatchVertex *bB = &bvs[1];
|
|
||||||
BatchVertex *bC = &bvs[2];
|
|
||||||
BatchVertex *bD = &bvs[3];
|
|
||||||
|
|
||||||
bA->pos.x = mins.x;
|
|
||||||
bA->pos.y = mins.y;
|
|
||||||
|
|
||||||
bB->pos.x = maxs.x;
|
|
||||||
bB->pos.y = mins.y;
|
|
||||||
|
|
||||||
bC->pos.x = maxs.x;
|
|
||||||
bC->pos.y = maxs.y;
|
|
||||||
|
|
||||||
bD->pos.x = mins.x;
|
|
||||||
bD->pos.y = maxs.y;
|
|
||||||
|
|
||||||
// possibility of applying flips here for normal mapping .. but they don't seem to be used
|
|
||||||
if (rect->rect.size.x < 0) {
|
|
||||||
SWAP(bA->pos, bB->pos);
|
|
||||||
SWAP(bC->pos, bD->pos);
|
|
||||||
}
|
|
||||||
if (rect->rect.size.y < 0) {
|
|
||||||
SWAP(bA->pos, bD->pos);
|
|
||||||
SWAP(bB->pos, bC->pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r_fill_state.transform_mode == TM_ALL) {
|
|
||||||
_software_transform_vertex(bA->pos, r_fill_state.transform_combined);
|
|
||||||
_software_transform_vertex(bB->pos, r_fill_state.transform_combined);
|
|
||||||
_software_transform_vertex(bC->pos, r_fill_state.transform_combined);
|
|
||||||
_software_transform_vertex(bD->pos, r_fill_state.transform_combined);
|
|
||||||
}
|
|
||||||
|
|
||||||
// uvs
|
|
||||||
Vector2 src_min;
|
|
||||||
Vector2 src_max;
|
|
||||||
if (rect->flags & CANVAS_RECT_REGION) {
|
|
||||||
src_min = rect->source.position;
|
|
||||||
src_max = src_min + rect->source.size;
|
|
||||||
|
|
||||||
src_min *= r_fill_state.texpixel_size;
|
|
||||||
src_max *= r_fill_state.texpixel_size;
|
|
||||||
|
|
||||||
const float uv_epsilon = bdata.settings_uv_contract_amount;
|
|
||||||
|
|
||||||
// nudge offset for the maximum to prevent precision error on GPU reading into line outside the source rect
|
|
||||||
// this is very difficult to get right.
|
|
||||||
if (r_fill_state.contract_uvs) {
|
|
||||||
src_min.x += uv_epsilon;
|
|
||||||
src_min.y += uv_epsilon;
|
|
||||||
src_max.x -= uv_epsilon;
|
|
||||||
src_max.y -= uv_epsilon;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
src_min = Vector2(0, 0);
|
|
||||||
src_max = Vector2(1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 10% faster calculating the max first
|
|
||||||
Vector2 uvs[4] = {
|
|
||||||
src_min,
|
|
||||||
Vector2(src_max.x, src_min.y),
|
|
||||||
src_max,
|
|
||||||
Vector2(src_min.x, src_max.y),
|
|
||||||
};
|
|
||||||
|
|
||||||
// for encoding in light angle
|
|
||||||
// flips should be optimized out when not being used for light angle.
|
|
||||||
bool flip_h = false;
|
|
||||||
bool flip_v = false;
|
|
||||||
|
|
||||||
if (rect->flags & CANVAS_RECT_TRANSPOSE) {
|
|
||||||
SWAP(uvs[1], uvs[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rect->flags & CANVAS_RECT_FLIP_H) {
|
|
||||||
SWAP(uvs[0], uvs[1]);
|
|
||||||
SWAP(uvs[2], uvs[3]);
|
|
||||||
flip_h = !flip_h;
|
|
||||||
flip_v = !flip_v;
|
|
||||||
}
|
|
||||||
if (rect->flags & CANVAS_RECT_FLIP_V) {
|
|
||||||
SWAP(uvs[0], uvs[3]);
|
|
||||||
SWAP(uvs[1], uvs[2]);
|
|
||||||
flip_v = !flip_v;
|
|
||||||
}
|
|
||||||
|
|
||||||
bA->uv.set(uvs[0]);
|
|
||||||
bB->uv.set(uvs[1]);
|
|
||||||
bC->uv.set(uvs[2]);
|
|
||||||
bD->uv.set(uvs[3]);
|
|
||||||
|
|
||||||
if (SEND_LIGHT_ANGLES) {
|
|
||||||
// we can either keep the light angles in sync with the verts when writing,
|
|
||||||
// or sync them up during translation. We are syncing in translation.
|
|
||||||
// N.B. There may be batches that don't require light_angles between batches that do.
|
|
||||||
float *angles = bdata.light_angles.request(4);
|
|
||||||
#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED)
|
|
||||||
CRASH_COND(angles == nullptr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
float angle = 0.0f;
|
|
||||||
const float TWO_PI = Math_PI * 2;
|
|
||||||
|
|
||||||
if (r_fill_state.transform_mode != TM_NONE) {
|
|
||||||
|
|
||||||
const Transform2D &tr = r_fill_state.transform_combined;
|
|
||||||
|
|
||||||
// apply to an x axis
|
|
||||||
// the x axis and y axis can be taken directly from the transform (no need to xform identity vectors)
|
|
||||||
Vector2 x_axis(tr.elements[0][0], tr.elements[1][0]);
|
|
||||||
|
|
||||||
// have to do a y axis to check for scaling flips
|
|
||||||
// this is hassle and extra slowness. We could only allow flips via the flags.
|
|
||||||
Vector2 y_axis(tr.elements[0][1], tr.elements[1][1]);
|
|
||||||
|
|
||||||
// has the x / y axis flipped due to scaling?
|
|
||||||
float cross = x_axis.cross(y_axis);
|
|
||||||
if (cross < 0.0f) {
|
|
||||||
flip_v = !flip_v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// passing an angle is smaller than a vector, it can be reconstructed in the shader
|
|
||||||
angle = x_axis.angle();
|
|
||||||
|
|
||||||
// we don't want negative angles, as negative is used to encode flips.
|
|
||||||
// This moves range from -PI to PI to 0 to TWO_PI
|
|
||||||
if (angle < 0.0f)
|
|
||||||
angle += TWO_PI;
|
|
||||||
|
|
||||||
} // if transform needed
|
|
||||||
|
|
||||||
// if horizontal flip, angle is shifted by 180 degrees
|
|
||||||
if (flip_h) {
|
|
||||||
angle += Math_PI;
|
|
||||||
|
|
||||||
// mod to get back to 0 to TWO_PI range
|
|
||||||
angle = fmodf(angle, TWO_PI);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add 1 (to take care of zero floating point error with sign)
|
|
||||||
angle += 1.0f;
|
|
||||||
|
|
||||||
// flip if necessary to indicate a vertical flip in the shader
|
|
||||||
if (flip_v)
|
|
||||||
angle *= -1.0f;
|
|
||||||
|
|
||||||
// light angle must be sent for each vert, instead as a single uniform in the uniform draw method
|
|
||||||
// this has the benefit of enabling batching with light angles.
|
|
||||||
for (int n = 0; n < 4; n++) {
|
|
||||||
angles[n] = angle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// increment quad count
|
|
||||||
bdata.total_quads++;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // RASTERIZERCANVASGLES2_H
|
#endif // RASTERIZERCANVASGLES2_H
|
||||||
|
|
|
@ -483,6 +483,42 @@ void RasterizerGLES2::make_current() {
|
||||||
void RasterizerGLES2::register_config() {
|
void RasterizerGLES2::register_config() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns NULL if no error, or an error string
|
||||||
|
const char *RasterizerGLES2::gl_check_for_error(bool p_print_error) {
|
||||||
|
GLenum err = glGetError();
|
||||||
|
|
||||||
|
const char *err_string = nullptr;
|
||||||
|
|
||||||
|
switch (err) {
|
||||||
|
default: {
|
||||||
|
// not recognised
|
||||||
|
} break;
|
||||||
|
case GL_NO_ERROR: {
|
||||||
|
} break;
|
||||||
|
case GL_INVALID_ENUM: {
|
||||||
|
err_string = "GL_INVALID_ENUM";
|
||||||
|
} break;
|
||||||
|
case GL_INVALID_VALUE: {
|
||||||
|
err_string = "GL_INVALID_VALUE";
|
||||||
|
} break;
|
||||||
|
case GL_INVALID_OPERATION: {
|
||||||
|
err_string = "GL_INVALID_OPERATION";
|
||||||
|
} break;
|
||||||
|
case GL_INVALID_FRAMEBUFFER_OPERATION: {
|
||||||
|
err_string = "GL_INVALID_FRAMEBUFFER_OPERATION";
|
||||||
|
} break;
|
||||||
|
case GL_OUT_OF_MEMORY: {
|
||||||
|
err_string = "GL_OUT_OF_MEMORY";
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_print_error && err_string) {
|
||||||
|
print_line(err_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err_string;
|
||||||
|
}
|
||||||
|
|
||||||
RasterizerGLES2::RasterizerGLES2() {
|
RasterizerGLES2::RasterizerGLES2() {
|
||||||
|
|
||||||
storage = memnew(RasterizerStorageGLES2);
|
storage = memnew(RasterizerStorageGLES2);
|
||||||
|
|
|
@ -71,6 +71,8 @@ public:
|
||||||
|
|
||||||
virtual bool is_low_end() const { return true; }
|
virtual bool is_low_end() const { return true; }
|
||||||
|
|
||||||
|
virtual const char *gl_check_for_error(bool p_print_error = true);
|
||||||
|
|
||||||
RasterizerGLES2();
|
RasterizerGLES2();
|
||||||
~RasterizerGLES2();
|
~RasterizerGLES2();
|
||||||
};
|
};
|
||||||
|
|
|
@ -1452,6 +1452,7 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const {
|
||||||
shaders.actions_canvas.usage_flag_pointers["TIME"] = &p_shader->canvas_item.uses_time;
|
shaders.actions_canvas.usage_flag_pointers["TIME"] = &p_shader->canvas_item.uses_time;
|
||||||
shaders.actions_canvas.usage_flag_pointers["MODULATE"] = &p_shader->canvas_item.uses_modulate;
|
shaders.actions_canvas.usage_flag_pointers["MODULATE"] = &p_shader->canvas_item.uses_modulate;
|
||||||
shaders.actions_canvas.usage_flag_pointers["COLOR"] = &p_shader->canvas_item.uses_color;
|
shaders.actions_canvas.usage_flag_pointers["COLOR"] = &p_shader->canvas_item.uses_color;
|
||||||
|
|
||||||
shaders.actions_canvas.usage_flag_pointers["VERTEX"] = &p_shader->canvas_item.uses_vertex;
|
shaders.actions_canvas.usage_flag_pointers["VERTEX"] = &p_shader->canvas_item.uses_vertex;
|
||||||
|
|
||||||
actions = &shaders.actions_canvas;
|
actions = &shaders.actions_canvas;
|
||||||
|
@ -1552,10 +1553,10 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const {
|
||||||
// some logic for batching
|
// some logic for batching
|
||||||
if (p_shader->mode == VS::SHADER_CANVAS_ITEM) {
|
if (p_shader->mode == VS::SHADER_CANVAS_ITEM) {
|
||||||
if (p_shader->canvas_item.uses_modulate | p_shader->canvas_item.uses_color) {
|
if (p_shader->canvas_item.uses_modulate | p_shader->canvas_item.uses_color) {
|
||||||
p_shader->canvas_item.batch_flags |= Shader::CanvasItem::PREVENT_COLOR_BAKING;
|
p_shader->canvas_item.batch_flags |= RasterizerStorageCommon::PREVENT_COLOR_BAKING;
|
||||||
}
|
}
|
||||||
if (p_shader->canvas_item.uses_vertex) {
|
if (p_shader->canvas_item.uses_vertex) {
|
||||||
p_shader->canvas_item.batch_flags |= Shader::CanvasItem::PREVENT_VERTEX_BAKING;
|
p_shader->canvas_item.batch_flags |= RasterizerStorageCommon::PREVENT_VERTEX_BAKING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,11 +40,6 @@
|
||||||
|
|
||||||
#include "shaders/copy.glsl.gen.h"
|
#include "shaders/copy.glsl.gen.h"
|
||||||
#include "shaders/cubemap_filter.glsl.gen.h"
|
#include "shaders/cubemap_filter.glsl.gen.h"
|
||||||
/*
|
|
||||||
#include "shaders/blend_shape.glsl.gen.h"
|
|
||||||
#include "shaders/canvas.glsl.gen.h"
|
|
||||||
#include "shaders/particles.glsl.gen.h"
|
|
||||||
*/
|
|
||||||
|
|
||||||
class RasterizerCanvasGLES2;
|
class RasterizerCanvasGLES2;
|
||||||
class RasterizerSceneGLES2;
|
class RasterizerSceneGLES2;
|
||||||
|
@ -450,10 +445,7 @@ public:
|
||||||
// these flags are specifically for batching
|
// these flags are specifically for batching
|
||||||
// some of the logic is thus in rasterizer_storage.cpp
|
// some of the logic is thus in rasterizer_storage.cpp
|
||||||
// we could alternatively set bitflags for each 'uses' and test on the fly
|
// we could alternatively set bitflags for each 'uses' and test on the fly
|
||||||
enum BatchFlags {
|
// defined in RasterizerStorageCommon::BatchFlags
|
||||||
PREVENT_COLOR_BAKING = 1 << 0,
|
|
||||||
PREVENT_VERTEX_BAKING = 1 << 1,
|
|
||||||
};
|
|
||||||
unsigned int batch_flags;
|
unsigned int batch_flags;
|
||||||
|
|
||||||
bool uses_screen_texture;
|
bool uses_screen_texture;
|
||||||
|
|
|
@ -19,7 +19,7 @@ uniform highp mat4 modelview_matrix;
|
||||||
uniform highp mat4 extra_matrix;
|
uniform highp mat4 extra_matrix;
|
||||||
attribute highp vec2 vertex; // attrib:0
|
attribute highp vec2 vertex; // attrib:0
|
||||||
|
|
||||||
#ifdef USE_LIGHT_ANGLE
|
#ifdef USE_ATTRIB_LIGHT_ANGLE
|
||||||
// shared with tangent, not used in canvas shader
|
// shared with tangent, not used in canvas shader
|
||||||
attribute highp float light_angle; // attrib:2
|
attribute highp float light_angle; // attrib:2
|
||||||
#endif
|
#endif
|
||||||
|
@ -27,6 +27,16 @@ attribute highp float light_angle; // attrib:2
|
||||||
attribute vec4 color_attrib; // attrib:3
|
attribute vec4 color_attrib; // attrib:3
|
||||||
attribute vec2 uv_attrib; // attrib:4
|
attribute vec2 uv_attrib; // attrib:4
|
||||||
|
|
||||||
|
#ifdef USE_ATTRIB_MODULATE
|
||||||
|
attribute highp vec4 modulate_attrib; // attrib:5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_ATTRIB_LARGE_VERTEX
|
||||||
|
// shared with skeleton attributes, not used in batched shader
|
||||||
|
attribute highp vec2 translate_attrib; // attrib:6
|
||||||
|
attribute highp vec4 basis_attrib; // attrib:7
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_SKELETON
|
#ifdef USE_SKELETON
|
||||||
attribute highp vec4 bone_indices; // attrib:6
|
attribute highp vec4 bone_indices; // attrib:6
|
||||||
attribute highp vec4 bone_weights; // attrib:7
|
attribute highp vec4 bone_weights; // attrib:7
|
||||||
|
@ -54,6 +64,12 @@ uniform highp mat4 skeleton_transform_inverse;
|
||||||
|
|
||||||
varying vec2 uv_interp;
|
varying vec2 uv_interp;
|
||||||
varying vec4 color_interp;
|
varying vec4 color_interp;
|
||||||
|
|
||||||
|
#ifdef USE_ATTRIB_MODULATE
|
||||||
|
// modulate doesn't need interpolating but we need to send it to the fragment shader
|
||||||
|
varying vec4 modulate_interp;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef MODULATE_USED
|
#ifdef MODULATE_USED
|
||||||
uniform vec4 final_modulate;
|
uniform vec4 final_modulate;
|
||||||
#endif
|
#endif
|
||||||
|
@ -171,6 +187,24 @@ VERTEX_SHADER_CODE
|
||||||
|
|
||||||
gl_PointSize = point_size;
|
gl_PointSize = point_size;
|
||||||
|
|
||||||
|
#ifdef USE_ATTRIB_MODULATE
|
||||||
|
// modulate doesn't need interpolating but we need to send it to the fragment shader
|
||||||
|
modulate_interp = modulate_attrib;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_ATTRIB_LARGE_VERTEX
|
||||||
|
// transform is in attributes
|
||||||
|
vec2 temp;
|
||||||
|
|
||||||
|
temp = outvec.xy;
|
||||||
|
temp.x = (outvec.x * basis_attrib.x) + (outvec.y * basis_attrib.z);
|
||||||
|
temp.y = (outvec.x * basis_attrib.y) + (outvec.y * basis_attrib.w);
|
||||||
|
|
||||||
|
temp += translate_attrib;
|
||||||
|
outvec.xy = temp;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(SKIP_TRANSFORM_USED)
|
#if !defined(SKIP_TRANSFORM_USED)
|
||||||
outvec = extra_matrix_instance * outvec;
|
outvec = extra_matrix_instance * outvec;
|
||||||
outvec = modelview_matrix * outvec;
|
outvec = modelview_matrix * outvec;
|
||||||
|
@ -225,7 +259,7 @@ VERTEX_SHADER_CODE
|
||||||
pos = outvec.xy;
|
pos = outvec.xy;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_LIGHT_ANGLE
|
#ifdef USE_ATTRIB_LIGHT_ANGLE
|
||||||
// we add a fixed offset because we are using the sign later,
|
// we add a fixed offset because we are using the sign later,
|
||||||
// and don't want floating point error around 0.0
|
// and don't want floating point error around 0.0
|
||||||
float la = abs(light_angle) - 1.0;
|
float la = abs(light_angle) - 1.0;
|
||||||
|
@ -303,6 +337,10 @@ uniform mediump sampler2D normal_texture; // texunit:-2
|
||||||
varying mediump vec2 uv_interp;
|
varying mediump vec2 uv_interp;
|
||||||
varying mediump vec4 color_interp;
|
varying mediump vec4 color_interp;
|
||||||
|
|
||||||
|
#ifdef USE_ATTRIB_MODULATE
|
||||||
|
varying mediump vec4 modulate_interp;
|
||||||
|
#endif
|
||||||
|
|
||||||
uniform highp float time;
|
uniform highp float time;
|
||||||
|
|
||||||
uniform vec4 final_modulate;
|
uniform vec4 final_modulate;
|
||||||
|
@ -442,6 +480,11 @@ FRAGMENT_SHADER_CODE
|
||||||
color *= final_modulate;
|
color *= final_modulate;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_ATTRIB_MODULATE
|
||||||
|
// todo .. this won't be used at the same time as MODULATE_USED
|
||||||
|
color *= modulate_interp;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_LIGHTING
|
#ifdef USE_LIGHTING
|
||||||
|
|
||||||
vec2 light_vec = transformed_light_uv;
|
vec2 light_vec = transformed_light_uv;
|
||||||
|
|
1305
drivers/gles3/rasterizer_canvas_base_gles3.cpp
Normal file
1305
drivers/gles3/rasterizer_canvas_base_gles3.cpp
Normal file
File diff suppressed because it is too large
Load diff
163
drivers/gles3/rasterizer_canvas_base_gles3.h
Normal file
163
drivers/gles3/rasterizer_canvas_base_gles3.h
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* rasterizer_canvas_base_gles3.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#ifndef RASTERIZERCANVASBASEGLES3_H
|
||||||
|
#define RASTERIZERCANVASBASEGLES3_H
|
||||||
|
|
||||||
|
#include "rasterizer_storage_gles3.h"
|
||||||
|
#include "servers/visual/rasterizer.h"
|
||||||
|
|
||||||
|
#include "shaders/canvas_shadow.glsl.gen.h"
|
||||||
|
#include "shaders/lens_distorted.glsl.gen.h"
|
||||||
|
|
||||||
|
class RasterizerSceneGLES3;
|
||||||
|
|
||||||
|
class RasterizerCanvasBaseGLES3 : public RasterizerCanvas {
|
||||||
|
public:
|
||||||
|
struct CanvasItemUBO {
|
||||||
|
|
||||||
|
float projection_matrix[16];
|
||||||
|
float time;
|
||||||
|
uint8_t padding[12];
|
||||||
|
};
|
||||||
|
|
||||||
|
RasterizerSceneGLES3 *scene_render;
|
||||||
|
|
||||||
|
struct Data {
|
||||||
|
|
||||||
|
enum { NUM_QUAD_ARRAY_VARIATIONS = 8 };
|
||||||
|
|
||||||
|
GLuint canvas_quad_vertices;
|
||||||
|
GLuint canvas_quad_array;
|
||||||
|
|
||||||
|
GLuint polygon_buffer;
|
||||||
|
GLuint polygon_buffer_quad_arrays[NUM_QUAD_ARRAY_VARIATIONS];
|
||||||
|
GLuint polygon_buffer_pointer_array;
|
||||||
|
GLuint polygon_index_buffer;
|
||||||
|
|
||||||
|
GLuint particle_quad_vertices;
|
||||||
|
GLuint particle_quad_array;
|
||||||
|
|
||||||
|
uint32_t polygon_buffer_size;
|
||||||
|
uint32_t polygon_index_buffer_size;
|
||||||
|
|
||||||
|
} data;
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
CanvasItemUBO canvas_item_ubo_data;
|
||||||
|
GLuint canvas_item_ubo;
|
||||||
|
bool canvas_texscreen_used;
|
||||||
|
CanvasShaderGLES3 canvas_shader;
|
||||||
|
CanvasShadowShaderGLES3 canvas_shadow_shader;
|
||||||
|
LensDistortedShaderGLES3 lens_shader;
|
||||||
|
|
||||||
|
bool using_texture_rect;
|
||||||
|
bool using_ninepatch;
|
||||||
|
|
||||||
|
bool using_light_angle;
|
||||||
|
bool using_modulate;
|
||||||
|
bool using_large_vertex;
|
||||||
|
|
||||||
|
RID current_tex;
|
||||||
|
RID current_normal;
|
||||||
|
RasterizerStorageGLES3::Texture *current_tex_ptr;
|
||||||
|
|
||||||
|
Transform vp;
|
||||||
|
|
||||||
|
Color canvas_item_modulate;
|
||||||
|
Transform2D extra_matrix;
|
||||||
|
Transform2D final_transform;
|
||||||
|
bool using_skeleton;
|
||||||
|
Transform2D skeleton_transform;
|
||||||
|
Transform2D skeleton_transform_inverse;
|
||||||
|
|
||||||
|
} state;
|
||||||
|
|
||||||
|
RasterizerStorageGLES3 *storage;
|
||||||
|
|
||||||
|
struct LightInternal : public RID_Data {
|
||||||
|
|
||||||
|
struct UBOData {
|
||||||
|
|
||||||
|
float light_matrix[16];
|
||||||
|
float local_matrix[16];
|
||||||
|
float shadow_matrix[16];
|
||||||
|
float color[4];
|
||||||
|
float shadow_color[4];
|
||||||
|
float light_pos[2];
|
||||||
|
float shadowpixel_size;
|
||||||
|
float shadow_gradient;
|
||||||
|
float light_height;
|
||||||
|
float light_outside_alpha;
|
||||||
|
float shadow_distance_mult;
|
||||||
|
uint8_t padding[4];
|
||||||
|
} ubo_data;
|
||||||
|
|
||||||
|
GLuint ubo;
|
||||||
|
};
|
||||||
|
|
||||||
|
RID_Owner<LightInternal> light_internal_owner;
|
||||||
|
|
||||||
|
virtual RID light_internal_create();
|
||||||
|
virtual void light_internal_update(RID p_rid, Light *p_light);
|
||||||
|
virtual void light_internal_free(RID p_rid);
|
||||||
|
|
||||||
|
virtual void canvas_begin();
|
||||||
|
virtual void canvas_end();
|
||||||
|
|
||||||
|
void _set_texture_rect_mode(bool p_enable, bool p_ninepatch = false, bool p_light_angle = false, bool p_modulate = false, bool p_large_vertex = false);
|
||||||
|
RasterizerStorageGLES3::Texture *_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map, bool p_force = false);
|
||||||
|
|
||||||
|
void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs, const float *p_light_angles = nullptr);
|
||||||
|
void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor, const int *p_bones, const float *p_weights);
|
||||||
|
void _draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor);
|
||||||
|
void _draw_generic_indices(GLuint p_primitive, const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor);
|
||||||
|
|
||||||
|
void _copy_texscreen(const Rect2 &p_rect);
|
||||||
|
|
||||||
|
virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow);
|
||||||
|
|
||||||
|
virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache);
|
||||||
|
|
||||||
|
virtual void reset_canvas();
|
||||||
|
|
||||||
|
void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src);
|
||||||
|
void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
|
||||||
|
void render_rect_nvidia_workaround(const Item::CommandRect *p_rect, const RasterizerStorageGLES3::Texture *p_texture);
|
||||||
|
|
||||||
|
void initialize();
|
||||||
|
void finalize();
|
||||||
|
|
||||||
|
virtual void draw_window_margins(int *black_margin, RID *black_image);
|
||||||
|
|
||||||
|
RasterizerCanvasBaseGLES3();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // RASTERIZERCANVASBASEGLES3_H
|
File diff suppressed because it is too large
Load diff
|
@ -31,132 +31,49 @@
|
||||||
#ifndef RASTERIZERCANVASGLES3_H
|
#ifndef RASTERIZERCANVASGLES3_H
|
||||||
#define RASTERIZERCANVASGLES3_H
|
#define RASTERIZERCANVASGLES3_H
|
||||||
|
|
||||||
#include "rasterizer_storage_gles3.h"
|
#include "drivers/gles_common/rasterizer_canvas_batcher.h"
|
||||||
#include "servers/visual/rasterizer.h"
|
#include "rasterizer_canvas_base_gles3.h"
|
||||||
|
|
||||||
#include "shaders/canvas_shadow.glsl.gen.h"
|
class RasterizerCanvasGLES3 : public RasterizerCanvasBaseGLES3, public RasterizerCanvasBatcher<RasterizerCanvasGLES3, RasterizerStorageGLES3> {
|
||||||
#include "shaders/lens_distorted.glsl.gen.h"
|
friend class RasterizerCanvasBatcher<RasterizerCanvasGLES3, RasterizerStorageGLES3>;
|
||||||
|
|
||||||
class RasterizerSceneGLES3;
|
private:
|
||||||
|
struct BatchGLData {
|
||||||
|
// for batching
|
||||||
|
GLuint batch_vertex_array[5];
|
||||||
|
} batch_gl_data;
|
||||||
|
|
||||||
class RasterizerCanvasGLES3 : public RasterizerCanvas {
|
|
||||||
public:
|
public:
|
||||||
struct CanvasItemUBO {
|
virtual void canvas_render_items_begin(const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform);
|
||||||
|
virtual void canvas_render_items_end();
|
||||||
float projection_matrix[16];
|
virtual void canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform);
|
||||||
float time;
|
|
||||||
uint8_t padding[12];
|
|
||||||
};
|
|
||||||
|
|
||||||
RasterizerSceneGLES3 *scene_render;
|
|
||||||
|
|
||||||
struct Data {
|
|
||||||
|
|
||||||
enum { NUM_QUAD_ARRAY_VARIATIONS = 8 };
|
|
||||||
|
|
||||||
GLuint canvas_quad_vertices;
|
|
||||||
GLuint canvas_quad_array;
|
|
||||||
|
|
||||||
GLuint polygon_buffer;
|
|
||||||
GLuint polygon_buffer_quad_arrays[NUM_QUAD_ARRAY_VARIATIONS];
|
|
||||||
GLuint polygon_buffer_pointer_array;
|
|
||||||
GLuint polygon_index_buffer;
|
|
||||||
|
|
||||||
GLuint particle_quad_vertices;
|
|
||||||
GLuint particle_quad_array;
|
|
||||||
|
|
||||||
uint32_t polygon_buffer_size;
|
|
||||||
uint32_t polygon_index_buffer_size;
|
|
||||||
|
|
||||||
} data;
|
|
||||||
|
|
||||||
struct State {
|
|
||||||
CanvasItemUBO canvas_item_ubo_data;
|
|
||||||
GLuint canvas_item_ubo;
|
|
||||||
bool canvas_texscreen_used;
|
|
||||||
CanvasShaderGLES3 canvas_shader;
|
|
||||||
CanvasShadowShaderGLES3 canvas_shadow_shader;
|
|
||||||
LensDistortedShaderGLES3 lens_shader;
|
|
||||||
|
|
||||||
bool using_texture_rect;
|
|
||||||
bool using_ninepatch;
|
|
||||||
bool using_light_angle;
|
|
||||||
|
|
||||||
RID current_tex;
|
|
||||||
RID current_normal;
|
|
||||||
RasterizerStorageGLES3::Texture *current_tex_ptr;
|
|
||||||
|
|
||||||
Transform vp;
|
|
||||||
|
|
||||||
Color canvas_item_modulate;
|
|
||||||
Transform2D extra_matrix;
|
|
||||||
Transform2D final_transform;
|
|
||||||
bool using_skeleton;
|
|
||||||
Transform2D skeleton_transform;
|
|
||||||
Transform2D skeleton_transform_inverse;
|
|
||||||
|
|
||||||
} state;
|
|
||||||
|
|
||||||
RasterizerStorageGLES3 *storage;
|
|
||||||
bool use_nvidia_rect_workaround;
|
|
||||||
|
|
||||||
struct LightInternal : public RID_Data {
|
|
||||||
|
|
||||||
struct UBOData {
|
|
||||||
|
|
||||||
float light_matrix[16];
|
|
||||||
float local_matrix[16];
|
|
||||||
float shadow_matrix[16];
|
|
||||||
float color[4];
|
|
||||||
float shadow_color[4];
|
|
||||||
float light_pos[2];
|
|
||||||
float shadowpixel_size;
|
|
||||||
float shadow_gradient;
|
|
||||||
float light_height;
|
|
||||||
float light_outside_alpha;
|
|
||||||
float shadow_distance_mult;
|
|
||||||
uint8_t padding[4];
|
|
||||||
} ubo_data;
|
|
||||||
|
|
||||||
GLuint ubo;
|
|
||||||
};
|
|
||||||
|
|
||||||
RID_Owner<LightInternal> light_internal_owner;
|
|
||||||
|
|
||||||
virtual RID light_internal_create();
|
|
||||||
virtual void light_internal_update(RID p_rid, Light *p_light);
|
|
||||||
virtual void light_internal_free(RID p_rid);
|
|
||||||
|
|
||||||
virtual void canvas_begin();
|
virtual void canvas_begin();
|
||||||
virtual void canvas_end();
|
virtual void canvas_end();
|
||||||
|
|
||||||
_FORCE_INLINE_ void _set_texture_rect_mode(bool p_enable, bool p_ninepatch = false, bool p_light_angle = false);
|
private:
|
||||||
_FORCE_INLINE_ RasterizerStorageGLES3::Texture *_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map, bool p_force = false);
|
// legacy codepath .. to remove after testing
|
||||||
|
void _legacy_canvas_render_item(Item *p_ci, RenderItemState &r_ris);
|
||||||
|
|
||||||
_FORCE_INLINE_ void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs, const float *p_light_angles = nullptr);
|
// high level batch funcs
|
||||||
_FORCE_INLINE_ void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor, const int *p_bones, const float *p_weights);
|
void canvas_render_items_implementation(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform);
|
||||||
_FORCE_INLINE_ void _draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor);
|
void render_joined_item(const BItemJoined &p_bij, RenderItemState &r_ris);
|
||||||
_FORCE_INLINE_ void _draw_generic_indices(GLuint p_primitive, const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor);
|
bool try_join_item(Item *p_ci, RenderItemState &r_ris, bool &r_batch_break);
|
||||||
|
void render_batches(Item::Command *const *p_commands, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES3::Material *p_material);
|
||||||
|
|
||||||
_FORCE_INLINE_ void _canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip);
|
// low level batch funcs
|
||||||
_FORCE_INLINE_ void _copy_texscreen(const Rect2 &p_rect);
|
void _batch_upload_buffers();
|
||||||
|
void _batch_render_rects(const Batch &p_batch, RasterizerStorageGLES3::Material *p_material);
|
||||||
|
void _batch_render_polys(const Batch &p_batch, RasterizerStorageGLES3::Material *p_material);
|
||||||
|
void _batch_render_lines(const Batch &p_batch, RasterizerStorageGLES3::Material *p_material, bool p_anti_alias);
|
||||||
|
|
||||||
virtual void canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_transform);
|
// funcs used from rasterizer_canvas_batcher template
|
||||||
virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow);
|
void gl_enable_scissor(int p_x, int p_y, int p_width, int p_height) const;
|
||||||
|
void gl_disable_scissor() const;
|
||||||
|
|
||||||
virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache);
|
void gl_checkerror();
|
||||||
|
|
||||||
virtual void reset_canvas();
|
|
||||||
|
|
||||||
void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src);
|
|
||||||
void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
|
|
||||||
void render_rect_nvidia_workaround(const Item::CommandRect *p_rect, const RasterizerStorageGLES3::Texture *p_texture);
|
|
||||||
|
|
||||||
|
public:
|
||||||
void initialize();
|
void initialize();
|
||||||
void finalize();
|
|
||||||
|
|
||||||
virtual void draw_window_margins(int *black_margin, RID *black_image);
|
|
||||||
|
|
||||||
RasterizerCanvasGLES3();
|
RasterizerCanvasGLES3();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ public:
|
||||||
|
|
||||||
virtual bool is_low_end() const { return false; }
|
virtual bool is_low_end() const { return false; }
|
||||||
|
|
||||||
const char *gl_check_for_error(bool p_print_error = true);
|
virtual const char *gl_check_for_error(bool p_print_error = true);
|
||||||
|
|
||||||
RasterizerGLES3();
|
RasterizerGLES3();
|
||||||
~RasterizerGLES3();
|
~RasterizerGLES3();
|
||||||
|
|
|
@ -2305,6 +2305,10 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const {
|
||||||
p_shader->canvas_item.uses_screen_texture = false;
|
p_shader->canvas_item.uses_screen_texture = false;
|
||||||
p_shader->canvas_item.uses_screen_uv = false;
|
p_shader->canvas_item.uses_screen_uv = false;
|
||||||
p_shader->canvas_item.uses_time = false;
|
p_shader->canvas_item.uses_time = false;
|
||||||
|
p_shader->canvas_item.uses_modulate = false;
|
||||||
|
p_shader->canvas_item.uses_color = false;
|
||||||
|
p_shader->canvas_item.uses_vertex = false;
|
||||||
|
p_shader->canvas_item.batch_flags = 0;
|
||||||
|
|
||||||
shaders.actions_canvas.render_mode_values["blend_add"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_ADD);
|
shaders.actions_canvas.render_mode_values["blend_add"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_ADD);
|
||||||
shaders.actions_canvas.render_mode_values["blend_mix"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_MIX);
|
shaders.actions_canvas.render_mode_values["blend_mix"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_MIX);
|
||||||
|
@ -2321,6 +2325,10 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const {
|
||||||
shaders.actions_canvas.usage_flag_pointers["SCREEN_TEXTURE"] = &p_shader->canvas_item.uses_screen_texture;
|
shaders.actions_canvas.usage_flag_pointers["SCREEN_TEXTURE"] = &p_shader->canvas_item.uses_screen_texture;
|
||||||
shaders.actions_canvas.usage_flag_pointers["TIME"] = &p_shader->canvas_item.uses_time;
|
shaders.actions_canvas.usage_flag_pointers["TIME"] = &p_shader->canvas_item.uses_time;
|
||||||
|
|
||||||
|
shaders.actions_canvas.usage_flag_pointers["MODULATE"] = &p_shader->canvas_item.uses_modulate;
|
||||||
|
shaders.actions_canvas.usage_flag_pointers["COLOR"] = &p_shader->canvas_item.uses_color;
|
||||||
|
shaders.actions_canvas.usage_flag_pointers["VERTEX"] = &p_shader->canvas_item.uses_vertex;
|
||||||
|
|
||||||
actions = &shaders.actions_canvas;
|
actions = &shaders.actions_canvas;
|
||||||
actions->uniforms = &p_shader->uniforms;
|
actions->uniforms = &p_shader->uniforms;
|
||||||
|
|
||||||
|
@ -2417,6 +2425,16 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const {
|
||||||
p_shader->uses_vertex_time = gen_code.uses_vertex_time;
|
p_shader->uses_vertex_time = gen_code.uses_vertex_time;
|
||||||
p_shader->uses_fragment_time = gen_code.uses_fragment_time;
|
p_shader->uses_fragment_time = gen_code.uses_fragment_time;
|
||||||
|
|
||||||
|
// some logic for batching
|
||||||
|
if (p_shader->mode == VS::SHADER_CANVAS_ITEM) {
|
||||||
|
if (p_shader->canvas_item.uses_modulate | p_shader->canvas_item.uses_color) {
|
||||||
|
p_shader->canvas_item.batch_flags |= RasterizerStorageCommon::PREVENT_COLOR_BAKING;
|
||||||
|
}
|
||||||
|
if (p_shader->canvas_item.uses_vertex) {
|
||||||
|
p_shader->canvas_item.batch_flags |= RasterizerStorageCommon::PREVENT_VERTEX_BAKING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//all materials using this shader will have to be invalidated, unfortunately
|
//all materials using this shader will have to be invalidated, unfortunately
|
||||||
|
|
||||||
for (SelfList<Material> *E = p_shader->materials.first(); E; E = E->next()) {
|
for (SelfList<Material> *E = p_shader->materials.first(); E; E = E->next()) {
|
||||||
|
@ -8313,6 +8331,9 @@ void RasterizerStorageGLES3::initialize() {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// not yet detected on GLES3 (is this mandated?)
|
||||||
|
config.support_npot_repeat_mipmap = true;
|
||||||
|
|
||||||
config.pvrtc_supported = config.extensions.has("GL_IMG_texture_compression_pvrtc");
|
config.pvrtc_supported = config.extensions.has("GL_IMG_texture_compression_pvrtc");
|
||||||
config.srgb_decode_supported = config.extensions.has("GL_EXT_texture_sRGB_decode");
|
config.srgb_decode_supported = config.extensions.has("GL_EXT_texture_sRGB_decode");
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,7 @@ public:
|
||||||
|
|
||||||
bool srgb_decode_supported;
|
bool srgb_decode_supported;
|
||||||
|
|
||||||
|
bool support_npot_repeat_mipmap;
|
||||||
bool texture_float_linear_supported;
|
bool texture_float_linear_supported;
|
||||||
bool framebuffer_float_supported;
|
bool framebuffer_float_supported;
|
||||||
bool framebuffer_half_float_supported;
|
bool framebuffer_half_float_supported;
|
||||||
|
@ -455,9 +456,18 @@ public:
|
||||||
|
|
||||||
int light_mode;
|
int light_mode;
|
||||||
|
|
||||||
|
// these flags are specifically for batching
|
||||||
|
// some of the logic is thus in rasterizer_storage.cpp
|
||||||
|
// we could alternatively set bitflags for each 'uses' and test on the fly
|
||||||
|
// defined in RasterizerStorageCommon::BatchFlags
|
||||||
|
unsigned int batch_flags;
|
||||||
|
|
||||||
bool uses_screen_texture;
|
bool uses_screen_texture;
|
||||||
bool uses_screen_uv;
|
bool uses_screen_uv;
|
||||||
bool uses_time;
|
bool uses_time;
|
||||||
|
bool uses_modulate;
|
||||||
|
bool uses_color;
|
||||||
|
bool uses_vertex;
|
||||||
|
|
||||||
} canvas_item;
|
} canvas_item;
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,23 @@
|
||||||
|
|
||||||
layout(location = 0) in highp vec2 vertex;
|
layout(location = 0) in highp vec2 vertex;
|
||||||
|
|
||||||
#ifdef USE_LIGHT_ANGLE
|
#ifdef USE_ATTRIB_LIGHT_ANGLE
|
||||||
layout(location = 2) in highp float light_angle;
|
layout(location = 2) in highp float light_angle;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
layout(location = 3) in vec4 color_attrib;
|
layout(location = 3) in vec4 color_attrib;
|
||||||
|
|
||||||
|
#ifdef USE_ATTRIB_MODULATE
|
||||||
|
layout(location = 5) in vec4 modulate_attrib; // attrib:5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_ATTRIB_LARGE_VERTEX
|
||||||
|
// shared with skeleton attributes, not used in batched shader
|
||||||
|
layout(location = 6) in vec2 translate_attrib; // attrib:6
|
||||||
|
layout(location = 7) in vec4 basis_attrib; // attrib:7
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_SKELETON
|
#ifdef USE_SKELETON
|
||||||
layout(location = 6) in uvec4 bone_indices; // attrib:6
|
layout(location = 6) in uvec4 bone_indices; // attrib:6
|
||||||
layout(location = 7) in vec4 bone_weights; // attrib:7
|
layout(location = 7) in vec4 bone_weights; // attrib:7
|
||||||
|
@ -53,6 +63,12 @@ uniform highp mat4 extra_matrix;
|
||||||
|
|
||||||
out highp vec2 uv_interp;
|
out highp vec2 uv_interp;
|
||||||
out mediump vec4 color_interp;
|
out mediump vec4 color_interp;
|
||||||
|
|
||||||
|
#ifdef USE_ATTRIB_MODULATE
|
||||||
|
// modulate doesn't need interpolating but we need to send it to the fragment shader
|
||||||
|
out mediump vec4 modulate_interp;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef MODULATE_USED
|
#ifdef MODULATE_USED
|
||||||
uniform mediump vec4 final_modulate;
|
uniform mediump vec4 final_modulate;
|
||||||
#endif
|
#endif
|
||||||
|
@ -177,6 +193,23 @@ VERTEX_SHADER_CODE
|
||||||
pixel_size_interp = abs(dst_rect.zw) * vertex;
|
pixel_size_interp = abs(dst_rect.zw) * vertex;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_ATTRIB_MODULATE
|
||||||
|
// modulate doesn't need interpolating but we need to send it to the fragment shader
|
||||||
|
modulate_interp = modulate_attrib;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_ATTRIB_LARGE_VERTEX
|
||||||
|
// transform is in attributes
|
||||||
|
vec2 temp;
|
||||||
|
|
||||||
|
temp = outvec.xy;
|
||||||
|
temp.x = (outvec.x * basis_attrib.x) + (outvec.y * basis_attrib.z);
|
||||||
|
temp.y = (outvec.x * basis_attrib.y) + (outvec.y * basis_attrib.w);
|
||||||
|
|
||||||
|
temp += translate_attrib;
|
||||||
|
outvec.xy = temp;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(SKIP_TRANSFORM_USED)
|
#if !defined(SKIP_TRANSFORM_USED)
|
||||||
outvec = extra_matrix * outvec;
|
outvec = extra_matrix * outvec;
|
||||||
outvec = modelview_matrix * outvec;
|
outvec = modelview_matrix * outvec;
|
||||||
|
@ -253,7 +286,7 @@ VERTEX_SHADER_CODE
|
||||||
pos = outvec.xy;
|
pos = outvec.xy;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_LIGHT_ANGLE
|
#ifdef USE_ATTRIB_LIGHT_ANGLE
|
||||||
// we add a fixed offset because we are using the sign later,
|
// we add a fixed offset because we are using the sign later,
|
||||||
// and don't want floating point error around 0.0
|
// and don't want floating point error around 0.0
|
||||||
float la = abs(light_angle) - 1.0;
|
float la = abs(light_angle) - 1.0;
|
||||||
|
@ -294,6 +327,10 @@ uniform mediump sampler2D normal_texture; // texunit:1
|
||||||
in highp vec2 uv_interp;
|
in highp vec2 uv_interp;
|
||||||
in mediump vec4 color_interp;
|
in mediump vec4 color_interp;
|
||||||
|
|
||||||
|
#ifdef USE_ATTRIB_MODULATE
|
||||||
|
in mediump vec4 modulate_interp;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(SCREEN_TEXTURE_USED)
|
#if defined(SCREEN_TEXTURE_USED)
|
||||||
|
|
||||||
uniform sampler2D screen_texture; // texunit:-3
|
uniform sampler2D screen_texture; // texunit:-3
|
||||||
|
@ -410,16 +447,14 @@ uniform bool np_draw_center;
|
||||||
// left top right bottom in pixel coordinates
|
// left top right bottom in pixel coordinates
|
||||||
uniform vec4 np_margins;
|
uniform vec4 np_margins;
|
||||||
|
|
||||||
float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, float margin_begin, float margin_end, float s_ratio, int np_repeat, inout int draw_center) {
|
float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, float margin_begin, float margin_end, int np_repeat, inout int draw_center) {
|
||||||
|
|
||||||
float tex_size = 1.0 / tex_pixel_size;
|
float tex_size = 1.0 / tex_pixel_size;
|
||||||
|
|
||||||
float screen_margin_begin = margin_begin / s_ratio;
|
if (pixel < margin_begin) {
|
||||||
float screen_margin_end = margin_end / s_ratio;
|
return pixel * tex_pixel_size;
|
||||||
if (pixel < screen_margin_begin) {
|
} else if (pixel >= draw_size - margin_end) {
|
||||||
return pixel * s_ratio * tex_pixel_size;
|
return (tex_size - (draw_size - pixel)) * tex_pixel_size;
|
||||||
} else if (pixel >= draw_size - screen_margin_end) {
|
|
||||||
return (tex_size - (draw_size - pixel) * s_ratio) * tex_pixel_size;
|
|
||||||
} else {
|
} else {
|
||||||
if (!np_draw_center) {
|
if (!np_draw_center) {
|
||||||
draw_center--;
|
draw_center--;
|
||||||
|
@ -428,21 +463,21 @@ float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, flo
|
||||||
// np_repeat is passed as uniform using NinePatchRect::AxisStretchMode enum.
|
// np_repeat is passed as uniform using NinePatchRect::AxisStretchMode enum.
|
||||||
if (np_repeat == 0) { // Stretch.
|
if (np_repeat == 0) { // Stretch.
|
||||||
// Convert to ratio.
|
// Convert to ratio.
|
||||||
float ratio = (pixel - screen_margin_begin) / (draw_size - screen_margin_begin - screen_margin_end);
|
float ratio = (pixel - margin_begin) / (draw_size - margin_begin - margin_end);
|
||||||
// Scale to source texture.
|
// Scale to source texture.
|
||||||
return (margin_begin + ratio * (tex_size - margin_begin - margin_end)) * tex_pixel_size;
|
return (margin_begin + ratio * (tex_size - margin_begin - margin_end)) * tex_pixel_size;
|
||||||
} else if (np_repeat == 1) { // Tile.
|
} else if (np_repeat == 1) { // Tile.
|
||||||
// Convert to offset.
|
// Convert to offset.
|
||||||
float ofs = mod((pixel - screen_margin_begin), tex_size - margin_begin - margin_end);
|
float ofs = mod((pixel - margin_begin), tex_size - margin_begin - margin_end);
|
||||||
// Scale to source texture.
|
// Scale to source texture.
|
||||||
return (margin_begin + ofs) * tex_pixel_size;
|
return (margin_begin + ofs) * tex_pixel_size;
|
||||||
} else if (np_repeat == 2) { // Tile Fit.
|
} else if (np_repeat == 2) { // Tile Fit.
|
||||||
// Calculate scale.
|
// Calculate scale.
|
||||||
float src_area = draw_size - screen_margin_begin - screen_margin_end;
|
float src_area = draw_size - margin_begin - margin_end;
|
||||||
float dst_area = tex_size - margin_begin - margin_end;
|
float dst_area = tex_size - margin_begin - margin_end;
|
||||||
float scale = max(1.0, floor(src_area / max(dst_area, 0.0000001) + 0.5));
|
float scale = max(1.0, floor(src_area / max(dst_area, 0.0000001) + 0.5));
|
||||||
// Convert to ratio.
|
// Convert to ratio.
|
||||||
float ratio = (pixel - screen_margin_begin) / src_area;
|
float ratio = (pixel - margin_begin) / src_area;
|
||||||
ratio = mod(ratio * scale, 1.0);
|
ratio = mod(ratio * scale, 1.0);
|
||||||
// Scale to source texture.
|
// Scale to source texture.
|
||||||
return (margin_begin + ratio * dst_area) * tex_pixel_size;
|
return (margin_begin + ratio * dst_area) * tex_pixel_size;
|
||||||
|
@ -467,11 +502,9 @@ void main() {
|
||||||
#ifdef USE_NINEPATCH
|
#ifdef USE_NINEPATCH
|
||||||
|
|
||||||
int draw_center = 2;
|
int draw_center = 2;
|
||||||
float s_ratio = max((1.0 / color_texpixel_size.x) / abs(dst_rect.z), (1.0 / color_texpixel_size.y) / abs(dst_rect.w));
|
|
||||||
s_ratio = max(1.0, s_ratio);
|
|
||||||
uv = vec2(
|
uv = vec2(
|
||||||
map_ninepatch_axis(pixel_size_interp.x, abs(dst_rect.z), color_texpixel_size.x, np_margins.x, np_margins.z, s_ratio, np_repeat_h, draw_center),
|
map_ninepatch_axis(pixel_size_interp.x, abs(dst_rect.z), color_texpixel_size.x, np_margins.x, np_margins.z, np_repeat_h, draw_center),
|
||||||
map_ninepatch_axis(pixel_size_interp.y, abs(dst_rect.w), color_texpixel_size.y, np_margins.y, np_margins.w, s_ratio, np_repeat_v, draw_center));
|
map_ninepatch_axis(pixel_size_interp.y, abs(dst_rect.w), color_texpixel_size.y, np_margins.y, np_margins.w, np_repeat_v, draw_center));
|
||||||
|
|
||||||
if (draw_center == 0) {
|
if (draw_center == 0) {
|
||||||
color.a = 0.0;
|
color.a = 0.0;
|
||||||
|
@ -549,6 +582,11 @@ FRAGMENT_SHADER_CODE
|
||||||
color *= final_modulate;
|
color *= final_modulate;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_ATTRIB_MODULATE
|
||||||
|
// todo .. this won't be used at the same time as MODULATE_USED
|
||||||
|
color *= modulate_interp;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_LIGHTING
|
#ifdef USE_LIGHTING
|
||||||
|
|
||||||
vec2 light_vec = transformed_light_uv;
|
vec2 light_vec = transformed_light_uv;
|
||||||
|
|
5
drivers/gles_common/SCsub
Normal file
5
drivers/gles_common/SCsub
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
Import("env")
|
||||||
|
|
||||||
|
env.add_source_files(env.drivers_sources, "*.cpp")
|
148
drivers/gles_common/batch_diagnose.inc
Normal file
148
drivers/gles_common/batch_diagnose.inc
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
String get_command_type_string(const RasterizerCanvas::Item::Command &p_command) const {
|
||||||
|
String sz = "";
|
||||||
|
|
||||||
|
switch (p_command.type) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case RasterizerCanvas::Item::Command::TYPE_LINE: {
|
||||||
|
sz = "l";
|
||||||
|
} break;
|
||||||
|
case RasterizerCanvas::Item::Command::TYPE_POLYLINE: {
|
||||||
|
sz = "PL";
|
||||||
|
} break;
|
||||||
|
case RasterizerCanvas::Item::Command::TYPE_RECT: {
|
||||||
|
sz = "r";
|
||||||
|
} break;
|
||||||
|
case RasterizerCanvas::Item::Command::TYPE_NINEPATCH: {
|
||||||
|
sz = "n";
|
||||||
|
} break;
|
||||||
|
case RasterizerCanvas::Item::Command::TYPE_PRIMITIVE: {
|
||||||
|
sz = "PR";
|
||||||
|
} break;
|
||||||
|
case RasterizerCanvas::Item::Command::TYPE_POLYGON: {
|
||||||
|
sz = "p";
|
||||||
|
} break;
|
||||||
|
case RasterizerCanvas::Item::Command::TYPE_MESH: {
|
||||||
|
sz = "m";
|
||||||
|
} break;
|
||||||
|
case RasterizerCanvas::Item::Command::TYPE_MULTIMESH: {
|
||||||
|
sz = "MM";
|
||||||
|
} break;
|
||||||
|
case RasterizerCanvas::Item::Command::TYPE_PARTICLES: {
|
||||||
|
sz = "PA";
|
||||||
|
} break;
|
||||||
|
case RasterizerCanvas::Item::Command::TYPE_CIRCLE: {
|
||||||
|
sz = "c";
|
||||||
|
} break;
|
||||||
|
case RasterizerCanvas::Item::Command::TYPE_TRANSFORM: {
|
||||||
|
sz = "t";
|
||||||
|
|
||||||
|
// add a bit more info in debug build
|
||||||
|
const RasterizerCanvas::Item::CommandTransform *transform = static_cast<const RasterizerCanvas::Item::CommandTransform *>(&p_command);
|
||||||
|
const Transform2D &mat = transform->xform;
|
||||||
|
|
||||||
|
sz += " ";
|
||||||
|
sz += String(Variant(mat.elements[2]));
|
||||||
|
sz += " ";
|
||||||
|
} break;
|
||||||
|
case RasterizerCanvas::Item::Command::TYPE_CLIP_IGNORE: {
|
||||||
|
sz = "CI";
|
||||||
|
} break;
|
||||||
|
} // switch
|
||||||
|
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
void diagnose_batches(RasterizerCanvas::Item::Command *const *p_commands) {
|
||||||
|
int num_batches = bdata.batches.size();
|
||||||
|
|
||||||
|
BatchColor curr_color;
|
||||||
|
curr_color.set(Color(-1, -1, -1, -1));
|
||||||
|
bool first_color_change = true;
|
||||||
|
|
||||||
|
for (int batch_num = 0; batch_num < num_batches; batch_num++) {
|
||||||
|
const Batch &batch = bdata.batches[batch_num];
|
||||||
|
bdata.frame_string += "\t\t\tbatch ";
|
||||||
|
|
||||||
|
switch (batch.type) {
|
||||||
|
|
||||||
|
case RasterizerStorageCommon::BT_POLY: {
|
||||||
|
bdata.frame_string += "P ";
|
||||||
|
bdata.frame_string += itos(batch.first_command) + "-";
|
||||||
|
bdata.frame_string += itos(batch.num_commands);
|
||||||
|
|
||||||
|
bdata.frame_string += " " + batch.color.to_string();
|
||||||
|
|
||||||
|
if (batch.num_commands > 1) {
|
||||||
|
bdata.frame_string += " MULTI";
|
||||||
|
}
|
||||||
|
if (curr_color != batch.color) {
|
||||||
|
curr_color = batch.color;
|
||||||
|
if (!first_color_change) {
|
||||||
|
bdata.frame_string += " color";
|
||||||
|
} else {
|
||||||
|
first_color_change = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bdata.frame_string += "\n";
|
||||||
|
} break;
|
||||||
|
case RasterizerStorageCommon::BT_LINE:
|
||||||
|
case RasterizerStorageCommon::BT_LINE_AA: {
|
||||||
|
bdata.frame_string += "L ";
|
||||||
|
bdata.frame_string += itos(batch.first_command) + "-";
|
||||||
|
bdata.frame_string += itos(batch.num_commands);
|
||||||
|
|
||||||
|
bdata.frame_string += " " + batch.color.to_string();
|
||||||
|
|
||||||
|
if (batch.num_commands > 1) {
|
||||||
|
bdata.frame_string += " MULTI";
|
||||||
|
}
|
||||||
|
if (curr_color != batch.color) {
|
||||||
|
curr_color = batch.color;
|
||||||
|
if (!first_color_change) {
|
||||||
|
bdata.frame_string += " color";
|
||||||
|
} else {
|
||||||
|
first_color_change = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bdata.frame_string += "\n";
|
||||||
|
} break;
|
||||||
|
case RasterizerStorageCommon::BT_RECT: {
|
||||||
|
bdata.frame_string += "R ";
|
||||||
|
bdata.frame_string += itos(batch.first_command) + "-";
|
||||||
|
bdata.frame_string += itos(batch.num_commands);
|
||||||
|
|
||||||
|
int tex_id = (int)bdata.batch_textures[batch.batch_texture_id].RID_texture.get_id();
|
||||||
|
bdata.frame_string += " [" + itos(batch.batch_texture_id) + " - " + itos(tex_id) + "]";
|
||||||
|
|
||||||
|
bdata.frame_string += " " + batch.color.to_string();
|
||||||
|
|
||||||
|
if (batch.num_commands > 1) {
|
||||||
|
bdata.frame_string += " MULTI";
|
||||||
|
}
|
||||||
|
if (curr_color != batch.color) {
|
||||||
|
curr_color = batch.color;
|
||||||
|
if (!first_color_change) {
|
||||||
|
bdata.frame_string += " color";
|
||||||
|
} else {
|
||||||
|
first_color_change = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bdata.frame_string += "\n";
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
bdata.frame_string += "D ";
|
||||||
|
bdata.frame_string += itos(batch.first_command) + "-";
|
||||||
|
bdata.frame_string += itos(batch.num_commands) + " ";
|
||||||
|
|
||||||
|
int num_show = MIN(batch.num_commands, 16);
|
||||||
|
for (int n = 0; n < num_show; n++) {
|
||||||
|
const RasterizerCanvas::Item::Command &comm = *p_commands[batch.first_command + n];
|
||||||
|
bdata.frame_string += get_command_type_string(comm) + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
bdata.frame_string += "\n";
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
/* rasterizer_array_gles2.h */
|
/* rasterizer_array.h */
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
/* This file is part of: */
|
/* This file is part of: */
|
||||||
/* GODOT ENGINE */
|
/* GODOT ENGINE */
|
||||||
|
@ -30,36 +30,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/*************************************************************************/
|
|
||||||
/* rasterizer_array_gles2.h */
|
|
||||||
/*************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/*************************************************************************/
|
|
||||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/*************************************************************************/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fast single-threaded growable array for POD types.
|
* Fast single-threaded growable array for POD types.
|
||||||
* For use in render drivers, not for general use.
|
* For use in render drivers, not for general use.
|
||||||
|
@ -141,14 +111,14 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class RasterizerArrayGLES2 {
|
class RasterizerArray {
|
||||||
public:
|
public:
|
||||||
RasterizerArrayGLES2() {
|
RasterizerArray() {
|
||||||
_list = 0;
|
_list = 0;
|
||||||
_size = 0;
|
_size = 0;
|
||||||
_max_size = 0;
|
_max_size = 0;
|
||||||
}
|
}
|
||||||
~RasterizerArrayGLES2() { free(); }
|
~RasterizerArray() { free(); }
|
||||||
|
|
||||||
T &operator[](unsigned int ui) { return _list[ui]; }
|
T &operator[](unsigned int ui) { return _list[ui]; }
|
||||||
const T &operator[](unsigned int ui) const { return _list[ui]; }
|
const T &operator[](unsigned int ui) const { return _list[ui]; }
|
||||||
|
@ -208,7 +178,7 @@ public:
|
||||||
int max_size() const { return _max_size; }
|
int max_size() const { return _max_size; }
|
||||||
const T *get_data() const { return _list; }
|
const T *get_data() const { return _list; }
|
||||||
|
|
||||||
bool copy_from(const RasterizerArrayGLES2<T> &o) {
|
bool copy_from(const RasterizerArray<T> &o) {
|
||||||
// no resizing done here, it should be done manually
|
// no resizing done here, it should be done manually
|
||||||
if (o.size() > _max_size)
|
if (o.size() > _max_size)
|
||||||
return false;
|
return false;
|
||||||
|
@ -247,9 +217,9 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class RasterizerArray_non_pod_GLES2 {
|
class RasterizerArray_non_pod {
|
||||||
public:
|
public:
|
||||||
RasterizerArray_non_pod_GLES2() {
|
RasterizerArray_non_pod() {
|
||||||
_size = 0;
|
_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,3 +257,72 @@ private:
|
||||||
Vector<T> _list;
|
Vector<T> _list;
|
||||||
int _size;
|
int _size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// very simple non-growable array, that keeps track of the size of a 'unit'
|
||||||
|
// which can be cast to whatever vertex format FVF required, and is initially
|
||||||
|
// created with enough memory to hold the biggest FVF.
|
||||||
|
// This allows multiple FVFs to use the same array.
|
||||||
|
class RasterizerUnitArray {
|
||||||
|
public:
|
||||||
|
RasterizerUnitArray() {
|
||||||
|
_list = nullptr;
|
||||||
|
free();
|
||||||
|
}
|
||||||
|
~RasterizerUnitArray() { free(); }
|
||||||
|
|
||||||
|
uint8_t *get_unit(unsigned int ui) { return &_list[ui * _unit_size_bytes]; }
|
||||||
|
const uint8_t *get_unit(unsigned int ui) const { return &_list[ui * _unit_size_bytes]; }
|
||||||
|
|
||||||
|
int size() const { return _size; }
|
||||||
|
int max_size() const { return _max_size; }
|
||||||
|
|
||||||
|
void free() {
|
||||||
|
if (_list) {
|
||||||
|
memdelete_arr(_list);
|
||||||
|
_list = 0;
|
||||||
|
}
|
||||||
|
_size = 0;
|
||||||
|
_max_size = 0;
|
||||||
|
_max_size_bytes = 0;
|
||||||
|
_unit_size_bytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void create(int p_max_size_units, int p_max_unit_size_bytes) {
|
||||||
|
free();
|
||||||
|
|
||||||
|
_max_unit_size_bytes = p_max_unit_size_bytes;
|
||||||
|
_max_size = p_max_size_units;
|
||||||
|
_max_size_bytes = p_max_size_units * p_max_unit_size_bytes;
|
||||||
|
|
||||||
|
if (_max_size_bytes) {
|
||||||
|
_list = memnew_arr(uint8_t, _max_size_bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepare(int p_unit_size_bytes) {
|
||||||
|
_unit_size_bytes = p_unit_size_bytes;
|
||||||
|
_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// several items at a time
|
||||||
|
uint8_t *request(int p_num_items = 1) {
|
||||||
|
int old_size = _size;
|
||||||
|
_size += p_num_items;
|
||||||
|
|
||||||
|
if (_size <= _max_size) {
|
||||||
|
return get_unit(old_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// revert
|
||||||
|
_size = old_size;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t *_list;
|
||||||
|
int _size; // in units
|
||||||
|
int _max_size; // in units
|
||||||
|
int _max_size_bytes;
|
||||||
|
int _unit_size_bytes;
|
||||||
|
int _max_unit_size_bytes;
|
||||||
|
};
|
2926
drivers/gles_common/rasterizer_canvas_batcher.h
Normal file
2926
drivers/gles_common/rasterizer_canvas_batcher.h
Normal file
File diff suppressed because it is too large
Load diff
71
drivers/gles_common/rasterizer_storage_common.h
Normal file
71
drivers/gles_common/rasterizer_storage_common.h
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* rasterizer_storage_common.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class RasterizerStorageCommon {
|
||||||
|
public:
|
||||||
|
enum FVF {
|
||||||
|
FVF_UNBATCHED,
|
||||||
|
FVF_REGULAR,
|
||||||
|
FVF_COLOR,
|
||||||
|
FVF_LIGHT_ANGLE,
|
||||||
|
FVF_MODULATED,
|
||||||
|
FVF_LARGE,
|
||||||
|
};
|
||||||
|
|
||||||
|
// these flags are specifically for batching
|
||||||
|
// some of the logic is thus in rasterizer_storage.cpp
|
||||||
|
// we could alternatively set bitflags for each 'uses' and test on the fly
|
||||||
|
enum BatchFlags {
|
||||||
|
PREVENT_COLOR_BAKING = 1 << 0,
|
||||||
|
PREVENT_VERTEX_BAKING = 1 << 1,
|
||||||
|
|
||||||
|
USE_MODULATE_FVF = 1 << 2,
|
||||||
|
USE_LARGE_FVF = 1 << 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BatchType : uint16_t {
|
||||||
|
BT_DEFAULT = 0,
|
||||||
|
BT_RECT = 1,
|
||||||
|
BT_LINE = 2,
|
||||||
|
BT_LINE_AA = 3,
|
||||||
|
BT_POLY = 4,
|
||||||
|
BT_DUMMY = 5, // dummy batch is just used to keep the batch creation loop simple
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BatchTypeFlags {
|
||||||
|
BTF_DEFAULT = 1 << BT_DEFAULT,
|
||||||
|
BTF_RECT = 1 << BT_RECT,
|
||||||
|
BTF_LINE = 1 << BT_LINE,
|
||||||
|
BTF_LINE_AA = 1 << BT_LINE_AA,
|
||||||
|
BTF_POLY = 1 << BT_POLY,
|
||||||
|
};
|
||||||
|
};
|
|
@ -53,6 +53,8 @@
|
||||||
#include "scene/main/viewport.h"
|
#include "scene/main/viewport.h"
|
||||||
#include "scene/resources/packed_scene.h"
|
#include "scene/resources/packed_scene.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
// Min and Max are power of two in order to play nicely with successive increment.
|
// Min and Max are power of two in order to play nicely with successive increment.
|
||||||
// That way, we can naturally reach a 100% zoom from boundaries.
|
// That way, we can naturally reach a 100% zoom from boundaries.
|
||||||
#define MIN_ZOOM 1. / 128
|
#define MIN_ZOOM 1. / 128
|
||||||
|
|
|
@ -116,6 +116,7 @@ def configure(env):
|
||||||
env.Prepend(CCFLAGS=["-g2"])
|
env.Prepend(CCFLAGS=["-g2"])
|
||||||
|
|
||||||
elif env["target"] == "debug":
|
elif env["target"] == "debug":
|
||||||
|
env.Prepend(CCFLAGS=["-ggdb"])
|
||||||
env.Prepend(CCFLAGS=["-g3"])
|
env.Prepend(CCFLAGS=["-g3"])
|
||||||
env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
|
env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
|
||||||
env.Append(LINKFLAGS=["-rdynamic"])
|
env.Append(LINKFLAGS=["-rdynamic"])
|
||||||
|
|
|
@ -1180,6 +1180,8 @@ public:
|
||||||
|
|
||||||
virtual bool is_low_end() const = 0;
|
virtual bool is_low_end() const = 0;
|
||||||
|
|
||||||
|
virtual const char *gl_check_for_error(bool p_print_error = true) = 0;
|
||||||
|
|
||||||
virtual ~Rasterizer() {}
|
virtual ~Rasterizer() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2439,6 +2439,10 @@ VisualServer::VisualServer() {
|
||||||
GLOBAL_DEF(sz_balance_render_tree, 0.17f);
|
GLOBAL_DEF(sz_balance_render_tree, 0.17f);
|
||||||
ProjectSettings::get_singleton()->set_custom_property_info(sz_balance_render_tree, PropertyInfo(Variant::REAL, sz_balance_render_tree, PROPERTY_HINT_RANGE, "0.0,1.0,0.01"));
|
ProjectSettings::get_singleton()->set_custom_property_info(sz_balance_render_tree, PropertyInfo(Variant::REAL, sz_balance_render_tree, PROPERTY_HINT_RANGE, "0.0,1.0,0.01"));
|
||||||
|
|
||||||
|
GLOBAL_DEF("rendering/quality/2d/use_software_skinning", true);
|
||||||
|
GLOBAL_DEF("rendering/quality/2d/ninepatch_mode", 0);
|
||||||
|
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/2d/ninepatch_mode", PropertyInfo(Variant::INT, "rendering/quality/2d/ninepatch_mode", PROPERTY_HINT_ENUM, "Default,Scaling"));
|
||||||
|
|
||||||
GLOBAL_DEF("rendering/batching/options/use_batching", true);
|
GLOBAL_DEF("rendering/batching/options/use_batching", true);
|
||||||
GLOBAL_DEF_RST("rendering/batching/options/use_batching_in_editor", true);
|
GLOBAL_DEF_RST("rendering/batching/options/use_batching_in_editor", true);
|
||||||
GLOBAL_DEF("rendering/batching/options/single_rect_fallback", false);
|
GLOBAL_DEF("rendering/batching/options/single_rect_fallback", false);
|
||||||
|
|
Loading…
Reference in a new issue