Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a1bdbea
Guard disk cache clearing with marker file
Jun 6, 2026
95a32f1
refactor a function
toloudis May 27, 2026
b560696
first iteration on graphics abstraction layer
toloudis Jun 3, 2026
5c332e3
keep cache dir fixed for duration of app. it is not user-selectable
toloudis Jun 3, 2026
f3ca5d1
reset unintentional cache changes
toloudis Jun 23, 2026
a868bc6
refactor, making the init code better
toloudis Jun 24, 2026
64b624c
move all context creation code into the gfxOpenGL backend
toloudis Jun 24, 2026
7de8aa5
update some deps for opengl
toloudis Jun 25, 2026
fe6215d
move glad into gfxOpenGL
toloudis Jun 25, 2026
1ac768c
move graphics/gl over
toloudis Jun 25, 2026
4714c91
move glsl shaders into gfxOpenGL
toloudis Jun 25, 2026
85b3936
move GestureGraphicsGL into gfxOpenGL and abstract it
toloudis Jun 25, 2026
7c03565
move framebuffer into opengl backend
toloudis Jun 25, 2026
33193ef
clean up some qt includes
toloudis Jun 25, 2026
670931c
move volume image wrapper to gfxopengl
toloudis Jun 25, 2026
2df0268
move renderers behind the opengl backend
toloudis Jun 25, 2026
d775e84
refactor framebuffer to behind the abstraction layer
toloudis Jun 25, 2026
7f5e259
clean up
toloudis Jun 25, 2026
d97736c
better abstraction for clearing framebuffer
toloudis Jun 25, 2026
8f2c44f
push qt surface format behind opengl abstraction layer
toloudis Jun 25, 2026
795a762
try cleaning up some of the context management logic
toloudis Jun 27, 2026
4bccfaa
factor context creation out so to remove the qt dependency
toloudis Jun 28, 2026
2c99331
renderlib takes a InitParams
toloudis Jun 28, 2026
c571807
refactoring for context creation
toloudis Jun 30, 2026
97d558a
move stb
toloudis Jun 30, 2026
5b3ae5b
renderdialog doesn't depend on QOpenGLContext, instead it depends on …
toloudis Jun 30, 2026
f4bd865
fix compile error
toloudis Jun 30, 2026
f6a00ba
fixup
toloudis Aug 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions agave_app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,11 @@ target_sources(agaveapp PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/mainwindow.h"
"${CMAKE_CURRENT_SOURCE_DIR}/ObjectTransformMode.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ObjectTransformMode.h"
"${CMAKE_CURRENT_SOURCE_DIR}/Projection.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Projection.h"
"${CMAKE_CURRENT_SOURCE_DIR}/QRenderSettings.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Projection.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Projection.h"
"${CMAKE_CURRENT_SOURCE_DIR}/QtGLContext.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/QtGLContext.h"
"${CMAKE_CURRENT_SOURCE_DIR}/QRenderSettings.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/QRenderSettings.h"
"${CMAKE_CURRENT_SOURCE_DIR}/RangeWidget.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/RangeWidget.h"
Expand Down Expand Up @@ -83,12 +85,15 @@ target_sources(agaveapp PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/TimelineDockWidget.h"
"${CMAKE_CURRENT_SOURCE_DIR}/ViewerState.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ViewerState.h"
"${CMAKE_CURRENT_SOURCE_DIR}/ViewToolbar.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ViewToolbar.h"
)
add_subdirectory(python)

add_subdirectory(tfeditor)
"${CMAKE_CURRENT_SOURCE_DIR}/ViewToolbar.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ViewToolbar.h"
)
option(AGAVE_ENABLE_PYRENDERER "Build the legacy unused Python offscreen renderer." OFF)
if(AGAVE_ENABLE_PYRENDERER)
add_subdirectory(python)
endif()

add_subdirectory(tfeditor)

if(MSVC)
target_sources(agaveapp PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/version.rc")
Expand Down
148 changes: 82 additions & 66 deletions agave_app/GLView3D.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,49 @@
#include "QRenderSettings.h"
#include "ViewerState.h"

#include "renderlib/AppScene.h"
#include "renderlib/ImageXYZC.h"
#include "renderlib/Logging.h"
#include "renderlib/MoveTool.h"
#include "renderlib/RotateTool.h"
#include "renderlib/graphics/RenderGL.h"
#include "renderlib/graphics/RenderGLPT.h"
#include "renderlib/graphics/gl/Image3D.h"
#include "renderlib/graphics/gl/Util.h"
#include "renderlib/MoveTool.h"
#include "renderlib/RotateTool.h"
#include "renderlib/Status.h"
#include "renderlib/gfxapi/Backend.h"
#include "renderlib/gfxapi/Framebuffer.h"
#include "renderlib/renderlib.h"

#include <glm.h>

#include <QApplication>
#include <QGuiApplication>
#include <QMouseEvent>
#include <QOpenGLFramebufferObject>
#include <QOpenGLFramebufferObjectFormat>
#include <QScreen>
#include <QTimer>
#include <QWindow>
#include <QApplication>
#include <QGuiApplication>
#include <QMouseEvent>
#include <QScreen>
#include <QTimer>
#include <QWindow>

#include <cmath>
#include <iostream>

// Only Microsoft issue warnings about correct behaviour...
#ifdef _MSVC_VER
#pragma warning(disable : 4351)
#endif
#ifdef _MSVC_VER
#pragma warning(disable : 4351)
#endif

namespace {

gfxApi::ClearColor
backgroundClearColor(const Scene* scene)
{
if (!scene) {
return {};
}

return { scene->m_material.m_backgroundColor[0],
scene->m_material.m_backgroundColor[1],
scene->m_material.m_backgroundColor[2],
1.0f };
}

} // namespace

GLView3D::GLView3D(QCamera* cam, QRenderSettings* qrs, RenderSettings* rs, QWidget* parent)
: QOpenGLWidget(parent)
Expand Down Expand Up @@ -126,12 +142,11 @@ GLView3D::onNewImage(Scene* scene)
rs->m_DirtyFlags.SetFlag(LightsDirty);
}

