switch to super before accessing the register
[AROS.git] / rom / graphics / allocbitmap.c
blob091408cb7180469e0911afad31b1daa117d8f0c8
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Create a new BitMap
6 Lang: english
7 */
9 #include <aros/debug.h>
10 #include <string.h>
11 #include <exec/memory.h>
12 #include <utility/tagitem.h>
13 #include <proto/exec.h>
14 #include <proto/oop.h>
15 #include <proto/utility.h>
16 #include <cybergraphx/cybergraphics.h>
18 #include "graphics_intern.h"
19 #include "gfxfuncsupport.h"
20 #include "dispinfo.h"
21 #include "fakegfxhidd.h"
23 #define SET_TAG(tags, idx, tag, val) \
24 tags[idx].ti_Tag = tag ; tags[idx].ti_Data = (IPTR)val;
26 #define SET_BM_TAG(tags, idx, tag, val) \
27 SET_TAG(tags, idx, aHidd_BitMap_ ## tag, val)
29 static HIDDT_StdPixFmt const cyber2hidd_pixfmt[] =
31 vHidd_StdPixFmt_LUT8,
32 vHidd_StdPixFmt_RGB15,
33 vHidd_StdPixFmt_BGR15,
34 vHidd_StdPixFmt_RGB15_LE,
35 vHidd_StdPixFmt_BGR15_LE,
36 vHidd_StdPixFmt_RGB16,
37 vHidd_StdPixFmt_BGR16,
38 vHidd_StdPixFmt_RGB16_LE,
39 vHidd_StdPixFmt_BGR16_LE,
40 vHidd_StdPixFmt_RGB24,
41 vHidd_StdPixFmt_BGR24,
42 vHidd_StdPixFmt_ARGB32,
43 vHidd_StdPixFmt_BGRA32,
44 vHidd_StdPixFmt_RGBA32
47 /*****************************************************************************
49 NAME */
50 #include <graphics/gfx.h>
51 #include <proto/graphics.h>
53 AROS_LH5(struct BitMap *, AllocBitMap,
55 /* SYNOPSIS */
56 AROS_LHA(UWORD , sizex, D0),
57 AROS_LHA(UWORD , sizey, D1),
58 AROS_LHA(ULONG , depth, D2),
59 AROS_LHA(ULONG , flags, D3),
60 AROS_LHA(struct BitMap *, friend_bitmap, A0),
62 /* LOCATION */
63 struct GfxBase *, GfxBase, 153, Graphics)
65 /* FUNCTION
66 Allocates and initializes a bitmap structure. Allocates and
67 initializes bitplane data, and sets the bitmap's planes to point to
68 it.
70 INPUTS
71 sizex, sizey - The width and height in pixels
73 depth - The depth of the bitmap. A depth of 1 will allocate a
74 bitmap for two colors, a depth of 24 will allocate a bitmap for
75 16 million colors. Pixels with AT LEAST this many bits will be
76 allocated.
78 flags - One of these flags:
80 BMF_CLEAR: Fill the bitmap with color 0.
82 BMF_DISPLAYABLE: to specify that this bitmap data should
83 be allocated in such a manner that it can be displayed.
84 Displayable data has more severe alignment restrictions
85 than non-displayable data in some systems.
86 Note that it may be not enough to specify only this flag
87 to make the bitmap really displayable. See "INTERNALS"
88 section below.
90 BMF_INTERLEAVED: tells graphics that you would like your
91 bitmap to be allocated with one large chunk of display
92 memory for all bitplanes. This minimizes color flashing on
93 deep displays. If there is not enough contiguous RAM for an
94 interleaved bitmap, graphics.library will fall back to a
95 non-interleaved one.
97 BMF_MINPLANES: causes graphics to only allocate enough
98 space in the bitmap structure for "depth" plane pointers.
99 This is for system use and should not be used by
100 applications use as it is inefficient, and may waste
101 memory.
103 BMF_SPECIALFMT: causes graphics to allocate a bitmap
104 of a standard CyberGraphX format. The format
105 (PIXFMT_????) must be stored in the 8 most significant bits.
107 BMF_RTGTAGS,
108 BMF_RTGCHECK,
109 BMF_FRIENDSTAG: Setting these flags to 1's while BMF_SPECIALFMT
110 and BMF_INVALID are set to 0 means that friend_bitmap
111 points to a taglist instead of BitMap structure.
113 friend_bitmap - pointer to another bitmap, or NULL. If this pointer
114 is passed, then the bitmap data will be allocated in
115 the most efficient form for blitting to friend_bitmap.
117 This pointer can also point to a TagList, if specified by flags.
118 In this case it may contain the following tags:
120 - BMATags_Friend (struct BitMap *)
121 An actual pointer to friend bitmap. Defaults to NULL.
123 - BMATags_Depth (ULONG)
124 Depth of the bitmap to create. Defaults to depth argument
125 of AllocBitMap().
127 - BMATags_Clear (BOOL)
128 Tells if the newly created bitmap should be explicitly
129 cleared. Defaults to the value of BMF_CLEAR flag in
130 AllocBitMap() arguments.
132 - BMATags_Displayable (BOOL)
133 Tells if the bitmap should be displayable by the hardware.
134 Defaults to the value of BMF_DISPLAYABLE flag in AllocBitMap()
135 arguments.
137 - BMATags_NoMemory (BOOL)
138 Tells AllocBitMap() not to allocate actual bitmap storage. Only
139 header is allocated and set up. Default value is FALSE.
141 - BMATags_DisplayID (ULONG)
142 Allocate a displayable bitmap for specified display mode.
144 RESULT
145 A pointer to the new bitmap.
147 NOTES
148 When allocating using a friend_bitmap bitmap, it is not safe to assume
149 anything about the structure of the bitmap data if that friend_bitmap
150 BitMap might not be a standard Amiga bitmap (for instance, if the
151 workbench is running on a non-Amiga display device, its
152 Screen->RastPort->BitMap won't be in standard Amiga format. The
153 only safe operations to perform on a non-standard BitMap are:
155 blitting it to another bitmap, which must be either a
156 standard Amiga bitmap, or a friend_bitmap of this bitmap.
158 blitting from this bitmap to a friend_bitmap bitmap or to a
159 standard Amiga bitmap.
161 attaching it to a rastport and making rendering calls.
163 Good arguments to pass for the friend_bitmap are your window's
164 RPort->BitMap, and your screen's RastPort->BitMap. Do NOT pass
165 &(screenptr->BitMap)!
167 BitMaps not allocated with BMF_DISPLAYABLE may not be used as
168 Intuition Custom BitMaps or as RasInfo->BitMaps. They may be
169 blitted to a BMF_DISPLAYABLE BitMap, using one of the BltBitMap()
170 family of functions.
172 When allocating a displayable bitmap, make sure that its size is
173 within limits allowed by the display driver. Use GetDisplayInfoData()
174 with DTAG_DIMS in order to obtain the needed information.
176 EXAMPLE
178 BUGS
180 SEE ALSO
181 FreeBitMap()
183 INTERNALS
184 In order to allocate a displayable bitmap, you need to pass
185 BMF_MINPLANES in addition to BMF_DISPLAYABLE flag. This is
186 standard CGX convention. You may use BMF_REQUESTVMEM definition
187 for this.
189 *****************************************************************************/
191 AROS_LIBFUNC_INIT
193 struct BitMap *nbm;
194 HIDDT_ModeID hiddmode = vHidd_ModeID_Invalid;
195 struct DisplayInfoHandle *dh;
196 struct monitor_driverdata *drv = NULL;
197 ULONG clear = flags & BMF_CLEAR;
198 BOOL alloc = TRUE;
200 if (BITMAPFLAGS_ARE_EXTENDED(flags))
202 struct TagItem *tag, *tstate = (struct TagItem *)friend_bitmap;
204 friend_bitmap = NULL;
206 while ((tag = NextTagItem(&tstate)))
208 switch (tag->ti_Tag) {
209 case BMATags_Friend:
210 friend_bitmap = (struct BitMap *)tag->ti_Data;
211 break;
213 case BMATags_Depth:
214 depth = tag->ti_Data;
215 break;
217 case BMATags_Clear:
218 clear = tag->ti_Data;
219 break;
221 case BMATags_NoMemory:
222 alloc = !tag->ti_Data;
223 break;
225 case BMATags_DisplayID:
226 dh = FindDisplayInfo(tag->ti_Data);
227 if (!dh)
228 return NULL;
230 drv = dh->drv;
231 hiddmode = dh->id;
232 flags |= BMF_REQUESTVMEM;
234 break;
239 ASSERT_VALID_PTR_OR_NULL(friend_bitmap);
240 D(bug("AllocBitMap(%u, %u, %u, 0x%08lX)\n", sizex, sizey, depth, flags));
241 D(bug("[AllocBitMap] ModeID: 0x%08lX, friend_bitmap: 0x%p\n", hiddmode, friend_bitmap));
244 If the depth is too large or the bitmap should be displayable or
245 there is a friend_bitmap bitmap and that's not a normal bitmap, then
246 call the RTG driver.
248 if ((depth > 8) || (hiddmode != vHidd_ModeID_Invalid) ||
249 (friend_bitmap && (friend_bitmap->Flags & BMF_SPECIALFMT)) ||
250 (friend_bitmap && (friend_bitmap->pad == HIDD_BM_PAD_MAGIC)) ||
251 (flags & BMF_SPECIALFMT) ||
252 (flags & BMF_DISPLAYABLE))
254 struct TagItem bm_tags[8];
255 HIDDT_StdPixFmt stdpf = vHidd_StdPixFmt_Unknown;
257 D(bug("[AllocBitMap] Allocating HIDD bitmap\n"));
259 /* Set size */
260 SET_BM_TAG( bm_tags, 0, Width, sizex );
261 SET_BM_TAG( bm_tags, 1, Height, sizey );
263 /* Set friend bitmap */
264 SET_TAG(bm_tags, 3, TAG_IGNORE, 0);
265 if (friend_bitmap && IS_HIDD_BM(friend_bitmap))
267 OOP_Object *friend_obj = HIDD_BM_OBJ(friend_bitmap);
269 D(bug("[AllocBitMap] Setting friend bitmap 0x%p, object 0x%p\n", friend_bitmap, friend_obj));
272 * Friend bitmap may hold a fakegfx bitmap object.
273 * fakegfx is our proxy layer on top of graphics drivers, providing
274 * software mouse pointer implementation. Graphics drivers do (and must)
275 * not know about fakegfx, so we need to de-masquerade such objects.
277 if (OOP_OCLASS(friend_obj) == CDD(GfxBase)->fakefbclass)
279 OOP_GetAttr(friend_obj, aHidd_FakeFB_RealBitMap, (IPTR *)&friend_obj);
280 D(bug("[AllocBitMap] Fakefb friend de-masqueraded to 0x%p\n", friend_obj));
283 SET_BM_TAG(bm_tags, 3, Friend, friend_obj);
286 * If we have no ModeID specified, obtain it from friend.
287 * This may assist some display drivers (especially hosted ones) in bitmap class selection.
288 * They may want to use host OS bitmap objects for non-displayable bitmaps which are friends
289 * of displayable ones. In this case they may simply check against ModeID != vHidd_ModeID_Invalid,
290 * and don't have to check friend object by themselves.
292 if (hiddmode == vHidd_ModeID_Invalid)
293 hiddmode = HIDD_BM_HIDDMODE(friend_bitmap);
295 if (depth <= 8) /* CHECKME: only set depth if planar? */
296 depth = HIDD_BM_REALDEPTH(friend_bitmap);
298 /* Obtain also GFX driver from friend bitmap */
299 drv = HIDD_BM_DRVDATA(friend_bitmap);
302 SET_BM_TAG( bm_tags, 2, Depth, depth );
304 /* Now let's deal with pixelformat */
305 if (flags & BMF_SPECIALFMT)
307 ULONG cgxpf = DOWNSHIFT_PIXFMT(flags);
309 if (cgxpf <= PIXFMT_RGBA32)
310 stdpf = cyber2hidd_pixfmt[cgxpf];
312 else if ((!friend_bitmap) && (hiddmode == vHidd_ModeID_Invalid))
314 /* If there is neither pixelformat nor friend bitmap nor ModeID specified,
315 we have to use some default pixelformat depending on the depth */
316 if (depth > 24)
317 stdpf = vHidd_StdPixFmt_ARGB32;
318 else if (depth > 16)
319 stdpf = vHidd_StdPixFmt_RGB24;
320 else if (depth > 15)
321 stdpf = vHidd_StdPixFmt_RGB16;
322 else if (depth > 8)
323 stdpf = vHidd_StdPixFmt_RGB15;
324 else
325 stdpf = vHidd_StdPixFmt_LUT8;
327 /* If we have a friend bitmap, pixelformat will be
328 picked up from it */
330 if (stdpf != vHidd_StdPixFmt_Unknown)
332 D(bug("[AllocBitMap] Setting pixelformat to %d\n", stdpf));
333 SET_BM_TAG(bm_tags, 4, StdPixFmt, stdpf);
334 hiddmode = vHidd_ModeID_Invalid;
336 else if (hiddmode != vHidd_ModeID_Invalid)
338 D(bug("[AllocBitMap] Setting ModeID to 0x%08lX\n", hiddmode));
339 SET_BM_TAG(bm_tags, 4, ModeID, hiddmode);
341 else
344 * SET_TAG() is TWO operators, so we absolutely need parenthesis here.
345 * Remember this!
347 SET_TAG(bm_tags, 4, TAG_IGNORE, 0);
348 hiddmode = vHidd_ModeID_Invalid;
351 /* Set Displayable attribute */
352 SET_BM_TAG(bm_tags, 5, Displayable, ((flags & BMF_REQUESTVMEM) == BMF_REQUESTVMEM) || ((flags & BMF_DISPLAYABLE) == BMF_DISPLAYABLE));
353 D(bug("[AllocBitMap] Displayable: %d\n", bm_tags[5].ti_Data));
356 SET_TAG(bm_tags, 7, TAG_DONE, 0);
358 /* Allocate an extra planes for HIDD bitmap info */
359 nbm = AllocMem (sizeof (struct BitMap) + sizeof(PLANEPTR) * HIDD_BM_EXTRAPLANES, MEMF_ANY|MEMF_CLEAR);
360 D(bug("[AllocBitMap] Allocated bitmap structure: 0x%p\n", nbm));
362 if (nbm)
364 OOP_Object *bm_obj = NULL;
365 BOOL ok = TRUE;
367 SET_BM_TAG(bm_tags, 6, BMStruct, nbm);
369 /* Use the memory driver if we didn't get another object in any way */
370 if (!drv)
371 drv = (struct monitor_driverdata *)CDD(GfxBase);
373 if (alloc)
375 bm_obj = HIDD_Gfx_NewBitMap(drv->gfxhidd, bm_tags);
376 D(bug("[AllocBitMap] Created bitmap object 0x%p\n", bm_obj));
377 if (!bm_obj)
378 ok = FALSE;
381 if (ok)
383 ULONG align = 15;
384 HIDDT_ColorModel colmod = -1;
386 if (alloc)
388 OOP_Object *pf;
391 * It is possible that the HIDD had to allocate a larger depth than that supplied, so
392 * we should get back the correct depth.
393 * This is because layers.library might want to allocate offscreen bitmaps to
394 * store obscured areas, and those offscreen bitmaps should be of the same depth as
395 * onscreen ones.
397 sizex = OOP_GET(bm_obj, aHidd_BitMap_Width);
398 sizey = OOP_GET(bm_obj, aHidd_BitMap_Height);
399 depth = OOP_GET(bm_obj, aHidd_BitMap_Depth);
400 align = OOP_GET(bm_obj, aHidd_BitMap_Align) - 1;
402 OOP_GetAttr(bm_obj, aHidd_BitMap_PixFmt, (IPTR *)&pf);
403 OOP_GetAttr(pf, aHidd_PixFmt_ColorModel, &colmod);
405 D(bug("[AllocBitMap] Resulting HIDD bitmap: %ldx%ldx%ld (%ld px-aligned)\n", sizex, sizey, depth, align));
407 /* Store object and supplementary data in plane array */
408 HIDD_BM_OBJ(nbm) = bm_obj;
409 HIDD_BM_COLMOD(nbm) = colmod;
410 HIDD_BM_COLMAP(nbm) = (OOP_Object *)OOP_GET(bm_obj, aHidd_BitMap_ColorMap);
411 HIDD_BM_REALDEPTH(nbm) = depth;
413 else
415 /* There's nothing to clear if we don't allocate an object */
416 clear = FALSE;
419 HIDD_BM_DRVDATA(nbm) = drv;
420 HIDD_BM_HIDDMODE(nbm) = hiddmode;
422 nbm->Rows = sizey;
423 nbm->BytesPerRow = (((sizex + align) & ~align) >> 3);
424 #if BMDEPTH_COMPATIBILITY
425 nbm->Depth = (depth > 8) ? 8 : depth;
426 #else
427 nbm->Depth = depth;
428 #endif
429 /* TODO: Allow interleaved Amiga chipset bitmaps. */
430 nbm->Flags = (flags & ~BMF_INTERLEAVED) | BMF_SPECIALFMT;
432 /* If this is a displayable bitmap, create a color table for it */
433 if (bm_obj && (friend_bitmap ||
434 (flags & BMF_REQUESTVMEM) == BMF_REQUESTVMEM))
436 HIDD_BM_FLAGS(nbm) |= HIDD_BMF_SCREEN_BITMAP;
438 if (friend_bitmap && IS_HIDD_BM(friend_bitmap))
440 /* We got a friend_bitmap bitmap. We inherit its
441 colormap.
442 !!! NOTE !!! If this is used after the
443 friend_bitmap bitmap is freed it means trouble,
444 as the colortab mem will no longer be valid */
445 OOP_Object *oldcolmap;
447 oldcolmap = HIDD_BM_SetColorMap(bm_obj, HIDD_BM_COLMAP(friend_bitmap));
448 if (oldcolmap)
449 OOP_DisposeObject(oldcolmap);
451 HIDD_BM_COLMAP(nbm) = HIDD_BM_COLMAP(friend_bitmap);
452 HIDD_BM_PIXTAB(nbm) = HIDD_BM_PIXTAB(friend_bitmap);
453 HIDD_BM_COLMOD(nbm) = HIDD_BM_COLMOD(friend_bitmap);
454 HIDD_BM_REALDEPTH(nbm) = HIDD_BM_REALDEPTH(friend_bitmap);
456 HIDD_BM_FLAGS(nbm) |= HIDD_BMF_SHARED_PIXTAB;
458 else
460 /* Allocate a pixtab */
461 HIDD_BM_PIXTAB(nbm) = AllocVec(sizeof (HIDDT_Pixel) * AROS_PALETTE_SIZE, MEMF_ANY);
463 if (HIDD_BM_PIXTAB(nbm))
465 /* Set this palette to all black by default */
467 HIDDT_Color col;
468 ULONG i;
470 col.red = 0;
471 col.green = 0;
472 col.blue = 0;
473 col.alpha = 0;
475 if (vHidd_ColorModel_Palette == colmod || vHidd_ColorModel_TrueColor == colmod)
477 ULONG numcolors;
479 numcolors = 1L << ((depth <= 8) ? depth : 8);
481 /* Set palette to all black */
482 for (i = 0; i < numcolors; i ++)
484 HIDD_BM_SetColors(bm_obj, &col, i, 1);
485 HIDD_BM_PIXTAB(nbm)[i] = col.pixval;
488 } /* if (pixtab successfully allocated) */
489 else
490 ok = FALSE;
494 if (ok)
496 struct BitMap *pbm = NULL;
498 if (clear)
499 BltBitMap(nbm, 0, 0, nbm, 0, 0, sizex, sizey, 0x00, 0xFF, NULL);
501 /* Is there a planar memory map? */
502 OOP_GetAttr(bm_obj, aHidd_PlanarBM_BitMap, (IPTR *)&pbm);
503 if (pbm) {
504 int i;
505 for (i = 0; i < 8; i++)
506 nbm->Planes[i] = pbm->Planes[i];
507 /* Mark this as a 'standard' bitmap */
508 nbm->Flags &= ~BMF_SPECIALFMT;
509 nbm->Flags |= BMF_STANDARD | (flags & BMF_DISPLAYABLE);
512 /* Mark this is a HIDD bitmap via the pad field */
513 nbm->pad = HIDD_BM_PAD_MAGIC;
515 ReturnPtr("AllocBitMap", struct BitMap *, nbm);
518 HIDD_Gfx_DisposeBitMap(drv->gfxhidd, bm_obj);
519 } /* if (bitmap object allocated) */
521 FreeMem(nbm, sizeof (struct BitMap));
522 nbm = NULL;
524 } /* if (nbm) */
527 else /* Otherwise init a plain Amiga bitmap. TODO: BMF_INTERLEAVED support */
529 nbm = AllocMem (sizeof(struct BitMap) + ((depth > 8) ? (depth - 8) * sizeof(PLANEPTR) : 0),
530 MEMF_ANY | MEMF_CLEAR);
532 if (nbm)
534 nbm->BytesPerRow = ((sizex + 15) >> 4) * 2;
535 nbm->Rows = sizey;
536 nbm->Flags = flags | BMF_STANDARD;
537 nbm->Depth = depth;
538 nbm->pad = 0;
540 if (alloc)
542 ULONG plane;
544 for (plane=0; plane<depth; plane++)
546 nbm->Planes[plane] = AllocRaster (sizex, sizey);
548 if (!nbm->Planes[plane])
549 break;
551 if (clear)
552 memset (nbm->Planes[plane], 0, RASSIZE(sizex,sizey));
555 if (plane != depth)
557 for (plane=0; plane<depth; plane++)
558 if (nbm->Planes[plane])
559 FreeRaster (nbm->Planes[plane], sizex, sizey);
561 FreeMem (nbm, sizeof (struct BitMap));
563 nbm = NULL;
567 ReturnPtr("AllocBitMap", struct BitMap *, nbm);
570 return nbm;
572 AROS_LIBFUNC_EXIT
573 } /* AllocBitMap */