Merge "Return status code from invoke()"
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c
index afa64f8..e34053b 100644
--- a/cmds/keystore/keystore.c
+++ b/cmds/keystore/keystore.c
@@ -493,6 +493,7 @@
{AID_VPN, AID_SYSTEM, GET},
{AID_WIFI, AID_SYSTEM, GET},
{AID_ROOT, AID_SYSTEM, GET},
+ {AID_KEYCHAIN, AID_SYSTEM, TEST | GET | SAW},
{~0, ~0, TEST | GET | INSERT | DELETE | EXIST | SAW},
};
diff --git a/cmds/runtime/main_runtime.cpp b/cmds/runtime/main_runtime.cpp
index 83cb533..785e4cc 100644
--- a/cmds/runtime/main_runtime.cpp
+++ b/cmds/runtime/main_runtime.cpp
@@ -12,7 +12,7 @@
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
-#include <utils/Log.h>
+#include <utils/Log.h>
#include <cutils/zygote.h>
#include <cutils/properties.h>
@@ -41,7 +41,7 @@
#undef LOG_TAG
#define LOG_TAG "runtime"
-static const char* ZYGOTE_ARGV[] = {
+static const char* ZYGOTE_ARGV[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
@@ -68,7 +68,6 @@
namespace android {
-extern status_t app_init(const char* className);
extern void set_finish_init_func(void (*func)());
@@ -76,7 +75,7 @@
* This class is used to kill this process (runtime) when the system_server dies.
*/
class GrimReaper : public IBinder::DeathRecipient {
-public:
+public:
GrimReaper() { }
virtual void binderDied(const wp<IBinder>& who)
@@ -170,7 +169,7 @@
/*
* Post-system-process initialization.
- *
+ *
* This function continues initialization after the system process
* has been initialized. It needs to be separate because the system
* initialization needs to care of starting the Android runtime if it is not
@@ -210,17 +209,17 @@
static void boot_init()
{
LOGI("Entered boot_init()!\n");
-
+
sp<ProcessState> proc(ProcessState::self());
LOGD("ProcessState: %p\n", proc.get());
proc->becomeContextManager(contextChecker, NULL);
-
+
if (proc->supportsProcesses()) {
LOGI("Binder driver opened. Multiprocess enabled.\n");
} else {
LOGI("Binder driver not found. Processes not supported.\n");
}
-
+
sp<BServiceManager> sm = new BServiceManager;
proc->setContextObject(sm);
}
@@ -258,7 +257,7 @@
int res;
time_t min_time = 1167652800; // jan 1 2007, type 'date -ud "1/1 12:00" +%s' to get value for current year
struct timespec ts;
-
+
fd = open("/dev/alarm", O_RDWR);
if(fd < 0) {
LOGW("Unable to open alarm driver: %s\n", strerror(errno));
@@ -346,14 +345,14 @@
int ic;
int result = 1;
pid_t systemPid;
-
+
sp<ProcessState> proc;
#ifndef HAVE_ANDROID_OS
/* Set stdout/stderr to unbuffered for MinGW/MSYS. */
//setvbuf(stdout, NULL, _IONBF, 0);
//setvbuf(stderr, NULL, _IONBF, 0);
-
+
LOGI("commandline args:\n");
for (int i = 0; i < argc; i++)
LOGI(" %2d: '%s'\n", i, argv[i]);
@@ -455,7 +454,7 @@
#if 0
// Hack to keep libc from beating the filesystem to death. It's
- // hitting /etc/localtime frequently,
+ // hitting /etc/localtime frequently,
//
// This statement locks us into Pacific time. We could do better,
// but there's not much point until we're sure that the library
@@ -467,15 +466,15 @@
/* track our progress through the boot sequence */
const int LOG_BOOT_PROGRESS_START = 3000;
- LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
+ LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
validateTime();
proc = ProcessState::self();
-
+
boot_init();
-
+
/* If we are in multiprocess mode, have zygote spawn the system
* server process and call system_init(). If we are running in
* single process mode just call system_init() directly.
@@ -488,8 +487,8 @@
property_get("log.redirect-stdio", propBuf, "");
logStdio = (strcmp(propBuf, "true") == 0);
- zygote_run_oneshot((int)(!logStdio),
- sizeof(ZYGOTE_ARGV) / sizeof(ZYGOTE_ARGV[0]),
+ zygote_run_oneshot((int)(!logStdio),
+ sizeof(ZYGOTE_ARGV) / sizeof(ZYGOTE_ARGV[0]),
ZYGOTE_ARGV);
//start_process("/system/bin/mediaserver");
@@ -497,7 +496,7 @@
} else {
#ifndef HAVE_ANDROID_OS
QuickRuntime* runt = new QuickRuntime();
- runt->start("com/android/server/SystemServer",
+ runt->start("com/android/server/SystemServer",
false /* spontaneously fork system server from zygote */);
#endif
}
@@ -506,11 +505,11 @@
finish_system_init(proc);
run(proc);
-
+
bail:
if (proc != NULL) {
proc->setContextObject(NULL);
}
-
+
return 0;
}
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index 32c9a1d..bfe13f0 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -53,7 +53,8 @@
status_t setData(const uint8_t* buffer, size_t len);
- status_t appendFrom(Parcel *parcel, size_t start, size_t len);
+ status_t appendFrom(const Parcel *parcel,
+ size_t start, size_t len);
bool hasFileDescriptors() const;
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 585d288..96828c6 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -127,11 +127,28 @@
// be called from the client.
status_t setDefaultBufferSize(uint32_t w, uint32_t h);
-private:
+ // getCurrentBuffer returns the buffer associated with the current image.
+ sp<GraphicBuffer> getCurrentBuffer() const;
+
+ // getCurrentTextureTarget returns the texture target of the current
+ // texture as returned by updateTexImage().
+ GLenum getCurrentTextureTarget() const;
+
+ // getCurrentCrop returns the cropping rectangle of the current buffer
+ Rect getCurrentCrop() const;
+
+ // getCurrentTransform returns the transform of the current buffer
+ uint32_t getCurrentTransform() const;
+
+protected:
// freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
// all slots.
void freeAllBuffers();
+ static bool isExternalFormat(uint32_t format);
+ static GLenum getTextureTarget(uint32_t format);
+
+private:
// createImage creates a new EGLImage from a GraphicBuffer.
EGLImageKHR createImage(EGLDisplay dpy,
@@ -194,6 +211,10 @@
// reset mCurrentTexture to INVALID_BUFFER_SLOT.
int mCurrentTexture;
+ // mCurrentTextureTarget is the GLES texture target to be used with the
+ // current texture.
+ GLenum mCurrentTextureTarget;
+
// mCurrentTextureBuf is the graphic buffer of the current texture. It's
// possible that this buffer is not associated with any buffer slot, so we
// must track it separately in order to properly use
@@ -248,12 +269,6 @@
// allocate new GraphicBuffer objects.
sp<IGraphicBufferAlloc> mGraphicBufferAlloc;
- // mAllocdBuffers is mirror of the list of buffers that SurfaceFlinger is
- // referencing. This is kept so that gralloc implementations do not need to
- // properly handle the case where SurfaceFlinger no longer holds a reference
- // to a buffer, but other processes do.
- Vector<sp<GraphicBuffer> > mAllocdBuffers;
-
// mFrameAvailableListener is the listener object that will be called when a
// new frame becomes available. If it is not NULL it will be called from
// queueBuffer.
@@ -262,7 +277,7 @@
// mMutex is the mutex used to prevent concurrent access to the member
// variables of SurfaceTexture objects. It must be locked whenever the
// member variables are accessed.
- Mutex mMutex;
+ mutable Mutex mMutex;
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index df82bf2..fe9b049 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -27,6 +27,8 @@
namespace android {
+class Surface;
+
class SurfaceTextureClient
: public EGLNativeBase<ANativeWindow, SurfaceTextureClient, RefBase>
{
@@ -36,6 +38,7 @@
sp<ISurfaceTexture> getISurfaceTexture() const;
private:
+ friend class Surface;
// can't be copied
SurfaceTextureClient& operator = (const SurfaceTextureClient& rhs);
@@ -78,6 +81,8 @@
void freeAllBuffers();
+ int getConnectedApi() const;
+
enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS };
enum { MIN_BUFFER_SLOTS = SurfaceTexture::MIN_BUFFER_SLOTS };
enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
@@ -121,10 +126,25 @@
// a timestamp is auto-generated when queueBuffer is called.
int64_t mTimestamp;
+ // mConnectedApi holds the currently connected API to this surface
+ int mConnectedApi;
+
+ // mQueryWidth is the width returned by query(). It is set to width
+ // of the last dequeued buffer or to mReqWidth if no buffer was dequeued.
+ uint32_t mQueryWidth;
+
+ // mQueryHeight is the height returned by query(). It is set to height
+ // of the last dequeued buffer or to mReqHeight if no buffer was dequeued.
+ uint32_t mQueryHeight;
+
+ // mQueryFormat is the format returned by query(). It is set to the last
+ // dequeued format or to mReqFormat if no buffer was dequeued.
+ uint32_t mQueryFormat;
+
// mMutex is the mutex used to prevent concurrent access to the member
// variables of SurfaceTexture objects. It must be locked whenever the
// member variables are accessed.
- Mutex mMutex;
+ mutable Mutex mMutex;
};
}; // namespace android
diff --git a/include/surfaceflinger/IGraphicBufferAlloc.h b/include/surfaceflinger/IGraphicBufferAlloc.h
index d996af7..01e4bd9 100644
--- a/include/surfaceflinger/IGraphicBufferAlloc.h
+++ b/include/surfaceflinger/IGraphicBufferAlloc.h
@@ -32,18 +32,10 @@
public:
DECLARE_META_INTERFACE(GraphicBufferAlloc);
- /* Create a new GraphicBuffer for the client to use. The server will
- * maintain a reference to the newly created GraphicBuffer until
- * freeAllGraphicBuffers is called.
+ /* Create a new GraphicBuffer for the client to use.
*/
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
PixelFormat format, uint32_t usage) = 0;
-
- /* Free all but one of the GraphicBuffer objects that the server is
- * currently referencing. If bufIndex is not a valid index of the buffers
- * the server is referencing, then all buffers are freed.
- */
- virtual void freeAllGraphicBuffersExcept(int bufIndex) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/surfaceflinger/ISurfaceComposerClient.h b/include/surfaceflinger/ISurfaceComposerClient.h
index a1e9e04..46b1bb7 100644
--- a/include/surfaceflinger/ISurfaceComposerClient.h
+++ b/include/surfaceflinger/ISurfaceComposerClient.h
@@ -64,7 +64,6 @@
* Requires ACCESS_SURFACE_FLINGER permission
*/
virtual sp<ISurface> createSurface( surface_data_t* data,
- int pid,
const String8& name,
DisplayID display,
uint32_t w,
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index 25b2ebf..c61a5bf 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -79,7 +79,6 @@
//! Create a surface
sp<SurfaceControl> createSurface(
- int pid, // pid of the process the surface is for
const String8& name,// name of the surface
DisplayID display, // Display to create this surface on
uint32_t w, // width in pixel
@@ -89,7 +88,6 @@
);
sp<SurfaceControl> createSurface(
- int pid, // pid of the process the surface is for
DisplayID display, // Display to create this surface on
uint32_t w, // width in pixel
uint32_t h, // height in pixel
diff --git a/include/tts/TtsEngine.h b/include/tts/TtsEngine.h
deleted file mode 100644
index 998e353..0000000
--- a/include/tts/TtsEngine.h
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc.
- *
- * 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.
- */
-#include <media/AudioSystem.h>
-
-// This header defines the interface used by the Android platform
-// to access Text-To-Speech functionality in shared libraries that implement
-// speech synthesis and the management of resources associated with the
-// synthesis.
-// An example of the implementation of this interface can be found in
-// FIXME: add path+name to implementation of default TTS engine
-// Libraries implementing this interface are used in:
-// frameworks/base/tts/jni/android_tts_SpeechSynthesis.cpp
-
-namespace android {
-
-#define ANDROID_TTS_ENGINE_PROPERTY_CONFIG "engineConfig"
-#define ANDROID_TTS_ENGINE_PROPERTY_PITCH "pitch"
-#define ANDROID_TTS_ENGINE_PROPERTY_RATE "rate"
-#define ANDROID_TTS_ENGINE_PROPERTY_VOLUME "volume"
-
-
-enum tts_synth_status {
- TTS_SYNTH_DONE = 0,
- TTS_SYNTH_PENDING = 1
-};
-
-enum tts_callback_status {
- TTS_CALLBACK_HALT = 0,
- TTS_CALLBACK_CONTINUE = 1
-};
-
-// The callback is used by the implementation of this interface to notify its
-// client, the Android TTS service, that the last requested synthesis has been
-// completed. // TODO reword
-// The callback for synthesis completed takes:
-// @param [inout] void *& - The userdata pointer set in the original
-// synth call
-// @param [in] uint32_t - Track sampling rate in Hz
-// @param [in] uint32_t - The audio format
-// @param [in] int - The number of channels
-// @param [inout] int8_t *& - A buffer of audio data only valid during the
-// execution of the callback
-// @param [inout] size_t & - The size of the buffer
-// @param [in] tts_synth_status - indicate whether the synthesis is done, or
-// if more data is to be synthesized.
-// @return TTS_CALLBACK_HALT to indicate the synthesis must stop,
-// TTS_CALLBACK_CONTINUE to indicate the synthesis must continue if
-// there is more data to produce.
-typedef tts_callback_status (synthDoneCB_t)(void *&, uint32_t,
- uint32_t, int, int8_t *&, size_t&, tts_synth_status);
-
-class TtsEngine;
-extern "C" TtsEngine* getTtsEngine();
-
-enum tts_result {
- TTS_SUCCESS = 0,
- TTS_FAILURE = -1,
- TTS_FEATURE_UNSUPPORTED = -2,
- TTS_VALUE_INVALID = -3,
- TTS_PROPERTY_UNSUPPORTED = -4,
- TTS_PROPERTY_SIZE_TOO_SMALL = -5,
- TTS_MISSING_RESOURCES = -6
-};
-
-enum tts_support_result {
- TTS_LANG_COUNTRY_VAR_AVAILABLE = 2,
- TTS_LANG_COUNTRY_AVAILABLE = 1,
- TTS_LANG_AVAILABLE = 0,
- TTS_LANG_MISSING_DATA = -1,
- TTS_LANG_NOT_SUPPORTED = -2
-};
-
-class TtsEngine
-{
-public:
- virtual ~TtsEngine() {}
-
- // Initialize the TTS engine and returns whether initialization succeeded.
- // @param synthDoneCBPtr synthesis callback function pointer
- // @return TTS_SUCCESS, or TTS_FAILURE
- virtual tts_result init(synthDoneCB_t synthDoneCBPtr, const char *engineConfig);
-
- // Shut down the TTS engine and releases all associated resources.
- // @return TTS_SUCCESS, or TTS_FAILURE
- virtual tts_result shutdown();
-
- // Interrupt synthesis and flushes any synthesized data that hasn't been
- // output yet. This will block until callbacks underway are completed.
- // @return TTS_SUCCESS, or TTS_FAILURE
- virtual tts_result stop();
-
- // Returns the level of support for the language, country and variant.
- // @return TTS_LANG_COUNTRY_VAR_AVAILABLE if the language, country and variant are supported,
- // and the corresponding resources are correctly installed
- // TTS_LANG_COUNTRY_AVAILABLE if the language and country are supported and the
- // corresponding resources are correctly installed, but there is no match for
- // the specified variant
- // TTS_LANG_AVAILABLE if the language is supported and the
- // corresponding resources are correctly installed, but there is no match for
- // the specified country and variant
- // TTS_LANG_MISSING_DATA if the required resources to provide any level of support
- // for the language are not correctly installed
- // TTS_LANG_NOT_SUPPORTED if the language is not supported by the TTS engine.
- virtual tts_support_result isLanguageAvailable(const char *lang, const char *country,
- const char *variant);
-
- // Load the resources associated with the specified language. The loaded
- // language will only be used once a call to setLanguage() with the same
- // language value is issued. Language and country values are coded according to the ISO three
- // letter codes for languages and countries, as can be retrieved from a java.util.Locale
- // instance. The variant value is encoded as the variant string retrieved from a
- // java.util.Locale instance built with that variant data.
- // @param lang pointer to the ISO three letter code for the language
- // @param country pointer to the ISO three letter code for the country
- // @param variant pointer to the variant code
- // @return TTS_SUCCESS, or TTS_FAILURE
- virtual tts_result loadLanguage(const char *lang, const char *country, const char *variant);
-
- // Load the resources associated with the specified language, country and Locale variant.
- // The loaded language will only be used once a call to setLanguageFromLocale() with the same
- // language value is issued. Language and country values are coded according to the ISO three
- // letter codes for languages and countries, as can be retrieved from a java.util.Locale
- // instance. The variant value is encoded as the variant string retrieved from a
- // java.util.Locale instance built with that variant data.
- // @param lang pointer to the ISO three letter code for the language
- // @param country pointer to the ISO three letter code for the country
- // @param variant pointer to the variant code
- // @return TTS_SUCCESS, or TTS_FAILURE
- virtual tts_result setLanguage(const char *lang, const char *country, const char *variant);
-
- // Retrieve the currently set language, country and variant, or empty strings if none of
- // parameters have been set. Language and country are represented by their 3-letter ISO code
- // @param[out] pointer to the retrieved 3-letter code language value
- // @param[out] pointer to the retrieved 3-letter code country value
- // @param[out] pointer to the retrieved variant value
- // @return TTS_SUCCESS, or TTS_FAILURE
- virtual tts_result getLanguage(char *language, char *country, char *variant);
-
- // Notifies the engine what audio parameters should be used for the synthesis.
- // This is meant to be used as a hint, the engine implementation will set the output values
- // to those of the synthesis format, based on a given hint.
- // @param[inout] encoding in: the desired audio sample format
- // out: the format used by the TTS engine
- // @param[inout] rate in: the desired audio sample rate
- // out: the sample rate used by the TTS engine
- // @param[inout] channels in: the desired number of audio channels
- // out: the number of channels used by the TTS engine
- // @return TTS_SUCCESS, or TTS_FAILURE
- virtual tts_result setAudioFormat(AudioSystem::audio_format& encoding, uint32_t& rate,
- int& channels);
-
- // Set a property for the the TTS engine
- // "size" is the maximum size of "value" for properties "property"
- // @param property pointer to the property name
- // @param value pointer to the property value
- // @param size maximum size required to store this type of property
- // @return TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS, or TTS_FAILURE,
- // or TTS_VALUE_INVALID
- virtual tts_result setProperty(const char *property, const char *value,
- const size_t size);
-
- // Retrieve a property from the TTS engine
- // @param property pointer to the property name
- // @param[out] value pointer to the retrieved language value
- // @param[inout] iosize in: stores the size available to store the
- // property value.
- // out: stores the size required to hold the language
- // value if getLanguage() returned
- // TTS_PROPERTY_SIZE_TOO_SMALL, unchanged otherwise
- // @return TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS,
- // or TTS_PROPERTY_SIZE_TOO_SMALL
- virtual tts_result getProperty(const char *property, char *value,
- size_t *iosize);
-
- // Synthesize the text.
- // As the synthesis is performed, the engine invokes the callback to notify
- // the TTS framework that it has filled the given buffer, and indicates how
- // many bytes it wrote. The callback is called repeatedly until the engine
- // has generated all the audio data corresponding to the text.
- // Note about the format of the input: the text parameter may use the
- // following elements
- // and their respective attributes as defined in the SSML 1.0 specification:
- // * lang
- // * say-as:
- // o interpret-as
- // * phoneme
- // * voice:
- // o gender,
- // o age,
- // o variant,
- // o name
- // * emphasis
- // * break:
- // o strength,
- // o time
- // * prosody:
- // o pitch,
- // o contour,
- // o range,
- // o rate,
- // o duration,
- // o volume
- // * mark
- // Differences between this text format and SSML are:
- // * full SSML documents are not supported
- // * namespaces are not supported
- // Text is coded in UTF-8.
- // @param text the UTF-8 text to synthesize
- // @param userdata pointer to be returned when the call is invoked
- // @param buffer the location where the synthesized data must be written
- // @param bufferSize the number of bytes that can be written in buffer
- // @return TTS_SUCCESS or TTS_FAILURE
- virtual tts_result synthesizeText(const char *text, int8_t *buffer,
- size_t bufferSize, void *userdata);
-
-};
-
-} // namespace android
-
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 0dc29c8..9b92c73 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -620,6 +620,11 @@
// Oldest sample to consider when calculating the velocity.
static const nsecs_t MAX_AGE = 200 * 1000000; // 200 ms
+ // When the total duration of the window of samples being averaged is less
+ // than the window size, the resulting velocity is scaled to reduce the impact
+ // of overestimation in short traces.
+ static const nsecs_t MIN_WINDOW = 100 * 1000000; // 100 ms
+
// The minimum duration between samples when estimating velocity.
static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms
diff --git a/include/utils/AssetManager.h b/include/utils/AssetManager.h
index 9e2bf37..a8c7ddb 100644
--- a/include/utils/AssetManager.h
+++ b/include/utils/AssetManager.h
@@ -222,6 +222,7 @@
{
String8 path;
FileType type;
+ String8 idmap;
};
Asset* openInPathLocked(const char* fileName, AccessMode mode,
@@ -262,6 +263,16 @@
void setLocaleLocked(const char* locale);
void updateResourceParamsLocked() const;
+ bool createIdmapFileLocked(const String8& originalPath, const String8& overlayPath,
+ const String8& idmapPath);
+
+ bool isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath,
+ const String8& idmapPath);
+
+ Asset* openIdmapLocked(const struct asset_path& ap) const;
+
+ bool getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename, uint32_t* pCrc);
+
class SharedZip : public RefBase {
public:
static sp<SharedZip> get(const String8& path);
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 35792dc..173412e 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -1798,9 +1798,9 @@
~ResTable();
status_t add(const void* data, size_t size, void* cookie,
- bool copyData=false);
+ bool copyData=false, const void* idmap = NULL);
status_t add(Asset* asset, void* cookie,
- bool copyData=false);
+ bool copyData=false, const void* idmap = NULL);
status_t add(ResTable* src);
status_t getError() const;
@@ -2046,6 +2046,24 @@
void getLocales(Vector<String8>* locales) const;
+ // Generate an idmap.
+ //
+ // Return value: on success: NO_ERROR; caller is responsible for free-ing
+ // outData (using free(3)). On failure, any status_t value other than
+ // NO_ERROR; the caller should not free outData.
+ status_t createIdmap(const ResTable& overlay, uint32_t originalCrc, uint32_t overlayCrc,
+ void** outData, size_t* outSize) const;
+
+ enum {
+ IDMAP_HEADER_SIZE_BYTES = 3 * sizeof(uint32_t),
+ };
+ // Retrieve idmap meta-data.
+ //
+ // This function only requires the idmap header (the first
+ // IDMAP_HEADER_SIZE_BYTES) bytes of an idmap file.
+ static bool getIdmapInfo(const void* idmap, size_t size,
+ uint32_t* pOriginalCrc, uint32_t* pOverlayCrc);
+
#ifndef HAVE_ANDROID_OS
void print(bool inclValues) const;
static String8 normalizeForOutput(const char* input);
@@ -2059,7 +2077,7 @@
struct bag_set;
status_t add(const void* data, size_t size, void* cookie,
- Asset* asset, bool copyData);
+ Asset* asset, bool copyData, const Asset* idmap);
ssize_t getResourcePackageIndex(uint32_t resID) const;
ssize_t getEntry(
@@ -2068,7 +2086,7 @@
const ResTable_type** outType, const ResTable_entry** outEntry,
const Type** outTypeClass) const;
status_t parsePackage(
- const ResTable_package* const pkg, const Header* const header);
+ const ResTable_package* const pkg, const Header* const header, uint32_t idmap_id);
void print_value(const Package* pkg, const Res_value& value) const;
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 95cfddf..392193b 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -851,6 +851,9 @@
tr.target.handle = handle;
tr.code = code;
tr.flags = binderFlags;
+ tr.cookie = 0;
+ tr.sender_pid = 0;
+ tr.sender_euid = 0;
const status_t err = data.errorCheck();
if (err == NO_ERROR) {
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index d57f2c9..a0fc4d0 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -338,7 +338,7 @@
status_t Parcel::setDataCapacity(size_t size)
{
- if (size > mDataSize) return continueWrite(size);
+ if (size > mDataCapacity) return continueWrite(size);
return NO_ERROR;
}
@@ -353,12 +353,12 @@
return err;
}
-status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len)
+status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len)
{
const sp<ProcessState> proc(ProcessState::self());
status_t err;
- uint8_t *data = parcel->mData;
- size_t *objects = parcel->mObjects;
+ const uint8_t *data = parcel->mData;
+ const size_t *objects = parcel->mObjects;
size_t size = parcel->mObjectsSize;
int startPos = mDataPos;
int firstIndex = -1, lastIndex = -2;
@@ -386,10 +386,12 @@
}
int numObjects = lastIndex - firstIndex + 1;
- // grow data
- err = growData(len);
- if (err != NO_ERROR) {
- return err;
+ if ((mDataSize+len) > mDataCapacity) {
+ // grow data
+ err = growData(len);
+ if (err != NO_ERROR) {
+ return err;
+ }
}
// append data
@@ -1384,8 +1386,10 @@
return NO_MEMORY;
}
} else {
- mDataSize = desired;
- LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+ if (mDataSize > desired) {
+ mDataSize = desired;
+ LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+ }
if (mDataPos > desired) {
mDataPos = desired;
LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
index e05da72..0cd51da 100644
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ b/libs/gui/IGraphicBufferAlloc.cpp
@@ -32,7 +32,6 @@
enum {
CREATE_GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
- FREE_ALL_GRAPHIC_BUFFERS_EXCEPT,
};
class BpGraphicBufferAlloc : public BpInterface<IGraphicBufferAlloc>
@@ -46,8 +45,7 @@
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
PixelFormat format, uint32_t usage) {
Parcel data, reply;
- data.writeInterfaceToken(
- IGraphicBufferAlloc::getInterfaceDescriptor());
+ data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor());
data.writeInt32(w);
data.writeInt32(h);
data.writeInt32(format);
@@ -58,17 +56,12 @@
if (nonNull) {
graphicBuffer = new GraphicBuffer();
reply.read(*graphicBuffer);
+ // reply.readStrongBinder();
+ // here we don't even have to read the BufferReference from
+ // the parcel, it'll die with the parcel.
}
return graphicBuffer;
}
-
- virtual void freeAllGraphicBuffersExcept(int bufIdx) {
- Parcel data, reply;
- data.writeInterfaceToken(
- IGraphicBufferAlloc::getInterfaceDescriptor());
- data.writeInt32(bufIdx);
- remote()->transact(FREE_ALL_GRAPHIC_BUFFERS_EXCEPT, data, &reply);
- }
};
IMPLEMENT_META_INTERFACE(GraphicBufferAlloc, "android.ui.IGraphicBufferAlloc");
@@ -80,6 +73,17 @@
{
// codes that don't require permission check
+ /* BufferReference just keeps a strong reference to a
+ * GraphicBuffer until it is destroyed (that is, until
+ * no local or remote process have a reference to it).
+ */
+ class BufferReference : public BBinder {
+ sp<GraphicBuffer> buffer;
+ public:
+ BufferReference(const sp<GraphicBuffer>& buffer) : buffer(buffer) { }
+ };
+
+
switch(code) {
case CREATE_GRAPHIC_BUFFER: {
CHECK_INTERFACE(IGraphicBufferAlloc, data, reply);
@@ -91,15 +95,16 @@
reply->writeInt32(result != 0);
if (result != 0) {
reply->write(*result);
+ // We add a BufferReference to this parcel to make sure the
+ // buffer stays alive until the GraphicBuffer object on
+ // the other side has been created.
+ // This is needed so that the buffer handle can be
+ // registered before the buffer is destroyed on implementations
+ // that do not use file-descriptors to track their buffers.
+ reply->writeStrongBinder( new BufferReference(result) );
}
return NO_ERROR;
} break;
- case FREE_ALL_GRAPHIC_BUFFERS_EXCEPT: {
- CHECK_INTERFACE(IGraphicBufferAlloc, data, reply);
- int bufIdx = data.readInt32();
- freeAllGraphicBuffersExcept(bufIdx);
- return NO_ERROR;
- } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 7730eb1..ea38e08 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -83,7 +83,6 @@
}
virtual sp<ISurface> createSurface( surface_data_t* params,
- int pid,
const String8& name,
DisplayID display,
uint32_t w,
@@ -93,7 +92,6 @@
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
- data.writeInt32(pid);
data.writeString8(name);
data.writeInt32(display);
data.writeInt32(w);
@@ -172,14 +170,13 @@
case CREATE_SURFACE: {
CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
surface_data_t params;
- int32_t pid = data.readInt32();
String8 name = data.readString8();
DisplayID display = data.readInt32();
uint32_t w = data.readInt32();
uint32_t h = data.readInt32();
PixelFormat format = data.readInt32();
uint32_t flags = data.readInt32();
- sp<ISurface> s = createSurface(¶ms, pid, name, display, w, h,
+ sp<ISurface> s = createSurface(¶ms, name, display, w, h,
format, flags);
params.writeToParcel(reply);
reply->writeStrongBinder(s->asBinder());
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index d336724..a1ff2c1 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -273,7 +273,6 @@
}
sp<SurfaceControl> SurfaceComposerClient::createSurface(
- int pid,
DisplayID display,
uint32_t w,
uint32_t h,
@@ -286,12 +285,11 @@
snprintf(buffer, SIZE, "<pid_%d>", getpid());
name.append(buffer);
- return SurfaceComposerClient::createSurface(pid, name, display,
+ return SurfaceComposerClient::createSurface(name, display,
w, h, format, flags);
}
sp<SurfaceControl> SurfaceComposerClient::createSurface(
- int pid,
const String8& name,
DisplayID display,
uint32_t w,
@@ -302,7 +300,7 @@
sp<SurfaceControl> result;
if (mStatus == NO_ERROR) {
ISurfaceComposerClient::surface_data_t data;
- sp<ISurface> surface = mClient->createSurface(&data, pid, name,
+ sp<ISurface> surface = mClient->createSurface(&data, name,
display, w, h, format, flags);
if (surface != 0) {
result = new SurfaceControl(this, surface, data, w, h, format, flags);
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index f4e2a67..39418f0 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -27,6 +27,8 @@
#include <gui/SurfaceTexture.h>
+#include <hardware/hardware.h>
+
#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/SurfaceComposerClient.h>
#include <surfaceflinger/IGraphicBufferAlloc.h>
@@ -82,6 +84,7 @@
mUseDefaultSize(true),
mBufferCount(MIN_BUFFER_SLOTS),
mCurrentTexture(INVALID_BUFFER_SLOT),
+ mCurrentTextureTarget(GL_TEXTURE_EXTERNAL_OES),
mCurrentTransform(0),
mCurrentTimestamp(0),
mLastQueued(INVALID_BUFFER_SLOT),
@@ -172,7 +175,6 @@
mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
}
- mAllocdBuffers.add(graphicBuffer);
}
return graphicBuffer;
}
@@ -198,6 +200,7 @@
if (buffer == NULL) {
return ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
}
+
if ((mUseDefaultSize) &&
((uint32_t(buffer->width) != mDefaultWidth) ||
(uint32_t(buffer->height) != mDefaultHeight))) {
@@ -264,9 +267,6 @@
LOGV("SurfaceTexture::updateTexImage");
Mutex::Autolock lock(mMutex);
- // We always bind the texture even if we don't update its contents.
- glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
-
// Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT,
// so this check will fail until a buffer gets queued.
if (mCurrentTexture != mLastQueued) {
@@ -284,7 +284,15 @@
while ((error = glGetError()) != GL_NO_ERROR) {
LOGE("GL error cleared before updating SurfaceTexture: %#04x", error);
}
- glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
+
+ GLenum target = getTextureTarget(
+ mSlots[mLastQueued].mGraphicBuffer->format);
+ if (target != mCurrentTextureTarget) {
+ glDeleteTextures(1, &mTexName);
+ }
+ glBindTexture(target, mTexName);
+ glEGLImageTargetTexture2DOES(target, (GLeglImageOES)image);
+
bool failed = false;
while ((error = glGetError()) != GL_NO_ERROR) {
LOGE("error binding external texture image %p (slot %d): %#04x",
@@ -297,14 +305,53 @@
// Update the SurfaceTexture state.
mCurrentTexture = mLastQueued;
+ mCurrentTextureTarget = target;
mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer;
mCurrentCrop = mLastQueuedCrop;
mCurrentTransform = mLastQueuedTransform;
mCurrentTimestamp = mLastQueuedTimestamp;
+ } else {
+ // We always bind the texture even if we don't update its contents.
+ glBindTexture(mCurrentTextureTarget, mTexName);
}
return OK;
}
+bool SurfaceTexture::isExternalFormat(uint32_t format)
+{
+ switch (format) {
+ // supported YUV formats
+ case HAL_PIXEL_FORMAT_YV12:
+ // Legacy/deprecated YUV formats
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ return true;
+ }
+
+ // Any OEM format needs to be considered
+ if (format>=0x100 && format<=0x1FF)
+ return true;
+
+ return false;
+}
+
+GLenum SurfaceTexture::getTextureTarget(uint32_t format)
+{
+ GLenum target = GL_TEXTURE_2D;
+#if defined(GL_OES_EGL_image_external)
+ if (isExternalFormat(format)) {
+ target = GL_TEXTURE_EXTERNAL_OES;
+ }
+#endif
+ return target;
+}
+
+GLenum SurfaceTexture::getCurrentTextureTarget() const {
+ Mutex::Autolock lock(mMutex);
+ return mCurrentTextureTarget;
+}
+
void SurfaceTexture::getTransformMatrix(float mtx[16]) {
LOGV("SurfaceTexture::getTransformMatrix");
Mutex::Autolock lock(mMutex);
@@ -425,19 +472,6 @@
mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
}
}
-
- int exceptBuf = -1;
- for (size_t i = 0; i < mAllocdBuffers.size(); i++) {
- if (mAllocdBuffers[i] == mCurrentTextureBuf) {
- exceptBuf = i;
- break;
- }
- }
- mAllocdBuffers.clear();
- if (exceptBuf >= 0) {
- mAllocdBuffers.add(mCurrentTextureBuf);
- }
- mGraphicBufferAlloc->freeAllGraphicBuffersExcept(exceptBuf);
}
EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
@@ -459,6 +493,22 @@
return image;
}
+sp<GraphicBuffer> SurfaceTexture::getCurrentBuffer() const {
+ Mutex::Autolock lock(mMutex);
+ return mCurrentTextureBuf;
+}
+
+Rect SurfaceTexture::getCurrentCrop() const {
+ Mutex::Autolock lock(mMutex);
+ return mCurrentCrop;
+}
+
+uint32_t SurfaceTexture::getCurrentTransform() const {
+ Mutex::Autolock lock(mMutex);
+ return mCurrentTransform;
+}
+
+
static void mtxMul(float out[16], const float a[16], const float b[16]) {
out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];
out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 29fc4d3..f4b2416 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -26,8 +26,10 @@
SurfaceTextureClient::SurfaceTextureClient(
const sp<ISurfaceTexture>& surfaceTexture):
mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0),
- mReqHeight(0), mReqFormat(DEFAULT_FORMAT), mReqUsage(0),
- mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mMutex() {
+ mReqHeight(0), mReqFormat(0), mReqUsage(0),
+ mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mConnectedApi(0),
+ mQueryWidth(0), mQueryHeight(0), mQueryFormat(0),
+ mMutex() {
// Initialize the ANativeWindow function pointers.
ANativeWindow::setSwapInterval = setSwapInterval;
ANativeWindow::dequeueBuffer = dequeueBuffer;
@@ -101,9 +103,10 @@
}
sp<GraphicBuffer>& gbuf(mSlots[buf]);
if (err == ISurfaceTexture::BUFFER_NEEDS_REALLOCATION ||
- gbuf == 0 || gbuf->getWidth() != mReqWidth ||
- gbuf->getHeight() != mReqHeight ||
- uint32_t(gbuf->getPixelFormat()) != mReqFormat ||
+ gbuf == 0 ||
+ (mReqWidth && gbuf->getWidth() != mReqWidth) ||
+ (mReqHeight && gbuf->getHeight() != mReqHeight) ||
+ (mReqFormat && uint32_t(gbuf->getPixelFormat()) != mReqFormat) ||
(gbuf->getUsage() & mReqUsage) != mReqUsage) {
gbuf = mSurfaceTexture->requestBuffer(buf, mReqWidth, mReqHeight,
mReqFormat, mReqUsage);
@@ -111,6 +114,9 @@
LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed");
return NO_MEMORY;
}
+ mQueryWidth = gbuf->width;
+ mQueryHeight = gbuf->height;
+ mQueryFormat = gbuf->format;
}
*buffer = gbuf.get();
return OK;
@@ -159,13 +165,13 @@
Mutex::Autolock lock(mMutex);
switch (what) {
case NATIVE_WINDOW_WIDTH:
+ *value = mQueryWidth ? mQueryWidth : mReqWidth;
+ return NO_ERROR;
case NATIVE_WINDOW_HEIGHT:
- // XXX: How should SurfaceTexture behave if setBuffersGeometry didn't
- // override the size?
- *value = 0;
+ *value = mQueryHeight ? mQueryHeight : mReqHeight;
return NO_ERROR;
case NATIVE_WINDOW_FORMAT:
- *value = DEFAULT_FORMAT;
+ *value = mQueryFormat ? mQueryFormat : mReqFormat;
return NO_ERROR;
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
*value = MIN_UNDEQUEUED_BUFFERS;
@@ -260,16 +266,49 @@
int SurfaceTextureClient::connect(int api) {
LOGV("SurfaceTextureClient::connect");
- // XXX: Implement this!
- return INVALID_OPERATION;
+ Mutex::Autolock lock(mMutex);
+ int err = NO_ERROR;
+ switch (api) {
+ case NATIVE_WINDOW_API_EGL:
+ if (mConnectedApi) {
+ err = -EINVAL;
+ } else {
+ mConnectedApi = api;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ return err;
}
int SurfaceTextureClient::disconnect(int api) {
LOGV("SurfaceTextureClient::disconnect");
- // XXX: Implement this!
- return INVALID_OPERATION;
+ Mutex::Autolock lock(mMutex);
+ int err = NO_ERROR;
+ switch (api) {
+ case NATIVE_WINDOW_API_EGL:
+ if (mConnectedApi == api) {
+ mConnectedApi = 0;
+ } else {
+ err = -EINVAL;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ return err;
}
+int SurfaceTextureClient::getConnectedApi() const
+{
+ Mutex::Autolock lock(mMutex);
+ return mConnectedApi;
+}
+
+
int SurfaceTextureClient::setUsage(uint32_t reqUsage)
{
LOGV("SurfaceTextureClient::setUsage");
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index bbe579e..a95f432 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -832,6 +832,7 @@
const Position& oldestPosition =
oldestMovement.positions[oldestMovement.idBits.getIndexOfBit(id)];
nsecs_t lastDuration = 0;
+
while (numTouches-- > 1) {
if (++index == HISTORY_SIZE) {
index = 0;
@@ -858,6 +859,14 @@
// Make sure we used at least one sample.
if (samplesUsed != 0) {
+ // Scale the velocity linearly if the window of samples is small.
+ nsecs_t totalDuration = newestMovement.eventTime - oldestMovement.eventTime;
+ if (totalDuration < MIN_WINDOW) {
+ float scale = float(totalDuration) / float(MIN_WINDOW);
+ accumVx *= scale;
+ accumVy *= scale;
+ }
+
*outVx = accumVx;
*outVy = accumVy;
return true;
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 9d1b8b9..93d0d1f 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -27,8 +27,14 @@
namespace android {
+#define ROUND_UP(value, boundary) (((value) + (boundary) - 1) & ~((boundary) - 1))
+#define MIN_HISTORY_DEPTH 20
+
// Must be at least sizeof(InputMessage) + sufficient space for pointer data
-static const int DEFAULT_MESSAGE_BUFFER_SIZE = 16384;
+static const int DEFAULT_MESSAGE_BUFFER_SIZE = ROUND_UP(
+ sizeof(InputMessage) + MIN_HISTORY_DEPTH
+ * (sizeof(InputMessage::SampleData) + MAX_POINTERS * sizeof(PointerCoords)),
+ 4096);
// Signal sent by the producer to the consumer to inform it that a new message is
// available to be consumed in the shared memory buffer.
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
index 6e57d93d..e41dd39 100644
--- a/libs/utils/AssetManager.cpp
+++ b/libs/utils/AssetManager.cpp
@@ -37,6 +37,19 @@
#include <errno.h>
#include <assert.h>
#include <strings.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({ \
+ typeof (exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1 && errno == EINTR); \
+ _rc; })
+#endif
using namespace android;
@@ -49,6 +62,7 @@
static const char* kAssetsRoot = "assets";
static const char* kAppZipName = NULL; //"classes.jar";
static const char* kSystemAssets = "framework/framework-res.apk";
+static const char* kIdmapCacheDir = "resource-cache";
static const char* kExcludeExtension = ".EXCLUDE";
@@ -56,6 +70,35 @@
static volatile int32_t gCount = 0;
+namespace {
+ // Transform string /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap
+ String8 idmapPathForPackagePath(const String8& pkgPath)
+ {
+ const char* root = getenv("ANDROID_DATA");
+ LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set");
+ String8 path(root);
+ path.appendPath(kIdmapCacheDir);
+
+ char buf[256]; // 256 chars should be enough for anyone...
+ strncpy(buf, pkgPath.string(), 255);
+ buf[255] = '\0';
+ char* filename = buf;
+ while (*filename && *filename == '/') {
+ ++filename;
+ }
+ char* p = filename;
+ while (*p) {
+ if (*p == '/') {
+ *p = '@';
+ }
+ ++p;
+ }
+ path.appendPath(filename);
+ path.append("@idmap");
+
+ return path;
+ }
+}
/*
* ===========================================================================
@@ -123,7 +166,7 @@
return true;
}
}
-
+
LOGV("In %p Asset %s path: %s", this,
ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string());
@@ -134,9 +177,181 @@
*cookie = (void*)mAssetPaths.size();
}
+ // add overlay packages for /system/framework; apps are handled by the
+ // (Java) package manager
+ if (strncmp(path.string(), "/system/framework/", 18) == 0) {
+ // When there is an environment variable for /vendor, this
+ // should be changed to something similar to how ANDROID_ROOT
+ // and ANDROID_DATA are used in this file.
+ String8 overlayPath("/vendor/overlay/framework/");
+ overlayPath.append(path.getPathLeaf());
+ if (TEMP_FAILURE_RETRY(access(overlayPath.string(), R_OK)) == 0) {
+ asset_path oap;
+ oap.path = overlayPath;
+ oap.type = ::getFileType(overlayPath.string());
+ bool addOverlay = (oap.type == kFileTypeRegular); // only .apks supported as overlay
+ if (addOverlay) {
+ oap.idmap = idmapPathForPackagePath(overlayPath);
+
+ if (isIdmapStaleLocked(ap.path, oap.path, oap.idmap)) {
+ addOverlay = createIdmapFileLocked(ap.path, oap.path, oap.idmap);
+ }
+ }
+ if (addOverlay) {
+ mAssetPaths.add(oap);
+ } else {
+ LOGW("failed to add overlay package %s\n", overlayPath.string());
+ }
+ }
+ }
+
return true;
}
+bool AssetManager::isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath,
+ const String8& idmapPath)
+{
+ struct stat st;
+ if (TEMP_FAILURE_RETRY(stat(idmapPath.string(), &st)) == -1) {
+ if (errno == ENOENT) {
+ return true; // non-existing idmap is always stale
+ } else {
+ LOGW("failed to stat file %s: %s\n", idmapPath.string(), strerror(errno));
+ return false;
+ }
+ }
+ if (st.st_size < ResTable::IDMAP_HEADER_SIZE_BYTES) {
+ LOGW("file %s has unexpectedly small size=%zd\n", idmapPath.string(), (size_t)st.st_size);
+ return false;
+ }
+ int fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_RDONLY));
+ if (fd == -1) {
+ LOGW("failed to open file %s: %s\n", idmapPath.string(), strerror(errno));
+ return false;
+ }
+ char buf[ResTable::IDMAP_HEADER_SIZE_BYTES];
+ ssize_t bytesLeft = ResTable::IDMAP_HEADER_SIZE_BYTES;
+ for (;;) {
+ ssize_t r = TEMP_FAILURE_RETRY(read(fd, buf + ResTable::IDMAP_HEADER_SIZE_BYTES - bytesLeft,
+ bytesLeft));
+ if (r < 0) {
+ TEMP_FAILURE_RETRY(close(fd));
+ return false;
+ }
+ bytesLeft -= r;
+ if (bytesLeft == 0) {
+ break;
+ }
+ }
+ TEMP_FAILURE_RETRY(close(fd));
+
+ uint32_t cachedOriginalCrc, cachedOverlayCrc;
+ if (!ResTable::getIdmapInfo(buf, ResTable::IDMAP_HEADER_SIZE_BYTES,
+ &cachedOriginalCrc, &cachedOverlayCrc)) {
+ return false;
+ }
+
+ uint32_t actualOriginalCrc, actualOverlayCrc;
+ if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &actualOriginalCrc)) {
+ return false;
+ }
+ if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &actualOverlayCrc)) {
+ return false;
+ }
+ return cachedOriginalCrc != actualOriginalCrc || cachedOverlayCrc != actualOverlayCrc;
+}
+
+bool AssetManager::getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename,
+ uint32_t* pCrc)
+{
+ asset_path ap;
+ ap.path = zipPath;
+ const ZipFileRO* zip = getZipFileLocked(ap);
+ if (zip == NULL) {
+ return false;
+ }
+ const ZipEntryRO entry = zip->findEntryByName(entryFilename);
+ if (entry == NULL) {
+ return false;
+ }
+ if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, (long*)pCrc)) {
+ return false;
+ }
+ return true;
+}
+
+bool AssetManager::createIdmapFileLocked(const String8& originalPath, const String8& overlayPath,
+ const String8& idmapPath)
+{
+ LOGD("%s: originalPath=%s overlayPath=%s idmapPath=%s\n",
+ __FUNCTION__, originalPath.string(), overlayPath.string(), idmapPath.string());
+ ResTable tables[2];
+ const String8* paths[2] = { &originalPath, &overlayPath };
+ uint32_t originalCrc, overlayCrc;
+ bool retval = false;
+ ssize_t offset = 0;
+ int fd = 0;
+ uint32_t* data = NULL;
+ size_t size;
+
+ for (int i = 0; i < 2; ++i) {
+ asset_path ap;
+ ap.type = kFileTypeRegular;
+ ap.path = *paths[i];
+ Asset* ass = openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap);
+ if (ass == NULL) {
+ LOGW("failed to find resources.arsc in %s\n", ap.path.string());
+ goto error;
+ }
+ tables[i].add(ass, (void*)1, false);
+ }
+
+ if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &originalCrc)) {
+ LOGW("failed to retrieve crc for resources.arsc in %s\n", originalPath.string());
+ goto error;
+ }
+ if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &overlayCrc)) {
+ LOGW("failed to retrieve crc for resources.arsc in %s\n", overlayPath.string());
+ goto error;
+ }
+
+ if (tables[0].createIdmap(tables[1], originalCrc, overlayCrc,
+ (void**)&data, &size) != NO_ERROR) {
+ LOGW("failed to generate idmap data for file %s\n", idmapPath.string());
+ goto error;
+ }
+
+ // This should be abstracted (eg replaced by a stand-alone
+ // application like dexopt, triggered by something equivalent to
+ // installd).
+ fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_WRONLY | O_CREAT | O_TRUNC, 0644));
+ if (fd == -1) {
+ LOGW("failed to write idmap file %s (open: %s)\n", idmapPath.string(), strerror(errno));
+ goto error_free;
+ }
+ for (;;) {
+ ssize_t written = TEMP_FAILURE_RETRY(write(fd, data + offset, size));
+ if (written < 0) {
+ LOGW("failed to write idmap file %s (write: %s)\n", idmapPath.string(),
+ strerror(errno));
+ goto error_close;
+ }
+ size -= (size_t)written;
+ offset += written;
+ if (size == 0) {
+ break;
+ }
+ }
+
+ retval = true;
+error_close:
+ TEMP_FAILURE_RETRY(close(fd));
+error_free:
+ free(data);
+error:
+ return retval;
+}
+
bool AssetManager::addDefaultAssets()
{
const char* root = getenv("ANDROID_ROOT");
@@ -405,6 +620,7 @@
ResTable* sharedRes = NULL;
bool shared = true;
const asset_path& ap = mAssetPaths.itemAt(i);
+ Asset* idmap = openIdmapLocked(ap);
LOGV("Looking for resource asset in '%s'\n", ap.path.string());
if (ap.type != kFileTypeDirectory) {
if (i == 0) {
@@ -434,7 +650,7 @@
// can quickly copy it out for others.
LOGV("Creating shared resources for %s", ap.path.string());
sharedRes = new ResTable();
- sharedRes->add(ass, (void*)(i+1), false);
+ sharedRes->add(ass, (void*)(i+1), false, idmap);
sharedRes = const_cast<AssetManager*>(this)->
mZipSet.setZipResourceTable(ap.path, sharedRes);
}
@@ -458,7 +674,7 @@
rt->add(sharedRes);
} else {
LOGV("Parsing resources for %s", ap.path.string());
- rt->add(ass, (void*)(i+1), !shared);
+ rt->add(ass, (void*)(i+1), !shared, idmap);
}
if (!shared) {
@@ -499,6 +715,21 @@
res->setParameters(mConfig);
}
+Asset* AssetManager::openIdmapLocked(const struct asset_path& ap) const
+{
+ Asset* ass = NULL;
+ if (ap.idmap.size() != 0) {
+ ass = const_cast<AssetManager*>(this)->
+ openAssetFromFileLocked(ap.idmap, Asset::ACCESS_BUFFER);
+ if (ass) {
+ LOGV("loading idmap %s\n", ap.idmap.string());
+ } else {
+ LOGW("failed to load idmap %s\n", ap.idmap.string());
+ }
+ }
+ return ass;
+}
+
const ResTable& AssetManager::getResources(bool required) const
{
const ResTable* rt = getResTable(required);
diff --git a/libs/utils/Looper.cpp b/libs/utils/Looper.cpp
index d5dd126..b54fb9d 100644
--- a/libs/utils/Looper.cpp
+++ b/libs/utils/Looper.cpp
@@ -662,7 +662,8 @@
#endif
void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
- sendMessageAtTime(LLONG_MIN, handler, message);
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ sendMessageAtTime(now, handler, message);
}
void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
diff --git a/libs/utils/README b/libs/utils/README
index 36a706d..01741e0 100644
--- a/libs/utils/README
+++ b/libs/utils/README
@@ -1,4 +1,6 @@
Android Utility Function Library
+================================
+
If you need a feature that is native to Linux but not present on other
platforms, construct a platform-dependent implementation that shares
@@ -12,3 +14,276 @@
layer. The goal is to provide an optimized solution for Linux with
reasonable implementations for other platforms.
+
+
+Resource overlay
+================
+
+
+Introduction
+------------
+
+Overlay packages are special .apk files which provide no code but
+additional resource values (and possibly new configurations) for
+resources in other packages. When an application requests resources,
+the system will return values from either the application's original
+package or any associated overlay package. Any redirection is completely
+transparent to the calling application.
+
+Resource values have the following precedence table, listed in
+descending precedence.
+
+ * overlay package, matching config (eg res/values-en-land)
+
+ * original package, matching config
+
+ * overlay package, no config (eg res/values)
+
+ * original package, no config
+
+During compilation, overlay packages are differentiated from regular
+packages by passing the -o flag to aapt.
+
+
+Background
+----------
+
+This section provides generic background material on resources in
+Android.
+
+
+How resources are bundled in .apk files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Android .apk files are .zip files, usually housing .dex code,
+certificates and resources, though packages containing resources but
+no code are possible. Resources can be divided into the following
+categories; a `configuration' indicates a set of phone language, display
+density, network operator, etc.
+
+ * assets: uncompressed, raw files packaged as part of an .apk and
+ explicitly referenced by filename. These files are
+ independent of configuration.
+
+ * res/drawable: bitmap or xml graphics. Each file may have different
+ values depending on configuration.
+
+ * res/values: integers, strings, etc. Each resource may have different
+ values depending on configuration.
+
+Resource meta information and information proper is stored in a binary
+format in a named file resources.arsc, bundled as part of the .apk.
+
+Resource IDs and lookup
+~~~~~~~~~~~~~~~~~~~~~~~
+During compilation, the aapt tool gathers application resources and
+generates a resources.arsc file. Each resource name is assigned an
+integer ID 0xppttiii (translated to a symbolic name via R.java), where
+
+ * pp: corresponds to the package namespace (details below).
+
+ * tt: corresponds to the resource type (string, int, etc). Every
+ resource of the same type within the same package has the same
+ tt value, but depending on available types, the actual numerical
+ value may be different between packages.
+
+ * iiii: sequential number, assigned in the order resources are found.
+
+Resource values are specified paired with a set of configuration
+constraints (the default being the empty set), eg res/values-sv-port
+which imposes restrictions on language (Swedish) and display orientation
+(portrait). During lookup, every constraint set is matched against the
+current configuration, and the value corresponding to the best matching
+constraint set is returned (ResourceTypes.{h,cpp}).
+
+Parsing of resources.arsc is handled by ResourceTypes.cpp; this utility
+is governed by AssetManager.cpp, which tracks loaded resources per
+process.
+
+Assets are looked up by path and filename in AssetManager.cpp. The path
+to resources in res/drawable are located by ResourceTypes.cpp and then
+handled like assets by AssetManager.cpp. Other resources are handled
+solely by ResourceTypes.cpp.
+
+Package ID as namespace
+~~~~~~~~~~~~~~~~~~~~~~~
+The pp part of a resource ID defines a namespace. Android currently
+defines two namespaces:
+
+ * 0x01: system resources (pre-installed in framework-res.apk)
+
+ * 0x7f: application resources (bundled in the application .apk)
+
+ResourceTypes.cpp supports package IDs between 0x01 and 0x7f
+(inclusive); values outside this range are invalid.
+
+Each running (Dalvik) process is assigned a unique instance of
+AssetManager, which in turn keeps a forest structure of loaded
+resource.arsc files. Normally, this forest is structured as follows,
+where mPackageMap is the internal vector employed in ResourceTypes.cpp.
+
+mPackageMap[0x00] -> system package
+mPackageMap[0x01] -> NULL
+mPackageMap[0x02] -> NULL
+...
+mPackageMap[0x7f - 2] -> NULL
+mPackageMap[0x7f - 1] -> application package
+
+
+
+The resource overlay extension
+------------------------------
+
+The resource overlay mechanism aims to (partly) shadow and extend
+existing resources with new values for defined and new configurations.
+Technically, this is achieved by adding resource-only packages (called
+overlay packages) to existing resource namespaces, like so:
+
+mPackageMap[0x00] -> system package -> system overlay package
+mPackageMap[0x01] -> NULL
+mPackageMap[0x02] -> NULL
+...
+mPackageMap[0x7f - 2] -> NULL
+mPackageMap[0x7f - 1] -> application package -> overlay 1 -> overlay 2
+
+The use of overlay resources is completely transparent to
+applications; no additional resource identifiers are introduced, only
+configuration/value pairs. Any number of overlay packages may be loaded
+at a time; overlay packages are agnostic to what they target -- both
+system and application resources are fair game.
+
+The package targeted by an overlay package is called the target or
+original package.
+
+Resource overlay operates on symbolic resources names. Hence, to
+override the string/str1 resources in a package, the overlay package
+would include a resource also named string/str1. The end user does not
+have to worry about the numeric resources IDs assigned by aapt, as this
+is resolved automatically by the system.
+
+As of this writing, the use of resource overlay has not been fully
+explored. Until it has, only OEMs are trusted to use resource overlay.
+For this reason, overlay packages must reside in /system/overlay.
+
+
+Resource ID mapping
+~~~~~~~~~~~~~~~~~~~
+Resource identifiers must be coherent within the same namespace (ie
+PackageGroup in ResourceTypes.cpp). Calling applications will refer to
+resources using the IDs defined in the original package, but there is no
+guarantee aapt has assigned the same ID to the corresponding resource in
+an overlay package. To translate between the two, a resource ID mapping
+{original ID -> overlay ID} is created during package installation
+(PackageManagerService.java) and used during resource lookup. The
+mapping is stored in /data/resource-cache, with a @idmap file name
+suffix.
+
+The idmap file format is documented in a separate section, below.
+
+
+Package management
+~~~~~~~~~~~~~~~~~~
+Packages are managed by the PackageManagerService. Addition and removal
+of packages are monitored via the inotify framework, exposed via
+android.os.FileObserver.
+
+During initialization of a Dalvik process, ActivityThread.java requests
+the process' AssetManager (by proxy, via AssetManager.java and JNI)
+to load a list of packages. This list includes overlay packages, if
+present.
+
+When a target package or a corresponding overlay package is installed,
+the target package's process is stopped and a new idmap is generated.
+This is similar to how applications are stopped when their packages are
+upgraded.
+
+
+Creating overlay packages
+-------------------------
+
+Overlay packages should contain no code, define (some) resources with
+the same type and name as in the original package, and be compiled with
+the -o flag passed to aapt.
+
+The aapt -o flag instructs aapt to create an overlay package.
+Technically, this means the package will be assigned package id 0x00.
+
+There are no restrictions on overlay packages names, though the naming
+convention <original.package.name>.overlay.<name> is recommended.
+
+
+Example overlay package
+~~~~~~~~~~~~~~~~~~~~~~~
+
+To overlay the resource bool/b in package com.foo.bar, to be applied
+when the display is in landscape mode, create a new package with
+no source code and a single .xml file under res/values-land, with
+an entry for bool/b. Compile with aapt -o and place the results in
+/system/overlay by adding the following to Android.mk:
+
+LOCAL_AAPT_FLAGS := -o com.foo.bar
+LOCAL_MODULE_PATH := $(TARGET_OUT)/overlay
+
+
+The ID map (idmap) file format
+------------------------------
+
+The idmap format is designed for lookup performance. However, leading
+and trailing undefined overlay values are discarded to reduce the memory
+footprint.
+
+
+idmap grammar
+~~~~~~~~~~~~~
+All atoms (names in square brackets) are uint32_t integers. The
+idmap-magic constant spells "idmp" in ASCII. Offsets are given relative
+to the data_header, not to the beginning of the file.
+
+map := header data
+header := idmap-magic <crc32-original-pkg> <crc32-overlay-pkg>
+idmap-magic := <0x706d6469>
+data := data_header type_block+
+data_header := <m> header_block{m}
+header_block := <0> | <type_block_offset>
+type_block := <n> <id_offset> entry{n}
+entry := <resource_id_in_target_package>
+
+
+idmap example
+~~~~~~~~~~~~~
+Given a pair of target and overlay packages with CRC sums 0x216a8fe2
+and 0x6b9beaec, each defining the following resources
+
+Name Target package Overlay package
+string/str0 0x7f010000 -
+string/str1 0x7f010001 0x7f010000
+string/str2 0x7f010002 -
+string/str3 0x7f010003 0x7f010001
+string/str4 0x7f010004 -
+bool/bool0 0x7f020000 -
+integer/int0 0x7f030000 0x7f020000
+integer/int1 0x7f030001 -
+
+the corresponding resource map is
+
+0x706d6469 0x216a8fe2 0x6b9beaec 0x00000003 \
+0x00000004 0x00000000 0x00000009 0x00000003 \
+0x00000001 0x7f010000 0x00000000 0x7f010001 \
+0x00000001 0x00000000 0x7f020000
+
+or, formatted differently
+
+0x706d6469 # magic: all idmap files begin with this constant
+0x216a8fe2 # CRC32 of the resources.arsc file in the original package
+0x6b9beaec # CRC32 of the resources.arsc file in the overlay package
+0x00000003 # header; three types (string, bool, integer) in the target package
+0x00000004 # header_block for type 0 (string) is located at offset 4
+0x00000000 # no bool type exists in overlay package -> no header_block
+0x00000009 # header_block for type 2 (integer) is located at offset 9
+0x00000003 # header_block for string; overlay IDs span 3 elements
+0x00000001 # the first string in target package is entry 1 == offset
+0x7f010000 # target 0x7f01001 -> overlay 0x7f010000
+0x00000000 # str2 not defined in overlay package
+0x7f010001 # target 0x7f010003 -> overlay 0x7f010001
+0x00000001 # header_block for integer; overlay IDs span 1 element
+0x00000000 # offset == 0
+0x7f020000 # target 0x7f030000 -> overlay 0x7f020000
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index ac9cdf9..784c9d2 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -63,6 +63,10 @@
#endif
#endif
+#define IDMAP_MAGIC 0x706d6469
+// size measured in sizeof(uint32_t)
+#define IDMAP_HEADER_SIZE (ResTable::IDMAP_HEADER_SIZE_BYTES / sizeof(uint32_t))
+
static void printToLogFunc(void* cookie, const char* txt)
{
LOGV("%s", txt);
@@ -214,6 +218,81 @@
outData->colors = (uint32_t*) data;
}
+static bool assertIdmapHeader(const uint32_t* map, size_t sizeBytes)
+{
+ if (sizeBytes < ResTable::IDMAP_HEADER_SIZE_BYTES) {
+ LOGW("idmap assertion failed: size=%d bytes\n", sizeBytes);
+ return false;
+ }
+ if (*map != htodl(IDMAP_MAGIC)) { // htodl: map data expected to be in correct endianess
+ LOGW("idmap assertion failed: invalid magic found (is 0x%08x, expected 0x%08x)\n",
+ *map, htodl(IDMAP_MAGIC));
+ return false;
+ }
+ return true;
+}
+
+static status_t idmapLookup(const uint32_t* map, size_t sizeBytes, uint32_t key, uint32_t* outValue)
+{
+ // see README for details on the format of map
+ if (!assertIdmapHeader(map, sizeBytes)) {
+ return UNKNOWN_ERROR;
+ }
+ map = map + IDMAP_HEADER_SIZE; // skip ahead to data segment
+ // size of data block, in uint32_t
+ const size_t size = (sizeBytes - ResTable::IDMAP_HEADER_SIZE_BYTES) / sizeof(uint32_t);
+ const uint32_t type = Res_GETTYPE(key) + 1; // add one, idmap stores "public" type id
+ const uint32_t entry = Res_GETENTRY(key);
+ const uint32_t typeCount = *map;
+
+ if (type > typeCount) {
+ LOGW("Resource ID map: type=%d exceeds number of types=%d\n", type, typeCount);
+ return UNKNOWN_ERROR;
+ }
+ if (typeCount > size) {
+ LOGW("Resource ID map: number of types=%d exceeds size of map=%d\n", typeCount, size);
+ return UNKNOWN_ERROR;
+ }
+ const uint32_t typeOffset = map[type];
+ if (typeOffset == 0) {
+ *outValue = 0;
+ return NO_ERROR;
+ }
+ if (typeOffset + 1 > size) {
+ LOGW("Resource ID map: type offset=%d exceeds reasonable value, size of map=%d\n",
+ typeOffset, size);
+ return UNKNOWN_ERROR;
+ }
+ const uint32_t entryCount = map[typeOffset];
+ const uint32_t entryOffset = map[typeOffset + 1];
+ if (entryCount == 0 || entry < entryOffset || entry - entryOffset > entryCount - 1) {
+ *outValue = 0;
+ return NO_ERROR;
+ }
+ const uint32_t index = typeOffset + 2 + entry - entryOffset;
+ if (index > size) {
+ LOGW("Resource ID map: entry index=%d exceeds size of map=%d\n", index, size);
+ *outValue = 0;
+ return NO_ERROR;
+ }
+ *outValue = map[index];
+
+ return NO_ERROR;
+}
+
+static status_t getIdmapPackageId(const uint32_t* map, size_t mapSize, uint32_t *outId)
+{
+ if (!assertIdmapHeader(map, mapSize)) {
+ return UNKNOWN_ERROR;
+ }
+ const uint32_t* p = map + IDMAP_HEADER_SIZE + 1;
+ while (*p == 0) {
+ ++p;
+ }
+ *outId = (map[*p + IDMAP_HEADER_SIZE + 2] >> 24) & 0x000000ff;
+ return NO_ERROR;
+}
+
Res_png_9patch* Res_png_9patch::deserialize(const void* inData)
{
if (sizeof(void*) != sizeof(int32_t)) {
@@ -1290,7 +1369,13 @@
struct ResTable::Header
{
- Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL) { }
+ Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL),
+ resourceIDMap(NULL), resourceIDMapSize(0) { }
+
+ ~Header()
+ {
+ free(resourceIDMap);
+ }
ResTable* const owner;
void* ownedData;
@@ -1301,6 +1386,8 @@
void* cookie;
ResStringPool values;
+ uint32_t* resourceIDMap;
+ size_t resourceIDMapSize;
};
struct ResTable::Type
@@ -1716,12 +1803,13 @@
return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1;
}
-status_t ResTable::add(const void* data, size_t size, void* cookie, bool copyData)
+status_t ResTable::add(const void* data, size_t size, void* cookie, bool copyData,
+ const void* idmap)
{
- return add(data, size, cookie, NULL, copyData);
+ return add(data, size, cookie, NULL, copyData, reinterpret_cast<const Asset*>(idmap));
}
-status_t ResTable::add(Asset* asset, void* cookie, bool copyData)
+status_t ResTable::add(Asset* asset, void* cookie, bool copyData, const void* idmap)
{
const void* data = asset->getBuffer(true);
if (data == NULL) {
@@ -1729,7 +1817,7 @@
return UNKNOWN_ERROR;
}
size_t size = (size_t)asset->getLength();
- return add(data, size, cookie, asset, copyData);
+ return add(data, size, cookie, asset, copyData, reinterpret_cast<const Asset*>(idmap));
}
status_t ResTable::add(ResTable* src)
@@ -1757,19 +1845,30 @@
}
status_t ResTable::add(const void* data, size_t size, void* cookie,
- Asset* asset, bool copyData)
+ Asset* asset, bool copyData, const Asset* idmap)
{
if (!data) return NO_ERROR;
Header* header = new Header(this);
header->index = mHeaders.size();
header->cookie = cookie;
+ if (idmap != NULL) {
+ const size_t idmap_size = idmap->getLength();
+ const void* idmap_data = const_cast<Asset*>(idmap)->getBuffer(true);
+ header->resourceIDMap = (uint32_t*)malloc(idmap_size);
+ if (header->resourceIDMap == NULL) {
+ delete header;
+ return (mError = NO_MEMORY);
+ }
+ memcpy((void*)header->resourceIDMap, idmap_data, idmap_size);
+ header->resourceIDMapSize = idmap_size;
+ }
mHeaders.add(header);
const bool notDeviceEndian = htods(0xf0) != 0xf0;
LOAD_TABLE_NOISY(
- LOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%p, asset=%p, copy=%d\n",
- data, size, cookie, asset, copyData));
+ LOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%p, asset=%p, copy=%d "
+ "idmap=%p\n", data, size, cookie, asset, copyData, idmap));
if (copyData || notDeviceEndian) {
header->ownedData = malloc(size);
@@ -1836,7 +1935,16 @@
dtohl(header->header->packageCount));
return (mError=BAD_TYPE);
}
- if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) {
+ uint32_t idmap_id = 0;
+ if (idmap != NULL) {
+ uint32_t tmp;
+ if (getIdmapPackageId(header->resourceIDMap,
+ header->resourceIDMapSize,
+ &tmp) == NO_ERROR) {
+ idmap_id = tmp;
+ }
+ }
+ if (parsePackage((ResTable_package*)chunk, header, idmap_id) != NO_ERROR) {
return mError;
}
curPackage++;
@@ -1858,6 +1966,7 @@
if (mError != NO_ERROR) {
LOGW("No string values found in resource table!");
}
+
TABLE_NOISY(LOGV("Returning from add with mError=%d\n", mError));
return mError;
}
@@ -2002,17 +2111,38 @@
size_t ip = grp->packages.size();
while (ip > 0) {
ip--;
+ int T = t;
+ int E = e;
const Package* const package = grp->packages[ip];
+ if (package->header->resourceIDMap) {
+ uint32_t overlayResID = 0x0;
+ status_t retval = idmapLookup(package->header->resourceIDMap,
+ package->header->resourceIDMapSize,
+ resID, &overlayResID);
+ if (retval == NO_ERROR && overlayResID != 0x0) {
+ // for this loop iteration, this is the type and entry we really want
+ LOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID);
+ T = Res_GETTYPE(overlayResID);
+ E = Res_GETENTRY(overlayResID);
+ } else {
+ // resource not present in overlay package, continue with the next package
+ continue;
+ }
+ }
const ResTable_type* type;
const ResTable_entry* entry;
const Type* typeClass;
- ssize_t offset = getEntry(package, t, e, desiredConfig, &type, &entry, &typeClass);
+ ssize_t offset = getEntry(package, T, E, desiredConfig, &type, &entry, &typeClass);
if (offset <= 0) {
- if (offset < 0) {
+ // No {entry, appropriate config} pair found in package. If this
+ // package is an overlay package (ip != 0), this simply means the
+ // overlay package did not specify a default.
+ // Non-overlay packages are still required to provide a default.
+ if (offset < 0 && ip == 0) {
LOGW("Failure getting entry for 0x%08x (t=%d e=%d) in package %zd (error %d)\n",
- resID, t, e, ip, (int)offset);
+ resID, T, E, ip, (int)offset);
rc = offset;
goto out;
}
@@ -2044,13 +2174,16 @@
if (outSpecFlags != NULL) {
if (typeClass->typeSpecFlags != NULL) {
- *outSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
+ *outSpecFlags |= dtohl(typeClass->typeSpecFlags[E]);
} else {
*outSpecFlags = -1;
}
}
-
- if (bestPackage != NULL && bestItem.isMoreSpecificThan(thisConfig)) {
+
+ if (bestPackage != NULL &&
+ (bestItem.isMoreSpecificThan(thisConfig) || bestItem.diff(thisConfig) == 0)) {
+ // Discard thisConfig not only if bestItem is more specific, but also if the two configs
+ // are identical (diff == 0), or overlay packages will not take effect.
continue;
}
@@ -2250,21 +2383,45 @@
TABLE_NOISY(LOGI("Building bag: %p\n", (void*)resID));
+ ResTable_config bestConfig;
+ memset(&bestConfig, 0, sizeof(bestConfig));
+
// Now collect all bag attributes from all packages.
size_t ip = grp->packages.size();
while (ip > 0) {
ip--;
+ int T = t;
+ int E = e;
const Package* const package = grp->packages[ip];
+ if (package->header->resourceIDMap) {
+ uint32_t overlayResID = 0x0;
+ status_t retval = idmapLookup(package->header->resourceIDMap,
+ package->header->resourceIDMapSize,
+ resID, &overlayResID);
+ if (retval == NO_ERROR && overlayResID != 0x0) {
+ // for this loop iteration, this is the type and entry we really want
+ LOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID);
+ T = Res_GETTYPE(overlayResID);
+ E = Res_GETENTRY(overlayResID);
+ } else {
+ // resource not present in overlay package, continue with the next package
+ continue;
+ }
+ }
const ResTable_type* type;
const ResTable_entry* entry;
const Type* typeClass;
- LOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, t, e);
- ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass);
+ LOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, T, E);
+ ssize_t offset = getEntry(package, T, E, &mParams, &type, &entry, &typeClass);
LOGV("Resulting offset=%d\n", offset);
if (offset <= 0) {
- if (offset < 0) {
+ // No {entry, appropriate config} pair found in package. If this
+ // package is an overlay package (ip != 0), this simply means the
+ // overlay package did not specify a default.
+ // Non-overlay packages are still required to provide a default.
+ if (offset < 0 && ip == 0) {
if (set) free(set);
return offset;
}
@@ -2277,6 +2434,15 @@
continue;
}
+ if (set != NULL && !type->config.isBetterThan(bestConfig, NULL)) {
+ continue;
+ }
+ bestConfig = type->config;
+ if (set) {
+ free(set);
+ set = NULL;
+ }
+
const uint16_t entrySize = dtohs(entry->size);
const uint32_t parent = entrySize >= sizeof(ResTable_map_entry)
? dtohl(((const ResTable_map_entry*)entry)->parent.ident) : 0;
@@ -2288,43 +2454,41 @@
TABLE_NOISY(LOGI("Found map: size=%p parent=%p count=%d\n",
entrySize, parent, count));
- if (set == NULL) {
- // If this map inherits from another, we need to start
- // with its parent's values. Otherwise start out empty.
- TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
- entrySize, parent));
- if (parent) {
- const bag_entry* parentBag;
- uint32_t parentTypeSpecFlags = 0;
- const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags);
- const size_t NT = ((NP >= 0) ? NP : 0) + N;
- set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
- if (set == NULL) {
- return NO_MEMORY;
- }
- if (NP > 0) {
- memcpy(set+1, parentBag, NP*sizeof(bag_entry));
- set->numAttrs = NP;
- TABLE_NOISY(LOGI("Initialized new bag with %d inherited attributes.\n", NP));
- } else {
- TABLE_NOISY(LOGI("Initialized new bag with no inherited attributes.\n"));
- set->numAttrs = 0;
- }
- set->availAttrs = NT;
- set->typeSpecFlags = parentTypeSpecFlags;
- } else {
- set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
- if (set == NULL) {
- return NO_MEMORY;
- }
- set->numAttrs = 0;
- set->availAttrs = N;
- set->typeSpecFlags = 0;
+ // If this map inherits from another, we need to start
+ // with its parent's values. Otherwise start out empty.
+ TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
+ entrySize, parent));
+ if (parent) {
+ const bag_entry* parentBag;
+ uint32_t parentTypeSpecFlags = 0;
+ const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags);
+ const size_t NT = ((NP >= 0) ? NP : 0) + N;
+ set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
+ if (set == NULL) {
+ return NO_MEMORY;
}
+ if (NP > 0) {
+ memcpy(set+1, parentBag, NP*sizeof(bag_entry));
+ set->numAttrs = NP;
+ TABLE_NOISY(LOGI("Initialized new bag with %d inherited attributes.\n", NP));
+ } else {
+ TABLE_NOISY(LOGI("Initialized new bag with no inherited attributes.\n"));
+ set->numAttrs = 0;
+ }
+ set->availAttrs = NT;
+ set->typeSpecFlags = parentTypeSpecFlags;
+ } else {
+ set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
+ if (set == NULL) {
+ return NO_MEMORY;
+ }
+ set->numAttrs = 0;
+ set->availAttrs = N;
+ set->typeSpecFlags = 0;
}
if (typeClass->typeSpecFlags != NULL) {
- set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
+ set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[E]);
} else {
set->typeSpecFlags = -1;
}
@@ -3870,7 +4034,7 @@
}
status_t ResTable::parsePackage(const ResTable_package* const pkg,
- const Header* const header)
+ const Header* const header, uint32_t idmap_id)
{
const uint8_t* base = (const uint8_t*)pkg;
status_t err = validate_chunk(&pkg->header, sizeof(*pkg),
@@ -3904,8 +4068,12 @@
Package* package = NULL;
PackageGroup* group = NULL;
- uint32_t id = dtohl(pkg->id);
- if (id != 0 && id < 256) {
+ uint32_t id = idmap_id != 0 ? idmap_id : dtohl(pkg->id);
+ // If at this point id == 0, pkg is an overlay package without a
+ // corresponding idmap. During regular usage, overlay packages are
+ // always loaded alongside their idmaps, but during idmap creation
+ // the package is temporarily loaded by itself.
+ if (id < 256) {
package = new Package(this, header, pkg);
if (package == NULL) {
@@ -3958,7 +4126,7 @@
return (mError=err);
}
} else {
- LOG_ALWAYS_FATAL("Skins not supported!");
+ LOG_ALWAYS_FATAL("Package id out of range");
return NO_ERROR;
}
@@ -4112,6 +4280,136 @@
return NO_ERROR;
}
+status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, uint32_t overlayCrc,
+ void** outData, size_t* outSize) const
+{
+ // see README for details on the format of map
+ if (mPackageGroups.size() == 0) {
+ return UNKNOWN_ERROR;
+ }
+ if (mPackageGroups[0]->packages.size() == 0) {
+ return UNKNOWN_ERROR;
+ }
+
+ Vector<Vector<uint32_t> > map;
+ const PackageGroup* pg = mPackageGroups[0];
+ const Package* pkg = pg->packages[0];
+ size_t typeCount = pkg->types.size();
+ // starting size is header + first item (number of types in map)
+ *outSize = (IDMAP_HEADER_SIZE + 1) * sizeof(uint32_t);
+ const String16 overlayPackage(overlay.mPackageGroups[0]->packages[0]->package->name);
+ const uint32_t pkg_id = pkg->package->id << 24;
+
+ for (size_t typeIndex = 0; typeIndex < typeCount; ++typeIndex) {
+ ssize_t offset = -1;
+ const Type* typeConfigs = pkg->getType(typeIndex);
+ ssize_t mapIndex = map.add();
+ if (mapIndex < 0) {
+ return NO_MEMORY;
+ }
+ Vector<uint32_t>& vector = map.editItemAt(mapIndex);
+ for (size_t entryIndex = 0; entryIndex < typeConfigs->entryCount; ++entryIndex) {
+ uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
+ | (0x00ff0000 & ((typeIndex+1)<<16))
+ | (0x0000ffff & (entryIndex));
+ resource_name resName;
+ if (!this->getResourceName(resID, &resName)) {
+ return UNKNOWN_ERROR;
+ }
+
+ const String16 overlayType(resName.type, resName.typeLen);
+ const String16 overlayName(resName.name, resName.nameLen);
+ uint32_t overlayResID = overlay.identifierForName(overlayName.string(),
+ overlayName.size(),
+ overlayType.string(),
+ overlayType.size(),
+ overlayPackage.string(),
+ overlayPackage.size());
+ if (overlayResID != 0) {
+ // overlay package has package ID == 0, use original package's ID instead
+ overlayResID |= pkg_id;
+ }
+ vector.push(overlayResID);
+ if (overlayResID != 0 && offset == -1) {
+ offset = Res_GETENTRY(resID);
+ }
+#if 0
+ if (overlayResID != 0) {
+ LOGD("%s/%s 0x%08x -> 0x%08x\n",
+ String8(String16(resName.type)).string(),
+ String8(String16(resName.name)).string(),
+ resID, overlayResID);
+ }
+#endif
+ }
+
+ if (offset != -1) {
+ // shave off leading and trailing entries which lack overlay values
+ vector.removeItemsAt(0, offset);
+ vector.insertAt((uint32_t)offset, 0, 1);
+ while (vector.top() == 0) {
+ vector.pop();
+ }
+ // reserve space for number and offset of entries, and the actual entries
+ *outSize += (2 + vector.size()) * sizeof(uint32_t);
+ } else {
+ // no entries of current type defined in overlay package
+ vector.clear();
+ // reserve space for type offset
+ *outSize += 1 * sizeof(uint32_t);
+ }
+ }
+
+ if ((*outData = malloc(*outSize)) == NULL) {
+ return NO_MEMORY;
+ }
+ uint32_t* data = (uint32_t*)*outData;
+ *data++ = htodl(IDMAP_MAGIC);
+ *data++ = htodl(originalCrc);
+ *data++ = htodl(overlayCrc);
+ const size_t mapSize = map.size();
+ *data++ = htodl(mapSize);
+ size_t offset = mapSize;
+ for (size_t i = 0; i < mapSize; ++i) {
+ const Vector<uint32_t>& vector = map.itemAt(i);
+ const size_t N = vector.size();
+ if (N == 0) {
+ *data++ = htodl(0);
+ } else {
+ offset++;
+ *data++ = htodl(offset);
+ offset += N;
+ }
+ }
+ for (size_t i = 0; i < mapSize; ++i) {
+ const Vector<uint32_t>& vector = map.itemAt(i);
+ const size_t N = vector.size();
+ if (N == 0) {
+ continue;
+ }
+ *data++ = htodl(N - 1); // do not count the offset (which is vector's first element)
+ for (size_t j = 0; j < N; ++j) {
+ const uint32_t& overlayResID = vector.itemAt(j);
+ *data++ = htodl(overlayResID);
+ }
+ }
+
+ return NO_ERROR;
+}
+
+bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes,
+ uint32_t* pOriginalCrc, uint32_t* pOverlayCrc)
+{
+ const uint32_t* map = (const uint32_t*)idmap;
+ if (!assertIdmapHeader(map, sizeBytes)) {
+ return false;
+ }
+ *pOriginalCrc = map[1];
+ *pOverlayCrc = map[2];
+ return true;
+}
+
+
#ifndef HAVE_ANDROID_OS
#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 7d72729..0747efb 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -13,8 +13,8 @@
EGL/hooks.cpp \
EGL/Loader.cpp \
#
-LOCAL_STATIC_LIBRARIES += libGLESv2_dbg libprotobuf-cpp-2.3.0-lite liblzf
-LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport
+
+LOCAL_SHARED_LIBRARIES += libcutils libutils libGLESv2_dbg
LOCAL_LDLIBS := -lpthread -ldl
LOCAL_MODULE:= libEGL
LOCAL_LDFLAGS += -Wl,--exclude-libs=ALL
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 6474c87..9cf7223 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -46,6 +46,7 @@
#include "egl_impl.h"
#include "Loader.h"
#include "glesv2dbg.h"
+#include "egl_tls.h"
#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
@@ -58,7 +59,7 @@
static char const * const gVendorString = "Android";
static char const * const gVersionString = "1.4 Android META-EGL";
static char const * const gClientApiString = "OpenGL ES";
-static char const * const gExtensionString =
+static char const * const gExtensionString =
"EGL_KHR_image "
"EGL_KHR_image_base "
"EGL_KHR_image_pixmap "
@@ -221,18 +222,15 @@
struct egl_context_t : public egl_object_t
{
typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
-
+
egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
- int impl, egl_connection_t const* cnx, int version)
- : egl_object_t(dpy), dpy(dpy), context(context), config(config), read(0), draw(0),
- impl(impl), cnx(cnx), version(version), dbg(NULL)
+ int impl, egl_connection_t const* cnx, int version)
+ : egl_object_t(dpy), dpy(dpy), context(context), config(config), read(0), draw(0),
+ impl(impl), cnx(cnx), version(version)
{
}
~egl_context_t()
{
- if (dbg)
- DestroyDbgContext(dbg);
- dbg = NULL;
}
EGLDisplay dpy;
EGLContext context;
@@ -242,7 +240,6 @@
int impl;
egl_connection_t const* cnx;
int version;
- DbgContext * dbg;
};
struct egl_image_t : public egl_object_t
@@ -277,15 +274,6 @@
typedef egl_image_t::Ref ImageRef;
typedef egl_sync_t::Ref SyncRef;
-struct tls_t
-{
- tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { }
- EGLint error;
- EGLContext ctx;
- EGLBoolean logCallWithNoContext;
-};
-
-
// ----------------------------------------------------------------------------
static egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
@@ -323,7 +311,7 @@
int propertyLevel = atoi(value);
int applicationLevel = gEGLApplicationTraceLevel;
gEGLTraceLevel = propertyLevel > applicationLevel ? propertyLevel : applicationLevel;
-
+
property_get("debug.egl.debug_proc", value, "");
long pid = getpid();
char procPath[128] = {};
@@ -336,14 +324,20 @@
{
if (!strcmp(value, cmdline))
gEGLDebugLevel = 1;
- }
+ }
fclose(file);
}
-
+
if (gEGLDebugLevel > 0)
{
property_get("debug.egl.debug_port", value, "5039");
- StartDebugServer(atoi(value));
+ const unsigned short port = (unsigned short)atoi(value);
+ property_get("debug.egl.debug_forceUseFile", value, "0");
+ const bool forceUseFile = (bool)atoi(value);
+ property_get("debug.egl.debug_maxFileSize", value, "8");
+ const unsigned int maxFileSize = atoi(value) << 20;
+ property_get("debug.egl.debug_filePath", value, "/data/local/tmp/dump.gles2dbg");
+ StartDebugServer(port, forceUseFile, maxFileSize, value);
}
}
@@ -586,7 +580,7 @@
}
static inline
-egl_surface_t* get_surface(EGLSurface surface) {
+egl_surface_t* get_surface(EGLSurface surface) {
return egl_to_native_cast<egl_surface_t>(surface);
}
@@ -595,11 +589,6 @@
return egl_to_native_cast<egl_context_t>(context);
}
-DbgContext * getDbgContextThreadSpecific()
-{
- return get_context(getContext())->dbg;
-}
-
static inline
egl_image_t* get_image(EGLImageKHR image) {
return egl_to_native_cast<egl_image_t>(image);
@@ -1442,10 +1431,12 @@
loseCurrent(cur_c);
if (ctx != EGL_NO_CONTEXT) {
- if (!c->dbg && gEGLDebugLevel > 0)
- c->dbg = CreateDbgContext(c->version, c->cnx->hooks[c->version]);
setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
setContext(ctx);
+ tls_t * const tls = getTLS();
+ if (!tls->dbg && gEGLDebugLevel > 0)
+ tls->dbg = CreateDbgContext(gEGLThreadLocalStorageKey, c->version,
+ c->cnx->hooks[c->version]);
_c.acquire();
_r.acquire();
_d.acquire();
diff --git a/opengl/libs/GLES2_dbg/Android.mk b/opengl/libs/GLES2_dbg/Android.mk
index fc40799..9f6e68c 100644
--- a/opengl/libs/GLES2_dbg/Android.mk
+++ b/opengl/libs/GLES2_dbg/Android.mk
@@ -11,7 +11,7 @@
src/server.cpp \
src/vertex.cpp
-LOCAL_C_INCLUDES := \
+LOCAL_C_INCLUDES := \
$(LOCAL_PATH) \
$(LOCAL_PATH)/../ \
external/stlport/stlport \
@@ -21,7 +21,8 @@
#LOCAL_CFLAGS += -O0 -g -DDEBUG -UNDEBUG
LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI
-
+LOCAL_STATIC_LIBRARIES := libprotobuf-cpp-2.3.0-lite liblzf
+LOCAL_SHARED_LIBRARIES := libcutils libutils libstlport
ifeq ($(TARGET_ARCH),arm)
LOCAL_CFLAGS += -fstrict-aliasing
endif
@@ -43,4 +44,6 @@
LOCAL_MODULE:= libGLESv2_dbg
LOCAL_MODULE_TAGS := optional
-include $(BUILD_STATIC_LIBRARY)
+include $(BUILD_SHARED_LIBRARY)
+
+include $(LOCAL_PATH)/test/Android.mk
diff --git a/opengl/libs/GLES2_dbg/generate_api_cpp.py b/opengl/libs/GLES2_dbg/generate_api_cpp.py
index 66c110f..96cde57 100755
--- a/opengl/libs/GLES2_dbg/generate_api_cpp.py
+++ b/opengl/libs/GLES2_dbg/generate_api_cpp.py
@@ -26,36 +26,36 @@
return line.replace(annotation, "*")
else:
return line
-
+
def generate_api(lines):
externs = []
i = 0
# these have been hand written
- skipFunctions = ["glReadPixels", "glDrawArrays", "glDrawElements"]
-
+ skipFunctions = ["glDrawArrays", "glDrawElements"]
+
# these have an EXTEND_Debug_* macro for getting data
- extendFunctions = ["glCopyTexImage2D", "glCopyTexSubImage2D", "glShaderSource",
-"glTexImage2D", "glTexSubImage2D"]
-
+ extendFunctions = ["glCopyTexImage2D", "glCopyTexSubImage2D", "glReadPixels",
+"glShaderSource", "glTexImage2D", "glTexSubImage2D"]
+
# these also needs to be forwarded to DbgContext
- contextFunctions = ["glUseProgram", "glEnableVertexAttribArray", "glDisableVertexAttribArray",
+ contextFunctions = ["glUseProgram", "glEnableVertexAttribArray", "glDisableVertexAttribArray",
"glVertexAttribPointer", "glBindBuffer", "glBufferData", "glBufferSubData", "glDeleteBuffers",]
-
+
for line in lines:
if line.find("API_ENTRY(") >= 0: # a function prototype
returnType = line[0: line.find(" API_ENTRY(")]
functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name
parameterList = line[line.find(")(") + 2: line.find(") {")]
-
+
#if line.find("*") >= 0:
# extern = "%s Debug_%s(%s);" % (returnType, functionName, parameterList)
# externs.append(extern)
# continue
-
+
if functionName in skipFunctions:
sys.stderr.write("!\n! skipping function '%s'\n!\n" % (functionName))
continue
-
+
parameters = parameterList.split(',')
paramIndex = 0
if line.find("*") >= 0 and (line.find("*") < line.find(":") or line.find("*") > line.rfind(":")): # unannotated pointer
@@ -65,21 +65,21 @@
sys.stderr.write("%s should be hand written\n" % (extern))
print "// FIXME: this function has pointers, it should be hand written"
externs.append(extern)
-
+
print "%s Debug_%s(%s)\n{" % (returnType, functionName, RemoveAnnotation(parameterList))
print " glesv2debugger::Message msg;"
-
+
if parameterList == "void":
parameters = []
arguments = ""
paramNames = []
inout = ""
getData = ""
-
+
callerMembers = ""
setCallerMembers = ""
setMsgParameters = ""
-
+
for parameter in parameters:
const = parameter.find("const")
parameter = parameter.replace("const", "")
@@ -107,17 +107,17 @@
annotation = "strlen(%s)" % (paramName)
else:
count = int(annotation)
-
+
setMsgParameters += " msg.set_arg%d(ToInt(%s));\n" % (paramIndex, paramName)
if paramType.find("void") >= 0:
getData += " msg.mutable_data()->assign(reinterpret_cast<const char *>(%s), %s * sizeof(char));" % (paramName, annotation)
else:
getData += " msg.mutable_data()->assign(reinterpret_cast<const char *>(%s), %s * sizeof(%s));" % (paramName, annotation, paramType)
paramType += "*"
- else:
+ else:
if paramType == "GLfloat" or paramType == "GLclampf" or paramType.find("*") >= 0:
setMsgParameters += " msg.set_arg%d(ToInt(%s));\n" % (paramIndex, paramName)
- else:
+ else:
setMsgParameters += " msg.set_arg%d(%s);\n" % (paramIndex, paramName)
if paramIndex < len(parameters) - 1:
arguments += ', '
@@ -127,7 +127,7 @@
paramIndex += 1
callerMembers += " %s %s;\n" % (paramType, paramName)
setCallerMembers += " caller.%s = %s;\n" % (paramName, paramName)
-
+
print " struct : public FunctionCall {"
print callerMembers
print " const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {"
@@ -141,6 +141,11 @@
if inout in ["out", "inout"]:
print " msg.set_time((systemTime(timeMode) - c0) * 1e-6f);"
print " " + getData
+ if functionName in extendFunctions:
+ print "\
+#ifdef EXTEND_AFTER_CALL_Debug_%s\n\
+ EXTEND_AFTER_CALL_Debug_%s;\n\
+#endif" % (functionName, functionName)
if functionName in contextFunctions:
print " getDbgContextThreadSpecific()->%s(%s);" % (functionName, arguments)
if returnType == "void":
@@ -151,13 +156,16 @@
} caller;"""
print setCallerMembers
print setMsgParameters
-
+
if line.find("*") >= 0 or line.find(":") >= 0:
print " // FIXME: check for pointer usage"
if inout in ["in", "inout"]:
print getData
if functionName in extendFunctions:
- print " EXTEND_Debug_%s;" % (functionName)
+ print "\
+#ifdef EXTEND_Debug_%s\n\
+ EXTEND_Debug_%s;\n\
+#endif" % (functionName, functionName)
print " int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_%s);"\
% (functionName)
if returnType != "void":
@@ -166,8 +174,8 @@
else:
print " return reinterpret_cast<%s>(ret);" % (returnType)
print "}\n"
-
-
+
+
print "// FIXME: the following functions should be written by hand"
for extern in externs:
print extern
@@ -189,18 +197,23 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-
+
// auto generated by generate_api_cpp.py
+#include <utils/Debug.h>
+
#include "src/header.h"
#include "src/api.h"
-template<typename T> static int ToInt(const T & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (int &)t; }
-template<typename T> static T FromInt(const int & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (T &)t; }
-"""
+template<typename T> static int ToInt(const T & t)
+{
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(sizeof(T) == sizeof(int));
+ return (int &)t;
+}
+"""
lines = open("gl2_api_annotated.in").readlines()
generate_api(lines)
#lines = open("gl2ext_api.in").readlines()
#generate_api(lines)
-
+
diff --git a/opengl/libs/GLES2_dbg/generate_caller_cpp.py b/opengl/libs/GLES2_dbg/generate_caller_cpp.py
index eac2292..ee4208d 100755
--- a/opengl/libs/GLES2_dbg/generate_caller_cpp.py
+++ b/opengl/libs/GLES2_dbg/generate_caller_cpp.py
@@ -177,7 +177,6 @@
{
LOGD("GenerateCall function=%u", cmd.function());
const int * ret = prevRet; // only some functions have return value
- gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;
nsecs_t c0 = systemTime(timeMode);
switch (cmd.function()) {""")
diff --git a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
index 466c447..535b13e 100755
--- a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
+++ b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
@@ -25,7 +25,7 @@
line = line.split(",")[1].strip() #extract EGL function name
output.write(" %s = %d;\n" % (line, i))
i += 1
- return i
+ return i
def generate_gl_entries(output,lines,i):
@@ -70,41 +70,43 @@
""")
i = 0;
-
+
lines = open("gl2_api_annotated.in").readlines()
i = generate_gl_entries(output, lines, i)
output.write(" // end of GL functions\n")
-
+
#lines = open("gl2ext_api.in").readlines()
#i = generate_gl_entries(output, lines, i)
#output.write(" // end of GL EXT functions\n")
-
+
lines = open("../EGL/egl_entries.in").readlines()
i = generate_egl_entries(output, lines, i)
output.write(" // end of GL EXT functions\n")
-
+
output.write(" ACK = %d;\n" % (i))
i += 1
-
+
output.write(" NEG = %d;\n" % (i))
i += 1
-
+
output.write(" CONTINUE = %d;\n" % (i))
i += 1
-
+
output.write(" SKIP = %d;\n" % (i))
i += 1
-
+
output.write(" SETPROP = %d;\n" % (i))
i += 1
-
+
output.write(""" }
required Function function = 2 [default = NEG]; // type/function of message
enum Type
{
BeforeCall = 0;
AfterCall = 1;
- Response = 2; // currently used for misc messages
+ AfterGeneratedCall = 2;
+ Response = 3; // currently used for misc messages
+ CompleteCall = 4; // BeforeCall and AfterCall merged
}
required Type type = 3;
required bool expect_response = 4;
@@ -116,7 +118,7 @@
optional int32 arg4 = 16;
optional int32 arg5 = 17;
optional int32 arg6 = 18;
- optional int32 arg7 = 19;
+ optional int32 arg7 = 19; // glDrawArrays/Elements sets this to active number of attributes
optional int32 arg8 = 20;
optional bytes data = 10; // variable length data used for GL call
@@ -125,16 +127,22 @@
ReferencedImage = 0; // for image sourced from ReadPixels
NonreferencedImage = 1; // for image sourced from ReadPixels
};
- optional DataType data_type = 23; // most data types can be inferred from function
- optional int32 pixel_format = 24; // used for image data if format and type
- optional int32 pixel_type = 25; // cannot be determined from arg
-
+ // most data types can be inferred from function
+ optional DataType data_type = 23;
+ // these are used for image data when they cannot be determined from args
+ optional int32 pixel_format = 24;
+ optional int32 pixel_type = 25;
+ optional int32 image_width = 26;
+ optional int32 image_height = 27;
+
optional float time = 11; // duration of previous GL call (ms)
enum Prop
{
- Capture = 0; // arg0 = true | false
+ CaptureDraw = 0; // arg0 = number of glDrawArrays/Elements to glReadPixels
TimeMode = 1; // arg0 = SYSTEM_TIME_* in utils/Timers.h
ExpectResponse = 2; // arg0 = enum Function, arg1 = true/false
+ CaptureSwap = 3; // arg0 = number of eglSwapBuffers to glReadPixels
+ GLConstant = 4; // arg0 = GLenum, arg1 = constant; send GL impl. constants
};
optional Prop prop = 21; // used with SETPROP, value in arg0
optional float clock = 22; // wall clock in seconds
@@ -142,6 +150,6 @@
""")
output.close()
-
+
os.system("aprotoc --cpp_out=src --java_out=../../../../../development/tools/glesv2debugger/src debugger_message.proto")
os.system('mv -f "src/debugger_message.pb.cc" "src/debugger_message.pb.cpp"')
diff --git a/opengl/libs/GLES2_dbg/src/api.cpp b/opengl/libs/GLES2_dbg/src/api.cpp
index 130ca7e..c483547 100644
--- a/opengl/libs/GLES2_dbg/src/api.cpp
+++ b/opengl/libs/GLES2_dbg/src/api.cpp
@@ -16,11 +16,16 @@
// auto generated by generate_api_cpp.py
+#include <utils/Debug.h>
+
#include "src/header.h"
#include "src/api.h"
-template<typename T> static int ToInt(const T & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (int &)t; }
-template<typename T> static T FromInt(const int & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (T &)t; }
+template<typename T> static int ToInt(const T & t)
+{
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(sizeof(T) == sizeof(int));
+ return (int &)t;
+}
void Debug_glActiveTexture(GLenum texture)
{
@@ -592,6 +597,9 @@
const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
_c->glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
+#ifdef EXTEND_AFTER_CALL_Debug_glCopyTexImage2D
+ EXTEND_AFTER_CALL_Debug_glCopyTexImage2D;
+#endif
return 0;
}
} caller;
@@ -613,7 +621,9 @@
msg.set_arg6(height);
msg.set_arg7(border);
+#ifdef EXTEND_Debug_glCopyTexImage2D
EXTEND_Debug_glCopyTexImage2D;
+#endif
int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCopyTexImage2D);
}
@@ -632,6 +642,9 @@
const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
_c->glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+#ifdef EXTEND_AFTER_CALL_Debug_glCopyTexSubImage2D
+ EXTEND_AFTER_CALL_Debug_glCopyTexSubImage2D;
+#endif
return 0;
}
} caller;
@@ -653,7 +666,9 @@
msg.set_arg6(width);
msg.set_arg7(height);
+#ifdef EXTEND_Debug_glCopyTexSubImage2D
EXTEND_Debug_glCopyTexSubImage2D;
+#endif
int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCopyTexSubImage2D);
}
@@ -2164,6 +2179,49 @@
int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glPolygonOffset);
}
+void Debug_glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
+{
+ glesv2debugger::Message msg;
+ struct : public FunctionCall {
+ GLint x;
+ GLint y;
+ GLsizei width;
+ GLsizei height;
+ GLenum format;
+ GLenum type;
+ GLvoid* pixels;
+
+ const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+ _c->glReadPixels(x, y, width, height, format, type, pixels);
+#ifdef EXTEND_AFTER_CALL_Debug_glReadPixels
+ EXTEND_AFTER_CALL_Debug_glReadPixels;
+#endif
+ return 0;
+ }
+ } caller;
+ caller.x = x;
+ caller.y = y;
+ caller.width = width;
+ caller.height = height;
+ caller.format = format;
+ caller.type = type;
+ caller.pixels = pixels;
+
+ msg.set_arg0(x);
+ msg.set_arg1(y);
+ msg.set_arg2(width);
+ msg.set_arg3(height);
+ msg.set_arg4(format);
+ msg.set_arg5(type);
+ msg.set_arg6(ToInt(pixels));
+
+ // FIXME: check for pointer usage
+#ifdef EXTEND_Debug_glReadPixels
+ EXTEND_Debug_glReadPixels;
+#endif
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glReadPixels);
+}
+
void Debug_glReleaseShaderCompiler(void)
{
glesv2debugger::Message msg;
@@ -2297,6 +2355,9 @@
const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
_c->glShaderSource(shader, count, string, length);
+#ifdef EXTEND_AFTER_CALL_Debug_glShaderSource
+ EXTEND_AFTER_CALL_Debug_glShaderSource;
+#endif
return 0;
}
} caller;
@@ -2311,7 +2372,9 @@
msg.set_arg3(ToInt(length));
// FIXME: check for pointer usage
+#ifdef EXTEND_Debug_glShaderSource
EXTEND_Debug_glShaderSource;
+#endif
int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glShaderSource);
}
@@ -2472,6 +2535,9 @@
const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
_c->glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
+#ifdef EXTEND_AFTER_CALL_Debug_glTexImage2D
+ EXTEND_AFTER_CALL_Debug_glTexImage2D;
+#endif
return 0;
}
} caller;
@@ -2496,7 +2562,9 @@
msg.set_arg8(ToInt(pixels));
// FIXME: check for pointer usage
+#ifdef EXTEND_Debug_glTexImage2D
EXTEND_Debug_glTexImage2D;
+#endif
int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexImage2D);
}
@@ -2616,6 +2684,9 @@
const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
_c->glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
+#ifdef EXTEND_AFTER_CALL_Debug_glTexSubImage2D
+ EXTEND_AFTER_CALL_Debug_glTexSubImage2D;
+#endif
return 0;
}
} caller;
@@ -2640,7 +2711,9 @@
msg.set_arg8(ToInt(pixels));
// FIXME: check for pointer usage
+#ifdef EXTEND_Debug_glTexSubImage2D
EXTEND_Debug_glTexSubImage2D;
+#endif
int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexSubImage2D);
}
diff --git a/opengl/libs/GLES2_dbg/src/api.h b/opengl/libs/GLES2_dbg/src/api.h
index b9fc341..0b227bc 100644
--- a/opengl/libs/GLES2_dbg/src/api.h
+++ b/opengl/libs/GLES2_dbg/src/api.h
@@ -16,19 +16,29 @@
#define EXTEND_Debug_glCopyTexImage2D \
DbgContext * const dbg = getDbgContextThreadSpecific(); \
- GLint readFormat, readType; \
- dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat); \
- dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType); \
- unsigned readSize = GetBytesPerPixel(readFormat, readType) * width * height; \
- void * readData = dbg->GetReadPixelsBuffer(readSize); \
- dbg->hooks->gl.glReadPixels(x, y, width, height, readFormat, readType, readData); \
+ void * readData = dbg->GetReadPixelsBuffer(4 * width * height); \
+ /* pick easy format for client to convert */ \
+ dbg->hooks->gl.glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, readData); \
dbg->CompressReadPixelBuffer(msg.mutable_data()); \
msg.set_data_type(msg.ReferencedImage); \
- msg.set_pixel_format(readFormat); \
- msg.set_pixel_type(readType);
+ msg.set_pixel_format(GL_RGBA); \
+ msg.set_pixel_type(GL_UNSIGNED_BYTE);
#define EXTEND_Debug_glCopyTexSubImage2D EXTEND_Debug_glCopyTexImage2D
+#define EXTEND_AFTER_CALL_Debug_glReadPixels \
+ { \
+ DbgContext * const dbg = getDbgContextThreadSpecific(); \
+ if (dbg->IsReadPixelBuffer(pixels)) { \
+ dbg->CompressReadPixelBuffer(msg.mutable_data()); \
+ msg.set_data_type(msg.ReferencedImage); \
+ } else { \
+ const unsigned int size = width * height * GetBytesPerPixel(format, type); \
+ dbg->Compress(pixels, size, msg.mutable_data()); \
+ msg.set_data_type(msg.NonreferencedImage); \
+ } \
+ }
+
#define EXTEND_Debug_glShaderSource \
std::string * const data = msg.mutable_data(); \
for (unsigned i = 0; i < count; i++) \
diff --git a/opengl/libs/GLES2_dbg/src/caller.cpp b/opengl/libs/GLES2_dbg/src/caller.cpp
index 9992f05..6b72751 100644
--- a/opengl/libs/GLES2_dbg/src/caller.cpp
+++ b/opengl/libs/GLES2_dbg/src/caller.cpp
@@ -105,7 +105,6 @@
{
LOGD("GenerateCall function=%u", cmd.function());
const int * ret = prevRet; // only some functions have return value
- gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;
nsecs_t c0 = systemTime(timeMode);
switch (cmd.function()) { case glesv2debugger::Message_Function_glActiveTexture:
dbg->hooks->gl.glActiveTexture(
@@ -772,7 +771,7 @@
msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
msg.set_context_id(reinterpret_cast<int>(dbg));
msg.set_function(cmd.function());
- msg.set_type(glesv2debugger::Message_Type_AfterCall);
+ msg.set_type(glesv2debugger::Message_Type_AfterGeneratedCall);
return ret;
}
diff --git a/opengl/libs/GLES2_dbg/src/caller.h b/opengl/libs/GLES2_dbg/src/caller.h
index 5447757..e8111b3 100644
--- a/opengl/libs/GLES2_dbg/src/caller.h
+++ b/opengl/libs/GLES2_dbg/src/caller.h
@@ -138,7 +138,9 @@
const glesv2debugger::Message & cmd,
glesv2debugger::Message & msg, const int * const prevRet)
{
- assert(0);
+ GLint params = -1;
+ dbg->hooks->gl.glGetProgramiv(cmd.arg0(), cmd.arg1(), ¶ms);
+ msg.mutable_data()->append(reinterpret_cast<char *>(¶ms), sizeof(params));
return prevRet;
}
@@ -146,7 +148,10 @@
const glesv2debugger::Message & cmd,
glesv2debugger::Message & msg, const int * const prevRet)
{
- assert(0);
+ const GLsizei bufSize = static_cast<GLsizei>(dbg->GetBufferSize());
+ GLsizei length = -1;
+ dbg->hooks->gl.glGetProgramInfoLog(cmd.arg0(), bufSize, &length, dbg->GetBuffer());
+ msg.mutable_data()->append(dbg->GetBuffer(), length);
return prevRet;
}
@@ -162,7 +167,9 @@
const glesv2debugger::Message & cmd,
glesv2debugger::Message & msg, const int * const prevRet)
{
- assert(0);
+ GLint params = -1;
+ dbg->hooks->gl.glGetShaderiv(cmd.arg0(), cmd.arg1(), ¶ms);
+ msg.mutable_data()->append(reinterpret_cast<char *>(¶ms), sizeof(params));
return prevRet;
}
@@ -170,7 +177,10 @@
const glesv2debugger::Message & cmd,
glesv2debugger::Message & msg, const int * const prevRet)
{
- assert(0);
+ const GLsizei bufSize = static_cast<GLsizei>(dbg->GetBufferSize());
+ GLsizei length = -1;
+ dbg->hooks->gl.glGetShaderInfoLog(cmd.arg0(), bufSize, &length, dbg->GetBuffer());
+ msg.mutable_data()->append(dbg->GetBuffer(), length);
return prevRet;
}
diff --git a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
index cc7336c..7f5b27b 100644
--- a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
+++ b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
@@ -15,6 +15,7 @@
*/
#include "header.h"
+#include "egl_tls.h"
extern "C"
{
@@ -24,11 +25,23 @@
namespace android
{
+pthread_key_t dbgEGLThreadLocalStorageKey = -1;
+
+DbgContext * getDbgContextThreadSpecific()
+{
+ tls_t* tls = (tls_t*)pthread_getspecific(dbgEGLThreadLocalStorageKey);
+ return tls->dbg;
+}
+
DbgContext::DbgContext(const unsigned version, const gl_hooks_t * const hooks,
- const unsigned MAX_VERTEX_ATTRIBS)
+ const unsigned MAX_VERTEX_ATTRIBS, const GLenum readFormat,
+ const GLenum readType)
: lzf_buf(NULL), lzf_readIndex(0), lzf_refSize(0), lzf_refBufSize(0)
, version(version), hooks(hooks)
, MAX_VERTEX_ATTRIBS(MAX_VERTEX_ATTRIBS)
+ , readFormat(readFormat), readType(readType)
+ , readBytesPerPixel(GetBytesPerPixel(readFormat, readType))
+ , captureSwap(0), captureDraw(0)
, vertexAttribs(new VertexAttrib[MAX_VERTEX_ATTRIBS])
, hasNonVBOAttribs(false), indexBuffers(NULL), indexBuffer(NULL)
, program(0), maxAttrib(0)
@@ -47,13 +60,35 @@
free(lzf_ref[1]);
}
-DbgContext * CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks)
+DbgContext * CreateDbgContext(const pthread_key_t EGLThreadLocalStorageKey,
+ const unsigned version, const gl_hooks_t * const hooks)
{
+ dbgEGLThreadLocalStorageKey = EGLThreadLocalStorageKey;
assert(version < 2);
assert(GL_NO_ERROR == hooks->gl.glGetError());
GLint MAX_VERTEX_ATTRIBS = 0;
hooks->gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &MAX_VERTEX_ATTRIBS);
- return new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS);
+ GLint readFormat, readType;
+ hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat);
+ hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);
+ DbgContext * const dbg = new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS, readFormat, readType);
+
+ glesv2debugger::Message msg, cmd;
+ msg.set_context_id(reinterpret_cast<int>(dbg));
+ msg.set_expect_response(false);
+ msg.set_type(msg.Response);
+ msg.set_function(msg.SETPROP);
+ msg.set_prop(msg.GLConstant);
+ msg.set_arg0(GL_MAX_VERTEX_ATTRIBS);
+ msg.set_arg1(MAX_VERTEX_ATTRIBS);
+ Send(msg, cmd);
+
+ GLint MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0;
+ hooks->gl.glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+ msg.set_arg0(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+ msg.set_arg1(MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+ Send(msg, cmd);
+ return dbg;
}
void DestroyDbgContext(DbgContext * const dbg)
@@ -113,6 +148,7 @@
{
if (!lzf_buf)
lzf_buf = (char *)malloc(LZF_CHUNK_SIZE);
+ assert(lzf_buf);
const uint32_t totalDecompSize = in_len;
outStr->append((const char *)&totalDecompSize, sizeof(totalDecompSize));
for (unsigned int i = 0; i < in_len; i += LZF_CHUNK_SIZE) {
@@ -130,13 +166,46 @@
}
}
+unsigned char * DbgContext::Decompress(const void * in, const unsigned int inLen,
+ unsigned int * const outLen)
+{
+ assert(inLen > 4 * 3);
+ if (inLen < 4 * 3)
+ return NULL;
+ *outLen = *(uint32_t *)in;
+ unsigned char * const out = (unsigned char *)malloc(*outLen);
+ unsigned int outPos = 0;
+ const unsigned char * const end = (const unsigned char *)in + inLen;
+ for (const unsigned char * inData = (const unsigned char *)in + 4; inData < end; ) {
+ const uint32_t chunkOut = *(uint32_t *)inData;
+ inData += 4;
+ const uint32_t chunkIn = *(uint32_t *)inData;
+ inData += 4;
+ if (chunkIn > 0) {
+ assert(inData + chunkIn <= end);
+ assert(outPos + chunkOut <= *outLen);
+ outPos += lzf_decompress(inData, chunkIn, out + outPos, chunkOut);
+ inData += chunkIn;
+ } else {
+ assert(inData + chunkOut <= end);
+ assert(outPos + chunkOut <= *outLen);
+ memcpy(out + outPos, inData, chunkOut);
+ inData += chunkOut;
+ outPos += chunkOut;
+ }
+ }
+ return out;
+}
+
void * DbgContext::GetReadPixelsBuffer(const unsigned size)
{
if (lzf_refBufSize < size + 8) {
lzf_refBufSize = size + 8;
lzf_ref[0] = (unsigned *)realloc(lzf_ref[0], lzf_refBufSize);
+ assert(lzf_ref[0]);
memset(lzf_ref[0], 0, lzf_refBufSize);
lzf_ref[1] = (unsigned *)realloc(lzf_ref[1], lzf_refBufSize);
+ assert(lzf_ref[1]);
memset(lzf_ref[1], 0, lzf_refBufSize);
}
if (lzf_refSize != size) // need to clear unused ref to maintain consistency
@@ -151,6 +220,7 @@
void DbgContext::CompressReadPixelBuffer(std::string * const outStr)
{
+ assert(lzf_ref[0] && lzf_ref[1]);
unsigned * const ref = lzf_ref[lzf_readIndex ^ 1];
unsigned * const src = lzf_ref[lzf_readIndex];
for (unsigned i = 0; i < lzf_refSize / sizeof(*ref) + 1; i++)
@@ -158,13 +228,34 @@
Compress(ref, lzf_refSize, outStr);
}
+char * DbgContext::GetBuffer()
+{
+ if (!lzf_buf)
+ lzf_buf = (char *)malloc(LZF_CHUNK_SIZE);
+ assert(lzf_buf);
+ return lzf_buf;
+}
+
+unsigned int DbgContext::GetBufferSize()
+{
+ if (!lzf_buf)
+ lzf_buf = (char *)malloc(LZF_CHUNK_SIZE);
+ assert(lzf_buf);
+ if (lzf_buf)
+ return LZF_CHUNK_SIZE;
+ else
+ return 0;
+}
+
void DbgContext::glUseProgram(GLuint program)
{
while (GLenum error = hooks->gl.glGetError())
- LOGD("DbgContext::glUseProgram: before glGetError() = 0x%.4X", error);
-
+ LOGD("DbgContext::glUseProgram(%u): before glGetError() = 0x%.4X",
+ program, error);
this->program = program;
-
+ maxAttrib = 0;
+ if (program == 0)
+ return;
GLint activeAttributes = 0;
hooks->gl.glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &activeAttributes);
maxAttrib = 0;
@@ -202,9 +293,9 @@
maxAttrib = slot;
}
delete name;
-
while (GLenum error = hooks->gl.glGetError())
- LOGD("DbgContext::glUseProgram: after glGetError() = 0x%.4X", error);
+ LOGD("DbgContext::glUseProgram(%u): after glGetError() = 0x%.4X",
+ program, error);
}
static bool HasNonVBOAttribs(const DbgContext * const ctx)
@@ -254,14 +345,16 @@
void DbgContext::glEnableVertexAttribArray(GLuint index)
{
- assert(index < MAX_VERTEX_ATTRIBS);
+ if (index >= MAX_VERTEX_ATTRIBS)
+ return;
vertexAttribs[index].enabled = true;
hasNonVBOAttribs = HasNonVBOAttribs(this);
}
void DbgContext::glDisableVertexAttribArray(GLuint index)
{
- assert(index < MAX_VERTEX_ATTRIBS);
+ if (index >= MAX_VERTEX_ATTRIBS)
+ return;
vertexAttribs[index].enabled = false;
hasNonVBOAttribs = HasNonVBOAttribs(this);
}
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
index 046c954..50f70f7 100644
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
+++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
@@ -436,6 +436,8 @@
case 0:
case 1:
case 2:
+ case 3:
+ case 4:
return true;
default:
return false;
@@ -445,7 +447,9 @@
#ifndef _MSC_VER
const Message_Type Message::BeforeCall;
const Message_Type Message::AfterCall;
+const Message_Type Message::AfterGeneratedCall;
const Message_Type Message::Response;
+const Message_Type Message::CompleteCall;
const Message_Type Message::Type_MIN;
const Message_Type Message::Type_MAX;
const int Message::Type_ARRAYSIZE;
@@ -472,6 +476,8 @@
case 0:
case 1:
case 2:
+ case 3:
+ case 4:
return true;
default:
return false;
@@ -479,9 +485,11 @@
}
#ifndef _MSC_VER
-const Message_Prop Message::Capture;
+const Message_Prop Message::CaptureDraw;
const Message_Prop Message::TimeMode;
const Message_Prop Message::ExpectResponse;
+const Message_Prop Message::CaptureSwap;
+const Message_Prop Message::GLConstant;
const Message_Prop Message::Prop_MIN;
const Message_Prop Message::Prop_MAX;
const int Message::Prop_ARRAYSIZE;
@@ -506,6 +514,8 @@
const int Message::kDataTypeFieldNumber;
const int Message::kPixelFormatFieldNumber;
const int Message::kPixelTypeFieldNumber;
+const int Message::kImageWidthFieldNumber;
+const int Message::kImageHeightFieldNumber;
const int Message::kTimeFieldNumber;
const int Message::kPropFieldNumber;
const int Message::kClockFieldNumber;
@@ -545,6 +555,8 @@
data_type_ = 0;
pixel_format_ = 0;
pixel_type_ = 0;
+ image_width_ = 0;
+ image_height_ = 0;
time_ = 0;
prop_ = 0;
clock_ = 0;
@@ -606,6 +618,8 @@
if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) {
pixel_format_ = 0;
pixel_type_ = 0;
+ image_width_ = 0;
+ image_height_ = 0;
time_ = 0;
prop_ = 0;
clock_ = 0;
@@ -790,7 +804,7 @@
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
input, &time_)));
- _set_bit(18);
+ _set_bit(20);
} else {
goto handle_uninterpreted;
}
@@ -905,7 +919,7 @@
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
input, &clock_)));
- _set_bit(20);
+ _set_bit(22);
} else {
goto handle_uninterpreted;
}
@@ -960,6 +974,38 @@
} else {
goto handle_uninterpreted;
}
+ if (input->ExpectTag(208)) goto parse_image_width;
+ break;
+ }
+
+ // optional int32 image_width = 26;
+ case 26: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_image_width:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ input, &image_width_)));
+ _set_bit(18);
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(216)) goto parse_image_height;
+ break;
+ }
+
+ // optional int32 image_height = 27;
+ case 27: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_image_height:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ input, &image_height_)));
+ _set_bit(19);
+ } else {
+ goto handle_uninterpreted;
+ }
if (input->ExpectAtEnd()) return true;
break;
}
@@ -1035,7 +1081,7 @@
}
// optional float time = 11;
- if (_has_bit(18)) {
+ if (_has_bit(20)) {
::google::protobuf::internal::WireFormatLite::WriteFloat(11, this->time(), output);
}
@@ -1065,13 +1111,13 @@
}
// optional .com.android.glesv2debugger.Message.Prop prop = 21;
- if (_has_bit(19)) {
+ if (_has_bit(21)) {
::google::protobuf::internal::WireFormatLite::WriteEnum(
21, this->prop(), output);
}
// optional float clock = 22;
- if (_has_bit(20)) {
+ if (_has_bit(22)) {
::google::protobuf::internal::WireFormatLite::WriteFloat(22, this->clock(), output);
}
@@ -1091,6 +1137,16 @@
::google::protobuf::internal::WireFormatLite::WriteInt32(25, this->pixel_type(), output);
}
+ // optional int32 image_width = 26;
+ if (_has_bit(18)) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt32(26, this->image_width(), output);
+ }
+
+ // optional int32 image_height = 27;
+ if (_has_bit(19)) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt32(27, this->image_height(), output);
+ }
+
}
int Message::ByteSize() const {
@@ -1222,6 +1278,20 @@
this->pixel_type());
}
+ // optional int32 image_width = 26;
+ if (has_image_width()) {
+ total_size += 2 +
+ ::google::protobuf::internal::WireFormatLite::Int32Size(
+ this->image_width());
+ }
+
+ // optional int32 image_height = 27;
+ if (has_image_height()) {
+ total_size += 2 +
+ ::google::protobuf::internal::WireFormatLite::Int32Size(
+ this->image_height());
+ }
+
// optional float time = 11;
if (has_time()) {
total_size += 1 + 4;
@@ -1312,12 +1382,18 @@
set_pixel_type(from.pixel_type());
}
if (from._has_bit(18)) {
- set_time(from.time());
+ set_image_width(from.image_width());
}
if (from._has_bit(19)) {
- set_prop(from.prop());
+ set_image_height(from.image_height());
}
if (from._has_bit(20)) {
+ set_time(from.time());
+ }
+ if (from._has_bit(21)) {
+ set_prop(from.prop());
+ }
+ if (from._has_bit(22)) {
set_clock(from.clock());
}
}
@@ -1355,6 +1431,8 @@
std::swap(data_type_, other->data_type_);
std::swap(pixel_format_, other->pixel_format_);
std::swap(pixel_type_, other->pixel_type_);
+ std::swap(image_width_, other->image_width_);
+ std::swap(image_height_, other->image_height_);
std::swap(time_, other->time_);
std::swap(prop_, other->prop_);
std::swap(clock_, other->clock_);
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
index b2ec5a0..5c94664 100644
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
+++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
@@ -236,11 +236,13 @@
enum Message_Type {
Message_Type_BeforeCall = 0,
Message_Type_AfterCall = 1,
- Message_Type_Response = 2
+ Message_Type_AfterGeneratedCall = 2,
+ Message_Type_Response = 3,
+ Message_Type_CompleteCall = 4
};
bool Message_Type_IsValid(int value);
const Message_Type Message_Type_Type_MIN = Message_Type_BeforeCall;
-const Message_Type Message_Type_Type_MAX = Message_Type_Response;
+const Message_Type Message_Type_Type_MAX = Message_Type_CompleteCall;
const int Message_Type_Type_ARRAYSIZE = Message_Type_Type_MAX + 1;
enum Message_DataType {
@@ -253,13 +255,15 @@
const int Message_DataType_DataType_ARRAYSIZE = Message_DataType_DataType_MAX + 1;
enum Message_Prop {
- Message_Prop_Capture = 0,
+ Message_Prop_CaptureDraw = 0,
Message_Prop_TimeMode = 1,
- Message_Prop_ExpectResponse = 2
+ Message_Prop_ExpectResponse = 2,
+ Message_Prop_CaptureSwap = 3,
+ Message_Prop_GLConstant = 4
};
bool Message_Prop_IsValid(int value);
-const Message_Prop Message_Prop_Prop_MIN = Message_Prop_Capture;
-const Message_Prop Message_Prop_Prop_MAX = Message_Prop_ExpectResponse;
+const Message_Prop Message_Prop_Prop_MIN = Message_Prop_CaptureDraw;
+const Message_Prop Message_Prop_Prop_MAX = Message_Prop_GLConstant;
const int Message_Prop_Prop_ARRAYSIZE = Message_Prop_Prop_MAX + 1;
// ===================================================================
@@ -510,7 +514,9 @@
typedef Message_Type Type;
static const Type BeforeCall = Message_Type_BeforeCall;
static const Type AfterCall = Message_Type_AfterCall;
+ static const Type AfterGeneratedCall = Message_Type_AfterGeneratedCall;
static const Type Response = Message_Type_Response;
+ static const Type CompleteCall = Message_Type_CompleteCall;
static inline bool Type_IsValid(int value) {
return Message_Type_IsValid(value);
}
@@ -535,9 +541,11 @@
Message_DataType_DataType_ARRAYSIZE;
typedef Message_Prop Prop;
- static const Prop Capture = Message_Prop_Capture;
+ static const Prop CaptureDraw = Message_Prop_CaptureDraw;
static const Prop TimeMode = Message_Prop_TimeMode;
static const Prop ExpectResponse = Message_Prop_ExpectResponse;
+ static const Prop CaptureSwap = Message_Prop_CaptureSwap;
+ static const Prop GLConstant = Message_Prop_GLConstant;
static inline bool Prop_IsValid(int value) {
return Message_Prop_IsValid(value);
}
@@ -679,6 +687,20 @@
inline ::google::protobuf::int32 pixel_type() const;
inline void set_pixel_type(::google::protobuf::int32 value);
+ // optional int32 image_width = 26;
+ inline bool has_image_width() const;
+ inline void clear_image_width();
+ static const int kImageWidthFieldNumber = 26;
+ inline ::google::protobuf::int32 image_width() const;
+ inline void set_image_width(::google::protobuf::int32 value);
+
+ // optional int32 image_height = 27;
+ inline bool has_image_height() const;
+ inline void clear_image_height();
+ static const int kImageHeightFieldNumber = 27;
+ inline ::google::protobuf::int32 image_height() const;
+ inline void set_image_height(::google::protobuf::int32 value);
+
// optional float time = 11;
inline bool has_time() const;
inline void clear_time();
@@ -723,6 +745,8 @@
int data_type_;
::google::protobuf::int32 pixel_format_;
::google::protobuf::int32 pixel_type_;
+ ::google::protobuf::int32 image_width_;
+ ::google::protobuf::int32 image_height_;
float time_;
int prop_;
float clock_;
@@ -730,7 +754,7 @@
friend void protobuf_AssignDesc_debugger_5fmessage_2eproto();
friend void protobuf_ShutdownFile_debugger_5fmessage_2eproto();
- ::google::protobuf::uint32 _has_bits_[(21 + 31) / 32];
+ ::google::protobuf::uint32 _has_bits_[(23 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
inline bool _has_bit(int index) const {
@@ -1070,52 +1094,84 @@
pixel_type_ = value;
}
+// optional int32 image_width = 26;
+inline bool Message::has_image_width() const {
+ return _has_bit(18);
+}
+inline void Message::clear_image_width() {
+ image_width_ = 0;
+ _clear_bit(18);
+}
+inline ::google::protobuf::int32 Message::image_width() const {
+ return image_width_;
+}
+inline void Message::set_image_width(::google::protobuf::int32 value) {
+ _set_bit(18);
+ image_width_ = value;
+}
+
+// optional int32 image_height = 27;
+inline bool Message::has_image_height() const {
+ return _has_bit(19);
+}
+inline void Message::clear_image_height() {
+ image_height_ = 0;
+ _clear_bit(19);
+}
+inline ::google::protobuf::int32 Message::image_height() const {
+ return image_height_;
+}
+inline void Message::set_image_height(::google::protobuf::int32 value) {
+ _set_bit(19);
+ image_height_ = value;
+}
+
// optional float time = 11;
inline bool Message::has_time() const {
- return _has_bit(18);
+ return _has_bit(20);
}
inline void Message::clear_time() {
time_ = 0;
- _clear_bit(18);
+ _clear_bit(20);
}
inline float Message::time() const {
return time_;
}
inline void Message::set_time(float value) {
- _set_bit(18);
+ _set_bit(20);
time_ = value;
}
// optional .com.android.glesv2debugger.Message.Prop prop = 21;
inline bool Message::has_prop() const {
- return _has_bit(19);
+ return _has_bit(21);
}
inline void Message::clear_prop() {
prop_ = 0;
- _clear_bit(19);
+ _clear_bit(21);
}
inline ::com::android::glesv2debugger::Message_Prop Message::prop() const {
return static_cast< ::com::android::glesv2debugger::Message_Prop >(prop_);
}
inline void Message::set_prop(::com::android::glesv2debugger::Message_Prop value) {
GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Prop_IsValid(value));
- _set_bit(19);
+ _set_bit(21);
prop_ = value;
}
// optional float clock = 22;
inline bool Message::has_clock() const {
- return _has_bit(20);
+ return _has_bit(22);
}
inline void Message::clear_clock() {
clock_ = 0;
- _clear_bit(20);
+ _clear_bit(22);
}
inline float Message::clock() const {
return clock_;
}
inline void Message::set_clock(float value) {
- _set_bit(20);
+ _set_bit(22);
clock_ = value;
}
diff --git a/opengl/libs/GLES2_dbg/src/egl.cpp b/opengl/libs/GLES2_dbg/src/egl.cpp
index 3a20e21..eb28d06 100644
--- a/opengl/libs/GLES2_dbg/src/egl.cpp
+++ b/opengl/libs/GLES2_dbg/src/egl.cpp
@@ -18,6 +18,7 @@
EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
{
+ DbgContext * const dbg = getDbgContextThreadSpecific();
glesv2debugger::Message msg;
struct : public FunctionCall {
EGLDisplay dpy;
@@ -33,7 +34,21 @@
msg.set_arg0(reinterpret_cast<int>(dpy));
msg.set_arg1(reinterpret_cast<int>(draw));
-
+ if (dbg->captureSwap > 0) {
+ dbg->captureSwap--;
+ int viewport[4] = {};
+ dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
+ void * pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
+ dbg->readBytesPerPixel);
+ dbg->hooks->gl.glReadPixels(viewport[0], viewport[1], viewport[2],
+ viewport[3], dbg->readFormat, dbg->readType, pixels);
+ dbg->CompressReadPixelBuffer(msg.mutable_data());
+ msg.set_data_type(msg.ReferencedImage);
+ msg.set_pixel_format(dbg->readFormat);
+ msg.set_pixel_type(dbg->readType);
+ msg.set_image_width(viewport[2]);
+ msg.set_image_height(viewport[3]);
+ }
int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_eglSwapBuffers);
return static_cast<EGLBoolean>(reinterpret_cast<int>(ret));
}
diff --git a/opengl/libs/GLES2_dbg/src/header.h b/opengl/libs/GLES2_dbg/src/header.h
index 9218da5..f2b1fa6 100644
--- a/opengl/libs/GLES2_dbg/src/header.h
+++ b/opengl/libs/GLES2_dbg/src/header.h
@@ -14,6 +14,9 @@
** limitations under the License.
*/
+#ifndef ANDROID_GLES2_DBG_HEADER_H
+#define ANDROID_GLES2_DBG_HEADER_H
+
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
@@ -24,9 +27,7 @@
#include <cutils/log.h>
#include <utils/Timers.h>
-#include <../../../libcore/include/StaticAssert.h>
-#define EGL_TRACE 1
#include "hooks.h"
#include "glesv2dbg.h"
@@ -39,8 +40,6 @@
using namespace android;
using namespace com::android;
-#define API_ENTRY(_api) Debug_##_api
-
#ifndef __location__
#define __HIERALLOC_STRING_0__(s) #s
#define __HIERALLOC_STRING_1__(s) __HIERALLOC_STRING_0__(s)
@@ -74,9 +73,10 @@
};
struct DbgContext {
-private:
static const unsigned int LZF_CHUNK_SIZE = 256 * 1024;
- char * lzf_buf; // malloc / free; for lzf chunk compression
+
+private:
+ char * lzf_buf; // malloc / free; for lzf chunk compression and other uses
// used as buffer and reference frame for ReadPixels; malloc/free
unsigned * lzf_ref [2];
@@ -84,9 +84,14 @@
unsigned lzf_refSize, lzf_refBufSize; // bytes
public:
- const unsigned version; // 0 is GLES1, 1 is GLES2
+ const unsigned int version; // 0 is GLES1, 1 is GLES2
const gl_hooks_t * const hooks;
- const unsigned MAX_VERTEX_ATTRIBS;
+ const unsigned int MAX_VERTEX_ATTRIBS;
+ const GLenum readFormat, readType; // implementation supported glReadPixels
+ const unsigned int readBytesPerPixel;
+
+ unsigned int captureSwap; // number of eglSwapBuffers to glReadPixels
+ unsigned int captureDraw; // number of glDrawArrays/Elements to glReadPixels
GLFunctionBitfield expectResponse;
@@ -119,16 +124,21 @@
unsigned maxAttrib; // number of slots used by program
DbgContext(const unsigned version, const gl_hooks_t * const hooks,
- const unsigned MAX_VERTEX_ATTRIBS);
+ const unsigned MAX_VERTEX_ATTRIBS, const GLenum readFormat,
+ const GLenum readType);
~DbgContext();
void Fetch(const unsigned index, std::string * const data) const;
void Compress(const void * in_data, unsigned in_len, std::string * const outStr);
+ static unsigned char * Decompress(const void * in, const unsigned int inLen,
+ unsigned int * const outLen); // malloc/free
void * GetReadPixelsBuffer(const unsigned size);
bool IsReadPixelBuffer(const void * const ptr) {
return ptr == lzf_ref[lzf_readIndex];
}
void CompressReadPixelBuffer(std::string * const outStr);
+ char * GetBuffer(); // allocates lzf_buf if NULL
+ unsigned int GetBufferSize(); // allocates lzf_buf if NULL
void glUseProgram(GLuint program);
void glEnableVertexAttribArray(GLuint index);
@@ -141,9 +151,7 @@
void glDeleteBuffers(GLsizei n, const GLuint *buffers);
};
-
DbgContext * getDbgContextThreadSpecific();
-#define DBGCONTEXT(ctx) DbgContext * const ctx = getDbgContextThreadSpecific();
struct FunctionCall {
virtual const int * operator()(gl_hooks_t::gl_t const * const _c,
@@ -152,7 +160,6 @@
};
// move these into DbgContext as static
-extern bool capture;
extern int timeMode; // SYSTEM_TIME_
extern int clientSock, serverSock;
@@ -169,3 +176,5 @@
const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message & cmd,
glesv2debugger::Message & msg, const int * const prevRet);
}; // namespace android {
+
+#endif // #ifndef ANDROID_GLES2_DBG_HEADER_H
diff --git a/opengl/libs/GLES2_dbg/src/server.cpp b/opengl/libs/GLES2_dbg/src/server.cpp
index 7039c84..0c711bf 100644
--- a/opengl/libs/GLES2_dbg/src/server.cpp
+++ b/opengl/libs/GLES2_dbg/src/server.cpp
@@ -28,7 +28,8 @@
{
int serverSock = -1, clientSock = -1;
-
+FILE * file = NULL;
+unsigned int MAX_FILE_SIZE = 0;
int timeMode = SYSTEM_TIME_THREAD;
static void Die(const char * msg)
@@ -38,18 +39,25 @@
exit(1);
}
-void StartDebugServer(unsigned short port)
+void StartDebugServer(const unsigned short port, const bool forceUseFile,
+ const unsigned int maxFileSize, const char * const filePath)
{
+ MAX_FILE_SIZE = maxFileSize;
+
LOGD("GLESv2_dbg: StartDebugServer");
- if (serverSock >= 0)
+ if (serverSock >= 0 || file)
return;
LOGD("GLESv2_dbg: StartDebugServer create socket");
struct sockaddr_in server = {}, client = {};
/* Create the TCP socket */
- if ((serverSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
- Die("Failed to create socket");
+ if (forceUseFile || (serverSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+ file = fopen(filePath, "wb");
+ if (!file)
+ Die("Failed to create socket and file");
+ else
+ return;
}
/* Construct the server sockaddr_in structure */
server.sin_family = AF_INET; /* Internet/IP */
@@ -92,13 +100,17 @@
close(serverSock);
serverSock = -1;
}
-
+ if (file) {
+ fclose(file);
+ file = NULL;
+ }
}
void Receive(glesv2debugger::Message & cmd)
{
+ if (clientSock < 0)
+ return;
unsigned len = 0;
-
int received = recv(clientSock, &len, 4, MSG_WAITALL);
if (received < 0)
Die("Failed to receive response length");
@@ -106,7 +118,6 @@
LOGD("received %dB: %.8X", received, len);
Die("Received length mismatch, expected 4");
}
- len = ntohl(len);
static void * buffer = NULL;
static unsigned bufferSize = 0;
if (bufferSize < len) {
@@ -125,6 +136,8 @@
bool TryReceive(glesv2debugger::Message & cmd)
{
+ if (clientSock < 0)
+ return false;
fd_set readSet;
FD_ZERO(&readSet);
FD_SET(clientSock, &readSet);
@@ -146,14 +159,34 @@
float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd)
{
+ // TODO: use per DbgContext send/receive buffer and async socket
+ // instead of mutex and blocking io; watch out for large messages
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- pthread_mutex_lock(&mutex); // TODO: this is just temporary
+ struct Autolock {
+ Autolock() {
+ pthread_mutex_lock(&mutex);
+ }
+ ~Autolock() {
+ pthread_mutex_unlock(&mutex);
+ }
+ } autolock;
if (msg.function() != glesv2debugger::Message_Function_ACK)
assert(msg.has_context_id() && msg.context_id() != 0);
static std::string str;
msg.SerializeToString(&str);
- uint32_t len = htonl(str.length());
+ const uint32_t len = str.length();
+ if (clientSock < 0) {
+ if (file) {
+ fwrite(&len, sizeof(len), 1, file);
+ fwrite(str.data(), len, 1, file);
+ if (ftell(file) >= MAX_FILE_SIZE) {
+ fclose(file);
+ Die("MAX_FILE_SIZE reached");
+ }
+ }
+ return 0;
+ }
int sent = -1;
sent = send(clientSock, &len, sizeof(len), 0);
if (sent != sizeof(len)) {
@@ -161,36 +194,37 @@
Die("Failed to send message length");
}
nsecs_t c0 = systemTime(timeMode);
- sent = send(clientSock, str.c_str(), str.length(), 0);
+ sent = send(clientSock, str.data(), str.length(), 0);
float t = (float)ns2ms(systemTime(timeMode) - c0);
if (sent != str.length()) {
LOGD("actual sent=%d expected=%d clientSock=%d", sent, str.length(), clientSock);
Die("Failed to send message");
}
-
+ // TODO: factor Receive & TryReceive out and into MessageLoop, or add control argument.
+ // mean while, if server is sending a SETPROP then don't try to receive,
+ // because server will not be processing received command
+ if (msg.function() == msg.SETPROP)
+ return t;
// try to receive commands even though not expecting response,
- // since client can send SETPROP commands anytime
+ // since client can send SETPROP and other commands anytime
if (!msg.expect_response()) {
if (TryReceive(cmd)) {
- LOGD("Send: TryReceived");
if (glesv2debugger::Message_Function_SETPROP == cmd.function())
- LOGD("Send: received SETPROP");
+ LOGD("Send: TryReceived SETPROP");
else
- LOGD("Send: received something else");
+ LOGD("Send: TryReceived %u", cmd.function());
}
} else
Receive(cmd);
-
- pthread_mutex_unlock(&mutex);
return t;
}
void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd)
{
switch (cmd.prop()) {
- case glesv2debugger::Message_Prop_Capture:
- LOGD("SetProp Message_Prop_Capture %d", cmd.arg0());
- capture = cmd.arg0();
+ case glesv2debugger::Message_Prop_CaptureDraw:
+ LOGD("SetProp Message_Prop_CaptureDraw %d", cmd.arg0());
+ dbg->captureDraw = cmd.arg0();
break;
case glesv2debugger::Message_Prop_TimeMode:
LOGD("SetProp Message_Prop_TimeMode %d", cmd.arg0());
@@ -200,6 +234,10 @@
LOGD("SetProp Message_Prop_ExpectResponse %d=%d", cmd.arg0(), cmd.arg1());
dbg->expectResponse.Bit((glesv2debugger::Message_Function)cmd.arg0(), cmd.arg1());
break;
+ case glesv2debugger::Message_Prop_CaptureSwap:
+ LOGD("SetProp CaptureSwap %d", cmd.arg0());
+ dbg->captureSwap = cmd.arg0();
+ break;
default:
assert(0);
}
@@ -213,12 +251,17 @@
glesv2debugger::Message cmd;
msg.set_context_id(reinterpret_cast<int>(dbg));
msg.set_type(glesv2debugger::Message_Type_BeforeCall);
- const bool expectResponse = dbg->expectResponse.Bit(function);
+ bool expectResponse = dbg->expectResponse.Bit(function);
msg.set_expect_response(expectResponse);
msg.set_function(function);
- if (!expectResponse)
- cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+
+ // when not exectResponse, set cmd to CONTINUE then SKIP
+ // cmd will be overwritten by received command
+ cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+ cmd.set_expect_response(expectResponse);
+ glesv2debugger::Message_Function oldCmd = cmd.function();
Send(msg, cmd);
+ expectResponse = cmd.expect_response();
while (true) {
msg.Clear();
nsecs_t c0 = systemTime(timeMode);
@@ -233,22 +276,34 @@
msg.set_function(function);
msg.set_type(glesv2debugger::Message_Type_AfterCall);
msg.set_expect_response(expectResponse);
- if (!expectResponse)
+ if (!expectResponse) {
cmd.set_function(glesv2debugger::Message_Function_SKIP);
+ cmd.set_expect_response(false);
+ }
+ oldCmd = cmd.function();
Send(msg, cmd);
+ expectResponse = cmd.expect_response();
break;
case glesv2debugger::Message_Function_SKIP:
return const_cast<int *>(ret);
case glesv2debugger::Message_Function_SETPROP:
SetProp(dbg, cmd);
- Receive(cmd);
+ expectResponse = cmd.expect_response();
+ if (!expectResponse) // SETPROP is "out of band"
+ cmd.set_function(oldCmd);
+ else
+ Receive(cmd);
break;
default:
ret = GenerateCall(dbg, cmd, msg, ret);
msg.set_expect_response(expectResponse);
- if (!expectResponse)
+ if (!expectResponse) {
cmd.set_function(cmd.SKIP);
+ cmd.set_expect_response(expectResponse);
+ }
+ oldCmd = cmd.function();
Send(msg, cmd);
+ expectResponse = cmd.expect_response();
break;
}
}
diff --git a/opengl/libs/GLES2_dbg/src/vertex.cpp b/opengl/libs/GLES2_dbg/src/vertex.cpp
index 471e5ad..029ee3b 100644
--- a/opengl/libs/GLES2_dbg/src/vertex.cpp
+++ b/opengl/libs/GLES2_dbg/src/vertex.cpp
@@ -21,74 +21,13 @@
bool capture; // capture after each glDraw*
}
-void Debug_glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
-{
- DbgContext * const dbg = getDbgContextThreadSpecific();
- glesv2debugger::Message msg, cmd;
- msg.set_context_id(reinterpret_cast<int>(dbg));
- msg.set_type(glesv2debugger::Message_Type_BeforeCall);
- const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glReadPixels);
- msg.set_expect_response(expectResponse);
- msg.set_function(glesv2debugger::Message_Function_glReadPixels);
- msg.set_arg0(x);
- msg.set_arg1(y);
- msg.set_arg2(width);
- msg.set_arg3(height);
- msg.set_arg4(format);
- msg.set_arg5(type);
- msg.set_arg6(reinterpret_cast<int>(pixels));
-
- const unsigned size = width * height * GetBytesPerPixel(format, type);
- if (!expectResponse)
- cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
- Send(msg, cmd);
- float t = 0;
- while (true) {
- msg.Clear();
- nsecs_t c0 = systemTime(timeMode);
- switch (cmd.function()) {
- case glesv2debugger::Message_Function_CONTINUE:
- dbg->hooks->gl.glReadPixels(x, y, width, height, format, type, pixels);
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- msg.set_context_id(reinterpret_cast<int>(dbg));
- msg.set_function(glesv2debugger::Message_Function_glReadPixels);
- msg.set_type(glesv2debugger::Message_Type_AfterCall);
- msg.set_expect_response(expectResponse);
- if (dbg->IsReadPixelBuffer(pixels)) {
- dbg->CompressReadPixelBuffer(msg.mutable_data());
- msg.set_data_type(msg.ReferencedImage);
- } else {
- dbg->Compress(pixels, size, msg.mutable_data());
- msg.set_data_type(msg.NonreferencedImage);
- }
- if (!expectResponse)
- cmd.set_function(glesv2debugger::Message_Function_SKIP);
- Send(msg, cmd);
- break;
- case glesv2debugger::Message_Function_SKIP:
- return;
- case glesv2debugger::Message_Function_SETPROP:
- SetProp(dbg, cmd);
- Receive(cmd);
- break;
- default:
- GenerateCall(dbg, cmd, msg, NULL);
- msg.set_expect_response(expectResponse);
- if (!expectResponse)
- cmd.set_function(cmd.SKIP);
- Send(msg, cmd);
- break;
- }
- }
-}
-
void Debug_glDrawArrays(GLenum mode, GLint first, GLsizei count)
{
DbgContext * const dbg = getDbgContextThreadSpecific();
glesv2debugger::Message msg, cmd;
msg.set_context_id(reinterpret_cast<int>(dbg));
msg.set_type(glesv2debugger::Message_Type_BeforeCall);
- const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawArrays);
+ bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawArrays);
msg.set_expect_response(expectResponse);
msg.set_function(glesv2debugger::Message_Function_glDrawArrays);
msg.set_arg0(mode);
@@ -103,11 +42,12 @@
}
void * pixels = NULL;
- GLint readFormat = 0, readType = 0;
int viewport[4] = {};
- if (!expectResponse)
- cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+ cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+ cmd.set_expect_response(expectResponse);
+ glesv2debugger::Message_Function oldCmd = cmd.function();
Send(msg, cmd);
+ expectResponse = cmd.expect_response();
while (true) {
msg.Clear();
nsecs_t c0 = systemTime(timeMode);
@@ -119,33 +59,47 @@
msg.set_function(glesv2debugger::Message_Function_glDrawArrays);
msg.set_type(glesv2debugger::Message_Type_AfterCall);
msg.set_expect_response(expectResponse);
- if (!expectResponse)
+ if (!expectResponse) {
cmd.set_function(glesv2debugger::Message_Function_SKIP);
+ cmd.set_expect_response(false);
+ }
+ oldCmd = cmd.function();
Send(msg, cmd);
- if (capture) {
+ expectResponse = cmd.expect_response();
+ // TODO: pack glReadPixels data with vertex data instead of
+ // relying on sperate call for transport, this would allow
+ // auto generated message loop using EXTEND_Debug macro
+ if (dbg->captureDraw > 0) {
+ dbg->captureDraw--;
dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
- dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat);
- dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);
// LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X",
// viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);
pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
- GetBytesPerPixel(readFormat, readType));
+ dbg->readBytesPerPixel);
Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
- readFormat, readType, pixels);
+ dbg->readFormat, dbg->readType, pixels);
}
break;
case glesv2debugger::Message_Function_SKIP:
return;
case glesv2debugger::Message_Function_SETPROP:
SetProp(dbg, cmd);
- Receive(cmd);
+ expectResponse = cmd.expect_response();
+ if (!expectResponse) // SETPROP is "out of band"
+ cmd.set_function(oldCmd);
+ else
+ Receive(cmd);
break;
default:
GenerateCall(dbg, cmd, msg, NULL);
msg.set_expect_response(expectResponse);
- if (!expectResponse)
+ if (!expectResponse) {
cmd.set_function(cmd.SKIP);
+ cmd.set_expect_response(expectResponse);
+ }
+ oldCmd = cmd.function();
Send(msg, cmd);
+ expectResponse = cmd.expect_response();
break;
}
}
@@ -169,7 +123,7 @@
glesv2debugger::Message msg, cmd;
msg.set_context_id(reinterpret_cast<int>(dbg));
msg.set_type(glesv2debugger::Message_Type_BeforeCall);
- const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawElements);
+ bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawElements);
msg.set_expect_response(expectResponse);
msg.set_function(glesv2debugger::Message_Function_glDrawElements);
msg.set_arg0(mode);
@@ -195,11 +149,12 @@
assert(0);
void * pixels = NULL;
- GLint readFormat = 0, readType = 0;
int viewport[4] = {};
- if (!expectResponse)
- cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+ cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+ cmd.set_expect_response(expectResponse);
+ glesv2debugger::Message_Function oldCmd = cmd.function();
Send(msg, cmd);
+ expectResponse = cmd.expect_response();
while (true) {
msg.Clear();
nsecs_t c0 = systemTime(timeMode);
@@ -211,33 +166,45 @@
msg.set_function(glesv2debugger::Message_Function_glDrawElements);
msg.set_type(glesv2debugger::Message_Type_AfterCall);
msg.set_expect_response(expectResponse);
- if (!expectResponse)
+ if (!expectResponse) {
cmd.set_function(glesv2debugger::Message_Function_SKIP);
+ cmd.set_expect_response(false);
+ }
+ oldCmd = cmd.function();
Send(msg, cmd);
- if (capture) {
+ expectResponse = cmd.expect_response();
+ // TODO: pack glReadPixels data with vertex data instead of
+ // relying on sperate call for transport, this would allow
+ // auto generated message loop using EXTEND_Debug macro
+ if (dbg->captureDraw > 0) {
+ dbg->captureDraw--;
dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
- dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat);
- dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);
-// LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X",
-// viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);
pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
- GetBytesPerPixel(readFormat, readType));
+ dbg->readBytesPerPixel);
Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
- readFormat, readType, pixels);
+ dbg->readFormat, dbg->readType, pixels);
}
break;
case glesv2debugger::Message_Function_SKIP:
return;
case glesv2debugger::Message_Function_SETPROP:
SetProp(dbg, cmd);
- Receive(cmd);
+ expectResponse = cmd.expect_response();
+ if (!expectResponse) // SETPROP is "out of band"
+ cmd.set_function(oldCmd);
+ else
+ Receive(cmd);
break;
default:
GenerateCall(dbg, cmd, msg, NULL);
msg.set_expect_response(expectResponse);
- if (!expectResponse)
+ if (!expectResponse) {
cmd.set_function(cmd.SKIP);
+ cmd.set_expect_response(expectResponse);
+ }
+ oldCmd = cmd.function();
Send(msg, cmd);
+ expectResponse = cmd.expect_response();
break;
}
}
diff --git a/opengl/libs/GLES2_dbg/test/Android.mk b/opengl/libs/GLES2_dbg/test/Android.mk
new file mode 100644
index 0000000..14a84b4
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/test/Android.mk
@@ -0,0 +1,39 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH) \
+ $(LOCAL_PATH)/../src \
+ $(LOCAL_PATH)/../../ \
+ external/gtest/include \
+ external/stlport/stlport \
+ external/protobuf/src \
+ bionic \
+ external \
+#
+
+LOCAL_SRC_FILES:= \
+ test_main.cpp \
+ test_server.cpp \
+ test_socket.cpp \
+#
+
+LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2_dbg libstlport
+LOCAL_STATIC_LIBRARIES := libgtest libprotobuf-cpp-2.3.0-lite liblzf
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE:= libGLESv2_dbg_test
+
+ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
+ LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+endif
+ifneq ($(TARGET_SIMULATOR),true)
+ LOCAL_C_INCLUDES += bionic/libc/private
+endif
+
+LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS += -fvisibility=hidden
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/opengl/libs/GLES2_dbg/test/test_main.cpp b/opengl/libs/GLES2_dbg/test/test_main.cpp
new file mode 100644
index 0000000..058bea4
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/test/test_main.cpp
@@ -0,0 +1,234 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** 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.
+ */
+
+#include "header.h"
+#include "gtest/gtest.h"
+#include "hooks.h"
+
+namespace
+{
+
+// The fixture for testing class Foo.
+class DbgContextTest : public ::testing::Test
+{
+protected:
+ android::DbgContext dbg;
+ gl_hooks_t hooks;
+
+ DbgContextTest()
+ : dbg(1, &hooks, 32, GL_RGBA, GL_UNSIGNED_BYTE) {
+ // You can do set-up work for each test here.
+ hooks.gl.glGetError = GetError;
+ }
+
+ static GLenum GetError() {
+ return GL_NO_ERROR;
+ }
+
+ virtual ~DbgContextTest() {
+ // You can do clean-up work that doesn't throw exceptions here.
+ }
+
+ // If the constructor and destructor are not enough for setting up
+ // and cleaning up each test, you can define the following methods:
+
+ virtual void SetUp() {
+ // Code here will be called immediately after the constructor (right
+ // before each test).
+ }
+
+ virtual void TearDown() {
+ // Code here will be called immediately after each test (right
+ // before the destructor).
+ }
+};
+
+TEST_F(DbgContextTest, GetReadPixelBuffer)
+{
+ const unsigned int bufferSize = 512;
+ // test that it's allocating two buffers and swapping them
+ void * const buffer0 = dbg.GetReadPixelsBuffer(bufferSize);
+ ASSERT_NE((void *)NULL, buffer0);
+ for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++) {
+ EXPECT_EQ(0, ((unsigned int *)buffer0)[i])
+ << "GetReadPixelsBuffer should allocate and zero";
+ ((unsigned int *)buffer0)[i] = i * 13;
+ }
+
+ void * const buffer1 = dbg.GetReadPixelsBuffer(bufferSize);
+ ASSERT_NE((void *)NULL, buffer1);
+ EXPECT_NE(buffer0, buffer1);
+ for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++) {
+ EXPECT_EQ(0, ((unsigned int *)buffer1)[i])
+ << "GetReadPixelsBuffer should allocate and zero";
+ ((unsigned int *)buffer1)[i] = i * 17;
+ }
+
+ void * const buffer2 = dbg.GetReadPixelsBuffer(bufferSize);
+ EXPECT_EQ(buffer2, buffer0);
+ for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++)
+ EXPECT_EQ(i * 13, ((unsigned int *)buffer2)[i])
+ << "GetReadPixelsBuffer should swap buffers";
+
+ void * const buffer3 = dbg.GetReadPixelsBuffer(bufferSize);
+ EXPECT_EQ(buffer3, buffer1);
+ for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++)
+ EXPECT_EQ(i * 17, ((unsigned int *)buffer3)[i])
+ << "GetReadPixelsBuffer should swap buffers";
+
+ void * const buffer4 = dbg.GetReadPixelsBuffer(bufferSize);
+ EXPECT_NE(buffer3, buffer4);
+ EXPECT_EQ(buffer0, buffer2);
+ EXPECT_EQ(buffer1, buffer3);
+ EXPECT_EQ(buffer2, buffer4);
+
+ // it reallocs as necessary; 0 size may result in NULL
+ for (unsigned int i = 0; i < 42; i++) {
+ void * const buffer = dbg.GetReadPixelsBuffer(((i & 7)) << 20);
+ EXPECT_NE((void *)NULL, buffer)
+ << "should be able to get a variety of reasonable sizes";
+ EXPECT_TRUE(dbg.IsReadPixelBuffer(buffer));
+ }
+}
+
+TEST_F(DbgContextTest, CompressReadPixelBuffer)
+{
+ const unsigned int bufferSize = dbg.LZF_CHUNK_SIZE * 4 + 33;
+ std::string out;
+ unsigned char * buffer = (unsigned char *)dbg.GetReadPixelsBuffer(bufferSize);
+ for (unsigned int i = 0; i < bufferSize; i++)
+ buffer[i] = i * 13;
+ dbg.CompressReadPixelBuffer(&out);
+ uint32_t decompSize = 0;
+ ASSERT_LT(12, out.length()); // at least written chunk header
+ ASSERT_EQ(bufferSize, *(uint32_t *)out.data())
+ << "total decompressed size should be as requested in GetReadPixelsBuffer";
+ for (unsigned int i = 4; i < out.length();) {
+ const uint32_t outSize = *(uint32_t *)(out.data() + i);
+ i += 4;
+ const uint32_t inSize = *(uint32_t *)(out.data() + i);
+ i += 4;
+ if (inSize == 0)
+ i += outSize; // chunk not compressed
+ else
+ i += inSize; // skip the actual compressed chunk
+ decompSize += outSize;
+ }
+ ASSERT_EQ(bufferSize, decompSize);
+ decompSize = 0;
+
+ unsigned char * decomp = dbg.Decompress(out.data(), out.length(), &decompSize);
+ ASSERT_EQ(decompSize, bufferSize);
+ for (unsigned int i = 0; i < bufferSize; i++)
+ EXPECT_EQ((unsigned char)(i * 13), decomp[i]) << "xor with 0 ref is identity";
+ free(decomp);
+
+ buffer = (unsigned char *)dbg.GetReadPixelsBuffer(bufferSize);
+ for (unsigned int i = 0; i < bufferSize; i++)
+ buffer[i] = i * 13;
+ out.clear();
+ dbg.CompressReadPixelBuffer(&out);
+ decompSize = 0;
+ decomp = dbg.Decompress(out.data(), out.length(), &decompSize);
+ ASSERT_EQ(decompSize, bufferSize);
+ for (unsigned int i = 0; i < bufferSize; i++)
+ EXPECT_EQ(0, decomp[i]) << "xor with same ref is 0";
+ free(decomp);
+
+ buffer = (unsigned char *)dbg.GetReadPixelsBuffer(bufferSize);
+ for (unsigned int i = 0; i < bufferSize; i++)
+ buffer[i] = i * 19;
+ out.clear();
+ dbg.CompressReadPixelBuffer(&out);
+ decompSize = 0;
+ decomp = dbg.Decompress(out.data(), out.length(), &decompSize);
+ ASSERT_EQ(decompSize, bufferSize);
+ for (unsigned int i = 0; i < bufferSize; i++)
+ EXPECT_EQ((unsigned char)(i * 13) ^ (unsigned char)(i * 19), decomp[i])
+ << "xor ref";
+ free(decomp);
+}
+
+TEST_F(DbgContextTest, UseProgram)
+{
+ static const GLuint _program = 74568;
+ static const struct Attribute {
+ const char * name;
+ GLint location;
+ GLint size;
+ GLenum type;
+ } _attributes [] = {
+ {"aaa", 2, 2, GL_FLOAT_VEC2},
+ {"bb", 6, 2, GL_FLOAT_MAT2},
+ {"c", 1, 1, GL_FLOAT},
+ };
+ static const unsigned int _attributeCount = sizeof(_attributes) / sizeof(*_attributes);
+ struct GL {
+ static void GetProgramiv(GLuint program, GLenum pname, GLint* params) {
+ EXPECT_EQ(_program, program);
+ ASSERT_NE((GLint *)NULL, params);
+ switch (pname) {
+ case GL_ACTIVE_ATTRIBUTES:
+ *params = _attributeCount;
+ return;
+ case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
+ *params = 4; // includes NULL terminator
+ return;
+ default:
+ ADD_FAILURE() << "not handled pname: " << pname;
+ }
+ }
+
+ static GLint GetAttribLocation(GLuint program, const GLchar* name) {
+ EXPECT_EQ(_program, program);
+ for (unsigned int i = 0; i < _attributeCount; i++)
+ if (!strcmp(name, _attributes[i].name))
+ return _attributes[i].location;
+ ADD_FAILURE() << "unknown attribute name: " << name;
+ return -1;
+ }
+
+ static void GetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize,
+ GLsizei* length, GLint* size, GLenum* type, GLchar* name) {
+ EXPECT_EQ(_program, program);
+ ASSERT_LT(index, _attributeCount);
+ const Attribute & att = _attributes[index];
+ ASSERT_GE(bufsize, strlen(att.name) + 1);
+ ASSERT_NE((GLint *)NULL, size);
+ ASSERT_NE((GLenum *)NULL, type);
+ ASSERT_NE((GLchar *)NULL, name);
+ strcpy(name, att.name);
+ if (length)
+ *length = strlen(name) + 1;
+ *size = att.size;
+ *type = att.type;
+ }
+ };
+ hooks.gl.glGetProgramiv = GL::GetProgramiv;
+ hooks.gl.glGetAttribLocation = GL::GetAttribLocation;
+ hooks.gl.glGetActiveAttrib = GL::GetActiveAttrib;
+ dbg.glUseProgram(_program);
+ EXPECT_EQ(10, dbg.maxAttrib);
+ dbg.glUseProgram(0);
+ EXPECT_EQ(0, dbg.maxAttrib);
+}
+} // namespace
+
+int main(int argc, char **argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/opengl/libs/GLES2_dbg/test/test_server.cpp b/opengl/libs/GLES2_dbg/test/test_server.cpp
new file mode 100644
index 0000000..b6401e0
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/test/test_server.cpp
@@ -0,0 +1,251 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** 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.
+ */
+
+#include "header.h"
+#include "gtest/gtest.h"
+#include "egl_tls.h"
+#include "hooks.h"
+
+namespace android
+{
+extern FILE * file;
+extern unsigned int MAX_FILE_SIZE;
+extern pthread_key_t dbgEGLThreadLocalStorageKey;
+};
+
+// tmpfile fails, so need to manually make a writable file first
+static const char * filePath = "/data/local/tmp/dump.gles2dbg";
+
+class ServerFileTest : public ::testing::Test
+{
+protected:
+ ServerFileTest() { }
+
+ virtual ~ServerFileTest() { }
+
+ virtual void SetUp() {
+ MAX_FILE_SIZE = 8 << 20;
+ ASSERT_EQ((FILE *)NULL, file);
+ file = fopen("/data/local/tmp/dump.gles2dbg", "wb+");
+ ASSERT_NE((FILE *)NULL, file) << "make sure file is writable: "
+ << filePath;
+ }
+
+ virtual void TearDown() {
+ ASSERT_NE((FILE *)NULL, file);
+ fclose(file);
+ file = NULL;
+ }
+
+ void Read(glesv2debugger::Message & msg) const {
+ msg.Clear();
+ uint32_t len = 0;
+ ASSERT_EQ(sizeof(len), fread(&len, 1, sizeof(len), file));
+ ASSERT_GT(len, 0u);
+ char * buffer = new char [len];
+ ASSERT_EQ(len, fread(buffer, 1, len, file));
+ msg.ParseFromArray(buffer, len);
+ delete buffer;
+ }
+
+ void CheckNoAvailable() {
+ const long pos = ftell(file);
+ fseek(file, 0, SEEK_END);
+ EXPECT_EQ(pos, ftell(file)) << "check no available";
+ }
+};
+
+TEST_F(ServerFileTest, Send)
+{
+ glesv2debugger::Message msg, cmd, read;
+ msg.set_context_id(1);
+ msg.set_function(msg.glFinish);
+ msg.set_expect_response(false);
+ msg.set_type(msg.BeforeCall);
+ rewind(file);
+ android::Send(msg, cmd);
+ rewind(file);
+ Read(read);
+ EXPECT_EQ(msg.context_id(), read.context_id());
+ EXPECT_EQ(msg.function(), read.function());
+ EXPECT_EQ(msg.expect_response(), read.expect_response());
+ EXPECT_EQ(msg.type(), read.type());
+}
+
+TEST_F(ServerFileTest, CreateDbgContext)
+{
+ gl_hooks_t hooks;
+ struct Constant {
+ GLenum pname;
+ GLint param;
+ };
+ static const Constant constants [] = {
+ {GL_MAX_VERTEX_ATTRIBS, 16},
+ {GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, 32},
+ {GL_IMPLEMENTATION_COLOR_READ_FORMAT, GL_RGBA},
+ {GL_IMPLEMENTATION_COLOR_READ_TYPE, GL_UNSIGNED_BYTE},
+ };
+ struct HookMock {
+ static void GetIntegerv(GLenum pname, GLint* params) {
+ ASSERT_TRUE(params != NULL);
+ for (unsigned int i = 0; i < sizeof(constants) / sizeof(*constants); i++)
+ if (pname == constants[i].pname) {
+ *params = constants[i].param;
+ return;
+ }
+ FAIL() << "GetIntegerv unknown pname: " << pname;
+ }
+ static GLenum GetError() {
+ return GL_NO_ERROR;
+ }
+ };
+ hooks.gl.glGetError = HookMock::GetError;
+ hooks.gl.glGetIntegerv = HookMock::GetIntegerv;
+ DbgContext * const dbg = CreateDbgContext(-1, 1, &hooks);
+ ASSERT_TRUE(dbg != NULL);
+ EXPECT_TRUE(dbg->vertexAttribs != NULL);
+
+ rewind(file);
+ glesv2debugger::Message read;
+ for (unsigned int i = 0; i < 2; i++) {
+ Read(read);
+ EXPECT_EQ(reinterpret_cast<int>(dbg), read.context_id());
+ EXPECT_FALSE(read.expect_response());
+ EXPECT_EQ(read.Response, read.type());
+ EXPECT_EQ(read.SETPROP, read.function());
+ EXPECT_EQ(read.GLConstant, read.prop());
+ GLint expectedConstant = 0;
+ HookMock::GetIntegerv(read.arg0(), &expectedConstant);
+ EXPECT_EQ(expectedConstant, read.arg1());
+ }
+ CheckNoAvailable();
+ DestroyDbgContext(dbg);
+}
+
+void * glNoop()
+{
+ return 0;
+}
+
+class ServerFileContextTest : public ServerFileTest
+{
+protected:
+ tls_t tls;
+ gl_hooks_t hooks;
+
+ ServerFileContextTest() { }
+
+ virtual ~ServerFileContextTest() { }
+
+ virtual void SetUp() {
+ ServerFileTest::SetUp();
+
+ if (dbgEGLThreadLocalStorageKey == -1)
+ pthread_key_create(&dbgEGLThreadLocalStorageKey, NULL);
+ ASSERT_NE(-1, dbgEGLThreadLocalStorageKey);
+ tls.dbg = new DbgContext(1, &hooks, 32, GL_RGBA, GL_UNSIGNED_BYTE);
+ ASSERT_NE((void *)NULL, tls.dbg);
+ pthread_setspecific(dbgEGLThreadLocalStorageKey, &tls);
+ for (unsigned int i = 0; i < sizeof(hooks) / sizeof(void *); i++)
+ ((void **)&hooks)[i] = reinterpret_cast<void *>(glNoop);
+ }
+
+ virtual void TearDown() {
+ ServerFileTest::TearDown();
+ }
+};
+
+TEST_F(ServerFileContextTest, MessageLoop)
+{
+ static const int arg0 = 45;
+ static const float arg7 = -87.2331f;
+ static const int arg8 = -3;
+ static const int * ret = reinterpret_cast<int *>(870);
+
+ struct Caller : public FunctionCall {
+ const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+ msg.set_arg0(arg0);
+ msg.set_arg7((int &)arg7);
+ msg.set_arg8(arg8);
+ return ret;
+ }
+ } caller;
+ const int contextId = reinterpret_cast<int>(tls.dbg);
+ glesv2debugger::Message msg, read;
+
+ EXPECT_EQ(ret, MessageLoop(caller, msg, msg.glFinish));
+
+ rewind(file);
+ Read(read);
+ EXPECT_EQ(contextId, read.context_id());
+ EXPECT_EQ(read.glFinish, read.function());
+ EXPECT_EQ(false, read.expect_response());
+ EXPECT_EQ(read.BeforeCall, read.type());
+
+ Read(read);
+ EXPECT_EQ(contextId, read.context_id());
+ EXPECT_EQ(read.glFinish, read.function());
+ EXPECT_EQ(false, read.expect_response());
+ EXPECT_EQ(read.AfterCall, read.type());
+ EXPECT_TRUE(read.has_time());
+ EXPECT_EQ(arg0, read.arg0());
+ const int readArg7 = read.arg7();
+ EXPECT_EQ(arg7, (float &)readArg7);
+ EXPECT_EQ(arg8, read.arg8());
+
+ const long pos = ftell(file);
+ fseek(file, 0, SEEK_END);
+ EXPECT_EQ(pos, ftell(file))
+ << "should only write the BeforeCall and AfterCall messages";
+}
+
+TEST_F(ServerFileContextTest, DisableEnableVertexAttribArray)
+{
+ Debug_glEnableVertexAttribArray(tls.dbg->MAX_VERTEX_ATTRIBS + 2); // should just ignore invalid index
+
+ glesv2debugger::Message read;
+ rewind(file);
+ Read(read);
+ EXPECT_EQ(read.glEnableVertexAttribArray, read.function());
+ EXPECT_EQ(tls.dbg->MAX_VERTEX_ATTRIBS + 2, read.arg0());
+ Read(read);
+
+ rewind(file);
+ Debug_glDisableVertexAttribArray(tls.dbg->MAX_VERTEX_ATTRIBS + 4); // should just ignore invalid index
+ rewind(file);
+ Read(read);
+ Read(read);
+
+ for (unsigned int i = 0; i < tls.dbg->MAX_VERTEX_ATTRIBS; i += 5) {
+ rewind(file);
+ Debug_glEnableVertexAttribArray(i);
+ EXPECT_TRUE(tls.dbg->vertexAttribs[i].enabled);
+ rewind(file);
+ Read(read);
+ EXPECT_EQ(read.glEnableVertexAttribArray, read.function());
+ EXPECT_EQ(i, read.arg0());
+ Read(read);
+
+ rewind(file);
+ Debug_glDisableVertexAttribArray(i);
+ EXPECT_FALSE(tls.dbg->vertexAttribs[i].enabled);
+ rewind(file);
+ Read(read);
+ EXPECT_EQ(read.glDisableVertexAttribArray, read.function());
+ EXPECT_EQ(i, read.arg0());
+ Read(read);
+ }
+}
diff --git a/opengl/libs/GLES2_dbg/test/test_socket.cpp b/opengl/libs/GLES2_dbg/test/test_socket.cpp
new file mode 100644
index 0000000..617292e
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/test/test_socket.cpp
@@ -0,0 +1,474 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** 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.
+ */
+
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include "header.h"
+#include "gtest/gtest.h"
+#include "egl_tls.h"
+#include "hooks.h"
+
+namespace android
+{
+extern int serverSock, clientSock;
+extern pthread_key_t dbgEGLThreadLocalStorageKey;
+};
+
+void * glNoop();
+
+class SocketContextTest : public ::testing::Test
+{
+protected:
+ tls_t tls;
+ gl_hooks_t hooks;
+ int sock;
+ char * buffer;
+ unsigned int bufferSize;
+
+ SocketContextTest() : sock(-1) {
+ }
+
+ virtual ~SocketContextTest() {
+ }
+
+ virtual void SetUp() {
+ if (dbgEGLThreadLocalStorageKey == -1)
+ pthread_key_create(&dbgEGLThreadLocalStorageKey, NULL);
+ ASSERT_NE(-1, dbgEGLThreadLocalStorageKey);
+ tls.dbg = new DbgContext(1, &hooks, 32, GL_RGBA, GL_UNSIGNED_BYTE);
+ ASSERT_TRUE(tls.dbg != NULL);
+ pthread_setspecific(dbgEGLThreadLocalStorageKey, &tls);
+ for (unsigned int i = 0; i < sizeof(hooks) / sizeof(void *); i++)
+ ((void **)&hooks)[i] = (void *)glNoop;
+
+ int socks[2] = {-1, -1};
+ ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, socks));
+ clientSock = socks[0];
+ sock = socks[1];
+
+ bufferSize = 128;
+ buffer = new char [128];
+ ASSERT_NE((char *)NULL, buffer);
+ }
+
+ virtual void TearDown() {
+ close(sock);
+ close(clientSock);
+ clientSock = -1;
+ delete buffer;
+ }
+
+ void Write(glesv2debugger::Message & msg) const {
+ msg.set_context_id((int)tls.dbg);
+ msg.set_type(msg.Response);
+ ASSERT_TRUE(msg.has_context_id());
+ ASSERT_TRUE(msg.has_function());
+ ASSERT_TRUE(msg.has_type());
+ ASSERT_TRUE(msg.has_expect_response());
+ static std::string str;
+ msg.SerializeToString(&str);
+ const uint32_t len = str.length();
+ ASSERT_EQ(sizeof(len), send(sock, &len, sizeof(len), 0));
+ ASSERT_EQ(str.length(), send(sock, str.data(), str.length(), 0));
+ }
+
+ void Read(glesv2debugger::Message & msg) {
+ int available = 0;
+ ASSERT_EQ(0, ioctl(sock, FIONREAD, &available));
+ ASSERT_GT(available, 0);
+ uint32_t len = 0;
+ ASSERT_EQ(sizeof(len), recv(sock, &len, sizeof(len), 0));
+ if (len > bufferSize) {
+ bufferSize = len;
+ buffer = new char[bufferSize];
+ ASSERT_TRUE(buffer != NULL);
+ }
+ ASSERT_EQ(len, recv(sock, buffer, len, 0));
+ msg.Clear();
+ msg.ParseFromArray(buffer, len);
+ ASSERT_TRUE(msg.has_context_id());
+ ASSERT_TRUE(msg.has_function());
+ ASSERT_TRUE(msg.has_type());
+ ASSERT_TRUE(msg.has_expect_response());
+ }
+
+ void CheckNoAvailable() {
+ int available = 0;
+ ASSERT_EQ(0, ioctl(sock, FIONREAD, &available));
+ ASSERT_EQ(available, 0);
+ }
+};
+
+TEST_F(SocketContextTest, MessageLoopSkip)
+{
+ static const int arg0 = 45;
+ static const float arg7 = -87.2331f;
+ static const int arg8 = -3;
+ static const int * ret = (int *)870;
+
+ struct Caller : public FunctionCall {
+ const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+ msg.set_arg0(arg0);
+ msg.set_arg7((int &)arg7);
+ msg.set_arg8(arg8);
+ return ret;
+ }
+ } caller;
+ glesv2debugger::Message msg, read, cmd;
+ tls.dbg->expectResponse.Bit(msg.glFinish, true);
+
+ cmd.set_function(cmd.SKIP);
+ cmd.set_expect_response(false);
+ Write(cmd);
+
+ EXPECT_NE(ret, MessageLoop(caller, msg, msg.glFinish));
+
+ Read(read);
+ EXPECT_EQ(read.glFinish, read.function());
+ EXPECT_EQ(read.BeforeCall, read.type());
+ EXPECT_NE(arg0, read.arg0());
+ EXPECT_NE((int &)arg7, read.arg7());
+ EXPECT_NE(arg8, read.arg8());
+
+ CheckNoAvailable();
+}
+
+TEST_F(SocketContextTest, MessageLoopContinue)
+{
+ static const int arg0 = GL_FRAGMENT_SHADER;
+ static const int ret = -342;
+ struct Caller : public FunctionCall {
+ const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+ msg.set_ret(ret);
+ return (int *)ret;
+ }
+ } caller;
+ glesv2debugger::Message msg, read, cmd;
+ tls.dbg->expectResponse.Bit(msg.glCreateShader, true);
+
+ cmd.set_function(cmd.CONTINUE);
+ cmd.set_expect_response(false); // MessageLoop should automatically skip after continue
+ Write(cmd);
+
+ msg.set_arg0(arg0);
+ EXPECT_EQ((int *)ret, MessageLoop(caller, msg, msg.glCreateShader));
+
+ Read(read);
+ EXPECT_EQ(read.glCreateShader, read.function());
+ EXPECT_EQ(read.BeforeCall, read.type());
+ EXPECT_EQ(arg0, read.arg0());
+
+ Read(read);
+ EXPECT_EQ(read.glCreateShader, read.function());
+ EXPECT_EQ(read.AfterCall, read.type());
+ EXPECT_EQ(ret, read.ret());
+
+ CheckNoAvailable();
+}
+
+TEST_F(SocketContextTest, MessageLoopGenerateCall)
+{
+ static const int ret = -342;
+ static unsigned int createShader, createProgram;
+ createShader = 0;
+ createProgram = 0;
+ struct Caller : public FunctionCall {
+ const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+ const int r = (int)_c->glCreateProgram();
+ msg.set_ret(r);
+ return (int *)r;
+ }
+ static GLuint CreateShader(const GLenum type) {
+ createShader++;
+ return type;
+ }
+ static GLuint CreateProgram() {
+ createProgram++;
+ return ret;
+ }
+ } caller;
+ glesv2debugger::Message msg, read, cmd;
+ hooks.gl.glCreateShader = caller.CreateShader;
+ hooks.gl.glCreateProgram = caller.CreateProgram;
+ tls.dbg->expectResponse.Bit(msg.glCreateProgram, true);
+
+ cmd.set_function(cmd.glCreateShader);
+ cmd.set_arg0(GL_FRAGMENT_SHADER);
+ cmd.set_expect_response(true);
+ Write(cmd);
+
+ cmd.Clear();
+ cmd.set_function(cmd.CONTINUE);
+ cmd.set_expect_response(true);
+ Write(cmd);
+
+ cmd.set_function(cmd.glCreateShader);
+ cmd.set_arg0(GL_VERTEX_SHADER);
+ cmd.set_expect_response(false); // MessageLoop should automatically skip afterwards
+ Write(cmd);
+
+ EXPECT_EQ((int *)ret, MessageLoop(caller, msg, msg.glCreateProgram));
+
+ Read(read);
+ EXPECT_EQ(read.glCreateProgram, read.function());
+ EXPECT_EQ(read.BeforeCall, read.type());
+
+ Read(read);
+ EXPECT_EQ(read.glCreateShader, read.function());
+ EXPECT_EQ(read.AfterGeneratedCall, read.type());
+ EXPECT_EQ(GL_FRAGMENT_SHADER, read.ret());
+
+ Read(read);
+ EXPECT_EQ(read.glCreateProgram, read.function());
+ EXPECT_EQ(read.AfterCall, read.type());
+ EXPECT_EQ(ret, read.ret());
+
+ Read(read);
+ EXPECT_EQ(read.glCreateShader, read.function());
+ EXPECT_EQ(read.AfterGeneratedCall, read.type());
+ EXPECT_EQ(GL_VERTEX_SHADER, read.ret());
+
+ EXPECT_EQ(2, createShader);
+ EXPECT_EQ(1, createProgram);
+
+ CheckNoAvailable();
+}
+
+TEST_F(SocketContextTest, MessageLoopSetProp)
+{
+ static const int ret = -342;
+ static unsigned int createShader, createProgram;
+ createShader = 0;
+ createProgram = 0;
+ struct Caller : public FunctionCall {
+ const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+ const int r = (int)_c->glCreateProgram();
+ msg.set_ret(r);
+ return (int *)r;
+ }
+ static GLuint CreateShader(const GLenum type) {
+ createShader++;
+ return type;
+ }
+ static GLuint CreateProgram() {
+ createProgram++;
+ return ret;
+ }
+ } caller;
+ glesv2debugger::Message msg, read, cmd;
+ hooks.gl.glCreateShader = caller.CreateShader;
+ hooks.gl.glCreateProgram = caller.CreateProgram;
+ tls.dbg->expectResponse.Bit(msg.glCreateProgram, false);
+
+ cmd.set_function(cmd.SETPROP);
+ cmd.set_prop(cmd.ExpectResponse);
+ cmd.set_arg0(cmd.glCreateProgram);
+ cmd.set_arg1(true);
+ cmd.set_expect_response(true);
+ Write(cmd);
+
+ cmd.Clear();
+ cmd.set_function(cmd.glCreateShader);
+ cmd.set_arg0(GL_FRAGMENT_SHADER);
+ cmd.set_expect_response(true);
+ Write(cmd);
+
+ cmd.set_function(cmd.SETPROP);
+ cmd.set_prop(cmd.CaptureDraw);
+ cmd.set_arg0(819);
+ cmd.set_expect_response(true);
+ Write(cmd);
+
+ cmd.Clear();
+ cmd.set_function(cmd.CONTINUE);
+ cmd.set_expect_response(true);
+ Write(cmd);
+
+ cmd.set_function(cmd.glCreateShader);
+ cmd.set_arg0(GL_VERTEX_SHADER);
+ cmd.set_expect_response(false); // MessageLoop should automatically skip afterwards
+ Write(cmd);
+
+ EXPECT_EQ((int *)ret, MessageLoop(caller, msg, msg.glCreateProgram));
+
+ EXPECT_TRUE(tls.dbg->expectResponse.Bit(msg.glCreateProgram));
+ EXPECT_EQ(819, tls.dbg->captureDraw);
+
+ Read(read);
+ EXPECT_EQ(read.glCreateProgram, read.function());
+ EXPECT_EQ(read.BeforeCall, read.type());
+
+ Read(read);
+ EXPECT_EQ(read.glCreateShader, read.function());
+ EXPECT_EQ(read.AfterGeneratedCall, read.type());
+ EXPECT_EQ(GL_FRAGMENT_SHADER, read.ret());
+
+ Read(read);
+ EXPECT_EQ(read.glCreateProgram, read.function());
+ EXPECT_EQ(read.AfterCall, read.type());
+ EXPECT_EQ(ret, read.ret());
+
+ Read(read);
+ EXPECT_EQ(read.glCreateShader, read.function());
+ EXPECT_EQ(read.AfterGeneratedCall, read.type());
+ EXPECT_EQ(GL_VERTEX_SHADER, read.ret());
+
+ EXPECT_EQ(2, createShader);
+ EXPECT_EQ(1, createProgram);
+
+ CheckNoAvailable();
+}
+
+TEST_F(SocketContextTest, TexImage2D)
+{
+ static const GLenum _target = GL_TEXTURE_2D;
+ static const GLint _level = 1, _internalformat = GL_RGBA;
+ static const GLsizei _width = 2, _height = 2;
+ static const GLint _border = 333;
+ static const GLenum _format = GL_RGB, _type = GL_UNSIGNED_SHORT_5_6_5;
+ static const short _pixels [_width * _height] = {11, 22, 33, 44};
+ static unsigned int texImage2D;
+ texImage2D = 0;
+
+ struct Caller {
+ static void TexImage2D(GLenum target, GLint level, GLint internalformat,
+ GLsizei width, GLsizei height, GLint border,
+ GLenum format, GLenum type, const GLvoid* pixels) {
+ EXPECT_EQ(_target, target);
+ EXPECT_EQ(_level, level);
+ EXPECT_EQ(_internalformat, internalformat);
+ EXPECT_EQ(_width, width);
+ EXPECT_EQ(_height, height);
+ EXPECT_EQ(_border, border);
+ EXPECT_EQ(_format, format);
+ EXPECT_EQ(_type, type);
+ EXPECT_EQ(0, memcmp(_pixels, pixels, sizeof(_pixels)));
+ texImage2D++;
+ }
+ } caller;
+ glesv2debugger::Message msg, read, cmd;
+ hooks.gl.glTexImage2D = caller.TexImage2D;
+ tls.dbg->expectResponse.Bit(msg.glTexImage2D, false);
+
+ Debug_glTexImage2D(_target, _level, _internalformat, _width, _height, _border,
+ _format, _type, _pixels);
+ EXPECT_EQ(1, texImage2D);
+
+ Read(read);
+ EXPECT_EQ(read.glTexImage2D, read.function());
+ EXPECT_EQ(read.BeforeCall, read.type());
+ EXPECT_EQ(_target, read.arg0());
+ EXPECT_EQ(_level, read.arg1());
+ EXPECT_EQ(_internalformat, read.arg2());
+ EXPECT_EQ(_width, read.arg3());
+ EXPECT_EQ(_height, read.arg4());
+ EXPECT_EQ(_border, read.arg5());
+ EXPECT_EQ(_format, read.arg6());
+ EXPECT_EQ(_type, read.arg7());
+
+ EXPECT_TRUE(read.has_data());
+ uint32_t dataLen = 0;
+ const unsigned char * data = tls.dbg->Decompress(read.data().data(),
+ read.data().length(), &dataLen);
+ EXPECT_EQ(sizeof(_pixels), dataLen);
+ if (sizeof(_pixels) == dataLen)
+ EXPECT_EQ(0, memcmp(_pixels, data, sizeof(_pixels)));
+
+ Read(read);
+ EXPECT_EQ(read.glTexImage2D, read.function());
+ EXPECT_EQ(read.AfterCall, read.type());
+
+ CheckNoAvailable();
+}
+
+TEST_F(SocketContextTest, CopyTexImage2D)
+{
+ static const GLenum _target = GL_TEXTURE_2D;
+ static const GLint _level = 1, _internalformat = GL_RGBA;
+ static const GLint _x = 9, _y = 99;
+ static const GLsizei _width = 2, _height = 3;
+ static const GLint _border = 333;
+ static const int _pixels [_width * _height] = {11, 22, 33, 44, 55, 66};
+ static unsigned int copyTexImage2D, readPixels;
+ copyTexImage2D = 0, readPixels = 0;
+
+ struct Caller {
+ static void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat,
+ GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
+ EXPECT_EQ(_target, target);
+ EXPECT_EQ(_level, level);
+ EXPECT_EQ(_internalformat, internalformat);
+ EXPECT_EQ(_x, x);
+ EXPECT_EQ(_y, y);
+ EXPECT_EQ(_width, width);
+ EXPECT_EQ(_height, height);
+ EXPECT_EQ(_border, border);
+ copyTexImage2D++;
+ }
+ static void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLvoid* pixels) {
+ EXPECT_EQ(_x, x);
+ EXPECT_EQ(_y, y);
+ EXPECT_EQ(_width, width);
+ EXPECT_EQ(_height, height);
+ EXPECT_EQ(GL_RGBA, format);
+ EXPECT_EQ(GL_UNSIGNED_BYTE, type);
+ ASSERT_TRUE(pixels != NULL);
+ memcpy(pixels, _pixels, sizeof(_pixels));
+ readPixels++;
+ }
+ } caller;
+ glesv2debugger::Message msg, read, cmd;
+ hooks.gl.glCopyTexImage2D = caller.CopyTexImage2D;
+ hooks.gl.glReadPixels = caller.ReadPixels;
+ tls.dbg->expectResponse.Bit(msg.glCopyTexImage2D, false);
+
+ Debug_glCopyTexImage2D(_target, _level, _internalformat, _x, _y, _width, _height,
+ _border);
+ ASSERT_EQ(1, copyTexImage2D);
+ ASSERT_EQ(1, readPixels);
+
+ Read(read);
+ EXPECT_EQ(read.glCopyTexImage2D, read.function());
+ EXPECT_EQ(read.BeforeCall, read.type());
+ EXPECT_EQ(_target, read.arg0());
+ EXPECT_EQ(_level, read.arg1());
+ EXPECT_EQ(_internalformat, read.arg2());
+ EXPECT_EQ(_x, read.arg3());
+ EXPECT_EQ(_y, read.arg4());
+ EXPECT_EQ(_width, read.arg5());
+ EXPECT_EQ(_height, read.arg6());
+ EXPECT_EQ(_border, read.arg7());
+
+ EXPECT_TRUE(read.has_data());
+ EXPECT_EQ(read.ReferencedImage, read.data_type());
+ EXPECT_EQ(GL_RGBA, read.pixel_format());
+ EXPECT_EQ(GL_UNSIGNED_BYTE, read.pixel_type());
+ uint32_t dataLen = 0;
+ unsigned char * const data = tls.dbg->Decompress(read.data().data(),
+ read.data().length(), &dataLen);
+ ASSERT_EQ(sizeof(_pixels), dataLen);
+ for (unsigned i = 0; i < sizeof(_pixels) / sizeof(*_pixels); i++)
+ EXPECT_EQ(_pixels[i], ((const int *)data)[i]) << "xor with 0 ref is identity";
+ free(data);
+
+ Read(read);
+ EXPECT_EQ(read.glCopyTexImage2D, read.function());
+ EXPECT_EQ(read.AfterCall, read.type());
+
+ CheckNoAvailable();
+}
diff --git a/opengl/libs/egl_tls.h b/opengl/libs/egl_tls.h
new file mode 100644
index 0000000..087989a
--- /dev/null
+++ b/opengl/libs/egl_tls.h
@@ -0,0 +1,40 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** 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.
+ */
+
+#ifndef ANDROID_EGL_TLS_H
+#define ANDROID_EGL_TLS_H
+
+#include <EGL/egl.h>
+
+#include "glesv2dbg.h"
+
+namespace android
+{
+struct tls_t {
+ tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE), dbg(0) { }
+ ~tls_t() {
+ if (dbg)
+ DestroyDbgContext(dbg);
+ }
+
+ EGLint error;
+ EGLContext ctx;
+ EGLBoolean logCallWithNoContext;
+ DbgContext* dbg;
+};
+}
+
+#endif
diff --git a/opengl/libs/glesv2dbg.h b/opengl/libs/glesv2dbg.h
index 8029dce..ee2c011 100644
--- a/opengl/libs/glesv2dbg.h
+++ b/opengl/libs/glesv2dbg.h
@@ -13,20 +13,27 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-
+
#ifndef _GLESV2_DBG_H_
#define _GLESV2_DBG_H_
+#include <pthread.h>
+
namespace android
{
- struct DbgContext;
-
- DbgContext * CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks);
- void DestroyDbgContext(DbgContext * const dbg);
-
- void StartDebugServer(unsigned short port); // create and bind socket if haven't already
- void StopDebugServer(); // close socket if open
-
+struct DbgContext;
+
+DbgContext * CreateDbgContext(const pthread_key_t EGLThreadLocalStorageKey,
+ const unsigned version, const gl_hooks_t * const hooks);
+
+void DestroyDbgContext(DbgContext * const dbg);
+
+// create and bind socket if haven't already, if failed to create socket or
+// forceUseFile, then open /data/local/tmp/dump.gles2dbg, exit when size reached
+void StartDebugServer(const unsigned short port, const bool forceUseFile,
+ const unsigned int maxFileSize, const char * const filePath);
+void StopDebugServer(); // close socket if open
+
}; // namespace android
#endif // #ifndef _GLESV2_DBG_H_
diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen
index 6c1a231..31f4190 100755
--- a/opengl/tools/glgen/gen
+++ b/opengl/tools/glgen/gen
@@ -21,7 +21,7 @@
echo "package android.graphics;" > out/android/graphics/Canvas.java
echo "public interface Canvas {}" >> out/android/graphics/Canvas.java
-echo "package android.app; import android.content.pm.IPackageManager; public class ActivityThread { public static final ActivityThread currentActivityThread() { return null; } public static final String currentPackageName(){ return null; } public static IPackageManager getPackageManager() { return null;} }" > out/android/app/ActivityThread.java
+echo "package android.app; import android.content.pm.IPackageManager; public class AppGlobals { public static IPackageManager getPackageManager() { return null;} }" > out/android/app/AppGlobals.java
# echo "package android.content; import android.content.pm.PackageManager; public interface Context { public PackageManager getPackageManager(); }" > out/android/content/Context.java
echo "package android.content.pm; public class ApplicationInfo {public int targetSdkVersion;}" > out/android/content/pm/ApplicationInfo.java
echo "package android.content.pm; public interface IPackageManager {ApplicationInfo getApplicationInfo(java.lang.String packageName, int flags) throws android.os.RemoteException;}" > out/android/content/pm/IPackageManager.java
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index 9d8c5a0..9fa2b74 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -58,7 +58,7 @@
} else if (baseType.equals("void")) {
// nothing.
} else {
- throw new RuntimeException("Uknown primitive basetype " + baseType);
+ throw new RuntimeException("Unknown primitive basetype " + baseType);
}
return jniName;
}
@@ -200,15 +200,9 @@
if (emitExceptionCheck) {
out.println(iii + indent + "_exception = 1;");
}
- out.println(iii + indent +
- (mUseCPlusPlus ? "_env" : "(*_env)") +
- "->ThrowNew(" +
- (mUseCPlusPlus ? "" : "_env, ") +
- "IAEClass, " +
- "\"" +
- (isBuffer ?
- "remaining()" : "length - " + offset) +
- " < needed\");");
+ out.println(iii + indent + "jniThrowException(_env, " +
+ "\"java/lang/IllegalArgumentException\", " +
+ "\"" + (isBuffer ? "remaining()" : "length - " + offset) + " < needed\");");
out.println(iii + indent + "goto exit;");
needsExit = true;
out.println(iii + "}");
@@ -302,7 +296,7 @@
}
return false;
}
-
+
String isRequiresFunc(CFunc cfunc) {
String[] checks = mChecker.getChecks(cfunc.getName());
int index = 1;
@@ -329,109 +323,94 @@
}
return null;
}
-
+
void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out,
boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) {
- String[] checks = mChecker.getChecks(cfunc.getName());
+ String[] checks = mChecker.getChecks(cfunc.getName());
- boolean lastWasIfcheck = false;
+ boolean lastWasIfcheck = false;
- int index = 1;
- if (checks != null) {
- while (index < checks.length) {
- if (checks[index].startsWith("check")) {
- if (lastWasIfcheck) {
- printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
- offset, remaining, iii);
- }
- lastWasIfcheck = false;
- if (cname != null && !cname.equals(checks[index + 1])) {
- index += 3;
- continue;
- }
- out.println(iii + "if (" + remaining + " < " +
- checks[index + 2] +
- ") {");
- if (emitExceptionCheck) {
- out.println(iii + indent + "_exception = 1;");
- }
- String exceptionClassName = "IAEClass";
+ int index = 1;
+ if (checks != null) {
+ while (index < checks.length) {
+ if (checks[index].startsWith("check")) {
+ if (lastWasIfcheck) {
+ printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
+ offset, remaining, iii);
+ }
+ lastWasIfcheck = false;
+ if (cname != null && !cname.equals(checks[index + 1])) {
+ index += 3;
+ continue;
+ }
+ out.println(iii + "if (" + remaining + " < " + checks[index + 2] + ") {");
+ if (emitExceptionCheck) {
+ out.println(iii + indent + "_exception = 1;");
+ }
+ String exceptionClassName = "java/lang/IllegalArgumentException";
// If the "check" keyword was of the form
// "check_<class name>", use the class name in the
// exception to be thrown
int underscore = checks[index].indexOf('_');
if (underscore >= 0) {
- exceptionClassName = checks[index].substring(underscore + 1) + "Class";
- }
- out.println(iii + indent +
- (mUseCPlusPlus ? "_env" : "(*_env)") +
- "->ThrowNew(" +
- (mUseCPlusPlus ? "" : "_env, ") +
- exceptionClassName + ", " +
- "\"" +
- (isBuffer ?
- "remaining()" : "length - " + offset) +
- " < " + checks[index + 2] +
- "\");");
-
- out.println(iii + indent + "goto exit;");
- needsExit = true;
- out.println(iii + "}");
-
- index += 3;
- } else if (checks[index].equals("ifcheck")) {
- String[] matches = checks[index + 4].split(",");
-
- if (!lastWasIfcheck) {
- out.println(iii + "int _needed;");
- out.println(iii +
- "switch (" +
- checks[index + 3] +
- ") {");
- }
-
- for (int i = 0; i < matches.length; i++) {
- out.println("#if defined(" + matches[i] + ")");
- out.println(iii +
- " case " +
- matches[i] +
- ":");
- out.println("#endif // defined(" + matches[i] + ")");
- }
- out.println(iii +
- " _needed = " +
- checks[index + 2] +
- ";");
- out.println(iii +
- " break;");
-
- lastWasIfcheck = true;
- index += 5;
- } else if (checks[index].equals("return")) {
- // ignore
- index += 2;
- } else if (checks[index].equals("unsupported")) {
- // ignore
- index += 1;
- } else if (checks[index].equals("requires")) {
- // ignore
- index += 2;
- } else if (checks[index].equals("nullAllowed")) {
- // ignore
- index += 1;
+ String abbr = checks[index].substring(underscore + 1);
+ if (abbr.equals("AIOOBE")) {
+ exceptionClassName = "java/lang/ArrayIndexOutOfBoundsException";
} else {
- System.out.println("Error: unknown keyword \"" +
- checks[index] + "\"");
- System.exit(0);
+ throw new RuntimeException("unknown exception abbreviation: " + abbr);
}
}
- }
+ out.println(iii + indent + "jniThrowException(_env, " +
+ "\"" + exceptionClassName + "\", " +
+ "\"" + (isBuffer ? "remaining()" : "length - " + offset) + " < " + checks[index + 2] + "\");");
- if (lastWasIfcheck) {
- printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii);
+ out.println(iii + indent + "goto exit;");
+ needsExit = true;
+ out.println(iii + "}");
+
+ index += 3;
+ } else if (checks[index].equals("ifcheck")) {
+ String[] matches = checks[index + 4].split(",");
+
+ if (!lastWasIfcheck) {
+ out.println(iii + "int _needed;");
+ out.println(iii + "switch (" + checks[index + 3] + ") {");
+ }
+
+ for (int i = 0; i < matches.length; i++) {
+ out.println("#if defined(" + matches[i] + ")");
+ out.println(iii + " case " + matches[i] + ":");
+ out.println("#endif // defined(" + matches[i] + ")");
+ }
+ out.println(iii + " _needed = " + checks[index + 2] + ";");
+ out.println(iii + " break;");
+
+ lastWasIfcheck = true;
+ index += 5;
+ } else if (checks[index].equals("return")) {
+ // ignore
+ index += 2;
+ } else if (checks[index].equals("unsupported")) {
+ // ignore
+ index += 1;
+ } else if (checks[index].equals("requires")) {
+ // ignore
+ index += 2;
+ } else if (checks[index].equals("nullAllowed")) {
+ // ignore
+ index += 1;
+ } else {
+ System.out.println("Error: unknown keyword \"" + checks[index] + "\"");
+ System.exit(0);
}
}
+ }
+
+ if (lastWasIfcheck) {
+ printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii);
+ }
+ }
boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, List<Integer> nonPrimitiveArgs) {
if (nonPrimitiveArgs.size() > 0) {
@@ -817,7 +796,7 @@
boolean isUnsupported = isUnsupportedFunc(cfunc);
if (isUnsupported) {
out.println(indent +
- "_env->ThrowNew(UOEClass,");
+ "jniThrowException(_env, \"java/lang/UnsupportedOperationException\",");
out.println(indent +
" \"" + cfunc.getName() + "\");");
if (!isVoid) {
@@ -828,13 +807,13 @@
out.println();
return;
}
-
+
String requiresExtension = isRequiresFunc(cfunc);
if (requiresExtension != null) {
out.println(indent +
"if (! supportsExtension(_env, _this, have_" + requiresExtension + "ID)) {");
out.println(indent + indent +
- "_env->ThrowNew(UOEClass,");
+ "jniThrowException(_env, \"java/lang/UnsupportedOperationException\",");
out.println(indent + indent +
" \"" + cfunc.getName() + "\");");
if (isVoid) {
@@ -945,7 +924,8 @@
CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
String decl = type.getDeclaration();
out.println(indent + "if (!" + cname + ") {");
- out.println(indent + " _env->ThrowNew(IAEClass, \"" + cname + " == null\");");
+ out.println(indent + " jniThrowException(_env, " +
+ "\"java/lang/IllegalArgumentException\", \"" + cname + " == null\");");
out.println(indent + " goto exit;");
needsExit = true;
out.println(indent + "}");
@@ -978,13 +958,9 @@
if (emitExceptionCheck) {
out.println(indent + indent + "_exception = 1;");
}
- out.println(indent + " " +
- (mUseCPlusPlus ? "_env" : "(*_env)") +
- "->ThrowNew(" +
- (mUseCPlusPlus ? "" : "_env, ") +
- "IAEClass, " +
- "\"" + cname +
- " == null\");");
+ out.println(indent + " jniThrowException(_env, " +
+ "\"java/lang/IllegalArgumentException\", " +
+ "\"" + cname + " == null\");");
out.println(indent + " goto exit;");
needsExit = true;
out.println(indent + "}");
@@ -993,12 +969,8 @@
if (emitExceptionCheck) {
out.println(indent + indent + "_exception = 1;");
}
- out.println(indent + " " +
- (mUseCPlusPlus ? "_env" : "(*_env)") +
- "->ThrowNew(" +
- (mUseCPlusPlus ? "" : "_env, ") +
- "IAEClass, " +
- "\"" + offset + " < 0\");");
+ out.println(indent + " jniThrowException(_env, " +
+ "\"java/lang/IllegalArgumentException\", \"" + offset + " < 0\");");
out.println(indent + " goto exit;");
needsExit = true;
out.println(indent + "}");
diff --git a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
index 294d1ce..5d418d7 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
@@ -1,21 +1,23 @@
**
** Copyright 2009, The Android Open Source Project
**
-** 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
+** 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
+** 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
+** 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.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -27,10 +29,6 @@
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
@@ -41,7 +39,7 @@
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -63,26 +61,6 @@
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -103,13 +81,13 @@
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -122,4 +100,3 @@
}
// --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
index e1c09f4..35a3c33 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
@@ -1,21 +1,23 @@
**
** Copyright 2009, The Android Open Source Project
**
-** 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
+** 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
+** 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
+** 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.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -40,10 +42,6 @@
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
@@ -54,7 +52,7 @@
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -75,26 +73,6 @@
_env->GetFieldID(bufferClass, "_elementSizeShift", "I");
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -115,13 +93,13 @@
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -140,7 +118,8 @@
jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
buf += position << elementSizeShift;
} else {
- _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Must use a native order direct Buffer");
}
return (void*) buf;
}
@@ -153,4 +132,3 @@
}
// --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
index 2548b32..9b29a44 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
@@ -1,21 +1,23 @@
**
** Copyright 2009, The Android Open Source Project
**
-** 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
+** 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
+** 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
+** 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.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -36,10 +38,6 @@
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
@@ -50,7 +48,7 @@
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -72,26 +70,6 @@
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -112,13 +90,13 @@
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -138,9 +116,9 @@
jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
buf += position << elementSizeShift;
} else {
- _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Must use a native order direct Buffer");
}
return (void*) buf;
}
// --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
index 4c297f7..823079f 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
@@ -1,21 +1,23 @@
**
** Copyright 2009, The Android Open Source Project
**
-** 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
+** 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
+** 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
+** 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.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -34,10 +36,6 @@
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
@@ -48,7 +46,7 @@
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -70,26 +68,6 @@
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -110,13 +88,13 @@
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -136,10 +114,10 @@
jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
buf += position << elementSizeShift;
} else {
- _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Must use a native order direct Buffer");
}
return (void*) buf;
}
// --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
index e451e9a..13a2577 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
@@ -1,21 +1,23 @@
**
** Copyright 2009, The Android Open Source Project
**
-** 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
+** 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
+** 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
+** 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.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -27,10 +29,6 @@
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
@@ -41,7 +39,7 @@
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -63,26 +61,6 @@
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -103,13 +81,13 @@
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -129,7 +107,8 @@
jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
buf += position << elementSizeShift;
} else {
- _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Must use a native order direct Buffer");
}
return (void*) buf;
}
@@ -147,4 +126,3 @@
}
// --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp b/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp
index d92f515..ce6ab24 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp
@@ -1,27 +1,19 @@
-#include <string.h>
+#include <stdlib.h>
/* void glGetProgramInfoLog ( GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog ) */
-static
-jstring
-android_glGetProgramInfoLog (JNIEnv *_env, jobject _this, jint shader) {
+static jstring android_glGetProgramInfoLog(JNIEnv *_env, jobject, jint shader) {
GLint infoLen = 0;
- jstring _result = 0;
- char* buf = 0;
glGetProgramiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
- if (infoLen) {
- char* buf = (char*) malloc(infoLen);
- if (buf == 0) {
- _env->ThrowNew(IAEClass, "out of memory");
- goto exit;
- }
- glGetProgramInfoLog(shader, infoLen, NULL, buf);
- _result = _env->NewStringUTF(buf);
- } else {
- _result = _env->NewStringUTF("");
+ if (!infoLen) {
+ return _env->NewStringUTF("");
}
-exit:
- if (buf) {
- free(buf);
+ char* buf = (char*) malloc(infoLen);
+ if (buf == NULL) {
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory");
+ return NULL;
}
- return _result;
-}
\ No newline at end of file
+ glGetProgramInfoLog(shader, infoLen, NULL, buf);
+ jstring result = _env->NewStringUTF(buf);
+ free(buf);
+ return result;
+}
diff --git a/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp b/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp
index 5441d66..dd656b6 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp
@@ -1,27 +1,19 @@
-#include <string.h>
+#include <stdlib.h>
/* void glGetShaderInfoLog ( GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog ) */
-static
-jstring
-android_glGetShaderInfoLog (JNIEnv *_env, jobject _this, jint shader) {
+static jstring android_glGetShaderInfoLog(JNIEnv *_env, jobject, jint shader) {
GLint infoLen = 0;
- jstring _result = 0;
- char* buf = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
- if (infoLen) {
- char* buf = (char*) malloc(infoLen);
- if (buf == 0) {
- _env->ThrowNew(IAEClass, "out of memory");
- goto exit;
- }
- glGetShaderInfoLog(shader, infoLen, NULL, buf);
- _result = _env->NewStringUTF(buf);
- } else {
- _result = _env->NewStringUTF("");
+ if (!infoLen) {
+ return _env->NewStringUTF("");
}
-exit:
- if (buf) {
- free(buf);
+ char* buf = (char*) malloc(infoLen);
+ if (buf == NULL) {
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory");
+ return NULL;
}
- return _result;
-}
\ No newline at end of file
+ glGetShaderInfoLog(shader, infoLen, NULL, buf);
+ jstring result = _env->NewStringUTF(buf);
+ free(buf);
+ return result;
+}
diff --git a/opengl/tools/glgen/stubs/gles11/glGetString.cpp b/opengl/tools/glgen/stubs/gles11/glGetString.cpp
index a400859..239fe4a 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetString.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetString.cpp
@@ -1,11 +1,5 @@
-#include <string.h>
-
/* const GLubyte * glGetString ( GLenum name ) */
-static
-jstring
-android_glGetString
- (JNIEnv *_env, jobject _this, jint name) {
- const char * chars = (const char *)glGetString((GLenum)name);
- jstring output = _env->NewStringUTF(chars);
- return output;
+static jstring android_glGetString(JNIEnv* _env, jobject, jint name) {
+ const char* chars = (const char*) glGetString((GLenum) name);
+ return _env->NewStringUTF(chars);
}
diff --git a/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp b/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp
index c274108..125fd0f 100644
--- a/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp
@@ -6,7 +6,7 @@
(JNIEnv *_env, jobject _this, jint shader, jstring string) {
if (!string) {
- _env->ThrowNew(IAEClass, "string == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "string == null");
return;
}
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index c2464b0..f7315ee 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -1,21 +1,23 @@
**
** Copyright 2006, The Android Open Source Project
**
-** 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
+** 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
+** 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
+** 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.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -63,10 +65,6 @@
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jclass G11ImplClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
@@ -84,7 +82,7 @@
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -114,26 +112,6 @@
_env->GetFieldID(bufferClass, "_elementSizeShift", "I");
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -154,7 +132,7 @@
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
if (*array == NULL) {
@@ -163,7 +141,7 @@
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -207,7 +185,8 @@
releasePointer(_env, array, buf, 0);
}
} else {
- _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Must use a native order direct Buffer");
}
}
return buf;
@@ -250,7 +229,7 @@
}
}
}
-
+
static bool
checkForExtension(const GLubyte* pExtensions, const GLubyte* pExtension) {
for (;*pExtensions != '\0'; pExtensions = nextExtension(pExtensions)) {
@@ -279,4 +258,3 @@
}
// --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
index 3727106..cd730aa 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
+++ b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
@@ -18,7 +18,7 @@
package com.google.android.gles_jni;
-import android.app.ActivityThread;
+import android.app.AppGlobals;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.os.Build;
@@ -64,7 +64,7 @@
private static boolean allowIndirectBuffers(String appName) {
boolean result = false;
int version = 0;
- IPackageManager pm = ActivityThread.getPackageManager();
+ IPackageManager pm = AppGlobals.getPackageManager();
try {
ApplicationInfo applicationInfo = pm.getApplicationInfo(appName, 0);
if (applicationInfo != null) {
diff --git a/opengl/tools/glgen/stubs/jsr239/glGetString.cpp b/opengl/tools/glgen/stubs/jsr239/glGetString.cpp
index a400859..cd6e3f3 100644
--- a/opengl/tools/glgen/stubs/jsr239/glGetString.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/glGetString.cpp
@@ -1,11 +1,5 @@
-#include <string.h>
-
/* const GLubyte * glGetString ( GLenum name ) */
-static
-jstring
-android_glGetString
- (JNIEnv *_env, jobject _this, jint name) {
- const char * chars = (const char *)glGetString((GLenum)name);
- jstring output = _env->NewStringUTF(chars);
- return output;
+static jstring android_glGetString(JNIEnv *_env, jobject, jint name) {
+ const char* chars = (const char*) glGetString((GLenum) name);
+ return _env->NewStringUTF(chars);
}
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 64cff96..a774841 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -93,7 +93,11 @@
int DisplayHardware::getHeight() const { return mHeight; }
PixelFormat DisplayHardware::getFormat() const { return mFormat; }
uint32_t DisplayHardware::getMaxTextureSize() const { return mMaxTextureSize; }
-uint32_t DisplayHardware::getMaxViewportDims() const { return mMaxViewportDims; }
+
+uint32_t DisplayHardware::getMaxViewportDims() const {
+ return mMaxViewportDims[0] < mMaxViewportDims[1] ?
+ mMaxViewportDims[0] : mMaxViewportDims[1];
+}
void DisplayHardware::init(uint32_t dpy)
{
@@ -228,7 +232,7 @@
eglQueryString(display, EGL_EXTENSIONS));
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
- glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &mMaxViewportDims);
+ glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
#ifdef EGL_ANDROID_swap_rectangle
@@ -260,7 +264,7 @@
LOGI("version : %s", extensions.getVersion());
LOGI("extensions: %s", extensions.getExtension());
LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
- LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims);
+ LOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]);
LOGI("flags = %08x", mFlags);
// Unbind the context from this thread
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index ee7a2af..cdf89fd 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -108,7 +108,7 @@
PixelFormat mFormat;
uint32_t mFlags;
mutable uint32_t mPageFlipCount;
- GLint mMaxViewportDims;
+ GLint mMaxViewportDims[2];
GLint mMaxTextureSize;
HWComposer* mHwc;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
index 90865da..59b7e5a 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -38,23 +38,10 @@
#include "SurfaceFlinger.h"
// ----------------------------------------------------------------------------
-// the sim build doesn't have gettid
-
-#ifndef HAVE_GETTID
-# define gettid getpid
-#endif
-
-// ----------------------------------------------------------------------------
namespace android {
-static char const * kSleepFileName = "/sys/power/wait_for_fb_sleep";
-static char const * kWakeFileName = "/sys/power/wait_for_fb_wake";
-static char const * const kOldSleepFileName = "/sys/android_power/wait_for_fb_sleep";
-static char const * const kOldWakeFileName = "/sys/android_power/wait_for_fb_wake";
-
-// This dir exists if the framebuffer console is present, either built into
-// the kernel or loaded as a module.
-static char const * const kFbconSysDir = "/sys/class/graphics/fbcon";
+static char const * const kSleepFileName = "/sys/power/wait_for_fb_sleep";
+static char const * const kWakeFileName = "/sys/power/wait_for_fb_wake";
// ----------------------------------------------------------------------------
@@ -122,237 +109,13 @@
status_t DisplayHardwareBase::DisplayEventThread::readyToRun()
{
- if (access(kSleepFileName, R_OK) || access(kWakeFileName, R_OK)) {
- if (access(kOldSleepFileName, R_OK) || access(kOldWakeFileName, R_OK)) {
- LOGE("Couldn't open %s or %s", kSleepFileName, kWakeFileName);
- return NO_INIT;
- }
- kSleepFileName = kOldSleepFileName;
- kWakeFileName = kOldWakeFileName;
- }
return NO_ERROR;
}
status_t DisplayHardwareBase::DisplayEventThread::initCheck() const
{
- return (((access(kSleepFileName, R_OK) == 0 &&
- access(kWakeFileName, R_OK) == 0) ||
- (access(kOldSleepFileName, R_OK) == 0 &&
- access(kOldWakeFileName, R_OK) == 0)) &&
- access(kFbconSysDir, F_OK) != 0) ? NO_ERROR : NO_INIT;
-}
-
-// ----------------------------------------------------------------------------
-
-pid_t DisplayHardwareBase::ConsoleManagerThread::sSignalCatcherPid = 0;
-
-DisplayHardwareBase::ConsoleManagerThread::ConsoleManagerThread(
- const sp<SurfaceFlinger>& flinger)
- : DisplayEventThreadBase(flinger), consoleFd(-1)
-{
- sSignalCatcherPid = 0;
-
- // create a new console
- char const * const ttydev = "/dev/tty0";
- int fd = open(ttydev, O_RDWR | O_SYNC);
- if (fd<0) {
- LOGE("Can't open %s", ttydev);
- this->consoleFd = -errno;
- return;
- }
-
- // to make sure that we are in text mode
- int res = ioctl(fd, KDSETMODE, (void*) KD_TEXT);
- if (res<0) {
- LOGE("ioctl(%d, KDSETMODE, ...) failed, res %d (%s)",
- fd, res, strerror(errno));
- }
-
- // get the current console
- struct vt_stat vs;
- res = ioctl(fd, VT_GETSTATE, &vs);
- if (res<0) {
- LOGE("ioctl(%d, VT_GETSTATE, ...) failed, res %d (%s)",
- fd, res, strerror(errno));
- this->consoleFd = -errno;
- return;
- }
-
- // switch to console 7 (which is what X normaly uses)
- int vtnum = 7;
- do {
- res = ioctl(fd, VT_ACTIVATE, (void*)vtnum);
- } while(res < 0 && errno == EINTR);
- if (res<0) {
- LOGE("ioctl(%d, VT_ACTIVATE, ...) failed, %d (%s) for %d",
- fd, errno, strerror(errno), vtnum);
- this->consoleFd = -errno;
- return;
- }
-
- do {
- res = ioctl(fd, VT_WAITACTIVE, (void*)vtnum);
- } while(res < 0 && errno == EINTR);
- if (res<0) {
- LOGE("ioctl(%d, VT_WAITACTIVE, ...) failed, %d %d %s for %d",
- fd, res, errno, strerror(errno), vtnum);
- this->consoleFd = -errno;
- return;
- }
-
- // open the new console
- close(fd);
- fd = open(ttydev, O_RDWR | O_SYNC);
- if (fd<0) {
- LOGE("Can't open new console %s", ttydev);
- this->consoleFd = -errno;
- return;
- }
-
- /* disable console line buffer, echo, ... */
- struct termios ttyarg;
- ioctl(fd, TCGETS , &ttyarg);
- ttyarg.c_iflag = 0;
- ttyarg.c_lflag = 0;
- ioctl(fd, TCSETS , &ttyarg);
-
- // set up signals so we're notified when the console changes
- // we can't use SIGUSR1 because it's used by the java-vm
- vm.mode = VT_PROCESS;
- vm.waitv = 0;
- vm.relsig = SIGUSR2;
- vm.acqsig = SIGUNUSED;
- vm.frsig = 0;
-
- struct sigaction act;
- sigemptyset(&act.sa_mask);
- act.sa_handler = sigHandler;
- act.sa_flags = 0;
- sigaction(vm.relsig, &act, NULL);
-
- sigemptyset(&act.sa_mask);
- act.sa_handler = sigHandler;
- act.sa_flags = 0;
- sigaction(vm.acqsig, &act, NULL);
-
- sigset_t mask;
- sigemptyset(&mask);
- sigaddset(&mask, vm.relsig);
- sigaddset(&mask, vm.acqsig);
- sigprocmask(SIG_BLOCK, &mask, NULL);
-
- // switch to graphic mode
- res = ioctl(fd, KDSETMODE, (void*)KD_GRAPHICS);
- LOGW_IF(res<0,
- "ioctl(%d, KDSETMODE, KD_GRAPHICS) failed, res %d", fd, res);
-
- this->prev_vt_num = vs.v_active;
- this->vt_num = vtnum;
- this->consoleFd = fd;
-}
-
-DisplayHardwareBase::ConsoleManagerThread::~ConsoleManagerThread()
-{
- if (this->consoleFd >= 0) {
- int fd = this->consoleFd;
- int prev_vt_num = this->prev_vt_num;
- int res;
- ioctl(fd, KDSETMODE, (void*)KD_TEXT);
- do {
- res = ioctl(fd, VT_ACTIVATE, (void*)prev_vt_num);
- } while(res < 0 && errno == EINTR);
- do {
- res = ioctl(fd, VT_WAITACTIVE, (void*)prev_vt_num);
- } while(res < 0 && errno == EINTR);
- close(fd);
- char const * const ttydev = "/dev/tty0";
- fd = open(ttydev, O_RDWR | O_SYNC);
- ioctl(fd, VT_DISALLOCATE, 0);
- close(fd);
- }
-}
-
-status_t DisplayHardwareBase::ConsoleManagerThread::readyToRun()
-{
- if (this->consoleFd >= 0) {
- sSignalCatcherPid = gettid();
-
- sigset_t mask;
- sigemptyset(&mask);
- sigaddset(&mask, vm.relsig);
- sigaddset(&mask, vm.acqsig);
- sigprocmask(SIG_BLOCK, &mask, NULL);
-
- int res = ioctl(this->consoleFd, VT_SETMODE, &vm);
- if (res<0) {
- LOGE("ioctl(%d, VT_SETMODE, ...) failed, %d (%s)",
- this->consoleFd, errno, strerror(errno));
- }
- return NO_ERROR;
- }
- return this->consoleFd;
-}
-
-void DisplayHardwareBase::ConsoleManagerThread::requestExit()
-{
- Thread::requestExit();
- if (sSignalCatcherPid != 0) {
- // wake the thread up
- kill(sSignalCatcherPid, SIGINT);
- // wait for it...
- }
-}
-
-void DisplayHardwareBase::ConsoleManagerThread::sigHandler(int sig)
-{
- // resend the signal to our signal catcher thread
- LOGW("received signal %d in thread %d, resending to %d",
- sig, gettid(), sSignalCatcherPid);
-
- // we absolutely need the delays below because without them
- // our main thread never gets a chance to handle the signal.
- usleep(10000);
- kill(sSignalCatcherPid, sig);
- usleep(10000);
-}
-
-status_t DisplayHardwareBase::ConsoleManagerThread::releaseScreen() const
-{
- int fd = this->consoleFd;
- int err = ioctl(fd, VT_RELDISP, (void*)1);
- LOGE_IF(err<0, "ioctl(%d, VT_RELDISP, 1) failed %d (%s)",
- fd, errno, strerror(errno));
- return (err<0) ? (-errno) : status_t(NO_ERROR);
-}
-
-bool DisplayHardwareBase::ConsoleManagerThread::threadLoop()
-{
- sigset_t mask;
- sigemptyset(&mask);
- sigaddset(&mask, vm.relsig);
- sigaddset(&mask, vm.acqsig);
-
- int sig = 0;
- sigwait(&mask, &sig);
-
- if (sig == vm.relsig) {
- sp<SurfaceFlinger> flinger = mFlinger.promote();
- //LOGD("About to give-up screen, flinger = %p", flinger.get());
- if (flinger != 0)
- flinger->screenReleased(0);
- } else if (sig == vm.acqsig) {
- sp<SurfaceFlinger> flinger = mFlinger.promote();
- //LOGD("Screen about to return, flinger = %p", flinger.get());
- if (flinger != 0)
- flinger->screenAcquired(0);
- }
-
- return true;
-}
-
-status_t DisplayHardwareBase::ConsoleManagerThread::initCheck() const
-{
- return consoleFd >= 0 ? NO_ERROR : NO_INIT;
+ return ((access(kSleepFileName, R_OK) == 0 &&
+ access(kWakeFileName, R_OK) == 0)) ? NO_ERROR : NO_INIT;
}
// ----------------------------------------------------------------------------
@@ -362,10 +125,6 @@
: mCanDraw(true), mScreenAcquired(true)
{
mDisplayEventThread = new DisplayEventThread(flinger);
- if (mDisplayEventThread->initCheck() != NO_ERROR) {
- // fall-back on the console
- mDisplayEventThread = new ConsoleManagerThread(flinger);
- }
}
DisplayHardwareBase::~DisplayHardwareBase()
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
index fa6a0c4..30eb258 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
@@ -73,24 +73,6 @@
virtual status_t initCheck() const;
};
- class ConsoleManagerThread : public DisplayEventThreadBase
- {
- int consoleFd;
- int vt_num;
- int prev_vt_num;
- vt_mode vm;
- static void sigHandler(int sig);
- static pid_t sSignalCatcherPid;
- public:
- ConsoleManagerThread(const sp<SurfaceFlinger>& flinger);
- virtual ~ConsoleManagerThread();
- virtual bool threadLoop();
- virtual status_t readyToRun();
- virtual void requestExit();
- virtual status_t releaseScreen() const;
- virtual status_t initCheck() const;
- };
-
sp<DisplayEventThreadBase> mDisplayEventThread;
mutable int mCanDraw;
mutable int mScreenAcquired;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ea283c6..7506f29 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1241,8 +1241,10 @@
return orientation;
}
-sp<ISurface> SurfaceFlinger::createSurface(const sp<Client>& client, int pid,
- const String8& name, ISurfaceComposerClient::surface_data_t* params,
+sp<ISurface> SurfaceFlinger::createSurface(
+ ISurfaceComposerClient::surface_data_t* params,
+ const String8& name,
+ const sp<Client>& client,
DisplayID d, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags)
{
@@ -2414,12 +2416,12 @@
return -1;
}
sp<ISurface> Client::createSurface(
- ISurfaceComposerClient::surface_data_t* params, int pid,
+ ISurfaceComposerClient::surface_data_t* params,
const String8& name,
DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags)
{
- return mFlinger->createSurface(this, pid, name, params,
+ return mFlinger->createSurface(params, name, this,
display, w, h, format, flags);
}
status_t Client::destroySurface(SurfaceID sid) {
@@ -2523,7 +2525,7 @@
}
sp<ISurface> UserClient::createSurface(
- ISurfaceComposerClient::surface_data_t* params, int pid,
+ ISurfaceComposerClient::surface_data_t* params,
const String8& name,
DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags) {
@@ -2553,22 +2555,9 @@
LOGE("createGraphicBuffer: unable to create GraphicBuffer");
return 0;
}
- Mutex::Autolock _l(mLock);
- mBuffers.add(graphicBuffer);
return graphicBuffer;
}
-void GraphicBufferAlloc::freeAllGraphicBuffersExcept(int bufIdx) {
- Mutex::Autolock _l(mLock);
- if (bufIdx >= 0 && size_t(bufIdx) < mBuffers.size()) {
- sp<GraphicBuffer> b(mBuffers[bufIdx]);
- mBuffers.clear();
- mBuffers.add(b);
- } else {
- mBuffers.clear();
- }
-}
-
// ---------------------------------------------------------------------------
GraphicPlane::GraphicPlane()
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0964848..1b36d1c 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -75,7 +75,7 @@
virtual sp<IMemoryHeap> getControlBlock() const;
virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const;
virtual sp<ISurface> createSurface(
- surface_data_t* params, int pid, const String8& name,
+ surface_data_t* params, const String8& name,
DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
uint32_t flags);
virtual status_t destroySurface(SurfaceID surfaceId);
@@ -107,7 +107,7 @@
virtual sp<IMemoryHeap> getControlBlock() const;
virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const;
virtual sp<ISurface> createSurface(
- surface_data_t* params, int pid, const String8& name,
+ surface_data_t* params, const String8& name,
DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
uint32_t flags);
virtual status_t destroySurface(SurfaceID surfaceId);
@@ -125,14 +125,8 @@
public:
GraphicBufferAlloc();
virtual ~GraphicBufferAlloc();
-
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
PixelFormat format, uint32_t usage);
- virtual void freeAllGraphicBuffersExcept(int bufIdx);
-
-private:
- Vector<sp<GraphicBuffer> > mBuffers;
- Mutex mLock;
};
// ---------------------------------------------------------------------------
@@ -238,9 +232,10 @@
friend class Layer;
friend class LayerDim;
- sp<ISurface> createSurface(const sp<Client>& client,
- int pid, const String8& name,
+ sp<ISurface> createSurface(
ISurfaceComposerClient::surface_data_t* params,
+ const String8& name,
+ const sp<Client>& client,
DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags);