Skip to content

Commit

Permalink
Added stencil support for GLES3
Browse files Browse the repository at this point in the history
  • Loading branch information
apples committed Aug 24, 2023
1 parent 8dd46d0 commit c6f581b
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 12 deletions.
88 changes: 86 additions & 2 deletions drivers/gles3/rasterizer_scene_gles3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1942,10 +1942,14 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_STENCIL_TEST);

glColorMask(0, 0, 0, 0);
glClearDepth(1.0f);
glClear(GL_DEPTH_BUFFER_BIT);
glClearStencil(0);
glStencilMask(255);
scene_state.current_stencil_write_mask = 255;
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
uint64_t spec_constant = SceneShaderGLES3::DISABLE_FOG | SceneShaderGLES3::DISABLE_LIGHT_DIRECTIONAL |
SceneShaderGLES3::DISABLE_LIGHTMAP | SceneShaderGLES3::DISABLE_LIGHT_OMNI |
SceneShaderGLES3::DISABLE_LIGHT_SPOT;
Expand Down Expand Up @@ -1976,11 +1980,25 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE);
scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
scene_state.current_depth_function = GLES3::SceneShaderData::DEPTH_FUNCTION_LESS_OR_EQUAL;
scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_ALWAYS;

glDisable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0, 255);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(255);
scene_state.current_stencil_enabled = false;
scene_state.current_stencil_compare = GL_ALWAYS;
scene_state.current_stencil_reference = 0;
scene_state.current_stencil_compare_mask = 255;
scene_state.current_stencil_op_dpfail = GL_KEEP;
scene_state.current_stencil_op_dppass = GL_KEEP;
scene_state.current_stencil_write_mask = 255;

if (!fb_cleared) {
glClearDepth(1.0f);
glClear(GL_DEPTH_BUFFER_BIT);
glClearStencil(0);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}

if (!keep_color) {
Expand All @@ -2005,6 +2023,9 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_

_render_list_template<PASS_MODE_COLOR>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_OPAQUE].elements.size());

glDisable(GL_STENCIL_TEST);
scene_state.current_stencil_enabled = false;

glDepthMask(GL_FALSE);
scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_DISABLED;

Expand Down Expand Up @@ -2053,6 +2074,9 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_

_render_list_template<PASS_MODE_COLOR_TRANSPARENT>(&render_list_params_alpha, &render_data, 0, render_list[RENDER_LIST_ALPHA].elements.size(), true);

glDisable(GL_STENCIL_TEST);
scene_state.current_stencil_enabled = false;

if (!flip_y) {
// Restore the default winding order.
glFrontFace(GL_CCW);
Expand Down Expand Up @@ -2204,6 +2228,66 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
scene_state.current_depth_draw = shader->depth_draw;
}

if (scene_state.current_stencil_enabled != shader->stencil_enabled) {
if (shader->stencil_enabled) {
glEnable(GL_STENCIL_TEST);
scene_state.current_stencil_enabled = true;
} else {
glDisable(GL_STENCIL_TEST);
scene_state.current_stencil_enabled = false;
}
}

