ANDROID: Chooose the best surface formats offered by the system
This commit is contained in:
parent
24565a5bd8
commit
6aea08860f
7 changed files with 92 additions and 35 deletions
|
@ -67,9 +67,17 @@ void AndroidGraphicsManager::initSurface() {
|
||||||
// Notify the OpenGL code about our context.
|
// Notify the OpenGL code about our context.
|
||||||
setContextType(OpenGL::kContextGLES2);
|
setContextType(OpenGL::kContextGLES2);
|
||||||
|
|
||||||
// We default to RGB565 and RGBA5551 which is closest to the actual output
|
if (JNI::egl_bits_per_pixel == 16) {
|
||||||
// mode we setup.
|
// 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));
|
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);
|
handleResize(JNI::egl_surface_width, JNI::egl_surface_height);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,10 +73,20 @@ AndroidGraphics3dManager::AndroidGraphics3dManager() :
|
||||||
_mouse_hotspot(),
|
_mouse_hotspot(),
|
||||||
_mouse_dont_scale(false),
|
_mouse_dont_scale(false),
|
||||||
_show_mouse(false) {
|
_show_mouse(false) {
|
||||||
_game_texture = new GLESFakePalette565Texture();
|
|
||||||
|
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_texture = new GLES5551Texture();
|
||||||
_overlay_background = new GLES5551Texture();
|
_overlay_background = new GLES565Texture();
|
||||||
_mouse_texture_palette = new GLESFakePalette5551Texture();
|
_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;
|
_mouse_texture = _mouse_texture_palette;
|
||||||
|
|
||||||
initSurface();
|
initSurface();
|
||||||
|
@ -374,6 +384,9 @@ bool AndroidGraphics3dManager::hasFeature(OSystem::Feature f) const {
|
||||||
f == OSystem::kFeatureAspectRatioCorrection) {
|
f == OSystem::kFeatureAspectRatioCorrection) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (f == OSystem::kFeatureOverlaySupportsAlpha) {
|
||||||
|
return _overlay_texture->getPixelFormat().aBits() > 3;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,13 +496,12 @@ void AndroidGraphics3dManager::grabOverlay(Graphics::Surface &surface) const {
|
||||||
|
|
||||||
assert(surface.w >= overlaySurface->w);
|
assert(surface.w >= overlaySurface->w);
|
||||||
assert(surface.h >= overlaySurface->h);
|
assert(surface.h >= overlaySurface->h);
|
||||||
assert(surface.format.bytesPerPixel == sizeof(uint16));
|
assert(surface.format.bytesPerPixel == overlaySurface->format.bytesPerPixel);
|
||||||
assert(overlaySurface->format.bytesPerPixel == sizeof(uint16));
|
|
||||||
|
|
||||||
const byte *src = (const byte *)overlaySurface->getPixels();
|
const byte *src = (const byte *)overlaySurface->getPixels();
|
||||||
byte *dst = (byte *)surface.getPixels();
|
byte *dst = (byte *)surface.getPixels();
|
||||||
Graphics::copyBlit(dst, src, surface.pitch, overlaySurface->pitch,
|
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,
|
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");
|
LOGD("switching to rgb mouse cursor");
|
||||||
|
|
||||||
assert(!_mouse_texture_rgb);
|
assert(!_mouse_texture_rgb);
|
||||||
|
if (JNI::egl_bits_per_pixel == 16) {
|
||||||
_mouse_texture_rgb = new GLES5551Texture();
|
_mouse_texture_rgb = new GLES5551Texture();
|
||||||
|
} else {
|
||||||
|
_mouse_texture_rgb = new GLES8888Texture();
|
||||||
|
}
|
||||||
_mouse_texture_rgb->setLinearFilter(_graphicsMode == 1);
|
_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);
|
_mouse_texture->updateBuffer(0, 0, w, h, buf, w);
|
||||||
} else {
|
} else {
|
||||||
uint16 pitch = _mouse_texture->pitch();
|
uint16 pitch = _mouse_texture->pitch();
|
||||||
|
uint16 bpp = _mouse_texture->getPixelFormat().bytesPerPixel;
|
||||||
|
|
||||||
byte *tmp = new byte[pitch * h];
|
byte *tmp = new byte[pitch * h];
|
||||||
|
|
||||||
|
@ -709,19 +726,19 @@ void AndroidGraphics3dManager::setMouseCursor(const void *buf, uint w, uint h,
|
||||||
|
|
||||||
if (format->bytesPerPixel == 2) {
|
if (format->bytesPerPixel == 2) {
|
||||||
const uint16 *s = (const uint16 *)buf;
|
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 y = 0; y < h; ++y, d += pitch / 2 - w)
|
||||||
for (uint16 x = 0; x < w; ++x, d++)
|
for (uint16 x = 0; x < w; ++x, d++)
|
||||||
if (*s++ == (keycolor & 0xffff)) {
|
if (*s++ == (keycolor & 0xffff)) {
|
||||||
*d = 0;
|
memset(d, 0, bpp);
|
||||||
}
|
}
|
||||||
} else if (format->bytesPerPixel == 4) {
|
} else if (format->bytesPerPixel == 4) {
|
||||||
const uint32 *s = (const uint32 *)buf;
|
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 y = 0; y < h; ++y, d += pitch / 2 - w)
|
||||||
for (uint16 x = 0; x < w; ++x, d++)
|
for (uint16 x = 0; x < w; ++x, d++)
|
||||||
if (*s++ == (keycolor & 0xffff)) {
|
if (*s++ == (keycolor & 0xffffffff)) {
|
||||||
*d = 0;
|
memset(d, 0, bpp);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error("AndroidGraphics3dManager::setMouseCursor: invalid bytesPerPixel %d", format->bytesPerPixel);
|
error("AndroidGraphics3dManager::setMouseCursor: invalid bytesPerPixel %d", format->bytesPerPixel);
|
||||||
|
|
|
@ -150,7 +150,7 @@ private:
|
||||||
bool _force_redraw;
|
bool _force_redraw;
|
||||||
|
|
||||||
// Game layer
|
// Game layer
|
||||||
GLESBaseTexture *_game_texture;
|
GLESTexture *_game_texture;
|
||||||
OpenGL::FrameBuffer *_frame_buffer;
|
OpenGL::FrameBuffer *_frame_buffer;
|
||||||
|
|
||||||
#ifdef USE_RGB_COLOR
|
#ifdef USE_RGB_COLOR
|
||||||
|
@ -164,14 +164,14 @@ private:
|
||||||
int _cursorX, _cursorY;
|
int _cursorX, _cursorY;
|
||||||
|
|
||||||
// Overlay layer
|
// Overlay layer
|
||||||
GLES5551Texture *_overlay_background;
|
GLESTexture *_overlay_background;
|
||||||
GLES5551Texture *_overlay_texture;
|
GLESTexture *_overlay_texture;
|
||||||
bool _show_overlay;
|
bool _show_overlay;
|
||||||
|
|
||||||
// Mouse layer
|
// Mouse layer
|
||||||
GLESBaseTexture *_mouse_texture;
|
GLESBaseTexture *_mouse_texture;
|
||||||
GLESBaseTexture *_mouse_texture_palette;
|
GLESFakePaletteTexture *_mouse_texture_palette;
|
||||||
GLES5551Texture *_mouse_texture_rgb;
|
GLESTexture *_mouse_texture_rgb;
|
||||||
Common::Point _mouse_hotspot;
|
Common::Point _mouse_hotspot;
|
||||||
Common::Point _mouse_hotspot_scaled;
|
Common::Point _mouse_hotspot_scaled;
|
||||||
int _mouse_width_scaled, _mouse_height_scaled;
|
int _mouse_width_scaled, _mouse_height_scaled;
|
||||||
|
|
|
@ -72,6 +72,7 @@ sem_t JNI::pause_sem = { 0 };
|
||||||
int JNI::surface_changeid = 0;
|
int JNI::surface_changeid = 0;
|
||||||
int JNI::egl_surface_width = 0;
|
int JNI::egl_surface_width = 0;
|
||||||
int JNI::egl_surface_height = 0;
|
int JNI::egl_surface_height = 0;
|
||||||
|
int JNI::egl_bits_per_pixel = 0;
|
||||||
bool JNI::_ready_for_events = 0;
|
bool JNI::_ready_for_events = 0;
|
||||||
|
|
||||||
jmethodID JNI::_MID_getDPI = 0;
|
jmethodID JNI::_MID_getDPI = 0;
|
||||||
|
@ -113,7 +114,7 @@ const JNINativeMethod JNI::_natives[] = {
|
||||||
(void *)JNI::create },
|
(void *)JNI::create },
|
||||||
{ "destroy", "()V",
|
{ "destroy", "()V",
|
||||||
(void *)JNI::destroy },
|
(void *)JNI::destroy },
|
||||||
{ "setSurface", "(II)V",
|
{ "setSurface", "(III)V",
|
||||||
(void *)JNI::setSurface },
|
(void *)JNI::setSurface },
|
||||||
{ "main", "([Ljava/lang/String;)I",
|
{ "main", "([Ljava/lang/String;)I",
|
||||||
(void *)JNI::main },
|
(void *)JNI::main },
|
||||||
|
@ -647,9 +648,10 @@ void JNI::destroy(JNIEnv *env, jobject self) {
|
||||||
JNI::getEnv()->DeleteGlobalRef(_jobj);
|
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_width = width;
|
||||||
egl_surface_height = height;
|
egl_surface_height = height;
|
||||||
|
egl_bits_per_pixel = bpp;
|
||||||
surface_changeid++;
|
surface_changeid++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ public:
|
||||||
static int surface_changeid;
|
static int surface_changeid;
|
||||||
static int egl_surface_width;
|
static int egl_surface_width;
|
||||||
static int egl_surface_height;
|
static int egl_surface_height;
|
||||||
|
static int egl_bits_per_pixel;
|
||||||
|
|
||||||
static jint onLoad(JavaVM *vm);
|
static jint onLoad(JavaVM *vm);
|
||||||
|
|
||||||
|
@ -146,7 +147,7 @@ private:
|
||||||
jint audio_buffer_size);
|
jint audio_buffer_size);
|
||||||
static void destroy(JNIEnv *env, jobject self);
|
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 jint main(JNIEnv *env, jobject self, jobjectArray args);
|
||||||
|
|
||||||
static void pushEvent(JNIEnv *env, jobject self, int type, int arg1,
|
static void pushEvent(JNIEnv *env, jobject self, int type, int arg1,
|
||||||
|
|
|
@ -2,6 +2,7 @@ package org.scummvm.scummvm;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import android.content.res.AssetManager;
|
import android.content.res.AssetManager;
|
||||||
|
import android.graphics.PixelFormat;
|
||||||
import android.media.AudioAttributes;
|
import android.media.AudioAttributes;
|
||||||
import android.media.AudioFormat;
|
import android.media.AudioFormat;
|
||||||
import android.media.AudioManager;
|
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 EGLSurface _egl_surface = EGL10.EGL_NO_SURFACE;
|
||||||
|
|
||||||
private SurfaceHolder _surface_holder;
|
private SurfaceHolder _surface_holder;
|
||||||
|
private int bitsPerPixel;
|
||||||
private AudioTrack _audio_track;
|
private AudioTrack _audio_track;
|
||||||
private int _sample_rate = 0;
|
private int _sample_rate = 0;
|
||||||
private int _buffer_size = 0;
|
private int _buffer_size = 0;
|
||||||
|
@ -46,7 +48,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
|
||||||
int sample_rate,
|
int sample_rate,
|
||||||
int buffer_size);
|
int buffer_size);
|
||||||
private native void destroy();
|
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);
|
private native int main(String[] args);
|
||||||
|
|
||||||
// pause the engine and all native threads
|
// pause the engine and all native threads
|
||||||
|
@ -109,13 +111,17 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.d(LOG_TAG, String.format(Locale.ROOT, "surfaceChanged: %dx%d (%d)",
|
PixelFormat pixelFormat = new PixelFormat();
|
||||||
width, height, format));
|
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
|
// store values for the native code
|
||||||
// make sure to do it before notifying the lock
|
// make sure to do it before notifying the lock
|
||||||
// as it leads to a race condition otherwise
|
// as it leads to a race condition otherwise
|
||||||
setSurface(width, height);
|
setSurface(width, height, bitsPerPixel);
|
||||||
|
|
||||||
synchronized(_sem_surface) {
|
synchronized(_sem_surface) {
|
||||||
_surface_holder = holder;
|
_surface_holder = holder;
|
||||||
|
@ -133,7 +139,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear values for the native code
|
// clear values for the native code
|
||||||
setSurface(0, 0);
|
setSurface(0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
final public void setArgs(String[] args) {
|
final public void setArgs(String[] args) {
|
||||||
|
@ -142,14 +148,14 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
|
||||||
|
|
||||||
final public void run() {
|
final public void run() {
|
||||||
try {
|
try {
|
||||||
initAudio();
|
|
||||||
initEGL();
|
|
||||||
|
|
||||||
// wait for the surfaceChanged callback
|
// wait for the surfaceChanged callback
|
||||||
synchronized(_sem_surface) {
|
synchronized(_sem_surface) {
|
||||||
while (_surface_holder == null)
|
while (_surface_holder == null)
|
||||||
_sem_surface.wait();
|
_sem_surface.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initAudio();
|
||||||
|
initEGL();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
deinitEGL();
|
deinitEGL();
|
||||||
deinitAudio();
|
deinitAudio();
|
||||||
|
@ -477,15 +483,24 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
|
||||||
|
|
||||||
for (EGLConfig config : configs) {
|
for (EGLConfig config : configs) {
|
||||||
if (config != null) {
|
if (config != null) {
|
||||||
|
boolean good = true;
|
||||||
|
|
||||||
EglAttribs attr = new EglAttribs(config);
|
EglAttribs attr = new EglAttribs(config);
|
||||||
|
|
||||||
// must have
|
// must have
|
||||||
if ((attr.get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_WINDOW_BIT) == 0)
|
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();
|
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) {
|
if (score > bestScore) {
|
||||||
res = config;
|
res = config;
|
||||||
|
|
|
@ -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
|
// 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
|
// 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
|
@Override
|
||||||
public void handle(int exitResult) {
|
public void handle(int exitResult) {
|
||||||
Log.d(ScummVM.LOG_TAG, "Via callback: ScummVM native terminated with code: " + 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();
|
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)
|
// Auxiliary function to overwrite a file (used for overwriting the scummvm.ini file with an existing other one)
|
||||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||||
private static void copyFileUsingStream(File source, File dest) throws IOException {
|
private static void copyFileUsingStream(File source, File dest) throws IOException {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue