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