Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.

Due to spam on this forum, all posts now need moderator approval.

 Entire forum ➜ MUSHclient ➜ Miniwindows ➜ WindowGradient is slooooowwww

WindowGradient is slooooowwww

It is now over 60 days since the last post. This thread is closed.     Refresh page


Posted by Fiendish   USA  (2,534 posts)  Bio   Global Moderator
Date Wed 27 Oct 2010 02:57 PM (UTC)

Amended on Wed 27 Oct 2010 03:14 PM (UTC) by Fiendish

Message
If I take the following code:
-- replacement for WindowRectOp action 5, which allows for a 3D look while maintaining color theme
-- Requires global theme.HIGHLIGHT, theme.FACE, theme.INNERSHADOW, and theme.OUTERSHADOW rgb colors to be set.
function DrawThemed3DRect(Window, left, top, right, bottom)
    WindowRectOp(Window, 2, left, top, right, bottom, theme.FACE)
    WindowLine(Window, left, top, right, top, theme.HIGHLIGHT, 0 + 0x0200, 1)
    WindowLine(Window, left, top, left, bottom, theme.HIGHLIGHT, 0 + 0x0200, 1)
    WindowLine(Window, left, bottom-2, right, bottom-2, theme.INNERSHADOW, 0 + 0x0200, 1)
    WindowLine(Window, right-2, top, right-2, bottom-2, theme.INNERSHADOW, 0 + 0x0200, 1)
    WindowLine(Window, left, bottom-1, right, bottom-1, theme.OUTERSHADOW, 0 + 0x0200, 1)
    WindowLine(Window, right-1, top, right-1, bottom-1, theme.OUTERSHADOW, 0 + 0x0200, 1)    
end


and replace the call to WindowRectOp with a call to WindowGradient with a second color, my channel capture miniwindow (which redraws 5 pretty small 3D rects each time the resize drag handler is called) can no longer keep up with even very slow user motion when dragging around the resizing tab. The code in its condition as presented above works flawlessly, and keeps up with even the fastest user motion as long as the window doesn't get too large.

Is there any way to bridge the performance gap here?

https://github.com/fiendish/aardwolfclientpackage
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #1 on Wed 27 Oct 2010 04:29 PM (UTC)
Message
One thing I notice when I look at the code for drawing gradients is that it sets every pixel manually:
   // main loop is columns
   for (long col = 0; col < iWidth; col++)
     {
     r = (uint8) rval;
     g = (uint8) gval;
     b = (uint8) bval;
     unsigned char * p = pBuffer + col * 3;
     for (long row = 0; row < iHeight; row++)
       {
       p [0] = b;
       p [1] = g;
       p [2] = r;
       p += increment;
       }  // end of each row
     rval += rinc;
     gval += ginc;
     bval += binc;                      
     }  // end of each column

One thing I'd be inclined to try is replacing that inner loop with a call to CMiniWindow::Line() so GDI can handle it. After all, GDI is hardware accelerated to some degree, and it buffers drawing instructions when it can.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #2 on Wed 27 Oct 2010 04:36 PM (UTC)

Amended on Wed 27 Oct 2010 04:38 PM (UTC) by Twisol

Message
I also found a GradientFill() function [1] that seems like it would be really useful to implement.

[1] http://msdn.microsoft.com/en-us/library/dd144957(VS.85).aspx

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #3 on Wed 27 Oct 2010 08:31 PM (UTC)
Message
My first comment is that the problem is vaguely described. Five "pretty small" rectangles could be anything. And the difference between GDI drawing and manually setting bytes is likely to change from insignificant for small rectangles to quite noticeable for large ones.

However, doing my best to reproduce, I made this (for the Immediate window):


<aliases>
  <alias
   match="gradient"
   enabled="y"
   group="miniwindows"
   send_to="12"
   sequence="100"
  >
  <send>

-- replacement for WindowRectOp action 5, which allows for a 3D look while maintaining color theme
-- Requires global theme.HIGHLIGHT, theme.FACE, theme.INNERSHADOW, and theme.OUTERSHADOW rgb colors to be set.
function DrawThemed3DRect(Window, left, top, right, bottom)
   WindowRectOp(Window, 2, left, top, right, bottom, theme.FACE)
    --WindowGradient ( Window , left, top, right, bottom, ColourNameToRGB "red", ColourNameToRGB "yellow" , 1)
    WindowLine(Window, left, top, right, top, theme.HIGHLIGHT, 0 + 0x0200, 1)
    WindowLine(Window, left, top, left, bottom, theme.HIGHLIGHT, 0 + 0x0200, 1)
    WindowLine(Window, left, bottom-2, right, bottom-2, theme.INNERSHADOW, 0 + 0x0200, 1)
    WindowLine(Window, right-2, top, right-2, bottom-2, theme.INNERSHADOW, 0 + 0x0200, 1)
    WindowLine(Window, left, bottom-1, right, bottom-1, theme.OUTERSHADOW, 0 + 0x0200, 1)
    WindowLine(Window, right-1, top, right-1, bottom-1, theme.OUTERSHADOW, 0 + 0x0200, 1)    
end

Window = "test"

theme = {
   FACE = ColourNameToRGB ("cyan"),
   HIGHLIGHT = ColourNameToRGB ( "red"),
   INNERSHADOW = ColourNameToRGB ( "lightgray"),
   OUTERSHADOW = ColourNameToRGB ( "darkgray"),
}

