@@ -323,9 +323,146 @@ void OpenGL::setProjectionMatrix(const glm::mat4 &m)
323323 getFunctions ().setProjectionMatrix (m);
324324}
325325
326+ void OpenGL::setMultisamplingFbo (int requestedSamples, const QSize &size)
327+ {
328+ // Calculate physical size based on logical size and device pixel ratio
329+ const float dpr = getDevicePixelRatio ();
330+ const QSize physicalSize (size.width () * static_cast <int >(dpr),
331+ size.height () * static_cast <int >(dpr));
332+
333+ // Always manage the resolved FBO if size is not empty
334+ if (!physicalSize.isEmpty ()) {
335+ QOpenGLFramebufferObjectFormat resolvedFormat;
336+ resolvedFormat.setAttachment (QOpenGLFramebufferObject::CombinedDepthStencil);
337+ resolvedFormat.setSamples (0 ); // Not multisampled
338+ resolvedFormat.setTextureTarget (GL_TEXTURE_2D);
339+ resolvedFormat.setInternalTextureFormat (GL_RGBA8);
340+
341+ if (!m_resolvedFbo || m_resolvedFbo->size () != physicalSize) {
342+ m_resolvedFbo = std::make_unique<QOpenGLFramebufferObject>(physicalSize, resolvedFormat);
343+ if (!m_resolvedFbo->isValid ()) {
344+ MMLOG_ERROR () << " Failed to create resolved FBO with physical size "
345+ << physicalSize.width () << " x" << physicalSize.height ()
346+ << " . This may cause rendering issues." ;
347+ m_resolvedFbo.reset (); // Indicate failure
348+ } else {
349+ MMLOG_INFO () << " Created resolved FBO with physical size "
350+ << m_resolvedFbo->size ().width () << " x"
351+ << m_resolvedFbo->size ().height ();
352+ }
353+ }
354+ } else {
355+ m_resolvedFbo.reset ();
356+ MMLOG_INFO () << " Resolved FBO destroyed (size empty)" ;
357+ }
358+
359+ // Manage the multisampling FBO only if samples > 0 and size is not empty
360+ if (requestedSamples > 0 && !physicalSize.isEmpty ()) {
361+ auto &gl = getFunctions ();
362+ GLint maxSamples = 0 ;
363+ gl.glGetIntegerv (GL_MAX_SAMPLES, &maxSamples);
364+ int actualSamples = std::min (requestedSamples, static_cast <int >(maxSamples));
365+
366+ if (actualSamples == 0 && requestedSamples > 0 ) {
367+ MMLOG_WARNING () << " Requested " << requestedSamples
368+ << " samples, but max supported is 0. Disabling multisampling." ;
369+ } else if (actualSamples < requestedSamples) {
370+ MMLOG_INFO () << " Requested " << requestedSamples << " samples, but using "
371+ << actualSamples << " (max supported)." ;
372+ }
373+
374+ QOpenGLFramebufferObjectFormat msFormat;
375+ msFormat.setAttachment (QOpenGLFramebufferObject::CombinedDepthStencil);
376+ msFormat.setSamples (actualSamples);
377+ msFormat.setTextureTarget (GL_TEXTURE_2D_MULTISAMPLE);
378+ msFormat.setInternalTextureFormat (GL_RGBA8);
379+
380+ if (!m_multisamplingFbo || m_multisamplingFbo->size () != physicalSize
381+ || m_multisamplingFbo->format ().samples () != actualSamples) {
382+ m_multisamplingFbo = std::make_unique<QOpenGLFramebufferObject>(physicalSize, msFormat);
383+ if (!m_multisamplingFbo->isValid ()) {
384+ MMLOG_ERROR () << " Failed to create multisampling FBO with " << actualSamples
385+ << " samples and physical size " << physicalSize.width () << " x"
386+ << physicalSize.height () << " . Falling back to no multisampling." ;
387+ m_multisamplingFbo.reset (); // Fallback
388+ } else {
389+ MMLOG_INFO () << " Created multisampling FBO with "
390+ << m_multisamplingFbo->format ().samples ()
391+ << " samples and physical size " << m_multisamplingFbo->size ().width ()
392+ << " x" << m_multisamplingFbo->size ().height ();
393+ }
394+ }
395+ } else {
396+ m_multisamplingFbo.reset ();
397+ MMLOG_INFO () << " Multisampling FBO destroyed (samples <= 0 or size empty)" ;
398+ }
399+ }
400+
401+ QOpenGLFramebufferObject *OpenGL::getRenderFbo () const
402+ {
403+ // Render to the multisampling FBO if it's valid, otherwise render to the resolved FBO
404+ if (m_multisamplingFbo && m_multisamplingFbo->isValid ()) {
405+ return m_multisamplingFbo.get ();
406+ }
407+ // Fallback to resolved FBO (which should always be valid if size is not empty)
408+ return m_resolvedFbo.get ();
409+ }
410+
411+ void OpenGL::bindMultisamplingFbo ()
412+ {
413+ if (m_multisamplingFbo) {
414+ m_multisamplingFbo->bind ();
415+ }
416+ }
417+
418+ void OpenGL::releaseMultisamplingFbo ()
419+ {
420+ if (m_multisamplingFbo) {
421+ m_multisamplingFbo->release ();
422+ }
423+ }
424+
425+ void OpenGL::blitResolvedToDefault (const QSize & /* size*/ )
426+ {
427+ if (!m_resolvedFbo || !m_resolvedFbo->isValid ()) {
428+ MMLOG_WARNING () << " Resolved FBO not valid for blitting. Skipping blit sequence." ;
429+ return ;
430+ }
431+
432+ // If multisampling FBO is valid, blit from it to the resolved FBO first
433+ if (m_multisamplingFbo && m_multisamplingFbo->isValid ()) {
434+ QOpenGLFramebufferObject::blitFramebuffer (m_resolvedFbo.get (),
435+ m_multisamplingFbo.get (),
436+ GL_COLOR_BUFFER_BIT,
437+ GL_LINEAR); // Use GL_LINEAR for filtering during resolve
438+ }
439+ // Always blit from the resolved FBO to the default framebuffer (displays on screen)
440+ QOpenGLFramebufferObject::blitFramebuffer (
441+ nullptr , // Default framebuffer
442+ m_resolvedFbo.get (),
443+ GL_COLOR_BUFFER_BIT,
444+ GL_NEAREST); // GL_NEAREST is usually fine for 1:1 blit to screen
445+ }
446+
326447bool OpenGL::tryEnableMultisampling (const int requestedSamples)
327448{
328- return getFunctions ().tryEnableMultisampling (requestedSamples);
449+ // This function now primarily manages the GL_MULTISAMPLE state for the default framebuffer.
450+ // The FBO handles the actual multisampling rendering.
451+ auto &gl = getFunctions ();
452+ if (requestedSamples > 0 ) {
453+ gl.glEnable (GL_MULTISAMPLE);
454+ // The old smoothing hints might still be useful as a fallback or in conjunction,
455+ // but the primary multisampling is now via FBO. We can keep them for now.
456+ gl.glEnable (GL_LINE_SMOOTH);
457+ gl.glDisable (GL_POLYGON_SMOOTH);
458+ gl.glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
459+ return true ;
460+ } else {
461+ gl.glDisable (GL_MULTISAMPLE);
462+ gl.glDisable (GL_LINE_SMOOTH);
463+ gl.glDisable (GL_POLYGON_SMOOTH);
464+ return false ;
465+ }
329466}
330467
331468UniqueMesh OpenGL::createPointBatch (const std::vector<ColorVert> &batch)
0 commit comments