summaryrefslogtreecommitdiffstats
path: root/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoSurface.java
blob: 7cf891aa59df5f44deafe3c09a0936ab137c949b (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
144
145
146
147
148
149
150
151
152
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.gecko.gfx;

import static org.mozilla.geckoview.BuildConfig.DEBUG_BUILD;

import android.os.Parcel;
import android.os.Parcelable;
import android.view.Surface;
import org.mozilla.gecko.annotation.WrapForJNI;

public final class GeckoSurface implements Parcelable {
  private static final String LOGTAG = "GeckoSurface";

  private Surface mSurface;
  private long mHandle;
  private boolean mIsSingleBuffer;
  private volatile boolean mIsAvailable;
  private boolean mOwned = true;
  private volatile boolean mIsReleased = false;

  private int mMyPid;
  // Locally allocated surface/texture. Do not pass it over IPC.
  private GeckoSurface mSyncSurface;

  @WrapForJNI(exceptionMode = "nsresult")
  public GeckoSurface(final GeckoSurfaceTexture gst) {
    mSurface = new Surface(gst);
    mHandle = gst.getHandle();
    mIsSingleBuffer = gst.isSingleBuffer();
    mIsAvailable = true;
    mMyPid = android.os.Process.myPid();
  }

  public GeckoSurface(final Parcel p) {
    mSurface = Surface.CREATOR.createFromParcel(p);
    mHandle = p.readLong();
    mIsSingleBuffer = p.readByte() == 1 ? true : false;
    mIsAvailable = (p.readByte() == 1 ? true : false);
    mMyPid = p.readInt();
  }

  public static final Parcelable.Creator<GeckoSurface> CREATOR =
      new Parcelable.Creator<GeckoSurface>() {
        public GeckoSurface createFromParcel(final Parcel p) {
          return new GeckoSurface(p);
        }

        public GeckoSurface[] newArray(final int size) {
          return new GeckoSurface[size];
        }
      };

  @Override
  public int describeContents() {
    return 0;
  }

  @Override
  public void writeToParcel(final Parcel out, final int flags) {
    mSurface.writeToParcel(out, flags);
    if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) == 0) {
      // GeckoSurface can be passed across processes as a return value or
      // an argument, and should always tranfers its ownership (move) to
      // the receiver of parcel. On the other hand, Surface is moved only
      // when passed as a return value and releases itself when corresponding
      // write flags is provided. (See Surface.writeToParcel().)
      // The superclass method must be called here to ensure the local instance
      // is truely forgotten.
      mSurface.release();
    }
    mOwned = false;

    out.writeLong(mHandle);
    out.writeByte((byte) (mIsSingleBuffer ? 1 : 0));
    out.writeByte((byte) (mIsAvailable ? 1 : 0));
    out.writeInt(mMyPid);
  }

  public void release() {
    if (mIsReleased) {
      return;
    }
    mIsReleased = true;

    if (mSyncSurface != null) {
      mSyncSurface.release();
      final GeckoSurfaceTexture gst = GeckoSurfaceTexture.lookup(mSyncSurface.getHandle());
      if (gst != null) {
        gst.decrementUse();
      }
      mSyncSurface = null;
    }

    if (mOwned) {
      mSurface.release();
    }
  }

  @WrapForJNI
  public long getHandle() {
    return mHandle;
  }

  @WrapForJNI
  public Surface getSurface() {
    return mSurface;
  }

  @WrapForJNI
  public boolean getAvailable() {
    return mIsAvailable;
  }

  @WrapForJNI
  public boolean isReleased() {
    return mIsReleased;
  }

  @WrapForJNI
  public void setAvailable(final boolean available) {
    mIsAvailable = available;
  }

  /* package */ boolean inProcess() {
    return android.os.Process.myPid() == mMyPid;
  }

  /* package */ SyncConfig initSyncSurface(final int width, final int height) {
    if (DEBUG_BUILD) {
      if (inProcess()) {
        throw new AssertionError("no need for sync when allocated in process");
      }
    }
    if (GeckoSurfaceTexture.lookup(mHandle) != null) {
      throw new AssertionError("texture#" + mHandle + " already in use.");
    }
    final GeckoSurfaceTexture texture =
        GeckoSurfaceTexture.acquire(GeckoSurfaceTexture.isSingleBufferSupported(), mHandle);
    if (texture != null) {
      texture.setDefaultBufferSize(width, height);
      texture.track(mHandle);
      mSyncSurface = new GeckoSurface(texture);
      return new SyncConfig(mHandle, mSyncSurface, width, height);
    }

    return null;
  }
}