GLView3D::~GLView3D()
{
makeCurrent();
check_gl("view dtor makecurrent");
// doneCurrent();
}
GLView3D::~GLView3D()
{
makeCurrent();
// doneCurrent();
}

QSize
GLView3D::minimumSizeHint() const
Expand Down Expand Up @@ -177,13 +192,10 @@ GLView3D::resizeGL(int w, int h)
return;
}
// clock tick?
makeCurrent();
float dpr = devicePixelRatioF();
m_viewerWindow->setSize(w * dpr, h * dpr);
m_viewerWindow->forEachTool(
[this](ManipulationTool* tool) { tool->setSize(ManipulationTool::s_manipulatorSize * devicePixelRatioF()); });

doneCurrent();
}

static Gesture::Input::ButtonId
Expand Down Expand Up @@ -424,7 +436,6 @@ GLView3D::keyPressEvent(QKeyEvent* event)
void
GLView3D::OnUpdateCamera()
{
// QMutexLocker Locker(&gSceneMutex);
RenderSettings* rs = m_viewerWindow->m_renderSettings;
m_viewerWindow->m_CCamera.m_Film.m_Exposure = 1.0f - m_qcamera->GetFilm().GetExposure();
m_viewerWindow->m_CCamera.m_Film.m_ExposureIterations = m_qcamera->GetFilm().GetExposureIterations();
Expand Down Expand Up @@ -461,7 +472,6 @@ GLView3D::OnUpdateCamera()
void
GLView3D::OnUpdateQRenderSettings()
{
// QMutexLocker Locker(&gSceneMutex);
RenderSettings* rs = m_viewerWindow->m_renderSettings;

rs->m_RenderSettings.m_DensityScale = m_qrendersettings->GetDensityScale();
Expand Down Expand Up @@ -543,44 +553,50 @@ GLView3D::captureQimage()
return QImage();
}

makeCurrent();

// Create a one-time FBO to receive the image
QOpenGLFramebufferObjectFormat fboFormat;
fboFormat.setAttachment(QOpenGLFramebufferObject::NoAttachment);
fboFormat.setMipmap(false);
fboFormat.setSamples(0);
fboFormat.setTextureTarget(GL_TEXTURE_2D);

// NOTE NO ALPHA. if alpha then this will get premultiplied and wash out colors
// TODO : allow user option for transparent qimage, and then put GL_RGBA8 back here
fboFormat.setInternalTextureFormat(GL_RGB8);
check_gl("pre screen capture");

const float dpr = devicePixelRatioF();
QOpenGLFramebufferObject* fbo = new QOpenGLFramebufferObject(width() * dpr, height() * dpr, fboFormat);
check_gl("create fbo");

fbo->bind();
check_glfb("bind framebuffer for screen capture");

// do a render into the temp framebuffer
glViewport(0, 0, fbo->width(), fbo->height());

// fill gesture graphics with draw commands
m_viewerWindow->update(m_viewerWindow->sceneView.viewport, m_viewerWindow->m_clock, m_viewerWindow->gesture);
m_viewerWindow->m_renderer->render(m_viewerWindow->m_CCamera);
// render and then clear out draw commands from gesture graphics
m_viewerWindow->m_gestureRenderer->draw(
m_viewerWindow->sceneView, &m_viewerWindow->m_selection, m_viewerWindow->gesture.graphics);

fbo->release();

QImage img(fbo->toImage());
delete fbo;

return img;
}
makeCurrent();

const float dpr = devicePixelRatioF();
const uint32_t captureWidth = static_cast<uint32_t>(width() * dpr);
const uint32_t captureHeight = static_cast<uint32_t>(height() * dpr);

std::unique_ptr<gfxApi::Framebuffer> fbo = renderlib::graphicsBackend()->createFramebuffer(
{ captureWidth, captureHeight, gfxApi::FramebufferColorFormat::Rgba8, true });

