summaryrefslogtreecommitdiffstats
path: root/core/jni/android/graphics/NIOBuffer.cpp
blob: cb937a36ed9b2c39090b24a6214bbc13fe07cae8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include "NIOBuffer.h"
#include "GraphicsJNI.h"

// enable this to dump each time we ref/unref a global java object (buffer)
//
//#define TRACE_GLOBAL_REFS

//#define TRACE_ARRAY_LOCKS

static jclass gNIOAccess_classID;
static jmethodID gNIOAccess_getBasePointer;
static jmethodID gNIOAccess_getBaseArray;
static jmethodID gNIOAccess_getBaseArrayOffset;
static jmethodID gNIOAccess_getRemainingBytes;

void NIOBuffer::RegisterJNI(JNIEnv* env) {
    if (0 != gNIOAccess_classID) {
        return; // already called
    }

    jclass c = env->FindClass("java/nio/NIOAccess");
    gNIOAccess_classID = (jclass)env->NewGlobalRef(c);

    gNIOAccess_getBasePointer = env->GetStaticMethodID(gNIOAccess_classID,
                                    "getBasePointer", "(Ljava/nio/Buffer;)J");
    gNIOAccess_getBaseArray = env->GetStaticMethodID(gNIOAccess_classID,
                    "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
    gNIOAccess_getBaseArrayOffset = env->GetStaticMethodID(gNIOAccess_classID,
                                "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
    gNIOAccess_getRemainingBytes = env->GetStaticMethodID(gNIOAccess_classID,
                                "getRemainingBytes", "(Ljava/nio/Buffer;)I");
}

///////////////////////////////////////////////////////////////////////////////

#ifdef TRACE_GLOBAL_REFS
    static int gGlobalRefs;
#endif

#ifdef TRACE_ARRAY_LOCKS
    static int gLockCount;
#endif

NIOBuffer::NIOBuffer(JNIEnv* env, jobject buffer) {
    fBuffer = env->NewGlobalRef(buffer);
#ifdef TRACE_GLOBAL_REFS
    SkDebugf("------------ newglobalref bbuffer %X %d\n", buffer, gGlobalRefs++);
#endif
    fLockedPtr = NULL;
    fLockedArray = NULL;
}

NIOBuffer::~NIOBuffer() {
    // free() needs to have already been called
    if (NULL != fBuffer) {
        SkDebugf("----- leaked fBuffer in NIOBuffer");
        sk_throw();
    }
}

void NIOBuffer::free(JNIEnv* env) {

    if (NULL != fLockedPtr) {
        SkDebugf("======= free: array still locked %x %p\n", fLockedArray, fLockedPtr);
    }
    
    
    if (NULL != fBuffer) {
#ifdef TRACE_GLOBAL_REFS
        SkDebugf("----------- deleteglobalref buffer %X %d\n", fBuffer, --gGlobalRefs);
#endif
        env->DeleteGlobalRef(fBuffer);
        fBuffer = NULL;
    }
}

void* NIOBuffer::lock(JNIEnv* env, int* remaining) {
    if (NULL != fLockedPtr) {
        SkDebugf("======= lock: array still locked %x %p\n", fLockedArray, fLockedPtr);
    }

    fLockedPtr = NULL;
    fLockedArray = NULL;

    if (NULL != remaining) {
        *remaining = env->CallStaticIntMethod(gNIOAccess_classID,
                                              gNIOAccess_getRemainingBytes,
                                              fBuffer);
        if (GraphicsJNI::hasException(env)) {
            return NULL;
        }
    }
    
    jlong pointer = env->CallStaticLongMethod(gNIOAccess_classID,
                                              gNIOAccess_getBasePointer,
                                              fBuffer);
    if (GraphicsJNI::hasException(env)) {
        return NULL;
    }
    if (0 != pointer) {
        return reinterpret_cast<void*>(pointer);
    }
    
    fLockedArray = (jbyteArray)env->CallStaticObjectMethod(gNIOAccess_classID,
                                                        gNIOAccess_getBaseArray,
                                                        fBuffer);
    if (GraphicsJNI::hasException(env) || NULL == fLockedArray) {
        return NULL;
    }
    jint offset = env->CallStaticIntMethod(gNIOAccess_classID,
                                           gNIOAccess_getBaseArrayOffset,
                                           fBuffer);
    fLockedPtr = env->GetByteArrayElements(fLockedArray, NULL);
    if (GraphicsJNI::hasException(env)) {
        SkDebugf("------------ failed to lockarray %x\n", fLockedArray);
        return NULL;
    }
#ifdef TRACE_ARRAY_LOCKS
    SkDebugf("------------ lockarray %x %p %d\n",
             fLockedArray, fLockedPtr, gLockCount++);
#endif
    if (NULL == fLockedPtr) {
        offset = 0;
    }
    return (char*)fLockedPtr + offset;
}

void NIOBuffer::unlock(JNIEnv* env, bool dataChanged) {
    if (NULL != fLockedPtr) {
#ifdef TRACE_ARRAY_LOCKS
        SkDebugf("------------ unlockarray %x %p %d\n",
                 fLockedArray, fLockedPtr, --gLockCount);
#endif
        env->ReleaseByteArrayElements(fLockedArray, (jbyte*)fLockedPtr,
                                      dataChanged ? 0 : JNI_ABORT);
        
        fLockedPtr = NULL;
        fLockedArray = NULL;
    } else {
        SkDebugf("============= unlock called with null ptr %x\n", fLockedArray);
    }
}