Talking to an App Store Review brick wall

In short, the Gold version of PPSSPP for iOS is stuck in review, and I am thus unable to update it at all, and I am also unable to update any aspect of the store presence, like the description. For now, I recommend all iOS users to use the free version of PPSSPP, even if you paid for Gold.

The App Store situation

Here's an overview, followed by the actual conversation with App Store Review.

PPSSPP is an open source PSP emulator, that lets you run your own PlayStation Portable games on your various devices. PPSSPP is officially available on Android through Google Play, PC, Mac, and recently iOS through the App Store. There is also a Linux flatpak build. The project is ongoing for more than 11 years now, and has been downloaded over 100M times. It has millions of active users on Android.

PPSSPP is completely free to download (and compile if you want, since it's open source) but there's also an optional paid version to finance the development and maintenance of the project, buildbot, website, etc.

The paid "Gold" version is, except cosmetically, identical to the free version. I've chosen this monetization model on the App Store to keep it consistent with the other platforms, where it's often the most practical one.

In May this year, Apple changed its policies and started allowing game console emulators on the App Store. The change was of course followed by a bunch of emulator releases. Here are a few examples:

  • Delta (Website) - Nintendo consoles (NES, SNES, GB, GBC, GBA, N64, DS). Open source.
  • RetroArch (Website) - Multisystem emulator supporting a large amount of game consoles. Open source.
  • BigPEmu (Website) - Atari Jaguar emulator. Closed source.
  • Folium (Website) - multisystem emulator supporting various portable Nintendo consoles. Open source.
  • ArcEmu - Nintendo GB/GBC/GBA emulator for Apple Watch.

For some time now, I have simply not been able to update the paid iOS version on Apple's App Store. The free version flies through review in a few hours, while the near-identical paid version is just stuck.

Below is an authentic conversation with App Store Review. This is the second conversation, I previously had a much longer one, but it disappeared when I submitted a new build. The arguments were the same, just more rounds of back-and-forth.


Apple App Store Rejection, initial message

Submission ID: 7fe4cdbf-80a6-43ba-a3d4-e54b73b14267

Review date: November 04, 2024

Version reviewed: 1.18

Guideline 4.1 - Design - Copycats

Your app's metadata contains content that is similar to third-party content, which may create a misleading association with another developer's app or intellectual property.

We understand that the mentioning of the console is to provide more context to the users, including trademarked terms such as "PSP" in a non-referential way is still not appropriate.

Next Steps

It would be appropriate to revise the app and metadata to remove this third-party content before resubmitting for review.

If you have the necessary rights to distribute an app with this third-party content, attach documentary evidence in the App Review Information section in App Store Connect and reply to this message.

Resources

Many factors may contribute to a guideline 4.1 rejection, including but not limited to the following examples:

  • Using the app metadata or developer account information to create a misleading association with another app.

  • Including irrelevant references to popular apps in an app's name or subtitle.

  • Copying the content, features, and user interface of popular apps.

Learn more about guideline 4.1.

Guideline 4.3(a) - Design - Spam

We noticed your app shares a similar binary, metadata, and/or concept as apps submitted to the App Store by other developers, with only minor differences.

Submitting similar or repackaged apps is a form of spam that creates clutter and makes it difficult for users to discover new apps.

Next Steps

Since we do not accept spam apps on the App Store, we encourage you to review your app concept and submit a unique app with distinct content and functionality.

Resources

Some factors that contribute to a spam rejection may include:

  • Submitting an app with the same source code or assets as other apps already submitted to the App Store

  • Creating and submitting multiple similar apps using a repackaged app template

  • Purchasing an app template with problematic code from a third party

  • Submitting several similar apps across multiple accounts

Learn more about our requirements to prevent spam in App Review Guideline 4.3(a).

Guideline 5.2.2 - Legal

The app appears to contain copyrighted video game files,

Apps and their content should not infringe upon the rights of another party. In the event an app infringes another party’s rights, the app's developers are responsible for any liability to Apple because of a claim.

Next Steps

Either remove the copyrighted third-party content from the app and its metadata or provide a written affirmation that you have the appropriate rights or license to use and distribute the third-party copyrighted materials.

Resources

Learn more about intellectual property requirements in guideline 5.2.2.

Support

  • Reply to this message in your preferred language if you need assistance. If you need additional support, use the Contact Us module.

  • Consult with fellow developers and Apple engineers on the Apple Developer Forums.

  • Provide feedback on this message and your review experience by completing a short survey.


My initial response

Please read! If you are not a robot, please indicate that you read the below, and respond to it properly.

Five minutes after this rejection was made, my near-identical free version of this very same app ("PPSSPP - PSP Emulator"), on the same account, with the same metadata, and same files, and essentially the same functionality, was APPROVED by App Review. Why not this one? It's 99.9% the same app, on the same account.

OK, so once again, I will refute your complaints point by point.

4.1 - Design - Copycats

Any games console emulator obviously needs to be able to mention what system it emulates. Anything else is unreasonable. Other emulators like Folium do this too.

4.3(a) - Design - Spam

I am the original author of this app. It is not spam, it's just the paid version of PPSSPP - PSP Emulator.

Guideline 5.2.2 - Legal

"The app appears to contain copyrighted video game files"

There are no such files. If there's a file you have a complaint about. PLEASE LET ME KNOW EXACTLY WHICH ONE. The filename please.


Apple App Store Reply

Hello,

Thank you for information.

However, to be in compliance with guideline 5.2.2, the app can open video games files without the appropriate authorisation from the right holder. it would still be appropriate to either remove the copyrighted third-party content from the app and its metadata or provide a written affirmation that you have the appropriate rights or license to use and distribute the third-party copyrighted materials.

To be in compliance with guideline 4.1, the app uses copyrighted terminology in the app name (PSP) in a non - referential manner, it would still be appropriate to revise the app and metadata to remove this third-party content before resubmitting for review.

To be in compliance with guideline 4.3, it would still be appropriate to review your app concept and submit a unique app with distinct content and functionality.

We look forward to reviewing your resubmission.

Best regards,

App Review


My second response

Hi again..

First, can you tell me what changed? This app was APPROVED by App Review a few months ago, but suddenly App Review started rejecting updates - but only for this paid version of the app, the free version still gets every update approved. I am simply trying to submit a bugfix update, no substantial change has been made to what the app does. Additionally, you APPROVED the free version of the app ("PPSSPP - PSP emulator"), on this very same developer account, just two days ago. It has all the same functionality.

Second, I believe that you have an automated system that has somehow started triggering on just this app. Is this the case? The three points are simply wrong. Again, point by point:

As for 5.2.2, there are, again, no copyrighted game files being shipped with the app. As for playing unauthorized files, just like an MP3 music player will play files that the user owns, this app will play retro PSP games that the user owns. This app is not in any way a violation of 5.2.2. Apple started allowing game console emulators with this type of functionality earlier this year, some other examples that are live on the App Store are Folium and RetroArch, and of course PPSSPP, the free version.

As for 4.1, for a user to understand what retro game console the app emulates, we really have to mention the name PSP. This is not any kind of copyright violation, and the free version of the app does this as well and was approved.

As for 4.3, it's really quite insulting to be told to "review my app concept". This app is serious software and is one of the most popular retro game console emulators in the world, with hundreds of millions of downloads on other platforms, and four million downloads of the free version on iOS . It has a great reputation in emulation circles. Here's the wikipedia page, which confirms that I, Henrik Rydgård, am the original author: https://en.wikipedia.org/wiki/PPSSPP

So please, consider the facts above.


Apple App Store Reply #2

Thank you for your reply.

Please note that we are unable to share with you the review process or other information regarding other apps.

All apps, including updates, undergo a complete review to ensure compliance with the most current version of the App Review Guidelines.

To be in compliance with guideline 5.2.2, the app can open video games files without the appropriate authorisation from the right holder. it would still be appropriate to either remove the copyrighted third-party content from the app and its metadata or provide a written affirmation that you have the appropriate rights or license to use and distribute the third-party copyrighted materials.

To be in compliance with guideline 4.1, the app uses copyrighted terminology in the app name( PSP) in a non - referential manner, it would still be appropriate to revise the app and metadata to remove this third-party content before resubmitting for review.

To be in compliance with guideline 4.3, it would still be appropriate to review your app concept and submit a unique app with distinct content and functionality.

Let us know if you have any further questions.

Best regards,

App Review


Conclusion

There seems to be no progress possible, despite Apple's complaints being entirely invalid:

  • The essentially-identical free version of PPSSPP flies through review every time, while the paid version is stuck. Why aren't the two treated the same?
  • Most of the other approved emulators also mention the names of the consoles they emulate in the App Store description - otherwise it's kind of hard for users to know what to download.
  • There are no copyrighted game files included. Emulators playing user-provided games are allowed on the App Store now.
  • It's the original app, not a cheap re-upload of someone else's content.

I tried appealing the previous conversation to the App Store review board, with no result.

It's just so frustrating. I want to get a bugfix update out, and I can't.

If you are an Apple employee and have any way to help, or any information or tips that might be helpful to get past this roadblock, contact me at [email protected].

At this point, I'm starting to think that the best way forward might be ditching the separate Gold app and switching to in-app purchase, though there are some practical issues with that.

1.18 is here!

PPSSPP 1.18.1 - announcement and progress report

PPSSPP 1.18.1 is now out, find downloads on the download page!

WARNING: There is a critical metadata parsing bug in 1.18 that may affect many devices when running homebrew apps and demos, or even having them in your folder. This is fixed in 1.18.1.

If you're on Android and already have it installed from Google Play, your update will arrive within a week (to catch crashes early).

iOS will also receive the update on the App Store. Howevwer, the Apple Store review process has been problematic recently (if this continues, a lengthy write-up is coming...), so it may take a quite long time before it's up, unfortunately.

For details on the changes, see the news item.

Download now!

Fixes in 1.18.1

  • Crashfix in PBP reader (homebrew/demos) (#19580)
  • Fix minor theme issue in the Homebrew Store (#19582)

Overview of fixes in 1.18

  • iOS support is now official and has been greatly improved, compared to old side-loaded builds. It's now nearly feature complete, only missing microphone emulation and a few minor UX things like easily setting a background image in the menu. A lot of iOS-specific optimizations have been implemented to keep performance as good as possible, even though we can't use JIT.
  • A lot of potential crashes have been fixed, both in-game and in the UI
  • A number of rendering and video playback problems have been fixed
  • Input changes: More mappable actions, the AxisSwap feature has been fixed
  • UI changes: Game info can be reached in-game, you can install savegames directly from zip files, etc
  • The Android VR build got "immersive mode" which makes better use of the built-in motion compensation, and many other fixes. Lubos explans it in this video.
  • And of course a huge amount of small bugfixes and performance improvements around the code base.

Enjoy!

1.17 is out!

PPSSPP 1.17 - release announcement and progress report

PPSSPP 1.17 is now out! Get it on the download page! If you're on Android and already have it installed from Google Play, your update will arrive within a week (to catch crashes early).

For fine details, see the news item.

Download now!

Beta program

For the first time, you can now sign up to receive beta versions automatically. This is easier and safer than installing APKs from the buildbot, and you make a valuable contribution to development. See details here.

CHD support

CHD was originally a format for compressing hard drives from arcade games in MAME, but has since became the most popular format for storing ISOs for CD- and DVD-based video game consoles. PSP already has a different format, CSO, which can be used to similarly loss-lessly compress ISOs, and as a bonus, unlike CHD, these actually work on the real hardware.

So you might ask, why support CHD? It does provide a slightly better compression ratio, but the main reason is that it's simply been requested a lot. Many people seem to familiarize themselves with a set of tools, and since CHD works to compress ISOs for most other systems, people just want to stick with it. So now we support it.

IMPORTANT! You MUST use the createdvd command from recent versions of chdman to generate your CHDs. createcd will work but there will be severe performance problems. See issue #18798.

Example command line:

chdman createdvd -i "Grand Theft Auto - Vice City Stories.ISO" -o GTA_VCS_dvd.chd

Important fixes in 1.17

  • Several serious hangs and crashes that could happen when switching away from the app, especially from the pause screen, have been fixed.
  • Multiple rendering issues have been fixed, and rendering performance has been further optimized.
  • PPSSPP now tracks total time played per game, you can check it in the info screen for each game (long press the icon).
  • Some new UI features, like the ability to keep the game running behind the pause menu overlay.
  • Many input fixes, especially around deadzone handling for both analog stick and tilt control.
  • Many bugfixes around texture replacement.
  • Input latency has been greatly improved on the SDL build with Vulkan. Don't use OpenGL on Linux if you can avoid it.
  • For RetroAchievements, renamed the Challenge mode to Hardcore mode and made it the default, as is standard.

For a more detailed changelog, see the release notes.

1.16 release

PPSSPP 1.16 - release announcement and progress report

PPSSPP 1.16 is now out! Get it on the download page!

PPSSPP 1.16.1-6 were also released, with some important hang and crash fixes.

For fine details, see the news item.

RetroAchievements support

RetroAchievements is a long-running project to add "achievements", similar to Xbox Achievements or Playstation Trophies, to game for old video game consoles, in order to add extra challenges and improve replayability, and also making the whole experience feel a bit more modern.

In 1.16, PPSSPP adds full support for RetroAchievements. On the System tab in settings, you can now click RetroAchievements to reach a dialog where you can log in to your RA account. You can't register the account directly from within PPSSPP though, as it's an external service.

RetroAchievements has a very passionate community and is getting more and more popular. Unfortunately, achievement definitions are not yet available for all games, and on the PSP they're often only available for a single regional version of a game, so watch out for that if you want to try it. To check, on the RetroAchievements website when browsing games, you can check the "Supported Game Files" link on a game's page to see which UMD you'll need to acquire and dump.

Important fixes in 1.16

  • A lot of people on Android 13 devices ended up in a situation where the choose-a-folder dialog during set up didn't work correctly. This has been fixed.
  • Multiple input event handling fixes, should help with external joysticks
  • Perf improvements on lower end devices by disabling ubershaders
  • Multiple fixes for glitches like flicker in WWE vs Smackdown 2006, shadows in Motorstorm, etc.
  • Lots of additional performance improvements and fixes
  • Multiple bugfixes around texture replacement, fixing Tactics Ogre fonts among other things

New JIT backends by [Unknown]

A background development that most people won't notice yet, but will have long-term performance benefits in addition to compatibility with more CPU architectures, is the addition of new IR-based JIT compiler backends.

PPSSPP has long supported recompiling the PSP's MIPS code to an easier-to-interpret intermediate representation which we call IR, in order to speed up platforms where we can't always JIT-compile like iOS. This IR is not only easier for the CPU to interpret than raw MIPS instructions, but can also easily be processed through optimization passes, which can thus be general across architectures.

We've long had a plan to eventually try to compile the IR to native code, which would gain the benefit of general optimization passes, while still producing really fast native code. When starting his RISC-V backend, [Unknown] chose to use this approach, and then proceeded to write x86/x86-64 and ARM64 backends, too. Currently, these are at parity or a bit faster than the existing JITs, but much less tested which is why they're not yet selectable in the UI.

Correct emulation of vrnd by fp64

fp64 has been working on trying to reverse engineer accurate implementations of some of the more obscure math instructions of the PSP's VFPU, a custom little SIMD coprocessor. Previously he solved sin/cos/sqrt among others, now the turn came to the vrnd instruction. Surprisingly it seems to consist of a mix of multiple traditional random number generators. Some details can be found in this issue on github.

The 1.15.x release process

The 1.15.x release series has been out now for a couple of weeks, including some point-releases. These have been made mostly as direct response to crash reports but also for some other fixes. Time to summarize!

  • Overall crash rate is down by about 20% from previous releases
  • It took three point-releases to get there though! A few new crashes emerged in this release, but I also fixed some old ones while at it.
  • People seem generally happy with the release, but there have been some negative reviews coming in, mostly about slowdown on older devices, control mapping problems, and even about how the new icon is ugly.

Thus, a fourth point-release is rolling out about now, 1.15.4, with the following changes:

  • Some optimizations to claw back most of the lost performance
  • The Android device resolution / HW scaler setting will be back
  • Fixes for running things directly out of the Downloads folder using the Load button on newer Android versions
  • Fixes for some control mapping problems
  • On devices that don't understand the new icon format, use the old icon instead of an ugly auto-generated one.
  • Fix loader bug triggered by WWE 2009, preventing it from starting
  • Tilt control gets back a lost setting (inverse deadzone, or "low end radius")
  • A couple of updates to compat.ini.

Hopefully this will be enough to avoid a fifth!

While looking at performance to eliminate some regressions, I found plenty of additional room for improvements, and I have a bunch of good changes pending. Mostly though, these will need serious testing so I cannot merge them until after we're done with the main series of 1.15.x releases, to keep things simple. But expect serious performance improvements on old devices in 1.16!

Anyway, enjoy!

Progress Report - spring 2023

PPSSPP Progress Report - Spring 2023

Welcome to the first official Progress Report! I've long enjoyed reading Dolphin's progress reports, but it turns out to take quite the effort to write one. So, it's not likely that these will be monthly going forward, but either way, here's the first one. More likely these will accompany each official new official release. Essentially, these will be longer form versions of the release notes.

PPSSPP has been an ongoing project for over 11 years now, but work never ends! The new version, 1.15, is another pretty good upgrade. The main themes are stutter fixes and quality-of-life improvements, and obviously some compatibility fixes and performance improvements as usual. Additionally, macOS is now an officially supported platform, and support has been improved substantially.

So go Download PPSSPP 1.15! New: There's now an official Mac build!

Please note that the Android version on Google Play will as usual roll out slowly over multiple days in order to catch any bad crashes early, so you may have to wait a few days before you receive the update.

1.15 - top improvements

Reduction of shader compilation stutter

PPSSPP has long had problems with stutter caused by shader compilation, and it had reached a point where it was stuttering enough to nearly be unplayable initially on some devices with very slow shader compilers, such as devices with the PowerVR GE8320.

Two changes have been made to improve on this: First, the sheer amount of different shader variants was a bit excessive. We'd compile separate shaders for every little shading state bit, such as the double-color-value or fog flags. Now, a bunch of these are controlled by uniform values instead, so the shader count has gone down by as much as half or more in many games. We still have more variants than we really need, but the problem is much smaller now. This change affects all rendering backends.

Additionally, in Vulkan, we now do shader compilation (as in pipeline creation) in parallel on multiple threads, which is a huge improvement on some drivers like the ones for PowerVR GPUs (which are increasingly common in lower-end phones like Galaxy A21), a minor improvement on Adreno and generally neutral on Mali. The devices seeing the biggest improvements were also the slowest before, so definitely worthwhile.

Texture replacement rework

In PPSSPP, you can install "texture replacement packs", containing higher resolution textures for a game. PSP games were made for a low resolution screen.

The texture replacement code has evolved over the years but had some lingering problems, like too much I/O on the main thread. It's now been substantially reorganized and partly rewritten, moving more work to background threads - which reduces stutters caused by loading new replacement textures by quite a bit. Additionally, support for efficient compressed texture formats has been added (KTX2 with Basis and UASTC, DDS with BC1-7), along with built-in mipmap support (#17134, #17092, #12059). Using these can further speed up loading and improve quality while also reducing the memory use.

In connection with this, video memory use when loading large textures to VRAM has been optimized. This mainly helps when using texture replacement packs with very high-resolution textures, but will reduce the risk of running out of memory in general, which is one of the major remaining causes of reported crashes on Android.

Display and post-processing features

Integer scaling can now be enabled. This ensures that the emulated PSP framebuffer is scaled to an even multiple of the rendering resolution. If you then enable "Nearest" filtering, you get nice square pixels, if you're after the retro look.

Additionally, a bug has been fixed where temporary buffers during applications of post filters were the wrong size if we detected oversized framebuffers in games, causing little glitches.

Rendering fixes and features

  • We can now texture-sample from render targets that have been cast to CLUT formats, using a palette that comes from yet another render target. Fixed some special effects: #8390. See the GPU image formats page for more information about the PSP's CLUT functionality and what can be done with it. Additionally, we now support a few additional CLUT texturing modes, which fixes night vision and other effects in the SOCOM games.

  • Xiaomi Poco C40 phones, which are quite widespread in some countries, only expose a software Vulkan device, which is missing some mandatory features. This caused PPSSPP's UI to render incorrectly and slowly, and even worse in-game. I have corrected the Vulkan device detection code to reject this software device - which simply means these phones will fallback to using OpenGL instead, which is reasonably functional on them.

  • Fixed a slowdown in Naruto Heroes: #16733. This is a very typical case of unnecessary readbacks. The PSP has a "block copy" command to copy around arbitrary GPU memory between RAM and VRAM. PPSSPP designates areas in VRAM as framebuffers if they have been previously rendered to, and copies between two framebuffers can be simply converted to a GPU copy on the host. However, if data is copied to "new" VRAM or to RAM, by default we assume that the game will try to read the copied data with the CPU. This means we have to do a very costly readback. Often it actually doesn't need the data on the CPU, though, so we added a per-game compatibility option where we automatically create framebuffers covering the destination area of memory. If the game later simply textures from it, this becomes much, more more efficient than a readback from the GPU. We enabled this for Naruto Heroes.

The curious case of skewed input

It was noticed that Daxter and the two God of War games (all three from the studio Ready At Dawn) both rotate the analog stick input by 15 degrees before passing it to the game's internal control system. This makes the analog stick feel better aligned on the real PSP and likely good for ergonomics, but is not appropriate for an emulator that takes many kinds of different inputs, so automatic pre-rotation in the other direction was added to compensate. Daxter now walks correctly along the cardinal directions as expected, and Kratos does too in the God of War games. See #17020.

Tilt control has been improved

The Android-only tilt (accelerometer) input feature has not been maintained nor tested for a long time, so it was simply time to go through it and fix it up, which is now done. The new behavior works much better and is more intuitive to configure, thanks to an updated configuration dialog.

Regressions fixed

  • Thrillville rendering corrected (#17169)
  • A major performance regression in Dante's Inferno has been fixed (#17032)
  • Mipmaps are now actually used with texture replacement, if provided (#17144)

Other changes

  • Depth readback added, fixing lens flares in Syphon Filter (at a perf cost.. turn off GPU readbacks for the old behavior) (#16907, #16905)
  • Enabling rewind savestates (automatic savestates every N seconds) no longer slow down gameplay noticeably.
  • Software renderer is even more playable, after another round of optimizations and fixes by [Unknown]
  • fp64 has worked on VFPU accuracy. It's not yet all enabled, though.
  • Multiple fixes for various depth clipping issues (#17055, more)
  • VR has gained some new features (top-down perspective), new control options, and various fixes, thanks Lubos!
  • Several large code cleanups and refactors have been performed across the code base, to make future changes easier.
  • The RISC-V JIT compiler has been improved by [Unknown]. Future-proofs the emulator a bit!
  • New app icon (#11996), assorted bugfixes (#16988, #17017, more)
  • And much more!

Go get it!

Go download 1.15 now to benefit from all this!

The lens flare in Burnout

PSP rendering tricks - a new blog post series

In these posts, I'm going to look at some of the more interesting visual effects that games accomplish on the PSP, and how they do it. The PSP's GPU is very limited by modern standards, but it's still capable of quite a lot of interesting things if your really know how to use it.

Burnout Dominator's lens flare effect

First up, one of the trickiest lens flare effects seen on the PSP.

Lens flare effects are easy to do on modern GPUs. There are lots of different approaches, both image-based which can handle light sources of any shape but are generally not very detailed, and sprite-based, which are more limited in terms of the light source, but can look really complex and colorful. There are queries that can be used to figure out how many pixels actually got rendered when drawing the sun sprite, for example, that can be used to control the size and shape of the lens flare on the next frame, or you can read back the Z buffer directly while drawing the sprites.

On old-school, fixed-function hardware such as that of the PSP, where you can’t even do multitexturing, and definitely can’t run any shader code, people had to get quite imaginative to achieve these effects. And the authors of Burnout Dominator certainly were, as we will see.

Let's start by looking at the wrong result - the way it was in PPSSPP before I started investigating the effect:

As you can see, the lens flare effect is visible going into the tunnel, and through various trees and stuff.

There are two main parts to rendering a traditional lens flare correctly:

  • Determining the location, and measuring the sun coverage (how brightly the flare should render should be based on how much of the sun is covered by blocking things).
  • Using the determined coverage value, adjust the brightness of the lens flare. If the source of light is fully covered, no lens flare should be drawn, while if it’s partially covered or not covered at all, the lens flare should be drawn but with a brightness adjusted by the coverage.

Computing the sun coverage

To achieve this, here’s what Burnout Dominator does to measure the sun coverage, every frame:

First, it makes a backup copy of a 14x14 rectangle around the sun location on-screen, and then renders a black and a white rectangle on top, with only the black one being depth tested. The result is a binary mask of where the sun is visible.

It then downsamples (through bilinear filtering) this binary image to 8x8, sitting out in the unused border of the main framebuffer. Then, it downsamples this 8x8 image three more times, until we reach a single value, which is thus the average of the black and white pixels, and thus an effective measurement of the coverage. The final value is for some obscure reason spread out over four pixels.

Picture of downsampling

After that, it restores the little modified square of image the way it was, using the backup copy from before:

Restored image region

Applying the coverage value

So, we now have the coverage as a byte value. We could now treat this value as a 1x1 texture and let it influence the brightness of basic gouraud shaded geometry, like some simple hexagons and stuff, could look OK. Ridge Racer, for example, stops here (though uses a simpler accumulation method) - it draws simple shapes.

But Burnout gets fancier, and uses a nice lens flare texture. We are now faced with the challenge of how to use this arbitrary value sitting in an image, to influence the brightness of the lens flare texture, using only the PSP GPU. We do not want to use the CPU to copy the brightness value to some vertex colors, for example, as that would require expensive synchronization, instead we need to coax the GPU to do the work directly.

If we had multitexturing with combiners, or even shaders, we’d just sample this texel and multiply the lens flare texture by it, but we don’t have that. However, the PSP has some others features we can use - or misuse. Games on the PSP mostly use palletted textures, 4-bit or 8-bit indexed color. Palettes can be loaded from RAM or VRAM. And that opens up for a cute trick: Since on the PSP, memory is just memory, the game can actually overlay a render target on top of the palette memory belonging to the lens flare texture in memory, and render into the alpha channel of this render target, while texturing from a 1x1 texture carefully defined to overlap the brightness value from the previous coverage computation in memory! Then it can finally draw the lens flare using a texture with that modified CLUT loaded, which now has the correct alpha value in all colors, matching the coverage.

A problem with a deep solution

Except… The PSP is actually not able to write arbitrary values into the alpha channel of a 32-bit render target, at all! Not sure exactly why that is, but it is likely related to the fact that on the PSP, the alpha and stencil buffers share bits. So how do we actually accomplish it anyway, given that we just stated that it’s impossible?

This is where we get to the next level of trickery. When the game renders to the CLUT, it doesn’t use 32-bit color, instead it uses 16-bit “565” color, setting the render width to be 512, twice the size of the palette. Now, every second 16-bit pixel can be used to control the A and B channels of a color, and the other ones will control the G and R channels. The mapping is not trivial, let’s try to see that:

The same 32 bits in memory (each letter represents is 1 bit):

AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR (one 32-bit color value)
bbbbbggg gggrrrrr bbbbbggg gggrrrrr (two 16-bit color values)
11111111 00000000 11111111 00000000 (bitmask for writing, see below)

When I said that it textures from the coverage value and writes it to the palette, what it really does is that it textures using another palette with a green-blue gradient to translate the coverage value into the appropriate green and blue bits to properly fill the alpha channel of the 32-bit CLUT entries, by rendering using 16-bit colors! The PSP GPU conveniently has a framebuffer bitmasking feature, where you can prevent writing to specific bits of each color value when rendering (modern GPUs don’t have that, they have a bit per channel instead), and it sets what's effectively a repeating 0xFF00 16-bit mask.

That creates a new problem though, it will now write that value to green as well in the corresponding 32-bit color values, as we can see in the diagram, which we don’t want. The color write bitmask is applied individually to each 16-bit pixel here, so that’s not very useful. So what can we use to mask away the writes to every other pixel? Well we are in fact using a GPU, so why not initialize a Z buffer with 0, 32767, 0, 32767, and use depth testing to discard every second value? And that’s what the game does, drawing to the palette, using a depth value and a depth compare function to make sure only every second 16-bit pixel actually gets written.

The result

And we reach the final moment, where the coverage value sits properly in the alpha channel of each entry of the color palette of the lens flare texture, and we can just do a simple draw to get it on the screen with the appropriate brightness.

Finally, we have:

Subtle working lens flare Bright working lens flare

And a video:

Phew! Getting this to work in PPSSPP was.. not trivial. I could write a whole other article about the improvements that needed to be done to the rendering pipeline so that all of the tricky steps above would actually work correctly.

Welcome to the new site!

Welcome to PPSSPP's new website!

Unlike the old one, this one has a blog. PPSSPP has long been missing a place to put those nice progress reports that the other big emulators release from time to time - also lacking the staff, but there will be content here similar to that!