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