Squeak
  links to this page:    
View this PageEdit this PageUploads to this PageHistory of this PageTop of the SwikiRecent ChangesSearch the SwikiHelp Guide
Surface Plugin
Last updated at 10:39 am UTC on 7 November 2006
The Surface Plugin is used to render graphics directly on an OS surface.

This page has a couple of email messages that outlines how this works.

Will put more detaled examples on how this works, e.g. rendering Morphic/Tweak on an OpenGL surface, as outlines in the message by Bert. (Will this speed up rendering of Morphic/Tweak?)

Here is code from Andreas for a an example surface plugin:
http://squeakvm.org/svn/squeak/trunk/platforms/Cross/plugins/ExampleSurfacePlugin/

Bert Freudenberg

Am 05.11.2006 um 12:27 schrieb Mikael Kindborg:

> Have also been experimenting with Tweak which is
> really nice, but as I understand it Tweak, like Morphic, uses standard
> Squeak Forms and Display to render graphics.

Tweak does not use Display directly. This allows for rendering to
multiple display surfaces simultaneously, like when using Host
Windows (a.k.a. Areithfa Ffenestri). Also, an experimental version of
Tweak exists that uses Rome for rendering, although this also writes
to Display in the end for now.

> What concerns me is the blit speed of Form and Display. Have searched
> the mailing list and the swiki and obviously there are lots of issues
> that have been up for discussion previously, like conversion between
> pixel formats, endianness, etc. Have seen mention of FXBlt,
> ExternalForm, and ExternalScreen, which seems to be in the Balloon3D
> package (which has been replaced by Croquet?).

No, FXBlt has been rolled into regular BitBlt. You can use BitBlt to
render to any surface registered via SurfacePlugin. Like, RomePlugin
registers Cairo surfaces that can be used as source or destination of
BitBlt.

> I am confused about the current status of Squeak technologies for high
> speed graphics. From what I understand, Croquet is the most recent
> work in this area, based on OpenGL.

Yes, which also is a severe limitation for general use as there is
one important platform lacking good general OpenGL support.

> I have found SDL to be a very good library, have been working with SDL
> in Python, using the Pygame library. It has good blitting performance
> (will post some performance tests later on, comparing Pygame to
> Squeak). Pygame/SDL uses bitmaps in the current format of the display
> screen, and I would like to look at how this could be done in Squeak.
>
> As I understand it, there are two ways of using libraries like OpenGL
> and SDL in Squeak:
>
> 1. As an "add on" that bypasses the Display, and renders "on top of"
> Morphic/Tweak. This is how I understand that Croquet works. Drawback
> is you cannot use Morphic/Tweak but have to do your own UI system
> (like the one in Croquet).

Actually, Tweak or Morphic run fine as an overlay inside an OpenGL
window. That's how Plopp implements its UI, for example.

> 2. As an integrated part of the VM, making Display and Forms use the
> native display format. Then you could use Morphic/Tweak with the best
> performance.

Actually I think Forms are outdated now, you really want a vector
graphics API. So what would be best IMHO is opening a host window and
a canvas on its surface, then using canvas commands to draw onto it.
I think we have almost all needed bits in place (Host Window Plugin,
Rome Plugin), they just need to be integrated.

Bert

Andreas Raab andreas.raab at gmx.de
Sat Nov 15 05:48:57 CET 2003

> However I'm not sure how you tell the BitBltPlugin to flip
> from using the screen to using the display surface
> anyone know?

Simple. Just substitute the surface handle for the "bits" of the form. If it
happens to be Display it'll call ioShowDisplay(). If you want to get
fancier, provide a subclass of DisplayScreen that handles creation/destroy
and simply make it #beDisplay.

Cheers,
- Andreas

> —–Original Message—–
> From: squeak-dev-bounces at lists.squeakfoundation.org
> [mailto:squeak-dev-bounces at lists.squeakfoundation.org] On
> Behalf Of John M McIntosh
> Sent: Saturday, November 15, 2003 5:36 AM
> To: The general-purpose Squeak developers list
> Subject: SurfacePlugin howto?
>
>
> Ok, I think I know how to setup a callback to the
> SurfacePlugin to say
> what the entry points are.
>
> However I'm not sure how you tell the BitBltPlugin to flip
> from using
> the screen to using the display surface
> anyone know?
>
> –
> ==============================================================
> ==========
> ===
> John M. McIntosh 1-800-477-2659
> Corporate Smalltalk Consulting Ltd.
> http://www.smalltalkconsulting.com
>

Andreas Raab Andreas.Raab at gmx.de
Tue Aug 20 00:36:41 CEST 2002

    *Previous message: Squeak DisplayScreen Bitmap Stationary?
    * Next message: R.F.Clarification:
    * Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]

