Mantis - Squeak
Viewing Issue Advanced Details
5013 Morphic minor always 09-20-06 17:11 10-01-06 09:30
new 3.8  
0005013: FormCanvas>>transformBy:clippingTo:during:smoothing

i've been puzzling over the slow performance of Transform*Morphs when their size becomes larger. (haven't found found much on the web beyond some vague references to slowness and some defunct threads on related subjects).

doing some profiling, i found that the issue is that if the transformation is more than just a translation, a new subcanvas is allocated, the area to be transformed is drawn to that subcanvas, then the result is warped to the original canvas.

all well and good--for small transformation areas, but it turns out that allocating the form often takes more time than is desirable if the form is much larger than 600x600 (x32bits). on my mac i found it taking 4-6 seconds. definitely enough to put a dent in smooth interaction.

i've been noodling around with a different approach, one which stores the transform in the GrafPort, so that when the actual drawing takes place, the transform is used.

my results are that for a 600x800 image form, the old way timeToRun is about 4700, with the experimental way, it is round 50.

i only played enough to get images working so far and can see that it would not be trivial to make it work for everything.

here's what i've done so far:

- [+] tried a new approach experimentally
    - [+] copied class GrafPort
        - [+] changed it to inherit from WarpBlt instead of BitBlt
        - [+] added transform instance var and set method
        - [+] changed image:... method to use transform and warp
            - [+] had to extend selector to include origin
                      old approach simply added origin to the
                      destination point, which doesn't work if the
                      destination point is in a different tranform
        - [+] added transformedRect so that FormCanvas>>isVisible could
    - [+] had to extend FormCanvas
        - [+] add setPort: to allow port to be set to a WarpGrafPort
            - [+] setPort also needed to set clipRect properly
        - [+] change isVisible to query port if it is a WarpGrafPort to
              transform rectangle
        - [+] change image:... to use image:origin:... method if port
              is WarpGrafPort
        - [+] create transform3by:... to allow testing without
              destroying existing interface
    - [+] put transform3by in drawSubmorphsOn: methods for
          for my test cases

these are some of the things that would need to be done:
- [ ] to generalize, need to:
    - [ ] make sure all drawing methods on WarpGrafPort use transform
          and warp
              is there a tradeoff between bitblt and warpblt (i.e.,
              should we use bitblt if a translateOnly transform is
    - [ ] fix any interfaces on FormCanvas side (e.g., if origin: needs
          to be added)
    - [ ] transform: on WarpGrafPort needs to compose the transform
          with an existing one (for transforms within transforms)
    - [ ] could really get rid of special case in transformBy, since it
          is subsumed by this approach (i think)
    - [ ] think about WarpGrafPort--does it need all the functions
          copied from GrafPort
              (more of a cleanup issue)
              couldn't use inheritance here since WarpGrafPort needed to inherit
              from GrafPort and WarpBlt.
              if there are no conflicts GrafPort could be made to inherit
              from WarpBlt which inherits from BitBlt, then WarpGrafPport could inherit
              from GrafPorts
              perhaps traits could be used?

here was my testing:

f _ Form fromFileNamed: 'file.jpg' "some image file"
transform _ (MorphicTransform identity withScale: 0.8) withOffset: -100@-100
    Display getCanvas transform3By: transform
        clippingTo: World innerBounds
        during: [:myCanvas |
                myCanvas paintImage: f2 at: 0@0]
        smoothing: 1
]timeToRun [^] (4,076 bytes) 09-20-06 17:11 [^] (17,686 bytes) 10-01-06 02:10
 TTCFont-* [^] (1,623 bytes) 10-01-06 04:45
 FormCanvas-* [^] (7,223 bytes) 10-01-06 04:46

09-26-06 10:43   
Hi Haleden,

I started to look at the changes code.

It did not contain the definition for WarpGrafPort (I am using an OS9.1 Mac). So I need to know what the definition is before it will load.

How did you file out ? I could see it had one catagory in each of two catagories. So I'm curious because I don't know how to do that at one go.

So can you help me by uploading the rest of the code.

I suspect filing out the class WrapGrafPort will work .

ah I just looked at what you wrote. Well I went back and tried it. Somethings wrong and I couldn't see your example work.
If you upload the full class that still might help. I try again when I'm fresh.

Yours in service, -- jerome Peace
09-28-06 01:32   
hey, jerome,

i was incomplete in my descriptions

i copied the class GrafPort and called it WarpGrafPort

i then made it inherit from WarpBlt instead of BitBlt

