How can I improve CGContextFillRect and CGContextDrawImage performance - cocoa

Those two functions are currently my bottleneck. I am working with very large bitmaps.
How can I improve their performance?

You could cache smaller versions of your bitmaps which you create before drawing the first time and then simply draw the downscaled samples instead of the full-blown 15 megapixel stuff.
Then again make sure you are only drawing what is necessary i.e. in 'drawRect: (NSRect) rect' only draw inside the rect (unless absolutely necessary). And try not do perform drawings outside of that method.

If you're drawing large background images with content in the foreground that moves, consider using a layer-backed NSView, adding a layer and setting its background image. You can then draw your content in a other layers (or layer-backed NSViews) above the background layer, and the view will never need to redraw the background image because it is stored in the GPU's texture memory. Your current image is too large for a single CALayer (CALayers are limited to the maximum OpenGL texture size of 2048 x 2048) so you will probably need to break it up into tiles.
Otherwise, as #iolo mentioned, you should make sure that you only redraw the parts of the view that really need updating.

Related

How does bitmaps draw pixel on window?

So I followed a few tutorials on how to draw on window using windows.h library, the part of the tutorial that I don't really understand is the bitmap part. They used createbitmap() and StrechBit() functions to draw on window. Do window references bitmap to draw pixels on the screen accordingly and bitmap is basically a chunk of memory large enough to store pixel's position and color value. If so, does bitmap automatically generate every time you created a window, because it seems that you don't really need to declare bitmap or use createbitmap() functions to type word on the window you created, you only need to create bitmap when you want to draw a custom pixel.
A window will receive the WM_PAINT message when it needs to be painted. This can happen because InvalidateRect was called, the window was resized etc.
Where the pixels are stored ("in" the HWND) is an implementation detail you don't have to worry about. On some versions/configurations the GDI functions are hardware accelerated and the result might be stored directly in the GPU, in others everything might be implemented in software and run on the CPU. When using a layered window I'm guessing everything older than Vista will use an internal bitmap to store the pixels.
GDI/GDI+ is the classic way to draw windows. If you need per-pixel alpha transparency you would draw to a bitmap and call UpdateLayeredWindow, otherwise you would just draw using any GDI function you want in WM_PAINT. This might include drawing one or several bitmaps, text, and lines/curves directly to the HWNDs HDC. As this can cause flicker in certain cases (if any area is drawn to more than once in one paint cycle), so people might draw to their own bitmap first and then BitBlt this bitmap to the window, this is called double-buffering.
The new way to draw is Direct2d/DirectComposition.

Direct2D: Check if image is outside visible area before drawing?

