[WIN32K]
[reactos.git] / subsystems / win32 / win32k / eng / surface.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: GDI Driver Surace Functions
5 * FILE: subsys/win32k/eng/surface.c
6 * PROGRAMERS: Jason Filby
7 * Timo Kreuzer
8 * REVISION HISTORY:
9 * 3/7/1999: Created
10 * 9/11/2000: Updated to handle real pixel packed bitmaps (UPDATE TO DATE COMPLETED)
11 * TESTING TO BE DONE:
12 * - Create a GDI bitmap with all formats, perform all drawing operations on them, render to VGA surface
13 * refer to \test\microwin\src\engine\devdraw.c for info on correct pixel plotting for various formats
14 */
15
16 #include <win32k.h>
17
18 #define NDEBUG
19 #include <debug.h>
20
21 ULONG giUniqueSurface = 0;
22
23 UCHAR
24 gajBitsPerFormat[11] =
25 {
26 0, /* 0: unused */
27 1, /* 1: BMF_1BPP */
28 4, /* 2: BMF_4BPP */
29 8, /* 3: BMF_8BPP */
30 16, /* 4: BMF_16BPP */
31 24, /* 5: BMF_24BPP */
32 32, /* 6: BMF_32BPP */
33 4, /* 7: BMF_4RLE */
34 8, /* 8: BMF_8RLE */
35 0, /* 9: BMF_JPEG */
36 0, /* 10: BMF_PNG */
37 };
38
39
40 ULONG FASTCALL BitmapFormat(WORD Bits, DWORD Compression)
41 {
42 switch (Compression)
43 {
44 case BI_RGB:
45 /* Fall through */
46 case BI_BITFIELDS:
47 switch (Bits)
48 {
49 case 1:
50 return BMF_1BPP;
51 case 4:
52 return BMF_4BPP;
53 case 8:
54 return BMF_8BPP;
55 case 16:
56 return BMF_16BPP;
57 case 24:
58 return BMF_24BPP;
59 case 32:
60 return BMF_32BPP;
61 }
62 return 0;
63
64 case BI_RLE4:
65 return BMF_4RLE;
66
67 case BI_RLE8:
68 return BMF_8RLE;
69
70 default:
71 return 0;
72 }
73 }
74
75 BOOL
76 INTERNAL_CALL
77 SURFACE_Cleanup(PVOID ObjectBody)
78 {
79 PSURFACE psurf = (PSURFACE)ObjectBody;
80 PVOID pvBits = psurf->SurfObj.pvBits;
81 NTSTATUS Status;
82
83 /* Check if the surface has bits */
84 if (pvBits)
85 {
86 /* Only bitmaps can have bits */
87 ASSERT(psurf->SurfObj.iType == STYPE_BITMAP);
88
89 /* Check if it is a DIB section */
90 if (psurf->hDIBSection)
91 {
92 /* Unsecure the memory */
93 EngUnsecureMem(psurf->hSecure);
94
95 /* Calculate the real start of the section */
96 pvBits = (PVOID)((ULONG_PTR)pvBits - psurf->dwOffset);
97
98 /* Unmap the section */
99 Status = MmUnmapViewOfSection(PsGetCurrentProcess(), pvBits);
100 if (!NT_SUCCESS(Status))
101 {
102 DPRINT1("Could not unmap section view!\n");
103 // Should we BugCheck here?
104 ASSERT(FALSE);
105 }
106 }
107 else if (psurf->SurfObj.fjBitmap & BMF_USERMEM)
108 {
109 /* Bitmap was allocated from usermode memory */
110 EngFreeUserMem(pvBits);
111 }
112 else if (psurf->SurfObj.fjBitmap & BMF_KMSECTION)
113 {
114 /* Bitmap was allocated from a kernel section */
115 if (!EngFreeSectionMem(NULL, pvBits))
116 {
117 DPRINT1("EngFreeSectionMem failed for %p!\n", pvBits);
118 // Should we BugCheck here?
119 ASSERT(FALSE);
120 }
121 }
122 else if (psurf->SurfObj.fjBitmap & BMF_RLE_HACK)
123 {
124 /* HACK: Free RLE decompressed bits */
125 EngFreeMem(pvBits);
126 }
127 else
128 {
129 /* There should be nothing to free */
130 ASSERT(psurf->SurfObj.fjBitmap & BMF_DONT_FREE);
131 }
132 }
133
134 /* Free palette */
135 if(psurf->ppal)
136 {
137 PALETTE_ShareUnlockPalette(psurf->ppal);
138 }
139
140 return TRUE;
141 }
142
143
144 PSURFACE
145 NTAPI
146 SURFACE_AllocSurface(
147 IN ULONG iType,
148 IN ULONG cx,
149 IN ULONG cy,
150 IN ULONG iFormat)
151 {
152 PSURFACE psurf;
153 SURFOBJ *pso;
154
155 /* Verify format */
156 if (iFormat < BMF_1BPP || iFormat > BMF_PNG)
157 {
158 DPRINT1("Invalid bitmap format: %ld\n", iFormat);
159 return NULL;
160 }
161
162 /* Allocate a SURFACE object */
163 psurf = (PSURFACE)GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_BITMAP);
164
165 if (psurf)
166 {
167 /* Initialize the basic fields */
168 pso = &psurf->SurfObj;
169 pso->hsurf = psurf->BaseObject.hHmgr;
170 pso->sizlBitmap.cx = cx;
171 pso->sizlBitmap.cy = cy;
172 pso->iBitmapFormat = iFormat;
173 pso->iType = iType;
174 pso->iUniq = InterlockedIncrement((PLONG)&giUniqueSurface);
175
176 /* Assign a default palette amd increment its reference count */
177 psurf->ppal = appalSurfaceDefault[iFormat];
178 GDIOBJ_IncrementShareCount(&psurf->ppal->BaseObject);
179 }
180
181 return psurf;
182 }
183
184 BOOL
185 NTAPI
186 SURFACE_bSetBitmapBits(
187 IN PSURFACE psurf,
188 IN USHORT fjBitmap,
189 IN ULONG ulWidth,
190 IN PVOID pvBits OPTIONAL)
191 {
192 SURFOBJ *pso = &psurf->SurfObj;
193 PVOID pvSection;
194 UCHAR cBitsPixel;
195
196 /* Only bitmaps can have bits */
197 ASSERT(psurf->SurfObj.iType == STYPE_BITMAP);
198
199 /* Get bits per pixel from the format */
200 cBitsPixel = gajBitsPerFormat[pso->iBitmapFormat];
201
202 /* Is a width in bytes given? */
203 if (ulWidth)
204 {
205 /* Align the width (Windows compatibility) */
206 ulWidth = ((((ulWidth << 3) / cBitsPixel) * cBitsPixel + 31) & ~31) >> 3;
207 }
208 else
209 {
210 /* Calculate width from the bitmap width in pixels */
211 ulWidth = ((pso->sizlBitmap.cx * cBitsPixel + 31) & ~31) >> 3;
212 }
213
214 /* Calculate the bitmap size in bytes */
215 pso->cjBits = ulWidth * pso->sizlBitmap.cy;
216
217 /* Did the caller provide bits? */
218 if (pvBits)
219 {
220 /* Yes, so let him free it */
221 fjBitmap |= BMF_DONT_FREE;
222 }
223 else if (pso->cjBits)
224 {
225 /* We must allocate memory, check what kind */
226 if (fjBitmap & BMF_USERMEM)
227 {
228 /* User mode memory was requested */
229 pvBits = EngAllocUserMem(pso->cjBits, 0);
230 }
231 else
232 {
233 /* Use a kernel mode section */
234 fjBitmap |= BMF_KMSECTION;
235 pvBits = EngAllocSectionMem(&pvSection,
236 (fjBitmap & BMF_NOZEROINIT) ?
237 0 : FL_ZERO_MEMORY,
238 pso->cjBits, TAG_DIB);
239
240 /* Free the section already, but keep the mapping */
241 if (pvBits) EngFreeSectionMem(pvSection, NULL);
242 }
243
244 /* Check for failure */
245 if (!pvBits) return FALSE;
246 }
247
248 /* Set pvBits, pvScan0 and lDelta */
249 pso->pvBits = pvBits;
250 if (fjBitmap & BMF_TOPDOWN)
251 {
252 /* Topdown is the normal way */
253 pso->pvScan0 = pso->pvBits;
254 pso->lDelta = ulWidth;
255 }
256 else
257 {
258 /* Inversed bitmap (bottom up) */
259 pso->pvScan0 = (PVOID)((ULONG_PTR)pso->pvBits + pso->cjBits - ulWidth);
260 pso->lDelta = -ulWidth;
261 }
262
263 pso->fjBitmap = fjBitmap;
264
265 /* Success */
266 return TRUE;
267 }
268
269 HBITMAP
270 APIENTRY
271 EngCreateBitmap(
272 IN SIZEL sizl,
273 IN LONG lWidth,
274 IN ULONG iFormat,
275 IN ULONG fl,
276 IN PVOID pvBits)
277 {
278 PSURFACE psurf;
279 HBITMAP hbmp;
280
281 /* Allocate a surface */
282 psurf = SURFACE_AllocSurface(STYPE_BITMAP, sizl.cx, sizl.cy, iFormat);
283 if (!psurf)
284 {
285 DPRINT1("SURFACE_AllocSurface failed.\n");
286 return NULL;
287 }
288
289 /* Get the handle for the bitmap */
290 hbmp = (HBITMAP)psurf->SurfObj.hsurf;
291
292 /* Set the bitmap bits */
293 if (!SURFACE_bSetBitmapBits(psurf, fl, lWidth, pvBits))
294 {
295 /* Bail out if that failed */
296 DPRINT1("SURFACE_bSetBitmapBits failed.\n");
297 SURFACE_FreeSurfaceByHandle(hbmp);
298 return NULL;
299 }
300
301 /* Set public ownership */
302 GDIOBJ_SetOwnership(hbmp, NULL);
303
304 /* Unlock the surface and return */
305 SURFACE_UnlockSurface(psurf);
306 return hbmp;
307 }
308
309 /*
310 * @implemented
311 */
312 HBITMAP
313 APIENTRY
314 EngCreateDeviceBitmap(
315 IN DHSURF dhsurf,
316 IN SIZEL sizl,
317 IN ULONG iFormat)
318 {
319 PSURFACE psurf;
320 HBITMAP hbmp;
321
322 /* Allocate a surface */
323 psurf = SURFACE_AllocSurface(STYPE_DEVBITMAP, sizl.cx, sizl.cy, iFormat);
324 if (!psurf)
325 {
326 return 0;
327 }
328
329 /* Set the device handle */
330 psurf->SurfObj.dhsurf = dhsurf;
331
332 /* Get the handle for the bitmap */
333 hbmp = (HBITMAP)psurf->SurfObj.hsurf;
334
335 /* Set public ownership */
336 GDIOBJ_SetOwnership(hbmp, NULL);
337
338 /* Unlock the surface and return */
339 SURFACE_UnlockSurface(psurf);
340 return hbmp;
341 }
342
343 HSURF
344 APIENTRY
345 EngCreateDeviceSurface(
346 IN DHSURF dhsurf,
347 IN SIZEL sizl,
348 IN ULONG iFormat)
349 {
350 PSURFACE psurf;
351 HSURF hsurf;
352
353 /* Allocate a surface */
354 psurf = SURFACE_AllocSurface(STYPE_DEVICE, sizl.cx, sizl.cy, iFormat);
355 if (!psurf)
356 {
357 return 0;
358 }
359
360 /* Set the device handle */
361 psurf->SurfObj.dhsurf = dhsurf;
362
363 /* Get the handle for the surface */
364 hsurf = psurf->SurfObj.hsurf;
365
366 /* Set public ownership */
367 GDIOBJ_SetOwnership(hsurf, NULL);
368
369 /* Unlock the surface and return */
370 SURFACE_UnlockSurface(psurf);
371 return hsurf;
372 }
373
374 BOOL
375 APIENTRY
376 EngAssociateSurface(
377 IN HSURF hsurf,
378 IN HDEV hdev,
379 IN FLONG flHooks)
380 {
381 SURFOBJ *pso;
382 PSURFACE psurf;
383 PDEVOBJ* ppdev;
384
385 ppdev = (PDEVOBJ*)hdev;
386
387 /* Lock the surface */
388 psurf = SURFACE_LockSurface(hsurf);
389 if (!psurf)
390 {
391 return FALSE;
392 }
393 pso = &psurf->SurfObj;
394
395 /* Associate the hdev */
396 pso->hdev = hdev;
397 pso->dhpdev = ppdev->dhpdev;
398
399 /* Hook up specified functions */
400 psurf->flags &= ~HOOK_FLAGS;
401 psurf->flags |= (flHooks & HOOK_FLAGS);
402
403 /* Get palette */
404 psurf->ppal = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault);
405
406 SURFACE_UnlockSurface(psurf);
407
408 return TRUE;
409 }
410
411 BOOL
412 APIENTRY
413 EngModifySurface(
414 IN HSURF hsurf,
415 IN HDEV hdev,
416 IN FLONG flHooks,
417 IN FLONG flSurface,
418 IN DHSURF dhsurf,
419 OUT VOID *pvScan0,
420 IN LONG lDelta,
421 IN VOID *pvReserved)
422 {
423 SURFOBJ *pso;
424 PSURFACE psurf;
425 PDEVOBJ* ppdev;
426
427 psurf = SURFACE_LockSurface(hsurf);
428 if (psurf == NULL)
429 {
430 return FALSE;
431 }
432
433 ppdev = (PDEVOBJ*)hdev;
434 pso = &psurf->SurfObj;
435 pso->dhsurf = dhsurf;
436 pso->lDelta = lDelta;
437 pso->pvScan0 = pvScan0;
438
439 /* Associate the hdev */
440 pso->hdev = hdev;
441 pso->dhpdev = ppdev->dhpdev;
442
443 /* Hook up specified functions */
444 psurf->flags &= ~HOOK_FLAGS;
445 psurf->flags |= (flHooks & HOOK_FLAGS);
446
447 /* Get palette */
448 psurf->ppal = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault);
449
450 SURFACE_UnlockSurface(psurf);
451
452 return TRUE;
453 }
454
455
456 BOOL
457 APIENTRY
458 EngDeleteSurface(IN HSURF hsurf)
459 {
460 GDIOBJ_SetOwnership(hsurf, PsGetCurrentProcess());
461 SURFACE_FreeSurfaceByHandle(hsurf);
462 return TRUE;
463 }
464
465 BOOL
466 APIENTRY
467 EngEraseSurface(
468 SURFOBJ *pso,
469 RECTL *prcl,
470 ULONG iColor)
471 {
472 ASSERT(pso);
473 ASSERT(prcl);
474 return FillSolid(pso, prcl, iColor);
475 }
476
477 /*
478 * @implemented
479 */
480 SURFOBJ * APIENTRY
481 NtGdiEngLockSurface(IN HSURF hsurf)
482 {
483 return EngLockSurface(hsurf);
484 }
485
486
487 SURFOBJ *
488 APIENTRY
489 EngLockSurface(IN HSURF hsurf)
490 {
491 SURFACE *psurf = GDIOBJ_ShareLockObj(hsurf, GDI_OBJECT_TYPE_BITMAP);
492
493 if (psurf != NULL)
494 return &psurf->SurfObj;
495
496 return NULL;
497 }
498
499 VOID
500 APIENTRY
501 NtGdiEngUnlockSurface(IN SURFOBJ *pso)
502 {
503 EngUnlockSurface(pso);
504 }
505
506 VOID
507 APIENTRY
508 EngUnlockSurface(IN SURFOBJ *pso)
509 {
510 if (pso != NULL)
511 {
512 SURFACE *psurf = CONTAINING_RECORD(pso, SURFACE, SurfObj);
513 GDIOBJ_ShareUnlockObjByPtr((POBJ)psurf);
514 }
515 }
516
517 /* EOF */