the changes in the change file (which i concatenated after i filed them out--maybe not good practice?) reflect the changes made there and elsewhere.

i'll give another dump (prob friday with some more changes) and will include all of the pieces then, but i'm swamped today.


09-28-06 06:45   
Hi hal,

cool. I'll check back on the weekend.

There is a related report Mantis 0002084 which started out noting that overlapping browsers slowed things down. I just reread it and it sort of loses its way tracking down other speed factors but the original problem seems like it might be related.

Also something is needed here to dramatize the problem and the fix.

If you know of something that would be great.

Yours in service, -- Jerome Peace
09-30-06 07:18   
sorry, i'm under a deadline, so still won't get to this for a few days.

it doesn't seem that 0002048 is related from what i can see--it doesn't seem to have anything going on with transforms.

what sort of dramatization--other than the evidence of a 50-100x performance difference?

maybe i'm going beyond the design limits by trying to use large transforms--this approach is fine for small ones.

anyway, i'll get some info up here as soon as i can.


10-01-06 02:13   
okay, i uploaded my current version of WarpGrafPort, with some various changes.

i also have some other changes from other places (mostly FormCanvas) that i need to pull together and post, as well--will do later this evening.

10-01-06 05:16   
okay, i think this is all i have done so far.

i have tried to work out the pieces for several elements that i needed right away, which should give some initial indication of what it would take to make this work.

one of the gotcha's is that now rotations become tricky. i tried an approach where WarpGrafPort>>copyBits would hide that, but things (e.g., ellipses) were very ugly because it was generating each scan line and warping that, so it didn't have good coverage. i finally opted for allocating a temporary form (which is what i was trying to avoid--but perhaps these will stay smallish).

i opted to defer BalloonCanvas for lines and rectangles, with reasonable results--the ovals there looked bad, so i didn't use that there.

i got TTCFont working before i did copyBits--when i tested strikeFonts later, didn't have to make any changes to displayString-- it just used copyBits (i had to have copyBits "cheat" by allocating a temp form because rotating grabs some of the glyphs on either side of the desired glyph if i don't. i think TTCFont could just use copyBits (yep, i just tried that and it works--so you probably don't need the TTCFont file)

one issue i haven't tracked down is that when you pick up something using this approach with the hand, it disappears. it seems to have something to do with caching cause when i change the disablecaching variable in the hand drawing code, it works.

i'm not sure what the history and relationships here are--it almost seems like the balloonCanvas balloonEngine stuff is trying to address some of the same issues that i am--having the transforms handled at a lower level and more generally. it was already being deferred to for polygons in some cases.

anyway, i've only tested this on a limited repertoire so far, but my application, which uses transforms for zooming, etc, works much better.

i did notice something strange with display refresh when i tested on a windows platform (i usually use macosx), but that might have been due to some overzealous removal of some "refreshWorld" elsewhere in my code.

let me know where you think this should go from here.



10-01-06 06:12   
re: 2084--perhaps i'm wrong--the system browsers do use transform morphs in several places, so it could have something to do with this.

however, it looks like they only use translations, not scaling or rotations, which avoids the allocation of a Form on each redraw.

i'll peek further.

10-01-06 09:30   
Hi hal,

Thanks for your efforts.

You are ahead of me in mucking into this code. I've mostly been poking at the bug from the outside. (Do this and this runs slow. (Display a framerate and see what makes things go better or worse.) I hadn't got anywhere near a patch. I am working on bringing myself up to speed.

Andreas might know something worthwhile but he is a busy man. It would be good to have some good questions lined up before calling things to his attention. He wrote the balloon stuff.

A good next step would be to get some solid red flag tests.

Red flag tests are tests that are designed to fail until a fix is created.
Here the test would be something like


self assert:
[ example code ] timeToRun <= 'whatYouThinkIsAGoodTarget' asMilliseconds.

where TimeTests is a subClass of TestCase.

What would be helpfull is if you could specify the [ example code ] and the
'whatYouThinkIsAGoodTarget' number.

This should obviously fail before things are patched.

And That will become what to shoot for.

I started looking at what were mucking in. I could see understanding a large enough subset of the code to be able to propose a good fix will be difficult.

We'll learn by trial and error and hopefully clues from others.

The point is that there is a high payoff to fixing this and I still have the feeling you've uncovered a major clue.

The first patches are allowed to have major holes. They only need to point the way. A working example of something that goes much faster will prove something important. Then we can look for the right and solid way to fix what is already there.