if (scene_state.current_stencil_enabled) {
GLenum stencil_compare_table[GLES3::SceneShaderData::STENCIL_COMPARE_MAX] = {
GL_LESS,
GL_EQUAL,
GL_LEQUAL,
GL_GREATER,
GL_NOTEQUAL,
GL_GEQUAL,
GL_ALWAYS,
};

GLenum stencil_compare = stencil_compare_table[shader->stencil_compare];
GLuint stencil_compare_mask = 0;
GLuint stencil_write_mask = 0;
GLenum stencil_op_dpfail = GL_KEEP;
GLenum stencil_op_dppass = GL_KEEP;

if (shader->stencil_flags & GLES3::SceneShaderData::STENCIL_FLAG_READ) {
stencil_compare_mask = shader->stencil_compare_mask;
}

if (shader->stencil_flags & GLES3::SceneShaderData::STENCIL_FLAG_WRITE) {
stencil_op_dppass = GL_REPLACE;
stencil_write_mask = shader->stencil_write_mask;
}

if (shader->stencil_flags & GLES3::SceneShaderData::STENCIL_FLAG_WRITE_DEPTH_FAIL) {
stencil_op_dpfail = GL_REPLACE;
stencil_write_mask = shader->stencil_write_mask;
}

if (scene_state.current_stencil_compare != stencil_compare || scene_state.current_stencil_reference != shader->stencil_reference || scene_state.current_stencil_compare_mask != shader->stencil_compare_mask) {
glStencilFunc(stencil_compare, shader->stencil_reference, stencil_compare_mask);
scene_state.current_stencil_compare = stencil_compare;
scene_state.current_stencil_reference = shader->stencil_reference;
scene_state.current_stencil_compare_mask = stencil_compare_mask;
}

if (scene_state.current_stencil_write_mask != stencil_write_mask) {
glStencilMask(stencil_write_mask);
scene_state.current_stencil_write_mask = stencil_write_mask;
}

if (scene_state.current_stencil_op_dpfail != stencil_op_dpfail || scene_state.current_stencil_op_dppass != stencil_op_dppass) {
glStencilOp(GL_KEEP, stencil_op_dpfail, stencil_op_dppass);
scene_state.current_stencil_op_dpfail = stencil_op_dpfail;
scene_state.current_stencil_op_dppass = stencil_op_dppass;
}
}

