diff --git a/krita/ui/CMakeLists.txt b/krita/ui/CMakeLists.txt index e316a0e9ed..88bc4aaf74 100644 --- a/krita/ui/CMakeLists.txt +++ b/krita/ui/CMakeLists.txt @@ -1,500 +1,501 @@ # Disable -Wswitch because of the extra definitions we here: # kis_input_manager.cpp: In member function ‘virtual bool KisInputManager::eventFilter(QObject*, QEvent*)’: # warning: case value ‘1001’ not in enumerated type ‘QEvent::Type’ [-Wswitch] # warning: case value ‘1002’ not in enumerated type ‘QEvent::Type’ [-Wswitch] if (CMAKE_COMPILER_IS_GNUCXX) add_definitions(${KDE4_ENABLE_EXCEPTIONS} -Wno-switch) else () kde_enable_exceptions() endif () include_directories( ${CMAKE_SOURCE_DIR}/libs/pigment/colorprofiles ${CMAKE_CURRENT_SOURCE_DIR}/flake ${CMAKE_CURRENT_SOURCE_DIR}/pigment/resources ${CMAKE_CURRENT_SOURCE_DIR}/widgets/resources ${CMAKE_CURRENT_SOURCE_DIR}/ora ${CMAKE_SOURCE_DIR}/krita/image/metadata ${CMAKE_SOURCE_DIR}/krita/ui/qtsingleapplication ${CMAKE_SOURCE_DIR}/krita/ui/qtlockedfile ${EXIV2_INCLUDE_DIR} ${OCIO_INCLUDE_DIR}) #add_subdirectory( tests ) if (APPLE) find_library(FOUNDATION_LIBRARY Foundation) 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_painter_configuration.cpp canvas/kis_perspective_grid_manager.cpp canvas/kis_perspective_grid_decoration.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 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_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 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 kis_autogradient.cc kis_bookmarked_configurations_editor.cc kis_bookmarked_configurations_model.cc kis_bookmarked_filter_configurations_model.cc kis_canvas_resource_provider.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_custom_pattern.cc kis_file_layer.cpp kis_safe_document_loader.cpp kis_splash_screen.cpp kis_filter_manager.cc kis_filters_model.cc kis_histogram_view.cc 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_model.cpp kis_model_index_converter_base.cpp kis_model_index_converter.cpp kis_model_index_converter_show_all.cpp kis_model_index_converter_animated_layers.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_resource_server_provider.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 kisexiv2/kis_exif_io.cpp kisexiv2/kis_exiv2.cpp kisexiv2/kis_iptc_io.cpp kisexiv2/kis_xmp_io.cpp kra/kis_kra_utils.cpp kra/kis_kra_load_visitor.cpp kra/kis_kra_loader.cpp kra/kis_kra_save_visitor.cpp kra/kis_kra_saver.cpp kra/kis_kra_savexml_visitor.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_texture_tile_update_info.cpp + kis_fps_decoration.cpp ora/kis_open_raster_stack_load_visitor.cpp ora/kis_open_raster_stack_save_visitor.cpp ora/ora_load_context.cc ora/ora_save_context.cc 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_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/strokes/freehand_stroke.cpp tool/strokes/kis_painter_based_stroke_strategy.cpp tool/strokes/kis_filter_stroke_strategy.cpp widgets/kis_channelflags_widget.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_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_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_tree_view_popup.cc 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 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_gamma_exposure_action.cpp input/kis_show_palette_action.cpp input/kis_change_primary_setting_action.cpp input/kis_abstract_shortcut.cpp input/kis_single_action_shortcut.cpp input/kis_stroke_shortcut.cpp input/kis_shortcut_matcher.cpp input/kis_select_layer_action.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 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 KisDocumentEntry.cpp KisNodeDelegate.cpp KisNodeToolTip.cpp KisNodeView.cpp KisFilterChain.cpp KisFilterChainLink.cpp KisFilterChainLinkList.cpp KisImportExportFilter.cpp KisFilterEdge.cpp KisFilterEntry.cpp KisFilterGraph.cpp KisImportExportManager.cpp KisImportExportManager_p.cpp KisFilterVertex.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 kis_md5_generator.cpp KisApplicationArguments.cpp KisNetworkAccessManager.cpp KisWelcomeScreen.cpp KisMultiFeedRSSModel.cpp ) if(WIN32) 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 ) include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS}) endif() if (HAVE_OPENGL) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} kis_animation_frame_cache.cpp kis_animation_cache_populator.cpp canvas/kis_animation_player.cpp kis_animation_exporter.cpp ) endif() 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 ) endif() endif() kde_enable_exceptions() if(WIN32) #ki18n_wrap_ui( # input/wintab/kis_screen_size_choice_dialog.ui #) endif() ki18n_wrap_ui(kritaui_LIB_SRCS forms/wdgdlgpngimport.ui forms/wdgfullscreensettings.ui forms/wdgautogradient.ui forms/wdggeneralsettings.ui forms/wdgperformancesettings.ui forms/wdggridsettings.ui forms/wdggenerators.ui forms/wdgcustompalette.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/wdgdlgblacklistcleanup.ui forms/wdgrectangleconstraints.ui forms/KisDetailsPaneBase.ui forms/KisOpenPaneBase.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 kritacolor kritaimage kritalibbrush kritawidgets kritawidgetutils ${PNG_LIBRARIES} ${EXIV2_LIBRARIES} ) 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}) endif() if(APPLE) target_link_libraries(kritaui ${FOUNDATION_LIBRARY}) endif () if(HAVE_OPENEXR) target_link_libraries(kritaui ${OPENEXR_LIBRARIES}) endif() if(HAVE_OPENGL) # Add VSync disable workaround if(NOT WIN32 AND NOT APPLE) target_link_libraries(kritaui ${CMAKE_DL_LIBS} Qt5::X11Extras) endif() endif() if(X11_FOUND) target_link_libraries(kritaui Qt5::X11Extras ${X11_LIBRARIES}) endif() target_link_libraries(kritaui LINK_INTERFACE_LIBRARIES kritaimage kritalibbrush kritapigment KF5::Completion KF5::I18n ${GL_INTERFACE_LIBRARIES}) set_target_properties(kritaui PROPERTIES VERSION ${GENERIC_CALLIGRA_LIB_VERSION} SOVERSION ${GENERIC_CALLIGRA_LIB_SOVERSION} ) install(TARGETS kritaui ${INSTALL_TARGETS_DEFAULT_ARGS}) if (APPLE) install(FILES osx.stylesheet DESTINATION ${DATA_INSTALL_DIR}/krita) endif () diff --git a/krita/ui/canvas/kis_canvas2.cpp b/krita/ui/canvas/kis_canvas2.cpp index 5f448933fa..93d20d435b 100644 --- a/krita/ui/canvas/kis_canvas2.cpp +++ b/krita/ui/canvas/kis_canvas2.cpp @@ -1,918 +1,922 @@ /* This file is part of the KDE project * * Copyright (C) 2006, 2010 Boudewijn Rempt * Copyright (C) Lukáš Tvrdý , (C) 2010 * Copyright (C) 2011 Silvio Heinrich * * 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 "kis_canvas2.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_tool_proxy.h" #include "kis_coordinates_converter.h" #include "kis_prescaled_projection.h" #include "kis_image.h" #include "kis_image_barrier_locker.h" #include "KisDocument.h" #include "flake/kis_shape_layer.h" #include "kis_canvas_resource_provider.h" #include "KisViewManager.h" #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_abstract_canvas_widget.h" #include "kis_qpainter_canvas.h" #include "kis_group_layer.h" #include "flake/kis_shape_controller.h" #include "kis_node_manager.h" #include "kis_selection.h" #include "kis_selection_component.h" #include "flake/kis_shape_selection.h" #include "kis_image_config.h" #include "kis_infinity_manager.h" #include "kis_signal_compressor.h" #include "kis_display_color_converter.h" #include "kis_exposure_gamma_correction_interface.h" #include "KisView.h" #include "kis_canvas_controller.h" #ifdef HAVE_OPENGL #include "kis_animation_player.h" #include "kis_animation_frame_cache.h" #include "opengl/kis_opengl_canvas2.h" #endif #include "opengl/kis_opengl.h" - +#include "kis_fps_decoration.h" #include #include #include "input/kis_input_manager.h" #include "kis_painting_assistants_decoration.h" #include "kis_canvas_updates_compressor.h" class Q_DECL_HIDDEN KisCanvas2::KisCanvas2Private { public: KisCanvas2Private(KoCanvasBase *parent, KisCoordinatesConverter* coordConverter, QPointer view, KoCanvasResourceManager* resourceManager) : coordinatesConverter(coordConverter) , view(view) , shapeManager(parent) , toolProxy(parent) , displayColorConverter(resourceManager, view) { } KisCoordinatesConverter *coordinatesConverter; QPointerview; KisAbstractCanvasWidget *canvasWidget = 0; KoShapeManager shapeManager; bool currentCanvasIsOpenGL; #ifdef HAVE_OPENGL int openGLFilterMode; #endif KisToolProxy toolProxy; KisPrescaledProjectionSP prescaledProjection; bool vastScrolling; KisSignalCompressor updateSignalCompressor; QRect savedUpdateRect; QBitArray channelFlags; KisPopupPalette *popupPalette = 0; KisDisplayColorConverter displayColorConverter; KisCanvasUpdatesCompressor projectionUpdatesCompressor; #ifdef HAVE_OPENGL KisAnimationPlayer *animationPlayer; KisAnimationFrameCacheSP frameCache; #endif bool lodAllowedInCanvas; bool bootsrapLodBlocked; bool effectiveLodAllowedInCanvas() { return lodAllowedInCanvas && !bootsrapLodBlocked; } }; KisCanvas2::KisCanvas2(KisCoordinatesConverter *coordConverter, KoCanvasResourceManager *resourceManager, KisView *view, KoShapeBasedDocumentBase *sc) : KoCanvasBase(sc, resourceManager) , m_d(new KisCanvas2Private(this, coordConverter, view, resourceManager)) { /** * While loading LoD should be blocked. Only when GUI has finished * loading and zoom level settled down, LoD is given a green * light. */ m_d->bootsrapLodBlocked = true; connect(view->mainWindow(), SIGNAL(guiLoadingFinished()), SLOT(bootstrapFinished())); } void KisCanvas2::setup() { // a bit of duplication from slotConfigChanged() KisConfig cfg; m_d->vastScrolling = cfg.vastScrolling(); m_d->lodAllowedInCanvas = cfg.levelOfDetailEnabled(); createCanvas(cfg.useOpenGL()); setLodAllowedInCanvas(m_d->lodAllowedInCanvas); #ifdef HAVE_OPENGL m_d->animationPlayer = new KisAnimationPlayer(this); #endif connect(m_d->view->canvasController()->proxyObject, SIGNAL(moveDocumentOffset(QPoint)), SLOT(documentOffsetMoved(QPoint))); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged())); /** * We switch the shape manager every time vector layer or * shape selection is activated. Flake does not expect this * and connects all the signals of the global shape manager * to the clients in the constructor. To workaround this we * forward the signals of local shape managers stored in the * vector layers to the signals of global shape manager. So the * sequence of signal deliveries is the following: * * shapeLayer.m_d.canvas.m_shapeManager.selection() -> * shapeLayer -> * shapeController -> * globalShapeManager.selection() */ KisShapeController *kritaShapeController = static_cast(shapeController()->documentBase()); connect(kritaShapeController, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged())); connect(kritaShapeController, SIGNAL(selectionContentChanged()), globalShapeManager(), SIGNAL(selectionContentChanged())); connect(kritaShapeController, SIGNAL(currentLayerChanged(const KoShapeLayer*)), globalShapeManager()->selection(), SIGNAL(currentLayerChanged(const KoShapeLayer*))); m_d->updateSignalCompressor.setDelay(10); m_d->updateSignalCompressor.setMode(KisSignalCompressor::FIRST_ACTIVE); connect(&m_d->updateSignalCompressor, SIGNAL(timeout()), SLOT(slotDoCanvasUpdate())); } KisCanvas2::~KisCanvas2() { #ifdef HAVE_OPENGL if (m_d->animationPlayer->isPlaying()) { m_d->animationPlayer->forcedStopOnExit(); } #endif delete m_d; } void KisCanvas2::setCanvasWidget(QWidget * widget) { KisAbstractCanvasWidget *tmp = dynamic_cast(widget); Q_ASSERT_X(tmp, "setCanvasWidget", "Cannot cast the widget to a KisAbstractCanvasWidget"); if (m_d->popupPalette) { m_d->popupPalette->setParent(widget); } if(m_d->canvasWidget != 0) { tmp->setDecorations(m_d->canvasWidget->decorations()); // Redundant check for the constructor case, see below if(viewManager() != 0) viewManager()->inputManager()->removeTrackedCanvas(this); } m_d->canvasWidget = tmp; // Either tmp was null or we are being called by KisCanvas2 constructor that is called by KisView // constructor, so the view manager still doesn't exists. if(m_d->canvasWidget != 0 && viewManager() != 0) viewManager()->inputManager()->addTrackedCanvas(this); if (!m_d->canvasWidget->decoration(INFINITY_DECORATION_ID)) { KisInfinityManager *manager = new KisInfinityManager(m_d->view, this); manager->setVisible(true); m_d->canvasWidget->addDecoration(manager); } widget->setAutoFillBackground(false); widget->setAttribute(Qt::WA_OpaquePaintEvent); widget->setMouseTracking(true); widget->setAcceptDrops(true); KoCanvasControllerWidget *controller = dynamic_cast(canvasController()); if (controller) { Q_ASSERT(controller->canvas() == this); controller->changeCanvasWidget(widget); } } bool KisCanvas2::canvasIsOpenGL() { return m_d->currentCanvasIsOpenGL; } void KisCanvas2::gridSize(qreal *horizontal, qreal *vertical) const { Q_ASSERT(horizontal); Q_ASSERT(vertical); QTransform transform = coordinatesConverter()->imageToDocumentTransform(); QPointF size = transform.map(QPointF(m_d->view->document()->gridData().gridX(), m_d->view->document()->gridData().gridY())); *horizontal = size.x(); *vertical = size.y(); } bool KisCanvas2::snapToGrid() const { return m_d->view->document()->gridData().snapToGrid(); } qreal KisCanvas2::rotationAngle() const { return m_d->coordinatesConverter->rotationAngle(); } bool KisCanvas2::xAxisMirrored() const { return m_d->coordinatesConverter->xAxisMirrored(); } bool KisCanvas2::yAxisMirrored() const { return m_d->coordinatesConverter->yAxisMirrored(); } void KisCanvas2::channelSelectionChanged() { KisImageWSP image = this->image(); m_d->channelFlags = image->rootLayer()->channelFlags(); image->barrierLock(); m_d->canvasWidget->channelSelectionChanged(m_d->channelFlags); startUpdateInPatches(image->bounds()); image->unlock(); } void KisCanvas2::addCommand(KUndo2Command *command) { // This method exists to support flake-related operations m_d->view->document()->addCommand(command); } KoShapeManager* KisCanvas2::shapeManager() const { if (!viewManager()) return globalShapeManager(); if (!viewManager()->nodeManager()) return globalShapeManager(); KisLayerSP activeLayer = viewManager()->nodeManager()->activeLayer(); if (activeLayer && activeLayer->isEditable()) { KisShapeLayer * shapeLayer = dynamic_cast(activeLayer.data()); if (shapeLayer) { return shapeLayer->shapeManager(); } KisSelectionSP selection = activeLayer->selection(); if (selection && !selection.isNull()) { if (selection->hasShapeSelection()) { KoShapeManager* m = dynamic_cast(selection->shapeSelection())->shapeManager(); return m; } } } return globalShapeManager(); } KoShapeManager * KisCanvas2::globalShapeManager() const { return &m_d->shapeManager; } void KisCanvas2::updateInputMethodInfo() { // TODO call (the protected) QWidget::updateMicroFocus() on the proper canvas widget... } const KisCoordinatesConverter* KisCanvas2::coordinatesConverter() const { return m_d->coordinatesConverter; } KoViewConverter* KisCanvas2::viewConverter() const { return m_d->coordinatesConverter; } KisInputManager* KisCanvas2::globalInputManager() const { return m_d->view->globalInputManager(); } QWidget* KisCanvas2::canvasWidget() { return m_d->canvasWidget->widget(); } const QWidget* KisCanvas2::canvasWidget() const { return m_d->canvasWidget->widget(); } KoUnit KisCanvas2::unit() const { KoUnit unit(KoUnit::Pixel); KisImageWSP image = m_d->view->image(); if (image) { if (!qFuzzyCompare(image->xRes(), image->yRes())) { warnKrita << "WARNING: resolution of the image is anisotropic" << ppVar(image->xRes()) << ppVar(image->yRes()); } const qreal resolution = image->xRes(); unit.setFactor(resolution); } return unit; } KoToolProxy * KisCanvas2::toolProxy() const { return &m_d->toolProxy; } void KisCanvas2::createQPainterCanvas() { m_d->currentCanvasIsOpenGL = false; KisQPainterCanvas * canvasWidget = new KisQPainterCanvas(this, m_d->coordinatesConverter, m_d->view); m_d->prescaledProjection = new KisPrescaledProjection(); m_d->prescaledProjection->setCoordinatesConverter(m_d->coordinatesConverter); m_d->prescaledProjection->setMonitorProfile(m_d->displayColorConverter.monitorProfile(), m_d->displayColorConverter.renderingIntent(), m_d->displayColorConverter.conversionFlags()); m_d->prescaledProjection->setDisplayFilter(m_d->displayColorConverter.displayFilter()); canvasWidget->setPrescaledProjection(m_d->prescaledProjection); setCanvasWidget(canvasWidget); } void KisCanvas2::createOpenGLCanvas() { #ifdef HAVE_OPENGL KisConfig cfg; m_d->openGLFilterMode = cfg.openGLFilteringMode(); m_d->currentCanvasIsOpenGL = true; KisOpenGLCanvas2 *canvasWidget = new KisOpenGLCanvas2(this, m_d->coordinatesConverter, 0, m_d->view->image(), &m_d->displayColorConverter); m_d->frameCache = KisAnimationFrameCache::getFrameCache(canvasWidget->openGLImageTextures()); setCanvasWidget(canvasWidget); + + if (canvasWidget->needsFpsDebugging() && !decoration(KisFpsDecoration::idTag)) { + addDecoration(new KisFpsDecoration(imageView())); + } #else qFatal("Bad use of createOpenGLCanvas(). It shouldn't have happened =("); #endif } void KisCanvas2::createCanvas(bool useOpenGL) { // deinitialize previous canvas structures m_d->prescaledProjection = 0; #ifdef HAVE_OPENGL m_d->frameCache = 0; #endif KisConfig cfg; QDesktopWidget dw; const KoColorProfile *profile = cfg.displayProfile(dw.screenNumber(imageView())); m_d->displayColorConverter.setMonitorProfile(profile); if (useOpenGL) { #ifdef HAVE_OPENGL if (KisOpenGL::hasOpenGL()) { createOpenGLCanvas(); if (cfg.canvasState() == "OPENGL_FAILED") { // Creating the opengl canvas failed, fall back warnKrita << "OpenGL Canvas initialization returned OPENGL_FAILED. Falling back to QPainter."; createQPainterCanvas(); } } else { warnKrita << "Tried to create OpenGL widget when system doesn't have OpenGL\n"; createQPainterCanvas(); } #else warnKrita << "User requested an OpenGL canvas, but Krita was compiled without OpenGL support. Falling back to QPainter."; createQPainterCanvas(); #endif } else { createQPainterCanvas(); } if (m_d->popupPalette) { m_d->popupPalette->setParent(m_d->canvasWidget->widget()); } } void KisCanvas2::initializeImage() { KisImageWSP image = m_d->view->image(); m_d->coordinatesConverter->setImage(image); connect(image, SIGNAL(sigImageUpdated(QRect)), SLOT(startUpdateCanvasProjection(QRect)), Qt::DirectConnection); connect(this, SIGNAL(sigCanvasCacheUpdated()), SLOT(updateCanvasProjection())); connect(image, SIGNAL(sigSizeChanged(const QPointF&, const QPointF&)), SLOT(startResizingImage()), Qt::DirectConnection); connect(this, SIGNAL(sigContinueResizeImage(qint32,qint32)), SLOT(finishResizingImage(qint32,qint32))); connectCurrentCanvas(); } void KisCanvas2::connectCurrentCanvas() { KisImageWSP image = m_d->view->image(); if (!m_d->currentCanvasIsOpenGL) { Q_ASSERT(m_d->prescaledProjection); m_d->prescaledProjection->setImage(image); } startResizingImage(); emit imageChanged(image); setLodAllowedInCanvas(m_d->lodAllowedInCanvas); } void KisCanvas2::disconnectCurrentCanvas() { m_d->canvasWidget->disconnectCurrentCanvas(); } void KisCanvas2::resetCanvas(bool useOpenGL) { // we cannot reset the canvas before it's created, but this method might be called, // for instance when setting the monitor profile. if (!m_d->canvasWidget) { return; } #ifdef HAVE_OPENGL KisConfig cfg; bool needReset = (m_d->currentCanvasIsOpenGL != useOpenGL) || (m_d->currentCanvasIsOpenGL && m_d->openGLFilterMode != cfg.openGLFilteringMode()); if (needReset) { disconnectCurrentCanvas(); createCanvas(useOpenGL); connectCurrentCanvas(); notifyZoomChanged(); } #else Q_UNUSED(useOpenGL) #endif updateCanvasWidgetImpl(); } void KisCanvas2::startUpdateInPatches(const QRect &imageRect) { if (m_d->currentCanvasIsOpenGL) { startUpdateCanvasProjection(imageRect); } else { KisImageConfig imageConfig; int patchWidth = imageConfig.updatePatchWidth(); int patchHeight = imageConfig.updatePatchHeight(); for (int y = 0; y < imageRect.height(); y += patchHeight) { for (int x = 0; x < imageRect.width(); x += patchWidth) { QRect patchRect(x, y, patchWidth, patchHeight); startUpdateCanvasProjection(patchRect); } } } } void KisCanvas2::setDisplayFilter(KisDisplayFilter *displayFilter) { m_d->displayColorConverter.setDisplayFilter(displayFilter); KisImageWSP image = this->image(); image->barrierLock(); m_d->canvasWidget->setDisplayFilter(displayFilter); image->unlock(); } KisDisplayFilter *KisCanvas2::displayFilter() const { return m_d->displayColorConverter.displayFilter(); } KisDisplayColorConverter* KisCanvas2::displayColorConverter() const { return &m_d->displayColorConverter; } KisExposureGammaCorrectionInterface* KisCanvas2::exposureGammaCorrectionInterface() const { KisDisplayFilter *displayFilter = m_d->displayColorConverter.displayFilter(); return displayFilter ? displayFilter->correctionInterface() : KisDumbExposureGammaCorrectionInterface::instance(); } void KisCanvas2::startResizingImage() { KisImageWSP image = this->image(); qint32 w = image->width(); qint32 h = image->height(); emit sigContinueResizeImage(w, h); QRect imageBounds(0, 0, w, h); startUpdateInPatches(imageBounds); } void KisCanvas2::finishResizingImage(qint32 w, qint32 h) { m_d->canvasWidget->finishResizingImage(w, h); } void KisCanvas2::startUpdateCanvasProjection(const QRect & rc) { KisUpdateInfoSP info = m_d->canvasWidget->startUpdateCanvasProjection(rc, m_d->channelFlags); if (m_d->projectionUpdatesCompressor.putUpdateInfo(info)) { emit sigCanvasCacheUpdated(); } } void KisCanvas2::updateCanvasProjection() { while (KisUpdateInfoSP info = m_d->projectionUpdatesCompressor.takeUpdateInfo()) { QRect vRect = m_d->canvasWidget->updateCanvasProjection(info); if (!vRect.isEmpty()) { updateCanvasWidgetImpl(m_d->coordinatesConverter->viewportToWidget(vRect).toAlignedRect()); } } // TODO: Implement info->dirtyViewportRect() for KisOpenGLCanvas2 to avoid updating whole canvas if (m_d->currentCanvasIsOpenGL) { updateCanvasWidgetImpl(); } } void KisCanvas2::slotDoCanvasUpdate() { if (m_d->canvasWidget->isBusy()) { // just restarting the timer updateCanvasWidgetImpl(m_d->savedUpdateRect); return; } if (m_d->savedUpdateRect.isEmpty()) { m_d->canvasWidget->widget()->update(); emit updateCanvasRequested(m_d->canvasWidget->widget()->rect()); } else { emit updateCanvasRequested(m_d->savedUpdateRect); m_d->canvasWidget->widget()->update(m_d->savedUpdateRect); } m_d->savedUpdateRect = QRect(); } void KisCanvas2::updateCanvasWidgetImpl(const QRect &rc) { if (!m_d->updateSignalCompressor.isActive() || !m_d->savedUpdateRect.isEmpty()) { m_d->savedUpdateRect |= rc; } m_d->updateSignalCompressor.start(); } void KisCanvas2::updateCanvas() { updateCanvasWidgetImpl(); } void KisCanvas2::updateCanvas(const QRectF& documentRect) { if (m_d->currentCanvasIsOpenGL && m_d->canvasWidget->decorations().size() > 0) { updateCanvasWidgetImpl(); } else { // updateCanvas is called from tools, never from the projection // updates, so no need to prescale! QRect widgetRect = m_d->coordinatesConverter->documentToWidget(documentRect).toAlignedRect(); widgetRect.adjust(-2, -2, 2, 2); if (!widgetRect.isEmpty()) { updateCanvasWidgetImpl(widgetRect); } } } void KisCanvas2::disconnectCanvasObserver(QObject *object) { KoCanvasBase::disconnectCanvasObserver(object); m_d->view->disconnect(object); } void KisCanvas2::notifyZoomChanged() { if (!m_d->currentCanvasIsOpenGL) { Q_ASSERT(m_d->prescaledProjection); m_d->prescaledProjection->notifyZoomChanged(); } notifyLevelOfDetailChange(); updateCanvas(); // update the canvas, because that isn't done when zooming using KoZoomAction } void KisCanvas2::notifyLevelOfDetailChange() { if (!m_d->effectiveLodAllowedInCanvas()) return; KisImageSP image = this->image(); const qreal effectiveZoom = m_d->coordinatesConverter->effectiveZoom(); KisConfig cfg; const int maxLod = cfg.numMipmapLevels(); int lod = KisLodTransform::scaleToLod(effectiveZoom, maxLod); image->setDesiredLevelOfDetail(lod); } void KisCanvas2::preScale() { if (!m_d->currentCanvasIsOpenGL) { Q_ASSERT(m_d->prescaledProjection); m_d->prescaledProjection->preScale(); } } const KoColorProfile * KisCanvas2::monitorProfile() { return m_d->displayColorConverter.monitorProfile(); } KisViewManager* KisCanvas2::viewManager() const { if (m_d->view) { return m_d->view->viewManager(); } return 0; } QPointerKisCanvas2::imageView() const { return m_d->view; } KisImageWSP KisCanvas2::image() const { return m_d->view->image(); } KisImageWSP KisCanvas2::currentImage() const { return m_d->view->image(); } void KisCanvas2::documentOffsetMoved(const QPoint &documentOffset) { QPointF offsetBefore = m_d->coordinatesConverter->imageRectInViewportPixels().topLeft(); m_d->coordinatesConverter->setDocumentOffset(documentOffset); QPointF offsetAfter = m_d->coordinatesConverter->imageRectInViewportPixels().topLeft(); QPointF moveOffset = offsetAfter - offsetBefore; if (!m_d->currentCanvasIsOpenGL) m_d->prescaledProjection->viewportMoved(moveOffset); emit documentOffsetUpdateFinished(); updateCanvas(); } void KisCanvas2::slotConfigChanged() { KisConfig cfg; m_d->vastScrolling = cfg.vastScrolling(); resetCanvas(cfg.useOpenGL()); slotSetDisplayProfile(cfg.displayProfile(QApplication::desktop()->screenNumber(this->canvasWidget()))); } void KisCanvas2::refetchDataFromImage() { KisImageSP image = this->image(); KisImageBarrierLocker l(image); startUpdateInPatches(image->bounds()); } void KisCanvas2::slotSetDisplayProfile(const KoColorProfile *monitorProfile) { if (m_d->displayColorConverter.monitorProfile() == monitorProfile) return; m_d->displayColorConverter.setMonitorProfile(monitorProfile); KisImageWSP image = this->image(); image->barrierLock(); m_d->canvasWidget->setDisplayProfile(&m_d->displayColorConverter); refetchDataFromImage(); } void KisCanvas2::addDecoration(KisCanvasDecoration* deco) { m_d->canvasWidget->addDecoration(deco); } KisCanvasDecoration* KisCanvas2::decoration(const QString& id) const { return m_d->canvasWidget->decoration(id); } QPoint KisCanvas2::documentOrigin() const { /** * In Krita we don't use document origin anymore. * All the centering when needed (vastScrolling < 0.5) is done * automatically by the KisCoordinatesConverter. */ return QPoint(); } QPoint KisCanvas2::documentOffset() const { return m_d->coordinatesConverter->documentOffset(); } void KisCanvas2::setFavoriteResourceManager(KisFavoriteResourceManager* favoriteResourceManager) { m_d->popupPalette = new KisPopupPalette(favoriteResourceManager, displayColorConverter()->displayRendererInterface(), m_d->canvasWidget->widget()); m_d->popupPalette->showPopupPalette(false); } void KisCanvas2::setCursor(const QCursor &cursor) { canvasWidget()->setCursor(cursor); } #ifdef HAVE_OPENGL KisAnimationFrameCacheSP KisCanvas2::frameCache() const { return m_d->frameCache; } KisAnimationPlayer *KisCanvas2::animationPlayer() const { return m_d->animationPlayer; } #endif void KisCanvas2::slotSelectionChanged() { KisShapeLayer* shapeLayer = dynamic_cast(viewManager()->activeLayer().data()); if (!shapeLayer) { return; } m_d->shapeManager.selection()->deselectAll(); Q_FOREACH (KoShape* shape, shapeLayer->shapeManager()->selection()->selectedShapes()) { m_d->shapeManager.selection()->select(shape); } } bool KisCanvas2::isPopupPaletteVisible() const { if (!m_d->popupPalette) { return false; } return m_d->popupPalette->isVisible(); } void KisCanvas2::setWrapAroundViewingMode(bool value) { KisCanvasDecoration *infinityDecoration = m_d->canvasWidget->decoration(INFINITY_DECORATION_ID); if (infinityDecoration) { infinityDecoration->setVisible(!value); } m_d->canvasWidget->setWrapAroundViewingMode(value); } bool KisCanvas2::wrapAroundViewingMode() const { KisCanvasDecoration *infinityDecoration = m_d->canvasWidget->decoration(INFINITY_DECORATION_ID); if (infinityDecoration) { return !(infinityDecoration->visible()); } return false; } void KisCanvas2::bootstrapFinished() { if (!m_d->bootsrapLodBlocked) return; m_d->bootsrapLodBlocked = false; setLodAllowedInCanvas(m_d->lodAllowedInCanvas); } void KisCanvas2::setLodAllowedInCanvas(bool value) { #ifdef HAVE_OPENGL m_d->lodAllowedInCanvas = value && m_d->currentCanvasIsOpenGL && KisOpenGL::supportsGLSL13(); #else Q_UNUSED(value); m_d->lodAllowedInCanvas = false; #endif KisImageSP image = this->image(); if (m_d->effectiveLodAllowedInCanvas() != !image->levelOfDetailBlocked()) { image->setLevelOfDetailBlocked(!m_d->effectiveLodAllowedInCanvas()); notifyLevelOfDetailChange(); } KisConfig cfg; cfg.setLevelOfDetailEnabled(m_d->lodAllowedInCanvas); } bool KisCanvas2::lodAllowedInCanvas() const { return m_d->lodAllowedInCanvas; } KoGuidesData *KisCanvas2::guidesData() { return &m_d->view->document()->guidesData(); } void KisCanvas2::slotShowPopupPalette(const QPoint &p) { if (!m_d->popupPalette) { return; } m_d->popupPalette->showPopupPalette(p); } KisPaintingAssistantsDecoration* KisCanvas2::paintingAssistantsDecoration() const { KisCanvasDecoration* deco = decoration("paintingAssistantsDecoration"); return qobject_cast(deco); } diff --git a/krita/ui/kis_fps_decoration.cpp b/krita/ui/kis_fps_decoration.cpp new file mode 100644 index 0000000000..4ba1a0445f --- /dev/null +++ b/krita/ui/kis_fps_decoration.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015 Dmitry Kazakov + * + * 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 "kis_fps_decoration.h" + +#include +#include "kis_canvas2.h" +#include "kis_coordinates_converter.h" +#include "opengl/kis_opengl_canvas_debugger.h" + +const QString KisFpsDecoration::idTag = "fps_decoration"; + +KisFpsDecoration::KisFpsDecoration(QPointer view) + : KisCanvasDecoration(idTag, view) +{ + setVisible(true); +} + +KisFpsDecoration::~KisFpsDecoration() +{ +} + +void KisFpsDecoration::drawDecoration(QPainter& gc, const QRectF& updateRect, const KisCoordinatesConverter *converter, KisCanvas2* canvas) +{ + const qreal value = KisOpenglCanvasDebugger::instance()->accumulatedFps(); + const QString text = QString("FPS: %1").arg(value); + + gc.save(); + gc.setPen(QPen(Qt::white)); + gc.drawText(QPoint(21,31), text); + gc.setPen(QPen(Qt::black)); + gc.drawText(QPoint(20,30), text); + gc.restore(); +} diff --git a/krita/ui/opengl/kis_opengl_canvas_debugger.h b/krita/ui/kis_fps_decoration.h similarity index 65% copy from krita/ui/opengl/kis_opengl_canvas_debugger.h copy to krita/ui/kis_fps_decoration.h index 1ccf82fa8a..02cab83bad 100644 --- a/krita/ui/opengl/kis_opengl_canvas_debugger.h +++ b/krita/ui/kis_fps_decoration.h @@ -1,42 +1,34 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * 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_CANVAS_DEBUGGER_H -#define __KIS_OPENGL_CANVAS_DEBUGGER_H +#ifndef __KIS_FPS_DECORATION_H +#define __KIS_FPS_DECORATION_H -#include +#include "canvas/kis_canvas_decoration.h" - - -class KisOpenglCanvasDebugger +class KisFpsDecoration : public KisCanvasDecoration { public: - KisOpenglCanvasDebugger(); - ~KisOpenglCanvasDebugger(); - - static KisOpenglCanvasDebugger* instance(); - - void nofityPaintRequested(); - void nofitySyncStatus(bool value); + KisFpsDecoration(QPointer view); + ~KisFpsDecoration(); -private: - struct Private; - const QScopedPointer m_d; + void drawDecoration(QPainter& gc, const QRectF& updateRect, const KisCoordinatesConverter *converter, KisCanvas2* canvas); + static const QString idTag; }; -#endif /* __KIS_OPENGL_CANVAS_DEBUGGER_H */ +#endif /* __KIS_FPS_DECORATION_H */ diff --git a/krita/ui/opengl/kis_opengl_canvas2.cpp b/krita/ui/opengl/kis_opengl_canvas2.cpp index 7c8c53a45b..8068c8eb82 100644 --- a/krita/ui/opengl/kis_opengl_canvas2.cpp +++ b/krita/ui/opengl/kis_opengl_canvas2.cpp @@ -1,858 +1,863 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2006-2013 * Copyright (C) 2015 Michael Abrahams * * 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. */ #define GL_GLEXT_PROTOTYPES #include "opengl/kis_opengl_canvas2.h" #ifdef HAVE_OPENGL #include "opengl/kis_opengl_canvas2_p.h" #include "opengl/kis_opengl_canvas_debugger.h" #include "canvas/kis_canvas2.h" #include "canvas/kis_coordinates_converter.h" #include "canvas/kis_display_filter.h" #include "canvas/kis_display_color_converter.h" #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_debug.h" #include #include #include #include #include #include #include #include #include #define NEAR_VAL -1000.0 #define FAR_VAL 1000.0 #ifndef GL_CLAMP_TO_EDGE #define GL_CLAMP_TO_EDGE 0x812F #endif #define PROGRAM_VERTEX_ATTRIBUTE 0 #define PROGRAM_TEXCOORD_ATTRIBUTE 1 static bool OPENGL_SUCCESS = false; typedef void (*kis_glLogicOp)(int); static kis_glLogicOp ptr_glLogicOp = 0; struct KisOpenGLCanvas2::Private { public: ~Private() { delete displayShader; delete checkerShader; delete cursorShader; Sync::deleteSync(glSyncObject); } bool canvasInitialized{false}; QVector3D vertices[6]; QVector2D texCoords[6]; KisOpenGLImageTexturesSP openGLImageTextures; QOpenGLShaderProgram *displayShader{0}; int displayUniformLocationModelViewProjection; int displayUniformLocationTextureMatrix; int displayUniformLocationViewPortScale; int displayUniformLocationTexelSize; int displayUniformLocationTexture0; int displayUniformLocationTexture1; int displayUniformLocationFixedLodLevel; QOpenGLShaderProgram *checkerShader{0}; GLfloat checkSizeScale; bool scrollCheckers; int checkerUniformLocationModelViewProjection; int checkerUniformLocationTextureMatrix; QOpenGLShaderProgram *cursorShader{0}; int cursorShaderModelViewProjectionUniform; KisDisplayFilter* displayFilter; KisTextureTile::FilterMode filterMode; GLsync glSyncObject{0}; bool wrapAroundMode{false}; int xToColWithWrapCompensation(int x, const QRect &imageRect) { int firstImageColumn = openGLImageTextures->xToCol(imageRect.left()); int lastImageColumn = openGLImageTextures->xToCol(imageRect.right()); int colsPerImage = lastImageColumn - firstImageColumn + 1; int numWraps = floor(qreal(x) / imageRect.width()); int remainder = x - imageRect.width() * numWraps; return colsPerImage * numWraps + openGLImageTextures->xToCol(remainder); } int yToRowWithWrapCompensation(int y, const QRect &imageRect) { int firstImageRow = openGLImageTextures->yToRow(imageRect.top()); int lastImageRow = openGLImageTextures->yToRow(imageRect.bottom()); int rowsPerImage = lastImageRow - firstImageRow + 1; int numWraps = floor(qreal(y) / imageRect.height()); int remainder = y - imageRect.height() * numWraps; return rowsPerImage * numWraps + openGLImageTextures->yToRow(remainder); } }; KisOpenGLCanvas2::KisOpenGLCanvas2(KisCanvas2 *canvas, KisCoordinatesConverter *coordinatesConverter, QWidget *parent, KisImageWSP image, KisDisplayColorConverter *colorConverter) : QOpenGLWidget(parent) , KisCanvasWidgetBase(canvas, coordinatesConverter) , d(new Private()) { QSurfaceFormat format; format.setDepthBufferSize(24); setFormat(format); KisConfig cfg; cfg.writeEntry("canvasState", "OPENGL_STARTED"); d->openGLImageTextures = KisOpenGLImageTextures::getImageTextures(image, colorConverter->monitorProfile(), colorConverter->renderingIntent(), colorConverter->conversionFlags()); setAcceptDrops(true); setFocusPolicy(Qt::StrongFocus); setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_AcceptTouchEvents); setAutoFillBackground(false); setAttribute(Qt::WA_InputMethodEnabled, true); setAttribute(Qt::WA_DontCreateNativeAncestors, true); setDisplayFilterImpl(colorConverter->displayFilter(), true); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged())); slotConfigChanged(); cfg.writeEntry("canvasState", "OPENGL_SUCCESS"); } KisOpenGLCanvas2::~KisOpenGLCanvas2() { delete d; } +bool KisOpenGLCanvas2::needsFpsDebugging() const +{ + return KisOpenglCanvasDebugger::instance()->showFpsOnCanvas(); +} + void KisOpenGLCanvas2::setDisplayFilter(KisDisplayFilter* displayFilter) { setDisplayFilterImpl(displayFilter, false); } void KisOpenGLCanvas2::setDisplayFilterImpl(KisDisplayFilter* displayFilter, bool initializing) { bool needsInternalColorManagement = !displayFilter || displayFilter->useInternalColorManagement(); bool needsFullRefresh = d->openGLImageTextures-> setInternalColorManagementActive(needsInternalColorManagement); d->displayFilter = displayFilter; if (d->canvasInitialized) { d->canvasInitialized = false; initializeDisplayShader(); initializeCheckerShader(); d->canvasInitialized = true; } if (!initializing && needsFullRefresh) { canvas()->startUpdateInPatches(canvas()->image()->bounds()); } else if (!initializing) { canvas()->updateCanvas(); } } void KisOpenGLCanvas2::disconnectCurrentCanvas() { Q_ASSERT(d->openGLImageTextures); d->openGLImageTextures->disconnect(canvas()); d->openGLImageTextures->disconnect(canvas()->image()); } void KisOpenGLCanvas2::setWrapAroundViewingMode(bool value) { d->wrapAroundMode = value; update(); } void KisOpenGLCanvas2::initializeGL() { // KisConfig cfg; // if (cfg.disableVSync()) { // if (!VSyncWorkaround::tryDisableVSync(this)) { // warnUI; // warnUI << "WARNING: We didn't manage to switch off VSync on your graphics adapter."; // warnUI << "WARNING: It means either your hardware or driver doesn't support it,"; // warnUI << "WARNING: or we just don't know about this hardware. Please report us a bug"; // warnUI << "WARNING: with the output of \'glxinfo\' for your card."; // warnUI; // warnUI << "WARNING: Trying to workaround it by disabling Double Buffering."; // warnUI << "WARNING: You may see some flickering when painting with some tools. It doesn't"; // warnUI << "WARNING: affect the quality of the final image, though."; // warnUI; // if (cfg.disableDoubleBuffering() && QOpenGLContext::currentContext()->format().swapBehavior() == QSurfaceFormat::DoubleBuffer) { // errUI << "CRITICAL: Failed to disable Double Buffering. Lines may look \"bended\" on your image."; // errUI << "CRITICAL: Your graphics card or driver does not fully support Krita's OpenGL canvas."; // errUI << "CRITICAL: For an optimal experience, please disable OpenGL"; // errUI; // } // } // } KisConfig cfg; dbgUI << "OpenGL: Preparing to initialize OpenGL for KisCanvas"; int glVersion = KisOpenGL::initializeContext(context()); dbgUI << "OpenGL: Version found" << glVersion; initializeOpenGLFunctions(); VSyncWorkaround::tryDisableVSync(context()); d->openGLImageTextures->initGL(context()->functions()); d->openGLImageTextures->generateCheckerTexture(createCheckersImage(cfg.checkSize())); initializeCheckerShader(); initializeDisplayShader(); ptr_glLogicOp = (kis_glLogicOp)(context()->getProcAddress("glLogicOp")); Sync::init(context()); /** * Warn about Intel's broken video drivers */ #if defined HAVE_OPENGL && defined Q_OS_WIN #ifndef GL_RENDERER # define GL_RENDERER 0x1F01 #endif QString renderer = QString((const char*)glGetString(GL_RENDERER)); if (cfg.useOpenGL() && renderer.startsWith("Intel") && !cfg.readEntry("WarnedAboutIntel", false)) { QMessageBox::information(0, i18nc("@title:window", "Krita: Warning"), i18n("You have an Intel(R) HD Graphics video adapter.\n" "If you experience problems like a black or blank screen," "please update your display driver to the latest version.\n\n" "You can also disable OpenGL rendering in Krita's Settings.\n")); cfg.writeEntry("WarnedAboutIntel", true); } #endif d->canvasInitialized = true; } void KisOpenGLCanvas2::resizeGL(int width, int height) { coordinatesConverter()->setCanvasWidgetSize(QSize(width, height)); paintGL(); } void KisOpenGLCanvas2::paintGL() { if (!OPENGL_SUCCESS) { KisConfig cfg; cfg.writeEntry("canvasState", "OPENGL_PAINT_STARTED"); } KisOpenglCanvasDebugger::instance()->nofityPaintRequested(); QPainter gc(this); gc.beginNativePainting(); renderCanvasGL(); if (d->glSyncObject) { Sync::deleteSync(d->glSyncObject); } d->glSyncObject = Sync::getSync(); gc.endNativePainting(); renderDecorations(&gc); gc.end(); if (!OPENGL_SUCCESS) { KisConfig cfg; cfg.writeEntry("canvasState", "OPENGL_SUCCESS"); OPENGL_SUCCESS = true; } } QOpenGLShaderProgram *KisOpenGLCanvas2::getCursorShader() { if (d->cursorShader == 0) { d->cursorShader = new QOpenGLShaderProgram(); d->cursorShader->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/cursor.vert"); d->cursorShader->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/cursor.frag"); d->cursorShader->bindAttributeLocation("a_vertexPosition", PROGRAM_VERTEX_ATTRIBUTE); if (! d->cursorShader->link()) { dbgUI << "OpenGL error" << glGetError(); qFatal("Failed linking cursor shader"); } Q_ASSERT(d->cursorShader->isLinked()); d->cursorShaderModelViewProjectionUniform = d->cursorShader->uniformLocation("modelViewProjection"); } return d->cursorShader; } void KisOpenGLCanvas2::paintToolOutline(const QPainterPath &path) { QOpenGLShaderProgram *cursorShader = getCursorShader(); cursorShader->bind(); // setup the mvp transformation KisCoordinatesConverter *converter = coordinatesConverter(); QMatrix4x4 projectionMatrix; projectionMatrix.setToIdentity(); projectionMatrix.ortho(0, width(), height(), 0, NEAR_VAL, FAR_VAL); // Set view/projection matrices QMatrix4x4 modelMatrix(converter->flakeToWidgetTransform()); modelMatrix.optimize(); modelMatrix = projectionMatrix * modelMatrix; cursorShader->setUniformValue(d->cursorShaderModelViewProjectionUniform, modelMatrix); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); // XXX: glLogicOp not in ES 2.0 -- it would be better to use another method. // It is defined in 3.1 core profile onward. glEnable(GL_COLOR_LOGIC_OP); if (ptr_glLogicOp) { ptr_glLogicOp(GL_XOR); } // setup the array of vertices QVector vertices; QList subPathPolygons = path.toSubpathPolygons(); for (int i=0; ienableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE); cursorShader->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, vertices.constData()); glDrawArrays(GL_LINE_STRIP, 0, vertices.size()); vertices.clear(); } glDisable(GL_COLOR_LOGIC_OP); cursorShader->release(); } bool KisOpenGLCanvas2::isBusy() const { const bool isBusyStatus = Sync::syncStatus(d->glSyncObject) == Sync::Unsignaled; KisOpenglCanvasDebugger::instance()->nofitySyncStatus(isBusyStatus); return isBusyStatus; } inline void rectToVertices(QVector3D* vertices, const QRectF &rc) { vertices[0] = QVector3D(rc.left(), rc.bottom(), 0.f); vertices[1] = QVector3D(rc.left(), rc.top(), 0.f); vertices[2] = QVector3D(rc.right(), rc.bottom(), 0.f); vertices[3] = QVector3D(rc.left(), rc.top(), 0.f); vertices[4] = QVector3D(rc.right(), rc.top(), 0.f); vertices[5] = QVector3D(rc.right(), rc.bottom(), 0.f); } inline void rectToTexCoords(QVector2D* texCoords, const QRectF &rc) { texCoords[0] = QVector2D(rc.left(), rc.bottom()); texCoords[1] = QVector2D(rc.left(), rc.top()); texCoords[2] = QVector2D(rc.right(), rc.bottom()); texCoords[3] = QVector2D(rc.left(), rc.top()); texCoords[4] = QVector2D(rc.right(), rc.top()); texCoords[5] = QVector2D(rc.right(), rc.bottom()); } void KisOpenGLCanvas2::drawCheckers() { if (!d->checkerShader) { return; } KisCoordinatesConverter *converter = coordinatesConverter(); QTransform textureTransform; QTransform modelTransform; QRectF textureRect; QRectF modelRect; QRectF viewportRect = !d->wrapAroundMode ? converter->imageRectInViewportPixels() : converter->widgetToViewport(this->rect()); converter->getOpenGLCheckersInfo(viewportRect, &textureTransform, &modelTransform, &textureRect, &modelRect, d->scrollCheckers); textureTransform *= QTransform::fromScale(d->checkSizeScale / KisOpenGLImageTextures::BACKGROUND_TEXTURE_SIZE, d->checkSizeScale / KisOpenGLImageTextures::BACKGROUND_TEXTURE_SIZE); d->checkerShader->bind(); QMatrix4x4 projectionMatrix; projectionMatrix.setToIdentity(); projectionMatrix.ortho(0, width(), height(), 0, NEAR_VAL, FAR_VAL); // Set view/projection matrices QMatrix4x4 modelMatrix(modelTransform); modelMatrix.optimize(); modelMatrix = projectionMatrix * modelMatrix; d->checkerShader->setUniformValue(d->checkerUniformLocationModelViewProjection, modelMatrix); QMatrix4x4 textureMatrix(textureTransform); d->checkerShader->setUniformValue(d->checkerUniformLocationTextureMatrix, textureMatrix); //Setup the geometry for rendering rectToVertices(d->vertices, modelRect); d->checkerShader->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE); d->checkerShader->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, d->vertices); rectToTexCoords(d->texCoords, textureRect); d->checkerShader->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE); d->checkerShader->setAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE, d->texCoords); // render checkers glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, d->openGLImageTextures->checkerTexture()); glDrawArrays(GL_TRIANGLES, 0, 6); glBindTexture(GL_TEXTURE_2D, 0); d->checkerShader->release(); } void KisOpenGLCanvas2::drawImage() { if (!d->displayShader) { return; } glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); KisCoordinatesConverter *converter = coordinatesConverter(); d->displayShader->bind(); QMatrix4x4 projectionMatrix; projectionMatrix.setToIdentity(); projectionMatrix.ortho(0, width(), height(), 0, NEAR_VAL, FAR_VAL); // Set view/projection matrices QMatrix4x4 modelMatrix(coordinatesConverter()->imageToWidgetTransform()); modelMatrix.optimize(); modelMatrix = projectionMatrix * modelMatrix; d->displayShader->setUniformValue(d->displayUniformLocationModelViewProjection, modelMatrix); QMatrix4x4 textureMatrix; textureMatrix.setToIdentity(); d->displayShader->setUniformValue(d->displayUniformLocationTextureMatrix, textureMatrix); QRectF widgetRect(0,0, width(), height()); QRectF widgetRectInImagePixels = converter->documentToImage(converter->widgetToDocument(widgetRect)); qreal scaleX, scaleY; converter->imageScale(&scaleX, &scaleY); d->displayShader->setUniformValue(d->displayUniformLocationViewPortScale, (GLfloat) scaleX); d->displayShader->setUniformValue(d->displayUniformLocationTexelSize, (GLfloat) d->openGLImageTextures->texelSize()); QRect ir = d->openGLImageTextures->storedImageBounds(); QRect wr = widgetRectInImagePixels.toAlignedRect(); if (!d->wrapAroundMode) { // if we don't want to paint wrapping images, just limit the // processing area, and the code will handle all the rest wr &= ir; } int firstColumn = d->xToColWithWrapCompensation(wr.left(), ir); int lastColumn = d->xToColWithWrapCompensation(wr.right(), ir); int firstRow = d->yToRowWithWrapCompensation(wr.top(), ir); int lastRow = d->yToRowWithWrapCompensation(wr.bottom(), ir); int minColumn = d->openGLImageTextures->xToCol(ir.left()); int maxColumn = d->openGLImageTextures->xToCol(ir.right()); int minRow = d->openGLImageTextures->yToRow(ir.top()); int maxRow = d->openGLImageTextures->yToRow(ir.bottom()); int imageColumns = maxColumn - minColumn + 1; int imageRows = maxRow - minRow + 1; for (int col = firstColumn; col <= lastColumn; col++) { for (int row = firstRow; row <= lastRow; row++) { int effectiveCol = col; int effectiveRow = row; QPointF tileWrappingTranslation; if (effectiveCol > maxColumn || effectiveCol < minColumn) { int translationStep = floor(qreal(col) / imageColumns); int originCol = translationStep * imageColumns; effectiveCol = col - originCol; tileWrappingTranslation.rx() = translationStep * ir.width(); } if (effectiveRow > maxRow || effectiveRow < minRow) { int translationStep = floor(qreal(row) / imageRows); int originRow = translationStep * imageRows; effectiveRow = row - originRow; tileWrappingTranslation.ry() = translationStep * ir.height(); } KisTextureTile *tile = d->openGLImageTextures->getTextureTileCR(effectiveCol, effectiveRow); if (!tile) { warnUI << "OpenGL: Trying to paint texture tile but it has not been created yet."; continue; } /* * We create a float rect here to workaround Qt's * "history reasons" in calculation of right() * and bottom() coordinates of integer rects. */ QRectF textureRect(tile->tileRectInTexturePixels()); QRectF modelRect(tile->tileRectInImagePixels().translated(tileWrappingTranslation.x(), tileWrappingTranslation.y())); //Setup the geometry for rendering rectToVertices(d->vertices, modelRect); d->displayShader->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE); d->displayShader->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, d->vertices); rectToTexCoords(d->texCoords, textureRect); d->displayShader->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE); d->displayShader->setAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE, d->texCoords); if (d->displayFilter) { glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_3D, d->displayFilter->lutTexture()); d->displayShader->setUniformValue(d->displayUniformLocationTexture1, 1); } int currentLodPlane = tile->currentLodPlane(); if (d->displayUniformLocationFixedLodLevel >= 0) { d->displayShader->setUniformValue(d->displayUniformLocationFixedLodLevel, (GLfloat) currentLodPlane); } glActiveTexture(GL_TEXTURE0); tile->bindToActiveTexture(); if (currentLodPlane) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); } else if (SCALE_MORE_OR_EQUAL_TO(scaleX, scaleY, 2.0)) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); switch(d->filterMode) { case KisTextureTile::NearestFilterMode: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); break; case KisTextureTile::BilinearFilterMode: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); break; case KisTextureTile::TrilinearFilterMode: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); break; case KisTextureTile::HighQualityFiltering: if (SCALE_LESS_THAN(scaleX, scaleY, 0.5)) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } break; } } glDrawArrays(GL_TRIANGLES, 0, 6); } } glBindTexture(GL_TEXTURE_2D, 0); d->displayShader->release(); } void KisOpenGLCanvas2::reportShaderLinkFailedAndExit(bool result, const QString &context, const QString &log) { KisConfig cfg; if (cfg.useVerboseOpenGLDebugOutput()) { dbgUI << "GL-log:" << context << log; } if (result) return; QMessageBox::critical(this, i18nc("@title:window", "Krita"), QString(i18n("Krita could not initialize the OpenGL canvas:\n\n%1\n\n%2\n\n Krita will disable OpenGL and close now.")).arg(context).arg(log), QMessageBox::Close); cfg.setUseOpenGL(false); cfg.setCanvasState("OPENGL_FAILED"); } void KisOpenGLCanvas2::initializeCheckerShader() { if (d->canvasInitialized) return; delete d->checkerShader; d->checkerShader = new QOpenGLShaderProgram(); QString vertexShaderName; QString fragmentShaderName; if (KisOpenGL::supportsGLSL13()) { vertexShaderName = ":/matrix_transform.vert"; fragmentShaderName = ":/simple_texture.frag"; } else { vertexShaderName = ":/matrix_transform_legacy.vert"; fragmentShaderName = ":/simple_texture_legacy.frag"; } bool result; result = d->checkerShader->addShaderFromSourceFile(QOpenGLShader::Vertex, vertexShaderName); reportShaderLinkFailedAndExit(result, "Checker vertex shader", d->checkerShader->log()); result = d->checkerShader->addShaderFromSourceFile(QOpenGLShader::Fragment, fragmentShaderName); reportShaderLinkFailedAndExit(result, "Checker fragment shader", d->checkerShader->log()); d->checkerShader->bindAttributeLocation("a_vertexPosition", PROGRAM_VERTEX_ATTRIBUTE); d->checkerShader->bindAttributeLocation("a_textureCoordinate", PROGRAM_TEXCOORD_ATTRIBUTE); result = d->checkerShader->link(); reportShaderLinkFailedAndExit(result, "Checker shader (link)", d->checkerShader->log()); Q_ASSERT(d->checkerShader->isLinked()); d->checkerUniformLocationModelViewProjection = d->checkerShader->uniformLocation("modelViewProjection"); d->checkerUniformLocationTextureMatrix = d->checkerShader->uniformLocation("textureMatrix"); } QByteArray KisOpenGLCanvas2::buildFragmentShader() { QByteArray shaderText; bool haveDisplayFilter = d->displayFilter && !d->displayFilter->program().isEmpty(); bool useHiQualityFiltering = d->filterMode == KisTextureTile::HighQualityFiltering; bool haveGLSL13 = KisOpenGL::supportsGLSL13(); bool useDirectLodFetch = haveGLSL13; QString filename; if (haveGLSL13) { filename = "highq_downscale.frag"; shaderText.append("#version 130\n"); } else { filename = "simple_texture_legacy.frag"; } if (haveDisplayFilter) { shaderText.append("#define USE_OCIO\n"); shaderText.append(d->displayFilter->program().toLatin1()); } if (haveGLSL13 && useHiQualityFiltering) { shaderText.append("#define HIGHQ_SCALING\n"); } if (haveGLSL13 && useDirectLodFetch) { shaderText.append("#define DIRECT_LOD_FETCH\n"); } { QFile prefaceFile(":/" + filename); prefaceFile.open(QIODevice::ReadOnly); shaderText.append(prefaceFile.readAll()); } return shaderText; } void KisOpenGLCanvas2::initializeDisplayShader() { if (d->canvasInitialized) return; delete d->displayShader; d->displayShader = new QOpenGLShaderProgram(); bool result = d->displayShader->addShaderFromSourceCode(QOpenGLShader::Fragment, buildFragmentShader()); reportShaderLinkFailedAndExit(result, "Display fragment shader", d->displayShader->log()); if (KisOpenGL::supportsGLSL13()) { result = d->displayShader->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/matrix_transform.vert"); } else { result = d->displayShader->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/matrix_transform_legacy.vert"); } reportShaderLinkFailedAndExit(result, "Display vertex shader", d->displayShader->log()); d->displayShader->bindAttributeLocation("a_vertexPosition", PROGRAM_VERTEX_ATTRIBUTE); d->displayShader->bindAttributeLocation("a_textureCoordinate", PROGRAM_TEXCOORD_ATTRIBUTE); result = d->displayShader->link(); reportShaderLinkFailedAndExit(result, "Display shader (link)", d->displayShader->log()); Q_ASSERT(d->displayShader->isLinked()); d->displayUniformLocationModelViewProjection = d->displayShader->uniformLocation("modelViewProjection"); d->displayUniformLocationTextureMatrix = d->displayShader->uniformLocation("textureMatrix"); d->displayUniformLocationTexture0 = d->displayShader->uniformLocation("texture0"); // ocio d->displayUniformLocationTexture1 = d->displayShader->uniformLocation("texture1"); // highq || lod d->displayUniformLocationViewPortScale = d->displayShader->uniformLocation("viewportScale"); // highq d->displayUniformLocationTexelSize = d->displayShader->uniformLocation("texelSize"); // TODO: The trilinear filtering mode is having issues when that is set in the application. It sometimes causes Krita to crash // I cannot tell where that is at in here... Scott P (11/8/2015) // lod d->displayUniformLocationFixedLodLevel = KisOpenGL::supportsGLSL13() ? d->displayShader->uniformLocation("fixedLodLevel") : -1; } void KisOpenGLCanvas2::slotConfigChanged() { KisConfig cfg; d->checkSizeScale = KisOpenGLImageTextures::BACKGROUND_TEXTURE_CHECK_SIZE / static_cast(cfg.checkSize()); d->scrollCheckers = cfg.scrollCheckers(); d->openGLImageTextures->generateCheckerTexture(createCheckersImage(cfg.checkSize())); d->openGLImageTextures->updateConfig(cfg.useOpenGLTextureBuffer(), cfg.numMipmapLevels()); d->filterMode = (KisTextureTile::FilterMode) cfg.openGLFilteringMode(); notifyConfigChanged(); } QVariant KisOpenGLCanvas2::inputMethodQuery(Qt::InputMethodQuery query) const { return processInputMethodQuery(query); } void KisOpenGLCanvas2::inputMethodEvent(QInputMethodEvent *event) { processInputMethodEvent(event); } void KisOpenGLCanvas2::renderCanvasGL() { // Draw the border (that is, clear the whole widget to the border color) QColor widgetBackgroundColor = borderColor(); glClearColor(widgetBackgroundColor.redF(), widgetBackgroundColor.greenF(), widgetBackgroundColor.blueF(), 1.0); glClear(GL_COLOR_BUFFER_BIT); drawCheckers(); drawImage(); } void KisOpenGLCanvas2::renderDecorations(QPainter *painter) { QRect boundingRect = coordinatesConverter()->imageRectInWidgetPixels().toAlignedRect(); drawDecorations(*painter, boundingRect); } void KisOpenGLCanvas2::setDisplayProfile(KisDisplayColorConverter *colorConverter) { d->openGLImageTextures->setMonitorProfile(colorConverter->monitorProfile(), colorConverter->renderingIntent(), colorConverter->conversionFlags()); } void KisOpenGLCanvas2::channelSelectionChanged(const QBitArray &channelFlags) { d->openGLImageTextures->setChannelFlags(channelFlags); } void KisOpenGLCanvas2::finishResizingImage(qint32 w, qint32 h) { if (d->canvasInitialized) { d->openGLImageTextures->slotImageSizeChanged(w, h); } } KisUpdateInfoSP KisOpenGLCanvas2::startUpdateCanvasProjection(const QRect & rc, const QBitArray &channelFlags) { d->openGLImageTextures->setChannelFlags(channelFlags); return d->openGLImageTextures->updateCache(rc); } QRect KisOpenGLCanvas2::updateCanvasProjection(KisUpdateInfoSP info) { // See KisQPainterCanvas::updateCanvasProjection for more info bool isOpenGLUpdateInfo = dynamic_cast(info.data()); if (isOpenGLUpdateInfo) { d->openGLImageTextures->recalculateCache(info); } return QRect(); // FIXME: Implement dirty rect for OpenGL } bool KisOpenGLCanvas2::callFocusNextPrevChild(bool next) { return focusNextPrevChild(next); } KisOpenGLImageTexturesSP KisOpenGLCanvas2::openGLImageTextures() const { return d->openGLImageTextures; } #endif // HAVE_OPENGL diff --git a/krita/ui/opengl/kis_opengl_canvas2.h b/krita/ui/opengl/kis_opengl_canvas2.h index ed76b4234a..a2c32aea4b 100644 --- a/krita/ui/opengl/kis_opengl_canvas2.h +++ b/krita/ui/opengl/kis_opengl_canvas2.h @@ -1,118 +1,119 @@ /* * Copyright (C) Boudewijn Rempt , (C) 2006 * Copyright (C) Michael Abrahams , (C) 2015 * * 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_CANVAS_2_H #define KIS_OPENGL_CANVAS_2_H #include // for HAVE_OPENGL #ifdef HAVE_OPENGL #include #include #include "canvas/kis_canvas_widget_base.h" #include "opengl/kis_opengl_image_textures.h" #include "kritaui_export.h" #include "kis_ui_types.h" class KisCanvas2; class KisDisplayColorConverter; class QOpenGLShaderProgram; class QPainterPath; /** * KisOpenGLCanvas is the widget that shows the actual image using OpenGL * * NOTE: if you change something in the event handling here, also change it * in the qpainter canvas. * */ class KRITAUI_EXPORT KisOpenGLCanvas2 : public QOpenGLWidget, protected QOpenGLFunctions, public KisCanvasWidgetBase { Q_OBJECT public: KisOpenGLCanvas2(KisCanvas2 *canvas, KisCoordinatesConverter *coordinatesConverter, QWidget *parent, KisImageWSP image, KisDisplayColorConverter *colorConverter); virtual ~KisOpenGLCanvas2(); public: // QOpenGLWidget void resizeGL(int width, int height); void initializeGL(); void paintGL(); virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const; virtual void inputMethodEvent(QInputMethodEvent *event); public: void initializeCheckerShader(); void initializeDisplayShader(); void renderCanvasGL(); void renderDecorations(QPainter *painter); void paintToolOutline(const QPainterPath &path); + bool needsFpsDebugging() const; public: // Implement kis_abstract_canvas_widget interface void setDisplayFilter(KisDisplayFilter* displayFilter); void setWrapAroundViewingMode(bool value); void channelSelectionChanged(const QBitArray &channelFlags); void setDisplayProfile(KisDisplayColorConverter *colorConverter); void disconnectCurrentCanvas(); void finishResizingImage(qint32 w, qint32 h); KisUpdateInfoSP startUpdateCanvasProjection(const QRect & rc, const QBitArray &channelFlags); QRect updateCanvasProjection(KisUpdateInfoSP info); QWidget *widget() { return this; } bool isBusy() const; void setDisplayFilterImpl(KisDisplayFilter* displayFilter, bool initializing); KisOpenGLImageTexturesSP openGLImageTextures() const; private Q_SLOTS: void slotConfigChanged(); protected: // KisCanvasWidgetBase virtual bool callFocusNextPrevChild(bool next); private: void reportShaderLinkFailedAndExit(bool result, const QString &context, const QString &log); QOpenGLShaderProgram *getCursorShader(); void drawImage(); void drawCheckers(); QByteArray buildFragmentShader(); private: struct Private; Private * const d; }; #endif // HAVE_OPENGL #endif // KIS_OPENGL_CANVAS_2_H diff --git a/krita/ui/opengl/kis_opengl_canvas_debugger.cpp b/krita/ui/opengl/kis_opengl_canvas_debugger.cpp index d4850ad29b..29399e5ed3 100644 --- a/krita/ui/opengl/kis_opengl_canvas_debugger.cpp +++ b/krita/ui/opengl/kis_opengl_canvas_debugger.cpp @@ -1,99 +1,115 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * 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 "kis_opengl_canvas_debugger.h" #include #include #include #include "kis_config.h" struct KisOpenglCanvasDebugger::Private { Private() : fpsCounter(0), fpsSum(0), syncFlaggedCounter(0), syncFlaggedSum(0), isEnabled(true) {} QElapsedTimer time; int fpsCounter; int fpsSum; int syncFlaggedCounter; int syncFlaggedSum; bool isEnabled; }; Q_GLOBAL_STATIC(KisOpenglCanvasDebugger, s_instance) KisOpenglCanvasDebugger::KisOpenglCanvasDebugger() : m_d(new Private) { KisConfig cfg; m_d->isEnabled = cfg.enableOpenGLDebugging(); if (m_d->isEnabled) { m_d->time.start(); } } KisOpenglCanvasDebugger::~KisOpenglCanvasDebugger() { } KisOpenglCanvasDebugger* KisOpenglCanvasDebugger::instance() { return s_instance; } +bool KisOpenglCanvasDebugger::showFpsOnCanvas() const +{ + return m_d->isEnabled; +} + +qreal KisOpenglCanvasDebugger::accumulatedFps() +{ + qreal value = 0; + + if (m_d->fpsSum > 0) { + value = qreal(m_d->fpsCounter) / m_d->fpsSum * 1000.0; + } + + return value; +} + void KisOpenglCanvasDebugger::nofityPaintRequested() { if (!m_d->isEnabled) return; m_d->fpsSum += m_d->time.restart(); m_d->fpsCounter++; if (m_d->fpsCounter > 100 && m_d->fpsSum > 0) { qDebug() << "Requested FPS:" << qreal(m_d->fpsCounter) / m_d->fpsSum * 1000.0; m_d->fpsSum = 0; m_d->fpsCounter = 0; } } void KisOpenglCanvasDebugger::nofitySyncStatus(bool isBusy) { if (!m_d->isEnabled) return; m_d->syncFlaggedSum += isBusy; m_d->syncFlaggedCounter++; if (m_d->syncFlaggedCounter > 500 && m_d->syncFlaggedSum > 0) { qDebug() << "glSync effectiveness:" << qreal(m_d->syncFlaggedSum) / m_d->syncFlaggedCounter; m_d->syncFlaggedSum = 0; m_d->syncFlaggedCounter = 0; } } diff --git a/krita/ui/opengl/kis_opengl_canvas_debugger.h b/krita/ui/opengl/kis_opengl_canvas_debugger.h index 1ccf82fa8a..8d7e605e96 100644 --- a/krita/ui/opengl/kis_opengl_canvas_debugger.h +++ b/krita/ui/opengl/kis_opengl_canvas_debugger.h @@ -1,42 +1,45 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * 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_CANVAS_DEBUGGER_H #define __KIS_OPENGL_CANVAS_DEBUGGER_H #include class KisOpenglCanvasDebugger { public: KisOpenglCanvasDebugger(); ~KisOpenglCanvasDebugger(); static KisOpenglCanvasDebugger* instance(); + bool showFpsOnCanvas() const; + void nofityPaintRequested(); void nofitySyncStatus(bool value); + qreal accumulatedFps(); private: struct Private; const QScopedPointer m_d; }; #endif /* __KIS_OPENGL_CANVAS_DEBUGGER_H */