diff --git a/libs/ui/CMakeLists.txt b/libs/ui/CMakeLists.txt index 7519eeac96..30d7be8d73 100644 --- a/libs/ui/CMakeLists.txt +++ b/libs/ui/CMakeLists.txt @@ -1,579 +1,580 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/qtlockedfile ${EXIV2_INCLUDE_DIR} ) include_directories(SYSTEM ${EIGEN3_INCLUDE_DIR} ${OCIO_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ) add_subdirectory( tests ) if (APPLE) find_library(FOUNDATION_LIBRARY Foundation) find_library(APPKIT_LIBRARY AppKit) endif () set(kritaui_LIB_SRCS canvas/kis_canvas_widget_base.cpp canvas/kis_canvas2.cpp canvas/kis_canvas_updates_compressor.cpp canvas/kis_canvas_controller.cpp canvas/kis_paintop_transformation_connector.cpp canvas/kis_display_color_converter.cpp canvas/kis_display_filter.cpp canvas/kis_exposure_gamma_correction_interface.cpp canvas/kis_tool_proxy.cpp canvas/kis_canvas_decoration.cc canvas/kis_coordinates_converter.cpp canvas/kis_grid_manager.cpp canvas/kis_grid_decoration.cpp canvas/kis_grid_config.cpp canvas/kis_prescaled_projection.cpp canvas/kis_qpainter_canvas.cpp canvas/kis_projection_backend.cpp canvas/kis_update_info.cpp canvas/kis_image_patch.cpp canvas/kis_image_pyramid.cpp canvas/kis_infinity_manager.cpp canvas/kis_change_guides_command.cpp canvas/kis_guides_decoration.cpp canvas/kis_guides_manager.cpp canvas/kis_guides_config.cpp canvas/kis_snap_config.cpp canvas/kis_snap_line_strategy.cpp canvas/KisSnapPointStrategy.cpp dialogs/kis_about_application.cpp dialogs/kis_dlg_adj_layer_props.cc dialogs/kis_dlg_adjustment_layer.cc dialogs/kis_dlg_filter.cpp dialogs/kis_dlg_generator_layer.cpp dialogs/kis_dlg_file_layer.cpp dialogs/kis_dlg_filter.cpp dialogs/kis_dlg_stroke_selection_properties.cpp dialogs/kis_dlg_image_properties.cc dialogs/kis_dlg_layer_properties.cc dialogs/kis_dlg_preferences.cc dialogs/slider_and_spin_box_sync.cpp dialogs/kis_dlg_blacklist_cleanup.cpp dialogs/kis_dlg_layer_style.cpp dialogs/kis_dlg_png_import.cpp dialogs/kis_dlg_import_image_sequence.cpp dialogs/kis_delayed_save_dialog.cpp dialogs/kis_dlg_internal_color_selector.cpp flake/kis_node_dummies_graph.cpp flake/kis_dummies_facade_base.cpp flake/kis_dummies_facade.cpp flake/kis_node_shapes_graph.cpp flake/kis_node_shape.cpp flake/kis_shape_controller.cpp flake/kis_shape_layer.cc flake/kis_shape_layer_canvas.cpp flake/kis_shape_selection.cpp flake/kis_shape_selection_canvas.cpp flake/kis_shape_selection_model.cpp flake/kis_take_all_shapes_command.cpp brushhud/kis_uniform_paintop_property_widget.cpp brushhud/kis_brush_hud.cpp brushhud/kis_round_hud_button.cpp brushhud/kis_dlg_brush_hud_config.cpp brushhud/kis_brush_hud_properties_list.cpp brushhud/kis_brush_hud_properties_config.cpp kis_aspect_ratio_locker.cpp kis_autogradient.cc kis_bookmarked_configurations_editor.cc kis_bookmarked_configurations_model.cc kis_bookmarked_filter_configurations_model.cc kis_base_option.cpp kis_canvas_resource_provider.cpp kis_derived_resources.cpp kis_categories_mapper.cpp kis_categorized_list_model.cpp kis_categorized_item_delegate.cpp kis_clipboard.cc kis_config.cc kis_config_notifier.cpp kis_control_frame.cpp kis_composite_ops_model.cc kis_paint_ops_model.cpp kis_cursor.cc kis_cursor_cache.cpp kis_custom_pattern.cc kis_file_layer.cpp kis_change_file_layer_command.h kis_safe_document_loader.cpp kis_splash_screen.cpp kis_filter_manager.cc kis_filters_model.cc kis_histogram_view.cc KisImageBarrierLockerWithFeedback.cpp kis_image_manager.cc kis_image_view_converter.cpp kis_import_catcher.cc kis_layer_manager.cc kis_mask_manager.cc kis_mimedata.cpp kis_node_commands_adapter.cpp kis_node_manager.cpp kis_node_juggler_compressed.cpp kis_node_selection_adapter.cpp kis_node_insertion_adapter.cpp kis_node_model.cpp kis_node_filter_proxy_model.cpp kis_model_index_converter_base.cpp kis_model_index_converter.cpp kis_model_index_converter_show_all.cpp kis_painting_assistant.cc kis_painting_assistants_decoration.cpp kis_painting_assistants_manager.cpp kis_paintop_box.cc kis_paintop_option.cpp kis_paintop_options_model.cpp kis_paintop_settings_widget.cpp kis_popup_palette.cpp kis_png_converter.cpp kis_preference_set_registry.cpp kis_script_manager.cpp kis_resource_server_provider.cpp KisSelectedShapesProxy.cpp kis_selection_decoration.cc kis_selection_manager.cc kis_statusbar.cc kis_zoom_manager.cc kis_favorite_resource_manager.cpp kis_workspace_resource.cpp kis_action.cpp kis_action_manager.cpp kis_view_plugin.cpp kis_canvas_controls_manager.cpp kis_tooltip_manager.cpp kis_multinode_property.cpp kis_stopgradient_editor.cpp kisexiv2/kis_exif_io.cpp kisexiv2/kis_exiv2.cpp kisexiv2/kis_iptc_io.cpp kisexiv2/kis_xmp_io.cpp opengl/kis_opengl.cpp opengl/kis_opengl_canvas2.cpp opengl/kis_opengl_canvas_debugger.cpp opengl/kis_opengl_image_textures.cpp opengl/kis_texture_tile.cpp opengl/kis_opengl_shader_loader.cpp opengl/kis_texture_tile_info_pool.cpp kis_fps_decoration.cpp recorder/kis_node_query_path_editor.cc recorder/kis_recorded_action_creator.cc recorder/kis_recorded_action_creator_factory.cc recorder/kis_recorded_action_creator_factory_registry.cc recorder/kis_recorded_action_editor_factory.cc recorder/kis_recorded_action_editor_factory_registry.cc recorder/kis_recorded_filter_action_editor.cc recorder/kis_recorded_filter_action_creator.cpp recorder/kis_recorded_paint_action_editor.cc tool/kis_selection_tool_helper.cpp tool/kis_selection_tool_config_widget_helper.cpp tool/kis_rectangle_constraint_widget.cpp tool/kis_shape_tool_helper.cpp tool/kis_tool.cc tool/kis_delegated_tool_policies.cpp tool/kis_tool_freehand.cc tool/kis_speed_smoother.cpp tool/kis_painting_information_builder.cpp tool/kis_stabilized_events_sampler.cpp tool/kis_tool_freehand_helper.cpp tool/kis_tool_multihand_helper.cpp tool/kis_figure_painting_tool_helper.cpp tool/kis_recording_adapter.cpp tool/kis_tool_paint.cc tool/kis_tool_shape.cc tool/kis_tool_ellipse_base.cpp tool/kis_tool_rectangle_base.cpp tool/kis_tool_polyline_base.cpp tool/kis_tool_utils.cpp tool/kis_resources_snapshot.cpp tool/kis_smoothing_options.cpp tool/KisStabilizerDelayedPaintHelper.cpp tool/KisStrokeSpeedMonitor.cpp tool/strokes/freehand_stroke.cpp tool/strokes/KisStrokeEfficiencyMeasurer.cpp tool/strokes/kis_painter_based_stroke_strategy.cpp tool/strokes/kis_filter_stroke_strategy.cpp tool/strokes/kis_color_picker_stroke_strategy.cpp widgets/kis_cmb_composite.cc widgets/kis_cmb_contour.cpp widgets/kis_cmb_gradient.cpp widgets/kis_paintop_list_widget.cpp widgets/kis_cmb_idlist.cc widgets/kis_color_space_selector.cc widgets/kis_advanced_color_space_selector.cc widgets/kis_cie_tongue_widget.cpp widgets/kis_tone_curve_widget.cpp widgets/kis_curve_widget.cpp widgets/kis_custom_image_widget.cc widgets/kis_image_from_clipboard_widget.cpp widgets/kis_double_widget.cc widgets/kis_filter_selector_widget.cc widgets/kis_gradient_chooser.cc widgets/kis_gradient_slider_widget.cc widgets/kis_gradient_slider.cpp widgets/kis_iconwidget.cc widgets/kis_mask_widgets.cpp widgets/kis_meta_data_merge_strategy_chooser_widget.cc widgets/kis_multi_bool_filter_widget.cc widgets/kis_multi_double_filter_widget.cc widgets/kis_multi_integer_filter_widget.cc widgets/kis_multipliers_double_slider_spinbox.cpp widgets/kis_paintop_presets_popup.cpp widgets/kis_tool_options_popup.cpp widgets/kis_paintop_presets_chooser_popup.cpp widgets/kis_paintop_presets_save.cpp widgets/kis_paintop_preset_icon_library.cpp widgets/kis_pattern_chooser.cc widgets/kis_popup_button.cc widgets/kis_preset_chooser.cpp widgets/kis_progress_widget.cpp widgets/kis_selection_options.cc widgets/kis_scratch_pad.cpp widgets/kis_scratch_pad_event_filter.cpp widgets/kis_preset_selector_strip.cpp widgets/kis_slider_spin_box.cpp widgets/kis_size_group.cpp widgets/kis_size_group_p.cpp widgets/kis_wdg_generator.cpp widgets/kis_workspace_chooser.cpp widgets/squeezedcombobox.cpp widgets/kis_categorized_list_view.cpp widgets/kis_widget_chooser.cpp widgets/kis_tool_button.cpp widgets/kis_floating_message.cpp widgets/kis_lod_availability_widget.cpp widgets/kis_color_label_selector_widget.cpp widgets/kis_color_filter_combo.cpp widgets/kis_elided_label.cpp widgets/kis_stopgradient_slider_widget.cpp widgets/kis_spinbox_color_selector.cpp widgets/kis_screen_color_picker.cpp widgets/kis_preset_live_preview_view.cpp widgets/KoDualColorButton.cpp widgets/kis_color_input.cpp widgets/kis_color_button.cpp widgets/KisVisualColorSelector.cpp widgets/KisVisualColorSelectorShape.cpp widgets/KisVisualEllipticalSelectorShape.cpp widgets/KisVisualRectangleSelectorShape.cpp widgets/KisVisualTriangleSelectorShape.cpp widgets/KoStrokeConfigWidget.cpp widgets/KoFillConfigWidget.cpp widgets/KoShapeFillWrapper.cpp utils/kis_document_aware_spin_box_unit_manager.cpp input/kis_input_manager.cpp input/kis_input_manager_p.cpp input/kis_extended_modifiers_mapper.cpp input/kis_abstract_input_action.cpp input/kis_tool_invocation_action.cpp input/kis_pan_action.cpp input/kis_alternate_invocation_action.cpp input/kis_rotate_canvas_action.cpp input/kis_zoom_action.cpp input/kis_change_frame_action.cpp input/kis_gamma_exposure_action.cpp input/kis_show_palette_action.cpp input/kis_change_primary_setting_action.cpp input/kis_abstract_shortcut.cpp input/kis_native_gesture_shortcut.cpp input/kis_single_action_shortcut.cpp input/kis_stroke_shortcut.cpp input/kis_shortcut_matcher.cpp input/kis_select_layer_action.cpp input/KisQtWidgetsTweaker.cpp operations/kis_operation.cpp operations/kis_operation_configuration.cpp operations/kis_operation_registry.cpp operations/kis_operation_ui_factory.cpp operations/kis_operation_ui_widget.cpp operations/kis_filter_selection_operation.cpp actions/kis_selection_action_factories.cpp actions/KisPasteActionFactory.cpp input/kis_touch_shortcut.cpp kis_document_undo_store.cpp kis_transaction_based_command.cpp kis_gui_context_command.cpp kis_gui_context_command_p.cpp input/kis_tablet_debugger.cpp input/kis_input_profile_manager.cpp input/kis_input_profile.cpp input/kis_shortcut_configuration.cpp input/config/kis_input_configuration_page.cpp input/config/kis_edit_profiles_dialog.cpp input/config/kis_input_profile_model.cpp input/config/kis_input_configuration_page_item.cpp input/config/kis_action_shortcuts_model.cpp input/config/kis_input_type_delegate.cpp input/config/kis_input_mode_delegate.cpp input/config/kis_input_button.cpp input/config/kis_input_editor_delegate.cpp input/config/kis_mouse_input_editor.cpp input/config/kis_wheel_input_editor.cpp input/config/kis_key_input_editor.cpp processing/fill_processing_visitor.cpp kis_asl_layer_style_serializer.cpp kis_psd_layer_style_resource.cpp canvas/kis_mirror_axis.cpp kis_abstract_perspective_grid.cpp KisApplication.cpp KisAutoSaveRecoveryDialog.cpp KisDetailsPane.cpp KisDocument.cpp KisNodeDelegate.cpp kis_node_view_visibility_delegate.cpp KisNodeToolTip.cpp KisNodeView.cpp kis_node_view_color_scheme.cpp KisImportExportFilter.cpp KisFilterEntry.cpp KisImportExportManager.cpp KisImportExportUtils.cpp kis_async_action_feedback.cpp KisMainWindow.cpp KisOpenPane.cpp KisPart.cpp KisPrintJob.cpp KisTemplate.cpp KisTemplateCreateDia.cpp KisTemplateGroup.cpp KisTemplates.cpp KisTemplatesPane.cpp KisTemplateTree.cpp KisUndoStackAction.cpp KisView.cpp thememanager.cpp kis_mainwindow_observer.cpp KisViewManager.cpp kis_mirror_manager.cpp qtlockedfile/qtlockedfile.cpp qtsingleapplication/qtlocalpeer.cpp qtsingleapplication/qtsingleapplication.cpp KisResourceBundle.cpp KisResourceBundleManifest.cpp kis_md5_generator.cpp KisApplicationArguments.cpp KisNetworkAccessManager.cpp KisMultiFeedRSSModel.cpp KisRemoteFileFetcher.cpp KisPaletteModel.cpp kis_palette_delegate.cpp kis_palette_view.cpp KisColorsetChooser.cpp KisSaveGroupVisitor.cpp ) if(WIN32) if (NOT Qt5Gui_PRIVATE_INCLUDE_DIRS) message(FATAL_ERROR "Qt5Gui Private header are missing!") endif() set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} input/kis_tablet_event.cpp input/wintab/kis_tablet_support_win.cpp input/wintab/kis_screen_size_choice_dialog.cpp qtlockedfile/qtlockedfile_win.cpp input/wintab/kis_tablet_support_win8.cpp + opengl/kis_opengl_win.cpp ) include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS}) endif() set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} kis_animation_frame_cache.cpp kis_animation_cache_populator.cpp KisAsyncAnimationRendererBase.cpp KisAsyncAnimationCacheRenderer.cpp KisAsyncAnimationFramesSavingRenderer.cpp dialogs/KisAsyncAnimationRenderDialogBase.cpp dialogs/KisAsyncAnimationCacheRenderDialog.cpp dialogs/KisAsyncAnimationFramesSaveDialog.cpp canvas/kis_animation_player.cpp kis_animation_importer.cpp KisSyncedAudioPlayback.cpp ) if(UNIX) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} input/kis_tablet_event.cpp input/wintab/kis_tablet_support.cpp qtlockedfile/qtlockedfile_unix.cpp ) if(NOT APPLE) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} input/wintab/kis_tablet_support_x11.cpp input/wintab/qxcbconnection_xi2.cpp input/wintab/qxcbconnection.cpp input/wintab/kis_xi2_event_filter.cpp ) endif() endif() if(APPLE) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} osx.mm ) endif() ki18n_wrap_ui(kritaui_LIB_SRCS widgets/KoFillConfigWidget.ui widgets/KoStrokeConfigWidget.ui forms/wdgdlgpngimport.ui forms/wdgfullscreensettings.ui forms/wdgautogradient.ui forms/wdggeneralsettings.ui forms/wdgperformancesettings.ui forms/wdggenerators.ui forms/wdgbookmarkedconfigurationseditor.ui forms/wdgapplyprofile.ui forms/wdgcustompattern.ui forms/wdglayerproperties.ui forms/wdgcolorsettings.ui forms/wdgtabletsettings.ui forms/wdgcolorspaceselector.ui forms/wdgcolorspaceselectoradvanced.ui forms/wdgdisplaysettings.ui forms/kis_previewwidgetbase.ui forms/kis_matrix_widget.ui forms/wdgselectionoptions.ui forms/wdggeometryoptions.ui forms/wdgnewimage.ui forms/wdgimageproperties.ui forms/wdgmaskfromselection.ui forms/wdgmasksource.ui forms/wdgfilterdialog.ui forms/wdgmetadatamergestrategychooser.ui forms/wdgpaintoppresets.ui forms/wdgpaintopsettings.ui forms/wdgdlggeneratorlayer.ui forms/wdgdlgfilelayer.ui forms/wdgfilterselector.ui forms/wdgfilternodecreation.ui forms/wdgpaintactioneditor.ui forms/wdgmultipliersdoublesliderspinbox.ui forms/wdgnodequerypatheditor.ui forms/wdgpresetselectorstrip.ui forms/wdgsavebrushpreset.ui forms/wdgpreseticonlibrary.ui forms/wdgdlgblacklistcleanup.ui forms/wdgrectangleconstraints.ui forms/wdgimportimagesequence.ui forms/wdgstrokeselectionproperties.ui forms/KisDetailsPaneBase.ui forms/KisOpenPaneBase.ui forms/wdgstopgradienteditor.ui brushhud/kis_dlg_brush_hud_config.ui forms/wdgdlginternalcolorselector.ui dialogs/kis_delayed_save_dialog.ui input/config/kis_input_configuration_page.ui input/config/kis_edit_profiles_dialog.ui input/config/kis_input_configuration_page_item.ui input/config/kis_mouse_input_editor.ui input/config/kis_wheel_input_editor.ui input/config/kis_key_input_editor.ui layerstyles/wdgBevelAndEmboss.ui layerstyles/wdgblendingoptions.ui layerstyles/WdgColorOverlay.ui layerstyles/wdgContour.ui layerstyles/wdgdropshadow.ui layerstyles/WdgGradientOverlay.ui layerstyles/wdgInnerGlow.ui layerstyles/wdglayerstyles.ui layerstyles/WdgPatternOverlay.ui layerstyles/WdgSatin.ui layerstyles/WdgStroke.ui layerstyles/wdgstylesselector.ui layerstyles/wdgTexture.ui wdgsplash.ui input/wintab/kis_screen_size_choice_dialog.ui ) QT5_WRAP_CPP(kritaui_HEADERS_MOC KisNodePropertyAction_p.h) add_library(kritaui SHARED ${kritaui_HEADERS_MOC} ${kritaui_LIB_SRCS} ) generate_export_header(kritaui BASE_NAME kritaui) target_link_libraries(kritaui KF5::CoreAddons KF5::Completion KF5::I18n KF5::ItemViews Qt5::Network kritaimpex kritacolor kritaimage kritalibbrush kritawidgets kritawidgetutils ${PNG_LIBRARIES} ${EXIV2_LIBRARIES} ) if (HAVE_QT_MULTIMEDIA) target_link_libraries(kritaui Qt5::Multimedia) endif() if (HAVE_KIO) target_link_libraries(kritaui KF5::KIOCore) endif() if (NOT WIN32 AND NOT APPLE) target_link_libraries(kritaui ${X11_X11_LIB} ${X11_Xinput_LIB} ${XCB_LIBRARIES}) endif() if(APPLE) target_link_libraries(kritaui ${FOUNDATION_LIBRARY}) target_link_libraries(kritaui ${APPKIT_LIBRARY}) endif () target_link_libraries(kritaui ${OPENEXR_LIBRARIES}) # Add VSync disable workaround if(NOT WIN32 AND NOT APPLE) target_link_libraries(kritaui ${CMAKE_DL_LIBS} Qt5::X11Extras) endif() if(X11_FOUND) target_link_libraries(kritaui Qt5::X11Extras ${X11_LIBRARIES}) endif() target_include_directories(kritaui PUBLIC $ $ $ $ $ $ $ ) set_target_properties(kritaui PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} ) install(TARGETS kritaui ${INSTALL_TARGETS_DEFAULT_ARGS}) if (APPLE) install(FILES osx.stylesheet DESTINATION ${DATA_INSTALL_DIR}/krita) endif () diff --git a/libs/ui/opengl/kis_opengl.cpp b/libs/ui/opengl/kis_opengl.cpp index fca7401017..5539df2008 100644 --- a/libs/ui/opengl/kis_opengl.cpp +++ b/libs/ui/opengl/kis_opengl.cpp @@ -1,564 +1,289 @@ /* * Copyright (c) 2007 Adrian Page * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "opengl/kis_opengl.h" #include "opengl/kis_opengl_p.h" #include #include #include #include #include #include #include #include #include -#include -#include -#include #include -#include - #include #include -#include #include #ifndef GL_RENDERER # define GL_RENDERER 0x1F01 #endif using namespace KisOpenGLPrivate; namespace { bool defaultFormatIsSet = false; bool isDebugEnabled = false; bool isDebugSynchronous = false; boost::optional openGLCheckResult; bool NeedsFenceWorkaround = false; bool NeedsPixmapCacheWorkaround = false; QString debugText("OpenGL Info\n **OpenGL not initialized**"); void openglOnMessageLogged(const QOpenGLDebugMessage& debugMessage) { qDebug() << "OpenGL:" << debugMessage; } } -#ifdef Q_OS_WIN -namespace -{ - struct WindowsOpenGLStatus { - bool supportsDesktopGL = false; - bool supportsAngleD3D11 = false; - bool isQtPreferAngle = false; - bool overridePreferAngle = false; // override Qt to force ANGLE to be preferred - }; - WindowsOpenGLStatus windowsOpenGLStatus = {}; - KisOpenGL::OpenGLRenderer userRendererConfig; - KisOpenGL::OpenGLRenderer nextUserRendererConfig; - KisOpenGL::OpenGLRenderer currentRenderer; - - QStringList qpaDetectionLog; - - boost::optional checkQpaOpenGLStatus() { - QWindow surface; - surface.setSurfaceType(QSurface::OpenGLSurface); - surface.create(); - QOpenGLContext context; - if (!context.create()) { - qDebug() << "OpenGL context cannot be created"; - return boost::none; - } - if (!context.isValid()) { - qDebug() << "OpenGL context is not valid while checking Qt's OpenGL status"; - return boost::none; - } - if (!context.makeCurrent(&surface)) { - qDebug() << "OpenGL context cannot be made current"; - return boost::none; - } - return OpenGLCheckResult(context); - } - - bool checkIsSupportedDesktopGL(const OpenGLCheckResult &checkResult) { - if (checkResult.isUsingAngle()) { - qWarning() << "ANGLE was being used when desktop OpenGL was wanted, assuming no desktop OpenGL support"; - return false; - } - if (checkResult.isOpenGLES()) { - qWarning() << "Got OpenGL ES instead of desktop OpenGL, this shouldn't happen!"; - return false; - } - return checkResult.isSupportedVersion(); - } - - bool checkIsSupportedAngleD3D11(const OpenGLCheckResult &checkResult) { - if (!checkResult.isUsingAngle()) { - qWarning() << "Desktop OpenGL was being used when ANGLE was wanted, assuming no ANGLE support"; - return false; - } - if (!checkResult.isOpenGLES()) { - qWarning() << "Got desktop OpenGL instead of OpenGL ES, this shouldn't happen!"; - return false; - } - // HACK: Block ANGLE with Direct3D9 - // Direct3D9 does not give OpenGL ES 3.0 - // Some versions of ANGLE returns OpenGL version 3.0 incorrectly - if (checkResult.rendererString().contains("Direct3D9", Qt::CaseInsensitive)) { - qWarning() << "ANGLE tried to use Direct3D9, Krita won't work with it"; - return false; - } - return checkResult.isSupportedVersion(); - } - - void specialOpenGLVendorFilter(WindowsOpenGLStatus &status, const OpenGLCheckResult &checkResult) { - if (!status.supportsAngleD3D11) { - return; - } - // HACK: Make ANGLE the preferred renderer for Intel driver versions - // between build 4636 and 4729 (exclusive) due to an UI offset bug. - // See https://communities.intel.com/thread/116003 - // (Build 4636 is known to work from some test results) - if (checkResult.rendererString().startsWith("Intel")) { - QRegularExpression regex("\\b\\d{2}\\.\\d{2}\\.\\d{2}\\.(\\d{4})\\b"); - QRegularExpressionMatch match = regex.match(checkResult.driverVersionString()); - if (match.hasMatch()) { - int driverBuild = match.captured(1).toInt(); - if (driverBuild > 4636 && driverBuild < 4729) { - qDebug() << "Detected Intel driver build between 4636 and 4729, making ANGLE the preferred renderer"; - status.overridePreferAngle = true; - } - } - } - } - -} // namespace - -/** - * This function probes the Qt Platform Abstraction (QPA) for OpenGL diagnostics - * information. The code works under the assumption that the bundled Qt is built - * with `-opengl dynamic` and includes support for ANGLE. - * - * This function is written for Qt 5.9.1. On other versions it might not work - * as well. - */ -void KisOpenGL::probeWindowsQpaOpenGL(int argc, char **argv, QString userRendererConfigString) -{ - KIS_SAFE_ASSERT_RECOVER(defaultFormatIsSet) { - qWarning() << "Default OpenGL format was not set before calling KisOpenGL::probeWindowsQpaOpenGL. This might be a BUG!"; - setDefaultFormat(); - } - - // Clear env var to prevent affecting tests - qunsetenv("QT_OPENGL"); - - boost::optional qpaDetectionResult; - - qDebug() << "Probing Qt OpenGL detection:"; - { - KisLoggingManager::ScopedLogCapturer logCapturer( - "qt.qpa.gl", - [](QtMsgType type, const QMessageLogContext &context, const QString &msg) { - Q_UNUSED(type) - Q_UNUSED(context) - qpaDetectionLog.append(msg); - } - ); - { - QGuiApplication app(argc, argv); - qpaDetectionResult = checkQpaOpenGLStatus(); - } - } - if (!qpaDetectionResult) { - qWarning() << "Could not initialize OpenGL context!"; - return; - } - qDebug() << "Done probing Qt OpenGL detection"; - - windowsOpenGLStatus.isQtPreferAngle = qpaDetectionResult->isUsingAngle(); - - boost::optional checkResultAngle, checkResultDesktopGL; - if (qpaDetectionResult->isUsingAngle()) { - checkResultAngle = qpaDetectionResult; - // We already checked ANGLE, now check desktop OpenGL - qputenv("QT_OPENGL", "desktop"); - qDebug() << "Checking desktop OpenGL..."; - { - QGuiApplication app(argc, argv); - checkResultDesktopGL = checkQpaOpenGLStatus(); - } - if (!checkResultDesktopGL) { - qWarning() << "Could not initialize OpenGL context!"; - } - qDebug() << "Done checking desktop OpenGL"; - qunsetenv("QT_OPENGL"); - } else { - checkResultDesktopGL = qpaDetectionResult; - // We already checked desktop OpenGL, now check ANGLE - qputenv("QT_OPENGL", "angle"); - qDebug() << "Checking ANGLE..."; - { - QGuiApplication app(argc, argv); - checkResultAngle = checkQpaOpenGLStatus(); - } - if (!checkResultAngle) { - qWarning() << "Could not initialize OpenGL context!"; - } - qDebug() << "Done checking ANGLE"; - qunsetenv("QT_OPENGL"); - } - - windowsOpenGLStatus.supportsDesktopGL = - checkResultDesktopGL && checkIsSupportedDesktopGL(*checkResultDesktopGL); - windowsOpenGLStatus.supportsAngleD3D11 = - checkResultAngle && checkIsSupportedAngleD3D11(*checkResultAngle); - - // HACK: Filter specific buggy drivers not handled by Qt OpenGL buglist - if (checkResultDesktopGL) { - specialOpenGLVendorFilter(windowsOpenGLStatus, *checkResultDesktopGL); - } - - userRendererConfig = convertConfigToOpenGLRenderer(userRendererConfigString); - if ((userRendererConfig == RendererDesktopGL && !windowsOpenGLStatus.supportsDesktopGL) || - (userRendererConfig == RendererAngle && !windowsOpenGLStatus.supportsAngleD3D11)) { - // Set it to auto so we won't get stuck - userRendererConfig = RendererAuto; - } - nextUserRendererConfig = userRendererConfig; - switch (userRendererConfig) { - case RendererDesktopGL: - QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL, true); - currentRenderer = RendererDesktopGL; - break; - case RendererAngle: - QCoreApplication::setAttribute(Qt::AA_UseOpenGLES, true); - currentRenderer = RendererAngle; - break; - default: - if (windowsOpenGLStatus.isQtPreferAngle && windowsOpenGLStatus.supportsAngleD3D11) { - currentRenderer = RendererAngle; - } else if (windowsOpenGLStatus.overridePreferAngle && windowsOpenGLStatus.supportsAngleD3D11) { - QCoreApplication::setAttribute(Qt::AA_UseOpenGLES, true); - currentRenderer = RendererAngle; - } else if (!windowsOpenGLStatus.isQtPreferAngle && windowsOpenGLStatus.supportsDesktopGL) { - currentRenderer = RendererDesktopGL; - } else { - currentRenderer = RendererNone; - } - break; - } -} - -KisOpenGL::OpenGLRenderer KisOpenGL::getCurrentOpenGLRenderer() -{ - return currentRenderer; -} - -KisOpenGL::OpenGLRenderer KisOpenGL::getQtPreferredOpenGLRenderer() -{ - return (windowsOpenGLStatus.isQtPreferAngle || windowsOpenGLStatus.overridePreferAngle) - ? RendererAngle : RendererDesktopGL; -} - -KisOpenGL::OpenGLRenderers KisOpenGL::getSupportedOpenGLRenderers() -{ - return RendererAuto | - (windowsOpenGLStatus.supportsDesktopGL ? RendererDesktopGL : static_cast(0)) | - (windowsOpenGLStatus.supportsAngleD3D11 ? RendererAngle : static_cast(0)); -} - -KisOpenGL::OpenGLRenderer KisOpenGL::getUserOpenGLRendererConfig() -{ - return userRendererConfig; -} - -KisOpenGL::OpenGLRenderer KisOpenGL::getNextUserOpenGLRendererConfig() -{ - return nextUserRendererConfig; -} - -void KisOpenGL::setNextUserOpenGLRendererConfig(KisOpenGL::OpenGLRenderer renderer) -{ - nextUserRendererConfig = renderer; -} - -QString KisOpenGL::convertOpenGLRendererToConfig(KisOpenGL::OpenGLRenderer renderer) -{ - switch (renderer) { - case RendererDesktopGL: - return QStringLiteral("desktop"); - case RendererAngle: - return QStringLiteral("angle"); - default: - return QStringLiteral("auto"); - } -} - -KisOpenGL::OpenGLRenderer KisOpenGL::convertConfigToOpenGLRenderer(QString renderer) -{ - if (renderer == "desktop") { - return RendererDesktopGL; - } else if (renderer == "angle") { - return RendererAngle; - } else { - return RendererAuto; - } -} -#endif - KisOpenGLPrivate::OpenGLCheckResult::OpenGLCheckResult(QOpenGLContext &context) { if (!context.isValid()) { return; } QOpenGLFunctions *funcs = context.functions(); // funcs is ready to be used m_rendererString = QString(reinterpret_cast(funcs->glGetString(GL_RENDERER))); m_driverVersionString = QString(reinterpret_cast(funcs->glGetString(GL_VERSION))); m_glMajorVersion = context.format().majorVersion(); m_glMinorVersion = context.format().minorVersion(); m_supportsDeprecatedFunctions = (context.format().options() & QSurfaceFormat::DeprecatedFunctions); m_isOpenGLES = context.isOpenGLES(); } +bool KisOpenGLPrivate::isDefaultFormatSet() { + return defaultFormatIsSet; +} + void KisOpenGL::initialize() { if (openGLCheckResult) return; KIS_SAFE_ASSERT_RECOVER(defaultFormatIsSet) { qWarning() << "Default OpenGL format was not set before calling KisOpenGL::initialize. This might be a BUG!"; setDefaultFormat(); } // we need a QSurface active to get our GL functions from the context QWindow surface; surface.setSurfaceType( QSurface::OpenGLSurface ); surface.create(); QOpenGLContext context; if (!context.create()) { qDebug() << "OpenGL context cannot be created"; return; } if (!context.isValid()) { qDebug() << "OpenGL context is not valid"; return; } if (!context.makeCurrent(&surface)) { qDebug() << "OpenGL context cannot be made current"; return; } QOpenGLFunctions *funcs = context.functions(); openGLCheckResult = OpenGLCheckResult(context); debugText.clear(); QDebug debugOut(&debugText); debugOut << "OpenGL Info"; debugOut << "\n Vendor: " << reinterpret_cast(funcs->glGetString(GL_VENDOR)); debugOut << "\n Renderer: " << openGLCheckResult->rendererString(); debugOut << "\n Version: " << openGLCheckResult->driverVersionString(); debugOut << "\n Shading language: " << reinterpret_cast(funcs->glGetString(GL_SHADING_LANGUAGE_VERSION)); debugOut << "\n Requested format: " << QSurfaceFormat::defaultFormat(); debugOut << "\n Current format: " << context.format(); debugOut.nospace(); debugOut << "\n Version: " << openGLCheckResult->glMajorVersion() << "." << openGLCheckResult->glMinorVersion(); debugOut.resetFormat(); debugOut << "\n Supports deprecated functions" << openGLCheckResult->supportsDeprecatedFunctions(); debugOut << "\n is OpenGL ES:" << openGLCheckResult->isOpenGLES(); -#ifdef Q_OS_WIN - debugOut << "\n\nQPA OpenGL Detection Info"; - debugOut << "\n supportsDesktopGL:" << windowsOpenGLStatus.supportsDesktopGL; - debugOut << "\n supportsAngleD3D11:" << windowsOpenGLStatus.supportsAngleD3D11; - debugOut << "\n isQtPreferAngle:" << windowsOpenGLStatus.isQtPreferAngle; - debugOut << "\n overridePreferAngle:" << windowsOpenGLStatus.overridePreferAngle; - debugOut << "\n== log ==\n"; - debugOut.noquote(); - debugOut << qpaDetectionLog.join('\n'); - debugOut.resetFormat(); - debugOut << "\n== end log =="; -#endif + appendPlatformOpenGLDebugText(debugOut); qDebug().noquote() << debugText; } void KisOpenGL::initializeContext(QOpenGLContext *ctx) { KisConfig cfg; initialize(); dbgUI << "OpenGL: Opening new context"; if (isDebugEnabled) { // Passing ctx for ownership management only, not specifying context. // QOpenGLDebugLogger only function on the current active context. // FIXME: Do we need to make sure ctx is the active context? QOpenGLDebugLogger* openglLogger = new QOpenGLDebugLogger(ctx); if (openglLogger->initialize()) { qDebug() << "QOpenGLDebugLogger is initialized. Check whether you get a message below."; QObject::connect(openglLogger, &QOpenGLDebugLogger::messageLogged, &openglOnMessageLogged); openglLogger->startLogging(isDebugSynchronous ? QOpenGLDebugLogger::SynchronousLogging : QOpenGLDebugLogger::AsynchronousLogging); openglLogger->logMessage(QOpenGLDebugMessage::createApplicationMessage(QStringLiteral("QOpenGLDebugLogger is logging."))); } else { qDebug() << "QOpenGLDebugLogger cannot be initialized."; delete openglLogger; } } // Double check we were given the version we requested QSurfaceFormat format = ctx->format(); QOpenGLFunctions *f = ctx->functions(); f->initializeOpenGLFunctions(); QFile log(QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/krita-opengl.txt"); log.open(QFile::WriteOnly); QString vendor((const char*)f->glGetString(GL_VENDOR)); log.write(vendor.toLatin1()); log.write(", "); log.write(openGLCheckResult->rendererString().toLatin1()); log.write(", "); QString version((const char*)f->glGetString(GL_VERSION)); log.write(version.toLatin1()); log.close(); // Check if we have a bugged driver that needs fence workaround bool isOnX11 = false; #ifdef HAVE_X11 isOnX11 = true; #endif if ((isOnX11 && openGLCheckResult->rendererString().startsWith("AMD")) || cfg.forceOpenGLFenceWorkaround()) { NeedsFenceWorkaround = true; } /** * NVidia + Qt's openGL don't play well together and one cannot * draw a pixmap on a widget more than once in one rendering cycle. * * It can be workarounded by drawing strictly via QPixmapCache and * only when the pixmap size in bigger than doubled size of the * display framebuffer. That is for 8-bit HD display, you should have * a cache bigger than 16 MiB. Don't ask me why. (DK) * * See bug: https://bugs.kde.org/show_bug.cgi?id=361709 * * TODO: check if this workaround is still needed after merging * Qt5+openGL3 branch. */ if (vendor.toUpper().contains("NVIDIA")) { NeedsPixmapCacheWorkaround = true; const QRect screenSize = QApplication::desktop()->screenGeometry(); const int minCacheSize = 20 * 1024; const int cacheSize = 2048 + 2 * 4 * screenSize.width() * screenSize.height() / 1024; //KiB QPixmapCache::setCacheLimit(qMax(minCacheSize, cacheSize)); } } const QString &KisOpenGL::getDebugText() { initialize(); return debugText; } // XXX Temporary function to allow LoD on OpenGL3 without triggering // all of the other 3.2 functionality, can be removed once we move to Qt5.7 bool KisOpenGL::supportsLoD() { initialize(); return openGLCheckResult->supportsLoD(); } bool KisOpenGL::hasOpenGL3() { initialize(); return openGLCheckResult->hasOpenGL3(); } bool KisOpenGL::hasOpenGLES() { initialize(); return openGLCheckResult->isOpenGLES(); } bool KisOpenGL::supportsFenceSync() { initialize(); return openGLCheckResult->supportsFenceSync(); } bool KisOpenGL::needsFenceWorkaround() { initialize(); return NeedsFenceWorkaround; } bool KisOpenGL::needsPixmapCacheWorkaround() { initialize(); return NeedsPixmapCacheWorkaround; } void KisOpenGL::setDefaultFormat(bool enableDebug, bool debugSynchronous) { if (defaultFormatIsSet) { return; } defaultFormatIsSet = true; QSurfaceFormat format; #ifdef Q_OS_OSX format.setVersion(3, 2); format.setProfile(QSurfaceFormat::CoreProfile); #else // XXX This can be removed once we move to Qt5.7 format.setVersion(3, 0); format.setProfile(QSurfaceFormat::CompatibilityProfile); format.setOptions(QSurfaceFormat::DeprecatedFunctions); #endif format.setDepthBufferSize(24); format.setStencilBufferSize(8); format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); format.setSwapInterval(0); // Disable vertical refresh syncing isDebugEnabled = enableDebug; if (enableDebug) { format.setOption(QSurfaceFormat::DebugContext, true); isDebugSynchronous = debugSynchronous; qDebug() << "QOpenGLDebugLogger will be enabled, synchronous:" << debugSynchronous; } QSurfaceFormat::setDefaultFormat(format); } bool KisOpenGL::hasOpenGL() { return openGLCheckResult->isSupportedVersion(); } diff --git a/libs/ui/opengl/kis_opengl.h b/libs/ui/opengl/kis_opengl.h index 4d3e20d52f..e87c41fe21 100644 --- a/libs/ui/opengl/kis_opengl.h +++ b/libs/ui/opengl/kis_opengl.h @@ -1,116 +1,114 @@ /* * Copyright (c) 2007 Adrian Page * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_OPENGL_H_ #define KIS_OPENGL_H_ /** @file */ -#include - #include #include -class QOpenGLContext; -class QString; #include "kritaui_export.h" +class QOpenGLContext; +class QString; /** * This class manages a shared OpenGL context and provides utility * functions for checking capabilities and error reporting. */ class KRITAUI_EXPORT KisOpenGL { public: enum FilterMode { NearestFilterMode, // nearest BilinearFilterMode, // linear, no mipmap TrilinearFilterMode, // LINEAR_MIPMAP_LINEAR HighQualityFiltering // Mipmaps + custom shader }; public: #ifdef Q_OS_WIN enum OpenGLRenderer { RendererNone = 0x00, RendererAuto = 0x01, RendererDesktopGL = 0x02, RendererAngle = 0x04, }; Q_DECLARE_FLAGS(OpenGLRenderers, OpenGLRenderer); // Probe the Windows platform abstraction layer for OpenGL detection static void probeWindowsQpaOpenGL(int argc, char **argv, QString userRendererConfigString); static OpenGLRenderer getCurrentOpenGLRenderer(); static OpenGLRenderer getQtPreferredOpenGLRenderer(); static OpenGLRenderers getSupportedOpenGLRenderers(); static OpenGLRenderer getUserOpenGLRendererConfig(); static OpenGLRenderer getNextUserOpenGLRendererConfig(); static void setNextUserOpenGLRendererConfig(OpenGLRenderer renderer); static QString convertOpenGLRendererToConfig(OpenGLRenderer renderer); static OpenGLRenderer convertConfigToOpenGLRenderer(QString renderer); #endif /// Request OpenGL version 3.2 static void initialize(); /// Initialize shared OpenGL context static void initializeContext(QOpenGLContext *ctx); static const QString &getDebugText(); static bool supportsLoD(); static bool hasOpenGL3(); static bool hasOpenGLES(); /// Check for OpenGL static bool hasOpenGL(); /** * @brief supportsFilter * @return True if OpenGL provides fence sync methods. */ static bool supportsFenceSync(); /** * Returns true if we have a driver that has bugged support to sync objects (a fence) * and false otherwise. */ static bool needsFenceWorkaround(); /** * @see a comment in initializeContext() */ static bool needsPixmapCacheWorkaround(); static void setDefaultFormat(bool enableDebug = false, bool debugSynchronous = false); private: KisOpenGL(); }; #ifdef Q_OS_WIN Q_DECLARE_OPERATORS_FOR_FLAGS(KisOpenGL::OpenGLRenderers); #endif #endif // KIS_OPENGL_H_ diff --git a/libs/ui/opengl/kis_opengl_p.h b/libs/ui/opengl/kis_opengl_p.h index 1cbe82d6ef..2fd47b6601 100644 --- a/libs/ui/opengl/kis_opengl_p.h +++ b/libs/ui/opengl/kis_opengl_p.h @@ -1,98 +1,106 @@ /* * Copyright (c) 2017 Alvin Wong * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_OPENGL_P_H_ #define KIS_OPENGL_P_H_ #include #include +class QDebug; class QOpenGLContext; namespace KisOpenGLPrivate { class OpenGLCheckResult { int m_glMajorVersion = 0; int m_glMinorVersion = 0; bool m_supportsDeprecatedFunctions = false; bool m_isOpenGLES = false; QString m_rendererString; QString m_driverVersionString; public: OpenGLCheckResult(QOpenGLContext &context); int glMajorVersion() const { return m_glMajorVersion; } int glMinorVersion() const { return m_glMinorVersion; } bool supportsDeprecatedFunctions() const { return m_supportsDeprecatedFunctions; } bool isOpenGLES() const { return m_isOpenGLES; } QString rendererString() const { return m_rendererString; } QString driverVersionString() const { return m_driverVersionString; } bool isSupportedVersion() const { return #ifdef Q_OS_OSX ((m_glMajorVersion * 100 + m_glMinorVersion) >= 302) #else (m_glMajorVersion >= 3 && (m_supportsDeprecatedFunctions || m_isOpenGLES)) || ((m_glMajorVersion * 100 + m_glMinorVersion) == 201) #endif ; } bool supportsLoD() const { return (m_glMajorVersion * 100 + m_glMinorVersion) >= 300; } bool hasOpenGL3() const { return (m_glMajorVersion * 100 + m_glMinorVersion) >= 302; } bool supportsFenceSync() const { return m_glMajorVersion >= 3; } #ifdef Q_OS_WIN // This is only for detecting whether ANGLE is being used. // For detecting generic OpenGL ES please check isOpenGLES bool isUsingAngle() const { return m_rendererString.startsWith("ANGLE", Qt::CaseInsensitive); } #endif }; +void appendPlatformOpenGLDebugText(QDebug &debugOut); +#ifndef Q_OS_WIN +void appendPlatformOpenGLDebugText(QDebug &debugOut) {} +#endif + +bool isDefaultFormatSet(); + } // namespace KisOpenGLPrivate #endif // KIS_OPENGL_P_H_ diff --git a/libs/ui/opengl/kis_opengl_win.cpp b/libs/ui/opengl/kis_opengl_win.cpp new file mode 100644 index 0000000000..2843f9c225 --- /dev/null +++ b/libs/ui/opengl/kis_opengl_win.cpp @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2017 Alvin Wong + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "opengl/kis_opengl.h" +#include "opengl/kis_opengl_p.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +using namespace KisOpenGLPrivate; + +namespace +{ + +struct WindowsOpenGLStatus { + bool supportsDesktopGL = false; + bool supportsAngleD3D11 = false; + bool isQtPreferAngle = false; + bool overridePreferAngle = false; // override Qt to force ANGLE to be preferred +}; +WindowsOpenGLStatus windowsOpenGLStatus = {}; +KisOpenGL::OpenGLRenderer userRendererConfig; +KisOpenGL::OpenGLRenderer nextUserRendererConfig; +KisOpenGL::OpenGLRenderer currentRenderer; + +QStringList qpaDetectionLog; + +boost::optional checkQpaOpenGLStatus() { + QWindow surface; + surface.setSurfaceType(QSurface::OpenGLSurface); + surface.create(); + QOpenGLContext context; + if (!context.create()) { + qDebug() << "OpenGL context cannot be created"; + return boost::none; + } + if (!context.isValid()) { + qDebug() << "OpenGL context is not valid while checking Qt's OpenGL status"; + return boost::none; + } + if (!context.makeCurrent(&surface)) { + qDebug() << "OpenGL context cannot be made current"; + return boost::none; + } + return OpenGLCheckResult(context); +} + +bool checkIsSupportedDesktopGL(const OpenGLCheckResult &checkResult) { + if (checkResult.isUsingAngle()) { + qWarning() << "ANGLE was being used when desktop OpenGL was wanted, assuming no desktop OpenGL support"; + return false; + } + if (checkResult.isOpenGLES()) { + qWarning() << "Got OpenGL ES instead of desktop OpenGL, this shouldn't happen!"; + return false; + } + return checkResult.isSupportedVersion(); +} + +bool checkIsSupportedAngleD3D11(const OpenGLCheckResult &checkResult) { + if (!checkResult.isUsingAngle()) { + qWarning() << "Desktop OpenGL was being used when ANGLE was wanted, assuming no ANGLE support"; + return false; + } + if (!checkResult.isOpenGLES()) { + qWarning() << "Got desktop OpenGL instead of OpenGL ES, this shouldn't happen!"; + return false; + } + // HACK: Block ANGLE with Direct3D9 + // Direct3D9 does not give OpenGL ES 3.0 + // Some versions of ANGLE returns OpenGL version 3.0 incorrectly + if (checkResult.rendererString().contains("Direct3D9", Qt::CaseInsensitive)) { + qWarning() << "ANGLE tried to use Direct3D9, Krita won't work with it"; + return false; + } + return checkResult.isSupportedVersion(); +} + +void specialOpenGLVendorFilter(WindowsOpenGLStatus &status, const OpenGLCheckResult &checkResult) { + if (!status.supportsAngleD3D11) { + return; + } + // HACK: Make ANGLE the preferred renderer for Intel driver versions + // between build 4636 and 4729 (exclusive) due to an UI offset bug. + // See https://communities.intel.com/thread/116003 + // (Build 4636 is known to work from some test results) + if (checkResult.rendererString().startsWith("Intel")) { + QRegularExpression regex("\\b\\d{2}\\.\\d{2}\\.\\d{2}\\.(\\d{4})\\b"); + QRegularExpressionMatch match = regex.match(checkResult.driverVersionString()); + if (match.hasMatch()) { + int driverBuild = match.captured(1).toInt(); + if (driverBuild > 4636 && driverBuild < 4729) { + qDebug() << "Detected Intel driver build between 4636 and 4729, making ANGLE the preferred renderer"; + status.overridePreferAngle = true; + } + } + } +} + +} // namespace + +void KisOpenGLPrivate::appendPlatformOpenGLDebugText(QDebug &debugOut) { + debugOut << "\n\nQPA OpenGL Detection Info"; + debugOut << "\n supportsDesktopGL:" << windowsOpenGLStatus.supportsDesktopGL; + debugOut << "\n supportsAngleD3D11:" << windowsOpenGLStatus.supportsAngleD3D11; + debugOut << "\n isQtPreferAngle:" << windowsOpenGLStatus.isQtPreferAngle; + debugOut << "\n overridePreferAngle:" << windowsOpenGLStatus.overridePreferAngle; + debugOut << "\n== log ==\n"; + debugOut.noquote(); + debugOut << qpaDetectionLog.join('\n'); + debugOut.resetFormat(); + debugOut << "\n== end log =="; +} + +/** + * This function probes the Qt Platform Abstraction (QPA) for OpenGL diagnostics + * information. The code works under the assumption that the bundled Qt is built + * with `-opengl dynamic` and includes support for ANGLE. + * + * This function is written for Qt 5.9.1. On other versions it might not work + * as well. + */ +void KisOpenGL::probeWindowsQpaOpenGL(int argc, char **argv, QString userRendererConfigString) +{ + KIS_SAFE_ASSERT_RECOVER(isDefaultFormatSet()) { + qWarning() << "Default OpenGL format was not set before calling KisOpenGL::probeWindowsQpaOpenGL. This might be a BUG!"; + setDefaultFormat(); + } + + // Clear env var to prevent affecting tests + qunsetenv("QT_OPENGL"); + + boost::optional qpaDetectionResult; + + qDebug() << "Probing Qt OpenGL detection:"; + { + KisLoggingManager::ScopedLogCapturer logCapturer( + "qt.qpa.gl", + [](QtMsgType type, const QMessageLogContext &context, const QString &msg) { + Q_UNUSED(type) + Q_UNUSED(context) + qpaDetectionLog.append(msg); + } + ); + { + QGuiApplication app(argc, argv); + qpaDetectionResult = checkQpaOpenGLStatus(); + } + } + if (!qpaDetectionResult) { + qWarning() << "Could not initialize OpenGL context!"; + return; + } + qDebug() << "Done probing Qt OpenGL detection"; + + windowsOpenGLStatus.isQtPreferAngle = qpaDetectionResult->isUsingAngle(); + + boost::optional checkResultAngle, checkResultDesktopGL; + if (qpaDetectionResult->isUsingAngle()) { + checkResultAngle = qpaDetectionResult; + // We already checked ANGLE, now check desktop OpenGL + qputenv("QT_OPENGL", "desktop"); + qDebug() << "Checking desktop OpenGL..."; + { + QGuiApplication app(argc, argv); + checkResultDesktopGL = checkQpaOpenGLStatus(); + } + if (!checkResultDesktopGL) { + qWarning() << "Could not initialize OpenGL context!"; + } + qDebug() << "Done checking desktop OpenGL"; + qunsetenv("QT_OPENGL"); + } else { + checkResultDesktopGL = qpaDetectionResult; + // We already checked desktop OpenGL, now check ANGLE + qputenv("QT_OPENGL", "angle"); + qDebug() << "Checking ANGLE..."; + { + QGuiApplication app(argc, argv); + checkResultAngle = checkQpaOpenGLStatus(); + } + if (!checkResultAngle) { + qWarning() << "Could not initialize OpenGL context!"; + } + qDebug() << "Done checking ANGLE"; + qunsetenv("QT_OPENGL"); + } + + windowsOpenGLStatus.supportsDesktopGL = + checkResultDesktopGL && checkIsSupportedDesktopGL(*checkResultDesktopGL); + windowsOpenGLStatus.supportsAngleD3D11 = + checkResultAngle && checkIsSupportedAngleD3D11(*checkResultAngle); + + // HACK: Filter specific buggy drivers not handled by Qt OpenGL buglist + if (checkResultDesktopGL) { + specialOpenGLVendorFilter(windowsOpenGLStatus, *checkResultDesktopGL); + } + + userRendererConfig = convertConfigToOpenGLRenderer(userRendererConfigString); + if ((userRendererConfig == RendererDesktopGL && !windowsOpenGLStatus.supportsDesktopGL) || + (userRendererConfig == RendererAngle && !windowsOpenGLStatus.supportsAngleD3D11)) { + // Set it to auto so we won't get stuck + userRendererConfig = RendererAuto; + } + nextUserRendererConfig = userRendererConfig; + switch (userRendererConfig) { + case RendererDesktopGL: + QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL, true); + currentRenderer = RendererDesktopGL; + break; + case RendererAngle: + QCoreApplication::setAttribute(Qt::AA_UseOpenGLES, true); + currentRenderer = RendererAngle; + break; + default: + if (windowsOpenGLStatus.isQtPreferAngle && windowsOpenGLStatus.supportsAngleD3D11) { + currentRenderer = RendererAngle; + } else if (windowsOpenGLStatus.overridePreferAngle && windowsOpenGLStatus.supportsAngleD3D11) { + QCoreApplication::setAttribute(Qt::AA_UseOpenGLES, true); + currentRenderer = RendererAngle; + } else if (!windowsOpenGLStatus.isQtPreferAngle && windowsOpenGLStatus.supportsDesktopGL) { + currentRenderer = RendererDesktopGL; + } else { + currentRenderer = RendererNone; + } + break; + } +} + +KisOpenGL::OpenGLRenderer KisOpenGL::getCurrentOpenGLRenderer() +{ + return currentRenderer; +} + +KisOpenGL::OpenGLRenderer KisOpenGL::getQtPreferredOpenGLRenderer() +{ + return (windowsOpenGLStatus.isQtPreferAngle || windowsOpenGLStatus.overridePreferAngle) + ? RendererAngle : RendererDesktopGL; +} + +KisOpenGL::OpenGLRenderers KisOpenGL::getSupportedOpenGLRenderers() +{ + return RendererAuto | + (windowsOpenGLStatus.supportsDesktopGL ? RendererDesktopGL : static_cast(0)) | + (windowsOpenGLStatus.supportsAngleD3D11 ? RendererAngle : static_cast(0)); +} + +KisOpenGL::OpenGLRenderer KisOpenGL::getUserOpenGLRendererConfig() +{ + return userRendererConfig; +} + +KisOpenGL::OpenGLRenderer KisOpenGL::getNextUserOpenGLRendererConfig() +{ + return nextUserRendererConfig; +} + +void KisOpenGL::setNextUserOpenGLRendererConfig(KisOpenGL::OpenGLRenderer renderer) +{ + nextUserRendererConfig = renderer; +} + +QString KisOpenGL::convertOpenGLRendererToConfig(KisOpenGL::OpenGLRenderer renderer) +{ + switch (renderer) { + case RendererDesktopGL: + return QStringLiteral("desktop"); + case RendererAngle: + return QStringLiteral("angle"); + default: + return QStringLiteral("auto"); + } +} + +KisOpenGL::OpenGLRenderer KisOpenGL::convertConfigToOpenGLRenderer(QString renderer) +{ + if (renderer == "desktop") { + return RendererDesktopGL; + } else if (renderer == "angle") { + return RendererAngle; + } else { + return RendererAuto; + } +}