com_android_server_AssetAtlasService.cpp revision 3b748a44c6bd2ea05fe16839caf73dbe50bd7ae9
13b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy/* 23b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy * Copyright (C) 2013 The Android Open Source Project 33b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy * 43b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy * Licensed under the Apache License, Version 2.0 (the "License"); 53b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy * you may not use this file except in compliance with the License. 63b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy * You may obtain a copy of the License at 73b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy * 83b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy * http://www.apache.org/licenses/LICENSE-2.0 93b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy * 103b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy * Unless required by applicable law or agreed to in writing, software 113b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy * distributed under the License is distributed on an "AS IS" BASIS, 123b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy * See the License for the specific language governing permissions and 143b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy * limitations under the License. 153b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy */ 163b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 173b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#define LOG_TAG "AssetAtlasService" 183b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 193b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#include "jni.h" 203b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#include "JNIHelp.h" 213b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 223b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#include <android_view_GraphicBuffer.h> 233b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 243b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#include <GLES2/gl2.h> 253b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#include <GLES2/gl2ext.h> 263b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 273b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#include <EGL/egl.h> 283b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#include <EGL/eglext.h> 293b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 303b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#include <SkCanvas.h> 313b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#include <SkBitmap.h> 323b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 333b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guynamespace android { 343b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 353b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy// ---------------------------------------------------------------------------- 363b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy// Defines 373b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy// ---------------------------------------------------------------------------- 383b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 393b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy// Defines how long to wait for the GPU when uploading the atlas 403b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy// This timeout is defined in nanoseconds (see EGL_KHR_fence_sync extension) 413b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#define FENCE_TIMEOUT 2000000000 423b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 433b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy// ---------------------------------------------------------------------------- 443b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy// JNI Helpers 453b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy// ---------------------------------------------------------------------------- 463b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 473b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guystatic struct { 483b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy jfieldID mFinalizer; 493b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy jfieldID mNativeCanvas; 503b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy} gCanvasClassInfo; 513b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 523b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guystatic struct { 533b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy jfieldID mNativeCanvas; 543b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy} gCanvasFinalizerClassInfo; 553b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 563b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#define GET_INT(object, field) \ 573b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy env->GetIntField(object, field) 583b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 593b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#define SET_INT(object, field, value) \ 603b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy env->SetIntField(object, field, value) 613b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 623b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy// ---------------------------------------------------------------------------- 633b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy// Canvas management 643b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy// ---------------------------------------------------------------------------- 653b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 663b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guystatic inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) { 673b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer); 683b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>( 693b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy GET_INT(canvasObj, gCanvasClassInfo.mNativeCanvas)); 703b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy SET_INT(canvasObj, gCanvasClassInfo.mNativeCanvas, (int) newCanvas); 713b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy SET_INT(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (int) newCanvas); 723b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy SkSafeUnref(previousCanvas); 733b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy} 743b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 753b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guystatic SkBitmap* com_android_server_AssetAtlasService_acquireCanvas(JNIEnv* env, jobject, 763b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy jobject canvas, jint width, jint height) { 773b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 783b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy SkBitmap* bitmap = new SkBitmap; 793b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); 803b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy bitmap->allocPixels(); 813b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy bitmap->eraseColor(0); 823b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 833b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (*bitmap)); 843b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy swapCanvasPtr(env, canvas, nativeCanvas); 853b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 863b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy return bitmap; 873b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy} 883b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 893b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guystatic void com_android_server_AssetAtlasService_releaseCanvas(JNIEnv* env, jobject, 903b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy jobject canvas, SkBitmap* bitmap) { 913b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 923b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy SkCanvas* nativeCanvas = SkNEW(SkCanvas); 933b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy swapCanvasPtr(env, canvas, nativeCanvas); 943b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 953b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy delete bitmap; 963b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy} 973b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 983b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#define CLEANUP_GL_AND_RETURN(result) \ 993b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (fence != EGL_NO_SYNC_KHR) eglDestroySyncKHR(display, fence); \ 1003b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (image) eglDestroyImageKHR(display, image); \ 1013b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (texture) glDeleteTextures(1, &texture); \ 1023b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (surface != EGL_NO_SURFACE) eglDestroySurface(display, surface); \ 1033b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (context != EGL_NO_CONTEXT) eglDestroyContext(display, context); \ 1043b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); \ 1053b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy eglReleaseThread(); \ 1063b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy eglTerminate(display); \ 1073b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy return result; 1083b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 1093b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guystatic jboolean com_android_server_AssetAtlasService_upload(JNIEnv* env, jobject, 1103b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy jobject graphicBuffer, SkBitmap* bitmap) { 1113b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 1123b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // The goal of this method is to copy the bitmap into the GraphicBuffer 1133b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // using the GPU to swizzle the texture content 1143b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer)); 1153b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 1163b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (buffer != NULL) { 1173b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); 1183b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (display == EGL_NO_DISPLAY) return false; 1193b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 1203b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGLint major; 1213b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGLint minor; 1223b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (!eglInitialize(display, &major, &minor)) { 1233b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy ALOGW("Could not initialize EGL"); 1243b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy return false; 1253b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy } 1263b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 1273b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // We're going to use a 1x1 pbuffer surface later on 1283b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // The configuration doesn't really matter for what we're trying to do 1293b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGLint configAttrs[] = { 1303b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 1313b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGL_RED_SIZE, 8, 1323b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGL_GREEN_SIZE, 8, 1333b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGL_BLUE_SIZE, 8, 1343b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGL_ALPHA_SIZE, 0, 1353b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGL_DEPTH_SIZE, 0, 1363b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGL_STENCIL_SIZE, 0, 1373b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGL_NONE 1383b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy }; 1393b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGLConfig configs[1]; 1403b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGLint configCount; 1413b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (!eglChooseConfig(display, configAttrs, configs, 1, &configCount)) { 1423b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy ALOGW("Could not select EGL configuration"); 1433b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy eglReleaseThread(); 1443b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy eglTerminate(display); 1453b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy return false; 1463b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy } 1473b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (configCount <= 0) { 1483b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy ALOGW("Could not find EGL configuration"); 1493b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy eglReleaseThread(); 1503b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy eglTerminate(display); 1513b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy return false; 1523b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy } 1533b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 1543b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // These objects are initialized below but the default "null" 1553b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // values are used to cleanup properly at any point in the 1563b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // initialization sequence 1573b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy GLuint texture = 0; 1583b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGLImageKHR image = EGL_NO_IMAGE_KHR; 1593b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGLSurface surface = EGL_NO_SURFACE; 1603b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGLSyncKHR fence = EGL_NO_SYNC_KHR; 1613b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 1623b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; 1633b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGLContext context = eglCreateContext(display, configs[0], EGL_NO_CONTEXT, attrs); 1643b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (context == EGL_NO_CONTEXT) { 1653b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy ALOGW("Could not create EGL context"); 1663b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy CLEANUP_GL_AND_RETURN(false); 1673b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy } 1683b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 1693b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // Create the 1x1 pbuffer 1703b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGLint surfaceAttrs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE }; 1713b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy surface = eglCreatePbufferSurface(display, configs[0], surfaceAttrs); 1723b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (surface == EGL_NO_SURFACE) { 1733b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy ALOGW("Could not create EGL surface"); 1743b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy CLEANUP_GL_AND_RETURN(false); 1753b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy } 1763b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 1773b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (!eglMakeCurrent(display, surface, surface, context)) { 1783b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy ALOGW("Could not change current EGL context"); 1793b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy CLEANUP_GL_AND_RETURN(false); 1803b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy } 1813b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 1823b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // We use an EGLImage to access the content of the GraphicBuffer 1833b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // The EGL image is later bound to a 2D texture 1843b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer->getNativeBuffer(); 1853b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; 1863b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy image = eglCreateImageKHR(display, EGL_NO_CONTEXT, 1873b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs); 1883b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (image == EGL_NO_IMAGE_KHR) { 1893b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy ALOGW("Could not create EGL image"); 1903b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy CLEANUP_GL_AND_RETURN(false); 1913b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy } 1923b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 1933b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy glGenTextures(1, &texture); 1943b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy glBindTexture(GL_TEXTURE_2D, texture); 1953b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); 1963b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (glGetError() != GL_NO_ERROR) { 1973b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy ALOGW("Could not create/bind texture"); 1983b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy CLEANUP_GL_AND_RETURN(false); 1993b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy } 2003b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 2013b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // Upload the content of the bitmap in the GraphicBuffer 2023b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel()); 2033b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap->width(), bitmap->height(), 2043b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels()); 2053b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (glGetError() != GL_NO_ERROR) { 2063b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy ALOGW("Could not upload to texture"); 2073b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy CLEANUP_GL_AND_RETURN(false); 2083b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy } 2093b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 2103b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // The fence is used to wait for the texture upload to finish 2113b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // properly. We cannot rely on glFlush() and glFinish() as 2123b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // some drivers completely ignore these API calls 2133b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, NULL); 2143b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (fence == EGL_NO_SYNC_KHR) { 2153b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy ALOGW("Could not create sync fence %#x", eglGetError()); 2163b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy CLEANUP_GL_AND_RETURN(false); 2173b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy } 2183b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 2193b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a 2203b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // pipeline flush (similar to what a glFlush() would do.) 2213b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 2223b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT); 2233b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (waitStatus != EGL_CONDITION_SATISFIED_KHR) { 2243b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy ALOGW("Failed to wait for the fence %#x", eglGetError()); 2253b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy CLEANUP_GL_AND_RETURN(false); 2263b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy } 2273b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 2283b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy CLEANUP_GL_AND_RETURN(true); 2293b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy } 2303b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 2313b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy return false; 2323b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy} 2333b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 2343b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy// ---------------------------------------------------------------------------- 2353b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy// JNI Glue 2363b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy// ---------------------------------------------------------------------------- 2373b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 2383b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#define FIND_CLASS(var, className) \ 2393b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy var = env->FindClass(className); \ 2403b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy LOG_FATAL_IF(! var, "Unable to find class " className); 2413b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 2423b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ 2433b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ 2443b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy LOG_FATAL_IF(! var, "Unable to find field " fieldName); 2453b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 2463b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guyconst char* const kClassPathName = "com/android/server/AssetAtlasService"; 2473b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 2483b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guystatic JNINativeMethod gMethods[] = { 2493b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy { "nAcquireAtlasCanvas", "(Landroid/graphics/Canvas;II)I", 2503b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy (void*) com_android_server_AssetAtlasService_acquireCanvas }, 2513b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy { "nReleaseAtlasCanvas", "(Landroid/graphics/Canvas;I)V", 2523b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy (void*) com_android_server_AssetAtlasService_releaseCanvas }, 2533b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy { "nUploadAtlas", "(Landroid/view/GraphicBuffer;I)Z", 2543b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy (void*) com_android_server_AssetAtlasService_upload }, 2553b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy}; 2563b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 2573b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guyint register_android_server_AssetAtlasService(JNIEnv* env) { 2583b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy jclass clazz; 2593b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 2603b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy FIND_CLASS(clazz, "android/graphics/Canvas"); 2613b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer", 2623b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy "Landroid/graphics/Canvas$CanvasFinalizer;"); 2633b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I"); 2643b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 2653b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer"); 2663b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I"); 2673b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 2683b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy return jniRegisterNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); 2693b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy} 2703b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 2713b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy}; 272