[WIN32SS] Add extra logging to failed SURFACE_AllocSurface calls. CORE-13036
[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. (STYPE_BITMAP, sizl.cx=%ld, sizl.cy=%ld, iFormat=%lu, fl=%lu, lWidth=%ld, pvBits=0x%p)\n",
328 sizl.cx, sizl.cy, iFormat, fl, lWidth, pvBits);
329 return NULL;
330 }
331
332 /* Get the handle for the bitmap */
333 hbmp = (HBITMAP)psurf->SurfObj.hsurf;
334
335 /* Set public ownership */
336 GDIOBJ_vSetObjectOwner(&psurf->BaseObject, GDI_OBJ_HMGR_PUBLIC);
337
338 /* Unlock the surface and return */
339 SURFACE_UnlockSurface(psurf);
340 return hbmp;
341 }
342
343 /*
344 * @implemented
345 */
346 HBITMAP
347 APIENTRY
348 EngCreateDeviceBitmap(
349 _In_ DHSURF dhsurf,
350 _In_ SIZEL sizl,
351 _In_ ULONG iFormat)
352 {
353 PSURFACE psurf;
354 HBITMAP hbmp;
355
356 /* Allocate a surface */
357 psurf = SURFACE_AllocSurface(STYPE_DEVBITMAP,
358 sizl.cx,
359 sizl.cy,
360 iFormat,
361 0,
362 0,
363 0,
364 NULL);
365 if (!psurf)
366 {
367 DPRINT1("SURFACE_AllocSurface failed. (STYPE_DEVBITMAP, sizl.cx=%ld, sizl.cy=%ld, iFormat=%lu)\n",
368 sizl.cx, sizl.cy, iFormat);
369 return NULL;
370 }
371
372 /* Set the device handle */
373 psurf->SurfObj.dhsurf = dhsurf;
374
375 /* Set public ownership */
376 GDIOBJ_vSetObjectOwner(&psurf->BaseObject, GDI_OBJ_HMGR_PUBLIC);
377
378 /* Get the handle for the bitmap */
379 hbmp = (HBITMAP)psurf->SurfObj.hsurf;
380
381 /* Unlock the surface and return */
382 SURFACE_UnlockSurface(psurf);
383 return hbmp;
384 }
385
386 HSURF
387 APIENTRY
388 EngCreateDeviceSurface(
389 _In_ DHSURF dhsurf,
390 _In_ SIZEL sizl,
391 _In_ ULONG iFormat)
392 {
393 PSURFACE psurf;
394 HSURF hsurf;
395
396 /* Allocate a surface */
397 psurf = SURFACE_AllocSurface(STYPE_DEVICE,
398 sizl.cx,
399 sizl.cy,
400 iFormat,
401 0,
402 0,
403 0,
404 NULL);
405 if (!psurf)
406 {
407 DPRINT1("SURFACE_AllocSurface failed. (STYPE_DEVICE, sizl.cx=%ld, sizl.cy=%ld, iFormat=%lu)\n",
408 sizl.cx, sizl.cy, iFormat);
409 return NULL;
410 }
411
412 /* Set the device handle */
413 psurf->SurfObj.dhsurf = dhsurf;
414
415 /* Set public ownership */
416 GDIOBJ_vSetObjectOwner(&psurf->BaseObject, GDI_OBJ_HMGR_PUBLIC);
417
418 /* Get the handle for the surface */
419 hsurf = psurf->SurfObj.hsurf;
420
421 /* Unlock the surface and return */
422 SURFACE_UnlockSurface(psurf);
423 return hsurf;
424 }
425
426 BOOL
427 APIENTRY
428 EngAssociateSurface(
429 _In_ HSURF hsurf,
430 _In_ HDEV hdev,
431 _In_ FLONG flHooks)
432 {
433 SURFOBJ *pso;
434 PSURFACE psurf;
435 PDEVOBJ* ppdev;
436 PPALETTE ppal;
437
438 ppdev = (PDEVOBJ*)hdev;
439
440 /* Lock the surface */
441 psurf = SURFACE_ShareLockSurface(hsurf);
442 if (!psurf)
443 {
444 return FALSE;
445 }
446 pso = &psurf->SurfObj;
447
448 /* Associate the hdev */
449 pso->hdev = hdev;
450 pso->dhpdev = ppdev->dhpdev;
451
452 /* Hook up specified functions */
453 psurf->flags &= ~HOOK_FLAGS;
454 psurf->flags |= (flHooks & HOOK_FLAGS);
455
456 /* Assign the PDEV's palette */
457 ppal = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault);
458 SURFACE_vSetPalette(psurf, ppal);
459 PALETTE_ShareUnlockPalette(ppal);
460
461 SURFACE_ShareUnlockSurface(psurf);
462
463 return TRUE;
464 }
465
466 BOOL
467 APIENTRY
468 EngModifySurface(
469 _In_ HSURF hsurf,
470 _In_ HDEV hdev,
471 _In_ FLONG flHooks,
472 _In_ FLONG flSurface,
473 _In_ DHSURF dhsurf,
474 _In_ PVOID pvScan0,
475 _In_ LONG lDelta,
476 _Reserved_ PVOID pvReserved)
477 {
478 SURFOBJ *pso;
479 PSURFACE psurf;
480 PDEVOBJ* ppdev;
481 PPALETTE ppal;
482
483 /* Lock the surface */
484 psurf = SURFACE_ShareLockSurface(hsurf);
485 if (psurf == NULL)
486 {
487 DPRINT1("Failed to reference surface %p\n", hsurf);
488 return FALSE;
489 }
490
491 ppdev = (PDEVOBJ*)hdev;
492 pso = &psurf->SurfObj;
493 pso->dhsurf = dhsurf;
494
495 /* Associate the hdev */
496 pso->hdev = hdev;
497 pso->dhpdev = ppdev->dhpdev;
498
499 /* Hook up specified functions */
500 psurf->flags &= ~HOOK_FLAGS;
501 psurf->flags |= (flHooks & HOOK_FLAGS);
502
503 /* Assign the PDEV's palette */
504 ppal = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault);
505 SURFACE_vSetPalette(psurf, ppal);
506 PALETTE_ShareUnlockPalette(ppal);
507
508 /* Update surface flags */
509 if (flSurface & MS_NOTSYSTEMMEMORY)
510 pso->fjBitmap |= BMF_NOTSYSMEM;
511 else
512 pso->fjBitmap &= ~BMF_NOTSYSMEM;
513 if (flSurface & MS_SHAREDACCESS)
514 psurf->flags |= SHAREACCESS_SURFACE;
515 else
516 psurf->flags &= ~SHAREACCESS_SURFACE;
517
518 /* Check if the caller passed bitmap bits */
519 if ((pvScan0 != NULL) && (lDelta != 0))
520 {
521 /* Update the fields */
522 pso->pvScan0 = pvScan0;
523 pso->lDelta = lDelta;
524
525 /* This is a bitmap now! */
526 pso->iType = STYPE_BITMAP;
527
528 /* Check memory layout */
529 if (lDelta > 0)
530 {
531 /* Topdown is the normal way */
532 pso->cjBits = lDelta * pso->sizlBitmap.cy;
533 pso->pvBits = pso->pvScan0;
534 pso->fjBitmap |= BMF_TOPDOWN;
535 }
536 else
537 {
538 /* Inversed bitmap (bottom up) */
539 pso->cjBits = (-lDelta) * pso->sizlBitmap.cy;
540 pso->pvBits = (PCHAR)pso->pvScan0 - pso->cjBits - lDelta;
541 pso->fjBitmap &= ~BMF_TOPDOWN;
542 }
543 }
544 else
545 {
546 /* Set bits to NULL */
547 pso->pvBits = NULL;
548 pso->pvScan0 = NULL;
549 pso->lDelta = 0;
550
551 /* Set appropriate surface type */
552 if (pso->iType != STYPE_DEVICE)
553 pso->iType = STYPE_DEVBITMAP;
554 }
555
556 SURFACE_ShareUnlockSurface(psurf);
557
558 return TRUE;
559 }
560
561
562 BOOL
563 APIENTRY
564 EngDeleteSurface(
565 _In_ _Post_ptr_invalid_ HSURF hsurf)
566 {
567 PSURFACE psurf;
568
569 psurf = SURFACE_ShareLockSurface(hsurf);
570 if (!psurf)
571 {
572 DPRINT1("Could not reference surface %p to delete\n", hsurf);
573 return FALSE;
574 }
575
576 GDIOBJ_vDeleteObject(&psurf->BaseObject);
577 return TRUE;
578 }
579
580 BOOL
581 APIENTRY
582 EngEraseSurface(
583 _In_ SURFOBJ *pso,
584 _In_ RECTL *prcl,
585 _In_ ULONG iColor)
586 {
587 ASSERT(pso);
588 ASSERT(prcl);
589 return FillSolid(pso, prcl, iColor);
590 }
591
592 /*
593 * @implemented
594 */
595 SURFOBJ * APIENTRY
596 NtGdiEngLockSurface(IN HSURF hsurf)
597 {
598 return EngLockSurface(hsurf);
599 }
600
601
602 SURFOBJ *
603 APIENTRY
604 EngLockSurface(
605 _In_ HSURF hsurf)
606 {
607 SURFACE *psurf = SURFACE_ShareLockSurface(hsurf);
608
609 return psurf ? &psurf->SurfObj : NULL;
610 }
611
612 __kernel_entry
613 NTSTATUS
614 APIENTRY
615 NtGdiEngUnlockSurface(
616 _In_ SURFOBJ *pso)
617 {
618 UNIMPLEMENTED;
619 ASSERT(FALSE);
620 return STATUS_NOT_IMPLEMENTED;
621 }
622
623 VOID
624 APIENTRY
625 EngUnlockSurface(
626 _In_ _Post_ptr_invalid_ SURFOBJ *pso)
627 {
628 if (pso != NULL)
629 {
630 SURFACE *psurf = CONTAINING_RECORD(pso, SURFACE, SurfObj);
631 SURFACE_ShareUnlockSurface(psurf);
632 }
633 }
634
635 /* EOF */