Saturday, December 6, 2008

iP* programming tip #5

Let's look today at the "pixel shader" level of the hardware functionality. The iPhone Application programming guide says that the application should not use more than 24 MB for textures and surfaces. It seems like those 24 MB are not in video card memory. I assume that all of the data is stored in system memory and the graphics card memory is not used.
Overall the iP* platform supports
  • The maximum texture size is 1024x1024
  • 2D texture are supported; other texture formats are not
  • Stencil buffers aren’t available
As far as I know stencil buffer support is available in hardware. That means the Light Pre-Pass renderer can only be implemented with the help of the scissor (hopefully available). As a side note: one of the other things that do not seem to be exposed is MSAA rendering. With the unofficial SDK it seems like you can use MSAA.
Texture filtering is described on page 99 of the iPhone Application programming guide. There is also an extension for anisotropic filtering supported, that I haven't tried.

The pixel shader of the iP* platform is programmed via texture combiners. There is an overview on all OpenGL ES 1.1 calls at

http://www.khronos.org/opengles/sdk/1.1/docs/man/

The texture combiners are described in the page on glTexEnv. Per-Pixel Lighting is a popular example:

glTexEnvf(GL_TEXTURE_ENV,
// N.L
.. GL_TEXTURE_ENV_MODE, GL_COMBINE);
.. GL_COMBINE_RGB, GL_DOT3_RGB); // Blend0 = N.L

.. GL_SOURCE0_RGB, GL_TEXTURE); // normal map
.. GL_OPERAND0_RGB, GL_SRC_COLOR);
.. GL_SOURCE1_RGB, GL_PRIMARY_COLOR); // light vec
.. GL_OPERAND1_RGB, GL_SRC_COLOR);

// N.L * color map
.. GL_TEXTURE_ENV_MODE, GL_COMBINE);
.. GL_COMBINE_RGB, GL_MODULATE); // N.L * color map

.. GL_SOURCE0_RGB, GL_PREVIOUS); // previous result: N.L
.. GL_OPERAND0_RGB, GL_SRC_COLOR);
.. GL_SOURCE1_RGB, GL_TEXTURE); // color map
.. GL_OPERAND1_RGB, GL_SRC_COLOR);



Check out the Oolong example "Per-Pixel Lighting" in the folder Examples/Renderer for a full implementation.

13 comments:

fluffy said...

My understanding was that the iPhone used the PowerVR chipset (same as on the Dreamcast), which at least historically never supported stencil buffers, but also it doesn't support depth buffers as it uses planar intersection to determine visibility, and at least in most cases of stencil buffer usage, planar intersection can produce the same (or at least very similar) results, but at least in the case of OpenGL it was up to the drivers to convert stencil operations to planar intersections. I can see them removing this from the OpenGL driver in order to reduce the complexity and memory consumption.

I do know that several games on the Dreamcast did planar-intersection shadow volumes (such as Sonic Adventure 2 and Shenmue) so if there's a way to get at the lower-level PowerVR functionality it should be possible to at least do some limited stencil-type effects.

Wolfgang Engel said...

Hey this is very cool background info. Thanks for this.

fluffy said...

No problem. Keep in mind that I only know this from secondhand information and never did any Dreamcast programming myself, so I have no idea what implications this brings to e.g. multipass rendering and the like. It's also quite possible that current-generation PowerVR chips just use an ordinary zbuffer.

Sinbad said...

I don't know for sure whether this will work on iP*, but we used to use a combination of Cg and nvparse to make it easier to write texture combiners code. You could then write a simple Cg pixel shader, which most people are already familiar with, and compile it using the 'fp20' profile before feeding it through nvparse. Although this tech is all NVIDIA it works just fine on other cards that support register combiners, since both Cg and nvparse are GPU agnostic. The converseion isn't free of course, but it's very convenient.

Ed said...

I know powervr sdk has a demo with various shadows cast on a plain, but what about self cast shadows? I assume the lack of the stencil buffer makes it impossible.

fluffy said...

Nope, again, the intersecting-planes stuff could be used to do self-shadows. Sonic Adventure 2 and Shenmue on the Dreamcast both did this.

Wolfgang Engel said...

Following POWERVR's MBX documentation there must be a stencil buffer. It is quite nicely located after the tile buffer and before everything else. Judging from the picture it looks like a huge speed-up.

fluffy said...

Hm, where do you see that? I can't find the MBX documentation specifically but every Google hit I get for "powervr mbx stencil" says it doesn't have one, aside from a couple of press releases from 2001 which say it will.

Ed said...

I'm sure I read somewhere that mbx chip does not support the opengl stencil commands

Wolfgang Engel said...

If you download the OpenGL ES 1.1 SDK from the POWERVR website you will find in there the PDF named

PowerVR MBX.Technology Overview.Undefinedf.External.pdf

Check out Figure 12 and the explanation.

fluffy said...

Figure 12 doesn't refer specficially to a stencil buffer, but rolls "stencil/depth test" together. I have a feeling they're waving their hands over the way that intersection-based culling works, and just describing the planar-intersection method as equivalent to stencils.

I mean, when it comes down to it, a stencil test at its most basic is just a way of tracking CSG operations on primitives - the PowerVR architecture just does the CSG up-front, and they (probably) call this "stencil" in the diagram to explain the equivalence.

It's telling that there's no other mention of stencil anywhere else in the documentation. So I'm still pretty much positive that there's no stencil buffer, and that translating stencil operations to deferred/in-place CSG is up to the driver.

Biosopher said...

Great posting. Been looking for this info and very interested in Oolong.

I can't get your code to work though. Specifically XCode tells me it cannot find these variables:

GL_SOURCE0_RGB
GL_SOURCE1_RGB

In which import are these defined?

Thanks,
Anthony

Biosopher said...

Ahhh...found it. It was defined in Oolong's OpenGLESExt.h.