WindowCreate (Window , 
  0, -- left
  0, -- top
  500, -- width
  500, -- height
  6, -- mode
  0, -- flags
  ColourNameToRGB ("navajowhite"))

start = utils.timer ( )
DrawThemed3DRect(Window, 5, 5, 250, 250)
DrawThemed3DRect(Window, 100, 100, 350, 350)
DrawThemed3DRect(Window, 200, 200, 450, 450)
DrawThemed3DRect(Window, 250, 250, 500, 500)
DrawThemed3DRect(Window, 350, 10, 600, 250)
print (string.format ("time take = %%0.6f", utils.timer () - start))

WindowShow (Window , true)

</send>
  </alias>
</aliases>


I am guessing here quite large rectangles (around 250 x 250) which is hardly "pretty small".

Anyway, with the timing I get this for the WindowGradient line uncommented (and hitting Ctrl+R to repeat the alias):


time take = 0.001843
time take = 0.001861
time take = 0.001781
time take = 0.001763
time take = 0.001949
time take = 0.001775
time take = 0.001759
time take = 0.001813


And with that commented out and the WindowRectOp instead, I get:


time take = 0.000406
time take = 0.000388
time take = 0.000410
time take = 0.000410
time take = 0.000385
time take = 0.000418


Certainly it is quicker doing one GDI call than mucking around setting bytes, but not by an order of magnitude. Four times slower I would say, roughly.

I'll look into making the function more efficient, but more detail about the rectangle sizes and comparative timing would help to know if the problem is acceptably solved.

The other question is, do you write on top of these rectangles, or are they decoration? In any case, it could be quicker to pre-render them (if their size doesn't change) into another window and just blit them onto the visible one.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #4 on Wed 27 Oct 2010 08:45 PM (UTC)
Message
Another thing that could speed up resizing is to do what Windows used to do - during a resize operation draw just the outline of the window (not filling it) thus reducing considerably the amount of drawing involved. Then when they let go of the mouse redraw everything.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Fiendish   USA  (2,534 posts)  Bio   Global Moderator
Date Reply #5 on Wed 27 Oct 2010 08:46 PM (UTC)

Amended on Wed 27 Oct 2010 08:47 PM (UTC) by Fiendish

Message
My pretty small rectangles are in fact quite small:

15 x 15 exactly
15 x 15 exactly
15 x 15 exactly
15 x 150 with the second value resizing
450 x 20 with the first value resizing

I could potentially prerender the first three, but not the other two. The key for me here is that I'm trying to do this many times per second with other processing also going on. The whole thing works reasonably well without gradients, but falls over with them.

https://github.com/fiendish/aardwolfclientpackage
Top

Posted by Fiendish   USA  (2,534 posts)  Bio   Global Moderator
Date Reply #6 on Wed 27 Oct 2010 08:48 PM (UTC)

Amended on Wed 27 Oct 2010 08:53 PM (UTC) by Fiendish

Message
Nick Gammon said:

Another thing that could speed up resizing is to do what Windows used to do - during a resize operation draw just the outline of the window (not filling it) thus reducing considerably the amount of drawing involved. Then when they let go of the mouse redraw everything.


I'll spend another month working out performance hacks before I let the interface go that far backward in time. It's likely that I can pre-render other complex bits of the drawing to make up for this slowness.

https://github.com/fiendish/aardwolfclientpackage
Top

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #7 on Wed 27 Oct 2010 10:18 PM (UTC)
Message
Well I've taken both of Twisol's suggestions and improved the speed. For older operating systems drawing lines rather than doing the bytes myself results in a smallish increase in speed.


time take = 0.001546
time take = 0.001473
time take = 0.001491
time take = 0.001487
time take = 0.001490
time take = 0.001543
time take = 0.001469
time take = 0.001514


It's interesting it isn't better but there you are.

However for Windows 2000 up (which includes XP, Vista etc.) then the GradientFill call gives significantly better results:


time take = 0.000452
time take = 0.000525
time take = 0.001296
time take = 0.001269
time take = 0.001198
time take = 0.000456
time take = 0.000519
time take = 0.001187


It seems to vary a bit, interestingly, but overall it appears we are back to about the speed of the rectangle, or maybe slightly slower.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #8 on Wed 27 Oct 2010 10:27 PM (UTC)

Amended on Wed 27 Oct 2010 10:31 PM (UTC) by Twisol

Message
Nick Gammon said:
It's interesting it isn't better but there you are.

Theoretically, if the distance between the two colors is smaller than the length of the gradient (for some definition of "smaller"), there will be multiple columns where the color is precisely the same. If I have a 100px gradient from #FF0000 to #EF0000, for example, there will be large divisions (I'd imagine of equal size) where the RGB values are identical.

If you wanted to, you could probably make that into an optimization, and draw rectangles instead of lines where possible.

Nick Gammon said:
However for Windows 2000 up (which includes XP, Vista etc.) then the GradientFill call gives significantly better results:

Excellent!

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by Fiendish   USA  (2,534 posts)  Bio   Global Moderator
Date Reply #9 on Thu 28 Oct 2010 04:09 AM (UTC)

Amended on Thu 28 Oct 2010 12:26 PM (UTC) by Fiendish

Message
Hey cool. It's interesting that pre-2000 has different performance. I wonder if they started adding in some sort of special hardware acceleration for 2D shading. Or maybe they just have a really great way of calculating gradients quickly. Anyway, thanks tons, Nick. Turns out I might not have needed it after all, but I like optimization everywhere I can get it. *grin*

https://github.com/fiendish/aardwolfclientpackage
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


12,292 views.

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.