[SHELL-EXPERIMENTS]
[reactos.git] / 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 pso->lDelta = lDelta;
456 pso->pvScan0 = pvScan0;
457
458 /* Associate the hdev */
459 pso->hdev = hdev;
460 pso->dhpdev = ppdev->dhpdev;
461
462 /* Hook up specified functions */
463 psurf->flags &= ~HOOK_FLAGS;
464 psurf->flags |= (flHooks & HOOK_FLAGS);
465
466 /* Assign the PDEV's palette */
467 ppal = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault);
468 SURFACE_vSetPalette(psurf, ppal);
469 PALETTE_ShareUnlockPalette(ppal);
470
471 SURFACE_ShareUnlockSurface(psurf);
472
473 return TRUE;
474 }
475
476
477 BOOL
478 APIENTRY
479 EngDeleteSurface(
480 _In_ _Post_ptr_invalid_ HSURF hsurf)
481 {
482 PSURFACE psurf;
483
484 psurf = SURFACE_ShareLockSurface(hsurf);
485 if (!psurf)
486 {
487 DPRINT1("Could not reference surface to delete\n");
488 return FALSE;
489 }
490
491 GDIOBJ_vDeleteObject(&psurf->BaseObject);
492 return TRUE;
493 }
494
495 BOOL
496 APIENTRY
497 EngEraseSurface(
498 _In_ SURFOBJ *pso,
499 _In_ RECTL *prcl,
500 _In_ ULONG iColor)
501 {
502 ASSERT(pso);
503 ASSERT(prcl);
504 return FillSolid(pso, prcl, iColor);
505 }
506
507 /*
508 * @implemented
509 */
510 SURFOBJ * APIENTRY
511 NtGdiEngLockSurface(IN HSURF hsurf)
512 {
513 return EngLockSurface(hsurf);
514 }
515
516
517 SURFOBJ *
518 APIENTRY
519 EngLockSurface(
520 _In_ HSURF hsurf)
521 {
522 SURFACE *psurf = SURFACE_ShareLockSurface(hsurf);
523
524 return psurf ? &psurf->SurfObj : NULL;
525 }
526
527 VOID
528 APIENTRY
529 NtGdiEngUnlockSurface(IN SURFOBJ *pso)
530 {
531 UNIMPLEMENTED;
532 ASSERT(FALSE);
533 }
534
535 VOID
536 APIENTRY
537 EngUnlockSurface(
538 _In_ _Post_ptr_invalid_ SURFOBJ *pso)
539 {
540 if (pso != NULL)
541 {
542 SURFACE *psurf = CONTAINING_RECORD(pso, SURFACE, SurfObj);
543 SURFACE_ShareUnlockSurface(psurf);
544 }
545 }
546
547 /* EOF */