uint32_t rendererWidth = 0;
uint32_t rendererHeight = 0;
m_viewerWindow->m_renderer->getSize(rendererWidth, rendererHeight);
if (rendererWidth != captureWidth || rendererHeight != captureHeight) {
m_viewerWindow->m_renderer->resize(captureWidth, captureHeight);
}

SceneView& sceneView = m_viewerWindow->sceneView;
sceneView.viewport.region = { { 0, 0 }, { static_cast<int>(captureWidth), static_cast<int>(captureHeight) } };
sceneView.camera = m_viewerWindow->m_CCamera;
sceneView.scene = m_viewerWindow->m_renderer->scene();
sceneView.renderSettings = m_viewerWindow->m_renderSettings;

m_viewerWindow->m_gestureRenderer->updateSelectionBuffer(captureWidth, captureHeight);
m_viewerWindow->update(sceneView.viewport, m_viewerWindow->m_clock, m_viewerWindow->gesture);

fbo->bind();
fbo->clear(backgroundClearColor(sceneView.scene));
m_viewerWindow->m_gestureRenderer->drawUnderlay(sceneView, m_viewerWindow->gesture.graphics);
fbo->release();

m_viewerWindow->m_renderer->renderTo(sceneView.camera, fbo.get());

fbo->bind();
m_viewerWindow->m_gestureRenderer->draw(sceneView, m_viewerWindow->gesture.graphics);
fbo->release();

std::unique_ptr<uint8_t> bytes(new uint8_t[captureWidth * captureHeight * 4]);
fbo->toImage(bytes.get());

return QImage(bytes.get(), captureWidth, captureHeight, QImage::Format_ARGB32)
.copy()
.mirrored()
.convertToFormat(QImage::Format_RGB32);
}

void
GLView3D::pauseRenderLoop()
Expand Down
11 changes: 4 additions & 7 deletions agave_app/GLView3D.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@

#include <memory>

#include "glad/glad.h"

#include "glm.h"
#include "renderlib/CCamera.h"
#include "renderlib/ViewerWindow.h"
#include "renderlib/gesture/gesture.h"
#include "glm.h"
#include "renderlib/CCamera.h"
#include "renderlib/ViewerWindow.h"
#include "renderlib/gesture/gesture.h"

#include <QOpenGLWidget>
#include <QTimer>

class CStatus;
class ImageXYZC;
class QCamera;
class IRenderWindow;
class QRenderSettings;
class Scene;
namespace Serialize {
Expand Down
123 changes: 123 additions & 0 deletions agave_app/QtGLContext.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#include "QtGLContext.h"

#include "renderlib/Logging.h"

#include <QOffscreenSurface>
#include <QOpenGLContext>
#include <QThread>

namespace {

constexpr int kGLVersionMajor = 4;
constexpr int kGLVersionMinor = 1;
constexpr int kDepthBufferBits = 24;
constexpr int kStencilBufferBits = 8;

} // namespace

QtGLContext::QtGLContext(QOpenGLContext* context)
: m_ownContext(context == nullptr)
, m_context(context)
{
}

QtGLContext::~QtGLContext()
{
destroy();
}

QSurfaceFormat
QtGLContext::defaultSurfaceFormat(bool enableDebug)
{
QSurfaceFormat format;
format.setDepthBufferSize(kDepthBufferBits);
format.setStencilBufferSize(kStencilBufferBits);
format.setVersion(kGLVersionMajor, kGLVersionMinor);
format.setProfile(QSurfaceFormat::CoreProfile);
if (enableDebug) {
format.setOption(QSurfaceFormat::DebugContext);
}
return format;
}

void
QtGLContext::setDefaultSurfaceFormat(bool enableDebug)
{
QSurfaceFormat::setDefaultFormat(defaultSurfaceFormat(enableDebug));
}

bool
QtGLContext::create()
{
if (!m_context) {
m_context = new QOpenGLContext();
m_context->setFormat(defaultSurfaceFormat());
if (!m_context->create()) {
LOG_ERROR << "QtGLContext: failed to create OpenGL context";
return false;
}
}

if (!m_context->isValid()) {
LOG_ERROR << "QtGLContext: OpenGL context is not valid";
return false;
}

if (!m_surface) {
m_surface = new QOffscreenSurface();
m_surface->setFormat(m_context->format());
m_surface->create();
}

if (!m_surface->isValid()) {
LOG_ERROR << "QtGLContext: offscreen surface is not valid";
return false;
}

return true;
}

bool
QtGLContext::isValid() const
{
return m_context && m_context->isValid() && m_surface && m_surface->isValid();
}

bool
QtGLContext::makeCurrent()
{
return isValid() && m_context->makeCurrent(m_surface);
}

void
QtGLContext::doneCurrent()
{
if (m_context) {
m_context->doneCurrent();
}
}

void
QtGLContext::moveToThread(QThread* thread)
{
if (m_context) {
m_context->moveToThread(thread);
}
if (m_surface) {
m_surface->moveToThread(thread);
}
}

void
QtGLContext::destroy()
{
doneCurrent();

delete m_surface;
m_surface = nullptr;

if (m_ownContext) {
delete m_context;
}
m_context = nullptr;
}
Loading
Loading