>I think you may well find that using the SurfacePlugin can provide the
 same general support in a more principled form not to mention with
 abilities to hande pixel format conversions. I really must 
 make time to try it out myslef one day,

So you should! The sole purpose of the SurfacePlugin is to provide
generalized access for forms living "outside" Squeak.

Here's a bit of basic information (someone take this email and put it up
on the Swiki). In order to support "external" forms you have to have a
way to create them by, e.g., calling some primitive. So let's assume we
got a #primitiveCreateForm residing in MyFormPlugin. What does it have
to do?!

* Step1: Take the parameters and create the form/bitmap/image whatever
* Step2: Register the bitmap with the surface plugin
* Step3: Pass back the handle obtained by the surface plugin

The resulting handle (which will be a small integer) must be stored in
the Form's 'bits' instVar. BitBlt will recognize these registered
surfaces and allow you to draw directly onto them. So, obviously, the
only question is what you have to do in order to register the bitmap
with the surface plugin. Here's how that works:

The surface plugin expects a set of functions which will be used to
query for certain properties of the bitmap used. Currently, there are
four functions:

* getSurfaceFormat(): Which queries the surface about attributes such as
width, height, pitch, lsb vs. msb etc

* lockSurface(): Which attempts to lock a portion of the surface for 
drawing operations

* unlockSurface(): Which releases a prior lock of the surface

* showSurface(): Which gets called if the surface in question 
represents Display

Let's take a look at some pseudo-code (most real implementations will be
exactly as simple as the following): We first define a structure which
is used to remember the attributes of any bitmap we might be using:

typedef struct MyBitmap {
   int w, h, d;    /* width, height, and depth */
   int pitch;   /* how many bytes per scan line? */
   void *bits;  /* where are those bits? */
} MyBitmap;

[Note: If you are dealing with native bitmaps chances are good that you
don't need the above structure but can just use a handle and query some
other function for those attributes. In this case just replace the
references below with calls to those functions.]

int getSurfaceFormat(MyBitmap *myBM, int *width, int *height, int
*depth, int *isMSB) {
	/* fill in status information */
	*width = myBM->w;
	*height = myBM->h;
	*depth = myBM->d;
	*isMSB = 1; /* or zero depending on platform or choice */
	return 1; /* success - otherwise return zero */
}

[Note: BitBlt will *always* query for the actual format of the surface
and not "trust" anything stored in the form itself].

int lockSurface(MyBitmap *myBM, int *pitch, int x, int y, int w, int h)
{
	/* lock the region x,y - (x+w),(y+h)
	   the area actually used is provided so that expensive
	   operations (like a round trip to the X-Server) can
	   be avoided. See SurfacePlugin.h */
	/* for our simple example, only fill in the pitch. No locking is
required. */
	*pitch = myBM->pitch;
	return 1; /* success */
}

int unlockSurface(MyBitmap *myBM, int x, int y, int w, int h) {
	/* Unlock a previously locked portion of myBM.
	   The area describes the 'dirty region' which might
	   need to be written back/flushed whatever. */
	/* for the simple example do nothing */
	return 1;
}

int showSurface(MyBitmap *myBM, int x, int y, int w, int h) {
	/* the surface represents Display - update the portion
	   described in x,y,w,h */
	/* for our simple example we just ignore this */
	return 0; /* e.g., fail */
}

Okay, that's basically it. Now all we need is a way to actually pass
these hooks into the surface plugin upon creation. Let's define the
required structure:

sqSurfaceDispatch myBMDispatch = {
	1, /* major version */
	0, /* minor version */
	(fn_getSurfaceFormat) getSurfaceFormat,
	(fn_lockSurface) lockSurface,
	(fn_unlockSurface) unlockSurface,
	(fn_showSurface) showSurface
};

and now a primitive that creates one of our own bitmaps (will be called
with width, height, and depth):

int primitiveCreateMyBitmap(void) {
	int width, height, depth;
	int sqHandle; /* the 'bits' instVar Squeak will get */
	MyBitmap *myBM;

	/* note: should check if depth is valid */
	depth = interpreterProxy->stackIntegerValue(0);
	height = interpreterProxy->stackIntegerValue(1);
	width = interpreterProxy->stackIntegerValue(2);

	/* create my bitmap */
	myBM = calloc(1, sizeof(MyBitmap));
	myBM->w = width;
	myBM->h = height;
	myBM->d = depth;
	myBM->pitch = (w*d) + 31 / 4; /* round to bytes */
	myBM->bits = calloc(h, myBM->pitch);

	/* register my bitmap - note: should check return value */
	(*registerSurface) ((int) myBM, &myBMDispatch, &sqHandle);

	/* pop args and return created handle */
	interpreterProxy->pop(4); /* args+rcvr*/
	interpreterProxy->pushInteger(sqHandle);
}

