From ee436a4495cd5b488e014df02fe784e1aaddc9a9 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Fri, 26 Mar 2021 14:10:25 -0700 Subject: [PATCH 01/29] Restructure rendering code into separate passes --- lib/CMakeLists.txt | 4 + lib/aux_vis.cpp | 60 +++++-- lib/aux_vis.hpp | 1 + lib/gl/attr_traits.hpp | 6 +- lib/gl/renderer.cpp | 349 +++++++------------------------------- lib/gl/renderer.hpp | 138 +++++++-------- lib/gl/renderer_core.cpp | 5 +- lib/gl/renderer_core.hpp | 6 +- lib/gl/renderer_ff.cpp | 136 +-------------- lib/gl/renderer_ff.hpp | 6 +- lib/gl/renderer_msaa.cpp | 190 +++++++++++++++++++++ lib/gl/renderer_msaa.hpp | 52 ++++++ lib/gl/renderer_print.cpp | 226 ++++++++++++++++++++++++ lib/gl/renderer_print.hpp | 73 ++++++++ lib/gl/shader.cpp | 37 +++- lib/gl/shader.hpp | 4 + lib/gl/types.hpp | 54 ++++-- lib/sdl.cpp | 1 - lib/vsdata.cpp | 13 -- makefile | 2 + 20 files changed, 813 insertions(+), 550 deletions(-) create mode 100644 lib/gl/renderer_msaa.cpp create mode 100644 lib/gl/renderer_msaa.hpp create mode 100644 lib/gl/renderer_print.cpp create mode 100644 lib/gl/renderer_print.hpp diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index a02c0b3e..6a840644 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -12,6 +12,8 @@ list(APPEND SOURCES gl/renderer.cpp gl/renderer_core.cpp + gl/renderer_msaa.cpp + gl/renderer_print.cpp gl/shader.cpp gl/types.cpp aux_vis.cpp @@ -32,6 +34,8 @@ list(APPEND HEADERS gl/platform_gl.hpp gl/renderer.hpp gl/renderer_core.hpp + gl/renderer_msaa.hpp + gl/renderer_print.hpp gl/shader.hpp gl/types.hpp aux_vis.hpp diff --git a/lib/aux_vis.cpp b/lib/aux_vis.cpp index 1ec14c18..780c8235 100644 --- a/lib/aux_vis.cpp +++ b/lib/aux_vis.cpp @@ -33,6 +33,9 @@ using namespace mfem; #include #endif +#include "gl/renderer_msaa.hpp" +#include "gl/renderer_print.hpp" + int visualize = 0; VisualizationScene * locscene; @@ -41,6 +44,7 @@ static int glvis_multisample = GLVIS_MULTISAMPLE; #else static int glvis_multisample = -1; #endif +bool multisample_status = false; float line_w = 1.f; float line_w_aa = gl3::LINE_WIDTH_AA; @@ -89,8 +93,6 @@ int InitVisualization (const char name[], int x, int y, int w, int h) cout << "Window should be up" << endl; #endif InitFont(); - wnd->getRenderer().setLineWidth(line_w); - wnd->getRenderer().setLineWidthMS(line_w_aa); // auxReshapeFunc (MyReshape); // not needed, MyExpose calls it // auxReshapeFunc (NULL); @@ -109,6 +111,7 @@ int InitVisualization (const char name[], int x, int y, int w, int h) wnd->setTouchPinchCallback(TouchPinch); + wnd->setOnKeyDown('A', KeyAPressed); // auxKeyFunc (AUX_p, KeyCtrlP); // handled in vsdata.cpp wnd->setOnKeyDown (SDLK_s, KeyS); wnd->setOnKeyDown ('S', KeyS); @@ -317,7 +320,6 @@ void SetVisualizationScene(VisualizationScene * scene, int view, // SendKeySequence(keys); CallKeySequence(keys); } - wnd->getRenderer().setPalette(&locscene->palette); } void RunVisualization() @@ -377,16 +379,21 @@ void MyReshape(GLsizei w, GLsizei h) void MyExpose(GLsizei w, GLsizei h) { MyReshape (w, h); - GLuint color_tex = locscene->palette.GetColorTexture(); - GLuint alpha_tex = locscene->palette.GetAlphaTexture(); - wnd->getRenderer().setColorTexture(color_tex); - wnd->getRenderer().setAlphaTexture(alpha_tex); + gl3::DefaultPass rndr_main_pass; + gl3::MultisamplePass rndr_msaa_pass; + rndr_main_pass.setFontTexture(GetFont()->getFontTex()); + rndr_main_pass.setPalette(locscene->palette); + // Set antialiasing parameters + rndr_msaa_pass.SetAntialiasing(multisample_status); + rndr_msaa_pass.SetNumSamples(GetMultisample()); + rndr_msaa_pass.SetLineWidth(line_w); + rndr_msaa_pass.SetLineWidthMS(line_w_aa); gl3::SceneInfo frame = locscene->GetSceneObjs(); for (auto drawable_ptr : frame.needs_buffering) { wnd->getRenderer().buffer(drawable_ptr); } - wnd->getRenderer().render(frame.queue); + wnd->getRenderer().render({&rndr_main_pass}, {&rndr_msaa_pass}, frame.queue); } void MyExpose() @@ -1096,6 +1103,8 @@ void PrintCaptureBuffer(gl3::CaptureBuffer& cbuf) } } +gl3::CapturePass print_pass; + void KeyCtrlP() { #ifdef __EMSCRIPTEN__ @@ -1126,7 +1135,10 @@ void KeyCtrlP() GL2PS_NO_BLENDING | GL2PS_NO_OPENGL_CONTEXT, GL_RGBA, 0, NULL, 16, 16, 16, 0, fp, "a" ); - gl3::CaptureBuffer cbuf = wnd->getRenderer().capture(wnd_scn.queue); + print_pass.setFontTexture(GetFont()->getFontTex()); + print_pass.setPalette(locscene->palette); + wnd->getRenderer().render( {&print_pass}, {}, wnd_scn.queue); + gl3::CaptureBuffer cbuf = print_pass.GetLastCaptureBuffer(); PrintCaptureBuffer(cbuf); gl2psEndPage(); } @@ -1137,6 +1149,28 @@ void KeyCtrlP() #endif } + +void KeyAPressed() +{ + if (glvis_multisample < 0) + { + cout << "Multisampling disabled." << endl; + return; + } + multisample_status = !multisample_status; + + if (multisample_status) + { + cout << "Multisampling/Antialiasing: on" << endl; + } + else + { + cout << "Multisampling/Antialiasing: off" << endl; + } + + SendExposeEvent(); +} + void KeyQPressed() { wnd->signalQuit(); @@ -1501,18 +1535,13 @@ void SetLineWidth(float width) line_w = width; if (wnd) { - wnd->getRenderer().setLineWidth(line_w); + wnd->getRenderer().SetLineWidth(line_w); } } void SetLineWidthMS(float width_ms) { line_w_aa = width_ms; - if (wnd) - { - wnd->getRenderer().setLineWidthMS(line_w_aa); - } - } float GetLineWidth() @@ -1580,7 +1609,6 @@ void InitFont() << endl; } } - wnd->getRenderer().setFontTexture(glvis_font.getFontTex()); } GlVisFont * GetFont() diff --git a/lib/aux_vis.hpp b/lib/aux_vis.hpp index 93542868..8660dd11 100644 --- a/lib/aux_vis.hpp +++ b/lib/aux_vis.hpp @@ -55,6 +55,7 @@ void RightButtonUp (EventInfo *event); void TouchPinch(SDL_MultiGestureEvent & e); +void KeyAPressed(); void KeyCtrlP(); void KeyS(); void KeyQPressed(); diff --git a/lib/gl/attr_traits.hpp b/lib/gl/attr_traits.hpp index 662ea078..b993c115 100644 --- a/lib/gl/attr_traits.hpp +++ b/lib/gl/attr_traits.hpp @@ -125,9 +125,9 @@ AttrNormal> const static GLenum FFArrayIdx = GL_NORMAL_ARRAY; static void FFSetupFunc(GLint /*size*/, GLenum type, GLsizei stride, const GLvoid* ptr) -{ - glNormalPointer(type, stride, ptr); -} + { + glNormalPointer(type, stride, ptr); + } }; template diff --git a/lib/gl/renderer.cpp b/lib/gl/renderer.cpp index 7d6442b4..a6b8615e 100644 --- a/lib/gl/renderer.cpp +++ b/lib/gl/renderer.cpp @@ -42,71 +42,7 @@ bool GLDevice::useLegacyTextureFmts() #endif } -void MeshRenderer::setAntialiasing(bool aa_status) -{ - if (msaa_enable != aa_status) - { - msaa_enable = aa_status; - if (msaa_enable) - { - if (!feat_use_fbo_antialias) - { - glEnable(GL_MULTISAMPLE); - glEnable(GL_LINE_SMOOTH); - device->enableBlend(); - } - device->setLineWidth(line_w_aa); - } - else - { - if (!feat_use_fbo_antialias) - { - glDisable(GL_MULTISAMPLE); - glDisable(GL_LINE_SMOOTH); - device->disableBlend(); - } - device->setLineWidth(line_w); - } - } -} - -void MeshRenderer::setLineWidth(float w) -{ - line_w = w; - if (device && !msaa_enable) - { - device->setLineWidth(line_w); - } -} - -void MeshRenderer::setLineWidthMS(float w) -{ - line_w_aa = w; - if (device && msaa_enable) - { - device->setLineWidth(line_w_aa); - } -} - -void MeshRenderer::init() -{ -#ifdef __EMSCRIPTEN__ - const std::string versionString - = reinterpret_cast(glGetString(GL_VERSION)); - bool is_webgl2 = (versionString.find("OpenGL ES 3.0") != std::string::npos); - feat_use_fbo_antialias = is_webgl2; - if (feat_use_fbo_antialias) - { - glGetIntegerv(GL_MAX_SAMPLES, &msaa_samples); - } -#else - // TODO: we could also support ARB_framebuffer_object - feat_use_fbo_antialias = GLEW_VERSION_3_0; - glGetIntegerv(GL_MAX_SAMPLES, &msaa_samples); -#endif -} - -void MeshRenderer::render(const RenderQueue& queue) +void DefaultPass::Render(const RenderQueue& queue) { // elements containing opaque objects should be rendered first RenderQueue sorted_queue = queue; @@ -115,52 +51,10 @@ void MeshRenderer::render(const RenderQueue& queue) { return !renderPair.first.contains_translucent; }); - RenderBufHandle renderBufs[2]; - FBOHandle msaaFb; - if (feat_use_fbo_antialias && msaa_enable) - { - GLuint colorBuf, depthBuf; - glGenRenderbuffers(1, &colorBuf); - glGenRenderbuffers(1, &depthBuf); - renderBufs[0] = RenderBufHandle(colorBuf); - renderBufs[1] = RenderBufHandle(depthBuf); - - GLuint fbo; - glGenFramebuffers(1, &fbo); - - int vp[4]; - device->getViewport(vp); - int width = vp[2]; - int height = vp[3]; - glBindRenderbuffer(GL_RENDERBUFFER, colorBuf); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_samples, - GL_RGBA8, width, height); - glBindRenderbuffer(GL_RENDERBUFFER, depthBuf); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_samples, - GL_DEPTH_COMPONENT24, width, height); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_RENDERBUFFER, colorBuf); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, depthBuf); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - { - cerr << "Unable to create multisampled renderbuffer." << flush; - glDeleteFramebuffers(1, &fbo); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - } - else - { - msaaFb = FBOHandle(fbo); - } -#ifndef __EMSCRIPTEN__ - glEnable(GL_MULTISAMPLE); -#endif - } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + int color_tex = palette->GetColorTexture(); + int alpha_tex = palette->GetAlphaTexture(); + bool always_blend = device->isBlendEnabled(); for (auto& q_elem : sorted_queue) { const RenderParams& params = q_elem.first; @@ -177,38 +71,20 @@ void MeshRenderer::render(const RenderQueue& queue) device->setClipPlaneEqn(params.clip_plane_eqn); // aggregate buffers with common parameters std::vector tex_bufs, no_tex_bufs; - std::vector text_bufs; GlDrawable* curr_drawable = q_elem.second; - for (int i = 0; i < NUM_LAYOUTS; i++) + auto buffers = curr_drawable->getArrayBuffers(); + for (const IVertexBuffer* buf : buffers) { - for (size_t j = 0; j < GlDrawable::NUM_SHAPES; j++) + if (buf->getVertexLayout() == LAYOUT_VTX_TEXTURE0 + || buf->getVertexLayout() == LAYOUT_VTX_NORMAL_TEXTURE0) { - if (curr_drawable->buffers[i][j]) - { - if (i == LAYOUT_VTX_TEXTURE0 || i == LAYOUT_VTX_NORMAL_TEXTURE0) - { - tex_bufs.emplace_back(curr_drawable->buffers[i][j].get()->getHandle()); - } - else - { - no_tex_bufs.emplace_back(curr_drawable->buffers[i][j].get()->getHandle()); - } - } - if (curr_drawable->indexed_buffers[i][j]) - { - if (i == LAYOUT_VTX_TEXTURE0 || i == LAYOUT_VTX_NORMAL_TEXTURE0) - { - tex_bufs.emplace_back(curr_drawable->indexed_buffers[i][j].get()->getHandle()); - } - else - { - no_tex_bufs.emplace_back( - curr_drawable->indexed_buffers[i][j].get()->getHandle()); - } - } + tex_bufs.emplace_back(buf->getHandle()); + } + else + { + no_tex_bufs.emplace_back(buf->getHandle()); } } - text_bufs.emplace_back(&curr_drawable->text_buffer); if (params.contains_translucent) { device->enableBlend(); @@ -236,162 +112,79 @@ void MeshRenderer::render(const RenderQueue& queue) } device->attachTexture(1, font_tex); device->setNumLights(0); - for (TextBuffer* buf : text_bufs) - { - device->drawDeviceBuffer(*buf); - } + device->drawDeviceBuffer(curr_drawable->getTextBuffer()); device->enableDepthWrite(); - if (feat_use_fbo_antialias || !msaa_enable) { device->disableBlend(); } - } - if (feat_use_fbo_antialias && msaa_enable && msaaFb) - { - device->enableBlend(); - int vp[4]; - device->getViewport(vp); - int width = vp[2]; - int height = vp[3]; - GLuint colorBufId; - glGenRenderbuffers(1, &colorBufId); - RenderBufHandle colorBuf(colorBufId); - - GLuint fboId; - glGenFramebuffers(1, &fboId); - FBOHandle resolveFb(fboId); - - glBindRenderbuffer(GL_RENDERBUFFER, colorBuf); - glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - - glBindFramebuffer(GL_FRAMEBUFFER, resolveFb); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_RENDERBUFFER, colorBuf); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - { - cerr << "Unable to create resolve renderbuffer." << endl; - glBindFramebuffer(GL_FRAMEBUFFER, 0); - } - - // bind our draw framebuffer and blit the multisampled image - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFb); - glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFb); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glBlitFramebuffer(0, 0, width, height, - 0, 0, width, height, - GL_COLOR_BUFFER_BIT, - GL_NEAREST); -#ifndef __EMSCRIPTEN__ - glDisable(GL_MULTISAMPLE); -#endif - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFb); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glBlitFramebuffer(0, 0, width, height, - 0, 0, width, height, - GL_COLOR_BUFFER_BIT, - GL_LINEAR); - device->disableBlend(); + if (!always_blend) { device->disableBlend(); } } } -CaptureBuffer MeshRenderer::capture(const RenderQueue& queue) +void MeshRenderer::render(const vector& main_passes, + const vector& extra_passes, + const RenderQueue& queued) { - CaptureBuffer cbuf; - device->initXfbMode(); - for (auto& q_elem : queue) + for (IMainRenderPass* pass : main_passes) { - const RenderParams& params = q_elem.first; - device->setTransformMatrices(params.model_view.mtx, params.projection.mtx); - device->setMaterial(params.mesh_material); - device->setNumLights(params.num_pt_lights); - for (int i = 0; i < params.num_pt_lights; i++) - { - device->setPointLight(i, params.lights[i]); - } - device->setAmbientLight(params.light_amb_scene); - device->setStaticColor(params.static_color); - device->setClipPlaneUse(params.use_clip_plane); - device->setClipPlaneEqn(params.clip_plane_eqn); - // aggregate buffers with common parameters - std::vector tex_bufs, no_tex_bufs; - std::vector text_bufs; - GlDrawable* curr_drawable = q_elem.second; - for (int i = 0; i < NUM_LAYOUTS; i++) + pass->SetGLDevice(device.get()); + } + for (IRenderPass* pass : extra_passes) + { + pass->SetGLDevice(device.get()); + } + // Step 1: Match renderables in the queue with the *first* render pass that + // can handle them. + std::vector matched_queues(main_passes.size()); + for (auto drawable : queued) + { + for (int ipass = 0; ipass < main_passes.size(); ipass++) { - for (size_t j = 0; j < GlDrawable::NUM_SHAPES; j++) + if (main_passes[ipass]->Filter(drawable.first)) { - if (curr_drawable->buffers[i][j]) - { - if (i == LAYOUT_VTX_TEXTURE0 || i == LAYOUT_VTX_NORMAL_TEXTURE0) - { - tex_bufs.emplace_back(curr_drawable->buffers[i][j].get()->getHandle()); - } - else - { - no_tex_bufs.emplace_back(curr_drawable->buffers[i][j].get()->getHandle()); - } - } - if (curr_drawable->indexed_buffers[i][j]) - { - if (i == LAYOUT_VTX_TEXTURE0 || i == LAYOUT_VTX_NORMAL_TEXTURE0) - { - tex_bufs.emplace_back(curr_drawable->indexed_buffers[i][j].get()->getHandle()); - } - else - { - no_tex_bufs.emplace_back( - curr_drawable->indexed_buffers[i][j].get()->getHandle()); - } - } + matched_queues[ipass].emplace_back(drawable); + break; } } - text_bufs.emplace_back(&curr_drawable->text_buffer); + } + // Step 2: Setup the framebuffer with the first extra pass, and render the + // queue with the main passes. + if (extra_passes.size() > 0) + { + extra_passes[0]->PreRender(); + } + for (int ipass = 0; ipass < main_passes.size(); ipass++) + { + main_passes[ipass]->PreRender(); + main_passes[ipass]->Render(matched_queues[ipass]); + main_passes[ipass]->PostRender(); + } - device->attachTexture(GLDevice::SAMPLER_COLOR, color_tex); - device->attachTexture(GLDevice::SAMPLER_ALPHA, alpha_tex); - for (auto buf : tex_bufs) - { - device->captureXfbBuffer(*pal, cbuf, buf); - } - device->detachTexture(GLDevice::SAMPLER_COLOR); - device->detachTexture(GLDevice::SAMPLER_ALPHA); - for (auto buf : no_tex_bufs) - { - device->captureXfbBuffer(*pal, cbuf, buf); - } - if (!params.contains_translucent) - { - device->enableBlend(); - device->disableDepthWrite(); - } - device->attachTexture(1, font_tex); - device->setNumLights(0); - for (TextBuffer* buf : text_bufs) + if (extra_passes.size() > 0) + { + for (int ipass = 1; ipass < extra_passes.size(); ipass++) { - device->captureXfbBuffer(cbuf, *buf); + // Finalize last stage's results onto next stage + extra_passes[ipass]->PreRender(); + extra_passes[ipass-1]->PostRender(); } + extra_passes[extra_passes.size() - 1]->PostRender(); } - device->exitXfbMode(); - return cbuf; } void MeshRenderer::buffer(GlDrawable* buf) { - for (int i = 0; i < NUM_LAYOUTS; i++) + auto buffers = buf->getArrayBuffers(); + for (IVertexBuffer* buf : buffers) { - for (size_t j = 0; j < GlDrawable::NUM_SHAPES; j++) + IIndexedBuffer* ibuf = dynamic_cast(buf); + if (ibuf) { - if (buf->buffers[i][j]) - { - device->bufferToDevice((array_layout) i, *(buf->buffers[i][j].get())); - } - if (buf->indexed_buffers[i][j]) - { - device->bufferToDevice((array_layout) i, *(buf->indexed_buffers[i][j].get())); - } + device->bufferToDevice(buf->getVertexLayout(), *ibuf); + } + else + { + device->bufferToDevice(buf->getVertexLayout(), *buf); } } - device->bufferToDevice(buf->text_buffer); + device->bufferToDevice(buf->getTextBuffer()); } void GLDevice::init() @@ -441,18 +234,4 @@ void GLDevice::setTransformMatrices(glm::mat4 model_view, glm::mat4 projection) proj_mtx = projection; } -void GLDevice::captureXfbBuffer(CaptureBuffer& capture, const TextBuffer& t_buf) -{ - for (const auto& entry : t_buf) - { - glm::vec3 raster = glm::project( - glm::vec3(entry.rx, entry.ry, entry.rz), - model_view_mtx, - proj_mtx, - glm::vec4(0, 0, vp_width, vp_height)); - capture.text.emplace_back(raster, glm::make_vec4(static_color.data()), - entry.text); - } -} - } diff --git a/lib/gl/renderer.hpp b/lib/gl/renderer.hpp index 6144faa0..fe5bfcef 100644 --- a/lib/gl/renderer.hpp +++ b/lib/gl/renderer.hpp @@ -57,42 +57,14 @@ struct RenderParams typedef vector> RenderQueue; +struct CaptureBuffer; + struct SceneInfo { vector needs_buffering; RenderQueue queue; }; -struct FeedbackVertex -{ - glm::vec3 position; - glm::vec4 color; - - FeedbackVertex() = default; - FeedbackVertex(glm::vec3 pos, glm::vec4 c) - : position(pos), color(c) { } - FeedbackVertex(glm::vec4 pos, glm::vec4 c) - : position(pos), color(c) { } -}; - -struct FeedbackText -{ - glm::vec3 offset; - glm::vec4 color; - std::string text; - - FeedbackText() = default; - FeedbackText(glm::vec3 t_off, glm::vec4 t_color, std::string txt) - : offset(t_off), color(t_color), text(std::move(txt)) { } -}; - -struct CaptureBuffer -{ - vector lines; - vector triangles; - vector text; -}; - // OpenGL device interface representing rendering capabilities class GLDevice { @@ -104,6 +76,8 @@ class GLDevice std::array static_color; + bool blend_enabled = false; + protected: TextureHandle passthrough_texture; @@ -135,8 +109,9 @@ class GLDevice // data. Otherwise, use the newer sized internal formats and GL_RED. static bool useLegacyTextureFmts(); - void enableBlend() { glEnable(GL_BLEND); } - void disableBlend() { glDisable(GL_BLEND); } + void enableBlend() { blend_enabled = true; glEnable(GL_BLEND); } + void disableBlend() { blend_enabled = false; glDisable(GL_BLEND); } + bool isBlendEnabled() { return blend_enabled; } void enableDepthWrite() { glDepthMask(GL_TRUE); } void disableDepthWrite() { glDepthMask(GL_FALSE); } void setLineWidth(float w) { glLineWidth(w); } @@ -171,8 +146,8 @@ class GLDevice // === Buffer management functions === // Load a client-side vertex buffer into a device buffer. - virtual void bufferToDevice(array_layout layout, IVertexBuffer& buf) = 0; - virtual void bufferToDevice(array_layout layout, IIndexedBuffer& buf) = 0; + virtual void bufferToDevice(ArrayLayout layout, IVertexBuffer& buf) = 0; + virtual void bufferToDevice(ArrayLayout layout, IIndexedBuffer& buf) = 0; virtual void bufferToDevice(TextBuffer& t_buf) = 0; // Draw the data loaded in a device buffer. virtual void drawDeviceBuffer(int hnd) = 0; @@ -193,23 +168,56 @@ class GLDevice }; +class IRenderPass +{ +public: + IRenderPass() { } + virtual void SetGLDevice(GLDevice* dev) { device = dev; } + virtual void PreRender() = 0; + virtual void PostRender() = 0; +protected: + GLDevice* device; +}; + +// Generic interface for an action on a queue of renderable objects. +class IMainRenderPass : public IRenderPass +{ +public: + IMainRenderPass() { } + // If the class will handle objects with the given set of render + // parameters, returns true. + virtual bool Filter(const RenderParams& param) = 0; + // Renders objects in the queue to the setup output surfaces. + virtual void Render(const RenderQueue& queue) = 0; + // Sets the palette state for this render pass. + void setPalette(PaletteState& pal) { palette = &pal; } + // Sets the texture handle of the font atlas. + void setFontTexture(GLuint tex_h) { font_tex = tex_h; } +protected: + bool use_default_output = true; + PaletteState* palette = nullptr; + GLuint font_tex = 0; +}; + +class DefaultPass : public IMainRenderPass +{ +public: + DefaultPass() { } + virtual bool Filter(const RenderParams& param) { return true; } + + virtual void PreRender() {} + virtual void Render(const RenderQueue& queued); + virtual void PostRender() {} +}; + class MeshRenderer { unique_ptr device; - bool msaa_enable; - int msaa_samples; - GLuint color_tex, alpha_tex, font_tex; - float line_w, line_w_aa; - PaletteState* pal; - - bool feat_use_fbo_antialias; - void init(); + float line_w; + public: MeshRenderer() - : msaa_enable(false) - , msaa_samples(0) - , line_w(1.f) - , line_w_aa(LINE_WIDTH_AA) { init(); } + : line_w(1.f) { } template void setDevice() @@ -217,7 +225,6 @@ class MeshRenderer device.reset(new TDevice()); device->setLineWidth(line_w); device->init(); - msaa_enable = false; } template @@ -225,43 +232,20 @@ class MeshRenderer { device.reset(new TDevice(device)); } - void setPalette(PaletteState* pal) { this->pal = pal; } - // Sets the texture handle of the color palette. - void setColorTexture(GLuint tex_h) { color_tex = tex_h; } - // Sets the texture handle of the alpha texture. - void setAlphaTexture(GLuint tex_h) { alpha_tex = tex_h; } - // Sets the texture handle of the font atlas. - void setFontTexture(GLuint tex_h) { font_tex = tex_h; } - - void setAntialiasing(bool aa_status); - bool getAntialiasing() { return msaa_enable; } - void setSamplesMSAA(int samples) + void SetLineWidth(float w) { - if (msaa_samples < samples) - { - std::cerr << "GL_MAX_SAMPLES = " << msaa_samples - << " but requested " << samples << "x MSAA. "; - std::cerr << "Setting antialiasing mode to " - << msaa_samples << "x MSAA." << endl; - } - else - { - msaa_samples = samples; - } + line_w = w; + if (device) { device->setLineWidth(w); } } - int getSamplesMSAA() { return msaa_samples; } - - void setLineWidth(float w); - float getLineWidth() { return line_w; } - void setLineWidthMS(float w); - float getLineWidthMS() { return line_w_aa; } + float GetLineWidth() { return line_w; } void setClearColor(float r, float g, float b, float a) { glClearColor(r, g, b, a); } void setViewport(GLsizei w, GLsizei h) { device->setViewport(w, h); } - void render(const RenderQueue& queued); - CaptureBuffer capture(const RenderQueue& queued); + void render(const std::vector& main_passes, + const std::vector& extra_passes, + const RenderQueue& queued); void buffer(GlDrawable* buf); }; diff --git a/lib/gl/renderer_core.cpp b/lib/gl/renderer_core.cpp index dc761643..dbae4667 100644 --- a/lib/gl/renderer_core.cpp +++ b/lib/gl/renderer_core.cpp @@ -11,6 +11,7 @@ #include "attr_traits.hpp" #include "renderer_core.hpp" +#include "renderer_print.hpp" #include "../aux_vis.hpp" #include @@ -244,7 +245,7 @@ void CoreGLDevice::setClipPlaneEqn(const std::array &eqn) glUniform4fv(uniforms["clipPlane"], 1, glm::value_ptr(clip_plane)); } -void CoreGLDevice::bufferToDevice(array_layout layout, IVertexBuffer &buf) +void CoreGLDevice::bufferToDevice(ArrayLayout layout, IVertexBuffer &buf) { if (buf.getHandle() == 0) { @@ -264,7 +265,7 @@ void CoreGLDevice::bufferToDevice(array_layout layout, IVertexBuffer &buf) buf.getData(), GL_STATIC_DRAW); } -void CoreGLDevice::bufferToDevice(array_layout layout, IIndexedBuffer& buf) +void CoreGLDevice::bufferToDevice(ArrayLayout layout, IIndexedBuffer& buf) { if (buf.getHandle() == 0) { diff --git a/lib/gl/renderer_core.hpp b/lib/gl/renderer_core.hpp index 5804c1a6..fe626339 100644 --- a/lib/gl/renderer_core.hpp +++ b/lib/gl/renderer_core.hpp @@ -56,7 +56,7 @@ class CoreGLDevice : public GLDevice BufObjHandle elem_buf; GLenum shape; size_t count; - array_layout layout; + ArrayLayout layout; }; std::vector vbos; @@ -90,8 +90,8 @@ class CoreGLDevice : public GLDevice void setClipPlaneUse(bool enable) override; void setClipPlaneEqn(const std::array& eqn) override; - void bufferToDevice(array_layout layout, IVertexBuffer& buf) override; - void bufferToDevice(array_layout layout, IIndexedBuffer& buf) override; + void bufferToDevice(ArrayLayout layout, IVertexBuffer& buf) override; + void bufferToDevice(ArrayLayout layout, IIndexedBuffer& buf) override; void bufferToDevice(TextBuffer& t_buf) override; void drawDeviceBuffer(int hnd) override; void drawDeviceBuffer(const TextBuffer& t_buf) override; diff --git a/lib/gl/renderer_ff.cpp b/lib/gl/renderer_ff.cpp index 0d641335..47a72792 100644 --- a/lib/gl/renderer_ff.cpp +++ b/lib/gl/renderer_ff.cpp @@ -157,7 +157,7 @@ void FFGLDevice::setClipPlaneEqn(const std::array& eqn) glClipPlane(GL_CLIP_PLANE0, eqn.data()); } -void FFGLDevice::bufferToDevice(array_layout layout, IVertexBuffer& buf) +void FFGLDevice::bufferToDevice(ArrayLayout layout, IVertexBuffer& buf) { if (buf.getHandle() == 0) { @@ -196,7 +196,7 @@ void FFGLDevice::bufferToDevice(array_layout layout, IVertexBuffer& buf) } } -void FFGLDevice::bufferToDevice(array_layout layout, IIndexedBuffer& buf) +void FFGLDevice::bufferToDevice(ArrayLayout layout, IIndexedBuffer& buf) { if (buf.getHandle() == 0) { @@ -326,136 +326,4 @@ void FFGLDevice::drawDeviceBuffer(const TextBuffer& buf) glPopMatrix(); } -void FFGLDevice::captureXfbBuffer(PaletteState& pal, CaptureBuffer& cbuf, - int hnd) -{ - if (hnd == 0) { return; } - if (disp_lists[hnd].count == 0) { return; } - GLenum fbType; - int fbStride; - if (disp_lists[hnd].layout == VertexTex::layout - || disp_lists[hnd].layout == VertexNormTex::layout) - { - //capture texture values too - // [ X Y Z ] [ R G B A ] [ U V - - ] - fbType = GL_3D_COLOR_TEXTURE; - fbStride = 11; - } - else - { - // only capture pos and color - // [ X Y Z ] [ R G B A ] - fbType = GL_3D_COLOR; - fbStride = 7; - } - // compute feedback buffer size - int sizebuf = 0; - if (disp_lists[hnd].shape == GL_LINES) - { - // for each line: LINE_TOKEN [Vtx] [Vtx] - sizebuf = (disp_lists[hnd].count / 2) + disp_lists[hnd].count * fbStride; - } - else if (disp_lists[hnd].shape == GL_TRIANGLES) - { - // for each tri: POLY_TOKEN 3 [Vtx] [Vtx] [Vtx] - // NOTE: when clip plane is enabled, we might get two triangles - // or a quad for an input triangle. However, the other clipped - // triangles get discarded, so this *should* be enough space. - sizebuf = (disp_lists[hnd].count / 3) * (2 + fbStride * 4); - } - else - { - std::cerr << "Warning: unhandled primitive type in FFPrinter::preDraw()" << - std::endl; - return; - } - // allocate feedback buffer - vector xfb_buf; - xfb_buf.resize(sizebuf); - glFeedbackBuffer(sizebuf, fbType, xfb_buf.data()); - // draw with feedback capture - glRenderMode(GL_FEEDBACK); - drawDeviceBuffer(hnd); -#ifndef GLVIS_DEBUG - glRenderMode(GL_RENDER); -#else - if (glRenderMode(GL_RENDER) < 0) - { - std::cerr << "Warning: feedback data exceeded available buffer size" << - std::endl; - } -#endif - size_t tok_idx = 0; - // process feedback buffer - while (tok_idx < xfb_buf.size()) - { - switch ((GLuint)xfb_buf[tok_idx]) - { - case GL_LINE_TOKEN: - case GL_LINE_RESET_TOKEN: - { - tok_idx++; - glm::vec3 coord0 = glm::make_vec3(&xfb_buf[tok_idx]), - coord1 = glm::make_vec3(&xfb_buf[tok_idx + fbStride]); - glm::vec4 color0 = glm::make_vec4(&xfb_buf[tok_idx + 3]), - color1 = glm::make_vec4(&xfb_buf[tok_idx + 3 + fbStride]); - if (fbStride == 11) - { - // get texture - pal.GetColorFromVal(xfb_buf[tok_idx + 7], glm::value_ptr(color0)); - pal.GetColorFromVal(xfb_buf[tok_idx + 7 + fbStride], glm::value_ptr(color1)); - } - cbuf.lines.emplace_back(coord0, color0); - cbuf.lines.emplace_back(coord1, color1); - tok_idx += fbStride * 2; - } - break; - case GL_POLYGON_TOKEN: - { - int n = xfb_buf[tok_idx + 1]; - tok_idx += 2; - // get vertex 0, 1 - glm::vec3 coord0 = glm::make_vec3(&xfb_buf[tok_idx]), - coord1 = glm::make_vec3(&xfb_buf[tok_idx + fbStride]); - glm::vec4 color0 = glm::make_vec4(&xfb_buf[tok_idx + 3]), - color1 = glm::make_vec4(&xfb_buf[tok_idx + 3 + fbStride]); - if (fbStride == 11) - { - // get texture - pal.GetColorFromVal(xfb_buf[tok_idx + 7], glm::value_ptr(color0)); - pal.GetColorFromVal(xfb_buf[tok_idx + 7 + fbStride], glm::value_ptr(color1)); - } - // decompose polygon into n-2 triangles [0 1 2] [0 2 3] ... - for (int i = 0; i < n-2; i++) - { - // get last vertex of current triangle - int vtxStart = fbStride * (2 + 3*i); - glm::vec3 coord2 = glm::make_vec3(&xfb_buf[tok_idx + vtxStart]); - glm::vec4 color2 = glm::make_vec4(&xfb_buf[tok_idx + 3 + vtxStart]); - if (fbStride == 11) - { - pal.GetColorFromVal(xfb_buf[tok_idx + 7 + vtxStart], glm::value_ptr(color2)); - } - cbuf.triangles.emplace_back(coord0, color0); - cbuf.triangles.emplace_back(coord1, color1); - cbuf.triangles.emplace_back(coord2, color2); - // last vertex becomes second vertex of next triangle - coord1 = coord2; - color1 = color2; - } - tok_idx += n * fbStride; - } - break; - case GL_POINT_TOKEN: - case GL_BITMAP_TOKEN: - case GL_DRAW_PIXEL_TOKEN: - case GL_COPY_PIXEL_TOKEN: - default: - // commands containing the token + a single vertex ignore for now - tok_idx += 1 + fbStride; - break; - } - } -} - } diff --git a/lib/gl/renderer_ff.hpp b/lib/gl/renderer_ff.hpp index 565ba517..950963cd 100644 --- a/lib/gl/renderer_ff.hpp +++ b/lib/gl/renderer_ff.hpp @@ -26,7 +26,7 @@ class FFGLDevice : public GLDevice DispListHandle list; GLenum shape; size_t count; - array_layout layout; + ArrayLayout layout; }; std::vector disp_lists; @@ -52,8 +52,8 @@ class FFGLDevice : public GLDevice void setClipPlaneUse(bool enable) override; void setClipPlaneEqn(const std::array& eqn) override; - void bufferToDevice(array_layout layout, IVertexBuffer& buf) override; - void bufferToDevice(array_layout layout, IIndexedBuffer& buf) override; + void bufferToDevice(ArrayLayout layout, IVertexBuffer& buf) override; + void bufferToDevice(ArrayLayout layout, IIndexedBuffer& buf) override; void bufferToDevice(TextBuffer& t_buf) override; void drawDeviceBuffer(int hnd) override; void drawDeviceBuffer(const TextBuffer& t_buf) override; diff --git a/lib/gl/renderer_msaa.cpp b/lib/gl/renderer_msaa.cpp new file mode 100644 index 00000000..bec133eb --- /dev/null +++ b/lib/gl/renderer_msaa.cpp @@ -0,0 +1,190 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-443271. +// +// This file is part of the GLVis visualization tool and library. For more +// information and source code availability see https://glvis.org. +// +// GLVis is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "renderer_msaa.hpp" + +namespace gl3 +{ + +void MultisamplePass::SetGLDevice(GLDevice* dev) +{ + IRenderPass::SetGLDevice(dev); + int max_msaa_samples; +#ifdef __EMSCRIPTEN__ + const std::string versionString + = reinterpret_cast(glGetString(GL_VERSION)); + bool is_webgl2 = (versionString.find("OpenGL ES 3.0") != std::string::npos); + feat_use_fbo_antialias = is_webgl2; + if (feat_use_fbo_antialias) + { + glGetIntegerv(GL_MAX_SAMPLES, &max_msaa_samples); + } +#else + // TODO: we could also support ARB_framebuffer_object + feat_use_fbo_antialias = GLEW_VERSION_3_0; + glGetIntegerv(GL_MAX_SAMPLES, &max_msaa_samples); +#endif + if (msaa_samples > max_msaa_samples) + { + std::cerr << "GL_MAX_SAMPLES = " << max_msaa_samples + << " but requested " << msaa_samples << "x MSAA. "; + std::cerr << "Setting antialiasing mode to " + << max_msaa_samples << "x MSAA." << endl; + msaa_samples = max_msaa_samples; + } + if (feat_use_fbo_antialias) + { + GLuint colorBuf, depthBuf; + glGenRenderbuffers(1, &colorBuf); + glGenRenderbuffers(1, &depthBuf); + renderBufs[0] = RenderBufHandle(colorBuf); + renderBufs[1] = RenderBufHandle(depthBuf); + + GLuint fbo; + glGenFramebuffers(1, &fbo); + + int vp[4]; + device->getViewport(vp); + int width = vp[2]; + int height = vp[3]; + glBindRenderbuffer(GL_RENDERBUFFER, colorBuf); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_samples, + GL_RGBA8, width, height); + glBindRenderbuffer(GL_RENDERBUFFER, depthBuf); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_samples, + GL_DEPTH_COMPONENT24, width, height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, colorBuf); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, depthBuf); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + cerr << "Unable to create multisampled renderbuffer." << flush; + glDeleteFramebuffers(1, &fbo); + } + else + { + msaaFb = FBOHandle(fbo); + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } +} + +void MultisamplePass::PreRender() +{ + if (msaa_enable) + { + if (feat_use_fbo_antialias) + { + glBindFramebuffer(GL_FRAMEBUFFER, msaaFb); + } + else + { + glEnable(GL_LINE_SMOOTH); + device->enableBlend(); + } +#ifndef __EMSCRIPTEN__ + glEnable(GL_MULTISAMPLE); +#endif + device->setLineWidth(line_w_aa); + } + else + { + device->setLineWidth(line_w); + } +} + +void MultisamplePass::PostRender() +{ + if (msaa_enable && feat_use_fbo_antialias && msaaFb) + { + int vp[4]; + device->getViewport(vp); + int width = vp[2]; + int height = vp[3]; + GLuint colorBufId; + glGenRenderbuffers(1, &colorBufId); + RenderBufHandle colorBuf(colorBufId); + + GLuint fboId; + glGenFramebuffers(1, &fboId); + FBOHandle resolveFb(fboId); + + glBindRenderbuffer(GL_RENDERBUFFER, colorBuf); + glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, resolveFb); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, colorBuf); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + cerr << "Unable to create resolve renderbuffer." << endl; + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + // bind our draw framebuffer and blit the multisampled image + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFb); + glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFb); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glBlitFramebuffer(0, 0, width, height, + 0, 0, width, height, + GL_COLOR_BUFFER_BIT, + GL_NEAREST); +#ifndef __EMSCRIPTEN__ + glDisable(GL_MULTISAMPLE); +#endif + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFb); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glBlitFramebuffer(0, 0, width, height, + 0, 0, width, height, + GL_COLOR_BUFFER_BIT, + GL_LINEAR); + } + else if (msaa_enable && !feat_use_fbo_antialias) + { + glDisable(GL_MULTISAMPLE); + glDisable(GL_LINE_SMOOTH); + device->disableBlend(); + } + device->setLineWidth(line_w); +} + +void MultisamplePass::SetAntialiasing(bool aa_status) +{ + msaa_enable = aa_status; +} + +void MultisamplePass::SetLineWidth(float w) +{ + line_w = w; + if (device && !msaa_enable) + { + device->setLineWidth(line_w); + } +} + +void MultisamplePass::SetLineWidthMS(float w) +{ + line_w_aa = w; + if (device && msaa_enable) + { + device->setLineWidth(line_w_aa); + } +} + +} diff --git a/lib/gl/renderer_msaa.hpp b/lib/gl/renderer_msaa.hpp new file mode 100644 index 00000000..56e3be3d --- /dev/null +++ b/lib/gl/renderer_msaa.hpp @@ -0,0 +1,52 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-443271. +// +// This file is part of the GLVis visualization tool and library. For more +// information and source code availability see https://glvis.org. +// +// GLVis is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#ifndef GLVIS_RENDERER_MSAA_HPP +#define GLVIS_RENDERER_MSAA_HPP + +#include "renderer.hpp" + +namespace gl3 +{ + +class MultisamplePass : public IRenderPass +{ +public: + MultisamplePass() { } + virtual void SetGLDevice(GLDevice* dev); + virtual void PreRender(); + virtual void PostRender(); + + void SetAntialiasing(bool aa_status); + bool GetAntialiasing() { return msaa_enable; } + void SetNumSamples(int samples) + { + msaa_samples = samples; + } + int GetNumSamples() { return msaa_samples; } + + void SetLineWidth(float w); + float GetLineWidth() { return line_w; } + void SetLineWidthMS(float w); + float GetLineWidthMS() { return line_w_aa; } +private: + bool feat_use_fbo_antialias; + bool msaa_enable{false}; + int msaa_samples; + float line_w, line_w_aa; + + RenderBufHandle renderBufs[2]; + FBOHandle msaaFb; +}; + +} + +#endif // GLVIS_RENDERER_MSAA_HPP diff --git a/lib/gl/renderer_print.cpp b/lib/gl/renderer_print.cpp new file mode 100644 index 00000000..60b95dd9 --- /dev/null +++ b/lib/gl/renderer_print.cpp @@ -0,0 +1,226 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-443271. +// +// This file is part of the GLVis visualization tool and library. For more +// information and source code availability see https://glvis.org. +// +// GLVis is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "renderer_print.hpp" +#include "renderer_ff.hpp" + +namespace gl3 +{ + +// Defined in renderer.hpp +void GLDevice::captureXfbBuffer(CaptureBuffer& capture, const TextBuffer& t_buf) +{ + for (const auto& entry : t_buf) + { + glm::vec3 raster = glm::project( + glm::vec3(entry.rx, entry.ry, entry.rz), + model_view_mtx, + proj_mtx, + glm::vec4(0, 0, vp_width, vp_height)); + capture.text.emplace_back(raster, glm::make_vec4(static_color.data()), + entry.text); + } +} + +// Defined in renderer_ff.hpp +void FFGLDevice::captureXfbBuffer(PaletteState& pal, CaptureBuffer& cbuf, + int hnd) +{ + if (hnd == 0) { return; } + if (disp_lists[hnd].count == 0) { return; } + GLenum fbType; + int fbStride; + if (disp_lists[hnd].layout == VertexTex::layout + || disp_lists[hnd].layout == VertexNormTex::layout) + { + //capture texture values too + // [ X Y Z ] [ R G B A ] [ U V - - ] + fbType = GL_3D_COLOR_TEXTURE; + fbStride = 11; + } + else + { + // only capture pos and color + // [ X Y Z ] [ R G B A ] + fbType = GL_3D_COLOR; + fbStride = 7; + } + // compute feedback buffer size + int sizebuf = 0; + if (disp_lists[hnd].shape == GL_LINES) + { + // for each line: LINE_TOKEN [Vtx] [Vtx] + sizebuf = (disp_lists[hnd].count / 2) + disp_lists[hnd].count * fbStride; + } + else if (disp_lists[hnd].shape == GL_TRIANGLES) + { + // for each tri: POLY_TOKEN 3 [Vtx] [Vtx] [Vtx] + // NOTE: when clip plane is enabled, we might get two triangles + // or a quad for an input triangle. However, the other clipped + // triangles get discarded, so this *should* be enough space. + sizebuf = (disp_lists[hnd].count / 3) * (2 + fbStride * 4); + } + else + { + std::cerr << "Warning: unhandled primitive type in FFPrinter::preDraw()" << + std::endl; + return; + } + // allocate feedback buffer + vector xfb_buf; + xfb_buf.resize(sizebuf); + glFeedbackBuffer(sizebuf, fbType, xfb_buf.data()); + // draw with feedback capture + glRenderMode(GL_FEEDBACK); + drawDeviceBuffer(hnd); +#ifndef GLVIS_DEBUG + glRenderMode(GL_RENDER); +#else + if (glRenderMode(GL_RENDER) < 0) + { + std::cerr << "Warning: feedback data exceeded available buffer size" << + std::endl; + } +#endif + size_t tok_idx = 0; + // process feedback buffer + while (tok_idx < xfb_buf.size()) + { + switch ((GLuint)xfb_buf[tok_idx]) + { + case GL_LINE_TOKEN: + case GL_LINE_RESET_TOKEN: + { + tok_idx++; + glm::vec3 coord0 = glm::make_vec3(&xfb_buf[tok_idx]), + coord1 = glm::make_vec3(&xfb_buf[tok_idx + fbStride]); + glm::vec4 color0 = glm::make_vec4(&xfb_buf[tok_idx + 3]), + color1 = glm::make_vec4(&xfb_buf[tok_idx + 3 + fbStride]); + if (fbStride == 11) + { + // get texture + pal.GetColorFromVal(xfb_buf[tok_idx + 7], glm::value_ptr(color0)); + pal.GetColorFromVal(xfb_buf[tok_idx + 7 + fbStride], glm::value_ptr(color1)); + } + cbuf.lines.emplace_back(coord0, color0); + cbuf.lines.emplace_back(coord1, color1); + tok_idx += fbStride * 2; + } + break; + case GL_POLYGON_TOKEN: + { + int n = xfb_buf[tok_idx + 1]; + tok_idx += 2; + // get vertex 0, 1 + glm::vec3 coord0 = glm::make_vec3(&xfb_buf[tok_idx]), + coord1 = glm::make_vec3(&xfb_buf[tok_idx + fbStride]); + glm::vec4 color0 = glm::make_vec4(&xfb_buf[tok_idx + 3]), + color1 = glm::make_vec4(&xfb_buf[tok_idx + 3 + fbStride]); + if (fbStride == 11) + { + // get texture + pal.GetColorFromVal(xfb_buf[tok_idx + 7], glm::value_ptr(color0)); + pal.GetColorFromVal(xfb_buf[tok_idx + 7 + fbStride], glm::value_ptr(color1)); + } + // decompose polygon into n-2 triangles [0 1 2] [0 2 3] ... + for (int i = 0; i < n-2; i++) + { + // get last vertex of current triangle + int vtxStart = fbStride * (2 + 3*i); + glm::vec3 coord2 = glm::make_vec3(&xfb_buf[tok_idx + vtxStart]); + glm::vec4 color2 = glm::make_vec4(&xfb_buf[tok_idx + 3 + vtxStart]); + if (fbStride == 11) + { + pal.GetColorFromVal(xfb_buf[tok_idx + 7 + vtxStart], glm::value_ptr(color2)); + } + cbuf.triangles.emplace_back(coord0, color0); + cbuf.triangles.emplace_back(coord1, color1); + cbuf.triangles.emplace_back(coord2, color2); + // last vertex becomes second vertex of next triangle + coord1 = coord2; + color1 = color2; + } + tok_idx += n * fbStride; + } + break; + case GL_POINT_TOKEN: + case GL_BITMAP_TOKEN: + case GL_DRAW_PIXEL_TOKEN: + case GL_COPY_PIXEL_TOKEN: + default: + // commands containing the token + a single vertex ignore for now + tok_idx += 1 + fbStride; + break; + } + } +} + +void CapturePass::Render(const RenderQueue& queue) +{ + int color_tex = palette->GetColorTexture(); + int alpha_tex = palette->GetAlphaTexture(); + bool always_blend = device->isBlendEnabled(); + for (auto& q_elem : queue) + { + const RenderParams& params = q_elem.first; + device->setTransformMatrices(params.model_view.mtx, params.projection.mtx); + device->setMaterial(params.mesh_material); + device->setNumLights(params.num_pt_lights); + for (int i = 0; i < params.num_pt_lights; i++) + { + device->setPointLight(i, params.lights[i]); + } + device->setAmbientLight(params.light_amb_scene); + device->setStaticColor(params.static_color); + device->setClipPlaneUse(params.use_clip_plane); + device->setClipPlaneEqn(params.clip_plane_eqn); + // aggregate buffers with common parameters + std::vector tex_bufs, no_tex_bufs; + GlDrawable* curr_drawable = q_elem.second; + auto buffers = curr_drawable->getArrayBuffers(); + for (const IVertexBuffer* buf : buffers) + { + if (buf->getVertexLayout() == LAYOUT_VTX_TEXTURE0 + || buf->getVertexLayout() == LAYOUT_VTX_NORMAL_TEXTURE0) + { + tex_bufs.emplace_back(buf->getHandle()); + } + else + { + no_tex_bufs.emplace_back(buf->getHandle()); + } + } + + device->attachTexture(GLDevice::SAMPLER_COLOR, color_tex); + device->attachTexture(GLDevice::SAMPLER_ALPHA, alpha_tex); + for (auto buf : tex_bufs) + { + device->captureXfbBuffer(*palette, cbuf, buf); + } + device->detachTexture(GLDevice::SAMPLER_COLOR); + device->detachTexture(GLDevice::SAMPLER_ALPHA); + for (auto buf : no_tex_bufs) + { + device->captureXfbBuffer(*palette, cbuf, buf); + } + if (!params.contains_translucent) + { + device->enableBlend(); + device->disableDepthWrite(); + } + device->attachTexture(1, font_tex); + device->setNumLights(0); + device->captureXfbBuffer(cbuf, curr_drawable->getTextBuffer()); + if (!always_blend) { device->disableBlend(); } + } +} + +} diff --git a/lib/gl/renderer_print.hpp b/lib/gl/renderer_print.hpp new file mode 100644 index 00000000..8b134bfc --- /dev/null +++ b/lib/gl/renderer_print.hpp @@ -0,0 +1,73 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-443271. +// +// This file is part of the GLVis visualization tool and library. For more +// information and source code availability see https://glvis.org. +// +// GLVis is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#ifndef GLVIS_RENDERER_PRINT_HPP +#define GLVIS_RENDERER_PRINT_HPP + +#include "renderer.hpp" + +namespace gl3 +{ + +struct FeedbackVertex +{ + glm::vec3 position; + glm::vec4 color; + + FeedbackVertex() = default; + FeedbackVertex(glm::vec3 pos, glm::vec4 c) + : position(pos), color(c) { } + FeedbackVertex(glm::vec4 pos, glm::vec4 c) + : position(pos), color(c) { } +}; + +struct FeedbackText +{ + glm::vec3 offset; + glm::vec4 color; + std::string text; + + FeedbackText() = default; + FeedbackText(glm::vec3 t_off, glm::vec4 t_color, std::string txt) + : offset(t_off), color(t_color), text(std::move(txt)) { } +}; + +struct CaptureBuffer +{ + vector lines; + vector triangles; + vector text; +}; + +class CapturePass : public IMainRenderPass +{ +public: + CapturePass() { } + virtual bool Filter(const RenderParams& param) { return true; } + + virtual void PreRender() { device->initXfbMode(); } + virtual void Render(const RenderQueue& queued); + virtual void PostRender() { device->exitXfbMode(); } + + CaptureBuffer GetLastCaptureBuffer() + { + CaptureBuffer b_mov = std::move(cbuf); + cbuf = {}; + return b_mov; + } + +private: + CaptureBuffer cbuf; +}; + +} + +#endif // GLVIS_RENDERER_PRINT_HPP diff --git a/lib/gl/shader.cpp b/lib/gl/shader.cpp index 40a9e0cb..421d83e9 100644 --- a/lib/gl/shader.cpp +++ b/lib/gl/shader.cpp @@ -58,7 +58,40 @@ bool ShaderProgram::create(std::string vertexShader, return is_compiled; } +void ShaderProgram::setOutputFramebuffer(const FBOHandle& fbo) +{ + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); + if (num_outputs == 0) + { + std::cerr << "Warning: shader has no outputs." << std::endl; + return; + } + vector output_bufs(num_outputs); + for (int iout = 0; iout < num_outputs; iout++) + { + output_bufs[iout] = GL_COLOR_ATTACHMENT0 + iout; + } + glDrawBuffers(num_outputs, output_bufs.data()); +} + +void ShaderProgram::setDefaultDrawFramebuffer() +{ + if (num_outputs == 0) + { + std::cerr << "Warning: shader has no outputs." << std::endl; + } + if (num_outputs > 1) + { + std::cerr << "Warning: attempting to set a shader with more than one " + << "output on the default framebuffer."; + } + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + GLenum back_buf = GL_BACK; + glDrawBuffers(1, &back_buf); +} + int ShaderProgram::glsl_version = -1; +bool ShaderProgram::glsl_es = false; void ShaderProgram::GetGLSLVersion() { @@ -116,6 +149,7 @@ void ShaderProgram::GetGLSLVersion() { glsl_version = 300; } + glsl_es = true; #endif std::cerr << "Using GLSL " << glsl_version << std::endl; } @@ -149,12 +183,11 @@ std::string ShaderProgram::formatShader(const std::string& inShader, outputString += std::to_string(i) + ";\n"; if (glsl_version > 130 && glsl_version < 330) { - formatted = outputString + formatted; formatted = std::regex_replace(formatted, std::regex(indexString), "fragColor"); } - else if (glsl_version >= 330) + else if (glsl_version >= 330 || (glsl_version == 300 && glsl_es)) { std::string layoutString = "layout(location = "; layoutString += std::to_string(i) + ") "; diff --git a/lib/gl/shader.hpp b/lib/gl/shader.hpp index 76535126..5f02bb73 100644 --- a/lib/gl/shader.hpp +++ b/lib/gl/shader.hpp @@ -56,6 +56,9 @@ class ShaderProgram void bind() const { glUseProgram(program_id); } + void setOutputFramebuffer(const FBOHandle& fbo); + void setDefaultDrawFramebuffer(); + private: static void GetGLSLVersion(); @@ -65,6 +68,7 @@ class ShaderProgram void mapShaderUniforms(); static int glsl_version; + static bool glsl_es; std::unordered_map attrib_idx; int num_outputs = 0; diff --git a/lib/gl/types.hpp b/lib/gl/types.hpp index 506d9e20..b7a8e7c4 100644 --- a/lib/gl/types.hpp +++ b/lib/gl/types.hpp @@ -165,7 +165,7 @@ struct GlMatrix } }; -enum array_layout +enum ArrayLayout { LAYOUT_VTX = 0, LAYOUT_VTX_NORMAL, @@ -203,10 +203,11 @@ struct alignas(16) Vertex std::array coord; static Vertex create(double * d) -{ - return Vertex {(float) d[0], (float) d[1], (float) d[2]}; -} -static const int layout = LAYOUT_VTX; + { + return Vertex {(float) d[0], (float) d[1], (float) d[2]}; + } + + static const ArrayLayout layout = LAYOUT_VTX; }; struct alignas(16) VertexColor @@ -214,7 +215,7 @@ struct alignas(16) VertexColor std::array coord; std::array color; - static const int layout = LAYOUT_VTX_COLOR; + static const ArrayLayout layout = LAYOUT_VTX_COLOR; }; struct alignas(16) VertexTex @@ -222,7 +223,7 @@ struct alignas(16) VertexTex std::array coord; std::array texCoord; - static const int layout = LAYOUT_VTX_TEXTURE0; + static const ArrayLayout layout = LAYOUT_VTX_TEXTURE0; }; struct alignas(16) VertexNorm @@ -230,7 +231,7 @@ struct alignas(16) VertexNorm std::array coord; std::array norm; - static const int layout = LAYOUT_VTX_NORMAL; + static const ArrayLayout layout = LAYOUT_VTX_NORMAL; }; struct alignas(16) VertexNormColor @@ -239,7 +240,7 @@ struct alignas(16) VertexNormColor std::array norm; std::array color; - static const int layout = LAYOUT_VTX_NORMAL_COLOR; + static const ArrayLayout layout = LAYOUT_VTX_NORMAL_COLOR; }; struct alignas(16) VertexNormTex @@ -248,7 +249,7 @@ struct alignas(16) VertexNormTex std::array norm; std::array texCoord; - static const int layout = LAYOUT_VTX_NORMAL_TEXTURE0; + static const ArrayLayout layout = LAYOUT_VTX_NORMAL_TEXTURE0; }; @@ -449,6 +450,8 @@ class IVertexBuffer virtual void clear() = 0; /// Gets the number of vertices contained in the buffer. virtual size_t count() const = 0; + /// Gets the vertex format held by the buffer. + virtual ArrayLayout getVertexLayout() const = 0; /// Gets the primitive type contained by the vertex buffer. virtual GLenum getShape() const = 0; /// Gets the stride between vertices. @@ -473,6 +476,7 @@ class VertexBuffer : public IVertexBuffer virtual void clear() { vertex_data.clear(); } virtual size_t count() const { return vertex_data.size(); } + virtual ArrayLayout getVertexLayout() const { return T::layout; } virtual GLenum getShape() const { return primitive; } virtual size_t getStride() const { return sizeof(T); } @@ -520,6 +524,7 @@ class IndexedVertexBuffer : public IIndexedBuffer virtual size_t count() const { return vertex_data.size(); } + virtual ArrayLayout getVertexLayout() const { return T::layout; } virtual GLenum getShape() const { return primitive; } virtual size_t getStride() const { return sizeof(T); } @@ -543,7 +548,7 @@ class IndexedVertexBuffer : public IIndexedBuffer } }; -class TextBuffer : public IVertexBuffer +class TextBuffer { public: struct Entry @@ -560,11 +565,15 @@ class TextBuffer : public IVertexBuffer private: std::vector vertex_data; size_t num_chars; + int handle = 0; public: TextBuffer() : num_chars(0) { } ~TextBuffer() { } + int getHandle() const { return handle; } + void setHandle(int dev_hnd) { handle = dev_hnd; } + /// Adds a text element at the specified local space (pre-transform) /// coordinates. void addText(float x, float y, float z, int ox, int oy, @@ -651,6 +660,29 @@ class GlDrawable } public: + std::vector getArrayBuffers() const + { + std::vector out_buffers; + for (int i = 0; i < NUM_LAYOUTS; i++) + { + for (size_t j = 0; j < NUM_SHAPES; j++) + { + if (buffers[i][j]) + { + out_buffers.emplace_back(buffers[i][j].get()); + } + if (indexed_buffers[i][j]) + { + out_buffers.emplace_back(indexed_buffers[i][j].get()); + } + } + } + return out_buffers; + } + + TextBuffer& getTextBuffer() { return text_buffer; } + const TextBuffer& getTextBuffer() const { return text_buffer; } + /// Adds a string at the given position in object coordinates. void addText(float x, float y, float z, const std::string& text) { diff --git a/lib/sdl.cpp b/lib/sdl.cpp index 63b31533..e590e2b1 100644 --- a/lib/sdl.cpp +++ b/lib/sdl.cpp @@ -304,7 +304,6 @@ bool SdlWindow::createWindow(const char * title, int x, int y, int w, int h, << "." << (int)sdl_ver.patch << std::endl); renderer.reset(new gl3::MeshRenderer); - renderer->setSamplesMSAA(GetMultisample()); #ifndef __EMSCRIPTEN__ if (!GLEW_VERSION_1_1) { diff --git a/lib/vsdata.cpp b/lib/vsdata.cpp index aa5c5fc9..d1680d7f 100644 --- a/lib/vsdata.cpp +++ b/lib/vsdata.cpp @@ -740,18 +740,6 @@ void KeyKPressed() SendExposeEvent(); } -void KeyAPressed() -{ - bool curr_aa = GetAppWindow()->getRenderer().getAntialiasing(); - GetAppWindow()->getRenderer().setAntialiasing(!curr_aa); - - cout << "Multisampling/Antialiasing: " - << strings_off_on[!curr_aa ? 1 : 0] << endl; - - // vsdata -> EventUpdateColors(); - SendExposeEvent(); -} - void KeyCommaPressed() { locscene->matAlphaCenter -= 0.25; @@ -1111,7 +1099,6 @@ void VisualizationSceneScalarData::Init() // wnd->setOnKeyDown('a', KeyaPressed); wnd->setOnKeyDown('a', Key_Mod_a_Pressed); - wnd->setOnKeyDown('A', KeyAPressed); wnd->setOnKeyDown('r', KeyrPressed); wnd->setOnKeyDown('R', KeyRPressed); diff --git a/makefile b/makefile index 3c1a2a1a..501cf03e 100644 --- a/makefile +++ b/makefile @@ -213,6 +213,7 @@ Ccc = $(strip $(CC) $(CFLAGS) $(GL_OPTS)) # generated with 'echo lib/gl/*.c* lib/*.c*', does not include lib/*.m (Obj-C) ALL_SOURCE_FILES = \ lib/gl/renderer.cpp lib/gl/renderer_core.cpp lib/gl/renderer_ff.cpp \ + lib/gl/renderer_msaa.cpp lib/gl/renderer_print.cpp \ lib/gl/shader.cpp lib/gl/types.cpp lib/aux_js.cpp lib/aux_vis.cpp lib/font.cpp \ lib/gl2ps.c lib/material.cpp lib/openglvis.cpp lib/palettes.cpp lib/sdl.cpp \ lib/stream_reader.cpp lib/threads.cpp lib/vsdata.cpp lib/vssolution.cpp \ @@ -229,6 +230,7 @@ COMMON_SOURCE_FILES = $(filter-out \ HEADER_FILES = \ lib/gl/attr_traits.hpp lib/gl/platform_gl.hpp lib/gl/renderer.hpp \ lib/gl/shader.hpp lib/gl/renderer_core.hpp lib/gl/renderer_ff.hpp \ + lib/gl/renderer_msaa.hpp lib/gl/renderer_print.hpp \ lib/gl/types.hpp lib/aux_vis.hpp lib/font.hpp lib/geom_utils.hpp lib/gl2ps.h \ lib/logo.hpp lib/material.hpp lib/openglvis.hpp lib/palettes.hpp lib/sdl.hpp \ lib/sdl_helper.hpp lib/sdl_mac.hpp lib/sdl_x11.hpp lib/stream_reader.hpp \ From dc3305159afa7b7545714e4feeea41652555c431 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Tue, 30 Mar 2021 15:38:46 -0700 Subject: [PATCH 02/29] Add functions for handling binding framebuffers in passes --- lib/gl/renderer.cpp | 18 ++++++++++++++++++ lib/gl/renderer.hpp | 9 +++++++++ lib/gl/renderer_msaa.cpp | 2 +- lib/gl/renderer_msaa.hpp | 12 ++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/lib/gl/renderer.cpp b/lib/gl/renderer.cpp index a6b8615e..cabeb2e0 100644 --- a/lib/gl/renderer.cpp +++ b/lib/gl/renderer.cpp @@ -42,6 +42,17 @@ bool GLDevice::useLegacyTextureFmts() #endif } +void GLDevice::attachFramebuffer(const FBOHandle& fbo) +{ + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); + GLenum drawOutput = GL_BACK; + if (fbo != 0) + { + drawOutput = GL_COLOR_ATTACHMENT0; + } + glDrawBuffers(1, &drawOutput); +} + void DefaultPass::Render(const RenderQueue& queue) { // elements containing opaque objects should be rendered first @@ -51,6 +62,7 @@ void DefaultPass::Render(const RenderQueue& queue) { return !renderPair.first.contains_translucent; }); + device->attachFramebuffer(*target); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); int color_tex = palette->GetColorTexture(); int alpha_tex = palette->GetAlphaTexture(); @@ -146,12 +158,16 @@ void MeshRenderer::render(const vector& main_passes, } // Step 2: Setup the framebuffer with the first extra pass, and render the // queue with the main passes. + FBOHandle default_target(0); + std::reference_wrapper curr_out = default_target; if (extra_passes.size() > 0) { extra_passes[0]->PreRender(); + curr_out = extra_passes[0]->GetSourceFramebuffer(); } for (int ipass = 0; ipass < main_passes.size(); ipass++) { + main_passes[ipass]->SetTargetFramebuffer(curr_out); main_passes[ipass]->PreRender(); main_passes[ipass]->Render(matched_queues[ipass]); main_passes[ipass]->PostRender(); @@ -163,8 +179,10 @@ void MeshRenderer::render(const vector& main_passes, { // Finalize last stage's results onto next stage extra_passes[ipass]->PreRender(); + curr_out = extra_passes[ipass]->GetSourceFramebuffer(); extra_passes[ipass-1]->PostRender(); } + extra_passes[extra_passes.size() - 1]->SetTargetFramebuffer(default_target); extra_passes[extra_passes.size() - 1]->PostRender(); } } diff --git a/lib/gl/renderer.hpp b/lib/gl/renderer.hpp index fe5bfcef..683f5865 100644 --- a/lib/gl/renderer.hpp +++ b/lib/gl/renderer.hpp @@ -105,6 +105,8 @@ class GLDevice glBindTexture(GL_TEXTURE_2D, tex_id); }; + void attachFramebuffer(const FBOHandle& fbo); + // If true, use unsized internal formats and GL_ALPHA for single-channel // data. Otherwise, use the newer sized internal formats and GL_RED. static bool useLegacyTextureFmts(); @@ -175,8 +177,15 @@ class IRenderPass virtual void SetGLDevice(GLDevice* dev) { device = dev; } virtual void PreRender() = 0; virtual void PostRender() = 0; + + virtual const FBOHandle& GetSourceFramebuffer() const + { return default_target; } + + virtual void SetTargetFramebuffer(const FBOHandle& fbo) { target = &fbo; } protected: GLDevice* device; + const FBOHandle* target = nullptr; + const FBOHandle default_target{0}; }; // Generic interface for an action on a queue of renderable objects. diff --git a/lib/gl/renderer_msaa.cpp b/lib/gl/renderer_msaa.cpp index bec133eb..70e8f8c2 100644 --- a/lib/gl/renderer_msaa.cpp +++ b/lib/gl/renderer_msaa.cpp @@ -147,7 +147,7 @@ void MultisamplePass::PostRender() #ifndef __EMSCRIPTEN__ glDisable(GL_MULTISAMPLE); #endif - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *target); glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFb); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBlitFramebuffer(0, 0, width, height, diff --git a/lib/gl/renderer_msaa.hpp b/lib/gl/renderer_msaa.hpp index 56e3be3d..8c9eb510 100644 --- a/lib/gl/renderer_msaa.hpp +++ b/lib/gl/renderer_msaa.hpp @@ -25,6 +25,18 @@ class MultisamplePass : public IRenderPass virtual void PreRender(); virtual void PostRender(); + virtual const FBOHandle& GetSourceFramebuffer() const + { + if (msaa_enable && msaaFb) + { + return msaaFb; + } + else + { + return IRenderPass::default_target; + } + } + void SetAntialiasing(bool aa_status); bool GetAntialiasing() { return msaa_enable; } void SetNumSamples(int samples) From 4333a5d3d560ef9ba7c0c86920e9b03d963cc24f Mon Sep 17 00:00:00 2001 From: Max Yang Date: Wed, 31 Mar 2021 09:59:09 -0700 Subject: [PATCH 03/29] Fix replacement of gl_FragData variables --- lib/gl/shader.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/gl/shader.cpp b/lib/gl/shader.cpp index 421d83e9..b2e0f77c 100644 --- a/lib/gl/shader.cpp +++ b/lib/gl/shader.cpp @@ -177,15 +177,19 @@ std::string ShaderProgram::formatShader(const std::string& inShader, // although gl_FragColor was deprecated in GLSL 1.3 for (int i = 0; i < num_outputs; i++) { - std::string indexString = "gl_FragData["; - indexString += std::to_string(i) + "]"; + std::string indexString = "gl_FragData\\["; + indexString += std::to_string(i) + "\\]"; std::string outputString = "out vec4 fragColor_"; outputString += std::to_string(i) + ";\n"; + if (glsl_version > 130) + { + formatted = std::regex_replace(formatted, std::regex(indexString), + "fragColor_" + std::to_string(i)); + } if (glsl_version > 130 && glsl_version < 330) { + // append output variable specifications without layout specifiers formatted = outputString + formatted; - formatted = std::regex_replace(formatted, std::regex(indexString), - "fragColor"); } else if (glsl_version >= 330 || (glsl_version == 300 && glsl_es)) { @@ -243,7 +247,7 @@ GLuint ShaderProgram::compileShader(const std::string& inShader, // glGetObjectParameteriv if (stat == GL_FALSE) { - std::cerr << "failed to compile shader" << std::endl; + std::cerr << "Failed to compile shader" << std::endl; int err_len; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &err_len); char *error_text = new char[err_len]; From e6ea065482d4003c512548ed070c0e1dee471fbd Mon Sep 17 00:00:00 2001 From: Max Yang Date: Wed, 31 Mar 2021 11:16:29 -0700 Subject: [PATCH 04/29] Add in-progress depth peeling render pass --- lib/CMakeLists.txt | 2 + lib/aux_vis.cpp | 24 +- lib/gl/depth_peel_oit.cpp | 304 +++++++++++++++++++++ lib/gl/depth_peel_oit.hpp | 61 +++++ lib/gl/shaders/depth_peel.frag | 89 ++++++ lib/gl/shaders/depth_peel_blend_back.frag | 27 ++ lib/gl/shaders/depth_peel_finalize.frag | 30 ++ lib/gl/shaders/depth_peel_passthrough.vert | 19 ++ 8 files changed, 553 insertions(+), 3 deletions(-) create mode 100644 lib/gl/depth_peel_oit.cpp create mode 100644 lib/gl/depth_peel_oit.hpp create mode 100644 lib/gl/shaders/depth_peel.frag create mode 100644 lib/gl/shaders/depth_peel_blend_back.frag create mode 100644 lib/gl/shaders/depth_peel_finalize.frag create mode 100644 lib/gl/shaders/depth_peel_passthrough.vert diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 6a840644..970e8182 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -14,6 +14,7 @@ list(APPEND SOURCES gl/renderer_core.cpp gl/renderer_msaa.cpp gl/renderer_print.cpp + gl/depth_peel_oit.cpp gl/shader.cpp gl/types.cpp aux_vis.cpp @@ -36,6 +37,7 @@ list(APPEND HEADERS gl/renderer_core.hpp gl/renderer_msaa.hpp gl/renderer_print.hpp + gl/depth_peel_oit.hpp gl/shader.hpp gl/types.hpp aux_vis.hpp diff --git a/lib/aux_vis.cpp b/lib/aux_vis.cpp index 780c8235..994c8844 100644 --- a/lib/aux_vis.cpp +++ b/lib/aux_vis.cpp @@ -35,6 +35,7 @@ using namespace mfem; #include "gl/renderer_msaa.hpp" #include "gl/renderer_print.hpp" +#include "gl/depth_peel_oit.hpp" int visualize = 0; VisualizationScene * locscene; @@ -379,10 +380,20 @@ void MyReshape(GLsizei w, GLsizei h) void MyExpose(GLsizei w, GLsizei h) { MyReshape (w, h); + bool use_depth_peel = true; gl3::DefaultPass rndr_main_pass; + gl3::DepthPeeler rndr_depth_peeled; + if (!use_depth_peel) + { + rndr_main_pass.setFontTexture(GetFont()->getFontTex()); + rndr_main_pass.setPalette(locscene->palette); + } + else + { + rndr_depth_peeled.setFontTexture(GetFont()->getFontTex()); + rndr_depth_peeled.setPalette(locscene->palette); + } gl3::MultisamplePass rndr_msaa_pass; - rndr_main_pass.setFontTexture(GetFont()->getFontTex()); - rndr_main_pass.setPalette(locscene->palette); // Set antialiasing parameters rndr_msaa_pass.SetAntialiasing(multisample_status); rndr_msaa_pass.SetNumSamples(GetMultisample()); @@ -393,7 +404,14 @@ void MyExpose(GLsizei w, GLsizei h) { wnd->getRenderer().buffer(drawable_ptr); } - wnd->getRenderer().render({&rndr_main_pass}, {&rndr_msaa_pass}, frame.queue); + if (!use_depth_peel) + { + wnd->getRenderer().render({&rndr_main_pass}, {&rndr_msaa_pass}, frame.queue); + } + else + { + wnd->getRenderer().render({&rndr_depth_peeled}, {&rndr_msaa_pass}, frame.queue); + } } void MyExpose() diff --git a/lib/gl/depth_peel_oit.cpp b/lib/gl/depth_peel_oit.cpp new file mode 100644 index 00000000..85616aac --- /dev/null +++ b/lib/gl/depth_peel_oit.cpp @@ -0,0 +1,304 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-443271. +// +// This file is part of the GLVis visualization tool and library. For more +// information and source code availability see https://glvis.org. +// +// GLVis is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "depth_peel_oit.hpp" +#include "renderer_core.hpp" +#include "shader.hpp" + +const std::string DepthPeelVS[2] = +{ +#include "shaders/default.vert" + , +#include "shaders/depth_peel_passthrough.vert" +}; + +const std::string DepthPeelFS[] = +{ +#include "shaders/lighting.glsl" +#include "shaders/depth_peel.frag" + , +#include "shaders/depth_peel_blend_back.frag" + , +#include "shaders/depth_peel_finalize.frag" +}; + + +namespace gl3 +{ + +void DepthPeeler::SetGLDevice(GLDevice* dev) +{ + IMainRenderPass::SetGLDevice(dev); + { + GLuint vbo; + glGenBuffers(1, &vbo); + rect_buf = BufObjHandle{vbo}; + float quad_verts[] = + { + -1.f, 1.f, -1.f, -1.f, 1.f, -1.f, + -1.f, 1.f, 1.f, -1.f, 1.f, 1.f, + }; + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, 12, quad_verts, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + + std::unordered_map attribMap = + { + { CoreGLDevice::ATTR_VERTEX, "vertex"}, + { CoreGLDevice::ATTR_TEXT_VERTEX, "textVertex"}, + { CoreGLDevice::ATTR_NORMAL, "normal"}, + { CoreGLDevice::ATTR_COLOR, "color"}, + { CoreGLDevice::ATTR_TEXCOORD0, "texCoord0"} + }; + if (!main_prgm.create(DepthPeelVS[0], DepthPeelFS[0], attribMap, 3)) + { + std::cerr << "Unable to create depth peeling main program." << std::endl; + } + if (!blend_prgm.create(DepthPeelVS[1], DepthPeelFS[1], attribMap, 1)) + { + std::cerr << "Unable to create depth peeling blending program." << std::endl; + } + if (!finalize_prgm.create(DepthPeelVS[1], DepthPeelFS[2], attribMap, 1)) + { + std::cerr << "Unable to create depth peeling blending program." << std::endl; + } + + GLint vp[4]; + device->getViewport(vp); + int tex_w = vp[2]; + int tex_h = vp[3]; + + for (int i = 0; i < 2; i++) + { + glBindFramebuffer(GL_FRAMEBUFFER, main_peel_fbs[i]); + + glBindTexture(GL_TEXTURE_2D, depthTex[i]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, tex_w, tex_h, 0, GL_RG, GL_FLOAT, + nullptr); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + depthTex[i], 0); + + glBindTexture(GL_TEXTURE_2D, frontColorTex[i]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, tex_w, tex_h, 0, GL_RGBA, + GL_HALF_FLOAT, nullptr); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, + frontColorTex[i], 0); + + glBindTexture(GL_TEXTURE_2D, backColorTex[i]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, tex_w, tex_h, 0, GL_RGBA, + GL_HALF_FLOAT, nullptr); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, + backColorTex[i], 0); + + glBindFramebuffer(GL_FRAMEBUFFER, color_fbs[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + frontColorTex[i], 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, + backColorTex[i], 0); + } + + glBindFramebuffer(GL_FRAMEBUFFER, blend_back_fb); + glBindTexture(GL_TEXTURE_2D, backBlendTex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, tex_w, tex_h, 0, GL_RGBA, + GL_HALF_FLOAT, nullptr); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + backBlendTex, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + + +void DepthPeeler::PreRender() +{ + // Clear back blend buffer + { + GLenum blendBufs = GL_COLOR_ATTACHMENT0; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, blend_back_fb); + glDrawBuffers(1, &blendBufs); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + } + for (int i = 0; i < 2; i++) + { + // Initial depth texture should be set to [-MAX_DEPTH, MAX_DEPTH] + GLenum depthBufs = GL_COLOR_ATTACHMENT0; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, main_peel_fbs[i]); + glDrawBuffers(1, &depthBufs); + glClearColor(MAX_DEPTH, MAX_DEPTH, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + + GLenum colorBufs[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, color_fbs[i]); + glDrawBuffers(2, colorBufs); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + } + device->enableBlend(); + device->enableDepthWrite(); +} + +void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) +{ + int src_i = i % 2; + int dst_i = 1 - src_i; + // Clear our target buffers for this pass + { + GLenum depthBufs = GL_COLOR_ATTACHMENT0; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, main_peel_fbs[dst_i]); + glDrawBuffers(1, &depthBufs); + glClearColor(MAX_DEPTH, MAX_DEPTH, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + + GLenum colorBufs[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, color_fbs[dst_i]); + glDrawBuffers(2, colorBufs); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + } + + // Setup main peel program and framebuffer + dynamic_cast(device)->bindExternalProgram(main_prgm); + main_prgm.setOutputFramebuffer(main_peel_fbs[dst_i]); + glBlendEquation(GL_MAX); + + // Bind source depth and front color texture + glActiveTexture(GL_TEXTURE0 + 2); + glBindTexture(GL_TEXTURE_2D, depthTex[src_i]); + + glActiveTexture(GL_TEXTURE0 + 3); + glBindTexture(GL_TEXTURE_2D, frontColorTex[src_i]); + + glUniform1i(main_prgm.uniform("lastDepthTex"), 2); + glUniform1i(main_prgm.uniform("lastFrontColorTex"), 3); + + int color_tex = palette->GetColorTexture(); + int alpha_tex = palette->GetAlphaTexture(); + device->enableDepthWrite(); + // Render the geometry to peel + for (auto& geom : queue) + { + const RenderParams& params = geom.first; + device->setTransformMatrices(params.model_view.mtx, params.projection.mtx); + device->setMaterial(params.mesh_material); + device->setNumLights(params.num_pt_lights); + for (int i = 0; i < params.num_pt_lights; i++) + { + device->setPointLight(i, params.lights[i]); + } + device->setAmbientLight(params.light_amb_scene); + device->setStaticColor(params.static_color); + device->setClipPlaneUse(params.use_clip_plane); + device->setClipPlaneEqn(params.clip_plane_eqn); + // aggregate buffers with common parameters + std::vector tex_bufs, no_tex_bufs; + GlDrawable* curr_drawable = geom.second; + auto buffers = curr_drawable->getArrayBuffers(); + for (const IVertexBuffer* buf : buffers) + { + if (buf->getVertexLayout() == LAYOUT_VTX_TEXTURE0 + || buf->getVertexLayout() == LAYOUT_VTX_NORMAL_TEXTURE0) + { + tex_bufs.emplace_back(buf->getHandle()); + } + else + { + no_tex_bufs.emplace_back(buf->getHandle()); + } + } + device->attachTexture(GLDevice::SAMPLER_COLOR, color_tex); + device->attachTexture(GLDevice::SAMPLER_ALPHA, alpha_tex); + for (auto buf : tex_bufs) + { + device->drawDeviceBuffer(buf); + } + device->detachTexture(GLDevice::SAMPLER_COLOR); + device->detachTexture(GLDevice::SAMPLER_ALPHA); + for (auto buf : no_tex_bufs) + { + device->drawDeviceBuffer(buf); + } + device->attachTexture(1, font_tex); + device->setNumLights(0); + device->drawDeviceBuffer(curr_drawable->getTextBuffer()); + } + + // Blend just-written back layer separately + blend_prgm.setOutputFramebuffer(blend_back_fb); + blend_prgm.bind(); + glBlendEquation(GL_FUNC_ADD); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, + GL_ONE_MINUS_SRC_ALPHA); + + glActiveTexture(GL_TEXTURE0 + 2); + glBindTexture(GL_TEXTURE_2D, backColorTex[dst_i]); + glUniform1i(blend_prgm.uniform("lastBackColor"), 2); + + glBindBuffer(GL_ARRAY_BUFFER, rect_buf); + glEnableVertexAttribArray(CoreGLDevice::ATTR_VERTEX); + glVertexAttribPointer(CoreGLDevice::ATTR_VERTEX, + 2, GL_FLOAT, false, 0, 0); + glDrawArrays(GL_TRIANGLES, 0, 6); +} + +void DepthPeeler::PostRender() +{ + int src_i = (NUM_PASSES+1) % 2; + + finalize_prgm.setOutputFramebuffer(*target); + finalize_prgm.bind(); + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, frontColorTex[src_i]); + + glActiveTexture(GL_TEXTURE0 + 1); + glBindTexture(GL_TEXTURE_2D, backBlendTex); + + glUniform1i(finalize_prgm.uniform("lastFrontColor"), 0); + glUniform1i(finalize_prgm.uniform("lastBackColor"), 1); + + glBindBuffer(GL_ARRAY_BUFFER, rect_buf); + glEnableVertexAttribArray(CoreGLDevice::ATTR_VERTEX); + glVertexAttribPointer(CoreGLDevice::ATTR_VERTEX, + 2, GL_FLOAT, false, 0, 0); + glDrawArrays(GL_TRIANGLES, 0, 6); +} + +void DepthPeeler::Render(const RenderQueue& queue) +{ + for (int i = 0; i < NUM_PASSES; i++) + { + DoRenderPass(i, queue); + } +} + +} + + diff --git a/lib/gl/depth_peel_oit.hpp b/lib/gl/depth_peel_oit.hpp new file mode 100644 index 00000000..ae16fb5e --- /dev/null +++ b/lib/gl/depth_peel_oit.hpp @@ -0,0 +1,61 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-443271. +// +// This file is part of the GLVis visualization tool and library. For more +// information and source code availability see https://glvis.org. +// +// GLVis is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#ifndef GLVIS_DEPTH_PEEL_OIT_HPP +#define GLVIS_DEPTH_PEEL_OIT_HPP + +#include "renderer.hpp" +#include "shader.hpp" + +namespace gl3 +{ + +class DepthPeeler : public IMainRenderPass +{ + virtual void SetGLDevice(GLDevice* device); + + virtual bool Filter(const RenderParams& param) + { + return true; + } + + virtual void PreRender(); + virtual void Render(const RenderQueue& queue); + virtual void PostRender(); +private: + const double MAX_DEPTH = 10.0; + const int NUM_PASSES = 4; + + void DoRenderPass(int i, const RenderQueue& queue); + + MeshRenderer* renderer; + + ShaderProgram main_prgm; + ShaderProgram blend_prgm; + ShaderProgram finalize_prgm; + + TextureHandle depthTex[2]; + TextureHandle frontColorTex[2]; + TextureHandle backColorTex[2]; + + TextureHandle backBlendTex; + + FBOHandle main_peel_fbs[2]; + FBOHandle color_fbs[2]; + FBOHandle blend_back_fb; + + // Drawing full-screen rectangles + BufObjHandle rect_buf; +}; + +} + +#endif diff --git a/lib/gl/shaders/depth_peel.frag b/lib/gl/shaders/depth_peel.frag new file mode 100644 index 00000000..ad58e630 --- /dev/null +++ b/lib/gl/shaders/depth_peel.frag @@ -0,0 +1,89 @@ +R"( +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-443271. +// +// This file is part of the GLVis visualization tool and library. For more +// information and source code availability see https://glvis.org. +// +// GLVis is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +uniform sampler2D alphaTex; +uniform sampler2D colorTex; +uniform sampler2D lastDepthTex; +uniform sampler2D lastFrontColorTex; + +varying vec3 fNormal; +varying vec3 fPosition; +varying vec4 fColor; +varying vec2 fTexCoord; + +uniform bool useClipPlane; +varying float fClipVal; + +void fragmentClipPlane() +{ + if (useClipPlane && fClipVal < 0.0) + { + discard; + } +} + +#define MAX_DEPTH 10.0 + +// location 0: depth +// location 1: front color +// location 2: back color + +// adapted from "Order Independent Transparency with Dual Depth Peeling": +// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.193.3485&rep=rep1&type=pdf +// and https://github.com/tsherif/webgl2examples/blob/master/oit-dual-depth-peeling.html + +void main() +{ + fragmentClipPlane(); + + ivec2 iFragCoord = ivec2(gl_FragCoord.xy); + vec2 lastDepths = texelFetch(lastDepthTex, iFragCoord, 0).xy; + vec4 lastFrontColor = texelFetch(lastFrontColorTex, iFragCoord, 0); + float nearestDepth = -lastDepths.x; + float farthestDepth = lastDepths.y; + float thisDepth = gl_FragCoord.z; + float alphaMultiplier = 1.0 - lastFrontColor.a; + + gl_FragData[0].xy = vec2(-MAX_DEPTH); + gl_FragData[1] = lastFrontColor; + gl_FragData[2] = vec4(0.0); + + if (thisDepth < nearestDepth || thisDepth > farthestDepth) + { + return; + } + + if (thisDepth > nearestDepth && thisDepth < farthestDepth) + { + gl_FragData[0].xy = vec2(-thisDepth, thisDepth); + return; + } + + vec4 color = fColor * texture2D(colorTex, vec2(fTexCoord)); + color = blinnPhong(fPosition, fNormal, color); +#ifdef USE_ALPHA + color.a *= texture2D(alphaTex, vec2(fTexCoord)).a; +#else + color.a *= texture2D(alphaTex, vec2(fTexCoord)).r; +#endif + + if (thisDepth == nearestDepth) + { + gl_FragData[1].rgb += color.rgb * color.a * alphaMultiplier; + gl_FragData[2].a = 1.0 - alphaMultiplier * (1.0 - color.a); + } + else + { + gl_FragData[2] += color; + } +} +)" diff --git a/lib/gl/shaders/depth_peel_blend_back.frag b/lib/gl/shaders/depth_peel_blend_back.frag new file mode 100644 index 00000000..588fa1a3 --- /dev/null +++ b/lib/gl/shaders/depth_peel_blend_back.frag @@ -0,0 +1,27 @@ +R"( +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-443271. +// +// This file is part of the GLVis visualization tool and library. For more +// information and source code availability see https://glvis.org. +// +// GLVis is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +uniform sampler2D lastBackColor; + +// adapted from "Order Independent Transparency with Dual Depth Peeling": +// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.193.3485&rep=rep1&type=pdf +// and https://github.com/tsherif/webgl2examples/blob/master/oit-dual-depth-peeling.html + +void main() +{ + gl_FragColor = texelFetch(lastBackColor, ivec2(gl_FragCoord.xy), 0); + if (gl_FragColor.a == 0) + { + discard; + } +} +)" diff --git a/lib/gl/shaders/depth_peel_finalize.frag b/lib/gl/shaders/depth_peel_finalize.frag new file mode 100644 index 00000000..c22e40db --- /dev/null +++ b/lib/gl/shaders/depth_peel_finalize.frag @@ -0,0 +1,30 @@ +R"( +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-443271. +// +// This file is part of the GLVis visualization tool and library. For more +// information and source code availability see https://glvis.org. +// +// GLVis is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +uniform sampler2D lastFrontColor; +uniform sampler2D lastBackColor; + +// adapted from "Order Independent Transparency with Dual Depth Peeling": +// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.193.3485&rep=rep1&type=pdf +// and https://github.com/tsherif/webgl2examples/blob/master/oit-dual-depth-peeling.html + +void main() +{ + ivec2 iQuadCoord = ivec2(gl_FragCoord.xy); + vec4 frontColor = texelFetch(lastFrontColor, iQuadCoord, 0); + vec4 backColor = texelFetch(lastBackColor, iQuadCoord, 0); + float alphaMultiplier = 1.0 - frontColor.a; + + gl_FragColor.rgb = frontColor.rgb + alphaMultiplier * backColor.rgb; + gl_FragColor.a = frontColor.a + backColor.a; +} +)" diff --git a/lib/gl/shaders/depth_peel_passthrough.vert b/lib/gl/shaders/depth_peel_passthrough.vert new file mode 100644 index 00000000..1eb64e4a --- /dev/null +++ b/lib/gl/shaders/depth_peel_passthrough.vert @@ -0,0 +1,19 @@ +R"( +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-443271. +// +// This file is part of the GLVis visualization tool and library. For more +// information and source code availability see https://glvis.org. +// +// GLVis is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +attribute vec4 vertex; + +void main() +{ + gl_Position = vertex; +} +)" From 05589ec7344010f2ea659a86ca45bee96b629fe5 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Tue, 13 Apr 2021 17:50:05 -0700 Subject: [PATCH 05/29] Bugfixes to get stuff to display --- lib/gl/depth_peel_oit.cpp | 30 ++++++++++++++++++++++++------ lib/gl/renderer_core.cpp | 15 +++++++++------ lib/gl/shader.hpp | 5 +++++ lib/gl/shaders/depth_peel.frag | 5 +++-- lib/gl/shaders/lighting.glsl | 2 +- 5 files changed, 42 insertions(+), 15 deletions(-) diff --git a/lib/gl/depth_peel_oit.cpp b/lib/gl/depth_peel_oit.cpp index 85616aac..6e6ab814 100644 --- a/lib/gl/depth_peel_oit.cpp +++ b/lib/gl/depth_peel_oit.cpp @@ -47,7 +47,7 @@ void DepthPeeler::SetGLDevice(GLDevice* dev) -1.f, 1.f, 1.f, -1.f, 1.f, 1.f, }; glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferData(GL_ARRAY_BUFFER, 12, quad_verts, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), quad_verts, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); } @@ -79,6 +79,16 @@ void DepthPeeler::SetGLDevice(GLDevice* dev) for (int i = 0; i < 2; i++) { + { + GLuint fb_ids[2], tex_ids[3]; + glGenFramebuffers(2, fb_ids); + glGenTextures(3, tex_ids); + main_peel_fbs[i] = fb_ids[0]; + color_fbs[i] = fb_ids[1]; + frontColorTex[i] = tex_ids[0]; + backColorTex[i] = tex_ids[1]; + depthTex[i] = tex_ids[2]; + } glBindFramebuffer(GL_FRAMEBUFFER, main_peel_fbs[i]); glBindTexture(GL_TEXTURE_2D, depthTex[i]); @@ -118,6 +128,13 @@ void DepthPeeler::SetGLDevice(GLDevice* dev) backColorTex[i], 0); } + { + GLuint fb_id, tex_id; + glGenFramebuffers(1, &fb_id); + glGenTextures(1, &tex_id); + blend_back_fb = fb_id; + backBlendTex = tex_id; + } glBindFramebuffer(GL_FRAMEBUFFER, blend_back_fb); glBindTexture(GL_TEXTURE_2D, backBlendTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -171,7 +188,7 @@ void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) GLenum depthBufs = GL_COLOR_ATTACHMENT0; glBindFramebuffer(GL_DRAW_FRAMEBUFFER, main_peel_fbs[dst_i]); glDrawBuffers(1, &depthBufs); - glClearColor(MAX_DEPTH, MAX_DEPTH, 0, 0); + glClearColor(-10., -10., 0, 0); glClear(GL_COLOR_BUFFER_BIT); GLenum colorBufs[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; @@ -184,7 +201,6 @@ void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) // Setup main peel program and framebuffer dynamic_cast(device)->bindExternalProgram(main_prgm); main_prgm.setOutputFramebuffer(main_peel_fbs[dst_i]); - glBlendEquation(GL_MAX); // Bind source depth and front color texture glActiveTexture(GL_TEXTURE0 + 2); @@ -198,7 +214,9 @@ void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) int color_tex = palette->GetColorTexture(); int alpha_tex = palette->GetAlphaTexture(); - device->enableDepthWrite(); + glDisable(GL_DEPTH_TEST); + device->enableBlend(); + glBlendEquation(GL_MAX); // Render the geometry to peel for (auto& geom : queue) { @@ -248,8 +266,8 @@ void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) } // Blend just-written back layer separately - blend_prgm.setOutputFramebuffer(blend_back_fb); blend_prgm.bind(); + blend_prgm.setOutputFramebuffer(blend_back_fb); glBlendEquation(GL_FUNC_ADD); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); @@ -269,8 +287,8 @@ void DepthPeeler::PostRender() { int src_i = (NUM_PASSES+1) % 2; - finalize_prgm.setOutputFramebuffer(*target); finalize_prgm.bind(); + finalize_prgm.setOutputFramebuffer(*target); glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); diff --git a/lib/gl/renderer_core.cpp b/lib/gl/renderer_core.cpp index dbae4667..86bf06a0 100644 --- a/lib/gl/renderer_core.cpp +++ b/lib/gl/renderer_core.cpp @@ -147,14 +147,17 @@ void CoreGLDevice::initializeShaderState(const ShaderProgram& prog) } } #ifdef GLVIS_DEBUG - unordered_set expectedUnifs(unif_list.begin(), unif_list.end()); - for (const auto& pairunif : uniforms) + if (prog == default_prgm) { - if (expectedUnifs.find(pairunif.first) == expectedUnifs.end()) + unordered_set expectedUnifs(unif_list.begin(), unif_list.end()); + for (const auto& pairunif : uniforms) { - std::cerr << "Warning: unexpected uniform \"" - << pairunif.first - << "\" found in shader." << std::endl; + if (expectedUnifs.find(pairunif.first) == expectedUnifs.end()) + { + std::cerr << "Warning: unexpected uniform \"" + << pairunif.first + << "\" found in shader." << std::endl; + } } } #endif diff --git a/lib/gl/shader.hpp b/lib/gl/shader.hpp index 5f02bb73..eaa732fa 100644 --- a/lib/gl/shader.hpp +++ b/lib/gl/shader.hpp @@ -59,6 +59,11 @@ class ShaderProgram void setOutputFramebuffer(const FBOHandle& fbo); void setDefaultDrawFramebuffer(); + bool operator== (const ShaderProgram& other) const + { + return program_id == other.program_id; + } + private: static void GetGLSLVersion(); diff --git a/lib/gl/shaders/depth_peel.frag b/lib/gl/shaders/depth_peel.frag index ad58e630..ee40fa4a 100644 --- a/lib/gl/shaders/depth_peel.frag +++ b/lib/gl/shaders/depth_peel.frag @@ -53,12 +53,12 @@ void main() float thisDepth = gl_FragCoord.z; float alphaMultiplier = 1.0 - lastFrontColor.a; - gl_FragData[0].xy = vec2(-MAX_DEPTH); gl_FragData[1] = lastFrontColor; gl_FragData[2] = vec4(0.0); if (thisDepth < nearestDepth || thisDepth > farthestDepth) { + gl_FragData[0].xy = vec2(-MAX_DEPTH); return; } @@ -68,6 +68,7 @@ void main() return; } + gl_FragData[0].xy = vec2(-MAX_DEPTH); vec4 color = fColor * texture2D(colorTex, vec2(fTexCoord)); color = blinnPhong(fPosition, fNormal, color); #ifdef USE_ALPHA @@ -79,7 +80,7 @@ void main() if (thisDepth == nearestDepth) { gl_FragData[1].rgb += color.rgb * color.a * alphaMultiplier; - gl_FragData[2].a = 1.0 - alphaMultiplier * (1.0 - color.a); + gl_FragData[1].a = 1.0 - alphaMultiplier * (1.0 - color.a); } else { diff --git a/lib/gl/shaders/lighting.glsl b/lib/gl/shaders/lighting.glsl index b957ad63..c92697a4 100644 --- a/lib/gl/shaders/lighting.glsl +++ b/lib/gl/shaders/lighting.glsl @@ -67,6 +67,6 @@ vec4 blinnPhong(in vec3 pos, in vec3 norm, in vec4 color) float specular_factor = max(dot(half_v, norm), 0.0); lit_color += lights[i].specular * material.specular * pow(specular_factor, material.shininess); } - return lit_color; + return vec4(lit_color.rgb, color.a); } )" From 939a47ca7608d1f120c8f6b7412fd4e58607a47d Mon Sep 17 00:00:00 2001 From: Max Yang Date: Wed, 14 Apr 2021 16:17:56 -0700 Subject: [PATCH 06/29] Fixes for background setting in depth peeling mode; use depth peeling only when transparent --- lib/aux_vis.cpp | 2 +- lib/gl/depth_peel_oit.cpp | 3 ++- lib/gl/renderer.cpp | 2 ++ lib/gl/renderer.hpp | 8 +++++++- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/aux_vis.cpp b/lib/aux_vis.cpp index 994c8844..48f16bd8 100644 --- a/lib/aux_vis.cpp +++ b/lib/aux_vis.cpp @@ -380,7 +380,7 @@ void MyReshape(GLsizei w, GLsizei h) void MyExpose(GLsizei w, GLsizei h) { MyReshape (w, h); - bool use_depth_peel = true; + bool use_depth_peel = !(locscene->matAlpha == 1.0); gl3::DefaultPass rndr_main_pass; gl3::DepthPeeler rndr_depth_peeled; if (!use_depth_peel) diff --git a/lib/gl/depth_peel_oit.cpp b/lib/gl/depth_peel_oit.cpp index 6e6ab814..6b205f1b 100644 --- a/lib/gl/depth_peel_oit.cpp +++ b/lib/gl/depth_peel_oit.cpp @@ -289,7 +289,8 @@ void DepthPeeler::PostRender() finalize_prgm.bind(); finalize_prgm.setOutputFramebuffer(*target); - glClearColor(0, 0, 0, 1); + auto clear_color = device->getClearColor(); + glClearColor(clear_color[0], clear_color[1], clear_color[2], clear_color[3]); glClear(GL_COLOR_BUFFER_BIT); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); diff --git a/lib/gl/renderer.cpp b/lib/gl/renderer.cpp index cabeb2e0..73514deb 100644 --- a/lib/gl/renderer.cpp +++ b/lib/gl/renderer.cpp @@ -55,6 +55,8 @@ void GLDevice::attachFramebuffer(const FBOHandle& fbo) void DefaultPass::Render(const RenderQueue& queue) { + auto clear_color = device->getClearColor(); + glClearColor(clear_color[0], clear_color[1], clear_color[2], clear_color[3]); // elements containing opaque objects should be rendered first RenderQueue sorted_queue = queue; std::stable_partition(sorted_queue.begin(), sorted_queue.end(), diff --git a/lib/gl/renderer.hpp b/lib/gl/renderer.hpp index 683f5865..7b6fac34 100644 --- a/lib/gl/renderer.hpp +++ b/lib/gl/renderer.hpp @@ -75,6 +75,7 @@ class GLDevice glm::mat4 proj_mtx; std::array static_color; + std::array clear_color { 1.f, 1.f, 1.f, 1.f }; bool blend_enabled = false; @@ -126,6 +127,10 @@ class GLDevice void getViewport(GLint (&vp)[4]); // Set the color to use, if a color attribute is not provided. void setStaticColor(const std::array& rgba) { static_color = rgba; } + // Set the background clear color to use. + void setClearColor(const std::array& rgba) { clear_color = rgba; } + // Gets the current background color. + std::array getClearColor() const { return clear_color; } // === Render pipeline functions === @@ -249,7 +254,8 @@ class MeshRenderer } float GetLineWidth() { return line_w; } - void setClearColor(float r, float g, float b, float a) { glClearColor(r, g, b, a); } + void setClearColor(float r, float g, float b, float a) + { device->setClearColor({r,g,b,a}); } void setViewport(GLsizei w, GLsizei h) { device->setViewport(w, h); } void render(const std::vector& main_passes, From 3ce16886ad19a314fccfec8be794ed1105eaaa87 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Wed, 14 Apr 2021 17:09:27 -0700 Subject: [PATCH 07/29] Reset to default state after depth peel --- lib/gl/depth_peel_oit.cpp | 8 +++++--- lib/gl/renderer.hpp | 2 +- lib/gl/renderer_core.hpp | 2 +- lib/gl/renderer_print.hpp | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/gl/depth_peel_oit.cpp b/lib/gl/depth_peel_oit.cpp index 6b205f1b..ab959d89 100644 --- a/lib/gl/depth_peel_oit.cpp +++ b/lib/gl/depth_peel_oit.cpp @@ -176,7 +176,6 @@ void DepthPeeler::PreRender() glClear(GL_COLOR_BUFFER_BIT); } device->enableBlend(); - device->enableDepthWrite(); } void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) @@ -214,8 +213,6 @@ void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) int color_tex = palette->GetColorTexture(); int alpha_tex = palette->GetAlphaTexture(); - glDisable(GL_DEPTH_TEST); - device->enableBlend(); glBlendEquation(GL_MAX); // Render the geometry to peel for (auto& geom : queue) @@ -308,6 +305,11 @@ void DepthPeeler::PostRender() glVertexAttribPointer(CoreGLDevice::ATTR_VERTEX, 2, GL_FLOAT, false, 0, 0); glDrawArrays(GL_TRIANGLES, 0, 6); + + // Reset to the default program state + device->initRenderMode(); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } void DepthPeeler::Render(const RenderQueue& queue) diff --git a/lib/gl/renderer.hpp b/lib/gl/renderer.hpp index 7b6fac34..f6bc14fa 100644 --- a/lib/gl/renderer.hpp +++ b/lib/gl/renderer.hpp @@ -165,7 +165,7 @@ class GLDevice // Initializes state needed for transform feedback. virtual void initXfbMode() {} // Prepares state when exiting transform feedback. - virtual void exitXfbMode() {} + virtual void initRenderMode() {} // Capture the next drawn vertex buffer to a feedback buffer instead of // drawing to screen. virtual void captureXfbBuffer(PaletteState& pal, CaptureBuffer& capture, diff --git a/lib/gl/renderer_core.hpp b/lib/gl/renderer_core.hpp index fe626339..afb382c3 100644 --- a/lib/gl/renderer_core.hpp +++ b/lib/gl/renderer_core.hpp @@ -102,7 +102,7 @@ class CoreGLDevice : public GLDevice initializeShaderState(feedback_prgm); glEnable(GL_RASTERIZER_DISCARD); } - void exitXfbMode() override + void initRenderMode() override { glDisable(GL_RASTERIZER_DISCARD); initializeShaderState(default_prgm); diff --git a/lib/gl/renderer_print.hpp b/lib/gl/renderer_print.hpp index 8b134bfc..d0b3b411 100644 --- a/lib/gl/renderer_print.hpp +++ b/lib/gl/renderer_print.hpp @@ -55,7 +55,7 @@ class CapturePass : public IMainRenderPass virtual void PreRender() { device->initXfbMode(); } virtual void Render(const RenderQueue& queued); - virtual void PostRender() { device->exitXfbMode(); } + virtual void PostRender() { device->initRenderMode(); } CaptureBuffer GetLastCaptureBuffer() { From c9a108e3aeb82283259513832bcd770764537528 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Wed, 14 Apr 2021 19:07:43 -0700 Subject: [PATCH 08/29] Render opaque objects first without depth peeling --- lib/gl/depth_peel_oit.cpp | 83 +++++++++++++++++++++++++++++++++++++-- lib/gl/depth_peel_oit.hpp | 4 ++ 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/lib/gl/depth_peel_oit.cpp b/lib/gl/depth_peel_oit.cpp index ab959d89..0b8857e7 100644 --- a/lib/gl/depth_peel_oit.cpp +++ b/lib/gl/depth_peel_oit.cpp @@ -77,6 +77,38 @@ void DepthPeeler::SetGLDevice(GLDevice* dev) int tex_w = vp[2]; int tex_h = vp[3]; + { + GLuint fb_id; + GLuint tex_ids[2]; + glGenFramebuffers(1, &fb_id); + glGenTextures(2, tex_ids); + opaque_fb = fb_id; + opaqueColorTex = tex_ids[0]; + opaqueDepthTex = tex_ids[1]; + + glBindFramebuffer(GL_FRAMEBUFFER, opaque_fb); + + glBindTexture(GL_TEXTURE_2D, opaqueColorTex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, tex_w, tex_h, 0, GL_RGBA, + GL_HALF_FLOAT, nullptr); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + opaqueColorTex, 0); + + glBindTexture(GL_TEXTURE_2D, opaqueDepthTex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, tex_w, tex_h, 0, + GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, + opaqueDepthTex, 0); + } + for (int i = 0; i < 2; i++) { { @@ -121,6 +153,9 @@ void DepthPeeler::SetGLDevice(GLDevice* dev) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, backColorTex[i], 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, + opaqueDepthTex, 0); + glBindFramebuffer(GL_FRAMEBUFFER, color_fbs[i]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, frontColorTex[i], 0); @@ -178,6 +213,33 @@ void DepthPeeler::PreRender() device->enableBlend(); } +void DepthPeeler::RenderOpaque(const RenderQueue& queue) +{ + GLint vp[4]; + device->getViewport(vp); + int tex_w = vp[2]; + int tex_h = vp[3]; + DefaultPass opaque_pass; + opaque_pass.SetGLDevice(device); + opaque_pass.SetTargetFramebuffer(opaque_fb); + opaque_pass.setPalette(*palette); + opaque_pass.setFontTexture(font_tex); + // Render opaque pass objects - this fills in the correct depth attachment + // texture for the depth testing of translucent peels. + opaque_pass.PreRender(); + opaque_pass.Render(queue); + opaque_pass.PostRender(); + // The opaque object depth data will be passed onto the peeling render + // passes, so all we need to do now is to blit the color data to the output + // framebuffer. + glBindFramebuffer(GL_READ_FRAMEBUFFER, opaque_fb); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *target); + glBlitFramebuffer(0, 0, tex_w, tex_h, + 0, 0, tex_w, tex_h, + GL_COLOR_BUFFER_BIT, + GL_LINEAR); +} + void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) { int src_i = i % 2; @@ -214,6 +276,7 @@ void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) int color_tex = palette->GetColorTexture(); int alpha_tex = palette->GetAlphaTexture(); glBlendEquation(GL_MAX); + glDepthMask(GL_FALSE); // Render the geometry to peel for (auto& geom : queue) { @@ -261,6 +324,7 @@ void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) device->setNumLights(0); device->drawDeviceBuffer(curr_drawable->getTextBuffer()); } + glDepthMask(GL_TRUE); // Blend just-written back layer separately blend_prgm.bind(); @@ -286,9 +350,6 @@ void DepthPeeler::PostRender() finalize_prgm.bind(); finalize_prgm.setOutputFramebuffer(*target); - auto clear_color = device->getClearColor(); - glClearColor(clear_color[0], clear_color[1], clear_color[2], clear_color[3]); - glClear(GL_COLOR_BUFFER_BIT); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glActiveTexture(GL_TEXTURE0); @@ -314,9 +375,23 @@ void DepthPeeler::PostRender() void DepthPeeler::Render(const RenderQueue& queue) { + // elements containing opaque objects should be rendered first + RenderQueue sorted_queue = queue; + auto begin_translucent = + std::stable_partition(sorted_queue.begin(), sorted_queue.end(), + [](RenderQueue::value_type& renderPair) + { + return !renderPair.first.contains_translucent; + }); + // Partition into two queues, one with opaque objects and one with + // translucent objects + RenderQueue opaque_queue(sorted_queue.begin(), begin_translucent); + RenderQueue translucent_queue(begin_translucent, sorted_queue.end()); + + RenderOpaque(opaque_queue); for (int i = 0; i < NUM_PASSES; i++) { - DoRenderPass(i, queue); + DoRenderPass(i, translucent_queue); } } diff --git a/lib/gl/depth_peel_oit.hpp b/lib/gl/depth_peel_oit.hpp index ae16fb5e..e2038a8f 100644 --- a/lib/gl/depth_peel_oit.hpp +++ b/lib/gl/depth_peel_oit.hpp @@ -34,6 +34,8 @@ class DepthPeeler : public IMainRenderPass const double MAX_DEPTH = 10.0; const int NUM_PASSES = 4; + void RenderOpaque(const RenderQueue& queue); + void DoRenderPass(int i, const RenderQueue& queue); MeshRenderer* renderer; @@ -45,12 +47,14 @@ class DepthPeeler : public IMainRenderPass TextureHandle depthTex[2]; TextureHandle frontColorTex[2]; TextureHandle backColorTex[2]; + TextureHandle opaqueColorTex, opaqueDepthTex; TextureHandle backBlendTex; FBOHandle main_peel_fbs[2]; FBOHandle color_fbs[2]; FBOHandle blend_back_fb; + FBOHandle opaque_fb; // Drawing full-screen rectangles BufObjHandle rect_buf; From 07bde314350872092be4cf4c439e725c2ae4d203 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Thu, 15 Apr 2021 17:22:47 -0700 Subject: [PATCH 09/29] Try to fix warnings --- lib/gl/renderer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/gl/renderer.cpp b/lib/gl/renderer.cpp index 73514deb..b901401f 100644 --- a/lib/gl/renderer.cpp +++ b/lib/gl/renderer.cpp @@ -149,7 +149,7 @@ void MeshRenderer::render(const vector& main_passes, std::vector matched_queues(main_passes.size()); for (auto drawable : queued) { - for (int ipass = 0; ipass < main_passes.size(); ipass++) + for (size_t ipass = 0; ipass < main_passes.size(); ipass++) { if (main_passes[ipass]->Filter(drawable.first)) { @@ -167,7 +167,7 @@ void MeshRenderer::render(const vector& main_passes, extra_passes[0]->PreRender(); curr_out = extra_passes[0]->GetSourceFramebuffer(); } - for (int ipass = 0; ipass < main_passes.size(); ipass++) + for (size_t ipass = 0; ipass < main_passes.size(); ipass++) { main_passes[ipass]->SetTargetFramebuffer(curr_out); main_passes[ipass]->PreRender(); @@ -177,7 +177,7 @@ void MeshRenderer::render(const vector& main_passes, if (extra_passes.size() > 0) { - for (int ipass = 1; ipass < extra_passes.size(); ipass++) + for (size_t ipass = 1; ipass < extra_passes.size(); ipass++) { // Finalize last stage's results onto next stage extra_passes[ipass]->PreRender(); From 4337bd836a47366d52301e3543c848e8d62c8508 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Fri, 16 Apr 2021 10:41:42 -0700 Subject: [PATCH 10/29] Trying to fix linking issues --- lib/gl/depth_peel_oit.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/gl/depth_peel_oit.hpp b/lib/gl/depth_peel_oit.hpp index e2038a8f..2640f21b 100644 --- a/lib/gl/depth_peel_oit.hpp +++ b/lib/gl/depth_peel_oit.hpp @@ -20,6 +20,7 @@ namespace gl3 class DepthPeeler : public IMainRenderPass { +public: virtual void SetGLDevice(GLDevice* device); virtual bool Filter(const RenderParams& param) @@ -38,8 +39,6 @@ class DepthPeeler : public IMainRenderPass void DoRenderPass(int i, const RenderQueue& queue); - MeshRenderer* renderer; - ShaderProgram main_prgm; ShaderProgram blend_prgm; ShaderProgram finalize_prgm; From 29a906957d43947fc7e356b43200b738e6e65f24 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Fri, 16 Apr 2021 11:13:55 -0700 Subject: [PATCH 11/29] Add missing source files to makefile --- makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index 501cf03e..5f22def1 100644 --- a/makefile +++ b/makefile @@ -213,7 +213,7 @@ Ccc = $(strip $(CC) $(CFLAGS) $(GL_OPTS)) # generated with 'echo lib/gl/*.c* lib/*.c*', does not include lib/*.m (Obj-C) ALL_SOURCE_FILES = \ lib/gl/renderer.cpp lib/gl/renderer_core.cpp lib/gl/renderer_ff.cpp \ - lib/gl/renderer_msaa.cpp lib/gl/renderer_print.cpp \ + lib/gl/depth_peel_oit.cpp lib/gl/renderer_msaa.cpp lib/gl/renderer_print.cpp \ lib/gl/shader.cpp lib/gl/types.cpp lib/aux_js.cpp lib/aux_vis.cpp lib/font.cpp \ lib/gl2ps.c lib/material.cpp lib/openglvis.cpp lib/palettes.cpp lib/sdl.cpp \ lib/stream_reader.cpp lib/threads.cpp lib/vsdata.cpp lib/vssolution.cpp \ @@ -230,7 +230,7 @@ COMMON_SOURCE_FILES = $(filter-out \ HEADER_FILES = \ lib/gl/attr_traits.hpp lib/gl/platform_gl.hpp lib/gl/renderer.hpp \ lib/gl/shader.hpp lib/gl/renderer_core.hpp lib/gl/renderer_ff.hpp \ - lib/gl/renderer_msaa.hpp lib/gl/renderer_print.hpp \ + lib/gl/depth_peel_oit.hpp lib/gl/renderer_msaa.hpp lib/gl/renderer_print.hpp \ lib/gl/types.hpp lib/aux_vis.hpp lib/font.hpp lib/geom_utils.hpp lib/gl2ps.h \ lib/logo.hpp lib/material.hpp lib/openglvis.hpp lib/palettes.hpp lib/sdl.hpp \ lib/sdl_helper.hpp lib/sdl_mac.hpp lib/sdl_x11.hpp lib/stream_reader.hpp \ From b02284de56d28ab5b2160454bfb6f9d82b82698a Mon Sep 17 00:00:00 2001 From: Tzanio Date: Sat, 24 Apr 2021 12:53:34 -0700 Subject: [PATCH 12/29] make style --- lib/aux_vis.cpp | 16 ++++++++-------- lib/gl/attr_traits.hpp | 6 +++--- lib/gl/depth_peel_oit.cpp | 4 ++-- lib/gl/types.hpp | 8 ++++---- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/aux_vis.cpp b/lib/aux_vis.cpp index 48f16bd8..1b003d2f 100644 --- a/lib/aux_vis.cpp +++ b/lib/aux_vis.cpp @@ -385,13 +385,13 @@ void MyExpose(GLsizei w, GLsizei h) gl3::DepthPeeler rndr_depth_peeled; if (!use_depth_peel) { - rndr_main_pass.setFontTexture(GetFont()->getFontTex()); - rndr_main_pass.setPalette(locscene->palette); + rndr_main_pass.setFontTexture(GetFont()->getFontTex()); + rndr_main_pass.setPalette(locscene->palette); } else { - rndr_depth_peeled.setFontTexture(GetFont()->getFontTex()); - rndr_depth_peeled.setPalette(locscene->palette); + rndr_depth_peeled.setFontTexture(GetFont()->getFontTex()); + rndr_depth_peeled.setPalette(locscene->palette); } gl3::MultisamplePass rndr_msaa_pass; // Set antialiasing parameters @@ -1172,18 +1172,18 @@ void KeyAPressed() { if (glvis_multisample < 0) { - cout << "Multisampling disabled." << endl; - return; + cout << "Multisampling disabled." << endl; + return; } multisample_status = !multisample_status; if (multisample_status) { - cout << "Multisampling/Antialiasing: on" << endl; + cout << "Multisampling/Antialiasing: on" << endl; } else { - cout << "Multisampling/Antialiasing: off" << endl; + cout << "Multisampling/Antialiasing: off" << endl; } SendExposeEvent(); diff --git a/lib/gl/attr_traits.hpp b/lib/gl/attr_traits.hpp index b993c115..662ea078 100644 --- a/lib/gl/attr_traits.hpp +++ b/lib/gl/attr_traits.hpp @@ -125,9 +125,9 @@ AttrNormal> const static GLenum FFArrayIdx = GL_NORMAL_ARRAY; static void FFSetupFunc(GLint /*size*/, GLenum type, GLsizei stride, const GLvoid* ptr) - { - glNormalPointer(type, stride, ptr); - } +{ + glNormalPointer(type, stride, ptr); +} }; template diff --git a/lib/gl/depth_peel_oit.cpp b/lib/gl/depth_peel_oit.cpp index 0b8857e7..ab334ec6 100644 --- a/lib/gl/depth_peel_oit.cpp +++ b/lib/gl/depth_peel_oit.cpp @@ -44,8 +44,8 @@ void DepthPeeler::SetGLDevice(GLDevice* dev) float quad_verts[] = { -1.f, 1.f, -1.f, -1.f, 1.f, -1.f, - -1.f, 1.f, 1.f, -1.f, 1.f, 1.f, - }; + -1.f, 1.f, 1.f, -1.f, 1.f, 1.f, + }; glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), quad_verts, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); diff --git a/lib/gl/types.hpp b/lib/gl/types.hpp index b7a8e7c4..5db4de8f 100644 --- a/lib/gl/types.hpp +++ b/lib/gl/types.hpp @@ -203,11 +203,11 @@ struct alignas(16) Vertex std::array coord; static Vertex create(double * d) - { - return Vertex {(float) d[0], (float) d[1], (float) d[2]}; - } +{ + return Vertex {(float) d[0], (float) d[1], (float) d[2]}; +} - static const ArrayLayout layout = LAYOUT_VTX; +static const ArrayLayout layout = LAYOUT_VTX; }; struct alignas(16) VertexColor From ebf34f851c1333ad114ede4213a8d25112d416dc Mon Sep 17 00:00:00 2001 From: Max Yang Date: Mon, 26 Apr 2021 14:44:44 -0700 Subject: [PATCH 13/29] Retain rendering stages to avoid recompilation of shaders --- lib/aux_vis.cpp | 11 ++++-- lib/gl/depth_peel_oit.cpp | 8 +++- lib/gl/depth_peel_oit.hpp | 2 + lib/gl/renderer.cpp | 8 ---- lib/gl/renderer.hpp | 2 + lib/gl/renderer_msaa.cpp | 83 ++++++++++++++++++--------------------- lib/gl/renderer_msaa.hpp | 15 ++++++- lib/gl/shader.cpp | 5 +++ lib/gl/shader.hpp | 5 --- 9 files changed, 74 insertions(+), 65 deletions(-) diff --git a/lib/aux_vis.cpp b/lib/aux_vis.cpp index 1b003d2f..d48b1ec2 100644 --- a/lib/aux_vis.cpp +++ b/lib/aux_vis.cpp @@ -53,6 +53,10 @@ float line_w_aa = gl3::LINE_WIDTH_AA; SdlWindow * wnd = nullptr; bool wndLegacyGl = false; +gl3::DefaultPass rndr_main_pass; +gl3::DepthPeeler rndr_depth_peeled; +gl3::MultisamplePass rndr_msaa_pass; + SdlWindow * GetAppWindow() { return wnd; @@ -90,6 +94,10 @@ int InitVisualization (const char name[], int x, int y, int w, int h) wnd->clearEvents(); } + rndr_main_pass.SetGLDevice(wnd->getRenderer().getDevice()); + rndr_msaa_pass.SetGLDevice(wnd->getRenderer().getDevice()); + rndr_depth_peeled.SetGLDevice(wnd->getRenderer().getDevice()); + #ifdef GLVIS_DEBUG cout << "Window should be up" << endl; #endif @@ -381,8 +389,6 @@ void MyExpose(GLsizei w, GLsizei h) { MyReshape (w, h); bool use_depth_peel = !(locscene->matAlpha == 1.0); - gl3::DefaultPass rndr_main_pass; - gl3::DepthPeeler rndr_depth_peeled; if (!use_depth_peel) { rndr_main_pass.setFontTexture(GetFont()->getFontTex()); @@ -393,7 +399,6 @@ void MyExpose(GLsizei w, GLsizei h) rndr_depth_peeled.setFontTexture(GetFont()->getFontTex()); rndr_depth_peeled.setPalette(locscene->palette); } - gl3::MultisamplePass rndr_msaa_pass; // Set antialiasing parameters rndr_msaa_pass.SetAntialiasing(multisample_status); rndr_msaa_pass.SetNumSamples(GetMultisample()); diff --git a/lib/gl/depth_peel_oit.cpp b/lib/gl/depth_peel_oit.cpp index ab334ec6..ac829eae 100644 --- a/lib/gl/depth_peel_oit.cpp +++ b/lib/gl/depth_peel_oit.cpp @@ -44,8 +44,8 @@ void DepthPeeler::SetGLDevice(GLDevice* dev) float quad_verts[] = { -1.f, 1.f, -1.f, -1.f, 1.f, -1.f, - -1.f, 1.f, 1.f, -1.f, 1.f, 1.f, - }; + -1.f, 1.f, 1.f, -1.f, 1.f, 1.f, + }; glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), quad_verts, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -71,7 +71,10 @@ void DepthPeeler::SetGLDevice(GLDevice* dev) { std::cerr << "Unable to create depth peeling blending program." << std::endl; } +} +void DepthPeeler::CreateScreenPeelObjs() +{ GLint vp[4]; device->getViewport(vp); int tex_w = vp[2]; @@ -187,6 +190,7 @@ void DepthPeeler::SetGLDevice(GLDevice* dev) void DepthPeeler::PreRender() { + CreateScreenPeelObjs(); // Clear back blend buffer { GLenum blendBufs = GL_COLOR_ATTACHMENT0; diff --git a/lib/gl/depth_peel_oit.hpp b/lib/gl/depth_peel_oit.hpp index 2640f21b..bc8febd4 100644 --- a/lib/gl/depth_peel_oit.hpp +++ b/lib/gl/depth_peel_oit.hpp @@ -35,6 +35,8 @@ class DepthPeeler : public IMainRenderPass const double MAX_DEPTH = 10.0; const int NUM_PASSES = 4; + void CreateScreenPeelObjs(); + void RenderOpaque(const RenderQueue& queue); void DoRenderPass(int i, const RenderQueue& queue); diff --git a/lib/gl/renderer.cpp b/lib/gl/renderer.cpp index b901401f..d2cca05d 100644 --- a/lib/gl/renderer.cpp +++ b/lib/gl/renderer.cpp @@ -136,14 +136,6 @@ void MeshRenderer::render(const vector& main_passes, const vector& extra_passes, const RenderQueue& queued) { - for (IMainRenderPass* pass : main_passes) - { - pass->SetGLDevice(device.get()); - } - for (IRenderPass* pass : extra_passes) - { - pass->SetGLDevice(device.get()); - } // Step 1: Match renderables in the queue with the *first* render pass that // can handle them. std::vector matched_queues(main_passes.size()); diff --git a/lib/gl/renderer.hpp b/lib/gl/renderer.hpp index f6bc14fa..51a7184a 100644 --- a/lib/gl/renderer.hpp +++ b/lib/gl/renderer.hpp @@ -247,6 +247,8 @@ class MeshRenderer device.reset(new TDevice(device)); } + GLDevice* getDevice() const { return device.get(); } + void SetLineWidth(float w) { line_w = w; diff --git a/lib/gl/renderer_msaa.cpp b/lib/gl/renderer_msaa.cpp index 70e8f8c2..214ef5fb 100644 --- a/lib/gl/renderer_msaa.cpp +++ b/lib/gl/renderer_msaa.cpp @@ -17,7 +17,6 @@ namespace gl3 void MultisamplePass::SetGLDevice(GLDevice* dev) { IRenderPass::SetGLDevice(dev); - int max_msaa_samples; #ifdef __EMSCRIPTEN__ const std::string versionString = reinterpret_cast(glGetString(GL_VERSION)); @@ -32,54 +31,47 @@ void MultisamplePass::SetGLDevice(GLDevice* dev) feat_use_fbo_antialias = GLEW_VERSION_3_0; glGetIntegerv(GL_MAX_SAMPLES, &max_msaa_samples); #endif - if (msaa_samples > max_msaa_samples) +} + +void MultisamplePass::CreateFramebuffer() +{ + GLuint colorBuf, depthBuf; + glGenRenderbuffers(1, &colorBuf); + glGenRenderbuffers(1, &depthBuf); + renderBufs[0] = RenderBufHandle(colorBuf); + renderBufs[1] = RenderBufHandle(depthBuf); + + GLuint fbo; + glGenFramebuffers(1, &fbo); + + int vp[4]; + device->getViewport(vp); + int width = vp[2]; + int height = vp[3]; + glBindRenderbuffer(GL_RENDERBUFFER, colorBuf); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_samples, + GL_RGBA8, width, height); + glBindRenderbuffer(GL_RENDERBUFFER, depthBuf); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_samples, + GL_DEPTH_COMPONENT24, width, height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, colorBuf); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, depthBuf); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - std::cerr << "GL_MAX_SAMPLES = " << max_msaa_samples - << " but requested " << msaa_samples << "x MSAA. "; - std::cerr << "Setting antialiasing mode to " - << max_msaa_samples << "x MSAA." << endl; - msaa_samples = max_msaa_samples; + cerr << "Unable to create multisampled renderbuffer." << flush; + glDeleteFramebuffers(1, &fbo); } - if (feat_use_fbo_antialias) + else { - GLuint colorBuf, depthBuf; - glGenRenderbuffers(1, &colorBuf); - glGenRenderbuffers(1, &depthBuf); - renderBufs[0] = RenderBufHandle(colorBuf); - renderBufs[1] = RenderBufHandle(depthBuf); - - GLuint fbo; - glGenFramebuffers(1, &fbo); - - int vp[4]; - device->getViewport(vp); - int width = vp[2]; - int height = vp[3]; - glBindRenderbuffer(GL_RENDERBUFFER, colorBuf); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_samples, - GL_RGBA8, width, height); - glBindRenderbuffer(GL_RENDERBUFFER, depthBuf); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_samples, - GL_DEPTH_COMPONENT24, width, height); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_RENDERBUFFER, colorBuf); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, depthBuf); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - { - cerr << "Unable to create multisampled renderbuffer." << flush; - glDeleteFramebuffers(1, &fbo); - } - else - { - msaaFb = FBOHandle(fbo); - } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + msaaFb = FBOHandle(fbo); } + glBindFramebuffer(GL_FRAMEBUFFER, 0); } void MultisamplePass::PreRender() @@ -88,6 +80,7 @@ void MultisamplePass::PreRender() { if (feat_use_fbo_antialias) { + CreateFramebuffer(); glBindFramebuffer(GL_FRAMEBUFFER, msaaFb); } else diff --git a/lib/gl/renderer_msaa.hpp b/lib/gl/renderer_msaa.hpp index 8c9eb510..23f5f207 100644 --- a/lib/gl/renderer_msaa.hpp +++ b/lib/gl/renderer_msaa.hpp @@ -42,6 +42,14 @@ class MultisamplePass : public IRenderPass void SetNumSamples(int samples) { msaa_samples = samples; + if (msaa_samples > max_msaa_samples) + { + std::cerr << "GL_MAX_SAMPLES = " << max_msaa_samples + << " but requested " << msaa_samples << "x MSAA. "; + std::cerr << "Setting antialiasing mode to " + << max_msaa_samples << "x MSAA." << endl; + msaa_samples = max_msaa_samples; + } } int GetNumSamples() { return msaa_samples; } @@ -50,9 +58,12 @@ class MultisamplePass : public IRenderPass void SetLineWidthMS(float w); float GetLineWidthMS() { return line_w_aa; } private: - bool feat_use_fbo_antialias; + void CreateFramebuffer(); + + bool feat_use_fbo_antialias = false; bool msaa_enable{false}; - int msaa_samples; + int max_msaa_samples = 1; + int msaa_samples = 1; float line_w, line_w_aa; RenderBufHandle renderBufs[2]; diff --git a/lib/gl/shader.cpp b/lib/gl/shader.cpp index b2e0f77c..93678c32 100644 --- a/lib/gl/shader.cpp +++ b/lib/gl/shader.cpp @@ -261,6 +261,11 @@ GLuint ShaderProgram::compileShader(const std::string& inShader, bool ShaderProgram::linkShaders(const std::vector& shaders) { + program_id = glCreateProgram(); + if (program_id == 0) + { + std::cerr << "Failed to create an OpenGL program object." << std::endl; + } // Bind all incoming attributes to their VAO indices. for (auto attrib_pair : attrib_idx) { diff --git a/lib/gl/shader.hpp b/lib/gl/shader.hpp index eaa732fa..3294a610 100644 --- a/lib/gl/shader.hpp +++ b/lib/gl/shader.hpp @@ -23,11 +23,6 @@ class ShaderProgram public: ShaderProgram() { - program_id = glCreateProgram(); - if (program_id == 0) - { - std::cerr << "Failed to create an OpenGL program object." << std::endl; - } } bool create(std::string vertexShader, From 48716f4e6378535c01e0bd4e886fafffc515c2a0 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Tue, 27 Apr 2021 14:16:37 -0700 Subject: [PATCH 14/29] Consolidate screen texture creation code, set tighter max depths --- lib/gl/depth_peel_oit.cpp | 92 ++++++++++++---------------------- lib/gl/depth_peel_oit.hpp | 8 ++- lib/gl/shaders/depth_peel.frag | 2 +- 3 files changed, 41 insertions(+), 61 deletions(-) diff --git a/lib/gl/depth_peel_oit.cpp b/lib/gl/depth_peel_oit.cpp index ac829eae..fc4835b0 100644 --- a/lib/gl/depth_peel_oit.cpp +++ b/lib/gl/depth_peel_oit.cpp @@ -34,6 +34,24 @@ const std::string DepthPeelFS[] = namespace gl3 { +TextureHandle DepthPeeler::CreateScreenTexture(GLenum internalFmt, + GLenum format, + GLenum type) +{ + GLuint tex_id; + glGenTextures(1, &tex_id); + + TextureHandle texture = tex_id; + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, screen_w, screen_h, 0, format, + type, nullptr); + return texture; +} + void DepthPeeler::SetGLDevice(GLDevice* dev) { IMainRenderPass::SetGLDevice(dev); @@ -77,37 +95,22 @@ void DepthPeeler::CreateScreenPeelObjs() { GLint vp[4]; device->getViewport(vp); - int tex_w = vp[2]; - int tex_h = vp[3]; + screen_w = vp[2]; + screen_h = vp[3]; { GLuint fb_id; - GLuint tex_ids[2]; glGenFramebuffers(1, &fb_id); - glGenTextures(2, tex_ids); opaque_fb = fb_id; - opaqueColorTex = tex_ids[0]; - opaqueDepthTex = tex_ids[1]; glBindFramebuffer(GL_FRAMEBUFFER, opaque_fb); - glBindTexture(GL_TEXTURE_2D, opaqueColorTex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, tex_w, tex_h, 0, GL_RGBA, - GL_HALF_FLOAT, nullptr); + opaqueColorTex = CreateScreenTexture(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); + opaqueDepthTex = CreateScreenTexture(GL_DEPTH_COMPONENT, + GL_DEPTH_COMPONENT, + GL_UNSIGNED_INT); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, opaqueColorTex, 0); - - glBindTexture(GL_TEXTURE_2D, opaqueDepthTex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, tex_w, tex_h, 0, - GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, opaqueDepthTex, 0); } @@ -115,44 +118,23 @@ void DepthPeeler::CreateScreenPeelObjs() for (int i = 0; i < 2; i++) { { - GLuint fb_ids[2], tex_ids[3]; + GLuint fb_ids[2]; glGenFramebuffers(2, fb_ids); - glGenTextures(3, tex_ids); main_peel_fbs[i] = fb_ids[0]; color_fbs[i] = fb_ids[1]; - frontColorTex[i] = tex_ids[0]; - backColorTex[i] = tex_ids[1]; - depthTex[i] = tex_ids[2]; } - glBindFramebuffer(GL_FRAMEBUFFER, main_peel_fbs[i]); - glBindTexture(GL_TEXTURE_2D, depthTex[i]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, tex_w, tex_h, 0, GL_RG, GL_FLOAT, - nullptr); + depthTex[i] = CreateScreenTexture(GL_RG32F, GL_RG, GL_FLOAT); + frontColorTex[i] = CreateScreenTexture(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); + backColorTex[i] = CreateScreenTexture(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); + + glBindFramebuffer(GL_FRAMEBUFFER, main_peel_fbs[i]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, depthTex[i], 0); - glBindTexture(GL_TEXTURE_2D, frontColorTex[i]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, tex_w, tex_h, 0, GL_RGBA, - GL_HALF_FLOAT, nullptr); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, frontColorTex[i], 0); - glBindTexture(GL_TEXTURE_2D, backColorTex[i]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, tex_w, tex_h, 0, GL_RGBA, - GL_HALF_FLOAT, nullptr); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, backColorTex[i], 0); @@ -167,20 +149,12 @@ void DepthPeeler::CreateScreenPeelObjs() } { - GLuint fb_id, tex_id; + GLuint fb_id; glGenFramebuffers(1, &fb_id); - glGenTextures(1, &tex_id); blend_back_fb = fb_id; - backBlendTex = tex_id; } + backBlendTex = CreateScreenTexture(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); glBindFramebuffer(GL_FRAMEBUFFER, blend_back_fb); - glBindTexture(GL_TEXTURE_2D, backBlendTex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, tex_w, tex_h, 0, GL_RGBA, - GL_HALF_FLOAT, nullptr); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, backBlendTex, 0); @@ -253,7 +227,7 @@ void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) GLenum depthBufs = GL_COLOR_ATTACHMENT0; glBindFramebuffer(GL_DRAW_FRAMEBUFFER, main_peel_fbs[dst_i]); glDrawBuffers(1, &depthBufs); - glClearColor(-10., -10., 0, 0); + glClearColor(-1., -1., 0, 0); glClear(GL_COLOR_BUFFER_BIT); GLenum colorBufs[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; diff --git a/lib/gl/depth_peel_oit.hpp b/lib/gl/depth_peel_oit.hpp index bc8febd4..eb048070 100644 --- a/lib/gl/depth_peel_oit.hpp +++ b/lib/gl/depth_peel_oit.hpp @@ -32,7 +32,7 @@ class DepthPeeler : public IMainRenderPass virtual void Render(const RenderQueue& queue); virtual void PostRender(); private: - const double MAX_DEPTH = 10.0; + const double MAX_DEPTH = 1.0; const int NUM_PASSES = 4; void CreateScreenPeelObjs(); @@ -41,6 +41,12 @@ class DepthPeeler : public IMainRenderPass void DoRenderPass(int i, const RenderQueue& queue); + TextureHandle CreateScreenTexture(GLenum internalFmt, + GLenum format, + GLenum type); + + int screen_w, screen_h; + ShaderProgram main_prgm; ShaderProgram blend_prgm; ShaderProgram finalize_prgm; diff --git a/lib/gl/shaders/depth_peel.frag b/lib/gl/shaders/depth_peel.frag index ee40fa4a..9c1844b5 100644 --- a/lib/gl/shaders/depth_peel.frag +++ b/lib/gl/shaders/depth_peel.frag @@ -31,7 +31,7 @@ void fragmentClipPlane() } } -#define MAX_DEPTH 10.0 +#define MAX_DEPTH 1.0 // location 0: depth // location 1: front color From 8a045b3d2ebc972b4dc12c20bf3b3fda68432267 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Wed, 28 Apr 2021 12:13:49 -0700 Subject: [PATCH 15/29] Fix source texture for depth peel finalization --- lib/gl/depth_peel_oit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gl/depth_peel_oit.cpp b/lib/gl/depth_peel_oit.cpp index fc4835b0..4ba69a66 100644 --- a/lib/gl/depth_peel_oit.cpp +++ b/lib/gl/depth_peel_oit.cpp @@ -324,7 +324,7 @@ void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) void DepthPeeler::PostRender() { - int src_i = (NUM_PASSES+1) % 2; + int src_i = NUM_PASSES % 2; finalize_prgm.bind(); finalize_prgm.setOutputFramebuffer(*target); From e7f28bd6c59ad5a793d8227bca544186c88480c5 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Wed, 28 Apr 2021 16:26:28 -0700 Subject: [PATCH 16/29] Rename a function to GLDevice::isOpenGL3 for more general use --- lib/aux_vis.cpp | 2 +- lib/gl/renderer.cpp | 8 ++++---- lib/gl/renderer.hpp | 2 +- lib/gl/shader.cpp | 2 +- lib/palettes.cpp | 14 +++++++------- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/aux_vis.cpp b/lib/aux_vis.cpp index d48b1ec2..8901da4b 100644 --- a/lib/aux_vis.cpp +++ b/lib/aux_vis.cpp @@ -1607,7 +1607,7 @@ void InitFont() { // This function is called after the window is created. GLenum alphaChannel = - gl3::GLDevice::useLegacyTextureFmts() ? GL_ALPHA : GL_RED; + gl3::GLDevice::isOpenGL3() ? GL_RED : GL_ALPHA; glvis_font.setAlphaChannel(alphaChannel); bool try_fc_patterns = true; if (!priority_font.empty()) diff --git a/lib/gl/renderer.cpp b/lib/gl/renderer.cpp index d2cca05d..10c5a1dd 100644 --- a/lib/gl/renderer.cpp +++ b/lib/gl/renderer.cpp @@ -24,21 +24,21 @@ namespace gl3 // unsized formats like GL_RED and GL_RGBA no longer support floating-point // data being passed in, so use of the sized internal formats is obligatory in // WebGL 2. -bool GLDevice::useLegacyTextureFmts() +bool GLDevice::isOpenGL3() { #ifdef __EMSCRIPTEN__ const std::string versionString = reinterpret_cast(glGetString(GL_VERSION)); if (versionString.find("OpenGL ES 3.0") != std::string::npos) { - return false; + return true; } else { - return true; + return false; } #else - return !GLEW_VERSION_3_0; + return GLEW_VERSION_3_0; #endif } diff --git a/lib/gl/renderer.hpp b/lib/gl/renderer.hpp index 51a7184a..fc0bb721 100644 --- a/lib/gl/renderer.hpp +++ b/lib/gl/renderer.hpp @@ -110,7 +110,7 @@ class GLDevice // If true, use unsized internal formats and GL_ALPHA for single-channel // data. Otherwise, use the newer sized internal formats and GL_RED. - static bool useLegacyTextureFmts(); + static bool isOpenGL3(); void enableBlend() { blend_enabled = true; glEnable(GL_BLEND); } void disableBlend() { blend_enabled = false; glDisable(GL_BLEND); } diff --git a/lib/gl/shader.cpp b/lib/gl/shader.cpp index 93678c32..797cc47f 100644 --- a/lib/gl/shader.cpp +++ b/lib/gl/shader.cpp @@ -214,7 +214,7 @@ std::string ShaderProgram::formatShader(const std::string& inShader, formatted = std::regex_replace(formatted, std::regex("texture2D"), "texture"); } - if (GLDevice::useLegacyTextureFmts()) + if (!GLDevice::isOpenGL3()) { formatted = "#define USE_ALPHA\n" + formatted; } diff --git a/lib/palettes.cpp b/lib/palettes.cpp index b9ff8e80..566ac843 100644 --- a/lib/palettes.cpp +++ b/lib/palettes.cpp @@ -7718,19 +7718,19 @@ void PaletteState::Init() alpha_tex = alphaTexId; GLenum alpha_internal; - if (gl3::GLDevice::useLegacyTextureFmts()) - { - alpha_internal = GL_ALPHA; - alpha_channel = GL_ALPHA; - rgba_internal = GL_RGBA; - } - else + if (gl3::GLDevice::isOpenGL3()) { // WebGL 2 requires sized internal format for float texture alpha_internal = GL_R32F; alpha_channel = GL_RED; rgba_internal = GL_RGBA32F; } + else + { + alpha_internal = GL_ALPHA; + alpha_channel = GL_ALPHA; + rgba_internal = GL_RGBA; + } // set alpha texture to 1.0 std::vector alphaTexData(MaxTextureSize * 2); std::fill(alphaTexData.begin(), alphaTexData.end(), 1.0f); From 804d25a785354331f1223af22a806b75423409ad Mon Sep 17 00:00:00 2001 From: Max Yang Date: Thu, 29 Apr 2021 12:00:16 -0700 Subject: [PATCH 17/29] Create a framebufffer class to handle common operations --- lib/CMakeLists.txt | 2 + lib/gl/depth_peel_oit.cpp | 126 ++++++++++------------------ lib/gl/depth_peel_oit.hpp | 9 +- lib/gl/framebuffer.cpp | 106 ++++++++++++++++++++++++ lib/gl/framebuffer.hpp | 167 ++++++++++++++++++++++++++++++++++++++ lib/gl/renderer.cpp | 17 +--- lib/gl/renderer.hpp | 11 ++- lib/gl/renderer_msaa.cpp | 55 +++---------- lib/gl/renderer_msaa.hpp | 4 +- lib/gl/shader.cpp | 32 -------- lib/gl/shader.hpp | 3 - makefile | 4 +- 12 files changed, 346 insertions(+), 190 deletions(-) create mode 100644 lib/gl/framebuffer.cpp create mode 100644 lib/gl/framebuffer.hpp diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 970e8182..fba58711 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -10,6 +10,7 @@ # CONTRIBUTING.md for details. list(APPEND SOURCES + gl/framebuffer.cpp gl/renderer.cpp gl/renderer_core.cpp gl/renderer_msaa.cpp @@ -31,6 +32,7 @@ list(APPEND SOURCES vsvector3d.cpp) list(APPEND HEADERS + gl/framebuffer.hpp gl/attr_traits.hpp gl/platform_gl.hpp gl/renderer.hpp diff --git a/lib/gl/depth_peel_oit.cpp b/lib/gl/depth_peel_oit.cpp index 4ba69a66..978b4d2b 100644 --- a/lib/gl/depth_peel_oit.cpp +++ b/lib/gl/depth_peel_oit.cpp @@ -38,18 +38,18 @@ TextureHandle DepthPeeler::CreateScreenTexture(GLenum internalFmt, GLenum format, GLenum type) { - GLuint tex_id; - glGenTextures(1, &tex_id); - - TextureHandle texture = tex_id; - glBindTexture(GL_TEXTURE_2D, texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, screen_w, screen_h, 0, format, - type, nullptr); - return texture; + GLuint tex_id; + glGenTextures(1, &tex_id); + + TextureHandle texture = tex_id; + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, screen_w, screen_h, 0, format, + type, nullptr); + return texture; } void DepthPeeler::SetGLDevice(GLDevice* dev) @@ -89,6 +89,14 @@ void DepthPeeler::SetGLDevice(GLDevice* dev) { std::cerr << "Unable to create depth peeling blending program." << std::endl; } + for (int i = 0; i < 2; i++) + { + main_peel_fbs[i].Init(); + color_fbs[i].Init(); + } + + blend_back_fb.Init(); + opaque_fb.Init(); } void DepthPeeler::CreateScreenPeelObjs() @@ -98,65 +106,30 @@ void DepthPeeler::CreateScreenPeelObjs() screen_w = vp[2]; screen_h = vp[3]; - { - GLuint fb_id; - glGenFramebuffers(1, &fb_id); - opaque_fb = fb_id; - - glBindFramebuffer(GL_FRAMEBUFFER, opaque_fb); - - opaqueColorTex = CreateScreenTexture(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); - opaqueDepthTex = CreateScreenTexture(GL_DEPTH_COMPONENT, - GL_DEPTH_COMPONENT, - GL_UNSIGNED_INT); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - opaqueColorTex, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, - opaqueDepthTex, 0); - } + opaqueColorTex = CreateScreenTexture(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); + opaqueDepthTex = CreateScreenTexture(GL_DEPTH_COMPONENT, + GL_DEPTH_COMPONENT, + GL_UNSIGNED_INT); + opaque_fb.Attach(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, opaqueColorTex); + opaque_fb.Attach(GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, opaqueDepthTex); for (int i = 0; i < 2; i++) { - { - GLuint fb_ids[2]; - glGenFramebuffers(2, fb_ids); - main_peel_fbs[i] = fb_ids[0]; - color_fbs[i] = fb_ids[1]; - } - depthTex[i] = CreateScreenTexture(GL_RG32F, GL_RG, GL_FLOAT); frontColorTex[i] = CreateScreenTexture(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); backColorTex[i] = CreateScreenTexture(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); - glBindFramebuffer(GL_FRAMEBUFFER, main_peel_fbs[i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - depthTex[i], 0); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, - frontColorTex[i], 0); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, - backColorTex[i], 0); + main_peel_fbs[i].Attach(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, depthTex[i]); + main_peel_fbs[i].Attach(GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, frontColorTex[i]); + main_peel_fbs[i].Attach(GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, backColorTex[i]); + main_peel_fbs[i].Attach(GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, opaqueDepthTex); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, - opaqueDepthTex, 0); - - glBindFramebuffer(GL_FRAMEBUFFER, color_fbs[i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - frontColorTex[i], 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, - backColorTex[i], 0); + color_fbs[i].Attach(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, frontColorTex[i]); + color_fbs[i].Attach(GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, backColorTex[i]); } - { - GLuint fb_id; - glGenFramebuffers(1, &fb_id); - blend_back_fb = fb_id; - } backBlendTex = CreateScreenTexture(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); - glBindFramebuffer(GL_FRAMEBUFFER, blend_back_fb); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - backBlendTex, 0); + blend_back_fb.Attach(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, backBlendTex); glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -167,24 +140,18 @@ void DepthPeeler::PreRender() CreateScreenPeelObjs(); // Clear back blend buffer { - GLenum blendBufs = GL_COLOR_ATTACHMENT0; - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, blend_back_fb); - glDrawBuffers(1, &blendBufs); + blend_back_fb.Bind(); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); } for (int i = 0; i < 2; i++) { // Initial depth texture should be set to [-MAX_DEPTH, MAX_DEPTH] - GLenum depthBufs = GL_COLOR_ATTACHMENT0; - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, main_peel_fbs[i]); - glDrawBuffers(1, &depthBufs); + main_peel_fbs[i].Bind(1); glClearColor(MAX_DEPTH, MAX_DEPTH, 0, 0); glClear(GL_COLOR_BUFFER_BIT); - GLenum colorBufs[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, color_fbs[i]); - glDrawBuffers(2, colorBufs); + color_fbs[i].Bind(); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); } @@ -210,12 +177,7 @@ void DepthPeeler::RenderOpaque(const RenderQueue& queue) // The opaque object depth data will be passed onto the peeling render // passes, so all we need to do now is to blit the color data to the output // framebuffer. - glBindFramebuffer(GL_READ_FRAMEBUFFER, opaque_fb); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *target); - glBlitFramebuffer(0, 0, tex_w, tex_h, - 0, 0, tex_w, tex_h, - GL_COLOR_BUFFER_BIT, - GL_LINEAR); + target->BlitFrom(opaque_fb, tex_w, tex_h, GL_LINEAR); } void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) @@ -224,22 +186,18 @@ void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) int dst_i = 1 - src_i; // Clear our target buffers for this pass { - GLenum depthBufs = GL_COLOR_ATTACHMENT0; - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, main_peel_fbs[dst_i]); - glDrawBuffers(1, &depthBufs); + main_peel_fbs[dst_i].Bind(1); glClearColor(-1., -1., 0, 0); glClear(GL_COLOR_BUFFER_BIT); - GLenum colorBufs[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, color_fbs[dst_i]); - glDrawBuffers(2, colorBufs); + color_fbs[dst_i].Bind(); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); } // Setup main peel program and framebuffer dynamic_cast(device)->bindExternalProgram(main_prgm); - main_prgm.setOutputFramebuffer(main_peel_fbs[dst_i]); + main_peel_fbs[dst_i].Bind(); // Bind source depth and front color texture glActiveTexture(GL_TEXTURE0 + 2); @@ -306,7 +264,7 @@ void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) // Blend just-written back layer separately blend_prgm.bind(); - blend_prgm.setOutputFramebuffer(blend_back_fb); + blend_back_fb.Bind(); glBlendEquation(GL_FUNC_ADD); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); @@ -327,7 +285,7 @@ void DepthPeeler::PostRender() int src_i = NUM_PASSES % 2; finalize_prgm.bind(); - finalize_prgm.setOutputFramebuffer(*target); + target->Bind(); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glActiveTexture(GL_TEXTURE0); diff --git a/lib/gl/depth_peel_oit.hpp b/lib/gl/depth_peel_oit.hpp index eb048070..3c3d2d4e 100644 --- a/lib/gl/depth_peel_oit.hpp +++ b/lib/gl/depth_peel_oit.hpp @@ -14,6 +14,7 @@ #include "renderer.hpp" #include "shader.hpp" +#include "framebuffer.hpp" namespace gl3 { @@ -58,10 +59,10 @@ class DepthPeeler : public IMainRenderPass TextureHandle backBlendTex; - FBOHandle main_peel_fbs[2]; - FBOHandle color_fbs[2]; - FBOHandle blend_back_fb; - FBOHandle opaque_fb; + Framebuffer main_peel_fbs[2]; + Framebuffer color_fbs[2]; + Framebuffer blend_back_fb; + Framebuffer opaque_fb; // Drawing full-screen rectangles BufObjHandle rect_buf; diff --git a/lib/gl/framebuffer.cpp b/lib/gl/framebuffer.cpp new file mode 100644 index 00000000..d7ce04e2 --- /dev/null +++ b/lib/gl/framebuffer.cpp @@ -0,0 +1,106 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-443271. +// +// This file is part of the GLVis visualization tool and library. For more +// information and source code availability see https://glvis.org. +// +// GLVis is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "framebuffer.hpp" +#include "renderer.hpp" +#include "shader.hpp" + +static const std::string BlitVertexShader = +#include "shaders/depth_peel_passthrough.vert" + ; + +static const std::string BlitFragShader = +#include "shaders/fb_blit.frag" + ; + +namespace gl3 +{ + +class ShaderBasedBlit +{ +public: + ShaderBasedBlit() + { + if (!passthrough_shader.create(BlitVertexShader, BlitFragShader, + {{ 0, "vertex" }}, 1)) + { + std::cerr << "Unable to create blit main program." << std::endl; + } + GLuint vbo; + glGenBuffers(1, &vbo); + quad_buffer = BufObjHandle{vbo}; + float quad_verts[] = + { + -1.f, 1.f, -1.f, -1.f, 1.f, -1.f, + -1.f, 1.f, 1.f, -1.f, 1.f, 1.f, + }; + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), quad_verts, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + ShaderProgram& GetPassthroughShader() { return passthrough_shader; } + BufObjHandle& GetQuadBuffer() { return quad_buffer; } +private: + ShaderProgram passthrough_shader; + BufObjHandle quad_buffer; +}; + +static ShaderBasedBlit& GetShaderBasedBlit() +{ + static ShaderBasedBlit blit; + return blit; +} + +void Framebuffer::BlitFrom(const Framebuffer &fb_from, int w, int h, + GLenum filter) const +{ + if (GLDevice::isOpenGL3()) + { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, handle); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_from); + glBlitFramebuffer(0, 0, w, h, + 0, 0, w, h, + GL_COLOR_BUFFER_BIT, filter); + } + else + { + if (!(filter == GL_NEAREST || filter == GL_LINEAR)) + { + std::cerr << "Blit error: no texture bound to color attachment 0 " + << "of source framebuffer" << std::endl; + return; + } + ShaderProgram& blit_shader = GetShaderBasedBlit().GetPassthroughShader(); + BufObjHandle& quad_buffer = GetShaderBasedBlit().GetQuadBuffer(); + + blit_shader.bind(); + Bind(); + GLuint texture_src = fb_from.color_attached_textures[0]; + if (texture_src == 0) + { + std::cerr << "Blit error: no texture bound to color attachment 0 " + << "of source framebuffer" << std::endl; + return; + } + glUniform1i(blit_shader.uniform("sourceColor"), 0); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture_src); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + + glBindBuffer(GL_ARRAY_BUFFER, quad_buffer); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0); + glDrawArrays(GL_TRIANGLES, 0, 6); + } +} + +} diff --git a/lib/gl/framebuffer.hpp b/lib/gl/framebuffer.hpp new file mode 100644 index 00000000..da941d3d --- /dev/null +++ b/lib/gl/framebuffer.hpp @@ -0,0 +1,167 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-443271. +// +// This file is part of the GLVis visualization tool and library. For more +// information and source code availability see https://glvis.org. +// +// GLVis is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#ifndef GLVIS_FRAMEBUFFER_HPP +#define GLVIS_FRAMEBUFFER_HPP + +#include "types.hpp" +#include + +namespace gl3 +{ + +class Framebuffer +{ +public: + Framebuffer() = default; + + operator bool() const + { + return handle; + } + + bool IsComplete() const + { + glBindFramebuffer(GL_FRAMEBUFFER, handle); + return glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE; + } + + void Init() + { + GLuint fb_id; + glGenFramebuffers(1, &fb_id); + handle = fb_id; + } + + void Detach(GLuint attach_point) + { + if (handle == 0) + { + std::cerr << "Can't attach textures from a default framebuffer." + << std::endl; + return; + } + if (attach_point >= GL_COLOR_ATTACHMENT0 && + attach_point < GL_COLOR_ATTACHMENT0 + NUM_ATTACHMENTS) + { + int attach_idx = attach_point - GL_COLOR_ATTACHMENT0; + color_attach_active[attach_idx] = false; + color_attached_textures[attach_idx] = 0; + } + } + + void Attach(GLuint attach_point, + GLuint texture_binding, + const resource::TextureHandle& tex_handle) + { + if (handle == 0) + { + std::cerr << "Can't attach textures to a default framebuffer." + << std::endl; + return; + } + if (attach_point >= GL_COLOR_ATTACHMENT0 && + attach_point < GL_COLOR_ATTACHMENT0 + NUM_ATTACHMENTS) + { + int attach_idx = attach_point - GL_COLOR_ATTACHMENT0; + color_attach_active[attach_idx] = true; + color_attached_textures[attach_idx] = tex_handle; + } + glBindFramebuffer(GL_FRAMEBUFFER, handle); + glFramebufferTexture2D(GL_FRAMEBUFFER, attach_point, + texture_binding, tex_handle, 0); + } + + + void Attach(GLuint attach_point, + const resource::RenderBufHandle& renderbuf_handle) + { + if (handle == 0) + { + std::cerr << "Can't attach renderbuffers to a default framebuffer." + << std::endl; + return; + } + if (attach_point >= GL_COLOR_ATTACHMENT0 && + attach_point < GL_COLOR_ATTACHMENT0 + NUM_ATTACHMENTS) + { + int attach_idx = attach_point - GL_COLOR_ATTACHMENT0; + color_attach_active[attach_idx] = true; + color_attached_textures[attach_idx] = 0; + } + glBindFramebuffer(GL_FRAMEBUFFER, handle); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, attach_point, + GL_RENDERBUFFER, renderbuf_handle); + } + + void Bind(int nbufs = 0) const + { + glBindFramebuffer(GL_FRAMEBUFFER, handle); + if (handle == 0) + { + if (nbufs > 1) + { + std::cerr << "Default framebuffer only has one valid output " + << "buffer." << std::endl; + } + glDrawBuffer(GL_BACK); + return; + } + // Set active color attachments in order + std::vector output_bufs; + for (int ibuf = 0; ibuf < NUM_ATTACHMENTS; ibuf++) + { + if (color_attach_active[ibuf]) + { + output_bufs.push_back(GL_COLOR_ATTACHMENT0 + ibuf); + } + } + if (nbufs == 0) + { + nbufs = output_bufs.size(); + } + while (output_bufs.size() < nbufs) + { + output_bufs.push_back(GL_NONE); + } + glDrawBuffers(nbufs, output_bufs.data()); + } + + void Bind(const std::vector& drawbufs) const + { + glBindFramebuffer(GL_FRAMEBUFFER, handle); + glDrawBuffers(drawbufs.size(), drawbufs.data()); + } + + // Unbinds the current framebuffer and binds the default framebuffer. + void Unbind() const + { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + GLenum drawOutput = GL_BACK; + glDrawBuffers(1, &drawOutput); + } + + // Blits an image located on GL_COLOR_ATTACHMENT0 of a source framebuffer + // to all the color attachments of this framebuffer. + void BlitFrom(const Framebuffer& fb_from, + int w, int h, + GLenum filter = GL_NEAREST) const; + +private: + resource::FBOHandle handle; + static constexpr int NUM_ATTACHMENTS=8; + bool color_attach_active[NUM_ATTACHMENTS] = {}; + GLuint color_attached_textures[NUM_ATTACHMENTS] = {}; +}; + +} + +#endif diff --git a/lib/gl/renderer.cpp b/lib/gl/renderer.cpp index 10c5a1dd..da019d29 100644 --- a/lib/gl/renderer.cpp +++ b/lib/gl/renderer.cpp @@ -42,17 +42,6 @@ bool GLDevice::isOpenGL3() #endif } -void GLDevice::attachFramebuffer(const FBOHandle& fbo) -{ - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); - GLenum drawOutput = GL_BACK; - if (fbo != 0) - { - drawOutput = GL_COLOR_ATTACHMENT0; - } - glDrawBuffers(1, &drawOutput); -} - void DefaultPass::Render(const RenderQueue& queue) { auto clear_color = device->getClearColor(); @@ -64,7 +53,7 @@ void DefaultPass::Render(const RenderQueue& queue) { return !renderPair.first.contains_translucent; }); - device->attachFramebuffer(*target); + target->Bind(1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); int color_tex = palette->GetColorTexture(); int alpha_tex = palette->GetAlphaTexture(); @@ -152,8 +141,8 @@ void MeshRenderer::render(const vector& main_passes, } // Step 2: Setup the framebuffer with the first extra pass, and render the // queue with the main passes. - FBOHandle default_target(0); - std::reference_wrapper curr_out = default_target; + Framebuffer default_target; + std::reference_wrapper curr_out = default_target; if (extra_passes.size() > 0) { extra_passes[0]->PreRender(); diff --git a/lib/gl/renderer.hpp b/lib/gl/renderer.hpp index fc0bb721..1d5f7a7d 100644 --- a/lib/gl/renderer.hpp +++ b/lib/gl/renderer.hpp @@ -19,6 +19,7 @@ #include "platform_gl.hpp" #include "types.hpp" +#include "framebuffer.hpp" #include "../material.hpp" #include "../palettes.hpp" @@ -106,8 +107,6 @@ class GLDevice glBindTexture(GL_TEXTURE_2D, tex_id); }; - void attachFramebuffer(const FBOHandle& fbo); - // If true, use unsized internal formats and GL_ALPHA for single-channel // data. Otherwise, use the newer sized internal formats and GL_RED. static bool isOpenGL3(); @@ -183,14 +182,14 @@ class IRenderPass virtual void PreRender() = 0; virtual void PostRender() = 0; - virtual const FBOHandle& GetSourceFramebuffer() const + virtual const Framebuffer& GetSourceFramebuffer() const { return default_target; } - virtual void SetTargetFramebuffer(const FBOHandle& fbo) { target = &fbo; } + virtual void SetTargetFramebuffer(const Framebuffer& fbo) { target = &fbo; } protected: GLDevice* device; - const FBOHandle* target = nullptr; - const FBOHandle default_target{0}; + const Framebuffer* target = nullptr; + const Framebuffer default_target; }; // Generic interface for an action on a queue of renderable objects. diff --git a/lib/gl/renderer_msaa.cpp b/lib/gl/renderer_msaa.cpp index 214ef5fb..bcd25169 100644 --- a/lib/gl/renderer_msaa.cpp +++ b/lib/gl/renderer_msaa.cpp @@ -41,9 +41,6 @@ void MultisamplePass::CreateFramebuffer() renderBufs[0] = RenderBufHandle(colorBuf); renderBufs[1] = RenderBufHandle(depthBuf); - GLuint fbo; - glGenFramebuffers(1, &fbo); - int vp[4]; device->getViewport(vp); int width = vp[2]; @@ -56,20 +53,14 @@ void MultisamplePass::CreateFramebuffer() GL_DEPTH_COMPONENT24, width, height); glBindRenderbuffer(GL_RENDERBUFFER, 0); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_RENDERBUFFER, colorBuf); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, depthBuf); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + msaaFb.Init(); + msaaFb.Attach(GL_COLOR_ATTACHMENT0, colorBuf); + msaaFb.Attach(GL_DEPTH_ATTACHMENT, depthBuf); + if (msaaFb.IsComplete()) { cerr << "Unable to create multisampled renderbuffer." << flush; - glDeleteFramebuffers(1, &fbo); - } - else - { - msaaFb = FBOHandle(fbo); + // Reset to default framebuffer + msaaFb = Framebuffer{}; } glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -81,7 +72,7 @@ void MultisamplePass::PreRender() if (feat_use_fbo_antialias) { CreateFramebuffer(); - glBindFramebuffer(GL_FRAMEBUFFER, msaaFb); + msaaFb.Bind(); } else { @@ -111,42 +102,20 @@ void MultisamplePass::PostRender() glGenRenderbuffers(1, &colorBufId); RenderBufHandle colorBuf(colorBufId); - GLuint fboId; - glGenFramebuffers(1, &fboId); - FBOHandle resolveFb(fboId); + Framebuffer resolveFb; + resolveFb.Init(); glBindRenderbuffer(GL_RENDERBUFFER, colorBuf); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height); glBindRenderbuffer(GL_RENDERBUFFER, 0); - glBindFramebuffer(GL_FRAMEBUFFER, resolveFb); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_RENDERBUFFER, colorBuf); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - { - cerr << "Unable to create resolve renderbuffer." << endl; - glBindFramebuffer(GL_FRAMEBUFFER, 0); - } - + resolveFb.Attach(GL_COLOR_ATTACHMENT0, colorBuf); // bind our draw framebuffer and blit the multisampled image - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFb); - glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFb); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glBlitFramebuffer(0, 0, width, height, - 0, 0, width, height, - GL_COLOR_BUFFER_BIT, - GL_NEAREST); + resolveFb.BlitFrom(msaaFb, width, height); #ifndef __EMSCRIPTEN__ glDisable(GL_MULTISAMPLE); #endif - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *target); - glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFb); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glBlitFramebuffer(0, 0, width, height, - 0, 0, width, height, - GL_COLOR_BUFFER_BIT, - GL_LINEAR); + target->BlitFrom(resolveFb, width, height, GL_LINEAR); } else if (msaa_enable && !feat_use_fbo_antialias) { diff --git a/lib/gl/renderer_msaa.hpp b/lib/gl/renderer_msaa.hpp index 23f5f207..7baef835 100644 --- a/lib/gl/renderer_msaa.hpp +++ b/lib/gl/renderer_msaa.hpp @@ -25,7 +25,7 @@ class MultisamplePass : public IRenderPass virtual void PreRender(); virtual void PostRender(); - virtual const FBOHandle& GetSourceFramebuffer() const + virtual const Framebuffer& GetSourceFramebuffer() const { if (msaa_enable && msaaFb) { @@ -67,7 +67,7 @@ class MultisamplePass : public IRenderPass float line_w, line_w_aa; RenderBufHandle renderBufs[2]; - FBOHandle msaaFb; + Framebuffer msaaFb; }; } diff --git a/lib/gl/shader.cpp b/lib/gl/shader.cpp index 797cc47f..2882047c 100644 --- a/lib/gl/shader.cpp +++ b/lib/gl/shader.cpp @@ -58,38 +58,6 @@ bool ShaderProgram::create(std::string vertexShader, return is_compiled; } -void ShaderProgram::setOutputFramebuffer(const FBOHandle& fbo) -{ - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); - if (num_outputs == 0) - { - std::cerr << "Warning: shader has no outputs." << std::endl; - return; - } - vector output_bufs(num_outputs); - for (int iout = 0; iout < num_outputs; iout++) - { - output_bufs[iout] = GL_COLOR_ATTACHMENT0 + iout; - } - glDrawBuffers(num_outputs, output_bufs.data()); -} - -void ShaderProgram::setDefaultDrawFramebuffer() -{ - if (num_outputs == 0) - { - std::cerr << "Warning: shader has no outputs." << std::endl; - } - if (num_outputs > 1) - { - std::cerr << "Warning: attempting to set a shader with more than one " - << "output on the default framebuffer."; - } - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - GLenum back_buf = GL_BACK; - glDrawBuffers(1, &back_buf); -} - int ShaderProgram::glsl_version = -1; bool ShaderProgram::glsl_es = false; diff --git a/lib/gl/shader.hpp b/lib/gl/shader.hpp index 3294a610..949b64fe 100644 --- a/lib/gl/shader.hpp +++ b/lib/gl/shader.hpp @@ -51,9 +51,6 @@ class ShaderProgram void bind() const { glUseProgram(program_id); } - void setOutputFramebuffer(const FBOHandle& fbo); - void setDefaultDrawFramebuffer(); - bool operator== (const ShaderProgram& other) const { return program_id == other.program_id; diff --git a/makefile b/makefile index 5f22def1..0ab31268 100644 --- a/makefile +++ b/makefile @@ -212,7 +212,7 @@ Ccc = $(strip $(CC) $(CFLAGS) $(GL_OPTS)) # generated with 'echo lib/gl/*.c* lib/*.c*', does not include lib/*.m (Obj-C) ALL_SOURCE_FILES = \ - lib/gl/renderer.cpp lib/gl/renderer_core.cpp lib/gl/renderer_ff.cpp \ + lib/gl/renderer.cpp lib/gl/renderer_core.cpp lib/gl/framebuffer.hpp lib/gl/renderer_ff.cpp \ lib/gl/depth_peel_oit.cpp lib/gl/renderer_msaa.cpp lib/gl/renderer_print.cpp \ lib/gl/shader.cpp lib/gl/types.cpp lib/aux_js.cpp lib/aux_vis.cpp lib/font.cpp \ lib/gl2ps.c lib/material.cpp lib/openglvis.cpp lib/palettes.cpp lib/sdl.cpp \ @@ -228,7 +228,7 @@ COMMON_SOURCE_FILES = $(filter-out \ # generated with 'echo lib/gl/*.h* lib/*.h*' HEADER_FILES = \ - lib/gl/attr_traits.hpp lib/gl/platform_gl.hpp lib/gl/renderer.hpp \ + lib/gl/attr_traits.hpp lib/gl/platform_gl.hpp lib/gl/framebuffer.hpp lib/gl/renderer.hpp \ lib/gl/shader.hpp lib/gl/renderer_core.hpp lib/gl/renderer_ff.hpp \ lib/gl/depth_peel_oit.hpp lib/gl/renderer_msaa.hpp lib/gl/renderer_print.hpp \ lib/gl/types.hpp lib/aux_vis.hpp lib/font.hpp lib/geom_utils.hpp lib/gl2ps.h \ From 8fe997bbf4e83d863a0e0ece2074d51cae885e3e Mon Sep 17 00:00:00 2001 From: Max Yang Date: Thu, 29 Apr 2021 12:06:46 -0700 Subject: [PATCH 18/29] Fix transform feedback varying setup --- lib/gl/renderer_core.cpp | 9 +-------- lib/gl/shader.cpp | 13 +++++++++++++ lib/gl/shader.hpp | 6 ++++++ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/gl/renderer_core.cpp b/lib/gl/renderer_core.cpp index 86bf06a0..5bc37522 100644 --- a/lib/gl/renderer_core.cpp +++ b/lib/gl/renderer_core.cpp @@ -110,14 +110,7 @@ bool CoreGLDevice::compileShaders() #ifndef __EMSCRIPTEN__ if (GLEW_EXT_transform_feedback || GLEW_VERSION_3_0) { - const char * xfrm_varyings[] = - { - "gl_Position", - "fColor", - "fClipCoord", - }; - glTransformFeedbackVaryings(feedback_prgm.getProgramId(), 3, xfrm_varyings, - GL_INTERLEAVED_ATTRIBS); + feedback_prgm.setFeedbackVaryings({"gl_Position", "fColor", "fClipCoord"}); if (!feedback_prgm.create(PRINTING_VS, PRINTING_FS, attribMap, 1)) { diff --git a/lib/gl/shader.cpp b/lib/gl/shader.cpp index 2882047c..08e04697 100644 --- a/lib/gl/shader.cpp +++ b/lib/gl/shader.cpp @@ -234,6 +234,19 @@ bool ShaderProgram::linkShaders(const std::vector& shaders) { std::cerr << "Failed to create an OpenGL program object." << std::endl; } + // Set transform feedback varyings, if any + if (!xfrm_varyings.empty()) + { + std::vector varyings_c_str; + for (const std::string& var : xfrm_varyings) + { + varyings_c_str.push_back(var.c_str()); + } + glTransformFeedbackVaryings(program_id, + xfrm_varyings.size(), + varyings_c_str.data(), + GL_INTERLEAVED_ATTRIBS); + } // Bind all incoming attributes to their VAO indices. for (auto attrib_pair : attrib_idx) { diff --git a/lib/gl/shader.hpp b/lib/gl/shader.hpp index 949b64fe..137ab063 100644 --- a/lib/gl/shader.hpp +++ b/lib/gl/shader.hpp @@ -32,6 +32,11 @@ class ShaderProgram bool isCompiled() const { return is_compiled; } + void setFeedbackVaryings(const std::vector& varyings) + { + xfrm_varyings = varyings; + } + int uniform(std::string uniformName) const { auto unifId = uniform_idx.find(uniformName); @@ -74,6 +79,7 @@ class ShaderProgram ShaderHandle fragment_shader = 0; bool is_compiled = false; std::unordered_map uniform_idx; + std::vector xfrm_varyings; }; } From 0db5ae8695f268fb172da3ee665e3ced96cbfd1e Mon Sep 17 00:00:00 2001 From: Max Yang Date: Thu, 29 Apr 2021 12:56:14 -0700 Subject: [PATCH 19/29] Add missing shader --- lib/gl/shaders/fb_blit.frag | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 lib/gl/shaders/fb_blit.frag diff --git a/lib/gl/shaders/fb_blit.frag b/lib/gl/shaders/fb_blit.frag new file mode 100644 index 00000000..97265309 --- /dev/null +++ b/lib/gl/shaders/fb_blit.frag @@ -0,0 +1,19 @@ +R"( +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-443271. +// +// This file is part of the GLVis visualization tool and library. For more +// information and source code availability see https://glvis.org. +// +// GLVis is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +uniform sampler2D sourceColor; + +void main() +{ + gl_FragColor = texture2D(sourceColor, gl_FragCoord.xy); +} +)" From 8ed9ed549928a2edd57505827f04cd6516675751 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Thu, 29 Apr 2021 13:14:28 -0700 Subject: [PATCH 20/29] Fix for framebuffer blit code --- lib/gl/framebuffer.cpp | 2 +- lib/gl/framebuffer.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gl/framebuffer.cpp b/lib/gl/framebuffer.cpp index d7ce04e2..4aa7c0d9 100644 --- a/lib/gl/framebuffer.cpp +++ b/lib/gl/framebuffer.cpp @@ -65,7 +65,7 @@ void Framebuffer::BlitFrom(const Framebuffer &fb_from, int w, int h, if (GLDevice::isOpenGL3()) { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, handle); - glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_from); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_from.handle); glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, filter); diff --git a/lib/gl/framebuffer.hpp b/lib/gl/framebuffer.hpp index da941d3d..97ffbdb6 100644 --- a/lib/gl/framebuffer.hpp +++ b/lib/gl/framebuffer.hpp @@ -23,7 +23,7 @@ class Framebuffer public: Framebuffer() = default; - operator bool() const + explicit operator bool() const { return handle; } From 26106b325d3ceecfab4a4603d69e00f6cf882d71 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Thu, 29 Apr 2021 13:38:40 -0700 Subject: [PATCH 21/29] Fix leak of some GL objects in assignment move --- lib/gl/types.hpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/gl/types.hpp b/lib/gl/types.hpp index 5db4de8f..32f74343 100644 --- a/lib/gl/types.hpp +++ b/lib/gl/types.hpp @@ -53,11 +53,7 @@ class Handle : hnd{other.hnd} { other.hnd = 0; } Handle& operator = (Handle&& other) noexcept { - if (this != &other) - { - hnd = other.hnd; - other.hnd = 0; - } + std::swap(hnd, other.hnd); return *this; } operator GLuint() const { return hnd; } From 824677591043aec2638e7da0240bef97381b781b Mon Sep 17 00:00:00 2001 From: Max Yang Date: Thu, 29 Apr 2021 17:01:08 -0700 Subject: [PATCH 22/29] Fix passing of renderbuffers in MultisamplePass --- lib/gl/renderer_msaa.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/gl/renderer_msaa.cpp b/lib/gl/renderer_msaa.cpp index bcd25169..2ade0d5a 100644 --- a/lib/gl/renderer_msaa.cpp +++ b/lib/gl/renderer_msaa.cpp @@ -54,9 +54,9 @@ void MultisamplePass::CreateFramebuffer() glBindRenderbuffer(GL_RENDERBUFFER, 0); msaaFb.Init(); - msaaFb.Attach(GL_COLOR_ATTACHMENT0, colorBuf); - msaaFb.Attach(GL_DEPTH_ATTACHMENT, depthBuf); - if (msaaFb.IsComplete()) + msaaFb.Attach(GL_COLOR_ATTACHMENT0, renderBufs[0]); + msaaFb.Attach(GL_DEPTH_ATTACHMENT, renderBufs[1]); + if (!msaaFb.IsComplete()) { cerr << "Unable to create multisampled renderbuffer." << flush; // Reset to default framebuffer From 74be0876246d503a12f554adf97405249ed3935b Mon Sep 17 00:00:00 2001 From: Max Yang Date: Thu, 29 Apr 2021 18:34:09 -0700 Subject: [PATCH 23/29] Use output depth texture for excluding clip plane fragments --- lib/gl/shaders/depth_peel.frag | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/gl/shaders/depth_peel.frag b/lib/gl/shaders/depth_peel.frag index 9c1844b5..56a7b5a6 100644 --- a/lib/gl/shaders/depth_peel.frag +++ b/lib/gl/shaders/depth_peel.frag @@ -23,14 +23,6 @@ varying vec2 fTexCoord; uniform bool useClipPlane; varying float fClipVal; -void fragmentClipPlane() -{ - if (useClipPlane && fClipVal < 0.0) - { - discard; - } -} - #define MAX_DEPTH 1.0 // location 0: depth @@ -43,8 +35,6 @@ void fragmentClipPlane() void main() { - fragmentClipPlane(); - ivec2 iFragCoord = ivec2(gl_FragCoord.xy); vec2 lastDepths = texelFetch(lastDepthTex, iFragCoord, 0).xy; vec4 lastFrontColor = texelFetch(lastFrontColorTex, iFragCoord, 0); @@ -62,6 +52,12 @@ void main() return; } + if (useClipPlane && fClipVal < 0.0) + { + gl_FragData[0].xy = vec2(-MAX_DEPTH); + return; + } + if (thisDepth > nearestDepth && thisDepth < farthestDepth) { gl_FragData[0].xy = vec2(-thisDepth, thisDepth); From aa41067201b804e4cc5e03cad091aae3eea28ab1 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Mon, 3 May 2021 12:01:42 -0700 Subject: [PATCH 24/29] Fix build warning --- lib/gl/framebuffer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gl/framebuffer.hpp b/lib/gl/framebuffer.hpp index 97ffbdb6..31a16aa5 100644 --- a/lib/gl/framebuffer.hpp +++ b/lib/gl/framebuffer.hpp @@ -102,7 +102,7 @@ class Framebuffer GL_RENDERBUFFER, renderbuf_handle); } - void Bind(int nbufs = 0) const + void Bind(unsigned int nbufs = 0) const { glBindFramebuffer(GL_FRAMEBUFFER, handle); if (handle == 0) From d1f6b43674273bf030705e7362b13869d086d515 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Mon, 3 May 2021 12:07:04 -0700 Subject: [PATCH 25/29] Fix makefile --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index 0ab31268..50261110 100644 --- a/makefile +++ b/makefile @@ -212,7 +212,7 @@ Ccc = $(strip $(CC) $(CFLAGS) $(GL_OPTS)) # generated with 'echo lib/gl/*.c* lib/*.c*', does not include lib/*.m (Obj-C) ALL_SOURCE_FILES = \ - lib/gl/renderer.cpp lib/gl/renderer_core.cpp lib/gl/framebuffer.hpp lib/gl/renderer_ff.cpp \ + lib/gl/renderer.cpp lib/gl/renderer_core.cpp lib/gl/framebuffer.cpp lib/gl/renderer_ff.cpp \ lib/gl/depth_peel_oit.cpp lib/gl/renderer_msaa.cpp lib/gl/renderer_print.cpp \ lib/gl/shader.cpp lib/gl/types.cpp lib/aux_js.cpp lib/aux_vis.cpp lib/font.cpp \ lib/gl2ps.c lib/material.cpp lib/openglvis.cpp lib/palettes.cpp lib/sdl.cpp \ From 1c58cd67f8c0c69a6fbdcad46f2579f097bfa661 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Mon, 3 May 2021 16:54:17 -0700 Subject: [PATCH 26/29] Fix depth peel finalization with multisampling enabled --- lib/gl/depth_peel_oit.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/gl/depth_peel_oit.cpp b/lib/gl/depth_peel_oit.cpp index 978b4d2b..586d2612 100644 --- a/lib/gl/depth_peel_oit.cpp +++ b/lib/gl/depth_peel_oit.cpp @@ -260,7 +260,6 @@ void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) device->setNumLights(0); device->drawDeviceBuffer(curr_drawable->getTextBuffer()); } - glDepthMask(GL_TRUE); // Blend just-written back layer separately blend_prgm.bind(); @@ -278,6 +277,7 @@ void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) glVertexAttribPointer(CoreGLDevice::ATTR_VERTEX, 2, GL_FLOAT, false, 0, 0); glDrawArrays(GL_TRIANGLES, 0, 6); + glDepthMask(GL_TRUE); } void DepthPeeler::PostRender() @@ -286,6 +286,7 @@ void DepthPeeler::PostRender() finalize_prgm.bind(); target->Bind(); + glClear(GL_DEPTH_BUFFER_BIT); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glActiveTexture(GL_TEXTURE0); From 5425e63a03e47a636a20631751614ffa491b7152 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Tue, 4 May 2021 18:32:26 -0700 Subject: [PATCH 27/29] Build fixes for shader code --- lib/gl/shader.cpp | 23 +++++++++++------------ lib/gl/shader.hpp | 2 +- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/gl/shader.cpp b/lib/gl/shader.cpp index 859ae6e2..daafa134 100644 --- a/lib/gl/shader.cpp +++ b/lib/gl/shader.cpp @@ -114,7 +114,6 @@ void ShaderProgram::GetGLSLVersion() { glsl_version = 300; } - glsl_es = true; #endif std::cerr << "Using GLSL " << glsl_version; if (glsl_is_es) { std::cerr << " ES"; } @@ -140,8 +139,6 @@ std::string ShaderProgram::formatShader(const std::string& inShader, formatted = std::regex_replace(formatted, std::regex("varying"), "in"); for (int i = 0; i < num_outputs; i++) { - std::string indexString = "gl_FragData["; - indexString += std::to_string(i) + "]"; std::string outputString = "out vec4 fragColor_"; outputString += std::to_string(i) + ";\n"; if (glsl_version >= 300) @@ -249,15 +246,17 @@ bool ShaderProgram::linkShaders(const std::vector& shaders) // Set transform feedback varyings, if any if (!xfrm_varyings.empty()) { - std::vector varyings_c_str; - for (const std::string& var : xfrm_varyings) - { - varyings_c_str.push_back(var.c_str()); - } - glTransformFeedbackVaryings(program_id, - xfrm_varyings.size(), - varyings_c_str.data(), - GL_INTERLEAVED_ATTRIBS); + std::vector varyings_c_str; + for (const std::string& var : xfrm_varyings) + { + varyings_c_str.push_back(var.c_str()); + } +#ifndef __EMSCRIPTEN__ + glTransformFeedbackVaryings(program_id, + xfrm_varyings.size(), + varyings_c_str.data(), + GL_INTERLEAVED_ATTRIBS); +#endif } // Bind all incoming attributes to their VAO indices. for (auto attrib_pair : attrib_idx) diff --git a/lib/gl/shader.hpp b/lib/gl/shader.hpp index 83ae47b7..1c35b4c0 100644 --- a/lib/gl/shader.hpp +++ b/lib/gl/shader.hpp @@ -34,7 +34,7 @@ class ShaderProgram void setFeedbackVaryings(const std::vector& varyings) { - xfrm_varyings = varyings; + xfrm_varyings = varyings; } int uniform(std::string uniformName) const From d52030b98f87108464dd9ca7ca1059a646e02767 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Tue, 4 May 2021 18:33:25 -0700 Subject: [PATCH 28/29] Changes needed to get WebGL depth peeling running --- lib/aux_js.cpp | 3 -- lib/aux_vis.cpp | 2 + lib/gl/depth_peel_oit.cpp | 55 ++++++++++++++++++----- lib/gl/shaders/depth_peel.frag | 16 +++++-- lib/gl/shaders/depth_peel_blend_back.frag | 15 ++++++- lib/gl/shaders/depth_peel_finalize.frag | 16 +++++-- 6 files changed, 86 insertions(+), 21 deletions(-) diff --git a/lib/aux_js.cpp b/lib/aux_js.cpp index e4b3b6e2..75cf9c4d 100644 --- a/lib/aux_js.cpp +++ b/lib/aux_js.cpp @@ -36,9 +36,6 @@ bool startVisualization(const std::string input, const std::string data_type, // 0 - scalar data, 1 - vector data, 2 - mesh only, (-1) - unknown const int field_type = stream_state.ReadStream(ss, data_type); - // reset antialiasing - GetAppWindow()->getRenderer().setAntialiasing(0); - std::string line; double minv = 0.0, maxv = 0.0; while (ss >> line) diff --git a/lib/aux_vis.cpp b/lib/aux_vis.cpp index 8901da4b..ba981fb1 100644 --- a/lib/aux_vis.cpp +++ b/lib/aux_vis.cpp @@ -94,6 +94,8 @@ int InitVisualization (const char name[], int x, int y, int w, int h) wnd->clearEvents(); } + multisample_status = false; + rndr_main_pass.SetGLDevice(wnd->getRenderer().getDevice()); rndr_msaa_pass.SetGLDevice(wnd->getRenderer().getDevice()); rndr_depth_peeled.SetGLDevice(wnd->getRenderer().getDevice()); diff --git a/lib/gl/depth_peel_oit.cpp b/lib/gl/depth_peel_oit.cpp index 586d2612..e7bfe325 100644 --- a/lib/gl/depth_peel_oit.cpp +++ b/lib/gl/depth_peel_oit.cpp @@ -106,18 +106,42 @@ void DepthPeeler::CreateScreenPeelObjs() screen_w = vp[2]; screen_h = vp[3]; - opaqueColorTex = CreateScreenTexture(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); - opaqueDepthTex = CreateScreenTexture(GL_DEPTH_COMPONENT, - GL_DEPTH_COMPONENT, - GL_UNSIGNED_INT); + if (GLDevice::isOpenGL3()) + { + backBlendTex = CreateScreenTexture(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); + opaqueColorTex = CreateScreenTexture(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); + opaqueDepthTex = CreateScreenTexture(GL_DEPTH_COMPONENT24, + GL_DEPTH_COMPONENT, + GL_UNSIGNED_INT); + } + else + { + backBlendTex = CreateScreenTexture(GL_RGBA, GL_RGBA, GL_FLOAT); + opaqueColorTex = CreateScreenTexture(GL_RGBA, GL_RGBA, GL_FLOAT); + opaqueDepthTex = CreateScreenTexture(GL_DEPTH_COMPONENT, + GL_DEPTH_COMPONENT, + GL_UNSIGNED_INT); + } + + blend_back_fb.Attach(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, backBlendTex); + opaque_fb.Attach(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, opaqueColorTex); opaque_fb.Attach(GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, opaqueDepthTex); for (int i = 0; i < 2; i++) { - depthTex[i] = CreateScreenTexture(GL_RG32F, GL_RG, GL_FLOAT); - frontColorTex[i] = CreateScreenTexture(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); - backColorTex[i] = CreateScreenTexture(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); + if (GLDevice::isOpenGL3()) + { + depthTex[i] = CreateScreenTexture(GL_RG32F, GL_RG, GL_FLOAT); + frontColorTex[i] = CreateScreenTexture(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); + backColorTex[i] = CreateScreenTexture(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); + } + else + { + depthTex[i] = CreateScreenTexture(GL_RGBA, GL_RGBA, GL_FLOAT); + frontColorTex[i] = CreateScreenTexture(GL_RGBA, GL_RGBA, GL_FLOAT); + backColorTex[i] = CreateScreenTexture(GL_RGBA, GL_RGBA, GL_FLOAT); + } main_peel_fbs[i].Attach(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, depthTex[i]); main_peel_fbs[i].Attach(GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, frontColorTex[i]); @@ -128,9 +152,6 @@ void DepthPeeler::CreateScreenPeelObjs() color_fbs[i].Attach(GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, backColorTex[i]); } - backBlendTex = CreateScreenTexture(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); - blend_back_fb.Attach(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, backBlendTex); - glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -198,6 +219,10 @@ void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) // Setup main peel program and framebuffer dynamic_cast(device)->bindExternalProgram(main_prgm); main_peel_fbs[dst_i].Bind(); + if (main_prgm.uniform("screenCoords") != -1) + { + glUniform2i(main_prgm.uniform("screenCoords"), screen_w, screen_h); + } // Bind source depth and front color texture glActiveTexture(GL_TEXTURE0 + 2); @@ -268,6 +293,11 @@ void DepthPeeler::DoRenderPass(int i, const RenderQueue& queue) glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + if (blend_prgm.uniform("screenCoords") != -1) + { + glUniform2i(blend_prgm.uniform("screenCoords"), screen_w, screen_h); + } + glActiveTexture(GL_TEXTURE0 + 2); glBindTexture(GL_TEXTURE_2D, backColorTex[dst_i]); glUniform1i(blend_prgm.uniform("lastBackColor"), 2); @@ -295,6 +325,11 @@ void DepthPeeler::PostRender() glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_2D, backBlendTex); + if (finalize_prgm.uniform("screenCoords") != -1) + { + glUniform2i(finalize_prgm.uniform("screenCoords"), screen_w, screen_h); + } + glUniform1i(finalize_prgm.uniform("lastFrontColor"), 0); glUniform1i(finalize_prgm.uniform("lastBackColor"), 1); diff --git a/lib/gl/shaders/depth_peel.frag b/lib/gl/shaders/depth_peel.frag index 56a7b5a6..d26a377e 100644 --- a/lib/gl/shaders/depth_peel.frag +++ b/lib/gl/shaders/depth_peel.frag @@ -23,6 +23,17 @@ varying vec2 fTexCoord; uniform bool useClipPlane; varying float fClipVal; +uniform ivec2 screenCoords; +vec4 getScreenTexel(sampler2D tex, vec2 coords) +{ +#if __VERSION__ < 140 + vec2 normalizedCoords = coords / vec2(screenCoords); + return texture2D(tex, normalizedCoords); +#else + return texelFetch(tex, ivec2(coords), 0); +#endif +} + #define MAX_DEPTH 1.0 // location 0: depth @@ -35,9 +46,8 @@ varying float fClipVal; void main() { - ivec2 iFragCoord = ivec2(gl_FragCoord.xy); - vec2 lastDepths = texelFetch(lastDepthTex, iFragCoord, 0).xy; - vec4 lastFrontColor = texelFetch(lastFrontColorTex, iFragCoord, 0); + vec2 lastDepths = getScreenTexel(lastDepthTex, gl_FragCoord.xy).xy; + vec4 lastFrontColor = getScreenTexel(lastFrontColorTex, gl_FragCoord.xy); float nearestDepth = -lastDepths.x; float farthestDepth = lastDepths.y; float thisDepth = gl_FragCoord.z; diff --git a/lib/gl/shaders/depth_peel_blend_back.frag b/lib/gl/shaders/depth_peel_blend_back.frag index 588fa1a3..00e53857 100644 --- a/lib/gl/shaders/depth_peel_blend_back.frag +++ b/lib/gl/shaders/depth_peel_blend_back.frag @@ -12,14 +12,25 @@ R"( uniform sampler2D lastBackColor; +uniform ivec2 screenCoords; +vec4 getScreenTexel(sampler2D tex, vec2 coords) +{ +#if __VERSION__ < 140 + vec2 normalizedCoords = coords / vec2(screenCoords); + return texture2D(tex, normalizedCoords); +#else + return texelFetch(tex, ivec2(coords), 0); +#endif +} + // adapted from "Order Independent Transparency with Dual Depth Peeling": // http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.193.3485&rep=rep1&type=pdf // and https://github.com/tsherif/webgl2examples/blob/master/oit-dual-depth-peeling.html void main() { - gl_FragColor = texelFetch(lastBackColor, ivec2(gl_FragCoord.xy), 0); - if (gl_FragColor.a == 0) + gl_FragColor = getScreenTexel(lastBackColor, gl_FragCoord.xy); + if (gl_FragColor.a == 0.0) { discard; } diff --git a/lib/gl/shaders/depth_peel_finalize.frag b/lib/gl/shaders/depth_peel_finalize.frag index c22e40db..bf20f5b5 100644 --- a/lib/gl/shaders/depth_peel_finalize.frag +++ b/lib/gl/shaders/depth_peel_finalize.frag @@ -13,15 +13,25 @@ R"( uniform sampler2D lastFrontColor; uniform sampler2D lastBackColor; +uniform ivec2 screenCoords; +vec4 getScreenTexel(sampler2D tex, vec2 coords) +{ +#if __VERSION__ < 140 + vec2 normalizedCoords = coords / vec2(screenCoords); + return texture2D(tex, normalizedCoords); +#else + return texelFetch(tex, ivec2(coords), 0); +#endif +} + // adapted from "Order Independent Transparency with Dual Depth Peeling": // http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.193.3485&rep=rep1&type=pdf // and https://github.com/tsherif/webgl2examples/blob/master/oit-dual-depth-peeling.html void main() { - ivec2 iQuadCoord = ivec2(gl_FragCoord.xy); - vec4 frontColor = texelFetch(lastFrontColor, iQuadCoord, 0); - vec4 backColor = texelFetch(lastBackColor, iQuadCoord, 0); + vec4 frontColor = getScreenTexel(lastFrontColor, gl_FragCoord.xy); + vec4 backColor = getScreenTexel(lastBackColor, gl_FragCoord.xy); float alphaMultiplier = 1.0 - frontColor.a; gl_FragColor.rgb = frontColor.rgb + alphaMultiplier * backColor.rgb; From eb5d2ba0672652400772c5633738a061cb033a96 Mon Sep 17 00:00:00 2001 From: Max Yang Date: Wed, 5 May 2021 13:48:41 -0700 Subject: [PATCH 29/29] Fix for shader-based blit method --- lib/gl/framebuffer.cpp | 1 + lib/gl/shaders/fb_blit.frag | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/gl/framebuffer.cpp b/lib/gl/framebuffer.cpp index 4aa7c0d9..c58aa728 100644 --- a/lib/gl/framebuffer.cpp +++ b/lib/gl/framebuffer.cpp @@ -90,6 +90,7 @@ void Framebuffer::BlitFrom(const Framebuffer &fb_from, int w, int h, << "of source framebuffer" << std::endl; return; } + glUniform2i(blit_shader.uniform("texDims"), w, h); glUniform1i(blit_shader.uniform("sourceColor"), 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture_src); diff --git a/lib/gl/shaders/fb_blit.frag b/lib/gl/shaders/fb_blit.frag index 97265309..310f1210 100644 --- a/lib/gl/shaders/fb_blit.frag +++ b/lib/gl/shaders/fb_blit.frag @@ -12,8 +12,10 @@ R"( uniform sampler2D sourceColor; +uniform ivec2 texDims; + void main() { - gl_FragColor = texture2D(sourceColor, gl_FragCoord.xy); + gl_FragColor = texture2D(sourceColor, gl_FragCoord.xy / vec2(texDims)); } )"