Win32k design guideline

From ReactOS Wiki
Revision as of 16:09, 18 November 2009 by Lone Rifle (talk | contribs)
Jump to: navigation, search

This is work in progress. Please add suggestions.


File layout

Suggestion for a new layout by Timo:

  • dib
    • as it is
  • driver
    • device.c
    • display.c
    • driver.c
    • loader.c
  • misc
    • copy.c
    • debug.c
    • engmisc.c
    • err.c
    • error.c
    • event.c
    • gdibatch.c
    • gdidbg.c
    • math.c
    • mem.c
    • mouse.c
    • perfcnt.c
    • print.c
    • sort.c
    • usrheap.c
  • ntuser
    • ???
  • objects
    • bitmap.c
    • brush.c
    • clipobj.c
    • dc.c
    • dcutil.c
    • dibobj.c
    • driverobj.c
    • floatobj.c
    • gdiobj.c
    • icm.c
    • lfont.c
    • metafile.c
    • palette.c
    • path.c
    • pen.c
    • rect.c
    • region.c
    • rfont.c
    • semaphor.c
    • stockobj.c
    • strobj.c
    • surface.c
    • window.c
    • xform.c
    • xlate.c
  • painting
    • alphablend.c (NtGdiAlphaBlend, NtGdiEngAlphaBlend, EngAlphaBlend, IntEngAlphaBlend)
    • arc.c (NtGdiArcInternal, NtGdiAngleArc, IntGdiArcInternal, IntArc)
    • bezier.c
    • bitblt.c (NtGdiBitBlt, NtGdiEngBitBlt, EngBitBlt, IntEngBitBlt, CallDibBitBlt)
    • copybits.c (EngCopyBits)
    • ellipse.c (NtGdiEllipse, NtGdiPie)
    • fill.c
    • floodfill.c
    • gradient.c
    • lineto.c
    • maskblt.c (NtGdiMaskBlt, IntEngMaskBlt, EngMaskBlt)
    • paint.c
    • patblt.c
    • pixel.c
    • polyblt.c
    • polyfill.c
    • polygon.c
    • polyline.c
    • pos.c
    • rectangle.c
    • stretchblt.c
    • textout.c (NtGdiExtTextOut, IntEngTextOut, EngTextOut)
    • transblt.c (NtGdiTransparentBlt, IntEngTransparentBlt, EngTransparentBlt)

GDI

GDI object Locking/Referencing

There are 2 ways of "locks" on gdi objects. Exclusive locks and shared locks or references.

  • Shared references: Getting a shared reference on a gdi objects means increasing it's BASEOBJECT's ulSharedCount member. This will prevent the object from being deleted and you can continue to use the pointer to the object instead of the handle. You must only use this for read only access to the object (manipulating the bits of a bitmap or drawing on a surface does not mean changing the object itself and is protected differently). See also delayed deletion.
  • Exclusive locks: Getting an exclusive lock on an object means incrementing it's BASEOBJ's cExclusiveLock member. Only one thread at a time can do that. Multiple locks are allowed for that thread. This is a very important point: If you lock more than one GDI object at a time it must be done in a special order: DCs -> Brushes -> Pens -> Bitmaps -> ... (not finished!) If you lock more than one object of the same type, use GDIOBJ_LockMultipleObjects (yes, I know it's not yet implemented, give me some time to test ;-)) The reason is, if 2 threads lock the same objects in a different order, they might both end up waiting for an object, that was locked by the other thread and none will be able to continue.

Pens and brushes

On the way from the Win32 GDI interface to the DDI interface, we have to switch from Brushes, pens, and colors to BRUSHOBJs. Brushes and pens are already more or less the same on the user mode side. They share the same object type and the same kernel BRUSH structure. On the DDI side of things, the BRUSHOBs are actually EBRUSHOBJs and normally come from the DC that is used for the drawing operation. It has 4 EBRUSHOBJs: eboFill (representing the selected brush), eboLine (representing the selected pen), eboText (representing the selected text color) and eboBackground (representing the selected background color). These objects need to be synchronized to the currently selected objects that are normally changed in the usermode DC_ATTR part of the DC. Simultaneously the corresponding dirty flags in the ulDirty field are set, which are DC_BRUSH_DIRTY for a changed brush handle, DC_PEN_DIRTY for a changed pen handle, DIRTY_TEXT for a changed text color, DIRTY_BACKGROUND for a changed background color, DIRTY_FILL for a changed brush or - if DC_BRUSH is selected - dc brush color and finally DIRTY_LINE for a changed pen or - if DC_PEN is selected - pen color. So before passing these EBRUSHOBJs to the DDI interface, we need to make sure that we have synchronized the user mode values with the kernel. You need to do 2 steps for that. The first is to get a pointer the selected brush and with it a shared reference to the object. This will prevent the object from being deleted. And as brushes and pens are immutable objects, thus their content cannot be changed once they are created, you are free to use the pointer in kernel mode. When you select a new brush, you need to release the shared reference from the old object. The second step is to update the contents of the EBRUSHOBJ, based on the newly selected brush. If the selected brush/pen is DC_BRUSH/DC_PEN, then the EBRUSHOBJ is a solid brush and the content of the BRUSH is actually ignored, instead it is initialized with the dc brush or pen color. The same way eboText and ebobackground are initialized. Their pbrush member points to a stock brush and the color is taken from the foreground and background color that was stored in the DC_ATTR. In most of the cases the ulDirty flags won't be set, so we have nothing todo and can directly use the cached EBRUSHOBJ and pass it on.

Delayed Deletion

GDI has the capability of deleteing objects in a delayed manner. For example when you select an object, like a brush, into a DC and then delete it using DeleteObject or even NtGdiDeleteObjectApp, the function will return TRUE and from now on you won't be able to get Info from that object using GetObject anymore. The handle is still valid though. As soon as you select another object in the dc, releasing the old one, it finally gets deleted. GDI stores a flag somewhere to mark the object as being deleted, but it cannot really delete it, as long as shared references exist. While Windows GDI seems to save this information in inkonsistent places (for a brush it stored in the BRUSHATTR's flags field as 0x2), a more unified solution seems appropriate. While a flag in the user mode attribute is a valid optimisation, allowing to do a quick deletion from user mode, it should be synced to a common BASEOBJECT flag. If this flag is set, GDI should finally delete the object as soon as the last shared reference is removed. This can be implemented in GDIOBJ_ShareUnlockObj (mabe rename into GDIOBJ_ReferenceObjByHdl, GDIOBJ_ReferenceObjByPtr and GDIOBJ_DereferenceObj).