That's basically it. Using the above you can create one of our bitmaps
and happily blt away. There's one piece missing though - that's the use
of "registerSurface" in the above. These entry points need to be looked
up dynamically and here is how this goes:

/* declare the entry points */
fn_ioRegisterSurface registerSurface = 0;
fn_ioUnregisterSurface unregisterSurface = 0;
fn_ioFindSurface findSurface = 0;

/* look up the entry points on module startup */
int initialiseModule(void) {
	registerSurface = (fn_ioRegisterSurface) 
	
interpreterProxy->ioLoadFunctionFrom("ioRegisterSurface","SurfacePlugin"
);
	unregisterSurface = (fn_ioUnregisterSurface)
	
interpreterProxy->ioLoadFunctionFrom("ioUnregisterSurface","SurfacePlugin");
	findSurface = (fn_ioFindSurface)
	
interpreterProxy->ioLoadFunctionFrom("ioFindSurface","SurfacePlugin");
	/* note: should return zero and FAIL module loading if any of
the above is not present */
};

Obviously, unregisterSurface() is being called for unregistering a
previously registered surface. findSurface() can be used to find out if
some surface handle is really what you *think* it is, e.g.,

int primitiveDestroyMyBitmap(void) {
	int sqHandle;
	MyBitmap *myBM;

	sqHandle = intepreterProxy->stackIntegerValue(0);
	/* see if the handle really describes a MyBitmap surface */
	if( ! (*findSurface)(sqHandle, &myBMDispatch, (int*) (&myBM)) )
{
		/* i don't know what it is but certainly no MyBitmap */
		return interpreterProxy->primitiveFail();
	}
	/* unregister and destroy */
	(*unregisterSurface)(sqHandle);
	free(myBM->bits);
	free(myBM);
}

And that's it for the basics. If the colors of the surface you're using
match those of Squeak you're done here. If they don't, you'll have to
provide sufficient information to get the color mapping right - which is
not that hard either. If you can find out the "color masks" for each of
R,G,B, and alpha you can just create a ColorMap from these masks and
everything will be hoopy. For indexed colors you'd have to query for the
RGB representation of the colors directly.

Cheers,
  - Andreas


Raab, Andreas Andreas.Raab at disney.com
Sun Jul 23 21:49:01 CEST 2000

    * Previous message: Squeak's Foreign Function Interface
    * Next message: Virtual Morphs
    * Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]

> In the course of those discussions, we eventually came up with the
> Treaty of Denver and the ideas that now exist in the FXBLT code ( I
> think - I haven't had time to even properly read the code yet) and
> should allow us to arbitrarily mix big-endian, little endian,
> middle-endian (yes it exists - dear old M$ does Windows bitmapts in
> middle-endian form!) as source, destiniatio, texture, halftone,
> whatever. It also allows bitmaps to be external to the Squeak object
> memory, so that memory in accelerator cards can be used.

Yup. That's the whole point. You can basically use any OS bitmap from within
Squeak with FXBlt. What you have to do is to implement about 5 C support
functions for the OS bitmap, register the thing with the surface plugin and
then you can blt from and to as you wish. No more byte reversals ;-)

> Sometime soon, VMs can be updated to make use of this and the
> pixel-swapping code will be removed from the Acorn, Windows and Unix
> windows files.

It's really trivial to do. All that's needed is to implement a couple of
primitives that actually create the bitmap (see the B3DDisplayScreen for an
example of those).

> Oh, and in most cases, the reversing loops you mentioned spend all their
> time reading from and writing to the cpu cache, so trying to do clever
> things by readinga word and hand manipulating instead of reading each
> byte separetly has no actual benefit. Been there, wasted my 
> time on that....

Ah... that actually depends. If you're doing a copying reversal you might be
right. But for an inplace reversal it *does* make a difference. Been there,
tried that ;-)

  - Andreas


Check out the example in the SVN repository. How do you access that?
Example surface plugin
Andreas Raab andreas.raab at gmx.de
Wed Apr 26 21:20:51 UTC 2006

    * Previous message: File and directory primitives are severely broken
    * Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]

Hi Guys -

Just FYI: I noticed that my earlier example for a surface plugin got 
lost in the depths of the internet so I posted an updated version to the 
SVN repository. Feel free to ignore for any regular builds; it's really 
just an example of how to deal with the surface plugin etc.

Cheers,
   - Andreas