ANDROID: Chooose the best surface formats offered by the system

This commit is contained in:
Le Philousophe 2021-12-14 20:32:31 +01:00 committed by Paweł Kołodziejski
parent 24565a5bd8
commit 6aea08860f
7 changed files with 92 additions and 35 deletions

View File

@ -67,9 +67,17 @@ void AndroidGraphicsManager::initSurface() {
// Notify the OpenGL code about our context.
setContextType(OpenGL::kContextGLES2);
// We default to RGB565 and RGBA5551 which is closest to the actual output
// mode we setup.
notifyContextCreate(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0));
if (JNI::egl_bits_per_pixel == 16) {
// We default to RGB565 and RGBA5551 which is closest to what we setup in Java side
notifyContextCreate(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0));
} else {
// If not 16, this must be 24 or 32 bpp so make use of them
#ifdef SCUMM_BIG_ENDIAN
notifyContextCreate(Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0), Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
#else
notifyContextCreate(Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0), Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
#endif
}
handleResize(JNI::egl_surface_width, JNI::egl_surface_height);
}

View File

@ -73,10 +73,20 @@ AndroidGraphics3dManager::AndroidGraphics3dManager() :
_mouse_hotspot(),
_mouse_dont_scale(false),
_show_mouse(false) {
_game_texture = new GLESFakePalette565Texture();
_overlay_texture = new GLES5551Texture();
_overlay_background = new GLES5551Texture();
_mouse_texture_palette = new GLESFakePalette5551Texture();
if (JNI::egl_bits_per_pixel == 16) {
// We default to RGB565 and RGBA5551 which is closest to what we setup in Java side
_game_texture = new GLES565Texture();
_overlay_texture = new GLES5551Texture();
_overlay_background = new GLES565Texture();
_mouse_texture_palette = new GLESFakePalette5551Texture();
} else {
// If not 16, this must be 24 or 32 bpp so make use of them
_game_texture = new GLES888Texture();
_overlay_texture = new GLES8888Texture();
_overlay_background = new GLES888Texture();
_mouse_texture_palette = new GLESFakePalette8888Texture();
}
_mouse_texture = _mouse_texture_palette;
initSurface();
@ -374,6 +384,9 @@ bool AndroidGraphics3dManager::hasFeature(OSystem::Feature f) const {
f == OSystem::kFeatureAspectRatioCorrection) {
return true;
}
if (f == OSystem::kFeatureOverlaySupportsAlpha) {
return _overlay_texture->getPixelFormat().aBits() > 3;
}
return false;
}
@ -483,13 +496,12 @@ void AndroidGraphics3dManager::grabOverlay(Graphics::Surface &surface) const {
assert(surface.w >= overlaySurface->w);
assert(surface.h >= overlaySurface->h);
assert(surface.format.bytesPerPixel == sizeof(uint16));
assert(overlaySurface->format.bytesPerPixel == sizeof(uint16));
assert(surface.format.bytesPerPixel == overlaySurface->format.bytesPerPixel);
const byte *src = (const byte *)overlaySurface->getPixels();
byte *dst = (byte *)surface.getPixels();
Graphics::copyBlit(dst, src, surface.pitch, overlaySurface->pitch,
overlaySurface->w, overlaySurface->h, sizeof(uint16));
overlaySurface->w, overlaySurface->h, overlaySurface->format.bytesPerPixel);
}
void AndroidGraphics3dManager::copyRectToOverlay(const void *buf, int pitch,
@ -659,7 +671,11 @@ void AndroidGraphics3dManager::setMouseCursor(const void *buf, uint w, uint h,
LOGD("switching to rgb mouse cursor");
assert(!_mouse_texture_rgb);
_mouse_texture_rgb = new GLES5551Texture();
if (JNI::egl_bits_per_pixel == 16) {
_mouse_texture_rgb = new GLES5551Texture();
} else {
_mouse_texture_rgb = new GLES8888Texture();
}
_mouse_texture_rgb->setLinearFilter(_graphicsMode == 1);
}
@ -691,6 +707,7 @@ void AndroidGraphics3dManager::setMouseCursor(const void *buf, uint w, uint h,
_mouse_texture->updateBuffer(0, 0, w, h, buf, w);
} else {
uint16 pitch = _mouse_texture->pitch();
uint16 bpp = _mouse_texture->getPixelFormat().bytesPerPixel;
byte *tmp = new byte[pitch * h];
@ -709,19 +726,19 @@ void AndroidGraphics3dManager::setMouseCursor(const void *buf, uint w, uint h,
if (format->bytesPerPixel == 2) {
const uint16 *s = (const uint16 *)buf;
uint16 *d = (uint16 *)tmp;
byte *d = tmp;
for (uint16 y = 0; y < h; ++y, d += pitch / 2 - w)
for (uint16 x = 0; x < w; ++x, d++)
if (*s++ == (keycolor & 0xffff)) {
*d = 0;
memset(d, 0, bpp);
}
} else if (format->bytesPerPixel == 4) {
const uint32 *s = (const uint32 *)buf;
uint16 *d = (uint16 *)tmp;
byte *d = tmp;
for (uint16 y = 0; y < h; ++y, d += pitch / 2 - w)
for (uint16 x = 0; x < w; ++x, d++)
if (*s++ == (keycolor & 0xffff)) {
*d = 0;
if (*s++ == (keycolor & 0xffffffff)) {
memset(d, 0, bpp);
}
} else {
error("AndroidGraphics3dManager::setMouseCursor: invalid bytesPerPixel %d", format->bytesPerPixel);

View File

@ -150,7 +150,7 @@ private:
bool _force_redraw;
// Game layer
GLESBaseTexture *_game_texture;
GLESTexture *_game_texture;
OpenGL::FrameBuffer *_frame_buffer;
#ifdef USE_RGB_COLOR
@ -164,14 +164,14 @@ private:
int _cursorX, _cursorY;
// Overlay layer
GLES5551Texture *_overlay_background;
GLES5551Texture *_overlay_texture;
GLESTexture *_overlay_background;
GLESTexture *_overlay_texture;
bool _show_overlay;
// Mouse layer
GLESBaseTexture *_mouse_texture;
GLESBaseTexture *_mouse_texture_palette;
GLES5551Texture *_mouse_texture_rgb;
GLESFakePaletteTexture *_mouse_texture_palette;
GLESTexture *_mouse_texture_rgb;
Common::Point _mouse_hotspot;
Common::Point _mouse_hotspot_scaled;
int _mouse_width_scaled, _mouse_height_scaled;

View File

@ -72,6 +72,7 @@ sem_t JNI::pause_sem = { 0 };
int JNI::surface_changeid = 0;
int JNI::egl_surface_width = 0;
int JNI::egl_surface_height = 0;
int JNI::egl_bits_per_pixel = 0;
bool JNI::_ready_for_events = 0;
jmethodID JNI::_MID_getDPI = 0;
@ -113,7 +114,7 @@ const JNINativeMethod JNI::_natives[] = {
(void *)JNI::create },
{ "destroy", "()V",
(void *)JNI::destroy },
{ "setSurface", "(II)V",
{ "setSurface", "(III)V",
(void *)JNI::setSurface },
{ "main", "([Ljava/lang/String;)I",
(void *)JNI::main },
@ -647,9 +648,10 @@ void JNI::destroy(JNIEnv *env, jobject self) {
JNI::getEnv()->DeleteGlobalRef(_jobj);
}
void JNI::setSurface(JNIEnv *env, jobject self, jint width, jint height) {
void JNI::setSurface(JNIEnv *env, jobject self, jint width, jint height, jint bpp) {
egl_surface_width = width;
egl_surface_height = height;
egl_bits_per_pixel = bpp;
surface_changeid++;
}

View File

@ -48,6 +48,7 @@ public:
static int surface_changeid;
static int egl_surface_width;
static int egl_surface_height;
static int egl_bits_per_pixel;
static jint onLoad(JavaVM *vm);
@ -146,7 +147,7 @@ private:
jint audio_buffer_size);
static void destroy(JNIEnv *env, jobject self);
static void setSurface(JNIEnv *env, jobject self, jint width, jint height);
static void setSurface(JNIEnv *env, jobject self, jint width, jint height, jint bpp);
static jint main(JNIEnv *env, jobject self, jobjectArray args);
static void pushEvent(JNIEnv *env, jobject self, int type, int arg1,

View File

@ -2,6 +2,7 @@ package org.scummvm.scummvm;
import androidx.annotation.NonNull;
import android.content.res.AssetManager;
import android.graphics.PixelFormat;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
@ -33,6 +34,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
private EGLSurface _egl_surface = EGL10.EGL_NO_SURFACE;
private SurfaceHolder _surface_holder;
private int bitsPerPixel;
private AudioTrack _audio_track;
private int _sample_rate = 0;
private int _buffer_size = 0;
@ -46,7 +48,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
int sample_rate,
int buffer_size);
private native void destroy();
private native void setSurface(int width, int height);
private native void setSurface(int width, int height, int bpp);
private native int main(String[] args);
// pause the engine and all native threads
@ -109,13 +111,17 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
return;
}
Log.d(LOG_TAG, String.format(Locale.ROOT, "surfaceChanged: %dx%d (%d)",
width, height, format));
PixelFormat pixelFormat = new PixelFormat();
PixelFormat.getPixelFormatInfo(format, pixelFormat);
bitsPerPixel = pixelFormat.bitsPerPixel;
Log.d(LOG_TAG, String.format(Locale.ROOT, "surfaceChanged: %dx%d (%d: %dbpp)",
width, height, format, bitsPerPixel));
// store values for the native code
// make sure to do it before notifying the lock
// as it leads to a race condition otherwise
setSurface(width, height);
setSurface(width, height, bitsPerPixel);
synchronized(_sem_surface) {
_surface_holder = holder;
@ -133,7 +139,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
}
// clear values for the native code
setSurface(0, 0);
setSurface(0, 0, 0);
}
final public void setArgs(String[] args) {
@ -142,14 +148,14 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
final public void run() {
try {
initAudio();
initEGL();
// wait for the surfaceChanged callback
synchronized(_sem_surface) {
while (_surface_holder == null)
_sem_surface.wait();
}
initAudio();
initEGL();
} catch (Exception e) {
deinitEGL();
deinitAudio();
@ -477,15 +483,24 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
for (EGLConfig config : configs) {
if (config != null) {
boolean good = true;
EglAttribs attr = new EglAttribs(config);
// must have
if ((attr.get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_WINDOW_BIT) == 0)
continue;
good = false;
if (attr.get(EGL10.EGL_BUFFER_SIZE) < bitsPerPixel)
good = false;
int score = attr.weight();
Log.d(LOG_TAG, String.format(Locale.ROOT, "%s (%d)", attr.toString(), score));
Log.d(LOG_TAG, String.format(Locale.ROOT, "%s (%d, %s)", attr.toString(), score, good ? "OK" : "NOK"));
if (!good) {
continue;
}
if (score > bestScore) {
res = config;

View File

@ -1007,7 +1007,14 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
// so app's internal space (which would be deleted on uninstall) was set as WORLD_READABLE which is no longer supported in newer versions of Android API
// In newer APIs we can set that path as Context.MODE_PRIVATE which is the default - but this makes the files inaccessible to other apps
_scummvm = new MyScummVM(_main_surface.getHolder(), new MyScummVMDestroyedCallback() {
SurfaceHolder main_surface_holder = _main_surface.getHolder();
// By default Android selects RGB_565 for backward compatibility, use the best one by querying the display
// It's deprecated on API level >= 17 and will always return RGBA_8888
// but on older versions it could return RGB_565 which could be more efficient for the GPU
main_surface_holder.setFormat(getDisplayPixelFormat());
_scummvm = new MyScummVM(main_surface_holder, new MyScummVMDestroyedCallback() {
@Override
public void handle(int exitResult) {
Log.d(ScummVM.LOG_TAG, "Via callback: ScummVM native terminated with code: " + exitResult);
@ -1385,6 +1392,13 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
hideSystemUI();
}
@SuppressWarnings("deprecation")
private int getDisplayPixelFormat() {
// Since API level 17 this always returns PixelFormat.RGBA_8888
// so if we target more recent API levels, we could remove this function
return getWindowManager().getDefaultDisplay().getPixelFormat();
}
// Auxiliary function to overwrite a file (used for overwriting the scummvm.ini file with an existing other one)
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private static void copyFileUsingStream(File source, File dest) throws IOException {