47

I'm trying to enable hw acceleration in Honeycomb, and display some Bitmaps on Canvas. All works fine, but for large bitmaps (>2048 in one dimension), I get error in log:

OpenGLRenderer: Bitmap too large to be uploaded into a texture

I know this is because of hw limitation, and can work-around it by reducing max bitmap size to be displayed if hw acceleration is enabled (checking by View.isHardwareAccelerated()).

My question is: how to easily determine max texture size available for Bitmap drawing by hardware. 2048 seems to be limit on my device, but it may be different on different ones.

Edit: I'm not creating OpenGL app, just normal app, which can utilize hw acceleration. Thus I'm not familiar with OpenGL at all, I just see OpenGL related error in log, and look to solve it.

Pointer Null
  • 39,597
  • 13
  • 90
  • 111

4 Answers4

67

Currently the minimum limit is 2048px (i.e. the hardware must support textures at least 2048x2048.) In ICS we will introduce a new API on the Canvas class that will give you this information:
Canvas.getMaximumBitmapWidth() and Canvas.getMaximumBitmapHeight().

TheHippo
  • 61,720
  • 15
  • 75
  • 100
Romain Guy
  • 97,993
  • 18
  • 219
  • 200
  • 3
    The method is called getMaximumBitmapHeight(). But it is not a static Method. Is there a static method or Constant that gives me values that I can use to download or resize Images without creating a Canvas Object for that every time? – Janusz Mar 28 '12 at 16:25
  • There is not, but I could add one. Note that creating a Canvas will give you a different answer since you will be using a software Canvas. – Romain Guy Mar 28 '12 at 22:44
  • 1
    It would be great to have a constant that contains the max texture size. Is 2048x2048 a reasonable default or are there devices with lower texture capabilities? – Janusz Mar 29 '12 at 05:38
  • 4
    It cannot be a constant as it depends on the GPU. 2048x2048 is a perfectly reasonable assumption. – Romain Guy Mar 29 '12 at 18:54
  • 3
    This cannot be true! I ran into a problem displaying an image of 1236x835 on a Galaxy Nexus!! My old HTC Hero is capable of displaying that! And: it's just a static image! I don't believe what I see there. How can I get around this?? – Zordid Apr 26 '12 at 19:37
  • On the G-N (Glaxy Nexus), a background of 720x1200 gives this error. I agree with @Zordid - Part of this answer is **NOT** true. – AlikElzin-kilaka May 06 '12 at 12:23
  • 48
    2048x2048 is the maximum texture size on GN. You are most likely running into this problem because your image is in the wrong density bucket. GN is an xhdpi device, so if your 720x1200 image is in the drawable folder for instance, it will be scaled by 100% and end up being 1440x2400. – Romain Guy May 06 '12 at 19:25
  • 1
    Very helpful indeed Romain, I was facing a similar issue and this image scaling explains a lot. Is there any documentation on how this scaling is done? – Soham May 27 '12 at 19:29
  • Is there a way to get the max texture size without using a Canvas Object? We are facing the following Problem: We are downloading images from the net that are shown in ViewPager. Since the images can be any size we try to limit them to the max texture size on the device itself. We don't have a proper Canvas at hand at the moment of saving the image. – Janusz Oct 31 '12 at 10:15
  • The Nexus 10 supports up to 4096x4096 already. This method is nice, but as already mentioned, you have to be careful since you need a Hardware-Accelerated canvas to get the right value – TSGames Dec 07 '12 at 11:33
  • I'm thinking of adding a static method somewhere for a future version. – Romain Guy Dec 07 '12 at 18:28
  • 9
    @RomainGuy both of those methods just return a static value Canvas.MAXMIMUM_BITMAP_SIZE, which is equal to `32766`. That doesn't seem right...? – Zac Sweers Feb 06 '15 at 11:39
  • 2
    @TSGames is there an example of how to use the 2 methods? Doing (new Canvas()).getMaximumBitmap{Width,Height()} seems to return an incorrect 32766 on the GN5. – kip2 Mar 23 '15 at 08:20
  • 3
    @HenriSweers On a Hardware accelerated canvas it returns the correct value. So you'll have to use a real View with `setLayerType(LAYER_TYPE_HARDWARE, null)` before getting the value. The `32788` value is only for a software based canvas. – Tspoon Mar 26 '15 at 13:52
  • @Tspoon What can I do without using it on an ImageView ? What are the steps exactly? – android developer Jul 29 '15 at 08:16
  • @HenriSweers Android use opengl to draw instead of skia. So the canvas instance will be GLES20Canvas, take a look at it and you will get the key. – dragonfly Dec 30 '15 at 11:32
  • @Tspoon this is incorrect — `setLayerType(LAYER_TYPE_HARDWARE, null)` does not influence "hardware" status of canvas if HW acceleration is already enabled in app. It simply renders the View in separate HW buffer (this is actually useless in case of ImageView, which already stores it's Bitmap in texture during display list creation). – user1643723 Dec 10 '16 at 10:01
18

Another way of getting the maximum allowed size would be to loop through all EGL10 configurations and keep track of the largest size.

public static int getMaxTextureSize() {
    // Safe minimum default size
    final int IMAGE_MAX_BITMAP_DIMENSION = 2048;

    // Get EGL Display
    EGL10 egl = (EGL10) EGLContext.getEGL();
    EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

    // Initialise
    int[] version = new int[2];
    egl.eglInitialize(display, version);

    // Query total number of configurations
    int[] totalConfigurations = new int[1];
    egl.eglGetConfigs(display, null, 0, totalConfigurations);

    // Query actual list configurations
    EGLConfig[] configurationsList = new EGLConfig[totalConfigurations[0]];
    egl.eglGetConfigs(display, configurationsList, totalConfigurations[0], totalConfigurations);

    int[] textureSize = new int[1];
    int maximumTextureSize = 0;

    // Iterate through all the configurations to located the maximum texture size
    for (int i = 0; i < totalConfigurations[0]; i++) {
        // Only need to check for width since opengl textures are always squared
        egl.eglGetConfigAttrib(display, configurationsList[i], EGL10.EGL_MAX_PBUFFER_WIDTH, textureSize);

        // Keep track of the maximum texture size
        if (maximumTextureSize < textureSize[0])
            maximumTextureSize = textureSize[0];
    }

    // Release
    egl.eglTerminate(display);

    // Return largest texture size found, or default
    return Math.max(maximumTextureSize, IMAGE_MAX_BITMAP_DIMENSION);
}

From my testing, this is pretty reliable and doesn't require you to create an instance. Performance-wise, this took 18 milliseconds to execute on my Note 2 and only 4 milliseconds on my G3.

Pkmmte
  • 2,822
  • 1
  • 31
  • 41
  • 2
    This gives you the maximum **PBuffer** size. That's not the same as getting the maximum texture size. They may be the same values on some devices, but there's absolutely no guarantee for that. – Reto Koradi Nov 08 '14 at 23:48
  • 1
    On every device I tried this seems to work properly. – ZoltanF Apr 23 '15 at 09:14
8

If you want to know dynamically the texture size limit of your device (because it's change depending on the device), you have to call this method:

int[] maxTextureSize = new int[1];
gl.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, maxTextureSize, 0);

And don't forget that for some device (the Nexus One for example), the texture size must be a power of 2 !

I know my answer comes a long time after the last update of this topic...sorry

VinceFR
  • 2,551
  • 1
  • 21
  • 27
4

According to the specification, calling glGetIntegerv with GL_MAX_TEXTURE_SIZE.

GL_MAX_TEXTURE_SIZE params returns one value. The value gives a rough estimate of the largest texture that the GL can handle. The value must be at least 64.

http://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml

K-ballo
  • 80,396
  • 20
  • 159
  • 169
  • Tried this already in Activity.onCreate, but doesn't seem to work, returns 0. Probably it misses some GL initialization. – Pointer Null Sep 18 '11 at 08:02
  • @mice: Exactly, the OpenGL context is not yet set at the point you call `glGetIntegerv`. – K-ballo Sep 18 '11 at 08:07
  • 4
    K-ballo: but I'm not creating OpenGL app, and don't care about some context. HW acceleration is hadled by system http://bit.ly/qw7BML. Just my Bitmap is not drawn, I'm looking for a clever fix. – Pointer Null Sep 18 '11 at 08:38