From dc611f0cc514a2b17644d0f630c44d23e201e481 Mon Sep 17 00:00:00 2001 From: Jim McKeeth Date: Wed, 2 Apr 2025 22:03:24 -0600 Subject: [PATCH 1/6] proposal - see readme.md # Skia4Delphi `AsInterface` Proposal & Demo Most of the Skia API is exposed as interfaces. This takes advantage of reference counting, which is nice to have. Usually, the class has limited public methods and most functionality is exposed through the interface. **Example:** ```Delphi type { ISkPaint } ISkPaint = interface(ISkObject) ['{C95825F8-0D51-4BCE-8945-84AFE6264213}'] function GetAlpha: Byte; function GetAlphaF: Single; { ... 50 other PUBLIC members ...} property StrokeWidth: Single read GetStrokeWidth write SetStrokeWidth; property Style: TSkPaintStyle read GetStyle write SetStyle; end; { TSkPaint } TSkPaint = class(TSkObject, ISkPaint) strict private function GetAlpha: Byte; function GetAlphaF: Single; { ... 34 other STRICT PRIVATE memebers ... } procedure SetStrokeWidth(const AValue: Single); procedure SetStyle(const AValue: TSkPaintStyle); public constructor Create; overload; constructor Create(const APaint: ISkPaint); overload; constructor Create(const AStyle: TSkPaintStyle); overload; end; ``` This is fine for *traditional* variable declarations: ```Delphi var paint: ISkPaint; begin paint := TSkPaint.Create; paint.Color := TAlphaColors.Darkorange; end; ``` Unfortunately, it is *incompatible* with **type inferance**: ```Delphi begin var inferred := TSkPaint.Create; inferred.Color := TAlphaColors.Darkorange; // E2003 Undeclared identifier: 'Color' end; ``` Forces the more verbose form of inline variable declaration: ```Delphi begin var explicit: ISkPaint := TSkPaint.Create(); explicit.Color := TAlphaColors.Darkorange; end; ``` The proposed `CreateAsInterace` methods fix this: ```Delphi begin var better := TSkPaint.Create(); better.Color := TAlphaColors.Darkorange; end; ``` Simply duplicate the existing constructors: ```Delphi public constructor Create; overload; constructor Create(const APaint: ISkPaint); overload; constructor Create(const AStyle: TSkPaintStyle); overload; end; ``` Making them a `class function` named `CreateAsInterface` with the same arguements, and returning the `interface`: ```Delphi public class function CreateAsInterface: ISkPaint; overload; class function CreateAsInterface(const APaint: ISkPaint): ISkPaint; overload; class function CreateAsInterface(const AStyle: TSkPaintStyle): ISkPaint; overload; end; ``` Any name could be used (`Init`, `AsInterface`, `George`, etc.), but this one makes them very visible in class completion to aid in discovery. The implementation just calls the existing constructors, but since the Result is explicitly the Interface, this works as expected: ```Delphi implementation { TSkPaint } class function TSkPaint.CreateAsInterface: ISkPaint; begin Result := TSkPaint.Create(); end; class function TSkPaint.CreateAsInterface(const APaint: ISkPaint): ISkPaint; begin Result := TSkPaint.Create(APaint); end; class function TSkPaint.CreateAsInterface(const AStyle: TSkPaintStyle): ISkPaint; begin Result := TSkPaint.Create(AStyle); end; ``` Type inferance is as preferable. Beyond less typing it makes code more maintainable (type only needs to be changed in one place) and reduces errors resulting from mismatched types and constructors. The easier it is to take advantage of this feature in Delphi the better. --- .gitignore | 2 + Samples/CreateAsInterface/AsInterfaceDemo.dpr | 14 + .../CreateAsInterface/AsInterfaceDemo.dproj | 162 +++ Samples/CreateAsInterface/AsInterfaceMain.dfm | 30 + Samples/CreateAsInterface/AsInterfaceMain.pas | 45 + Source/FMX/FMX.Skia.Canvas.Vulkan.pas | 1142 +++++++++++++++++ Source/System.Skia.pas | 45 +- 7 files changed, 1433 insertions(+), 7 deletions(-) create mode 100644 Samples/CreateAsInterface/AsInterfaceDemo.dpr create mode 100644 Samples/CreateAsInterface/AsInterfaceDemo.dproj create mode 100644 Samples/CreateAsInterface/AsInterfaceMain.dfm create mode 100644 Samples/CreateAsInterface/AsInterfaceMain.pas create mode 100644 Source/FMX/FMX.Skia.Canvas.Vulkan.pas diff --git a/.gitignore b/.gitignore index cd7d7dc1..27b4d2a6 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,5 @@ dunitx-results.xml !/Binary/** !/Tools/Setup/Style/*.dll !/Tools/*.exe +unins*.dat +*.delphilsp.json diff --git a/Samples/CreateAsInterface/AsInterfaceDemo.dpr b/Samples/CreateAsInterface/AsInterfaceDemo.dpr new file mode 100644 index 00000000..d8ce9a11 --- /dev/null +++ b/Samples/CreateAsInterface/AsInterfaceDemo.dpr @@ -0,0 +1,14 @@ +program AsInterfaceDemo; + +uses + Vcl.Forms, + AsInterfaceMain in 'AsInterfaceMain.pas' {Form31}; + +{$R *.res} + +begin + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.CreateForm(TForm31, Form31); + Application.Run; +end. diff --git a/Samples/CreateAsInterface/AsInterfaceDemo.dproj b/Samples/CreateAsInterface/AsInterfaceDemo.dproj new file mode 100644 index 00000000..b8a9de0f --- /dev/null +++ b/Samples/CreateAsInterface/AsInterfaceDemo.dproj @@ -0,0 +1,162 @@ + + + True + Application + Debug + VCL + AsInterfaceDemo.dpr + Win32 + {FCB99591-6739-45CE-9331-E46C62D778C0} + AsInterfaceDemo + 20.3 + 3 + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + AsInterfaceDemo + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + ..\Source;..\Source\FMX;..\Source\VCL;$(DCC_SysLibRoot) + ..\Source;..\Source\FMX;..\Source\VCL;$(DCC_UnitSearchPath) + $(BDS)\bin\delphi_PROJECTICON.ico + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + + + none + Debug + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + soapserver;vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;Skia.Package.RTL;RadiantShapesFmx_Design;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;VCLColorTrackers;inetdb;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;vclactnband;TeeUI;fmxFireDAC;dbexpress;FireDACInfxDriver;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;vcltouch;fmxase;DBXOdbcDriver;dbrtl;FireDACDBXDriver;FireDACOracleDriver;Skia.Package.FMX;fmxdae;TeeDB;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;RadiantShapesFmx;FireDACTDataDriver;Skia.Package.VCL;vcldb;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;inetstn;DOSCommandDR;RESTBackendComponents;IndyCore;bindcompdbx;rtl;FireDACMySQLDriver;RaizeComponentsVclDb;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;VirtualTreesDR;DataSnapClient;dsnapcon;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;fmxobj;FMXTee;bindcompvclsmp;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;RaizeComponentsVcl;FireDACIBDriver;$(DCC_UsePackage) + $(BDS)\bin\default_app.manifest + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + + + Debug + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + soapserver;vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;RadiantShapesFmx_Design;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;VCLColorTrackers;inetdb;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;vclactnband;TeeUI;fmxFireDAC;dbexpress;FireDACInfxDriver;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;vcltouch;fmxase;DBXOdbcDriver;dbrtl;FireDACDBXDriver;FireDACOracleDriver;fmxdae;TeeDB;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;RadiantShapesFmx;FireDACTDataDriver;Skia.Package.VCL;vcldb;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;inetstn;DOSCommandDR;RESTBackendComponents;IndyCore;bindcompdbx;rtl;FireDACMySQLDriver;RaizeComponentsVclDb;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;VirtualTreesDR;DataSnapClient;dsnapcon;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;fmxobj;FMXTee;bindcompvclsmp;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;RaizeComponentsVcl;FireDACIBDriver;$(DCC_UsePackage) + $(BDS)\bin\default_app.manifest + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + + + true + true + DEBUG;$(DCC_Define) + true + true + false + true + true + + + PerMonitorV2 + false + true + 1033 + + + PerMonitorV2 + + + 0 + RELEASE;$(DCC_Define) + false + 0 + + + PerMonitorV2 + + + PerMonitorV2 + + + + MainSource + + +
Form31
+ dfm +
+ + Base + + + Cfg_1 + Base + + + Cfg_2 + Base + +
+ + Delphi.Personality.12 + Application + + + + AsInterfaceDemo.dpr + + + + + True + True + + + 12 + + + + +
diff --git a/Samples/CreateAsInterface/AsInterfaceMain.dfm b/Samples/CreateAsInterface/AsInterfaceMain.dfm new file mode 100644 index 00000000..481c2d7b --- /dev/null +++ b/Samples/CreateAsInterface/AsInterfaceMain.dfm @@ -0,0 +1,30 @@ +object Form31: TForm31 + Left = 0 + Top = 0 + Margins.Left = 5 + Margins.Top = 5 + Margins.Right = 5 + Margins.Bottom = 5 + Caption = 'Form31' + ClientHeight = 664 + ClientWidth = 938 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -18 + Font.Name = 'Segoe UI' + Font.Style = [] + PixelsPerInch = 144 + TextHeight = 25 + object SkPaintBox1: TSkPaintBox + Left = 10 + Top = 10 + Width = 385 + Height = 277 + Margins.Left = 5 + Margins.Top = 5 + Margins.Right = 5 + Margins.Bottom = 5 + OnDraw = SkPaintBox1Draw + end +end diff --git a/Samples/CreateAsInterface/AsInterfaceMain.pas b/Samples/CreateAsInterface/AsInterfaceMain.pas new file mode 100644 index 00000000..841531d9 --- /dev/null +++ b/Samples/CreateAsInterface/AsInterfaceMain.pas @@ -0,0 +1,45 @@ +unit AsInterfaceMain; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Skia, Vcl.Skia, + System.Types, + System.UITypes; + +type + TForm31 = class(TForm) + SkPaintBox1: TSkPaintBox; + procedure SkPaintBox1Draw(ASender: TObject; const ACanvas: ISkCanvas; + const ADest: TRectF; const AOpacity: Single); + private + { Private declarations } + public + { Public declarations } + end; + +var + Form31: TForm31; + +implementation + +{$R *.dfm} + +procedure TForm31.SkPaintBox1Draw(ASender: TObject; + const ACanvas: ISkCanvas; const ADest: TRectF; const AOpacity: Single); +begin + var font: ISkFont := TSkFont.Create(nil, 24); + var paint: ISkPaint := TSkPaint.Create(); + paint.Color := TAlphaColors.Blueviolet; + ACanvas.DrawSimpleText('before',2,30,font,paint); + + var easyFont := TSkFont.CreateAsInteface(nil, 24); + var easyPaint := TSkPaint.CreateAsInteface(); + easyPaint := TAlphaColors.Green; + ACanvas.DrawSimpleText('Easy',32,30,font,paint); + + +end; + +end. diff --git a/Source/FMX/FMX.Skia.Canvas.Vulkan.pas b/Source/FMX/FMX.Skia.Canvas.Vulkan.pas new file mode 100644 index 00000000..5cf4c3d0 --- /dev/null +++ b/Source/FMX/FMX.Skia.Canvas.Vulkan.pas @@ -0,0 +1,1142 @@ +{*******************************************************} +{ } +{ Delphi FireMonkey Platform } +{ } +{ Copyright(c) 2023-2025 Embarcadero Technologies, Inc. } +{ All rights reserved } +{ } +{*******************************************************} + +unit FMX.Skia.Canvas.Vulkan; + +interface + +{$SCOPEDENUMS ON} +{$HPPEMIT NOUSINGNAMESPACE} + +{$IF DEFINED(MSWINDOWS) or DEFINED(ANDROID)} + {$DEFINE SKIA_VULKAN} +{$ENDIF} + +{$IFDEF SKIA_VULKAN} + +uses + { Delphi } + {$IF DEFINED(ANDROID)} + Androidapi.Vulkan, + {$ELSEIF DEFINED(MSWINDOWS)} + Winapi.Vulkan, + {$ENDIF} + System.SysUtils, + System.Vulkan, + + { Skia } + System.Skia, + FMX.Skia.Canvas; + +type + { TVkInterface } + + TVkInterface = record + private + FAcquireNextImageKHR: PFN_vkAcquireNextImageKHR; + FCreateDevice: PFN_vkCreateDevice; + FCreateInstance: PFN_vkCreateInstance; + FCreateSemaphore: PFN_vkCreateSemaphore; + FCreateSwapchainKHR: PFN_vkCreateSwapchainKHR; + FDestroyDevice: PFN_vkDestroyDevice; + FDestroyInstance: PFN_vkDestroyInstance; + FDestroySemaphore: PFN_vkDestroySemaphore; + FDestroySurfaceKHR: PFN_vkDestroySurfaceKHR; + FDestroySwapchainKHR: PFN_vkDestroySwapchainKHR; + FDeviceWaitIdle: PFN_vkDeviceWaitIdle; + FEnumerateDeviceExtensionProperties: PFN_vkEnumerateDeviceExtensionProperties; + FEnumerateInstanceExtensionProperties: PFN_vkEnumerateInstanceExtensionProperties; + FEnumerateInstanceVersion: PFN_vkEnumerateInstanceVersion; + FEnumeratePhysicalDevices: PFN_vkEnumeratePhysicalDevices; + FGetDeviceProcAddr: PFN_vkGetDeviceProcAddr; + FGetDeviceQueue: PFN_vkGetDeviceQueue; + FGetInstanceProcAddr: PFN_vkGetInstanceProcAddr; + FGetPhysicalDeviceFeatures: PFN_vkGetPhysicalDeviceFeatures; + FGetPhysicalDeviceFeatures2: PFN_vkGetPhysicalDeviceFeatures2; + FGetPhysicalDeviceProperties: PFN_vkGetPhysicalDeviceProperties; + FGetPhysicalDeviceQueueFamilyProperties: PFN_vkGetPhysicalDeviceQueueFamilyProperties; + FGetPhysicalDeviceSurfaceCapabilitiesKHR: PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR; + FGetPhysicalDeviceSurfaceFormatsKHR: PFN_vkGetPhysicalDeviceSurfaceFormatsKHR; + FGetPhysicalDeviceSurfacePresentModesKHR: PFN_vkGetPhysicalDeviceSurfacePresentModesKHR; + FGetSwapchainImagesKHR: PFN_vkGetSwapchainImagesKHR; + FQueuePresentKHR: PFN_vkQueuePresentKHR; + FQueueWaitIdle: PFN_vkQueueWaitIdle; + {$IF DEFINED(ANDROID)} + FCreateAndroidSurfaceKHR: PFN_vkCreateAndroidSurfaceKHR; + {$ELSEIF DEFINED(MSWINDOWS)} + FCreateWin32SurfaceKHR: PFN_vkCreateWin32SurfaceKHR; + FGetPhysicalDeviceWin32PresentationSupportKHR: PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR; + {$ENDIF} + procedure AcquireDestroyInstanceProc(const AInstance: VkInstance); inline; + procedure AcquireDeviceProcs(const ADevice: VkDevice); + procedure AcquireExtensionProcs(const AInstance: VkInstance; const APhysicalDeviceApiVersion: Cardinal; const AGrVkExtensions: IGrVkExtensions); + procedure AcquireInstanceProcs(const AInstance: VkInstance); + procedure GetDeviceProc(const ADevice: VkDevice; const AName: MarshaledAString; out APFN_vkFunction); + procedure GetInstanceProc(const AInstance: VkInstance; const AName: MarshaledAString; out APFN_vkFunction; const ARaiseIfNotExist: Boolean = True); + procedure Initialize(const ALibraryHandle: HMODULE); + public + { Global Procs } + property CreateInstance: PFN_vkCreateInstance read FCreateInstance; + property EnumerateInstanceExtensionProperties: PFN_vkEnumerateInstanceExtensionProperties read FEnumerateInstanceExtensionProperties; + property EnumerateInstanceVersion: PFN_vkEnumerateInstanceVersion read FEnumerateInstanceVersion; + property GetInstanceProcAddr: PFN_vkGetInstanceProcAddr read FGetInstanceProcAddr; + + { Instance Procs } + property CreateDevice: PFN_vkCreateDevice read FCreateDevice; + property DestroyDevice: PFN_vkDestroyDevice read FDestroyDevice; + property DestroyInstance: PFN_vkDestroyInstance read FDestroyInstance; + property EnumerateDeviceExtensionProperties: PFN_vkEnumerateDeviceExtensionProperties read FEnumerateDeviceExtensionProperties; + property EnumeratePhysicalDevices: PFN_vkEnumeratePhysicalDevices read FEnumeratePhysicalDevices; + property GetDeviceProcAddr: PFN_vkGetDeviceProcAddr read FGetDeviceProcAddr; + property GetPhysicalDeviceFeatures: PFN_vkGetPhysicalDeviceFeatures read FGetPhysicalDeviceFeatures; + property GetPhysicalDeviceProperties: PFN_vkGetPhysicalDeviceProperties read FGetPhysicalDeviceProperties; + property GetPhysicalDeviceQueueFamilyProperties: PFN_vkGetPhysicalDeviceQueueFamilyProperties read FGetPhysicalDeviceQueueFamilyProperties; + property DestroySurfaceKHR: PFN_vkDestroySurfaceKHR read FDestroySurfaceKHR; + property GetPhysicalDeviceSurfaceCapabilitiesKHR: PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR read FGetPhysicalDeviceSurfaceCapabilitiesKHR; + property GetPhysicalDeviceSurfaceFormatsKHR: PFN_vkGetPhysicalDeviceSurfaceFormatsKHR read FGetPhysicalDeviceSurfaceFormatsKHR; + property GetPhysicalDeviceSurfacePresentModesKHR: PFN_vkGetPhysicalDeviceSurfacePresentModesKHR read FGetPhysicalDeviceSurfacePresentModesKHR; + {$IF DEFINED(ANDROID)} + property CreateAndroidSurfaceKHR: PFN_vkCreateAndroidSurfaceKHR read FCreateAndroidSurfaceKHR; + {$ELSEIF DEFINED(MSWINDOWS)} + property CreateWin32SurfaceKHR: PFN_vkCreateWin32SurfaceKHR read FCreateWin32SurfaceKHR; + property GetPhysicalDeviceWin32PresentationSupportKHR: PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR read FGetPhysicalDeviceWin32PresentationSupportKHR; + {$ENDIF} + + { Instance Extension Procs } + property GetPhysicalDeviceFeatures2: PFN_vkGetPhysicalDeviceFeatures2 read FGetPhysicalDeviceFeatures2; + + { Device Procs } + property CreateSemaphore: PFN_vkCreateSemaphore read FCreateSemaphore; + property DestroySemaphore: PFN_vkDestroySemaphore read FDestroySemaphore; + property DeviceWaitIdle: PFN_vkDeviceWaitIdle read FDeviceWaitIdle; + property GetDeviceQueue: PFN_vkGetDeviceQueue read FGetDeviceQueue; + property QueueWaitIdle: PFN_vkQueueWaitIdle read FQueueWaitIdle; + property AcquireNextImageKHR: PFN_vkAcquireNextImageKHR read FAcquireNextImageKHR; + property CreateSwapchainKHR: PFN_vkCreateSwapchainKHR read FCreateSwapchainKHR; + property DestroySwapchainKHR: PFN_vkDestroySwapchainKHR read FDestroySwapchainKHR; + property GetSwapchainImagesKHR: PFN_vkGetSwapchainImagesKHR read FGetSwapchainImagesKHR; + property QueuePresentKHR: PFN_vkQueuePresentKHR read FQueuePresentKHR; + end; + + { TVkSharedContextCustom } + + TVkSharedContextCustom = class abstract(TGrSharedContext) + protected + FDevice: VkDevice; + FGraphicsQueue: VkQueue; + FGraphicsQueueIndex: Cardinal; + FInstance: VkInstance; + FPhysicalDevice: VkPhysicalDevice; + FPresentQueue: VkQueue; + FPresentQueueIndex: Cardinal; + FVkInterface: TVkInterface; + public + property Device: VkDevice read FDevice; + property GraphicsQueue: VkQueue read FGraphicsQueue; + property GraphicsQueueIndex: Cardinal read FGraphicsQueueIndex; + property Instance: VkInstance read FInstance; + property PhysicalDevice: VkPhysicalDevice read FPhysicalDevice; + property PresentQueue: VkQueue read FPresentQueue; + property PresentQueueIndex: Cardinal read FPresentQueueIndex; + property VkInterface: TVkInterface read FVkInterface; + end; + +var + GlobalUseSkiaVulkanFifoKHR: Boolean; + +implementation + +uses + { Delphi } + FMX.Graphics, + FMX.Types, + {$IF DEFINED(ANDROID)} + FMX.Platform.UI.Android, + FMX.Presentation.Android.Style, + Androidapi.JNI.GraphicsContentViewText, + Androidapi.JNIBridge, + Androidapi.NativeWindow, + Androidapi.NativeWindowJni, + {$ELSEIF DEFINED(MSWINDOWS)} + FMX.Platform.Win, + Winapi.Windows, + {$ENDIF} + System.AnsiStrings, + System.Math; + +type + EVkError = class(EGrCanvas); + + { TVkCanvas } + + TVkCanvas = class(TGrCanvas) + private type + TBackBufferInfo = record + Index: Cardinal; + Semaphore: VkSemaphore; + end; + + private const + SemaphoreCreateInfo: VkSemaphoreCreateInfo = (sType: VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; pNext: nil; flags: 0); + private + {$IFDEF ANDROID} + FANativeWindow: PANativeWindow; + {$ENDIF} + FBackBuffers: TArray; + FBackBufferSurfaces: TArray; + FCurrentBackBufferIndex: Integer; + FImageLayouts: TArray; + FImages: TArray; + FSwapchain: VkSwapchainKHR; + FVkSurface: VkSurfaceKHR; + function CreateSurface: Boolean; + function CreateSwapchain: Boolean; + procedure DestroySurface; + procedure DestroySwapchain; + protected + constructor CreateFromWindow(const AParent: TWindowHandle; const AWidth, AHeight: Integer; const AQuality: TCanvasQuality = TCanvasQuality.SystemDefault); override; + function CreateSharedContext: IGrSharedContext; override; + function GetSurfaceFromWindow(const AContextHandle: THandle): TSkSurface; override; + procedure Resized; override; + procedure SwapBuffers(const AContextHandle: THandle); override; + public + destructor Destroy; override; + class function IsSupported: Boolean; + end; + + { TVkSharedContext } + + TVkSharedContext = class(TVkSharedContextCustom) + private + FFeatures: VkPhysicalDeviceFeatures2; + FLibraryHandle: HMODULE; + procedure DestroyFeatures; + protected + procedure DestroyContext; override; + function GetTextureColorType: TSkColorType; override; + function GetTextureOrigin: TGrSurfaceOrigin; override; + public + constructor Create; + end; + +procedure VkCheckSuccess(const AResult: VkResult); + + function ErrorToStr(const AResult: VkResult): string; inline; + begin + case AResult of + VK_NOT_READY : Result := 'VK_NOT_READY'; + VK_TIMEOUT : Result := 'VK_TIMEOUT'; + VK_EVENT_SET : Result := 'VK_EVENT_SET'; + VK_EVENT_RESET : Result := 'VK_EVENT_RESET'; + VK_INCOMPLETE : Result := 'VK_INCOMPLETE'; + VK_ERROR_OUT_OF_HOST_MEMORY : Result := 'VK_ERROR_OUT_OF_HOST_MEMORY'; + VK_ERROR_OUT_OF_DEVICE_MEMORY : Result := 'VK_ERROR_OUT_OF_DEVICE_MEMORY'; + VK_ERROR_INITIALIZATION_FAILED : Result := 'VK_ERROR_INITIALIZATION_FAILED'; + VK_ERROR_DEVICE_LOST : Result := 'VK_ERROR_DEVICE_LOST'; + VK_ERROR_MEMORY_MAP_FAILED : Result := 'VK_ERROR_MEMORY_MAP_FAILED'; + VK_ERROR_LAYER_NOT_PRESENT : Result := 'VK_ERROR_LAYER_NOT_PRESENT'; + VK_ERROR_EXTENSION_NOT_PRESENT : Result := 'VK_ERROR_EXTENSION_NOT_PRESENT'; + VK_ERROR_FEATURE_NOT_PRESENT : Result := 'VK_ERROR_FEATURE_NOT_PRESENT'; + VK_ERROR_INCOMPATIBLE_DRIVER : Result := 'VK_ERROR_INCOMPATIBLE_DRIVER'; + VK_ERROR_TOO_MANY_OBJECTS : Result := 'VK_ERROR_TOO_MANY_OBJECTS'; + VK_ERROR_FORMAT_NOT_SUPPORTED : Result := 'VK_ERROR_FORMAT_NOT_SUPPORTED'; + VK_ERROR_FRAGMENTED_POOL : Result := 'VK_ERROR_FRAGMENTED_POOL'; + VK_ERROR_UNKNOWN : Result := 'VK_ERROR_UNKNOWN'; + VK_ERROR_OUT_OF_POOL_MEMORY : Result := 'VK_ERROR_OUT_OF_POOL_MEMORY'; + VK_ERROR_INVALID_EXTERNAL_HANDLE : Result := 'VK_ERROR_INVALID_EXTERNAL_HANDLE'; + VK_ERROR_SURFACE_LOST_KHR : Result := 'VK_ERROR_SURFACE_LOST_KHR'; + VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: Result := 'VK_ERROR_NATIVE_WINDOW_IN_USE_KHR'; + VK_SUBOPTIMAL_KHR : Result := 'VK_SUBOPTIMAL_KHR'; + VK_ERROR_OUT_OF_DATE_KHR : Result := 'VK_ERROR_OUT_OF_DATE_KHR'; + else + Result := AResult.ToString; + end; + end; + +begin + if AResult <> VK_SUCCESS then + raise EVkError.CreateFmt('Vulkan API call failed with error: %s', [ErrorToStr(AResult)]) at ReturnAddress; +end; + +function VkLoadLibrary: HMODULE; inline; +begin + {$IF DEFINED(ANDROID)} + Result := SafeLoadLibrary('libvulkan.so'); + // In an attempt to load the library, Vulkan Info searches for it in two + // distinct locations, and as a result, we replicate this behavior. + // + // https://github.com/KhronosGroup/Vulkan-Tools/blob/078d44e4664b7efa0b6c96ebced1995c4425d57a/vulkaninfo/vulkaninfo.h#L249 + if Result = 0 then + Result := SafeLoadLibrary('libvulkan.so.1'); + //{$ELSEIF DEFINED(LINUX)} + //Result := SafeLoadLibrary('libvulkan.so.1'); + //{$ELSEIF DEFINED(MACOS)} + //Result := SafeLoadLibrary('libvk_swiftshader.dylib'); + {$ELSEIF DEFINED(MSWINDOWS)} + Result := SafeLoadLibrary('vulkan-1.dll'); + {$ELSE} + Result := 0; + {$ENDIF} +end; + +{ TVkCanvas } + +constructor TVkCanvas.CreateFromWindow(const AParent: TWindowHandle; + const AWidth, AHeight: Integer; const AQuality: TCanvasQuality); +begin + inherited; + FGrDirectContext := TGrSharedContext(SharedContext).GrDirectContext; +end; + +function TVkCanvas.CreateSharedContext: IGrSharedContext; +begin + Result := TVkSharedContext.Create; +end; + +function TVkCanvas.CreateSurface: Boolean; +{$IF DEFINED(ANDROID)} +var + LJSurface: JSurface; + LSurface: Pointer; + LSurfaceCreateInfo: VkAndroidSurfaceCreateInfoKHR; +{$ELSEIF DEFINED(MSWINDOWS)} +var + LSurfaceCreateInfo: VkWin32SurfaceCreateInfoKHR; +{$ENDIF} +begin + {$IF DEFINED(ANDROID)} + Result := False; + if Parent is TAndroidWindowHandle then + begin + if TAndroidWindowHandle(Parent).Holder = nil then + Exit; + LSurface := (TAndroidWindowHandle(Parent).Holder.getSurface as ILocalObject).GetObjectID; + end + else if Parent is TAndroidHandle then + begin + if TAndroidHandle(Parent).Surface = nil then + Exit; + LJSurface := TJSurface.JavaClass.init(TAndroidHandle(Parent).Surface); + LSurface := TJNIResolver.JavaInstanceToID(LJSurface); + end + else + Exit; + FANativeWindow := ANativeWindow_fromSurface(TJNIResolver.GetJNIEnv, LSurface); + if FANativeWindow = nil then + Exit; + try + LSurfaceCreateInfo.sType := VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; + LSurfaceCreateInfo.pNext := nil; + LSurfaceCreateInfo.flags := 0; + LSurfaceCreateInfo.window := FANativeWindow; + Result := TVkSharedContext(SharedContext).VkInterface.CreateAndroidSurfaceKHR(TVkSharedContext(SharedContext).Instance, @LSurfaceCreateInfo, nil, @FVkSurface) = VK_SUCCESS; + finally + if not Result then + ANativeWindow_release(FANativeWindow); + end; + {$ELSEIF DEFINED(MSWINDOWS)} + LSurfaceCreateInfo.sType := VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + LSurfaceCreateInfo.pNext := nil; + LSurfaceCreateInfo.flags := 0; + LSurfaceCreateInfo.hinstance := HInstance; + LSurfaceCreateInfo.hwnd := WindowHandleToPlatform(Parent).Wnd; + Result := TVkSharedContext(SharedContext).VkInterface.CreateWin32SurfaceKHR(TVkSharedContext(SharedContext).Instance, @LSurfaceCreateInfo, nil, @FVkSurface) = VK_SUCCESS; + {$ELSE} + Result := False; + {$ENDIF} +end; + +function TVkCanvas.CreateSwapchain: Boolean; + + function CreateBuffers(const ASwapchain: VkSwapchainKHR; + const AFormat: VkFormat; const AColorType: TSkColorType; + const AExtent: VkExtent2D; const AUsageFlags: VkImageUsageFlags; + const ASharingMode: VkSharingMode): Boolean; + var + I: Integer; + J: Integer; + LBackBuffers: TArray; + LCount: Cardinal; + LGrBackendRenderTarget: IGrBackendRenderTarget; + LGrBackendTexture: IGrBackendTexture; + LGrVkImageInfo: TGrVkImageInfo; + LImageLayouts: TArray; + LImages: TArray; + LSurfaces: TArray; + begin + if TVkSharedContext(SharedContext).VkInterface.GetSwapchainImagesKHR(TVkSharedContext(SharedContext).Device, ASwapchain, @LCount, nil) <> VK_SUCCESS then + Exit(False); + SetLength(LImages, LCount); + if TVkSharedContext(SharedContext).VkInterface.GetSwapchainImagesKHR(TVkSharedContext(SharedContext).Device, ASwapchain, @LCount, Pointer(LImages)) <> VK_SUCCESS then + Exit(False); + SetLength(LImageLayouts, LCount); + SetLength(LSurfaces, LCount); + for I := 0 to Length(LImages) - 1 do + begin + LImageLayouts[I] := VK_IMAGE_LAYOUT_UNDEFINED; + LGrVkImageInfo.Image := LImages[I]; + LGrVkImageInfo.Alloc.DeviceMemory := VK_NULL_HANDLE; + LGrVkImageInfo.Alloc.Offset := 0; + LGrVkImageInfo.Alloc.Size := 0; + LGrVkImageInfo.Alloc.Flags := []; + LGrVkImageInfo.Alloc.Memory := 0; + LGrVkImageInfo.ImageTiling := VK_IMAGE_TILING_OPTIMAL; + LGrVkImageInfo.ImageLayout := VK_IMAGE_LAYOUT_UNDEFINED; + LGrVkImageInfo.Format := AFormat; + LGrVkImageInfo.ImageUsageFlags := AUsageFlags; + LGrVkImageInfo.SampleCount := 1; + LGrVkImageInfo.LevelCount := 1; + LGrVkImageInfo.CurrentQueueFamily := TVkSharedContext(SharedContext).PresentQueueIndex; + LGrVkImageInfo.ProtectedImage := False; + LGrVkImageInfo.YcbcrConversionInfo.Format := VK_FORMAT_UNDEFINED; + LGrVkImageInfo.YcbcrConversionInfo.FExternalFormat := 0; + LGrVkImageInfo.YcbcrConversionInfo.YcbcrModel := VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY; + LGrVkImageInfo.YcbcrConversionInfo.YcbcrRange := VK_SAMPLER_YCBCR_RANGE_ITU_FULL; + LGrVkImageInfo.YcbcrConversionInfo.XChromaOffset := VK_CHROMA_LOCATION_COSITED_EVEN; + LGrVkImageInfo.YcbcrConversionInfo.YChromaOffset := VK_CHROMA_LOCATION_COSITED_EVEN; + LGrVkImageInfo.YcbcrConversionInfo.ChromaFilter := VK_FILTER_NEAREST; + LGrVkImageInfo.YcbcrConversionInfo.ForceExplicitReconstruction := VK_FALSE; + LGrVkImageInfo.YcbcrConversionInfo.FormatFeatures := 0; + LGrVkImageInfo.SharingMode := ASharingMode; + if (AUsageFlags and VK_IMAGE_USAGE_SAMPLED_BIT) <> 0 then + begin + LGrBackendTexture := TGrBackendTexture.CreateVulkan(AExtent.width, AExtent.height, LGrVkImageInfo); + LSurfaces[I] := TSkSurface.MakeFromTexture(FGrDirectContext, LGrBackendTexture, TGrSurfaceOrigin.TopLeft, Min(CanvasQualitySampleCount[Quality], FGrDirectContext.GetMaxSurfaceSampleCountForColorType(AColorType)), AColorType); + end + else + begin + LGrBackendRenderTarget := TGrBackendRenderTarget.CreateVulkan(AExtent.width, AExtent.height, LGrVkImageInfo); + LSurfaces[I] := TSkSurface.MakeFromRenderTarget(FGrDirectContext, LGrBackendRenderTarget, TGrSurfaceOrigin.TopLeft, AColorType); + end; + if LSurfaces[I] = nil then + Exit(False); + end; + SetLength(LBackBuffers, LCount + 1); + for I := 0 to LCount do + begin + LBackBuffers[I].Index := Cardinal(-1); + if TVkSharedContext(SharedContext).VkInterface.CreateSemaphore(TVkSharedContext(SharedContext).Device, @SemaphoreCreateInfo, nil, @LBackBuffers[I].Semaphore) <> VK_SUCCESS then + begin + for J := 0 to I - 1 do + TVkSharedContext(SharedContext).VkInterface.DestroySemaphore(TVkSharedContext(SharedContext).Device, LBackBuffers[J].Semaphore, nil); + Exit(False); + end; + end; + FBackBuffers := LBackBuffers; + FBackBufferSurfaces := LSurfaces; + FCurrentBackBufferIndex := LCount; + FImageLayouts := LImageLayouts; + FImages := LImages; + Result := True; + end; + +var + I: Integer; + LCapabilities: VkSurfaceCapabilitiesKHR; + LColorType: TSkColorType; + LCompositeAlpha: VkCompositeAlphaFlagBitsKHR; + LCount: Cardinal; + LExtent: VkExtent2D; + LFormat: VkSurfaceFormatKHR; + LFormats: TArray; + LImageCount: Cardinal; + LPresentMode: VkPresentModeKHR; + LPresentModes: TArray; + LQueueFamilyIndices: array[0..1] of Cardinal; + LSwapchain: VkSwapchainKHR; + LSwapchainCreateInfo: VkSwapchainCreateInfoKHR; + LUsageFlags: VkImageUsageFlags; +begin + Result := False; + if TVkSharedContext(SharedContext).VkInterface.GetPhysicalDeviceSurfaceCapabilitiesKHR(TVkSharedContext(SharedContext).PhysicalDevice, FVkSurface, @LCapabilities) <> VK_SUCCESS then + Exit; + if TVkSharedContext(SharedContext).VkInterface.GetPhysicalDeviceSurfaceFormatsKHR(TVkSharedContext(SharedContext).PhysicalDevice, FVkSurface, @LCount, nil) <> VK_SUCCESS then + Exit; + SetLength(LFormats, LCount); + if TVkSharedContext(SharedContext).VkInterface.GetPhysicalDeviceSurfaceFormatsKHR(TVkSharedContext(SharedContext).PhysicalDevice, FVkSurface, @LCount, Pointer(LFormats)) <> VK_SUCCESS then + Exit; + if TVkSharedContext(SharedContext).VkInterface.GetPhysicalDeviceSurfacePresentModesKHR(TVkSharedContext(SharedContext).PhysicalDevice, FVkSurface, @LCount, nil) <> VK_SUCCESS then + Exit; + SetLength(LPresentModes, LCount); + if TVkSharedContext(SharedContext).VkInterface.GetPhysicalDeviceSurfacePresentModesKHR(TVkSharedContext(SharedContext).PhysicalDevice, FVkSurface, @LCount, Pointer(LPresentModes)) <> VK_SUCCESS then + Exit; + LExtent := LCapabilities.currentExtent; + if LExtent.width = Cardinal(-1) then + begin + LExtent.width := Round(Width * Scale); + LExtent.height := Round(Height * Scale); + end; + if LExtent.width < LCapabilities.minImageExtent.width then + LExtent.width := LCapabilities.minImageExtent.width + else if LExtent.width > LCapabilities.maxImageExtent.width then + LExtent.width := LCapabilities.maxImageExtent.width; + if LExtent.height < LCapabilities.minImageExtent.height then + LExtent.height := LCapabilities.minImageExtent.height + else if LExtent.height > LCapabilities.maxImageExtent.height then + LExtent.height := LCapabilities.maxImageExtent.height; + LImageCount := LCapabilities.minImageCount + 2; + if (LCapabilities.maxImageCount > 0) and (LImageCount > LCapabilities.maxImageCount) then + LImageCount := LCapabilities.maxImageCount; + LUsageFlags := VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT or VK_IMAGE_USAGE_TRANSFER_SRC_BIT or VK_IMAGE_USAGE_TRANSFER_DST_BIT; + if (LCapabilities.supportedUsageFlags and VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) <> 0 then + LUsageFlags := LUsageFlags or VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + if (LCapabilities.supportedUsageFlags and VK_IMAGE_USAGE_SAMPLED_BIT) <> 0 then + LUsageFlags := LUsageFlags or VK_IMAGE_USAGE_SAMPLED_BIT; + if (LCapabilities.supportedCompositeAlpha and VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) <> 0 then + LCompositeAlpha := VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR + else + LCompositeAlpha := VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + LColorType := TSkColorType.Unknown; + for I := 0 to Length(LFormats) - 1 do + begin + case LFormats[I].format of + VK_FORMAT_R8G8B8A8_UNORM, + VK_FORMAT_R8G8B8A8_SRGB, + VK_FORMAT_B8G8R8A8_UNORM: + begin + LFormat := LFormats[I]; + if LFormats[I].format = VK_FORMAT_B8G8R8A8_UNORM then + LColorType := TSkColorType.BGRA8888 + else + LColorType := TSkColorType.RGBA8888; + Break; + end; + end; + end; + if LColorType = TSkColorType.Unknown then + Exit; + LPresentMode := VK_PRESENT_MODE_FIFO_KHR; + if not GlobalUseSkiaVulkanFifoKHR then + for I := 0 to Length(LPresentModes) - 1 do + begin + if LPresentModes[I] = VK_PRESENT_MODE_MAILBOX_KHR then + LPresentMode := VK_PRESENT_MODE_MAILBOX_KHR; + if LPresentModes[I] = VK_PRESENT_MODE_IMMEDIATE_KHR then + begin + LPresentMode := VK_PRESENT_MODE_IMMEDIATE_KHR; + Break; + end; + end; + LSwapchainCreateInfo.sType := VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + LSwapchainCreateInfo.pNext := nil; + LSwapchainCreateInfo.flags := 0; + LSwapchainCreateInfo.surface := FVkSurface; + LSwapchainCreateInfo.minImageCount := LImageCount; + LSwapchainCreateInfo.imageFormat := LFormat.format; + LSwapchainCreateInfo.imageColorSpace := LFormat.colorSpace; + LSwapchainCreateInfo.imageExtent := LExtent; + LSwapchainCreateInfo.imageArrayLayers := 1; + LSwapchainCreateInfo.imageUsage := LUsageFlags; + if TVkSharedContext(SharedContext).GraphicsQueueIndex <> TVkSharedContext(SharedContext).PresentQueueIndex then + begin + LQueueFamilyIndices[0] := TVkSharedContext(SharedContext).GraphicsQueueIndex; + LQueueFamilyIndices[1] := TVkSharedContext(SharedContext).PresentQueueIndex; + LSwapchainCreateInfo.imageSharingMode := VK_SHARING_MODE_CONCURRENT; + LSwapchainCreateInfo.queueFamilyIndexCount := 2; + LSwapchainCreateInfo.pQueueFamilyIndices := @LQueueFamilyIndices; + end + else + begin + LSwapchainCreateInfo.imageSharingMode := VK_SHARING_MODE_EXCLUSIVE; + LSwapchainCreateInfo.queueFamilyIndexCount := 0; + LSwapchainCreateInfo.pQueueFamilyIndices := nil; + end; + LSwapchainCreateInfo.preTransform := VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + LSwapchainCreateInfo.compositeAlpha := LCompositeAlpha; + LSwapchainCreateInfo.presentMode := LPresentMode; + LSwapchainCreateInfo.clipped := VK_TRUE; + LSwapchainCreateInfo.oldSwapchain := FSwapchain; + if TVkSharedContext(SharedContext).VkInterface.CreateSwapchainKHR(TVkSharedContext(SharedContext).Device, @LSwapchainCreateInfo, nil, @LSwapchain) <> VK_SUCCESS then + Exit; + try + if LSwapchainCreateInfo.oldSwapchain <> VK_NULL_HANDLE then + DestroySwapchain; + if not CreateBuffers(LSwapchain, LSwapchainCreateInfo.imageFormat, LColorType, LSwapchainCreateInfo.imageExtent, LSwapchainCreateInfo.imageUsage, LSwapchainCreateInfo.imageSharingMode) then + Exit; + FSwapchain := LSwapchain; + Result := FSwapchain <> VK_NULL_HANDLE; + finally + if not Result then + TVkSharedContext(SharedContext).VkInterface.DestroySwapchainKHR(TVkSharedContext(SharedContext).Device, LSwapchain, nil); + end; +end; + +destructor TVkCanvas.Destroy; +begin + if Parent <> nil then + begin + TVkSharedContext(SharedContext).VkInterface.QueueWaitIdle(TVkSharedContext(SharedContext).PresentQueue); + DestroySwapchain; + DestroySurface; + FGrDirectContext := nil; + end; + inherited; +end; + +procedure TVkCanvas.DestroySurface; +begin + if FVkSurface <> VK_NULL_HANDLE then + begin + TVkSharedContext(SharedContext).VkInterface.DestroySurfaceKHR(TVkSharedContext(SharedContext).Instance, FVkSurface, nil); + FVkSurface := VK_NULL_HANDLE; + {$IFDEF ANDROID} + ANativeWindow_release(FANativeWindow); + {$ENDIF} + end; +end; + +procedure TVkCanvas.DestroySwapchain; + + procedure DestroyBuffers; + var + I: Integer; + begin + FBackBufferSurfaces := nil; + FImages := nil; + FImageLayouts := nil; + for I := 0 to Length(FBackBuffers) - 1 do + TVkSharedContext(SharedContext).VkInterface.DestroySemaphore(TVkSharedContext(SharedContext).Device, FBackBuffers[I].Semaphore, nil); + FBackBuffers := nil; + end; + +begin + if FSwapchain <> VK_NULL_HANDLE then + begin + TVkSharedContext(SharedContext).VkInterface.DeviceWaitIdle(TVkSharedContext(SharedContext).Device); + DestroyBuffers; + TVkSharedContext(SharedContext).VkInterface.DestroySwapchainKHR(TVkSharedContext(SharedContext).Device, FSwapchain, nil); + FSwapchain := VK_NULL_HANDLE; + end; +end; + +function TVkCanvas.GetSurfaceFromWindow( + const AContextHandle: THandle): TSkSurface; +var + LGrBackendSemaphore: IGrBackendSemaphore; + LResult: VkResult; + LSemaphore: VkSemaphore; +begin + Result := nil; + SharedContext.BeginContext; + try + if ((FVkSurface = VK_NULL_HANDLE) and (not CreateSurface)) or ((FSwapchain = VK_NULL_HANDLE) and (not CreateSwapchain)) then + Exit; + if TVkSharedContext(SharedContext).VkInterface.CreateSemaphore(TVkSharedContext(SharedContext).Device, @SemaphoreCreateInfo, nil, @LSemaphore) <> VK_SUCCESS then + Exit; + Inc(FCurrentBackBufferIndex); + if FCurrentBackBufferIndex > Length(FImages) then + FCurrentBackBufferIndex := 0; + LResult := TVkSharedContext(SharedContext).VkInterface.AcquireNextImageKHR(TVkSharedContext(SharedContext).Device, FSwapchain, High(UInt64), LSemaphore, VK_NULL_HANDLE, @FBackBuffers[FCurrentBackBufferIndex].Index); + if (LResult = VK_ERROR_SURFACE_LOST_KHR) or (LResult = VK_ERROR_OUT_OF_DATE_KHR) then + begin + TVkSharedContext(SharedContext).VkInterface.DestroySemaphore(TVkSharedContext(SharedContext).Device, LSemaphore, nil); + if LResult = VK_ERROR_SURFACE_LOST_KHR then + begin + DestroySwapchain; + DestroySurface; + if not CreateSurface then + Exit; + end; + if not CreateSwapchain then + Exit; + if TVkSharedContext(SharedContext).VkInterface.CreateSemaphore(TVkSharedContext(SharedContext).Device, @SemaphoreCreateInfo, nil, @LSemaphore) <> VK_SUCCESS then + Exit; + Inc(FCurrentBackBufferIndex); + if FCurrentBackBufferIndex > Length(FImages) then + FCurrentBackBufferIndex := 0; + if TVkSharedContext(SharedContext).VkInterface.AcquireNextImageKHR(TVkSharedContext(SharedContext).Device, FSwapchain, High(UInt64), LSemaphore, VK_NULL_HANDLE, @FBackBuffers[FCurrentBackBufferIndex].Index) <> VK_SUCCESS then + begin + TVkSharedContext(SharedContext).VkInterface.DestroySemaphore(TVkSharedContext(SharedContext).Device, LSemaphore, nil); + Exit; + end; + end; + LGrBackendSemaphore := TGrBackendSemaphore.Create; + LGrBackendSemaphore.InitVulkan(LSemaphore); + FBackBufferSurfaces[FBackBuffers[FCurrentBackBufferIndex].Index].Wait([LGrBackendSemaphore]); + Result := TSkSurface(FBackBufferSurfaces[FBackBuffers[FCurrentBackBufferIndex].Index]); + finally + if Result = nil then + SharedContext.EndContext; + end; +end; + +class function TVkCanvas.IsSupported: Boolean; +var + LCount: Cardinal; + LCreateInstance: PFN_vkCreateInstance; + LDestroyInstance: PFN_vkDestroyInstance; + LEnumeratePhysicalDevices: PFN_vkEnumeratePhysicalDevices; + LGetInstanceProcAddr: PFN_vkGetInstanceProcAddr; + LInstance: VkInstance; + LInstanceCreateInfo: VkInstanceCreateInfo; + LLibraryHandle: HMODULE; +begin + LLibraryHandle := VkLoadLibrary; + if LLibraryHandle = 0 then + Exit(False); + try + LGetInstanceProcAddr := PFN_vkGetInstanceProcAddr(GetProcAddress(LLibraryHandle, 'vkGetInstanceProcAddr')); + if not Assigned(LGetInstanceProcAddr) then + Exit(False); + LCreateInstance := PFN_vkCreateInstance(LGetInstanceProcAddr(VK_NULL_HANDLE, 'vkCreateInstance')); + if not Assigned(LCreateInstance) then + Exit(False); + LInstanceCreateInfo.sType := VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + LInstanceCreateInfo.pNext := nil; + LInstanceCreateInfo.flags := 0; + LInstanceCreateInfo.pApplicationInfo := nil; + LInstanceCreateInfo.enabledLayerCount := 0; + LInstanceCreateInfo.ppEnabledLayerNames := nil; + LInstanceCreateInfo.enabledExtensionCount := 0; + LInstanceCreateInfo.ppEnabledExtensionNames := nil; + if LCreateInstance(@LInstanceCreateInfo, nil, @LInstance) <> VK_SUCCESS then + Exit(False); + LDestroyInstance := PFN_vkDestroyInstance(LGetInstanceProcAddr(LInstance, 'vkDestroyInstance')); + // The function 'vkGetInstanceProcAddr' should not fail to retrieve the + // address of 'vkDestroyInstance' once the Vulkan instance has been + // successfully created. However, we cannot fully trust the manufacturers' + // implementations. + if not Assigned(LDestroyInstance) then + Exit(False); + try + LEnumeratePhysicalDevices := PFN_vkEnumeratePhysicalDevices(LGetInstanceProcAddr(LInstance, 'vkEnumeratePhysicalDevices')); + Result := (Assigned(LEnumeratePhysicalDevices)) and (LEnumeratePhysicalDevices(LInstance, @LCount, nil) = VK_SUCCESS) and (LCount > 0); + finally + LDestroyInstance(LInstance, nil); + end; + finally + {$IFDEF MSWINDOWS}Winapi.Windows{$ELSE}System.SysUtils{$ENDIF}.FreeLibrary(LLibraryHandle); + end; +end; + +procedure TVkCanvas.Resized; +begin + inherited; + if FSwapchain <> VK_NULL_HANDLE then + CreateSwapchain; +end; + +procedure TVkCanvas.SwapBuffers(const AContextHandle: THandle); +var + LGrBackendSemaphore: IGrBackendSemaphore; + LPresentInfo: VkPresentInfoKHR; + LPresentState: IGrBackendSurfaceMutableState; +begin + inherited; + LGrBackendSemaphore := TGrBackendSemaphore.Create; + LGrBackendSemaphore.InitVulkan(FBackBuffers[FCurrentBackBufferIndex].Semaphore); + LPresentState := TGrBackendSurfaceMutableState.Create(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, TVkSharedContext(SharedContext).PresentQueueIndex); + FBackBufferSurfaces[FBackBuffers[FCurrentBackBufferIndex].Index].FlushAndSubmit([LGrBackendSemaphore], LPresentState); + LPresentInfo.sType := VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + LPresentInfo.pNext := nil; + LPresentInfo.waitSemaphoreCount := 1; + LPresentInfo.pWaitSemaphores := @FBackBuffers[FCurrentBackBufferIndex].Semaphore; + LPresentInfo.swapchainCount := 1; + LPresentInfo.pSwapchains := @FSwapchain; + LPresentInfo.pImageIndices := @FBackBuffers[FCurrentBackBufferIndex].Index; + LPresentInfo.pResults := nil; + TVkSharedContext(SharedContext).VkInterface.QueuePresentKHR(TVkSharedContext(SharedContext).PresentQueue, @LPresentInfo); + SharedContext.EndContext; +end; + +{ TVkInterface } + +procedure TVkInterface.AcquireDestroyInstanceProc(const AInstance: VkInstance); +begin + GetInstanceProc(AInstance, 'vkDestroyInstance', FDestroyInstance); +end; + +procedure TVkInterface.AcquireDeviceProcs(const ADevice: VkDevice); +begin + GetDeviceProc(ADevice, 'vkCreateSemaphore', FCreateSemaphore); + GetDeviceProc(ADevice, 'vkDestroySemaphore', FDestroySemaphore); + GetDeviceProc(ADevice, 'vkDeviceWaitIdle', FDeviceWaitIdle); + GetDeviceProc(ADevice, 'vkGetDeviceQueue', FGetDeviceQueue); + GetDeviceProc(ADevice, 'vkQueueWaitIdle', FQueueWaitIdle); + GetDeviceProc(ADevice, 'vkCreateSwapchainKHR', FCreateSwapchainKHR); + GetDeviceProc(ADevice, 'vkDestroySwapchainKHR', FDestroySwapchainKHR); + GetDeviceProc(ADevice, 'vkGetSwapchainImagesKHR', FGetSwapchainImagesKHR); + GetDeviceProc(ADevice, 'vkAcquireNextImageKHR', FAcquireNextImageKHR); + GetDeviceProc(ADevice, 'vkQueuePresentKHR', FQueuePresentKHR); +end; + +procedure TVkInterface.AcquireExtensionProcs(const AInstance: VkInstance; + const APhysicalDeviceApiVersion: Cardinal; + const AGrVkExtensions: IGrVkExtensions); +begin + if APhysicalDeviceApiVersion >= VK_MAKE_VERSION(1, 1, 0) then + begin + GetInstanceProc(AInstance, 'vkGetPhysicalDeviceFeatures2', FGetPhysicalDeviceFeatures2); + end + else + begin + if AGrVkExtensions.HasExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 1) then + GetInstanceProc(AInstance, 'vkGetPhysicalDeviceFeatures2KHR', FGetPhysicalDeviceFeatures2); + end; +end; + +procedure TVkInterface.AcquireInstanceProcs(const AInstance: VkInstance); +begin + GetInstanceProc(AInstance, 'vkCreateDevice', FCreateDevice); + GetInstanceProc(AInstance, 'vkDestroyDevice', FDestroyDevice); + GetInstanceProc(AInstance, 'vkEnumerateDeviceExtensionProperties', FEnumerateDeviceExtensionProperties); + GetInstanceProc(AInstance, 'vkEnumeratePhysicalDevices', FEnumeratePhysicalDevices); + GetInstanceProc(AInstance, 'vkGetDeviceProcAddr', FGetDeviceProcAddr); + GetInstanceProc(AInstance, 'vkGetPhysicalDeviceFeatures', FGetPhysicalDeviceFeatures); + GetInstanceProc(AInstance, 'vkGetPhysicalDeviceProperties', FGetPhysicalDeviceProperties); + GetInstanceProc(AInstance, 'vkGetPhysicalDeviceQueueFamilyProperties', FGetPhysicalDeviceQueueFamilyProperties); + GetInstanceProc(AInstance, 'vkDestroySurfaceKHR', FDestroySurfaceKHR); + GetInstanceProc(AInstance, 'vkGetPhysicalDeviceSurfaceCapabilitiesKHR', FGetPhysicalDeviceSurfaceCapabilitiesKHR); + GetInstanceProc(AInstance, 'vkGetPhysicalDeviceSurfaceFormatsKHR', FGetPhysicalDeviceSurfaceFormatsKHR); + GetInstanceProc(AInstance, 'vkGetPhysicalDeviceSurfacePresentModesKHR', FGetPhysicalDeviceSurfacePresentModesKHR); + {$IF DEFINED(ANDROID)} + GetInstanceProc(AInstance, 'vkCreateAndroidSurfaceKHR', FCreateAndroidSurfaceKHR); + {$ELSEIF DEFINED(MSWINDOWS)} + GetInstanceProc(AInstance, 'vkCreateWin32SurfaceKHR', FCreateWin32SurfaceKHR); + GetInstanceProc(AInstance, 'vkGetPhysicalDeviceWin32PresentationSupportKHR', FGetPhysicalDeviceWin32PresentationSupportKHR); + {$ENDIF} +end; + +procedure TVkInterface.GetDeviceProc(const ADevice: VkDevice; + const AName: MarshaledAString; out APFN_vkFunction); +begin + PPointer(@APFN_vkFunction)^ := Pointer(FGetDeviceProcAddr(ADevice, AName)); + if PPointer(@APFN_vkFunction)^ = nil then + raise EVkError.CreateFmt('Could not get the address of the "%s" device function.', [AName]) at ReturnAddress; +end; + +procedure TVkInterface.GetInstanceProc(const AInstance: VkInstance; + const AName: MarshaledAString; out APFN_vkFunction; + const ARaiseIfNotExist: Boolean); +begin + PPointer(@APFN_vkFunction)^ := Pointer(FGetInstanceProcAddr(AInstance, AName)); + if (ARaiseIfNotExist) and (PPointer(@APFN_vkFunction)^ = nil) then + raise EVkError.CreateFmt('Could not get the address of the "%s" instance function.', [AName]) at ReturnAddress; +end; + +procedure TVkInterface.Initialize(const ALibraryHandle: HMODULE); +begin + FGetInstanceProcAddr := GetProcAddress(ALibraryHandle, 'vkGetInstanceProcAddr'); + if not Assigned(FGetInstanceProcAddr) then + raise EGrCanvas.Create('Could not get the address of the "vkGetInstanceProcAddr" function.'); + GetInstanceProc(VK_NULL_HANDLE, 'vkCreateInstance', FCreateInstance); + GetInstanceProc(VK_NULL_HANDLE, 'vkEnumerateInstanceExtensionProperties', FEnumerateInstanceExtensionProperties); + GetInstanceProc(VK_NULL_HANDLE, 'vkEnumerateInstanceVersion', FEnumerateInstanceVersion, False); +end; + +{ TVkSharedContext } + +constructor TVkSharedContext.Create; +const + QueuePriorities: array[0..0] of Single = (0); +var + I: Integer; + J: Integer; + LApplicationInfo: VkApplicationInfo; + LBlend: PVkPhysicalDeviceBlendOperationAdvancedFeaturesEXT; + LCount: Cardinal; + LDeviceCreateInfo: VkDeviceCreateInfo; + LDeviceExtensionNames: TArray; + LDeviceExtensions: TArray; + LDeviceQueueCreateInfo: array[0..1] of VkDeviceQueueCreateInfo; + LExtensions: IGrVkExtensions; + LGetProc: TGrVkGetProc; + LGrVkBackendContext: TGrVkBackendContext; + LHasKHRBufferDeviceAddress: Boolean; + LInstanceCreateInfo: VkInstanceCreateInfo; + LInstanceExtensionNames: TArray; + LInstanceExtensions: TArray; + LMaxApiVersion: Cardinal; + LPhysicalDeviceApiVersion: Cardinal; + LPhysicalDeviceFeatures: PVkPhysicalDeviceFeatures; + LPhysicalDeviceFeatures2: PVkPhysicalDeviceFeatures2; + LPhysicalDeviceProperties: VkPhysicalDeviceProperties; + LPhysicalDevices: TArray; + LQueueFamilyProperties: TArray; + LTailNext: PPointer; + LYcbcr: PVkPhysicalDeviceSamplerYcbcrConversionFeatures; +begin + inherited; + FLibraryHandle := VkLoadLibrary; + if FLibraryHandle = 0 then + raise EGrCanvas.Create('Could not load Vulkan library.'); + try + FVkInterface.Initialize(FLibraryHandle); + if not Assigned(FVkInterface.EnumerateInstanceVersion) then + LMaxApiVersion := VK_MAKE_VERSION(1, 0, 0) + else + begin + VkCheckSuccess(FVkInterface.EnumerateInstanceVersion(@LMaxApiVersion)); + if LMaxApiVersion > VK_MAKE_VERSION(1, 1, 0) then + LMaxApiVersion := VK_MAKE_VERSION(1, 1, 0); + end; + VkCheckSuccess(FVkInterface.EnumerateInstanceExtensionProperties(nil, @LCount, nil)); + SetLength(LInstanceExtensions, LCount); + VkCheckSuccess(FVkInterface.EnumerateInstanceExtensionProperties(nil, @LCount, Pointer(LInstanceExtensions))); + SetLength(LInstanceExtensionNames, Length(LInstanceExtensions)); + J := 0; + for I := 0 to Length(LInstanceExtensions) - 1 do + begin + if StrLComp(@LInstanceExtensions[I].extensionName, 'VK_KHX', 6) <> 0 then + begin + LInstanceExtensionNames[J] := @LInstanceExtensions[I].extensionName; + Inc(J); + end; + end; + SetLength(LInstanceExtensionNames, J); + LApplicationInfo.sType := VK_STRUCTURE_TYPE_APPLICATION_INFO; + LApplicationInfo.pNext := nil; + LApplicationInfo.pApplicationName := nil; + LApplicationInfo.applicationVersion := 0; + LApplicationInfo.pEngineName := nil; + LApplicationInfo.engineVersion := 0; + LApplicationInfo.apiVersion := LMaxApiVersion; + LInstanceCreateInfo.sType := VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + LInstanceCreateInfo.pNext := nil; + LInstanceCreateInfo.flags := 0; + LInstanceCreateInfo.pApplicationInfo := @LApplicationInfo; + LInstanceCreateInfo.enabledLayerCount := 0; + LInstanceCreateInfo.ppEnabledLayerNames := nil; + LInstanceCreateInfo.enabledExtensionCount := Length(LInstanceExtensionNames); + LInstanceCreateInfo.ppEnabledExtensionNames := Pointer(LInstanceExtensionNames); + VkCheckSuccess(FVkInterface.CreateInstance(@LInstanceCreateInfo, nil, @FInstance)); + FVkInterface.AcquireDestroyInstanceProc(FInstance); + try + FVkInterface.AcquireInstanceProcs(FInstance); + LGetProc := + function (const AName: MarshaledAString; const AInstance: GrVkInstance; const ADevice: GrVkDevice): Pointer + begin + if ADevice <> VK_NULL_HANDLE then + Result := Pointer(FVkInterface.GetDeviceProcAddr(ADevice, AName)) + else + Result := Pointer(FVkInterface.GetInstanceProcAddr(AInstance, AName)); + end; + VkCheckSuccess(FVkInterface.EnumeratePhysicalDevices(FInstance, @LCount, nil)); + if LCount = 0 then + raise EVkError.Create('No compatible graphics card found for Vulkan rendering.'); + SetLength(LPhysicalDevices, LCount); + VkCheckSuccess(FVkInterface.EnumeratePhysicalDevices(FInstance, @LCount, Pointer(LPhysicalDevices))); + FPhysicalDevice := LPhysicalDevices[0]; + FVkInterface.GetPhysicalDeviceProperties(FPhysicalDevice, @LPhysicalDeviceProperties); + LPhysicalDeviceApiVersion := Min(LPhysicalDeviceProperties.apiVersion, LMaxApiVersion); + FVkInterface.GetPhysicalDeviceQueueFamilyProperties(FPhysicalDevice, @LCount, nil); + if LCount = 0 then + raise EVkError.Create('No queue families were found for the specified physical device.'); + SetLength(LQueueFamilyProperties, LCount); + FVkInterface.GetPhysicalDeviceQueueFamilyProperties(FPhysicalDevice, @LCount, Pointer(LQueueFamilyProperties)); + FGraphicsQueueIndex := LCount; + for I := 0 to Length(LQueueFamilyProperties) - 1 do + begin + if (LQueueFamilyProperties[I].queueFlags and VK_QUEUE_GRAPHICS_BIT) <> 0 then + begin + FGraphicsQueueIndex := I; + Break; + end; + end; + if FGraphicsQueueIndex = LCount then + raise EVkError.Create('The physical device does not support graphics operations.'); + {$IF DEFINED(MSWINDOWS)} + FPresentQueueIndex := LCount; + for I := 0 to Length(LQueueFamilyProperties) - 1 do + begin + if FVkInterface.GetPhysicalDeviceWin32PresentationSupportKHR(FPhysicalDevice, I) <> VK_FALSE then + begin + FPresentQueueIndex := I; + Break; + end; + end; + if FPresentQueueIndex = LCount then + raise EVkError.Create('The physical device does not support presentation operations.'); + {$ELSE} + FPresentQueueIndex := FGraphicsQueueIndex; + {$ENDIF} + VkCheckSuccess(FVkInterface.EnumerateDeviceExtensionProperties(FPhysicalDevice, nil, @LCount, nil)); + SetLength(LDeviceExtensions, LCount); + VkCheckSuccess(FVkInterface.EnumerateDeviceExtensionProperties(FPhysicalDevice, nil, @LCount, Pointer(LDeviceExtensions))); + LHasKHRBufferDeviceAddress := False; + for I := 0 to Length(LDeviceExtensions) - 1 do + begin + if StrComp(@LDeviceExtensions[I].extensionName, 'VK_KHR_buffer_device_address') = 0 then + begin + LHasKHRBufferDeviceAddress := True; + Break; + end; + end; + SetLength(LDeviceExtensionNames, Length(LDeviceExtensions)); + J := 0; + for I := 0 to Length(LDeviceExtensions) - 1 do + begin + if (StrLComp(@LDeviceExtensions[I].extensionName, 'VK_KHX', 6) <> 0) and (StrLComp(@LDeviceExtensions[I].extensionName, 'VK_NVX', 6) <> 0) then + begin + if (not LHasKHRBufferDeviceAddress) or (StrComp(@LDeviceExtensions[I].extensionName, 'VK_EXT_buffer_device_address') <> 0) then + begin + LDeviceExtensionNames[J] := @LDeviceExtensions[I].extensionName; + Inc(J); + end; + end; + end; + SetLength(LDeviceExtensionNames, J); + LExtensions := TGrVkExtensions.Create; + LExtensions.Init(LGetProc, FInstance, FPhysicalDevice, LInstanceExtensionNames, LDeviceExtensionNames); + FVkInterface.AcquireExtensionProcs(FInstance, LPhysicalDeviceApiVersion, LExtensions); + FFeatures.sType := VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + LPhysicalDeviceFeatures := @FFeatures.features; + try + if Assigned(FVkInterface.GetPhysicalDeviceFeatures2) then + begin + LPhysicalDeviceFeatures2 := @FFeatures; + LTailNext := @FFeatures.pNext; + if LExtensions.HasExtension(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, 2) then + begin + GetMem(LBlend, SizeOf(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT)); + LBlend.sType := VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT; + LBlend.pNext := nil; + LTailNext^ := LBlend; + LTailNext := @LBlend.pNext; + end; + if LExtensions.HasExtension(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, 1) then + begin + GetMem(LYcbcr, SizeOf(VkPhysicalDeviceSamplerYcbcrConversionFeatures)); + LYcbcr.sType := VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES; + LYcbcr.pNext := nil; + LYcbcr.samplerYcbcrConversion := VK_TRUE; + LTailNext^ := LYcbcr; + //LTailNext := @LYcbcr.pNext; + end; + FVkInterface.GetPhysicalDeviceFeatures2(FPhysicalDevice, LPhysicalDeviceFeatures2); + end + else + begin + LPhysicalDeviceFeatures2 := nil; + FVkInterface.GetPhysicalDeviceFeatures(FPhysicalDevice, LPhysicalDeviceFeatures); + end; + FFeatures.features.robustBufferAccess := VK_FALSE; + LDeviceCreateInfo.sType := VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + LDeviceCreateInfo.flags := 0; + LDeviceCreateInfo.enabledLayerCount := 0; + LDeviceCreateInfo.ppEnabledLayerNames := nil; + LDeviceCreateInfo.enabledExtensionCount := Length(LDeviceExtensionNames); + LDeviceCreateInfo.ppEnabledExtensionNames := Pointer(LDeviceExtensionNames); + LDeviceQueueCreateInfo[0].sType := VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + LDeviceQueueCreateInfo[0].pNext := nil; + LDeviceQueueCreateInfo[0].flags := 0; + LDeviceQueueCreateInfo[0].queueFamilyIndex := FGraphicsQueueIndex; + LDeviceQueueCreateInfo[0].queueCount := 1; + LDeviceQueueCreateInfo[0].pQueuePriorities := @QueuePriorities; + if FGraphicsQueueIndex = FPresentQueueIndex then + LDeviceCreateInfo.queueCreateInfoCount := 1 + else + begin + LDeviceQueueCreateInfo[1].sType := VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + LDeviceQueueCreateInfo[1].pNext := nil; + LDeviceQueueCreateInfo[1].flags := 0; + LDeviceQueueCreateInfo[1].queueFamilyIndex := FPresentQueueIndex; + LDeviceQueueCreateInfo[1].queueCount := 1; + LDeviceQueueCreateInfo[1].pQueuePriorities := @QueuePriorities; + LDeviceCreateInfo.queueCreateInfoCount := 2; + end; + LDeviceCreateInfo.pQueueCreateInfos := @LDeviceQueueCreateInfo; + LDeviceCreateInfo.pNext := LPhysicalDeviceFeatures2; + if LDeviceCreateInfo.pNext = nil then + LDeviceCreateInfo.pEnabledFeatures := LPhysicalDeviceFeatures + else + LDeviceCreateInfo.pEnabledFeatures := nil; + VkCheckSuccess(FVkInterface.CreateDevice(FPhysicalDevice, @LDeviceCreateInfo, nil, @FDevice)); + try + FVkInterface.AcquireDeviceProcs(FDevice); + FVkInterface.GetDeviceQueue(FDevice, FGraphicsQueueIndex, 0, @FGraphicsQueue); + FVkInterface.GetDeviceQueue(FDevice, FPresentQueueIndex, 0, @FPresentQueue); + LGrVkBackendContext.Instance := FInstance; + LGrVkBackendContext.PhysicalDevice := FPhysicalDevice; + LGrVkBackendContext.Device := FDevice; + LGrVkBackendContext.Queue := FGraphicsQueue; + LGrVkBackendContext.GraphicsQueueIndex := FGraphicsQueueIndex; + LGrVkBackendContext.MaxApiVersion := LMaxApiVersion; + LGrVkBackendContext.Extensions := LExtensions; + LGrVkBackendContext.PhysicalDeviceFeatures := LPhysicalDeviceFeatures; + LGrVkBackendContext.PhysicalDeviceFeatures2 := LPhysicalDeviceFeatures2; + LGrVkBackendContext.GetProc := LGetProc; + LGrVkBackendContext.ProtectedContext := False; + FGrDirectContext := TGrDirectContext.MakeVulkan(LGrVkBackendContext); + if FGrDirectContext = nil then + raise EGrCanvas.Create('Could not create shared direct context.'); + except + FVkInterface.DestroyDevice(FDevice, nil); + raise; + end; + except + DestroyFeatures; + raise; + end; + except + FVkInterface.DestroyInstance(FInstance, nil); + raise; + end; + except + {$IFDEF MSWINDOWS}Winapi.Windows{$ELSE}System.SysUtils{$ENDIF}.FreeLibrary(FLibraryHandle); + raise; + end; +end; + +procedure TVkSharedContext.DestroyContext; +begin + inherited; + FVkInterface.DestroyDevice(FDevice, nil); + DestroyFeatures; + FVkInterface.DestroyInstance(FInstance, nil); + {$IFDEF MSWINDOWS}Winapi.Windows{$ELSE}System.SysUtils{$ENDIF}.FreeLibrary(FLibraryHandle); +end; + +procedure TVkSharedContext.DestroyFeatures; +type + PVkCommon = ^TVkCommon; + TVkCommon = record + sType: VkStructureType; + pNext: Pointer; + end; +var + LCurrent: Pointer; + LNext: Pointer; +begin + LNext := FFeatures.pNext; + while LNext <> nil do + begin + LCurrent := LNext; + LNext := PVkCommon(LCurrent).pNext; + FreeMem(LCurrent); + end; +end; + +function TVkSharedContext.GetTextureColorType: TSkColorType; +begin + Result := {$IFDEF MSWINDOWS}TSkColorType.BGRA8888{$ELSE}TSkColorType.RGBA8888{$ENDIF}; +end; + +function TVkSharedContext.GetTextureOrigin: TGrSurfaceOrigin; +begin + Result := TGrSurfaceOrigin.TopLeft; +end; + +{$HPPEMIT END '#if !defined(DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE) && !defined(NO_USING_NAMESPACE_FMX_SKIA_CANVAS_VULKAN)'} +{$HPPEMIT END ' using ::Fmx::Skia::Canvas::Vulkan::TVkInterface;'} +{$HPPEMIT END ' using ::Fmx::Skia::Canvas::Vulkan::TVkSharedContextCustom;'} +{$HPPEMIT END ' using ::Fmx::Skia::Canvas::Vulkan::GlobalUseSkiaVulkanFifoKHR;'} +{$HPPEMIT END '#endif'} + +initialization + GlobalUseSkiaVulkanFifoKHR := {$IFDEF ANDROID}True{$ELSE}False{$ENDIF}; + RegisterSkiaRenderCanvas(TVkCanvas, True, + function: Boolean + begin + Result := GlobalUseVulkan and TVkCanvas.IsSupported; + end); +{$ELSE} +implementation +{$ENDIF} +end. diff --git a/Source/System.Skia.pas b/Source/System.Skia.pas index d1ac52df..ac242d49 100644 --- a/Source/System.Skia.pas +++ b/Source/System.Skia.pas @@ -1743,8 +1743,10 @@ TSkFont = class(TSkObject, ISkFont) class procedure path_proc(const path: sk_path_t; const matrix: psk_matrix_t; context: Pointer); cdecl; static; public constructor Create(ATypeface: ISkTypeface = nil; const ASize: Single = 12; const AScaleX: Single = 1; const ASkewX: Single = 0); overload; - constructor Create(const AFont: ISkFont); overload; - class procedure __DestroyHandle(const AHandle: sk_handle_t); override; + constructor Create(const AFont: ISkFont); overload; + class function CreateAsInterface(ATypeface: ISkTypeface = nil; const ASize: Single = 12; const AScaleX: Single = 1; const ASkewX: Single = 0): ISkFont; overload; + class function CreateAsInterface(const AFont: ISkFont): ISkFont; overload; + class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; {$HPPEMIT END '#define SkFont(...) __SkCreate(TSkFont, ISkFont, __VA_ARGS__)'} @@ -2059,11 +2061,14 @@ TSkPaint = class(TSkObject, ISkPaint) procedure SetStrokeWidth(const AValue: Single); procedure SetStyle(const AValue: TSkPaintStyle); public - constructor Create; overload; - constructor Create(const APaint: ISkPaint); overload; - constructor Create(const AStyle: TSkPaintStyle); overload; - class procedure __DestroyHandle(const AHandle: sk_handle_t); override; - end; + constructor Create; overload; + constructor Create(const APaint: ISkPaint); overload; + constructor Create(const AStyle: TSkPaintStyle); overload; + class function CreateAsInterface: ISkPaint; overload; + class function CreateAsInterface(const APaint: ISkPaint): ISkPaint; overload; + class function CreateAsInterface(const AStyle: TSkPaintStyle): ISkPaint; overload; + class procedure __DestroyHandle(const AHandle: sk_handle_t); override; + end; {$HPPEMIT END '#define SkPaint(...) __SkCreate(TSkPaint, ISkPaint, __VA_ARGS__)'} @@ -7273,6 +7278,17 @@ constructor TSkFont.Create(const AFont: ISkFont); inherited Create(sk4d_font_create2(AFont.Handle)); end; +class function TSkFont.CreateAsInterface(const AFont: ISkFont): ISkFont; +begin + Result := TSkFont.Create(AFont); +end; + +class function TSkFont.CreateAsInterface(ATypeface: ISkTypeface; + const ASize, AScaleX, ASkewX: Single): ISkFont; +begin + Result := TSkFont.Create(ATypeface, ASize, AScaleX, ASkewX); +end; + function TSkFont.GetBaselineSnap: Boolean; begin Result := sk4d_font_get_baseline_snap(Handle); @@ -8538,6 +8554,21 @@ constructor TSkPaint.Create(const AStyle: TSkPaintStyle); SetStyle(AStyle); end; +class function TSkPaint.CreateAsInterface: ISkPaint; +begin + Result := TSkPaint.Create(); +end; + +class function TSkPaint.CreateAsInterface(const APaint: ISkPaint): ISkPaint; +begin + Result := TSkPaint.Create(APaint); +end; + +class function TSkPaint.CreateAsInterface(const AStyle: TSkPaintStyle): ISkPaint; +begin + Result := TSkPaint.Create(AStyle); +end; + function TSkPaint.GetAlpha: Byte; begin Result := sk4d_paint_get_alpha(Handle); From 3c428034274225e21cd214bacf2e56187b911c62 Mon Sep 17 00:00:00 2001 From: Jim McKeeth Date: Wed, 2 Apr 2025 22:17:33 -0600 Subject: [PATCH 2/6] proposal - see CreateAsInterface sample https://github.com/skia4delphi/skia4delphi/tree/CreateAsInterface/Samples/CreateAsInterface --- Samples/CreateAsInterface/AsInterfaceDemo.dpr | 14 -- .../CreateAsInterfaceDemo.dpr | 14 ++ ...Demo.dproj => CreateAsInterfaceDemo.dproj} | 21 +-- ...faceMain.dfm => CreateAsInterfaceMain.dfm} | 8 +- ...faceMain.pas => CreateAsInterfaceMain.pas} | 22 ++-- Samples/CreateAsInterface/readme.md | 123 ++++++++++++++++++ 6 files changed, 156 insertions(+), 46 deletions(-) delete mode 100644 Samples/CreateAsInterface/AsInterfaceDemo.dpr create mode 100644 Samples/CreateAsInterface/CreateAsInterfaceDemo.dpr rename Samples/CreateAsInterface/{AsInterfaceDemo.dproj => CreateAsInterfaceDemo.dproj} (90%) rename Samples/CreateAsInterface/{AsInterfaceMain.dfm => CreateAsInterfaceMain.dfm} (81%) rename Samples/CreateAsInterface/{AsInterfaceMain.pas => CreateAsInterfaceMain.pas} (58%) create mode 100644 Samples/CreateAsInterface/readme.md diff --git a/Samples/CreateAsInterface/AsInterfaceDemo.dpr b/Samples/CreateAsInterface/AsInterfaceDemo.dpr deleted file mode 100644 index d8ce9a11..00000000 --- a/Samples/CreateAsInterface/AsInterfaceDemo.dpr +++ /dev/null @@ -1,14 +0,0 @@ -program AsInterfaceDemo; - -uses - Vcl.Forms, - AsInterfaceMain in 'AsInterfaceMain.pas' {Form31}; - -{$R *.res} - -begin - Application.Initialize; - Application.MainFormOnTaskbar := True; - Application.CreateForm(TForm31, Form31); - Application.Run; -end. diff --git a/Samples/CreateAsInterface/CreateAsInterfaceDemo.dpr b/Samples/CreateAsInterface/CreateAsInterfaceDemo.dpr new file mode 100644 index 00000000..a3e94896 --- /dev/null +++ b/Samples/CreateAsInterface/CreateAsInterfaceDemo.dpr @@ -0,0 +1,14 @@ +program CreateAsInterfaceDemo; + +uses + Vcl.Forms, + CreateAsInterfaceMain in 'CreateAsInterfaceMain.pas' {SkIntfDemoMain}; + +{$R *.res} + +begin + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.CreateForm(TSkIntfDemoMain, SkIntfDemoMain); + Application.Run; +end. diff --git a/Samples/CreateAsInterface/AsInterfaceDemo.dproj b/Samples/CreateAsInterface/CreateAsInterfaceDemo.dproj similarity index 90% rename from Samples/CreateAsInterface/AsInterfaceDemo.dproj rename to Samples/CreateAsInterface/CreateAsInterfaceDemo.dproj index b8a9de0f..5f45c885 100644 --- a/Samples/CreateAsInterface/AsInterfaceDemo.dproj +++ b/Samples/CreateAsInterface/CreateAsInterfaceDemo.dproj @@ -4,10 +4,10 @@ Application Debug VCL - AsInterfaceDemo.dpr + CreateAsInterfaceDemo.dpr Win32 {FCB99591-6739-45CE-9331-E46C62D778C0} - AsInterfaceDemo + CreateAsInterfaceDemo 20.3 3 @@ -59,18 +59,13 @@ true - AsInterfaceDemo + CreateAsInterfaceDemo .\$(Platform)\$(Config) .\$(Platform)\$(Config) System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) - ..\Source;..\Source\FMX;..\Source\VCL;$(DCC_SysLibRoot) - ..\Source;..\Source\FMX;..\Source\VCL;$(DCC_UnitSearchPath) $(BDS)\bin\delphi_PROJECTICON.ico - CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= - 1033 - none Debug Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) soapserver;vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;Skia.Package.RTL;RadiantShapesFmx_Design;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;VCLColorTrackers;inetdb;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;vclactnband;TeeUI;fmxFireDAC;dbexpress;FireDACInfxDriver;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;vcltouch;fmxase;DBXOdbcDriver;dbrtl;FireDACDBXDriver;FireDACOracleDriver;Skia.Package.FMX;fmxdae;TeeDB;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;RadiantShapesFmx;FireDACTDataDriver;Skia.Package.VCL;vcldb;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;inetstn;DOSCommandDR;RESTBackendComponents;IndyCore;bindcompdbx;rtl;FireDACMySQLDriver;RaizeComponentsVclDb;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;VirtualTreesDR;DataSnapClient;dsnapcon;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;fmxobj;FMXTee;bindcompvclsmp;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;RaizeComponentsVcl;FireDACIBDriver;$(DCC_UsePackage) @@ -101,8 +96,6 @@ PerMonitorV2 false - true - 1033 PerMonitorV2 @@ -123,10 +116,11 @@ MainSource - -
Form31
+ +
SkIntfDemoMain
dfm
+ Base @@ -145,9 +139,8 @@ - AsInterfaceDemo.dpr + CreateAsInterfaceDemo.dpr - True diff --git a/Samples/CreateAsInterface/AsInterfaceMain.dfm b/Samples/CreateAsInterface/CreateAsInterfaceMain.dfm similarity index 81% rename from Samples/CreateAsInterface/AsInterfaceMain.dfm rename to Samples/CreateAsInterface/CreateAsInterfaceMain.dfm index 481c2d7b..b1ad8921 100644 --- a/Samples/CreateAsInterface/AsInterfaceMain.dfm +++ b/Samples/CreateAsInterface/CreateAsInterfaceMain.dfm @@ -1,13 +1,13 @@ -object Form31: TForm31 +object SkIntfDemoMain: TSkIntfDemoMain Left = 0 Top = 0 Margins.Left = 5 Margins.Top = 5 Margins.Right = 5 Margins.Bottom = 5 - Caption = 'Form31' - ClientHeight = 664 - ClientWidth = 938 + Caption = 'Skia4Delphi Proposal' + ClientHeight = 405 + ClientWidth = 532 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText diff --git a/Samples/CreateAsInterface/AsInterfaceMain.pas b/Samples/CreateAsInterface/CreateAsInterfaceMain.pas similarity index 58% rename from Samples/CreateAsInterface/AsInterfaceMain.pas rename to Samples/CreateAsInterface/CreateAsInterfaceMain.pas index 841531d9..c9b7bd93 100644 --- a/Samples/CreateAsInterface/AsInterfaceMain.pas +++ b/Samples/CreateAsInterface/CreateAsInterfaceMain.pas @@ -1,4 +1,4 @@ -unit AsInterfaceMain; +unit CreateAsInterfaceMain; interface @@ -9,7 +9,7 @@ interface System.UITypes; type - TForm31 = class(TForm) + TSkIntfDemoMain = class(TForm) SkPaintBox1: TSkPaintBox; procedure SkPaintBox1Draw(ASender: TObject; const ACanvas: ISkCanvas; const ADest: TRectF; const AOpacity: Single); @@ -20,26 +20,20 @@ TForm31 = class(TForm) end; var - Form31: TForm31; + SkIntfDemoMain: TSkIntfDemoMain; implementation {$R *.dfm} -procedure TForm31.SkPaintBox1Draw(ASender: TObject; +procedure TSkIntfDemoMain.SkPaintBox1Draw(ASender: TObject; const ACanvas: ISkCanvas; const ADest: TRectF; const AOpacity: Single); begin - var font: ISkFont := TSkFont.Create(nil, 24); - var paint: ISkPaint := TSkPaint.Create(); + // Much better! + var font := TSkFont.CreateAsInterface(nil, 24); + var paint := TSkPaint.CreateAsInterface(); paint.Color := TAlphaColors.Blueviolet; - ACanvas.DrawSimpleText('before',2,30,font,paint); - - var easyFont := TSkFont.CreateAsInteface(nil, 24); - var easyPaint := TSkPaint.CreateAsInteface(); - easyPaint := TAlphaColors.Green; - ACanvas.DrawSimpleText('Easy',32,30,font,paint); - - + ACanvas.DrawSimpleText('CreateAsInterface!',2,30,font,paint) end; end. diff --git a/Samples/CreateAsInterface/readme.md b/Samples/CreateAsInterface/readme.md new file mode 100644 index 00000000..dfd06e56 --- /dev/null +++ b/Samples/CreateAsInterface/readme.md @@ -0,0 +1,123 @@ +# Skia4Delphi `AsInterface` Proposal & Demo + +Most of the Skia API is exposed as interfaces. This takes advantage of reference counting, which is nice to have. Usually, the class has limited public methods and most functionality is exposed through the interface. + +**Example:** + +```Delphi +type + { ISkPaint } + + ISkPaint = interface(ISkObject) + ['{C95825F8-0D51-4BCE-8945-84AFE6264213}'] + function GetAlpha: Byte; + function GetAlphaF: Single; + + { ... 50 other PUBLIC members ...} + + property StrokeWidth: Single read GetStrokeWidth write SetStrokeWidth; + property Style: TSkPaintStyle read GetStyle write SetStyle; + end; + + { TSkPaint } + + TSkPaint = class(TSkObject, ISkPaint) + strict private + function GetAlpha: Byte; + function GetAlphaF: Single; + + { ... 34 other STRICT PRIVATE memebers ... } + + procedure SetStrokeWidth(const AValue: Single); + procedure SetStyle(const AValue: TSkPaintStyle); + public + constructor Create; overload; + constructor Create(const APaint: ISkPaint); overload; + constructor Create(const AStyle: TSkPaintStyle); overload; + end; + ``` + +This is fine for *traditional* variable declarations: + +```Delphi +var + paint: ISkPaint; +begin + paint := TSkPaint.Create; + paint.Color := TAlphaColors.Darkorange; +end; +``` + +Unfortunately, it is *incompatible* with **type inferance**: + +```Delphi +begin + var inferred := TSkPaint.Create; + inferred.Color := TAlphaColors.Darkorange; // E2003 Undeclared identifier: 'Color' +end; +``` + +Forces the more verbose form of inline variable declaration: + +```Delphi +begin + var explicit: ISkPaint := TSkPaint.Create(); + explicit.Color := TAlphaColors.Darkorange; +end; +``` + +The proposed `CreateAsInterace` methods fix this: + +```Delphi +begin + var better := TSkPaint.Create(); + better.Color := TAlphaColors.Darkorange; +end; +``` + +Simply duplicate the existing constructors: + +```Delphi +public + constructor Create; overload; + constructor Create(const APaint: ISkPaint); overload; + constructor Create(const AStyle: TSkPaintStyle); overload; +end; +``` + +Making them a `class function` named `CreateAsInterface` with the same arguements, and returning the `interface`: + +```Delphi +public + class function CreateAsInterface: ISkPaint; overload; + class function CreateAsInterface(const APaint: ISkPaint): ISkPaint; overload; + class function CreateAsInterface(const AStyle: TSkPaintStyle): ISkPaint; overload; +end; +``` + +Any name could be used (`Init`, `AsInterface`, `George`, etc.), but this one makes them very visible in class completion to aid in discovery. + +The implementation just calls the existing constructors, but since the Result is explicitly the Interface, this works as expected: + +```Delphi +implementation + +{ TSkPaint } + +class function TSkPaint.CreateAsInterface: ISkPaint; +begin + Result := TSkPaint.Create(); +end; + +class function TSkPaint.CreateAsInterface(const APaint: ISkPaint): ISkPaint; +begin + Result := TSkPaint.Create(APaint); +end; + +class function TSkPaint.CreateAsInterface(const AStyle: TSkPaintStyle): ISkPaint; +begin + Result := TSkPaint.Create(AStyle); +end; +``` + +Type inferance is as preferable. Beyond less typing it makes code more maintainable (type only needs to be changed in one place) and reduces errors resulting from mismatched types and constructors. The easier it is to take advantage of this feature in Delphi the better. From af9123bace613c5cb496fe9c1fc1e5fff0ebe491 Mon Sep 17 00:00:00 2001 From: Jim McKeeth Date: Wed, 2 Apr 2025 22:30:09 -0600 Subject: [PATCH 3/6] proposal - see CreateAsInterface sample C:\Users\jim\Documents\GitHub\skia4delphi\Samples\CreateAsInterface --- Samples/CreateAsInterface/readme.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Samples/CreateAsInterface/readme.md b/Samples/CreateAsInterface/readme.md index dfd06e56..e2360e2b 100644 --- a/Samples/CreateAsInterface/readme.md +++ b/Samples/CreateAsInterface/readme.md @@ -1,8 +1,6 @@ -# Skia4Delphi `AsInterface` Proposal & Demo +# Skia4Delphi `CreateAsInterface` Proposal & Demo -Most of the Skia API is exposed as interfaces. This takes advantage of reference counting, which is nice to have. Usually, the class has limited public methods and most functionality is exposed through the interface. - -**Example:** +Most of the Skia API is exposed as interfaces. This takes advantage of reference counting, which is nice to have. Usually, the class has limited public methods and most functionality is exposed through the interface. Here is the declaration for `TSkPaint` and `ISkPaint` for example. ```Delphi type @@ -26,7 +24,7 @@ type function GetAlpha: Byte; function GetAlphaF: Single; - { ... 34 other STRICT PRIVATE memebers ... } + { ... 34 other STRICT PRIVATE members ... } procedure SetStrokeWidth(const AValue: Single); procedure SetStyle(const AValue: TSkPaintStyle); @@ -70,7 +68,7 @@ The proposed `CreateAsInterace` methods fix this: ```Delphi begin - var better := TSkPaint.Create(); + var better := TSkPaint.CreateAsInterface(); better.Color := TAlphaColors.Darkorange; end; ``` @@ -85,7 +83,7 @@ public end; ``` -Making them a `class function` named `CreateAsInterface` with the same arguements, and returning the `interface`: +Making them a `class function` named `CreateAsInterface` with the same arguments, and returning the `interface`: ```Delphi public @@ -120,4 +118,4 @@ begin end; ``` -Type inferance is as preferable. Beyond less typing it makes code more maintainable (type only needs to be changed in one place) and reduces errors resulting from mismatched types and constructors. The easier it is to take advantage of this feature in Delphi the better. +Type inference is as preferable. Beyond less typing it makes code more maintainable (type only needs to be changed in one place) and reduces errors resulting from mismatched types and constructors. The easier it is to take advantage of this feature in Delphi the better. From 83f3e960e250589665e603339639b3f99e915119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Felipe=20Botelho=20Barbosa?= Date: Tue, 8 Apr 2025 14:09:00 -0300 Subject: [PATCH 4/6] Removed unauthorized units --- Source/FMX/FMX.Skia.Canvas.Vulkan.pas | 1142 ------------------------- 1 file changed, 1142 deletions(-) delete mode 100644 Source/FMX/FMX.Skia.Canvas.Vulkan.pas diff --git a/Source/FMX/FMX.Skia.Canvas.Vulkan.pas b/Source/FMX/FMX.Skia.Canvas.Vulkan.pas deleted file mode 100644 index 5cf4c3d0..00000000 --- a/Source/FMX/FMX.Skia.Canvas.Vulkan.pas +++ /dev/null @@ -1,1142 +0,0 @@ -{*******************************************************} -{ } -{ Delphi FireMonkey Platform } -{ } -{ Copyright(c) 2023-2025 Embarcadero Technologies, Inc. } -{ All rights reserved } -{ } -{*******************************************************} - -unit FMX.Skia.Canvas.Vulkan; - -interface - -{$SCOPEDENUMS ON} -{$HPPEMIT NOUSINGNAMESPACE} - -{$IF DEFINED(MSWINDOWS) or DEFINED(ANDROID)} - {$DEFINE SKIA_VULKAN} -{$ENDIF} - -{$IFDEF SKIA_VULKAN} - -uses - { Delphi } - {$IF DEFINED(ANDROID)} - Androidapi.Vulkan, - {$ELSEIF DEFINED(MSWINDOWS)} - Winapi.Vulkan, - {$ENDIF} - System.SysUtils, - System.Vulkan, - - { Skia } - System.Skia, - FMX.Skia.Canvas; - -type - { TVkInterface } - - TVkInterface = record - private - FAcquireNextImageKHR: PFN_vkAcquireNextImageKHR; - FCreateDevice: PFN_vkCreateDevice; - FCreateInstance: PFN_vkCreateInstance; - FCreateSemaphore: PFN_vkCreateSemaphore; - FCreateSwapchainKHR: PFN_vkCreateSwapchainKHR; - FDestroyDevice: PFN_vkDestroyDevice; - FDestroyInstance: PFN_vkDestroyInstance; - FDestroySemaphore: PFN_vkDestroySemaphore; - FDestroySurfaceKHR: PFN_vkDestroySurfaceKHR; - FDestroySwapchainKHR: PFN_vkDestroySwapchainKHR; - FDeviceWaitIdle: PFN_vkDeviceWaitIdle; - FEnumerateDeviceExtensionProperties: PFN_vkEnumerateDeviceExtensionProperties; - FEnumerateInstanceExtensionProperties: PFN_vkEnumerateInstanceExtensionProperties; - FEnumerateInstanceVersion: PFN_vkEnumerateInstanceVersion; - FEnumeratePhysicalDevices: PFN_vkEnumeratePhysicalDevices; - FGetDeviceProcAddr: PFN_vkGetDeviceProcAddr; - FGetDeviceQueue: PFN_vkGetDeviceQueue; - FGetInstanceProcAddr: PFN_vkGetInstanceProcAddr; - FGetPhysicalDeviceFeatures: PFN_vkGetPhysicalDeviceFeatures; - FGetPhysicalDeviceFeatures2: PFN_vkGetPhysicalDeviceFeatures2; - FGetPhysicalDeviceProperties: PFN_vkGetPhysicalDeviceProperties; - FGetPhysicalDeviceQueueFamilyProperties: PFN_vkGetPhysicalDeviceQueueFamilyProperties; - FGetPhysicalDeviceSurfaceCapabilitiesKHR: PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR; - FGetPhysicalDeviceSurfaceFormatsKHR: PFN_vkGetPhysicalDeviceSurfaceFormatsKHR; - FGetPhysicalDeviceSurfacePresentModesKHR: PFN_vkGetPhysicalDeviceSurfacePresentModesKHR; - FGetSwapchainImagesKHR: PFN_vkGetSwapchainImagesKHR; - FQueuePresentKHR: PFN_vkQueuePresentKHR; - FQueueWaitIdle: PFN_vkQueueWaitIdle; - {$IF DEFINED(ANDROID)} - FCreateAndroidSurfaceKHR: PFN_vkCreateAndroidSurfaceKHR; - {$ELSEIF DEFINED(MSWINDOWS)} - FCreateWin32SurfaceKHR: PFN_vkCreateWin32SurfaceKHR; - FGetPhysicalDeviceWin32PresentationSupportKHR: PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR; - {$ENDIF} - procedure AcquireDestroyInstanceProc(const AInstance: VkInstance); inline; - procedure AcquireDeviceProcs(const ADevice: VkDevice); - procedure AcquireExtensionProcs(const AInstance: VkInstance; const APhysicalDeviceApiVersion: Cardinal; const AGrVkExtensions: IGrVkExtensions); - procedure AcquireInstanceProcs(const AInstance: VkInstance); - procedure GetDeviceProc(const ADevice: VkDevice; const AName: MarshaledAString; out APFN_vkFunction); - procedure GetInstanceProc(const AInstance: VkInstance; const AName: MarshaledAString; out APFN_vkFunction; const ARaiseIfNotExist: Boolean = True); - procedure Initialize(const ALibraryHandle: HMODULE); - public - { Global Procs } - property CreateInstance: PFN_vkCreateInstance read FCreateInstance; - property EnumerateInstanceExtensionProperties: PFN_vkEnumerateInstanceExtensionProperties read FEnumerateInstanceExtensionProperties; - property EnumerateInstanceVersion: PFN_vkEnumerateInstanceVersion read FEnumerateInstanceVersion; - property GetInstanceProcAddr: PFN_vkGetInstanceProcAddr read FGetInstanceProcAddr; - - { Instance Procs } - property CreateDevice: PFN_vkCreateDevice read FCreateDevice; - property DestroyDevice: PFN_vkDestroyDevice read FDestroyDevice; - property DestroyInstance: PFN_vkDestroyInstance read FDestroyInstance; - property EnumerateDeviceExtensionProperties: PFN_vkEnumerateDeviceExtensionProperties read FEnumerateDeviceExtensionProperties; - property EnumeratePhysicalDevices: PFN_vkEnumeratePhysicalDevices read FEnumeratePhysicalDevices; - property GetDeviceProcAddr: PFN_vkGetDeviceProcAddr read FGetDeviceProcAddr; - property GetPhysicalDeviceFeatures: PFN_vkGetPhysicalDeviceFeatures read FGetPhysicalDeviceFeatures; - property GetPhysicalDeviceProperties: PFN_vkGetPhysicalDeviceProperties read FGetPhysicalDeviceProperties; - property GetPhysicalDeviceQueueFamilyProperties: PFN_vkGetPhysicalDeviceQueueFamilyProperties read FGetPhysicalDeviceQueueFamilyProperties; - property DestroySurfaceKHR: PFN_vkDestroySurfaceKHR read FDestroySurfaceKHR; - property GetPhysicalDeviceSurfaceCapabilitiesKHR: PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR read FGetPhysicalDeviceSurfaceCapabilitiesKHR; - property GetPhysicalDeviceSurfaceFormatsKHR: PFN_vkGetPhysicalDeviceSurfaceFormatsKHR read FGetPhysicalDeviceSurfaceFormatsKHR; - property GetPhysicalDeviceSurfacePresentModesKHR: PFN_vkGetPhysicalDeviceSurfacePresentModesKHR read FGetPhysicalDeviceSurfacePresentModesKHR; - {$IF DEFINED(ANDROID)} - property CreateAndroidSurfaceKHR: PFN_vkCreateAndroidSurfaceKHR read FCreateAndroidSurfaceKHR; - {$ELSEIF DEFINED(MSWINDOWS)} - property CreateWin32SurfaceKHR: PFN_vkCreateWin32SurfaceKHR read FCreateWin32SurfaceKHR; - property GetPhysicalDeviceWin32PresentationSupportKHR: PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR read FGetPhysicalDeviceWin32PresentationSupportKHR; - {$ENDIF} - - { Instance Extension Procs } - property GetPhysicalDeviceFeatures2: PFN_vkGetPhysicalDeviceFeatures2 read FGetPhysicalDeviceFeatures2; - - { Device Procs } - property CreateSemaphore: PFN_vkCreateSemaphore read FCreateSemaphore; - property DestroySemaphore: PFN_vkDestroySemaphore read FDestroySemaphore; - property DeviceWaitIdle: PFN_vkDeviceWaitIdle read FDeviceWaitIdle; - property GetDeviceQueue: PFN_vkGetDeviceQueue read FGetDeviceQueue; - property QueueWaitIdle: PFN_vkQueueWaitIdle read FQueueWaitIdle; - property AcquireNextImageKHR: PFN_vkAcquireNextImageKHR read FAcquireNextImageKHR; - property CreateSwapchainKHR: PFN_vkCreateSwapchainKHR read FCreateSwapchainKHR; - property DestroySwapchainKHR: PFN_vkDestroySwapchainKHR read FDestroySwapchainKHR; - property GetSwapchainImagesKHR: PFN_vkGetSwapchainImagesKHR read FGetSwapchainImagesKHR; - property QueuePresentKHR: PFN_vkQueuePresentKHR read FQueuePresentKHR; - end; - - { TVkSharedContextCustom } - - TVkSharedContextCustom = class abstract(TGrSharedContext) - protected - FDevice: VkDevice; - FGraphicsQueue: VkQueue; - FGraphicsQueueIndex: Cardinal; - FInstance: VkInstance; - FPhysicalDevice: VkPhysicalDevice; - FPresentQueue: VkQueue; - FPresentQueueIndex: Cardinal; - FVkInterface: TVkInterface; - public - property Device: VkDevice read FDevice; - property GraphicsQueue: VkQueue read FGraphicsQueue; - property GraphicsQueueIndex: Cardinal read FGraphicsQueueIndex; - property Instance: VkInstance read FInstance; - property PhysicalDevice: VkPhysicalDevice read FPhysicalDevice; - property PresentQueue: VkQueue read FPresentQueue; - property PresentQueueIndex: Cardinal read FPresentQueueIndex; - property VkInterface: TVkInterface read FVkInterface; - end; - -var - GlobalUseSkiaVulkanFifoKHR: Boolean; - -implementation - -uses - { Delphi } - FMX.Graphics, - FMX.Types, - {$IF DEFINED(ANDROID)} - FMX.Platform.UI.Android, - FMX.Presentation.Android.Style, - Androidapi.JNI.GraphicsContentViewText, - Androidapi.JNIBridge, - Androidapi.NativeWindow, - Androidapi.NativeWindowJni, - {$ELSEIF DEFINED(MSWINDOWS)} - FMX.Platform.Win, - Winapi.Windows, - {$ENDIF} - System.AnsiStrings, - System.Math; - -type - EVkError = class(EGrCanvas); - - { TVkCanvas } - - TVkCanvas = class(TGrCanvas) - private type - TBackBufferInfo = record - Index: Cardinal; - Semaphore: VkSemaphore; - end; - - private const - SemaphoreCreateInfo: VkSemaphoreCreateInfo = (sType: VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; pNext: nil; flags: 0); - private - {$IFDEF ANDROID} - FANativeWindow: PANativeWindow; - {$ENDIF} - FBackBuffers: TArray; - FBackBufferSurfaces: TArray; - FCurrentBackBufferIndex: Integer; - FImageLayouts: TArray; - FImages: TArray; - FSwapchain: VkSwapchainKHR; - FVkSurface: VkSurfaceKHR; - function CreateSurface: Boolean; - function CreateSwapchain: Boolean; - procedure DestroySurface; - procedure DestroySwapchain; - protected - constructor CreateFromWindow(const AParent: TWindowHandle; const AWidth, AHeight: Integer; const AQuality: TCanvasQuality = TCanvasQuality.SystemDefault); override; - function CreateSharedContext: IGrSharedContext; override; - function GetSurfaceFromWindow(const AContextHandle: THandle): TSkSurface; override; - procedure Resized; override; - procedure SwapBuffers(const AContextHandle: THandle); override; - public - destructor Destroy; override; - class function IsSupported: Boolean; - end; - - { TVkSharedContext } - - TVkSharedContext = class(TVkSharedContextCustom) - private - FFeatures: VkPhysicalDeviceFeatures2; - FLibraryHandle: HMODULE; - procedure DestroyFeatures; - protected - procedure DestroyContext; override; - function GetTextureColorType: TSkColorType; override; - function GetTextureOrigin: TGrSurfaceOrigin; override; - public - constructor Create; - end; - -procedure VkCheckSuccess(const AResult: VkResult); - - function ErrorToStr(const AResult: VkResult): string; inline; - begin - case AResult of - VK_NOT_READY : Result := 'VK_NOT_READY'; - VK_TIMEOUT : Result := 'VK_TIMEOUT'; - VK_EVENT_SET : Result := 'VK_EVENT_SET'; - VK_EVENT_RESET : Result := 'VK_EVENT_RESET'; - VK_INCOMPLETE : Result := 'VK_INCOMPLETE'; - VK_ERROR_OUT_OF_HOST_MEMORY : Result := 'VK_ERROR_OUT_OF_HOST_MEMORY'; - VK_ERROR_OUT_OF_DEVICE_MEMORY : Result := 'VK_ERROR_OUT_OF_DEVICE_MEMORY'; - VK_ERROR_INITIALIZATION_FAILED : Result := 'VK_ERROR_INITIALIZATION_FAILED'; - VK_ERROR_DEVICE_LOST : Result := 'VK_ERROR_DEVICE_LOST'; - VK_ERROR_MEMORY_MAP_FAILED : Result := 'VK_ERROR_MEMORY_MAP_FAILED'; - VK_ERROR_LAYER_NOT_PRESENT : Result := 'VK_ERROR_LAYER_NOT_PRESENT'; - VK_ERROR_EXTENSION_NOT_PRESENT : Result := 'VK_ERROR_EXTENSION_NOT_PRESENT'; - VK_ERROR_FEATURE_NOT_PRESENT : Result := 'VK_ERROR_FEATURE_NOT_PRESENT'; - VK_ERROR_INCOMPATIBLE_DRIVER : Result := 'VK_ERROR_INCOMPATIBLE_DRIVER'; - VK_ERROR_TOO_MANY_OBJECTS : Result := 'VK_ERROR_TOO_MANY_OBJECTS'; - VK_ERROR_FORMAT_NOT_SUPPORTED : Result := 'VK_ERROR_FORMAT_NOT_SUPPORTED'; - VK_ERROR_FRAGMENTED_POOL : Result := 'VK_ERROR_FRAGMENTED_POOL'; - VK_ERROR_UNKNOWN : Result := 'VK_ERROR_UNKNOWN'; - VK_ERROR_OUT_OF_POOL_MEMORY : Result := 'VK_ERROR_OUT_OF_POOL_MEMORY'; - VK_ERROR_INVALID_EXTERNAL_HANDLE : Result := 'VK_ERROR_INVALID_EXTERNAL_HANDLE'; - VK_ERROR_SURFACE_LOST_KHR : Result := 'VK_ERROR_SURFACE_LOST_KHR'; - VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: Result := 'VK_ERROR_NATIVE_WINDOW_IN_USE_KHR'; - VK_SUBOPTIMAL_KHR : Result := 'VK_SUBOPTIMAL_KHR'; - VK_ERROR_OUT_OF_DATE_KHR : Result := 'VK_ERROR_OUT_OF_DATE_KHR'; - else - Result := AResult.ToString; - end; - end; - -begin - if AResult <> VK_SUCCESS then - raise EVkError.CreateFmt('Vulkan API call failed with error: %s', [ErrorToStr(AResult)]) at ReturnAddress; -end; - -function VkLoadLibrary: HMODULE; inline; -begin - {$IF DEFINED(ANDROID)} - Result := SafeLoadLibrary('libvulkan.so'); - // In an attempt to load the library, Vulkan Info searches for it in two - // distinct locations, and as a result, we replicate this behavior. - // - // https://github.com/KhronosGroup/Vulkan-Tools/blob/078d44e4664b7efa0b6c96ebced1995c4425d57a/vulkaninfo/vulkaninfo.h#L249 - if Result = 0 then - Result := SafeLoadLibrary('libvulkan.so.1'); - //{$ELSEIF DEFINED(LINUX)} - //Result := SafeLoadLibrary('libvulkan.so.1'); - //{$ELSEIF DEFINED(MACOS)} - //Result := SafeLoadLibrary('libvk_swiftshader.dylib'); - {$ELSEIF DEFINED(MSWINDOWS)} - Result := SafeLoadLibrary('vulkan-1.dll'); - {$ELSE} - Result := 0; - {$ENDIF} -end; - -{ TVkCanvas } - -constructor TVkCanvas.CreateFromWindow(const AParent: TWindowHandle; - const AWidth, AHeight: Integer; const AQuality: TCanvasQuality); -begin - inherited; - FGrDirectContext := TGrSharedContext(SharedContext).GrDirectContext; -end; - -function TVkCanvas.CreateSharedContext: IGrSharedContext; -begin - Result := TVkSharedContext.Create; -end; - -function TVkCanvas.CreateSurface: Boolean; -{$IF DEFINED(ANDROID)} -var - LJSurface: JSurface; - LSurface: Pointer; - LSurfaceCreateInfo: VkAndroidSurfaceCreateInfoKHR; -{$ELSEIF DEFINED(MSWINDOWS)} -var - LSurfaceCreateInfo: VkWin32SurfaceCreateInfoKHR; -{$ENDIF} -begin - {$IF DEFINED(ANDROID)} - Result := False; - if Parent is TAndroidWindowHandle then - begin - if TAndroidWindowHandle(Parent).Holder = nil then - Exit; - LSurface := (TAndroidWindowHandle(Parent).Holder.getSurface as ILocalObject).GetObjectID; - end - else if Parent is TAndroidHandle then - begin - if TAndroidHandle(Parent).Surface = nil then - Exit; - LJSurface := TJSurface.JavaClass.init(TAndroidHandle(Parent).Surface); - LSurface := TJNIResolver.JavaInstanceToID(LJSurface); - end - else - Exit; - FANativeWindow := ANativeWindow_fromSurface(TJNIResolver.GetJNIEnv, LSurface); - if FANativeWindow = nil then - Exit; - try - LSurfaceCreateInfo.sType := VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; - LSurfaceCreateInfo.pNext := nil; - LSurfaceCreateInfo.flags := 0; - LSurfaceCreateInfo.window := FANativeWindow; - Result := TVkSharedContext(SharedContext).VkInterface.CreateAndroidSurfaceKHR(TVkSharedContext(SharedContext).Instance, @LSurfaceCreateInfo, nil, @FVkSurface) = VK_SUCCESS; - finally - if not Result then - ANativeWindow_release(FANativeWindow); - end; - {$ELSEIF DEFINED(MSWINDOWS)} - LSurfaceCreateInfo.sType := VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - LSurfaceCreateInfo.pNext := nil; - LSurfaceCreateInfo.flags := 0; - LSurfaceCreateInfo.hinstance := HInstance; - LSurfaceCreateInfo.hwnd := WindowHandleToPlatform(Parent).Wnd; - Result := TVkSharedContext(SharedContext).VkInterface.CreateWin32SurfaceKHR(TVkSharedContext(SharedContext).Instance, @LSurfaceCreateInfo, nil, @FVkSurface) = VK_SUCCESS; - {$ELSE} - Result := False; - {$ENDIF} -end; - -function TVkCanvas.CreateSwapchain: Boolean; - - function CreateBuffers(const ASwapchain: VkSwapchainKHR; - const AFormat: VkFormat; const AColorType: TSkColorType; - const AExtent: VkExtent2D; const AUsageFlags: VkImageUsageFlags; - const ASharingMode: VkSharingMode): Boolean; - var - I: Integer; - J: Integer; - LBackBuffers: TArray; - LCount: Cardinal; - LGrBackendRenderTarget: IGrBackendRenderTarget; - LGrBackendTexture: IGrBackendTexture; - LGrVkImageInfo: TGrVkImageInfo; - LImageLayouts: TArray; - LImages: TArray; - LSurfaces: TArray; - begin - if TVkSharedContext(SharedContext).VkInterface.GetSwapchainImagesKHR(TVkSharedContext(SharedContext).Device, ASwapchain, @LCount, nil) <> VK_SUCCESS then - Exit(False); - SetLength(LImages, LCount); - if TVkSharedContext(SharedContext).VkInterface.GetSwapchainImagesKHR(TVkSharedContext(SharedContext).Device, ASwapchain, @LCount, Pointer(LImages)) <> VK_SUCCESS then - Exit(False); - SetLength(LImageLayouts, LCount); - SetLength(LSurfaces, LCount); - for I := 0 to Length(LImages) - 1 do - begin - LImageLayouts[I] := VK_IMAGE_LAYOUT_UNDEFINED; - LGrVkImageInfo.Image := LImages[I]; - LGrVkImageInfo.Alloc.DeviceMemory := VK_NULL_HANDLE; - LGrVkImageInfo.Alloc.Offset := 0; - LGrVkImageInfo.Alloc.Size := 0; - LGrVkImageInfo.Alloc.Flags := []; - LGrVkImageInfo.Alloc.Memory := 0; - LGrVkImageInfo.ImageTiling := VK_IMAGE_TILING_OPTIMAL; - LGrVkImageInfo.ImageLayout := VK_IMAGE_LAYOUT_UNDEFINED; - LGrVkImageInfo.Format := AFormat; - LGrVkImageInfo.ImageUsageFlags := AUsageFlags; - LGrVkImageInfo.SampleCount := 1; - LGrVkImageInfo.LevelCount := 1; - LGrVkImageInfo.CurrentQueueFamily := TVkSharedContext(SharedContext).PresentQueueIndex; - LGrVkImageInfo.ProtectedImage := False; - LGrVkImageInfo.YcbcrConversionInfo.Format := VK_FORMAT_UNDEFINED; - LGrVkImageInfo.YcbcrConversionInfo.FExternalFormat := 0; - LGrVkImageInfo.YcbcrConversionInfo.YcbcrModel := VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY; - LGrVkImageInfo.YcbcrConversionInfo.YcbcrRange := VK_SAMPLER_YCBCR_RANGE_ITU_FULL; - LGrVkImageInfo.YcbcrConversionInfo.XChromaOffset := VK_CHROMA_LOCATION_COSITED_EVEN; - LGrVkImageInfo.YcbcrConversionInfo.YChromaOffset := VK_CHROMA_LOCATION_COSITED_EVEN; - LGrVkImageInfo.YcbcrConversionInfo.ChromaFilter := VK_FILTER_NEAREST; - LGrVkImageInfo.YcbcrConversionInfo.ForceExplicitReconstruction := VK_FALSE; - LGrVkImageInfo.YcbcrConversionInfo.FormatFeatures := 0; - LGrVkImageInfo.SharingMode := ASharingMode; - if (AUsageFlags and VK_IMAGE_USAGE_SAMPLED_BIT) <> 0 then - begin - LGrBackendTexture := TGrBackendTexture.CreateVulkan(AExtent.width, AExtent.height, LGrVkImageInfo); - LSurfaces[I] := TSkSurface.MakeFromTexture(FGrDirectContext, LGrBackendTexture, TGrSurfaceOrigin.TopLeft, Min(CanvasQualitySampleCount[Quality], FGrDirectContext.GetMaxSurfaceSampleCountForColorType(AColorType)), AColorType); - end - else - begin - LGrBackendRenderTarget := TGrBackendRenderTarget.CreateVulkan(AExtent.width, AExtent.height, LGrVkImageInfo); - LSurfaces[I] := TSkSurface.MakeFromRenderTarget(FGrDirectContext, LGrBackendRenderTarget, TGrSurfaceOrigin.TopLeft, AColorType); - end; - if LSurfaces[I] = nil then - Exit(False); - end; - SetLength(LBackBuffers, LCount + 1); - for I := 0 to LCount do - begin - LBackBuffers[I].Index := Cardinal(-1); - if TVkSharedContext(SharedContext).VkInterface.CreateSemaphore(TVkSharedContext(SharedContext).Device, @SemaphoreCreateInfo, nil, @LBackBuffers[I].Semaphore) <> VK_SUCCESS then - begin - for J := 0 to I - 1 do - TVkSharedContext(SharedContext).VkInterface.DestroySemaphore(TVkSharedContext(SharedContext).Device, LBackBuffers[J].Semaphore, nil); - Exit(False); - end; - end; - FBackBuffers := LBackBuffers; - FBackBufferSurfaces := LSurfaces; - FCurrentBackBufferIndex := LCount; - FImageLayouts := LImageLayouts; - FImages := LImages; - Result := True; - end; - -var - I: Integer; - LCapabilities: VkSurfaceCapabilitiesKHR; - LColorType: TSkColorType; - LCompositeAlpha: VkCompositeAlphaFlagBitsKHR; - LCount: Cardinal; - LExtent: VkExtent2D; - LFormat: VkSurfaceFormatKHR; - LFormats: TArray; - LImageCount: Cardinal; - LPresentMode: VkPresentModeKHR; - LPresentModes: TArray; - LQueueFamilyIndices: array[0..1] of Cardinal; - LSwapchain: VkSwapchainKHR; - LSwapchainCreateInfo: VkSwapchainCreateInfoKHR; - LUsageFlags: VkImageUsageFlags; -begin - Result := False; - if TVkSharedContext(SharedContext).VkInterface.GetPhysicalDeviceSurfaceCapabilitiesKHR(TVkSharedContext(SharedContext).PhysicalDevice, FVkSurface, @LCapabilities) <> VK_SUCCESS then - Exit; - if TVkSharedContext(SharedContext).VkInterface.GetPhysicalDeviceSurfaceFormatsKHR(TVkSharedContext(SharedContext).PhysicalDevice, FVkSurface, @LCount, nil) <> VK_SUCCESS then - Exit; - SetLength(LFormats, LCount); - if TVkSharedContext(SharedContext).VkInterface.GetPhysicalDeviceSurfaceFormatsKHR(TVkSharedContext(SharedContext).PhysicalDevice, FVkSurface, @LCount, Pointer(LFormats)) <> VK_SUCCESS then - Exit; - if TVkSharedContext(SharedContext).VkInterface.GetPhysicalDeviceSurfacePresentModesKHR(TVkSharedContext(SharedContext).PhysicalDevice, FVkSurface, @LCount, nil) <> VK_SUCCESS then - Exit; - SetLength(LPresentModes, LCount); - if TVkSharedContext(SharedContext).VkInterface.GetPhysicalDeviceSurfacePresentModesKHR(TVkSharedContext(SharedContext).PhysicalDevice, FVkSurface, @LCount, Pointer(LPresentModes)) <> VK_SUCCESS then - Exit; - LExtent := LCapabilities.currentExtent; - if LExtent.width = Cardinal(-1) then - begin - LExtent.width := Round(Width * Scale); - LExtent.height := Round(Height * Scale); - end; - if LExtent.width < LCapabilities.minImageExtent.width then - LExtent.width := LCapabilities.minImageExtent.width - else if LExtent.width > LCapabilities.maxImageExtent.width then - LExtent.width := LCapabilities.maxImageExtent.width; - if LExtent.height < LCapabilities.minImageExtent.height then - LExtent.height := LCapabilities.minImageExtent.height - else if LExtent.height > LCapabilities.maxImageExtent.height then - LExtent.height := LCapabilities.maxImageExtent.height; - LImageCount := LCapabilities.minImageCount + 2; - if (LCapabilities.maxImageCount > 0) and (LImageCount > LCapabilities.maxImageCount) then - LImageCount := LCapabilities.maxImageCount; - LUsageFlags := VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT or VK_IMAGE_USAGE_TRANSFER_SRC_BIT or VK_IMAGE_USAGE_TRANSFER_DST_BIT; - if (LCapabilities.supportedUsageFlags and VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) <> 0 then - LUsageFlags := LUsageFlags or VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; - if (LCapabilities.supportedUsageFlags and VK_IMAGE_USAGE_SAMPLED_BIT) <> 0 then - LUsageFlags := LUsageFlags or VK_IMAGE_USAGE_SAMPLED_BIT; - if (LCapabilities.supportedCompositeAlpha and VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) <> 0 then - LCompositeAlpha := VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR - else - LCompositeAlpha := VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - LColorType := TSkColorType.Unknown; - for I := 0 to Length(LFormats) - 1 do - begin - case LFormats[I].format of - VK_FORMAT_R8G8B8A8_UNORM, - VK_FORMAT_R8G8B8A8_SRGB, - VK_FORMAT_B8G8R8A8_UNORM: - begin - LFormat := LFormats[I]; - if LFormats[I].format = VK_FORMAT_B8G8R8A8_UNORM then - LColorType := TSkColorType.BGRA8888 - else - LColorType := TSkColorType.RGBA8888; - Break; - end; - end; - end; - if LColorType = TSkColorType.Unknown then - Exit; - LPresentMode := VK_PRESENT_MODE_FIFO_KHR; - if not GlobalUseSkiaVulkanFifoKHR then - for I := 0 to Length(LPresentModes) - 1 do - begin - if LPresentModes[I] = VK_PRESENT_MODE_MAILBOX_KHR then - LPresentMode := VK_PRESENT_MODE_MAILBOX_KHR; - if LPresentModes[I] = VK_PRESENT_MODE_IMMEDIATE_KHR then - begin - LPresentMode := VK_PRESENT_MODE_IMMEDIATE_KHR; - Break; - end; - end; - LSwapchainCreateInfo.sType := VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - LSwapchainCreateInfo.pNext := nil; - LSwapchainCreateInfo.flags := 0; - LSwapchainCreateInfo.surface := FVkSurface; - LSwapchainCreateInfo.minImageCount := LImageCount; - LSwapchainCreateInfo.imageFormat := LFormat.format; - LSwapchainCreateInfo.imageColorSpace := LFormat.colorSpace; - LSwapchainCreateInfo.imageExtent := LExtent; - LSwapchainCreateInfo.imageArrayLayers := 1; - LSwapchainCreateInfo.imageUsage := LUsageFlags; - if TVkSharedContext(SharedContext).GraphicsQueueIndex <> TVkSharedContext(SharedContext).PresentQueueIndex then - begin - LQueueFamilyIndices[0] := TVkSharedContext(SharedContext).GraphicsQueueIndex; - LQueueFamilyIndices[1] := TVkSharedContext(SharedContext).PresentQueueIndex; - LSwapchainCreateInfo.imageSharingMode := VK_SHARING_MODE_CONCURRENT; - LSwapchainCreateInfo.queueFamilyIndexCount := 2; - LSwapchainCreateInfo.pQueueFamilyIndices := @LQueueFamilyIndices; - end - else - begin - LSwapchainCreateInfo.imageSharingMode := VK_SHARING_MODE_EXCLUSIVE; - LSwapchainCreateInfo.queueFamilyIndexCount := 0; - LSwapchainCreateInfo.pQueueFamilyIndices := nil; - end; - LSwapchainCreateInfo.preTransform := VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - LSwapchainCreateInfo.compositeAlpha := LCompositeAlpha; - LSwapchainCreateInfo.presentMode := LPresentMode; - LSwapchainCreateInfo.clipped := VK_TRUE; - LSwapchainCreateInfo.oldSwapchain := FSwapchain; - if TVkSharedContext(SharedContext).VkInterface.CreateSwapchainKHR(TVkSharedContext(SharedContext).Device, @LSwapchainCreateInfo, nil, @LSwapchain) <> VK_SUCCESS then - Exit; - try - if LSwapchainCreateInfo.oldSwapchain <> VK_NULL_HANDLE then - DestroySwapchain; - if not CreateBuffers(LSwapchain, LSwapchainCreateInfo.imageFormat, LColorType, LSwapchainCreateInfo.imageExtent, LSwapchainCreateInfo.imageUsage, LSwapchainCreateInfo.imageSharingMode) then - Exit; - FSwapchain := LSwapchain; - Result := FSwapchain <> VK_NULL_HANDLE; - finally - if not Result then - TVkSharedContext(SharedContext).VkInterface.DestroySwapchainKHR(TVkSharedContext(SharedContext).Device, LSwapchain, nil); - end; -end; - -destructor TVkCanvas.Destroy; -begin - if Parent <> nil then - begin - TVkSharedContext(SharedContext).VkInterface.QueueWaitIdle(TVkSharedContext(SharedContext).PresentQueue); - DestroySwapchain; - DestroySurface; - FGrDirectContext := nil; - end; - inherited; -end; - -procedure TVkCanvas.DestroySurface; -begin - if FVkSurface <> VK_NULL_HANDLE then - begin - TVkSharedContext(SharedContext).VkInterface.DestroySurfaceKHR(TVkSharedContext(SharedContext).Instance, FVkSurface, nil); - FVkSurface := VK_NULL_HANDLE; - {$IFDEF ANDROID} - ANativeWindow_release(FANativeWindow); - {$ENDIF} - end; -end; - -procedure TVkCanvas.DestroySwapchain; - - procedure DestroyBuffers; - var - I: Integer; - begin - FBackBufferSurfaces := nil; - FImages := nil; - FImageLayouts := nil; - for I := 0 to Length(FBackBuffers) - 1 do - TVkSharedContext(SharedContext).VkInterface.DestroySemaphore(TVkSharedContext(SharedContext).Device, FBackBuffers[I].Semaphore, nil); - FBackBuffers := nil; - end; - -begin - if FSwapchain <> VK_NULL_HANDLE then - begin - TVkSharedContext(SharedContext).VkInterface.DeviceWaitIdle(TVkSharedContext(SharedContext).Device); - DestroyBuffers; - TVkSharedContext(SharedContext).VkInterface.DestroySwapchainKHR(TVkSharedContext(SharedContext).Device, FSwapchain, nil); - FSwapchain := VK_NULL_HANDLE; - end; -end; - -function TVkCanvas.GetSurfaceFromWindow( - const AContextHandle: THandle): TSkSurface; -var - LGrBackendSemaphore: IGrBackendSemaphore; - LResult: VkResult; - LSemaphore: VkSemaphore; -begin - Result := nil; - SharedContext.BeginContext; - try - if ((FVkSurface = VK_NULL_HANDLE) and (not CreateSurface)) or ((FSwapchain = VK_NULL_HANDLE) and (not CreateSwapchain)) then - Exit; - if TVkSharedContext(SharedContext).VkInterface.CreateSemaphore(TVkSharedContext(SharedContext).Device, @SemaphoreCreateInfo, nil, @LSemaphore) <> VK_SUCCESS then - Exit; - Inc(FCurrentBackBufferIndex); - if FCurrentBackBufferIndex > Length(FImages) then - FCurrentBackBufferIndex := 0; - LResult := TVkSharedContext(SharedContext).VkInterface.AcquireNextImageKHR(TVkSharedContext(SharedContext).Device, FSwapchain, High(UInt64), LSemaphore, VK_NULL_HANDLE, @FBackBuffers[FCurrentBackBufferIndex].Index); - if (LResult = VK_ERROR_SURFACE_LOST_KHR) or (LResult = VK_ERROR_OUT_OF_DATE_KHR) then - begin - TVkSharedContext(SharedContext).VkInterface.DestroySemaphore(TVkSharedContext(SharedContext).Device, LSemaphore, nil); - if LResult = VK_ERROR_SURFACE_LOST_KHR then - begin - DestroySwapchain; - DestroySurface; - if not CreateSurface then - Exit; - end; - if not CreateSwapchain then - Exit; - if TVkSharedContext(SharedContext).VkInterface.CreateSemaphore(TVkSharedContext(SharedContext).Device, @SemaphoreCreateInfo, nil, @LSemaphore) <> VK_SUCCESS then - Exit; - Inc(FCurrentBackBufferIndex); - if FCurrentBackBufferIndex > Length(FImages) then - FCurrentBackBufferIndex := 0; - if TVkSharedContext(SharedContext).VkInterface.AcquireNextImageKHR(TVkSharedContext(SharedContext).Device, FSwapchain, High(UInt64), LSemaphore, VK_NULL_HANDLE, @FBackBuffers[FCurrentBackBufferIndex].Index) <> VK_SUCCESS then - begin - TVkSharedContext(SharedContext).VkInterface.DestroySemaphore(TVkSharedContext(SharedContext).Device, LSemaphore, nil); - Exit; - end; - end; - LGrBackendSemaphore := TGrBackendSemaphore.Create; - LGrBackendSemaphore.InitVulkan(LSemaphore); - FBackBufferSurfaces[FBackBuffers[FCurrentBackBufferIndex].Index].Wait([LGrBackendSemaphore]); - Result := TSkSurface(FBackBufferSurfaces[FBackBuffers[FCurrentBackBufferIndex].Index]); - finally - if Result = nil then - SharedContext.EndContext; - end; -end; - -class function TVkCanvas.IsSupported: Boolean; -var - LCount: Cardinal; - LCreateInstance: PFN_vkCreateInstance; - LDestroyInstance: PFN_vkDestroyInstance; - LEnumeratePhysicalDevices: PFN_vkEnumeratePhysicalDevices; - LGetInstanceProcAddr: PFN_vkGetInstanceProcAddr; - LInstance: VkInstance; - LInstanceCreateInfo: VkInstanceCreateInfo; - LLibraryHandle: HMODULE; -begin - LLibraryHandle := VkLoadLibrary; - if LLibraryHandle = 0 then - Exit(False); - try - LGetInstanceProcAddr := PFN_vkGetInstanceProcAddr(GetProcAddress(LLibraryHandle, 'vkGetInstanceProcAddr')); - if not Assigned(LGetInstanceProcAddr) then - Exit(False); - LCreateInstance := PFN_vkCreateInstance(LGetInstanceProcAddr(VK_NULL_HANDLE, 'vkCreateInstance')); - if not Assigned(LCreateInstance) then - Exit(False); - LInstanceCreateInfo.sType := VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - LInstanceCreateInfo.pNext := nil; - LInstanceCreateInfo.flags := 0; - LInstanceCreateInfo.pApplicationInfo := nil; - LInstanceCreateInfo.enabledLayerCount := 0; - LInstanceCreateInfo.ppEnabledLayerNames := nil; - LInstanceCreateInfo.enabledExtensionCount := 0; - LInstanceCreateInfo.ppEnabledExtensionNames := nil; - if LCreateInstance(@LInstanceCreateInfo, nil, @LInstance) <> VK_SUCCESS then - Exit(False); - LDestroyInstance := PFN_vkDestroyInstance(LGetInstanceProcAddr(LInstance, 'vkDestroyInstance')); - // The function 'vkGetInstanceProcAddr' should not fail to retrieve the - // address of 'vkDestroyInstance' once the Vulkan instance has been - // successfully created. However, we cannot fully trust the manufacturers' - // implementations. - if not Assigned(LDestroyInstance) then - Exit(False); - try - LEnumeratePhysicalDevices := PFN_vkEnumeratePhysicalDevices(LGetInstanceProcAddr(LInstance, 'vkEnumeratePhysicalDevices')); - Result := (Assigned(LEnumeratePhysicalDevices)) and (LEnumeratePhysicalDevices(LInstance, @LCount, nil) = VK_SUCCESS) and (LCount > 0); - finally - LDestroyInstance(LInstance, nil); - end; - finally - {$IFDEF MSWINDOWS}Winapi.Windows{$ELSE}System.SysUtils{$ENDIF}.FreeLibrary(LLibraryHandle); - end; -end; - -procedure TVkCanvas.Resized; -begin - inherited; - if FSwapchain <> VK_NULL_HANDLE then - CreateSwapchain; -end; - -procedure TVkCanvas.SwapBuffers(const AContextHandle: THandle); -var - LGrBackendSemaphore: IGrBackendSemaphore; - LPresentInfo: VkPresentInfoKHR; - LPresentState: IGrBackendSurfaceMutableState; -begin - inherited; - LGrBackendSemaphore := TGrBackendSemaphore.Create; - LGrBackendSemaphore.InitVulkan(FBackBuffers[FCurrentBackBufferIndex].Semaphore); - LPresentState := TGrBackendSurfaceMutableState.Create(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, TVkSharedContext(SharedContext).PresentQueueIndex); - FBackBufferSurfaces[FBackBuffers[FCurrentBackBufferIndex].Index].FlushAndSubmit([LGrBackendSemaphore], LPresentState); - LPresentInfo.sType := VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - LPresentInfo.pNext := nil; - LPresentInfo.waitSemaphoreCount := 1; - LPresentInfo.pWaitSemaphores := @FBackBuffers[FCurrentBackBufferIndex].Semaphore; - LPresentInfo.swapchainCount := 1; - LPresentInfo.pSwapchains := @FSwapchain; - LPresentInfo.pImageIndices := @FBackBuffers[FCurrentBackBufferIndex].Index; - LPresentInfo.pResults := nil; - TVkSharedContext(SharedContext).VkInterface.QueuePresentKHR(TVkSharedContext(SharedContext).PresentQueue, @LPresentInfo); - SharedContext.EndContext; -end; - -{ TVkInterface } - -procedure TVkInterface.AcquireDestroyInstanceProc(const AInstance: VkInstance); -begin - GetInstanceProc(AInstance, 'vkDestroyInstance', FDestroyInstance); -end; - -procedure TVkInterface.AcquireDeviceProcs(const ADevice: VkDevice); -begin - GetDeviceProc(ADevice, 'vkCreateSemaphore', FCreateSemaphore); - GetDeviceProc(ADevice, 'vkDestroySemaphore', FDestroySemaphore); - GetDeviceProc(ADevice, 'vkDeviceWaitIdle', FDeviceWaitIdle); - GetDeviceProc(ADevice, 'vkGetDeviceQueue', FGetDeviceQueue); - GetDeviceProc(ADevice, 'vkQueueWaitIdle', FQueueWaitIdle); - GetDeviceProc(ADevice, 'vkCreateSwapchainKHR', FCreateSwapchainKHR); - GetDeviceProc(ADevice, 'vkDestroySwapchainKHR', FDestroySwapchainKHR); - GetDeviceProc(ADevice, 'vkGetSwapchainImagesKHR', FGetSwapchainImagesKHR); - GetDeviceProc(ADevice, 'vkAcquireNextImageKHR', FAcquireNextImageKHR); - GetDeviceProc(ADevice, 'vkQueuePresentKHR', FQueuePresentKHR); -end; - -procedure TVkInterface.AcquireExtensionProcs(const AInstance: VkInstance; - const APhysicalDeviceApiVersion: Cardinal; - const AGrVkExtensions: IGrVkExtensions); -begin - if APhysicalDeviceApiVersion >= VK_MAKE_VERSION(1, 1, 0) then - begin - GetInstanceProc(AInstance, 'vkGetPhysicalDeviceFeatures2', FGetPhysicalDeviceFeatures2); - end - else - begin - if AGrVkExtensions.HasExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 1) then - GetInstanceProc(AInstance, 'vkGetPhysicalDeviceFeatures2KHR', FGetPhysicalDeviceFeatures2); - end; -end; - -procedure TVkInterface.AcquireInstanceProcs(const AInstance: VkInstance); -begin - GetInstanceProc(AInstance, 'vkCreateDevice', FCreateDevice); - GetInstanceProc(AInstance, 'vkDestroyDevice', FDestroyDevice); - GetInstanceProc(AInstance, 'vkEnumerateDeviceExtensionProperties', FEnumerateDeviceExtensionProperties); - GetInstanceProc(AInstance, 'vkEnumeratePhysicalDevices', FEnumeratePhysicalDevices); - GetInstanceProc(AInstance, 'vkGetDeviceProcAddr', FGetDeviceProcAddr); - GetInstanceProc(AInstance, 'vkGetPhysicalDeviceFeatures', FGetPhysicalDeviceFeatures); - GetInstanceProc(AInstance, 'vkGetPhysicalDeviceProperties', FGetPhysicalDeviceProperties); - GetInstanceProc(AInstance, 'vkGetPhysicalDeviceQueueFamilyProperties', FGetPhysicalDeviceQueueFamilyProperties); - GetInstanceProc(AInstance, 'vkDestroySurfaceKHR', FDestroySurfaceKHR); - GetInstanceProc(AInstance, 'vkGetPhysicalDeviceSurfaceCapabilitiesKHR', FGetPhysicalDeviceSurfaceCapabilitiesKHR); - GetInstanceProc(AInstance, 'vkGetPhysicalDeviceSurfaceFormatsKHR', FGetPhysicalDeviceSurfaceFormatsKHR); - GetInstanceProc(AInstance, 'vkGetPhysicalDeviceSurfacePresentModesKHR', FGetPhysicalDeviceSurfacePresentModesKHR); - {$IF DEFINED(ANDROID)} - GetInstanceProc(AInstance, 'vkCreateAndroidSurfaceKHR', FCreateAndroidSurfaceKHR); - {$ELSEIF DEFINED(MSWINDOWS)} - GetInstanceProc(AInstance, 'vkCreateWin32SurfaceKHR', FCreateWin32SurfaceKHR); - GetInstanceProc(AInstance, 'vkGetPhysicalDeviceWin32PresentationSupportKHR', FGetPhysicalDeviceWin32PresentationSupportKHR); - {$ENDIF} -end; - -procedure TVkInterface.GetDeviceProc(const ADevice: VkDevice; - const AName: MarshaledAString; out APFN_vkFunction); -begin - PPointer(@APFN_vkFunction)^ := Pointer(FGetDeviceProcAddr(ADevice, AName)); - if PPointer(@APFN_vkFunction)^ = nil then - raise EVkError.CreateFmt('Could not get the address of the "%s" device function.', [AName]) at ReturnAddress; -end; - -procedure TVkInterface.GetInstanceProc(const AInstance: VkInstance; - const AName: MarshaledAString; out APFN_vkFunction; - const ARaiseIfNotExist: Boolean); -begin - PPointer(@APFN_vkFunction)^ := Pointer(FGetInstanceProcAddr(AInstance, AName)); - if (ARaiseIfNotExist) and (PPointer(@APFN_vkFunction)^ = nil) then - raise EVkError.CreateFmt('Could not get the address of the "%s" instance function.', [AName]) at ReturnAddress; -end; - -procedure TVkInterface.Initialize(const ALibraryHandle: HMODULE); -begin - FGetInstanceProcAddr := GetProcAddress(ALibraryHandle, 'vkGetInstanceProcAddr'); - if not Assigned(FGetInstanceProcAddr) then - raise EGrCanvas.Create('Could not get the address of the "vkGetInstanceProcAddr" function.'); - GetInstanceProc(VK_NULL_HANDLE, 'vkCreateInstance', FCreateInstance); - GetInstanceProc(VK_NULL_HANDLE, 'vkEnumerateInstanceExtensionProperties', FEnumerateInstanceExtensionProperties); - GetInstanceProc(VK_NULL_HANDLE, 'vkEnumerateInstanceVersion', FEnumerateInstanceVersion, False); -end; - -{ TVkSharedContext } - -constructor TVkSharedContext.Create; -const - QueuePriorities: array[0..0] of Single = (0); -var - I: Integer; - J: Integer; - LApplicationInfo: VkApplicationInfo; - LBlend: PVkPhysicalDeviceBlendOperationAdvancedFeaturesEXT; - LCount: Cardinal; - LDeviceCreateInfo: VkDeviceCreateInfo; - LDeviceExtensionNames: TArray; - LDeviceExtensions: TArray; - LDeviceQueueCreateInfo: array[0..1] of VkDeviceQueueCreateInfo; - LExtensions: IGrVkExtensions; - LGetProc: TGrVkGetProc; - LGrVkBackendContext: TGrVkBackendContext; - LHasKHRBufferDeviceAddress: Boolean; - LInstanceCreateInfo: VkInstanceCreateInfo; - LInstanceExtensionNames: TArray; - LInstanceExtensions: TArray; - LMaxApiVersion: Cardinal; - LPhysicalDeviceApiVersion: Cardinal; - LPhysicalDeviceFeatures: PVkPhysicalDeviceFeatures; - LPhysicalDeviceFeatures2: PVkPhysicalDeviceFeatures2; - LPhysicalDeviceProperties: VkPhysicalDeviceProperties; - LPhysicalDevices: TArray; - LQueueFamilyProperties: TArray; - LTailNext: PPointer; - LYcbcr: PVkPhysicalDeviceSamplerYcbcrConversionFeatures; -begin - inherited; - FLibraryHandle := VkLoadLibrary; - if FLibraryHandle = 0 then - raise EGrCanvas.Create('Could not load Vulkan library.'); - try - FVkInterface.Initialize(FLibraryHandle); - if not Assigned(FVkInterface.EnumerateInstanceVersion) then - LMaxApiVersion := VK_MAKE_VERSION(1, 0, 0) - else - begin - VkCheckSuccess(FVkInterface.EnumerateInstanceVersion(@LMaxApiVersion)); - if LMaxApiVersion > VK_MAKE_VERSION(1, 1, 0) then - LMaxApiVersion := VK_MAKE_VERSION(1, 1, 0); - end; - VkCheckSuccess(FVkInterface.EnumerateInstanceExtensionProperties(nil, @LCount, nil)); - SetLength(LInstanceExtensions, LCount); - VkCheckSuccess(FVkInterface.EnumerateInstanceExtensionProperties(nil, @LCount, Pointer(LInstanceExtensions))); - SetLength(LInstanceExtensionNames, Length(LInstanceExtensions)); - J := 0; - for I := 0 to Length(LInstanceExtensions) - 1 do - begin - if StrLComp(@LInstanceExtensions[I].extensionName, 'VK_KHX', 6) <> 0 then - begin - LInstanceExtensionNames[J] := @LInstanceExtensions[I].extensionName; - Inc(J); - end; - end; - SetLength(LInstanceExtensionNames, J); - LApplicationInfo.sType := VK_STRUCTURE_TYPE_APPLICATION_INFO; - LApplicationInfo.pNext := nil; - LApplicationInfo.pApplicationName := nil; - LApplicationInfo.applicationVersion := 0; - LApplicationInfo.pEngineName := nil; - LApplicationInfo.engineVersion := 0; - LApplicationInfo.apiVersion := LMaxApiVersion; - LInstanceCreateInfo.sType := VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - LInstanceCreateInfo.pNext := nil; - LInstanceCreateInfo.flags := 0; - LInstanceCreateInfo.pApplicationInfo := @LApplicationInfo; - LInstanceCreateInfo.enabledLayerCount := 0; - LInstanceCreateInfo.ppEnabledLayerNames := nil; - LInstanceCreateInfo.enabledExtensionCount := Length(LInstanceExtensionNames); - LInstanceCreateInfo.ppEnabledExtensionNames := Pointer(LInstanceExtensionNames); - VkCheckSuccess(FVkInterface.CreateInstance(@LInstanceCreateInfo, nil, @FInstance)); - FVkInterface.AcquireDestroyInstanceProc(FInstance); - try - FVkInterface.AcquireInstanceProcs(FInstance); - LGetProc := - function (const AName: MarshaledAString; const AInstance: GrVkInstance; const ADevice: GrVkDevice): Pointer - begin - if ADevice <> VK_NULL_HANDLE then - Result := Pointer(FVkInterface.GetDeviceProcAddr(ADevice, AName)) - else - Result := Pointer(FVkInterface.GetInstanceProcAddr(AInstance, AName)); - end; - VkCheckSuccess(FVkInterface.EnumeratePhysicalDevices(FInstance, @LCount, nil)); - if LCount = 0 then - raise EVkError.Create('No compatible graphics card found for Vulkan rendering.'); - SetLength(LPhysicalDevices, LCount); - VkCheckSuccess(FVkInterface.EnumeratePhysicalDevices(FInstance, @LCount, Pointer(LPhysicalDevices))); - FPhysicalDevice := LPhysicalDevices[0]; - FVkInterface.GetPhysicalDeviceProperties(FPhysicalDevice, @LPhysicalDeviceProperties); - LPhysicalDeviceApiVersion := Min(LPhysicalDeviceProperties.apiVersion, LMaxApiVersion); - FVkInterface.GetPhysicalDeviceQueueFamilyProperties(FPhysicalDevice, @LCount, nil); - if LCount = 0 then - raise EVkError.Create('No queue families were found for the specified physical device.'); - SetLength(LQueueFamilyProperties, LCount); - FVkInterface.GetPhysicalDeviceQueueFamilyProperties(FPhysicalDevice, @LCount, Pointer(LQueueFamilyProperties)); - FGraphicsQueueIndex := LCount; - for I := 0 to Length(LQueueFamilyProperties) - 1 do - begin - if (LQueueFamilyProperties[I].queueFlags and VK_QUEUE_GRAPHICS_BIT) <> 0 then - begin - FGraphicsQueueIndex := I; - Break; - end; - end; - if FGraphicsQueueIndex = LCount then - raise EVkError.Create('The physical device does not support graphics operations.'); - {$IF DEFINED(MSWINDOWS)} - FPresentQueueIndex := LCount; - for I := 0 to Length(LQueueFamilyProperties) - 1 do - begin - if FVkInterface.GetPhysicalDeviceWin32PresentationSupportKHR(FPhysicalDevice, I) <> VK_FALSE then - begin - FPresentQueueIndex := I; - Break; - end; - end; - if FPresentQueueIndex = LCount then - raise EVkError.Create('The physical device does not support presentation operations.'); - {$ELSE} - FPresentQueueIndex := FGraphicsQueueIndex; - {$ENDIF} - VkCheckSuccess(FVkInterface.EnumerateDeviceExtensionProperties(FPhysicalDevice, nil, @LCount, nil)); - SetLength(LDeviceExtensions, LCount); - VkCheckSuccess(FVkInterface.EnumerateDeviceExtensionProperties(FPhysicalDevice, nil, @LCount, Pointer(LDeviceExtensions))); - LHasKHRBufferDeviceAddress := False; - for I := 0 to Length(LDeviceExtensions) - 1 do - begin - if StrComp(@LDeviceExtensions[I].extensionName, 'VK_KHR_buffer_device_address') = 0 then - begin - LHasKHRBufferDeviceAddress := True; - Break; - end; - end; - SetLength(LDeviceExtensionNames, Length(LDeviceExtensions)); - J := 0; - for I := 0 to Length(LDeviceExtensions) - 1 do - begin - if (StrLComp(@LDeviceExtensions[I].extensionName, 'VK_KHX', 6) <> 0) and (StrLComp(@LDeviceExtensions[I].extensionName, 'VK_NVX', 6) <> 0) then - begin - if (not LHasKHRBufferDeviceAddress) or (StrComp(@LDeviceExtensions[I].extensionName, 'VK_EXT_buffer_device_address') <> 0) then - begin - LDeviceExtensionNames[J] := @LDeviceExtensions[I].extensionName; - Inc(J); - end; - end; - end; - SetLength(LDeviceExtensionNames, J); - LExtensions := TGrVkExtensions.Create; - LExtensions.Init(LGetProc, FInstance, FPhysicalDevice, LInstanceExtensionNames, LDeviceExtensionNames); - FVkInterface.AcquireExtensionProcs(FInstance, LPhysicalDeviceApiVersion, LExtensions); - FFeatures.sType := VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - LPhysicalDeviceFeatures := @FFeatures.features; - try - if Assigned(FVkInterface.GetPhysicalDeviceFeatures2) then - begin - LPhysicalDeviceFeatures2 := @FFeatures; - LTailNext := @FFeatures.pNext; - if LExtensions.HasExtension(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, 2) then - begin - GetMem(LBlend, SizeOf(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT)); - LBlend.sType := VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT; - LBlend.pNext := nil; - LTailNext^ := LBlend; - LTailNext := @LBlend.pNext; - end; - if LExtensions.HasExtension(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, 1) then - begin - GetMem(LYcbcr, SizeOf(VkPhysicalDeviceSamplerYcbcrConversionFeatures)); - LYcbcr.sType := VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES; - LYcbcr.pNext := nil; - LYcbcr.samplerYcbcrConversion := VK_TRUE; - LTailNext^ := LYcbcr; - //LTailNext := @LYcbcr.pNext; - end; - FVkInterface.GetPhysicalDeviceFeatures2(FPhysicalDevice, LPhysicalDeviceFeatures2); - end - else - begin - LPhysicalDeviceFeatures2 := nil; - FVkInterface.GetPhysicalDeviceFeatures(FPhysicalDevice, LPhysicalDeviceFeatures); - end; - FFeatures.features.robustBufferAccess := VK_FALSE; - LDeviceCreateInfo.sType := VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - LDeviceCreateInfo.flags := 0; - LDeviceCreateInfo.enabledLayerCount := 0; - LDeviceCreateInfo.ppEnabledLayerNames := nil; - LDeviceCreateInfo.enabledExtensionCount := Length(LDeviceExtensionNames); - LDeviceCreateInfo.ppEnabledExtensionNames := Pointer(LDeviceExtensionNames); - LDeviceQueueCreateInfo[0].sType := VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - LDeviceQueueCreateInfo[0].pNext := nil; - LDeviceQueueCreateInfo[0].flags := 0; - LDeviceQueueCreateInfo[0].queueFamilyIndex := FGraphicsQueueIndex; - LDeviceQueueCreateInfo[0].queueCount := 1; - LDeviceQueueCreateInfo[0].pQueuePriorities := @QueuePriorities; - if FGraphicsQueueIndex = FPresentQueueIndex then - LDeviceCreateInfo.queueCreateInfoCount := 1 - else - begin - LDeviceQueueCreateInfo[1].sType := VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - LDeviceQueueCreateInfo[1].pNext := nil; - LDeviceQueueCreateInfo[1].flags := 0; - LDeviceQueueCreateInfo[1].queueFamilyIndex := FPresentQueueIndex; - LDeviceQueueCreateInfo[1].queueCount := 1; - LDeviceQueueCreateInfo[1].pQueuePriorities := @QueuePriorities; - LDeviceCreateInfo.queueCreateInfoCount := 2; - end; - LDeviceCreateInfo.pQueueCreateInfos := @LDeviceQueueCreateInfo; - LDeviceCreateInfo.pNext := LPhysicalDeviceFeatures2; - if LDeviceCreateInfo.pNext = nil then - LDeviceCreateInfo.pEnabledFeatures := LPhysicalDeviceFeatures - else - LDeviceCreateInfo.pEnabledFeatures := nil; - VkCheckSuccess(FVkInterface.CreateDevice(FPhysicalDevice, @LDeviceCreateInfo, nil, @FDevice)); - try - FVkInterface.AcquireDeviceProcs(FDevice); - FVkInterface.GetDeviceQueue(FDevice, FGraphicsQueueIndex, 0, @FGraphicsQueue); - FVkInterface.GetDeviceQueue(FDevice, FPresentQueueIndex, 0, @FPresentQueue); - LGrVkBackendContext.Instance := FInstance; - LGrVkBackendContext.PhysicalDevice := FPhysicalDevice; - LGrVkBackendContext.Device := FDevice; - LGrVkBackendContext.Queue := FGraphicsQueue; - LGrVkBackendContext.GraphicsQueueIndex := FGraphicsQueueIndex; - LGrVkBackendContext.MaxApiVersion := LMaxApiVersion; - LGrVkBackendContext.Extensions := LExtensions; - LGrVkBackendContext.PhysicalDeviceFeatures := LPhysicalDeviceFeatures; - LGrVkBackendContext.PhysicalDeviceFeatures2 := LPhysicalDeviceFeatures2; - LGrVkBackendContext.GetProc := LGetProc; - LGrVkBackendContext.ProtectedContext := False; - FGrDirectContext := TGrDirectContext.MakeVulkan(LGrVkBackendContext); - if FGrDirectContext = nil then - raise EGrCanvas.Create('Could not create shared direct context.'); - except - FVkInterface.DestroyDevice(FDevice, nil); - raise; - end; - except - DestroyFeatures; - raise; - end; - except - FVkInterface.DestroyInstance(FInstance, nil); - raise; - end; - except - {$IFDEF MSWINDOWS}Winapi.Windows{$ELSE}System.SysUtils{$ENDIF}.FreeLibrary(FLibraryHandle); - raise; - end; -end; - -procedure TVkSharedContext.DestroyContext; -begin - inherited; - FVkInterface.DestroyDevice(FDevice, nil); - DestroyFeatures; - FVkInterface.DestroyInstance(FInstance, nil); - {$IFDEF MSWINDOWS}Winapi.Windows{$ELSE}System.SysUtils{$ENDIF}.FreeLibrary(FLibraryHandle); -end; - -procedure TVkSharedContext.DestroyFeatures; -type - PVkCommon = ^TVkCommon; - TVkCommon = record - sType: VkStructureType; - pNext: Pointer; - end; -var - LCurrent: Pointer; - LNext: Pointer; -begin - LNext := FFeatures.pNext; - while LNext <> nil do - begin - LCurrent := LNext; - LNext := PVkCommon(LCurrent).pNext; - FreeMem(LCurrent); - end; -end; - -function TVkSharedContext.GetTextureColorType: TSkColorType; -begin - Result := {$IFDEF MSWINDOWS}TSkColorType.BGRA8888{$ELSE}TSkColorType.RGBA8888{$ENDIF}; -end; - -function TVkSharedContext.GetTextureOrigin: TGrSurfaceOrigin; -begin - Result := TGrSurfaceOrigin.TopLeft; -end; - -{$HPPEMIT END '#if !defined(DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE) && !defined(NO_USING_NAMESPACE_FMX_SKIA_CANVAS_VULKAN)'} -{$HPPEMIT END ' using ::Fmx::Skia::Canvas::Vulkan::TVkInterface;'} -{$HPPEMIT END ' using ::Fmx::Skia::Canvas::Vulkan::TVkSharedContextCustom;'} -{$HPPEMIT END ' using ::Fmx::Skia::Canvas::Vulkan::GlobalUseSkiaVulkanFifoKHR;'} -{$HPPEMIT END '#endif'} - -initialization - GlobalUseSkiaVulkanFifoKHR := {$IFDEF ANDROID}True{$ELSE}False{$ENDIF}; - RegisterSkiaRenderCanvas(TVkCanvas, True, - function: Boolean - begin - Result := GlobalUseVulkan and TVkCanvas.IsSupported; - end); -{$ELSE} -implementation -{$ENDIF} -end. From af209c52ea898aabbc3cf5fce01340eb9db41826 Mon Sep 17 00:00:00 2001 From: Jim McKeeth Date: Tue, 8 Apr 2025 21:17:32 -0600 Subject: [PATCH 5/6] updated based on feedback and implemented on other classes * TSkColorFilter - For color transformations * TSkFont - Font rendering and text metrics handling * TSkPaint - Graphics styling configuration including colors, strokes, and effects * TSkParagraphBuilder - A builder class for creating formatted text paragraphs with advanced text layout features like styles, fonts, and text decorations * TSkParagraphStyle - Styling configuration for paragraph layouts * TSkPath - Vector path definition and manipulation * TSkPathBuilder - Used for building paths incrementally * TSkPathMeasure - For measuring and extracting information about paths * TSkPictureRecorder - Used for recording drawing commands * TSkPixmap - For pixel buffer access * TSkRegion - Represents a 2D set of pixels for clipping or hit-testing * TSkRoundRect - Used for rounded rectangles * TSkRuntimeBlenderBuilder - A builder class for creating custom blend modes at runtime, enabling custom pixel blending operations * TSkRuntimeShaderBuilder - A builder class for creating custom shaders at runtime, allowing dynamic generation of graphical effects and patterns * TSkShaper - Text shaping engine for complex script rendering * TSkString - String handling utilities for Skia * TSkStrutStyle - Text layout configuration for line spacing and alignment * TSkTextStyle - Text styling configuration for paragraphs * TSkUnicode - Unicode text processing and manipulation utilities for international text handling --- .../CreateAsInterfaceDemo.dpr | 14 - .../CreateAsInterfaceFmxDemo.dpr | 24 + .../CreateAsInterfaceFmxDemo.dproj | 358 ++++++++++++++ .../CreateAsInterfaceFmxMain.fmx | 19 + .../CreateAsInterfaceFmxMain.pas | 38 ++ .../CreateAsInterfaceVclDemo.dpr | 17 + ...o.dproj => CreateAsInterfaceVclDemo.dproj} | 13 +- ...eMain.dfm => CreateAsInterfaceVclMain.dfm} | 0 ...eMain.pas => CreateAsInterfaceVclMain.pas} | 13 +- .../CreateAsInterfaces.groupproj | 48 ++ Samples/CreateAsInterface/readme.md | 51 +- Source/FMX/FMX.Skia.Canvas.pas | 24 +- Source/FMX/FMX.Skia.pas | 28 +- Source/System.Skia.pas | 468 ++++++++++++++---- Source/VCL/Vcl.Skia.pas | 81 ++- 15 files changed, 980 insertions(+), 216 deletions(-) delete mode 100644 Samples/CreateAsInterface/CreateAsInterfaceDemo.dpr create mode 100644 Samples/CreateAsInterface/CreateAsInterfaceFmxDemo.dpr create mode 100644 Samples/CreateAsInterface/CreateAsInterfaceFmxDemo.dproj create mode 100644 Samples/CreateAsInterface/CreateAsInterfaceFmxMain.fmx create mode 100644 Samples/CreateAsInterface/CreateAsInterfaceFmxMain.pas create mode 100644 Samples/CreateAsInterface/CreateAsInterfaceVclDemo.dpr rename Samples/CreateAsInterface/{CreateAsInterfaceDemo.dproj => CreateAsInterfaceVclDemo.dproj} (95%) rename Samples/CreateAsInterface/{CreateAsInterfaceMain.dfm => CreateAsInterfaceVclMain.dfm} (100%) rename Samples/CreateAsInterface/{CreateAsInterfaceMain.pas => CreateAsInterfaceVclMain.pas} (68%) create mode 100644 Samples/CreateAsInterface/CreateAsInterfaces.groupproj diff --git a/Samples/CreateAsInterface/CreateAsInterfaceDemo.dpr b/Samples/CreateAsInterface/CreateAsInterfaceDemo.dpr deleted file mode 100644 index a3e94896..00000000 --- a/Samples/CreateAsInterface/CreateAsInterfaceDemo.dpr +++ /dev/null @@ -1,14 +0,0 @@ -program CreateAsInterfaceDemo; - -uses - Vcl.Forms, - CreateAsInterfaceMain in 'CreateAsInterfaceMain.pas' {SkIntfDemoMain}; - -{$R *.res} - -begin - Application.Initialize; - Application.MainFormOnTaskbar := True; - Application.CreateForm(TSkIntfDemoMain, SkIntfDemoMain); - Application.Run; -end. diff --git a/Samples/CreateAsInterface/CreateAsInterfaceFmxDemo.dpr b/Samples/CreateAsInterface/CreateAsInterfaceFmxDemo.dpr new file mode 100644 index 00000000..10aea464 --- /dev/null +++ b/Samples/CreateAsInterface/CreateAsInterfaceFmxDemo.dpr @@ -0,0 +1,24 @@ +program CreateAsInterfaceFmxDemo; + +uses + System.StartUpCopy, + FMX.Forms, + CreateAsInterfaceFmxMain in 'CreateAsInterfaceFmxMain.pas' {Form32}, + System.Skia.API in '..\..\Source\System.Skia.API.pas', + System.Skia in '..\..\Source\System.Skia.pas', + FMX.Skia.AnimatedCodec in '..\..\Source\FMX\FMX.Skia.AnimatedCodec.pas', + FMX.Skia.Canvas.GL in '..\..\Source\FMX\FMX.Skia.Canvas.GL.pas', + FMX.Skia.Canvas.Metal in '..\..\Source\FMX\FMX.Skia.Canvas.Metal.pas', + FMX.Skia.Canvas in '..\..\Source\FMX\FMX.Skia.Canvas.pas', + FMX.Skia.Filter in '..\..\Source\FMX\FMX.Skia.Filter.pas', + FMX.Skia in '..\..\Source\FMX\FMX.Skia.pas', + FMX.Skia.Printer in '..\..\Source\FMX\FMX.Skia.Printer.pas', + FMX.Skia.Canvas.Vulkan in 'C:\Program Files (x86)\Embarcadero\Studio\23.0\source\fmx\FMX.Skia.Canvas.Vulkan.pas'; + +{$R *.res} + +begin + Application.Initialize; + Application.CreateForm(TForm32, Form32); + Application.Run; +end. diff --git a/Samples/CreateAsInterface/CreateAsInterfaceFmxDemo.dproj b/Samples/CreateAsInterface/CreateAsInterfaceFmxDemo.dproj new file mode 100644 index 00000000..43f288e2 --- /dev/null +++ b/Samples/CreateAsInterface/CreateAsInterfaceFmxDemo.dproj @@ -0,0 +1,358 @@ + + + True + Application + Debug + FMX + CreateAsInterfaceFmxDemo.dpr + Win32 + {4B69E98D-E040-40C1-842B-834D8E213761} + CreateAsInterfaceFmxDemo + 20.3 + 693395 + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + CreateAsInterfaceFmxDemo + true + true + true + true + true + true + true + true + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) + ..\Source;..\Source\FMX;$(DCC_UnitSearchPath) + $(BDS)\bin\delphi_PROJECTICNS.icns + $(BDS)\bin\delphi_PROJECTICON.ico + + + $(BDS)\bin\Artwork\Android\FM_AdaptiveIcon_Background.xml + $(BDS)\bin\Artwork\Android\FM_AdaptiveIcon_Foreground.xml + $(BDS)\bin\Artwork\Android\FM_AdaptiveIcon_Monochrome.xml + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png + $(BDS)\bin\Artwork\Android\FM_VectorizedNotificationIcon.xml + $(BDS)\bin\Artwork\Android\FM_VectorizedSplash.xml + $(BDS)\bin\Artwork\Android\FM_VectorizedSplashDark.xml + $(BDS)\bin\Artwork\Android\FM_VectorizedSplashV31.xml + $(BDS)\bin\Artwork\Android\FM_VectorizedSplashV31Dark.xml + Debug + soapserver;fmx;emshosting;DbxCommonDriver;bindengine;IndyIPCommon;emsclient;FireDACCommonDriver;IndyProtocols;RadiantShapesFmx_Design;IndyIPClient;dbxcds;FmxTeeUI;emsedge;bindcompfmx;FireDACSqliteDriver;DbxClientDriver;soapmidas;fmxFireDAC;dbexpress;inet;DataSnapCommon;fmxase;dbrtl;FireDACDBXDriver;CustomIPTransport;DBXInterBaseDriver;IndySystem;RadiantShapesFmx;bindcomp;FireDACCommon;emsserverresource;inetstn;RESTBackendComponents;IndyCore;bindcompdbx;rtl;RESTComponents;DBXSqliteDriver;IndyIPServer;dsnapxml;DataSnapClient;DataSnapProviderClient;DataSnapFireDAC;emsclientfiredac;FireDAC;FireDACDSDriver;xmlrtl;tethering;dsnap;CloudService;FMXTee;DataSnapNativeClient;soaprtl;FireDACIBDriver;$(DCC_UsePackage) + activity-1.7.2.dex.jar;annotation-experimental-1.4.1.dex.jar;annotation-jvm-1.8.1.dex.jar;annotations-13.0.dex.jar;appcompat-1.2.0.dex.jar;appcompat-resources-1.2.0.dex.jar;billing-7.1.1.dex.jar;biometric-1.1.0.dex.jar;browser-1.4.0.dex.jar;cloud-messaging.dex.jar;collection-jvm-1.4.2.dex.jar;concurrent-futures-1.1.0.dex.jar;core-1.15.0.dex.jar;core-common-2.2.0.dex.jar;core-ktx-1.15.0.dex.jar;core-runtime-2.2.0.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;error_prone_annotations-2.9.0.dex.jar;exifinterface-1.3.6.dex.jar;firebase-annotations-16.2.0.dex.jar;firebase-common-20.3.1.dex.jar;firebase-components-17.1.0.dex.jar;firebase-datatransport-18.1.7.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-encoders-proto-16.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.1.3.dex.jar;firebase-installations-interop-17.1.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-23.1.2.dex.jar;fmx.dex.jar;fragment-1.2.5.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;kotlin-stdlib-1.8.22.dex.jar;kotlin-stdlib-common-1.8.22.dex.jar;kotlin-stdlib-jdk7-1.8.22.dex.jar;kotlin-stdlib-jdk8-1.8.22.dex.jar;kotlinx-coroutines-android-1.6.4.dex.jar;kotlinx-coroutines-core-jvm-1.6.4.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.6.2.dex.jar;lifecycle-livedata-2.6.2.dex.jar;lifecycle-livedata-core-2.6.2.dex.jar;lifecycle-runtime-2.6.2.dex.jar;lifecycle-service-2.6.2.dex.jar;lifecycle-viewmodel-2.6.2.dex.jar;lifecycle-viewmodel-savedstate-2.6.2.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;okio-jvm-3.4.0.dex.jar;play-services-ads-22.2.0.dex.jar;play-services-ads-base-22.2.0.dex.jar;play-services-ads-identifier-18.0.0.dex.jar;play-services-ads-lite-22.2.0.dex.jar;play-services-appset-16.0.1.dex.jar;play-services-base-18.5.0.dex.jar;play-services-basement-18.4.0.dex.jar;play-services-cloud-messaging-17.0.1.dex.jar;play-services-location-21.0.1.dex.jar;play-services-maps-18.1.0.dex.jar;play-services-measurement-base-20.1.2.dex.jar;play-services-measurement-sdk-api-20.1.2.dex.jar;play-services-stats-17.0.2.dex.jar;play-services-tasks-18.2.0.dex.jar;print-1.0.0.dex.jar;profileinstaller-1.3.0.dex.jar;room-common-2.2.5.dex.jar;room-runtime-2.2.5.dex.jar;savedstate-1.2.1.dex.jar;sqlite-2.1.0.dex.jar;sqlite-framework-2.1.0.dex.jar;startup-runtime-1.1.1.dex.jar;tracing-1.2.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.1.8.dex.jar;transport-runtime-3.1.8.dex.jar;user-messaging-platform-2.0.0.dex.jar;vectordrawable-1.1.0.dex.jar;vectordrawable-animated-1.1.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.7.0.dex.jar + true + false + true + true + true + package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=35 + + + $(BDS)\bin\Artwork\Android\FM_AdaptiveIcon_Background.xml + $(BDS)\bin\Artwork\Android\FM_AdaptiveIcon_Foreground.xml + $(BDS)\bin\Artwork\Android\FM_AdaptiveIcon_Monochrome.xml + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png + $(BDS)\bin\Artwork\Android\FM_VectorizedNotificationIcon.xml + $(BDS)\bin\Artwork\Android\FM_VectorizedSplash.xml + $(BDS)\bin\Artwork\Android\FM_VectorizedSplashDark.xml + $(BDS)\bin\Artwork\Android\FM_VectorizedSplashV31.xml + $(BDS)\bin\Artwork\Android\FM_VectorizedSplashV31Dark.xml + Debug + soapserver;fmx;emshosting;DbxCommonDriver;bindengine;IndyIPCommon;emsclient;FireDACCommonDriver;IndyProtocols;RadiantShapesFmx_Design;IndyIPClient;dbxcds;FmxTeeUI;emsedge;bindcompfmx;FireDACSqliteDriver;DbxClientDriver;soapmidas;fmxFireDAC;dbexpress;inet;DataSnapCommon;dbrtl;FireDACDBXDriver;CustomIPTransport;DBXInterBaseDriver;IndySystem;RadiantShapesFmx;bindcomp;FireDACCommon;emsserverresource;inetstn;RESTBackendComponents;IndyCore;bindcompdbx;rtl;RESTComponents;DBXSqliteDriver;IndyIPServer;dsnapxml;DataSnapClient;DataSnapProviderClient;DataSnapFireDAC;emsclientfiredac;FireDAC;FireDACDSDriver;xmlrtl;tethering;dsnap;CloudService;FMXTee;DataSnapNativeClient;soaprtl;FireDACIBDriver;$(DCC_UsePackage) + activity-1.7.2.dex.jar;annotation-experimental-1.4.1.dex.jar;annotation-jvm-1.8.1.dex.jar;annotations-13.0.dex.jar;appcompat-1.2.0.dex.jar;appcompat-resources-1.2.0.dex.jar;billing-7.1.1.dex.jar;biometric-1.1.0.dex.jar;browser-1.4.0.dex.jar;cloud-messaging.dex.jar;collection-jvm-1.4.2.dex.jar;concurrent-futures-1.1.0.dex.jar;core-1.15.0.dex.jar;core-common-2.2.0.dex.jar;core-ktx-1.15.0.dex.jar;core-runtime-2.2.0.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;error_prone_annotations-2.9.0.dex.jar;exifinterface-1.3.6.dex.jar;firebase-annotations-16.2.0.dex.jar;firebase-common-20.3.1.dex.jar;firebase-components-17.1.0.dex.jar;firebase-datatransport-18.1.7.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-encoders-proto-16.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.1.3.dex.jar;firebase-installations-interop-17.1.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-23.1.2.dex.jar;fmx.dex.jar;fragment-1.2.5.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;kotlin-stdlib-1.8.22.dex.jar;kotlin-stdlib-common-1.8.22.dex.jar;kotlin-stdlib-jdk7-1.8.22.dex.jar;kotlin-stdlib-jdk8-1.8.22.dex.jar;kotlinx-coroutines-android-1.6.4.dex.jar;kotlinx-coroutines-core-jvm-1.6.4.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.6.2.dex.jar;lifecycle-livedata-2.6.2.dex.jar;lifecycle-livedata-core-2.6.2.dex.jar;lifecycle-runtime-2.6.2.dex.jar;lifecycle-service-2.6.2.dex.jar;lifecycle-viewmodel-2.6.2.dex.jar;lifecycle-viewmodel-savedstate-2.6.2.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;okio-jvm-3.4.0.dex.jar;play-services-ads-22.2.0.dex.jar;play-services-ads-base-22.2.0.dex.jar;play-services-ads-identifier-18.0.0.dex.jar;play-services-ads-lite-22.2.0.dex.jar;play-services-appset-16.0.1.dex.jar;play-services-base-18.5.0.dex.jar;play-services-basement-18.4.0.dex.jar;play-services-cloud-messaging-17.0.1.dex.jar;play-services-location-21.0.1.dex.jar;play-services-maps-18.1.0.dex.jar;play-services-measurement-base-20.1.2.dex.jar;play-services-measurement-sdk-api-20.1.2.dex.jar;play-services-stats-17.0.2.dex.jar;play-services-tasks-18.2.0.dex.jar;print-1.0.0.dex.jar;profileinstaller-1.3.0.dex.jar;room-common-2.2.5.dex.jar;room-runtime-2.2.5.dex.jar;savedstate-1.2.1.dex.jar;sqlite-2.1.0.dex.jar;sqlite-framework-2.1.0.dex.jar;startup-runtime-1.1.1.dex.jar;tracing-1.2.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.1.8.dex.jar;transport-runtime-3.1.8.dex.jar;user-messaging-platform-2.0.0.dex.jar;vectordrawable-1.1.0.dex.jar;vectordrawable-animated-1.1.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.7.0.dex.jar + true + false + true + true + true + package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=35 + + + soapserver;DataSnapServer;fmx;emshosting;DbxCommonDriver;bindengine;FireDACCommonODBC;emsclient;FireDACCommonDriver;IndyProtocols;RadiantShapesFmx_Design;dbxcds;emsedge;inetdb;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;soapmidas;dbexpress;FireDACInfxDriver;inet;DataSnapCommon;dbrtl;FireDACOracleDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;FireDACMongoDBDriver;IndySystem;RadiantShapesFmx;FireDACTDataDriver;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;inetstn;RESTBackendComponents;IndyCore;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;dsnapxml;DataSnapClient;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;xmlrtl;dsnap;CloudService;FireDACDb2Driver;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;FireDACIBDriver;$(DCC_UsePackage) + + + Debug + soapserver;DataSnapServer;fmx;emshosting;DbxCommonDriver;bindengine;IndyIPCommon;FireDACCommonODBC;emsclient;FireDACCommonDriver;IndyProtocols;RadiantShapesFmx_Design;IndyIPClient;dbxcds;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;inetdb;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;soapmidas;fmxFireDAC;dbexpress;DBXMySQLDriver;inet;DataSnapCommon;fmxase;dbrtl;FireDACDBXDriver;FireDACOracleDriver;fmxdae;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;RadiantShapesFmx;FireDACTDataDriver;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;inetstn;RESTBackendComponents;IndyCore;bindcompdbx;rtl;FireDACMySQLDriver;RESTComponents;DBXSqliteDriver;IndyIPServer;dsnapxml;DataSnapClient;DataSnapProviderClient;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;DBXInformixDriver;fmxobj;FMXTee;DataSnapNativeClient;soaprtl;FireDACIBDriver;$(DCC_UsePackage) + true + CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers;ITSAppUsesNonExemptEncryption=false;NSBluetoothAlwaysUsageDescription=The reason for accessing the Bluetooth interface + + + Debug + soapserver;DataSnapServer;fmx;emshosting;DbxCommonDriver;bindengine;IndyIPCommon;FireDACCommonODBC;emsclient;FireDACCommonDriver;IndyProtocols;RadiantShapesFmx_Design;IndyIPClient;dbxcds;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;inetdb;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;soapmidas;fmxFireDAC;dbexpress;DBXMySQLDriver;inet;DataSnapCommon;fmxase;dbrtl;FireDACDBXDriver;FireDACOracleDriver;fmxdae;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;RadiantShapesFmx;FireDACTDataDriver;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;inetstn;RESTBackendComponents;IndyCore;bindcompdbx;rtl;FireDACMySQLDriver;RESTComponents;DBXSqliteDriver;IndyIPServer;dsnapxml;DataSnapClient;DataSnapProviderClient;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;DBXInformixDriver;fmxobj;FMXTee;DataSnapNativeClient;soaprtl;FireDACIBDriver;$(DCC_UsePackage) + true + CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers;ITSAppUsesNonExemptEncryption=false;NSBluetoothAlwaysUsageDescription=The reason for accessing the Bluetooth interface + + + Debug + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + soapserver;vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;RadiantShapesFmx_Design;Skia.Package.RTL;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;VCLColorTrackers;inetdb;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;vclactnband;TeeUI;fmxFireDAC;dbexpress;FireDACInfxDriver;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;vcltouch;fmxase;DBXOdbcDriver;dbrtl;FireDACDBXDriver;FireDACOracleDriver;Skia.Package.FMX;fmxdae;TeeDB;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;RadiantShapesFmx;FireDACTDataDriver;Skia.Package.VCL;vcldb;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;inetstn;DOSCommandDR;RESTBackendComponents;IndyCore;bindcompdbx;rtl;FireDACMySQLDriver;RaizeComponentsVclDb;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;VirtualTreesDR;DataSnapClient;dsnapcon;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;fmxobj;FMXTee;bindcompvclsmp;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;RaizeComponentsVcl;FireDACIBDriver;$(DCC_UsePackage) + $(BDS)\bin\default_app.manifest + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + + + Debug + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + soapserver;vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;RadiantShapesFmx_Design;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;VCLColorTrackers;inetdb;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;vclactnband;TeeUI;fmxFireDAC;dbexpress;FireDACInfxDriver;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;vcltouch;fmxase;DBXOdbcDriver;dbrtl;FireDACDBXDriver;FireDACOracleDriver;fmxdae;TeeDB;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;RadiantShapesFmx;FireDACTDataDriver;Skia.Package.VCL;vcldb;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;inetstn;DOSCommandDR;RESTBackendComponents;IndyCore;bindcompdbx;rtl;FireDACMySQLDriver;RaizeComponentsVclDb;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;VirtualTreesDR;DataSnapClient;dsnapcon;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;fmxobj;FMXTee;bindcompvclsmp;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;RaizeComponentsVcl;FireDACIBDriver;$(DCC_UsePackage) + $(BDS)\bin\default_app.manifest + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + + + Debug + soapserver;fmx;emshosting;DbxCommonDriver;bindengine;IndyIPCommon;emsclient;FireDACCommonDriver;IndyProtocols;RadiantShapesFmx_Design;IndyIPClient;dbxcds;FmxTeeUI;emsedge;bindcompfmx;FireDACSqliteDriver;DbxClientDriver;soapmidas;fmxFireDAC;dbexpress;inet;DataSnapCommon;fmxase;dbrtl;FireDACDBXDriver;CustomIPTransport;DBXInterBaseDriver;IndySystem;RadiantShapesFmx;bindcomp;FireDACCommon;emsserverresource;inetstn;RESTBackendComponents;IndyCore;bindcompdbx;rtl;RESTComponents;DBXSqliteDriver;IndyIPServer;dsnapxml;DataSnapClient;DataSnapProviderClient;DataSnapFireDAC;emsclientfiredac;FireDAC;FireDACDSDriver;xmlrtl;tethering;dsnap;CloudService;FMXTee;DataSnapNativeClient;soaprtl;FireDACIBDriver;$(DCC_UsePackage) + $(MSBuildProjectName) + true + CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;NSLocationAlwaysAndWhenInUseUsageDescription=The reason for accessing the location information of the user;UIBackgroundModes=;NSContactsUsageDescription=The reason for accessing the contacts;NSPhotoLibraryUsageDescription=The reason for accessing the photo library;NSPhotoLibraryAddUsageDescription=The reason for adding to the photo library;NSCameraUsageDescription=The reason for accessing the camera;NSFaceIDUsageDescription=The reason for accessing the face id;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSSiriUsageDescription=The reason for accessing Siri;ITSAppUsesNonExemptEncryption=false;NSBluetoothAlwaysUsageDescription=The reason for accessing bluetooth;NSBluetoothPeripheralUsageDescription=The reason for accessing bluetooth peripherals;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSMotionUsageDescription=The reason for accessing the accelerometer;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers + iPhoneAndiPad + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_1024x1024.png + $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png + $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_167x167.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImage_2x.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageDark_2x.png + $(BDS)\bin\Artwork\iOS\iPad\FM_NotificationIcon_40x40.png + $(BDS)\bin\Artwork\iOS\iPad\FM_SettingIcon_58x58.png + $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_180x180.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_2x.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_3x.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImageDark_2x.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImageDark_3x.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_40x40.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_60x60.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_SettingIcon_58x58.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_SettingIcon_87x87.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_120x120.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png + + + soapserver;fmx;emshosting;DbxCommonDriver;bindengine;IndyIPCommon;emsclient;FireDACCommonDriver;IndyProtocols;RadiantShapesFmx_Design;IndyIPClient;dbxcds;FmxTeeUI;emsedge;bindcompfmx;FireDACSqliteDriver;DbxClientDriver;soapmidas;fmxFireDAC;dbexpress;inet;DataSnapCommon;fmxase;dbrtl;FireDACDBXDriver;CustomIPTransport;DBXInterBaseDriver;IndySystem;RadiantShapesFmx;bindcomp;FireDACCommon;emsserverresource;inetstn;RESTBackendComponents;IndyCore;bindcompdbx;rtl;RESTComponents;DBXSqliteDriver;IndyIPServer;dsnapxml;DataSnapClient;DataSnapProviderClient;DataSnapFireDAC;emsclientfiredac;FireDAC;FireDACDSDriver;xmlrtl;tethering;dsnap;CloudService;FMXTee;DataSnapNativeClient;soaprtl;FireDACIBDriver;$(DCC_UsePackage) + true + CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;NSLocationAlwaysAndWhenInUseUsageDescription=The reason for accessing the location information of the user;UIBackgroundModes=;NSContactsUsageDescription=The reason for accessing the contacts;NSPhotoLibraryUsageDescription=The reason for accessing the photo library;NSPhotoLibraryAddUsageDescription=The reason for adding to the photo library;NSCameraUsageDescription=The reason for accessing the camera;NSFaceIDUsageDescription=The reason for accessing the face id;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSSiriUsageDescription=The reason for accessing Siri;ITSAppUsesNonExemptEncryption=false;NSBluetoothAlwaysUsageDescription=The reason for accessing bluetooth;NSBluetoothPeripheralUsageDescription=The reason for accessing bluetooth peripherals;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSMotionUsageDescription=The reason for accessing the accelerometer;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers + iPhoneAndiPad + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_1024x1024.png + $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png + $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_167x167.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImage_2x.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageDark_2x.png + $(BDS)\bin\Artwork\iOS\iPad\FM_NotificationIcon_40x40.png + $(BDS)\bin\Artwork\iOS\iPad\FM_SettingIcon_58x58.png + $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_180x180.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_2x.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_3x.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImageDark_2x.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImageDark_3x.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_40x40.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_60x60.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_SettingIcon_58x58.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_SettingIcon_87x87.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_120x120.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png + + + true + true + DEBUG;$(DCC_Define) + true + true + false + true + true + + + PerMonitorV2 + false + true + 1033 + + + PerMonitorV2 + + + 0 + RELEASE;$(DCC_Define) + false + 0 + + + PerMonitorV2 + + + PerMonitorV2 + + + + MainSource + + +
Form32
+ fmx +
+ + + + + + + + + + + + Base + + + Cfg_1 + Base + + + Cfg_2 + Base + +
+ + Delphi.Personality.12 + Application + + + + CreateAsInterfaceFmxDemo.dpr + + + + + True + True + True + False + True + True + True + True + False + True + True + + + 12 + + + + +
diff --git a/Samples/CreateAsInterface/CreateAsInterfaceFmxMain.fmx b/Samples/CreateAsInterface/CreateAsInterfaceFmxMain.fmx new file mode 100644 index 00000000..8693423d --- /dev/null +++ b/Samples/CreateAsInterface/CreateAsInterfaceFmxMain.fmx @@ -0,0 +1,19 @@ +object Form32: TForm32 + Left = 0 + Top = 0 + Caption = 'Skia4Delphi Proposal' + ClientHeight = 366 + ClientWidth = 570 + FormFactor.Width = 320 + FormFactor.Height = 480 + FormFactor.Devices = [Desktop] + DesignerMasterStyle = 0 + object SkPaintBox1: TSkPaintBox + Position.X = 96.000000000000000000 + Position.Y = 48.000000000000000000 + Size.Width = 281.000000000000000000 + Size.Height = 217.000000000000000000 + Size.PlatformDefault = False + OnDraw = SkPaintBox1Draw + end +end diff --git a/Samples/CreateAsInterface/CreateAsInterfaceFmxMain.pas b/Samples/CreateAsInterface/CreateAsInterfaceFmxMain.pas new file mode 100644 index 00000000..96250cbf --- /dev/null +++ b/Samples/CreateAsInterface/CreateAsInterfaceFmxMain.pas @@ -0,0 +1,38 @@ +unit CreateAsInterfaceFmxMain; + +interface + +uses + System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, + FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, + System.Skia, FMX.Skia, FMX.Controls.Presentation, FMX.StdCtrls; + +type + TForm32 = class(TForm) + SkPaintBox1: TSkPaintBox; + procedure SkPaintBox1Draw(ASender: TObject; const ACanvas: ISkCanvas; + const ADest: TRectF; const AOpacity: Single); + private + { Private declarations } + public + { Public declarations } + end; + +var + Form32: TForm32; + +implementation + +{$R *.fmx} + +procedure TForm32.SkPaintBox1Draw(ASender: TObject; + const ACanvas: ISkCanvas; const ADest: TRectF; const AOpacity: Single); +begin + var family := TSkTypeface.MakeFromName('Segoe Script', TSkFontStyle.Italic); + var font := TSkFont.Make(family, 24); + var paint := TSkPaint.Make(); + paint.Color := TAlphaColors.Blueviolet; + ACanvas.DrawSimpleText('.Make',2,30,font,paint) +end; + +end. diff --git a/Samples/CreateAsInterface/CreateAsInterfaceVclDemo.dpr b/Samples/CreateAsInterface/CreateAsInterfaceVclDemo.dpr new file mode 100644 index 00000000..9af7c954 --- /dev/null +++ b/Samples/CreateAsInterface/CreateAsInterfaceVclDemo.dpr @@ -0,0 +1,17 @@ +program CreateAsInterfaceVclDemo; + +uses + Vcl.Forms, + CreateAsInterfaceVclMain in 'CreateAsInterfaceVclMain.pas' {SkIntfDemoMain}, + System.Skia.API in '..\..\Source\System.Skia.API.pas', + System.Skia in '..\..\Source\System.Skia.pas', + Vcl.Skia in '..\..\Source\VCL\Vcl.Skia.pas'; + +{$R *.res} + +begin + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.CreateForm(TSkIntfDemoMain, SkIntfDemoMain); + Application.Run; +end. diff --git a/Samples/CreateAsInterface/CreateAsInterfaceDemo.dproj b/Samples/CreateAsInterface/CreateAsInterfaceVclDemo.dproj similarity index 95% rename from Samples/CreateAsInterface/CreateAsInterfaceDemo.dproj rename to Samples/CreateAsInterface/CreateAsInterfaceVclDemo.dproj index 5f45c885..050460e0 100644 --- a/Samples/CreateAsInterface/CreateAsInterfaceDemo.dproj +++ b/Samples/CreateAsInterface/CreateAsInterfaceVclDemo.dproj @@ -4,10 +4,10 @@ Application Debug VCL - CreateAsInterfaceDemo.dpr + CreateAsInterfaceVclDemo.dpr Win32 {FCB99591-6739-45CE-9331-E46C62D778C0} - CreateAsInterfaceDemo + CreateAsInterfaceVclDemo 20.3 3
@@ -59,7 +59,7 @@ true
- CreateAsInterfaceDemo + CreateAsInterfaceVclDemo .\$(Platform)\$(Config) .\$(Platform)\$(Config) System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) @@ -116,10 +116,13 @@ MainSource - +
SkIntfDemoMain
dfm
+ + + Base @@ -139,7 +142,7 @@ - CreateAsInterfaceDemo.dpr + CreateAsInterfaceVclDemo.dpr diff --git a/Samples/CreateAsInterface/CreateAsInterfaceMain.dfm b/Samples/CreateAsInterface/CreateAsInterfaceVclMain.dfm similarity index 100% rename from Samples/CreateAsInterface/CreateAsInterfaceMain.dfm rename to Samples/CreateAsInterface/CreateAsInterfaceVclMain.dfm diff --git a/Samples/CreateAsInterface/CreateAsInterfaceMain.pas b/Samples/CreateAsInterface/CreateAsInterfaceVclMain.pas similarity index 68% rename from Samples/CreateAsInterface/CreateAsInterfaceMain.pas rename to Samples/CreateAsInterface/CreateAsInterfaceVclMain.pas index c9b7bd93..2613c33a 100644 --- a/Samples/CreateAsInterface/CreateAsInterfaceMain.pas +++ b/Samples/CreateAsInterface/CreateAsInterfaceVclMain.pas @@ -1,12 +1,10 @@ -unit CreateAsInterfaceMain; +unit CreateAsInterfaceVclMain; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, - Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Skia, Vcl.Skia, - System.Types, - System.UITypes; + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Skia, Vcl.Skia, System.Types, System.UITypes; type TSkIntfDemoMain = class(TForm) @@ -29,11 +27,10 @@ implementation procedure TSkIntfDemoMain.SkPaintBox1Draw(ASender: TObject; const ACanvas: ISkCanvas; const ADest: TRectF; const AOpacity: Single); begin - // Much better! - var font := TSkFont.CreateAsInterface(nil, 24); - var paint := TSkPaint.CreateAsInterface(); + var font := TSkFont.Make(nil, 24); + var paint := TSkPaint.Make(); paint.Color := TAlphaColors.Blueviolet; - ACanvas.DrawSimpleText('CreateAsInterface!',2,30,font,paint) + ACanvas.DrawSimpleText('.Make!',2,30,font,paint) end; end. diff --git a/Samples/CreateAsInterface/CreateAsInterfaces.groupproj b/Samples/CreateAsInterface/CreateAsInterfaces.groupproj new file mode 100644 index 00000000..ddae1e6d --- /dev/null +++ b/Samples/CreateAsInterface/CreateAsInterfaces.groupproj @@ -0,0 +1,48 @@ + + + {36AB3BD2-8480-405E-9C0C-C24E62C7DB4F} + + + + + + + + + + + Default.Personality.12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/CreateAsInterface/readme.md b/Samples/CreateAsInterface/readme.md index e2360e2b..59fbdcbe 100644 --- a/Samples/CreateAsInterface/readme.md +++ b/Samples/CreateAsInterface/readme.md @@ -1,7 +1,9 @@ -# Skia4Delphi `CreateAsInterface` Proposal & Demo +# Skia4Delphi Proposal & Demo to CreateAsInterface with `.Make` Most of the Skia API is exposed as interfaces. This takes advantage of reference counting, which is nice to have. Usually, the class has limited public methods and most functionality is exposed through the interface. Here is the declaration for `TSkPaint` and `ISkPaint` for example. +**Update:** Changed the proposed method name to **`.Make`** instead of *`.CreateAsInterface`* per [viniciusfbb suggestion](https://github.com/skia4delphi/skia4delphi/pull/408#issuecomment-2787132333). + ```Delphi type { ISkPaint } @@ -64,11 +66,11 @@ begin end; ``` -The proposed `CreateAsInterace` methods fix this: +The proposed `.Make` methods fix this: ```Delphi begin - var better := TSkPaint.CreateAsInterface(); + var better := TSkPaint.Make(); better.Color := TAlphaColors.Darkorange; end; ``` @@ -83,39 +85,62 @@ public end; ``` -Making them a `class function` named `CreateAsInterface` with the same arguments, and returning the `interface`: +Making as a `class function` with the name `Make` using the same arguments, and returning the `interface`. Finally `deprictate` the constructor. ```Delphi public - class function CreateAsInterface: ISkPaint; overload; - class function CreateAsInterface(const APaint: ISkPaint): ISkPaint; overload; - class function CreateAsInterface(const AStyle: TSkPaintStyle): ISkPaint; overload; + class function Make: ISkPaint; overload; static; + class function Make(const AStyle: TSkPaintStyle): ISkPaint; overload; static; + class function MakeCopy(const APaint: ISkPaint): ISkPaint; static; + constructor Create; overload; deprecated 'Use TSkPaint.Make instead.'; + constructor Create(const APaint: ISkPaint); overload; deprecated 'Use TSkPaint.MakeCopy instead.'; + constructor Create(const AStyle: TSkPaintStyle); overload; deprecated 'Use TSkPaint.Make instead.'; end; ``` -Any name could be used (`Init`, `AsInterface`, `George`, etc.), but this one makes them very visible in class completion to aid in discovery. - -The implementation just calls the existing constructors, but since the Result is explicitly the Interface, this works as expected: +The implementation calls the existing constructors, but since `Result` is explicitly the Interface, the code works as expected: ```Delphi implementation { TSkPaint } -class function TSkPaint.CreateAsInterface: ISkPaint; +class function TSkPaint.Make: ISkPaint; begin Result := TSkPaint.Create(); end; -class function TSkPaint.CreateAsInterface(const APaint: ISkPaint): ISkPaint; +class function TSkPaint.MakeCopy(const APaint: ISkPaint): ISkPaint; begin Result := TSkPaint.Create(APaint); end; -class function TSkPaint.CreateAsInterface(const AStyle: TSkPaintStyle): ISkPaint; +class function TSkPaint.Make(const AStyle: TSkPaintStyle): ISkPaint; begin Result := TSkPaint.Create(AStyle); end; ``` Type inference is as preferable. Beyond less typing it makes code more maintainable (type only needs to be changed in one place) and reduces errors resulting from mismatched types and constructors. The easier it is to take advantage of this feature in Delphi the better. + +## Modified classes + +* TSkColorFilter - For color transformations +* TSkFont - Font rendering and text metrics handling +* TSkPaint - Graphics styling configuration including colors, strokes, and effects +* TSkParagraphBuilder - A builder class for creating formatted text paragraphs with advanced text layout features like styles, fonts, and text decorations +* TSkParagraphStyle - Styling configuration for paragraph layouts +* TSkPath - Vector path definition and manipulation +* TSkPathBuilder - Used for building paths incrementally +* TSkPathMeasure - For measuring and extracting information about paths +* TSkPictureRecorder - Used for recording drawing commands +* TSkPixmap - For pixel buffer access +* TSkRegion - Represents a 2D set of pixels for clipping or hit-testing +* TSkRoundRect - Used for rounded rectangles +* TSkRuntimeBlenderBuilder - A builder class for creating custom blend modes at runtime, enabling custom pixel blending operations +* TSkRuntimeShaderBuilder - A builder class for creating custom shaders at runtime, allowing dynamic generation of graphical effects and patterns +* TSkShaper - Text shaping engine for complex script rendering +* TSkString - String handling utilities for Skia +* TSkStrutStyle - Text layout configuration for line spacing and alignment +* TSkTextStyle - Text styling configuration for paragraphs +* TSkUnicode - Unicode text processing and manipulation utilities for international text handling diff --git a/Source/FMX/FMX.Skia.Canvas.pas b/Source/FMX/FMX.Skia.Canvas.pas index 03da75cf..58f76ee7 100644 --- a/Source/FMX/FMX.Skia.Canvas.pas +++ b/Source/FMX/FMX.Skia.Canvas.pas @@ -1869,7 +1869,7 @@ function TSkCanvasCustom.BeginPaintWithBrush(const ABrush: TBrush; ABrushData.Brush := ABrushData.Brush.Resource.Brush; if (ABrushData.Brush = nil) or (ABrushData.Brush.Kind = TBrushKind.None) then Exit(nil); - ABrushData.Paint := TSkPaint.Create(TSkPaintStyle.Fill); + ABrushData.Paint := TSkPaint.Make(TSkPaintStyle.Fill); BeginPaint(ARect, AOpacity, ABrushData); Result := TSkPaint(ABrushData.Paint); end; @@ -1896,8 +1896,8 @@ function TSkCanvasCustom.BeginPaintWithStrokeBrush(const ABrush: TStrokeBrush; end; if (ABrushData.Brush = nil) or (ABrushData.Brush.Kind = TBrushKind.None) or (SameValue(LFinalStrokeBrush.Thickness, 0, TEpsilon.Position)) then Exit(nil); - ABrushData.Paint := TSkPaint.Create(TSkPaintStyle.Stroke); - BeginPaint(ARect, AOpacity, ABrushData); + ABrushData.Paint := TSkPaint.Make(TSkPaintStyle.Stroke); + BeginPaint(ARect, AOpacity, ABrushData); ABrushData.Paint.StrokeCap := StrokeCap[LFinalStrokeBrush.Cap]; ABrushData.Paint.StrokeJoin := StrokeJoin[LFinalStrokeBrush.Join]; ABrushData.Paint.StrokeWidth := LFinalStrokeBrush.Thickness; @@ -1976,7 +1976,7 @@ function TSkCanvasCustom.DoBeginScene({$IF CompilerVersion < 35}const {$ENDIF}AC begin if Length(AClipRects) > 1 then begin - LPathBuilder := TSkPathBuilder.Create; + LPathBuilder := TSkPathBuilder.Make; for I := 0 to Length(AClipRects) - 1 do LPathBuilder.AddRect(AClipRects[I]); ACanvas.ClipPath(LPathBuilder.Snapshot, TSkClipOp.Intersect, True); @@ -2036,7 +2036,7 @@ procedure TSkCanvasCustom.DoDrawBitmap(const ABitmap: FMX.Graphics.TBitmap; LSrcRect := ASrcRect * TRectF.Create(0, 0, ABitmap.Width, ABitmap.Height); if ABitmap.HandleAllocated and (not LSrcRect.IsEmpty) and (not ADestRect.IsEmpty) then begin - LPaint := TSkPaint.Create; + LPaint := TSkPaint.Make; LPaint.AlphaF := AOpacity; {$IFDEF MODULATE_CANVAS} if FModulateColor <> TAlphaColors.White then @@ -2301,7 +2301,7 @@ function TSkCanvasCustom.PtInPath(const APoint: TPointF; LPaint: ISkPaint; LPath: ISkPath; begin - LPaint := TSkPaint.Create; + LPaint := TSkPaint.Make; LPath := LPaint.GetFillPath(APath.ToSkPath); Result := (LPath <> nil) and (LPath.Contains(APoint.X, APoint.Y)); end; @@ -3400,7 +3400,7 @@ procedure TSkTextLayout.UpdateParagraph; function CreateTextStyle(const AAttribute: TTextAttribute): ISkTextStyle; begin - Result := TSkTextStyle.Create; + Result := TSkTextStyle.Make; if AAttribute.Font <> nil then InitializeTextStyle(Result, AAttribute.Font, AAttribute.Color) else @@ -3409,7 +3409,7 @@ procedure TSkTextLayout.UpdateParagraph; function CreateDefaultTextStyle: ISkTextStyle; begin - Result := TSkTextStyle.Create; + Result := TSkTextStyle.Make; InitializeTextStyle(Result, Font, Color); end; @@ -3421,7 +3421,7 @@ procedure TSkTextLayout.UpdateParagraph; LAttribute: TTextAttributedRange; LMinFontSize: Single; begin - Result := TSkParagraphStyle.Create; + Result := TSkParagraphStyle.Make; if RightToLeft then Result.TextDirection := TSkTextDirection.RightToLeft; if Trimming in [TTextTrimming.Character, TTextTrimming.Word] then @@ -3492,8 +3492,8 @@ procedure TSkTextLayout.UpdateParagraph; FOpacity := Opacity; LAttributes := GetNormalizedAttributes(ASubText, ASubTextPosition); try - LBuilder := TSkParagraphBuilder.Create(CreateParagraphStyle(LAttributes, AMaxLines), - TSkDefaultProviders.TypefaceFont); + LBuilder := TSkParagraphBuilder.Make(CreateParagraphStyle(LAttributes, AMaxLines), + TSkDefaultProviders.TypefaceFont); LLastAttributeEndIndex := 0; for LAttribute in LAttributes do begin @@ -3668,7 +3668,7 @@ function TSkTextLayout.TGraphemesMap.CreateGraphemesMapping( SetLength(Result, Length(AText) + 1); if AText <> '' then begin - LUnicode := TSkUnicode.Create; + LUnicode := TSkUnicode.Make; LGraphemesIterator := LUnicode.GetBreakIterator(TSkBreakType.Graphemes, AText); LGraphemesIterator.MoveNext; I := 0; diff --git a/Source/FMX/FMX.Skia.pas b/Source/FMX/FMX.Skia.pas index cec0b3b6..c1450934 100644 --- a/Source/FMX/FMX.Skia.pas +++ b/Source/FMX/FMX.Skia.pas @@ -1459,7 +1459,7 @@ procedure DrawDesignBorder(const ACanvas: ISkCanvas; ADest: TRectF; const AOpaci var LPaint: ISkPaint; begin - LPaint := TSkPaint.Create(TSkPaintStyle.Stroke); + LPaint := TSkPaint.Make(TSkPaintStyle.Stroke); LPaint.Color := DesignBorderColor; LPaint.AlphaF := AOpacity; LPaint.StrokeWidth := 1; @@ -1714,7 +1714,7 @@ function TSkPathDataHelper.ToSkPath: ISkPath; I: Integer; LPathBuilder: ISkPathBuilder; begin - LPathBuilder := TSkPathBuilder.Create(TSkPathFillType.EvenOdd); + LPathBuilder := TSkPathBuilder.Make(TSkPathFillType.EvenOdd); I := 0; while I < Count do begin @@ -2346,22 +2346,22 @@ procedure TSkSvgBrush.Render(const ACanvas: ISkCanvas; const ADestRect: TRectF; LCanvas: ISkCanvas; LPaint: ISkPaint; begin - LPictureRecorder := TSkPictureRecorder.Create; + LPictureRecorder := TSkPictureRecorder.Make; LCanvas := LPictureRecorder.BeginRecording(AWrappedDest.Width, AWrappedDest.Height); if AIntrinsicSize.IsZero then begin if AWrapMode <> TSkSvgWrapMode.Default then begin LCanvas.Scale(AWrappedDest.Width / ASvgRect.Width, AWrappedDest.Height / ASvgRect.Height); - ADOM.Root.Width := TSkSVGLength.Create(ASvgRect.Width, TSkSVGLengthUnit.Pixel); + ADOM.Root.Width := TSkSVGLength.Create(ASvgRect.Width, TSkSVGLengthUnit.Pixel); ADOM.Root.Height := TSkSVGLength.Create(ASvgRect.Height, TSkSVGLengthUnit.Pixel); end; end else LCanvas.Scale(AWrappedDest.Width / ASvgRect.Width, AWrappedDest.Height / ASvgRect.Height); ADOM.Render(LCanvas); - LPicture := LPictureRecorder.FinishRecording; - LPaint := TSkPaint.Create; + LPicture := LPictureRecorder.FinishRecording; + LPaint := TSkPaint.Make; if FGrayScale then LPaint.ColorFilter := TSkColorFilter.MakeMatrix(TSkColorMatrix.CreateSaturation(0)) else if FOverrideColor <> TAlphaColors.Null then @@ -3782,7 +3782,7 @@ procedure TSkDefaultAnimationCodec.Render(const ACanvas: ISkCanvas; LPaint := nil else begin - LPaint := TSkPaint.Create; + LPaint := TSkPaint.Make; LPaint.AlphaF := AOpacity; end; case Quality of @@ -5401,9 +5401,9 @@ procedure TSkLabel.Draw(const ACanvas: ISkCanvas; const ADest: TRectF; LLastRect: TRectF; LLastColor: TAlphaColor; begin - LPictureRecorder := TSkPictureRecorder.Create; + LPictureRecorder := TSkPictureRecorder.Make; LCanvas := LPictureRecorder.BeginRecording(ADest); - LPaint := TSkPaint.Create; + LPaint := TSkPaint.Make; LPaint.AntiAlias := True; LTextEndIndex := 0; LRects := nil; @@ -5673,7 +5673,7 @@ function TSkLabel.GetParagraph: ISkParagraph; begin if (ADecorations.StrokeColor <> TAlphaColors.Null) and not SameValue(ADecorations.Thickness, 0, TEpsilon.Position) then begin - LPaint := TSkPaint.Create(TSkPaintStyle.Stroke); + LPaint := TSkPaint.Make(TSkPaintStyle.Stroke); LPaint.Color := ADecorations.StrokeColor; LPaint.StrokeWidth := (ADecorations.Thickness / 2) * (ATextStyle.FontSize / 14); ATextStyle.SetForegroundColor(LPaint); @@ -5690,7 +5690,7 @@ function TSkLabel.GetParagraph: ISkParagraph; const ADefaultTextStyle: ISkTextStyle; const ADrawKind: TDrawKind): ISkTextStyle; begin - Result := TSkTextStyle.Create; + Result := TSkTextStyle.Make; if TStyledSetting.FontColor in AWordsItem.StyledSettings then Result.Color := ResultingTextSettings.FontColor else @@ -5725,7 +5725,7 @@ function TSkLabel.GetParagraph: ISkParagraph; function CreateDefaultTextStyle(const ADrawKind: TDrawKind): ISkTextStyle; begin - Result := TSkTextStyle.Create; + Result := TSkTextStyle.Make; Result.Color := ResultingTextSettings.FontColor; Result.FontFamilies := GetFontFamilies(ResultingTextSettings.Font.Families); Result.FontSize := GetFontSize(ResultingTextSettings.Font.Size); @@ -5741,7 +5741,7 @@ function TSkLabel.GetParagraph: ISkParagraph; const SkTextAlign: array[TSkTextHorzAlign] of TSkTextAlign = (TSkTextAlign.Center, TSkTextAlign.Start, TSkTextAlign.Terminate, TSkTextAlign.Justify); begin - Result := TSkParagraphStyle.Create; + Result := TSkParagraphStyle.Make; FLastFillTextFlags := FillTextFlags; if TFillTextFlag.RightToLeft in FLastFillTextFlags then Result.TextDirection := TSkTextDirection.RightToLeft; @@ -5764,7 +5764,7 @@ function TSkLabel.GetParagraph: ISkParagraph; begin LFontBehavior := nil; LDefaultTextStyle := CreateDefaultTextStyle(ADrawKind); - LBuilder := TSkParagraphBuilder.Create(CreateParagraphStyle(LDefaultTextStyle), TSkDefaultProviders.TypefaceFont); + LBuilder := TSkParagraphBuilder.Make(CreateParagraphStyle(LDefaultTextStyle), TSkDefaultProviders.TypefaceFont); for I := 0 to FWords.Count- 1 do begin if FWords[I].Text = '' then diff --git a/Source/System.Skia.pas b/Source/System.Skia.pas index ac242d49..fa9c1bef 100644 --- a/Source/System.Skia.pas +++ b/Source/System.Skia.pas @@ -1742,10 +1742,10 @@ TSkFont = class(TSkObject, ISkFont) function UnicharsToGlyphs(const AUnichars: TArray): TArray; class procedure path_proc(const path: sk_path_t; const matrix: psk_matrix_t; context: Pointer); cdecl; static; public - constructor Create(ATypeface: ISkTypeface = nil; const ASize: Single = 12; const AScaleX: Single = 1; const ASkewX: Single = 0); overload; - constructor Create(const AFont: ISkFont); overload; - class function CreateAsInterface(ATypeface: ISkTypeface = nil; const ASize: Single = 12; const AScaleX: Single = 1; const ASkewX: Single = 0): ISkFont; overload; - class function CreateAsInterface(const AFont: ISkFont): ISkFont; overload; + constructor Create(ATypeface: ISkTypeface = nil; const ASize: Single = 12; const AScaleX: Single = 1; const ASkewX: Single = 0); overload; deprecated 'Use TSkFont.Make instead.'; + constructor Create(const AFont: ISkFont); overload; deprecated 'Use TSkFont.Make instead.'; + class function Make(ATypeface: ISkTypeface = nil; const ASize: Single = 12; const AScaleX: Single = 1; const ASkewX: Single = 0): ISkFont; overload; + class function MakeCopy(const AFont: ISkFont): ISkFont; overload; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2059,14 +2059,14 @@ TSkPaint = class(TSkObject, ISkPaint) procedure SetStrokeJoin(const AValue: TSkStrokeJoin); procedure SetStrokeMiter(const AValue: Single); procedure SetStrokeWidth(const AValue: Single); - procedure SetStyle(const AValue: TSkPaintStyle); - public - constructor Create; overload; - constructor Create(const APaint: ISkPaint); overload; - constructor Create(const AStyle: TSkPaintStyle); overload; - class function CreateAsInterface: ISkPaint; overload; - class function CreateAsInterface(const APaint: ISkPaint): ISkPaint; overload; - class function CreateAsInterface(const AStyle: TSkPaintStyle): ISkPaint; overload; + procedure SetStyle(const AValue: TSkPaintStyle); + public + constructor Create; overload; deprecated 'Use TSkPaint.Make instead.'; + constructor Create(const APaint: ISkPaint); overload; deprecated 'Use TSkPaint.MakeCopy instead.'; + constructor Create(const AStyle: TSkPaintStyle); overload; deprecated 'Use TSkPaint.Make instead.'; + class function Make: ISkPaint; overload; + class function MakeCopy(const APaint: ISkPaint): ISkPaint; overload; + class function Make(const AStyle: TSkPaintStyle): ISkPaint; overload; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2182,11 +2182,14 @@ TPathIterator = class(TSkEnumerable, ISkPathIterator) procedure SerializeToStream(const AStream: TStream); function ToSVG: string; function Transform(const AMatrix: TMatrix): ISkPath; - public - constructor Create(const ASVG: string); overload; - constructor Create(const ABytes: TBytes); overload; - constructor Create(const AStream: TStream); overload; - class function ConvertConicToQuads(const APoint1, APoint2, APoint3: TPointF; const AWeight: Single; const APower2: Integer): TArray; static; + public + constructor Create(const ASVG: string); overload; deprecated 'Use TSkPath.Make instead.'; + constructor Create(const ABytes: TBytes); overload; deprecated 'Use TSkPath.Make instead.'; + constructor Create(const AStream: TStream); overload; deprecated 'Use TSkPath.Make instead.'; + class function Make(const AStream: TStream): ISkPath; overload; + class function Make(const ASVG: string): ISkPath; overload; + class function Make(const ABytes: TBytes): ISkPath; overload; + class function ConvertConicToQuads(const APoint1, APoint2, APoint3: TPointF; const AWeight: Single; const APower2: Integer): TArray; static; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2246,7 +2249,7 @@ TPathIterator = class(TSkEnumerable, ISkPathIterator) { TSkPathBuilder } - TSkPathBuilder = class(TSkObject, ISkPathBuilder) + TSkPathBuilder = class(TSkObject, ISkPathBuilder) strict private procedure AddArc(const AOval: TRectF; const AStartAngle, ASweepAngle: Single); procedure AddCircle(const ACenter: TPointF; ARadius: Single; ADirection: TSkPathDirection = TSkPathDirection.CW); overload; @@ -2293,9 +2296,12 @@ TSkPathBuilder = class(TSkObject, ISkPathBuilder) function Snapshot: ISkPath; procedure ToggleInverseFillType; public - constructor Create; overload; - constructor Create(const APathBuilder: ISkPathBuilder); overload; - constructor Create(const AFillType: TSkPathFillType); overload; + constructor Create; overload; deprecated 'Use TSkPathBuilder.Make instead.'; + constructor Create(const APathBuilder: ISkPathBuilder); overload; deprecated 'Use TSkPathBuilder.MakeCopy instead.'; + constructor Create(const AFillType: TSkPathFillType); overload; deprecated 'Use TSkPathBuilder.Make instead.'; + class function Make: ISkPathBuilder; overload; static; + class function MakeCopy(const APathBuilder: ISkPathBuilder): ISkPathBuilder; static; + class function Make(const AFillType: TSkPathFillType): ISkPathBuilder; overload; static; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2351,7 +2357,8 @@ TSkPathMeasure = class(TSkObject, ISkPathMeasure) function IsClosed: Boolean; function NextContour: Boolean; public - constructor Create(const APath: ISkPath; const AForceClosed: Boolean = False; const AResScale: Single = 1); + class function Make(const APath: ISkPath; const AForceClosed: Boolean = False; const AResScale: Single = 1): ISkPathMeasure; + constructor Create(const APath: ISkPath; const AForceClosed: Boolean = False; const AResScale: Single = 1); deprecated 'Use TSkPathMeasure.Make instead.'; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2413,7 +2420,8 @@ TSkPictureRecorder = class(TSkObject, ISkPictureRecorder) function FinishRecording: ISkPicture; overload; function FinishRecording(const ACullRect: TRectF): ISkPicture; overload; public - constructor Create; + constructor Create; overload; deprecated 'Use TSkPictureRecorder.Make instead.'; + class function Make: ISkPictureRecorder; static; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2490,7 +2498,8 @@ TSkPixmap = class(TSkObject, ISkPixmap) function ScalePixels(const ADestImageInfo: TSkImageInfo; const ADestPixels: Pointer; const ADestRowBytes: NativeUInt; const ASampling: TSkSamplingOptions): Boolean; overload; procedure SetColorSpace(AValue: ISkColorSpace); public - constructor Create(const AImageInfo: TSkImageInfo; const APixels: Pointer; const ARowBytes: NativeUInt); + constructor Create(const AImageInfo: TSkImageInfo; const APixels: Pointer; const ARowBytes: NativeUInt); deprecated 'Use TSkPixmap.Make instead.'; + class function Make(const AImageInfo: TSkImageInfo; const APixels: Pointer; const ARowBytes: NativeUInt): ISkPixmap; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2611,9 +2620,12 @@ TRegionSpanerator = class(TSkEnumerable, ISkRegionSpanerator) function SetRects(const ARects: TArray): Boolean; procedure Translate(const ADeltaX, ADeltaY: Integer); public - constructor Create; overload; - constructor Create(const ARegion: ISkRegion); overload; - constructor Create(const ARect: TRect); overload; + constructor Create; overload; deprecated 'Use TSkRegion.Make instead.'; + constructor Create(const ARegion: ISkRegion); overload; deprecated 'Use TSkRegion.MakeCopy instead.'; + constructor Create(const ARect: TRect); overload; deprecated 'Use TSkRegion.Make instead.'; + class function Make: ISkRegion; overload; static; + class function MakeCopy(const ARegion: ISkRegion): ISkRegion; static; + class function Make(const ARect: TRect): ISkRegion; overload; static; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2680,15 +2692,19 @@ TSkRoundRect = class(TSkObject, ISkRoundRect) procedure SetOval(const ARect: TRectF); procedure SetRect(const ARect: TRectF); overload; procedure SetRect(const ARect: TRectF; const ARadiusX, ARadiusY: Single); overload; - procedure SetRect(const ARect: TRectF; const ARadii: TSkRoundRectRadii); overload; - function Transform(const AMatrix: TMatrix): ISkRoundRect; - public - constructor Create; overload; - constructor Create(const ARoundRect: ISkRoundRect); overload; - constructor Create(const ARect: TRectF; const ARadiusX, ARadiusY: Single); overload; - constructor Create(const ARect: TRectF; const ARadii: TSkRoundRectRadii); overload; - class procedure __DestroyHandle(const AHandle: sk_handle_t); override; - end; + procedure SetRect(const ARect: TRectF; const ARadii: TSkRoundRectRadii); overload; + function Transform(const AMatrix: TMatrix): ISkRoundRect; + public + constructor Create; overload; deprecated 'Use TSkRoundRect.Make instead'; + constructor Create(const ARect: TRectF; const ARadiusX, ARadiusY: Single); overload; deprecated 'Use TSkRoundRect.Make instead'; + constructor Create(const ARoundRect: ISkRoundRect); overload; deprecated 'Use TSkRoundRect.Make instead'; + constructor Create(const ARect: TRectF; const ARadii: TSkRoundRectRadii); overload; deprecated 'Use TSkRoundRect.Make instead'; + class function Make: ISkRoundRect; overload; static; + class function Make(const ARect: TRectF; const ARadiusX, ARadiusY: Single): ISkRoundRect; overload; static; + class function Make(const ARoundRect: ISkRoundRect): ISkRoundRect; overload; static; + class function Make(const ARect: TRectF; const ARadii: TSkRoundRectRadii): ISkRoundRect; overload; static; + class procedure __DestroyHandle(const AHandle: sk_handle_t); override; + end; {$HPPEMIT END '#define SkRoundRect(...) __SkCreate(TSkRoundRect, ISkRoundRect, __VA_ARGS__)'} @@ -2866,11 +2882,12 @@ TSkRuntimeBlenderBuilder = class(TSkRuntimeEffectBuilder, ISkRuntimeBlenderBui strict private function MakeBlender: ISkBlender; public - constructor Create(const AEffect: ISkRuntimeEffect); + constructor Create(const AEffect: ISkRuntimeEffect); + class function Make(const AEffect: ISkRuntimeEffect): ISkRuntimeBlenderBuilder; static; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; - {$HPPEMIT END '#define SkRuntimeBlenderBuilder(...) __SkCreate(TSkRuntimeBlenderBuilder, ISkRuntimeBlenderBuilder, __VA_ARGS__)'} + {$HPPEMIT END '#define SkRuntimeBlenderBuilder(...) __SkCreate(TSkRuntimeBlenderBuilder, ISkRuntimeBlenderBuilder, __VA_ARGS__)'} { ISkRuntimeShaderBuilder } @@ -2892,6 +2909,7 @@ TSkRuntimeShaderBuilder = class(TSkRuntimeEffectBuilder, ISkRuntimeShaderBuild function MakeShader(const ALocalMatrix: TMatrix): ISkShader; overload; public constructor Create(const AEffect: ISkRuntimeEffect); + class function Make(const AEffect: ISkRuntimeEffect): ISkRuntimeShaderBuilder; static; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -3311,8 +3329,10 @@ TSkParagraphBuilder = class(TSkObject, ISkParagraphBuilder) procedure Pop; procedure PushStyle(const ATextStyle: ISkTextStyle); public - constructor Create(const AParagraphStyle: ISkParagraphStyle); overload; - constructor Create(const AParagraphStyle: ISkParagraphStyle; const AFontProvider: ISkTypefaceFontProvider; const AEnableFontFallback: Boolean = True); overload; + constructor Create(const AParagraphStyle: ISkParagraphStyle); overload; deprecated 'Use TSkParagraphBuilder.Make instead'; + constructor Create(const AParagraphStyle: ISkParagraphStyle; const AFontProvider: ISkTypefaceFontProvider; const AEnableFontFallback: Boolean = True); overload; deprecated 'Use TSkParagraphBuilder.Make instead'; + class function Make(const AParagraphStyle: ISkParagraphStyle): ISkParagraphBuilder; overload; static; + class function Make(const AParagraphStyle: ISkParagraphStyle; const AFontProvider: ISkTypefaceFontProvider; const AEnableFontFallback: Boolean = True): ISkParagraphBuilder; overload; static; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -3371,7 +3391,8 @@ TSkStrutStyle = class(TSkObject, ISkStrutStyle) procedure SetHeightMultiplier(const AValue: Single); procedure SetLeading(const AValue: Single); public - constructor Create; + constructor Create; overload; deprecated 'Use TSkStrutStyle.Make instead'; + class function Make: ISkStrutStyle; static; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -3430,7 +3451,8 @@ TSkParagraphStyle = class(TSkObject, ISkParagraphStyle) procedure SetTextHeightBehaviors(const AValue: TSkTextHeightBehaviors); procedure SetTextStyle(AValue: ISkTextStyle); public - constructor Create; + constructor Create; deprecated 'Use TSkParagraphStyle.Make instead'; + class function Make: ISkParagraphStyle; static; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -3537,7 +3559,8 @@ TSkTextStyle = class(TSkObject, ISkTextStyle) procedure SetLocale(const AValue: string); procedure SetWordSpacing(const AValue: Single); public - constructor Create; + constructor Create; deprecated 'Use TSkTextStyle.Make instead'; + class function Make: ISkTextStyle; static; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -3615,7 +3638,8 @@ TSkShaper = class(TSkObject, ISkShaper) function Shape(const AText: string; const AFont: ISkFont; const ALeftToRight: Boolean; const AWidth: Single): ISkTextBlob; overload; function Shape(const AText: string; const AFont: ISkFont; const ALeftToRight: Boolean; const AWidth: Single; const AOffset: TPointF; out AEndPoint: TPointF): ISkTextBlob; overload; public - constructor Create; + constructor Create; deprecated 'Use TSkShaper.Make instead'; + class function Make: ISkShaper; static; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -3762,7 +3786,8 @@ TUnicodeBreakIterator = class(TSkEnumerable, IS class procedure break_proc(position, status: int32_t; context: Pointer); cdecl; static; class procedure codepoint_proc(unichar: sk_unichar_t; start, &end: int32_t; context: Pointer); cdecl; static; public - constructor Create; + constructor Create; deprecated 'Use Make instead'; + class function Make: ISkUnicode; static; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -3997,7 +4022,8 @@ TSkString = class(TSkObject, ISkString) strict private function GetText: string; public - constructor Create; + constructor Create; deprecated 'Use Make instead'; + class function Make: ISkString; static; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -5059,7 +5085,7 @@ constructor TSkFrame.Create(const AImageInfo: TSkImageInfo; const APixels: Pointer; const ARowBytes: NativeUInt; const ADuration: Integer); begin - Pixmap := TSkPixmap.Create(AImageInfo, APixels, ARowBytes); + Pixmap := TSkPixmap.Make(AImageInfo, APixels, ARowBytes); Duration := ADuration; end; @@ -5149,7 +5175,7 @@ class function TSkImageEncoder.Encode(const ASrcImageInfo: TSkImageInfo; var LPixmap: ISkPixmap; begin - LPixmap := TSkPixmap.Create(ASrcImageInfo, ASrcPixels, ASrcRowBytes); + LPixmap := TSkPixmap.Make(ASrcImageInfo, ASrcPixels, ASrcRowBytes); Result := Encode(LPixmap, AEncodedImageFormat, AQuality); end; @@ -5185,7 +5211,7 @@ class function TSkImageEncoder.EncodeToFile(const AFileName: string; var LPixmap: ISkPixmap; begin - LPixmap := TSkPixmap.Create(ASrcImageInfo, ASrcPixels, ASrcRowBytes); + LPixmap := TSkPixmap.Make(ASrcImageInfo, ASrcPixels, ASrcRowBytes); Result := EncodeToFile(AFileName, LPixmap, AEncodedImageFormat, AQuality); end; @@ -5209,7 +5235,7 @@ class function TSkImageEncoder.EncodeToStream(const AStream: TStream; var LPixmap: ISkPixmap; begin - LPixmap := TSkPixmap.Create(ASrcImageInfo, ASrcPixels, ASrcRowBytes); + LPixmap := TSkPixmap.Make(ASrcImageInfo, ASrcPixels, ASrcRowBytes); Result := EncodeToStream(AStream, LPixmap, AEncodedImageFormat, AQuality); end; @@ -7273,20 +7299,24 @@ constructor TSkFont.Create(ATypeface: ISkTypeface; const ASize, AScaleX, constructor TSkFont.Create(const AFont: ISkFont); begin - if not Assigned(AFont) then - raise ESkArgumentException.CreateFmt(SParamIsNil, ['AFont']); - inherited Create(sk4d_font_create2(AFont.Handle)); + if not Assigned(AFont) then + raise ESkArgumentException.CreateFmt(SParamIsNil, ['AFont']); + inherited Create(sk4d_font_create2(AFont.Handle)); end; -class function TSkFont.CreateAsInterface(const AFont: ISkFont): ISkFont; +class function TSkFont.MakeCopy(const AFont: ISkFont): ISkFont; begin + {$WARN SYMBOL_DEPRECATED OFF} Result := TSkFont.Create(AFont); + {$WARN SYMBOL_DEPRECATED ON} end; -class function TSkFont.CreateAsInterface(ATypeface: ISkTypeface; +class function TSkFont.Make(ATypeface: ISkTypeface; const ASize, AScaleX, ASkewX: Single): ISkFont; begin + {$WARN SYMBOL_DEPRECATED OFF} Result := TSkFont.Create(ATypeface, ASize, AScaleX, ASkewX); + {$WARN SYMBOL_DEPRECATED ON} end; function TSkFont.GetBaselineSnap: Boolean; @@ -7465,8 +7495,10 @@ function TSkFont.IsEqual(const AFont: ISkFont): Boolean; function TSkFont.MakeWithSize(const ASize: Single): ISkFont; begin - Result := TSkFont.Create(Self); - Result.Size := ASize; + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkFont.Create(Self); + Result.Size := ASize; + {$WARN SYMBOL_DEPRECATED ON} end; function TSkFont.MeasureText(const AText: string; out ABounds: TRectF; @@ -7718,7 +7750,7 @@ class function TSkImage.MakeCrossContext(const AContext: IGrDirectContext; var LPixmap: ISkPixmap; begin - LPixmap := TSkPixmap.Create(AImageInfo, APixels, ARowBytes); + LPixmap := TSkPixmap.Make(AImageInfo, APixels, ARowBytes); Result := MakeCrossContext(AContext, LPixmap, ABuildMips, ALimitToMaxTextureSize); end; @@ -7834,7 +7866,7 @@ class function TSkImage.MakeFromRaster(const AImageInfo: TSkImageInfo; var LPixmap: ISkPixmap; begin - LPixmap := TSkPixmap.Create(AImageInfo, APixels, ARowBytes); + LPixmap := TSkPixmap.Make(AImageInfo, APixels, ARowBytes); Result := MakeFromRaster(LPixmap, ARasterReleaseProc); end; @@ -7870,7 +7902,7 @@ class function TSkImage.MakeRasterCopy(const AImageInfo: TSkImageInfo; var LPixmap: ISkPixmap; begin - LPixmap := TSkPixmap.Create(AImageInfo, APixels, ARowBytes); + LPixmap := TSkPixmap.Make(AImageInfo, APixels, ARowBytes); Result := MakeRasterCopy(LPixmap); end; @@ -7987,7 +8019,7 @@ function TSkImage.ReadPixels(const ADestImageInfo: TSkImageInfo; var LPixmap: ISkPixmap; begin - LPixmap := TSkPixmap.Create(ADestImageInfo, ADestPixels, ADestRowBytes); + LPixmap := TSkPixmap.Make(ADestImageInfo, ADestPixels, ADestRowBytes); Result := ReadPixels(LPixmap, ASrcX, ASrcY, ACachingHint, AContext); end; @@ -7998,7 +8030,7 @@ function TSkImage.ScalePixels(const ADestImageInfo: TSkImageInfo; var LPixmap: ISkPixmap; begin - LPixmap := TSkPixmap.Create(ADestImageInfo, ADestPixels, ADestRowBytes); + LPixmap := TSkPixmap.Make(ADestImageInfo, ADestPixels, ADestRowBytes); Result := ScalePixels(LPixmap, ASampling, ACachingHint); end; @@ -8008,7 +8040,7 @@ function TSkImage.ScalePixels(const ADestImageInfo: TSkImageInfo; var LPixmap: ISkPixmap; begin - LPixmap := TSkPixmap.Create(ADestImageInfo, ADestPixels, ADestRowBytes); + LPixmap := TSkPixmap.Make(ADestImageInfo, ADestPixels, ADestRowBytes); Result := ScalePixels(LPixmap, ACachingHint); end; @@ -8050,7 +8082,7 @@ class function TSkImageFilter.MakeAlphaThreshold(const ARegion: TRect; var LRegion: ISkRegion; begin - LRegion := TSkRegion.Create; + LRegion := TSkRegion.Make; LRegion.SetRect(ARegion); Result := MakeAlphaThreshold(LRegion, AInnerMin, AOuterMax, AInput); end; @@ -8550,23 +8582,31 @@ constructor TSkPaint.Create(const APaint: ISkPaint); constructor TSkPaint.Create(const AStyle: TSkPaintStyle); begin - Create; - SetStyle(AStyle); + {$WARN SYMBOL_DEPRECATED OFF} + Create; + SetStyle(AStyle); + {$WARN SYMBOL_DEPRECATED ON} end; -class function TSkPaint.CreateAsInterface: ISkPaint; +class function TSkPaint.Make: ISkPaint; begin - Result := TSkPaint.Create(); + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkPaint.Create(); + {$WARN SYMBOL_DEPRECATED ON} end; -class function TSkPaint.CreateAsInterface(const APaint: ISkPaint): ISkPaint; +class function TSkPaint.MakeCopy(const APaint: ISkPaint): ISkPaint; begin + {$WARN SYMBOL_DEPRECATED OFF} Result := TSkPaint.Create(APaint); + {$WARN SYMBOL_DEPRECATED ON} end; -class function TSkPaint.CreateAsInterface(const AStyle: TSkPaintStyle): ISkPaint; +class function TSkPaint.Make(const AStyle: TSkPaintStyle): ISkPaint; begin + {$WARN SYMBOL_DEPRECATED OFF} Result := TSkPaint.Create(AStyle); + {$WARN SYMBOL_DEPRECATED ON} end; function TSkPaint.GetAlpha: Byte; @@ -8811,19 +8851,21 @@ class function TSkPath.ConvertConicToQuads(const APoint1, APoint2, constructor TSkPath.Create(const ASVG: string); begin - inherited Create(sk4d_path_create(MarshaledAString(MarshaledAString(UTF8String(ASVG))))); + inherited Create(sk4d_path_create(MarshaledAString(MarshaledAString(UTF8String(ASVG))))); end; constructor TSkPath.Create(const ABytes: TBytes); var LStream: TStream; begin - LStream := TBytesStream.Create(ABytes); - try - Create(LStream); - finally - LStream.Free; - end; + {$WARN SYMBOL_DEPRECATED OFF} + LStream := TBytesStream.Create(ABytes); + try + Create(LStream); + finally + LStream.Free; + end; + {$WARN SYMBOL_DEPRECATED ON} end; constructor TSkPath.Create(const AStream: TStream); @@ -8938,10 +8980,33 @@ function TSkPath.IsRoundRect(out ARoundRect: ISkRoundRect): Boolean; var LRoundRect: ISkRoundRect; begin - LRoundRect := TSkRoundRect.Create; - Result := sk4d_path_is_rrect(Handle, TSkBindings.SafeHandle(LRoundRect)); - if Result then - ARoundRect := LRoundRect; + {$WARN SYMBOL_DEPRECATED OFF} + LRoundRect := TSkRoundRect.Create; + {$WARN SYMBOL_DEPRECATED ON} + Result := sk4d_path_is_rrect(Handle, TSkBindings.SafeHandle(LRoundRect)); + if Result then + ARoundRect := LRoundRect; +end; + +class function TSkPath.Make(const AStream: TStream): ISkPath; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkPath.Create(AStream); + {$WARN SYMBOL_DEPRECATED ON} +end; + +class function TSkPath.Make(const ASVG: string): ISkPath; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkPath.Create(ASVG); + {$WARN SYMBOL_DEPRECATED ON} +end; + +class function TSkPath.Make(const ABytes: TBytes): ISkPath; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkPath.Create(ABytes); + {$WARN SYMBOL_DEPRECATED ON} end; function TSkPath.IsRoundRect: Boolean; @@ -9133,8 +9198,10 @@ constructor TSkPathBuilder.Create; constructor TSkPathBuilder.Create(const AFillType: TSkPathFillType); begin - Create; - SetFillType(AFillType); + {$WARN SYMBOL_DEPRECATED OFF} + Create; + {$WARN SYMBOL_DEPRECATED ON} + SetFillType(AFillType); end; constructor TSkPathBuilder.Create(const APathBuilder: ISkPathBuilder); @@ -9190,9 +9257,30 @@ procedure TSkPathBuilder.LineTo(const APoint: TPointF); sk4d_pathbuilder_line_to(Handle, @APoint); end; +class function TSkPathBuilder.Make: ISkPathBuilder; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkPathBuilder.Create; + {$WARN SYMBOL_DEPRECATED ON} +end; + +class function TSkPathBuilder.MakeCopy(const APathBuilder: ISkPathBuilder): ISkPathBuilder; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkPathBuilder.Create(APathBuilder); + {$WARN SYMBOL_DEPRECATED ON} +end; + +class function TSkPathBuilder.Make(const AFillType: TSkPathFillType): ISkPathBuilder; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkPathBuilder.Create(AFillType); + {$WARN SYMBOL_DEPRECATED ON} +end; + procedure TSkPathBuilder.MoveTo(const AX, AY: Single); begin - MoveTo(TPointF.Create(AX, AY)); + MoveTo(TPointF.Create(AX, AY)); end; procedure TSkPathBuilder.MoveTo(const APoint: TPointF); @@ -9400,6 +9488,13 @@ constructor TSkPathMeasure.Create(const APath: ISkPath; inherited Create(sk4d_pathmeasure_create(APath.Handle, AForceClosed, AResScale)); end; +class function TSkPathMeasure.Make(const APath: ISkPath; const AForceClosed: Boolean = False; const AResScale: Single = 1): ISkPathMeasure; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkBindings.SafeCreate(sk4d_pathmeasure_create(APath.Handle, AForceClosed, AResScale)); + {$WARN SYMBOL_DEPRECATED ON} +end; + function TSkPathMeasure.GetLength: Single; begin Result := sk4d_pathmeasure_get_length(Handle); @@ -9543,7 +9638,16 @@ function TSkPictureRecorder.BeginRecording(const ABounds: TRectF): ISkCanvas; constructor TSkPictureRecorder.Create; begin + {$WARN SYMBOL_DEPRECATED OFF} inherited Create(sk4d_picturerecorder_create()); + {$WARN SYMBOL_DEPRECATED ON} +end; + +class function TSkPictureRecorder.Make: ISkPictureRecorder; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkPictureRecorder.Create; + {$WARN SYMBOL_DEPRECATED ON} end; function TSkPictureRecorder.FinishRecording: ISkPicture; @@ -9573,6 +9677,14 @@ constructor TSkPixmap.Create(const AImageInfo: TSkImageInfo; inherited Create(sk4d_pixmap_create(@LImageInfo, APixels, ARowBytes)); end; +class function TSkPixmap.Make(const AImageInfo: TSkImageInfo; + const APixels: Pointer; const ARowBytes: NativeUInt): ISkPixmap; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkPixmap.Create(AImageInfo, APixels, ARowBytes); + {$WARN SYMBOL_DEPRECATED ON} +end; + function TSkPixmap.Erase(const AColor: TAlphaColorF; const ASubset: TRectF; AColorSpace: ISkColorSpace): Boolean; begin @@ -9685,8 +9797,10 @@ function TSkPixmap.ReadPixels(const ADestImageInfo: TSkImageInfo; var LPixmap: ISkPixmap; begin + {$WARN SYMBOL_DEPRECATED OFF} LPixmap := TSkPixmap.Create(ADestImageInfo, ADestPixels, ADestRowBytes); Result := ReadPixels(LPixmap, ASrcX, ASrcY); + {$WARN SYMBOL_DEPRECATED ON} end; function TSkPixmap.ScalePixels(const ADestImageInfo: TSkImageInfo; @@ -9695,7 +9809,7 @@ function TSkPixmap.ScalePixels(const ADestImageInfo: TSkImageInfo; var LPixmap: ISkPixmap; begin - LPixmap := TSkPixmap.Create(ADestImageInfo, ADestPixels, ADestRowBytes); + LPixmap := TSkPixmap.Make(ADestImageInfo, ADestPixels, ADestRowBytes); Result := ScalePixels(LPixmap, ASampling); end; @@ -9704,8 +9818,10 @@ function TSkPixmap.ScalePixels(const ADestImageInfo: TSkImageInfo; var LPixmap: ISkPixmap; begin + {$WARN SYMBOL_DEPRECATED OFF} LPixmap := TSkPixmap.Create(ADestImageInfo, ADestPixels, ADestRowBytes); Result := ScalePixels(LPixmap); + {$WARN SYMBOL_DEPRECATED ON} end; function TSkPixmap.ScalePixels(const ADest: ISkPixmap; @@ -9752,8 +9868,10 @@ function TSkRegion.Contains(const AX, AY: Integer): Boolean; constructor TSkRegion.Create(const ARect: TRect); begin + {$WARN SYMBOL_DEPRECATED OFF} Create; SetRect(ARect); + {$WARN SYMBOL_DEPRECATED ON} end; constructor TSkRegion.Create(const ARegion: ISkRegion); @@ -9768,6 +9886,27 @@ constructor TSkRegion.Create; inherited Create(sk4d_region_create()); end; +class function TSkRegion.Make: ISkRegion; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkRegion.Create; + {$WARN SYMBOL_DEPRECATED ON} +end; + +class function TSkRegion.MakeCopy(const ARegion: ISkRegion): ISkRegion; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkRegion.Create(ARegion); + {$WARN SYMBOL_DEPRECATED ON} +end; + +class function TSkRegion.Make(const ARect: TRect): ISkRegion; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkRegion.Create(ARect); + {$WARN SYMBOL_DEPRECATED ON} +end; + function TSkRegion.GetBoundaryPath: ISkPath; begin Result := TSkBindings.SafeCreate(sk4d_region_get_boundary_path(Handle)); @@ -9976,8 +10115,10 @@ function TSkRoundRect.Contains(const ARect: TRect): Boolean; constructor TSkRoundRect.Create(const ARect: TRectF; const ARadiusX, ARadiusY: Single); begin - Create; - SetRect(ARect, ARadiusX, ARadiusY); + {$WARN SYMBOL_DEPRECATED OFF} + Create; + {$WARN SYMBOL_DEPRECATED ON} + SetRect(ARect, ARadiusX, ARadiusY); end; constructor TSkRoundRect.Create(const ARoundRect: ISkRoundRect); @@ -9995,8 +10136,10 @@ constructor TSkRoundRect.Create; constructor TSkRoundRect.Create(const ARect: TRectF; const ARadii: TSkRoundRectRadii); begin - Create; - SetRect(ARect, ARadii); + {$WARN SYMBOL_DEPRECATED OFF} + Create; + {$WARN SYMBOL_DEPRECATED ON} + SetRect(ARect, ARadii); end; procedure TSkRoundRect.Deflate(const ADeltaX, ADeltaY: Single); @@ -10073,7 +10216,35 @@ function TSkRoundRect.IsSimple: Boolean; function TSkRoundRect.IsValid: Boolean; begin - Result := sk4d_rrect_is_valid(Handle); + Result := sk4d_rrect_is_valid(Handle); +end; + +class function TSkRoundRect.Make: ISkRoundRect; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkRoundRect.Create; + {$WARN SYMBOL_DEPRECATED ON} +end; + +class function TSkRoundRect.Make(const ARect: TRectF; const ARadiusX, ARadiusY: Single): ISkRoundRect; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkRoundRect.Create(ARect, ARadiusX, ARadiusY); + {$WARN SYMBOL_DEPRECATED ON} +end; + +class function TSkRoundRect.Make(const ARoundRect: ISkRoundRect): ISkRoundRect; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkRoundRect.Create(ARoundRect); + {$WARN SYMBOL_DEPRECATED ON} +end; + +class function TSkRoundRect.Make(const ARect: TRectF; const ARadii: TSkRoundRectRadii): ISkRoundRect; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkRoundRect.Create(ARect, ARadii); + {$WARN SYMBOL_DEPRECATED ON} end; procedure TSkRoundRect.Offset(const ADeltaX, ADeltaY: Single); @@ -10100,28 +10271,28 @@ procedure TSkRoundRect.SetOval(const ARect: TRectF); procedure TSkRoundRect.SetRect(const ARect: TRectF; const ARadii: TSkRoundRectRadii); begin - sk4d_rrect_set_rect2(Handle, @ARect, @ARadii); + sk4d_rrect_set_rect2(Handle, @ARect, @ARadii); end; procedure TSkRoundRect.SetRect(const ARect: TRectF; const ARadiusX, - ARadiusY: Single); + ARadiusY: Single); begin - sk4d_rrect_set_rect3(Handle, @ARect, ARadiusX, ARadiusY); + sk4d_rrect_set_rect3(Handle, @ARect, ARadiusX, ARadiusY); end; procedure TSkRoundRect.SetRect(const ARect: TRectF); begin - sk4d_rrect_set_rect(Handle, @ARect); + sk4d_rrect_set_rect(Handle, @ARect); end; function TSkRoundRect.Transform(const AMatrix: TMatrix): ISkRoundRect; begin - Result := TSkBindings.SafeCreate(sk4d_rrect_transform(Handle, @AMatrix)); + Result := TSkBindings.SafeCreate(sk4d_rrect_transform(Handle, @AMatrix)); end; class procedure TSkRoundRect.__DestroyHandle(const AHandle: sk_handle_t); begin - sk4d_rrect_destroy(AHandle); + sk4d_rrect_destroy(AHandle); end; { TSkRuntimeEffect } @@ -10286,7 +10457,7 @@ class function TSkRuntimeEffect.MakeForBlender(const ASkSL: MarshaledAString; begin if Length(ASKSL) < 1 then raise ESkArgumentException.CreateFmt(SParamIsEmpty, ['ASKSL']); - LErrorText := TSkString.Create; + LErrorText := TSkString.Make; Result := TSkBindings.SafeCreate(sk4d_runtimeeffect_make_for_blender(ASkSL, LErrorText.Handle)); AErrorText := LErrorText.Text; end; @@ -10310,7 +10481,7 @@ class function TSkRuntimeEffect.MakeForColorFilter( begin if Length(ASKSL) < 1 then raise ESkArgumentException.CreateFmt(SParamIsEmpty, ['ASKSL']); - LErrorText := TSkString.Create; + LErrorText := TSkString.Make; Result := TSkBindings.SafeCreate(sk4d_runtimeeffect_make_for_color_filter(ASKSL, LErrorText.Handle)); AErrorText := LErrorText.Text; end; @@ -10348,9 +10519,9 @@ class function TSkRuntimeEffect.MakeForShader(const ASkSL: MarshaledAString; begin if Length(ASKSL) < 1 then raise ESkArgumentException.CreateFmt(SParamIsEmpty, ['ASKSL']); - LErrorText := TSkString.Create; + LErrorText := TSkString.Make; Result := TSkBindings.SafeCreate(sk4d_runtimeeffect_make_for_shader(ASkSL, LErrorText.Handle)); - AErrorText := LErrorText.Text; + AErrorText := LErrorText.Text; end; class function TSkRuntimeEffect.MakeForShader( @@ -10634,7 +10805,15 @@ constructor TSkRuntimeBlenderBuilder.Create(const AEffect: ISkRuntimeEffect); begin if not Assigned(AEffect) then raise ESkArgumentException.CreateFmt(SParamIsNil, ['AEffect']); - inherited Create(sk4d_runtimeblendbuilder_create(AEffect.Handle)); + inherited Create(sk4d_runtimeblendbuilder_create(AEffect.Handle)); +end; + +class function TSkRuntimeBlenderBuilder.Make( + const AEffect: ISkRuntimeEffect): ISkRuntimeBlenderBuilder; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkRuntimeBlenderBuilder.Create(AEffect); + {$WARN SYMBOL_DEPRECATED ON} end; function TSkRuntimeBlenderBuilder.MakeBlender: ISkBlender; @@ -10657,6 +10836,13 @@ constructor TSkRuntimeShaderBuilder.Create(const AEffect: ISkRuntimeEffect); inherited Create(sk4d_runtimeshaderbuilder_create(AEffect.Handle)); end; +class function TSkRuntimeShaderBuilder.Make(const AEffect: ISkRuntimeEffect): ISkRuntimeShaderBuilder; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkRuntimeShaderBuilder.Create(AEffect); + {$WARN SYMBOL_DEPRECATED ON} +end; + function TSkRuntimeShaderBuilder.MakeImage(const AImageInfo: TSkImageInfo; const AMipmapped: Boolean; const AContext: IGrDirectContext): ISkImage; var @@ -11368,8 +11554,10 @@ class function TSkSurface.MakeRasterDirect(const AImageInfo: TSkImageInfo; var LPixmap: ISkPixmap; begin - LPixmap := TSkPixmap.Create(AImageInfo, APixels, ARowBytes); - Result := MakeRasterDirect(LPixmap, ARasterReleaseProc); + {$WARN SYMBOL_DEPRECATED OFF} + LPixmap := TSkPixmap.Create(AImageInfo, APixels, ARowBytes); + Result := MakeRasterDirect(LPixmap, ARasterReleaseProc); + {$WARN SYMBOL_DEPRECATED ON} end; class function TSkSurface.MakeRasterDirect(const AImageInfo: TSkImageInfo; @@ -11379,8 +11567,10 @@ class function TSkSurface.MakeRasterDirect(const AImageInfo: TSkImageInfo; var LPixmap: ISkPixmap; begin - LPixmap := TSkPixmap.Create(AImageInfo, APixels, ARowBytes); - Result := MakeRasterDirect(LPixmap, AProperties, ARasterReleaseProc); + {$WARN SYMBOL_DEPRECATED OFF} + LPixmap := TSkPixmap.Create(AImageInfo, APixels, ARowBytes); + Result := MakeRasterDirect(LPixmap, AProperties, ARasterReleaseProc); + {$WARN SYMBOL_DEPRECATED ON} end; class function TSkSurface.MakeRasterDirect(const APixmap: ISkPixmap; @@ -11446,8 +11636,10 @@ function TSkSurface.ReadPixels(const ADestImageInfo: TSkImageInfo; var LPixmap: ISkPixmap; begin - LPixmap := TSkPixmap.Create(ADestImageInfo, ADestPixels, ADestRowBytes); - Result := ReadPixels(LPixmap, ASrcX, ASrcY); + {$WARN SYMBOL_DEPRECATED OFF} + LPixmap := TSkPixmap.Create(ADestImageInfo, ADestPixels, ADestRowBytes); + Result := ReadPixels(LPixmap, ASrcX, ASrcY); + {$WARN SYMBOL_DEPRECATED ON} end; function TSkSurface.ReadPixels(const ADest: ISkPixmap; const ASrcX, @@ -11479,8 +11671,10 @@ procedure TSkSurface.WritePixels(const ASrcImageInfo: TSkImageInfo; var LPixmap: ISkPixmap; begin - LPixmap := TSkPixmap.Create(ASrcImageInfo, ASrcPixels, ASrcRowBytes); - WritePixels(LPixmap, ADestX, ADestY); + {$WARN SYMBOL_DEPRECATED OFF} + LPixmap := TSkPixmap.Create(ASrcImageInfo, ASrcPixels, ASrcRowBytes); + WritePixels(LPixmap, ADestX, ADestY); + {$WARN SYMBOL_DEPRECATED ON} end; procedure TSkSurface.WritePixels(const ASrc: ISkPixmap; const ADestX, @@ -12057,6 +12251,21 @@ constructor TSkParagraphBuilder.Create( inherited Create(sk4d_paragraphbuilder_create(AParagraphStyle.Handle)); end; +class function TSkParagraphBuilder.Make( + const AParagraphStyle: ISkParagraphStyle): ISkParagraphBuilder; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkParagraphBuilder.Create(AParagraphStyle); + {$WARN SYMBOL_DEPRECATED ON} +end; + +class function TSkParagraphBuilder.Make(const AParagraphStyle: ISkParagraphStyle; const AFontProvider: ISkTypefaceFontProvider; const AEnableFontFallback: Boolean = True): ISkParagraphBuilder; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkParagraphBuilder.Create(AParagraphStyle, AFontProvider, AEnableFontFallback); + {$WARN SYMBOL_DEPRECATED ON} +end; + procedure TSkParagraphBuilder.Pop; begin sk4d_paragraphbuilder_pop(Handle); @@ -12081,6 +12290,13 @@ constructor TSkStrutStyle.Create; inherited Create(sk4d_strutstyle_create()); end; +class function TSkStrutStyle.Make: ISkStrutStyle; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkStrutStyle.Create; + {$WARN SYMBOL_DEPRECATED ON} +end; + function TSkStrutStyle.GetEnabled: Boolean; begin Result := sk4d_strutstyle_get_enabled(Handle); @@ -12198,6 +12414,13 @@ constructor TSkParagraphStyle.Create; inherited Create(sk4d_paragraphstyle_create()); end; +class function TSkParagraphStyle.Make: ISkParagraphStyle; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkParagraphStyle.Create; + {$WARN SYMBOL_DEPRECATED ON} +end; + procedure TSkParagraphStyle.DisableHinting; begin sk4d_paragraphstyle_disable_hinting(Handle); @@ -12319,6 +12542,12 @@ procedure TSkTextStyle.ClearForegroundColor; sk4d_textstyle_clear_foreground_color(Handle); end; +class function TSkTextStyle.Make: ISkTextStyle; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkTextStyle.Create; + {$WARN SYMBOL_DEPRECATED ON} +end; constructor TSkTextStyle.Create; begin @@ -12629,6 +12858,13 @@ constructor TSkShaper.Create; inherited Create(sk4d_shaper_create()); end; +class function TSkShaper.Make: ISkShaper; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkShaper.Create; + {$WARN SYMBOL_DEPRECATED ON} +end; + function TSkShaper.Shape(const AText: string; const AFont: ISkFont; const ALeftToRight: Boolean; const AWidth: Single): ISkTextBlob; begin @@ -12828,6 +13064,13 @@ constructor TSkUnicode.Create; inherited Create(sk4d_unicode_create()); end; +class function TSkUnicode.Make: ISkUnicode; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkUnicode.Create; + {$WARN SYMBOL_DEPRECATED ON} +end; + procedure TSkUnicode.ForEachBidiRegion(const AText: string; const ADirection: TSkDirection; const AProc: TSkUnicodeBidiRegionProc); begin @@ -13060,6 +13303,13 @@ constructor TSkString.Create; inherited Create(sk4d_string_create()); end; +class function TSkString.Make: ISkString; +begin + {$WARN SYMBOL_DEPRECATED OFF} + Result := TSkString.Create; + {$WARN SYMBOL_DEPRECATED ON} +end; + function TSkString.GetText: string; begin Result := string(sk4d_string_get_text(Handle)); diff --git a/Source/VCL/Vcl.Skia.pas b/Source/VCL/Vcl.Skia.pas index 5ba58381..09edb2fb 100644 --- a/Source/VCL/Vcl.Skia.pas +++ b/Source/VCL/Vcl.Skia.pas @@ -1402,7 +1402,7 @@ procedure DrawDesignBorder(const ACanvas: ISkCanvas; ADest: TRectF; const AOpaci var LPaint: ISkPaint; begin - LPaint := TSkPaint.Create(TSkPaintStyle.Stroke); + LPaint := TSkPaint.Make(TSkPaintStyle.Stroke); LPaint.Color := DesignBorderColor; LPaint.AlphaF := AOpacity; LPaint.StrokeWidth := 1; @@ -2132,9 +2132,9 @@ procedure TSkSvgBrush.Render(const ACanvas: ISkCanvas; const ADestRect: TRectF; LPictureRecorder: ISkPictureRecorder; LCanvas: ISkCanvas; LPaint: ISkPaint; - begin - LPictureRecorder := TSkPictureRecorder.Create; - LCanvas := LPictureRecorder.BeginRecording(AWrappedDest.Width, AWrappedDest.Height); + begin + LPictureRecorder := TSkPictureRecorder.Make; + LCanvas := LPictureRecorder.BeginRecording(AWrappedDest.Width, AWrappedDest.Height); if AIntrinsicSize.IsZero then begin if AWrapMode <> TSkSvgWrapMode.Default then @@ -2147,9 +2147,9 @@ procedure TSkSvgBrush.Render(const ACanvas: ISkCanvas; const ADestRect: TRectF; else LCanvas.Scale(AWrappedDest.Width / ASvgRect.Width, AWrappedDest.Height / ASvgRect.Height); ADOM.Render(LCanvas); - LPicture := LPictureRecorder.FinishRecording; - LPaint := TSkPaint.Create; - if FGrayScale then + LPicture := LPictureRecorder.FinishRecording; + LPaint := TSkPaint.Make; + if FGrayScale then LPaint.ColorFilter := TSkColorFilter.MakeMatrix(TSkColorMatrix.CreateSaturation(0)) else if FOverrideColor <> TAlphaColors.Null then LPaint.ColorFilter := TSkColorFilter.MakeBlend(FOverrideColor, TSkBlendMode.SrcIn); @@ -2673,9 +2673,9 @@ function TSkGlControlRender.TryRender(const ABackgroundBuffer: TBitmap; const AO UpdateCache; if FCachedImage <> nil then - begin - LPaint := TSkPaint.Create; - LPaint.Alpha := AOpacity; + begin + LPaint := TSkPaint.Make; + LPaint.Alpha := AOpacity; LSurface.Canvas.DrawImage(FCachedImage, 0, 0, LPaint); end else @@ -2761,9 +2761,9 @@ procedure TSkCustomWinControl.Draw(const ACanvas: ISkCanvas; const ADest: TRectF LPaint: ISkPaint; begin if TAlphaColorRec(FBackgroundColor).A > 0 then - begin - LPaint := TSkPaint.Create; - LPaint.Color := FBackgroundColor; + begin + LPaint := TSkPaint.Make; + LPaint.Color := FBackgroundColor; LPaint.AntiAlias := True; ACanvas.DrawRect(ADest, LPaint); end; @@ -4230,9 +4230,9 @@ procedure TSkDefaultAnimationCodec.Render(const ACanvas: ISkCanvas; if SameValue(AOpacity, 1, TEpsilon.Position) then LPaint := nil else - begin - LPaint := TSkPaint.Create; - LPaint.AlphaF := AOpacity; + begin + LPaint := TSkPaint.Make; + LPaint.AlphaF := AOpacity; end; ACanvas.DrawImageRect(FAnimationCodec.Frame, ADest, TSkSamplingOptions.Medium, LPaint); end; @@ -5630,11 +5630,11 @@ procedure TSkLabel.Draw(const ACanvas: ISkCanvas; const ADest: TRectF; LRectsColor: TArray; LLastRect: TRectF; LLastColor: TAlphaColor; - begin - LPictureRecorder := TSkPictureRecorder.Create; - LCanvas := LPictureRecorder.BeginRecording(ADest); - LPaint := TSkPaint.Create; - LPaint.AntiAlias := True; + begin + LPictureRecorder := TSkPictureRecorder.Make; + LCanvas := LPictureRecorder.BeginRecording(ADest); + LPaint := TSkPaint.Make; + LPaint.AntiAlias := True; LTextEndIndex := 0; LRects := nil; for I := 0 to FWords.Count - 1 do @@ -5812,9 +5812,9 @@ function TSkLabel.GetParagraph: ISkParagraph; if ADrawKind = TDrawKind.Stroke then begin if (ADecorations.StrokeColor <> TAlphaColors.Null) and not SameValue(ADecorations.Thickness, 0, TEpsilon.Position) then - begin - LPaint := TSkPaint.Create(TSkPaintStyle.Stroke); - LPaint.Color := ADecorations.StrokeColor; + begin + LPaint := TSkPaint.Make(TSkPaintStyle.Stroke); + LPaint.Color := ADecorations.StrokeColor; LPaint.StrokeWidth := (ADecorations.Thickness / 2) * (ATextStyle.FontSize / 14); ATextStyle.SetForegroundColor(LPaint); end @@ -5828,9 +5828,9 @@ function TSkLabel.GetParagraph: ISkParagraph; function CreateTextStyle(const AWordsItem: TCustomWordsItem; const ADefaultTextStyle: ISkTextStyle; const ADrawKind: TDrawKind): ISkTextStyle; - begin - Result := TSkTextStyle.Create; - if TSkStyledSetting.FontColor in AWordsItem.StyledSettings then + begin + Result := TSkTextStyle.Make; + if TSkStyledSetting.FontColor in AWordsItem.StyledSettings then Result.Color := ResultingTextSettings.FontColor else Result.Color := AWordsItem.FontColor; @@ -5861,9 +5861,9 @@ function TSkLabel.GetParagraph: ISkParagraph; end; function CreateDefaultTextStyle(const ADrawKind: TDrawKind): ISkTextStyle; - begin - Result := TSkTextStyle.Create; - Result.Color := ResultingTextSettings.FontColor; + begin + Result := TSkTextStyle.Make; + Result.Color := ResultingTextSettings.FontColor; Result.FontFamilies := GetFontFamilies(ResultingTextSettings.Font.Families); Result.FontSize := ResultingTextSettings.Font.Size; Result.FontStyle := TSkFontStyle.Create(SkFontWeightValue[ResultingTextSettings.Font.Weight], SkFontWidthValue[ResultingTextSettings.Font.Stretch], SkFontSlant[ResultingTextSettings.Font.Slant]); @@ -5873,9 +5873,9 @@ function TSkLabel.GetParagraph: ISkParagraph; end; function CreateParagraphStyle(const ADefaultTextStyle: ISkTextStyle): ISkParagraphStyle; - begin - Result := TSkParagraphStyle.Create; - if UseRightToLeftAlignment then + begin + Result := TSkParagraphStyle.Make; + if UseRightToLeftAlignment then Result.TextDirection := TSkTextDirection.RightToLeft; if ResultingTextSettings.Trimming in [TSkTextTrimming.Character, TSkTextTrimming.Word] then Result.Ellipsis := '...'; @@ -5893,11 +5893,10 @@ function TSkLabel.GetParagraph: ISkParagraph; LDefaultTextStyle: ISkTextStyle; LText: string; I: Integer; - begin - LDefaultTextStyle := CreateDefaultTextStyle(ADrawKind); - LBuilder := TSkParagraphBuilder.Create(CreateParagraphStyle(LDefaultTextStyle), TSkDefaultProviders.TypefaceFont); - - for I := 0 to FWords.Count- 1 do + begin + LDefaultTextStyle := CreateDefaultTextStyle(ADrawKind); + LBuilder := TSkParagraphBuilder.Make(CreateParagraphStyle(LDefaultTextStyle), TSkDefaultProviders.TypefaceFont); + for I := 0 to FWords.Count- 1 do begin if FWords[I].Caption = '' then Continue; @@ -6431,9 +6430,9 @@ function TSkGraphic.GetBuffer(const ASize: TSize; const AOpacity: Byte): TBitmap if AOpacity = High(AOpacity) then LPaint := nil else - begin - LPaint := TSkPaint.Create; - LPaint.Alpha := AOpacity; + begin + LPaint := TSkPaint.Make; + LPaint.Alpha := AOpacity; end; if (FBuffer.Width = Width) and (FBuffer.Height = Height) then ACanvas.DrawImage(FImage, 0, 0, LPaint) From 3f84ae1de097814d24ad2434f7aa64dc819a9bbb Mon Sep 17 00:00:00 2001 From: Jim McKeeth Date: Wed, 9 Apr 2025 16:08:27 -0600 Subject: [PATCH 6/6] added `inline` as suggested by Bruneau Babet --- .../CreateAsInterfaceFmxMain.pas | 2 +- .../CreateAsInterfaceVclMain.pas | 5 +- .../CreateAsInterfaces.groupproj | 20 ++-- Source/System.Skia.pas | 100 +++++++++--------- 4 files changed, 64 insertions(+), 63 deletions(-) diff --git a/Samples/CreateAsInterface/CreateAsInterfaceFmxMain.pas b/Samples/CreateAsInterface/CreateAsInterfaceFmxMain.pas index 96250cbf..57114cd7 100644 --- a/Samples/CreateAsInterface/CreateAsInterfaceFmxMain.pas +++ b/Samples/CreateAsInterface/CreateAsInterfaceFmxMain.pas @@ -32,7 +32,7 @@ procedure TForm32.SkPaintBox1Draw(ASender: TObject; var font := TSkFont.Make(family, 24); var paint := TSkPaint.Make(); paint.Color := TAlphaColors.Blueviolet; - ACanvas.DrawSimpleText('.Make',2,30,font,paint) + ACanvas.DrawSimpleText('.Make',2,30,font,paint); end; end. diff --git a/Samples/CreateAsInterface/CreateAsInterfaceVclMain.pas b/Samples/CreateAsInterface/CreateAsInterfaceVclMain.pas index 2613c33a..5778faad 100644 --- a/Samples/CreateAsInterface/CreateAsInterfaceVclMain.pas +++ b/Samples/CreateAsInterface/CreateAsInterfaceVclMain.pas @@ -27,10 +27,11 @@ implementation procedure TSkIntfDemoMain.SkPaintBox1Draw(ASender: TObject; const ACanvas: ISkCanvas; const ADest: TRectF; const AOpacity: Single); begin - var font := TSkFont.Make(nil, 24); + var family := TSkTypeface.MakeFromName('Segoe Script', TSkFontStyle.Italic); + var font := TSkFont.Make(family, 24); var paint := TSkPaint.Make(); paint.Color := TAlphaColors.Blueviolet; - ACanvas.DrawSimpleText('.Make!',2,30,font,paint) + ACanvas.DrawSimpleText('.Make',2,30,font,paint); end; end. diff --git a/Samples/CreateAsInterface/CreateAsInterfaces.groupproj b/Samples/CreateAsInterface/CreateAsInterfaces.groupproj index ddae1e6d..760a574d 100644 --- a/Samples/CreateAsInterface/CreateAsInterfaces.groupproj +++ b/Samples/CreateAsInterface/CreateAsInterfaces.groupproj @@ -3,7 +3,7 @@ {36AB3BD2-8480-405E-9C0C-C24E62C7DB4F}
- + @@ -17,14 +17,14 @@ - - + + - - + + - - + + @@ -36,13 +36,13 @@ - + - + - + diff --git a/Source/System.Skia.pas b/Source/System.Skia.pas index fa9c1bef..63c6a7d2 100644 --- a/Source/System.Skia.pas +++ b/Source/System.Skia.pas @@ -1572,12 +1572,12 @@ TSkColorSpace = class(TSkNonVirtualReferenceCounted, ISkColorSpace) function MakeLinearGamma: ISkColorSpace; function MakeSRGBGamma: ISkColorSpace; function ToProfile: ISkColorSpaceICCProfile; - function ToXyz(out ADest: TSkColorSpaceXyz): Boolean; - class function Make(const AProfile: ISkColorSpaceICCProfile): ISkColorSpace; static; - class function MakeRGB(const ATransferFunction: TSkColorSpaceTransferFunction; const AToXyzD50: TSkColorSpaceXyz): ISkColorSpace; static; - class function MakeSRGB: ISkColorSpace; static; - class function MakeSRGBLinear: ISkColorSpace; static; - class procedure __RefHandle(const AHandle: sk_handle_t); override; + function ToXyz(out ADest: TSkColorSpaceXyz): Boolean; + class function Make(const AProfile: ISkColorSpaceICCProfile): ISkColorSpace; static; inline; + class function MakeRGB(const ATransferFunction: TSkColorSpaceTransferFunction; const AToXyzD50: TSkColorSpaceXyz): ISkColorSpace; static; inline; + class function MakeSRGB: ISkColorSpace; static; inline; + class function MakeSRGBLinear: ISkColorSpace; static; inline; + class procedure __RefHandle(const AHandle: sk_handle_t); override; class procedure __UnrefHandle(const AHandle: sk_handle_t); override; end; @@ -1744,8 +1744,8 @@ TSkFont = class(TSkObject, ISkFont) public constructor Create(ATypeface: ISkTypeface = nil; const ASize: Single = 12; const AScaleX: Single = 1; const ASkewX: Single = 0); overload; deprecated 'Use TSkFont.Make instead.'; constructor Create(const AFont: ISkFont); overload; deprecated 'Use TSkFont.Make instead.'; - class function Make(ATypeface: ISkTypeface = nil; const ASize: Single = 12; const AScaleX: Single = 1; const ASkewX: Single = 0): ISkFont; overload; - class function MakeCopy(const AFont: ISkFont): ISkFont; overload; + class function Make(ATypeface: ISkTypeface = nil; const ASize: Single = 12; const AScaleX: Single = 1; const ASkewX: Single = 0): ISkFont; overload; inline; + class function MakeCopy(const AFont: ISkFont): ISkFont; overload; inline; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2064,9 +2064,9 @@ TSkPaint = class(TSkObject, ISkPaint) constructor Create; overload; deprecated 'Use TSkPaint.Make instead.'; constructor Create(const APaint: ISkPaint); overload; deprecated 'Use TSkPaint.MakeCopy instead.'; constructor Create(const AStyle: TSkPaintStyle); overload; deprecated 'Use TSkPaint.Make instead.'; - class function Make: ISkPaint; overload; - class function MakeCopy(const APaint: ISkPaint): ISkPaint; overload; - class function Make(const AStyle: TSkPaintStyle): ISkPaint; overload; + class function Make: ISkPaint; overload; inline; + class function MakeCopy(const APaint: ISkPaint): ISkPaint; overload; inline; + class function Make(const AStyle: TSkPaintStyle): ISkPaint; overload; inline; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2186,9 +2186,9 @@ TPathIterator = class(TSkEnumerable, ISkPathIterator) constructor Create(const ASVG: string); overload; deprecated 'Use TSkPath.Make instead.'; constructor Create(const ABytes: TBytes); overload; deprecated 'Use TSkPath.Make instead.'; constructor Create(const AStream: TStream); overload; deprecated 'Use TSkPath.Make instead.'; - class function Make(const AStream: TStream): ISkPath; overload; - class function Make(const ASVG: string): ISkPath; overload; - class function Make(const ABytes: TBytes): ISkPath; overload; + class function Make(const AStream: TStream): ISkPath; overload; inline; + class function Make(const ASVG: string): ISkPath; overload; inline; + class function Make(const ABytes: TBytes): ISkPath; overload; inline; class function ConvertConicToQuads(const APoint1, APoint2, APoint3: TPointF; const AWeight: Single; const APower2: Integer): TArray; static; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2299,9 +2299,9 @@ TSkPathBuilder = class(TSkObject, ISkPathBuilder) constructor Create; overload; deprecated 'Use TSkPathBuilder.Make instead.'; constructor Create(const APathBuilder: ISkPathBuilder); overload; deprecated 'Use TSkPathBuilder.MakeCopy instead.'; constructor Create(const AFillType: TSkPathFillType); overload; deprecated 'Use TSkPathBuilder.Make instead.'; - class function Make: ISkPathBuilder; overload; static; - class function MakeCopy(const APathBuilder: ISkPathBuilder): ISkPathBuilder; static; - class function Make(const AFillType: TSkPathFillType): ISkPathBuilder; overload; static; + class function Make: ISkPathBuilder; overload; static; inline; + class function MakeCopy(const APathBuilder: ISkPathBuilder): ISkPathBuilder; static; inline; + class function Make(const AFillType: TSkPathFillType): ISkPathBuilder; overload; static; inline; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2357,7 +2357,7 @@ TSkPathMeasure = class(TSkObject, ISkPathMeasure) function IsClosed: Boolean; function NextContour: Boolean; public - class function Make(const APath: ISkPath; const AForceClosed: Boolean = False; const AResScale: Single = 1): ISkPathMeasure; + class function Make(const APath: ISkPath; const AForceClosed: Boolean = False; const AResScale: Single = 1): ISkPathMeasure; static; inline; constructor Create(const APath: ISkPath; const AForceClosed: Boolean = False; const AResScale: Single = 1); deprecated 'Use TSkPathMeasure.Make instead.'; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2421,7 +2421,7 @@ TSkPictureRecorder = class(TSkObject, ISkPictureRecorder) function FinishRecording(const ACullRect: TRectF): ISkPicture; overload; public constructor Create; overload; deprecated 'Use TSkPictureRecorder.Make instead.'; - class function Make: ISkPictureRecorder; static; + class function Make: ISkPictureRecorder; static; inline; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2499,7 +2499,7 @@ TSkPixmap = class(TSkObject, ISkPixmap) procedure SetColorSpace(AValue: ISkColorSpace); public constructor Create(const AImageInfo: TSkImageInfo; const APixels: Pointer; const ARowBytes: NativeUInt); deprecated 'Use TSkPixmap.Make instead.'; - class function Make(const AImageInfo: TSkImageInfo; const APixels: Pointer; const ARowBytes: NativeUInt): ISkPixmap; + class function Make(const AImageInfo: TSkImageInfo; const APixels: Pointer; const ARowBytes: NativeUInt): ISkPixmap; inline; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2623,9 +2623,9 @@ TRegionSpanerator = class(TSkEnumerable, ISkRegionSpanerator) constructor Create; overload; deprecated 'Use TSkRegion.Make instead.'; constructor Create(const ARegion: ISkRegion); overload; deprecated 'Use TSkRegion.MakeCopy instead.'; constructor Create(const ARect: TRect); overload; deprecated 'Use TSkRegion.Make instead.'; - class function Make: ISkRegion; overload; static; - class function MakeCopy(const ARegion: ISkRegion): ISkRegion; static; - class function Make(const ARect: TRect): ISkRegion; overload; static; + class function Make: ISkRegion; overload; static; inline; + class function MakeCopy(const ARegion: ISkRegion): ISkRegion; static; inline; + class function Make(const ARect: TRect): ISkRegion; overload; static; inline; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2699,10 +2699,10 @@ TSkRoundRect = class(TSkObject, ISkRoundRect) constructor Create(const ARect: TRectF; const ARadiusX, ARadiusY: Single); overload; deprecated 'Use TSkRoundRect.Make instead'; constructor Create(const ARoundRect: ISkRoundRect); overload; deprecated 'Use TSkRoundRect.Make instead'; constructor Create(const ARect: TRectF; const ARadii: TSkRoundRectRadii); overload; deprecated 'Use TSkRoundRect.Make instead'; - class function Make: ISkRoundRect; overload; static; - class function Make(const ARect: TRectF; const ARadiusX, ARadiusY: Single): ISkRoundRect; overload; static; - class function Make(const ARoundRect: ISkRoundRect): ISkRoundRect; overload; static; - class function Make(const ARect: TRectF; const ARadii: TSkRoundRectRadii): ISkRoundRect; overload; static; + class function Make: ISkRoundRect; overload; static; inline; + class function Make(const ARect: TRectF; const ARadiusX, ARadiusY: Single): ISkRoundRect; overload; static; inline; + class function Make(const ARoundRect: ISkRoundRect): ISkRoundRect; overload; static; inline; + class function Make(const ARect: TRectF; const ARadii: TSkRoundRectRadii): ISkRoundRect; overload; static; inline; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2883,7 +2883,7 @@ TSkRuntimeBlenderBuilder = class(TSkRuntimeEffectBuilder, ISkRuntimeBlenderBui function MakeBlender: ISkBlender; public constructor Create(const AEffect: ISkRuntimeEffect); - class function Make(const AEffect: ISkRuntimeEffect): ISkRuntimeBlenderBuilder; static; + class function Make(const AEffect: ISkRuntimeEffect): ISkRuntimeBlenderBuilder; static; inline; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -2909,7 +2909,7 @@ TSkRuntimeShaderBuilder = class(TSkRuntimeEffectBuilder, ISkRuntimeShaderBuild function MakeShader(const ALocalMatrix: TMatrix): ISkShader; overload; public constructor Create(const AEffect: ISkRuntimeEffect); - class function Make(const AEffect: ISkRuntimeEffect): ISkRuntimeShaderBuilder; static; + class function Make(const AEffect: ISkRuntimeEffect): ISkRuntimeShaderBuilder; static; inline; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -3193,10 +3193,10 @@ TSkParticleEffect = class(TSkReferenceCounted, ISkParticleEffect) property UniformData: PSingleArray read GetUniformData; property UniformDataCount: Integer read GetUniformDataCount; property UniformName[const AIndex: NativeUInt]: string read GetUniformName; - class function Make(const AData: string; const AResourceProvider: ISkResourceProvider = nil): ISkParticleEffect; static; deprecated; - class function MakeFromFile(const AFileName: string): ISkParticleEffect; static; deprecated; - class function MakeFromStream(const AStream: TStream; const AResourceProvider: ISkResourceProvider = nil): ISkParticleEffect; static; deprecated; - end; + class function Make(const AData: string; const AResourceProvider: ISkResourceProvider = nil): ISkParticleEffect; static; + class function MakeFromFile(const AFileName: string): ISkParticleEffect; static; + class function MakeFromStream(const AStream: TStream; const AResourceProvider: ISkResourceProvider = nil): ISkParticleEffect; static; + end; { ISkottieAnimation } @@ -3241,10 +3241,10 @@ TSkottieAnimation = class(TSkNonVirtualReferenceCounted, ISkottieAnimation) property OutPoint: Double read GetOutPoint; property Size: TSizeF read GetSize; property Version: string read GetVersion; - class function Make(const AData: string; const AResourceProvider: ISkResourceProvider = nil; const AFontProvider: ISkTypefaceFontProvider = nil): ISkottieAnimation; static; - class function MakeFromFile(const AFileName: string; const AFontProvider: ISkTypefaceFontProvider = nil): ISkottieAnimation; static; - class function MakeFromStream(const AStream: TStream; const AResourceProvider: ISkResourceProvider = nil; const AFontProvider: ISkTypefaceFontProvider = nil): ISkottieAnimation; static; - class procedure __RefHandle(const AHandle: sk_handle_t); override; + class function Make(const AData: string; const AResourceProvider: ISkResourceProvider = nil; const AFontProvider: ISkTypefaceFontProvider = nil): ISkottieAnimation; static; + class function MakeFromFile(const AFileName: string; const AFontProvider: ISkTypefaceFontProvider = nil): ISkottieAnimation; static; + class function MakeFromStream(const AStream: TStream; const AResourceProvider: ISkResourceProvider = nil; const AFontProvider: ISkTypefaceFontProvider = nil): ISkottieAnimation; static; + class procedure __RefHandle(const AHandle: sk_handle_t); override; class procedure __UnrefHandle(const AHandle: sk_handle_t); override; end; @@ -3331,8 +3331,8 @@ TSkParagraphBuilder = class(TSkObject, ISkParagraphBuilder) public constructor Create(const AParagraphStyle: ISkParagraphStyle); overload; deprecated 'Use TSkParagraphBuilder.Make instead'; constructor Create(const AParagraphStyle: ISkParagraphStyle; const AFontProvider: ISkTypefaceFontProvider; const AEnableFontFallback: Boolean = True); overload; deprecated 'Use TSkParagraphBuilder.Make instead'; - class function Make(const AParagraphStyle: ISkParagraphStyle): ISkParagraphBuilder; overload; static; - class function Make(const AParagraphStyle: ISkParagraphStyle; const AFontProvider: ISkTypefaceFontProvider; const AEnableFontFallback: Boolean = True): ISkParagraphBuilder; overload; static; + class function Make(const AParagraphStyle: ISkParagraphStyle): ISkParagraphBuilder; overload; static; inline; + class function Make(const AParagraphStyle: ISkParagraphStyle; const AFontProvider: ISkTypefaceFontProvider; const AEnableFontFallback: Boolean = True): ISkParagraphBuilder; overload; static; inline; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -3392,7 +3392,7 @@ TSkStrutStyle = class(TSkObject, ISkStrutStyle) procedure SetLeading(const AValue: Single); public constructor Create; overload; deprecated 'Use TSkStrutStyle.Make instead'; - class function Make: ISkStrutStyle; static; + class function Make: ISkStrutStyle; static; inline; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -3452,7 +3452,7 @@ TSkParagraphStyle = class(TSkObject, ISkParagraphStyle) procedure SetTextStyle(AValue: ISkTextStyle); public constructor Create; deprecated 'Use TSkParagraphStyle.Make instead'; - class function Make: ISkParagraphStyle; static; + class function Make: ISkParagraphStyle; static; inline; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -3560,7 +3560,7 @@ TSkTextStyle = class(TSkObject, ISkTextStyle) procedure SetWordSpacing(const AValue: Single); public constructor Create; deprecated 'Use TSkTextStyle.Make instead'; - class function Make: ISkTextStyle; static; + class function Make: ISkTextStyle; static; inline; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -3639,7 +3639,7 @@ TSkShaper = class(TSkObject, ISkShaper) function Shape(const AText: string; const AFont: ISkFont; const ALeftToRight: Boolean; const AWidth: Single; const AOffset: TPointF; out AEndPoint: TPointF): ISkTextBlob; overload; public constructor Create; deprecated 'Use TSkShaper.Make instead'; - class function Make: ISkShaper; static; + class function Make: ISkShaper; static; inline; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -3676,10 +3676,10 @@ TSkSVGDOM = class(TSkReferenceCounted, ISkSVGDOM) procedure Render(const ACanvas: ISkCanvas); procedure SetContainerSize(const ASize: TSizeF); property Root: ISkSVGSVG read GetRoot; - class function Make(const AData: string; const AResourceProvider: ISkResourceProvider = nil; const AFontProvider: ISkTypefaceFontProvider = nil): ISkSVGDOM; static; - class function MakeFromFile(const AFileName: string; const AFontProvider: ISkTypefaceFontProvider = nil): ISkSVGDOM; static; - class function MakeFromStream(const AStream: TStream; const AResourceProvider: ISkResourceProvider = nil; const AFontProvider: ISkTypefaceFontProvider = nil): ISkSVGDOM; static; - end; + class function Make(const AData: string; const AResourceProvider: ISkResourceProvider = nil; const AFontProvider: ISkTypefaceFontProvider = nil): ISkSVGDOM; static; + class function MakeFromFile(const AFileName: string; const AFontProvider: ISkTypefaceFontProvider = nil): ISkSVGDOM; static; + class function MakeFromStream(const AStream: TStream; const AResourceProvider: ISkResourceProvider = nil; const AFontProvider: ISkTypefaceFontProvider = nil): ISkSVGDOM; static; + end; { ISkSVGNode } @@ -3787,7 +3787,7 @@ TUnicodeBreakIterator = class(TSkEnumerable, IS class procedure codepoint_proc(unichar: sk_unichar_t; start, &end: int32_t; context: Pointer); cdecl; static; public constructor Create; deprecated 'Use Make instead'; - class function Make: ISkUnicode; static; + class function Make: ISkUnicode; static; inline; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -4023,7 +4023,7 @@ TSkString = class(TSkObject, ISkString) function GetText: string; public constructor Create; deprecated 'Use Make instead'; - class function Make: ISkString; static; + class function Make: ISkString; static; inline; class procedure __DestroyHandle(const AHandle: sk_handle_t); override; end; @@ -11945,7 +11945,7 @@ class function TSkParticleEffect.Make(const AData: string; class function TSkParticleEffect.MakeFromFile( const AFileName: string): ISkParticleEffect; begin - if Length(AFileName) = 0 then + if Length(AFileName) = 0 then raise ESkException.Create(SFileNameIsEmpty); Result := TSkBindings.SafeCreate(sk4d_particleeffect_make_from_file(MarshaledAString(UTF8String(AFileName)))); end;