Jump to content

pyscripter

Members
  • Content Count

    787
  • Joined

  • Last visited

  • Days Won

    42

Posts posted by pyscripter


  1. @Mahdi Safsafi Amazing stuff.

    Questions: 

    1. There are many more overloads in the include file implemented as inline functions.   Do those interfere with the above?
    2. After the first set of Set/GetAttributeValue there is a GetAttributeValueLength function.  Does this comes last?

    It was just by accident that my GetAttributeCall was picking the correct overload!!  That really confused me.


  2. 19 minutes ago, Mahdi Safsafi said:

    I believe you're wrong on $78 ! its for an overloaded GetAttributeValue function (not SetAttributeValue). So your code is calling an overloaded version of GetAttributeValue instead of SetAttributeValue.

    Thanks, but this is puzzling.  at $7C is the GetAttributeValue, which I know it works  and  at $78 should be the one before. (right?).  In the include file the function before the GetAttributeValue is the relevant SetAttributeValue.   How can I find the correct order?


  3. 15 minutes ago, Attila Kovacs said:

    looks like I'm being ignored here.

    change the order of the last 2 SetAttributeValue()'s in the interface, no AV but I can't see any changes, maybe you would know why and see if it helps.

    Wow.  I was using the order in the include file.  What exactly is the order that works?  Could you please post the relevant section of the file or the file as a whole?


  4. 6 minutes ago, Kas Ob. said:

    Thank you for sharing the sample.

     

    And here is the thing,

    1) in that sample fill, RecolorSubtree is using IsAttributeSpecified and GetAttributeValue then utilizing paint->SetColor to change the color, not using SetAttributeValue.

    2) SetAttributeValue is been used after GetAttributeValue for 'display' and not for fill

     

    may be that is the case ?

    I have tried to used the method used in the sample see the commented out code:

     

     Assert(Succeeded(
        Element.GetAttributeValue('fill', IID_ID2D1SvgPaint, Pointer(Paint))
        ));

    but that did not work either.  So I then tried to use a different overload to get the color and that worked.  But setting it back produces the crash.


  5. 24 minutes ago, Kas Ob. said:

    Means nothing, as it depends on different factors, like the local variables initialized or not, the stack protection cookie, stack frame.. etc

    So being different help with nothing here.

     

    But lets approach this differently, is the value returned in OldColor with GetAttributeValue is right ? if yes then passing it to SetAttributeValue should be OK, i have no idea what POD means ?!, may be try with string type at first then switch to that POD.

    "Crashes Access violation" this is not very helpful without the address triggering the AV with the invalid value trying to read, this will help you understand if the message have reading address XXXXX, is your stack in other word belongs to OldColor the pointer itself instead of the memory it pointing to.

     

    And last, i would suggest to double check if you landing on the right function SetAttributeValue

    https://docs.microsoft.com/en-us/windows/win32/direct2d/id2d1svgelement-setattributevalue-overload

     

     

    The value of OldColor returned by GetAttributeValue is right.  (I have a simple svg file and checked with the contents of the file).  So GetAttributeValue works fine.

     

    Access violation at 0x75db8cbx read of address 0x000000001

      D2D1_SVG_ATTRIBUTE_POD_TYPE = DWord;
      {$EXTERNALSYM D2D1_SVG_ATTRIBUTE_POD_TYPE}
    const
      // The attribute is a D2D1_COLOR_F.
      D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR                = D2D1_SVG_ATTRIBUTE_POD_TYPE(1);

     

    I did check that the correct overload is called. (looked at the assembly code calliing the function: call dword ptr [eax+$7c] for GetAttributeValue  , dword ptr [eax+$78] for SetAttributeValue  , tripled checked with the C header file order of interface members etc).

    MSDN description of SetAttributeValue overload used.

     

    I am attaching the project source code in case anyone wants to have a go.   The display of svg files works fine and now without using Vcl.Direct2D.

    Svg.zip

    d2d1svg.h


  6. 41 minutes ago, David Heffernan said:

    Problem could be how you call the function 

    OldColor: TD2D1ColorF;
    
    //works with correct results
    if Succeeded(Element.GetAttributeValue('fill', D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR,
           @OldColor, SizeOf(OldColor)))
    
    // Crashes Access violation
    Element.SetAttributeValue('fill', D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR,
               @OldColor, SizeOf(OldColor));
    D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR = 1

    The prolog of the two functions differ.  Doesn't this mean the declaration should be different?  But I am not sure what SetAttributeValue expects


  7. For comparison the following method is GetAttributeValue:

    /// <summary>
    /// Gets an attribute of this element as a POD type. Returns an error if the
    /// attribute is not specified. Returns an error if the attribute name is not valid
    /// on this element. Returns an error if the attribute cannot be expressed as the
    /// specified POD type.
    /// </summary>
    STDMETHOD(GetAttributeValue)(
    _In_ PCWSTR name,
    D2D1_SVG_ATTRIBUTE_POD_TYPE type,
    _Out_writes_bytes_(valueSizeInBytes) void *value,
    UINT32 valueSizeInBytes
    ) PURE;
     

    which I am successfully using by translating to (same parameters)

        function GetAttributeValue(name: LPWSTR;
                                   _type: D2D1_SVG_ATTRIBUTE_POD_TYPE;
                                   value: Pointer;
                                   valueSizeInBytes: UINT32): HResult; overload; stdcall;

    However the prolog of GetAttributeValue is different:

     

    564713C0 6690             nop 
    564713C2 55               push ebp
    564713C3 8BEC             mov ebp,esp
    564713C5 83EC24           sub esp,$24
    564713C8 8B4D08           mov ecx,[ebp+$08]
    564713CB 53               push ebx
    564713CC 8BD9             mov ebx,ecx
    564713CE 56               push esi
    564713CF 8D4108           lea eax,[ecx+$08]
    564713D2 33C9             xor ecx,ecx
    564713D4 85C0             test eax,eax
    564713D6 57               push edi
    564713D7 0F44D9           cmovz ebx,ecx
    564713DA 6A08             push $08
    564713DC 5A               pop edx

     


  8. In d2d1svg.h (Direct2D) there is the following declaration of the ID2D1SvgElement interface:

    /// <summary>
    /// Sets an attribute of this element using a POD type. Returns an error if the
    /// attribute name is not valid on this element. Returns an error if the attribute
    /// cannot be expressed as the specified type.
    /// </summary>
    STDMETHOD(SetAttributeValue)(
    _In_ PCWSTR name,
    D2D1_SVG_ATTRIBUTE_POD_TYPE type,
    _In_reads_bytes_(valueSizeInBytes) CONST void *value,
    UINT32 valueSizeInBytes
    ) PURE;
     

    D2D1_SVG_ATTRIBUTE_POD_TYPE = DWord;

     

    I am translating this as 

        function SetAttributeValue(name: LPWSTR;
                                   _type: D2D1_SVG_ATTRIBUTE_POD_TYPE;
                                   value: Pointer;
                                   valueSizeInBytes: UINT32): HResult; overload; stdcall;

    But it crashes when it is used.

     

    The assembly prolog of SetAttributeValue is

    564711F0 6690             nop 
    564711F2 55               push ebp
    564711F3 8BEC             mov ebp,esp
    564711F5 83EC14           sub esp,$14
    564711F8 8B4508           mov eax,[ebp+$08]
    564711FB 33C9             xor ecx,ecx
    564711FD 53               push ebx
    564711FE 56               push esi
    564711FF 57               push edi
    56471200 8D5808           lea ebx,[eax+$08]
    56471203 85DB             test ebx,ebx
    56471205 6A08             push $08
    56471207 0F44C1           cmovz eax,ecx
    5647120A 8945F8           mov [ebp-$08],eax
    5647120D 5A               pop edx

     

    Any idea what I am doing wrong?

    Thanks!

     

     

     


    • FLRE is the fastest of all! 
    • One single pascal file which is good
    • The  author is a kind of genius

    But

    • not as extensively tested as PCRE
    • poorly documented
    • not very well supported
    • the performance gain compared to PCRE+JIT is not that big
    • System.RegularExpressions has a nicer interface

     

    All-in-all I would stick to System.RegularExpressions at least if you add JIT.

    • Like 2

  9. 25 minutes ago, Vincent Parrett said:

    Nice, however the lack of text support might be an issue. I pains me that windows doesn't have a fully featured svg render build it.. it's not like svg's are a new thing!

    True.  And for the last 3-4 years there was no improvement in Windows svg support.  However converting text to path is a reasonable workaround.  In any case it is not common to have text in toolbar icons etc.


  10. I am not sure many know that since the Windows Creators update, svg parsing and painting is natively supported and is part of Direct2D.  I wanted to test this Windows feature, however, the first obstacle was that the Direct2d headers that come with Delphi are very very old.  There are two open tickets in https://quality.embarcadero.com/.

     

     

    You may want to vote for them, since lack of good Direct2D support (includes DirectWrite) it is a bit of a shame.

     

    I then looked at other Direct2D translations and found two that are regularly updated.   

     

     

    They both had some issues but that was a good start.  It turned out that parsing and painting svg files to Canvas is quite straightforward.  Once you establish a renderer (Vcl.Direct2d does this, but it is easy to do it from scratch) you can do everything with two lines of code.

     fDeviceContext5.CreateSvgDocument(fStream,
                                   D2D1SizeF(ClientWidth, ClientHeight),
                                   fsvgDocument);
    fDeviceContext5.DrawSvgDocument(fsvgDocument);

    You can check whether Svg is supported by:

      if Supports( rt, ID2D1DeviceContext5, fDeviceContext5) then
    

    And it is easy to do things like scaling, opacity, rotation, recoloring etc.  The quality and speed appear to be quite good, but there are some limitations, the most important of which I think is the lack of support for the text element.  I am attaching the source code of my test project (no dependencies) in case anyone wants to play with it.  The Svg scales automatically as you resize the form.

    Svg.zip

    • Like 4

  11. 1 hour ago, dummzeuch said:

    In 2011 Eric Grange blogged about a problem with the then current implementation of TCriticalSection and TMonitor:

     

    According to Allen Bauer this was fixed for TMonitor in Delphi XE2:

    I just looked at the code, it indeed has been done. But apparently nothing has been changed in TCriticalSection.

     

    Is this still relevant?

     

    If yes, is there a way to change the allocated memory of an object instance dynamically?

    I just found that David Millington blogged about Custom object memory allocation in Delphi which seems to fit the bill.

    I would use the TRTLCriticalSection which is a record defined in Windows.pas. 

      TRTLCriticalSection = record
        DebugInfo: PRTLCriticalSectionDebug;
        LockCount: Longint;
        RecursionCount: Longint;
        OwningThread: THandle;
        LockSemaphore: THandle;
        Reserved: ULONG_PTR;
      end;

    A record helper is provided in SynchObjs.pas

      TCriticalSectionHelper = record helper for TRTLCriticalSection
        procedure Initialize; inline;
        procedure Destroy; inline;
        procedure Free; inline;
        procedure Enter; inline;
        procedure Leave; inline;
        function TryEnter: Boolean; inline;
      end;

    According to Eric It is much less prone to this issue (I don't have the reference though) and does not incur the overhead of object creation/destruction.

     

    The SpinLock is another option. So is the Windows Slim reader writer (SRW) lock.   And of course you can use TMonitor which nowadays is comparable in performance to the CriticalSection.   (SpinLock and SRW locks are faster).  

     

    For anyone interested here is a record wrapper to SRW locks.

      (*
        Multiple Read Exclusive Write lock based on Windows slim reader/writer
        (SRW) Locks.  Can be also used instead of a critical session.
        Limitations: non-reentrant, not "fair"
      *)
      TSlimMREWSync = record
      private
        Lock: TRTLSRWLock;
      public
        procedure Create;
        procedure BeginRead;
        procedure EndRead;
        procedure BeginWrite;
        procedure EndWrite;
        function TryRead: Boolean;
        function TryWrite: Boolean;
      end;
      
      { TSMREWSync }
    
    procedure TSlimMREWSync.BeginRead;
    begin
      AcquireSRWLockShared(Lock);
    end;
    
    procedure TSlimMREWSync.BeginWrite;
    begin
      AcquireSRWLockExclusive(Lock);
    end;
    
    procedure TSlimMREWSync.Create;
    begin
      InitializeSRWLock(Lock);
    end;
    
    procedure TSlimMREWSync.EndRead;
    begin
      ReleaseSRWLockShared(Lock);
    end;
    
    procedure TSlimMREWSync.EndWrite;
    begin
      ReleaseSRWLockExclusive(Lock);
    end;
    
    function TSlimMREWSync.TryRead: Boolean;
    begin
      Result := TryAcquireSRWLockShared(Lock);
    end;
    
    function TSlimMREWSync.TryWrite: Boolean;
    begin
      Result := TryAcquireSRWLockExclusive(Lock);
    end;

     

     

     

     

     

     

     

    • Thanks 1

  12. I had the same problem.  I though I had installed the patch through Getit but it was not actually installed.  After reading this thread I installed by the command prompt.  It appears that just clicking on the bat file via the File Explorer did not work despite getting the elevation prompt.

    • Like 1

  13. 1 hour ago, Mahdi Safsafi said:

    @pyscripter I just made a benchmark against Perl regex. Yes its weird to compare a compiler vs interpreter ... but Perl beats Delphi own & study regex. However it failed to bit jit regex. A script and detailed result are attached.

    Benchmark.rar

    Here it is not an issue of compiler/interpreter because PERL is using a C library anyway.

     

    Perl uses its own regular expression engine not PCRE.  There are many other options, Google RE, Intel's Hyperscan to mention a couple.   PCRE+JIT is one of the fastest around and most widely used.   I should not forget to mention FLRE written in Pascal, which is probably the fastest of all!  Sometime ago I had posted in Google+ a benchmark comparing many of the above,  But I not sure how to access Google+ material.  Also note that the number of matches differs between Delphi and Perl.  This is not surprising, because there are subtle differences in how these engines work.


  14.  

    Pcre-Jit-Delphi

     

    Delphi wraps the PCRE library into the System.RegularExpressions unit. This unit provides a high-level, easy-to-use interface to PCRE. A limitation however is that it does not provide access to the Just-In-Time (JIT) compiler of PCRE. PCRE JIT can improve the performance of regular expression matching dramatically and is particularly useful, when you apply the same regular expression repetitively. The purpose of the Pcre-Jit-Delphi project is to patch the Delphi RTL in order to provide access to JIT.  Please visit the project page at Github to see how you can use PCRE JIT in your projects.

     

    Benchmark

    The console project Benchmark.dpr in Demos folder compares the performance of the built-in Delphi regular expressions library, with the those of using Study without JIT and Study with JIT on a commonly used regular expression benchmark.

    Here are the results I got from the 64 bit version.

     

                                                            Time     | Match count
    ==============================================================================
    Delphi's own TRegEx:
                                            /Twain/ :        7.00 ms |         811
                                        /(?i)Twain/ :       41.00 ms |         965
                                       /[a-z]shing/ :      384.00 ms |        1540
                       /Huck[a-zA-Z]+|Saw[a-zA-Z]+/ :      461.00 ms |         262
                                        /\b\w+nn\b/ :      588.00 ms |         262
                                 /[a-q][^u-z]{13}x/ :      539.00 ms |        4094
                      /Tom|Sawyer|Huckleberry|Finn/ :      757.00 ms |        2598
                  /(?i)Tom|Sawyer|Huckleberry|Finn/ :      861.00 ms |        4152
              /.{0,2}(Tom|Sawyer|Huckleberry|Finn)/ :     2615.00 ms |        2598
              /.{2,4}(Tom|Sawyer|Huckleberry|Finn)/ :     2766.00 ms |        1976
                /Tom.{10,25}river|river.{10,25}Tom/ :      455.00 ms |           2
                                     /[a-zA-Z]+ing/ :      807.00 ms |       78423
                            /\s[a-zA-Z]{0,12}ing\s/ :      560.00 ms |       49659
                    /([A-Za-z]awyer|[A-Za-z]inn)\s/ :      789.00 ms |         209
                        /["'][^"']{0,30}[?!\.]["']/ :      321.00 ms |        8885
    Total Time:    11963.00 ms
    ==============================================================================
    Delphi's own TRegEx with Study:
                                            /Twain/ :        6.00 ms |         811
                                        /(?i)Twain/ :       41.00 ms |         965
                                       /[a-z]shing/ :      316.00 ms |        1540
                       /Huck[a-zA-Z]+|Saw[a-zA-Z]+/ :       21.00 ms |         262
                                        /\b\w+nn\b/ :      581.00 ms |         262
                                 /[a-q][^u-z]{13}x/ :      413.00 ms |        4094
                      /Tom|Sawyer|Huckleberry|Finn/ :       28.00 ms |        2598
                  /(?i)Tom|Sawyer|Huckleberry|Finn/ :      217.00 ms |        4152
              /.{0,2}(Tom|Sawyer|Huckleberry|Finn)/ :     2632.00 ms |        2598
              /.{2,4}(Tom|Sawyer|Huckleberry|Finn)/ :     2785.00 ms |        1976
                /Tom.{10,25}river|river.{10,25}Tom/ :       50.00 ms |           2
                                     /[a-zA-Z]+ing/ :      759.00 ms |       78423
                            /\s[a-zA-Z]{0,12}ing\s/ :      563.00 ms |       49659
                    /([A-Za-z]awyer|[A-Za-z]inn)\s/ :      699.00 ms |         209
                        /["'][^"']{0,30}[?!\.]["']/ :       52.00 ms |        8885
    Total Time:     9179.00 ms
    ==============================================================================
    Delphi's own TRegEx with JIT:
                                            /Twain/ :       11.00 ms |         811
                                        /(?i)Twain/ :       14.00 ms |         965
                                       /[a-z]shing/ :       12.00 ms |        1540
                       /Huck[a-zA-Z]+|Saw[a-zA-Z]+/ :        3.00 ms |         262
                                        /\b\w+nn\b/ :      126.00 ms |         262
                                 /[a-q][^u-z]{13}x/ :      154.00 ms |        4094
                      /Tom|Sawyer|Huckleberry|Finn/ :       22.00 ms |        2598
                  /(?i)Tom|Sawyer|Huckleberry|Finn/ :       61.00 ms |        4152
              /.{0,2}(Tom|Sawyer|Huckleberry|Finn)/ :      277.00 ms |        2598
              /.{2,4}(Tom|Sawyer|Huckleberry|Finn)/ :      346.00 ms |        1976
                /Tom.{10,25}river|river.{10,25}Tom/ :       12.00 ms |           2
                                     /[a-zA-Z]+ing/ :       84.00 ms |       78423
                            /\s[a-zA-Z]{0,12}ing\s/ :      156.00 ms |       49659
                    /([A-Za-z]awyer|[A-Za-z]inn)\s/ :       35.00 ms |         209
                        /["'][^"']{0,30}[?!\.]["']/ :       18.00 ms |        8885
    Total Time:     1350.00 ms

    As you can see the increase in performance is impressive.

     

    Credits

     

    Many thanks to @Mahdi Safsafi who provided the assembly code for __chkstk  and other Delphi developers (@Kas Ob., @David Heffernan, @Remy Lebeau, @Fr0sT.Brutal) that have provided useful advice.

     

    • Like 6
    • Thanks 2
×