12

Is it possible to render to texture with OpenGL ES 1.1 on the iPhone (2G and older)? If I bind a texture as a render buffer, it has to be the size of the render buffer, which isn't POT-sized. But OpenGL ES 1.1 requires textures to be POT.

Maybe it can't be done on ES 1.1?

GhassanPL
  • 2,679
  • 5
  • 32
  • 40

2 Answers2

27

While OpenGL ES 1.1 does not support non-power-of-two textures, newer iOS device models have the extension GL_APPLE_texture_2D_limited_npot, which states:

Conventional OpenGL ES 1.X texturing is limited to images with power-of-two (POT) dimensions. APPLE_texture_2D_limited_npot extension relaxes these size restrictions for 2D textures. The restrictions remain in place for cube map and 3D textures, if supported.

There is no additional procedural or enumerant API introduced by this extension except that an implementation which exports the extension string will allow an application to pass in 2D texture dimensions that may or may not be a power of two.

In the absence of OES_texture_npot, which lifts these restrictions, neither mipmapping nor wrap modes other than CLAMP_TO_EDGE are supported in conjunction with NPOT 2D textures. A NPOT 2D texture with a wrap mode that is not CLAMP_TO_EDGE or a minfilter that is not NEAREST or LINEAR is considered incomplete. If such a texture is bound to a texture unit, it is as if texture mapping were disabled for that texture unit.

You can use the following code to determine if this extension is supported on your device (drawn from Philip Rideout's excellent iPhone 3D Programming book):

const char* extensions = (char*) glGetString(GL_EXTENSIONS); 
bool npot = strstr(extensions, "GL_APPLE_texture_2D_limited_npot") != 0;

On these devices, you should then be able to use non-power-of-two textures as long as you set the proper texture wrapping:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

Unfortunately, this example application that I have which renders to a non-power-of-two texture uses OpenGL ES 2.0, so I'm not sure that will help you in this case.

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
  • 9
    You should *not* use *strstr* to check for the extension name in the extension string. This does not ensure you that another extension starting with the same prefix may not be misinterpreted. Say check for *GL_ARB_shadow* with strstr will bite you if you have *GL_ARB_shadow_ambient*. I've been bitten once a long time ago when a software update brought a new GL extension in the driver, and broke my code months after its release. – rotoglup Jan 21 '11 at 21:33
  • @rotoglup - That's a great point. As I said, this was code drawn from Philip Rideout's book. Perhaps you might write him something for the errata on the book. – Brad Larson Jan 21 '11 at 22:20
  • 5
    Thanks @rotoglup, I'm adding this to my book's errata. – prideout Jan 21 '11 at 23:30
2

It can be done, all you need to do is get the next power of 2 bigger than the non-POT.

Then generate a framebuffer:

GLuint aFramebuffer;
glGenFramebuffersOES(1, &aFramebuffer);

And a texture:

GLuint aTexturebuffer;
glGenTextures(1, &aTexturebuffer);

Then you do the same texture like things:

glBindTexture(GL_TEXTURE_2D, aTexturebuffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glColor4ub(0, 0, 0, 255);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

int area[] = {0.0, 0.0, renderWidth, renderHeight};

glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, area);

glBindFramebufferOES(GL_FRAMEBUFFER_OES, aFramebuffer);
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, aTexturebuffer, 0);

Here I used the draw_texture extension. textureWidth and textureHeight are the power of 2 bigger, and renderWidth and renderHeight are the the rendere's width and height. Then when you bind to aFramebuffer it will draw to texture.

NebulaFox
  • 7,813
  • 9
  • 47
  • 65
  • Unfortunately, it doesn't work. glCheckFramebufferStatusOES returns GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS. – GhassanPL Jan 21 '11 at 16:04
  • @Kronikarz: Did you create a renderbuffer also? As in `glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, width, height);` to connect to the framebuffer? – Ben Zotto Jan 21 '11 at 16:26
  • @Kronikarz: In my experience, you should also be able to render to a non-POT texture as well without rounding up the sizes, I believe. – Ben Zotto Jan 21 '11 at 16:27
  • @quixoto: That may be so, but I won't be able to display such a texture, I don't think. – GhassanPL Jan 21 '11 at 16:28
  • @quixoto: I created the renderbuffer and connected it. – GhassanPL Jan 21 '11 at 16:33
  • 2
    @Kronikarz: To be clear, iPhone definitely supports non-POT textures under GL 1.1 under very specific conditions. (I use them all the time.) The tech note is here: http://www.khronos.org/registry/gles/extensions/APPLE/APPLE_texture_2D_limited_npot.txt I can't find the iOS doc the references it. Your tex params must conform to certain limitations. – Ben Zotto Jan 21 '11 at 17:03
  • How odd. I got the code out of O'Reilly's iPhone 3d Programming book, and works on my end. @quixoto I knew there was an extension, but I always thought it was for OpenGL ES 2.0. – NebulaFox Jan 21 '11 at 17:29
  • @quixoto: This extension is not available on the iPhone versions I have, unfortunately. – GhassanPL Jan 21 '11 at 17:30
  • 2
    @Kronikarz: Ah, you're way back on the 2G or whatever. You should clarify this in your question so people know you're asking about legacy (frankly) platform stuff. Good luck! – Ben Zotto Jan 21 '11 at 17:47