Jump to content

vfbb

Members
  • Content Count

    266
  • Joined

  • Last visited

  • Days Won

    30

Posts posted by vfbb


  1. Moving away from the profile issue and talking specifically about the CPU usage of FMX on macOS, the same can be related to the use or not of metal. I advise using GlobalUseMetal := True; to take some of the CPU load off.


  2. 2 hours ago, A.M. Hoornweg said:

    Such rounded edges "miss" the points of the polygon, they deviate before hitting the point.

    Here's an example:

     

    uses
      Skia;
    
    function MakeCubicSplineInterpolation(const APoints: TArray<TPointF>): ISkPath;
    var
      LPathBuilder: ISkPathBuilder;
      LSegments: Integer;
      I: Integer;
      mx: Single;
      my: Single;
      LScratches: array of
        record
          a, b, c, r, p: TPointF;
        end;
    begin
      LPathBuilder := TSkPathBuilder.Create;
      if Length(APoints) < 2 then
        Exit(LPathBuilder.Detach);
      if Length(APoints) = 2 then
      begin
        LPathBuilder.MoveTo(APoints[0]);
        LPathBuilder.LineTo(APoints[1]);
        Exit(LPathBuilder.Detach);
      end;
      LSegments := Length(APoints) - 1;
      SetLength(LScratches, LSegments);
      LScratches[0].a := PointF(0, 0);
      LScratches[0].b := PointF(2, 2);
      LScratches[0].c := PointF(1, 1);
      LScratches[0].r := PointF(APoints[0].X + 2 * APoints[1].X, APoints[0].Y + 2 * APoints[1].Y);
      for I := 1 to LSegments - 2 do
      begin
        LScratches[I].a := PointF(1, 1);
        LScratches[I].b := PointF(4, 4);
        LScratches[I].c := PointF(1, 1);
        LScratches[I].r := PointF(4 * APoints[i].X + 2 * APoints[I + 1].X, 4 * APoints[I].Y + 2 * APoints[I + 1].Y);
      end;
      LScratches[LSegments - 1].a := PointF(2, 2);
      LScratches[LSegments - 1].b := PointF(7, 7);
      LScratches[LSegments - 1].c := PointF(0, 0);
      LScratches[LSegments - 1].r := PointF(8 * APoints[LSegments - 1].X + APoints[LSegments].X, 8 * APoints[LSegments - 1].Y + APoints[LSegments].Y);
      for I := 1 to LSegments - 1 do
      begin
        mx := LScratches[I].a.X / LScratches[I - 1].b.X;
        my := LScratches[I].a.Y / LScratches[I - 1].b.Y;
        LScratches[I].b := LScratches[I].b - PointF(mx * LScratches[I - 1].c.X, my * LScratches[I - 1].c.Y);
        LScratches[I].r := LScratches[I].r - PointF(mx * LScratches[I - 1].r.X, my * LScratches[I - 1].r.Y);
      end;
      LScratches[LSegments - 1].p := PointF(LScratches[LSegments - 1].r.X / LScratches[LSegments - 1].b.X,
        LScratches[LSegments - 1].r.Y / LScratches[LSegments - 1].b.Y);
      for I := Length(APoints) - 3 downto 0 do
      begin
        LScratches[I].p := PointF((LScratches[I].r.X - LScratches[I].c.X * LScratches[I + 1].p.X) / LScratches[I].b.X,
          (LScratches[I].r.Y - LScratches[I].c.Y * LScratches[I + 1].p.Y) / LScratches[I].b.Y);
      end;
      LPathBuilder.MoveTo(APoints[0]);
      for I := 0 to LSegments - 2 do
      begin
        LPathBuilder.CubicTo(LScratches[I].p,
          PointF(2 * APoints[I + 1].X - LScratches[I + 1].p.X, 2 * APoints[I + 1].Y - LScratches[I + 1].p.Y), APoints[I + 1]);
      end;
      LPathBuilder.CubicTo(LScratches[LSegments - 1].p,
        PointF(0.5 * (APoints[LSegments].X + LScratches[LSegments - 1].p.X),
        0.5 * (APoints[LSegments].Y + LScratches[LSegments - 1].p.Y)), APoints[LSegments]);
      Result := LPathBuilder.Detach;
    end;
    
    procedure TForm1.SkPaintBox1Draw(ASender: TObject; const ACanvas: ISkCanvas;
      const ADest: TRectF; const AOpacity: Single);
    var
      LPaint: ISkPaint;
      LMyPoints: TArray<TPointF>;
    begin
      LMyPoints := [PointF(62, 511), PointF(162, 605), PointF(262, 610),
        PointF(362, 402), PointF(462, 959), PointF(562, 58), PointF(662, 272),
        PointF(762, 99), PointF(862, 759), PointF(962, 945)];
    
      LPaint := TSkPaint.Create(TSkPaintStyle.Stroke);
      LPaint.Color := TAlphaColors.Red;
      LPaint.AntiAlias := True;
      LPaint.StrokeWidth := 3;
      LPaint.StrokeCap := TSkStrokeCap.Round;
      ACanvas.DrawPath(MakeCubicSplineInterpolation(LMyPoints), LPaint);
      LPaint.StrokeWidth := 10;
      LPaint.Color := TAlphaColors.Black;
      ACanvas.DrawPoints(TSkDrawPointsMode.Points, LMyPoints, LPaint);
    end;

     

    Result:

    image.thumb.png.8e591b43296bb2c8cd20f3fe88c773b2.png

     

    Note: You don't need to use Skia, it was just a facilitator for the example.

    • Like 8

  3. We started porting the Skia4Delphi library to C++Builder and we came across a problem in the static linking of objects, specifically linking the file “/usr/lib/clang/lib/darwin/libclang_rt.ios.a” which is in the SDK path (ex: “C:\Users\<username>\Documents\Embarcadero\Studio\SDKs\iPhoneOS15.2.sdk\usr\lib\clang\lib\darwin\libclang_rt.ios.a”)

     

    In Delphi, this linking is very simple to do. We can simply declare a fake method and add the external '/<sdk_sub_path>/<filename>.a', which is exactly what we do in our Delphi implementation:

    procedure libcompiler_rt; external '/usr/lib/clang/lib/darwin/libclang_rt.ios.a';

     

    In C++Builder however, we didn't find anything similar. So far we've only been able to force this link in two different (but very rudimentary) ways:

     

    Method 1 - Configuring project linking:

    1. Adding to the project library path “$(BDSPLATFORMSDKSDIR)\<DefaultPlatformSDK>\usr\lib\clang\lib\darwin\”
      Note: This is necessary because although some SDK paths are automatically passed to the linker, this is not.
    2. Adding the command -lclang_rt.ios to the project link

    The problem with this method is that apparently there is no environment variable for the <DefaultPlatformSDK>, and adding only relative paths, in this case “\usr\lib\clang\lib\darwin\”, doesn't work. We also tried “$(SDKROOT)\usr\lib\clang\lib\darwin\” but to no avail.

     

    Method 2 – Adding objects to the project

    1. Directly add the file “libclang_rt.ios.a” to the project.

    It also works, but this is also a bad option.

     

    Questions

    1. Is there any other way to force link an SDK object in C++Builder?
      It would be nice to have a simple solution that requires no configuration:
      #pragma link "/usr/lib/clang/lib/darwin/libclang_rt.ios.a" // But this don't work
    2. Would there be any variables we could use to represent the path of the SDK being used? (Ex: “$(SDKROOT)\usr\lib\clang\lib\darwin\”)

     

     


  4. 1 hour ago, schaumermal said:

    Especially since it is recreated each time it is compiled.

    This can be avoided by simply disabling it from the project deployment and creating yours with the same remotedir and remotename. Whenever possible, it's better to do this in your project than in the default delphi files, because you won't be able to share your project with someone else without them having the same issue unless they also edit their default splash . Here's a practical example of a project that does this: https://github.com/skia4delphi/skia4delphi/tree/main/Samples/Webinar - Demo/FMX

    • Like 1

  5. 15 hours ago, domus said:

    As an aside, this test rendered the animation perfectly when loaded and played in the https://lottiefiles.com/ site.

     

    Don't know if this is useful info.

    Can you send me your lottie file?

     

    10 minutes ago, domus said:

    Is there any Skia4delphi specific documentation for TSkShader etc.? Or do we use https://api.skia.org/?

    Official skia documentation is incomplete, but it helps. The official skia api is very similar to Skia4Delphi, just few methods and functions have been renamed for readability.

     

    I imagine you want to know more about custom shaders. They are made in SKSL language, using the SkRuntimeEffect class to build the shader. See some useful links below:

     

    SKSL doc: https://skia.org/docs/user/sksl/
    SKSL playground: https://shaders.skia.org/

     

    SkiaSimpleShaderViewer - Demo using custom shaders in skia4delphi: https://github.com/jimmckeeth/SkiaSimpleShaderViewer
    BricksGame - Game using custom shaders in skia4delphi: https://github.com/skia4delphi/skia4delphi/tree/main/Samples/Webinar - Game/FMX

     

    Skia4Delphi Demo using custom shaders in two units: https://github.com/skia4delphi/skia4delphi/blob/main/Samples/Demo/FMX/Source/Sample.Form.RuntimeEffects.pas
    https://github.com/skia4delphi/skia4delphi/blob/main/Samples/Demo/FMX/Source/Sample.Form.Filter.pas

     

    There is also new documentation from the android team, which is AGSL section. Android Graphics Shader Language (AGSL) is Skia Shader Language (SKSL), the android team just changed the name:

    https://developer.android.com/guide/topics/graphics/agsl

     

    You can also solve all your doubts on our telegram channel: https://t.me/skia4delphi

     

     


  6. 2 hours ago, domus said:

    my test used a Gaussian blur effect and that seemed to work fine, so I hope it doesn't concern all of them...

    AE covers all kinds of animation, there are effects and raster features, for example, that would not even make sense to be supported in lottie, because the idea of lottie is to be vectorized and lightweight.
     

    Lastly, lottie and the bodymovin plugin are constantly developing and adding new features every day, so blogs from 1 year ago may no longer reflect reality.


  7. 1 hour ago, domus said:

    First test with a Lottie export from AE. Two superimposed circles with animated trim paths (connected parameters). Only one circle is animated, the other not. In the Lottie preview in the AE Plugin, all seems fine. In Delphi, only one circle is animated.

     

    Are there any limitations to the complexity of these Lottie imports (or unsupported functionality)?

    There are several limitations of Adobe After Effects to lottie (using bodymovin plugin) and they are not very well documented.

    This site lists some: https://www.elpassion.com/blog/lottie-who-common-mistakes-in-after-effects-animation-for-lottie

     

    Your case may have something to do with Keyframe or expressions...


  8. 37 minutes ago, domus said:

    So, no (truly) interactive animations possible? Only fixed animation sequences?

    No truly interactive animations. But you could create these iterations artificially. Consider this example: https://lottiefiles.com/5222-switch between progress 0% to 50% is the animation enabling a switch, and progress 50% to 100% is the animation disabling a switch. Based on that you can configure the animation in your control so that when you click it execute the progress from 0% to 50% or from 50% to 100%.

     

    Note: Currently our TSkAnimatedImage control is capable of running lottie animations but it is not "so tunable". Either it automatically runs the entire animation or you activate the manual mode and change the progress on your own (for example by adding a timer and changing the progress manually every 15 ms).

     

    In our next release (in a few weeks) we will improve this a lot, we will add new properties to get better control of the animations in the TSkAnimatedImage control.

     

    37 minutes ago, domus said:

    I noticed there is a way to create SVGs in runtime. Maybe I'll experiment with that.

     

    Yes it is possible with Skia4Delphi.

     

    37 minutes ago, domus said:

    Is the entire SKIA library exposed in Delphi, or just part of it?

     

    Excluding experimental or deprecated modules, 99% of the library is exposed.


  9. 17 minutes ago, domus said:

    I'll continue testing nevertheless. I'm mainly interested in exploring the animation possibilities using SVG. Could you tell me if the SVG component allows run-time created animations, like dynamic path creation and altering of SVG parameters (as opposed to loading file-based SVG animations)?

    Skia does not support animated SVG. There are very few libs that support SVG animations and even then I believe there are no versions for delphi.

     

    However, there is something similar, and much better: lottie. Lottie are also vectorized animations in json format. As with SVG, you can also find lottie of everything on the internet. You can also create your own animation using Adobe After Effects (although it's hard for programmers lol). However it is not possible to edit it at runtime.

     

    Note: Replacing your app's canvas (GlobalUseSkia := True) is optional. You'll be able to use svg, lottie, skia controls, even without skia being your app's renderer. However, skia controls perform better when your app's canvas is based on skia (GlobalUseSkia := True)


  10. 23 minutes ago, domus said:

    Tested with over 3000 rotating rectangles, with assigned bitmaps. FMX still runs very smoothly, but Skia was jerky (even with GlobalUseSkiaRasterWhenAvailable = False).

     

    With 200 rotating rectangles, I have the impression Skia is smoother.

     

    All very subjective observations, of course. Not certain if any of this information is useful.

    There are 2 questions in your test:

     

    1) On the Windows platform, both the FMX and Skia canvas present very similar results, both in terms of quality and performance. Although on my machine there was a 10% gain, some reported the opposite, but overall both were satisfactory in all tests. On non-Windows platforms, the performance differences are greater and a second problem arises, which is the quality of the drawings (there is only antialiasing on FMX Windows, while on Skia there is maximum quality on all platforms);

     

    2) In our canvas implementation, bitmaps are not as optimized as they could be. We split our canvas into 2 parts, the window canvas (form) and the bitmap canvas. In the implementation of the canvas bitmap we always decided to use the raster mode because we wanted the TBitmap to be used in background threads without locking the UI (embarcadero put a lock on the canvas that blocks drawings in parallel, even if you use bitmaps in threads, the drawings are not actually done in parallel, one blocks the other during BeginScene and EndScene). In our tests this raster implementation of bitmaps didn't affect the performance of projects that don't abuse bitmaps as much (but it's not your case, you're drawing 300 bitmaps at once);


  11. 39 minutes ago, domus said:

    Now it's flying again!

     

    However, is Skia still being used for bitmaps when this is set to False?

     

    Yes. When you set "GlobalUseSkia := True;", the lib replaces the app's default canvas to the skia-based canvas. However, we made more than 1 canvas based on skia: a raster canvas (CPU), an opengl canvas (GPU) and a metal canvas (GPU).

     

    When creating the first form or drawing with bitmaps (which is when the FMX canvas system is started), we check if GlobalUseSkia is true, and if it is, we will choose one of our implementations based on the booleans GlobalUseSkiaRasterWhenAvailable and GlobalUseMetal, and on the target platform.

     

    But why use by default on Windows a raster canvas (which runs on the CPU), since the canvases that run on the GPU are faster? This was done because it is the most compatible mode of all, as some specific VMs do not implement full openGL support and often this is not possible to verify via code.

     

    In the future we intend to add new canvas implementations based on skia, such as the Vulkan implementation. Perhaps Vulkan was better implemented on Windows VMs.


  12. 7 minutes ago, domus said:

    That was it! Many thanks!

    Odd that this wasn't necessary in the first test project.

    Without this step it will work when you run your app on Windows through the IDE run (because the IDE shares the same env PATH with the exe it is running).

    But the rule is: whenever you are going to use any skia code in an application (vcl, console or fmx), do this step. This should only not be done in libraries that use skia.

     

    9 minutes ago, domus said:

    However, while the test (just rotation bitmaps) runs very smoothly in standard FMX, it comes to an absolute crawl when I set GlobalUseSkia := True.

    This is not expected. Can you add a new line above your GlobalUseSkia declaration:

    GlobalUseSkiaRasterWhenAvailable := False;


  13. 35 minutes ago, domus said:

    Installed fine (Windows 10) and worked fine in first project test. When I try a second project, I keep getting "skia library could not be loaded". These are tiny one-unit test projects.

     

    Anyone have any idea what I'm overlooking? Thx.

    Have you enabled skia in your project? Inside of IDE, right click in your project > Enable Skia. Maybe after that you have to rebuild your project (Clean and Compile). This step is made to configure skia binaries in your project...

     

    Maybe this is also @Serge_G problem too.

     

    6 hours ago, Serge_G said:

    installing Ubuntu 20.04

    My Ubuntu is 20.04 too (although it should work on 18.04 too)


  14. 42 minutes ago, everybyte2 said:

    Webinar demo creates a PDF from a bitmap of the control, as a result PDF does not scale well.

     

    With a fix in Skia I do create scalable PDFs on Windows (where Printer canvas is available),

    but this solution is not portable, at least for Android.

    You are sure! I hadn't realized it.

    I have an idea how to solve this, maybe I can put it in a next version.

    • Thanks 1

  15. On 5/2/2022 at 5:33 AM, Serge_G said:

    Hi,
    It worked as expected on Android, but I can't test on Ubuntu :classic_blush:
    I first have a problem of a lacking package I think it was zlib1g-dev, I install this one. 

    But, if now I can deploy my project or the demo the program don't run. What did I miss ? Is there any doc/help for a "good" deployment ? 

    What is your Ubuntu version? The packages needed to run on Ubuntu are the same for FMXLinux, if you can run a blank fmx app on your Ubuntu, you will be able to run our demo.

     

    @Edit

    Note: The Linux version of skia4delphi works only in RAD Studio 11.


  16. 11 minutes ago, everybyte2 said:

    A second question about printing:

     

    Skia has an example of rendering to a PDF canvas, but this canvas is of a  TskCanvas  class

    and thus not compatible with FMX adapter class TSkCanvasCustom  (which uses TskCanvas internally).

    Is there an easy way to create TSkCanvasCustom from a given TskCanvas instance?

    You cannot convert SkCustomCanvas <> SkCanvas. However, you can transform bitmaps into ISkImage (via TBitmap.ToSkImage) and paint it in ISkCanvas of the PDF. That way you can do anything, for example, paint controls on a TBitmap, convert that TBitmap to ISkImage, and then paint that ISkImage onto the PDF's ISkCanvas.

     

    20 minutes ago, everybyte2 said:

    Has anybody tried to do printing of an control ?

     

    The TextLayout is bound to TSkCanvasCustom for display but the printing goes to GDI+ canvas,

    which custom TextLayout knows nothing about. As a result all text is missing in the printout.

    Printing is an untested area in our project, so it's possibly an issue. It would really help if you opened an issue on the GitHub page with a project that simulates the problem.

    https://github.com/skia4delphi/skia4delphi/issues


  17. @Rollo62 Eugene's idea (creator of FMX) is great. He creates regions with cached drawings, through his control, then it is the programmer who has to define where he will cache the drawings, and have moderation about it. Unfortunately I had some issues mainly with updating the drawings of some controls inside it, so I never used it in production.

     

    I'm very conservative when I think about third-party libraries. Some libs also partially solve the FMX performance problem, but they leave you hostage, since you have to change all your codes, use their controls, etc. This is the main difference, you implement Skia in your app changing only 1 line in dpr. The day you want to remove the library, just remove the line...

     

    About updates and development stage, we still don't have the best code design and there's still a lot to optimize, a lot, such as: using Vulkan on Android and Windows 10+, and using hardware acceleration in drawings inside bitmaps, etc. But one thing I can say, it's very stable, it's no wonder that today we have 0 issues.

    • Like 1
    • Thanks 2

  18. 19 hours ago, Rollo62 said:

    FMX has the drawback that it repaints the whole screen, even when only a small fraction of the screen has changed.

    How is the screen painting handled in Skia controls ?

    Is the control handled by Skia external library, or does it still behave like the original FMX ?

    Yes, we repaint the entire screen with every render.

     

    Unfortunately FMX is right. To repaint only modified controls, we would have to have a layering system, basically a bitmap for each control containing the control draw cached. It would be a very high speed drawing system, because drawing bitmaps on the screen (without strech), is an almost instantaneous operation. However, there is an insurmountable problem with this solution: memory consumption. Bitmaps consume a lot of memory, if each control has its own, you will quickly have a memory overflow. In addition you will have other problems, such as controls that are larger than the MaxSize of the bitmap accepted on the device (such as scrollbox). On a device with infinite memory this would be the best option, but it is not the case.

     

    There is another option, which FMX even implemented, which is to "filter" all controls that were changed through the region that was changed, repainting only them and with ClipRect on the changed region (it does this for Canvas that have the flag TCanvasStyle.SupportClipRects). Intuitively, this seemed like a great solution, but in practice it surprisingly turned out to be slightly worse. This is probably why FMX also disabled this option on non-Windows platforms.


  19. @Rollo62 The replacement of the FMX graphic engine by Ski4Delphi graphic engine (which is done just by adding the line "GlobalUseSkia := True;" in the dpr), affects all the drawings in your app, whether the screen controls or drawings in TBitmaps. So even delphi controls like TRectangle, TCircle, and all others (even third-party controls) are now rendered on screen by the Skia-based Canvas. Everything is done automatically internally. With this, your entire application will automatically gain:

     

    - Performance (up to 50%)
    - Quality in drawings (everything is rendered with antialiasing, and maximum quality, producing smooth curves, no jagged edges)
    - Fidelity (there are dozens of bugs in the FMX render that do not occur with Canvas based on Skia, mainly involving Metal)
    - And other advantages

     

    • Like 3
    • Thanks 4

  20. github-social-preview.thumb.png.c133051d6f734675598ba501a7d5f867.png

     

     

    v3.4.0

     

     

    • Added StrokeColor property to TSkLabel;
    • Added LetterSpacing property to TSkLabel;
    • Added automatically Skia to uses when use controls in form;
    • Added EncodedImageFormat property and MakeFromStream to SkCodec;
    • Added MakeRawShader to SkImage;
    • Added MakeImage to SkRuntimeEffects;
    • Exposed DirectContext in TGrCanvasCustom class to run code on the GPU more easily;
    • Fixed BackgroundColor property of TSkLabel;
    • Fixed issue loading bitmaps from stream when using Skia in Vcl project;
    • Fixed build script with python3 as default;
    • Minor improvements and fixes.

     

     

     

    New StrokeColor property of TSkLabel

     

    TSkLabel.thumb.png.f7e97774b9c560bc51c80e24435e264c.png

     

     

    Github: github.com/skia4delphi/skia4delphi

    Website: skia4delphi.org

     

    • Like 7
    • Thanks 1
×