xref: /reactos/win32ss/gdi/eng/surface.c (revision e1ef0787)
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 */
550