xref: /reactos/win32ss/reactx/dxg/ddhmg.c (revision 2a5e2a2a)
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