1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Native driver for dxg implementation
5 * FILE: win32ss/reactx/dxg/ddhmg.c
6 * PROGRAMER: Magnus olsen (magnus@greatlord.com)
7 * Sebastian Gasiorek (sebastian.gasiorek@reactos.org)
8 * REVISION HISTORY:
9 * 30/12-2007 Magnus Olsen
10 */
11
12 #include <dxg_int.h>
13
14 /* The DdHmgr manger stuff */
15 ULONG gcSizeDdHmgr = 1024;
16 PDD_ENTRY gpentDdHmgr = NULL;
17
18 ULONG gcMaxDdHmgr = 0;
19 PDD_ENTRY gpentDdHmgrLast = NULL;
20
21 /* next free ddhmg handle number available to reuse */
22 ULONG ghFreeDdHmgr = 0;
23 HSEMAPHORE ghsemHmgr = NULL;
24
25 BOOL
26 FASTCALL
VerifyObjectOwner(PDD_ENTRY pEntry)27 VerifyObjectOwner(PDD_ENTRY pEntry)
28 {
29 DWORD Pid = (DWORD)(DWORD_PTR)PsGetCurrentProcessId() & 0xFFFFFFFC;
30 DWORD check = (DWORD_PTR)pEntry->Pid & 0xFFFFFFFE;
31 return ( (check == Pid) || (!check));
32 }
33
34 /*++
35 * @name DdHmgCreate
36 * @implemented
37 *
38 * The function DdHmgCreate is used internally in dxg.sys
39 * It creates all DX kernel objects that are need it for creation of DX objects.
40 *
41 * @return
42 * Return FALSE for failure and TRUE for success in creating the DX object
43 *
44 * @remarks.
45 * Only used internally in dxg.sys
46 *--*/
47 BOOL
48 FASTCALL
DdHmgCreate(VOID)49 DdHmgCreate(VOID)
50 {
51 gpentDdHmgr = EngAllocMem(FL_ZERO_MEMORY, gcSizeDdHmgr * sizeof(DD_ENTRY), TAG_THDD);
52 ghFreeDdHmgr = 0;
53 gcMaxDdHmgr = 1;
54
55 if (gpentDdHmgr)
56 {
57 ghsemHmgr = EngCreateSemaphore();
58
59 if (ghsemHmgr)
60 {
61 gpLockShortDelay = EngAllocMem(FL_ZERO_MEMORY | FL_NONPAGED_MEMORY, sizeof(LARGE_INTEGER), TAG_GINI);
62
63 if (gpLockShortDelay)
64 {
65 gpLockShortDelay->HighPart = -1;
66 return TRUE;
67 }
68
69 EngDeleteSemaphore(ghsemHmgr);
70 ghsemHmgr = NULL;
71 }
72
73 EngFreeMem(gpentDdHmgr);
74 gpentDdHmgr = NULL;
75 }
76
77 return FALSE;
78 }
79
80 /*++
81 * @name DdHmgDestroy
82 * @implemented
83 *
84 * The function DdHmgDestroy is used internally in dxg.sys
85 * It destroys all DX kernel objects
86 *
87 * @return
88 * Always returns true, as a failure here would result in a BSOD.
89 *
90 * @remarks.
91 * Only used internally in dxg.sys
92 *--*/
93 BOOL
94 FASTCALL
DdHmgDestroy(VOID)95 DdHmgDestroy(VOID)
96 {
97 gcMaxDdHmgr = 0;
98 gcSizeDdHmgr = 0;
99 ghFreeDdHmgr = 0;
100 gpentDdHmgrLast = NULL;
101
102 if (gpentDdHmgr)
103 {
104 EngFreeMem(gpentDdHmgr);
105 gpentDdHmgr = NULL;
106 }
107
108 if (ghsemHmgr)
109 {
110 EngDeleteSemaphore(ghsemHmgr);
111 ghsemHmgr = NULL;
112 }
113
114 return TRUE;
115 }
116
117 /*++
118 * @name DdHmgLock
119 * @implemented
120 *
121 * The function DdHmgLock is used internally in dxg.sys
122 * It locks a DX kernel object
123 *
124 * @param HANDLE DdHandle
125 * The handle we want locked
126 *
127 * @param UCHAR ObjectType
128 * The type of the object we expected the handle to contain
129 * value 0 is for ?
130 * value 1 is for EDD_DIRECTDRAW_LOCAL
131 * value 2 is for EDD_SURFACE
132 * value 3 is for ?
133 * value 4 is for EDD_VIDEOPORT
134 * value 5 is for EDD_MOTIONCOMP
135
136 * @param BOOLEAN LockOwned
137 * If it needs to call EngAcquireSemaphore or not
138 *
139 * @return
140 * Returns an EDD_* object, or NULL if it fails
141 *
142 * @remarks.
143 * Only used internally in dxg.sys
144 *--*/
145 PVOID
146 FASTCALL
DdHmgLock(HANDLE DdHandle,UCHAR ObjectType,BOOLEAN LockOwned)147 DdHmgLock(HANDLE DdHandle, UCHAR ObjectType, BOOLEAN LockOwned)
148 {
149 DWORD Index = DDHMG_HTOI(DdHandle);
150
151 PDD_ENTRY pEntry = NULL;
152 PVOID Object = NULL;
153
154 if ( !LockOwned )
155 {
156 EngAcquireSemaphore(ghsemHmgr);
157 }
158
159 if ( Index < gcMaxDdHmgr )
160 {
161 pEntry = (PDD_ENTRY)((PBYTE)gpentDdHmgr + (sizeof(DD_ENTRY) * Index));
162
163 if ( VerifyObjectOwner(pEntry) )
164 {
165 if ( ( pEntry->Objt == ObjectType ) &&
166 ( pEntry->FullUnique == (((ULONG_PTR)DdHandle >> 21) & 0x7FF) ) &&
167 ( !pEntry->pobj->cExclusiveLock ) )
168 {
169 InterlockedIncrement((VOID*)&pEntry->pobj->cExclusiveLock);
170 pEntry->pobj->Tid = KeGetCurrentThread();
171 Object = pEntry->pobj;
172 }
173 }
174 }
175
176 if ( !LockOwned )
177 {
178 EngReleaseSemaphore(ghsemHmgr);
179 }
180
181 return Object;
182 }
183
184 /*++
185 * @name DdAllocateObject
186 * @implemented
187 *
188 * The function DdAllocateObject is used internally in dxg.sys
189 * It allocates memory for a DX kernel object
190 *
191 * @param UINT32 oSize
192 * Size of memory to be allocated
193 * @param UCHAR oType
194 * Object type
195 * @param BOOLEAN oZeroMemory
196 * Zero memory
197 *
198 * @remarks.
199 * Only used internally in dxg.sys
200 */
201 PVOID
202 FASTCALL
DdAllocateObject(ULONG objSize,UCHAR objType,BOOLEAN objZeroMemory)203 DdAllocateObject(ULONG objSize, UCHAR objType, BOOLEAN objZeroMemory)
204 {
205 PVOID pObject = NULL;
206
207 if (objZeroMemory)
208 pObject = EngAllocMem(FL_ZERO_MEMORY, objSize, ((ULONG)objType << 24) + TAG_DH_0);
209 else
210 pObject = EngAllocMem(0, objSize, ((ULONG)objType << 24) + TAG_DH_0);
211
212 if (!pObject)
213 {
214 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
215 }
216
217 return pObject;
218 }
219
220 /*++
221 * @name DdFreeObject
222 * @implemented
223 *
224 * The function DdFreeObject is used internally in dxg.sys
225 * It frees memory of DX kernel object
226 *
227 * @param PVOID pObject
228 * Object memory to be freed
229 *
230 * @remarks.
231 * Only used internally in dxg.sys
232 */
233 VOID
234 FASTCALL
DdFreeObject(PVOID pObject)235 DdFreeObject(PVOID pObject)
236 {
237 EngFreeMem(pObject);
238 }
239
240
241 /*++
242 * @name DdGetFreeHandle
243 * @implemented
244 *
245 * The function DdGetFreeHandle is used internally in dxg.sys
246 * It allocates new handle for specified object type
247 *
248 * @param UCHAR oType
249 * Object type
250 *
251 * @return
252 * Returns handle or 0 if it fails.
253 *
254 * @remarks.
255 * Only used internally in dxg.sys
256 *--*/
257 HANDLE
258 FASTCALL
DdGetFreeHandle(UCHAR objType)259 DdGetFreeHandle(UCHAR objType)
260 {
261 PVOID mAllocMem = NULL;
262 ULONG mAllocEntries = 0;
263 PDD_ENTRY pEntry = NULL;
264 ULONG_PTR retVal;
265 ULONG index;
266
267 // check if memory is allocated
268 if (!gpentDdHmgr)
269 return 0;
270
271 // check if we reached maximum handle index
272 if (gcMaxDdHmgr == DDHMG_HANDLE_LIMIT)
273 return 0;
274
275 // check if we have free handle to reuse
276 if (ghFreeDdHmgr)
277 {
278 index = ghFreeDdHmgr;
279 pEntry = (PDD_ENTRY)((PBYTE)gpentDdHmgr + (sizeof(DD_ENTRY) * index));
280
281 // put next free index to our global variable
282 ghFreeDdHmgr = pEntry->NextFree;
283
284 // build handle
285 pEntry->FullUnique = objType | 8;
286 retVal = (pEntry->FullUnique << 21) | index;
287 return (HANDLE)retVal;
288 }
289
290 // if all pre-allocated memory is already used then allocate more
291 if (gcSizeDdHmgr == gcMaxDdHmgr)
292 {
293 // allocate buffer for next 1024 handles
294 mAllocEntries = gcSizeDdHmgr + 1024;
295 mAllocMem = EngAllocMem(FL_ZERO_MEMORY, sizeof(DD_ENTRY) * (mAllocEntries), TAG_THDD);
296 if (!mAllocMem)
297 return 0;
298
299 memmove(&mAllocMem, gpentDdHmgr, sizeof(DD_ENTRY) * gcSizeDdHmgr);
300 gcSizeDdHmgr = mAllocEntries;
301 gpentDdHmgrLast = gpentDdHmgr;
302 EngFreeMem(gpentDdHmgr);
303 gpentDdHmgr = mAllocMem;
304 }
305
306 pEntry = (PDD_ENTRY)((PBYTE)gpentDdHmgr + (sizeof(DD_ENTRY) * gcMaxDdHmgr));
307
308 // build handle
309 pEntry->FullUnique = objType | 8;
310 retVal = (pEntry->FullUnique << 21) | gcMaxDdHmgr;
311 gcMaxDdHmgr = gcMaxDdHmgr + 1;
312
313 return (HANDLE)retVal;
314 }
315
316 /*++
317 * @name DdHmgAlloc
318 * @implemented
319 *
320 * The function DdHmgAlloc is used internally in dxg.sys
321 * It allocates object
322 *
323 * @param ULONG objSize
324 * Size of memory to be allocated
325 * @param CHAR objType
326 * Object type
327 * @param UINT objLock
328 * Object lock flag
329 *
330 * @return
331 * Handle if object is not locked by objLock
332 * Object if lock is set in objLock
333 * 0 if it fails.
334 *
335 * @remarks.
336 * Only used internally in dxg.sys
337 *--*/
338 HANDLE
339 FASTCALL
DdHmgAlloc(ULONG objSize,CHAR objType,BOOLEAN objLock)340 DdHmgAlloc(ULONG objSize, CHAR objType, BOOLEAN objLock)
341 {
342 PVOID pObject = NULL;
343 HANDLE DdHandle = NULL;
344 PDD_ENTRY pEntry = NULL;
345 DWORD Index;
346
347 pObject = DdAllocateObject(objSize, objType, TRUE);
348 if (!pObject)
349 return 0;
350
351 EngAcquireSemaphore(ghsemHmgr);
352
353 /* Get next free handle */
354 DdHandle = DdGetFreeHandle(objType);
355
356 if (DdHandle)
357 {
358 Index = DDHMG_HTOI(DdHandle);
359
360 pEntry = (PDD_ENTRY)((PBYTE)gpentDdHmgr + (sizeof(DD_ENTRY) * Index));
361
362 pEntry->pobj = pObject;
363 pEntry->Objt = objType;
364
365 pEntry->Pid = (HANDLE)(((ULONG_PTR)PsGetCurrentProcessId() & 0xFFFFFFFC) | ((ULONG_PTR)(pEntry->Pid) & 1));
366
367 if (objLock)
368 {
369 InterlockedIncrement((VOID*)&pEntry->pobj->cExclusiveLock);
370 pEntry->pobj->Tid = KeGetCurrentThread();
371 }
372 pEntry->pobj->hHmgr = DdHandle;
373
374 EngReleaseSemaphore(ghsemHmgr);
375
376 /* Return handle if object not locked */
377 if (!objLock)
378 return DdHandle;
379
380 return (HANDLE)pEntry;
381 }
382
383 EngReleaseSemaphore(ghsemHmgr);
384 DdFreeObject(pObject);
385 return 0;
386 }
387
388 /*++
389 * @name DdHmgFree
390 * @implemented
391 *
392 * The function DdHmgFree is used internally in dxg.sys
393 * It frees DX object and memory allocated to it
394 *
395 * @param HANDLE DdHandle
396 * DX object handle
397 *
398 * @remarks.
399 * Only used internally in dxg.sys
400 *--*/
401 VOID
402 FASTCALL
DdHmgFree(HANDLE DdHandle)403 DdHmgFree(HANDLE DdHandle)
404 {
405 PDD_ENTRY pEntry = NULL;
406
407 DWORD Index = DDHMG_HTOI(DdHandle);
408
409 EngAcquireSemaphore(ghsemHmgr);
410
411 pEntry = (PDD_ENTRY)((PBYTE)gpentDdHmgr + (sizeof(DD_ENTRY) * Index));
412
413 // check if we have object that should be freed
414 if (pEntry->pobj)
415 DdFreeObject(pEntry->pobj);
416
417 pEntry->NextFree = ghFreeDdHmgr;
418
419 // reset process ID
420 pEntry->Pid = (HANDLE)((DWORD_PTR)pEntry->Pid & 1);
421 ghFreeDdHmgr = Index;
422
423 EngReleaseSemaphore(ghsemHmgr);
424 }
425