2
0

GR32_Backends_Generic.pas 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. unit GR32_Backends_Generic;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is Backend Extension for Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Andre Beckedorf - metaException
  26. * [email protected]
  27. *
  28. * Portions created by the Initial Developer are Copyright (C) 2007-2009
  29. * the Initial Developer. All Rights Reserved.
  30. *
  31. * Contributor(s):
  32. *
  33. * ***** END LICENSE BLOCK ***** *)
  34. interface
  35. {$include GR32.inc}
  36. uses
  37. {$ifdef MSWINDOWS}
  38. Windows,
  39. {$ENDIF}
  40. {$ifndef FPC}
  41. System.IOUtils,
  42. {$endif}
  43. SysUtils,
  44. Classes,
  45. GR32;
  46. type
  47. { TMemoryBackend }
  48. { A backend that keeps the backing buffer entirely in memory.}
  49. TMemoryBackend = class(TCustomBackend)
  50. protected
  51. procedure InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean); override;
  52. procedure FinalizeSurface; override;
  53. end;
  54. {$ifdef MSWINDOWS}
  55. { TMMFBackend }
  56. { A backend that uses memory mapped files or mapped swap space for the
  57. backing buffer.}
  58. TMMFBackend = class(TMemoryBackend)
  59. private
  60. FMapHandle: THandle;
  61. FMapIsTemporary: boolean;
  62. FMapFileHandle: THandle;
  63. FMapFileName: string;
  64. protected
  65. procedure InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean); override;
  66. procedure FinalizeSurface; override;
  67. public
  68. constructor Create(Owner: TCustomBitmap32; IsTemporary: Boolean = True; const MapFileName: string = ''); virtual;
  69. destructor Destroy; override;
  70. class procedure InitializeFileMapping(var MapHandle, MapFileHandle: THandle; var MapFileName: string);
  71. class procedure DeinitializeFileMapping(MapHandle, MapFileHandle: THandle; const MapFileName: string);
  72. class procedure CreateFileMapping(var MapHandle, MapFileHandle: THandle; var MapFileName: string; IsTemporary: Boolean; NewWidth, NewHeight: Integer);
  73. end;
  74. {$ENDIF}
  75. implementation
  76. uses
  77. GR32_LowLevel;
  78. {$ifdef MSWINDOWS}
  79. resourcestring
  80. RCStrFailedToMapFile = 'Failed to map file';
  81. RCStrFailedToCreateMapFile = 'Failed to create map file (%s)';
  82. RCStrFailedToMapViewOfFile = 'Failed to map view of file.';
  83. {$ENDIF}
  84. { TMemoryBackend }
  85. procedure TMemoryBackend.InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean);
  86. begin
  87. GetMem(FBits, NewWidth * NewHeight * 4);
  88. if ClearBuffer then
  89. FillLongword(FBits[0], NewWidth * NewHeight, clBlack32);
  90. end;
  91. procedure TMemoryBackend.FinalizeSurface;
  92. begin
  93. if (FBits <> nil) then
  94. begin
  95. FreeMem(FBits);
  96. FBits := nil;
  97. end;
  98. end;
  99. {$ifdef MSWINDOWS}
  100. { TMMFBackend }
  101. constructor TMMFBackend.Create(Owner: TCustomBitmap32; IsTemporary: Boolean; const MapFileName: string);
  102. begin
  103. FMapFileName := MapFileName;
  104. FMapIsTemporary := IsTemporary;
  105. InitializeFileMapping(FMapHandle, FMapFileHandle, FMapFileName);
  106. inherited Create(Owner);
  107. end;
  108. destructor TMMFBackend.Destroy;
  109. begin
  110. DeinitializeFileMapping(FMapHandle, FMapFileHandle, FMapFileName);
  111. inherited;
  112. end;
  113. procedure TMMFBackend.FinalizeSurface;
  114. begin
  115. if Assigned(FBits) then
  116. begin
  117. UnmapViewOfFile(FBits);
  118. FBits := nil;
  119. end;
  120. end;
  121. procedure TMMFBackend.InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean);
  122. begin
  123. CreateFileMapping(FMapHandle, FMapFileHandle, FMapFileName, FMapIsTemporary, NewWidth, NewHeight);
  124. FBits := MapViewOfFile(FMapHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
  125. if not Assigned(FBits) then
  126. raise Exception.Create(RCStrFailedToMapViewOfFile);
  127. if ClearBuffer then
  128. FillLongword(FBits[0], NewWidth * NewHeight, clBlack32);
  129. end;
  130. class procedure TMMFBackend.InitializeFileMapping(var MapHandle, MapFileHandle: THandle; var MapFileName: string);
  131. begin
  132. MapHandle := INVALID_HANDLE_VALUE;
  133. MapFileHandle := INVALID_HANDLE_VALUE;
  134. if MapFileName <> '' then
  135. ForceDirectories(IncludeTrailingPathDelimiter(ExtractFilePath(MapFileName)));
  136. end;
  137. class procedure TMMFBackend.DeinitializeFileMapping(MapHandle, MapFileHandle: THandle; const MapFileName: string);
  138. begin
  139. if MapFileName <> '' then
  140. begin
  141. CloseHandle(MapHandle);
  142. CloseHandle(MapFileHandle);
  143. if FileExists(MapFileName) then
  144. DeleteFile(MapFileName);
  145. end;
  146. end;
  147. class procedure TMMFBackend.CreateFileMapping(var MapHandle, MapFileHandle: THandle;
  148. var MapFileName: string; IsTemporary: Boolean; NewWidth, NewHeight: Integer);
  149. var
  150. Flags: Cardinal;
  151. {$IFDEF USE_GUIDS_IN_MMF}
  152. function GetTempFileName(const Prefix: string): string;
  153. var
  154. PathAndPrefix: string;
  155. begin
  156. {$ifdef FPC}
  157. PathAndPrefix := GetTempDir + Prefix;
  158. {$else}
  159. PathAndPrefix := TPath.GetTempPath + Prefix;
  160. {$endif}
  161. repeat
  162. Result := PathAndPrefix + TGUID.NewGuid.ToString;
  163. until not FileExists(Result);
  164. end;
  165. {$ELSE}
  166. function GetTempFileName(const Prefix: string): string;
  167. var
  168. PathAndPrefix: string;
  169. n: integer;
  170. begin
  171. {$ifdef FPC}
  172. PathAndPrefix := GetTempDir + Prefix;
  173. {$else}
  174. PathAndPrefix := TPath.GetTempPath + Prefix;
  175. {$endif}
  176. n := 0;
  177. repeat
  178. Result := PathAndPrefix + IntToHex(n, 8);
  179. Inc(n);
  180. until not FileExists(Result);
  181. end;
  182. {$ENDIF}
  183. begin
  184. // close previous handles
  185. if MapHandle <> INVALID_HANDLE_VALUE then
  186. begin
  187. CloseHandle(MapHandle);
  188. MapHandle := INVALID_HANDLE_VALUE;
  189. end;
  190. if MapFileHandle <> INVALID_HANDLE_VALUE then
  191. begin
  192. CloseHandle(MapFileHandle);
  193. MapHandle := INVALID_HANDLE_VALUE;
  194. end;
  195. // Do we want to use an external map file?
  196. if (MapFileName <> '') or IsTemporary then
  197. begin
  198. if MapFileName = '' then
  199. MapFileName := GetTempFileName(IntToStr(NativeUInt(Self)));
  200. // delete file if exists
  201. if FileExists(MapFileName) then
  202. DeleteFile(MapFileName);
  203. // open file
  204. if IsTemporary then
  205. Flags := FILE_ATTRIBUTE_TEMPORARY OR FILE_FLAG_DELETE_ON_CLOSE
  206. else
  207. Flags := FILE_ATTRIBUTE_NORMAL;
  208. MapFileHandle := CreateFile(PChar(MapFileName), GENERIC_READ or GENERIC_WRITE,
  209. 0, nil, CREATE_ALWAYS, Flags, 0);
  210. if MapFileHandle = INVALID_HANDLE_VALUE then
  211. begin
  212. if not IsTemporary then
  213. raise Exception.CreateFmt(RCStrFailedToCreateMapFile, [MapFileName])
  214. else
  215. begin
  216. // Reset and fall back to allocating in the system's paging file...
  217. // delete file if exists
  218. if FileExists(MapFileName) then
  219. DeleteFile(MapFileName);
  220. MapFileName := '';
  221. end;
  222. end;
  223. end
  224. else // use the system's paging file
  225. MapFileHandle := INVALID_HANDLE_VALUE;
  226. // create map
  227. MapHandle := Windows.CreateFileMapping(MapFileHandle, nil, PAGE_READWRITE, 0, NewWidth * NewHeight * 4, nil);
  228. if MapHandle = 0 then
  229. raise Exception.Create(RCStrFailedToMapFile);
  230. end;
  231. {$ENDIF}
  232. end.