This means that now when you create a surface, or a sprite/background from a surface (especially when you target mobile platforms), the size of it should be closest to the value of power of 2
Not really. The runner has
always generated power-of-2 textures under the hood. What we are seeing in this version
is actually a bug.
I have done thorough testing and can confirm that this is 100% correct information:
Before this update, the way the runner handled dynamic sprite generation (this includes web/storage-based asynchronous sprite loading and creating sprites from surfaces) was the following:
1. Create a texture that is a power-of-2 size in both width and height, where the dimensions are the first powers of 2 that are bigger than the dimensions of the original image.
For example, if we were to load rarestPepe.png of size 230x320 pixels, the GM runner would first create in video memory a texture of dimensions 256x512.
2. Render the image onto the texture at its native size.
In our example, this would render a 230x320 image over a 256x512 texture.
3. Set the newly created texture's meta-data to reflect how much of the sprite actually occupies the texture. The functions texture_get_width and texture_get_height actually return that meta-data.
In the above case, texture_get_width would return 230/256 = 0.8984375 and texture_get_height would return 320/512 = 0.625. The runner actually reads this data automatically when drawing sprites, in order to know where to stop when mapping texture coordinates to primitives (as also evidenced by the docs for the two functions), i.e. in this case, when drawing the full sprite (NOT with draw_sprite_part, which TRIMS the sprite), the runner will draw a quad and map the sprite's texture to it, going on the horizontal axis from texels 0 through 0.8984375 (maybe this number gets truncated a bit), and on the vertical axis from texels 0 through 0.625.
Now that we've got the Game Maker Runner Texture Management Theory™ out of the way, let's get to what's changed:
After the update, the way the runner handles creating dynamic sprites has changed just a little bit (and
not everywhere necessary):
1. [this step is 100% identical to the one in the previous version]
2. Render the image onto the texture
scaled to fit the entire texture.
This is the 1st change. In order to not use scissoring anymore on any dynamic textures (dynamic sprites are that too, save for being volatile), they are now filling the
entire texture. By doing this, the textures never need to be "snipped", since the entire surface of the textures is useful data. This also does not use any additional memory, as blank pixels in a texture still take up space.
3.
This is where they forgot to do something. Normally, since now they are
always using the entire effective pixel size of a texture for dynamically-allocated textures, when setting the texture's useful width and useful height meta data, they should set the two properties to 1.0 and 1.0 respectively. However, they
aren't. They forgot to add this condition for the Android runner, which still computes the proportions in the same exact way as presented in point
3. above. I have confirmed this by using texture_get_width/height on a dynamically-loaded 320x320 sprite on Android. To everyone's "surprise", the functions are reporting 0.625 and 0.625 respectively, which accounts to a sprite of 320x320 occupying a texture of 512x512 (when in fact, the sprite occupies the entirety of the 512x512 texture here). A simple oversight, essentially just forgetting to set two properties to 1, 1 instead of performing a certain calculation in the Android runner is what breaks the dynamic sprites.
It is excusable for them to forget this, as it does not affect the pre-baked sprites. These sprites all get written into texture atlases ("texture pages") but then get their very own "textures" with widths and heights always set to 1, which actually point to regions in the texture pages. This makes them draw correctly all the time, since the runner always maps them from 0, 0 to 1, 1. (In case you were wondering why this issue does not affect pre-compiled sprites).
tl;dr This is a bug where they forgot to set two values to 1, 1 in the Android runner when loading sprites from external sources (even VRAM).
Another important point to understand is related to:
So as I understand now functions surface_get_width() and surface_get_height() are useless on Android as they still return old 1920 x 1080 instead of new 2048 x 2048 pixels.
They are, in fact, not useless. This also goes back to how the GM runner actually draws stuff to the screen. The sizes that something_get_width, something_get_height (sprites, backgrounds, surfaces) return are, in fact, the original image's size, NOT the one stored in memory!
When you load up a 24x24 sprite from an external source (or create a surface, but let's stick to sprites here in order to remain somewhat consistent. The mechanism applies for all dynamic textures anyway.), it gets loaded up into a 32x32 texture, BUT when you draw it on the screen, you know you want a 24x24 image, not some other size that the computer chose for you. This is why when you create a sprite/surface/background asset, GM keeps the original size in memory so that it knows what sizes to use when drawing the
polygons onto the screen.
As such, when drawing your shiny 24x24 sprite, GM will draw 4 vertices where the top-left one is at the current x and y position, and the bottom-right one is at the current x and y position off-set by 24 pixels on each axis, and the texel coordinate is 0.75, 0.75 (24 divided by 32). This, of course, should be 1.0, 1.0 on Android in the new version of the runner, but because of the bug, it is still 0.75, 0.75, making the sprite appear blown up.
But, although the sprite is magnified and cropped as a result of the wrong texel coordinates set when loading the sprite under the new version of the runner, if you check the space is occupies on the screen, you will notice the pixel count is in fact the correct 24x24 pixels (or whatever the sprite size is in your case).
The only thing that is wrong here is setting the texture "width" and "height" meta-data correctly when loading dynamic sprites on Android in the new runner. Everything else works exactly as it should.
Also: The docs for texture_get_width and texture_get_height state that they return the "width/height of the texture page" -- this is rather confusing. A better statement would be that they return the proportion of texels actually being used in the given texture (which is precisely what these functions return), since the real width or height of said texture is actually a power of 2, not a sub-unitary number.
For when staff reads this: Hi guys. This is an extremely simple fix. Literally just replacing two math calls to just "= 1;". Please make this fix part of the next EA. Thank you!