Is it a reasonable optimization to omit calls to ID2D1HwndRenderTarget::DrawBitmap() if the image will end up outside the visible area? If I implement the checking logic in the application that will cost some performance, so if the first thing D2D does is doing the same check then I'd rather not do it.
I had a test with my application which renders some UI part using Direct2D (and attaching renderdoc), seems it is a bit random.
I render a mix of Rectangles, Text, Path geometries (beziers) and Rectangle with a bitmap brush (which should be equivalent to your DrawBitmap call).
Then I capture a frame with all those objects visible, and another one panning my UI (using transform) so objects are not visible.
From there could check what is drawn or not:
Text is always culled
Solid color rectangles are not culled
Most of the times path geometries are culled, but sometimes not.
Rectangle with bitmap brush are NEVER culled
So it seems Direct2D is making different decisions depending on the types of elements you plan to draw.
Since rectangles are easily batched and cheap to draw, it seems that they are just drawn regardless.
Bitmap rectangles and text require more work, so it seems they are effectively culled.
Path geometry was looking to depend on how many polygon the geometry is tesselated to (I had a path that was translating to 26 primitives and it was not culled, another one translating to 120 and it got culled).
So you can either trust Direct2D that it will perform that optimization, but I would personally implement a quick rectangle to rectangle check just in case (it's not gonna hurt your performances as its an extremely simple operation).

OpenGL ES. Hide layers in 2D?

For example I have 2 layers: background and image. In my case I must show or hide an image on zoom value changed (simply float variable).
The only solution I know is to keep 2 various frame buffers for both background and image and not to draw the image when it is not necessary.
But is it possible to do this in an easier way?
Just don't pass the geometry to glDrawArrays() for the layer you want to hide when the zoom occurs. OpenGL ES completely re-renders everything every frame. You should have a glClear() call at the start of your frame render loop. So, removing something is done by just not sending its triangles. You might need to divide your geometry into separate lists for each layer.

Make HTML5 canvas behave like TclTK canvas for scale/translate?

I'm trying to port a TclTK program I wrote 20 years ago to HTML5.
After hours of frustation, I learned that when you "scale" or
"translate" HTML5's canvas element, it only applies to future
drawings, not items already on the canvas.
This is the opposite of TclTK, where items already on the canvas are
scaled/translated instead.
Short of creating a draw/redraw loop (where I clear the canvas and
redraw all the objects myself when I want to scale/translate), is
there anyway to make HTML5's canvas element behave like TclTK's?
Or am I missing something big?
The Canvas 2D Context is based around pixel-wise image manipulations — it is not a “retained mode” graphics interface as you are apparently familiar with. There literally is no record of your graphics for it to redraw. If you want to change the graphics, you have to redraw them somehow.
Everything is redrawing, in the end (though the redrawing may be hidden from your code), but there are ways to reduce the amount of work you have to do. Here are some options, roughly in order of amount of change you'll have to do to your code (and roughly in order of improved quality/performance):
Draw your graphics on the canvas, then scale and translate the canvas itself using CSS properties (not the width and height attributes of the canvas, which will clear it). This will rescale the image, possibly losing quality, since you're not drawing it anew optimized for the current scale.
Draw your graphics on the canvas, then export them into an ImageData or a data URL, then when needed redraw that onto the canvas. Again, may lose quality.
The above two are essentially kludges to keep using the canvas code you've already written. To get a proper system like you describe TK as being, you want to:
Build your own scene graph: Create a set of objects like Circle, Line, etc. which represent graphics, and containers for those which store transform attributes like scale and position. Then write routines to walk this graph and execute the appropriate drawing commands, whenever you need to redraw.
Use SVG instead. SVG is a language for vector graphics which, in modern browsers, you can embed directly in your HTML, and manipulate in JavaScript just like you would the rest of your page. In SVG, you can simply change a scale attribute and get the change you expect to see.
(The previous option is basically reinventing a small amount of SVG.)

Copy arbitrarily sized block of pixels into OpenGL ES texture... somehow?

I'm writing a drawing application, and the drawing canvas is an OpenGL texture. When you draw onto the canvas, it determines which region of the canvas texture has been changed, and copies that pixel data out (using glReadPixels) before applying the changes you made.
To undo, I want to simply revert to the previous texture state using that pixel data that was copied out. However, OpenGL ES doesn't provide a glDrawPixels command. What's the best way to do it?
I've considered two options, but I'm not sure either is that great:
Create a temporary texture using the pixels I copied out and draw that in. (However, copied region is not a power of two!)
Unbind the large canvas texture completely, manually alter the bytes of the texture, and then put it back into OpenGL. I'm not using any sort of compression, so this might not be that bad. But it seems like a hack?
Anybody have any ideas? I'd really appreciate it!
In case anyone stumbles across this while trying to do something similar, I've come up with a solution that seems to work well.
Grab an image of the current texture by binding it to the framebuffer and then writing the framebuffer to a CGImageRef.
Create a new CGContext and draw in the existing texture CGImageRef. Then draw old texture data in to the portion that the user changed, effectively "undoing" that change to the image.
Destroy old OpenGL texture and create a texture from the CGContext.
I think this is a pretty slow way of going about things, but I don't need huge performance - my real concern was limiting the amount of data being kept to represent the "old" texture.
If you need help with this (there's quite a bit of code) feel free to email me.

Resources