285 {
286#if defined(SK_GRAPHITE)
288#ifdef SK_DAWN
289 case sk_app::Window::kGraphiteDawn_BackendType:
290#endif
291#ifdef SK_METAL
292 case sk_app::Window::kGraphiteMetal_BackendType:
293#endif
294#ifdef SK_VULKAN
295 case sk_app::Window::kGraphiteVulkan_BackendType:
296#endif
297 return true;
298 default:
299 break;
300 }
301#endif
302 return false;
303}
304
305#if defined(SK_GRAPHITE)
306static const char*
309 switch (strategy) {
310 case Strategy::kDefault:
311 return "Default";
312 case Strategy::kComputeAnalyticAA:
313 return "GPU Compute AA (Analytic)";
314 case Strategy::kComputeMSAA16:
315 return "GPU Compute AA (16xMSAA)";
316 case Strategy::kComputeMSAA8:
317 return "GPU Compute AA (8xMSAA)";
318 case Strategy::kRasterAA:
319 return "CPU Raster AA";
320 case Strategy::kTessellation:
321 return "Tessellation";
322 }
323 return "unknown";
324}
325
328 if (0 == strcmp(str, "default")) {
329 return Strategy::kDefault;
330 } else if (0 == strcmp(str, "raster")) {
331 return Strategy::kRasterAA;
332#ifdef SK_ENABLE_VELLO_SHADERS
333 } else if (0 == strcmp(str, "compute-analytic")) {
334 return Strategy::kComputeAnalyticAA;
335 } else if (0 == strcmp(str, "compute-msaa16")) {
336 return Strategy::kComputeMSAA16;
337 } else if (0 == strcmp(str, "compute-msaa8")) {
338 return Strategy::kComputeMSAA8;
339#endif
340 } else if (0 == strcmp(str, "tessellation")) {
341 return Strategy::kTessellation;
342 } else {
343 SkDebugf(
"Unknown path renderer strategy type, %s, defaulting to default.", str);
344 return Strategy::kDefault;
345 }
346}
347#endif
348
351 case sk_app::Window::kNativeGL_BackendType: return "OpenGL";
352#if SK_ANGLE && (defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC))
353 case sk_app::Window::kANGLE_BackendType: return "ANGLE";
354#endif
355#ifdef SK_DAWN
356#if defined(SK_GRAPHITE)
357 case sk_app::Window::kGraphiteDawn_BackendType: return "Dawn (Graphite)";
358#endif
359#endif
360#ifdef SK_VULKAN
361 case sk_app::Window::kVulkan_BackendType: return "Vulkan";
362#if defined(SK_GRAPHITE)
363 case sk_app::Window::kGraphiteVulkan_BackendType: return "Vulkan (Graphite)";
364#endif
365#endif
366#ifdef SK_METAL
367 case sk_app::Window::kMetal_BackendType: return "Metal";
368#if defined(SK_GRAPHITE)
369 case sk_app::Window::kGraphiteMetal_BackendType: return "Metal (Graphite)";
370#endif
371#endif
372#ifdef SK_DIRECT3D
373 case sk_app::Window::kDirect3D_BackendType: return "Direct3D";
374#endif
376 }
378 return nullptr;
379}
380
382#ifdef SK_DAWN
383#if defined(SK_GRAPHITE)
384 if (0 == strcmp(str, "grdawn")) {
385 return sk_app::Window::kGraphiteDawn_BackendType;
386 } else
387#endif
388#endif
389#ifdef SK_VULKAN
390 if (0 == strcmp(str, "vk")) {
391 return sk_app::Window::kVulkan_BackendType;
392 } else
393#if defined(SK_GRAPHITE)
394 if (0 == strcmp(str, "grvk")) {
395 return sk_app::Window::kGraphiteVulkan_BackendType;
396 } else
397#endif
398#endif
399#if SK_ANGLE && (defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC))
400 if (0 == strcmp(str, "angle")) {
401 return sk_app::Window::kANGLE_BackendType;
402 } else
403#endif
404#ifdef SK_METAL
405 if (0 == strcmp(str, "mtl")) {
406 return sk_app::Window::kMetal_BackendType;
407 } else
408#if defined(SK_GRAPHITE)
409 if (0 == strcmp(str, "grmtl")) {
410 return sk_app::Window::kGraphiteMetal_BackendType;
411 } else
412#endif
413#endif
414#ifdef SK_DIRECT3D
415 if (0 == strcmp(str, "d3d")) {
416 return sk_app::Window::kDirect3D_BackendType;
417 } else
418#endif
419
420 if (0 == strcmp(str, "gl")) {
421 return sk_app::Window::kNativeGL_BackendType;
422 } else if (0 == strcmp(str, "sw")) {
424 } else {
425 SkDebugf(
"Unknown backend type, %s, defaulting to sw.", str);
427 }
428}
429
431 0.64f, 0.33f,
432 0.30f, 0.60f,
433 0.15f, 0.06f,
434 0.3127f, 0.3290f };
435
437 0.64f, 0.33f,
438 0.21f, 0.71f,
439 0.15f, 0.06f,
440 0.3127f, 0.3290f };
441
443 0.680f, 0.320f,
444 0.265f, 0.690f,
445 0.150f, 0.060f,
446 0.3127f, 0.3290f };
447
449 0.708f, 0.292f,
450 0.170f, 0.797f,
451 0.131f, 0.046f,
452 0.3127f, 0.3290f };
453
462};
463
466}
467
469
470
471 return Window::kRaster_BackendType == backendType ? Window::kNativeGL_BackendType : backendType;
472}
473
476 canvas->
clear(0xffff11ff);
477 }
478};
479
480static const char kName[] =
"name";
481static const char kValue[] =
"value";
482static const char kOptions[] =
"options";
488static const char kSoftkeyHint[] =
"Please select a softkey";
489static const char kON[] =
"ON";
491
493 : fCurrentSlide(-1)
496 , fShowSlideDimensions(
false)
497 , fShowImGuiDebugWindow(
false)
498 , fShowSlidePicker(
false)
499 , fShowImGuiTestWindow(
false)
500 , fShowHistogramWindow(
false)
501 , fShowZoomWindow(
false)
502 , fZoomWindowFixed(
false)
503 , fZoomWindowLocation{0.0
f, 0.0
f}
504 , fLastImage(nullptr)
507 , fColorMode(ColorMode::
kLegacy)
509
511 , fApplyBackingScale(
true)
514 , fOffset{0.5
f, 0.5
f}
515 , fGestureDevice(GestureDevice::
kNone)
517 , fDrawTileBoundaries(
false)
518 , fTileScale{0.25
f, 0.25
f}
519 , fPerspectiveMode(kPerspective_Off)
520{
522#if defined(SK_ENABLE_SVG)
524#endif
526
533
534 SkDebugf(
"Command line arguments: ");
535 for (int i = 1; i < argc; ++i) {
537 }
539
541#ifdef SK_BUILD_FOR_ANDROID
543#endif
544
547
549 fWindow = Window::CreateNativeWindow(platformData);
550
560 if (FLAGS_dmsaa) {
564 }
566#if defined(SK_GRAPHITE)
567 displayParams.fGraphiteContextOptions.fPriv.fPathRendererStrategy =
568 get_path_renderer_strategy_type(FLAGS_pathstrategy[0]);
569#endif
570 fWindow->setRequestedDisplayParams(displayParams);
571 fDisplay = fWindow->getRequestedDisplayParams();
572 fRefresh = FLAGS_redraw;
573
574 fImGuiLayer.setScaleFactor(fWindow->scaleFactor());
575 fStatsLayer.setDisplayScale((fZoomUI ? 2.0f : 1.0
f) * fWindow->scaleFactor());
576
577
578 fStatsLayer.setActive(FLAGS_stats);
579 fAnimateTimer = fStatsLayer.addTimer(
"Animate",
SK_ColorMAGENTA, 0xffff66ff);
581 fFlushTimer = fStatsLayer.addTimer(
"Flush",
SK_ColorRED, 0xffff6666);
582
583
584 fCommands.attach(fWindow);
585 fWindow->pushLayer(this);
586 fWindow->pushLayer(&fStatsLayer);
587 fWindow->pushLayer(&fImGuiLayer);
588
589
590 fCommands.addCommand(' ', "GUI", "Toggle Debug GUI", [this]() {
591 this->fShowImGuiDebugWindow = !this->fShowImGuiDebugWindow;
592 fWindow->inval();
593 });
594
595 fCommands.addCommand('/', "GUI", "Jump to slide picker", [this]() {
596 this->fShowImGuiDebugWindow = true;
597 this->fShowSlidePicker = true;
598 fWindow->inval();
599 });
600
601 fCommands.addCommand(skui::Key::kBack, "Backspace", "GUI", "Jump to slide picker", [this]() {
602 this->fShowImGuiDebugWindow = true;
603 this->fShowSlidePicker = true;
604 fWindow->inval();
605 });
606 fCommands.addCommand('g', "GUI", "Toggle GUI Demo", [this]() {
607 this->fShowImGuiTestWindow = !this->fShowImGuiTestWindow;
608 fWindow->inval();
609 });
610 fCommands.addCommand('z', "GUI", "Toggle zoom window", [this]() {
611 this->fShowZoomWindow = !this->fShowZoomWindow;
612 fWindow->inval();
613 });
614 fCommands.addCommand('Z', "GUI", "Toggle zoom window state", [this]() {
615 this->fZoomWindowFixed = !this->fZoomWindowFixed;
616 fWindow->inval();
617 });
618 fCommands.addCommand('v', "Swapchain", "Toggle vsync on/off", [this]() {
621 fWindow->setRequestedDisplayParams(
params);
622 this->updateTitle();
623 fWindow->inval();
624 });
625 fCommands.addCommand('V', "Swapchain", "Toggle delayed acquire on/off (Metal only)", [this]() {
628 fWindow->setRequestedDisplayParams(
params);
629 this->updateTitle();
630 fWindow->inval();
631 });
632 fCommands.addCommand('r', "Redraw", "Toggle redraw", [this]() {
633 fRefresh = !fRefresh;
634 fWindow->inval();
635 });
636 fCommands.addCommand('s', "Overlays", "Toggle stats display", [this]() {
637 fStatsLayer.setActive(!fStatsLayer.getActive());
638 fWindow->inval();
639 });
640 fCommands.addCommand('0', "Overlays", "Reset stats", [this]() {
641 fStatsLayer.resetMeasurements();
642 this->updateTitle();
643 fWindow->inval();
644 });
645 fCommands.addCommand('C', "GUI", "Toggle color histogram", [this]() {
646 this->fShowHistogramWindow = !this->fShowHistogramWindow;
647 fWindow->inval();
648 });
649 fCommands.addCommand('c', "Modes", "Cycle color mode", [this]() {
650 switch (fColorMode) {
651 case ColorMode::kLegacy:
652 this->setColorMode(ColorMode::kColorManaged8888);
653 break;
654 case ColorMode::kColorManaged8888:
655 this->setColorMode(ColorMode::kColorManagedF16);
656 break;
657 case ColorMode::kColorManagedF16:
658 this->setColorMode(ColorMode::kColorManagedF16Norm);
659 break;
660 case ColorMode::kColorManagedF16Norm:
661 this->setColorMode(ColorMode::kLegacy);
662 break;
663 }
664 });
665 fCommands.addCommand('w', "Modes", "Toggle wireframe", [this]() {
668 fWindow->setRequestedDisplayParams(
params);
669 fWindow->inval();
670 });
671 fCommands.addCommand('w', "Modes", "Toggle reduced shaders", [this]() {
674 !
params.fGrContextOptions.fReducedShaderVariations;
675 fWindow->setRequestedDisplayParams(
params);
676 fWindow->inval();
677 });
678 fCommands.addCommand(skui::Key::kRight, "Right", "Navigation", "Next slide", [this]() {
679 this->setCurrentSlide(fCurrentSlide < fSlides.size() - 1 ? fCurrentSlide + 1 : 0);
680 });
681 fCommands.addCommand(skui::Key::kLeft, "Left", "Navigation", "Previous slide", [this]() {
682 this->setCurrentSlide(fCurrentSlide > 0 ? fCurrentSlide - 1 : fSlides.
size() - 1);
683 });
684 fCommands.addCommand(skui::Key::kUp, "Up", "Transform", "Zoom in", [this]() {
685 this->changeZoomLevel(1.f / 32.f);
686 fWindow->inval();
687 });
688 fCommands.addCommand(skui::Key::kDown, "Down", "Transform", "Zoom out", [this]() {
689 this->changeZoomLevel(-1.f / 32.f);
690 fWindow->inval();
691 });
692 fCommands.addCommand('d', "Modes", "Change rendering backend", [this]() {
695
696#if defined(SK_BUILD_FOR_UNIX) && defined(SK_VULKAN)
697 if (newBackend == sk_app::Window::kVulkan_BackendType) {
700 } else if (fBackendType == sk_app::Window::kVulkan_BackendType) {
701 newBackend = sk_app::Window::kVulkan_BackendType;
702 }
703#endif
704 this->setBackend(newBackend);
705 });
706 fCommands.addCommand('K', "IO", "Save slide to SKP", [this]() {
707 fSaveToSKP = true;
708 fWindow->inval();
709 });
710 fCommands.addCommand('&', "Overlays", "Show slide dimensios", [this]() {
711 fShowSlideDimensions = !fShowSlideDimensions;
712 fWindow->inval();
713 });
714 fCommands.addCommand('G', "Modes", "Geometry", [this]() {
717 SkPixelGeometry defaultPixelGeometry = fDisplay.fSurfaceProps.pixelGeometry();
718 if (!fDisplayOverrides.fSurfaceProps.fPixelGeometry) {
719 fDisplayOverrides.fSurfaceProps.fPixelGeometry = true;
721 } else {
722 switch (
params.fSurfaceProps.pixelGeometry()) {
725 break;
728 break;
731 break;
734 break;
737 fDisplayOverrides.fSurfaceProps.fPixelGeometry = false;
738 break;
739 }
740 }
741 fWindow->setRequestedDisplayParams(
params);
742 this->updateTitle();
743 fWindow->inval();
744 });
745 fCommands.addCommand('H', "Font", "Hinting mode", [this]() {
746 if (!fFontOverrides.fHinting) {
747 fFontOverrides.fHinting = true;
749 } else {
753 break;
756 break;
759 break;
762 fFontOverrides.fHinting = false;
763 break;
764 }
765 }
766 this->updateTitle();
767 fWindow->inval();
768 });
769 fCommands.addCommand('D', "Modes", "DFT", [this]() {
774 fWindow->setRequestedDisplayParams(
params);
775 this->updateTitle();
776 fWindow->inval();
777 });
778 fCommands.addCommand('L', "Font", "Subpixel Antialias Mode", [this]() {
779 if (!fFontOverrides.fEdging) {
780 fFontOverrides.fEdging = true;
782 } else {
786 break;
789 break;
792 fFontOverrides.fEdging = false;
793 break;
794 }
795 }
796 this->updateTitle();
797 fWindow->inval();
798 });
799 fCommands.addCommand('S', "Font", "Subpixel Position Mode", [this]() {
800 if (!fFontOverrides.fSubpixel) {
801 fFontOverrides.fSubpixel = true;
803 } else {
806 } else {
807 fFontOverrides.fSubpixel = false;
808 }
809 }
810 this->updateTitle();
811 fWindow->inval();
812 });
813 fCommands.addCommand('B', "Font", "Baseline Snapping", [this]() {
814 if (!fFontOverrides.fBaselineSnap) {
815 fFontOverrides.fBaselineSnap = true;
817 } else {
820 } else {
821 fFontOverrides.fBaselineSnap = false;
822 }
823 }
824 this->updateTitle();
825 fWindow->inval();
826 });
827 fCommands.addCommand('p', "Transform", "Toggle Perspective Mode", [this]() {
828 fPerspectiveMode = (kPerspective_Real == fPerspectiveMode) ? kPerspective_Fake
829 : kPerspective_Real;
830 this->updateTitle();
831 fWindow->inval();
832 });
833 fCommands.addCommand('P', "Transform", "Toggle Perspective", [this]() {
834 fPerspectiveMode = (kPerspective_Off == fPerspectiveMode) ? kPerspective_Real
835 : kPerspective_Off;
836 this->updateTitle();
837 fWindow->inval();
838 });
839 fCommands.addCommand('a', "Transform", "Toggle Animation", [this]() {
840 fAnimTimer.togglePauseResume();
841 });
842 fCommands.addCommand('u', "GUI", "Zoom UI", [this]() {
843 fZoomUI = !fZoomUI;
844 fStatsLayer.setDisplayScale((fZoomUI ? 2.0f : 1.0
f) * fWindow->scaleFactor());
845 fWindow->inval();
846 });
847 fCommands.addCommand('$', "ViaSerialize", "Toggle ViaSerialize", [this]() {
848 fDrawViaSerialize = !fDrawViaSerialize;
849 this->updateTitle();
850 fWindow->inval();
851 });
852
853
854 this->initSlides();
855 if (FLAGS_list) {
856 this->listNames();
857 }
858
859 fPerspectivePoints[0].set(0, 0);
860 fPerspectivePoints[1].set(1, 0);
861 fPerspectivePoints[2].set(0, 1);
862 fPerspectivePoints[3].set(1, 1);
863 fAnimTimer.run();
864
866 if (gamutImage) {
868 }
870
872 this->setCurrentSlide(this->startupSlide());
873}
874
877 char buf[4096];
878 while (size_t bytesRead = fread(buf, 1, 4096, fp)) {
879 stream.write(buf, bytesRead);
880 }
881 return stream.detachAsData();
882}
883
885 size_t dataLen;
887 return nullptr;
888 }
889
891 void* rawData = decodedData->writable_data();
893 return nullptr;
894 }
895
896 return decodedData;
897}
898
900 std::string str(
reinterpret_cast<const char*
>(
data->data()),
data->size());
901 std::regex re("data:image/png;base64,([a-zA-Z0-9+/=]+)");
902 std::sregex_iterator images_begin(str.begin(), str.end(), re);
903 std::sregex_iterator images_end;
904 std::vector<sk_sp<SkImage>>
images;
905
906 for (auto iter = images_begin; iter != images_end; ++iter) {
907 const std::smatch&
match = *iter;
909 if (!raw) {
910 continue;
911 }
915 }
916 }
917
919}
920
921void Viewer::initSlides() {
923 static const struct {
924 const char* fExtension;
925 const char* fDirName;
927 const SlideMaker fFactory;
928 } gExternalSlidesInfo[] = {
929 { ".mskp", "mskp-dir", FLAGS_mskps,
931 return sk_make_sp<MSKPSlide>(
name, path);}
932 },
933 { ".skp", "skp-dir", FLAGS_skps,
935 return sk_make_sp<SKPSlide>(
name, path);}
936 },
937 { ".jpg", "jpg-dir", FLAGS_jpgs,
939 return sk_make_sp<ImageSlide>(
name, path);}
940 },
941 { ".jxl", "jxl-dir", FLAGS_jxls,
943 return sk_make_sp<ImageSlide>(
name, path);}
944 },
945#if defined(SK_ENABLE_SKOTTIE)
946 { ".json", "skottie-dir", FLAGS_lotties,
948 return sk_make_sp<SkottieSlide>(
name, path);}
949 },
950#endif
951
952#if defined(SK_ENABLE_SVG)
953 { ".svg", "svg-dir", FLAGS_svgs,
955 return sk_make_sp<SvgSlide>(
name, path);}
956 },
957#endif
958 };
959
961
964 return;
965 }
966
967 if (
auto slide = fact(
name, path)) {
970 }
971 };
972
973 if (!FLAGS_file.isEmpty()) {
974
976
977
978 if (
file.equals(
"stdin")) {
981
982
984 char imageID =
'A' + fSlides.
size();
987 }
988 if (!fSlides.
empty()) {
989 fShowZoomWindow = true;
990 return;
991 }
992 }
993
995 for (const auto& sinfo : gExternalSlidesInfo) {
996 if (
file.endsWith(sinfo.fExtension)) {
998 return;
999 }
1000 }
1001
1002 fprintf(stderr,
"Unsupported file type \"%s\"\n",
file.c_str());
1003 } else {
1004 fprintf(stderr,
"Cannot read \"%s\"\n",
file.c_str());
1005 }
1006
1007 return;
1008 }
1009
1010
1011 if (!FLAGS_bisect.isEmpty()) {
1014 if (FLAGS_bisect.size() >= 2) {
1015 for (const char* ch = FLAGS_bisect[1]; *ch; ++ch) {
1016 bisect->onChar(*ch);
1017 }
1018 }
1020 }
1021 }
1022
1023
1024 int firstGM = fSlides.
size();
1026 std::unique_ptr<skiagm::GM> gm = gmFactory();
1028 auto slide = sk_make_sp<GMSlide>(std::move(gm));
1030 }
1031 }
1032
1035 };
1036 std::sort(fSlides.
begin() + firstGM, fSlides.
end(), orderBySlideName);
1037
1038 int firstRegisteredSlide = fSlides.
size();
1039
1040
1045 }
1046 }
1047
1048 std::sort(fSlides.
begin() + firstRegisteredSlide, fSlides.
end(), orderBySlideName);
1049
1050
1051 {
1052 auto slide = sk_make_sp<SkSLSlide>();
1055 }
1056 }
1057
1058
1059 {
1060 auto slide = sk_make_sp<SkSLDebuggerSlide>();
1063 }
1064 }
1065
1066 for (
const auto&
info : gExternalSlidesInfo) {
1069
1071 } else {
1072
1076 while (it.next(&
name)) {
1078 }
1079 if (sortedFilenames.
size()) {
1082 return strcmp(a.c_str(), b.c_str()) < 0;
1083 });
1084 }
1085 for (
const SkString& filename : sortedFilenames) {
1088 }
1089 }
1090 if (!dirSlides.
empty()) {
1093 std::move(dirSlides)));
1095 }
1096 }
1097 }
1098
1099 if (fSlides.
empty()) {
1100 auto slide = sk_make_sp<NullSlide>();
1102 }
1103}
1104
1105
1107 for(auto& slide : fSlides) {
1109 }
1110
1112 delete fWindow;
1113}
1114
1120 } else {
1122 }
1125 }
1129 }
1130 }
1133};
1134
1135void Viewer::updateTitle() {
1136 if (!fWindow) {
1137 return;
1138 }
1140 return;
1141 }
1142
1144 title.append(fSlides[fCurrentSlide]->getName());
1145
1146 if (fDrawViaSerialize) {
1147 title.append(" <serialize>");
1148 }
1149
1151 auto paintFlag = [
this, &paintTitle](
bool SkPaintFields::*
flag,
1152 bool (
SkPaint::* isFlag)() const,
1153 const char* on, const char* off)
1154 {
1155 if (fPaintOverrides.*
flag) {
1156 paintTitle.append((fPaint.*isFlag)() ? on : off);
1157 }
1158 };
1159
1160 auto fontFlag = [
this, &paintTitle](
bool SkFontFields::*
flag, bool (
SkFont::* isFlag)() const,
1161 const char* on, const char* off)
1162 {
1163 if (fFontOverrides.*
flag) {
1164 paintTitle.append((fFont.*isFlag)() ? on : off);
1165 }
1166 };
1167
1170
1172 "Force Autohint", "No Force Autohint");
1176 "Linear Metrics", "Non-Linear Metrics");
1178 "Bitmap Text", "No Bitmap Text");
1180
1184 paintTitle.append("Alias Text");
1185 break;
1187 paintTitle.append("Antialias Text");
1188 break;
1190 paintTitle.append("Subpixel Antialias Text");
1191 break;
1192 }
1193 }
1194
1198 paintTitle.append("No Hinting");
1199 break;
1201 paintTitle.append("Slight Hinting");
1202 break;
1204 paintTitle.append("Normal Hinting");
1205 break;
1207 paintTitle.append("Full Hinting");
1208 break;
1209 }
1210 }
1211 paintTitle.done();
1212
1213 switch (fColorMode) {
1214 case ColorMode::kLegacy:
1215 title.append(" Legacy 8888");
1216 break;
1217 case ColorMode::kColorManaged8888:
1218 title.append(" ColorManaged 8888");
1219 break;
1220 case ColorMode::kColorManagedF16:
1221 title.append(" ColorManaged F16");
1222 break;
1223 case ColorMode::kColorManagedF16Norm:
1224 title.append(" ColorManaged F16 Norm");
1225 break;
1226 }
1227
1228 if (ColorMode::kLegacy != fColorMode) {
1229 int curPrimaries = -1;
1232 curPrimaries = i;
1233 break;
1234 }
1235 }
1236 title.appendf(" %s Gamma %f",
1238 fColorSpaceTransferFn.g);
1239 }
1240
1243 switch (
params.fSurfaceProps.pixelGeometry()) {
1245 title.append( " Flat");
1246 break;
1248 title.append( " RGB");
1249 break;
1251 title.append( " BGR");
1252 break;
1254 title.append( " RGBV");
1255 break;
1257 title.append( " BGRV");
1258 break;
1259 }
1260 }
1261
1262 if (
params.fSurfaceProps.isUseDeviceIndependentFonts()) {
1263 title.append(" DFT");
1264 }
1265
1266 title.append(" [");
1269 if (msaa > 1) {
1270 title.appendf(" MSAA: %i", msaa);
1271 }
1272 title.append("]");
1273
1275#if defined(SK_GRAPHITE)
1278 .fGraphiteContextOptions.fPriv.fPathRendererStrategy;
1280 title.appendf(" [Path renderer strategy: %s]",
1281 get_path_renderer_strategy_string(strategy));
1282 }
1283#endif
1284 } else {
1289 }
1290 }
1291
1292 if (kPerspective_Real == fPerspectiveMode) {
1293 title.append(" Perspective (Real)");
1294 } else if (kPerspective_Fake == fPerspectiveMode) {
1295 title.append(" Perspective (Fake)");
1296 }
1297
1299}
1300
1301int Viewer::startupSlide() const {
1302
1303 if (!FLAGS_slide.isEmpty()) {
1305 for (
int i = 0; i <
count; i++) {
1306 if (fSlides[i]->getName().
equals(FLAGS_slide[0])) {
1307 return i;
1308 }
1309 }
1310
1311 fprintf(stderr, "Unknown slide \"%s\"\n", FLAGS_slide[0]);
1312 this->listNames();
1313 }
1314
1315 return 0;
1316}
1317
1318void Viewer::listNames() const {
1320 for (const auto& slide : fSlides) {
1321 SkDebugf(
" %s\n", slide->getName().c_str());
1322 }
1323}
1324
1325void Viewer::setCurrentSlide(int slide) {
1327
1328 if (slide == fCurrentSlide) {
1329 return;
1330 }
1331
1332 if (fCurrentSlide >= 0) {
1333 fSlides[fCurrentSlide]->unload();
1334 }
1335
1337 if (fApplyBackingScale) {
1339 }
1342 fCurrentSlide = slide;
1343 this->setupCurrentSlide();
1344}
1345
1346SkISize Viewer::currentSlideSize()
const {
1347 if (
auto size = fSlides[fCurrentSlide]->getDimensions(); !
size.isEmpty()) {
1349 }
1351}
1352
1353void Viewer::setupCurrentSlide() {
1354 if (fCurrentSlide >= 0) {
1355
1357 fDefaultMatrix.
reset();
1358
1361
1362
1364 if (windowRect.
width() > 0 && windowRect.
height() > 0) {
1367 }
1368 }
1369
1370
1371 fGesture.
setTransLimit(slideBounds, windowRect, this->computePreTouchMatrix());
1372
1373 this->updateTitle();
1374 this->updateUIState();
1375
1377
1379 }
1380}
1381
1382#define MAX_ZOOM_LEVEL 8.0f
1383#define MIN_ZOOM_LEVEL -8.0f
1384
1385void Viewer::changeZoomLevel(float delta) {
1386 fZoomLevel +=
delta;
1388 this->preTouchMatrixChanged();
1389}
1390
1391void Viewer::preTouchMatrixChanged() {
1392
1395 fGesture.
setTransLimit(slideBounds, windowRect, this->computePreTouchMatrix());
1396}
1397
1398SkMatrix Viewer::computePerspectiveMatrix() {
1400 SkPoint orthoPts[4] = { { 0, 0 }, {
w, 0 }, { 0,
h }, {
w,
h } };
1402 { fPerspectivePoints[0].
fX *
w, fPerspectivePoints[0].
fY *
h },
1403 { fPerspectivePoints[1].
fX *
w, fPerspectivePoints[1].
fY *
h },
1404 { fPerspectivePoints[2].
fX *
w, fPerspectivePoints[2].
fY *
h },
1405 { fPerspectivePoints[3].
fX *
w, fPerspectivePoints[3].
fY *
h }
1406 };
1408 m.setPolyToPoly(orthoPts, perspPts, 4);
1410}
1411
1412SkMatrix Viewer::computePreTouchMatrix() {
1414
1415 SkScalar zoomScale = exp(fZoomLevel);
1416 if (fApplyBackingScale) {
1418 }
1419 m.preTranslate((fOffset.
x() - 0.5f) * 2.0f, (fOffset.
y() - 0.5f) * 2.0f);
1420 m.preScale(zoomScale, zoomScale);
1421
1422 const SkISize slideSize = this->currentSlideSize();
1423 m.preRotate(fRotation, slideSize.
width() * 0.5f, slideSize.
height() * 0.5f);
1424
1425 if (kPerspective_Real == fPerspectiveMode) {
1426 SkMatrix persp = this->computePerspectiveMatrix();
1427 m.postConcat(persp);
1428 }
1429
1431}
1432
1436 m.preConcat(this->computePreTouchMatrix());
1438}
1439
1441 fPersistentCache.
reset();
1442 fCachedShaders.
clear();
1443 fBackendType = backendType;
1444
1445
1446 for(auto& slide : fSlides) {
1447 slide->gpuTeardown();
1448 }
1449
1451
1452#if defined(SK_BUILD_FOR_WIN)
1453
1454
1456 delete fWindow;
1457 fWindow = Window::CreateNativeWindow(nullptr);
1458
1459
1460 fCommands.
attach(fWindow);
1464
1465
1466
1467
1468
1469
1470
1472#endif
1473
1475}
1476
1477void Viewer::setColorMode(ColorMode colorMode) {
1478 fColorMode = colorMode;
1479 this->updateTitle();
1481}
1482
1484public:
1493 }
1494
1498 bool blobWillChange = false;
1501 bool shouldDraw = this->
filterFont(&filteredFont);
1502 if (it.font() != *filteredFont || !shouldDraw) {
1503 blobWillChange = true;
1504 break;
1505 }
1506 }
1507 if (!blobWillChange) {
1508 return blob;
1509 }
1510
1514 bool shouldDraw = this->
filterFont(&filteredFont);
1515 if (!shouldDraw) {
1516 continue;
1517 }
1518
1520
1523 ?
builder.allocRunText(font, it.glyphCount(), it.offset().x(),it.offset().y(),
1524 it.textSize())
1526 ?
builder.allocRunTextPosH(font, it.glyphCount(), it.offset().y(),
1527 it.textSize())
1529 ?
builder.allocRunTextPos(font, it.glyphCount(), it.textSize())
1531 ?
builder.allocRunTextRSXform(font, it.glyphCount(), it.textSize())
1533 uint32_t glyphCount = it.glyphCount();
1534 if (it.glyphs()) {
1535 size_t glyphSize = sizeof(decltype(*it.glyphs()));
1536 memcpy(runBuffer.
glyphs, it.glyphs(), glyphCount * glyphSize);
1537 }
1538 if (it.pos()) {
1539 size_t posSize = sizeof(decltype(*it.pos()));
1540 unsigned posPerGlyph = it.scalarsPerGlyph();
1541 memcpy(runBuffer.
pos, it.pos(), glyphCount * posPerGlyph * posSize);
1542 }
1543 if (it.text()) {
1544 size_t textSize = sizeof(decltype(*it.text()));
1545 uint32_t textCount = it.textSize();
1546 memcpy(runBuffer.
utf8text, it.text(), textCount * textSize);
1547 }
1548 if (it.clusters()) {
1549 size_t clusterSize = sizeof(decltype(*it.clusters()));
1550 memcpy(runBuffer.
clusters, it.clusters(), glyphCount * clusterSize);
1551 }
1552 }
1554 return cache->get();
1555 }
1561 }
1562
1568 if (!cache) {
1570 return;
1571 }
1576 }
1577
1581 }
1584 }
1587 }
1590 }
1593 }
1596 }
1599 }
1602 }
1605 }
1608 }
1611 }
1614 }
1615
1616 return true;
1617 }
1618
1622 }
1625 }
1628 }
1631 }
1634 }
1637 }
1640 }
1643 }
1646 }
1649 }
1652 }
1654 if (std::optional<SkBlendMode> mode =
paint.asBlendMode()) {
1656 }
1657 }
1660 }
1663 }
1666 }
1667 return true;
1668 }
1673};
1674
1679 };
1680 return sProcs;
1681}
1682
1684 if (fCurrentSlide < 0) {
1685 return;
1686 }
1687
1689
1690
1694
1695
1697 if (ColorMode::kLegacy != fColorMode) {
1701 }
1702
1703 if (fSaveToSKP) {
1706 fSlides[fCurrentSlide]->draw(recorderCanvas);
1711 fSaveToSKP = false;
1712 }
1713
1714
1716 switch (fColorMode) {
1717 case ColorMode::kLegacy:
1718 case ColorMode::kColorManaged8888:
1720 break;
1721 case ColorMode::kColorManagedF16:
1723 break;
1724 case ColorMode::kColorManagedF16Norm:
1726 break;
1727 }
1728
1729
1730
1731
1732
1733
1735 if (kPerspective_Fake == fPerspectiveMode ||
1736 fShowZoomWindow ||
1737 fShowHistogramWindow ||
1738 Window::kRaster_BackendType == fBackendType ||
1739 colorSpace != nullptr ||
1740 FLAGS_offscreen) {
1743
1746 offscreenSurface = Window::kRaster_BackendType == this->fBackendType
1749
1750 slideSurface = offscreenSurface.
get();
1751 slideCanvas = offscreenSurface->getCanvas();
1752 }
1753
1755 SkCanvas* recorderRestoreCanvas =
nullptr;
1756 if (fDrawViaSerialize) {
1757 recorderRestoreCanvas = slideCanvas;
1759 }
1760
1763
1765 if (fTiled) {
1768 for (
int y = 0;
y < fWindow->
height();
y += tileH) {
1769 for (
int x = 0;
x < fWindow->
width();
x += tileW) {
1772 fSlides[fCurrentSlide]->draw(slideCanvas);
1773 }
1774 }
1775
1776
1777 if (fDrawTileBoundaries) {
1781 for (
int y = 0;
y < fWindow->
height();
y += tileH) {
1782 for (
int x = 0;
x < fWindow->
width();
x += tileW) {
1784 }
1785 }
1786 }
1787 } else {
1788 slideCanvas->
concat(this->computeMatrix());
1789 if (kPerspective_Real == fPerspectiveMode) {
1791 }
1794 &fPaint, &fPaintOverrides,
1795 &fFont, &fFontOverrides);
1796 fSlides[fCurrentSlide]->draw(&filterCanvas);
1797 } else {
1798 fSlides[fCurrentSlide]->draw(slideCanvas);
1799 }
1800 }
1803
1804 if (recorderRestoreCanvas) {
1808 slideCanvas = recorderRestoreCanvas;
1810 }
1811
1812
1816
1817
1818 if (offscreenSurface) {
1819 fLastImage = offscreenSurface->makeImageSnapshot();
1820
1825 int prePerspectiveCount = canvas->
save();
1826 if (kPerspective_Fake == fPerspectiveMode) {
1829 canvas->
concat(this->computePerspectiveMatrix());
1830 }
1833 }
1834
1835 if (fShowSlideDimensions) {
1838 canvas->
concat(this->computeMatrix());
1841 paint.setColor(0x40FFFF00);
1843 }
1844}
1845
1847 this->setupCurrentSlide();
1849}
1850
1853
1855
1856 this->drawImGui();
1857
1859
1861
1862 direct->performDeferredCleanup(std::chrono::seconds(10));
1863 }
1864}
1865
1867 if (fCurrentSlide >= 0) {
1869 if (fApplyBackingScale) {
1871 }
1873 }
1874}
1875
1876SkPoint Viewer::mapEvent(
float x,
float y) {
1877 const auto m = this->computeMatrix();
1879
1881
1882 return inv.mapXY(
x,
y);
1883}
1884
1886 if (GestureDevice::kMouse == fGestureDevice) {
1887 return false;
1888 }
1889
1890 const auto slidePt = this->mapEvent(
x,
y);
1893 return true;
1894 }
1895
1896 void* castedOwner = reinterpret_cast<void*>(owner);
1900#if defined(SK_BUILD_FOR_IOS)
1901
1904
1907 this->setCurrentSlide(fCurrentSlide < fSlides.
size() - 1 ?
1908 fCurrentSlide + 1 : 0);
1909 } else {
1910 this->setCurrentSlide(fCurrentSlide > 0 ?
1911 fCurrentSlide - 1 : fSlides.
size() - 1);
1912 }
1913 }
1915 }
1916#endif
1917 break;
1918 }
1921 break;
1922 }
1925 break;
1926 }
1927 default: {
1928
1930 break;
1931 }
1932 }
1933 fGestureDevice = fGesture.
isBeingTouched() ? GestureDevice::kTouch : GestureDevice::kNone;
1935 return true;
1936}
1937
1939 if (GestureDevice::kTouch == fGestureDevice) {
1940 return false;
1941 }
1942
1943 const auto slidePt = this->mapEvent(
x,
y);
1944 if (fSlides[fCurrentSlide]->
onMouse(slidePt.x(), slidePt.y(),
state, modifiers)) {
1946 return true;
1947 }
1948
1952 break;
1953 }
1956 break;
1957 }
1960 break;
1961 }
1962 default: {
1964 break;
1965 }
1966 }
1967 fGestureDevice = fGesture.
isBeingTouched() ? GestureDevice::kMouse : GestureDevice::kNone;
1968
1971 }
1972 return true;
1973}
1974
1976
1977
1978
1984 return true;
1985}
1986
1989 this->setCurrentSlide(fCurrentSlide > 0 ? fCurrentSlide - 1 : fSlides.
size() - 1);
1990 return true;
1992 this->setCurrentSlide(fCurrentSlide < fSlides.
size() - 1 ? fCurrentSlide + 1 : 0);
1993 return true;
1994 }
1995 return false;
1996}
1997
2002 return true;
2005 return true;
2008 return true;
2009 default:
2011 break;
2012 }
2013
2014 return false;
2015}
2016
2018
2020
2021
2022
2023
2024 dc.
fDrawList->AddImage(gamutPaint, dc.fPos,
2025 ImVec2(dc.fPos.x + dc.fSize.x, dc.fPos.y + dc.fSize.y),
2026 ImVec2(242, 61), ImVec2(1897, 1922));
2027
2028 dc.dragPoint((
SkPoint*)(&primaries->
fRX),
true, 0xFF000040);
2029 dc.dragPoint((
SkPoint*)(&primaries->
fGX),
true, 0xFF004000);
2030 dc.dragPoint((
SkPoint*)(&primaries->
fBX),
true, 0xFF400000);
2031 dc.dragPoint((
SkPoint*)(&primaries->
fWX),
true);
2032 dc.fDrawList->AddPolyline(dc.fScreenPoints.begin(), 3, 0xFFFFFFFF, true, 1.5f);
2033}
2034
2037 dc.fillColor(IM_COL32(0, 0, 0, 128));
2038 dc.dragPoint(pt);
2039 return dc.fDragging;
2040}
2041
2044 dc.fillColor(IM_COL32(0, 0, 0, 128));
2045
2046 for (int i = 0; i < 4; ++i) {
2047 dc.dragPoint(pts + i);
2048 }
2049
2050 dc.fDrawList->AddLine(dc.fScreenPoints[0], dc.fScreenPoints[1], 0xFFFFFFFF);
2051 dc.fDrawList->AddLine(dc.fScreenPoints[1], dc.fScreenPoints[3], 0xFFFFFFFF);
2052 dc.fDrawList->AddLine(dc.fScreenPoints[3], dc.fScreenPoints[2], 0xFFFFFFFF);
2053 dc.fDrawList->AddLine(dc.fScreenPoints[2], dc.fScreenPoints[0], 0xFFFFFFFF);
2054
2055 return dc.fDragging;
2056}
2057
2059 return std::string("void main() { sk_FragColor = half4(1, 0, 1, 0.5); }");
2060}
2061
2063
2064
2065 size_t pos = inShader.rfind(
"return _out;\n");
2066 if (
pos == std::string::npos) {
2067 return inShader;
2068 }
2069
2070 std::string replacementShader = inShader;
2071 replacementShader.insert(
pos,
"_out.sk_FragColor = float4(1.0, 0.0, 1.0, 0.5); ");
2072 return replacementShader;
2073}
2074
2077 std::string highlight = versionDecl ? versionDecl : "";
2079 highlight.append("precision mediump float;\n");
2080 }
2082 "void main() { sk_FragColor = vec4(1, 0, 1, 0.5); }");
2083 return highlight;
2084}
2085
2086void Viewer::drawImGui() {
2087
2088 if (fShowImGuiTestWindow) {
2089 ImGui::ShowDemoWindow(&fShowImGuiTestWindow);
2090 }
2091
2092 if (fShowImGuiDebugWindow) {
2093
2094
2095 ImGui::SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver);
2097 bool displayParamsChanged = false;
2098 bool uiParamsChanged = false;
2100
2101 if (ImGui::Begin("Tools", &fShowImGuiDebugWindow,
2102 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
2103 if (ImGui::CollapsingHeader("Backend")) {
2104 int newBackend = static_cast<int>(fBackendType);
2106 ImGui::SameLine();
2107 ImGui::RadioButton("OpenGL", &newBackend, sk_app::Window::kNativeGL_BackendType);
2108#if SK_ANGLE && (defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC))
2109 ImGui::SameLine();
2110 ImGui::RadioButton("ANGLE", &newBackend, sk_app::Window::kANGLE_BackendType);
2111#endif
2112#if defined(SK_DAWN)
2113#if defined(SK_GRAPHITE)
2114 ImGui::SameLine();
2115 ImGui::RadioButton("Dawn (Graphite)", &newBackend,
2116 sk_app::Window::kGraphiteDawn_BackendType);
2117#endif
2118#endif
2119#if defined(SK_VULKAN) && !defined(SK_BUILD_FOR_MAC)
2120 ImGui::SameLine();
2121 ImGui::RadioButton("Vulkan", &newBackend, sk_app::Window::kVulkan_BackendType);
2122#if defined(SK_GRAPHITE)
2123 ImGui::SameLine();
2124 ImGui::RadioButton("Vulkan (Graphite)", &newBackend,
2125 sk_app::Window::kGraphiteVulkan_BackendType);
2126#endif
2127#endif
2128#if defined(SK_METAL)
2129 ImGui::SameLine();
2130 ImGui::RadioButton("Metal", &newBackend, sk_app::Window::kMetal_BackendType);
2131#if defined(SK_GRAPHITE)
2132 ImGui::SameLine();
2133 ImGui::RadioButton("Metal (Graphite)", &newBackend,
2134 sk_app::Window::kGraphiteMetal_BackendType);
2135#endif
2136#endif
2137#if defined(SK_DIRECT3D)
2138 ImGui::SameLine();
2139 ImGui::RadioButton("Direct3D", &newBackend, sk_app::Window::kDirect3D_BackendType);
2140#endif
2141 if (newBackend != fBackendType) {
2142 fDeferredActions.
push_back([newBackend,
this]() {
2144 });
2145 }
2146
2147 if (ctx) {
2148 bool* wire = &
params.fGrContextOptions.fWireframeMode;
2149 if (ImGui::Checkbox("Wireframe Mode", wire)) {
2150 displayParamsChanged = true;
2151 }
2152
2153 bool* reducedShaders = &
params.fGrContextOptions.fReducedShaderVariations;
2154 if (ImGui::Checkbox("Reduced shaders", reducedShaders)) {
2155 displayParamsChanged = true;
2156 }
2157
2158
2162 1;
2163
2164
2165 if (maxMSAA >= 4) {
2166 ImGui::Text("MSAA: ");
2167
2168 for (int curMSAA = 1; curMSAA <= maxMSAA; curMSAA *= 2) {
2169
2170
2171 if (curMSAA == 2) {
2172 continue;
2173 }
2174 ImGui::SameLine();
2176 &sampleCount, curMSAA);
2177 }
2178 }
2179
2180 if (sampleCount !=
params.fMSAASampleCount) {
2181 params.fMSAASampleCount = sampleCount;
2182 displayParamsChanged = true;
2183 }
2184 }
2185
2186 int pixelGeometryIdx = 0;
2188 pixelGeometryIdx =
params.fSurfaceProps.pixelGeometry() + 1;
2189 }
2190 if (ImGui::Combo("Pixel Geometry", &pixelGeometryIdx,
2191 "Default\0Flat\0RGB\0BGR\0RGBV\0BGRV\0\0"))
2192 {
2194 if (pixelGeometryIdx == 0) {
2198 } else {
2200 SkPixelGeometry pixelGeometry = SkTo<SkPixelGeometry>(pixelGeometryIdx - 1);
2202 }
2203 displayParamsChanged = true;
2204 }
2205
2206 bool useDFT =
params.fSurfaceProps.isUseDeviceIndependentFonts();
2207 if (ImGui::Checkbox("DFT", &useDFT)) {
2209 if (useDFT) {
2211 } else {
2213 }
2216 displayParamsChanged = true;
2217 }
2218
2219 if (ImGui::TreeNode("Path Renderers")) {
2222#if defined(SK_GRAPHITE)
2225 &
params.fGraphiteContextOptions.fPriv;
2228 if (ImGui::RadioButton(get_path_renderer_strategy_string(
s),
2232 displayParamsChanged = true;
2233 }
2234 }
2235 };
2236
2237 prsButton(PathRendererStrategy::kDefault);
2238
2240 PathRendererStrategy::kComputeAnalyticAA,
2241 PathRendererStrategy::kComputeMSAA16,
2242 PathRendererStrategy::kComputeMSAA8,
2243 PathRendererStrategy::kRasterAA,
2244 PathRendererStrategy::kTessellation,
2245 };
2246 for (size_t i = 0; i < std::size(strategies); ++i) {
2247 if (gctx->
priv().supportsPathRendererStrategy(strategies[i])) {
2248 prsButton(strategies[i]);
2249 }
2250 }
2251#endif
2252 } else if (ctx) {
2257 if (
x !=
params.fGrContextOptions.fGpuPathRenderers) {
2258 params.fGrContextOptions.fGpuPathRenderers =
x;
2259 displayParamsChanged = true;
2260 }
2261 }
2262 };
2263
2265#if defined(SK_GANESH)
2267 const auto* caps = ctx->
priv().
caps();
2270 }
2273 }
2274 }
2275#endif
2278 }
2281 } else {
2282 ImGui::RadioButton("Software", true);
2283 }
2284 ImGui::TreePop();
2285 }
2286 }
2287
2288 if (ImGui::CollapsingHeader("Tiling")) {
2289 ImGui::Checkbox("Enable", &fTiled);
2290 ImGui::Checkbox("Draw Boundaries", &fDrawTileBoundaries);
2291 ImGui::SliderFloat(
"Horizontal", &fTileScale.
fWidth, 0.1f, 1.0f);
2292 ImGui::SliderFloat(
"Vertical", &fTileScale.
fHeight, 0.1f, 1.0f);
2293 }
2294
2295 if (ImGui::CollapsingHeader("Transform")) {
2296 if (ImGui::Checkbox("Apply Backing Scale", &fApplyBackingScale)) {
2297 this->preTouchMatrixChanged();
2299
2300
2301 uiParamsChanged = true;
2302 }
2303
2304 float zoom = fZoomLevel;
2306 fZoomLevel = zoom;
2307 this->preTouchMatrixChanged();
2308 uiParamsChanged = true;
2309 }
2310 float deg = fRotation;
2311 if (ImGui::SliderFloat("Rotate", °, -30, 360, "%.3f deg")) {
2312 fRotation = deg;
2313 this->preTouchMatrixChanged();
2314 uiParamsChanged = true;
2315 }
2316 if (ImGui::CollapsingHeader("Subpixel offset", ImGuiTreeNodeFlags_NoTreePushOnOpen)) {
2318 this->preTouchMatrixChanged();
2319 uiParamsChanged = true;
2320 }
2321 }
else if (fOffset !=
SkVector{0.5f, 0.5f}) {
2322 this->preTouchMatrixChanged();
2323 uiParamsChanged = true;
2324 fOffset = {0.5f, 0.5f};
2325 }
2326 int perspectiveMode = static_cast<int>(fPerspectiveMode);
2327 if (ImGui::Combo("Perspective", &perspectiveMode, "Off\0Real\0Fake\0\0")) {
2328 fPerspectiveMode = static_cast<PerspectiveMode>(perspectiveMode);
2329 this->preTouchMatrixChanged();
2330 uiParamsChanged = true;
2331 }
2332 if (perspectiveMode != kPerspective_Off &&
ImGui_DragQuad(fPerspectivePoints)) {
2333 this->preTouchMatrixChanged();
2334 uiParamsChanged = true;
2335 }
2336 }
2337
2338 if (ImGui::CollapsingHeader("Paint")) {
2339 auto paintFlag = [this, &uiParamsChanged](const char* label, const char* items,
2340 bool SkPaintFields::*
flag,
2341 bool (
SkPaint::* isFlag)() const,
2342 void (
SkPaint::* setFlag)(bool) )
2343 {
2344 int itemIndex = 0;
2345 if (fPaintOverrides.*
flag) {
2346 itemIndex = (fPaint.*isFlag)() ? 2 : 1;
2347 }
2348 if (ImGui::Combo(label, &itemIndex, items)) {
2349 if (itemIndex == 0) {
2350 fPaintOverrides.*
flag =
false;
2351 } else {
2352 fPaintOverrides.*
flag =
true;
2353 (fPaint.*setFlag)(itemIndex == 2);
2354 }
2355 uiParamsChanged = true;
2356 }
2357 };
2358
2359 paintFlag("Antialias",
2360 "Default\0No AA\0AA\0\0",
2363
2364 paintFlag("Dither",
2365 "Default\0No Dither\0Dither\0\0",
2368
2369 int styleIdx = 0;
2370 if (fPaintOverrides.
fStyle) {
2371 styleIdx = SkTo<int>(fPaint.
getStyle()) + 1;
2372 }
2373 if (ImGui::Combo("Style", &styleIdx,
2374 "Default\0Fill\0Stroke\0Stroke and Fill\0\0"))
2375 {
2376 if (styleIdx == 0) {
2377 fPaintOverrides.
fStyle =
false;
2379 } else {
2380 fPaint.
setStyle(SkTo<SkPaint::Style>(styleIdx - 1));
2381 fPaintOverrides.
fStyle =
true;
2382 }
2383 uiParamsChanged = true;
2384 }
2385
2387
2388 ImGui::Checkbox(
"Override Stroke Width", &fPaintOverrides.
fStrokeWidth);
2391 if (ImGui::SliderFloat(
"Stroke Width", &
width, 0, 20)) {
2393 uiParamsChanged = true;
2394 }
2395 }
2396
2397 ImGui::Checkbox(
"Override Miter Limit", &fPaintOverrides.
fMiterLimit);
2400 if (ImGui::SliderFloat("Miter Limit", &miterLimit, 0, 20)) {
2402 uiParamsChanged = true;
2403 }
2404 }
2405
2406 int capIdx = 0;
2409 }
2410 if (ImGui::Combo("Cap Type", &capIdx,
2411 "Default\0Butt\0Round\0Square\0\0"))
2412 {
2413 if (capIdx == 0) {
2416 } else {
2419 }
2420 uiParamsChanged = true;
2421 }
2422
2423 int joinIdx = 0;
2426 }
2427 if (ImGui::Combo("Join Type", &joinIdx,
2428 "Default\0Miter\0Round\0Bevel\0\0"))
2429 {
2430 if (joinIdx == 0) {
2433 } else {
2436 }
2437 uiParamsChanged = true;
2438 }
2439 }
2440
2441 if (ImGui::CollapsingHeader("Font")) {
2442 int hintingIdx = 0;
2444 hintingIdx = SkTo<int>(fFont.
getHinting()) + 1;
2445 }
2446 if (ImGui::Combo("Hinting", &hintingIdx,
2447 "Default\0None\0Slight\0Normal\0Full\0\0"))
2448 {
2449 if (hintingIdx == 0) {
2452 } else {
2453 fFont.
setHinting(SkTo<SkFontHinting>(hintingIdx - 1));
2455 }
2456 uiParamsChanged = true;
2457 }
2458
2459 auto fontFlag = [this, &uiParamsChanged](const char* label, const char* items,
2460 bool SkFontFields::*
flag,
2461 bool (
SkFont::* isFlag)() const,
2462 void (
SkFont::* setFlag)(bool) )
2463 {
2464 int itemIndex = 0;
2465 if (fFontOverrides.*
flag) {
2466 itemIndex = (fFont.*isFlag)() ? 2 : 1;
2467 }
2468 if (ImGui::Combo(label, &itemIndex, items)) {
2469 if (itemIndex == 0) {
2470 fFontOverrides.*
flag =
false;
2471 } else {
2472 fFontOverrides.*
flag =
true;
2473 (fFont.*setFlag)(itemIndex == 2);
2474 }
2475 uiParamsChanged = true;
2476 }
2477 };
2478
2479 fontFlag("Fake Bold Glyphs",
2480 "Default\0No Fake Bold\0Fake Bold\0\0",
2483
2484 fontFlag("Baseline Snapping",
2485 "Default\0No Baseline Snapping\0Baseline Snapping\0\0",
2488
2489 fontFlag("Linear Text",
2490 "Default\0No Linear Text\0Linear Text\0\0",
2493
2494 fontFlag("Subpixel Position Glyphs",
2495 "Default\0Pixel Text\0Subpixel Text\0\0",
2498
2499 fontFlag("Embedded Bitmap Text",
2500 "Default\0No Embedded Bitmaps\0Embedded Bitmaps\0\0",
2503
2504 fontFlag("Force Auto-Hinting",
2505 "Default\0No Force Auto-Hinting\0Force Auto-Hinting\0\0",
2508
2509 int edgingIdx = 0;
2511 edgingIdx = SkTo<int>(fFont.
getEdging()) + 1;
2512 }
2513 if (ImGui::Combo("Edging", &edgingIdx,
2514 "Default\0Alias\0Antialias\0Subpixel Antialias\0\0"))
2515 {
2516 if (edgingIdx == 0) {
2517 fFontOverrides.
fEdging =
false;
2519 } else {
2520 fFont.
setEdging(SkTo<SkFont::Edging>(edgingIdx-1));
2521 fFontOverrides.
fEdging =
true;
2522 }
2523 uiParamsChanged = true;
2524 }
2525
2526 ImGui::Checkbox(
"Override Size", &fFontOverrides.
fSize);
2527 if (fFontOverrides.
fSize) {
2528 ImGui::DragFloat2(
"TextRange", fFontOverrides.
fSizeRange,
2529 0.001f, -10.0f, 300.0f, "%.6f", ImGuiSliderFlags_Logarithmic);
2530 float textSize = fFont.
getSize();
2531 if (ImGui::DragFloat("TextSize", &textSize, 0.001f,
2534 "%.6f", ImGuiSliderFlags_Logarithmic))
2535 {
2537 uiParamsChanged = true;
2538 }
2539 }
2540
2541 ImGui::Checkbox(
"Override ScaleX", &fFontOverrides.
fScaleX);
2546 uiParamsChanged = true;
2547 }
2548 }
2549
2550 ImGui::Checkbox(
"Override SkewX", &fFontOverrides.
fSkewX);
2551 if (fFontOverrides.
fSkewX) {
2555 uiParamsChanged = true;
2556 }
2557 }
2558 }
2559
2560 {
2562 if (fSlides[fCurrentSlide]->onGetControls(&controls)) {
2563 if (ImGui::CollapsingHeader("Current Slide")) {
2570 float val[3];
2573 if (ImGui::SliderFloat(
name, &val[0], val[1], val[2])) {
2575 }
2577 bool val;
2580 if (ImGui::Checkbox(
name, &val)) {
2582 }
2583 }
2584 }
2585 fSlides[fCurrentSlide]->onSetControls(controls);
2586 }
2587 }
2588 }
2589
2590 if (fShowSlidePicker) {
2591 ImGui::SetNextTreeNodeOpen(true);
2592 }
2593 if (ImGui::CollapsingHeader("Slide")) {
2594 static ImGuiTextFilter filter;
2595 static ImVector<const char*> filteredSlideNames;
2596 static ImVector<int> filteredSlideIndices;
2597
2598 if (fShowSlidePicker) {
2599 ImGui::SetKeyboardFocusHere();
2600 fShowSlidePicker = false;
2601 }
2602
2603 filter.Draw();
2604 filteredSlideNames.clear();
2605 filteredSlideIndices.clear();
2606 int filteredIndex = 0;
2607 for (
int i = 0; i < fSlides.
size(); ++i) {
2608 const char* slideName = fSlides[i]->getName().c_str();
2609 if (filter.PassFilter(slideName) || i == fCurrentSlide) {
2610 if (i == fCurrentSlide) {
2611 filteredIndex = filteredSlideIndices.
size();
2612 }
2613 filteredSlideNames.push_back(slideName);
2614 filteredSlideIndices.push_back(i);
2615 }
2616 }
2617
2618 if (ImGui::ListBox("", &filteredIndex, filteredSlideNames.begin(),
2619 filteredSlideNames.size(), 20)) {
2620 this->setCurrentSlide(filteredSlideIndices[filteredIndex]);
2621 }
2622 }
2623
2624 if (ImGui::CollapsingHeader("Color Mode")) {
2625 ColorMode newMode = fColorMode;
2626 auto cmButton = [&](ColorMode
mode,
const char* label) {
2627 if (ImGui::RadioButton(label, mode == fColorMode)) {
2629 }
2630 };
2631
2632 cmButton(ColorMode::kLegacy, "Legacy 8888");
2633 cmButton(ColorMode::kColorManaged8888, "Color Managed 8888");
2634 cmButton(ColorMode::kColorManagedF16, "Color Managed F16");
2635 cmButton(ColorMode::kColorManagedF16Norm, "Color Managed F16 Norm");
2636
2637 if (newMode != fColorMode) {
2638 this->setColorMode(newMode);
2639 }
2640
2641
2642 int primariesIdx = 4;
2645 primariesIdx = i;
2646 break;
2647 }
2648 }
2649
2650
2651 ImGui::SliderFloat(
"Gamma", &fColorSpaceTransferFn.
g, 0.5f, 3.5f);
2652
2653 if (ImGui::Combo("Primaries", &primariesIdx,
2654 "sRGB\0AdobeRGB\0P3\0Rec. 2020\0Custom\0\0")) {
2655 if (primariesIdx >= 0 && primariesIdx <= 3) {
2657 }
2658 }
2659
2660 if (ImGui::Button("Spin")) {
2661 float rx = fColorSpacePrimaries.
fRX,
2662 ry = fColorSpacePrimaries.
fRY;
2663 fColorSpacePrimaries.
fRX = fColorSpacePrimaries.
fGX;
2664 fColorSpacePrimaries.
fRY = fColorSpacePrimaries.
fGY;
2665 fColorSpacePrimaries.
fGX = fColorSpacePrimaries.
fBX;
2666 fColorSpacePrimaries.
fGY = fColorSpacePrimaries.
fBY;
2667 fColorSpacePrimaries.
fBX = rx;
2668 fColorSpacePrimaries.
fBY = ry;
2669 }
2670
2671
2673 }
2674
2675 if (ImGui::CollapsingHeader("Animation")) {
2677 if (ImGui::Checkbox("Pause", &isPaused)) {
2679 }
2680
2681 float speed = fAnimTimer.
getSpeed();
2682 if (ImGui::DragFloat("Speed", &speed, 0.1f)) {
2684 }
2685 }
2686
2687 if (ImGui::CollapsingHeader("Shaders")) {
2688 bool sksl =
params.fGrContextOptions.fShaderCacheStrategy ==
2690
2691#if defined(SK_VULKAN)
2692 const bool isVulkan = fBackendType == sk_app::Window::kVulkan_BackendType;
2693#else
2694 const bool isVulkan = false;
2695#endif
2696
2697
2698
2699 static bool gLoadPending = false;
2700 if (gLoadPending) {
2701 fCachedShaders.
clear();
2702
2703 if (ctx) {
2707 int hitCount) {
2708 CachedShader& entry(fCachedShaders.
push_back());
2712 entry.fKeyString =
hash.finish().toHexString();
2713 entry.fKeyDescription = description;
2714
2718 entry.fInterfaces,
2720 });
2721 }
2722#if defined(SK_GRAPHITE)
2724 int index = 1;
2727
2728 const skgpu::graphite::GraphicsPipeline::PipelineInfo& pipelineInfo =
2729 pipeline->getPipelineInfo();
2733 dict->
lookup(pipelineInfo.fPaintID);
2734
2735 CachedShader& entry(fCachedShaders.
push_back());
2736 entry.fKey = nullptr;
2737 entry.fKeyString =
SkStringPrintf(
"#%-3d RenderStep: %u, Paint: ",
2738 index++,
2739 pipelineInfo.fRenderStepID);
2740 entry.fKeyString.append(paintKey.
toString(dict));
2741
2742 if (sksl) {
2744 pipelineInfo.fSkSLVertexShader;
2746 pipelineInfo.fSkSLFragmentShader;
2748 } else {
2750 pipelineInfo.fNativeVertexShader;
2752 pipelineInfo.fNativeFragmentShader;
2753
2754
2756 }
2757 };
2759 }
2760#endif
2761
2762 gLoadPending = false;
2763
2764#if defined(SK_VULKAN)
2765 if (isVulkan && !sksl) {
2766
2767 spvtools::SpirvTools
tools(SPV_ENV_VULKAN_1_0);
2768 for (auto& entry : fCachedShaders) {
2770 const std::string& spirv(entry.fShader[i]);
2771 std::string disasm;
2772 tools.Disassemble((
const uint32_t*)spirv.c_str(), spirv.size() / 4,
2773 &disasm);
2774 entry.fShader[i].assign(disasm);
2775 }
2776 }
2777 } else
2778#endif
2779 {
2780
2781 for (auto& entry : fCachedShaders) {
2784 }
2785 }
2786 }
2787 }
2788
2789
2790
2791 bool doView = ImGui::Button("View"); ImGui::SameLine();
2792 bool doApply = false;
2793 bool doDump = false;
2794 if (ctx) {
2795
2796 doApply = ImGui::Button("Apply Changes"); ImGui::SameLine();
2797 doDump = ImGui::Button("Dump SkSL to resources/sksl/");
2798 }
2799 int newOptLevel = fOptLevel;
2800 ImGui::RadioButton("SkSL", &newOptLevel, kShaderOptLevel_Source);
2801 ImGui::SameLine();
2802 ImGui::RadioButton("Compile", &newOptLevel, kShaderOptLevel_Compile);
2803 ImGui::SameLine();
2804 ImGui::RadioButton("Optimize", &newOptLevel, kShaderOptLevel_Optimize);
2805 ImGui::SameLine();
2806 ImGui::RadioButton("Inline", &newOptLevel, kShaderOptLevel_Inline);
2807
2808
2809
2810 static bool sDoDeferredView = false;
2811 if (doView || doDump || newOptLevel != fOptLevel) {
2812 sksl = doDump || (newOptLevel == kShaderOptLevel_Source);
2813 fOptLevel = (ShaderOptLevel)newOptLevel;
2814 switch (fOptLevel) {
2815 case kShaderOptLevel_Source:
2816 Compiler::EnableOptimizer(OverrideFlag::kOff);
2817 Compiler::EnableInliner(OverrideFlag::kOff);
2818 break;
2819 case kShaderOptLevel_Compile:
2820 Compiler::EnableOptimizer(OverrideFlag::kOff);
2821 Compiler::EnableInliner(OverrideFlag::kOff);
2822 break;
2823 case kShaderOptLevel_Optimize:
2824 Compiler::EnableOptimizer(OverrideFlag::kOn);
2825 Compiler::EnableInliner(OverrideFlag::kOff);
2826 break;
2827 case kShaderOptLevel_Inline:
2828 Compiler::EnableOptimizer(OverrideFlag::kOn);
2829 Compiler::EnableInliner(OverrideFlag::kOn);
2830 break;
2831 }
2832
2833 params.fGrContextOptions.fShaderCacheStrategy =
2836 displayParamsChanged = true;
2837
2838 fDeferredActions.
push_back([doDump,
this]() {
2839
2840 fPersistentCache.
reset();
2841 sDoDeferredView = true;
2842
2843
2844 if (doDump) {
2846 this->dumpShadersToResources();
2847 });
2848 }
2849 });
2850 }
2851
2852 ImGui::BeginChild("##ScrollingRegion");
2853 for (auto& entry : fCachedShaders) {
2854 bool inTreeNode = ImGui::TreeNode(entry.fKeyString.c_str());
2855 bool hovered = ImGui::IsItemHovered();
2856 if (hovered != entry.fHovered) {
2857
2858 entry.fHovered = hovered;
2859 doApply = true;
2860 }
2861 if (inTreeNode) {
2862 auto stringBox = [](const char* label, std::string* str) {
2863
2864 int lines = std::count(str->begin(), str->end(),
'\n') + 2;
2865 ImVec2 boxSize(-1.0f, ImGui::GetTextLineHeight() * std::min(lines, 30));
2866 ImGui::InputTextMultiline(label, str, boxSize);
2867 };
2868 if (ImGui::TreeNode("Key")) {
2869 ImGui::TextWrapped("%s", entry.fKeyDescription.c_str());
2870 ImGui::TreePop();
2871 }
2874 ImGui::TreePop();
2875 }
2876 }
2877 ImGui::EndChild();
2878
2879 if (doView || sDoDeferredView) {
2880 fPersistentCache.
reset();
2881 if (ctx) {
2882 ctx->
priv().
getGpu()->resetShaderCacheForTesting();
2883 }
2884#if defined(SK_GRAPHITE)
2887 }
2888#endif
2889 gLoadPending = true;
2890 sDoDeferredView = false;
2891 }
2892
2893
2894
2895 if (isVulkan && !sksl) {
2896 doApply = false;
2897 }
2898 if (ctx && doApply) {
2899 fPersistentCache.
reset();
2900 ctx->
priv().
getGpu()->resetShaderCacheForTesting();
2901 for (auto& entry : fCachedShaders) {
2903 if (entry.fHovered) {
2904
2905
2907 switch (entry.fShaderType) {
2910 break;
2911 }
2915 break;
2916 }
2919 break;
2920 }
2921 }
2922 }
2923
2925 entry.fShader,
2926 entry.fInterfaces,
2928 fPersistentCache.
store(*entry.fKey, *data, entry.fKeyDescription);
2929
2931 }
2932 }
2933 }
2934 }
2935 if (displayParamsChanged || uiParamsChanged) {
2937 if (displayParamsChanged) {
2939 }
2941 this->updateTitle();
2942 });
2943 }
2944 ImGui::End();
2945 }
2946
2948 ImGui::SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver);
2949 ImGui::Begin("Shader Errors", nullptr, ImGuiWindowFlags_NoFocusOnAppearing);
2954 ImGui::TextWrapped("%4i\t%s\n", lineNumber, lineText);
2955 });
2956 }
2957 ImGui::End();
2959 }
2960
2961 if (fShowZoomWindow && fLastImage) {
2962 ImGui::SetNextWindowSize(ImVec2(200, 200), ImGuiCond_FirstUseEver);
2963 if (ImGui::Begin("Zoom", &fShowZoomWindow)) {
2964 static int zoomFactor = 8;
2965 if (ImGui::Button("<<")) {
2966 zoomFactor = std::max(zoomFactor / 2, 4);
2967 }
2968 ImGui::SameLine(); ImGui::Text("%2d", zoomFactor); ImGui::SameLine();
2969 if (ImGui::Button(">>")) {
2970 zoomFactor = std::min(zoomFactor * 2, 32);
2971 }
2972
2973 if (!fZoomWindowFixed) {
2974 ImVec2 mousePos = ImGui::GetMousePos();
2975 fZoomWindowLocation =
SkPoint::Make(mousePos.x, mousePos.y);
2976 }
2981 ImVec2 avail = ImGui::GetContentRegionAvail();
2982
2983 uint32_t pixel = 0;
2985 bool didGraphiteRead = false;
2987#if defined(GRAPHITE_TEST_UTILS)
2992 didGraphiteRead = fLastImage->readPixelsGraphite(fWindow->
graphiteRecorder(),
2993 pixels,
2994 xInt,
2995 yInt);
2996 pixel = *pixels.
addr32();
2997 ImGui::SameLine();
2998 ImGui::Text("(X, Y): %d, %d RGBA: %X %X %X %X",
2999 xInt, yInt,
3002#endif
3003 }
3007 &pixel,
3009 xInt,
3010 yInt)) {
3011 ImGui::SameLine();
3012 ImGui::Text("(X, Y): %d, %d RGBA: %X %X %X %X",
3013 xInt, yInt,
3016 } else {
3017 if (!didGraphiteRead) {
3018 ImGui::SameLine();
3019 ImGui::Text("Failed to readPixels");
3020 }
3021 }
3022
3024
3025
3026 c->
scale(zoomFactor, zoomFactor);
3027 c->
translate(avail.x * 0.5f / zoomFactor -
x - 0.5f,
3028 avail.y * 0.5f / zoomFactor -
y - 0.5f);
3030
3034 });
3035 }
3036
3037 ImGui::End();
3038 }
3039
3040 if (fShowHistogramWindow && fLastImage) {
3041 ImGui::SetNextWindowSize(ImVec2(450, 500));
3042 ImGui::SetNextWindowBgAlpha(0.5f);
3043 if (ImGui::Begin("Color Histogram (R,G,B)", &fShowHistogramWindow)) {
3047
3049 info.minRowBytes(), 0, 0)) {
3050 std::vector<float> r(256), g(256),
b(256);
3051 for (
int y = 0;
y <
info.height(); ++
y) {
3052 for (
int x = 0;
x <
info.width(); ++
x) {
3053 const auto pmc = *pixmap.
addr32(
x,
y);
3057 }
3058 }
3059
3060 ImGui::PushItemWidth(-1);
3061 ImGui::PlotHistogram("R", r.data(), r.size(), 0, nullptr,
3062 FLT_MAX, FLT_MAX, ImVec2(0, 150));
3063 ImGui::PlotHistogram("G", g.data(), g.size(), 0, nullptr,
3064 FLT_MAX, FLT_MAX, ImVec2(0, 150));
3065 ImGui::PlotHistogram(
"B",
b.data(),
b.size(), 0,
nullptr,
3066 FLT_MAX, FLT_MAX, ImVec2(0, 150));
3067 ImGui::PopItemWidth();
3068 }
3069 }
3070
3071 ImGui::End();
3072 }
3073}
3074
3075void Viewer::dumpShadersToResources() {
3076
3077
3078 std::vector<const CachedShader*> shaders;
3079 shaders.reserve(fCachedShaders.
size());
3080 for (const CachedShader& shader : fCachedShaders) {
3081 shaders.push_back(&shader);
3082 }
3083
3084 std::sort(shaders.begin(), shaders.end(), [](
const CachedShader*
a,
const CachedShader*
b) {
3085 return std::tie(a->fShader[kFragment_GrShaderType], a->fShader[kVertex_GrShaderType]) <
3086 std::tie(b->fShader[kFragment_GrShaderType], b->fShader[kVertex_GrShaderType]);
3087 });
3088
3089
3092 fSlides[fCurrentSlide]->getName().c_str());
3095 return;
3096 }
3097
3098 int index = 0;
3099 for (const auto& entry : shaders) {
3102 if (vertFile) {
3106 } else {
3108 }
3109
3112 if (fragFile) {
3116 } else {
3118 }
3119
3120 ++index;
3121 }
3122}
3123
3125 TArray<std::function<void()>> actionsToRun;
3126 actionsToRun.
swap(fDeferredActions);
3127
3128 for (const auto& fn : actionsToRun) {
3129 fn();
3130 }
3131
3134 bool animateWantsInval = fSlides[fCurrentSlide]->animate(fAnimTimer.
nanos());
3136
3137 ImGuiIO& io = ImGui::GetIO();
3138
3139
3140
3141
3142 if (animateWantsInval || fStatsLayer.
getActive() || fRefresh ||
3143 io.MetricsActiveWindows > 1 || io.MetricsRenderWindows > 0) {
3145 }
3146}
3147
3148template <typename OptionsFunc>
3150 OptionsFunc&& optionsFunc) {
3152 {
3155
3157 {
3158 optionsFunc(writer);
3159 }
3161 }
3163}
3164
3165
3166void Viewer::updateUIState() {
3167 if (!fWindow) {
3168 return;
3169 }
3171 return;
3172 }
3173
3177
3178
3181 for(const auto& slide : fSlides) {
3183 }
3184 });
3185
3186
3192 }
3193 });
3194
3195
3199 writer.appendS32(0);
3200
3201 if (sk_app::Window::kRaster_BackendType == fBackendType) {
3202 return;
3203 }
3204
3205 for (
int msaa : {4, 8, 16}) {
3207 }
3208 });
3209
3210
3211
3212 GpuPathRenderers pr = fWindow->getRequestedDisplayParams().fGrContextOptions.fGpuPathRenderers;
3215 auto ctx = fWindow->directContext();
3216 if (!ctx) {
3218 } else {
3220#if defined(SK_GANESH)
3221 if (fWindow->sampleCount() > 1 || FLAGS_dmsaa) {
3222 const auto* caps = ctx->priv().caps();
3223 if (skgpu::ganesh::AtlasPathRenderer::IsSupported(ctx)) {
3224 writer.appendString(gGaneshPathRendererNames[GpuPathRenderers::kAtlas]);
3225 }
3228 }
3229 }
3230#endif
3231 if (1 == fWindow->sampleCount()) {
3232 writer.appendString(gGaneshPathRendererNames[GpuPathRenderers::kSmall]);
3233 }
3236 }
3237 });
3238
3239
3243 for (const auto& softkey : fCommands.getCommandsAsSoftkeys()) {
3245 }
3246 });
3247
3250
3252
3253
3254 const SkString cstring(
static_cast<const char*
>(
data->data()),
data->size());
3255
3256 fWindow->setUIState(cstring.c_str());
3257}
3258
3260
3261
3262
3263
3265 for (
int i = 0; i < fSlides.
size(); ++i) {
3266 if (fSlides[i]->getName().
equals(stateValue)) {
3267 this->setCurrentSlide(i);
3268 return;
3269 }
3270 }
3271
3277 if (fBackendType != i) {
3278 fBackendType = backendType;
3279 for(auto& slide : fSlides) {
3280 slide->gpuTeardown();
3281 }
3284 }
3285 break;
3286 }
3287 }
3290 int sampleCount = atoi(stateValue.
c_str());
3291 if (sampleCount !=
params.fMSAASampleCount) {
3292 params.fMSAASampleCount = sampleCount;
3295 this->updateTitle();
3296 this->updateUIState();
3297 }
3301 if (pair.second == stateValue.
c_str()) {
3302 if (
params.fGrContextOptions.fGpuPathRenderers != pair.first) {
3306 this->updateTitle();
3307 this->updateUIState();
3308 }
3309 break;
3310 }
3311 }
3315 this->updateUIState();
3316 }
3318
3319
3321 } else {
3323 }
3324}
3325
3328}
3329
3331 if (fSlides[fCurrentSlide]->
onChar(c)) {
3333 return true;
3334 } else {
3335 return fCommands.
onChar(c, modifiers);
3336 }
3337}
static SkM44 inv(const SkM44 &m)
static bool match(const char *needle, const char *haystack)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
void initializeEventTracingForTools(const char *traceFlag)
static const int kGrShaderTypeCount
void SetResourcePath(const char *resource)
SkString GetResourcePath(const char *resource)
sk_sp< SkBlender > GetRuntimeBlendForBlendMode(SkBlendMode mode)
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
#define SkAssertResult(cond)
#define SkASSERT_RELEASE(cond)
#define SkDEBUGFAILF(fmt,...)
#define SkGetPackedB32(packed)
#define SkGetPackedR32(packed)
#define SkGetPackedA32(packed)
#define SkGetPackedG32(packed)
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
@ kRGBA_F16Norm_SkColorType
pixel with half floats in [0,1] for red, green, blue, alpha;
constexpr SkColor SK_ColorMAGENTA
constexpr SkColor SK_ColorRED
constexpr SkColor SK_ColorGREEN
constexpr SkColor SK_ColorWHITE
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
@ kNormal
glyph outlines modified to improve constrast
@ kNone
glyph outlines unchanged
@ kSlight
minimal modification to improve constrast
@ kFull
modifies glyph outlines for maximum constrast
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
static SkImage_Base * as_IB(SkImage *image)
bool sk_mkdir(const char *path)
FILE * sk_fopen(const char path[], SkFILE_Flags)
size_t sk_fwrite(const void *buffer, size_t byteCount, FILE *)
bool sk_exists(const char *path, SkFILE_Flags=(SkFILE_Flags) 0)
static uint32_t hash(const SkShaderBase::GradientInfo &v)
static bool equals(T *a, T *b)
#define SkScalarRoundToInt(x)
#define SkScalarCeilToInt(x)
SK_API SkString static SkString SkStringPrintf()
bool SkStrEndsWith(const char string[], const char suffixStr[])
@ kUnknown_SkPixelGeometry
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
void SkTQSort(T *begin, T *end, const C &lessThan)
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
Slide *(*)() SlideFactory
static SkColorSpacePrimaries gSrgbPrimaries
static void WriteStateObject(SkJSONWriter &writer, const char *name, const char *value, OptionsFunc &&optionsFunc)
static std::map< GpuPathRenderers, std::string > gGaneshPathRendererNames
static const char kSoftkeyHint[]
static void ImGui_Primaries(SkColorSpacePrimaries *primaries, SkPaint *gamutPaint)
static const char kName[]
static const char kValue[]
static SkColorSpacePrimaries gAdobePrimaries
static SkSerialProcs serial_procs_using_png()
static CapturingShaderErrorHandler gShaderErrorHandler
const char * get_backend_string(sk_app::Window::BackendType type)
static sk_sp< SkData > base64_string_to_data(const std::string &s)
static std::string build_metal_highlight_shader(const std::string &inShader)
static Window::BackendType backend_type_for_window(Window::BackendType backendType)
static bool primaries_equal(const SkColorSpacePrimaries &a, const SkColorSpacePrimaries &b)
static bool ImGui_DragLocation(SkPoint *pt)
static const char kOptions[]
static bool ImGui_DragQuad(SkPoint *pts)
static SkColorSpacePrimaries gRec2020Primaries
static sk_sp< SkData > data_from_file(FILE *fp)
static std::string build_glsl_highlight_shader(const GrShaderCaps &shaderCaps)
static const char kMSAAStateName[]
static SkColorSpacePrimaries gP3Primaries
static bool is_graphite_backend_type(sk_app::Window::BackendType type)
static const char kPathRendererStateName[]
static std::vector< sk_sp< SkImage > > find_data_uri_images(sk_sp< SkData > data)
struct NamedPrimaries gNamedPrimaries[]
static const char kRefreshStateName[]
static const char kBackendStateName[]
static sk_app::Window::BackendType get_backend_type(const char *str)
static std::string build_sksl_highlight_shader()
static const char kSlideStateName[]
static const char kSoftkeyStateName[]
void setSpeed(float speed)
static sk_sp< BisectSlide > Create(const char filepath[])
TArray< SkString > fErrors
TArray< SkString > fShaders
static bool ShouldSkip(const SkTDArray< const char * > &strings, const char *name)
static void Parse(int argc, const char *const *argv)
const GrCaps * caps() const
const GrShaderCaps * shaderCaps() const
SK_API int maxSurfaceSampleCountForColorType(SkColorType colorType) const
GrDirectContextPriv priv()
void skiaWidget(const ImVec2 &size, SkiaWidgetFunc func)
void draw(SkCanvas *canvas) override
void onDrawGlyphRunList(const sktext::GlyphRunList &glyphRunList, const SkPaint &paint) override
bool filterFont(SkTCopyOnFirstWrite< SkFont > *font) const
Viewer::SkFontFields * fFontOverrides
Viewer::SkPaintFields * fPaintOverrides
const SkTextBlob * filterTextBlob(const SkPaint &paint, const SkTextBlob *blob, sk_sp< SkTextBlob > *cache)
void onDrawTextBlob(const SkTextBlob *blob, SkScalar x, SkScalar y, const SkPaint &paint) override
bool onFilter(SkPaint &paint) const override
void alloc(const SkImageInfo &)
bool getProps(SkSurfaceProps *props) const
void drawRect(const SkRect &rect, const SkPaint &paint)
void clipRect(const SkRect &rect, SkClipOp op, bool doAntiAlias)
void translate(SkScalar dx, SkScalar dy)
void clear(SkColor color)
void restoreToCount(int saveCount)
void scale(SkScalar sx, SkScalar sy)
void concat(const SkMatrix &matrix)
void drawPicture(const SkPicture *picture)
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
static sk_sp< SkColorSpace > MakeRGB(const skcms_TransferFunction &transferFn, const skcms_Matrix3x3 &toXYZ)
static sk_sp< SkData > MakeUninitialized(size_t length)
sk_sp< SkData > detachAsData()
bool isBaselineSnap() const
void setSubpixel(bool subpixel)
void setScaleX(SkScalar scaleX)
void setLinearMetrics(bool linearMetrics)
void setBaselineSnap(bool baselineSnap)
void setEdging(Edging edging)
SkFontHinting getHinting() const
void setSize(SkScalar textSize)
bool isForceAutoHinting() const
bool isLinearMetrics() const
bool isEmbeddedBitmaps() const
SkScalar getScaleX() const
SkScalar getSkewX() const
void setSkewX(SkScalar skewX)
void setForceAutoHinting(bool forceAutoHinting)
sk_sp< SkTypeface > refTypeface() const
void setHinting(SkFontHinting hintingLevel)
@ kAntiAlias
may have transparent pixels on glyph edges
@ kAlias
no transparent pixels on glyph edges
@ kSubpixelAntiAlias
glyph positioned in pixel using transparency
void setEmbolden(bool embolden)
void setEmbeddedBitmaps(bool embeddedBitmaps)
static OpenTypeSVGDecoderFactory SetOpenTypeSVGDecoderFactory(OpenTypeSVGDecoderFactory)
bool readPixels(GrDirectContext *context, const SkImageInfo &dstInfo, void *dstPixels, size_t dstRowBytes, int srcX, int srcY, CachingHint cachingHint=kAllow_CachingHint) const
void appendS32(int32_t value)
void appendNString(char const (&value)[N])
void beginArray(const char *name=nullptr, bool multiline=true)
void beginObject(const char *name=nullptr, bool multiline=true)
void appendCString(const char *value)
void appendString(const char *value, size_t size)
bool write(const void *buffer, size_t size) final
static SkMatrix RectToRect(const SkRect &src, const SkRect &dst, ScaleToFit mode=kFill_ScaleToFit)
@ kStart_ScaleToFit
scales and aligns to left and top
static SkString Join(const char *rootPath, const char *relativePath)
static SkString Basename(const char *fullPath)
void onDrawTextBlob(const SkTextBlob *blob, SkScalar x, SkScalar y, const SkPaint &paint) override
void onDrawGlyphRunList(const sktext::GlyphRunList &, const SkPaint &) override
SkScalar getStrokeMiter() const
@ kDefault_Cap
equivalent to kButt_Cap
void setStyle(Style style)
void setColor(SkColor color)
void setStrokeMiter(SkScalar miter)
sk_sp< SkShader > refShader() const
void setAntiAlias(bool aa)
sk_sp< SkImageFilter > refImageFilter() const
void setDither(bool dither)
void setStrokeCap(Cap cap)
SkBlendMode getBlendMode_or(SkBlendMode defaultMode) const
@ kStroke_Style
set to stroke geometry
@ kFill_Style
set to fill geometry
void setStrokeJoin(Join join)
sk_sp< SkColorFilter > refColorFilter() const
SkColor4f getColor4f() const
SkScalar getStrokeWidth() const
@ kDefault_Join
equivalent to kMiter_Join
sk_sp< SkMaskFilter > refMaskFilter() const
sk_sp< SkPathEffect > refPathEffect() const
Join getStrokeJoin() const
void setStrokeWidth(SkScalar width)
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
sk_sp< SkPicture > finishRecordingAsPicture()
sk_sp< SkData > serialize(const SkSerialProcs *procs=nullptr) const
static sk_sp< SkPicture > MakeFromData(const SkData *data, const SkDeserialProcs *procs=nullptr)
const uint32_t * addr32() const
void * writable_addr() const
static std::unique_ptr< SkOpenTypeSVGDecoder > Make(const uint8_t *svg, size_t svgLength)
bool equals(const SkString &) const
void append(const char text[])
const char * c_str() const
@ kUseDeviceIndependentFonts_Flag
SkPixelGeometry pixelGeometry() const
@ kHorizontal_Positioning
virtual void gpuTeardown()
void setTransLimit(const SkRect &contentRect, const SkRect &windowRect, const SkMatrix &preTouchM)
void touchEnd(void *owner)
bool isFling(SkPoint *dir)
void touchBegin(void *owner, float x, float y)
void touchMoved(void *owner, float x, float y)
const SkMatrix & localM()
const SkMatrix & globalM() const
void updateZoom(float scale, float startX, float startY, float lastX, float lastY)
bool onChar(SkUnichar c, skui::ModifierKey modifiers) override
bool onKey(skui::Key key, skui::InputState state, skui::ModifierKey modifiers) override
bool onTouch(intptr_t owner, skui::InputState state, float x, float y) override
void onBackendCreated() override
bool onMouseWheel(float delta, int x, int y, skui::ModifierKey) override
bool onPinch(skui::InputState state, float scale, float x, float y) override
void onResize(int width, int height) override
Viewer(int argc, char **argv, void *platformData)
void onUIStateChanged(const SkString &stateName, const SkString &stateValue) override
void onPaint(SkSurface *) override
bool onFling(skui::InputState state) override
bool onMouse(int x, int y, skui::InputState state, skui::ModifierKey modifiers) override
void attach(Window *window)
void drawHelp(SkCanvas *canvas)
bool onChar(SkUnichar, skui::ModifierKey modifiers)
bool onKey(skui::Key key, skui::InputState state, skui::ModifierKey modifiers)
bool onSoftkey(const SkString &softkey)
virtual const DisplayParams & getRequestedDisplayParams()
virtual bool scaleContentToFit() const
skgpu::graphite::Context * graphiteContext() const
void pushLayer(Layer *layer)
virtual void setRequestedDisplayParams(const DisplayParams &, bool allowReattach=true)
virtual bool attach(BackendType)=0
GrDirectContext * directContext() const
virtual void setTitle(const char *)=0
virtual float scaleFactor() const
skgpu::graphite::Recorder * graphiteRecorder() const
void store(const SkData &key, const SkData &data, const SkString &description) override
void reset(T *ptr=nullptr)
static bool IsSupported(GrRecordingContext *)
static bool IsSupported(const GrCaps &)
const GlobalCache * globalCache() const
const ShaderCodeDictionary * shaderCodeDictionary() const
SkString toString(const ShaderCodeDictionary *dict) const
PaintParamsKey lookup(UniquePaintParamsID) const SK_EXCLUDES(fSpinLock)
void resize(size_t count)
sk_sp< SkTextBlob > makeBlob() const
const EmbeddedViewParams * params
FlutterSemanticsFlag flag
FlutterSemanticsFlag flags
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
std::array< MockImage, 3 > images
void RegisterAllAvailable()
void SetCtxOptions(struct GrContextOptions *)
sk_sp< SkData > PackCachedShaders(SkFourByteTag shaderType, const std::string shaders[], const SkSL::Program::Interface interfaces[], int numInterfaces, const ShaderMetadata *meta)
bool UnpackCachedShaders(SkReadBuffer *reader, std::string shaders[], SkSL::Program::Interface interfaces[], int numInterfaces, ShaderMetadata *meta)
SkFourByteTag GetType(SkReadBuffer *reader)
SK_API sk_sp< SkImage > DeferredFromEncodedData(sk_sp< SkData > encoded, std::optional< SkAlphaType > alphaType=std::nullopt)
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
sk_sp< const SkPicture > picture
SkSamplingOptions sampling
std::string void appendf(std::string *str, const char *fmt,...) SK_PRINTF_LIKE(2
std::string PrettyPrint(const std::string &string)
void VisitLineByLine(const std::string &text, const std::function< void(int lineNumber, const char *lineText)> &visitFn)
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port Allow the VM service to fallback to automatic port selection if binding to a specified port fails trace Trace early application lifecycle Automatically switches to an endless trace buffer trace skia Filters out all Skia trace event categories except those that are specified in this comma separated list dump skp on shader Automatically dump the skp that triggers new shader compilations This is useful for writing custom ShaderWarmUp to reduce jank By this is not enabled to reduce the overhead purge persistent cache
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
font
Font Metadata and Metrics.
void FlushAndSubmit(SkSurface *surface)
std::function< std::unique_ptr< skiagm::GM >()> GMFactory
sk_tools::Registry< GMFactory > GMRegistry
for(int row=0;row< height;++row)
PersistentCache * fPersistentCache
ShaderErrorHandler * fShaderErrorHandler
bool fSupportBilerpFromGlyphAtlas
bool fReducedShaderVariations
ShaderCacheStrategy fShaderCacheStrategy
SkColorSpacePrimaries * fPrimaries
static Error Decode(const void *src, size_t srcLength, void *dst, size_t *dstLength)
bool toXYZD50(skcms_Matrix3x3 *toXYZD50) const
constexpr int32_t width() const
constexpr int32_t height() const
static SkImageInfo MakeN32Premul(int width, int height)
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
void append(const char *s)
static constexpr SkPoint Make(float x, float y)
constexpr float y() const
constexpr float x() const
static SkRect Make(const SkISize &size)
static SkRect MakeIWH(int w, int h)
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
constexpr float height() const
constexpr float width() const
static constexpr SkRect MakeWH(float w, float h)
const char * fVersionDeclString
bool fUsesPrecisionModifiers
SkSerialImageProc fImageProc
SkScalar * pos
storage for glyph positions in run
char * utf8text
storage for text UTF-8 code units in run
SkGlyphID * glyphs
storage for glyph indexes in run
uint32_t * clusters
storage for glyph clusters (index of UTF-8 code unit)
SkSurfacePropsFields fSurfaceProps
bool overridesSomething() const
bool overridesSomething() const
PathRendererStrategy fPathRendererStrategy
bool fDelayDrawableAcquisition
SkSurfaceProps fSurfaceProps
GrContextOptions fGrContextOptions
bool fCreateProtectedNativeBackend