From c55ed36f2cfc299341910da40d72972e41d05bbb Mon Sep 17 00:00:00 2001 From: omigamedev Date: Wed, 30 Jan 2019 15:43:45 +0100 Subject: [PATCH] glsl framebuffer_fetch extension check at runtime --- src/app_shaders.cpp | 31 ++++++++++++---- src/canvas.cpp | 88 +++++++++++++++++++++++++++++---------------- src/node_canvas.cpp | 27 +++++++------- src/shader.cpp | 2 ++ src/shader.h | 1 + 5 files changed, 99 insertions(+), 50 deletions(-) diff --git a/src/app_shaders.cpp b/src/app_shaders.cpp index 4283abd..7861818 100644 --- a/src/app_shaders.cpp +++ b/src/app_shaders.cpp @@ -63,6 +63,13 @@ " return fract(sin(sn) * c);\n"\ "}\n" +#define SHADER_EXT_FB_FETCH \ + "#if defined(GL_EXT_shader_framebuffer_fetch)\n"\ + " #extension GL_EXT_shader_framebuffer_fetch : enable\n"\ + "#elif defined(GL_ARM_shader_framebuffer_fetch)\n"\ + " #extension GL_ARM_shader_framebuffer_fetch : enable\n"\ + "#endif\n" + void App::initShaders() { static const char* shader_v = @@ -85,9 +92,7 @@ void App::initShaders() "}\n"; static const char* shader_blend_f = SHADER_VERSION - "#if defined(GL_EXT_shader_framebuffer_fetch)\n" - " #extension GL_EXT_shader_framebuffer_fetch : enable\n" - "#endif\n" + SHADER_EXT_FB_FETCH "uniform sampler2D tex;\n" "uniform sampler2D tex_alpha;\n" "uniform sampler2D tex_bg;\n" @@ -103,6 +108,8 @@ void App::initShaders() "void main() {\n" "#if defined(GL_EXT_shader_framebuffer_fetch)\n" " highp vec4 bg = frag;\n" + "#elif defined(GL_ARM_shader_framebuffer_fetch)\n" + " highp vec4 bg = gl_LastFragColorARM;\n" "#else\n" " mediump vec4 bg = texture(tex_bg, uv);\n" "#endif\n" @@ -357,9 +364,7 @@ void App::initShaders() "}\n"; static const char* shader_stroke_f = SHADER_VERSION - "#if defined(GL_EXT_shader_framebuffer_fetch)\n" - " #extension GL_EXT_shader_framebuffer_fetch : enable\n" - "#endif\n" + SHADER_EXT_FB_FETCH "uniform mediump sampler2D tex;\n" "uniform mediump sampler2D tex_bg;\n" "uniform mediump sampler2D tex_stencil;\n" @@ -388,6 +393,8 @@ void App::initShaders() " mediump vec4 fg = vec4(col.rgb, brush_alpha * stencil);\n" "#if defined(GL_EXT_shader_framebuffer_fetch)\n" " mediump vec4 bg = frag;\n" + "#elif defined(GL_ARM_shader_framebuffer_fetch)\n" + " mediump vec4 bg = gl_LastFragColorARM;\n" "#else\n" " mediump vec4 bg = texture(tex_bg, uv2);\n" "#endif\n" @@ -592,6 +599,18 @@ void App::initShaders() " }\n" "}\n"; + GLint n_exts; + glGetIntegerv(GL_NUM_EXTENSIONS, &n_exts); + for (int i = 0; i < n_exts; i++) + { + std::string ext = (const char*)glGetStringi(GL_EXTENSIONS, i); + if (ext.find("shader_framebuffer_fetch") != std::string::npos) + { + ShaderManager::ext_framebuffer_fetch = true; + } + } + + LOG("Shader Extension shader_framebuffer_fetch: %s", ShaderManager::ext_framebuffer_fetch ? "enabled" : "disabled"); LOG("initializing shaders"); if (!ShaderManager::create(kShader::Texture, shader_v, shader_f)) diff --git a/src/canvas.cpp b/src/canvas.cpp index 4050424..7f6fb7f 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -394,9 +394,8 @@ void Canvas::stroke_draw() glDisable(GL_BLEND); ShaderManager::use(kShader::Stroke); ShaderManager::u_int(kShaderUniform::Tex, 0); // brush -#ifndef __IOS__ - ShaderManager::u_int(kShaderUniform::TexBG, 1); // bg -#endif + if (!ShaderManager::ext_framebuffer_fetch) + ShaderManager::u_int(kShaderUniform::TexBG, 1); // bg ShaderManager::u_int(kShaderUniform::TexStencil, 2); // stencil ShaderManager::u_int(kShaderUniform::TexMix, 3); // mixer //ShaderManager::u_int(kShaderUniform::TexMixA, 4); // mixer @@ -549,8 +548,11 @@ void Canvas::stroke_draw() m_tmp[i].bindFramebuffer(); - glActiveTexture(GL_TEXTURE1); - m_tex[i].bind(); // bg, copy of framebuffer (copied before drawing) + if (!ShaderManager::ext_framebuffer_fetch) + { + glActiveTexture(GL_TEXTURE1); + m_tex[i].bind(); // bg, copy of framebuffer (copied before drawing) + } glm::vec2 bb_min(m_width, m_height); glm::vec2 bb_max(0, 0); @@ -564,12 +566,11 @@ void Canvas::stroke_draw() glm::vec2 pad(1); glm::ivec2 tex_pos = glm::clamp(glm::floor(bb_min) - pad , { 0, 0 }, { m_width, m_height }); glm::ivec2 tex_sz = glm::clamp(glm::ceil(bb_sz ) + pad*2.f, { 0, 0 }, (glm::vec2)(glm::ivec2(m_width, m_height) - tex_pos)); - #ifndef __IOS__ - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, - tex_pos.x, tex_pos.y, - tex_pos.x, tex_pos.y, - tex_sz.x, tex_sz.y); - #endif + if (!ShaderManager::ext_framebuffer_fetch) + { + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, tex_pos.x, tex_pos.y, + tex_pos.x, tex_pos.y, tex_sz.x, tex_sz.y); + } m_dirty_box[i] = glm::vec4( glm::min(xy(m_dirty_box[i]), (glm::vec2)tex_pos), @@ -630,8 +631,11 @@ void Canvas::stroke_draw() m_brush_shape.draw_stroke(); */ - glActiveTexture(GL_TEXTURE1); - m_tex[i].unbind(); + if (!ShaderManager::ext_framebuffer_fetch) + { + glActiveTexture(GL_TEXTURE1); + m_tex[i].unbind(); + } m_tmp[i].unbindFramebuffer(); } @@ -1307,26 +1311,32 @@ void Canvas::export_equirectangular_thread(std::string file_path) ShaderManager::use(kShader::TextureBlend); ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_int(kShaderUniform::TexA, 1); - ShaderManager::u_int(kShaderUniform::TexBG, 2); ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); m_tmp[i].bindFramebuffer(); // clear transparent not to mess with blending modes m_tmp[i].clear({ 1, 1, 1, 0 }); - glActiveTexture(GL_TEXTURE2); - face.bind(); + if (!ShaderManager::ext_framebuffer_fetch) + { + ShaderManager::u_int(kShaderUniform::TexBG, 2); + glActiveTexture(GL_TEXTURE2); + face.bind(); + m_sampler_bg.bind(2); + } m_sampler_bg.bind(0); // nearest m_sampler_mask.bind(1); // linear - m_sampler_bg.bind(2); for (auto layer_index : m_order) { if (!m_layers[layer_index].m_visible || m_layers[layer_index].m_opacity == 0.f || !m_layers[layer_index].m_dirty_face[i]) continue; - glActiveTexture(GL_TEXTURE2); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height); + if (!ShaderManager::ext_framebuffer_fetch) + { + glActiveTexture(GL_TEXTURE2); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height); + } ShaderManager::u_int(kShaderUniform::BlendMode, m_layers[layer_index].m_blend_mode); ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index].m_opacity); glActiveTexture(GL_TEXTURE0); @@ -1338,8 +1348,12 @@ void Canvas::export_equirectangular_thread(std::string file_path) glActiveTexture(GL_TEXTURE0); m_layers[layer_index].m_rtt[i].unbindTexture(); } - glActiveTexture(GL_TEXTURE2); - face.unbind(); + + if (!ShaderManager::ext_framebuffer_fetch) + { + glActiveTexture(GL_TEXTURE2); + face.unbind(); + } // now blend with the background glEnable(GL_BLEND); @@ -2131,21 +2145,27 @@ Image Canvas::thumbnail_generate(int w, int h) ShaderManager::use(kShader::TextureBlend); ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_int(kShaderUniform::TexA, 1); - ShaderManager::u_int(kShaderUniform::TexBG, 2); ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp); - glActiveTexture(GL_TEXTURE2); - blendtex.bind(); + if (!ShaderManager::ext_framebuffer_fetch) + { + ShaderManager::u_int(kShaderUniform::TexBG, 2); + glActiveTexture(GL_TEXTURE2); + blendtex.bind(); + m_sampler_bg.bind(2); + } m_sampler_bg.bind(0); // nearest m_sampler_mask.bind(1); // linear - m_sampler_bg.bind(2); for (auto layer_index : m_order) { if (!m_layers[layer_index].m_visible || m_layers[layer_index].m_opacity == 0.f || !m_layers[layer_index].m_dirty_face[i]) continue; - glActiveTexture(GL_TEXTURE2); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w, h); + if (!ShaderManager::ext_framebuffer_fetch) + { + glActiveTexture(GL_TEXTURE2); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w, h); + } ShaderManager::u_int(kShaderUniform::BlendMode, m_layers[layer_index].m_blend_mode); ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index].m_opacity); glActiveTexture(GL_TEXTURE0); @@ -2158,8 +2178,15 @@ Image Canvas::thumbnail_generate(int w, int h) m_layers[layer_index].m_rtt[i].unbindTexture(); } - // copy the framebuffer before clearing to white - glActiveTexture(GL_TEXTURE2); + if (!ShaderManager::ext_framebuffer_fetch) + { + glActiveTexture(GL_TEXTURE2); + blendtex.unbind(); + } + + glActiveTexture(GL_TEXTURE0); + blendtex.bind(); + // copy the content of the fb before drawing the grid glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w, h); // draw the grid @@ -2173,9 +2200,8 @@ Image Canvas::thumbnail_generate(int w, int h) ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); m_sampler_mask.bind(0); // linear - glActiveTexture(GL_TEXTURE0); - blendtex.bind(); m_plane.draw_fill(); + blendtex.unbind(); } diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp index ee1e8ec..9c4f011 100644 --- a/src/node_canvas.cpp +++ b/src/node_canvas.cpp @@ -267,9 +267,8 @@ void NodeCanvas::draw() ShaderManager::use(kShader::TextureBlend); ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_int(kShaderUniform::TexA, 1); -#ifndef __IOS__ - ShaderManager::u_int(kShaderUniform::TexBG, 2); -#endif + if (!ShaderManager::ext_framebuffer_fetch) + ShaderManager::u_int(kShaderUniform::TexBG, 2); ShaderManager::u_int(kShaderUniform::BlendMode, m_canvas->m_layers[layer_index].m_blend_mode); ShaderManager::u_float(kShaderUniform::Alpha, 1.f); ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-1, 1, -1, 1)); @@ -278,19 +277,21 @@ void NodeCanvas::draw() m_blender_rtt.bindTexture(); glActiveTexture(GL_TEXTURE1); m_blender_rtt.bindTexture(); -#ifndef __IOS__ - glActiveTexture(GL_TEXTURE2); - m_blender_bg.bind(); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, - m_blender_bg.size().x, m_blender_bg.size().y); -#endif + if (!ShaderManager::ext_framebuffer_fetch) + { + glActiveTexture(GL_TEXTURE2); + m_blender_bg.bind(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, + m_blender_bg.size().x, m_blender_bg.size().y); + } m_face_plane.draw_fill(); -#ifndef __IOS__ - glActiveTexture(GL_TEXTURE2); - m_blender_bg.unbind(); -#endif + if (!ShaderManager::ext_framebuffer_fetch) + { + glActiveTexture(GL_TEXTURE2); + m_blender_bg.unbind(); + } glActiveTexture(GL_TEXTURE1); m_blender_rtt.unbindTexture(); glActiveTexture(GL_TEXTURE0); diff --git a/src/shader.cpp b/src/shader.cpp index 6e4974d..5a0cbff 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -4,6 +4,7 @@ std::map ShaderManager::m_shaders; Shader* ShaderManager::m_current; +bool ShaderManager::ext_framebuffer_fetch = false; bool Shader::create(const char* vertex, const char* fragment) { @@ -157,6 +158,7 @@ GLint Shader::GetAttribLocation(const char* name) { return glGetAttribLocation(prog, name); } + bool ShaderManager::create(kShader id, const char* vertex, const char* fragment) { m_shaders[id].name = id; diff --git a/src/shader.h b/src/shader.h index be18aaf..1a2d815 100644 --- a/src/shader.h +++ b/src/shader.h @@ -84,6 +84,7 @@ class ShaderManager static std::map m_shaders; static Shader* m_current; public: + static bool ext_framebuffer_fetch; static bool create(kShader id, const char* vertex, const char* fragment); static void use(kShader id); static void use(const char* name);