source: trunk/Packages/Graphics32/GR32_Backends_Generic.pas

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