Most API issues for the 1.5 definition have been resolved by now.
The current Graphtype scheme is too inflexible for architectures other than VGA-related cards.
Let's make the graphtype consist of three components: depth, scheme, and
sub-scheme, as follows :
#define GT_SCHEME_MASK 0xff0000
#define GT_SUBSCHEME_MASK 0x00ff00
#define GT_DEPTH_MASK 0x0000ff
The schemes would be :
#define GT_RGB 0x010000
#define GT_INDEXED 0x020000
#define GT_GREYSCALE 0x030000
#define GT_TEXT 0x040000
The depth is just what you'd expect.
The sub-scheme doesn't make any sense on its own. Its only purpose
would be to differentiate all the possible pixel formats within a
particular scheme + depth combination.
Here's how the current ggi_common_plb_setup values would be defined :
ggi_common_plb_setup scheme sub-scheme depth
sp1a8lbl = GT_INDEXED | 1 << 8 | 1
sp1a8hbl = GT_INDEXED | 2 << 8 | 1
sp2a8lpl = GT_INDEXED | 1 << 8 | 2
sp2a8hpl = GT_INDEXED | 2 << 8 | 2
sp4a8lnl = GT_INDEXED | 1 << 8 | 4
sp4a8hnl = GT_INDEXED | 2 << 8 | 4
sp8a8i8 = GT_INDEXED | 1 << 8 | 8
sp16a16r5g5b5A1 = GT_RGB | 1 << 8 | 16
sp16a16r5g5b5A1rev = GT_RGB | 2 << 8 | 16
sp16a16b5g5r5A1 = GT_RGB | 3 << 8 | 16
sp16a16b5g5r5A1rev = GT_RGB | 4 << 8 | 16
sp16a16r5g6b5 = GT_RGB | 5 << 8 | 16
sp16a16r5g6b5rev = GT_RGB | 6 << 8 | 16
sp16a16b5g6r5 = GT_RGB | 7 << 8 | 16
sp16a16b5g6r5rev = GT_RGB | 8 << 8 | 16
sp24a8b8g8r8 = GT_RGB | 1 << 8 | 24
sp24a8r8g8b8 = GT_RGB | 2 << 8 | 24
sp32a32b8g8r8A8 = GT_RGB | 1 << 8 | 32
sp32a32b8g8r8A8rev = GT_RGB | 2 << 8 | 32
sp32a32r8g8b8A8 = GT_RGB | 3 << 8 | 32
sp32a32r8g8b8A8rev = GT_RGB | 4 << 8 | 32
Here's how the current graphtypes would be defined :
GT_1BIT = GT_INDEXED | 1
GT_2BIT = GT_INDEXED | 2
GT_4BIT = GT_INDEXED | 4
GT_8BIT = GT_INDEXED | 8
GT_16BIT = GT_RGB | 16
GT_24BIT = GT_RGB | 24
GT_32BIT = GT_RGB | 32
GT_TEXT16 = GT_TEXT | 16
GT_TEXT32 = GT_TEXT | 32
Now, using zero in one of the fields has a special meaning, not unlike
GGI_AUTO. Usually a program will use ggiSetGraphMode() with something
like GT_RGB | 16, leaving the sub-scheme field zero. The display target
then fills in that field with the actual pixel format (e.g. becoming
GT_RGB | 5<<8 | 16 for a sp16a16r5g6b5 framebuffer).
If a program really wanted a certain format (and this would be
especially valid with the memory target), then it is free to call
ggiSetGraphMode() with GT_RGB | 5<<8 | 16, for example. If that
particular format wasn't available, the setmode would just fail.
Also, a program could use "GT_RGB" (leaving the depth 0), which would be
interpreted as "give me the best RGB mode you've got", and the result
could come back as GT_RGB | 1<<8 | 24 (== sp24a8b8g8r8).
The full graphtype also [A] serves as the buffer format for ggiGetBox()
and ggiPutBox() and others, and [B] serves as the pixel format for
ggiGetPixel(), ggiPutPixel(), ggiSetGCForeground() and others.
The new graphtype is an integer with (currently) at least 32 bit.
As users should use ggi_graphtype, they shouldn't be affected if
we need to change this to 64 bits some day.
bits 7-0 contain the bits per pixel actually used,
this means: padding bits are not counted, a 15 bpp mode has 15 here.
I would like to suggest to count the number of *foreground colours*
possible, which makes most text modes ==4.
bits 15:8 contain the bits per pixel occupied in memory. Marcus pointed
out that one might want not to code that into the 'subtypes' field.
bits 23:16 contain the subtypes.
Subtype 0 always means: don't know/don't care.
Other types are allocated as needed, together with a proper define
along the 'old' common_plb_setup's.
bit 24: 1 for text mode
bit 25: 1 for indexed mode
(think of it, you can specify an indexed text mode in YUV, and
it makes some sense ...)
bit 31:28 enumerated color space definitions: (are there more than 16?)
1:RGB
2: YUV
3: ...
4: RGB double precision floats ??
(two spare bits :-)
If everything is 'hidden' by defines, nobody will ever want to deal
with that bitmap in detail anyway ...
#define GT_TEXTMODE 0x01000000
#define GT_INDEXED 0x02000000
#define GT_RGB 0x10000000
#define GT_YUV 0x20000000
#define GT_MODE(x,bpp,consumed,sub) x+bpp+(consumed<<8)+(sub<<16)
#define sp16a16r5g5b5A1rev GT_MODE(GT_RGB,15,16,1)
/* 15 bit BGR 5/5/5 reverse endian */
#define sp16a16b5g5r5A1 GT_MODE(GT_RGB,15,16,2)
/* 15 bit RGB 5/5/5 native endian */
int ggiModeBpp(graphtype g){return (g&&0xff)};
....
> bit 24: 1 for text mode
> bit 25: 1 for indexed mode
> (think of it, you can specify an indexed text mode in YUV, and
> it makes some sense ...)
>
> bit 31:28 enumerated color space definitions: (are there more than 16?)
> 1:RGB
> 2: YUV
> 3: ...
> 4: RGB double precision floats ??
> (two spare bits :-)
I would suggest:
bit 24-25: enumerated colorspace definitions
0: Don't care
1: RGB
2: YUV
3: allocated when needed
bit 26-29: allocated when we need them
bit 30: 1 for indexed mode
bit 31: 1 for text mode
This will allow us to expand both the enumeration
values and the flags when needed.
Hartmut Niemann wrote: > The new graphtype is an integer with (currently) at least 32 bit. > As users should use ggi_graphtype, they shouldn't be affected if > we need to change this to 64 bits some day. Do we really need to save _so much_ memory for mode setting? If we change one bit we would get into trouble... Is this really necessary? I would suggest a simple mode struct. > bit 31:28 enumerated color space definitions: (are there more than 16?) > 1:RGB > 2: YUV > 3: ... > 4: RGB double precision floats ?? > (two spare bits :-) indexed, greyscale, RGB, HSV, HLS, YUV, YCrCb, CMY, CYMK, CIE L*a*b*, CIE L*u*v , CIE uvY, CIE xyY, CIE XYZ (most general) ... This are 14 color spaces, and with integer/double precision we have 28. > What do you think? Looks nice at the first glance but it would cause many problems in future.
Hartmut writes:
> The new graphtype is an integer with (currently) at least 32 bit.
> As users should use ggi_graphtype, they shouldn't be affected if
> we need to change this to 64 bits some day.
>
> bits 7-0 contain the bits per pixel actually used,
> this means: padding bits are not counted, a 15 bpp mode has 15 here.
> I would like to suggest to count the number of *foreground colours*
> possible, which makes most text modes ==4.
Ok. We can call it "color depth" to be really precise. I also agree
with using 4 for text modes.
> bits 15:8 contain the bits per pixel occupied in memory. Marcus pointed
> out that one might want not to code that into the 'subtypes' field.
Ok. We can call it "access" as in the DirectBuffer stuff.
> bits 23:16 contain the subtypes.
> Subtype 0 always means: don't know/don't care.
Well, I'm saying that when it is 0, it will get filled out by ggiSetMode()
(like the way GGI_AUTO works). Is that what you meant too ?
BTW, we also need a value that says "the subtype is private, so don't
try to encode/decode the format, instead use ggiMapColor() and
ggiUnmapPixel()". I suggest using all ones (i.e. 0xff << 16).
> bit 24: 1 for text mode
> bit 25: 1 for indexed mode
> (think of it, you can specify an indexed text mode in YUV, and
> it makes some sense ...)
This doesn't make sense to me... could you please explain what you had
in mind ?
I am yet to be convinced that having either TEXT or INDEXED as an "or'd
option" would actually be useful. For example, RGB | TEXT would imply
that the text colors were encoded in the pixels with a mask for red,
green and blue (e.g. rrggbbRRGGBBcccccccc), which is pretty silly IMHO.
> bit 31:28 enumerated color space definitions: (are there more than 16?)
> 1:RGB
> 2: YUV
> 3: ...
> 4: RGB double precision floats ??
> (two spare bits :-)
We should think very carefully before adding *any* extra colorspaces
other than RGB. For example, just by including YUV we would need to
change ggi_color to be a union, like this :
typedef union ggi_color
{
struct { uint16 r, uint16 g, uint16 b, uint16 a } rgb;
struct { uint16 y, uint16 u, uint16 v, uint16 a } yuv;
} ggi_color;
and while I'm not completely against this, I think it is a *big* step
to take and needs to be discussed at length.
> #define GT_MODE(x,bpp,consumed,sub) x+bpp+(consumed<<8)+(sub<<16)
> #define sp16a16r5g5b5A1rev GT_MODE(GT_RGB,15,16,1)
> /* 15 bit BGR 5/5/5 reverse endian */
> #define sp16a16b5g5r5A1 GT_MODE(GT_RGB,15,16,2)
> /* 15 bit RGB 5/5/5 native endian */
Ok, Take II :
The masks would be :
#define GT_SCHEME_MASK 0xff000000
#define GT_SUBSCHEME_MASK 0x00ff0000
#define GT_ACCESS_MASK 0x0000ff00
#define GT_DEPTH_MASK 0x000000ff
#define GT_MODE(scheme,sub,access,depth) \
(scheme + (sub << 16) + (access << 8) + depth)
The schemes would be :
#define GT_RGB 0x01000000
#define GT_INDEXED 0x02000000
#define GT_GREYSCALE 0x03000000
#define GT_TEXT 0x04000000
(possible future additions: GT_YUV, GT_CMYK, ...)
Here's how the current ggi_common_plb_setup values would be defined :
ggi_common_plb_setup scheme sub-scheme access depth
sp1a8lbl = GT_MODE(GT_INDEXED, 1, 8, 1)
sp1a8hbl = GT_MODE(GT_INDEXED, 2, 8, 1)
sp2a8lpl = GT_MODE(GT_INDEXED, 1, 8, 2)
sp2a8hpl = GT_MODE(GT_INDEXED, 2, 8, 2)
sp4a8lnl = GT_MODE(GT_INDEXED, 1, 8, 4)
sp4a8hnl = GT_MODE(GT_INDEXED, 2, 8, 4)
sp8a8i8 = GT_MODE(GT_INDEXED, 1, 8, 8)
sp16a16r5g5b5A1 = GT_MODE(GT_RGB, 1, 16, 15)
sp16a16r5g5b5A1rev = GT_MODE(GT_RGB, 2, 16, 15)
sp16a16b5g5r5A1 = GT_MODE(GT_RGB, 3, 16, 15)
sp16a16b5g5r5A1rev = GT_MODE(GT_RGB, 4, 16, 15)
sp16a16r5g6b5 = GT_MODE(GT_RGB, 5, 16, 16)
sp16a16r5g6b5rev = GT_MODE(GT_RGB, 6, 16, 16)
sp16a16b5g6r5 = GT_MODE(GT_RGB, 7, 16, 16)
sp16a16b5g6r5rev = GT_MODE(GT_RGB, 8, 16, 16)
sp24a8b8g8r8 = GT_MODE(GT_RGB, 1, 8, 24)
sp24a8r8g8b8 = GT_MODE(GT_RGB, 2, 8, 24)
sp32a32b8g8r8A8 = GT_MODE(GT_RGB, 1, 32, 24)
sp32a32b8g8r8A8rev = GT_MODE(GT_RGB, 2, 32, 24)
sp32a32r8g8b8A8 = GT_MODE(GT_RGB, 3, 32, 24)
sp32a32r8g8b8A8rev = GT_MODE(GT_RGB, 4, 32, 24)
Here's how the current graphtypes would be defined :
#define GT_1BIT GT_MODE(GT_INDEXED, 0, 0, 1)
#define GT_2BIT GT_MODE(GT_INDEXED, 0, 0, 2)
#define GT_4BIT GT_MODE(GT_INDEXED, 0, 0, 4)
#define GT_8BIT GT_MODE(GT_INDEXED, 0, 0, 8)
#define GT_15BIT GT_MODE(GT_RGB, 0, 0, 15)
#define GT_16BIT GT_MODE(GT_RGB, 0, 0, 16)
#define GT_24BIT GT_MODE(GT_RGB, 0, 8, 24)
#define GT_32BIT GT_MODE(GT_RGB, 0, 32, 24)
#define GT_TEXT16 GT_MODE(GT_TEXT, 0, 16, 4)
#define GT_TEXT32 GT_MODE(GT_TEXT, 0, 32, 4)
> bits 7-0 contain the bits per pixel actually used, > this means: padding bits are not counted, a 15 bpp mode has 15 here. > I would like to suggest to count the number of *foreground colours* > possible, which makes most text modes ==4. Where do you put blinking? To take the number of foreground colours is ok. But you might want to say, the standard VGA Textmode is 1 bpp + 2 attributes. Well you have the basic 8 colors, and the attributes highlight and blink. Some cards might also have underline or something like this. Just think of this, your idea is more practicable, but someone might find a even better one.
Now that the fbdev target is coming along, there is a need for libggi to
support 2 bit, 3 bit, 5 bit, 6 bit and possibly 7 bit modes. The
simplest thing would be to add GT_2BIT, GT_3BIT, GT_5BIT, GT_6BIT and
GT_7BIT constants to the ggi_graphtype enum, but I think there is a
better way.
What I'd like to see is something like this :
#define GT_BPP_MASK 0x00ff
#define GT_TYPE_MASK 0xff00
#define GT_INDEXED 0x0100
#define GT_RGB 0x0200
#define GT_TEXT 0x0300
#define GT_GRAYSCALE 0x0400
#define GT_YUV 0x0500
where the lowest 8 bits is just the depth (e.g. 8, 16, or whatever), and
the upper 8 bits is the type (only a rough indication). The current
values would be mapped as follows :
GT_1BIT -> GT_INDEXED + 1
GT_4BIT -> GT_INDEXED + 4
GT_8BIT -> GT_INDEXED + 8
GT_15BIT -> GT_RGB + 15
GT_16BIT -> GT_RGB + 16
GT_24BIT -> GT_RGB + 24
GT_32BIT -> GT_RGB + 32
GT_TEXT16 -> GT_TEXT + 16
GT_TEXT32 -> GT_TEXT + 32
(Me) pointed out that Andrews proposal does not completely satisfy needs for requesting a graph type.
#define GT_BPP_ORMORE 0x0080 #define GT_BPP_ORLESS 0x0040 so I can check a mode GR_RGB + 15+ GT_BPP_ORMORE to get at least 15 high colour. the standard GGI_AUTO will be GT_RGB + 63+ GT_BPP_ORLESS (highest available), but GT_RGB + 0 + GT_BPP_ORMORE will make perfect sense and will give the lowest unpalettised mode. > > #define GT_INDEXED 0x0100 > #define GT_RGB 0x0200 > #define GT_TEXT 0x0300 > #define GT_GRAYSCALE 0x0400 > #define GT_YUV 0x0500 If this is and enumeration instead of a bit field, we run into trouble. It would make sense to request GT_INDEXED | GT_RGB|GT_YUV, but then the values need to be 0x0100, 0x200, 0x400 ... I think your system is superiour to what we had and very well suited for defining a certain mode, but for requesting a mode some additions (for more flexibility) are needed. And if 16 bits are too small, let's make the mode a ggi_uint32. Then GT_BPP_ORLESS = 1 <<8, ORMORE 1<<9, GT_INDEXED 1<<10 ... Nobody should mess with the values and bits on his own anyway.
> Of course you can still do a 'simple-mode-init' that takes the graphtypes, > but it should use the enhanced scheme. 'graphtype' should be removed entierly, as it has no real meaning if we are supporting other hardware than common VGAcards. (No real meaning as in doesn't separate an 8 bit indexed mode from an 8 bit YUV mode) The "simple-mode-init" should IMO use something like the proposed scheme. One more thing about modes: As we're supporting an increasing number of diffrent mode-types the complexity of mode negotiation gets more complex. My suggestion is that the driver exports a structure that gives complete information of what modes it support and which it doesn't support. The driver will then only check the validity of requested modes, and all GGI_AUTO handling/suggesting modes will be handled in userspace. After all modenegotiation needn't be in the kernel, and therefore it shouldn't.
> One thing I don't understand is: we say nowhere that GT_15BIT actually consume s > 16bits for a pixel. Also, GT_32BIT actually uses only 24bits on most cards. > Don't we need to clean the depth/bpp separation like in XFree86? > (one is the _consumed_ bits in the framebuffer, the other the _actually_used_ > bits) I think we should have a SetMode function that does no GGI_AUTO expansion and no suggestions if the mode can't be set. This function should take a mode struct (just like the current ggiSetMode()) which can be passed on to kernel-drivers without modification. This struct should separate depth/bpp, and other things currently not separated. And as I suggested earlier drivers should export a struct that tells which modes it can handle and which it can not. If we have this a piece of cake to implement every possible mode setting/querying/negotiation, and thus there's no need for discussion and no decissions to be made. If someone want a certain type of modenegotiation he will just implement it and if it works it will go into libggu.
> After all modenegotiation needn't be in the kernel, and therefore > it shouldn't. This is probably an important point. Mode _validation_ and _setting_ must be in the kernel, but complex handling of AUTO settings, weird interactions between the various card components and thus the whole mode negotiation routines could probably be moved to a general userspace library, unless they are so small and simple (which I doubt) that keeping them in the kernel harms noone. Even if it will turn out that there are many card-specific rules and tricks, a card-specific userspace library for mode negotiation looks useful. Also, I agree that the current GT_xBIT are a bit limited, but the ORMORE/ORLESS thing seems unnecessary to me. We already decided that when a certain mode can't be done, we use the rule "increase settings if possible, otherwise decrease", that can be applied happily to graphmode types too. The following splitting instead looks nice to me (except for the values of the #defines) > #define GT_INDEXED 0x0100 > #define GT_RGB 0x0200 > #define GT_TEXT 0x0300 > #define GT_GRAYSCALE 0x0400 > #define GT_YUV 0x0500 One thing I don't understand is: we say nowhere that GT_15BIT actually consumes 16bits for a pixel. Also, GT_32BIT actually uses only 24bits on most cards. Don't we need to clean the depth/bpp separation like in XFree86? (one is the _consumed_ bits in the framebuffer, the other the _actually_used_ bits)
How about these for masks:
GT_BPP_MASK = 0x00000000000000ff
GT_ACHAN_MASK = 0x0000000000000f00
GT_ZBUFF_MASK = 0x000000000000f000
GT_PIX_LAYO_MASK = 0x0000000fffff0000
/* For RGB layout red mask = 0x0f000000, etc. == # of bits red per pixel
For YUV layout yel mask = 0x0f000000, etc.
For 2D/3D chipsets alpha mask = 0xf0000000
For 3D chipsets z mask = 0xf00000000 */
GT_PIX_TYPE_MASK = 0x000000f000000000
GT_INDEXED = 0x0000008000000000 /*Can be combined with RGB, YUV, etc */
GT_RGB = 0x0000000000000000
GT_TEXT = 0x0000001000000000
GT_GRAYSCALE = 0x0000002000000000
GT_YUV = 0x0000003000000000
GT_FB_LAYO_MASK = 0x0fffff0000000000
GT_PACKED_MASK = 0x0000ff0000000000 /* # of packed pixels per plane */
GT_PLANES_MASK = 0x00ff000000000000 /* # of planes */
GT_CUSTOM_LAYO = 0x0800000000000000 /* For strangeness like MDA */
/* For alpha or x channels in separate buffers */
GT_ACHAN_SEP = 0x0100000000000000 /* For separate alpha "plane" */
GT_ZBUF_SEP = 0x0200000000000000 /* For separate z-buffer "plane" */
/* Examples:
VGA_MODEX = 0x0004808006660008
PLANAR8_RGB = 0x0008000003320008
*/
I think teunis had something thought of here as well. Of course
basic KGI drivers/driver-libs don't break these apart and analyse
them, they just know the ones for their own layouts.
On Fri, 17 Apr 1998, Massimiliano Ghilardi wrote: > > After all modenegotiation needn't be in the kernel, and therefore > > it shouldn't. > > This is probably an important point. Mode _validation_ and _setting_ > must be in the kernel, but complex handling of AUTO settings, weird > interactions between the various card components and thus the whole mode > negotiation routines could probably be moved to a general userspace library, Yes, this is the general arrangement I want for the mode negotiation stuff I have. Note the kernel still has to "negotiate" text modes to grab VC's when the module is inserted but this can be a much more basic algorithm than the userspace one. The in-kernel functions will merely examine the structure sent in from userspace and validate that it is within their capability to produce this timing/layout, and flag the offending fields if they cannot. This should be pretty small/fast. They will also be able to take clues from the request since it will be based on a structure they passed to userspace before mode negotiation, so they won't e.g. have to check both packed and modex to see if either one can fit the request; they will know which to used based on the offset in their structure to which the request refers. I want to see Steffen's strategy for separating FB layout from timings, which is sort of what I was doing when working on this. They can pretty much be cleanly separated AFAIHS.
Some means is necessary to report the colour depth of a display.
unsigned int ggiVisualBpp(vis) was suggested, which
returns the bits per pixel actually used, i.e. ld(number of colours).
The question is whether to pass a visual, a mode or a graphtype to it.
It has been agreed on that neither libggi nor its targets try to handle a screen redraw themselves.
It is still unclear whether restoring the palette is done by the application (along te redraw action), or by the libggi (target). Most targets have a local copy of the palette anyway, so it would be rather easy.
If an application loses the 'attention', it will receive a SIGSTP.
Most applications will be stopped, but for some (POVRAY) it could make sense to work in the background, especially if they keep a backbuffer anyway.
Should such application catch SIGSTP and stop issuing drawing commands (then: how?) or can the target be made ignore all drawing requests (ggiSetInfoFlags(vis,GGI_IGNOREWHENINACTIVE) ???)?