Coding style

Function naming

Finally here all those Int... Eng.. Nt* should be explained, since every time a new developer comes, he has questions.

When you look at Symbol dumps from win32k, you will find a large number of functions that don't have a prefix or funny prefixes, like xxx, yyy, zzz. Some functions use hungarion notation (bCaptureBitmapInfo, cjFillPolygon, vPatCpy...) others use a _ prefix. All in all Windows naming looks quite unstructured. A possibility for ReactOS to be more clear here. We should take over the known interfaces and create proper interfaces and naming conventions for the rest. Below is an excerpt from Windows and ReactOS function naming.


NtGdiXxx / NtUserXxx

  • Win32k Syscall Interface
  • Could be called from kmode, but for clearness GreXxx or UserXxx (see below) should be used instead
  • Objects are passed by handles
  • Buffers must be probed (never call such functions with kmode buffers)

GreXxx

  • Windows name for internal graphics engine interface
  • Identical interface to NtGdiXxx
  • Objects are passed by handles
  • Buffers are not probed and are assumed to be either valid or declared OPTIONAL

UserXxx

  • Reactos name for internal user function interface
  • Windows has some functions starting with User, but Interface is unclear
  • Should be used equivalent to GreXxx

IntGdiXxx, IntUserXxx, IntXxxx

  • Totally unclear internal reactos Interface
  • No standard of whether objects are passed as pointers or handles
  • No standard of whether it's between Gre and Eng or below Eng
  • Should be restructured

EngXxx

  • Exported Gdi engine interface for drivers
  • Serves various purposes, from drawing to DebugPrinting (generic driver support routines)
  • Objects are passed by pointers or handles
  • Buffers are not probed

XXXOBJ_Xxx

  • Gdi objects interface
  • Can be exported and used by display drivers (windows exports all these and uses C++ functions for objects internally. ReactOS uses this naming for internal functions, too)
  • First parameter is always a pointer to the object we deal with (Exception: private ROS XXXOBJ_AllocObj functions, that return this pointer)
  • Low level, should not call higher level functions (like User, Gre, Nt)


Internal naming of XXXOBJ / EXXXOBJ functions

a) Call them all XXXOBJ_Something.

  • Example: Current implementation of XFORMBJ
  • + Consistent naming
  • - No difference between official and internal api names

b) Call them all EXXXOBJ_Something, export them as XXXOBJ_DoSomething

  • Example: XFORMOBJ_iGetXform@8=EXFORMOBJ_iGetXform@8
  • Official names could be #defined to use the internal functions in win32k
  • + Consistent naming
  • + EXXXOBJ can be used as parameter instead of XXXOBJ
  • + Windows does this with CLIPOBJ_bEnum = WNDOBJ_bEnum
  • - No difference between official and internal api names

c) Call the offical apis XXXOBJ_Something, the prive ones EXXXOBJ_Something

  • + Clear difference between official and internal api names
  • - Inkonsistent naming

Indentation

  • Should match the kernel's indentation preferably? At least Ged, me (Aleksey) and some other people on IRC supported that idea.
  • I support the idea of using the kernel's indentation style (4 spaces) as well :-) - Colin Finck 10:46, 14 June 2008 (UTC)
  • I also support 4 spaces. Code::Blocks ANSI style indentation works quite good --ThePhysicist 18:37, 23 December 2008 (UTC)

Call chains

We should try to get our call chains as clear as possible. A hierachical structure should be achieved. Things like Gdi calling User or Eng calling NtGdi should be avoided. In our window handling code we currently have code that does recursive function calls through 3 or 4 levels! Example:

  • co_WinPosSetWindowPos
    • co_IntSetForegroundWindow
      • co_IntSetForegroundAndFocusWindow
        • co_IntSendActivateMessages
          • co_WinPosSetWindowPos

Combined with the fact that those functions do callouts to usermode, too. It's a great mess.

other

just found this on the wiki, old, but ...: win32k.sys

Physicus et al, I have managed to retrieve an article from Mark Tempel's personal site that may be useful later when converting the win32k design guideline into a future reference. Find it at User:Lone_Rifle/GDI_Function_Implementation_Guidelines -- Lone Rifle 11:44, 9 November 2009 (UTC)