Exclusively lock surface bits before reading or writing them
[reactos.git] / reactos / subsys / win32k / eng / surface.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: GDI Driver Surace Functions
24 * FILE: subsys/win32k/eng/surface.c
25 * PROGRAMER: Jason Filby
26 * REVISION HISTORY:
27 * 3/7/1999: Created
28 * 9/11/2000: Updated to handle real pixel packed bitmaps (UPDATE TO DATE COMPLETED)
29 * TESTING TO BE DONE:
30 * - Create a GDI bitmap with all formats, perform all drawing operations on them, render to VGA surface
31 * refer to \test\microwin\src\engine\devdraw.c for info on correct pixel plotting for various formats
32 */
33 #include <w32k.h>
34
35 enum Rle_EscapeCodes
36 {
37 RLE_EOL = 0, /* End of line */
38 RLE_END = 1, /* End of bitmap */
39 RLE_DELTA = 2 /* Delta */
40 };
41
42 INT FASTCALL BitsPerFormat(ULONG Format)
43 {
44 switch(Format)
45 {
46 case BMF_1BPP: return 1;
47 case BMF_4BPP:
48 case BMF_4RLE: return 4;
49 case BMF_8BPP:
50 case BMF_8RLE: return 8;
51 case BMF_16BPP: return 16;
52 case BMF_24BPP: return 24;
53 case BMF_32BPP: return 32;
54 default: return 0;
55 }
56 }
57
58 ULONG FASTCALL BitmapFormat(WORD Bits, DWORD Compression)
59 {
60 switch(Compression)
61 {
62 case BI_RGB:
63 case BI_BITFIELDS:
64 switch(Bits)
65 {
66 case 1: return BMF_1BPP;
67 case 4: return BMF_4BPP;
68 case 8: return BMF_8BPP;
69 case 16: return BMF_16BPP;
70 case 24: return BMF_24BPP;
71 case 32: return BMF_32BPP;
72 }
73 return 0;
74
75 case BI_RLE4: return BMF_4RLE;
76 case BI_RLE8: return BMF_8RLE;
77
78 default: return 0;
79 }
80 }
81
82 BOOL INTERNAL_CALL
83 BITMAPOBJ_InitBitsLock(BITMAPOBJ *BitmapObj)
84 {
85 BitmapObj->BitsLock = ExAllocatePoolWithTag(NonPagedPool,
86 sizeof(FAST_MUTEX),
87 TAG_BITMAPOBJ);
88 if (NULL == BitmapObj->BitsLock)
89 {
90 return FALSE;
91 }
92
93 ExInitializeFastMutex(BitmapObj->BitsLock);
94
95 return TRUE;
96 }
97
98 void INTERNAL_CALL
99 BITMAPOBJ_CleanupBitsLock(BITMAPOBJ *BitmapObj)
100 {
101 if (NULL != BitmapObj->BitsLock)
102 {
103 ExFreePoolWithTag(BitmapObj->BitsLock, TAG_BITMAPOBJ);
104 BitmapObj->BitsLock = NULL;
105 }
106 }
107
108
109 /*
110 * @implemented
111 */
112 HBITMAP STDCALL
113 EngCreateDeviceBitmap(IN DHSURF dhsurf,
114 IN SIZEL Size,
115 IN ULONG Format)
116 {
117 HBITMAP NewBitmap;
118 SURFOBJ *SurfObj;
119
120 NewBitmap = EngCreateBitmap(Size, DIB_GetDIBWidthBytes(Size.cx, BitsPerFormat(Format)), Format, 0, NULL);
121 SurfObj = EngLockSurface((HSURF)NewBitmap);
122 SurfObj->dhsurf = dhsurf;
123 EngUnlockSurface(SurfObj);
124
125 return NewBitmap;
126 }
127
128 VOID Decompress4bpp(SIZEL Size, BYTE *CompressedBits, BYTE *UncompressedBits, LONG Delta)
129 {
130 int x = 0;
131 int y = Size.cy - 1;
132 int c;
133 int length;
134 int width = ((Size.cx+1)/2);
135 int height = Size.cy - 1;
136 BYTE *begin = CompressedBits;
137 BYTE *bits = CompressedBits;
138 BYTE *temp;
139 while (y >= 0)
140 {
141 length = *bits++ / 2;
142 if (length)
143 {
144 c = *bits++;
145 while (length--)
146 {
147 if (x >= width) break;
148 temp = UncompressedBits + (((height - y) * Delta) + x);
149 x++;
150 *temp = c;
151 }
152 } else {
153 length = *bits++;
154 switch (length)
155 {
156 case RLE_EOL:
157 x = 0;
158 y--;
159 break;
160 case RLE_END:
161 return;
162 case RLE_DELTA:
163 x += (*bits++)/2;
164 y -= (*bits++)/2;
165 break;
166 default:
167 length /= 2;
168 while (length--)
169 {
170 c = *bits++;
171 if (x < width)
172 {
173 temp = UncompressedBits + (((height - y) * Delta) + x);
174 x++;
175 *temp = c;
176 }
177 }
178 if ((bits - begin) & 1)
179 bits++;
180 }
181 }
182 }
183 }
184
185 VOID Decompress8bpp(SIZEL Size, BYTE *CompressedBits, BYTE *UncompressedBits, LONG Delta)
186 {
187 int x = 0;
188 int y = Size.cy - 1;
189 int c;
190 int length;
191 int width = Size.cx;
192 int height = Size.cy - 1;
193 BYTE *begin = CompressedBits;
194 BYTE *bits = CompressedBits;
195 BYTE *temp;
196 while (y >= 0)
197 {
198 length = *bits++;
199 if (length)
200 {
201 c = *bits++;
202 while (length--)
203 {
204 if (x >= width) break;
205 temp = UncompressedBits + (((height - y) * Delta) + x);
206 x++;
207 *temp = c;
208 }
209 } else {
210 length = *bits++;
211 switch (length)
212 {
213 case RLE_EOL:
214 x = 0;
215 y--;
216 break;
217 case RLE_END:
218 return;
219 case RLE_DELTA:
220 x += *bits++;
221 y -= *bits++;
222 break;
223 default:
224 while (length--)
225 {
226 c = *bits++;
227 if (x < width)
228 {
229 temp = UncompressedBits + (((height - y) * Delta) + x);
230 x++;
231 *temp = c;
232 }
233 }
234 if ((bits - begin) & 1)
235 bits++;
236 }
237 }
238 }
239 }
240
241 HBITMAP FASTCALL
242 IntCreateBitmap(IN SIZEL Size,
243 IN LONG Width,
244 IN ULONG Format,
245 IN ULONG Flags,
246 IN PVOID Bits)
247 {
248 HBITMAP NewBitmap;
249 SURFOBJ *SurfObj;
250 BITMAPOBJ *BitmapObj;
251 PVOID UncompressedBits;
252 ULONG UncompressedFormat;
253
254 if (Format == 0)
255 return 0;
256
257 NewBitmap = BITMAPOBJ_AllocBitmap();
258 if (NewBitmap == NULL)
259 return 0;
260
261 BitmapObj = BITMAPOBJ_LockBitmap(NewBitmap);
262 if (! BITMAPOBJ_InitBitsLock(BitmapObj))
263 {
264 BITMAPOBJ_UnlockBitmap(BitmapObj);
265 BITMAPOBJ_FreeBitmap(NewBitmap);
266 return 0;
267 }
268 SurfObj = &BitmapObj->SurfObj;
269
270 if (Format == BMF_4RLE)
271 {
272 SurfObj->lDelta = DIB_GetDIBWidthBytes(Size.cx, BitsPerFormat(BMF_4BPP));
273 SurfObj->cjBits = SurfObj->lDelta * Size.cy;
274 UncompressedFormat = BMF_4BPP;
275 UncompressedBits = EngAllocMem(FL_ZERO_MEMORY, SurfObj->cjBits, 0);
276 Decompress4bpp(Size, (BYTE *)Bits, (BYTE *)UncompressedBits, SurfObj->lDelta);
277 }
278 else if (Format == BMF_8RLE)
279 {
280 SurfObj->lDelta = DIB_GetDIBWidthBytes(Size.cx, BitsPerFormat(BMF_8BPP));
281 SurfObj->cjBits = SurfObj->lDelta * Size.cy;
282 UncompressedFormat = BMF_8BPP;
283 UncompressedBits = EngAllocMem(FL_ZERO_MEMORY, SurfObj->cjBits, 0);
284 Decompress8bpp(Size, (BYTE *)Bits, (BYTE *)UncompressedBits, SurfObj->lDelta);
285 }
286 else
287 {
288 SurfObj->lDelta = abs(Width);
289 SurfObj->cjBits = SurfObj->lDelta * Size.cy;
290 UncompressedBits = Bits;
291 UncompressedFormat = Format;
292 }
293
294 if (UncompressedBits != NULL)
295 {
296 SurfObj->pvBits = UncompressedBits;
297 }
298 else
299 {
300 if (SurfObj->cjBits == 0)
301 {
302 SurfObj->pvBits = NULL;
303 }
304 else
305 {
306 if (0 != (Flags & BMF_USERMEM))
307 {
308 SurfObj->pvBits = EngAllocUserMem(SurfObj->cjBits, 0);
309 }
310 else
311 {
312 SurfObj->pvBits = EngAllocMem(0 != (Flags & BMF_NOZEROINIT) ? 0 : FL_ZERO_MEMORY,
313 SurfObj->cjBits, 0);
314 }
315 if (SurfObj->pvBits == NULL)
316 {
317 BITMAPOBJ_UnlockBitmap(BitmapObj);
318 BITMAPOBJ_FreeBitmap(NewBitmap);
319 return 0;
320 }
321 }
322 }
323
324
325 if (0 == (Flags & BMF_TOPDOWN))
326 {
327 SurfObj->pvScan0 = (PVOID) ((ULONG_PTR) SurfObj->pvBits + SurfObj->cjBits - SurfObj->lDelta);
328 SurfObj->lDelta = - SurfObj->lDelta;
329 }
330 else
331 {
332 SurfObj->pvScan0 = SurfObj->pvBits;
333 }
334
335 SurfObj->dhsurf = 0; /* device managed surface */
336 SurfObj->hsurf = (HSURF)NewBitmap;
337 SurfObj->dhpdev = NULL;
338 SurfObj->hdev = NULL;
339 SurfObj->sizlBitmap = Size;
340 SurfObj->iBitmapFormat = UncompressedFormat;
341 SurfObj->iType = STYPE_BITMAP;
342 SurfObj->fjBitmap = Flags & (BMF_TOPDOWN | BMF_NOZEROINIT);
343 SurfObj->iUniq = 0;
344
345 BitmapObj->flHooks = 0;
346 BitmapObj->flFlags = 0;
347 BitmapObj->dimension.cx = 0;
348 BitmapObj->dimension.cy = 0;
349 BitmapObj->dib = NULL;
350
351 BITMAPOBJ_UnlockBitmap(BitmapObj);
352
353 return NewBitmap;
354 }
355
356 /*
357 * @implemented
358 */
359 HBITMAP STDCALL
360 EngCreateBitmap(IN SIZEL Size,
361 IN LONG Width,
362 IN ULONG Format,
363 IN ULONG Flags,
364 IN PVOID Bits)
365 {
366 HBITMAP NewBitmap;
367
368 NewBitmap = IntCreateBitmap(Size, Width, Format, Flags, Bits);
369 if ( !NewBitmap )
370 return 0;
371
372 GDIOBJ_SetOwnership(NewBitmap, NULL);
373
374 return NewBitmap;
375 }
376
377 /*
378 * @unimplemented
379 */
380 HSURF STDCALL
381 EngCreateDeviceSurface(IN DHSURF dhsurf,
382 IN SIZEL Size,
383 IN ULONG Format)
384 {
385 HSURF NewSurface;
386 SURFOBJ *SurfObj;
387 BITMAPOBJ *BitmapObj;
388
389 NewSurface = (HSURF)BITMAPOBJ_AllocBitmap();
390 if (NewSurface == NULL)
391 return 0;
392
393 BitmapObj = BITMAPOBJ_LockBitmap(NewSurface);
394 if (! BITMAPOBJ_InitBitsLock(BitmapObj))
395 {
396 BITMAPOBJ_UnlockBitmap(BitmapObj);
397 BITMAPOBJ_FreeBitmap(NewSurface);
398 return 0;
399 }
400 SurfObj = &BitmapObj->SurfObj;
401
402 GDIOBJ_SetOwnership(NewSurface, NULL);
403
404 SurfObj->dhsurf = dhsurf;
405 SurfObj->hsurf = NewSurface;
406 SurfObj->sizlBitmap = Size;
407 SurfObj->iBitmapFormat = Format;
408 SurfObj->lDelta = DIB_GetDIBWidthBytes(Size.cx, BitsPerFormat(Format));
409 SurfObj->iType = STYPE_DEVICE;
410 SurfObj->iUniq = 0;
411
412 BitmapObj->flHooks = 0;
413
414 BITMAPOBJ_UnlockBitmap(BitmapObj);
415
416 return NewSurface;
417 }
418
419 PFN FASTCALL DriverFunction(DRVENABLEDATA *DED, ULONG DriverFunc)
420 {
421 ULONG i;
422
423 for(i=0; i<DED->c; i++)
424 {
425 if(DED->pdrvfn[i].iFunc == DriverFunc)
426 return DED->pdrvfn[i].pfn;
427 }
428 return NULL;
429 }
430
431 /*
432 * @implemented
433 */
434 BOOL STDCALL
435 EngAssociateSurface(IN HSURF Surface,
436 IN HDEV Dev,
437 IN ULONG Hooks)
438 {
439 SURFOBJ *SurfObj;
440 BITMAPOBJ *BitmapObj;
441 GDIDEVICE* Device;
442
443 Device = (GDIDEVICE*)Dev;
444
445 BitmapObj = BITMAPOBJ_LockBitmap(Surface);
446 ASSERT(BitmapObj);
447 SurfObj = &BitmapObj->SurfObj;
448
449 /* Associate the hdev */
450 SurfObj->hdev = Dev;
451 SurfObj->dhpdev = Device->PDev;
452
453 /* Hook up specified functions */
454 BitmapObj->flHooks = Hooks;
455
456 BITMAPOBJ_UnlockBitmap(BitmapObj);
457
458 return TRUE;
459 }
460
461 /*
462 * @implemented
463 */
464 BOOL STDCALL
465 EngModifySurface(
466 IN HSURF hsurf,
467 IN HDEV hdev,
468 IN FLONG flHooks,
469 IN FLONG flSurface,
470 IN DHSURF dhsurf,
471 OUT VOID *pvScan0,
472 IN LONG lDelta,
473 IN VOID *pvReserved)
474 {
475 SURFOBJ *pso;
476
477 pso = EngLockSurface(hsurf);
478 if (pso == NULL)
479 {
480 return FALSE;
481 }
482
483 if (!EngAssociateSurface(hsurf, hdev, flHooks))
484 {
485 EngUnlockSurface(pso);
486
487 return FALSE;
488 }
489
490 pso->dhsurf = dhsurf;
491 pso->lDelta = lDelta;
492 pso->pvScan0 = pvScan0;
493
494 EngUnlockSurface(pso);
495
496 return TRUE;
497 }
498
499 /*
500 * @implemented
501 */
502 BOOL STDCALL
503 EngDeleteSurface(IN HSURF Surface)
504 {
505 GDIOBJ_SetOwnership(Surface, PsGetCurrentProcess());
506 BITMAPOBJ_FreeBitmap(Surface);
507 return TRUE;
508 }
509
510 /*
511 * @implemented
512 */
513 BOOL STDCALL
514 EngEraseSurface(SURFOBJ *Surface,
515 RECTL *Rect,
516 ULONG iColor)
517 {
518 ASSERT(Surface);
519 ASSERT(Rect);
520 return FillSolid(Surface, Rect, iColor);
521 }
522
523 #define GDIBdyToHdr(body) \
524 ((PGDIOBJHDR)(body) - 1)
525
526 /*
527 * @implemented
528 */
529 SURFOBJ * STDCALL
530 EngLockSurface(IN HSURF Surface)
531 {
532 BITMAPOBJ *bmp = GDIOBJ_ShareLockObj(Surface, GDI_OBJECT_TYPE_BITMAP);
533
534 if (bmp != NULL)
535 return &bmp->SurfObj;
536
537 return NULL;
538 }
539
540 /*
541 * @implemented
542 */
543 VOID STDCALL
544 EngUnlockSurface(IN SURFOBJ *Surface)
545 {
546 if (Surface != NULL)
547 GDIOBJ_UnlockObjByPtr(Surface);
548 }
549 /* EOF */