[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 VOID
66 NTAPI
67 SURFACE_vCleanup(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
113
114 PSURFACE
115 NTAPI
116 SURFACE_AllocSurface(
117 _In_ USHORT iType,
118 _In_ ULONG cx,
119 _In_ ULONG cy,
120 _In_ ULONG iFormat,
121 _In_ ULONG fjBitmap,
122 _In_opt_ ULONG cjWidth,
123 _In_opt_ PVOID pvBits)
124 {
125 ULONG cBitsPixel, cjBits, cjObject;
126 PSURFACE psurf;
127 SURFOBJ *pso;
128 PVOID pvSection;
129
130 ASSERT(!pvBits || (iType == STYPE_BITMAP));
131
132 /* Verify format */
133 if ((iFormat < BMF_1BPP) || (iFormat > BMF_PNG))
134 {
135 DPRINT1("Invalid bitmap format: %lu\n", iFormat);
136 return NULL;
137 }
138
139 /* Get bits per pixel from the format */
140 cBitsPixel = gajBitsPerFormat[iFormat];
141
142 /* Are bits and a width in bytes given? */
143 if (pvBits && cjWidth)
144 {
145 /* Align the width (Windows compatibility, drivers expect that) */
146 cjWidth = WIDTH_BYTES_ALIGN32((cjWidth << 3) / cBitsPixel, cBitsPixel);
147 }
148 else
149 {
150 /* Calculate width from the bitmap width in pixels */
151 cjWidth = WIDTH_BYTES_ALIGN32(cx, cBitsPixel);
152 }
153
154 /* Calculate the bitmap size in bytes */
155 cjBits = cjWidth * cy;
156
157 /* Check if we need an extra large object */
158 if ((iType == STYPE_BITMAP) && (pvBits == NULL) &&
159 !(fjBitmap & BMF_USERMEM) && !(fjBitmap & BMF_KMSECTION))
160 {
161 /* Allocate an object large enough to hold the bits */
162 cjObject = sizeof(SURFACE) + cjBits;
163 }
164 else
165 {
166 /* Otherwise just allocate the SURFACE structure */
167 cjObject = sizeof(SURFACE);
168 }
169
170 /* Check for arithmetic overflow */
171 if ((cjBits < cjWidth) || (cjObject < sizeof(SURFACE)))
172 {
173 /* Fail! */
174 return NULL;
175 }
176
177 /* Allocate a SURFACE object */
178 psurf = (PSURFACE)GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_BITMAP, cjObject);
179 if (!psurf)
180 {
181 return NULL;
182 }
183
184 /* Initialize the basic fields */
185 pso = &psurf->SurfObj;
186 pso->hsurf = psurf->BaseObject.hHmgr;
187 pso->sizlBitmap.cx = cx;
188 pso->sizlBitmap.cy = cy;
189 pso->iBitmapFormat = iFormat;
190 pso->iType = iType;
191 pso->fjBitmap = (USHORT)fjBitmap;
192 pso->iUniq = InterlockedIncrement(&giUniqueSurface);
193 pso->cjBits = cjBits;
194
195 /* Check if we need a bitmap buffer */
196 if (iType == STYPE_BITMAP)
197 {
198 /* Check if we got one or if we need to allocate one */
199 if (pvBits != NULL)
200 {
201 /* Use the caller provided buffer */
202 pso->pvBits = pvBits;
203 }
204 else if (fjBitmap & BMF_USERMEM)
205 {
206 /* User mode memory was requested */
207 pso->pvBits = EngAllocUserMem(cjBits, 0);
208
209 /* Check for failure */
210 if (!pso->pvBits)
211 {
212 GDIOBJ_vDeleteObject(&psurf->BaseObject);
213 return NULL;
214 }
215 }
216 else if (fjBitmap & BMF_KMSECTION)
217 {
218 /* Use a kernel mode section */
219 pso->pvBits = EngAllocSectionMem(&pvSection,
220 (fjBitmap & BMF_NOZEROINIT) ?
221 0 : FL_ZERO_MEMORY,
222 cjBits, TAG_DIB);
223
224 /* Check for failure */
225 if (!pso->pvBits)
226 {
227 GDIOBJ_vDeleteObject(&psurf->BaseObject);
228 return NULL;
229 }
230
231 /* Free the section already, but keep the mapping */
232 EngFreeSectionMem(pvSection, NULL);
233 }
234 else
235 {
236 /* Buffer is after the object */
237 pso->pvBits = psurf + 1;
238
239 /* Zero the buffer, except requested otherwise */
240 if (!(fjBitmap & BMF_NOZEROINIT))
241 {
242 RtlZeroMemory(pso->pvBits, cjBits);
243 }
244 }
245
246 /* Set pvScan0 and lDelta */
247 if (fjBitmap & BMF_TOPDOWN)
248 {
249 /* Topdown is the normal way */
250 pso->pvScan0 = pso->pvBits;
251 pso->lDelta = cjWidth;
252 }
253 else
254 {
255 /* Inversed bitmap (bottom up) */
256 pso->pvScan0 = ((PCHAR)pso->pvBits + pso->cjBits - cjWidth);
257 pso->lDelta = -(LONG)cjWidth;
258 }
259 }
260 else
261 {
262 /* There are no bitmap bits */
263 pso->pvScan0 = pso->pvBits = NULL;
264 pso->lDelta = 0;
265 }
266
267 /* Assign a default palette and increment its reference count */
268 SURFACE_vSetPalette(psurf, appalSurfaceDefault[iFormat]);
269
270 return psurf;
271 }
272
273 HBITMAP
274 APIENTRY
275 EngCreateBitmap(
276 _In_ SIZEL sizl,
277 _In_ LONG lWidth,
278 _In_ ULONG iFormat,
279 _In_ ULONG fl,
280 _In_opt_ PVOID pvBits)
281 {
282 PSURFACE psurf;
283 HBITMAP hbmp;
284
285 /* Allocate a surface */
286 psurf = SURFACE_AllocSurface(STYPE_BITMAP,
287 sizl.cx,
288 sizl.cy,
289 iFormat,
290 fl,
291 lWidth,
292 pvBits);
293 if (!psurf)
294 {
295 DPRINT1("SURFACE_AllocSurface failed.\n");
296 return NULL;
297 }
298
299 /* Get the handle for the bitmap */
300 hbmp = (HBITMAP)psurf->SurfObj.hsurf;
301
302 /* Set public ownership */
303 GDIOBJ_vSetObjectOwner(&psurf->BaseObject, GDI_OBJ_HMGR_PUBLIC);
304
305 /* Unlock the surface and return */
306 SURFACE_UnlockSurface(psurf);
307 return hbmp;
308 }
309
310 /*
311 * @implemented
312 */
313 HBITMAP
314 APIENTRY
315 EngCreateDeviceBitmap(
316 _In_ DHSURF dhsurf,
317 _In_ SIZEL sizl,
318 _In_ ULONG iFormat)
319 {
320 PSURFACE psurf;
321 HBITMAP hbmp;
322
323 /* Allocate a surface */
324 psurf = SURFACE_AllocSurface(STYPE_DEVBITMAP,
325 sizl.cx,
326 sizl.cy,
327 iFormat,
328 0,
329 0,
330 NULL);
331 if (!psurf)
332 {
333 DPRINT1("SURFACE_AllocSurface failed.\n");
334 return NULL;
335 }
336
337 /* Set the device handle */
338 psurf->SurfObj.dhsurf = dhsurf;
339
340 /* Set public ownership */
341 GDIOBJ_vSetObjectOwner(&psurf->BaseObject, GDI_OBJ_HMGR_PUBLIC);
342
343 /* Get the handle for the bitmap */
344 hbmp = (HBITMAP)psurf->SurfObj.hsurf;
345
346 /* Unlock the surface and return */
347 SURFACE_UnlockSurface(psurf);
348 return hbmp;
349 }
350
351 HSURF
352 APIENTRY
353 EngCreateDeviceSurface(
354 _In_ DHSURF dhsurf,
355 _In_ SIZEL sizl,
356 _In_ ULONG iFormat)
357 {
358 PSURFACE psurf;
359 HSURF hsurf;
360
361 /* Allocate a surface */
362 psurf = SURFACE_AllocSurface(STYPE_DEVICE,
363 sizl.cx,
364 sizl.cy,
365 iFormat,
366 0,
367 0,
368 NULL);
369 if (!psurf)
370 {
371 DPRINT1("SURFACE_AllocSurface failed.\n");
372 return NULL;
373 }
374
375 /* Set the device handle */
376 psurf->SurfObj.dhsurf = dhsurf;
377
378 /* Set public ownership */
379 GDIOBJ_vSetObjectOwner(&psurf->BaseObject, GDI_OBJ_HMGR_PUBLIC);
380
381 /* Get the handle for the surface */
382 hsurf = psurf->SurfObj.hsurf;
383
384 /* Unlock the surface and return */
385 SURFACE_UnlockSurface(psurf);
386 return hsurf;
387 }
388
389 BOOL
390 APIENTRY
391 EngAssociateSurface(
392 _In_ HSURF hsurf,
393 _In_ HDEV hdev,
394 _In_ FLONG flHooks)
395 {
396 SURFOBJ *pso;
397 PSURFACE psurf;
398 PDEVOBJ* ppdev;
399 PPALETTE ppal;
400
401 ppdev = (PDEVOBJ*)hdev;
402
403 /* Lock the surface */
404 psurf = SURFACE_ShareLockSurface(hsurf);
405 if (!psurf)
406 {
407 return FALSE;
408 }
409 pso = &psurf->SurfObj;
410
411 /* Associate the hdev */
412 pso->hdev = hdev;
413 pso->dhpdev = ppdev->dhpdev;
414
415 /* Hook up specified functions */
416 psurf->flags &= ~HOOK_FLAGS;
417 psurf->flags |= (flHooks & HOOK_FLAGS);
418
419 /* Assign the PDEV's palette */
420 ppal = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault);
421 SURFACE_vSetPalette(psurf, ppal);
422 PALETTE_ShareUnlockPalette(ppal);
423
424 SURFACE_ShareUnlockSurface(psurf);
425
426 return TRUE;
427 }
428
429 BOOL
430 APIENTRY
431 EngModifySurface(
432 _In_ HSURF hsurf,
433 _In_ HDEV hdev,
434 _In_ FLONG flHooks,
435 _In_ FLONG flSurface,
436 _In_ DHSURF dhsurf,
437 _In_ VOID *pvScan0,
438 _In_ LONG lDelta,
439 _Reserved_ VOID *pvReserved)
440 {
441 SURFOBJ *pso;
442 PSURFACE psurf;
443 PDEVOBJ* ppdev;
444 PPALETTE ppal;
445
446 psurf = SURFACE_ShareLockSurface(hsurf);
447 if (psurf == NULL)
448 {
449 return FALSE;
450 }
451
452 ppdev = (PDEVOBJ*)hdev;
453 pso = &psurf->SurfObj;
454 pso->dhsurf = dhsurf;
455
456 /* Associate the hdev */
457 pso->hdev = hdev;
458 pso->dhpdev = ppdev->dhpdev;
459
460 /* Hook up specified functions */
461 psurf->flags &= ~HOOK_FLAGS;
462 psurf->flags |= (flHooks & HOOK_FLAGS);
463
464 /* Assign the PDEV's palette */
465 ppal = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault);
466 SURFACE_vSetPalette(psurf, ppal);
467 PALETTE_ShareUnlockPalette(ppal);
468
469 /* Check if the caller passed bitmap bits */
470 if ((pvScan0 != NULL) && (lDelta != 0))
471 {
472 /* Update the fields */
473 pso->pvScan0 = pvScan0;
474 pso->lDelta = lDelta;
475
476 /* This is a bitmap now! */
477 pso->iType = STYPE_BITMAP;
478
479 /* Check memory layout */
480 if (lDelta > 0)
481 {
482 /* Topdown is the normal way */
483 pso->cjBits = lDelta * pso->sizlBitmap.cy;
484 pso->pvBits = pso->pvScan0;
485 pso->fjBitmap |= BMF_TOPDOWN;
486 }
487 else
488 {
489 /* Inversed bitmap (bottom up) */
490 pso->cjBits = (-lDelta) * pso->sizlBitmap.cy;
491 pso->pvBits = (PCHAR)pso->pvScan0 - pso->cjBits - lDelta;
492 pso->fjBitmap &= ~BMF_TOPDOWN;
493 }
494
495 /* Update surface flags */
496 if (flSurface & MS_NOTSYSTEMMEMORY)
497 pso->fjBitmap |= BMF_NOTSYSMEM;
498 else
499 pso->fjBitmap &= ~BMF_NOTSYSMEM;
500 if (flSurface & MS_SHAREDACCESS)
501 psurf->flags |= SHAREACCESS_SURFACE;
502 else
503 psurf->flags &= ~SHAREACCESS_SURFACE;
504 }
505 else
506 {
507 /* Set bits to NULL */
508 pso->pvBits = NULL;
509 pso->pvScan0 = NULL;
510 pso->lDelta = 0;
511
512 /* Set appropriate surface type */
513 if (pso->iType != STYPE_DEVICE)
514 pso->iType = STYPE_DEVBITMAP;
515 }
516
517 SURFACE_ShareUnlockSurface(psurf);
518
519 return TRUE;
520 }
521
522
523 BOOL
524 APIENTRY
525 EngDeleteSurface(
526 _In_ _Post_ptr_invalid_ HSURF hsurf)
527 {
528 PSURFACE psurf;
529
530 psurf = SURFACE_ShareLockSurface(hsurf);
531 if (!psurf)
532 {
533 DPRINT1("Could not reference surface to delete\n");
534 return FALSE;
535 }
536
537 GDIOBJ_vDeleteObject(&psurf->BaseObject);
538 return TRUE;
539 }
540
541 BOOL
542 APIENTRY
543 EngEraseSurface(
544 _In_ SURFOBJ *pso,
545 _In_ RECTL *prcl,
546 _In_ ULONG iColor)
547 {
548 ASSERT(pso);
549 ASSERT(prcl);
550 return FillSolid(pso, prcl, iColor);
551 }
552
553 /*
554 * @implemented
555 */
556 SURFOBJ * APIENTRY
557 NtGdiEngLockSurface(IN HSURF hsurf)
558 {
559 return EngLockSurface(hsurf);
560 }
561
562
563 SURFOBJ *
564 APIENTRY
565 EngLockSurface(
566 _In_ HSURF hsurf)
567 {
568 SURFACE *psurf = SURFACE_ShareLockSurface(hsurf);
569
570 return psurf ? &psurf->SurfObj : NULL;
571 }
572
573 VOID
574 APIENTRY
575 NtGdiEngUnlockSurface(IN SURFOBJ *pso)
576 {
577 UNIMPLEMENTED;
578 ASSERT(FALSE);
579 }
580
581 VOID
582 APIENTRY
583 EngUnlockSurface(
584 _In_ _Post_ptr_invalid_ SURFOBJ *pso)
585 {
586 if (pso != NULL)
587 {
588 SURFACE *psurf = CONTAINING_RECORD(pso, SURFACE, SurfObj);
589 SURFACE_ShareUnlockSurface(psurf);
590 }
591 }
592
593 /* EOF */