Project

General

Profile

Download (9.6 KB) Statistics
| Branch: | Revision:

library / src / main / java / org / distorted / library / main / InternalObject.java @ 9519d1b1

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2016 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted is free software: you can redistribute it and/or modify                             //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Distorted is distributed in the hope that it will be useful,                                  //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.library.main;
21

    
22
import java.util.ArrayList;
23
import java.util.HashMap;
24
import java.util.LinkedList;
25

    
26
///////////////////////////////////////////////////////////////////////////////////////////////////
27
/**
28
 * Any Object which gets uploaded to GPU memory and thus needs to be re-created (transparently to
29
 * applications!) whenever we lose OpenGL context.
30
 *
31
 * Keep all objects created in a static LinkedList. The point: we need to be able to mark
32
 * Objects for deletion, and delete all marked Objects later at a convenient time (that's
33
 * because we can only delete from a thread that holds the OpenGL context so here we provide a
34
 * framework where one is able to mark for deletion at any time and actual deletion takes place
35
 * on the next render).
36
*/
37
abstract class InternalObject
38
{
39
  static final int FAILED_TO_CREATE = 1;
40
  static final int NOT_CREATED_YET  = 2;
41
  static final int DONT_CREATE      = 3;
42
  static final int CREATED          = 4;
43

    
44
  static final int TYPE_USER = 0;
45
  static final int TYPE_TREE = 1;
46
  static final int TYPE_SYST = 2;
47

    
48
  private static final int JOB_CREATE = 0;
49
  private static final int JOB_DELETE = 1;
50

    
51
  private final static Object mLock = new Object();
52

    
53
  private long mID;
54
  private int mType;
55

    
56
  /////////////////////////////////////////////////////////////////
57

    
58
  private static class Job
59
    {
60
    InternalObject object;
61
    int action;
62

    
63
    Job(InternalObject o, int a)
64
      {
65
      object = o;
66
      action = a;
67
      }
68
    }
69

    
70
  /////////////////////////////////////////////////////////////////
71

    
72
  private static boolean mToDo = false;
73
  private static StackFrame mCurrentFrame = null;
74
  private static ArrayList<StackFrame> mFrameList = new ArrayList<>();
75

    
76
  /////////////////////////////////////////////////////////////////
77

    
78
  private static class StackFrame
79
    {
80
    private LinkedList<InternalObject> mDoneList;
81
    private HashMap<Long,Job> mToDoMap;
82
    private long mNextClientID;
83
    private long mNextSystemID;
84

    
85
    /////////////////////////////////////////////////////////
86

    
87
    StackFrame()
88
      {
89
      mDoneList = new LinkedList<>();
90
      mToDoMap  = new HashMap<>();
91
      mNextClientID = 0;
92
      mNextSystemID = 0;
93
      }
94

    
95
    /////////////////////////////////////////////////////////
96

    
97
    void onPause()
98
      {
99
      int num = mDoneList.size();
100

    
101
      try
102
        {
103
        for (int i=0; i<num; i++)
104
          {
105
          InternalObject object = mDoneList.removeFirst();
106
          Job job = new Job(object, JOB_CREATE);
107
          mToDoMap.put(object.mID,job);
108
          object.recreate();
109
          }
110
        }
111
      catch( Exception ignored )
112
        {
113
        // something else removed an object in the meantime; ignore
114
        }
115
      }
116

    
117
    /////////////////////////////////////////////////////////
118

    
119
    void toDo()
120
      {
121
      for(Long key: mToDoMap.keySet())
122
        {
123
        Job job = mToDoMap.get(key);
124
        InternalObject object = job.object;
125

    
126
        if( job.action==JOB_CREATE )
127
          {
128
          object.create();
129
          mDoneList.add(object);
130
          }
131
        else if( job.action==JOB_DELETE )
132
          {
133
          object.delete();
134
          }
135
        }
136

    
137
      mToDoMap.clear();
138
      }
139

    
140
    /////////////////////////////////////////////////////////
141

    
142
    long generateID(int type)
143
      {
144
      return type==TYPE_SYST ? --mNextSystemID : ++mNextClientID;
145
      }
146

    
147
    /////////////////////////////////////////////////////////
148

    
149
    void addToDoneList(InternalObject obj)
150
      {
151
      mDoneList.add(obj);
152
      }
153

    
154

    
155
    /////////////////////////////////////////////////////////
156

    
157
    void markFor(InternalObject obj, long id, int jobType)
158
      {
159
      mDoneList.remove(obj);
160
      mToDoMap.put(id, new Job(obj,jobType) );
161
      }
162

    
163
    /////////////////////////////////////////////////////////
164

    
165
    void debugLists(String frameMarker)
166
      {
167
      android.util.Log.e("Object", frameMarker);
168
      android.util.Log.e("Object", "  Done list:");
169

    
170
      for(InternalObject object : mDoneList)
171
        {
172
        object.print("  ");
173
        }
174

    
175
      android.util.Log.e("Object", "  ToDo list:");
176

    
177
      Job job;
178

    
179
      for(Long key: mToDoMap.keySet())
180
        {
181
        job = mToDoMap.get(key);
182
        job.object.print(job.action==JOB_CREATE ? " create":" delete");
183
        }
184
      }
185
    }
186

    
187
///////////////////////////////////////////////////////////////////////////////////////////////////
188

    
189
  abstract void create();
190
  abstract void delete();
191
  abstract void recreate();
192
  abstract String printDetails();
193

    
194
///////////////////////////////////////////////////////////////////////////////////////////////////
195
// must be called from a thread holding OpenGL Context
196

    
197
  static boolean toDo()
198
    {
199
    if( mToDo )
200
      {
201
      mToDo = false;
202

    
203
      synchronized(mLock)
204
        {
205
        mCurrentFrame.toDo();
206
        }
207
      return true;
208
      }
209

    
210
    return false;
211
    }
212

    
213
///////////////////////////////////////////////////////////////////////////////////////////////////
214

    
215
  static void onCreate()
216
    {
217
    synchronized(mLock)
218
      {
219
      mCurrentFrame = new StackFrame();
220
      mFrameList.add(mCurrentFrame);
221
      mToDo = false;
222
      }
223
    }
224

    
225
///////////////////////////////////////////////////////////////////////////////////////////////////
226

    
227
  static void onPause()
228
    {
229
    synchronized(mLock)
230
      {
231
      mCurrentFrame.onPause();
232
      mToDo = true;
233
      }
234
    }
235

    
236
///////////////////////////////////////////////////////////////////////////////////////////////////
237

    
238
  static void onDestroy()
239
    {
240
    synchronized(mLock)
241
      {
242
      int num = mFrameList.size();
243

    
244
      if( num>0 )
245
        {
246
        mFrameList.remove(num-1);
247

    
248
        if( num>1 )
249
          {
250
          mCurrentFrame = mFrameList.get(num-2);
251
          mToDo = true;
252
          }
253
        else
254
          {
255
          mCurrentFrame = null;
256
          mToDo = false;
257
          }
258
        }
259
      }
260
    }
261

    
262
///////////////////////////////////////////////////////////////////////////////////////////////////
263

    
264
  @SuppressWarnings("unused")
265
  static void debugLists()
266
    {
267
    int num = mFrameList.size();
268
    StackFrame frame;
269

    
270
    for(int i=0; i<num; i++)
271
      {
272
      frame = mFrameList.get(i);
273
      frame.debugLists("frame "+i);
274
      }
275
    }
276

    
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278

    
279
  private void print(String msg)
280
    {
281
    String str = "ID:"+mID;
282

    
283
    switch(mType)
284
      {
285
      case TYPE_SYST: str+=" SYSTEM "; break;
286
      case TYPE_USER: str+=" USER   "; break;
287
      case TYPE_TREE: str+=" TREE   "; break;
288
      default       : str+=" ERROR? ";
289
      }
290

    
291
    android.util.Log.e("Object", str+printDetails()+msg);
292
    }
293

    
294
///////////////////////////////////////////////////////////////////////////////////////////////////
295

    
296
  InternalObject(int type)
297
    {
298
    if( mCurrentFrame==null ) onCreate();
299

    
300
    mID = mCurrentFrame.generateID(type);
301
    mType= type;
302
    }
303

    
304
///////////////////////////////////////////////////////////////////////////////////////////////////
305

    
306
  void markWasCreatedImmediately()
307
    {
308
    mCurrentFrame.addToDoneList(this);
309
    }
310

    
311
///////////////////////////////////////////////////////////////////////////////////////////////////
312

    
313
  void markForCreation()
314
    {
315
    synchronized(mLock)
316
      {
317
      mCurrentFrame.markFor(this,mID,JOB_CREATE);
318
      mToDo = true;
319
      }
320
    }
321

    
322
///////////////////////////////////////////////////////////////////////////////////////////////////
323
// PUBLIC API
324
///////////////////////////////////////////////////////////////////////////////////////////////////
325
/**
326
 * Mark the underlying OpenGL object for deletion. Actual deletion will take place on the next render.
327
 */
328
  public void markForDeletion()
329
    {
330
    synchronized(mLock)
331
      {
332
      mCurrentFrame.markFor(this,mID,JOB_DELETE);
333
      mToDo = true;
334
      }
335
    }
336

    
337
////////////////////////////////////////////////////////////////////////////////////////////////////
338
/**
339
 * Return unique ID of this Object.
340
 */
341
  public long getID()
342
    {
343
    return mID;
344
    }
345
}
(11-11/14)