Importing a set of 80 icons in QML as non-visible images to be used for shader sources (for arbitrary colorization):
property Image action: Image { sourceSize.width: 512; sourceSize.height: 512; source: "icons/action.svg"; mipmap: true; antialiasing: true }
// 79 more of those
I discover that my memory consumption has skyrocketed, from 45 mb to 128 mb, a whooping ~185% increase, thats 83 extra mb for the 80 icons.
It was expected, after all, 512 * 512 * 4 / 1024 / 1024 makes up for exactly 1 mb of memory. However, that cost is not acceptable, especially in the face of targeting mobile phones with the app.
I could reduce the rasterization size, however, I want the icons to be nice and crisp. The icon size itself varies according to the device display, but for optimal user experience it needs to be about an inch or so. Given that most new high end phones are already pushing above 500 dpi, I'd really hate to scale the icons down and have them appear blurry.
Since the SVGs are supposed to be colorized in arbitrary colors, they are in effect simply alpha masks, meaning that all I really need is one of those 4 channels. Unfortunately, QML's Image doesn't seem to offer any sort of control, the SVG is rasterized to a RGBA image.
And indeed, if I
QVector<QImage> imgs;
imgs.reserve(80);
QDirIterator it(":/icons", QDirIterator::Subdirectories);
while (it.hasNext()) {
QSvgRenderer renderer (it.next());
QImage ic(512, 512, QImage::Format_Alpha8);
ic.fill(Qt::transparent);
QPainter pp(&ic);
renderer.render(&pp);
imgs.append(ic);
}
I get the expected modest 20 mb increase in memory usage.
Any ideas how to save on some memory?
2 hours later - good news, first and foremost, a custom QQuickImageProvider works out of the box with QImage::Format_Alpha8, no problems there. Unnecessary channels are eliminated.
But more importantly, I realized that the icons lend themselves very well to distance fields representation. So I now employ 128x128 SDF textures, which scale beautifully to far above 512x512, reducing the memory usage for the icons to the measly 1.25 mb, for a total of 64x reduction of ram usage compared to the initial implementation.
The only downside is the 3-4 seconds (on a Note 3 phone) additional startup, because the distance fields are calculated on startup, but there are remedies for this as well, I might switch to pre-computed SDFs or offload if to shaders, which would be a little more complex, but should reduce the time at least 5-fold.
The thing with the Image component is it appears to render the SVG to a bitmap before it is drawn. Hence the requirement to set sourceSize to force it to render your SVG at different resolutions. This force rendering can lead to poor memory usage and poor performance.
As an alternative, I found a number of components in QML that render SVG perfectly via the icon property.
Item {
width: 256
height: 256
Button {
anchors.centerIn: parent
background: Item { }
icon.source: "https://raw.githubusercontent.com/Esri/calcite-ui-icons/master/icons/biking-32.svg"
icon.width: 256
icon.height: 256
icon.color: "blue"
enabled: false
}
}
Which renders my biking-32.svg at 256x256 resolution in blue:
Related
From Arch Wiki:
For Xft.dpi, using integer multiples of 96 usually works best, e.g. 192 for 200% scaling.
I know that 200%, 300%,... scaling is the best possible because every pixel replaced with integer amount of pixels and we don't have situation where we need to display 1.5 pixels.
But what if don't have 4k monitor, and have for example 2.5k(2560x1440) monitor or monitor with some non-standard resolution or aspect ratio. In this case increasing scale factor 2 times is too much.
I have only 2 ideas:
Scale it in 1.25, 1.5, 1.75, so objects with 16x16 and 32x32 size will be properly scaled.
Scale it in (vertical_pixels*horizontal_pixels)/(1920*1080)*96, so you will get size of objects similar to normal display.
I understand the use of thumbnail in network applications but assuming all the image are in the application itself (photo application), in this case do we still need thumbnail images for performance reasons or is it just fine for the device to resize the actual image on run time?
Since the question is too opinion based I am going to ask more quantitively.
The images are 500x500, about 200-300kb size jpg.
There will be about 200 images.
It is targeted for iphone4 and higher, so that would be the minimum hardware specs users will have.
The maximum memory used should not pass 20% of the devices capacity.
Will the application in this case need separate thumbnail images?
It depends on your application. Just test performance and memory usage on device.
If you show a lot of images and/or they change very quickly (like when you are scrolling UITableView with a lot of images) you will probably have to use thumbnails.
UPDATE:
When image is shown it takes width * height * 3 (width * height * 4 for images with ALPHA channel) bytes of memory. 10 photos 2592 x 1936 stored in memory will require 200Mb of RAM. It is too much. You definitely have to use thumbnails.
Your question is a bit lacking on detail but I assume you're asking if, for say a photo album app, can you just throw around full size UIImages and let a UIImageView resize them to fit on the screen, or do you need to resize?
You absolutely need to resize.
An image taken by an iPhone camera will be several megabytes in compressed file size, more in actual bytes used to represent pixels. The dimensions of the image will be far greater than the screen dimensions of the device. The memory use is very high, particularly if you're thinking of showing multiple "thumbnails". It's not so much a CPU issue (once the image has been rendered it doesn't need re-rendering) but a memory one, and you're severely memory constrained on a mobile device.
Each doubling in size of an image (e.g. from a 100x100 to a 200x200) represents a four-fold increase in the memory needed to hold it.
I have a website using three.js with CanvasRenderer. The renderer's size is set depending on the window size. On an iPad, the size is 1024 x 672 pixels. With this size, I get extremely bad performance (~1 FPS). If I reduce the width to 1023 Pixels, I get about 60 FPS.
Is there any specific reasion why the performance should drop significantly when hitting 1024 pixels? I don't have any issues with this resolution in Firefox.
I have heard about the HTML5 canvas element in some browsers losing a massive amount of performance once a certain number of pixels is being rendered. This would appear to be caching issue with the browser itself. Though the question is still unanswered.
Why does drawImage performance differ greatly with larger than 65776 pixel canvas sources
Render the canvas at a lower resolution and use CSS to scale it up to full HD.
I am playing through an animation of about 90 images # 480x320 each, and I am wondering with the images not being power of 2, will this be a big performance hit? I am programing for as far back as the iphone 3Gs. Also I am using cocs2d.
Assuming you load all of these images at the start and they are 16 bit images.
Well you will have 512x512x90 = 23,592,960 pixels
With 16 bit images thats 377,487,360 bits.
377,487,360 bits = 45 Megabytes of RAM.
So yes that is a big performance hit.
Let's see...
480x320 image will create a texture of 512x512 (next nearest power of two). 512x512 times 32bit color depth (4 bytes) equals 1 Megabyte. 90 times 1 Megabyte equals 90 Megabytes.
Your biggest problem will be allocating this much memory and caching it. Without caching the animation images, you'll have to load each image every time the animation frame changes. Loading 1 Megabyte from flash memory is pretty darn slow, I'm guessing > 100 milliseconds. So every time a frame changes, your app will stop for a fraction of a second. This will be a problem on the 3GS, and possibly the Retina devices as well if you use Retina images (each 960x640 image then requires 4 Megabytes texture memory).
You can only improve this by using PVR compressed images (use TexturePacker). Even halving texture size to 16 bit will probably not be enough for a smooth animation.
I am trying to use SpriteSheet to run an animation. My frames are of 320x480 in size each, So I am able to put max 6 frames on the texture image. But my animation consists of frame number ranging from 50 to 200 sometimes, and all are of size 320x480.
But this much number of frames cannot be added on the Texture image as the size is restricted to 1024x1024.
Is there any other approach I can try out. Can I play one animation after the other.And won't it be hampering the performance.
Please, I need suggestions.
Best,
Vaibhav Tekam.
Ugh, you're going way past what the device can handle! You'll have to reconsider what you're trying to achieve and how to achieve it. Let me explain.
Every 1024x1024 texture with 32 bit colors requires 4 MB of memory. If you want a sprite animation consisting of 60 full-screen sprites, you need 10 such textures. That makes 40 MB of memory. Or 120 MB for your upper-case scenario with 180 animation frames.
Keep in mind that the 128 MB RAM memory models of the iOS devices have about 30 MB memory available for your App, at most and under ideal conditions. You will start running into memory issues with only five 1024x1024 textures. The 256 MB devices still have only about 100 MB available for your App.
Since it's supposed to be an animation, it's also not an option to load one texture, and after every 6th image, remove that texture and load the next one. Loading a 1024x1024 texture into memory takes about 1-3 seconds depending on the device. Your App will be irresponsible during that time.