if constexpr (p_pass_mode == PASS_MODE_COLOR_TRANSPARENT || p_pass_mode == PASS_MODE_COLOR_ADDITIVE) {
GLES3::SceneShaderData::BlendMode desired_blend_mode;
if constexpr (p_pass_mode == PASS_MODE_COLOR_ADDITIVE) {
Expand Down
8 changes: 8 additions & 0 deletions drivers/gles3/rasterizer_scene_gles3.h
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,14 @@ class RasterizerSceneGLES3 : public RendererSceneRender {
GLES3::SceneShaderData::DepthFunction current_depth_function = GLES3::SceneShaderData::DEPTH_FUNCTION_LESS_OR_EQUAL;
GLES3::SceneShaderData::Cull cull_mode = GLES3::SceneShaderData::CULL_BACK;

GLenum current_stencil_compare = GL_ALWAYS;
GLuint current_stencil_compare_mask = 255;
GLuint current_stencil_write_mask = 255;
GLint current_stencil_reference = 0;
GLenum current_stencil_op_dpfail = GL_KEEP;
GLenum current_stencil_op_dppass = GL_KEEP;
bool current_stencil_enabled = false;

bool texscreen_copied = false;
bool used_screen_texture = false;
bool used_normal_texture = false;
Expand Down
30 changes: 30 additions & 0 deletions drivers/gles3/storage/material_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2843,6 +2843,12 @@ void SceneShaderData::set_code(const String &p_code) {
int cull_modei = CULL_BACK;
int depth_drawi = DEPTH_DRAW_OPAQUE;

int stencil_readi = 0;
int stencil_writei = 0;
int stencil_write_depth_faili = 0;
int stencil_comparei = STENCIL_COMPARE_ALWAYS;
int stencil_referencei = -1;

uses_point_size = false;
uses_alpha = false;
uses_alpha_clip = false;
Expand Down Expand Up @@ -2938,6 +2944,20 @@ void SceneShaderData::set_code(const String &p_code) {
actions.usage_flag_pointers["BONE_INDICES"] = &uses_bones;
actions.usage_flag_pointers["BONE_WEIGHTS"] = &uses_weights;

actions.stencil_mode_values["read"] = Pair<int *, int>(&stencil_readi, STENCIL_FLAG_READ);
actions.stencil_mode_values["write"] = Pair<int *, int>(&stencil_writei, STENCIL_FLAG_WRITE);
actions.stencil_mode_values["write_depth_fail"] = Pair<int *, int>(&stencil_write_depth_faili, STENCIL_FLAG_WRITE_DEPTH_FAIL);

actions.stencil_mode_values["compare_less"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_LESS);
actions.stencil_mode_values["compare_equal"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_EQUAL);
actions.stencil_mode_values["compare_less_or_equal"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_LESS_OR_EQUAL);
actions.stencil_mode_values["compare_greater"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_GREATER);
actions.stencil_mode_values["compare_not_equal"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_NOT_EQUAL);
actions.stencil_mode_values["compare_greater_or_equal"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_GREATER_OR_EQUAL);
actions.stencil_mode_values["compare_always"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_ALWAYS);

actions.stencil_reference = &stencil_referencei;

actions.uniforms = &uniforms;

Error err = MaterialStorage::get_singleton()->shaders.compiler_scene.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
Expand Down Expand Up @@ -2971,6 +2991,16 @@ void SceneShaderData::set_code(const String &p_code) {
uses_vertex_time = gen_code.uses_vertex_time;
uses_fragment_time = gen_code.uses_fragment_time;

stencil_enabled = stencil_referencei != -1;
stencil_flags = stencil_readi | stencil_writei | stencil_write_depth_faili;
stencil_compare = StencilCompare(stencil_comparei);
stencil_reference = stencil_referencei;

bool stencil_mask_uses_ref = bool(GLOBAL_GET("rendering/driver/stencil/mask_uses_ref"));
uint32_t stencil_mask = stencil_mask_uses_ref ? stencil_reference : 255;
stencil_compare_mask = stencil_mask;
stencil_write_mask = stencil_mask;

#ifdef DEBUG_ENABLED
if (uses_particle_trails) {
WARN_PRINT_ONCE_ED("Particle trails are only available when using the Forward+ or Mobile rendering backends.");
Expand Down
24 changes: 24 additions & 0 deletions drivers/gles3/storage/material_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,23 @@ struct SceneShaderData : public ShaderData {
DEPTH_FUNCTION_MAX
};

enum StencilCompare {
STENCIL_COMPARE_LESS,
STENCIL_COMPARE_EQUAL,
STENCIL_COMPARE_LESS_OR_EQUAL,
STENCIL_COMPARE_GREATER,
STENCIL_COMPARE_NOT_EQUAL,
STENCIL_COMPARE_GREATER_OR_EQUAL,
STENCIL_COMPARE_ALWAYS,
STENCIL_COMPARE_MAX // not an actual operator, just the amount of operators
};

enum StencilFlags {
STENCIL_FLAG_READ = 1,
STENCIL_FLAG_WRITE = 2,
STENCIL_FLAG_WRITE_DEPTH_FAIL = 4,
};

enum Cull {
CULL_DISABLED,
CULL_FRONT,
Expand Down Expand Up @@ -293,6 +310,13 @@ struct SceneShaderData : public ShaderData {
DepthFunction depth_function;
Cull cull_mode;

StencilCompare stencil_compare;
uint32_t stencil_flags;
uint32_t stencil_compare_mask;
uint32_t stencil_write_mask;
int32_t stencil_reference;
bool stencil_enabled;

bool uses_point_size;
bool uses_alpha;
bool uses_blend_alpha;
Expand Down
48 changes: 38 additions & 10 deletions drivers/gles3/storage/texture_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1722,31 +1722,35 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
ERR_FAIL_COND(!texture);

rt->depth = texture->tex_id;
rt->depth_has_stencil = rt->overridden.depth_has_stencil;
} else {
glGenTextures(1, &rt->depth);
glBindTexture(texture_target, rt->depth);

if (use_multiview) {
glTexImage3D(texture_target, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, rt->view_count, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
glTexImage3D(texture_target, 0, GL_DEPTH24_STENCIL8, rt->size.x, rt->size.y, rt->view_count, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
} else {
glTexImage2D(texture_target, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
glTexImage2D(texture_target, 0, GL_DEPTH24_STENCIL8, rt->size.x, rt->size.y, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
}

glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

GLES3::Utilities::get_singleton()->texture_allocated_data(rt->depth, rt->size.x * rt->size.y * rt->view_count * 3, "Render target depth texture");
rt->depth_has_stencil = true;

GLES3::Utilities::get_singleton()->texture_allocated_data(rt->depth, rt->size.x * rt->size.y * rt->view_count * 4, "Render target depth texture");
}

#ifndef IOS_ENABLED
if (use_multiview) {
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, rt->depth, 0, 0, rt->view_count);
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, rt->depth_has_stencil ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT, rt->depth, 0, 0, rt->view_count);
} else {
#else
{
#endif
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, rt->depth_has_stencil ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0);
}

GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
Expand Down Expand Up @@ -1893,25 +1897,46 @@ void GLES3::TextureStorage::copy_scene_to_backbuffer(RenderTarget *rt, const boo
if (rt->backbuffer_depth == 0 && uses_depth_texture) {
glGenTextures(1, &rt->backbuffer_depth);
glBindTexture(texture_target, rt->backbuffer_depth);

GLint internal_format;
GLenum format;
GLenum type;
GLenum attachment;
int element_size;

if (rt->depth_has_stencil) {
internal_format = GL_DEPTH24_STENCIL8;
format = GL_DEPTH_STENCIL;
type = GL_UNSIGNED_INT_24_8;
attachment = GL_DEPTH_STENCIL_ATTACHMENT;
element_size = 4;
} else {
internal_format = GL_DEPTH_COMPONENT24;
format = GL_DEPTH_COMPONENT;
type = GL_UNSIGNED_INT;
attachment = GL_DEPTH_ATTACHMENT;
element_size = 3;
}

if (use_multiview) {
glTexImage3D(texture_target, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, rt->view_count, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
glTexImage3D(texture_target, 0, internal_format, rt->size.x, rt->size.y, rt->view_count, 0, format, type, nullptr);
} else {
glTexImage2D(texture_target, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
glTexImage2D(texture_target, 0, internal_format, rt->size.x, rt->size.y, 0, format, type, nullptr);
}
GLES3::Utilities::get_singleton()->texture_allocated_data(rt->backbuffer_depth, rt->size.x * rt->size.y * rt->view_count * 3, "Render target backbuffer depth texture");
GLES3::Utilities::get_singleton()->texture_allocated_data(rt->backbuffer_depth, rt->size.x * rt->size.y * rt->view_count * element_size, "Render target backbuffer depth texture");

glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#ifndef IOS_ENABLED
if (use_multiview) {
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, rt->backbuffer_depth, 0, 0, rt->view_count);
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, attachment, rt->backbuffer_depth, 0, 0, rt->view_count);
} else {
#else
{
#endif
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->backbuffer_depth, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, rt->backbuffer_depth, 0);
}
}
}
Expand Down Expand Up @@ -2083,6 +2108,7 @@ void TextureStorage::render_target_set_override(RID p_render_target, RID p_color

rt->overridden.color = p_color_texture;
rt->overridden.depth = p_depth_texture;
rt->overridden.depth_has_stencil = false;
rt->overridden.is_overridden = true;

uint32_t hash_key = hash_murmur3_one_64(p_color_texture.get_id());
Expand All @@ -2094,6 +2120,7 @@ void TextureStorage::render_target_set_override(RID p_render_target, RID p_color
rt->fbo = cache->get().fbo;
rt->color = cache->get().color;
rt->depth = cache->get().depth;
rt->depth_has_stencil = cache->get().depth_has_stencil;
rt->size = cache->get().size;
rt->texture = p_color_texture;
return;
Expand All @@ -2105,6 +2132,7 @@ void TextureStorage::render_target_set_override(RID p_render_target, RID p_color
new_entry.fbo = rt->fbo;
new_entry.color = rt->color;
new_entry.depth = rt->depth;
new_entry.depth_has_stencil = rt->depth_has_stencil;
new_entry.size = rt->size;
// Keep track of any textures we had to allocate because they weren't overridden.
if (p_color_texture.is_null()) {
Expand Down
3 changes: 3 additions & 0 deletions drivers/gles3/storage/texture_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ struct RenderTarget {
GLuint backbuffer_fbo = 0;
GLuint backbuffer = 0;
GLuint backbuffer_depth = 0;
bool depth_has_stencil = true;

GLuint color_internal_format = GL_RGBA8;
GLuint color_format = GL_RGBA;
Expand All @@ -378,6 +379,7 @@ struct RenderTarget {

struct RTOverridden {
bool is_overridden = false;
bool depth_has_stencil = false;
RID color;
RID depth;
RID velocity;
Expand All @@ -388,6 +390,7 @@ struct RenderTarget {
GLuint depth;
Size2i size;
Vector<GLuint> allocated_textures;
bool depth_has_stencil;
};
RBMap<uint32_t, FBOCacheEntry> fbo_cache;
} overridden;
Expand Down

0 comments on commit c6f581b

Please sign in to comment.