diff --git a/krita/data/shaders/bilinear_gradient.frag b/krita/data/shaders/bilinear_gradient.frag index 0567ef6a4d..adae01ffc9 100644 --- a/krita/data/shaders/bilinear_gradient.frag +++ b/krita/data/shaders/bilinear_gradient.frag @@ -1,37 +1,35 @@ /* * 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. */ -#version 120 - uniform sampler1D gradientColors; uniform vec2 gradientVectorStart; uniform vec2 normalisedGradientVector; void main(void) { vec2 v = gl_TexCoord[0].st - gradientVectorStart; /* Project the vector onto the normalised gradient vector. */ float t = dot(v, normalisedGradientVector); /* Reflect if t < 0 */ t = abs(t); gl_FragColor = texture1D(gradientColors, t); } diff --git a/krita/data/shaders/conical_gradient.frag b/krita/data/shaders/conical_gradient.frag index cea39a4981..147e26e32b 100644 --- a/krita/data/shaders/conical_gradient.frag +++ b/krita/data/shaders/conical_gradient.frag @@ -1,42 +1,40 @@ /* * 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. */ -#version 120 - uniform sampler1D gradientColors; uniform vec2 gradientVectorStart; uniform float gradientVectorAngle; const float PI = 3.1415926535; void main(void) { vec2 p = gl_TexCoord[0].st - gradientVectorStart; float angle = atan(p.y, p.x) + PI; angle -= gradientVectorAngle; if (angle < 0.0) { angle += 2.0 * PI; } float t = angle / (2.0 * PI); gl_FragColor = texture1D(gradientColors, t); } diff --git a/krita/data/shaders/conical_symetric_gradient.frag b/krita/data/shaders/conical_symetric_gradient.frag index cdad24cffd..22280f71d8 100644 --- a/krita/data/shaders/conical_symetric_gradient.frag +++ b/krita/data/shaders/conical_symetric_gradient.frag @@ -1,49 +1,47 @@ /* * 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. */ -#version 120 - uniform sampler1D gradientColors; uniform vec2 gradientVectorStart; uniform float gradientVectorAngle; const float PI = 3.1415926535; void main(void) { vec2 p = gl_TexCoord[0].st - gradientVectorStart; float angle = atan(p.y, p.x) + PI; angle -= gradientVectorAngle; if (angle < 0.0) { angle += 2.0 * PI; } float t; if (angle < PI) { t = angle / PI; } else { t = 1.0 - ((angle - PI) / PI); } gl_FragColor = texture1D(gradientColors, t); } diff --git a/krita/data/shaders/cursor.frag b/krita/data/shaders/cursor.frag index 70e12a3b43..dbf7816df2 100644 --- a/krita/data/shaders/cursor.frag +++ b/krita/data/shaders/cursor.frag @@ -1,8 +1,6 @@ -#version 150 core - out vec4 fragColor; void main(void) { fragColor = vec4(0.501961, 1.0, 0.501961, 1.0); } diff --git a/krita/data/shaders/cursor.vert b/krita/data/shaders/cursor.vert index 874b6bcf82..d5f05999ea 100644 --- a/krita/data/shaders/cursor.vert +++ b/krita/data/shaders/cursor.vert @@ -1,10 +1,8 @@ -#version 150 core - uniform mat4 modelViewProjection; in vec4 a_vertexPosition; void main() { gl_Position = modelViewProjection * a_vertexPosition; } diff --git a/krita/data/shaders/linear_gradient.frag b/krita/data/shaders/linear_gradient.frag index c7650a6cba..bf2363e3b4 100644 --- a/krita/data/shaders/linear_gradient.frag +++ b/krita/data/shaders/linear_gradient.frag @@ -1,34 +1,32 @@ /* * 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. */ -#version 120 - uniform sampler1D gradientColors; uniform vec2 gradientVectorStart; uniform vec2 normalisedGradientVector; void main(void) { vec2 v = gl_TexCoord[0].st - gradientVectorStart; /* Project the vector onto the normalised gradient vector. */ float t = dot(v, normalisedGradientVector); gl_FragColor = texture1D(gradientColors, t); } diff --git a/krita/data/shaders/matrix_transform.vert b/krita/data/shaders/matrix_transform.vert index 92490fb25c..ff05e33278 100644 --- a/krita/data/shaders/matrix_transform.vert +++ b/krita/data/shaders/matrix_transform.vert @@ -1,18 +1,17 @@ -#version 150 core - /* * Vertex shader for handling scaling */ + uniform mat4 modelViewProjection; uniform mat4 textureMatrix; in vec4 a_vertexPosition; in vec4 a_textureCoordinate; out vec4 v_textureCoordinate; void main() { gl_Position = modelViewProjection * a_vertexPosition; v_textureCoordinate = textureMatrix * a_textureCoordinate; } diff --git a/krita/data/shaders/matrix_transform_legacy.vert b/krita/data/shaders/matrix_transform_legacy.vert index ec0246e4be..86e3991277 100644 --- a/krita/data/shaders/matrix_transform_legacy.vert +++ b/krita/data/shaders/matrix_transform_legacy.vert @@ -1,18 +1,17 @@ /* * Vertex shader for handling scaling */ -#version 120 uniform mat4 modelViewProjection; uniform mat4 textureMatrix; attribute highp vec4 a_vertexPosition; attribute mediump vec4 a_textureCoordinate; varying vec4 v_textureCoordinate; void main() { gl_Position = modelViewProjection * a_vertexPosition; v_textureCoordinate = textureMatrix * a_textureCoordinate; } diff --git a/krita/data/shaders/radial_gradient.frag b/krita/data/shaders/radial_gradient.frag index 8ea8e6f311..4c6ff0073b 100644 --- a/krita/data/shaders/radial_gradient.frag +++ b/krita/data/shaders/radial_gradient.frag @@ -1,30 +1,28 @@ /* * 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. */ -#version 120 - uniform sampler1D gradientColors; uniform vec2 gradientVectorStart; void main(void) { float t = distance(gl_TexCoord[0].st, gradientVectorStart); gl_FragColor = texture1D(gradientColors, t); } diff --git a/krita/data/shaders/simple_texture.frag b/krita/data/shaders/simple_texture.frag index f9b7d131f8..32236216f6 100644 --- a/krita/data/shaders/simple_texture.frag +++ b/krita/data/shaders/simple_texture.frag @@ -1,14 +1,12 @@ /* * shader for handling scaling */ -#version 150 core - uniform sampler2D texture0; in vec4 v_textureCoordinate; out vec4 fragColor; void main() { fragColor = texture(texture0, v_textureCoordinate.st); } diff --git a/krita/data/shaders/simple_texture_legacy.frag b/krita/data/shaders/simple_texture_legacy.frag index c70444a563..49a6eb9195 100644 --- a/krita/data/shaders/simple_texture_legacy.frag +++ b/krita/data/shaders/simple_texture_legacy.frag @@ -1,25 +1,23 @@ /* * shader for handling scaling */ -#version 120 - uniform sampler2D texture0; varying mediump vec4 v_textureCoordinate; #ifdef USE_OCIO uniform sampler3D texture1; #endif /* USE_OCIO */ void main() { vec4 col = texture2D(texture0, v_textureCoordinate.st); #ifdef USE_OCIO gl_FragColor = OCIODisplay(col, texture1); #else /* USE_OCIO */ gl_FragColor = col; #endif /* USE_OCIO */ } diff --git a/krita/data/shaders/square_gradient.frag b/krita/data/shaders/square_gradient.frag index 2c9680e525..1392df68db 100644 --- a/krita/data/shaders/square_gradient.frag +++ b/krita/data/shaders/square_gradient.frag @@ -1,46 +1,44 @@ /* * 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. */ -#version 120 - uniform sampler1D gradientColors; uniform vec2 gradientVectorStart; uniform vec2 normalisedGradientVector; void main(void) { vec2 p = gl_TexCoord[0].st - gradientVectorStart; /* Point to line distance is: * distance = ((l0.y() - l1.y()) * p.x() + (l1.x() - l0.x()) * p.y() + l0.x() * l1.y() - l1.x() * l0.y()) * * Here l0 = (0, 0) and |l1 - l0| = 1 */ float distance1 = -normalisedGradientVector.y * p.x + normalisedGradientVector.x * p.y; distance1 = abs(distance1); /* Rotate point by 90 degrees and get the distance to the perpendicular */ float distance2 = -normalisedGradientVector.y * -p.y + normalisedGradientVector.x * p.x; distance2 = abs(distance2); float t = max(distance1, distance2); gl_FragColor = texture1D(gradientColors, t); } diff --git a/libs/ui/CMakeLists.txt b/libs/ui/CMakeLists.txt index 0cb23da1bc..1ab56bd10a 100644 --- a/libs/ui/CMakeLists.txt +++ b/libs/ui/CMakeLists.txt @@ -1,542 +1,543 @@ # 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) endif () 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) 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 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 dialogs/kis_dlg_import_image_sequence.cpp dialogs/kis_delayed_save_dialog.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_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_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_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_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 kis_multinode_property.cpp kis_async_action_feedback.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_opengl_shader_loader.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_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/strokes/freehand_stroke.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_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 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_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 KisNodeDelegate.cpp kis_node_view_visibility_delegate.cpp KisNodeToolTip.cpp KisNodeView.cpp kis_node_view_color_scheme.cpp KisFilterChain.cpp KisFilterChainLink.cpp KisFilterChainLinkList.cpp KisImportExportFilter.cpp KisFilterEdge.cpp KisFilterEntry.cpp KisFilterGraph.cpp KisImportExportManager.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 KisResourceBundle.cpp KisResourceBundleManifest.cpp kis_md5_generator.cpp KisApplicationArguments.cpp KisNetworkAccessManager.cpp KisMultiFeedRSSModel.cpp KisRemoteFileFetcher.cpp KisPaletteModel.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 ) include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS}) endif() 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 kis_animation_importer.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(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/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/wdgdlgblacklistcleanup.ui forms/wdgrectangleconstraints.ui forms/wdgimportimagesequence.ui forms/KisDetailsPaneBase.ui forms/KisOpenPaneBase.ui brushhud/kis_dlg_brush_hud_config.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 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} ${XCB_LIBRARIES}) endif() if(APPLE) target_link_libraries(kritaui ${FOUNDATION_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_link_libraries(kritaui LINK_INTERFACE_LIBRARIES kritaimage kritalibbrush kritapigment kritawidgets KF5::Completion KF5::I18n ${GL_INTERFACE_LIBRARIES}) 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 944326e5e9..14b9939efa 100644 --- a/libs/ui/opengl/kis_opengl.cpp +++ b/libs/ui/opengl/kis_opengl.cpp @@ -1,201 +1,191 @@ /* * 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 #include #include #include #include #include #include #include #include #include -#include -#include -#include #include #include #include namespace { bool initialized = false; bool NeedsFenceWorkaround = false; bool NeedsPixmapCacheWorkaround = false; int glMajorVersion = 0; int glMinorVersion = 0; bool supportsDeprecatedFunctions = false; QString Renderer; } void KisOpenGL::initialize() { if (initialized) return; setDefaultFormat(); // we need a QSurface active to get our GL functions from the context QWindow surface; surface.setSurfaceType( QSurface::OpenGLSurface ); surface.create(); QOpenGLContext context; context.create(); context.makeCurrent( &surface ); QOpenGLFunctions *funcs = context.functions(); funcs->initializeOpenGLFunctions(); qDebug() << "OpenGL Info"; qDebug() << " Vendor: " << reinterpret_cast(funcs->glGetString(GL_VENDOR)); qDebug() << " Renderer: " << reinterpret_cast(funcs->glGetString(GL_RENDERER)); qDebug() << " Version: " << reinterpret_cast(funcs->glGetString(GL_VERSION)); qDebug() << " Shading language: " << reinterpret_cast(funcs->glGetString(GL_SHADING_LANGUAGE_VERSION)); qDebug() << " Requested format: " << QSurfaceFormat::defaultFormat(); qDebug() << " Current format: " << context.format(); glMajorVersion = context.format().majorVersion(); glMinorVersion = context.format().minorVersion(); supportsDeprecatedFunctions = (context.format().options() & QSurfaceFormat::DeprecatedFunctions); qDebug() << " Version:" << glMajorVersion << "." << glMinorVersion; qDebug() << " Supports deprecated functions" << supportsDeprecatedFunctions; - initialized = true; } void KisOpenGL::initializeContext(QOpenGLContext *ctx) { initialize(); dbgUI << "OpenGL: Opening new context"; // Double check we were given the version we requested QSurfaceFormat format = ctx->format(); QOpenGLFunctions *f = ctx->functions(); f->initializeOpenGLFunctions(); #ifndef GL_RENDERER # define GL_RENDERER 0x1F01 #endif Renderer = QString((const char*)f->glGetString(GL_RENDERER)); QFile log(QDesktopServices::storageLocation(QDesktopServices::TempLocation) + "/krita-opengl.txt"); log.open(QFile::WriteOnly); QString vendor((const char*)f->glGetString(GL_VENDOR)); log.write(vendor.toLatin1()); log.write(", "); log.write(Renderer.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 KisConfig cfg; if ((isOnX11 && Renderer.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)); } } bool KisOpenGL::hasOpenGL3() { initialize(); - if (glMajorVersion == 3) { - return glMinorVersion >= 2; - } - if (glMajorVersion > 3) { - return true; - } - return false; + return (glMajorVersion * 100 + glMinorVersion) >= 302; } bool KisOpenGL::supportsFenceSync() { initialize(); return glMajorVersion >= 3; } bool KisOpenGL::needsFenceWorkaround() { initialize(); return NeedsFenceWorkaround; } bool KisOpenGL::needsPixmapCacheWorkaround() { initialize(); return NeedsPixmapCacheWorkaround; } void KisOpenGL::setDefaultFormat() { QSurfaceFormat format; format.setProfile(QSurfaceFormat::CoreProfile); format.setVersion(3, 2); format.setDepthBufferSize(24); format.setStencilBufferSize(8); format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); format.setSwapInterval(0); // Disable vertical refresh syncing QSurfaceFormat::setDefaultFormat(format); } bool KisOpenGL::hasOpenGL() { return ((glMajorVersion * 100 + glMinorVersion) >= 201); //return (glMajorVersion >= 3 && supportsDeprecatedFunctions); } diff --git a/libs/ui/opengl/kis_opengl_canvas2.cpp b/libs/ui/opengl/kis_opengl_canvas2.cpp index a563283e81..68f9213080 100644 --- a/libs/ui/opengl/kis_opengl_canvas2.cpp +++ b/libs/ui/opengl/kis_opengl_canvas2.cpp @@ -1,915 +1,759 @@ /* 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" #include "opengl/kis_opengl_canvas2_p.h" +#include "opengl/kis_opengl_shader_loader.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 #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}; KisOpenGLImageTexturesSP openGLImageTextures; - QOpenGLShaderProgram *displayShader{0}; - int displayUniformLocationModelViewProjection; - int displayUniformLocationTextureMatrix; - int displayUniformLocationViewPortScale; - int displayUniformLocationTexelSize; - int displayUniformLocationTexture0; - int displayUniformLocationTexture1; - int displayUniformLocationFixedLodLevel; + KisOpenGLShaderLoader shaderLoader; + KisShaderProgram *displayShader{0}; + KisShaderProgram *checkerShader{0}; + KisShaderProgram *cursorShader{0}; - QOpenGLShaderProgram *checkerShader{0}; GLfloat checkSizeScale; bool scrollCheckers; - int checkerUniformLocationModelViewProjection; - int checkerUniformLocationTextureMatrix; - - QOpenGLShaderProgram *cursorShader{0}; - int cursorShaderModelViewProjectionUniform; KisDisplayFilter* displayFilter; KisOpenGL::FilterMode filterMode; bool proofingConfigIsUpdated=false; GLsync glSyncObject{0}; bool wrapAroundMode{false}; // Stores a quad for drawing the canvas QOpenGLVertexArrayObject quadVAO; QOpenGLBuffer quadBuffers[2]; // Stores data for drawing tool outlines QOpenGLVertexArrayObject outlineVAO; QOpenGLBuffer lineBuffer; QVector3D vertices[6]; QVector2D texCoords[6]; 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()) { KisConfig cfg; cfg.writeEntry("canvasState", "OPENGL_STARTED"); d->openGLImageTextures = KisOpenGLImageTextures::getImageTextures(image, colorConverter->monitorProfile(), colorConverter->renderingIntent(), colorConverter->conversionFlags()); setAcceptDrops(true); setAutoFillBackground(false); setFocusPolicy(Qt::StrongFocus); setAttribute(Qt::WA_NoSystemBackground, true); #ifdef Q_OS_MAC setAttribute(Qt::WA_AcceptTouchEvents, false); #else setAttribute(Qt::WA_AcceptTouchEvents, true); #endif 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(); + delete d->displayShader; + bool useHiQualityFiltering = d->filterMode == KisOpenGL::HighQualityFiltering; + d->displayShader = d->shaderLoader.loadDisplayShader(d->displayFilter, useHiQualityFiltering); d->canvasInitialized = true; } if (!initializing && needsFullRefresh) { canvas()->startUpdateInPatches(canvas()->image()->bounds()); } else if (!initializing) { canvas()->updateCanvas(); } } void KisOpenGLCanvas2::setWrapAroundViewingMode(bool value) { d->wrapAroundMode = value; update(); } 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::initializeGL() { KisOpenGL::initializeContext(context()); initializeOpenGLFunctions(); KisConfig cfg; d->openGLImageTextures->setProofingConfig(canvas()->proofingConfiguration()); d->openGLImageTextures->initGL(context()->functions()); d->openGLImageTextures->generateCheckerTexture(createCheckersImage(cfg.checkSize())); - initializeCheckerShader(); - initializeDisplayShader(); - // If we support OpenGL 3.2, then prepare out VAOs and VBOs for drawing + initializeShaders(); + + // If we support OpenGL 3.2, then prepare our VAOs and VBOs for drawing if (KisOpenGL::hasOpenGL3()) { d->quadVAO.create(); d->quadVAO.bind(); glEnableVertexAttribArray(PROGRAM_VERTEX_ATTRIBUTE); glEnableVertexAttribArray(PROGRAM_TEXCOORD_ATTRIBUTE); // Create the vertex buffer object, it has 6 vertices with 3 components d->quadBuffers[0].create(); d->quadBuffers[0].setUsagePattern(QOpenGLBuffer::StaticDraw); d->quadBuffers[0].bind(); d->quadBuffers[0].allocate(d->vertices, 6 * 3 * sizeof(float)); glVertexAttribPointer(PROGRAM_VERTEX_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, 0, 0); // Create the texture buffer object, it has 6 texture coordinates with 2 components d->quadBuffers[1].create(); d->quadBuffers[1].setUsagePattern(QOpenGLBuffer::StaticDraw); d->quadBuffers[1].bind(); d->quadBuffers[1].allocate(d->texCoords, 6 * 2 * sizeof(float)); glVertexAttribPointer(PROGRAM_TEXCOORD_ATTRIBUTE, 2, GL_FLOAT, GL_FALSE, 0, 0); // Create the outline buffer, this buffer will store the outlines of // tools and will frequently change data d->outlineVAO.create(); d->outlineVAO.bind(); glEnableVertexAttribArray(PROGRAM_VERTEX_ATTRIBUTE); d->lineBuffer.create(); d->lineBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw); d->lineBuffer.bind(); glVertexAttribPointer(PROGRAM_VERTEX_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, 0, 0); } ptr_glLogicOp = (kis_glLogicOp)(context()->getProcAddress("glLogicOp")); Sync::init(context()); d->canvasInitialized = true; } +void KisOpenGLCanvas2::initializeShaders() +{ + bool useHiQualityFiltering = d->filterMode == KisOpenGL::HighQualityFiltering; + + if (!d->canvasInitialized) { + delete d->displayShader; + delete d->checkerShader; + delete d->cursorShader; + d->displayShader = d->shaderLoader.loadDisplayShader(d->displayFilter, useHiQualityFiltering); + d->checkerShader = d->shaderLoader.loadCheckerShader(); + d->cursorShader = d->shaderLoader.loadCursorShader(); + } +} + 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(); renderCanvasGL(); if (d->glSyncObject) { Sync::deleteSync(d->glSyncObject); } d->glSyncObject = Sync::getSync(); QPainter gc(this); 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(); + d->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); + d->cursorShader->setUniformValue(d->cursorShader->location("modelViewProjection"), 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. // Actually, https://www.opengl.org/sdk/docs/man/html/glLogicOp.xhtml says it's in 2.0 onwards, // only not in ES, but we don't care about ES, so we could use the function directly. glEnable(GL_COLOR_LOGIC_OP); if (ptr_glLogicOp) { ptr_glLogicOp(GL_XOR); } // Paint the tool outline if (KisOpenGL::hasOpenGL3()) { d->outlineVAO.bind(); d->lineBuffer.bind(); } // Convert every disjointed subpath to a polygon and draw that polygon QList subPathPolygons = path.toSubpathPolygons(); for (int i = 0; i < subPathPolygons.size(); i++) { const QPolygonF& polygon = subPathPolygons.at(i); QVector vertices; vertices.resize(polygon.count()); for (int j = 0; j < polygon.count(); j++) { QPointF p = polygon.at(j); vertices[j].setX(p.x()); vertices[j].setY(p.y()); } if (KisOpenGL::hasOpenGL3()) { d->lineBuffer.allocate(vertices.constData(), 3 * vertices.size() * sizeof(float)); } else { - cursorShader->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE); - cursorShader->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, vertices.constData()); + d->cursorShader->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE); + d->cursorShader->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, vertices.constData()); } glDrawArrays(GL_LINE_STRIP, 0, vertices.size()); } if (KisOpenGL::hasOpenGL3()) { d->lineBuffer.release(); d->outlineVAO.release(); } glDisable(GL_COLOR_LOGIC_OP); - cursorShader->release(); + d->cursorShader->release(); } bool KisOpenGLCanvas2::isBusy() const { const bool isBusyStatus = Sync::syncStatus(d->glSyncObject) == Sync::Unsignaled; KisOpenglCanvasDebugger::instance()->nofitySyncStatus(isBusyStatus); return isBusyStatus; } 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); if (!d->checkerShader->bind()) { qWarning() << "Could not bind checker shader"; return; } 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); + d->checkerShader->setUniformValue(d->checkerShader->location("modelViewProjection"), modelMatrix); QMatrix4x4 textureMatrix(textureTransform); - d->checkerShader->setUniformValue(d->checkerUniformLocationTextureMatrix, textureMatrix); + d->checkerShader->setUniformValue(d->checkerShader->location("textureMatrix"), textureMatrix); //Setup the geometry for rendering if (KisOpenGL::hasOpenGL3()) { rectToVertices(d->vertices, modelRect); d->quadBuffers[0].bind(); d->quadBuffers[0].write(0, d->vertices, 3 * 6 * sizeof(float)); rectToTexCoords(d->texCoords, textureRect); d->quadBuffers[1].bind(); d->quadBuffers[1].write(0, d->texCoords, 2 * 6 * sizeof(float)); } else { 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(); glBindBuffer(GL_ARRAY_BUFFER, 0); } 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); + d->displayShader->setUniformValue(d->displayShader->location("modelViewProjection"), modelMatrix); QMatrix4x4 textureMatrix; textureMatrix.setToIdentity(); - d->displayShader->setUniformValue(d->displayUniformLocationTextureMatrix, textureMatrix); + d->displayShader->setUniformValue(d->displayShader->location("textureMatrix"), 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()); + d->displayShader->setUniformValue(d->displayShader->location("viewportScale"), (GLfloat) scaleX); + d->displayShader->setUniformValue(d->displayShader->location("texelSize"), (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 if (KisOpenGL::hasOpenGL3()) { rectToVertices(d->vertices, modelRect); d->quadBuffers[0].bind(); d->quadBuffers[0].write(0, d->vertices, 3 * 6 * sizeof(float)); rectToTexCoords(d->texCoords, textureRect); d->quadBuffers[1].bind(); d->quadBuffers[1].write(0, d->texCoords, 2 * 6 * sizeof(float)); } else { 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); + d->displayShader->setUniformValue(d->displayShader->location("texture1"), 1); } int currentLodPlane = tile->currentLodPlane(); - if (d->displayUniformLocationFixedLodLevel >= 0) { - d->displayShader->setUniformValue(d->displayUniformLocationFixedLodLevel, + if (d->displayShader->location("fixedLodLevel") >= 0) { + d->displayShader->setUniformValue(d->displayShader->location("fixedLodLevel"), (GLfloat) currentLodPlane); } glActiveTexture(GL_TEXTURE0); tile->bindToActiveTexture(); if (currentLodPlane > 0) { 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 KisOpenGL::NearestFilterMode: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); break; case KisOpenGL::BilinearFilterMode: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); break; case KisOpenGL::TrilinearFilterMode: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); break; case KisOpenGL::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(); glBindBuffer(GL_ARRAY_BUFFER, 0); } -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; - - bool result; - - if (KisOpenGL::hasOpenGL3()) { - vertexShaderName = ":/matrix_transform.vert"; - fragmentShaderName = ":/simple_texture.frag"; - } - else { - vertexShaderName = ":/matrix_transform_legacy.vert"; - fragmentShaderName = ":/simple_texture_legacy.frag"; - } - - 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::buildDisplayShader() -{ - QByteArray shaderText; - - bool haveDisplayFilter = d->displayFilter && !d->displayFilter->program().isEmpty(); - bool useHiQualityFiltering = d->filterMode == KisOpenGL::HighQualityFiltering; - - QString filename; - - if (KisOpenGL::hasOpenGL3()) { - filename = "highq_downscale.frag"; - shaderText.append("#version 150 core\n"); - } else { - filename = "simple_texture_legacy.frag"; - } - - if (haveDisplayFilter) { - shaderText.append("#define USE_OCIO\n"); - shaderText.append(d->displayFilter->program().toLatin1()); - } - - if (KisOpenGL::hasOpenGL3() && useHiQualityFiltering) { - shaderText.append("#define HIGHQ_SCALING\n"); - } - if (KisOpenGL::hasOpenGL3()) { - 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, buildDisplayShader()); - reportShaderLinkFailedAndExit(result, "Display fragment shader", d->displayShader->log()); - - if (KisOpenGL::hasOpenGL3()) { - 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::hasOpenGL3() ? - 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 = (KisOpenGL::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); if (d->displayFilter) { d->displayFilter->updateShader(); } if (KisOpenGL::hasOpenGL3()) { d->quadVAO.bind(); } drawCheckers(); drawImage(); if (KisOpenGL::hasOpenGL3()) { d->quadVAO.release(); } } 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); if (canvas()->proofingConfigUpdated()) { d->openGLImageTextures->setProofingConfig(canvas()->proofingConfiguration()); canvas()->setProofingConfigUpdated(false); } 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); } #ifdef Q_OS_MAC /** * There is a bug on OSX: if we issue frame redraw before the tiles finished * uploading, the tiles will become corrupted. Depending on the GPU/driver * version either the tile itself, or its mipmaps will become totally * transparent. */ glFinish(); #endif return QRect(); // FIXME: Implement dirty rect for OpenGL } bool KisOpenGLCanvas2::callFocusNextPrevChild(bool next) { return focusNextPrevChild(next); } KisOpenGLImageTexturesSP KisOpenGLCanvas2::openGLImageTextures() const { return d->openGLImageTextures; } diff --git a/libs/ui/opengl/kis_opengl_canvas2.h b/libs/ui/opengl/kis_opengl_canvas2.h index 9d02b34678..adbf143c03 100644 --- a/libs/ui/opengl/kis_opengl_canvas2.h +++ b/libs/ui/opengl/kis_opengl_canvas2.h @@ -1,113 +1,111 @@ /* * 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 #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 initializeShaders(); 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 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 buildDisplayShader(); private: struct Private; Private * const d; }; #endif // KIS_OPENGL_CANVAS_2_H diff --git a/libs/ui/opengl/kis_opengl_shader_loader.cpp b/libs/ui/opengl/kis_opengl_shader_loader.cpp new file mode 100644 index 0000000000..10ad72405c --- /dev/null +++ b/libs/ui/opengl/kis_opengl_shader_loader.cpp @@ -0,0 +1,146 @@ +#include "kis_opengl_shader_loader.h" + +#include "opengl/kis_opengl.h" +#include "kis_config.h" + +#include +#include + +#include + +#define PROGRAM_VERTEX_ATTRIBUTE 0 +#define PROGRAM_TEXCOORD_ATTRIBUTE 1 + +KisOpenGLShaderLoader::KisOpenGLShaderLoader() +{ + +} + +KisShaderProgram *KisOpenGLShaderLoader::loadShader(QString vertPath, QString fragPath, + QByteArray vertHeader, QByteArray fragHeader) +{ + bool result; + + KisShaderProgram *shader = new KisShaderProgram(); + + // Load vertex shader + QByteArray vertSource; + + vertSource.append(KisOpenGL::hasOpenGL3() ? "#version 150 core\n" : "#version 120"); + vertSource.append(vertHeader); + QFile vertexShaderFile(":/" + vertPath); + vertexShaderFile.open(QIODevice::ReadOnly); + vertSource.append(vertexShaderFile.readAll()); + + result = shader->addShaderFromSourceCode(QOpenGLShader::Vertex, vertSource); + reportShaderLinkFailedAndExit(result, "Adding vertex shader source", shader->log()); + + // Load fragment shader + QByteArray fragSource; + + fragSource.append(KisOpenGL::hasOpenGL3() ? "#version 150 core\n" : "#version 120"); + fragSource.append(fragHeader); + QFile fragmentShaderFile(":/" + fragPath); + fragmentShaderFile.open(QIODevice::ReadOnly); + fragSource.append(fragmentShaderFile.readAll()); + + result = shader->addShaderFromSourceCode(QOpenGLShader::Fragment, fragSource); + reportShaderLinkFailedAndExit(result, "Adding fragment shader source", shader->log()); + + // Bind uniforms + shader->bindAttributeLocation("a_vertexPosition", PROGRAM_VERTEX_ATTRIBUTE); + shader->bindAttributeLocation("a_textureCoordinate", PROGRAM_TEXCOORD_ATTRIBUTE); + + // Link + result = shader->link(); + reportShaderLinkFailedAndExit(result, "Linking shader", shader->log()); + + Q_ASSERT(shader->isLinked()); + + return shader; +} + +KisShaderProgram *KisOpenGLShaderLoader::loadDisplayShader(KisDisplayFilter *displayFilter, bool useHiQualityFiltering) +{ + QByteArray fragHeader; + + if (KisOpenGL::hasOpenGL3()) { + fragHeader.append("#define DIRECT_LOD_FETCH\n"); + if (useHiQualityFiltering) { + fragHeader.append("#define HIGHQ_SCALING\n"); + } + } + + bool haveDisplayFilter = displayFilter && !displayFilter->program().isEmpty(); + if (haveDisplayFilter) { + fragHeader.append("#define USE_OCIO\n"); + fragHeader.append(displayFilter->program().toLatin1()); + } + + QString vertPath, fragPath; + // Select appropriate vertex shader + if (KisOpenGL::hasOpenGL3()) { + vertPath = "matrix_transform.vert"; + fragPath = "highq_downscale.frag"; + } else { + vertPath = "matrix_transform_legacy.vert"; + fragPath = "simple_texture_legacy.frag"; + } + + KisShaderProgram *shader = loadShader(vertPath, fragPath, QByteArray(), fragHeader); + + return shader; +} + +KisShaderProgram *KisOpenGLShaderLoader::loadCheckerShader() +{ + QString vertPath, fragPath; + // Select appropriate vertex shader + if (KisOpenGL::hasOpenGL3()) { + vertPath = "matrix_transform.vert"; + fragPath = "simple_texture.frag"; + } else { + vertPath = "matrix_transform_legacy.vert"; + fragPath = "simple_texture_legacy.frag"; + } + + KisShaderProgram *shader = loadShader(vertPath, fragPath, QByteArray(), QByteArray()); + + return shader; +} + +KisShaderProgram *KisOpenGLShaderLoader::loadCursorShader() +{ + QString vertPath, fragPath; + // Select appropriate vertex shader + if (KisOpenGL::hasOpenGL3()) { + vertPath = "cursor.vert"; + fragPath = "cursor.frag"; + } else { + vertPath = "cursor_legacy.vert"; + fragPath = "cursor_legacy.frag"; + } + + KisShaderProgram *shader = loadShader(vertPath, fragPath, QByteArray(), QByteArray()); + + return shader; +} + +void KisOpenGLShaderLoader::reportShaderLinkFailedAndExit(bool result, const QString &context, const QString &log) +{ + KisConfig cfg; + + if (cfg.useVerboseOpenGLDebugOutput()) { + dbgUI << "GL-log:" << context << log; + } + + if (result) return; + + qDebug() << "Shader failed to compile/link/anything: " << context; + //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"); +} diff --git a/libs/ui/opengl/kis_opengl_shader_loader.h b/libs/ui/opengl/kis_opengl_shader_loader.h new file mode 100644 index 0000000000..9739034380 --- /dev/null +++ b/libs/ui/opengl/kis_opengl_shader_loader.h @@ -0,0 +1,36 @@ +#include "canvas/kis_display_filter.h" + +#include +#include +#include + +#include +#include + +class KisShaderProgram : public QOpenGLShaderProgram { +public: + int location(const char* name) { + std::unordered_map::const_iterator it = locationMap.find(std::string(name)); + if (it != locationMap.end()) { + return it->second; + } else { + int location = uniformLocation(name); + locationMap[std::string(name)] = location; + return location; + } + } +private: + std::unordered_map locationMap; +}; + +class KisOpenGLShaderLoader { +public: + KisOpenGLShaderLoader(); + KisShaderProgram *loadDisplayShader(KisDisplayFilter *displayFilter, bool useHiQualityFiltering); + KisShaderProgram *loadCheckerShader(); + KisShaderProgram *loadCursorShader(); + +private: + KisShaderProgram *loadShader(QString vertPath, QString fragPath, QByteArray vertHeader, QByteArray fragHeader); + void reportShaderLinkFailedAndExit(bool result, const QString &context, const QString &log); +}; diff --git a/plugins/dockers/lut/ocio_display_filter.cpp b/plugins/dockers/lut/ocio_display_filter.cpp index fead27f05f..69435dc493 100644 --- a/plugins/dockers/lut/ocio_display_filter.cpp +++ b/plugins/dockers/lut/ocio_display_filter.cpp @@ -1,350 +1,361 @@ /* * Copyright (c) 2012 Boudewijn Rempt * * 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 "ocio_display_filter.h" #include #include #include #include #include #include #include #include #include #include #include +#include #include static const int LUT3D_EDGE_SIZE = 32; OcioDisplayFilter::OcioDisplayFilter(KisExposureGammaCorrectionInterface *interface, QObject *parent) : KisDisplayFilter(parent) , inputColorSpaceName(0) , displayDevice(0) , view(0) , look(0) , swizzle(RGBA) , m_interface(interface) , m_lut3dTexID(0) , m_shaderDirty(true) { } OcioDisplayFilter::~OcioDisplayFilter() { } KisExposureGammaCorrectionInterface* OcioDisplayFilter::correctionInterface() const { return m_interface; } void OcioDisplayFilter::filter(quint8 *pixels, quint32 numPixels) { // processes that data _in_ place if (m_processor) { OCIO::PackedImageDesc img(reinterpret_cast(pixels), numPixels, 1, 4); m_processor->apply(img); } } void OcioDisplayFilter::approximateInverseTransformation(quint8 *pixels, quint32 numPixels) { // processes that data _in_ place if (m_revereseApproximationProcessor) { OCIO::PackedImageDesc img(reinterpret_cast(pixels), numPixels, 1, 4); m_revereseApproximationProcessor->apply(img); } } void OcioDisplayFilter::approximateForwardTransformation(quint8 *pixels, quint32 numPixels) { // processes that data _in_ place if (m_forwardApproximationProcessor) { OCIO::PackedImageDesc img(reinterpret_cast(pixels), numPixels, 1, 4); m_forwardApproximationProcessor->apply(img); } } bool OcioDisplayFilter::useInternalColorManagement() const { return forceInternalColorManagement; } bool OcioDisplayFilter::lockCurrentColorVisualRepresentation() const { return m_lockCurrentColorVisualRepresentation; } void OcioDisplayFilter::setLockCurrentColorVisualRepresentation(bool value) { m_lockCurrentColorVisualRepresentation = value; } QString OcioDisplayFilter::program() const { return m_program; } GLuint OcioDisplayFilter::lutTexture() const { return m_lut3dTexID; } void OcioDisplayFilter::updateProcessor() { if (!config) { return; } if (!displayDevice) { displayDevice = config->getDefaultDisplay(); } if (!view) { view = config->getDefaultView(displayDevice); } if (!inputColorSpaceName) { inputColorSpaceName = config->getColorSpaceNameByIndex(0); } if (!look) { look = config->getLookNameByIndex(0); } if (!displayDevice || !view || !inputColorSpaceName) { return; } OCIO::DisplayTransformRcPtr transform = OCIO::DisplayTransform::Create(); transform->setInputColorSpaceName(inputColorSpaceName); transform->setDisplay(displayDevice); transform->setView(view); /** * Look support: * As the OCIO docs will tell you, looks are a aesthetic transform that is * added onto the mix. * A view+display can have it's own assigned Look, or list of looks, and these * can be overriden optionally. * What the OCIO docs won't tell you is that a display transform won't use the * looks attached to it unless "skipColorSpaceConversions" is false... * I have no idea what "skipColorSpaceConversions" is beyond what it says on the * tin. It is not mentioned in the documentation anywhere. Or on the website. * Or how to set it. Or unset it. Why it is apparantly set true to begin with. * Only that, apparantly, this was done with non-color data in mind... * * Until there's clear documentation on how to use this feature, I am afraid the * override is all we can offer. */ if (config->getLook(look)) { transform->setLooksOverride(look); transform->setLooksOverrideEnabled(true); } OCIO::GroupTransformRcPtr approximateTransform = OCIO::GroupTransform::Create(); // fstop exposure control -- not sure how that translates to our exposure { float exposureGain = powf(2.0f, exposure); const qreal minRange = 0.001; if (qAbs(blackPoint - whitePoint) < minRange) { whitePoint = blackPoint + minRange; } const float oldMin[] = { blackPoint, blackPoint, blackPoint, 0.0f }; const float oldMax[] = { whitePoint, whitePoint, whitePoint, 1.0f }; const float newMin[] = { 0.0f, 0.0f, 0.0f, 0.0f }; const float newMax[] = { exposureGain, exposureGain, exposureGain, 1.0f }; float m44[16]; float offset4[4]; OCIO::MatrixTransform::Fit(m44, offset4, oldMin, oldMax, newMin, newMax); OCIO::MatrixTransformRcPtr mtx = OCIO::MatrixTransform::Create(); mtx->setValue(m44, offset4); transform->setLinearCC(mtx); // approximation (no color correction); approximateTransform->push_back(mtx); } // channel swizzle { int channelHot[4]; switch (swizzle) { case LUMINANCE: channelHot[0] = 1; channelHot[1] = 1; channelHot[2] = 1; channelHot[3] = 0; break; case RGBA: channelHot[0] = 1; channelHot[1] = 1; channelHot[2] = 1; channelHot[3] = 1; break; case R: channelHot[0] = 1; channelHot[1] = 0; channelHot[2] = 0; channelHot[3] = 0; break; case G: channelHot[0] = 0; channelHot[1] = 1; channelHot[2] = 0; channelHot[3] = 0; break; case B: channelHot[0] = 0; channelHot[1] = 0; channelHot[2] = 1; channelHot[3] = 0; break; case A: channelHot[0] = 0; channelHot[1] = 0; channelHot[2] = 0; channelHot[3] = 1; default: ; } float lumacoef[3]; config->getDefaultLumaCoefs(lumacoef); float m44[16]; float offset[4]; OCIO::MatrixTransform::View(m44, offset, channelHot, lumacoef); OCIO::MatrixTransformRcPtr swizzle = OCIO::MatrixTransform::Create(); swizzle->setValue(m44, offset); transform->setChannelView(swizzle); } // Post-display transform gamma { float exponent = 1.0f/std::max(1e-6f, static_cast(gamma)); const float exponent4f[] = { exponent, exponent, exponent, exponent }; OCIO::ExponentTransformRcPtr expTransform = OCIO::ExponentTransform::Create(); expTransform->setValue(exponent4f); transform->setDisplayCC(expTransform); // approximation (no color correction); approximateTransform->push_back(expTransform); } m_processor = config->getProcessor(transform); m_forwardApproximationProcessor = config->getProcessor(approximateTransform, OCIO::TRANSFORM_DIR_FORWARD); try { m_revereseApproximationProcessor = config->getProcessor(approximateTransform, OCIO::TRANSFORM_DIR_INVERSE); } catch (...) { warnKrita << "OCIO inverted matrix does not exist!"; //m_revereseApproximationProcessor; } m_shaderDirty = true; } void OcioDisplayFilter::updateShader() { + if (KisOpenGL::hasOpenGL3()) { + QOpenGLFunctions_3_2_Core *f = QOpenGLContext::currentContext()->versionFunctions(); + updateShaderImpl(f); + } else { + QOpenGLFunctions_2_0 *f = QOpenGLContext::currentContext()->versionFunctions(); + updateShaderImpl(f); + } +} + +template +void OcioDisplayFilter::updateShaderImpl(F *f) { // check whether we are allowed to use shaders -- though that should // work for everyone these days KisConfig cfg; if (!cfg.useOpenGL()) return; if (!m_shaderDirty) return; - QOpenGLFunctions_2_0 *f = QOpenGLContext::currentContext()->versionFunctions(); if (!f) { - qWarning() << "Could not create OpenGL 2.0 functions!"; + qWarning() << "Failed to get valid OpenGL functions for OcioDisplayFilter!"; return; } f->initializeOpenGLFunctions(); const int lut3DEdgeSize = cfg.ocioLutEdgeSize(); if (m_lut3d.size() == 0) { //dbgKrita << "generating lut"; f->glGenTextures(1, &m_lut3dTexID); int num3Dentries = 3 * lut3DEdgeSize * lut3DEdgeSize * lut3DEdgeSize; m_lut3d.fill(0.0, num3Dentries); f->glActiveTexture(GL_TEXTURE1); f->glBindTexture(GL_TEXTURE_3D, m_lut3dTexID); f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); f->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); f->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F_ARB, lut3DEdgeSize, lut3DEdgeSize, lut3DEdgeSize, 0, GL_RGB, GL_FLOAT, &m_lut3d.constData()[0]); } // Step 1: Create a GPU Shader Description OCIO::GpuShaderDesc shaderDesc; if (KisOpenGL::hasOpenGL3()) { shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_3); } else { shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0); } shaderDesc.setFunctionName("OCIODisplay"); shaderDesc.setLut3DEdgeLen(lut3DEdgeSize); // Step 2: Compute the 3D LUT QString lut3dCacheID = QString::fromLatin1(m_processor->getGpuLut3DCacheID(shaderDesc)); if (lut3dCacheID != m_lut3dcacheid) { //dbgKrita << "Computing 3DLut " << m_lut3dcacheid; m_lut3dcacheid = lut3dCacheID; m_processor->getGpuLut3D(&m_lut3d[0], shaderDesc); f->glBindTexture(GL_TEXTURE_3D, m_lut3dTexID); f->glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, lut3DEdgeSize, lut3DEdgeSize, lut3DEdgeSize, GL_RGB, GL_FLOAT, &m_lut3d[0]); } // Step 3: Generate the shader text QString shaderCacheID = QString::fromLatin1(m_processor->getGpuShaderTextCacheID(shaderDesc)); if (m_program.isEmpty() || shaderCacheID != m_shadercacheid) { //dbgKrita << "Computing Shader " << m_shadercacheid; m_shadercacheid = shaderCacheID; std::ostringstream os; os << m_processor->getGpuShaderText(shaderDesc) << "\n"; m_program = QString::fromLatin1(os.str().c_str()); } m_shaderDirty = false; } diff --git a/plugins/dockers/lut/ocio_display_filter.h b/plugins/dockers/lut/ocio_display_filter.h index 304bcc045f..87222ac196 100644 --- a/plugins/dockers/lut/ocio_display_filter.h +++ b/plugins/dockers/lut/ocio_display_filter.h @@ -1,94 +1,96 @@ /* * Copyright (c) 2012 Boudewijn Rempt * * 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 OCIO_DISPLAY_FILTER_H #define OCIO_DISPLAY_FILTER_H #include "kritalutdocker_export.h" #include #include #include #include #include "kis_exposure_gamma_correction_interface.h" namespace OCIO = OCIO_NAMESPACE; enum OCIO_CHANNEL_SWIZZLE { LUMINANCE, RGBA, R, G, B, A }; class KRITALUTDOCKER_EXPORT OcioDisplayFilter : public KisDisplayFilter { Q_OBJECT public: explicit OcioDisplayFilter(KisExposureGammaCorrectionInterface *interface, QObject *parent = 0); ~OcioDisplayFilter(); void filter(quint8 *pixels, quint32 numPixels); void approximateInverseTransformation(quint8 *pixels, quint32 numPixels); void approximateForwardTransformation(quint8 *pixels, quint32 numPixels); bool useInternalColorManagement() const; bool lockCurrentColorVisualRepresentation() const; void setLockCurrentColorVisualRepresentation(bool value); void updateShader(); + template + void updateShaderImpl(F *f); KisExposureGammaCorrectionInterface *correctionInterface() const; virtual QString program() const; GLuint lutTexture() const; void updateProcessor(); OCIO::ConstConfigRcPtr config; const char *inputColorSpaceName; const char *displayDevice; const char *view; const char *look; OCIO_CHANNEL_SWIZZLE swizzle; float exposure; float gamma; float blackPoint; float whitePoint; bool forceInternalColorManagement; private: OCIO::ConstProcessorRcPtr m_processor; OCIO::ConstProcessorRcPtr m_revereseApproximationProcessor; OCIO::ConstProcessorRcPtr m_forwardApproximationProcessor; KisExposureGammaCorrectionInterface *m_interface; bool m_lockCurrentColorVisualRepresentation; QString m_program; GLuint m_lut3dTexID; QVector m_lut3d; QString m_lut3dcacheid; QString m_shadercacheid; bool m_shaderDirty; }; #endif // OCIO_DISPLAY_FILTER_H