Call glTexSubImage2D in native code for ImageTexture.Tile

This commit is contained in:
seven332 committed 2016-03-05 16:34:59 +08:00
1 parent e80df262a3
commit 92fc062ca0
17 files changed
+268 -99

No files matched your search

@@ -33,7 +33,7 @@ public class ImageWrapper implements Animatable, Runnable {
private static final String TAG = ImageWrapper.class.getSimpleName();
private Image mImage;
private final Image mImage;
private boolean mRunning = false;
@@ -51,9 +51,9 @@ public class ImageWrapper implements Animatable, Runnable {
return mImage.getHeight();
}
public boolean render(int srcX, int srcY, Bitmap dst, int dstX, int dstY,
public void render(int srcX, int srcY, Bitmap dst, int dstX, int dstY,
int width, int height, boolean fillBlank, int defaultColor) {
return mImage.render(srcX, srcY, dst, dstX, dstY,
mImage.render(srcX, srcY, dst, dstX, dstY,
width, height, fillBlank, defaultColor);
}
@@ -16,8 +16,6 @@
package com.hippo.gl.glrenderer;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.RectF;
import android.graphics.drawable.Animatable;
import android.os.SystemClock;
@@ -61,8 +59,6 @@ public class ImageTexture implements Texture, Animatable {
// In this 16ms, we use about 4~8 ms to upload tiles.
private static final long UPLOAD_TILE_LIMIT = 4; // ms
private static final Bitmap sSmallUploadBitmap;
private static final Bitmap sLargeUploadBitmap;
private static final PriorityThreadFactory sThreadFactory;
private static final PVLock sPVLock;
@@ -90,8 +86,6 @@ public class ImageTexture implements Texture, Animatable {
private WeakReference<Callback> mCallback;
static {
sSmallUploadBitmap = Bitmap.createBitmap(SMALL_TILE_SIZE, SMALL_TILE_SIZE, Bitmap.Config.ARGB_8888);
sLargeUploadBitmap = Bitmap.createBitmap(LARGE_TILE_SIZE, LARGE_TILE_SIZE, Bitmap.Config.ARGB_8888);
sThreadFactory = new PriorityThreadFactory("ImageTexture$AnimateTask", android.os.Process.THREAD_PRIORITY_BACKGROUND);
sPVLock = new PVLock(3);
}
@@ -142,7 +136,7 @@ public class ImageTexture implements Texture, Animatable {
}
}
private static class Tile extends UploadedTexture {
private static class Tile extends NativeTexture {
@TileType
private int mTileType;
@@ -153,76 +147,38 @@ public class ImageTexture implements Texture, Animatable {
public int contentWidth;
public int contentHeight;
public int borderSize;
public int tileSize;
public Bitmap uploadBitmap;
public void setSize(@TileType int tileType, int width, int height) {
mTileType = tileType;
int tileSize;
if (tileType == TILE_SMALL) {
borderSize = SMALL_BORDER_SIZE;
tileSize = SMALL_TILE_SIZE;
uploadBitmap = sSmallUploadBitmap;
} else if (tileType == TILE_LARGE) {
borderSize = LARGE_BORDER_SIZE;
tileSize = LARGE_TILE_SIZE;
uploadBitmap = sLargeUploadBitmap;
} else {
throw new IllegalStateException("Not support tile type: " + tileType);
}
contentWidth = width;
contentHeight = height;
mWidth = width + 2 * borderSize;
mHeight = height + 2 * borderSize;
mTextureWidth = tileSize;
mTextureHeight = tileSize;
}
@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
@Override
protected Bitmap onGetBitmap() {
final Image image = this.image;
if (image != null) {
int srcX;
int dstX;
if (offsetX - borderSize < 0) {
srcX = 0;
dstX = borderSize - offsetX;
} else {
srcX = offsetX - borderSize;
dstX = 0;
}
int srcY;
int dstY;
if (offsetY - borderSize < 0) {
srcY = 0;
dstY = borderSize - offsetY;
} else {
srcY = offsetY - borderSize;
dstY = 0;
}
image.render(srcX, srcY, uploadBitmap, dstX, dstY,
Math.min(image.getWidth() - srcX, tileSize - dstX),
Math.min(image.getHeight() - srcY, tileSize - dstY),
true, Color.TRANSPARENT);
protected void texImage(boolean init) {
if (image != null && !image.isRecycled()) {
image.texImage(init, mTileType, offsetX, offsetY);
}
return uploadBitmap;
}
@Override
protected void onFreeBitmap(Bitmap bitmap) {
// Nothing
}
@Override
public boolean isOpaque() {
return false;
}
private void invalidate() {
invalidateContent();
image = null;
uploadBitmap = null;
}
public void free() {
@@ -584,11 +540,7 @@ public class ImageTexture implements Texture, Animatable {
if (mFrameDirty.getAndSet(false)) {
// invalid tiles
for (Tile tile : mTiles) {
int width = tile.mWidth;
int height = tile.mHeight;
tile.invalidateContent();
tile.mWidth = width;
tile.mHeight = height;
}
}
}
@@ -0,0 +1,101 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.gl.glrenderer;
import android.opengl.GLES20;
import android.util.Log;
import javax.microedition.khronos.opengles.GL11;
public abstract class NativeTexture extends BasicTexture {
private static final String TAG = NativeTexture.class.getSimpleName();
private boolean mContentValid = true;
private boolean mOpaque = true;
public void invalidateContent() {
mContentValid = false;
}
public static void checkError() {
int error = GLES20.glGetError();
if (error != 0) {
Throwable t = new Throwable();
Log.e(TAG, "GL error: " + error, t);
}
}
protected abstract void texImage(boolean init);
private void uploadToCanvas(GLCanvas canvas) {
// Get id
mId = canvas.getGLId().generateTexture();
// Prepare
canvas.setTextureParameters(this);
// Call glTexImage2D
GLES20.glBindTexture(getTarget(), mId);
checkError();
texImage(true);
setAssociatedCanvas(canvas);
mState = STATE_LOADED;
mContentValid = true;
}
public void updateContent(GLCanvas canvas) {
if (!isLoaded()) {
uploadToCanvas(canvas);
} else if (!mContentValid) {
// Call glTexSubImage2D
GLES20.glBindTexture(getTarget(), mId);
checkError();
texImage(false);
mContentValid = true;
}
}
/**
* Whether the content on GPU is valid.
*/
public boolean isContentValid() {
return isLoaded() && mContentValid;
}
@Override
protected boolean onBind(GLCanvas canvas) {
updateContent(canvas);
return isContentValid();
}
@Override
protected int getTarget() {
return GL11.GL_TEXTURE_2D;
}
public void setOpaque(boolean isOpaque) {
mOpaque = isOpaque;
}
@Override
public boolean isOpaque() {
return mOpaque;
}
}
+11 -3
View File
@@ -66,13 +66,18 @@ public class Image {
return nativeIsCompleted(mNativePtr, mFormat);
}
public boolean render(int srcX, int srcY, Bitmap dst, int dstX, int dstY,
public void render(int srcX, int srcY, Bitmap dst, int dstX, int dstY,
int width, int height, boolean fillBlank, int defaultColor) {
checkRecycled();
return nativeRender(mNativePtr, mFormat, srcX, srcY, dst, dstX, dstY,
nativeRender(mNativePtr, mFormat, srcX, srcY, dst, dstX, dstY,
width, height, fillBlank, defaultColor);
}
public void texImage(boolean init, int tileType, int offsetX, int offsetY) {
checkRecycled();
nativeTexImage(mNativePtr, mFormat, init, tileType, offsetX, offsetY);
}
public void advance() {
checkRecycled();
nativeAdvance(mNativePtr, mFormat);
@@ -118,10 +123,13 @@ public class Image {
private static native boolean nativeIsCompleted(long nativePtr, int format);
private static native boolean nativeRender(long nativePtr, int format,
private static native void nativeRender(long nativePtr, int format,
int srcX, int srcY, Bitmap dst, int dstX, int dstY,
int width, int height, boolean fillBlank, int defaultColor);
private static native void nativeTexImage(long nativePtr, int format,
boolean init, int tileType, int offsetX, int offsetY);
private static native void nativeAdvance(long nativePtr, int format);
private static native int nativeGetDelay(long nativePtr, int format);
+1 -1
View File
@@ -25,7 +25,7 @@ image_png.c \
image_gif.c \
image_utils.c \
java_wrapper.c
LOCAL_LDLIBS := -llog -ljnigraphics
LOCAL_LDLIBS := -llog -ljnigraphics -lGLESv2
LOCAL_STATIC_LIBRARIES := jpeg-turbo png gif stream
include $(BUILD_SHARED_LIBRARY)
+8 -5
View File
@@ -195,32 +195,35 @@ int get_height(void* image, int format)
}
}
bool render(void* image, int format, int src_x, int src_y,
void render(void* image, int format, int src_x, int src_y,
void* dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color)
{
switch (format) {
#ifdef IMAGE_SUPPORT_JPEG
case IMAGE_FORMAT_JPEG:
return JPEG_render((JPEG*) image, src_x, src_y,
JPEG_render((JPEG*) image, src_x, src_y,
dst, dst_w, dst_h, dst_x, dst_y,
width, height, fill_blank, default_color);
break;
#endif
#ifdef IMAGE_SUPPORT_PNG
case IMAGE_FORMAT_PNG:
return PNG_render((PNG*) image, src_x, src_y,
PNG_render((PNG*) image, src_x, src_y,
dst, dst_w, dst_h, dst_x, dst_y,
width, height, fill_blank, default_color);
break;
#endif
#ifdef IMAGE_SUPPORT_GIF
case IMAGE_FORMAT_GIF:
return GIF_render((GIF*) image, src_x, src_y,
GIF_render((GIF*) image, src_x, src_y,
dst, dst_w, dst_h, dst_x, dst_y,
width, height, fill_blank, default_color);
break;
#endif
default:
LOGE(EMSG("Can't detect format %d"), format);
return false;
break;
}
}
+1 -1
View File
@@ -42,7 +42,7 @@ bool complete(void* image, int format);
bool is_completed(void* image, int format);
int get_width(void* image, int format);
int get_height(void* image, int format);
bool render(void* image, int format, int src_x, int src_y,
void render(void* image, int format, int src_x, int src_y,
void* dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color);
void advance(void* image, int format);
+2 -2
View File
@@ -289,11 +289,11 @@ int GIF_get_height(GIF* gif)
return gif->gif_file->SHeight;
}
bool GIF_render(GIF* gif, int src_x, int src_y,
void GIF_render(GIF* gif, int src_x, int src_y,
void* dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color)
{
return copy_pixels(gif->buffer, gif->gif_file->SWidth, gif->gif_file->SHeight, src_x, src_y,
copy_pixels(gif->buffer, gif->gif_file->SWidth, gif->gif_file->SHeight, src_x, src_y,
dst, dst_w, dst_h, dst_x, dst_y,
width, height, fill_blank, default_color);
}
+1 -1
View File
@@ -61,7 +61,7 @@ bool GIF_complete(GIF* gif);
bool GIF_is_completed(GIF* gif);
int GIF_get_width(GIF* gif);
int GIF_get_height(GIF* gif);
bool GIF_render(GIF* gif, int src_x, int src_y,
void GIF_render(GIF* gif, int src_x, int src_y,
void* dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color);
void GIF_advance(GIF* gif);
+2 -2
View File
@@ -153,11 +153,11 @@ int JPEG_get_height(JPEG* jpeg)
return jpeg->height;
}
bool JPEG_render(JPEG* jpeg, int src_x, int src_y,
void JPEG_render(JPEG* jpeg, int src_x, int src_y,
void* dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color)
{
return copy_pixels(jpeg->buffer, jpeg->width, jpeg->height, src_x, src_y,
copy_pixels(jpeg->buffer, jpeg->width, jpeg->height, src_x, src_y,
dst, dst_w, dst_h, dst_x, dst_y,
width, height, fill_blank, default_color);
}
+1 -1
View File
@@ -43,7 +43,7 @@ bool JPEG_complete(JPEG* jpeg);
bool JPEG_is_completed(JPEG* jpeg);
int JPEG_get_width(JPEG* jpeg);
int JPEG_get_height(JPEG* jpeg);
bool JPEG_render(JPEG* jpeg, int src_x, int src_y,
void JPEG_render(JPEG* jpeg, int src_x, int src_y,
void* dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color);
void JPEG_advance(JPEG* jpeg);
+2 -2
View File
@@ -410,11 +410,11 @@ int PNG_get_height(PNG* png)
return png->height;
}
bool PNG_render(PNG* png, int src_x, int src_y,
void PNG_render(PNG* png, int src_x, int src_y,
void* dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color)
{
return copy_pixels(png->buffer, png->width, png->height, src_x, src_y,
copy_pixels(png->buffer, png->width, png->height, src_x, src_y,
dst, dst_w, dst_h, dst_x, dst_y,
width, height, fill_blank, default_color);
}
+1 -1
View File
@@ -71,7 +71,7 @@ bool PNG_complete(PNG* png);
bool PNG_is_completed(PNG* png);
int PNG_get_width(PNG* png);
int PNG_get_height(PNG* png);
bool PNG_render(PNG* png, int src_x, int src_y,
void PNG_render(PNG* png, int src_x, int src_y,
void* dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color);
void PNG_advance(PNG* png);
+64 -16
View File
@@ -68,30 +68,66 @@ static void memset_int(int* dst, int val, size_t size) {
*ptr++ = val;
}
bool copy_pixels(const void* src, int src_w, int src_h, int src_x, int src_y,
bool copy_pixels_internal(const void* src, int src_w, int src_h, int src_x, int src_y,
void* dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color)
int width, int height, bool fill_blank, int color)
{
int left;
int line;
size_t line_stride;
int src_stride;
int src_pos;
int dst_pos;
size_t dst_blank_length;
int color = 0;
// Check valid first
if (src_w < 0 || src_h < 0 || src_x < 0 || src_y < 0 ||
dst_w < 0 || dst_h < 0 || dst_x < 0 || dst_y < 0 ||
width < 0 || height < 0 ||
src_x + width > src_w || src_y + height > src_h ||
dst_x + width > dst_w || dst_y + height > dst_h) {
// Sanitize
if (src_x < 0) {
width -= src_x;
dst_x -= src_x;
src_x = 0;
}
if (dst_x < 0) {
width -= dst_x;
src_x -= dst_x;
dst_x = 0;
}
if (width <= 0) {
return false;
}
if (width == 0 || height == 0) {
// No need to copy pixels
return true;
if (src_y < 0) {
height -= src_y;
dst_y -= src_y;
src_y = 0;
}
if (dst_y < 0) {
height -= dst_y;
src_y -= dst_y;
dst_y = 0;
}
if (height <= 0) {
return false;
}
left = src_x + width - src_w;
if (left > 0) {
width -= left;
}
left = dst_x + width - dst_w;
if (left > 0) {
width -= left;
}
if (width <= 0) {
return false;
}
left = src_y + height - src_h;
if (left > 0) {
height -= left;
}
left = dst_y + height - dst_h;
if (left > 0) {
height -= left;
}
if (height <= 0) {
return false;
}
// Init
@@ -99,9 +135,6 @@ bool copy_pixels(const void* src, int src_w, int src_h, int src_x, int src_y,
src_stride = src_w * 4;
src_pos = src_y * src_stride + src_x * 4;
dst_pos = 0;
if (fill_blank) {
color = convert_color(default_color);
}
dst_blank_length = (size_t) (dst_y * dst_w + dst_x) * 4;
// Fill start blank if necessary
@@ -134,3 +167,18 @@ bool copy_pixels(const void* src, int src_w, int src_h, int src_x, int src_y,
return true;
}
void copy_pixels(const void* src, int src_w, int src_h, int src_x, int src_y,
void* dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color)
{
int color = 0;
if (fill_blank) {
color = convert_color(default_color);
}
if (!copy_pixels_internal(src, src_w, src_h, src_x, src_y, dst, dst_w, dst_h, dst_x,
dst_y, width, height, fill_blank, color) && fill_blank) {
memset_int(dst, color, (size_t) (dst_w * dst_h));
}
}
+1 -1
View File
@@ -7,7 +7,7 @@
#include <stdbool.h>
bool copy_pixels(const void* src, int src_w, int src_h, int src_x, int src_y,
void copy_pixels(const void* src, int src_w, int src_h, int src_x, int src_y,
void* dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color);
+53 -6
View File
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <android/bitmap.h>
#include <GLES2/gl2.h>
#include "java_wrapper.h"
#include "input_stream.h"
@@ -28,6 +29,8 @@
static JavaVM* jvm;
static void* tile_buffer;
JNIEnv *get_env()
{
JNIEnv *env;
@@ -98,7 +101,7 @@ Java_com_hippo_image_Image_nativeIsCompleted(JNIEnv* env,
return (jboolean) is_completed((void*) (intptr_t) ptr, format);
}
JNIEXPORT jboolean JNICALL
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeRender(JNIEnv* env,
jclass clazz, jlong ptr, jint format,
jint src_x, jint src_y, jobject dst, jint dst_x, jint dst_y,
@@ -106,22 +109,60 @@ Java_com_hippo_image_Image_nativeRender(JNIEnv* env,
{
AndroidBitmapInfo info;
void *pixels = NULL;
bool result;
AndroidBitmap_getInfo(env, dst, &info);
AndroidBitmap_lockPixels(env, dst, &pixels);
if (pixels == NULL) {
LOGE(EMSG("Can't lock bitmap pixels"));
return JNI_FALSE;
return;
}
result = render((void*) (intptr_t) ptr, format, src_x, src_y,
render((void*) (intptr_t) ptr, format, src_x, src_y,
pixels, info.width, info.height, dst_x, dst_y,
width, height, fill_blank, default_color);
AndroidBitmap_unlockPixels(env, dst);
return (jboolean) result;
return;
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeTexImage(JNIEnv* env,
jclass clazz, jlong ptr, jint format, jboolean init, jint tile_type,
jint offset_x, jint offset_y)
{
// Check tile_buffer NULL
if (NULL == tile_buffer) {
return;
}
// Get border size and tile size
int border_size;
int tile_size;
switch (tile_type) {
case IMAGE_TILE_TYPE_SMALL:
border_size = IMAGE_SMALL_TILE_BORDER_SIZE;
tile_size = IMAGE_SMALL_TILE_SIZE;
break;
case IMAGE_TILE_TYPE_LARGE:
border_size = IMAGE_LARGE_TILE_BORDER_SIZE;
tile_size = IMAGE_LARGE_TILE_SIZE;
break;
default:
return;
}
render((void*) (intptr_t) ptr, format,
offset_x - border_size, offset_y - border_size,
tile_buffer, tile_size, tile_size, 0, 0,
tile_size, tile_size, true, 0);
if (init) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tile_size, tile_size,
0, GL_RGBA, GL_UNSIGNED_BYTE, tile_buffer);
} else {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tile_size, tile_size,
GL_RGBA, GL_UNSIGNED_BYTE, tile_buffer);
}
}
JNIEXPORT void JNICALL
@@ -162,12 +203,18 @@ Java_com_hippo_image_Image_nativeRecycle(JNIEnv* env,
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv* env;
if ((*vm)->GetEnv(vm, (void**) (&env), JNI_VERSION_1_6) != JNI_OK)
if ((*vm)->GetEnv(vm, (void**) (&env), JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
jvm = vm;
tile_buffer = malloc(IMAGE_LARGE_TILE_SIZE * IMAGE_LARGE_TILE_SIZE * 4);
return JNI_VERSION_1_6;
}
void JNI_OnUnload(JavaVM *vm, void *reserved)
{
free(tile_buffer);
tile_buffer = NULL;
}
+10
View File
@@ -7,6 +7,16 @@
#include <jni.h>
#define IMAGE_TILE_TYPE_SMALL 0x00
#define IMAGE_SMALL_TILE_CONTENT_SIZE 254
#define IMAGE_SMALL_TILE_BORDER_SIZE 1
#define IMAGE_SMALL_TILE_SIZE 256
#define IMAGE_TILE_TYPE_LARGE 0x01
#define IMAGE_LARGE_TILE_CONTENT_SIZE 508
#define IMAGE_LARGE_TILE_BORDER_SIZE 2
#define IMAGE_LARGE_TILE_SIZE 512
JNIEnv *get_env();
#endif // IMAGE_JAVA_WRAPPER_H