GR32_Backends_Generic.pas 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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. {$I GR32.inc}
  36. uses
  37. {$IFDEF FPC}
  38. {$IFDEF Windows}
  39. Windows,
  40. {$ENDIF}
  41. {$ELSE}
  42. Windows,
  43. {$ENDIF}
  44. {$IFDEF USE_GUIDS_IN_MMF}
  45. ActiveX,
  46. {$ENDIF}
  47. SysUtils, Classes, GR32;
  48. type
  49. { TMemoryBackend }
  50. { A backend that keeps the backing buffer entirely in memory.}
  51. TMemoryBackend = class(TCustomBackend)
  52. protected
  53. procedure InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean); override;
  54. procedure FinalizeSurface; override;
  55. end;
  56. {$IFDEF Windows}
  57. { TMMFBackend }
  58. { A backend that uses memory mapped files or mapped swap space for the
  59. backing buffer.}
  60. TMMFBackend = class(TMemoryBackend)
  61. private
  62. FMapHandle: THandle;
  63. FMapIsTemporary: boolean;
  64. FMapFileHandle: THandle;
  65. FMapFileName: string;
  66. protected
  67. procedure InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean); override;
  68. procedure FinalizeSurface; override;
  69. public
  70. constructor Create(Owner: TCustomBitmap32; IsTemporary: Boolean = True; const MapFileName: string = ''); virtual;
  71. destructor Destroy; override;
  72. class procedure InitializeFileMapping(var MapHandle, MapFileHandle: THandle; var MapFileName: string);
  73. class procedure DeinitializeFileMapping(MapHandle, MapFileHandle: THandle; const MapFileName: string);
  74. class procedure CreateFileMapping(var MapHandle, MapFileHandle: THandle; var MapFileName: string; IsTemporary: Boolean; NewWidth, NewHeight: Integer);
  75. end;
  76. {$ENDIF}
  77. implementation
  78. uses
  79. GR32_LowLevel;
  80. {$IFDEF Windows}
  81. var
  82. TempPath: TFileName;
  83. resourcestring
  84. RCStrFailedToMapFile = 'Failed to map file';
  85. RCStrFailedToCreateMapFile = 'Failed to create map file (%s)';
  86. RCStrFailedToMapViewOfFile = 'Failed to map view of file.';
  87. function GetTempPath: TFileName;
  88. var
  89. PC: PChar;
  90. begin
  91. PC := StrAlloc(MAX_PATH + 1);
  92. try
  93. Windows.GetTempPath(MAX_PATH, PC);
  94. Result := TFileName(PC);
  95. finally
  96. StrDispose(PC);
  97. end;
  98. end;
  99. {$ENDIF}
  100. { TMemoryBackend }
  101. procedure TMemoryBackend.InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean);
  102. begin
  103. GetMem(FBits, NewWidth * NewHeight * 4);
  104. if ClearBuffer then
  105. FillLongword(FBits[0], NewWidth * NewHeight, clBlack32);
  106. end;
  107. procedure TMemoryBackend.FinalizeSurface;
  108. begin
  109. if Assigned(FBits) then
  110. begin
  111. FreeMem(FBits);
  112. FBits := nil;
  113. end;
  114. end;
  115. {$IFDEF Windows}
  116. { TMMFBackend }
  117. constructor TMMFBackend.Create(Owner: TCustomBitmap32; IsTemporary: Boolean = True; const MapFileName: string = '');
  118. begin
  119. FMapFileName := MapFileName;
  120. FMapIsTemporary := IsTemporary;
  121. InitializeFileMapping(FMapHandle, FMapFileHandle, FMapFileName);
  122. inherited Create(Owner);
  123. end;
  124. destructor TMMFBackend.Destroy;
  125. begin
  126. DeinitializeFileMapping(FMapHandle, FMapFileHandle, FMapFileName);
  127. inherited;
  128. end;
  129. procedure TMMFBackend.FinalizeSurface;
  130. begin
  131. if Assigned(FBits) then
  132. begin
  133. UnmapViewOfFile(FBits);
  134. FBits := nil;
  135. end;
  136. end;
  137. procedure TMMFBackend.InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean);
  138. begin
  139. CreateFileMapping(FMapHandle, FMapFileHandle, FMapFileName, FMapIsTemporary, NewWidth, NewHeight);
  140. FBits := MapViewOfFile(FMapHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
  141. if not Assigned(FBits) then
  142. raise Exception.Create(RCStrFailedToMapViewOfFile);
  143. if ClearBuffer then
  144. FillLongword(FBits[0], NewWidth * NewHeight, clBlack32);
  145. end;
  146. class procedure TMMFBackend.InitializeFileMapping(var MapHandle, MapFileHandle: THandle; var MapFileName: string);
  147. begin
  148. MapHandle := INVALID_HANDLE_VALUE;
  149. MapFileHandle := INVALID_HANDLE_VALUE;
  150. if MapFileName <> '' then
  151. ForceDirectories(IncludeTrailingPathDelimiter(ExtractFilePath(MapFileName)));
  152. end;
  153. class procedure TMMFBackend.DeinitializeFileMapping(MapHandle, MapFileHandle: THandle; const MapFileName: string);
  154. begin
  155. if MapFileName <> '' then
  156. begin
  157. CloseHandle(MapHandle);
  158. CloseHandle(MapFileHandle);
  159. if FileExists(MapFileName) then
  160. DeleteFile(MapFileName);
  161. end;
  162. end;
  163. class procedure TMMFBackend.CreateFileMapping(var MapHandle, MapFileHandle: THandle;
  164. var MapFileName: string; IsTemporary: Boolean; NewWidth, NewHeight: Integer);
  165. var
  166. Flags: Cardinal;
  167. {$IFDEF USE_GUIDS_IN_MMF}
  168. function GetTempFileName(const Prefix: string): string;
  169. var
  170. GUID: TGUID;
  171. begin
  172. repeat
  173. CoCreateGuid(GUID);
  174. Result := TempPath + Prefix + GUIDToString(GUID);
  175. until not FileExists(Result);
  176. end;
  177. {$ELSE}
  178. function GetTempFileName(const Prefix: string): string;
  179. var
  180. PC: PChar;
  181. begin
  182. PC := StrAlloc(MAX_PATH + 1);
  183. Windows.GetTempFileName(PChar(GetTempPath), PChar(Prefix), 0, PC);
  184. Result := string(PC);
  185. StrDispose(PC);
  186. end;
  187. {$ENDIF}
  188. begin
  189. // close previous handles
  190. if MapHandle <> INVALID_HANDLE_VALUE then
  191. begin
  192. CloseHandle(MapHandle);
  193. MapHandle := INVALID_HANDLE_VALUE;
  194. end;
  195. if MapFileHandle <> INVALID_HANDLE_VALUE then
  196. begin
  197. CloseHandle(MapFileHandle);
  198. MapHandle := INVALID_HANDLE_VALUE;
  199. end;
  200. // Do we want to use an external map file?
  201. if (MapFileName <> '') or IsTemporary then
  202. begin
  203. if MapFileName = '' then
  204. {$IFDEF HAS_NATIVEINT}
  205. MapFileName := GetTempFileName(IntToStr(NativeUInt(Self)));
  206. {$ELSE}
  207. MapFileName := GetTempFileName(IntToStr(Cardinal(Self)));
  208. {$ENDIF}
  209. // delete file if exists
  210. if FileExists(MapFileName) then
  211. DeleteFile(MapFileName);
  212. // open file
  213. if IsTemporary then
  214. Flags := FILE_ATTRIBUTE_TEMPORARY OR FILE_FLAG_DELETE_ON_CLOSE
  215. else
  216. Flags := FILE_ATTRIBUTE_NORMAL;
  217. MapFileHandle := CreateFile(PChar(MapFileName), GENERIC_READ or GENERIC_WRITE,
  218. 0, nil, CREATE_ALWAYS, Flags, 0);
  219. if MapFileHandle = INVALID_HANDLE_VALUE then
  220. begin
  221. if not IsTemporary then
  222. raise Exception.CreateFmt(RCStrFailedToCreateMapFile, [MapFileName])
  223. else
  224. begin
  225. // Reset and fall back to allocating in the system's paging file...
  226. // delete file if exists
  227. if FileExists(MapFileName) then
  228. DeleteFile(MapFileName);
  229. MapFileName := '';
  230. end;
  231. end;
  232. end
  233. else // use the system's paging file
  234. MapFileHandle := INVALID_HANDLE_VALUE;
  235. // create map
  236. MapHandle := Windows.CreateFileMapping(MapFileHandle, nil, PAGE_READWRITE, 0, NewWidth * NewHeight * 4, nil);
  237. if MapHandle = 0 then
  238. raise Exception.Create(RCStrFailedToMapFile);
  239. end;
  240. {$ENDIF}
  241. {$IFDEF Windows}
  242. initialization
  243. TempPath := IncludeTrailingPathDelimiter(GetTempPath);
  244. finalization
  245. TempPath := '';
  246. {$ENDIF}
  247. end.