1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci* Copyright 2016 Google Inc. 3cb93a386Sopenharmony_ci* 4cb93a386Sopenharmony_ci* Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci* found in the LICENSE file. 6cb93a386Sopenharmony_ci*/ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "tools/viewer/Viewer.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 11cb93a386Sopenharmony_ci#include "include/core/SkData.h" 12cb93a386Sopenharmony_ci#include "include/core/SkGraphics.h" 13cb93a386Sopenharmony_ci#include "include/core/SkPictureRecorder.h" 14cb93a386Sopenharmony_ci#include "include/core/SkStream.h" 15cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 16cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 17cb93a386Sopenharmony_ci#include "include/private/SkTPin.h" 18cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 19cb93a386Sopenharmony_ci#include "include/utils/SkPaintFilterCanvas.h" 20cb93a386Sopenharmony_ci#include "src/core/SkColorSpacePriv.h" 21cb93a386Sopenharmony_ci#include "src/core/SkImagePriv.h" 22cb93a386Sopenharmony_ci#include "src/core/SkMD5.h" 23cb93a386Sopenharmony_ci#include "src/core/SkOSFile.h" 24cb93a386Sopenharmony_ci#include "src/core/SkReadBuffer.h" 25cb93a386Sopenharmony_ci#include "src/core/SkScan.h" 26cb93a386Sopenharmony_ci#include "src/core/SkSurfacePriv.h" 27cb93a386Sopenharmony_ci#include "src/core/SkTSort.h" 28cb93a386Sopenharmony_ci#include "src/core/SkTaskGroup.h" 29cb93a386Sopenharmony_ci#include "src/core/SkTextBlobPriv.h" 30cb93a386Sopenharmony_ci#include "src/core/SkVMBlitter.h" 31cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 32cb93a386Sopenharmony_ci#include "src/gpu/GrGpu.h" 33cb93a386Sopenharmony_ci#include "src/gpu/GrPersistentCacheUtils.h" 34cb93a386Sopenharmony_ci#include "src/gpu/GrShaderUtils.h" 35cb93a386Sopenharmony_ci#include "src/image/SkImage_Base.h" 36cb93a386Sopenharmony_ci#include "src/sksl/SkSLCompiler.h" 37cb93a386Sopenharmony_ci#include "src/utils/SkJSONWriter.h" 38cb93a386Sopenharmony_ci#include "src/utils/SkOSPath.h" 39cb93a386Sopenharmony_ci#include "tools/Resources.h" 40cb93a386Sopenharmony_ci#include "tools/RuntimeBlendUtils.h" 41cb93a386Sopenharmony_ci#include "tools/ToolUtils.h" 42cb93a386Sopenharmony_ci#include "tools/flags/CommandLineFlags.h" 43cb93a386Sopenharmony_ci#include "tools/flags/CommonFlags.h" 44cb93a386Sopenharmony_ci#include "tools/trace/EventTracingPriv.h" 45cb93a386Sopenharmony_ci#include "tools/viewer/BisectSlide.h" 46cb93a386Sopenharmony_ci#include "tools/viewer/GMSlide.h" 47cb93a386Sopenharmony_ci#include "tools/viewer/ImageSlide.h" 48cb93a386Sopenharmony_ci#include "tools/viewer/MSKPSlide.h" 49cb93a386Sopenharmony_ci#include "tools/viewer/ParticlesSlide.h" 50cb93a386Sopenharmony_ci#include "tools/viewer/SKPSlide.h" 51cb93a386Sopenharmony_ci#include "tools/viewer/SampleSlide.h" 52cb93a386Sopenharmony_ci#include "tools/viewer/SkSLSlide.h" 53cb93a386Sopenharmony_ci#include "tools/viewer/SlideDir.h" 54cb93a386Sopenharmony_ci#include "tools/viewer/SvgSlide.h" 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ci#if SK_GPU_V1 57cb93a386Sopenharmony_ci#include "src/gpu/ops/AtlasPathRenderer.h" 58cb93a386Sopenharmony_ci#include "src/gpu/ops/TessellationPathRenderer.h" 59cb93a386Sopenharmony_ci#endif 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci#include <cstdlib> 62cb93a386Sopenharmony_ci#include <map> 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_ci#include "imgui.h" 65cb93a386Sopenharmony_ci#include "misc/cpp/imgui_stdlib.h" // For ImGui support of std::string 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_ci#ifdef SK_VULKAN 68cb93a386Sopenharmony_ci#include "spirv-tools/libspirv.hpp" 69cb93a386Sopenharmony_ci#endif 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ci#if defined(SK_ENABLE_SKOTTIE) 72cb93a386Sopenharmony_ci #include "tools/viewer/SkottieSlide.h" 73cb93a386Sopenharmony_ci#endif 74cb93a386Sopenharmony_ci#if defined(SK_ENABLE_SKRIVE) 75cb93a386Sopenharmony_ci #include "tools/viewer/SkRiveSlide.h" 76cb93a386Sopenharmony_ci#endif 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_ciclass CapturingShaderErrorHandler : public GrContextOptions::ShaderErrorHandler { 79cb93a386Sopenharmony_cipublic: 80cb93a386Sopenharmony_ci void compileError(const char* shader, const char* errors) override { 81cb93a386Sopenharmony_ci fShaders.push_back(SkString(shader)); 82cb93a386Sopenharmony_ci fErrors.push_back(SkString(errors)); 83cb93a386Sopenharmony_ci } 84cb93a386Sopenharmony_ci 85cb93a386Sopenharmony_ci void reset() { 86cb93a386Sopenharmony_ci fShaders.reset(); 87cb93a386Sopenharmony_ci fErrors.reset(); 88cb93a386Sopenharmony_ci } 89cb93a386Sopenharmony_ci 90cb93a386Sopenharmony_ci SkTArray<SkString> fShaders; 91cb93a386Sopenharmony_ci SkTArray<SkString> fErrors; 92cb93a386Sopenharmony_ci}; 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_cistatic CapturingShaderErrorHandler gShaderErrorHandler; 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ciGrContextOptions::ShaderErrorHandler* Viewer::ShaderErrorHandler() { return &gShaderErrorHandler; } 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_ciusing namespace sk_app; 99cb93a386Sopenharmony_ciusing SkSL::Compiler; 100cb93a386Sopenharmony_ciusing OverrideFlag = SkSL::Compiler::OverrideFlag; 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_cistatic std::map<GpuPathRenderers, std::string> gPathRendererNames; 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ciApplication* Application::Create(int argc, char** argv, void* platformData) { 105cb93a386Sopenharmony_ci return new Viewer(argc, argv, platformData); 106cb93a386Sopenharmony_ci} 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_cistatic DEFINE_string(slide, "", "Start on this sample."); 109cb93a386Sopenharmony_cistatic DEFINE_bool(list, false, "List samples?"); 110cb93a386Sopenharmony_ci 111cb93a386Sopenharmony_ci#ifdef SK_GL 112cb93a386Sopenharmony_ci#define GL_BACKEND_STR ", \"gl\"" 113cb93a386Sopenharmony_ci#else 114cb93a386Sopenharmony_ci#define GL_BACKEND_STR 115cb93a386Sopenharmony_ci#endif 116cb93a386Sopenharmony_ci#ifdef SK_VULKAN 117cb93a386Sopenharmony_ci#define VK_BACKEND_STR ", \"vk\"" 118cb93a386Sopenharmony_ci#else 119cb93a386Sopenharmony_ci#define VK_BACKEND_STR 120cb93a386Sopenharmony_ci#endif 121cb93a386Sopenharmony_ci#ifdef SK_METAL 122cb93a386Sopenharmony_ci#define MTL_BACKEND_STR ", \"mtl\"" 123cb93a386Sopenharmony_ci#else 124cb93a386Sopenharmony_ci#define MTL_BACKEND_STR 125cb93a386Sopenharmony_ci#endif 126cb93a386Sopenharmony_ci#ifdef SK_DIRECT3D 127cb93a386Sopenharmony_ci#define D3D_BACKEND_STR ", \"d3d\"" 128cb93a386Sopenharmony_ci#else 129cb93a386Sopenharmony_ci#define D3D_BACKEND_STR 130cb93a386Sopenharmony_ci#endif 131cb93a386Sopenharmony_ci#ifdef SK_DAWN 132cb93a386Sopenharmony_ci#define DAWN_BACKEND_STR ", \"dawn\"" 133cb93a386Sopenharmony_ci#else 134cb93a386Sopenharmony_ci#define DAWN_BACKEND_STR 135cb93a386Sopenharmony_ci#endif 136cb93a386Sopenharmony_ci#define BACKENDS_STR_EVALUATOR(sw, gl, vk, mtl, d3d, dawn) sw gl vk mtl d3d dawn 137cb93a386Sopenharmony_ci#define BACKENDS_STR BACKENDS_STR_EVALUATOR( \ 138cb93a386Sopenharmony_ci "\"sw\"", GL_BACKEND_STR, VK_BACKEND_STR, MTL_BACKEND_STR, D3D_BACKEND_STR, DAWN_BACKEND_STR) 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_cistatic DEFINE_string2(backend, b, "sw", "Backend to use. Allowed values are " BACKENDS_STR "."); 141cb93a386Sopenharmony_ci 142cb93a386Sopenharmony_cistatic DEFINE_int(msaa, 1, "Number of subpixel samples. 0 for no HW antialiasing."); 143cb93a386Sopenharmony_cistatic DEFINE_bool(dmsaa, false, "Use internal MSAA to render to non-MSAA surfaces?"); 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_cistatic DEFINE_string(bisect, "", "Path to a .skp or .svg file to bisect."); 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_cistatic DEFINE_string2(file, f, "", "Open a single file for viewing."); 148cb93a386Sopenharmony_ci 149cb93a386Sopenharmony_cistatic DEFINE_string2(match, m, nullptr, 150cb93a386Sopenharmony_ci "[~][^]substring[$] [...] of name to run.\n" 151cb93a386Sopenharmony_ci "Multiple matches may be separated by spaces.\n" 152cb93a386Sopenharmony_ci "~ causes a matching name to always be skipped\n" 153cb93a386Sopenharmony_ci "^ requires the start of the name to match\n" 154cb93a386Sopenharmony_ci "$ requires the end of the name to match\n" 155cb93a386Sopenharmony_ci "^ and $ requires an exact match\n" 156cb93a386Sopenharmony_ci "If a name does not match any list entry,\n" 157cb93a386Sopenharmony_ci "it is skipped unless some list entry starts with ~"); 158cb93a386Sopenharmony_ci 159cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_ANDROID) 160cb93a386Sopenharmony_ci# define PATH_PREFIX "/data/local/tmp/" 161cb93a386Sopenharmony_ci#else 162cb93a386Sopenharmony_ci# define PATH_PREFIX "" 163cb93a386Sopenharmony_ci#endif 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_cistatic DEFINE_string(jpgs , PATH_PREFIX "jpgs" , "Directory to read jpgs from."); 166cb93a386Sopenharmony_cistatic DEFINE_string(skps , PATH_PREFIX "skps" , "Directory to read skps from."); 167cb93a386Sopenharmony_cistatic DEFINE_string(mskps , PATH_PREFIX "mskps" , "Directory to read mskps from."); 168cb93a386Sopenharmony_cistatic DEFINE_string(lotties, PATH_PREFIX "lotties", "Directory to read (Bodymovin) jsons from."); 169cb93a386Sopenharmony_cistatic DEFINE_string(rives , PATH_PREFIX "rives" , "Directory to read Rive (Flare) files from."); 170cb93a386Sopenharmony_ci#undef PATH_PREFIX 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_cistatic DEFINE_string(svgs, "", "Directory to read SVGs from, or a single SVG file."); 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_cistatic DEFINE_int_2(threads, j, -1, 175cb93a386Sopenharmony_ci "Run threadsafe tests on a threadpool with this many extra threads, " 176cb93a386Sopenharmony_ci "defaulting to one extra thread per core."); 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_cistatic DEFINE_bool(redraw, false, "Toggle continuous redraw."); 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_cistatic DEFINE_bool(offscreen, false, "Force rendering to an offscreen surface."); 181cb93a386Sopenharmony_cistatic DEFINE_bool(skvm, false, "Force skvm blitters for raster."); 182cb93a386Sopenharmony_cistatic DEFINE_bool(jit, true, "JIT SkVM?"); 183cb93a386Sopenharmony_cistatic DEFINE_bool(dylib, false, "JIT via dylib (much slower compile but easier to debug/profile)"); 184cb93a386Sopenharmony_cistatic DEFINE_bool(stats, false, "Display stats overlay on startup."); 185cb93a386Sopenharmony_cistatic DEFINE_bool(binaryarchive, false, "Enable MTLBinaryArchive use (if available)."); 186cb93a386Sopenharmony_ci 187cb93a386Sopenharmony_ci#ifndef SK_GL 188cb93a386Sopenharmony_cistatic_assert(false, "viewer requires GL backend for raster.") 189cb93a386Sopenharmony_ci#endif 190cb93a386Sopenharmony_ci 191cb93a386Sopenharmony_ciconst char* kBackendTypeStrings[sk_app::Window::kBackendTypeCount] = { 192cb93a386Sopenharmony_ci "OpenGL", 193cb93a386Sopenharmony_ci#if SK_ANGLE && defined(SK_BUILD_FOR_WIN) 194cb93a386Sopenharmony_ci "ANGLE", 195cb93a386Sopenharmony_ci#endif 196cb93a386Sopenharmony_ci#ifdef SK_DAWN 197cb93a386Sopenharmony_ci "Dawn", 198cb93a386Sopenharmony_ci#endif 199cb93a386Sopenharmony_ci#ifdef SK_VULKAN 200cb93a386Sopenharmony_ci "Vulkan", 201cb93a386Sopenharmony_ci#endif 202cb93a386Sopenharmony_ci#ifdef SK_METAL 203cb93a386Sopenharmony_ci "Metal", 204cb93a386Sopenharmony_ci#ifdef SK_GRAPHITE_ENABLED 205cb93a386Sopenharmony_ci "Metal (Graphite)", 206cb93a386Sopenharmony_ci#endif 207cb93a386Sopenharmony_ci#endif 208cb93a386Sopenharmony_ci#ifdef SK_DIRECT3D 209cb93a386Sopenharmony_ci "Direct3D", 210cb93a386Sopenharmony_ci#endif 211cb93a386Sopenharmony_ci "Raster" 212cb93a386Sopenharmony_ci}; 213cb93a386Sopenharmony_ci 214cb93a386Sopenharmony_cistatic sk_app::Window::BackendType get_backend_type(const char* str) { 215cb93a386Sopenharmony_ci#ifdef SK_DAWN 216cb93a386Sopenharmony_ci if (0 == strcmp(str, "dawn")) { 217cb93a386Sopenharmony_ci return sk_app::Window::kDawn_BackendType; 218cb93a386Sopenharmony_ci } else 219cb93a386Sopenharmony_ci#endif 220cb93a386Sopenharmony_ci#ifdef SK_VULKAN 221cb93a386Sopenharmony_ci if (0 == strcmp(str, "vk")) { 222cb93a386Sopenharmony_ci return sk_app::Window::kVulkan_BackendType; 223cb93a386Sopenharmony_ci } else 224cb93a386Sopenharmony_ci#endif 225cb93a386Sopenharmony_ci#if SK_ANGLE && defined(SK_BUILD_FOR_WIN) 226cb93a386Sopenharmony_ci if (0 == strcmp(str, "angle")) { 227cb93a386Sopenharmony_ci return sk_app::Window::kANGLE_BackendType; 228cb93a386Sopenharmony_ci } else 229cb93a386Sopenharmony_ci#endif 230cb93a386Sopenharmony_ci#ifdef SK_METAL 231cb93a386Sopenharmony_ci if (0 == strcmp(str, "mtl")) { 232cb93a386Sopenharmony_ci return sk_app::Window::kMetal_BackendType; 233cb93a386Sopenharmony_ci } else 234cb93a386Sopenharmony_ci#ifdef SK_GRAPHITE_ENABLED 235cb93a386Sopenharmony_ci if (0 == strcmp(str, "grmtl")) { 236cb93a386Sopenharmony_ci return sk_app::Window::kGraphiteMetal_BackendType; 237cb93a386Sopenharmony_ci } else 238cb93a386Sopenharmony_ci#endif 239cb93a386Sopenharmony_ci#endif 240cb93a386Sopenharmony_ci#ifdef SK_DIRECT3D 241cb93a386Sopenharmony_ci if (0 == strcmp(str, "d3d")) { 242cb93a386Sopenharmony_ci return sk_app::Window::kDirect3D_BackendType; 243cb93a386Sopenharmony_ci } else 244cb93a386Sopenharmony_ci#endif 245cb93a386Sopenharmony_ci 246cb93a386Sopenharmony_ci if (0 == strcmp(str, "gl")) { 247cb93a386Sopenharmony_ci return sk_app::Window::kNativeGL_BackendType; 248cb93a386Sopenharmony_ci } else if (0 == strcmp(str, "sw")) { 249cb93a386Sopenharmony_ci return sk_app::Window::kRaster_BackendType; 250cb93a386Sopenharmony_ci } else { 251cb93a386Sopenharmony_ci SkDebugf("Unknown backend type, %s, defaulting to sw.", str); 252cb93a386Sopenharmony_ci return sk_app::Window::kRaster_BackendType; 253cb93a386Sopenharmony_ci } 254cb93a386Sopenharmony_ci} 255cb93a386Sopenharmony_ci 256cb93a386Sopenharmony_cistatic SkColorSpacePrimaries gSrgbPrimaries = { 257cb93a386Sopenharmony_ci 0.64f, 0.33f, 258cb93a386Sopenharmony_ci 0.30f, 0.60f, 259cb93a386Sopenharmony_ci 0.15f, 0.06f, 260cb93a386Sopenharmony_ci 0.3127f, 0.3290f }; 261cb93a386Sopenharmony_ci 262cb93a386Sopenharmony_cistatic SkColorSpacePrimaries gAdobePrimaries = { 263cb93a386Sopenharmony_ci 0.64f, 0.33f, 264cb93a386Sopenharmony_ci 0.21f, 0.71f, 265cb93a386Sopenharmony_ci 0.15f, 0.06f, 266cb93a386Sopenharmony_ci 0.3127f, 0.3290f }; 267cb93a386Sopenharmony_ci 268cb93a386Sopenharmony_cistatic SkColorSpacePrimaries gP3Primaries = { 269cb93a386Sopenharmony_ci 0.680f, 0.320f, 270cb93a386Sopenharmony_ci 0.265f, 0.690f, 271cb93a386Sopenharmony_ci 0.150f, 0.060f, 272cb93a386Sopenharmony_ci 0.3127f, 0.3290f }; 273cb93a386Sopenharmony_ci 274cb93a386Sopenharmony_cistatic SkColorSpacePrimaries gRec2020Primaries = { 275cb93a386Sopenharmony_ci 0.708f, 0.292f, 276cb93a386Sopenharmony_ci 0.170f, 0.797f, 277cb93a386Sopenharmony_ci 0.131f, 0.046f, 278cb93a386Sopenharmony_ci 0.3127f, 0.3290f }; 279cb93a386Sopenharmony_ci 280cb93a386Sopenharmony_cistruct NamedPrimaries { 281cb93a386Sopenharmony_ci const char* fName; 282cb93a386Sopenharmony_ci SkColorSpacePrimaries* fPrimaries; 283cb93a386Sopenharmony_ci} gNamedPrimaries[] = { 284cb93a386Sopenharmony_ci { "sRGB", &gSrgbPrimaries }, 285cb93a386Sopenharmony_ci { "AdobeRGB", &gAdobePrimaries }, 286cb93a386Sopenharmony_ci { "P3", &gP3Primaries }, 287cb93a386Sopenharmony_ci { "Rec. 2020", &gRec2020Primaries }, 288cb93a386Sopenharmony_ci}; 289cb93a386Sopenharmony_ci 290cb93a386Sopenharmony_cistatic bool primaries_equal(const SkColorSpacePrimaries& a, const SkColorSpacePrimaries& b) { 291cb93a386Sopenharmony_ci return memcmp(&a, &b, sizeof(SkColorSpacePrimaries)) == 0; 292cb93a386Sopenharmony_ci} 293cb93a386Sopenharmony_ci 294cb93a386Sopenharmony_cistatic Window::BackendType backend_type_for_window(Window::BackendType backendType) { 295cb93a386Sopenharmony_ci // In raster mode, we still use GL for the window. 296cb93a386Sopenharmony_ci // This lets us render the GUI faster (and correct). 297cb93a386Sopenharmony_ci return Window::kRaster_BackendType == backendType ? Window::kNativeGL_BackendType : backendType; 298cb93a386Sopenharmony_ci} 299cb93a386Sopenharmony_ci 300cb93a386Sopenharmony_ciclass NullSlide : public Slide { 301cb93a386Sopenharmony_ci SkISize getDimensions() const override { 302cb93a386Sopenharmony_ci return SkISize::Make(640, 480); 303cb93a386Sopenharmony_ci } 304cb93a386Sopenharmony_ci 305cb93a386Sopenharmony_ci void draw(SkCanvas* canvas) override { 306cb93a386Sopenharmony_ci canvas->clear(0xffff11ff); 307cb93a386Sopenharmony_ci } 308cb93a386Sopenharmony_ci}; 309cb93a386Sopenharmony_ci 310cb93a386Sopenharmony_cistatic const char kName[] = "name"; 311cb93a386Sopenharmony_cistatic const char kValue[] = "value"; 312cb93a386Sopenharmony_cistatic const char kOptions[] = "options"; 313cb93a386Sopenharmony_cistatic const char kSlideStateName[] = "Slide"; 314cb93a386Sopenharmony_cistatic const char kBackendStateName[] = "Backend"; 315cb93a386Sopenharmony_cistatic const char kMSAAStateName[] = "MSAA"; 316cb93a386Sopenharmony_cistatic const char kPathRendererStateName[] = "Path renderer"; 317cb93a386Sopenharmony_cistatic const char kSoftkeyStateName[] = "Softkey"; 318cb93a386Sopenharmony_cistatic const char kSoftkeyHint[] = "Please select a softkey"; 319cb93a386Sopenharmony_cistatic const char kON[] = "ON"; 320cb93a386Sopenharmony_cistatic const char kRefreshStateName[] = "Refresh"; 321cb93a386Sopenharmony_ci 322cb93a386Sopenharmony_ciextern bool gUseSkVMBlitter; 323cb93a386Sopenharmony_ciextern bool gSkVMAllowJIT; 324cb93a386Sopenharmony_ciextern bool gSkVMJITViaDylib; 325cb93a386Sopenharmony_ci 326cb93a386Sopenharmony_ciViewer::Viewer(int argc, char** argv, void* platformData) 327cb93a386Sopenharmony_ci : fCurrentSlide(-1) 328cb93a386Sopenharmony_ci , fRefresh(false) 329cb93a386Sopenharmony_ci , fSaveToSKP(false) 330cb93a386Sopenharmony_ci , fShowSlideDimensions(false) 331cb93a386Sopenharmony_ci , fShowImGuiDebugWindow(false) 332cb93a386Sopenharmony_ci , fShowSlidePicker(false) 333cb93a386Sopenharmony_ci , fShowImGuiTestWindow(false) 334cb93a386Sopenharmony_ci , fShowZoomWindow(false) 335cb93a386Sopenharmony_ci , fZoomWindowFixed(false) 336cb93a386Sopenharmony_ci , fZoomWindowLocation{0.0f, 0.0f} 337cb93a386Sopenharmony_ci , fLastImage(nullptr) 338cb93a386Sopenharmony_ci , fZoomUI(false) 339cb93a386Sopenharmony_ci , fBackendType(sk_app::Window::kNativeGL_BackendType) 340cb93a386Sopenharmony_ci , fColorMode(ColorMode::kLegacy) 341cb93a386Sopenharmony_ci , fColorSpacePrimaries(gSrgbPrimaries) 342cb93a386Sopenharmony_ci // Our UI can only tweak gamma (currently), so start out gamma-only 343cb93a386Sopenharmony_ci , fColorSpaceTransferFn(SkNamedTransferFn::k2Dot2) 344cb93a386Sopenharmony_ci , fApplyBackingScale(true) 345cb93a386Sopenharmony_ci , fZoomLevel(0.0f) 346cb93a386Sopenharmony_ci , fRotation(0.0f) 347cb93a386Sopenharmony_ci , fOffset{0.5f, 0.5f} 348cb93a386Sopenharmony_ci , fGestureDevice(GestureDevice::kNone) 349cb93a386Sopenharmony_ci , fTiled(false) 350cb93a386Sopenharmony_ci , fDrawTileBoundaries(false) 351cb93a386Sopenharmony_ci , fTileScale{0.25f, 0.25f} 352cb93a386Sopenharmony_ci , fPerspectiveMode(kPerspective_Off) 353cb93a386Sopenharmony_ci{ 354cb93a386Sopenharmony_ci SkGraphics::Init(); 355cb93a386Sopenharmony_ci 356cb93a386Sopenharmony_ci gPathRendererNames[GpuPathRenderers::kDefault] = "Default Path Renderers"; 357cb93a386Sopenharmony_ci gPathRendererNames[GpuPathRenderers::kAtlas] = "Atlas (tessellation)"; 358cb93a386Sopenharmony_ci gPathRendererNames[GpuPathRenderers::kTessellation] = "Tessellation"; 359cb93a386Sopenharmony_ci gPathRendererNames[GpuPathRenderers::kSmall] = "Small paths (cached sdf or alpha masks)"; 360cb93a386Sopenharmony_ci gPathRendererNames[GpuPathRenderers::kTriangulating] = "Triangulating"; 361cb93a386Sopenharmony_ci gPathRendererNames[GpuPathRenderers::kNone] = "Software masks"; 362cb93a386Sopenharmony_ci 363cb93a386Sopenharmony_ci SkDebugf("Command line arguments: "); 364cb93a386Sopenharmony_ci for (int i = 1; i < argc; ++i) { 365cb93a386Sopenharmony_ci SkDebugf("%s ", argv[i]); 366cb93a386Sopenharmony_ci } 367cb93a386Sopenharmony_ci SkDebugf("\n"); 368cb93a386Sopenharmony_ci 369cb93a386Sopenharmony_ci CommandLineFlags::Parse(argc, argv); 370cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_ANDROID 371cb93a386Sopenharmony_ci SetResourcePath("/data/local/tmp/resources"); 372cb93a386Sopenharmony_ci#endif 373cb93a386Sopenharmony_ci 374cb93a386Sopenharmony_ci gUseSkVMBlitter = FLAGS_skvm; 375cb93a386Sopenharmony_ci gSkVMAllowJIT = FLAGS_jit; 376cb93a386Sopenharmony_ci gSkVMJITViaDylib = FLAGS_dylib; 377cb93a386Sopenharmony_ci 378cb93a386Sopenharmony_ci CommonFlags::SetDefaultFontMgr(); 379cb93a386Sopenharmony_ci 380cb93a386Sopenharmony_ci initializeEventTracingForTools(); 381cb93a386Sopenharmony_ci static SkTaskGroup::Enabler kTaskGroupEnabler(FLAGS_threads); 382cb93a386Sopenharmony_ci 383cb93a386Sopenharmony_ci fBackendType = get_backend_type(FLAGS_backend[0]); 384cb93a386Sopenharmony_ci fWindow = Window::CreateNativeWindow(platformData); 385cb93a386Sopenharmony_ci 386cb93a386Sopenharmony_ci DisplayParams displayParams; 387cb93a386Sopenharmony_ci displayParams.fMSAASampleCount = FLAGS_msaa; 388cb93a386Sopenharmony_ci displayParams.fEnableBinaryArchive = FLAGS_binaryarchive; 389cb93a386Sopenharmony_ci CommonFlags::SetCtxOptions(&displayParams.fGrContextOptions); 390cb93a386Sopenharmony_ci displayParams.fGrContextOptions.fPersistentCache = &fPersistentCache; 391cb93a386Sopenharmony_ci displayParams.fGrContextOptions.fShaderCacheStrategy = 392cb93a386Sopenharmony_ci GrContextOptions::ShaderCacheStrategy::kSkSL; 393cb93a386Sopenharmony_ci displayParams.fGrContextOptions.fShaderErrorHandler = &gShaderErrorHandler; 394cb93a386Sopenharmony_ci displayParams.fGrContextOptions.fSuppressPrints = true; 395cb93a386Sopenharmony_ci if (FLAGS_dmsaa) { 396cb93a386Sopenharmony_ci displayParams.fSurfaceProps = SkSurfaceProps( 397cb93a386Sopenharmony_ci displayParams.fSurfaceProps.flags() | SkSurfaceProps::kDynamicMSAA_Flag, 398cb93a386Sopenharmony_ci displayParams.fSurfaceProps.pixelGeometry()); 399cb93a386Sopenharmony_ci } 400cb93a386Sopenharmony_ci fWindow->setRequestedDisplayParams(displayParams); 401cb93a386Sopenharmony_ci fDisplay = fWindow->getRequestedDisplayParams(); 402cb93a386Sopenharmony_ci fRefresh = FLAGS_redraw; 403cb93a386Sopenharmony_ci 404cb93a386Sopenharmony_ci fImGuiLayer.setScaleFactor(fWindow->scaleFactor()); 405cb93a386Sopenharmony_ci fStatsLayer.setDisplayScale((fZoomUI ? 2.0f : 1.0f) * fWindow->scaleFactor()); 406cb93a386Sopenharmony_ci 407cb93a386Sopenharmony_ci // Configure timers 408cb93a386Sopenharmony_ci fStatsLayer.setActive(FLAGS_stats); 409cb93a386Sopenharmony_ci fAnimateTimer = fStatsLayer.addTimer("Animate", SK_ColorMAGENTA, 0xffff66ff); 410cb93a386Sopenharmony_ci fPaintTimer = fStatsLayer.addTimer("Paint", SK_ColorGREEN); 411cb93a386Sopenharmony_ci fFlushTimer = fStatsLayer.addTimer("Flush", SK_ColorRED, 0xffff6666); 412cb93a386Sopenharmony_ci 413cb93a386Sopenharmony_ci // register callbacks 414cb93a386Sopenharmony_ci fCommands.attach(fWindow); 415cb93a386Sopenharmony_ci fWindow->pushLayer(this); 416cb93a386Sopenharmony_ci fWindow->pushLayer(&fStatsLayer); 417cb93a386Sopenharmony_ci fWindow->pushLayer(&fImGuiLayer); 418cb93a386Sopenharmony_ci 419cb93a386Sopenharmony_ci // add key-bindings 420cb93a386Sopenharmony_ci fCommands.addCommand(' ', "GUI", "Toggle Debug GUI", [this]() { 421cb93a386Sopenharmony_ci this->fShowImGuiDebugWindow = !this->fShowImGuiDebugWindow; 422cb93a386Sopenharmony_ci fWindow->inval(); 423cb93a386Sopenharmony_ci }); 424cb93a386Sopenharmony_ci // Command to jump directly to the slide picker and give it focus 425cb93a386Sopenharmony_ci fCommands.addCommand('/', "GUI", "Jump to slide picker", [this]() { 426cb93a386Sopenharmony_ci this->fShowImGuiDebugWindow = true; 427cb93a386Sopenharmony_ci this->fShowSlidePicker = true; 428cb93a386Sopenharmony_ci fWindow->inval(); 429cb93a386Sopenharmony_ci }); 430cb93a386Sopenharmony_ci // Alias that to Backspace, to match SampleApp 431cb93a386Sopenharmony_ci fCommands.addCommand(skui::Key::kBack, "Backspace", "GUI", "Jump to slide picker", [this]() { 432cb93a386Sopenharmony_ci this->fShowImGuiDebugWindow = true; 433cb93a386Sopenharmony_ci this->fShowSlidePicker = true; 434cb93a386Sopenharmony_ci fWindow->inval(); 435cb93a386Sopenharmony_ci }); 436cb93a386Sopenharmony_ci fCommands.addCommand('g', "GUI", "Toggle GUI Demo", [this]() { 437cb93a386Sopenharmony_ci this->fShowImGuiTestWindow = !this->fShowImGuiTestWindow; 438cb93a386Sopenharmony_ci fWindow->inval(); 439cb93a386Sopenharmony_ci }); 440cb93a386Sopenharmony_ci fCommands.addCommand('z', "GUI", "Toggle zoom window", [this]() { 441cb93a386Sopenharmony_ci this->fShowZoomWindow = !this->fShowZoomWindow; 442cb93a386Sopenharmony_ci fWindow->inval(); 443cb93a386Sopenharmony_ci }); 444cb93a386Sopenharmony_ci fCommands.addCommand('Z', "GUI", "Toggle zoom window state", [this]() { 445cb93a386Sopenharmony_ci this->fZoomWindowFixed = !this->fZoomWindowFixed; 446cb93a386Sopenharmony_ci fWindow->inval(); 447cb93a386Sopenharmony_ci }); 448cb93a386Sopenharmony_ci fCommands.addCommand('v', "Swapchain", "Toggle vsync on/off", [this]() { 449cb93a386Sopenharmony_ci DisplayParams params = fWindow->getRequestedDisplayParams(); 450cb93a386Sopenharmony_ci params.fDisableVsync = !params.fDisableVsync; 451cb93a386Sopenharmony_ci fWindow->setRequestedDisplayParams(params); 452cb93a386Sopenharmony_ci this->updateTitle(); 453cb93a386Sopenharmony_ci fWindow->inval(); 454cb93a386Sopenharmony_ci }); 455cb93a386Sopenharmony_ci fCommands.addCommand('V', "Swapchain", "Toggle delayed acquire on/off (Metal only)", [this]() { 456cb93a386Sopenharmony_ci DisplayParams params = fWindow->getRequestedDisplayParams(); 457cb93a386Sopenharmony_ci params.fDelayDrawableAcquisition = !params.fDelayDrawableAcquisition; 458cb93a386Sopenharmony_ci fWindow->setRequestedDisplayParams(params); 459cb93a386Sopenharmony_ci this->updateTitle(); 460cb93a386Sopenharmony_ci fWindow->inval(); 461cb93a386Sopenharmony_ci }); 462cb93a386Sopenharmony_ci fCommands.addCommand('r', "Redraw", "Toggle redraw", [this]() { 463cb93a386Sopenharmony_ci fRefresh = !fRefresh; 464cb93a386Sopenharmony_ci fWindow->inval(); 465cb93a386Sopenharmony_ci }); 466cb93a386Sopenharmony_ci fCommands.addCommand('s', "Overlays", "Toggle stats display", [this]() { 467cb93a386Sopenharmony_ci fStatsLayer.setActive(!fStatsLayer.getActive()); 468cb93a386Sopenharmony_ci fWindow->inval(); 469cb93a386Sopenharmony_ci }); 470cb93a386Sopenharmony_ci fCommands.addCommand('0', "Overlays", "Reset stats", [this]() { 471cb93a386Sopenharmony_ci fStatsLayer.resetMeasurements(); 472cb93a386Sopenharmony_ci this->updateTitle(); 473cb93a386Sopenharmony_ci fWindow->inval(); 474cb93a386Sopenharmony_ci }); 475cb93a386Sopenharmony_ci fCommands.addCommand('c', "Modes", "Cycle color mode", [this]() { 476cb93a386Sopenharmony_ci switch (fColorMode) { 477cb93a386Sopenharmony_ci case ColorMode::kLegacy: 478cb93a386Sopenharmony_ci this->setColorMode(ColorMode::kColorManaged8888); 479cb93a386Sopenharmony_ci break; 480cb93a386Sopenharmony_ci case ColorMode::kColorManaged8888: 481cb93a386Sopenharmony_ci this->setColorMode(ColorMode::kColorManagedF16); 482cb93a386Sopenharmony_ci break; 483cb93a386Sopenharmony_ci case ColorMode::kColorManagedF16: 484cb93a386Sopenharmony_ci this->setColorMode(ColorMode::kColorManagedF16Norm); 485cb93a386Sopenharmony_ci break; 486cb93a386Sopenharmony_ci case ColorMode::kColorManagedF16Norm: 487cb93a386Sopenharmony_ci this->setColorMode(ColorMode::kLegacy); 488cb93a386Sopenharmony_ci break; 489cb93a386Sopenharmony_ci } 490cb93a386Sopenharmony_ci }); 491cb93a386Sopenharmony_ci fCommands.addCommand('w', "Modes", "Toggle wireframe", [this]() { 492cb93a386Sopenharmony_ci DisplayParams params = fWindow->getRequestedDisplayParams(); 493cb93a386Sopenharmony_ci params.fGrContextOptions.fWireframeMode = !params.fGrContextOptions.fWireframeMode; 494cb93a386Sopenharmony_ci fWindow->setRequestedDisplayParams(params); 495cb93a386Sopenharmony_ci fWindow->inval(); 496cb93a386Sopenharmony_ci }); 497cb93a386Sopenharmony_ci fCommands.addCommand('w', "Modes", "Toggle reduced shaders", [this]() { 498cb93a386Sopenharmony_ci DisplayParams params = fWindow->getRequestedDisplayParams(); 499cb93a386Sopenharmony_ci params.fGrContextOptions.fReducedShaderVariations = 500cb93a386Sopenharmony_ci !params.fGrContextOptions.fReducedShaderVariations; 501cb93a386Sopenharmony_ci fWindow->setRequestedDisplayParams(params); 502cb93a386Sopenharmony_ci fWindow->inval(); 503cb93a386Sopenharmony_ci }); 504cb93a386Sopenharmony_ci fCommands.addCommand(skui::Key::kRight, "Right", "Navigation", "Next slide", [this]() { 505cb93a386Sopenharmony_ci this->setCurrentSlide(fCurrentSlide < fSlides.count() - 1 ? fCurrentSlide + 1 : 0); 506cb93a386Sopenharmony_ci }); 507cb93a386Sopenharmony_ci fCommands.addCommand(skui::Key::kLeft, "Left", "Navigation", "Previous slide", [this]() { 508cb93a386Sopenharmony_ci this->setCurrentSlide(fCurrentSlide > 0 ? fCurrentSlide - 1 : fSlides.count() - 1); 509cb93a386Sopenharmony_ci }); 510cb93a386Sopenharmony_ci fCommands.addCommand(skui::Key::kUp, "Up", "Transform", "Zoom in", [this]() { 511cb93a386Sopenharmony_ci this->changeZoomLevel(1.f / 32.f); 512cb93a386Sopenharmony_ci fWindow->inval(); 513cb93a386Sopenharmony_ci }); 514cb93a386Sopenharmony_ci fCommands.addCommand(skui::Key::kDown, "Down", "Transform", "Zoom out", [this]() { 515cb93a386Sopenharmony_ci this->changeZoomLevel(-1.f / 32.f); 516cb93a386Sopenharmony_ci fWindow->inval(); 517cb93a386Sopenharmony_ci }); 518cb93a386Sopenharmony_ci fCommands.addCommand('d', "Modes", "Change rendering backend", [this]() { 519cb93a386Sopenharmony_ci sk_app::Window::BackendType newBackend = (sk_app::Window::BackendType)( 520cb93a386Sopenharmony_ci (fBackendType + 1) % sk_app::Window::kBackendTypeCount); 521cb93a386Sopenharmony_ci // Switching to and from Vulkan is problematic on Linux so disabled for now 522cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_UNIX) && defined(SK_VULKAN) 523cb93a386Sopenharmony_ci if (newBackend == sk_app::Window::kVulkan_BackendType) { 524cb93a386Sopenharmony_ci newBackend = (sk_app::Window::BackendType)((newBackend + 1) % 525cb93a386Sopenharmony_ci sk_app::Window::kBackendTypeCount); 526cb93a386Sopenharmony_ci } else if (fBackendType == sk_app::Window::kVulkan_BackendType) { 527cb93a386Sopenharmony_ci newBackend = sk_app::Window::kVulkan_BackendType; 528cb93a386Sopenharmony_ci } 529cb93a386Sopenharmony_ci#endif 530cb93a386Sopenharmony_ci this->setBackend(newBackend); 531cb93a386Sopenharmony_ci }); 532cb93a386Sopenharmony_ci fCommands.addCommand('K', "IO", "Save slide to SKP", [this]() { 533cb93a386Sopenharmony_ci fSaveToSKP = true; 534cb93a386Sopenharmony_ci fWindow->inval(); 535cb93a386Sopenharmony_ci }); 536cb93a386Sopenharmony_ci fCommands.addCommand('&', "Overlays", "Show slide dimensios", [this]() { 537cb93a386Sopenharmony_ci fShowSlideDimensions = !fShowSlideDimensions; 538cb93a386Sopenharmony_ci fWindow->inval(); 539cb93a386Sopenharmony_ci }); 540cb93a386Sopenharmony_ci fCommands.addCommand('G', "Modes", "Geometry", [this]() { 541cb93a386Sopenharmony_ci DisplayParams params = fWindow->getRequestedDisplayParams(); 542cb93a386Sopenharmony_ci uint32_t flags = params.fSurfaceProps.flags(); 543cb93a386Sopenharmony_ci SkPixelGeometry defaultPixelGeometry = fDisplay.fSurfaceProps.pixelGeometry(); 544cb93a386Sopenharmony_ci if (!fDisplayOverrides.fSurfaceProps.fPixelGeometry) { 545cb93a386Sopenharmony_ci fDisplayOverrides.fSurfaceProps.fPixelGeometry = true; 546cb93a386Sopenharmony_ci params.fSurfaceProps = SkSurfaceProps(flags, kUnknown_SkPixelGeometry); 547cb93a386Sopenharmony_ci } else { 548cb93a386Sopenharmony_ci switch (params.fSurfaceProps.pixelGeometry()) { 549cb93a386Sopenharmony_ci case kUnknown_SkPixelGeometry: 550cb93a386Sopenharmony_ci params.fSurfaceProps = SkSurfaceProps(flags, kRGB_H_SkPixelGeometry); 551cb93a386Sopenharmony_ci break; 552cb93a386Sopenharmony_ci case kRGB_H_SkPixelGeometry: 553cb93a386Sopenharmony_ci params.fSurfaceProps = SkSurfaceProps(flags, kBGR_H_SkPixelGeometry); 554cb93a386Sopenharmony_ci break; 555cb93a386Sopenharmony_ci case kBGR_H_SkPixelGeometry: 556cb93a386Sopenharmony_ci params.fSurfaceProps = SkSurfaceProps(flags, kRGB_V_SkPixelGeometry); 557cb93a386Sopenharmony_ci break; 558cb93a386Sopenharmony_ci case kRGB_V_SkPixelGeometry: 559cb93a386Sopenharmony_ci params.fSurfaceProps = SkSurfaceProps(flags, kBGR_V_SkPixelGeometry); 560cb93a386Sopenharmony_ci break; 561cb93a386Sopenharmony_ci case kBGR_V_SkPixelGeometry: 562cb93a386Sopenharmony_ci params.fSurfaceProps = SkSurfaceProps(flags, defaultPixelGeometry); 563cb93a386Sopenharmony_ci fDisplayOverrides.fSurfaceProps.fPixelGeometry = false; 564cb93a386Sopenharmony_ci break; 565cb93a386Sopenharmony_ci } 566cb93a386Sopenharmony_ci } 567cb93a386Sopenharmony_ci fWindow->setRequestedDisplayParams(params); 568cb93a386Sopenharmony_ci this->updateTitle(); 569cb93a386Sopenharmony_ci fWindow->inval(); 570cb93a386Sopenharmony_ci }); 571cb93a386Sopenharmony_ci fCommands.addCommand('H', "Font", "Hinting mode", [this]() { 572cb93a386Sopenharmony_ci if (!fFontOverrides.fHinting) { 573cb93a386Sopenharmony_ci fFontOverrides.fHinting = true; 574cb93a386Sopenharmony_ci fFont.setHinting(SkFontHinting::kNone); 575cb93a386Sopenharmony_ci } else { 576cb93a386Sopenharmony_ci switch (fFont.getHinting()) { 577cb93a386Sopenharmony_ci case SkFontHinting::kNone: 578cb93a386Sopenharmony_ci fFont.setHinting(SkFontHinting::kSlight); 579cb93a386Sopenharmony_ci break; 580cb93a386Sopenharmony_ci case SkFontHinting::kSlight: 581cb93a386Sopenharmony_ci fFont.setHinting(SkFontHinting::kNormal); 582cb93a386Sopenharmony_ci break; 583cb93a386Sopenharmony_ci case SkFontHinting::kNormal: 584cb93a386Sopenharmony_ci fFont.setHinting(SkFontHinting::kFull); 585cb93a386Sopenharmony_ci break; 586cb93a386Sopenharmony_ci case SkFontHinting::kFull: 587cb93a386Sopenharmony_ci fFont.setHinting(SkFontHinting::kNone); 588cb93a386Sopenharmony_ci fFontOverrides.fHinting = false; 589cb93a386Sopenharmony_ci break; 590cb93a386Sopenharmony_ci } 591cb93a386Sopenharmony_ci } 592cb93a386Sopenharmony_ci this->updateTitle(); 593cb93a386Sopenharmony_ci fWindow->inval(); 594cb93a386Sopenharmony_ci }); 595cb93a386Sopenharmony_ci fCommands.addCommand('A', "Paint", "Antialias Mode", [this]() { 596cb93a386Sopenharmony_ci if (!fPaintOverrides.fAntiAlias) { 597cb93a386Sopenharmony_ci fPaintOverrides.fAntiAliasState = SkPaintFields::AntiAliasState::Alias; 598cb93a386Sopenharmony_ci fPaintOverrides.fAntiAlias = true; 599cb93a386Sopenharmony_ci fPaint.setAntiAlias(false); 600cb93a386Sopenharmony_ci gSkUseAnalyticAA = gSkForceAnalyticAA = false; 601cb93a386Sopenharmony_ci } else { 602cb93a386Sopenharmony_ci fPaint.setAntiAlias(true); 603cb93a386Sopenharmony_ci switch (fPaintOverrides.fAntiAliasState) { 604cb93a386Sopenharmony_ci case SkPaintFields::AntiAliasState::Alias: 605cb93a386Sopenharmony_ci fPaintOverrides.fAntiAliasState = SkPaintFields::AntiAliasState::Normal; 606cb93a386Sopenharmony_ci gSkUseAnalyticAA = gSkForceAnalyticAA = false; 607cb93a386Sopenharmony_ci break; 608cb93a386Sopenharmony_ci case SkPaintFields::AntiAliasState::Normal: 609cb93a386Sopenharmony_ci fPaintOverrides.fAntiAliasState = SkPaintFields::AntiAliasState::AnalyticAAEnabled; 610cb93a386Sopenharmony_ci gSkUseAnalyticAA = true; 611cb93a386Sopenharmony_ci gSkForceAnalyticAA = false; 612cb93a386Sopenharmony_ci break; 613cb93a386Sopenharmony_ci case SkPaintFields::AntiAliasState::AnalyticAAEnabled: 614cb93a386Sopenharmony_ci fPaintOverrides.fAntiAliasState = SkPaintFields::AntiAliasState::AnalyticAAForced; 615cb93a386Sopenharmony_ci gSkUseAnalyticAA = gSkForceAnalyticAA = true; 616cb93a386Sopenharmony_ci break; 617cb93a386Sopenharmony_ci case SkPaintFields::AntiAliasState::AnalyticAAForced: 618cb93a386Sopenharmony_ci fPaintOverrides.fAntiAliasState = SkPaintFields::AntiAliasState::Alias; 619cb93a386Sopenharmony_ci fPaintOverrides.fAntiAlias = false; 620cb93a386Sopenharmony_ci gSkUseAnalyticAA = fPaintOverrides.fOriginalSkUseAnalyticAA; 621cb93a386Sopenharmony_ci gSkForceAnalyticAA = fPaintOverrides.fOriginalSkForceAnalyticAA; 622cb93a386Sopenharmony_ci break; 623cb93a386Sopenharmony_ci } 624cb93a386Sopenharmony_ci } 625cb93a386Sopenharmony_ci this->updateTitle(); 626cb93a386Sopenharmony_ci fWindow->inval(); 627cb93a386Sopenharmony_ci }); 628cb93a386Sopenharmony_ci fCommands.addCommand('D', "Modes", "DFT", [this]() { 629cb93a386Sopenharmony_ci DisplayParams params = fWindow->getRequestedDisplayParams(); 630cb93a386Sopenharmony_ci uint32_t flags = params.fSurfaceProps.flags(); 631cb93a386Sopenharmony_ci flags ^= SkSurfaceProps::kUseDeviceIndependentFonts_Flag; 632cb93a386Sopenharmony_ci params.fSurfaceProps = SkSurfaceProps(flags, params.fSurfaceProps.pixelGeometry()); 633cb93a386Sopenharmony_ci fWindow->setRequestedDisplayParams(params); 634cb93a386Sopenharmony_ci this->updateTitle(); 635cb93a386Sopenharmony_ci fWindow->inval(); 636cb93a386Sopenharmony_ci }); 637cb93a386Sopenharmony_ci fCommands.addCommand('L', "Font", "Subpixel Antialias Mode", [this]() { 638cb93a386Sopenharmony_ci if (!fFontOverrides.fEdging) { 639cb93a386Sopenharmony_ci fFontOverrides.fEdging = true; 640cb93a386Sopenharmony_ci fFont.setEdging(SkFont::Edging::kAlias); 641cb93a386Sopenharmony_ci } else { 642cb93a386Sopenharmony_ci switch (fFont.getEdging()) { 643cb93a386Sopenharmony_ci case SkFont::Edging::kAlias: 644cb93a386Sopenharmony_ci fFont.setEdging(SkFont::Edging::kAntiAlias); 645cb93a386Sopenharmony_ci break; 646cb93a386Sopenharmony_ci case SkFont::Edging::kAntiAlias: 647cb93a386Sopenharmony_ci fFont.setEdging(SkFont::Edging::kSubpixelAntiAlias); 648cb93a386Sopenharmony_ci break; 649cb93a386Sopenharmony_ci case SkFont::Edging::kSubpixelAntiAlias: 650cb93a386Sopenharmony_ci fFont.setEdging(SkFont::Edging::kAlias); 651cb93a386Sopenharmony_ci fFontOverrides.fEdging = false; 652cb93a386Sopenharmony_ci break; 653cb93a386Sopenharmony_ci } 654cb93a386Sopenharmony_ci } 655cb93a386Sopenharmony_ci this->updateTitle(); 656cb93a386Sopenharmony_ci fWindow->inval(); 657cb93a386Sopenharmony_ci }); 658cb93a386Sopenharmony_ci fCommands.addCommand('S', "Font", "Subpixel Position Mode", [this]() { 659cb93a386Sopenharmony_ci if (!fFontOverrides.fSubpixel) { 660cb93a386Sopenharmony_ci fFontOverrides.fSubpixel = true; 661cb93a386Sopenharmony_ci fFont.setSubpixel(false); 662cb93a386Sopenharmony_ci } else { 663cb93a386Sopenharmony_ci if (!fFont.isSubpixel()) { 664cb93a386Sopenharmony_ci fFont.setSubpixel(true); 665cb93a386Sopenharmony_ci } else { 666cb93a386Sopenharmony_ci fFontOverrides.fSubpixel = false; 667cb93a386Sopenharmony_ci } 668cb93a386Sopenharmony_ci } 669cb93a386Sopenharmony_ci this->updateTitle(); 670cb93a386Sopenharmony_ci fWindow->inval(); 671cb93a386Sopenharmony_ci }); 672cb93a386Sopenharmony_ci fCommands.addCommand('B', "Font", "Baseline Snapping", [this]() { 673cb93a386Sopenharmony_ci if (!fFontOverrides.fBaselineSnap) { 674cb93a386Sopenharmony_ci fFontOverrides.fBaselineSnap = true; 675cb93a386Sopenharmony_ci fFont.setBaselineSnap(false); 676cb93a386Sopenharmony_ci } else { 677cb93a386Sopenharmony_ci if (!fFont.isBaselineSnap()) { 678cb93a386Sopenharmony_ci fFont.setBaselineSnap(true); 679cb93a386Sopenharmony_ci } else { 680cb93a386Sopenharmony_ci fFontOverrides.fBaselineSnap = false; 681cb93a386Sopenharmony_ci } 682cb93a386Sopenharmony_ci } 683cb93a386Sopenharmony_ci this->updateTitle(); 684cb93a386Sopenharmony_ci fWindow->inval(); 685cb93a386Sopenharmony_ci }); 686cb93a386Sopenharmony_ci fCommands.addCommand('p', "Transform", "Toggle Perspective Mode", [this]() { 687cb93a386Sopenharmony_ci fPerspectiveMode = (kPerspective_Real == fPerspectiveMode) ? kPerspective_Fake 688cb93a386Sopenharmony_ci : kPerspective_Real; 689cb93a386Sopenharmony_ci this->updateTitle(); 690cb93a386Sopenharmony_ci fWindow->inval(); 691cb93a386Sopenharmony_ci }); 692cb93a386Sopenharmony_ci fCommands.addCommand('P', "Transform", "Toggle Perspective", [this]() { 693cb93a386Sopenharmony_ci fPerspectiveMode = (kPerspective_Off == fPerspectiveMode) ? kPerspective_Real 694cb93a386Sopenharmony_ci : kPerspective_Off; 695cb93a386Sopenharmony_ci this->updateTitle(); 696cb93a386Sopenharmony_ci fWindow->inval(); 697cb93a386Sopenharmony_ci }); 698cb93a386Sopenharmony_ci fCommands.addCommand('a', "Transform", "Toggle Animation", [this]() { 699cb93a386Sopenharmony_ci fAnimTimer.togglePauseResume(); 700cb93a386Sopenharmony_ci }); 701cb93a386Sopenharmony_ci fCommands.addCommand('u', "GUI", "Zoom UI", [this]() { 702cb93a386Sopenharmony_ci fZoomUI = !fZoomUI; 703cb93a386Sopenharmony_ci fStatsLayer.setDisplayScale((fZoomUI ? 2.0f : 1.0f) * fWindow->scaleFactor()); 704cb93a386Sopenharmony_ci fWindow->inval(); 705cb93a386Sopenharmony_ci }); 706cb93a386Sopenharmony_ci fCommands.addCommand('$', "ViaSerialize", "Toggle ViaSerialize", [this]() { 707cb93a386Sopenharmony_ci fDrawViaSerialize = !fDrawViaSerialize; 708cb93a386Sopenharmony_ci this->updateTitle(); 709cb93a386Sopenharmony_ci fWindow->inval(); 710cb93a386Sopenharmony_ci }); 711cb93a386Sopenharmony_ci fCommands.addCommand('!', "SkVM", "Toggle SkVM blitter", [this]() { 712cb93a386Sopenharmony_ci gUseSkVMBlitter = !gUseSkVMBlitter; 713cb93a386Sopenharmony_ci this->updateTitle(); 714cb93a386Sopenharmony_ci fWindow->inval(); 715cb93a386Sopenharmony_ci }); 716cb93a386Sopenharmony_ci fCommands.addCommand('@', "SkVM", "Toggle SkVM JIT", [this]() { 717cb93a386Sopenharmony_ci gSkVMAllowJIT = !gSkVMAllowJIT; 718cb93a386Sopenharmony_ci this->updateTitle(); 719cb93a386Sopenharmony_ci fWindow->inval(); 720cb93a386Sopenharmony_ci }); 721cb93a386Sopenharmony_ci 722cb93a386Sopenharmony_ci // set up slides 723cb93a386Sopenharmony_ci this->initSlides(); 724cb93a386Sopenharmony_ci if (FLAGS_list) { 725cb93a386Sopenharmony_ci this->listNames(); 726cb93a386Sopenharmony_ci } 727cb93a386Sopenharmony_ci 728cb93a386Sopenharmony_ci fPerspectivePoints[0].set(0, 0); 729cb93a386Sopenharmony_ci fPerspectivePoints[1].set(1, 0); 730cb93a386Sopenharmony_ci fPerspectivePoints[2].set(0, 1); 731cb93a386Sopenharmony_ci fPerspectivePoints[3].set(1, 1); 732cb93a386Sopenharmony_ci fAnimTimer.run(); 733cb93a386Sopenharmony_ci 734cb93a386Sopenharmony_ci auto gamutImage = GetResourceAsImage("images/gamut.png"); 735cb93a386Sopenharmony_ci if (gamutImage) { 736cb93a386Sopenharmony_ci fImGuiGamutPaint.setShader(gamutImage->makeShader(SkSamplingOptions(SkFilterMode::kLinear))); 737cb93a386Sopenharmony_ci } 738cb93a386Sopenharmony_ci fImGuiGamutPaint.setColor(SK_ColorWHITE); 739cb93a386Sopenharmony_ci 740cb93a386Sopenharmony_ci fWindow->attach(backend_type_for_window(fBackendType)); 741cb93a386Sopenharmony_ci this->setCurrentSlide(this->startupSlide()); 742cb93a386Sopenharmony_ci} 743cb93a386Sopenharmony_ci 744cb93a386Sopenharmony_civoid Viewer::initSlides() { 745cb93a386Sopenharmony_ci using SlideFactory = sk_sp<Slide>(*)(const SkString& name, const SkString& path); 746cb93a386Sopenharmony_ci static const struct { 747cb93a386Sopenharmony_ci const char* fExtension; 748cb93a386Sopenharmony_ci const char* fDirName; 749cb93a386Sopenharmony_ci const CommandLineFlags::StringArray& fFlags; 750cb93a386Sopenharmony_ci const SlideFactory fFactory; 751cb93a386Sopenharmony_ci } gExternalSlidesInfo[] = { 752cb93a386Sopenharmony_ci { ".mskp", "mskp-dir", FLAGS_mskps, 753cb93a386Sopenharmony_ci [](const SkString& name, const SkString& path) -> sk_sp<Slide> { 754cb93a386Sopenharmony_ci return sk_make_sp<MSKPSlide>(name, path);} 755cb93a386Sopenharmony_ci }, 756cb93a386Sopenharmony_ci { ".skp", "skp-dir", FLAGS_skps, 757cb93a386Sopenharmony_ci [](const SkString& name, const SkString& path) -> sk_sp<Slide> { 758cb93a386Sopenharmony_ci return sk_make_sp<SKPSlide>(name, path);} 759cb93a386Sopenharmony_ci }, 760cb93a386Sopenharmony_ci { ".jpg", "jpg-dir", FLAGS_jpgs, 761cb93a386Sopenharmony_ci [](const SkString& name, const SkString& path) -> sk_sp<Slide> { 762cb93a386Sopenharmony_ci return sk_make_sp<ImageSlide>(name, path);} 763cb93a386Sopenharmony_ci }, 764cb93a386Sopenharmony_ci#if defined(SK_ENABLE_SKOTTIE) 765cb93a386Sopenharmony_ci { ".json", "skottie-dir", FLAGS_lotties, 766cb93a386Sopenharmony_ci [](const SkString& name, const SkString& path) -> sk_sp<Slide> { 767cb93a386Sopenharmony_ci return sk_make_sp<SkottieSlide>(name, path);} 768cb93a386Sopenharmony_ci }, 769cb93a386Sopenharmony_ci#endif 770cb93a386Sopenharmony_ci #if defined(SK_ENABLE_SKRIVE) 771cb93a386Sopenharmony_ci { ".flr", "skrive-dir", FLAGS_rives, 772cb93a386Sopenharmony_ci [](const SkString& name, const SkString& path) -> sk_sp<Slide> { 773cb93a386Sopenharmony_ci return sk_make_sp<SkRiveSlide>(name, path);} 774cb93a386Sopenharmony_ci }, 775cb93a386Sopenharmony_ci #endif 776cb93a386Sopenharmony_ci#if defined(SK_ENABLE_SVG) 777cb93a386Sopenharmony_ci { ".svg", "svg-dir", FLAGS_svgs, 778cb93a386Sopenharmony_ci [](const SkString& name, const SkString& path) -> sk_sp<Slide> { 779cb93a386Sopenharmony_ci return sk_make_sp<SvgSlide>(name, path);} 780cb93a386Sopenharmony_ci }, 781cb93a386Sopenharmony_ci#endif 782cb93a386Sopenharmony_ci }; 783cb93a386Sopenharmony_ci 784cb93a386Sopenharmony_ci SkTArray<sk_sp<Slide>> dirSlides; 785cb93a386Sopenharmony_ci 786cb93a386Sopenharmony_ci const auto addSlide = 787cb93a386Sopenharmony_ci [&](const SkString& name, const SkString& path, const SlideFactory& fact) { 788cb93a386Sopenharmony_ci if (CommandLineFlags::ShouldSkip(FLAGS_match, name.c_str())) { 789cb93a386Sopenharmony_ci return; 790cb93a386Sopenharmony_ci } 791cb93a386Sopenharmony_ci 792cb93a386Sopenharmony_ci if (auto slide = fact(name, path)) { 793cb93a386Sopenharmony_ci dirSlides.push_back(slide); 794cb93a386Sopenharmony_ci fSlides.push_back(std::move(slide)); 795cb93a386Sopenharmony_ci } 796cb93a386Sopenharmony_ci }; 797cb93a386Sopenharmony_ci 798cb93a386Sopenharmony_ci if (!FLAGS_file.isEmpty()) { 799cb93a386Sopenharmony_ci // single file mode 800cb93a386Sopenharmony_ci const SkString file(FLAGS_file[0]); 801cb93a386Sopenharmony_ci 802cb93a386Sopenharmony_ci if (sk_exists(file.c_str(), kRead_SkFILE_Flag)) { 803cb93a386Sopenharmony_ci for (const auto& sinfo : gExternalSlidesInfo) { 804cb93a386Sopenharmony_ci if (file.endsWith(sinfo.fExtension)) { 805cb93a386Sopenharmony_ci addSlide(SkOSPath::Basename(file.c_str()), file, sinfo.fFactory); 806cb93a386Sopenharmony_ci return; 807cb93a386Sopenharmony_ci } 808cb93a386Sopenharmony_ci } 809cb93a386Sopenharmony_ci 810cb93a386Sopenharmony_ci fprintf(stderr, "Unsupported file type \"%s\"\n", file.c_str()); 811cb93a386Sopenharmony_ci } else { 812cb93a386Sopenharmony_ci fprintf(stderr, "Cannot read \"%s\"\n", file.c_str()); 813cb93a386Sopenharmony_ci } 814cb93a386Sopenharmony_ci 815cb93a386Sopenharmony_ci return; 816cb93a386Sopenharmony_ci } 817cb93a386Sopenharmony_ci 818cb93a386Sopenharmony_ci // Bisect slide. 819cb93a386Sopenharmony_ci if (!FLAGS_bisect.isEmpty()) { 820cb93a386Sopenharmony_ci sk_sp<BisectSlide> bisect = BisectSlide::Create(FLAGS_bisect[0]); 821cb93a386Sopenharmony_ci if (bisect && !CommandLineFlags::ShouldSkip(FLAGS_match, bisect->getName().c_str())) { 822cb93a386Sopenharmony_ci if (FLAGS_bisect.count() >= 2) { 823cb93a386Sopenharmony_ci for (const char* ch = FLAGS_bisect[1]; *ch; ++ch) { 824cb93a386Sopenharmony_ci bisect->onChar(*ch); 825cb93a386Sopenharmony_ci } 826cb93a386Sopenharmony_ci } 827cb93a386Sopenharmony_ci fSlides.push_back(std::move(bisect)); 828cb93a386Sopenharmony_ci } 829cb93a386Sopenharmony_ci } 830cb93a386Sopenharmony_ci 831cb93a386Sopenharmony_ci // GMs 832cb93a386Sopenharmony_ci int firstGM = fSlides.count(); 833cb93a386Sopenharmony_ci for (skiagm::GMFactory gmFactory : skiagm::GMRegistry::Range()) { 834cb93a386Sopenharmony_ci std::unique_ptr<skiagm::GM> gm = gmFactory(); 835cb93a386Sopenharmony_ci if (!CommandLineFlags::ShouldSkip(FLAGS_match, gm->getName())) { 836cb93a386Sopenharmony_ci sk_sp<Slide> slide(new GMSlide(std::move(gm))); 837cb93a386Sopenharmony_ci fSlides.push_back(std::move(slide)); 838cb93a386Sopenharmony_ci } 839cb93a386Sopenharmony_ci } 840cb93a386Sopenharmony_ci // reverse gms 841cb93a386Sopenharmony_ci int numGMs = fSlides.count() - firstGM; 842cb93a386Sopenharmony_ci for (int i = 0; i < numGMs/2; ++i) { 843cb93a386Sopenharmony_ci std::swap(fSlides[firstGM + i], fSlides[fSlides.count() - i - 1]); 844cb93a386Sopenharmony_ci } 845cb93a386Sopenharmony_ci 846cb93a386Sopenharmony_ci // samples 847cb93a386Sopenharmony_ci for (const SampleFactory factory : SampleRegistry::Range()) { 848cb93a386Sopenharmony_ci sk_sp<Slide> slide(new SampleSlide(factory)); 849cb93a386Sopenharmony_ci if (!CommandLineFlags::ShouldSkip(FLAGS_match, slide->getName().c_str())) { 850cb93a386Sopenharmony_ci fSlides.push_back(slide); 851cb93a386Sopenharmony_ci } 852cb93a386Sopenharmony_ci } 853cb93a386Sopenharmony_ci 854cb93a386Sopenharmony_ci // Particle demo 855cb93a386Sopenharmony_ci { 856cb93a386Sopenharmony_ci // TODO: Convert this to a sample 857cb93a386Sopenharmony_ci sk_sp<Slide> slide(new ParticlesSlide()); 858cb93a386Sopenharmony_ci if (!CommandLineFlags::ShouldSkip(FLAGS_match, slide->getName().c_str())) { 859cb93a386Sopenharmony_ci fSlides.push_back(std::move(slide)); 860cb93a386Sopenharmony_ci } 861cb93a386Sopenharmony_ci } 862cb93a386Sopenharmony_ci 863cb93a386Sopenharmony_ci // Runtime shader editor 864cb93a386Sopenharmony_ci { 865cb93a386Sopenharmony_ci sk_sp<Slide> slide(new SkSLSlide()); 866cb93a386Sopenharmony_ci if (!CommandLineFlags::ShouldSkip(FLAGS_match, slide->getName().c_str())) { 867cb93a386Sopenharmony_ci fSlides.push_back(std::move(slide)); 868cb93a386Sopenharmony_ci } 869cb93a386Sopenharmony_ci } 870cb93a386Sopenharmony_ci 871cb93a386Sopenharmony_ci for (const auto& info : gExternalSlidesInfo) { 872cb93a386Sopenharmony_ci for (const auto& flag : info.fFlags) { 873cb93a386Sopenharmony_ci if (SkStrEndsWith(flag.c_str(), info.fExtension)) { 874cb93a386Sopenharmony_ci // single file 875cb93a386Sopenharmony_ci addSlide(SkOSPath::Basename(flag.c_str()), flag, info.fFactory); 876cb93a386Sopenharmony_ci } else { 877cb93a386Sopenharmony_ci // directory 878cb93a386Sopenharmony_ci SkString name; 879cb93a386Sopenharmony_ci SkTArray<SkString> sortedFilenames; 880cb93a386Sopenharmony_ci SkOSFile::Iter it(flag.c_str(), info.fExtension); 881cb93a386Sopenharmony_ci while (it.next(&name)) { 882cb93a386Sopenharmony_ci sortedFilenames.push_back(name); 883cb93a386Sopenharmony_ci } 884cb93a386Sopenharmony_ci if (sortedFilenames.count()) { 885cb93a386Sopenharmony_ci SkTQSort(sortedFilenames.begin(), sortedFilenames.end(), 886cb93a386Sopenharmony_ci [](const SkString& a, const SkString& b) { 887cb93a386Sopenharmony_ci return strcmp(a.c_str(), b.c_str()) < 0; 888cb93a386Sopenharmony_ci }); 889cb93a386Sopenharmony_ci } 890cb93a386Sopenharmony_ci for (const SkString& filename : sortedFilenames) { 891cb93a386Sopenharmony_ci addSlide(filename, SkOSPath::Join(flag.c_str(), filename.c_str()), 892cb93a386Sopenharmony_ci info.fFactory); 893cb93a386Sopenharmony_ci } 894cb93a386Sopenharmony_ci } 895cb93a386Sopenharmony_ci if (!dirSlides.empty()) { 896cb93a386Sopenharmony_ci fSlides.push_back( 897cb93a386Sopenharmony_ci sk_make_sp<SlideDir>(SkStringPrintf("%s[%s]", info.fDirName, flag.c_str()), 898cb93a386Sopenharmony_ci std::move(dirSlides))); 899cb93a386Sopenharmony_ci dirSlides.reset(); // NOLINT(bugprone-use-after-move) 900cb93a386Sopenharmony_ci } 901cb93a386Sopenharmony_ci } 902cb93a386Sopenharmony_ci } 903cb93a386Sopenharmony_ci 904cb93a386Sopenharmony_ci if (!fSlides.count()) { 905cb93a386Sopenharmony_ci sk_sp<Slide> slide(new NullSlide()); 906cb93a386Sopenharmony_ci fSlides.push_back(std::move(slide)); 907cb93a386Sopenharmony_ci } 908cb93a386Sopenharmony_ci} 909cb93a386Sopenharmony_ci 910cb93a386Sopenharmony_ci 911cb93a386Sopenharmony_ciViewer::~Viewer() { 912cb93a386Sopenharmony_ci for(auto& slide : fSlides) { 913cb93a386Sopenharmony_ci slide->gpuTeardown(); 914cb93a386Sopenharmony_ci } 915cb93a386Sopenharmony_ci 916cb93a386Sopenharmony_ci fWindow->detach(); 917cb93a386Sopenharmony_ci delete fWindow; 918cb93a386Sopenharmony_ci} 919cb93a386Sopenharmony_ci 920cb93a386Sopenharmony_cistruct SkPaintTitleUpdater { 921cb93a386Sopenharmony_ci SkPaintTitleUpdater(SkString* title) : fTitle(title), fCount(0) {} 922cb93a386Sopenharmony_ci void append(const char* s) { 923cb93a386Sopenharmony_ci if (fCount == 0) { 924cb93a386Sopenharmony_ci fTitle->append(" {"); 925cb93a386Sopenharmony_ci } else { 926cb93a386Sopenharmony_ci fTitle->append(", "); 927cb93a386Sopenharmony_ci } 928cb93a386Sopenharmony_ci fTitle->append(s); 929cb93a386Sopenharmony_ci ++fCount; 930cb93a386Sopenharmony_ci } 931cb93a386Sopenharmony_ci void done() { 932cb93a386Sopenharmony_ci if (fCount > 0) { 933cb93a386Sopenharmony_ci fTitle->append("}"); 934cb93a386Sopenharmony_ci } 935cb93a386Sopenharmony_ci } 936cb93a386Sopenharmony_ci SkString* fTitle; 937cb93a386Sopenharmony_ci int fCount; 938cb93a386Sopenharmony_ci}; 939cb93a386Sopenharmony_ci 940cb93a386Sopenharmony_civoid Viewer::updateTitle() { 941cb93a386Sopenharmony_ci if (!fWindow) { 942cb93a386Sopenharmony_ci return; 943cb93a386Sopenharmony_ci } 944cb93a386Sopenharmony_ci if (fWindow->sampleCount() < 1) { 945cb93a386Sopenharmony_ci return; // Surface hasn't been created yet. 946cb93a386Sopenharmony_ci } 947cb93a386Sopenharmony_ci 948cb93a386Sopenharmony_ci SkString title("Viewer: "); 949cb93a386Sopenharmony_ci title.append(fSlides[fCurrentSlide]->getName()); 950cb93a386Sopenharmony_ci 951cb93a386Sopenharmony_ci if (gSkUseAnalyticAA) { 952cb93a386Sopenharmony_ci if (gSkForceAnalyticAA) { 953cb93a386Sopenharmony_ci title.append(" <FAAA>"); 954cb93a386Sopenharmony_ci } else { 955cb93a386Sopenharmony_ci title.append(" <AAA>"); 956cb93a386Sopenharmony_ci } 957cb93a386Sopenharmony_ci } 958cb93a386Sopenharmony_ci if (fDrawViaSerialize) { 959cb93a386Sopenharmony_ci title.append(" <serialize>"); 960cb93a386Sopenharmony_ci } 961cb93a386Sopenharmony_ci if (gUseSkVMBlitter) { 962cb93a386Sopenharmony_ci title.append(" <SkVMBlitter>"); 963cb93a386Sopenharmony_ci } 964cb93a386Sopenharmony_ci if (!gSkVMAllowJIT) { 965cb93a386Sopenharmony_ci title.append(" <SkVM interpreter>"); 966cb93a386Sopenharmony_ci } 967cb93a386Sopenharmony_ci 968cb93a386Sopenharmony_ci SkPaintTitleUpdater paintTitle(&title); 969cb93a386Sopenharmony_ci auto paintFlag = [this, &paintTitle](bool SkPaintFields::* flag, 970cb93a386Sopenharmony_ci bool (SkPaint::* isFlag)() const, 971cb93a386Sopenharmony_ci const char* on, const char* off) 972cb93a386Sopenharmony_ci { 973cb93a386Sopenharmony_ci if (fPaintOverrides.*flag) { 974cb93a386Sopenharmony_ci paintTitle.append((fPaint.*isFlag)() ? on : off); 975cb93a386Sopenharmony_ci } 976cb93a386Sopenharmony_ci }; 977cb93a386Sopenharmony_ci 978cb93a386Sopenharmony_ci auto fontFlag = [this, &paintTitle](bool SkFontFields::* flag, bool (SkFont::* isFlag)() const, 979cb93a386Sopenharmony_ci const char* on, const char* off) 980cb93a386Sopenharmony_ci { 981cb93a386Sopenharmony_ci if (fFontOverrides.*flag) { 982cb93a386Sopenharmony_ci paintTitle.append((fFont.*isFlag)() ? on : off); 983cb93a386Sopenharmony_ci } 984cb93a386Sopenharmony_ci }; 985cb93a386Sopenharmony_ci 986cb93a386Sopenharmony_ci paintFlag(&SkPaintFields::fAntiAlias, &SkPaint::isAntiAlias, "Antialias", "Alias"); 987cb93a386Sopenharmony_ci paintFlag(&SkPaintFields::fDither, &SkPaint::isDither, "DITHER", "No Dither"); 988cb93a386Sopenharmony_ci 989cb93a386Sopenharmony_ci fontFlag(&SkFontFields::fForceAutoHinting, &SkFont::isForceAutoHinting, 990cb93a386Sopenharmony_ci "Force Autohint", "No Force Autohint"); 991cb93a386Sopenharmony_ci fontFlag(&SkFontFields::fEmbolden, &SkFont::isEmbolden, "Fake Bold", "No Fake Bold"); 992cb93a386Sopenharmony_ci fontFlag(&SkFontFields::fBaselineSnap, &SkFont::isBaselineSnap, "BaseSnap", "No BaseSnap"); 993cb93a386Sopenharmony_ci fontFlag(&SkFontFields::fLinearMetrics, &SkFont::isLinearMetrics, 994cb93a386Sopenharmony_ci "Linear Metrics", "Non-Linear Metrics"); 995cb93a386Sopenharmony_ci fontFlag(&SkFontFields::fEmbeddedBitmaps, &SkFont::isEmbeddedBitmaps, 996cb93a386Sopenharmony_ci "Bitmap Text", "No Bitmap Text"); 997cb93a386Sopenharmony_ci fontFlag(&SkFontFields::fSubpixel, &SkFont::isSubpixel, "Subpixel Text", "Pixel Text"); 998cb93a386Sopenharmony_ci 999cb93a386Sopenharmony_ci if (fFontOverrides.fEdging) { 1000cb93a386Sopenharmony_ci switch (fFont.getEdging()) { 1001cb93a386Sopenharmony_ci case SkFont::Edging::kAlias: 1002cb93a386Sopenharmony_ci paintTitle.append("Alias Text"); 1003cb93a386Sopenharmony_ci break; 1004cb93a386Sopenharmony_ci case SkFont::Edging::kAntiAlias: 1005cb93a386Sopenharmony_ci paintTitle.append("Antialias Text"); 1006cb93a386Sopenharmony_ci break; 1007cb93a386Sopenharmony_ci case SkFont::Edging::kSubpixelAntiAlias: 1008cb93a386Sopenharmony_ci paintTitle.append("Subpixel Antialias Text"); 1009cb93a386Sopenharmony_ci break; 1010cb93a386Sopenharmony_ci } 1011cb93a386Sopenharmony_ci } 1012cb93a386Sopenharmony_ci 1013cb93a386Sopenharmony_ci if (fFontOverrides.fHinting) { 1014cb93a386Sopenharmony_ci switch (fFont.getHinting()) { 1015cb93a386Sopenharmony_ci case SkFontHinting::kNone: 1016cb93a386Sopenharmony_ci paintTitle.append("No Hinting"); 1017cb93a386Sopenharmony_ci break; 1018cb93a386Sopenharmony_ci case SkFontHinting::kSlight: 1019cb93a386Sopenharmony_ci paintTitle.append("Slight Hinting"); 1020cb93a386Sopenharmony_ci break; 1021cb93a386Sopenharmony_ci case SkFontHinting::kNormal: 1022cb93a386Sopenharmony_ci paintTitle.append("Normal Hinting"); 1023cb93a386Sopenharmony_ci break; 1024cb93a386Sopenharmony_ci case SkFontHinting::kFull: 1025cb93a386Sopenharmony_ci paintTitle.append("Full Hinting"); 1026cb93a386Sopenharmony_ci break; 1027cb93a386Sopenharmony_ci } 1028cb93a386Sopenharmony_ci } 1029cb93a386Sopenharmony_ci paintTitle.done(); 1030cb93a386Sopenharmony_ci 1031cb93a386Sopenharmony_ci switch (fColorMode) { 1032cb93a386Sopenharmony_ci case ColorMode::kLegacy: 1033cb93a386Sopenharmony_ci title.append(" Legacy 8888"); 1034cb93a386Sopenharmony_ci break; 1035cb93a386Sopenharmony_ci case ColorMode::kColorManaged8888: 1036cb93a386Sopenharmony_ci title.append(" ColorManaged 8888"); 1037cb93a386Sopenharmony_ci break; 1038cb93a386Sopenharmony_ci case ColorMode::kColorManagedF16: 1039cb93a386Sopenharmony_ci title.append(" ColorManaged F16"); 1040cb93a386Sopenharmony_ci break; 1041cb93a386Sopenharmony_ci case ColorMode::kColorManagedF16Norm: 1042cb93a386Sopenharmony_ci title.append(" ColorManaged F16 Norm"); 1043cb93a386Sopenharmony_ci break; 1044cb93a386Sopenharmony_ci } 1045cb93a386Sopenharmony_ci 1046cb93a386Sopenharmony_ci if (ColorMode::kLegacy != fColorMode) { 1047cb93a386Sopenharmony_ci int curPrimaries = -1; 1048cb93a386Sopenharmony_ci for (size_t i = 0; i < SK_ARRAY_COUNT(gNamedPrimaries); ++i) { 1049cb93a386Sopenharmony_ci if (primaries_equal(*gNamedPrimaries[i].fPrimaries, fColorSpacePrimaries)) { 1050cb93a386Sopenharmony_ci curPrimaries = i; 1051cb93a386Sopenharmony_ci break; 1052cb93a386Sopenharmony_ci } 1053cb93a386Sopenharmony_ci } 1054cb93a386Sopenharmony_ci title.appendf(" %s Gamma %f", 1055cb93a386Sopenharmony_ci curPrimaries >= 0 ? gNamedPrimaries[curPrimaries].fName : "Custom", 1056cb93a386Sopenharmony_ci fColorSpaceTransferFn.g); 1057cb93a386Sopenharmony_ci } 1058cb93a386Sopenharmony_ci 1059cb93a386Sopenharmony_ci const DisplayParams& params = fWindow->getRequestedDisplayParams(); 1060cb93a386Sopenharmony_ci if (fDisplayOverrides.fSurfaceProps.fPixelGeometry) { 1061cb93a386Sopenharmony_ci switch (params.fSurfaceProps.pixelGeometry()) { 1062cb93a386Sopenharmony_ci case kUnknown_SkPixelGeometry: 1063cb93a386Sopenharmony_ci title.append( " Flat"); 1064cb93a386Sopenharmony_ci break; 1065cb93a386Sopenharmony_ci case kRGB_H_SkPixelGeometry: 1066cb93a386Sopenharmony_ci title.append( " RGB"); 1067cb93a386Sopenharmony_ci break; 1068cb93a386Sopenharmony_ci case kBGR_H_SkPixelGeometry: 1069cb93a386Sopenharmony_ci title.append( " BGR"); 1070cb93a386Sopenharmony_ci break; 1071cb93a386Sopenharmony_ci case kRGB_V_SkPixelGeometry: 1072cb93a386Sopenharmony_ci title.append( " RGBV"); 1073cb93a386Sopenharmony_ci break; 1074cb93a386Sopenharmony_ci case kBGR_V_SkPixelGeometry: 1075cb93a386Sopenharmony_ci title.append( " BGRV"); 1076cb93a386Sopenharmony_ci break; 1077cb93a386Sopenharmony_ci } 1078cb93a386Sopenharmony_ci } 1079cb93a386Sopenharmony_ci 1080cb93a386Sopenharmony_ci if (params.fSurfaceProps.isUseDeviceIndependentFonts()) { 1081cb93a386Sopenharmony_ci title.append(" DFT"); 1082cb93a386Sopenharmony_ci } 1083cb93a386Sopenharmony_ci 1084cb93a386Sopenharmony_ci title.append(" ["); 1085cb93a386Sopenharmony_ci title.append(kBackendTypeStrings[fBackendType]); 1086cb93a386Sopenharmony_ci int msaa = fWindow->sampleCount(); 1087cb93a386Sopenharmony_ci if (msaa > 1) { 1088cb93a386Sopenharmony_ci title.appendf(" MSAA: %i", msaa); 1089cb93a386Sopenharmony_ci } 1090cb93a386Sopenharmony_ci title.append("]"); 1091cb93a386Sopenharmony_ci 1092cb93a386Sopenharmony_ci GpuPathRenderers pr = fWindow->getRequestedDisplayParams().fGrContextOptions.fGpuPathRenderers; 1093cb93a386Sopenharmony_ci if (GpuPathRenderers::kDefault != pr) { 1094cb93a386Sopenharmony_ci title.appendf(" [Path renderer: %s]", gPathRendererNames[pr].c_str()); 1095cb93a386Sopenharmony_ci } 1096cb93a386Sopenharmony_ci 1097cb93a386Sopenharmony_ci if (kPerspective_Real == fPerspectiveMode) { 1098cb93a386Sopenharmony_ci title.append(" Perpsective (Real)"); 1099cb93a386Sopenharmony_ci } else if (kPerspective_Fake == fPerspectiveMode) { 1100cb93a386Sopenharmony_ci title.append(" Perspective (Fake)"); 1101cb93a386Sopenharmony_ci } 1102cb93a386Sopenharmony_ci 1103cb93a386Sopenharmony_ci fWindow->setTitle(title.c_str()); 1104cb93a386Sopenharmony_ci} 1105cb93a386Sopenharmony_ci 1106cb93a386Sopenharmony_ciint Viewer::startupSlide() const { 1107cb93a386Sopenharmony_ci 1108cb93a386Sopenharmony_ci if (!FLAGS_slide.isEmpty()) { 1109cb93a386Sopenharmony_ci int count = fSlides.count(); 1110cb93a386Sopenharmony_ci for (int i = 0; i < count; i++) { 1111cb93a386Sopenharmony_ci if (fSlides[i]->getName().equals(FLAGS_slide[0])) { 1112cb93a386Sopenharmony_ci return i; 1113cb93a386Sopenharmony_ci } 1114cb93a386Sopenharmony_ci } 1115cb93a386Sopenharmony_ci 1116cb93a386Sopenharmony_ci fprintf(stderr, "Unknown slide \"%s\"\n", FLAGS_slide[0]); 1117cb93a386Sopenharmony_ci this->listNames(); 1118cb93a386Sopenharmony_ci } 1119cb93a386Sopenharmony_ci 1120cb93a386Sopenharmony_ci return 0; 1121cb93a386Sopenharmony_ci} 1122cb93a386Sopenharmony_ci 1123cb93a386Sopenharmony_civoid Viewer::listNames() const { 1124cb93a386Sopenharmony_ci SkDebugf("All Slides:\n"); 1125cb93a386Sopenharmony_ci for (const auto& slide : fSlides) { 1126cb93a386Sopenharmony_ci SkDebugf(" %s\n", slide->getName().c_str()); 1127cb93a386Sopenharmony_ci } 1128cb93a386Sopenharmony_ci} 1129cb93a386Sopenharmony_ci 1130cb93a386Sopenharmony_civoid Viewer::setCurrentSlide(int slide) { 1131cb93a386Sopenharmony_ci SkASSERT(slide >= 0 && slide < fSlides.count()); 1132cb93a386Sopenharmony_ci 1133cb93a386Sopenharmony_ci if (slide == fCurrentSlide) { 1134cb93a386Sopenharmony_ci return; 1135cb93a386Sopenharmony_ci } 1136cb93a386Sopenharmony_ci 1137cb93a386Sopenharmony_ci if (fCurrentSlide >= 0) { 1138cb93a386Sopenharmony_ci fSlides[fCurrentSlide]->unload(); 1139cb93a386Sopenharmony_ci } 1140cb93a386Sopenharmony_ci 1141cb93a386Sopenharmony_ci SkScalar scaleFactor = 1.0; 1142cb93a386Sopenharmony_ci if (fApplyBackingScale) { 1143cb93a386Sopenharmony_ci scaleFactor = fWindow->scaleFactor(); 1144cb93a386Sopenharmony_ci } 1145cb93a386Sopenharmony_ci fSlides[slide]->load(SkIntToScalar(fWindow->width()) / scaleFactor, 1146cb93a386Sopenharmony_ci SkIntToScalar(fWindow->height()) / scaleFactor); 1147cb93a386Sopenharmony_ci fCurrentSlide = slide; 1148cb93a386Sopenharmony_ci this->setupCurrentSlide(); 1149cb93a386Sopenharmony_ci} 1150cb93a386Sopenharmony_ci 1151cb93a386Sopenharmony_civoid Viewer::setupCurrentSlide() { 1152cb93a386Sopenharmony_ci if (fCurrentSlide >= 0) { 1153cb93a386Sopenharmony_ci // prepare dimensions for image slides 1154cb93a386Sopenharmony_ci fGesture.resetTouchState(); 1155cb93a386Sopenharmony_ci fDefaultMatrix.reset(); 1156cb93a386Sopenharmony_ci 1157cb93a386Sopenharmony_ci const SkISize slideSize = fSlides[fCurrentSlide]->getDimensions(); 1158cb93a386Sopenharmony_ci const SkRect slideBounds = SkRect::MakeIWH(slideSize.width(), slideSize.height()); 1159cb93a386Sopenharmony_ci const SkRect windowRect = SkRect::MakeIWH(fWindow->width(), fWindow->height()); 1160cb93a386Sopenharmony_ci 1161cb93a386Sopenharmony_ci // Start with a matrix that scales the slide to the available screen space 1162cb93a386Sopenharmony_ci if (fWindow->scaleContentToFit()) { 1163cb93a386Sopenharmony_ci if (windowRect.width() > 0 && windowRect.height() > 0) { 1164cb93a386Sopenharmony_ci fDefaultMatrix = SkMatrix::RectToRect(slideBounds, windowRect, 1165cb93a386Sopenharmony_ci SkMatrix::kStart_ScaleToFit); 1166cb93a386Sopenharmony_ci } 1167cb93a386Sopenharmony_ci } 1168cb93a386Sopenharmony_ci 1169cb93a386Sopenharmony_ci // Prevent the user from dragging content so far outside the window they can't find it again 1170cb93a386Sopenharmony_ci fGesture.setTransLimit(slideBounds, windowRect, this->computePreTouchMatrix()); 1171cb93a386Sopenharmony_ci 1172cb93a386Sopenharmony_ci this->updateTitle(); 1173cb93a386Sopenharmony_ci this->updateUIState(); 1174cb93a386Sopenharmony_ci 1175cb93a386Sopenharmony_ci fStatsLayer.resetMeasurements(); 1176cb93a386Sopenharmony_ci 1177cb93a386Sopenharmony_ci fWindow->inval(); 1178cb93a386Sopenharmony_ci } 1179cb93a386Sopenharmony_ci} 1180cb93a386Sopenharmony_ci 1181cb93a386Sopenharmony_ci#define MAX_ZOOM_LEVEL 8.0f 1182cb93a386Sopenharmony_ci#define MIN_ZOOM_LEVEL -8.0f 1183cb93a386Sopenharmony_ci 1184cb93a386Sopenharmony_civoid Viewer::changeZoomLevel(float delta) { 1185cb93a386Sopenharmony_ci fZoomLevel += delta; 1186cb93a386Sopenharmony_ci fZoomLevel = SkTPin(fZoomLevel, MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL); 1187cb93a386Sopenharmony_ci this->preTouchMatrixChanged(); 1188cb93a386Sopenharmony_ci} 1189cb93a386Sopenharmony_ci 1190cb93a386Sopenharmony_civoid Viewer::preTouchMatrixChanged() { 1191cb93a386Sopenharmony_ci // Update the trans limit as the transform changes. 1192cb93a386Sopenharmony_ci const SkISize slideSize = fSlides[fCurrentSlide]->getDimensions(); 1193cb93a386Sopenharmony_ci const SkRect slideBounds = SkRect::MakeIWH(slideSize.width(), slideSize.height()); 1194cb93a386Sopenharmony_ci const SkRect windowRect = SkRect::MakeIWH(fWindow->width(), fWindow->height()); 1195cb93a386Sopenharmony_ci fGesture.setTransLimit(slideBounds, windowRect, this->computePreTouchMatrix()); 1196cb93a386Sopenharmony_ci} 1197cb93a386Sopenharmony_ci 1198cb93a386Sopenharmony_ciSkMatrix Viewer::computePerspectiveMatrix() { 1199cb93a386Sopenharmony_ci SkScalar w = fWindow->width(), h = fWindow->height(); 1200cb93a386Sopenharmony_ci SkPoint orthoPts[4] = { { 0, 0 }, { w, 0 }, { 0, h }, { w, h } }; 1201cb93a386Sopenharmony_ci SkPoint perspPts[4] = { 1202cb93a386Sopenharmony_ci { fPerspectivePoints[0].fX * w, fPerspectivePoints[0].fY * h }, 1203cb93a386Sopenharmony_ci { fPerspectivePoints[1].fX * w, fPerspectivePoints[1].fY * h }, 1204cb93a386Sopenharmony_ci { fPerspectivePoints[2].fX * w, fPerspectivePoints[2].fY * h }, 1205cb93a386Sopenharmony_ci { fPerspectivePoints[3].fX * w, fPerspectivePoints[3].fY * h } 1206cb93a386Sopenharmony_ci }; 1207cb93a386Sopenharmony_ci SkMatrix m; 1208cb93a386Sopenharmony_ci m.setPolyToPoly(orthoPts, perspPts, 4); 1209cb93a386Sopenharmony_ci return m; 1210cb93a386Sopenharmony_ci} 1211cb93a386Sopenharmony_ci 1212cb93a386Sopenharmony_ciSkMatrix Viewer::computePreTouchMatrix() { 1213cb93a386Sopenharmony_ci SkMatrix m = fDefaultMatrix; 1214cb93a386Sopenharmony_ci 1215cb93a386Sopenharmony_ci SkScalar zoomScale = exp(fZoomLevel); 1216cb93a386Sopenharmony_ci if (fApplyBackingScale) { 1217cb93a386Sopenharmony_ci zoomScale *= fWindow->scaleFactor(); 1218cb93a386Sopenharmony_ci } 1219cb93a386Sopenharmony_ci m.preTranslate((fOffset.x() - 0.5f) * 2.0f, (fOffset.y() - 0.5f) * 2.0f); 1220cb93a386Sopenharmony_ci m.preScale(zoomScale, zoomScale); 1221cb93a386Sopenharmony_ci 1222cb93a386Sopenharmony_ci const SkISize slideSize = fSlides[fCurrentSlide]->getDimensions(); 1223cb93a386Sopenharmony_ci m.preRotate(fRotation, slideSize.width() * 0.5f, slideSize.height() * 0.5f); 1224cb93a386Sopenharmony_ci 1225cb93a386Sopenharmony_ci if (kPerspective_Real == fPerspectiveMode) { 1226cb93a386Sopenharmony_ci SkMatrix persp = this->computePerspectiveMatrix(); 1227cb93a386Sopenharmony_ci m.postConcat(persp); 1228cb93a386Sopenharmony_ci } 1229cb93a386Sopenharmony_ci 1230cb93a386Sopenharmony_ci return m; 1231cb93a386Sopenharmony_ci} 1232cb93a386Sopenharmony_ci 1233cb93a386Sopenharmony_ciSkMatrix Viewer::computeMatrix() { 1234cb93a386Sopenharmony_ci SkMatrix m = fGesture.localM(); 1235cb93a386Sopenharmony_ci m.preConcat(fGesture.globalM()); 1236cb93a386Sopenharmony_ci m.preConcat(this->computePreTouchMatrix()); 1237cb93a386Sopenharmony_ci return m; 1238cb93a386Sopenharmony_ci} 1239cb93a386Sopenharmony_ci 1240cb93a386Sopenharmony_civoid Viewer::setBackend(sk_app::Window::BackendType backendType) { 1241cb93a386Sopenharmony_ci fPersistentCache.reset(); 1242cb93a386Sopenharmony_ci fCachedShaders.reset(); 1243cb93a386Sopenharmony_ci fBackendType = backendType; 1244cb93a386Sopenharmony_ci 1245cb93a386Sopenharmony_ci // The active context is going away in 'detach' 1246cb93a386Sopenharmony_ci for(auto& slide : fSlides) { 1247cb93a386Sopenharmony_ci slide->gpuTeardown(); 1248cb93a386Sopenharmony_ci } 1249cb93a386Sopenharmony_ci 1250cb93a386Sopenharmony_ci fWindow->detach(); 1251cb93a386Sopenharmony_ci 1252cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_WIN) 1253cb93a386Sopenharmony_ci // Switching between OpenGL, Vulkan, and ANGLE in the same window is problematic at this point 1254cb93a386Sopenharmony_ci // on Windows, so we just delete the window and recreate it. 1255cb93a386Sopenharmony_ci DisplayParams params = fWindow->getRequestedDisplayParams(); 1256cb93a386Sopenharmony_ci delete fWindow; 1257cb93a386Sopenharmony_ci fWindow = Window::CreateNativeWindow(nullptr); 1258cb93a386Sopenharmony_ci 1259cb93a386Sopenharmony_ci // re-register callbacks 1260cb93a386Sopenharmony_ci fCommands.attach(fWindow); 1261cb93a386Sopenharmony_ci fWindow->pushLayer(this); 1262cb93a386Sopenharmony_ci fWindow->pushLayer(&fStatsLayer); 1263cb93a386Sopenharmony_ci fWindow->pushLayer(&fImGuiLayer); 1264cb93a386Sopenharmony_ci 1265cb93a386Sopenharmony_ci // Don't allow the window to re-attach. If we're in MSAA mode, the params we grabbed above 1266cb93a386Sopenharmony_ci // will still include our correct sample count. But the re-created fWindow will lose that 1267cb93a386Sopenharmony_ci // information. On Windows, we need to re-create the window when changing sample count, 1268cb93a386Sopenharmony_ci // so we'll incorrectly detect that situation, then re-initialize the window in GL mode, 1269cb93a386Sopenharmony_ci // rendering this tear-down step pointless (and causing the Vulkan window context to fail 1270cb93a386Sopenharmony_ci // as if we had never changed windows at all). 1271cb93a386Sopenharmony_ci fWindow->setRequestedDisplayParams(params, false); 1272cb93a386Sopenharmony_ci#endif 1273cb93a386Sopenharmony_ci 1274cb93a386Sopenharmony_ci fWindow->attach(backend_type_for_window(fBackendType)); 1275cb93a386Sopenharmony_ci} 1276cb93a386Sopenharmony_ci 1277cb93a386Sopenharmony_civoid Viewer::setColorMode(ColorMode colorMode) { 1278cb93a386Sopenharmony_ci fColorMode = colorMode; 1279cb93a386Sopenharmony_ci this->updateTitle(); 1280cb93a386Sopenharmony_ci fWindow->inval(); 1281cb93a386Sopenharmony_ci} 1282cb93a386Sopenharmony_ci 1283cb93a386Sopenharmony_ciclass OveridePaintFilterCanvas : public SkPaintFilterCanvas { 1284cb93a386Sopenharmony_cipublic: 1285cb93a386Sopenharmony_ci OveridePaintFilterCanvas(SkCanvas* canvas, 1286cb93a386Sopenharmony_ci SkPaint* paint, Viewer::SkPaintFields* pfields, 1287cb93a386Sopenharmony_ci SkFont* font, Viewer::SkFontFields* ffields) 1288cb93a386Sopenharmony_ci : SkPaintFilterCanvas(canvas) 1289cb93a386Sopenharmony_ci , fPaint(paint) 1290cb93a386Sopenharmony_ci , fPaintOverrides(pfields) 1291cb93a386Sopenharmony_ci , fFont(font) 1292cb93a386Sopenharmony_ci , fFontOverrides(ffields) { 1293cb93a386Sopenharmony_ci } 1294cb93a386Sopenharmony_ci 1295cb93a386Sopenharmony_ci const SkTextBlob* filterTextBlob(const SkPaint& paint, 1296cb93a386Sopenharmony_ci const SkTextBlob* blob, 1297cb93a386Sopenharmony_ci sk_sp<SkTextBlob>* cache) { 1298cb93a386Sopenharmony_ci bool blobWillChange = false; 1299cb93a386Sopenharmony_ci for (SkTextBlobRunIterator it(blob); !it.done(); it.next()) { 1300cb93a386Sopenharmony_ci SkTCopyOnFirstWrite<SkFont> filteredFont(it.font()); 1301cb93a386Sopenharmony_ci bool shouldDraw = this->filterFont(&filteredFont); 1302cb93a386Sopenharmony_ci if (it.font() != *filteredFont || !shouldDraw) { 1303cb93a386Sopenharmony_ci blobWillChange = true; 1304cb93a386Sopenharmony_ci break; 1305cb93a386Sopenharmony_ci } 1306cb93a386Sopenharmony_ci } 1307cb93a386Sopenharmony_ci if (!blobWillChange) { 1308cb93a386Sopenharmony_ci return blob; 1309cb93a386Sopenharmony_ci } 1310cb93a386Sopenharmony_ci 1311cb93a386Sopenharmony_ci SkTextBlobBuilder builder; 1312cb93a386Sopenharmony_ci for (SkTextBlobRunIterator it(blob); !it.done(); it.next()) { 1313cb93a386Sopenharmony_ci SkTCopyOnFirstWrite<SkFont> filteredFont(it.font()); 1314cb93a386Sopenharmony_ci bool shouldDraw = this->filterFont(&filteredFont); 1315cb93a386Sopenharmony_ci if (!shouldDraw) { 1316cb93a386Sopenharmony_ci continue; 1317cb93a386Sopenharmony_ci } 1318cb93a386Sopenharmony_ci 1319cb93a386Sopenharmony_ci SkFont font = *filteredFont; 1320cb93a386Sopenharmony_ci 1321cb93a386Sopenharmony_ci const SkTextBlobBuilder::RunBuffer& runBuffer 1322cb93a386Sopenharmony_ci = it.positioning() == SkTextBlobRunIterator::kDefault_Positioning 1323cb93a386Sopenharmony_ci ? builder.allocRunText(font, it.glyphCount(), it.offset().x(),it.offset().y(), 1324cb93a386Sopenharmony_ci it.textSize()) 1325cb93a386Sopenharmony_ci : it.positioning() == SkTextBlobRunIterator::kHorizontal_Positioning 1326cb93a386Sopenharmony_ci ? builder.allocRunTextPosH(font, it.glyphCount(), it.offset().y(), 1327cb93a386Sopenharmony_ci it.textSize()) 1328cb93a386Sopenharmony_ci : it.positioning() == SkTextBlobRunIterator::kFull_Positioning 1329cb93a386Sopenharmony_ci ? builder.allocRunTextPos(font, it.glyphCount(), it.textSize()) 1330cb93a386Sopenharmony_ci : it.positioning() == SkTextBlobRunIterator::kRSXform_Positioning 1331cb93a386Sopenharmony_ci ? builder.allocRunTextRSXform(font, it.glyphCount(), it.textSize()) 1332cb93a386Sopenharmony_ci : (SkASSERT_RELEASE(false), SkTextBlobBuilder::RunBuffer()); 1333cb93a386Sopenharmony_ci uint32_t glyphCount = it.glyphCount(); 1334cb93a386Sopenharmony_ci if (it.glyphs()) { 1335cb93a386Sopenharmony_ci size_t glyphSize = sizeof(decltype(*it.glyphs())); 1336cb93a386Sopenharmony_ci memcpy(runBuffer.glyphs, it.glyphs(), glyphCount * glyphSize); 1337cb93a386Sopenharmony_ci } 1338cb93a386Sopenharmony_ci if (it.pos()) { 1339cb93a386Sopenharmony_ci size_t posSize = sizeof(decltype(*it.pos())); 1340cb93a386Sopenharmony_ci unsigned posPerGlyph = it.scalarsPerGlyph(); 1341cb93a386Sopenharmony_ci memcpy(runBuffer.pos, it.pos(), glyphCount * posPerGlyph * posSize); 1342cb93a386Sopenharmony_ci } 1343cb93a386Sopenharmony_ci if (it.text()) { 1344cb93a386Sopenharmony_ci size_t textSize = sizeof(decltype(*it.text())); 1345cb93a386Sopenharmony_ci uint32_t textCount = it.textSize(); 1346cb93a386Sopenharmony_ci memcpy(runBuffer.utf8text, it.text(), textCount * textSize); 1347cb93a386Sopenharmony_ci } 1348cb93a386Sopenharmony_ci if (it.clusters()) { 1349cb93a386Sopenharmony_ci size_t clusterSize = sizeof(decltype(*it.clusters())); 1350cb93a386Sopenharmony_ci memcpy(runBuffer.clusters, it.clusters(), glyphCount * clusterSize); 1351cb93a386Sopenharmony_ci } 1352cb93a386Sopenharmony_ci } 1353cb93a386Sopenharmony_ci *cache = builder.make(); 1354cb93a386Sopenharmony_ci return cache->get(); 1355cb93a386Sopenharmony_ci } 1356cb93a386Sopenharmony_ci void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 1357cb93a386Sopenharmony_ci const SkPaint& paint) override { 1358cb93a386Sopenharmony_ci sk_sp<SkTextBlob> cache; 1359cb93a386Sopenharmony_ci this->SkPaintFilterCanvas::onDrawTextBlob( 1360cb93a386Sopenharmony_ci this->filterTextBlob(paint, blob, &cache), x, y, paint); 1361cb93a386Sopenharmony_ci } 1362cb93a386Sopenharmony_ci bool filterFont(SkTCopyOnFirstWrite<SkFont>* font) const { 1363cb93a386Sopenharmony_ci if (fFontOverrides->fTypeface) { 1364cb93a386Sopenharmony_ci font->writable()->setTypeface(fFont->refTypeface()); 1365cb93a386Sopenharmony_ci } 1366cb93a386Sopenharmony_ci if (fFontOverrides->fSize) { 1367cb93a386Sopenharmony_ci font->writable()->setSize(fFont->getSize()); 1368cb93a386Sopenharmony_ci } 1369cb93a386Sopenharmony_ci if (fFontOverrides->fScaleX) { 1370cb93a386Sopenharmony_ci font->writable()->setScaleX(fFont->getScaleX()); 1371cb93a386Sopenharmony_ci } 1372cb93a386Sopenharmony_ci if (fFontOverrides->fSkewX) { 1373cb93a386Sopenharmony_ci font->writable()->setSkewX(fFont->getSkewX()); 1374cb93a386Sopenharmony_ci } 1375cb93a386Sopenharmony_ci if (fFontOverrides->fHinting) { 1376cb93a386Sopenharmony_ci font->writable()->setHinting(fFont->getHinting()); 1377cb93a386Sopenharmony_ci } 1378cb93a386Sopenharmony_ci if (fFontOverrides->fEdging) { 1379cb93a386Sopenharmony_ci font->writable()->setEdging(fFont->getEdging()); 1380cb93a386Sopenharmony_ci } 1381cb93a386Sopenharmony_ci if (fFontOverrides->fSubpixel) { 1382cb93a386Sopenharmony_ci font->writable()->setSubpixel(fFont->isSubpixel()); 1383cb93a386Sopenharmony_ci } 1384cb93a386Sopenharmony_ci if (fFontOverrides->fForceAutoHinting) { 1385cb93a386Sopenharmony_ci font->writable()->setForceAutoHinting(fFont->isForceAutoHinting()); 1386cb93a386Sopenharmony_ci } 1387cb93a386Sopenharmony_ci if (fFontOverrides->fEmbeddedBitmaps) { 1388cb93a386Sopenharmony_ci font->writable()->setEmbeddedBitmaps(fFont->isEmbeddedBitmaps()); 1389cb93a386Sopenharmony_ci } 1390cb93a386Sopenharmony_ci if (fFontOverrides->fLinearMetrics) { 1391cb93a386Sopenharmony_ci font->writable()->setLinearMetrics(fFont->isLinearMetrics()); 1392cb93a386Sopenharmony_ci } 1393cb93a386Sopenharmony_ci if (fFontOverrides->fEmbolden) { 1394cb93a386Sopenharmony_ci font->writable()->setEmbolden(fFont->isEmbolden()); 1395cb93a386Sopenharmony_ci } 1396cb93a386Sopenharmony_ci if (fFontOverrides->fBaselineSnap) { 1397cb93a386Sopenharmony_ci font->writable()->setBaselineSnap(fFont->isBaselineSnap()); 1398cb93a386Sopenharmony_ci } 1399cb93a386Sopenharmony_ci 1400cb93a386Sopenharmony_ci return true; // we, currently, never elide a draw 1401cb93a386Sopenharmony_ci } 1402cb93a386Sopenharmony_ci 1403cb93a386Sopenharmony_ci bool onFilter(SkPaint& paint) const override { 1404cb93a386Sopenharmony_ci if (fPaintOverrides->fPathEffect) { 1405cb93a386Sopenharmony_ci paint.setPathEffect(fPaint->refPathEffect()); 1406cb93a386Sopenharmony_ci } 1407cb93a386Sopenharmony_ci if (fPaintOverrides->fShader) { 1408cb93a386Sopenharmony_ci paint.setShader(fPaint->refShader()); 1409cb93a386Sopenharmony_ci } 1410cb93a386Sopenharmony_ci if (fPaintOverrides->fMaskFilter) { 1411cb93a386Sopenharmony_ci paint.setMaskFilter(fPaint->refMaskFilter()); 1412cb93a386Sopenharmony_ci } 1413cb93a386Sopenharmony_ci if (fPaintOverrides->fColorFilter) { 1414cb93a386Sopenharmony_ci paint.setColorFilter(fPaint->refColorFilter()); 1415cb93a386Sopenharmony_ci } 1416cb93a386Sopenharmony_ci if (fPaintOverrides->fImageFilter) { 1417cb93a386Sopenharmony_ci paint.setImageFilter(fPaint->refImageFilter()); 1418cb93a386Sopenharmony_ci } 1419cb93a386Sopenharmony_ci if (fPaintOverrides->fColor) { 1420cb93a386Sopenharmony_ci paint.setColor4f(fPaint->getColor4f()); 1421cb93a386Sopenharmony_ci } 1422cb93a386Sopenharmony_ci if (fPaintOverrides->fStrokeWidth) { 1423cb93a386Sopenharmony_ci paint.setStrokeWidth(fPaint->getStrokeWidth()); 1424cb93a386Sopenharmony_ci } 1425cb93a386Sopenharmony_ci if (fPaintOverrides->fMiterLimit) { 1426cb93a386Sopenharmony_ci paint.setStrokeMiter(fPaint->getStrokeMiter()); 1427cb93a386Sopenharmony_ci } 1428cb93a386Sopenharmony_ci if (fPaintOverrides->fBlendMode) { 1429cb93a386Sopenharmony_ci paint.setBlendMode(fPaint->getBlendMode_or(SkBlendMode::kSrc)); 1430cb93a386Sopenharmony_ci } 1431cb93a386Sopenharmony_ci if (fPaintOverrides->fAntiAlias) { 1432cb93a386Sopenharmony_ci paint.setAntiAlias(fPaint->isAntiAlias()); 1433cb93a386Sopenharmony_ci } 1434cb93a386Sopenharmony_ci if (fPaintOverrides->fDither) { 1435cb93a386Sopenharmony_ci paint.setDither(fPaint->isDither()); 1436cb93a386Sopenharmony_ci } 1437cb93a386Sopenharmony_ci if (fPaintOverrides->fForceRuntimeBlend) { 1438cb93a386Sopenharmony_ci if (skstd::optional<SkBlendMode> mode = paint.asBlendMode()) { 1439cb93a386Sopenharmony_ci paint.setBlender(GetRuntimeBlendForBlendMode(*mode)); 1440cb93a386Sopenharmony_ci } 1441cb93a386Sopenharmony_ci } 1442cb93a386Sopenharmony_ci if (fPaintOverrides->fCapType) { 1443cb93a386Sopenharmony_ci paint.setStrokeCap(fPaint->getStrokeCap()); 1444cb93a386Sopenharmony_ci } 1445cb93a386Sopenharmony_ci if (fPaintOverrides->fJoinType) { 1446cb93a386Sopenharmony_ci paint.setStrokeJoin(fPaint->getStrokeJoin()); 1447cb93a386Sopenharmony_ci } 1448cb93a386Sopenharmony_ci if (fPaintOverrides->fStyle) { 1449cb93a386Sopenharmony_ci paint.setStyle(fPaint->getStyle()); 1450cb93a386Sopenharmony_ci } 1451cb93a386Sopenharmony_ci return true; // we, currently, never elide a draw 1452cb93a386Sopenharmony_ci } 1453cb93a386Sopenharmony_ci SkPaint* fPaint; 1454cb93a386Sopenharmony_ci Viewer::SkPaintFields* fPaintOverrides; 1455cb93a386Sopenharmony_ci SkFont* fFont; 1456cb93a386Sopenharmony_ci Viewer::SkFontFields* fFontOverrides; 1457cb93a386Sopenharmony_ci}; 1458cb93a386Sopenharmony_ci 1459cb93a386Sopenharmony_civoid Viewer::drawSlide(SkSurface* surface) { 1460cb93a386Sopenharmony_ci if (fCurrentSlide < 0) { 1461cb93a386Sopenharmony_ci return; 1462cb93a386Sopenharmony_ci } 1463cb93a386Sopenharmony_ci 1464cb93a386Sopenharmony_ci SkAutoCanvasRestore autorestore(surface->getCanvas(), false); 1465cb93a386Sopenharmony_ci 1466cb93a386Sopenharmony_ci // By default, we render directly into the window's surface/canvas 1467cb93a386Sopenharmony_ci SkSurface* slideSurface = surface; 1468cb93a386Sopenharmony_ci SkCanvas* slideCanvas = surface->getCanvas(); 1469cb93a386Sopenharmony_ci fLastImage.reset(); 1470cb93a386Sopenharmony_ci 1471cb93a386Sopenharmony_ci // If we're in any of the color managed modes, construct the color space we're going to use 1472cb93a386Sopenharmony_ci sk_sp<SkColorSpace> colorSpace = nullptr; 1473cb93a386Sopenharmony_ci if (ColorMode::kLegacy != fColorMode) { 1474cb93a386Sopenharmony_ci skcms_Matrix3x3 toXYZ; 1475cb93a386Sopenharmony_ci SkAssertResult(fColorSpacePrimaries.toXYZD50(&toXYZ)); 1476cb93a386Sopenharmony_ci colorSpace = SkColorSpace::MakeRGB(fColorSpaceTransferFn, toXYZ); 1477cb93a386Sopenharmony_ci } 1478cb93a386Sopenharmony_ci 1479cb93a386Sopenharmony_ci if (fSaveToSKP) { 1480cb93a386Sopenharmony_ci SkPictureRecorder recorder; 1481cb93a386Sopenharmony_ci SkCanvas* recorderCanvas = recorder.beginRecording( 1482cb93a386Sopenharmony_ci SkRect::Make(fSlides[fCurrentSlide]->getDimensions())); 1483cb93a386Sopenharmony_ci fSlides[fCurrentSlide]->draw(recorderCanvas); 1484cb93a386Sopenharmony_ci sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture()); 1485cb93a386Sopenharmony_ci SkFILEWStream stream("sample_app.skp"); 1486cb93a386Sopenharmony_ci picture->serialize(&stream); 1487cb93a386Sopenharmony_ci fSaveToSKP = false; 1488cb93a386Sopenharmony_ci } 1489cb93a386Sopenharmony_ci 1490cb93a386Sopenharmony_ci // Grab some things we'll need to make surfaces (for tiling or general offscreen rendering) 1491cb93a386Sopenharmony_ci SkColorType colorType; 1492cb93a386Sopenharmony_ci switch (fColorMode) { 1493cb93a386Sopenharmony_ci case ColorMode::kLegacy: 1494cb93a386Sopenharmony_ci case ColorMode::kColorManaged8888: 1495cb93a386Sopenharmony_ci colorType = kN32_SkColorType; 1496cb93a386Sopenharmony_ci break; 1497cb93a386Sopenharmony_ci case ColorMode::kColorManagedF16: 1498cb93a386Sopenharmony_ci colorType = kRGBA_F16_SkColorType; 1499cb93a386Sopenharmony_ci break; 1500cb93a386Sopenharmony_ci case ColorMode::kColorManagedF16Norm: 1501cb93a386Sopenharmony_ci colorType = kRGBA_F16Norm_SkColorType; 1502cb93a386Sopenharmony_ci break; 1503cb93a386Sopenharmony_ci } 1504cb93a386Sopenharmony_ci 1505cb93a386Sopenharmony_ci auto make_surface = [=](int w, int h) { 1506cb93a386Sopenharmony_ci SkSurfaceProps props(fWindow->getRequestedDisplayParams().fSurfaceProps); 1507cb93a386Sopenharmony_ci slideCanvas->getProps(&props); 1508cb93a386Sopenharmony_ci 1509cb93a386Sopenharmony_ci SkImageInfo info = SkImageInfo::Make(w, h, colorType, kPremul_SkAlphaType, colorSpace); 1510cb93a386Sopenharmony_ci return Window::kRaster_BackendType == this->fBackendType 1511cb93a386Sopenharmony_ci ? SkSurface::MakeRaster(info, &props) 1512cb93a386Sopenharmony_ci : slideCanvas->makeSurface(info, &props); 1513cb93a386Sopenharmony_ci }; 1514cb93a386Sopenharmony_ci 1515cb93a386Sopenharmony_ci // We need to render offscreen if we're... 1516cb93a386Sopenharmony_ci // ... in fake perspective or zooming (so we have a snapped copy of the results) 1517cb93a386Sopenharmony_ci // ... in any raster mode, because the window surface is actually GL 1518cb93a386Sopenharmony_ci // ... in any color managed mode, because we always make the window surface with no color space 1519cb93a386Sopenharmony_ci // ... or if the user explicitly requested offscreen rendering 1520cb93a386Sopenharmony_ci sk_sp<SkSurface> offscreenSurface = nullptr; 1521cb93a386Sopenharmony_ci if (kPerspective_Fake == fPerspectiveMode || 1522cb93a386Sopenharmony_ci fShowZoomWindow || 1523cb93a386Sopenharmony_ci Window::kRaster_BackendType == fBackendType || 1524cb93a386Sopenharmony_ci colorSpace != nullptr || 1525cb93a386Sopenharmony_ci FLAGS_offscreen) { 1526cb93a386Sopenharmony_ci 1527cb93a386Sopenharmony_ci offscreenSurface = make_surface(fWindow->width(), fWindow->height()); 1528cb93a386Sopenharmony_ci slideSurface = offscreenSurface.get(); 1529cb93a386Sopenharmony_ci slideCanvas = offscreenSurface->getCanvas(); 1530cb93a386Sopenharmony_ci } 1531cb93a386Sopenharmony_ci 1532cb93a386Sopenharmony_ci SkPictureRecorder recorder; 1533cb93a386Sopenharmony_ci SkCanvas* recorderRestoreCanvas = nullptr; 1534cb93a386Sopenharmony_ci if (fDrawViaSerialize) { 1535cb93a386Sopenharmony_ci recorderRestoreCanvas = slideCanvas; 1536cb93a386Sopenharmony_ci slideCanvas = recorder.beginRecording( 1537cb93a386Sopenharmony_ci SkRect::Make(fSlides[fCurrentSlide]->getDimensions())); 1538cb93a386Sopenharmony_ci } 1539cb93a386Sopenharmony_ci 1540cb93a386Sopenharmony_ci int count = slideCanvas->save(); 1541cb93a386Sopenharmony_ci slideCanvas->clear(SK_ColorWHITE); 1542cb93a386Sopenharmony_ci // Time the painting logic of the slide 1543cb93a386Sopenharmony_ci fStatsLayer.beginTiming(fPaintTimer); 1544cb93a386Sopenharmony_ci if (fTiled) { 1545cb93a386Sopenharmony_ci int tileW = SkScalarCeilToInt(fWindow->width() * fTileScale.width()); 1546cb93a386Sopenharmony_ci int tileH = SkScalarCeilToInt(fWindow->height() * fTileScale.height()); 1547cb93a386Sopenharmony_ci for (int y = 0; y < fWindow->height(); y += tileH) { 1548cb93a386Sopenharmony_ci for (int x = 0; x < fWindow->width(); x += tileW) { 1549cb93a386Sopenharmony_ci SkAutoCanvasRestore acr(slideCanvas, true); 1550cb93a386Sopenharmony_ci slideCanvas->clipRect(SkRect::MakeXYWH(x, y, tileW, tileH)); 1551cb93a386Sopenharmony_ci fSlides[fCurrentSlide]->draw(slideCanvas); 1552cb93a386Sopenharmony_ci } 1553cb93a386Sopenharmony_ci } 1554cb93a386Sopenharmony_ci 1555cb93a386Sopenharmony_ci // Draw borders between tiles 1556cb93a386Sopenharmony_ci if (fDrawTileBoundaries) { 1557cb93a386Sopenharmony_ci SkPaint border; 1558cb93a386Sopenharmony_ci border.setColor(0x60FF00FF); 1559cb93a386Sopenharmony_ci border.setStyle(SkPaint::kStroke_Style); 1560cb93a386Sopenharmony_ci for (int y = 0; y < fWindow->height(); y += tileH) { 1561cb93a386Sopenharmony_ci for (int x = 0; x < fWindow->width(); x += tileW) { 1562cb93a386Sopenharmony_ci slideCanvas->drawRect(SkRect::MakeXYWH(x, y, tileW, tileH), border); 1563cb93a386Sopenharmony_ci } 1564cb93a386Sopenharmony_ci } 1565cb93a386Sopenharmony_ci } 1566cb93a386Sopenharmony_ci } else { 1567cb93a386Sopenharmony_ci slideCanvas->concat(this->computeMatrix()); 1568cb93a386Sopenharmony_ci if (kPerspective_Real == fPerspectiveMode) { 1569cb93a386Sopenharmony_ci slideCanvas->clipRect(SkRect::MakeWH(fWindow->width(), fWindow->height())); 1570cb93a386Sopenharmony_ci } 1571cb93a386Sopenharmony_ci if (fPaintOverrides.overridesSomething() || fFontOverrides.overridesSomething()) { 1572cb93a386Sopenharmony_ci OveridePaintFilterCanvas filterCanvas(slideCanvas, 1573cb93a386Sopenharmony_ci &fPaint, &fPaintOverrides, 1574cb93a386Sopenharmony_ci &fFont, &fFontOverrides); 1575cb93a386Sopenharmony_ci fSlides[fCurrentSlide]->draw(&filterCanvas); 1576cb93a386Sopenharmony_ci } else { 1577cb93a386Sopenharmony_ci fSlides[fCurrentSlide]->draw(slideCanvas); 1578cb93a386Sopenharmony_ci } 1579cb93a386Sopenharmony_ci } 1580cb93a386Sopenharmony_ci fStatsLayer.endTiming(fPaintTimer); 1581cb93a386Sopenharmony_ci slideCanvas->restoreToCount(count); 1582cb93a386Sopenharmony_ci 1583cb93a386Sopenharmony_ci if (recorderRestoreCanvas) { 1584cb93a386Sopenharmony_ci sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture()); 1585cb93a386Sopenharmony_ci auto data = picture->serialize(); 1586cb93a386Sopenharmony_ci slideCanvas = recorderRestoreCanvas; 1587cb93a386Sopenharmony_ci slideCanvas->drawPicture(SkPicture::MakeFromData(data.get())); 1588cb93a386Sopenharmony_ci } 1589cb93a386Sopenharmony_ci 1590cb93a386Sopenharmony_ci // Force a flush so we can time that, too 1591cb93a386Sopenharmony_ci fStatsLayer.beginTiming(fFlushTimer); 1592cb93a386Sopenharmony_ci slideSurface->flushAndSubmit(); 1593cb93a386Sopenharmony_ci fStatsLayer.endTiming(fFlushTimer); 1594cb93a386Sopenharmony_ci 1595cb93a386Sopenharmony_ci // If we rendered offscreen, snap an image and push the results to the window's canvas 1596cb93a386Sopenharmony_ci if (offscreenSurface) { 1597cb93a386Sopenharmony_ci fLastImage = offscreenSurface->makeImageSnapshot(); 1598cb93a386Sopenharmony_ci 1599cb93a386Sopenharmony_ci SkCanvas* canvas = surface->getCanvas(); 1600cb93a386Sopenharmony_ci SkPaint paint; 1601cb93a386Sopenharmony_ci paint.setBlendMode(SkBlendMode::kSrc); 1602cb93a386Sopenharmony_ci SkSamplingOptions sampling; 1603cb93a386Sopenharmony_ci int prePerspectiveCount = canvas->save(); 1604cb93a386Sopenharmony_ci if (kPerspective_Fake == fPerspectiveMode) { 1605cb93a386Sopenharmony_ci sampling = SkSamplingOptions({1.0f/3, 1.0f/3}); 1606cb93a386Sopenharmony_ci canvas->clear(SK_ColorWHITE); 1607cb93a386Sopenharmony_ci canvas->concat(this->computePerspectiveMatrix()); 1608cb93a386Sopenharmony_ci } 1609cb93a386Sopenharmony_ci canvas->drawImage(fLastImage, 0, 0, sampling, &paint); 1610cb93a386Sopenharmony_ci canvas->restoreToCount(prePerspectiveCount); 1611cb93a386Sopenharmony_ci } 1612cb93a386Sopenharmony_ci 1613cb93a386Sopenharmony_ci if (fShowSlideDimensions) { 1614cb93a386Sopenharmony_ci SkCanvas* canvas = surface->getCanvas(); 1615cb93a386Sopenharmony_ci SkAutoCanvasRestore acr(canvas, true); 1616cb93a386Sopenharmony_ci canvas->concat(this->computeMatrix()); 1617cb93a386Sopenharmony_ci SkRect r = SkRect::Make(fSlides[fCurrentSlide]->getDimensions()); 1618cb93a386Sopenharmony_ci SkPaint paint; 1619cb93a386Sopenharmony_ci paint.setColor(0x40FFFF00); 1620cb93a386Sopenharmony_ci canvas->drawRect(r, paint); 1621cb93a386Sopenharmony_ci } 1622cb93a386Sopenharmony_ci} 1623cb93a386Sopenharmony_ci 1624cb93a386Sopenharmony_civoid Viewer::onBackendCreated() { 1625cb93a386Sopenharmony_ci this->setupCurrentSlide(); 1626cb93a386Sopenharmony_ci fWindow->show(); 1627cb93a386Sopenharmony_ci} 1628cb93a386Sopenharmony_ci 1629cb93a386Sopenharmony_civoid Viewer::onPaint(SkSurface* surface) { 1630cb93a386Sopenharmony_ci this->drawSlide(surface); 1631cb93a386Sopenharmony_ci 1632cb93a386Sopenharmony_ci fCommands.drawHelp(surface->getCanvas()); 1633cb93a386Sopenharmony_ci 1634cb93a386Sopenharmony_ci this->drawImGui(); 1635cb93a386Sopenharmony_ci 1636cb93a386Sopenharmony_ci fLastImage.reset(); 1637cb93a386Sopenharmony_ci 1638cb93a386Sopenharmony_ci if (auto direct = fWindow->directContext()) { 1639cb93a386Sopenharmony_ci // Clean out cache items that haven't been used in more than 10 seconds. 1640cb93a386Sopenharmony_ci direct->performDeferredCleanup(std::chrono::seconds(10)); 1641cb93a386Sopenharmony_ci } 1642cb93a386Sopenharmony_ci} 1643cb93a386Sopenharmony_ci 1644cb93a386Sopenharmony_civoid Viewer::onResize(int width, int height) { 1645cb93a386Sopenharmony_ci if (fCurrentSlide >= 0) { 1646cb93a386Sopenharmony_ci SkScalar scaleFactor = 1.0; 1647cb93a386Sopenharmony_ci if (fApplyBackingScale) { 1648cb93a386Sopenharmony_ci scaleFactor = fWindow->scaleFactor(); 1649cb93a386Sopenharmony_ci } 1650cb93a386Sopenharmony_ci fSlides[fCurrentSlide]->resize(width / scaleFactor, height / scaleFactor); 1651cb93a386Sopenharmony_ci } 1652cb93a386Sopenharmony_ci} 1653cb93a386Sopenharmony_ci 1654cb93a386Sopenharmony_ciSkPoint Viewer::mapEvent(float x, float y) { 1655cb93a386Sopenharmony_ci const auto m = this->computeMatrix(); 1656cb93a386Sopenharmony_ci SkMatrix inv; 1657cb93a386Sopenharmony_ci 1658cb93a386Sopenharmony_ci SkAssertResult(m.invert(&inv)); 1659cb93a386Sopenharmony_ci 1660cb93a386Sopenharmony_ci return inv.mapXY(x, y); 1661cb93a386Sopenharmony_ci} 1662cb93a386Sopenharmony_ci 1663cb93a386Sopenharmony_cibool Viewer::onTouch(intptr_t owner, skui::InputState state, float x, float y) { 1664cb93a386Sopenharmony_ci if (GestureDevice::kMouse == fGestureDevice) { 1665cb93a386Sopenharmony_ci return false; 1666cb93a386Sopenharmony_ci } 1667cb93a386Sopenharmony_ci 1668cb93a386Sopenharmony_ci const auto slidePt = this->mapEvent(x, y); 1669cb93a386Sopenharmony_ci if (fSlides[fCurrentSlide]->onMouse(slidePt.x(), slidePt.y(), state, skui::ModifierKey::kNone)) { 1670cb93a386Sopenharmony_ci fWindow->inval(); 1671cb93a386Sopenharmony_ci return true; 1672cb93a386Sopenharmony_ci } 1673cb93a386Sopenharmony_ci 1674cb93a386Sopenharmony_ci void* castedOwner = reinterpret_cast<void*>(owner); 1675cb93a386Sopenharmony_ci switch (state) { 1676cb93a386Sopenharmony_ci case skui::InputState::kUp: { 1677cb93a386Sopenharmony_ci fGesture.touchEnd(castedOwner); 1678cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_IOS) 1679cb93a386Sopenharmony_ci // TODO: move IOS swipe detection higher up into the platform code 1680cb93a386Sopenharmony_ci SkPoint dir; 1681cb93a386Sopenharmony_ci if (fGesture.isFling(&dir)) { 1682cb93a386Sopenharmony_ci // swiping left or right 1683cb93a386Sopenharmony_ci if (SkTAbs(dir.fX) > SkTAbs(dir.fY)) { 1684cb93a386Sopenharmony_ci if (dir.fX < 0) { 1685cb93a386Sopenharmony_ci this->setCurrentSlide(fCurrentSlide < fSlides.count() - 1 ? 1686cb93a386Sopenharmony_ci fCurrentSlide + 1 : 0); 1687cb93a386Sopenharmony_ci } else { 1688cb93a386Sopenharmony_ci this->setCurrentSlide(fCurrentSlide > 0 ? 1689cb93a386Sopenharmony_ci fCurrentSlide - 1 : fSlides.count() - 1); 1690cb93a386Sopenharmony_ci } 1691cb93a386Sopenharmony_ci } 1692cb93a386Sopenharmony_ci fGesture.reset(); 1693cb93a386Sopenharmony_ci } 1694cb93a386Sopenharmony_ci#endif 1695cb93a386Sopenharmony_ci break; 1696cb93a386Sopenharmony_ci } 1697cb93a386Sopenharmony_ci case skui::InputState::kDown: { 1698cb93a386Sopenharmony_ci fGesture.touchBegin(castedOwner, x, y); 1699cb93a386Sopenharmony_ci break; 1700cb93a386Sopenharmony_ci } 1701cb93a386Sopenharmony_ci case skui::InputState::kMove: { 1702cb93a386Sopenharmony_ci fGesture.touchMoved(castedOwner, x, y); 1703cb93a386Sopenharmony_ci break; 1704cb93a386Sopenharmony_ci } 1705cb93a386Sopenharmony_ci default: { 1706cb93a386Sopenharmony_ci // kLeft and kRight are only for swipes 1707cb93a386Sopenharmony_ci SkASSERT(false); 1708cb93a386Sopenharmony_ci break; 1709cb93a386Sopenharmony_ci } 1710cb93a386Sopenharmony_ci } 1711cb93a386Sopenharmony_ci fGestureDevice = fGesture.isBeingTouched() ? GestureDevice::kTouch : GestureDevice::kNone; 1712cb93a386Sopenharmony_ci fWindow->inval(); 1713cb93a386Sopenharmony_ci return true; 1714cb93a386Sopenharmony_ci} 1715cb93a386Sopenharmony_ci 1716cb93a386Sopenharmony_cibool Viewer::onMouse(int x, int y, skui::InputState state, skui::ModifierKey modifiers) { 1717cb93a386Sopenharmony_ci if (GestureDevice::kTouch == fGestureDevice) { 1718cb93a386Sopenharmony_ci return false; 1719cb93a386Sopenharmony_ci } 1720cb93a386Sopenharmony_ci 1721cb93a386Sopenharmony_ci const auto slidePt = this->mapEvent(x, y); 1722cb93a386Sopenharmony_ci if (fSlides[fCurrentSlide]->onMouse(slidePt.x(), slidePt.y(), state, modifiers)) { 1723cb93a386Sopenharmony_ci fWindow->inval(); 1724cb93a386Sopenharmony_ci return true; 1725cb93a386Sopenharmony_ci } 1726cb93a386Sopenharmony_ci 1727cb93a386Sopenharmony_ci switch (state) { 1728cb93a386Sopenharmony_ci case skui::InputState::kUp: { 1729cb93a386Sopenharmony_ci fGesture.touchEnd(nullptr); 1730cb93a386Sopenharmony_ci break; 1731cb93a386Sopenharmony_ci } 1732cb93a386Sopenharmony_ci case skui::InputState::kDown: { 1733cb93a386Sopenharmony_ci fGesture.touchBegin(nullptr, x, y); 1734cb93a386Sopenharmony_ci break; 1735cb93a386Sopenharmony_ci } 1736cb93a386Sopenharmony_ci case skui::InputState::kMove: { 1737cb93a386Sopenharmony_ci fGesture.touchMoved(nullptr, x, y); 1738cb93a386Sopenharmony_ci break; 1739cb93a386Sopenharmony_ci } 1740cb93a386Sopenharmony_ci default: { 1741cb93a386Sopenharmony_ci SkASSERT(false); // shouldn't see kRight or kLeft here 1742cb93a386Sopenharmony_ci break; 1743cb93a386Sopenharmony_ci } 1744cb93a386Sopenharmony_ci } 1745cb93a386Sopenharmony_ci fGestureDevice = fGesture.isBeingTouched() ? GestureDevice::kMouse : GestureDevice::kNone; 1746cb93a386Sopenharmony_ci 1747cb93a386Sopenharmony_ci if (state != skui::InputState::kMove || fGesture.isBeingTouched()) { 1748cb93a386Sopenharmony_ci fWindow->inval(); 1749cb93a386Sopenharmony_ci } 1750cb93a386Sopenharmony_ci return true; 1751cb93a386Sopenharmony_ci} 1752cb93a386Sopenharmony_ci 1753cb93a386Sopenharmony_cibool Viewer::onFling(skui::InputState state) { 1754cb93a386Sopenharmony_ci if (skui::InputState::kRight == state) { 1755cb93a386Sopenharmony_ci this->setCurrentSlide(fCurrentSlide > 0 ? fCurrentSlide - 1 : fSlides.count() - 1); 1756cb93a386Sopenharmony_ci return true; 1757cb93a386Sopenharmony_ci } else if (skui::InputState::kLeft == state) { 1758cb93a386Sopenharmony_ci this->setCurrentSlide(fCurrentSlide < fSlides.count() - 1 ? fCurrentSlide + 1 : 0); 1759cb93a386Sopenharmony_ci return true; 1760cb93a386Sopenharmony_ci } 1761cb93a386Sopenharmony_ci return false; 1762cb93a386Sopenharmony_ci} 1763cb93a386Sopenharmony_ci 1764cb93a386Sopenharmony_cibool Viewer::onPinch(skui::InputState state, float scale, float x, float y) { 1765cb93a386Sopenharmony_ci switch (state) { 1766cb93a386Sopenharmony_ci case skui::InputState::kDown: 1767cb93a386Sopenharmony_ci fGesture.startZoom(); 1768cb93a386Sopenharmony_ci return true; 1769cb93a386Sopenharmony_ci break; 1770cb93a386Sopenharmony_ci case skui::InputState::kMove: 1771cb93a386Sopenharmony_ci fGesture.updateZoom(scale, x, y, x, y); 1772cb93a386Sopenharmony_ci return true; 1773cb93a386Sopenharmony_ci break; 1774cb93a386Sopenharmony_ci case skui::InputState::kUp: 1775cb93a386Sopenharmony_ci fGesture.endZoom(); 1776cb93a386Sopenharmony_ci return true; 1777cb93a386Sopenharmony_ci break; 1778cb93a386Sopenharmony_ci default: 1779cb93a386Sopenharmony_ci SkASSERT(false); 1780cb93a386Sopenharmony_ci break; 1781cb93a386Sopenharmony_ci } 1782cb93a386Sopenharmony_ci 1783cb93a386Sopenharmony_ci return false; 1784cb93a386Sopenharmony_ci} 1785cb93a386Sopenharmony_ci 1786cb93a386Sopenharmony_cistatic void ImGui_Primaries(SkColorSpacePrimaries* primaries, SkPaint* gamutPaint) { 1787cb93a386Sopenharmony_ci // The gamut image covers a (0.8 x 0.9) shaped region 1788cb93a386Sopenharmony_ci ImGui::DragCanvas dc(primaries, { 0.0f, 0.9f }, { 0.8f, 0.0f }); 1789cb93a386Sopenharmony_ci 1790cb93a386Sopenharmony_ci // Background image. Only draw a subset of the image, to avoid the regions less than zero. 1791cb93a386Sopenharmony_ci // Simplifes re-mapping math, clipping behavior, and increases resolution in the useful area. 1792cb93a386Sopenharmony_ci // Magic numbers are pixel locations of the origin and upper-right corner. 1793cb93a386Sopenharmony_ci dc.fDrawList->AddImage(gamutPaint, dc.fPos, 1794cb93a386Sopenharmony_ci ImVec2(dc.fPos.x + dc.fSize.x, dc.fPos.y + dc.fSize.y), 1795cb93a386Sopenharmony_ci ImVec2(242, 61), ImVec2(1897, 1922)); 1796cb93a386Sopenharmony_ci 1797cb93a386Sopenharmony_ci dc.dragPoint((SkPoint*)(&primaries->fRX), true, 0xFF000040); 1798cb93a386Sopenharmony_ci dc.dragPoint((SkPoint*)(&primaries->fGX), true, 0xFF004000); 1799cb93a386Sopenharmony_ci dc.dragPoint((SkPoint*)(&primaries->fBX), true, 0xFF400000); 1800cb93a386Sopenharmony_ci dc.dragPoint((SkPoint*)(&primaries->fWX), true); 1801cb93a386Sopenharmony_ci dc.fDrawList->AddPolyline(dc.fScreenPoints.begin(), 3, 0xFFFFFFFF, true, 1.5f); 1802cb93a386Sopenharmony_ci} 1803cb93a386Sopenharmony_ci 1804cb93a386Sopenharmony_cistatic bool ImGui_DragLocation(SkPoint* pt) { 1805cb93a386Sopenharmony_ci ImGui::DragCanvas dc(pt); 1806cb93a386Sopenharmony_ci dc.fillColor(IM_COL32(0, 0, 0, 128)); 1807cb93a386Sopenharmony_ci dc.dragPoint(pt); 1808cb93a386Sopenharmony_ci return dc.fDragging; 1809cb93a386Sopenharmony_ci} 1810cb93a386Sopenharmony_ci 1811cb93a386Sopenharmony_cistatic bool ImGui_DragQuad(SkPoint* pts) { 1812cb93a386Sopenharmony_ci ImGui::DragCanvas dc(pts); 1813cb93a386Sopenharmony_ci dc.fillColor(IM_COL32(0, 0, 0, 128)); 1814cb93a386Sopenharmony_ci 1815cb93a386Sopenharmony_ci for (int i = 0; i < 4; ++i) { 1816cb93a386Sopenharmony_ci dc.dragPoint(pts + i); 1817cb93a386Sopenharmony_ci } 1818cb93a386Sopenharmony_ci 1819cb93a386Sopenharmony_ci dc.fDrawList->AddLine(dc.fScreenPoints[0], dc.fScreenPoints[1], 0xFFFFFFFF); 1820cb93a386Sopenharmony_ci dc.fDrawList->AddLine(dc.fScreenPoints[1], dc.fScreenPoints[3], 0xFFFFFFFF); 1821cb93a386Sopenharmony_ci dc.fDrawList->AddLine(dc.fScreenPoints[3], dc.fScreenPoints[2], 0xFFFFFFFF); 1822cb93a386Sopenharmony_ci dc.fDrawList->AddLine(dc.fScreenPoints[2], dc.fScreenPoints[0], 0xFFFFFFFF); 1823cb93a386Sopenharmony_ci 1824cb93a386Sopenharmony_ci return dc.fDragging; 1825cb93a386Sopenharmony_ci} 1826cb93a386Sopenharmony_ci 1827cb93a386Sopenharmony_cistatic SkSL::String build_sksl_highlight_shader() { 1828cb93a386Sopenharmony_ci return SkSL::String("out half4 sk_FragColor;\n" 1829cb93a386Sopenharmony_ci "void main() { sk_FragColor = half4(1, 0, 1, 0.5); }"); 1830cb93a386Sopenharmony_ci} 1831cb93a386Sopenharmony_ci 1832cb93a386Sopenharmony_cistatic SkSL::String build_metal_highlight_shader(const SkSL::String& inShader) { 1833cb93a386Sopenharmony_ci // Metal fragment shaders need a lot of non-trivial boilerplate that we don't want to recompute 1834cb93a386Sopenharmony_ci // here. So keep all shader code, but right before `return *_out;`, swap out the sk_FragColor. 1835cb93a386Sopenharmony_ci size_t pos = inShader.rfind("return *_out;\n"); 1836cb93a386Sopenharmony_ci if (pos == std::string::npos) { 1837cb93a386Sopenharmony_ci return inShader; 1838cb93a386Sopenharmony_ci } 1839cb93a386Sopenharmony_ci 1840cb93a386Sopenharmony_ci SkSL::String replacementShader = inShader; 1841cb93a386Sopenharmony_ci replacementShader.insert(pos, "_out->sk_FragColor = float4(1.0, 0.0, 1.0, 0.5); "); 1842cb93a386Sopenharmony_ci return replacementShader; 1843cb93a386Sopenharmony_ci} 1844cb93a386Sopenharmony_ci 1845cb93a386Sopenharmony_cistatic SkSL::String build_glsl_highlight_shader(const GrShaderCaps& shaderCaps) { 1846cb93a386Sopenharmony_ci const char* versionDecl = shaderCaps.versionDeclString(); 1847cb93a386Sopenharmony_ci SkSL::String highlight = versionDecl ? versionDecl : ""; 1848cb93a386Sopenharmony_ci if (shaderCaps.usesPrecisionModifiers()) { 1849cb93a386Sopenharmony_ci highlight.append("precision mediump float;\n"); 1850cb93a386Sopenharmony_ci } 1851cb93a386Sopenharmony_ci highlight.appendf("out vec4 sk_FragColor;\n" 1852cb93a386Sopenharmony_ci "void main() { sk_FragColor = vec4(1, 0, 1, 0.5); }"); 1853cb93a386Sopenharmony_ci return highlight; 1854cb93a386Sopenharmony_ci} 1855cb93a386Sopenharmony_ci 1856cb93a386Sopenharmony_cistatic skvm::Program build_skvm_highlight_program(SkColorType ct, int nargs) { 1857cb93a386Sopenharmony_ci // Code here is heavily tied to (and inspired by) SkVMBlitter::BuildProgram 1858cb93a386Sopenharmony_ci skvm::Builder b; 1859cb93a386Sopenharmony_ci 1860cb93a386Sopenharmony_ci // All VM blitters start with two arguments (uniforms, dst surface) 1861cb93a386Sopenharmony_ci SkASSERT(nargs >= 2); 1862cb93a386Sopenharmony_ci (void)b.uniform(); 1863cb93a386Sopenharmony_ci skvm::Ptr dst_ptr = b.varying(SkColorTypeBytesPerPixel(ct)); 1864cb93a386Sopenharmony_ci 1865cb93a386Sopenharmony_ci // Depending on coverage and shader, there can be additional arguments. 1866cb93a386Sopenharmony_ci // Make sure that we append the right number, so that we don't assert when 1867cb93a386Sopenharmony_ci // the CPU backend tries to run this program. 1868cb93a386Sopenharmony_ci for (int i = 2; i < nargs; ++i) { 1869cb93a386Sopenharmony_ci (void)b.uniform(); 1870cb93a386Sopenharmony_ci } 1871cb93a386Sopenharmony_ci 1872cb93a386Sopenharmony_ci skvm::Color magenta = {b.splat(1.0f), b.splat(0.0f), b.splat(1.0f), b.splat(0.5f)}; 1873cb93a386Sopenharmony_ci skvm::PixelFormat dstFormat = skvm::SkColorType_to_PixelFormat(ct); 1874cb93a386Sopenharmony_ci store(dstFormat, dst_ptr, magenta); 1875cb93a386Sopenharmony_ci 1876cb93a386Sopenharmony_ci return b.done(); 1877cb93a386Sopenharmony_ci} 1878cb93a386Sopenharmony_ci 1879cb93a386Sopenharmony_civoid Viewer::drawImGui() { 1880cb93a386Sopenharmony_ci // Support drawing the ImGui demo window. Superfluous, but gives a good idea of what's possible 1881cb93a386Sopenharmony_ci if (fShowImGuiTestWindow) { 1882cb93a386Sopenharmony_ci ImGui::ShowDemoWindow(&fShowImGuiTestWindow); 1883cb93a386Sopenharmony_ci } 1884cb93a386Sopenharmony_ci 1885cb93a386Sopenharmony_ci if (fShowImGuiDebugWindow) { 1886cb93a386Sopenharmony_ci // We have some dynamic content that sizes to fill available size. If the scroll bar isn't 1887cb93a386Sopenharmony_ci // always visible, we can end up in a layout feedback loop. 1888cb93a386Sopenharmony_ci ImGui::SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver); 1889cb93a386Sopenharmony_ci DisplayParams params = fWindow->getRequestedDisplayParams(); 1890cb93a386Sopenharmony_ci bool displayParamsChanged = false; // heavy-weight, might recreate entire context 1891cb93a386Sopenharmony_ci bool uiParamsChanged = false; // light weight, just triggers window invalidation 1892cb93a386Sopenharmony_ci auto ctx = fWindow->directContext(); 1893cb93a386Sopenharmony_ci 1894cb93a386Sopenharmony_ci if (ImGui::Begin("Tools", &fShowImGuiDebugWindow, 1895cb93a386Sopenharmony_ci ImGuiWindowFlags_AlwaysVerticalScrollbar)) { 1896cb93a386Sopenharmony_ci if (ImGui::CollapsingHeader("Backend")) { 1897cb93a386Sopenharmony_ci int newBackend = static_cast<int>(fBackendType); 1898cb93a386Sopenharmony_ci ImGui::RadioButton("Raster", &newBackend, sk_app::Window::kRaster_BackendType); 1899cb93a386Sopenharmony_ci ImGui::SameLine(); 1900cb93a386Sopenharmony_ci ImGui::RadioButton("OpenGL", &newBackend, sk_app::Window::kNativeGL_BackendType); 1901cb93a386Sopenharmony_ci#if SK_ANGLE && defined(SK_BUILD_FOR_WIN) 1902cb93a386Sopenharmony_ci ImGui::SameLine(); 1903cb93a386Sopenharmony_ci ImGui::RadioButton("ANGLE", &newBackend, sk_app::Window::kANGLE_BackendType); 1904cb93a386Sopenharmony_ci#endif 1905cb93a386Sopenharmony_ci#if defined(SK_DAWN) 1906cb93a386Sopenharmony_ci ImGui::SameLine(); 1907cb93a386Sopenharmony_ci ImGui::RadioButton("Dawn", &newBackend, sk_app::Window::kDawn_BackendType); 1908cb93a386Sopenharmony_ci#endif 1909cb93a386Sopenharmony_ci#if defined(SK_VULKAN) && !defined(SK_BUILD_FOR_MAC) 1910cb93a386Sopenharmony_ci ImGui::SameLine(); 1911cb93a386Sopenharmony_ci ImGui::RadioButton("Vulkan", &newBackend, sk_app::Window::kVulkan_BackendType); 1912cb93a386Sopenharmony_ci#endif 1913cb93a386Sopenharmony_ci#if defined(SK_METAL) 1914cb93a386Sopenharmony_ci ImGui::SameLine(); 1915cb93a386Sopenharmony_ci ImGui::RadioButton("Metal", &newBackend, sk_app::Window::kMetal_BackendType); 1916cb93a386Sopenharmony_ci#if defined(SK_GRAPHITE_ENABLED) 1917cb93a386Sopenharmony_ci ImGui::SameLine(); 1918cb93a386Sopenharmony_ci ImGui::RadioButton("Metal (Graphite)", &newBackend, 1919cb93a386Sopenharmony_ci sk_app::Window::kGraphiteMetal_BackendType); 1920cb93a386Sopenharmony_ci#endif 1921cb93a386Sopenharmony_ci#endif 1922cb93a386Sopenharmony_ci#if defined(SK_DIRECT3D) 1923cb93a386Sopenharmony_ci ImGui::SameLine(); 1924cb93a386Sopenharmony_ci ImGui::RadioButton("Direct3D", &newBackend, sk_app::Window::kDirect3D_BackendType); 1925cb93a386Sopenharmony_ci#endif 1926cb93a386Sopenharmony_ci if (newBackend != fBackendType) { 1927cb93a386Sopenharmony_ci fDeferredActions.push_back([=]() { 1928cb93a386Sopenharmony_ci this->setBackend(static_cast<sk_app::Window::BackendType>(newBackend)); 1929cb93a386Sopenharmony_ci }); 1930cb93a386Sopenharmony_ci } 1931cb93a386Sopenharmony_ci 1932cb93a386Sopenharmony_ci bool* wire = ¶ms.fGrContextOptions.fWireframeMode; 1933cb93a386Sopenharmony_ci if (ctx && ImGui::Checkbox("Wireframe Mode", wire)) { 1934cb93a386Sopenharmony_ci displayParamsChanged = true; 1935cb93a386Sopenharmony_ci } 1936cb93a386Sopenharmony_ci 1937cb93a386Sopenharmony_ci bool* reducedShaders = ¶ms.fGrContextOptions.fReducedShaderVariations; 1938cb93a386Sopenharmony_ci if (ctx && ImGui::Checkbox("Reduced shaders", reducedShaders)) { 1939cb93a386Sopenharmony_ci displayParamsChanged = true; 1940cb93a386Sopenharmony_ci } 1941cb93a386Sopenharmony_ci 1942cb93a386Sopenharmony_ci if (ctx) { 1943cb93a386Sopenharmony_ci // Determine the context's max sample count for MSAA radio buttons. 1944cb93a386Sopenharmony_ci int sampleCount = fWindow->sampleCount(); 1945cb93a386Sopenharmony_ci int maxMSAA = (fBackendType != sk_app::Window::kRaster_BackendType) ? 1946cb93a386Sopenharmony_ci ctx->maxSurfaceSampleCountForColorType(kRGBA_8888_SkColorType) : 1947cb93a386Sopenharmony_ci 1; 1948cb93a386Sopenharmony_ci 1949cb93a386Sopenharmony_ci // Only display the MSAA radio buttons when there are options above 1x MSAA. 1950cb93a386Sopenharmony_ci if (maxMSAA >= 4) { 1951cb93a386Sopenharmony_ci ImGui::Text("MSAA: "); 1952cb93a386Sopenharmony_ci 1953cb93a386Sopenharmony_ci for (int curMSAA = 1; curMSAA <= maxMSAA; curMSAA *= 2) { 1954cb93a386Sopenharmony_ci // 2x MSAA works, but doesn't offer much of a visual improvement, so we 1955cb93a386Sopenharmony_ci // don't show it in the list. 1956cb93a386Sopenharmony_ci if (curMSAA == 2) { 1957cb93a386Sopenharmony_ci continue; 1958cb93a386Sopenharmony_ci } 1959cb93a386Sopenharmony_ci ImGui::SameLine(); 1960cb93a386Sopenharmony_ci ImGui::RadioButton(SkStringPrintf("%d", curMSAA).c_str(), 1961cb93a386Sopenharmony_ci &sampleCount, curMSAA); 1962cb93a386Sopenharmony_ci } 1963cb93a386Sopenharmony_ci } 1964cb93a386Sopenharmony_ci 1965cb93a386Sopenharmony_ci if (sampleCount != params.fMSAASampleCount) { 1966cb93a386Sopenharmony_ci params.fMSAASampleCount = sampleCount; 1967cb93a386Sopenharmony_ci displayParamsChanged = true; 1968cb93a386Sopenharmony_ci } 1969cb93a386Sopenharmony_ci } 1970cb93a386Sopenharmony_ci 1971cb93a386Sopenharmony_ci int pixelGeometryIdx = 0; 1972cb93a386Sopenharmony_ci if (fDisplayOverrides.fSurfaceProps.fPixelGeometry) { 1973cb93a386Sopenharmony_ci pixelGeometryIdx = params.fSurfaceProps.pixelGeometry() + 1; 1974cb93a386Sopenharmony_ci } 1975cb93a386Sopenharmony_ci if (ImGui::Combo("Pixel Geometry", &pixelGeometryIdx, 1976cb93a386Sopenharmony_ci "Default\0Flat\0RGB\0BGR\0RGBV\0BGRV\0\0")) 1977cb93a386Sopenharmony_ci { 1978cb93a386Sopenharmony_ci uint32_t flags = params.fSurfaceProps.flags(); 1979cb93a386Sopenharmony_ci if (pixelGeometryIdx == 0) { 1980cb93a386Sopenharmony_ci fDisplayOverrides.fSurfaceProps.fPixelGeometry = false; 1981cb93a386Sopenharmony_ci SkPixelGeometry pixelGeometry = fDisplay.fSurfaceProps.pixelGeometry(); 1982cb93a386Sopenharmony_ci params.fSurfaceProps = SkSurfaceProps(flags, pixelGeometry); 1983cb93a386Sopenharmony_ci } else { 1984cb93a386Sopenharmony_ci fDisplayOverrides.fSurfaceProps.fPixelGeometry = true; 1985cb93a386Sopenharmony_ci SkPixelGeometry pixelGeometry = SkTo<SkPixelGeometry>(pixelGeometryIdx - 1); 1986cb93a386Sopenharmony_ci params.fSurfaceProps = SkSurfaceProps(flags, pixelGeometry); 1987cb93a386Sopenharmony_ci } 1988cb93a386Sopenharmony_ci displayParamsChanged = true; 1989cb93a386Sopenharmony_ci } 1990cb93a386Sopenharmony_ci 1991cb93a386Sopenharmony_ci bool useDFT = params.fSurfaceProps.isUseDeviceIndependentFonts(); 1992cb93a386Sopenharmony_ci if (ImGui::Checkbox("DFT", &useDFT)) { 1993cb93a386Sopenharmony_ci uint32_t flags = params.fSurfaceProps.flags(); 1994cb93a386Sopenharmony_ci if (useDFT) { 1995cb93a386Sopenharmony_ci flags |= SkSurfaceProps::kUseDeviceIndependentFonts_Flag; 1996cb93a386Sopenharmony_ci } else { 1997cb93a386Sopenharmony_ci flags &= ~SkSurfaceProps::kUseDeviceIndependentFonts_Flag; 1998cb93a386Sopenharmony_ci } 1999cb93a386Sopenharmony_ci SkPixelGeometry pixelGeometry = params.fSurfaceProps.pixelGeometry(); 2000cb93a386Sopenharmony_ci params.fSurfaceProps = SkSurfaceProps(flags, pixelGeometry); 2001cb93a386Sopenharmony_ci displayParamsChanged = true; 2002cb93a386Sopenharmony_ci } 2003cb93a386Sopenharmony_ci 2004cb93a386Sopenharmony_ci if (ImGui::TreeNode("Path Renderers")) { 2005cb93a386Sopenharmony_ci GpuPathRenderers prevPr = params.fGrContextOptions.fGpuPathRenderers; 2006cb93a386Sopenharmony_ci auto prButton = [&](GpuPathRenderers x) { 2007cb93a386Sopenharmony_ci if (ImGui::RadioButton(gPathRendererNames[x].c_str(), prevPr == x)) { 2008cb93a386Sopenharmony_ci if (x != params.fGrContextOptions.fGpuPathRenderers) { 2009cb93a386Sopenharmony_ci params.fGrContextOptions.fGpuPathRenderers = x; 2010cb93a386Sopenharmony_ci displayParamsChanged = true; 2011cb93a386Sopenharmony_ci } 2012cb93a386Sopenharmony_ci } 2013cb93a386Sopenharmony_ci }; 2014cb93a386Sopenharmony_ci 2015cb93a386Sopenharmony_ci if (!ctx) { 2016cb93a386Sopenharmony_ci ImGui::RadioButton("Software", true); 2017cb93a386Sopenharmony_ci } else { 2018cb93a386Sopenharmony_ci prButton(GpuPathRenderers::kDefault); 2019cb93a386Sopenharmony_ci#if SK_GPU_V1 2020cb93a386Sopenharmony_ci if (fWindow->sampleCount() > 1 || FLAGS_dmsaa) { 2021cb93a386Sopenharmony_ci const auto* caps = ctx->priv().caps(); 2022cb93a386Sopenharmony_ci if (skgpu::v1::AtlasPathRenderer::IsSupported(ctx)) { 2023cb93a386Sopenharmony_ci prButton(GpuPathRenderers::kAtlas); 2024cb93a386Sopenharmony_ci } 2025cb93a386Sopenharmony_ci if (skgpu::v1::TessellationPathRenderer::IsSupported(*caps)) { 2026cb93a386Sopenharmony_ci prButton(GpuPathRenderers::kTessellation); 2027cb93a386Sopenharmony_ci } 2028cb93a386Sopenharmony_ci } 2029cb93a386Sopenharmony_ci#endif 2030cb93a386Sopenharmony_ci if (1 == fWindow->sampleCount()) { 2031cb93a386Sopenharmony_ci prButton(GpuPathRenderers::kSmall); 2032cb93a386Sopenharmony_ci } 2033cb93a386Sopenharmony_ci prButton(GpuPathRenderers::kTriangulating); 2034cb93a386Sopenharmony_ci prButton(GpuPathRenderers::kNone); 2035cb93a386Sopenharmony_ci } 2036cb93a386Sopenharmony_ci ImGui::TreePop(); 2037cb93a386Sopenharmony_ci } 2038cb93a386Sopenharmony_ci } 2039cb93a386Sopenharmony_ci 2040cb93a386Sopenharmony_ci if (ImGui::CollapsingHeader("Tiling")) { 2041cb93a386Sopenharmony_ci ImGui::Checkbox("Enable", &fTiled); 2042cb93a386Sopenharmony_ci ImGui::Checkbox("Draw Boundaries", &fDrawTileBoundaries); 2043cb93a386Sopenharmony_ci ImGui::SliderFloat("Horizontal", &fTileScale.fWidth, 0.1f, 1.0f); 2044cb93a386Sopenharmony_ci ImGui::SliderFloat("Vertical", &fTileScale.fHeight, 0.1f, 1.0f); 2045cb93a386Sopenharmony_ci } 2046cb93a386Sopenharmony_ci 2047cb93a386Sopenharmony_ci if (ImGui::CollapsingHeader("Transform")) { 2048cb93a386Sopenharmony_ci if (ImGui::Checkbox("Apply Backing Scale", &fApplyBackingScale)) { 2049cb93a386Sopenharmony_ci this->preTouchMatrixChanged(); 2050cb93a386Sopenharmony_ci this->onResize(fWindow->width(), fWindow->height()); 2051cb93a386Sopenharmony_ci // This changes how we manipulate the canvas transform, it's not changing the 2052cb93a386Sopenharmony_ci // window's actual parameters. 2053cb93a386Sopenharmony_ci uiParamsChanged = true; 2054cb93a386Sopenharmony_ci } 2055cb93a386Sopenharmony_ci 2056cb93a386Sopenharmony_ci float zoom = fZoomLevel; 2057cb93a386Sopenharmony_ci if (ImGui::SliderFloat("Zoom", &zoom, MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL)) { 2058cb93a386Sopenharmony_ci fZoomLevel = zoom; 2059cb93a386Sopenharmony_ci this->preTouchMatrixChanged(); 2060cb93a386Sopenharmony_ci uiParamsChanged = true; 2061cb93a386Sopenharmony_ci } 2062cb93a386Sopenharmony_ci float deg = fRotation; 2063cb93a386Sopenharmony_ci if (ImGui::SliderFloat("Rotate", °, -30, 360, "%.3f deg")) { 2064cb93a386Sopenharmony_ci fRotation = deg; 2065cb93a386Sopenharmony_ci this->preTouchMatrixChanged(); 2066cb93a386Sopenharmony_ci uiParamsChanged = true; 2067cb93a386Sopenharmony_ci } 2068cb93a386Sopenharmony_ci if (ImGui::CollapsingHeader("Subpixel offset", ImGuiTreeNodeFlags_NoTreePushOnOpen)) { 2069cb93a386Sopenharmony_ci if (ImGui_DragLocation(&fOffset)) { 2070cb93a386Sopenharmony_ci this->preTouchMatrixChanged(); 2071cb93a386Sopenharmony_ci uiParamsChanged = true; 2072cb93a386Sopenharmony_ci } 2073cb93a386Sopenharmony_ci } else if (fOffset != SkVector{0.5f, 0.5f}) { 2074cb93a386Sopenharmony_ci this->preTouchMatrixChanged(); 2075cb93a386Sopenharmony_ci uiParamsChanged = true; 2076cb93a386Sopenharmony_ci fOffset = {0.5f, 0.5f}; 2077cb93a386Sopenharmony_ci } 2078cb93a386Sopenharmony_ci int perspectiveMode = static_cast<int>(fPerspectiveMode); 2079cb93a386Sopenharmony_ci if (ImGui::Combo("Perspective", &perspectiveMode, "Off\0Real\0Fake\0\0")) { 2080cb93a386Sopenharmony_ci fPerspectiveMode = static_cast<PerspectiveMode>(perspectiveMode); 2081cb93a386Sopenharmony_ci this->preTouchMatrixChanged(); 2082cb93a386Sopenharmony_ci uiParamsChanged = true; 2083cb93a386Sopenharmony_ci } 2084cb93a386Sopenharmony_ci if (perspectiveMode != kPerspective_Off && ImGui_DragQuad(fPerspectivePoints)) { 2085cb93a386Sopenharmony_ci this->preTouchMatrixChanged(); 2086cb93a386Sopenharmony_ci uiParamsChanged = true; 2087cb93a386Sopenharmony_ci } 2088cb93a386Sopenharmony_ci } 2089cb93a386Sopenharmony_ci 2090cb93a386Sopenharmony_ci if (ImGui::CollapsingHeader("Paint")) { 2091cb93a386Sopenharmony_ci int aliasIdx = 0; 2092cb93a386Sopenharmony_ci if (fPaintOverrides.fAntiAlias) { 2093cb93a386Sopenharmony_ci aliasIdx = SkTo<int>(fPaintOverrides.fAntiAliasState) + 1; 2094cb93a386Sopenharmony_ci } 2095cb93a386Sopenharmony_ci if (ImGui::Combo("Anti-Alias", &aliasIdx, 2096cb93a386Sopenharmony_ci "Default\0Alias\0Normal\0AnalyticAAEnabled\0AnalyticAAForced\0\0")) 2097cb93a386Sopenharmony_ci { 2098cb93a386Sopenharmony_ci gSkUseAnalyticAA = fPaintOverrides.fOriginalSkUseAnalyticAA; 2099cb93a386Sopenharmony_ci gSkForceAnalyticAA = fPaintOverrides.fOriginalSkForceAnalyticAA; 2100cb93a386Sopenharmony_ci if (aliasIdx == 0) { 2101cb93a386Sopenharmony_ci fPaintOverrides.fAntiAliasState = SkPaintFields::AntiAliasState::Alias; 2102cb93a386Sopenharmony_ci fPaintOverrides.fAntiAlias = false; 2103cb93a386Sopenharmony_ci } else { 2104cb93a386Sopenharmony_ci fPaintOverrides.fAntiAlias = true; 2105cb93a386Sopenharmony_ci fPaintOverrides.fAntiAliasState = SkTo<SkPaintFields::AntiAliasState>(aliasIdx-1); 2106cb93a386Sopenharmony_ci fPaint.setAntiAlias(aliasIdx > 1); 2107cb93a386Sopenharmony_ci switch (fPaintOverrides.fAntiAliasState) { 2108cb93a386Sopenharmony_ci case SkPaintFields::AntiAliasState::Alias: 2109cb93a386Sopenharmony_ci break; 2110cb93a386Sopenharmony_ci case SkPaintFields::AntiAliasState::Normal: 2111cb93a386Sopenharmony_ci break; 2112cb93a386Sopenharmony_ci case SkPaintFields::AntiAliasState::AnalyticAAEnabled: 2113cb93a386Sopenharmony_ci gSkUseAnalyticAA = true; 2114cb93a386Sopenharmony_ci gSkForceAnalyticAA = false; 2115cb93a386Sopenharmony_ci break; 2116cb93a386Sopenharmony_ci case SkPaintFields::AntiAliasState::AnalyticAAForced: 2117cb93a386Sopenharmony_ci gSkUseAnalyticAA = gSkForceAnalyticAA = true; 2118cb93a386Sopenharmony_ci break; 2119cb93a386Sopenharmony_ci } 2120cb93a386Sopenharmony_ci } 2121cb93a386Sopenharmony_ci uiParamsChanged = true; 2122cb93a386Sopenharmony_ci } 2123cb93a386Sopenharmony_ci 2124cb93a386Sopenharmony_ci auto paintFlag = [this, &uiParamsChanged](const char* label, const char* items, 2125cb93a386Sopenharmony_ci bool SkPaintFields::* flag, 2126cb93a386Sopenharmony_ci bool (SkPaint::* isFlag)() const, 2127cb93a386Sopenharmony_ci void (SkPaint::* setFlag)(bool) ) 2128cb93a386Sopenharmony_ci { 2129cb93a386Sopenharmony_ci int itemIndex = 0; 2130cb93a386Sopenharmony_ci if (fPaintOverrides.*flag) { 2131cb93a386Sopenharmony_ci itemIndex = (fPaint.*isFlag)() ? 2 : 1; 2132cb93a386Sopenharmony_ci } 2133cb93a386Sopenharmony_ci if (ImGui::Combo(label, &itemIndex, items)) { 2134cb93a386Sopenharmony_ci if (itemIndex == 0) { 2135cb93a386Sopenharmony_ci fPaintOverrides.*flag = false; 2136cb93a386Sopenharmony_ci } else { 2137cb93a386Sopenharmony_ci fPaintOverrides.*flag = true; 2138cb93a386Sopenharmony_ci (fPaint.*setFlag)(itemIndex == 2); 2139cb93a386Sopenharmony_ci } 2140cb93a386Sopenharmony_ci uiParamsChanged = true; 2141cb93a386Sopenharmony_ci } 2142cb93a386Sopenharmony_ci }; 2143cb93a386Sopenharmony_ci 2144cb93a386Sopenharmony_ci paintFlag("Dither", 2145cb93a386Sopenharmony_ci "Default\0No Dither\0Dither\0\0", 2146cb93a386Sopenharmony_ci &SkPaintFields::fDither, 2147cb93a386Sopenharmony_ci &SkPaint::isDither, &SkPaint::setDither); 2148cb93a386Sopenharmony_ci 2149cb93a386Sopenharmony_ci int styleIdx = 0; 2150cb93a386Sopenharmony_ci if (fPaintOverrides.fStyle) { 2151cb93a386Sopenharmony_ci styleIdx = SkTo<int>(fPaint.getStyle()) + 1; 2152cb93a386Sopenharmony_ci } 2153cb93a386Sopenharmony_ci if (ImGui::Combo("Style", &styleIdx, 2154cb93a386Sopenharmony_ci "Default\0Fill\0Stroke\0Stroke and Fill\0\0")) 2155cb93a386Sopenharmony_ci { 2156cb93a386Sopenharmony_ci if (styleIdx == 0) { 2157cb93a386Sopenharmony_ci fPaintOverrides.fStyle = false; 2158cb93a386Sopenharmony_ci fPaint.setStyle(SkPaint::kFill_Style); 2159cb93a386Sopenharmony_ci } else { 2160cb93a386Sopenharmony_ci fPaint.setStyle(SkTo<SkPaint::Style>(styleIdx - 1)); 2161cb93a386Sopenharmony_ci fPaintOverrides.fStyle = true; 2162cb93a386Sopenharmony_ci } 2163cb93a386Sopenharmony_ci uiParamsChanged = true; 2164cb93a386Sopenharmony_ci } 2165cb93a386Sopenharmony_ci 2166cb93a386Sopenharmony_ci ImGui::Checkbox("Force Runtime Blends", &fPaintOverrides.fForceRuntimeBlend); 2167cb93a386Sopenharmony_ci 2168cb93a386Sopenharmony_ci ImGui::Checkbox("Override Stroke Width", &fPaintOverrides.fStrokeWidth); 2169cb93a386Sopenharmony_ci if (fPaintOverrides.fStrokeWidth) { 2170cb93a386Sopenharmony_ci float width = fPaint.getStrokeWidth(); 2171cb93a386Sopenharmony_ci if (ImGui::SliderFloat("Stroke Width", &width, 0, 20)) { 2172cb93a386Sopenharmony_ci fPaint.setStrokeWidth(width); 2173cb93a386Sopenharmony_ci uiParamsChanged = true; 2174cb93a386Sopenharmony_ci } 2175cb93a386Sopenharmony_ci } 2176cb93a386Sopenharmony_ci 2177cb93a386Sopenharmony_ci ImGui::Checkbox("Override Miter Limit", &fPaintOverrides.fMiterLimit); 2178cb93a386Sopenharmony_ci if (fPaintOverrides.fMiterLimit) { 2179cb93a386Sopenharmony_ci float miterLimit = fPaint.getStrokeMiter(); 2180cb93a386Sopenharmony_ci if (ImGui::SliderFloat("Miter Limit", &miterLimit, 0, 20)) { 2181cb93a386Sopenharmony_ci fPaint.setStrokeMiter(miterLimit); 2182cb93a386Sopenharmony_ci uiParamsChanged = true; 2183cb93a386Sopenharmony_ci } 2184cb93a386Sopenharmony_ci } 2185cb93a386Sopenharmony_ci 2186cb93a386Sopenharmony_ci int capIdx = 0; 2187cb93a386Sopenharmony_ci if (fPaintOverrides.fCapType) { 2188cb93a386Sopenharmony_ci capIdx = SkTo<int>(fPaint.getStrokeCap()) + 1; 2189cb93a386Sopenharmony_ci } 2190cb93a386Sopenharmony_ci if (ImGui::Combo("Cap Type", &capIdx, 2191cb93a386Sopenharmony_ci "Default\0Butt\0Round\0Square\0\0")) 2192cb93a386Sopenharmony_ci { 2193cb93a386Sopenharmony_ci if (capIdx == 0) { 2194cb93a386Sopenharmony_ci fPaintOverrides.fCapType = false; 2195cb93a386Sopenharmony_ci fPaint.setStrokeCap(SkPaint::kDefault_Cap); 2196cb93a386Sopenharmony_ci } else { 2197cb93a386Sopenharmony_ci fPaint.setStrokeCap(SkTo<SkPaint::Cap>(capIdx - 1)); 2198cb93a386Sopenharmony_ci fPaintOverrides.fCapType = true; 2199cb93a386Sopenharmony_ci } 2200cb93a386Sopenharmony_ci uiParamsChanged = true; 2201cb93a386Sopenharmony_ci } 2202cb93a386Sopenharmony_ci 2203cb93a386Sopenharmony_ci int joinIdx = 0; 2204cb93a386Sopenharmony_ci if (fPaintOverrides.fJoinType) { 2205cb93a386Sopenharmony_ci joinIdx = SkTo<int>(fPaint.getStrokeJoin()) + 1; 2206cb93a386Sopenharmony_ci } 2207cb93a386Sopenharmony_ci if (ImGui::Combo("Join Type", &joinIdx, 2208cb93a386Sopenharmony_ci "Default\0Miter\0Round\0Bevel\0\0")) 2209cb93a386Sopenharmony_ci { 2210cb93a386Sopenharmony_ci if (joinIdx == 0) { 2211cb93a386Sopenharmony_ci fPaintOverrides.fJoinType = false; 2212cb93a386Sopenharmony_ci fPaint.setStrokeJoin(SkPaint::kDefault_Join); 2213cb93a386Sopenharmony_ci } else { 2214cb93a386Sopenharmony_ci fPaint.setStrokeJoin(SkTo<SkPaint::Join>(joinIdx - 1)); 2215cb93a386Sopenharmony_ci fPaintOverrides.fJoinType = true; 2216cb93a386Sopenharmony_ci } 2217cb93a386Sopenharmony_ci uiParamsChanged = true; 2218cb93a386Sopenharmony_ci } 2219cb93a386Sopenharmony_ci } 2220cb93a386Sopenharmony_ci 2221cb93a386Sopenharmony_ci if (ImGui::CollapsingHeader("Font")) { 2222cb93a386Sopenharmony_ci int hintingIdx = 0; 2223cb93a386Sopenharmony_ci if (fFontOverrides.fHinting) { 2224cb93a386Sopenharmony_ci hintingIdx = SkTo<int>(fFont.getHinting()) + 1; 2225cb93a386Sopenharmony_ci } 2226cb93a386Sopenharmony_ci if (ImGui::Combo("Hinting", &hintingIdx, 2227cb93a386Sopenharmony_ci "Default\0None\0Slight\0Normal\0Full\0\0")) 2228cb93a386Sopenharmony_ci { 2229cb93a386Sopenharmony_ci if (hintingIdx == 0) { 2230cb93a386Sopenharmony_ci fFontOverrides.fHinting = false; 2231cb93a386Sopenharmony_ci fFont.setHinting(SkFontHinting::kNone); 2232cb93a386Sopenharmony_ci } else { 2233cb93a386Sopenharmony_ci fFont.setHinting(SkTo<SkFontHinting>(hintingIdx - 1)); 2234cb93a386Sopenharmony_ci fFontOverrides.fHinting = true; 2235cb93a386Sopenharmony_ci } 2236cb93a386Sopenharmony_ci uiParamsChanged = true; 2237cb93a386Sopenharmony_ci } 2238cb93a386Sopenharmony_ci 2239cb93a386Sopenharmony_ci auto fontFlag = [this, &uiParamsChanged](const char* label, const char* items, 2240cb93a386Sopenharmony_ci bool SkFontFields::* flag, 2241cb93a386Sopenharmony_ci bool (SkFont::* isFlag)() const, 2242cb93a386Sopenharmony_ci void (SkFont::* setFlag)(bool) ) 2243cb93a386Sopenharmony_ci { 2244cb93a386Sopenharmony_ci int itemIndex = 0; 2245cb93a386Sopenharmony_ci if (fFontOverrides.*flag) { 2246cb93a386Sopenharmony_ci itemIndex = (fFont.*isFlag)() ? 2 : 1; 2247cb93a386Sopenharmony_ci } 2248cb93a386Sopenharmony_ci if (ImGui::Combo(label, &itemIndex, items)) { 2249cb93a386Sopenharmony_ci if (itemIndex == 0) { 2250cb93a386Sopenharmony_ci fFontOverrides.*flag = false; 2251cb93a386Sopenharmony_ci } else { 2252cb93a386Sopenharmony_ci fFontOverrides.*flag = true; 2253cb93a386Sopenharmony_ci (fFont.*setFlag)(itemIndex == 2); 2254cb93a386Sopenharmony_ci } 2255cb93a386Sopenharmony_ci uiParamsChanged = true; 2256cb93a386Sopenharmony_ci } 2257cb93a386Sopenharmony_ci }; 2258cb93a386Sopenharmony_ci 2259cb93a386Sopenharmony_ci fontFlag("Fake Bold Glyphs", 2260cb93a386Sopenharmony_ci "Default\0No Fake Bold\0Fake Bold\0\0", 2261cb93a386Sopenharmony_ci &SkFontFields::fEmbolden, 2262cb93a386Sopenharmony_ci &SkFont::isEmbolden, &SkFont::setEmbolden); 2263cb93a386Sopenharmony_ci 2264cb93a386Sopenharmony_ci fontFlag("Baseline Snapping", 2265cb93a386Sopenharmony_ci "Default\0No Baseline Snapping\0Baseline Snapping\0\0", 2266cb93a386Sopenharmony_ci &SkFontFields::fBaselineSnap, 2267cb93a386Sopenharmony_ci &SkFont::isBaselineSnap, &SkFont::setBaselineSnap); 2268cb93a386Sopenharmony_ci 2269cb93a386Sopenharmony_ci fontFlag("Linear Text", 2270cb93a386Sopenharmony_ci "Default\0No Linear Text\0Linear Text\0\0", 2271cb93a386Sopenharmony_ci &SkFontFields::fLinearMetrics, 2272cb93a386Sopenharmony_ci &SkFont::isLinearMetrics, &SkFont::setLinearMetrics); 2273cb93a386Sopenharmony_ci 2274cb93a386Sopenharmony_ci fontFlag("Subpixel Position Glyphs", 2275cb93a386Sopenharmony_ci "Default\0Pixel Text\0Subpixel Text\0\0", 2276cb93a386Sopenharmony_ci &SkFontFields::fSubpixel, 2277cb93a386Sopenharmony_ci &SkFont::isSubpixel, &SkFont::setSubpixel); 2278cb93a386Sopenharmony_ci 2279cb93a386Sopenharmony_ci fontFlag("Embedded Bitmap Text", 2280cb93a386Sopenharmony_ci "Default\0No Embedded Bitmaps\0Embedded Bitmaps\0\0", 2281cb93a386Sopenharmony_ci &SkFontFields::fEmbeddedBitmaps, 2282cb93a386Sopenharmony_ci &SkFont::isEmbeddedBitmaps, &SkFont::setEmbeddedBitmaps); 2283cb93a386Sopenharmony_ci 2284cb93a386Sopenharmony_ci fontFlag("Force Auto-Hinting", 2285cb93a386Sopenharmony_ci "Default\0No Force Auto-Hinting\0Force Auto-Hinting\0\0", 2286cb93a386Sopenharmony_ci &SkFontFields::fForceAutoHinting, 2287cb93a386Sopenharmony_ci &SkFont::isForceAutoHinting, &SkFont::setForceAutoHinting); 2288cb93a386Sopenharmony_ci 2289cb93a386Sopenharmony_ci int edgingIdx = 0; 2290cb93a386Sopenharmony_ci if (fFontOverrides.fEdging) { 2291cb93a386Sopenharmony_ci edgingIdx = SkTo<int>(fFont.getEdging()) + 1; 2292cb93a386Sopenharmony_ci } 2293cb93a386Sopenharmony_ci if (ImGui::Combo("Edging", &edgingIdx, 2294cb93a386Sopenharmony_ci "Default\0Alias\0Antialias\0Subpixel Antialias\0\0")) 2295cb93a386Sopenharmony_ci { 2296cb93a386Sopenharmony_ci if (edgingIdx == 0) { 2297cb93a386Sopenharmony_ci fFontOverrides.fEdging = false; 2298cb93a386Sopenharmony_ci fFont.setEdging(SkFont::Edging::kAlias); 2299cb93a386Sopenharmony_ci } else { 2300cb93a386Sopenharmony_ci fFont.setEdging(SkTo<SkFont::Edging>(edgingIdx-1)); 2301cb93a386Sopenharmony_ci fFontOverrides.fEdging = true; 2302cb93a386Sopenharmony_ci } 2303cb93a386Sopenharmony_ci uiParamsChanged = true; 2304cb93a386Sopenharmony_ci } 2305cb93a386Sopenharmony_ci 2306cb93a386Sopenharmony_ci ImGui::Checkbox("Override Size", &fFontOverrides.fSize); 2307cb93a386Sopenharmony_ci if (fFontOverrides.fSize) { 2308cb93a386Sopenharmony_ci ImGui::DragFloat2("TextRange", fFontOverrides.fSizeRange, 2309cb93a386Sopenharmony_ci 0.001f, -10.0f, 300.0f, "%.6f", 2.0f); 2310cb93a386Sopenharmony_ci float textSize = fFont.getSize(); 2311cb93a386Sopenharmony_ci if (ImGui::DragFloat("TextSize", &textSize, 0.001f, 2312cb93a386Sopenharmony_ci fFontOverrides.fSizeRange[0], 2313cb93a386Sopenharmony_ci fFontOverrides.fSizeRange[1], 2314cb93a386Sopenharmony_ci "%.6f", 2.0f)) 2315cb93a386Sopenharmony_ci { 2316cb93a386Sopenharmony_ci fFont.setSize(textSize); 2317cb93a386Sopenharmony_ci uiParamsChanged = true; 2318cb93a386Sopenharmony_ci } 2319cb93a386Sopenharmony_ci } 2320cb93a386Sopenharmony_ci 2321cb93a386Sopenharmony_ci ImGui::Checkbox("Override ScaleX", &fFontOverrides.fScaleX); 2322cb93a386Sopenharmony_ci if (fFontOverrides.fScaleX) { 2323cb93a386Sopenharmony_ci float scaleX = fFont.getScaleX(); 2324cb93a386Sopenharmony_ci if (ImGui::SliderFloat("ScaleX", &scaleX, MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL)) { 2325cb93a386Sopenharmony_ci fFont.setScaleX(scaleX); 2326cb93a386Sopenharmony_ci uiParamsChanged = true; 2327cb93a386Sopenharmony_ci } 2328cb93a386Sopenharmony_ci } 2329cb93a386Sopenharmony_ci 2330cb93a386Sopenharmony_ci ImGui::Checkbox("Override SkewX", &fFontOverrides.fSkewX); 2331cb93a386Sopenharmony_ci if (fFontOverrides.fSkewX) { 2332cb93a386Sopenharmony_ci float skewX = fFont.getSkewX(); 2333cb93a386Sopenharmony_ci if (ImGui::SliderFloat("SkewX", &skewX, MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL)) { 2334cb93a386Sopenharmony_ci fFont.setSkewX(skewX); 2335cb93a386Sopenharmony_ci uiParamsChanged = true; 2336cb93a386Sopenharmony_ci } 2337cb93a386Sopenharmony_ci } 2338cb93a386Sopenharmony_ci } 2339cb93a386Sopenharmony_ci 2340cb93a386Sopenharmony_ci { 2341cb93a386Sopenharmony_ci SkMetaData controls; 2342cb93a386Sopenharmony_ci if (fSlides[fCurrentSlide]->onGetControls(&controls)) { 2343cb93a386Sopenharmony_ci if (ImGui::CollapsingHeader("Current Slide")) { 2344cb93a386Sopenharmony_ci SkMetaData::Iter iter(controls); 2345cb93a386Sopenharmony_ci const char* name; 2346cb93a386Sopenharmony_ci SkMetaData::Type type; 2347cb93a386Sopenharmony_ci int count; 2348cb93a386Sopenharmony_ci while ((name = iter.next(&type, &count)) != nullptr) { 2349cb93a386Sopenharmony_ci if (type == SkMetaData::kScalar_Type) { 2350cb93a386Sopenharmony_ci float val[3]; 2351cb93a386Sopenharmony_ci SkASSERT(count == 3); 2352cb93a386Sopenharmony_ci controls.findScalars(name, &count, val); 2353cb93a386Sopenharmony_ci if (ImGui::SliderFloat(name, &val[0], val[1], val[2])) { 2354cb93a386Sopenharmony_ci controls.setScalars(name, 3, val); 2355cb93a386Sopenharmony_ci } 2356cb93a386Sopenharmony_ci } else if (type == SkMetaData::kBool_Type) { 2357cb93a386Sopenharmony_ci bool val; 2358cb93a386Sopenharmony_ci SkASSERT(count == 1); 2359cb93a386Sopenharmony_ci controls.findBool(name, &val); 2360cb93a386Sopenharmony_ci if (ImGui::Checkbox(name, &val)) { 2361cb93a386Sopenharmony_ci controls.setBool(name, val); 2362cb93a386Sopenharmony_ci } 2363cb93a386Sopenharmony_ci } 2364cb93a386Sopenharmony_ci } 2365cb93a386Sopenharmony_ci fSlides[fCurrentSlide]->onSetControls(controls); 2366cb93a386Sopenharmony_ci } 2367cb93a386Sopenharmony_ci } 2368cb93a386Sopenharmony_ci } 2369cb93a386Sopenharmony_ci 2370cb93a386Sopenharmony_ci if (fShowSlidePicker) { 2371cb93a386Sopenharmony_ci ImGui::SetNextTreeNodeOpen(true); 2372cb93a386Sopenharmony_ci } 2373cb93a386Sopenharmony_ci if (ImGui::CollapsingHeader("Slide")) { 2374cb93a386Sopenharmony_ci static ImGuiTextFilter filter; 2375cb93a386Sopenharmony_ci static ImVector<const char*> filteredSlideNames; 2376cb93a386Sopenharmony_ci static ImVector<int> filteredSlideIndices; 2377cb93a386Sopenharmony_ci 2378cb93a386Sopenharmony_ci if (fShowSlidePicker) { 2379cb93a386Sopenharmony_ci ImGui::SetKeyboardFocusHere(); 2380cb93a386Sopenharmony_ci fShowSlidePicker = false; 2381cb93a386Sopenharmony_ci } 2382cb93a386Sopenharmony_ci 2383cb93a386Sopenharmony_ci filter.Draw(); 2384cb93a386Sopenharmony_ci filteredSlideNames.clear(); 2385cb93a386Sopenharmony_ci filteredSlideIndices.clear(); 2386cb93a386Sopenharmony_ci int filteredIndex = 0; 2387cb93a386Sopenharmony_ci for (int i = 0; i < fSlides.count(); ++i) { 2388cb93a386Sopenharmony_ci const char* slideName = fSlides[i]->getName().c_str(); 2389cb93a386Sopenharmony_ci if (filter.PassFilter(slideName) || i == fCurrentSlide) { 2390cb93a386Sopenharmony_ci if (i == fCurrentSlide) { 2391cb93a386Sopenharmony_ci filteredIndex = filteredSlideIndices.size(); 2392cb93a386Sopenharmony_ci } 2393cb93a386Sopenharmony_ci filteredSlideNames.push_back(slideName); 2394cb93a386Sopenharmony_ci filteredSlideIndices.push_back(i); 2395cb93a386Sopenharmony_ci } 2396cb93a386Sopenharmony_ci } 2397cb93a386Sopenharmony_ci 2398cb93a386Sopenharmony_ci if (ImGui::ListBox("", &filteredIndex, filteredSlideNames.begin(), 2399cb93a386Sopenharmony_ci filteredSlideNames.size(), 20)) { 2400cb93a386Sopenharmony_ci this->setCurrentSlide(filteredSlideIndices[filteredIndex]); 2401cb93a386Sopenharmony_ci } 2402cb93a386Sopenharmony_ci } 2403cb93a386Sopenharmony_ci 2404cb93a386Sopenharmony_ci if (ImGui::CollapsingHeader("Color Mode")) { 2405cb93a386Sopenharmony_ci ColorMode newMode = fColorMode; 2406cb93a386Sopenharmony_ci auto cmButton = [&](ColorMode mode, const char* label) { 2407cb93a386Sopenharmony_ci if (ImGui::RadioButton(label, mode == fColorMode)) { 2408cb93a386Sopenharmony_ci newMode = mode; 2409cb93a386Sopenharmony_ci } 2410cb93a386Sopenharmony_ci }; 2411cb93a386Sopenharmony_ci 2412cb93a386Sopenharmony_ci cmButton(ColorMode::kLegacy, "Legacy 8888"); 2413cb93a386Sopenharmony_ci cmButton(ColorMode::kColorManaged8888, "Color Managed 8888"); 2414cb93a386Sopenharmony_ci cmButton(ColorMode::kColorManagedF16, "Color Managed F16"); 2415cb93a386Sopenharmony_ci cmButton(ColorMode::kColorManagedF16Norm, "Color Managed F16 Norm"); 2416cb93a386Sopenharmony_ci 2417cb93a386Sopenharmony_ci if (newMode != fColorMode) { 2418cb93a386Sopenharmony_ci this->setColorMode(newMode); 2419cb93a386Sopenharmony_ci } 2420cb93a386Sopenharmony_ci 2421cb93a386Sopenharmony_ci // Pick from common gamuts: 2422cb93a386Sopenharmony_ci int primariesIdx = 4; // Default: Custom 2423cb93a386Sopenharmony_ci for (size_t i = 0; i < SK_ARRAY_COUNT(gNamedPrimaries); ++i) { 2424cb93a386Sopenharmony_ci if (primaries_equal(*gNamedPrimaries[i].fPrimaries, fColorSpacePrimaries)) { 2425cb93a386Sopenharmony_ci primariesIdx = i; 2426cb93a386Sopenharmony_ci break; 2427cb93a386Sopenharmony_ci } 2428cb93a386Sopenharmony_ci } 2429cb93a386Sopenharmony_ci 2430cb93a386Sopenharmony_ci // Let user adjust the gamma 2431cb93a386Sopenharmony_ci ImGui::SliderFloat("Gamma", &fColorSpaceTransferFn.g, 0.5f, 3.5f); 2432cb93a386Sopenharmony_ci 2433cb93a386Sopenharmony_ci if (ImGui::Combo("Primaries", &primariesIdx, 2434cb93a386Sopenharmony_ci "sRGB\0AdobeRGB\0P3\0Rec. 2020\0Custom\0\0")) { 2435cb93a386Sopenharmony_ci if (primariesIdx >= 0 && primariesIdx <= 3) { 2436cb93a386Sopenharmony_ci fColorSpacePrimaries = *gNamedPrimaries[primariesIdx].fPrimaries; 2437cb93a386Sopenharmony_ci } 2438cb93a386Sopenharmony_ci } 2439cb93a386Sopenharmony_ci 2440cb93a386Sopenharmony_ci if (ImGui::Button("Spin")) { 2441cb93a386Sopenharmony_ci float rx = fColorSpacePrimaries.fRX, 2442cb93a386Sopenharmony_ci ry = fColorSpacePrimaries.fRY; 2443cb93a386Sopenharmony_ci fColorSpacePrimaries.fRX = fColorSpacePrimaries.fGX; 2444cb93a386Sopenharmony_ci fColorSpacePrimaries.fRY = fColorSpacePrimaries.fGY; 2445cb93a386Sopenharmony_ci fColorSpacePrimaries.fGX = fColorSpacePrimaries.fBX; 2446cb93a386Sopenharmony_ci fColorSpacePrimaries.fGY = fColorSpacePrimaries.fBY; 2447cb93a386Sopenharmony_ci fColorSpacePrimaries.fBX = rx; 2448cb93a386Sopenharmony_ci fColorSpacePrimaries.fBY = ry; 2449cb93a386Sopenharmony_ci } 2450cb93a386Sopenharmony_ci 2451cb93a386Sopenharmony_ci // Allow direct editing of gamut 2452cb93a386Sopenharmony_ci ImGui_Primaries(&fColorSpacePrimaries, &fImGuiGamutPaint); 2453cb93a386Sopenharmony_ci } 2454cb93a386Sopenharmony_ci 2455cb93a386Sopenharmony_ci if (ImGui::CollapsingHeader("Animation")) { 2456cb93a386Sopenharmony_ci bool isPaused = AnimTimer::kPaused_State == fAnimTimer.state(); 2457cb93a386Sopenharmony_ci if (ImGui::Checkbox("Pause", &isPaused)) { 2458cb93a386Sopenharmony_ci fAnimTimer.togglePauseResume(); 2459cb93a386Sopenharmony_ci } 2460cb93a386Sopenharmony_ci 2461cb93a386Sopenharmony_ci float speed = fAnimTimer.getSpeed(); 2462cb93a386Sopenharmony_ci if (ImGui::DragFloat("Speed", &speed, 0.1f)) { 2463cb93a386Sopenharmony_ci fAnimTimer.setSpeed(speed); 2464cb93a386Sopenharmony_ci } 2465cb93a386Sopenharmony_ci } 2466cb93a386Sopenharmony_ci 2467cb93a386Sopenharmony_ci if (ImGui::CollapsingHeader("Shaders")) { 2468cb93a386Sopenharmony_ci bool sksl = params.fGrContextOptions.fShaderCacheStrategy == 2469cb93a386Sopenharmony_ci GrContextOptions::ShaderCacheStrategy::kSkSL; 2470cb93a386Sopenharmony_ci 2471cb93a386Sopenharmony_ci#if defined(SK_VULKAN) 2472cb93a386Sopenharmony_ci const bool isVulkan = fBackendType == sk_app::Window::kVulkan_BackendType; 2473cb93a386Sopenharmony_ci#else 2474cb93a386Sopenharmony_ci const bool isVulkan = false; 2475cb93a386Sopenharmony_ci#endif 2476cb93a386Sopenharmony_ci 2477cb93a386Sopenharmony_ci // To re-load shaders from the currently active programs, we flush all 2478cb93a386Sopenharmony_ci // caches on one frame, then set a flag to poll the cache on the next frame. 2479cb93a386Sopenharmony_ci static bool gLoadPending = false; 2480cb93a386Sopenharmony_ci if (gLoadPending) { 2481cb93a386Sopenharmony_ci auto collectShaders = [this](sk_sp<const SkData> key, sk_sp<SkData> data, 2482cb93a386Sopenharmony_ci const SkString& description, int hitCount) { 2483cb93a386Sopenharmony_ci CachedShader& entry(fCachedShaders.push_back()); 2484cb93a386Sopenharmony_ci entry.fKey = key; 2485cb93a386Sopenharmony_ci SkMD5 hash; 2486cb93a386Sopenharmony_ci hash.write(key->bytes(), key->size()); 2487cb93a386Sopenharmony_ci SkMD5::Digest digest = hash.finish(); 2488cb93a386Sopenharmony_ci for (int i = 0; i < 16; ++i) { 2489cb93a386Sopenharmony_ci entry.fKeyString.appendf("%02x", digest.data[i]); 2490cb93a386Sopenharmony_ci } 2491cb93a386Sopenharmony_ci entry.fKeyDescription = description; 2492cb93a386Sopenharmony_ci 2493cb93a386Sopenharmony_ci SkReadBuffer reader(data->data(), data->size()); 2494cb93a386Sopenharmony_ci entry.fShaderType = GrPersistentCacheUtils::GetType(&reader); 2495cb93a386Sopenharmony_ci GrPersistentCacheUtils::UnpackCachedShaders(&reader, entry.fShader, 2496cb93a386Sopenharmony_ci entry.fInputs, 2497cb93a386Sopenharmony_ci kGrShaderTypeCount); 2498cb93a386Sopenharmony_ci }; 2499cb93a386Sopenharmony_ci fCachedShaders.reset(); 2500cb93a386Sopenharmony_ci fPersistentCache.foreach(collectShaders); 2501cb93a386Sopenharmony_ci gLoadPending = false; 2502cb93a386Sopenharmony_ci 2503cb93a386Sopenharmony_ci#if defined(SK_VULKAN) 2504cb93a386Sopenharmony_ci if (isVulkan && !sksl) { 2505cb93a386Sopenharmony_ci spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0); 2506cb93a386Sopenharmony_ci for (auto& entry : fCachedShaders) { 2507cb93a386Sopenharmony_ci for (int i = 0; i < kGrShaderTypeCount; ++i) { 2508cb93a386Sopenharmony_ci const SkSL::String& spirv(entry.fShader[i]); 2509cb93a386Sopenharmony_ci std::string disasm; 2510cb93a386Sopenharmony_ci tools.Disassemble((const uint32_t*)spirv.c_str(), spirv.size() / 4, 2511cb93a386Sopenharmony_ci &disasm); 2512cb93a386Sopenharmony_ci entry.fShader[i].assign(disasm); 2513cb93a386Sopenharmony_ci } 2514cb93a386Sopenharmony_ci } 2515cb93a386Sopenharmony_ci } 2516cb93a386Sopenharmony_ci#endif 2517cb93a386Sopenharmony_ci } 2518cb93a386Sopenharmony_ci 2519cb93a386Sopenharmony_ci // Defer actually doing the View/Apply logic so that we can trigger an Apply when we 2520cb93a386Sopenharmony_ci // start or finish hovering on a tree node in the list below: 2521cb93a386Sopenharmony_ci bool doView = ImGui::Button("View"); ImGui::SameLine(); 2522cb93a386Sopenharmony_ci bool doApply = ImGui::Button("Apply Changes"); ImGui::SameLine(); 2523cb93a386Sopenharmony_ci bool doDump = ImGui::Button("Dump SkSL to resources/sksl/"); 2524cb93a386Sopenharmony_ci 2525cb93a386Sopenharmony_ci int newOptLevel = fOptLevel; 2526cb93a386Sopenharmony_ci ImGui::RadioButton("SkSL", &newOptLevel, kShaderOptLevel_Source); 2527cb93a386Sopenharmony_ci ImGui::SameLine(); 2528cb93a386Sopenharmony_ci ImGui::RadioButton("Compile", &newOptLevel, kShaderOptLevel_Compile); 2529cb93a386Sopenharmony_ci ImGui::SameLine(); 2530cb93a386Sopenharmony_ci ImGui::RadioButton("Optimize", &newOptLevel, kShaderOptLevel_Optimize); 2531cb93a386Sopenharmony_ci ImGui::SameLine(); 2532cb93a386Sopenharmony_ci ImGui::RadioButton("Inline", &newOptLevel, kShaderOptLevel_Inline); 2533cb93a386Sopenharmony_ci 2534cb93a386Sopenharmony_ci // If we are changing the compile mode, we want to reset the cache and redo 2535cb93a386Sopenharmony_ci // everything. 2536cb93a386Sopenharmony_ci if (doDump || newOptLevel != fOptLevel) { 2537cb93a386Sopenharmony_ci sksl = doDump || (newOptLevel == kShaderOptLevel_Source); 2538cb93a386Sopenharmony_ci fOptLevel = (ShaderOptLevel)newOptLevel; 2539cb93a386Sopenharmony_ci switch (fOptLevel) { 2540cb93a386Sopenharmony_ci case kShaderOptLevel_Source: 2541cb93a386Sopenharmony_ci Compiler::EnableOptimizer(OverrideFlag::kDefault); 2542cb93a386Sopenharmony_ci Compiler::EnableInliner(OverrideFlag::kDefault); 2543cb93a386Sopenharmony_ci break; 2544cb93a386Sopenharmony_ci case kShaderOptLevel_Compile: 2545cb93a386Sopenharmony_ci Compiler::EnableOptimizer(OverrideFlag::kOff); 2546cb93a386Sopenharmony_ci Compiler::EnableInliner(OverrideFlag::kOff); 2547cb93a386Sopenharmony_ci break; 2548cb93a386Sopenharmony_ci case kShaderOptLevel_Optimize: 2549cb93a386Sopenharmony_ci Compiler::EnableOptimizer(OverrideFlag::kOn); 2550cb93a386Sopenharmony_ci Compiler::EnableInliner(OverrideFlag::kOff); 2551cb93a386Sopenharmony_ci break; 2552cb93a386Sopenharmony_ci case kShaderOptLevel_Inline: 2553cb93a386Sopenharmony_ci Compiler::EnableOptimizer(OverrideFlag::kOn); 2554cb93a386Sopenharmony_ci Compiler::EnableInliner(OverrideFlag::kOn); 2555cb93a386Sopenharmony_ci break; 2556cb93a386Sopenharmony_ci } 2557cb93a386Sopenharmony_ci 2558cb93a386Sopenharmony_ci params.fGrContextOptions.fShaderCacheStrategy = 2559cb93a386Sopenharmony_ci sksl ? GrContextOptions::ShaderCacheStrategy::kSkSL 2560cb93a386Sopenharmony_ci : GrContextOptions::ShaderCacheStrategy::kBackendSource; 2561cb93a386Sopenharmony_ci displayParamsChanged = true; 2562cb93a386Sopenharmony_ci doView = true; 2563cb93a386Sopenharmony_ci 2564cb93a386Sopenharmony_ci fDeferredActions.push_back([=]() { 2565cb93a386Sopenharmony_ci // Reset the cache. 2566cb93a386Sopenharmony_ci fPersistentCache.reset(); 2567cb93a386Sopenharmony_ci // Dump the cache once we have drawn a frame with it. 2568cb93a386Sopenharmony_ci if (doDump) { 2569cb93a386Sopenharmony_ci fDeferredActions.push_back([this]() { 2570cb93a386Sopenharmony_ci this->dumpShadersToResources(); 2571cb93a386Sopenharmony_ci }); 2572cb93a386Sopenharmony_ci } 2573cb93a386Sopenharmony_ci }); 2574cb93a386Sopenharmony_ci } 2575cb93a386Sopenharmony_ci 2576cb93a386Sopenharmony_ci ImGui::BeginChild("##ScrollingRegion"); 2577cb93a386Sopenharmony_ci for (auto& entry : fCachedShaders) { 2578cb93a386Sopenharmony_ci bool inTreeNode = ImGui::TreeNode(entry.fKeyString.c_str()); 2579cb93a386Sopenharmony_ci bool hovered = ImGui::IsItemHovered(); 2580cb93a386Sopenharmony_ci if (hovered != entry.fHovered) { 2581cb93a386Sopenharmony_ci // Force an Apply to patch the highlight shader in/out 2582cb93a386Sopenharmony_ci entry.fHovered = hovered; 2583cb93a386Sopenharmony_ci doApply = true; 2584cb93a386Sopenharmony_ci } 2585cb93a386Sopenharmony_ci if (inTreeNode) { 2586cb93a386Sopenharmony_ci auto stringBox = [](const char* label, std::string* str) { 2587cb93a386Sopenharmony_ci // Full width, and not too much space for each shader 2588cb93a386Sopenharmony_ci int lines = std::count(str->begin(), str->end(), '\n') + 2; 2589cb93a386Sopenharmony_ci ImVec2 boxSize(-1.0f, ImGui::GetTextLineHeight() * std::min(lines, 30)); 2590cb93a386Sopenharmony_ci ImGui::InputTextMultiline(label, str, boxSize); 2591cb93a386Sopenharmony_ci }; 2592cb93a386Sopenharmony_ci if (ImGui::TreeNode("Key")) { 2593cb93a386Sopenharmony_ci ImGui::TextWrapped("%s", entry.fKeyDescription.c_str()); 2594cb93a386Sopenharmony_ci ImGui::TreePop(); 2595cb93a386Sopenharmony_ci } 2596cb93a386Sopenharmony_ci stringBox("##VP", &entry.fShader[kVertex_GrShaderType]); 2597cb93a386Sopenharmony_ci stringBox("##FP", &entry.fShader[kFragment_GrShaderType]); 2598cb93a386Sopenharmony_ci ImGui::TreePop(); 2599cb93a386Sopenharmony_ci } 2600cb93a386Sopenharmony_ci } 2601cb93a386Sopenharmony_ci ImGui::EndChild(); 2602cb93a386Sopenharmony_ci 2603cb93a386Sopenharmony_ci if (doView) { 2604cb93a386Sopenharmony_ci fPersistentCache.reset(); 2605cb93a386Sopenharmony_ci ctx->priv().getGpu()->resetShaderCacheForTesting(); 2606cb93a386Sopenharmony_ci gLoadPending = true; 2607cb93a386Sopenharmony_ci } 2608cb93a386Sopenharmony_ci 2609cb93a386Sopenharmony_ci // We don't support updating SPIRV shaders. We could re-assemble them (with edits), 2610cb93a386Sopenharmony_ci // but I'm not sure anyone wants to do that. 2611cb93a386Sopenharmony_ci if (isVulkan && !sksl) { 2612cb93a386Sopenharmony_ci doApply = false; 2613cb93a386Sopenharmony_ci } 2614cb93a386Sopenharmony_ci if (doApply) { 2615cb93a386Sopenharmony_ci fPersistentCache.reset(); 2616cb93a386Sopenharmony_ci ctx->priv().getGpu()->resetShaderCacheForTesting(); 2617cb93a386Sopenharmony_ci for (auto& entry : fCachedShaders) { 2618cb93a386Sopenharmony_ci SkSL::String backup = entry.fShader[kFragment_GrShaderType]; 2619cb93a386Sopenharmony_ci if (entry.fHovered) { 2620cb93a386Sopenharmony_ci // The hovered item (if any) gets a special shader to make it 2621cb93a386Sopenharmony_ci // identifiable. 2622cb93a386Sopenharmony_ci SkSL::String& fragShader = entry.fShader[kFragment_GrShaderType]; 2623cb93a386Sopenharmony_ci switch (entry.fShaderType) { 2624cb93a386Sopenharmony_ci case SkSetFourByteTag('S', 'K', 'S', 'L'): { 2625cb93a386Sopenharmony_ci fragShader = build_sksl_highlight_shader(); 2626cb93a386Sopenharmony_ci break; 2627cb93a386Sopenharmony_ci } 2628cb93a386Sopenharmony_ci case SkSetFourByteTag('G', 'L', 'S', 'L'): { 2629cb93a386Sopenharmony_ci fragShader = build_glsl_highlight_shader( 2630cb93a386Sopenharmony_ci *ctx->priv().caps()->shaderCaps()); 2631cb93a386Sopenharmony_ci break; 2632cb93a386Sopenharmony_ci } 2633cb93a386Sopenharmony_ci case SkSetFourByteTag('M', 'S', 'L', ' '): { 2634cb93a386Sopenharmony_ci fragShader = build_metal_highlight_shader(fragShader); 2635cb93a386Sopenharmony_ci break; 2636cb93a386Sopenharmony_ci } 2637cb93a386Sopenharmony_ci } 2638cb93a386Sopenharmony_ci } 2639cb93a386Sopenharmony_ci 2640cb93a386Sopenharmony_ci auto data = GrPersistentCacheUtils::PackCachedShaders(entry.fShaderType, 2641cb93a386Sopenharmony_ci entry.fShader, 2642cb93a386Sopenharmony_ci entry.fInputs, 2643cb93a386Sopenharmony_ci kGrShaderTypeCount); 2644cb93a386Sopenharmony_ci fPersistentCache.store(*entry.fKey, *data, entry.fKeyDescription); 2645cb93a386Sopenharmony_ci 2646cb93a386Sopenharmony_ci entry.fShader[kFragment_GrShaderType] = backup; 2647cb93a386Sopenharmony_ci } 2648cb93a386Sopenharmony_ci } 2649cb93a386Sopenharmony_ci } 2650cb93a386Sopenharmony_ci 2651cb93a386Sopenharmony_ci if (ImGui::CollapsingHeader("SkVM")) { 2652cb93a386Sopenharmony_ci auto* cache = SkVMBlitter::TryAcquireProgramCache(); 2653cb93a386Sopenharmony_ci SkASSERT(cache); 2654cb93a386Sopenharmony_ci 2655cb93a386Sopenharmony_ci if (ImGui::Button("Clear")) { 2656cb93a386Sopenharmony_ci cache->reset(); 2657cb93a386Sopenharmony_ci fDisassemblyCache.reset(); 2658cb93a386Sopenharmony_ci } 2659cb93a386Sopenharmony_ci 2660cb93a386Sopenharmony_ci // First, go through the cache and restore the original program if we were hovering 2661cb93a386Sopenharmony_ci if (!fHoveredProgram.empty()) { 2662cb93a386Sopenharmony_ci auto restoreHoveredProgram = [this](const SkVMBlitter::Key* key, 2663cb93a386Sopenharmony_ci skvm::Program* program) { 2664cb93a386Sopenharmony_ci if (*key == fHoveredKey) { 2665cb93a386Sopenharmony_ci *program = std::move(fHoveredProgram); 2666cb93a386Sopenharmony_ci fHoveredProgram = {}; 2667cb93a386Sopenharmony_ci } 2668cb93a386Sopenharmony_ci }; 2669cb93a386Sopenharmony_ci cache->foreach(restoreHoveredProgram); 2670cb93a386Sopenharmony_ci } 2671cb93a386Sopenharmony_ci 2672cb93a386Sopenharmony_ci // Now iterate again, and dump any expanded program. If any program is hovered, 2673cb93a386Sopenharmony_ci // patch it, and remember the original (so it can be restored next frame). 2674cb93a386Sopenharmony_ci auto showVMEntry = [this](const SkVMBlitter::Key* key, skvm::Program* program) { 2675cb93a386Sopenharmony_ci SkString keyString = SkVMBlitter::DebugName(*key); 2676cb93a386Sopenharmony_ci bool inTreeNode = ImGui::TreeNode(keyString.c_str()); 2677cb93a386Sopenharmony_ci bool hovered = ImGui::IsItemHovered(); 2678cb93a386Sopenharmony_ci 2679cb93a386Sopenharmony_ci if (inTreeNode) { 2680cb93a386Sopenharmony_ci auto stringBox = [](const char* label, std::string* str) { 2681cb93a386Sopenharmony_ci int lines = std::count(str->begin(), str->end(), '\n') + 2; 2682cb93a386Sopenharmony_ci ImVec2 boxSize(-1.0f, ImGui::GetTextLineHeight() * std::min(lines, 30)); 2683cb93a386Sopenharmony_ci ImGui::InputTextMultiline(label, str, boxSize); 2684cb93a386Sopenharmony_ci }; 2685cb93a386Sopenharmony_ci 2686cb93a386Sopenharmony_ci SkDynamicMemoryWStream stream; 2687cb93a386Sopenharmony_ci program->dump(&stream); 2688cb93a386Sopenharmony_ci auto dumpData = stream.detachAsData(); 2689cb93a386Sopenharmony_ci std::string dumpString((const char*)dumpData->data(), dumpData->size()); 2690cb93a386Sopenharmony_ci stringBox("##VM", &dumpString); 2691cb93a386Sopenharmony_ci 2692cb93a386Sopenharmony_ci#if defined(SKVM_JIT) 2693cb93a386Sopenharmony_ci std::string* asmString = fDisassemblyCache.find(*key); 2694cb93a386Sopenharmony_ci if (!asmString) { 2695cb93a386Sopenharmony_ci program->disassemble(&stream); 2696cb93a386Sopenharmony_ci auto asmData = stream.detachAsData(); 2697cb93a386Sopenharmony_ci asmString = fDisassemblyCache.set( 2698cb93a386Sopenharmony_ci *key, 2699cb93a386Sopenharmony_ci std::string((const char*)asmData->data(), asmData->size())); 2700cb93a386Sopenharmony_ci } 2701cb93a386Sopenharmony_ci stringBox("##ASM", asmString); 2702cb93a386Sopenharmony_ci#endif 2703cb93a386Sopenharmony_ci 2704cb93a386Sopenharmony_ci ImGui::TreePop(); 2705cb93a386Sopenharmony_ci } 2706cb93a386Sopenharmony_ci if (hovered) { 2707cb93a386Sopenharmony_ci // Generate a new blitter that just draws magenta 2708cb93a386Sopenharmony_ci skvm::Program highlightProgram = build_skvm_highlight_program( 2709cb93a386Sopenharmony_ci static_cast<SkColorType>(key->colorType), program->nargs()); 2710cb93a386Sopenharmony_ci 2711cb93a386Sopenharmony_ci fHoveredKey = *key; 2712cb93a386Sopenharmony_ci fHoveredProgram = std::move(*program); 2713cb93a386Sopenharmony_ci *program = std::move(highlightProgram); 2714cb93a386Sopenharmony_ci } 2715cb93a386Sopenharmony_ci }; 2716cb93a386Sopenharmony_ci cache->foreach(showVMEntry); 2717cb93a386Sopenharmony_ci 2718cb93a386Sopenharmony_ci SkVMBlitter::ReleaseProgramCache(); 2719cb93a386Sopenharmony_ci } 2720cb93a386Sopenharmony_ci } 2721cb93a386Sopenharmony_ci if (displayParamsChanged || uiParamsChanged) { 2722cb93a386Sopenharmony_ci fDeferredActions.push_back([=]() { 2723cb93a386Sopenharmony_ci if (displayParamsChanged) { 2724cb93a386Sopenharmony_ci fWindow->setRequestedDisplayParams(params); 2725cb93a386Sopenharmony_ci } 2726cb93a386Sopenharmony_ci fWindow->inval(); 2727cb93a386Sopenharmony_ci this->updateTitle(); 2728cb93a386Sopenharmony_ci }); 2729cb93a386Sopenharmony_ci } 2730cb93a386Sopenharmony_ci ImGui::End(); 2731cb93a386Sopenharmony_ci } 2732cb93a386Sopenharmony_ci 2733cb93a386Sopenharmony_ci if (gShaderErrorHandler.fErrors.count()) { 2734cb93a386Sopenharmony_ci ImGui::SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver); 2735cb93a386Sopenharmony_ci ImGui::Begin("Shader Errors", nullptr, ImGuiWindowFlags_NoFocusOnAppearing); 2736cb93a386Sopenharmony_ci for (int i = 0; i < gShaderErrorHandler.fErrors.count(); ++i) { 2737cb93a386Sopenharmony_ci ImGui::TextWrapped("%s", gShaderErrorHandler.fErrors[i].c_str()); 2738cb93a386Sopenharmony_ci SkSL::String sksl(gShaderErrorHandler.fShaders[i].c_str()); 2739cb93a386Sopenharmony_ci GrShaderUtils::VisitLineByLine(sksl, [](int lineNumber, const char* lineText) { 2740cb93a386Sopenharmony_ci ImGui::TextWrapped("%4i\t%s\n", lineNumber, lineText); 2741cb93a386Sopenharmony_ci }); 2742cb93a386Sopenharmony_ci } 2743cb93a386Sopenharmony_ci ImGui::End(); 2744cb93a386Sopenharmony_ci gShaderErrorHandler.reset(); 2745cb93a386Sopenharmony_ci } 2746cb93a386Sopenharmony_ci 2747cb93a386Sopenharmony_ci if (fShowZoomWindow && fLastImage) { 2748cb93a386Sopenharmony_ci ImGui::SetNextWindowSize(ImVec2(200, 200), ImGuiCond_FirstUseEver); 2749cb93a386Sopenharmony_ci if (ImGui::Begin("Zoom", &fShowZoomWindow)) { 2750cb93a386Sopenharmony_ci static int zoomFactor = 8; 2751cb93a386Sopenharmony_ci if (ImGui::Button("<<")) { 2752cb93a386Sopenharmony_ci zoomFactor = std::max(zoomFactor / 2, 4); 2753cb93a386Sopenharmony_ci } 2754cb93a386Sopenharmony_ci ImGui::SameLine(); ImGui::Text("%2d", zoomFactor); ImGui::SameLine(); 2755cb93a386Sopenharmony_ci if (ImGui::Button(">>")) { 2756cb93a386Sopenharmony_ci zoomFactor = std::min(zoomFactor * 2, 32); 2757cb93a386Sopenharmony_ci } 2758cb93a386Sopenharmony_ci 2759cb93a386Sopenharmony_ci if (!fZoomWindowFixed) { 2760cb93a386Sopenharmony_ci ImVec2 mousePos = ImGui::GetMousePos(); 2761cb93a386Sopenharmony_ci fZoomWindowLocation = SkPoint::Make(mousePos.x, mousePos.y); 2762cb93a386Sopenharmony_ci } 2763cb93a386Sopenharmony_ci SkScalar x = fZoomWindowLocation.x(); 2764cb93a386Sopenharmony_ci SkScalar y = fZoomWindowLocation.y(); 2765cb93a386Sopenharmony_ci int xInt = SkScalarRoundToInt(x); 2766cb93a386Sopenharmony_ci int yInt = SkScalarRoundToInt(y); 2767cb93a386Sopenharmony_ci ImVec2 avail = ImGui::GetContentRegionAvail(); 2768cb93a386Sopenharmony_ci 2769cb93a386Sopenharmony_ci uint32_t pixel = 0; 2770cb93a386Sopenharmony_ci SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); 2771cb93a386Sopenharmony_ci auto dContext = fWindow->directContext(); 2772cb93a386Sopenharmony_ci if (fLastImage->readPixels(dContext, info, &pixel, info.minRowBytes(), xInt, yInt)) { 2773cb93a386Sopenharmony_ci ImGui::SameLine(); 2774cb93a386Sopenharmony_ci ImGui::Text("(X, Y): %d, %d RGBA: %X %X %X %X", 2775cb93a386Sopenharmony_ci xInt, yInt, 2776cb93a386Sopenharmony_ci SkGetPackedR32(pixel), SkGetPackedG32(pixel), 2777cb93a386Sopenharmony_ci SkGetPackedB32(pixel), SkGetPackedA32(pixel)); 2778cb93a386Sopenharmony_ci } 2779cb93a386Sopenharmony_ci 2780cb93a386Sopenharmony_ci fImGuiLayer.skiaWidget(avail, [=, lastImage = fLastImage](SkCanvas* c) { 2781cb93a386Sopenharmony_ci // Translate so the region of the image that's under the mouse cursor is centered 2782cb93a386Sopenharmony_ci // in the zoom canvas: 2783cb93a386Sopenharmony_ci c->scale(zoomFactor, zoomFactor); 2784cb93a386Sopenharmony_ci c->translate(avail.x * 0.5f / zoomFactor - x - 0.5f, 2785cb93a386Sopenharmony_ci avail.y * 0.5f / zoomFactor - y - 0.5f); 2786cb93a386Sopenharmony_ci c->drawImage(lastImage, 0, 0); 2787cb93a386Sopenharmony_ci 2788cb93a386Sopenharmony_ci SkPaint outline; 2789cb93a386Sopenharmony_ci outline.setStyle(SkPaint::kStroke_Style); 2790cb93a386Sopenharmony_ci c->drawRect(SkRect::MakeXYWH(x, y, 1, 1), outline); 2791cb93a386Sopenharmony_ci }); 2792cb93a386Sopenharmony_ci } 2793cb93a386Sopenharmony_ci 2794cb93a386Sopenharmony_ci ImGui::End(); 2795cb93a386Sopenharmony_ci } 2796cb93a386Sopenharmony_ci} 2797cb93a386Sopenharmony_ci 2798cb93a386Sopenharmony_civoid Viewer::dumpShadersToResources() { 2799cb93a386Sopenharmony_ci // Sort the list of cached shaders so we can maintain some minimal level of consistency. 2800cb93a386Sopenharmony_ci // It doesn't really matter, but it will keep files from switching places unpredictably. 2801cb93a386Sopenharmony_ci std::vector<const CachedShader*> shaders; 2802cb93a386Sopenharmony_ci shaders.reserve(fCachedShaders.size()); 2803cb93a386Sopenharmony_ci for (const CachedShader& shader : fCachedShaders) { 2804cb93a386Sopenharmony_ci shaders.push_back(&shader); 2805cb93a386Sopenharmony_ci } 2806cb93a386Sopenharmony_ci 2807cb93a386Sopenharmony_ci std::sort(shaders.begin(), shaders.end(), [](const CachedShader* a, const CachedShader* b) { 2808cb93a386Sopenharmony_ci return std::tie(a->fShader[kFragment_GrShaderType], a->fShader[kVertex_GrShaderType]) < 2809cb93a386Sopenharmony_ci std::tie(b->fShader[kFragment_GrShaderType], b->fShader[kVertex_GrShaderType]); 2810cb93a386Sopenharmony_ci }); 2811cb93a386Sopenharmony_ci 2812cb93a386Sopenharmony_ci // Make the resources/sksl/SlideName/ directory. 2813cb93a386Sopenharmony_ci SkString directory = SkStringPrintf("%ssksl/%s", 2814cb93a386Sopenharmony_ci GetResourcePath().c_str(), 2815cb93a386Sopenharmony_ci fSlides[fCurrentSlide]->getName().c_str()); 2816cb93a386Sopenharmony_ci if (!sk_mkdir(directory.c_str())) { 2817cb93a386Sopenharmony_ci SkDEBUGFAILF("Unable to create directory '%s'", directory.c_str()); 2818cb93a386Sopenharmony_ci return; 2819cb93a386Sopenharmony_ci } 2820cb93a386Sopenharmony_ci 2821cb93a386Sopenharmony_ci int index = 0; 2822cb93a386Sopenharmony_ci for (const auto& entry : shaders) { 2823cb93a386Sopenharmony_ci SkString vertPath = SkStringPrintf("%s/Vertex_%02d.vert", directory.c_str(), index); 2824cb93a386Sopenharmony_ci FILE* vertFile = sk_fopen(vertPath.c_str(), kWrite_SkFILE_Flag); 2825cb93a386Sopenharmony_ci if (vertFile) { 2826cb93a386Sopenharmony_ci const SkSL::String& vertText = entry->fShader[kVertex_GrShaderType]; 2827cb93a386Sopenharmony_ci SkAssertResult(sk_fwrite(vertText.c_str(), vertText.size(), vertFile)); 2828cb93a386Sopenharmony_ci sk_fclose(vertFile); 2829cb93a386Sopenharmony_ci } else { 2830cb93a386Sopenharmony_ci SkDEBUGFAILF("Unable to write shader to path '%s'", vertPath.c_str()); 2831cb93a386Sopenharmony_ci } 2832cb93a386Sopenharmony_ci 2833cb93a386Sopenharmony_ci SkString fragPath = SkStringPrintf("%s/Fragment_%02d.frag", directory.c_str(), index); 2834cb93a386Sopenharmony_ci FILE* fragFile = sk_fopen(fragPath.c_str(), kWrite_SkFILE_Flag); 2835cb93a386Sopenharmony_ci if (fragFile) { 2836cb93a386Sopenharmony_ci const SkSL::String& fragText = entry->fShader[kFragment_GrShaderType]; 2837cb93a386Sopenharmony_ci SkAssertResult(sk_fwrite(fragText.c_str(), fragText.size(), fragFile)); 2838cb93a386Sopenharmony_ci sk_fclose(fragFile); 2839cb93a386Sopenharmony_ci } else { 2840cb93a386Sopenharmony_ci SkDEBUGFAILF("Unable to write shader to path '%s'", fragPath.c_str()); 2841cb93a386Sopenharmony_ci } 2842cb93a386Sopenharmony_ci 2843cb93a386Sopenharmony_ci ++index; 2844cb93a386Sopenharmony_ci } 2845cb93a386Sopenharmony_ci} 2846cb93a386Sopenharmony_ci 2847cb93a386Sopenharmony_civoid Viewer::onIdle() { 2848cb93a386Sopenharmony_ci SkTArray<std::function<void()>> actionsToRun; 2849cb93a386Sopenharmony_ci actionsToRun.swap(fDeferredActions); 2850cb93a386Sopenharmony_ci 2851cb93a386Sopenharmony_ci for (const auto& fn : actionsToRun) { 2852cb93a386Sopenharmony_ci fn(); 2853cb93a386Sopenharmony_ci } 2854cb93a386Sopenharmony_ci 2855cb93a386Sopenharmony_ci fStatsLayer.beginTiming(fAnimateTimer); 2856cb93a386Sopenharmony_ci fAnimTimer.updateTime(); 2857cb93a386Sopenharmony_ci bool animateWantsInval = fSlides[fCurrentSlide]->animate(fAnimTimer.nanos()); 2858cb93a386Sopenharmony_ci fStatsLayer.endTiming(fAnimateTimer); 2859cb93a386Sopenharmony_ci 2860cb93a386Sopenharmony_ci ImGuiIO& io = ImGui::GetIO(); 2861cb93a386Sopenharmony_ci // ImGui always has at least one "active" window, which is the default "Debug" window. It may 2862cb93a386Sopenharmony_ci // not be visible, though. So we need to redraw if there is at least one visible window, or 2863cb93a386Sopenharmony_ci // more than one active window. Newly created windows are active but not visible for one frame 2864cb93a386Sopenharmony_ci // while they determine their layout and sizing. 2865cb93a386Sopenharmony_ci if (animateWantsInval || fStatsLayer.getActive() || fRefresh || 2866cb93a386Sopenharmony_ci io.MetricsActiveWindows > 1 || io.MetricsRenderWindows > 0) { 2867cb93a386Sopenharmony_ci fWindow->inval(); 2868cb93a386Sopenharmony_ci } 2869cb93a386Sopenharmony_ci} 2870cb93a386Sopenharmony_ci 2871cb93a386Sopenharmony_citemplate <typename OptionsFunc> 2872cb93a386Sopenharmony_cistatic void WriteStateObject(SkJSONWriter& writer, const char* name, const char* value, 2873cb93a386Sopenharmony_ci OptionsFunc&& optionsFunc) { 2874cb93a386Sopenharmony_ci writer.beginObject(); 2875cb93a386Sopenharmony_ci { 2876cb93a386Sopenharmony_ci writer.appendString(kName , name); 2877cb93a386Sopenharmony_ci writer.appendString(kValue, value); 2878cb93a386Sopenharmony_ci 2879cb93a386Sopenharmony_ci writer.beginArray(kOptions); 2880cb93a386Sopenharmony_ci { 2881cb93a386Sopenharmony_ci optionsFunc(writer); 2882cb93a386Sopenharmony_ci } 2883cb93a386Sopenharmony_ci writer.endArray(); 2884cb93a386Sopenharmony_ci } 2885cb93a386Sopenharmony_ci writer.endObject(); 2886cb93a386Sopenharmony_ci} 2887cb93a386Sopenharmony_ci 2888cb93a386Sopenharmony_ci 2889cb93a386Sopenharmony_civoid Viewer::updateUIState() { 2890cb93a386Sopenharmony_ci if (!fWindow) { 2891cb93a386Sopenharmony_ci return; 2892cb93a386Sopenharmony_ci } 2893cb93a386Sopenharmony_ci if (fWindow->sampleCount() < 1) { 2894cb93a386Sopenharmony_ci return; // Surface hasn't been created yet. 2895cb93a386Sopenharmony_ci } 2896cb93a386Sopenharmony_ci 2897cb93a386Sopenharmony_ci SkDynamicMemoryWStream memStream; 2898cb93a386Sopenharmony_ci SkJSONWriter writer(&memStream); 2899cb93a386Sopenharmony_ci writer.beginArray(); 2900cb93a386Sopenharmony_ci 2901cb93a386Sopenharmony_ci // Slide state 2902cb93a386Sopenharmony_ci WriteStateObject(writer, kSlideStateName, fSlides[fCurrentSlide]->getName().c_str(), 2903cb93a386Sopenharmony_ci [this](SkJSONWriter& writer) { 2904cb93a386Sopenharmony_ci for(const auto& slide : fSlides) { 2905cb93a386Sopenharmony_ci writer.appendString(slide->getName().c_str()); 2906cb93a386Sopenharmony_ci } 2907cb93a386Sopenharmony_ci }); 2908cb93a386Sopenharmony_ci 2909cb93a386Sopenharmony_ci // Backend state 2910cb93a386Sopenharmony_ci WriteStateObject(writer, kBackendStateName, kBackendTypeStrings[fBackendType], 2911cb93a386Sopenharmony_ci [](SkJSONWriter& writer) { 2912cb93a386Sopenharmony_ci for (const auto& str : kBackendTypeStrings) { 2913cb93a386Sopenharmony_ci writer.appendString(str); 2914cb93a386Sopenharmony_ci } 2915cb93a386Sopenharmony_ci }); 2916cb93a386Sopenharmony_ci 2917cb93a386Sopenharmony_ci // MSAA state 2918cb93a386Sopenharmony_ci const auto countString = SkStringPrintf("%d", fWindow->sampleCount()); 2919cb93a386Sopenharmony_ci WriteStateObject(writer, kMSAAStateName, countString.c_str(), 2920cb93a386Sopenharmony_ci [this](SkJSONWriter& writer) { 2921cb93a386Sopenharmony_ci writer.appendS32(0); 2922cb93a386Sopenharmony_ci 2923cb93a386Sopenharmony_ci if (sk_app::Window::kRaster_BackendType == fBackendType) { 2924cb93a386Sopenharmony_ci return; 2925cb93a386Sopenharmony_ci } 2926cb93a386Sopenharmony_ci 2927cb93a386Sopenharmony_ci for (int msaa : {4, 8, 16}) { 2928cb93a386Sopenharmony_ci writer.appendS32(msaa); 2929cb93a386Sopenharmony_ci } 2930cb93a386Sopenharmony_ci }); 2931cb93a386Sopenharmony_ci 2932cb93a386Sopenharmony_ci // Path renderer state 2933cb93a386Sopenharmony_ci GpuPathRenderers pr = fWindow->getRequestedDisplayParams().fGrContextOptions.fGpuPathRenderers; 2934cb93a386Sopenharmony_ci WriteStateObject(writer, kPathRendererStateName, gPathRendererNames[pr].c_str(), 2935cb93a386Sopenharmony_ci [this](SkJSONWriter& writer) { 2936cb93a386Sopenharmony_ci auto ctx = fWindow->directContext(); 2937cb93a386Sopenharmony_ci if (!ctx) { 2938cb93a386Sopenharmony_ci writer.appendString("Software"); 2939cb93a386Sopenharmony_ci } else { 2940cb93a386Sopenharmony_ci writer.appendString(gPathRendererNames[GpuPathRenderers::kDefault].c_str()); 2941cb93a386Sopenharmony_ci#if SK_GPU_V1 2942cb93a386Sopenharmony_ci if (fWindow->sampleCount() > 1 || FLAGS_dmsaa) { 2943cb93a386Sopenharmony_ci const auto* caps = ctx->priv().caps(); 2944cb93a386Sopenharmony_ci if (skgpu::v1::AtlasPathRenderer::IsSupported(ctx)) { 2945cb93a386Sopenharmony_ci writer.appendString( 2946cb93a386Sopenharmony_ci gPathRendererNames[GpuPathRenderers::kAtlas].c_str()); 2947cb93a386Sopenharmony_ci } 2948cb93a386Sopenharmony_ci if (skgpu::v1::TessellationPathRenderer::IsSupported(*caps)) { 2949cb93a386Sopenharmony_ci writer.appendString( 2950cb93a386Sopenharmony_ci gPathRendererNames[GpuPathRenderers::kTessellation].c_str()); 2951cb93a386Sopenharmony_ci } 2952cb93a386Sopenharmony_ci } 2953cb93a386Sopenharmony_ci#endif 2954cb93a386Sopenharmony_ci if (1 == fWindow->sampleCount()) { 2955cb93a386Sopenharmony_ci writer.appendString(gPathRendererNames[GpuPathRenderers::kSmall].c_str()); 2956cb93a386Sopenharmony_ci } 2957cb93a386Sopenharmony_ci writer.appendString(gPathRendererNames[GpuPathRenderers::kTriangulating].c_str()); 2958cb93a386Sopenharmony_ci writer.appendString(gPathRendererNames[GpuPathRenderers::kNone].c_str()); 2959cb93a386Sopenharmony_ci } 2960cb93a386Sopenharmony_ci }); 2961cb93a386Sopenharmony_ci 2962cb93a386Sopenharmony_ci // Softkey state 2963cb93a386Sopenharmony_ci WriteStateObject(writer, kSoftkeyStateName, kSoftkeyHint, 2964cb93a386Sopenharmony_ci [this](SkJSONWriter& writer) { 2965cb93a386Sopenharmony_ci writer.appendString(kSoftkeyHint); 2966cb93a386Sopenharmony_ci for (const auto& softkey : fCommands.getCommandsAsSoftkeys()) { 2967cb93a386Sopenharmony_ci writer.appendString(softkey.c_str()); 2968cb93a386Sopenharmony_ci } 2969cb93a386Sopenharmony_ci }); 2970cb93a386Sopenharmony_ci 2971cb93a386Sopenharmony_ci writer.endArray(); 2972cb93a386Sopenharmony_ci writer.flush(); 2973cb93a386Sopenharmony_ci 2974cb93a386Sopenharmony_ci auto data = memStream.detachAsData(); 2975cb93a386Sopenharmony_ci 2976cb93a386Sopenharmony_ci // TODO: would be cool to avoid this copy 2977cb93a386Sopenharmony_ci const SkString cstring(static_cast<const char*>(data->data()), data->size()); 2978cb93a386Sopenharmony_ci 2979cb93a386Sopenharmony_ci fWindow->setUIState(cstring.c_str()); 2980cb93a386Sopenharmony_ci} 2981cb93a386Sopenharmony_ci 2982cb93a386Sopenharmony_civoid Viewer::onUIStateChanged(const SkString& stateName, const SkString& stateValue) { 2983cb93a386Sopenharmony_ci // For those who will add more features to handle the state change in this function: 2984cb93a386Sopenharmony_ci // After the change, please call updateUIState no notify the frontend (e.g., Android app). 2985cb93a386Sopenharmony_ci // For example, after slide change, updateUIState is called inside setupCurrentSlide; 2986cb93a386Sopenharmony_ci // after backend change, updateUIState is called in this function. 2987cb93a386Sopenharmony_ci if (stateName.equals(kSlideStateName)) { 2988cb93a386Sopenharmony_ci for (int i = 0; i < fSlides.count(); ++i) { 2989cb93a386Sopenharmony_ci if (fSlides[i]->getName().equals(stateValue)) { 2990cb93a386Sopenharmony_ci this->setCurrentSlide(i); 2991cb93a386Sopenharmony_ci return; 2992cb93a386Sopenharmony_ci } 2993cb93a386Sopenharmony_ci } 2994cb93a386Sopenharmony_ci 2995cb93a386Sopenharmony_ci SkDebugf("Slide not found: %s", stateValue.c_str()); 2996cb93a386Sopenharmony_ci } else if (stateName.equals(kBackendStateName)) { 2997cb93a386Sopenharmony_ci for (int i = 0; i < sk_app::Window::kBackendTypeCount; i++) { 2998cb93a386Sopenharmony_ci if (stateValue.equals(kBackendTypeStrings[i])) { 2999cb93a386Sopenharmony_ci if (fBackendType != i) { 3000cb93a386Sopenharmony_ci fBackendType = (sk_app::Window::BackendType)i; 3001cb93a386Sopenharmony_ci for(auto& slide : fSlides) { 3002cb93a386Sopenharmony_ci slide->gpuTeardown(); 3003cb93a386Sopenharmony_ci } 3004cb93a386Sopenharmony_ci fWindow->detach(); 3005cb93a386Sopenharmony_ci fWindow->attach(backend_type_for_window(fBackendType)); 3006cb93a386Sopenharmony_ci } 3007cb93a386Sopenharmony_ci break; 3008cb93a386Sopenharmony_ci } 3009cb93a386Sopenharmony_ci } 3010cb93a386Sopenharmony_ci } else if (stateName.equals(kMSAAStateName)) { 3011cb93a386Sopenharmony_ci DisplayParams params = fWindow->getRequestedDisplayParams(); 3012cb93a386Sopenharmony_ci int sampleCount = atoi(stateValue.c_str()); 3013cb93a386Sopenharmony_ci if (sampleCount != params.fMSAASampleCount) { 3014cb93a386Sopenharmony_ci params.fMSAASampleCount = sampleCount; 3015cb93a386Sopenharmony_ci fWindow->setRequestedDisplayParams(params); 3016cb93a386Sopenharmony_ci fWindow->inval(); 3017cb93a386Sopenharmony_ci this->updateTitle(); 3018cb93a386Sopenharmony_ci this->updateUIState(); 3019cb93a386Sopenharmony_ci } 3020cb93a386Sopenharmony_ci } else if (stateName.equals(kPathRendererStateName)) { 3021cb93a386Sopenharmony_ci DisplayParams params = fWindow->getRequestedDisplayParams(); 3022cb93a386Sopenharmony_ci for (const auto& pair : gPathRendererNames) { 3023cb93a386Sopenharmony_ci if (pair.second == stateValue.c_str()) { 3024cb93a386Sopenharmony_ci if (params.fGrContextOptions.fGpuPathRenderers != pair.first) { 3025cb93a386Sopenharmony_ci params.fGrContextOptions.fGpuPathRenderers = pair.first; 3026cb93a386Sopenharmony_ci fWindow->setRequestedDisplayParams(params); 3027cb93a386Sopenharmony_ci fWindow->inval(); 3028cb93a386Sopenharmony_ci this->updateTitle(); 3029cb93a386Sopenharmony_ci this->updateUIState(); 3030cb93a386Sopenharmony_ci } 3031cb93a386Sopenharmony_ci break; 3032cb93a386Sopenharmony_ci } 3033cb93a386Sopenharmony_ci } 3034cb93a386Sopenharmony_ci } else if (stateName.equals(kSoftkeyStateName)) { 3035cb93a386Sopenharmony_ci if (!stateValue.equals(kSoftkeyHint)) { 3036cb93a386Sopenharmony_ci fCommands.onSoftkey(stateValue); 3037cb93a386Sopenharmony_ci this->updateUIState(); // This is still needed to reset the value to kSoftkeyHint 3038cb93a386Sopenharmony_ci } 3039cb93a386Sopenharmony_ci } else if (stateName.equals(kRefreshStateName)) { 3040cb93a386Sopenharmony_ci // This state is actually NOT in the UI state. 3041cb93a386Sopenharmony_ci // We use this to allow Android to quickly set bool fRefresh. 3042cb93a386Sopenharmony_ci fRefresh = stateValue.equals(kON); 3043cb93a386Sopenharmony_ci } else { 3044cb93a386Sopenharmony_ci SkDebugf("Unknown stateName: %s", stateName.c_str()); 3045cb93a386Sopenharmony_ci } 3046cb93a386Sopenharmony_ci} 3047cb93a386Sopenharmony_ci 3048cb93a386Sopenharmony_cibool Viewer::onKey(skui::Key key, skui::InputState state, skui::ModifierKey modifiers) { 3049cb93a386Sopenharmony_ci return fCommands.onKey(key, state, modifiers); 3050cb93a386Sopenharmony_ci} 3051cb93a386Sopenharmony_ci 3052cb93a386Sopenharmony_cibool Viewer::onChar(SkUnichar c, skui::ModifierKey modifiers) { 3053cb93a386Sopenharmony_ci if (fSlides[fCurrentSlide]->onChar(c)) { 3054cb93a386Sopenharmony_ci fWindow->inval(); 3055cb93a386Sopenharmony_ci return true; 3056cb93a386Sopenharmony_ci } else { 3057cb93a386Sopenharmony_ci return fCommands.onChar(c, modifiers); 3058cb93a386Sopenharmony_ci } 3059cb93a386Sopenharmony_ci} 3060