Merge "Fix FusionEngine so it isn't confused by location providers enabling/disabling."
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index 03540e1..347db05 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -328,15 +328,15 @@
appendStreamConfig(availableStreamConfigs,
ImageFormat.YUV_420_888, previewSizes);
for (int format : p.getSupportedPreviewFormats()) {
- if (ImageFormat.isPublicFormat(format)) {
+ if (ImageFormat.isPublicFormat(format) && format != ImageFormat.NV21) {
appendStreamConfig(availableStreamConfigs, format, previewSizes);
- } else {
+ } else if (VERBOSE) {
/*
* Do not add any formats unknown to us
* (since it would fail runtime checks in StreamConfigurationMap)
*/
- Log.w(TAG,
- String.format("mapStreamConfigs - Skipping non-public format %x", format));
+ Log.v(TAG,
+ String.format("mapStreamConfigs - Skipping format %x", format));
}
}
@@ -389,8 +389,8 @@
int j = 0;
for (String mode : antiBandingModes) {
int convertedMode = convertAntiBandingMode(mode);
- if (convertedMode == -1) {
- Log.w(TAG, "Antibanding mode " + ((mode == null) ? "NULL" : mode) +
+ if (VERBOSE && convertedMode == -1) {
+ Log.v(TAG, "Antibanding mode " + ((mode == null) ? "NULL" : mode) +
" not supported, skipping...");
} else {
modes[j++] = convertedMode;
diff --git a/core/java/android/hardware/camera2/utils/ArrayUtils.java b/core/java/android/hardware/camera2/utils/ArrayUtils.java
index 5a78bbd..79a335c 100644
--- a/core/java/android/hardware/camera2/utils/ArrayUtils.java
+++ b/core/java/android/hardware/camera2/utils/ArrayUtils.java
@@ -117,7 +117,7 @@
// Guard against unexpected values
if (strIndex < 0) {
- Log.w(TAG, "Ignoring invalid value " + str);
+ if (VERBOSE) Log.v(TAG, "Ignoring invalid value " + str);
continue;
}
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index f64ef87..f283051 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -68,6 +68,8 @@
* accessory function is enabled
* <li> {@link #USB_FUNCTION_AUDIO_SOURCE} boolean extra indicating whether the
* audio source function is enabled
+ * <li> {@link #USB_FUNCTION_MIDI} boolean extra indicating whether the
+ * MIDI function is enabled
* </ul>
*
* {@hide}
@@ -188,6 +190,14 @@
public static final String USB_FUNCTION_AUDIO_SOURCE = "audio_source";
/**
+ * Name of the MIDI USB function.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
+ */
+ public static final String USB_FUNCTION_MIDI = "midi";
+
+ /**
* Name of the Accessory USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
diff --git a/core/java/android/midi/MidiInputPort.java b/core/java/android/midi/MidiInputPort.java
index 5d806cf8..88ace5f 100644
--- a/core/java/android/midi/MidiInputPort.java
+++ b/core/java/android/midi/MidiInputPort.java
@@ -33,7 +33,7 @@
private final FileOutputStream mOutputStream;
// buffer to use for sending messages out our output stream
- private final byte[] mBuffer = new byte[MAX_PACKED_MESSAGE_SIZE];
+ private final byte[] mBuffer = new byte[MAX_PACKET_SIZE];
/* package */ MidiInputPort(ParcelFileDescriptor pfd, int portNumber) {
super(portNumber);
@@ -50,10 +50,19 @@
* {@link java.lang.System#nanoTime}
*/
public void onPost(byte[] msg, int offset, int count, long timestamp) throws IOException {
+ assert(offset >= 0 && count >= 0 && offset + count <= msg.length);
+
synchronized (mBuffer) {
- int length = packMessage(msg, offset, count, timestamp, mBuffer);
try {
- mOutputStream.write(mBuffer, 0, length);
+ while (count > 0) {
+ int length = packMessage(msg, offset, count, timestamp, mBuffer);
+ mOutputStream.write(mBuffer, 0, length);
+ int sent = getMessageSize(mBuffer, length);
+ assert(sent >= 0 && sent <= length);
+
+ offset += sent;
+ count -= sent;
+ }
} catch (IOException e) {
IoUtils.closeQuietly(mOutputStream);
// report I/O failure
diff --git a/core/java/android/midi/MidiOutputPort.java b/core/java/android/midi/MidiOutputPort.java
index b550ed4..00b7bad 100644
--- a/core/java/android/midi/MidiOutputPort.java
+++ b/core/java/android/midi/MidiOutputPort.java
@@ -45,7 +45,7 @@
private final Thread mThread = new Thread() {
@Override
public void run() {
- byte[] buffer = new byte[MAX_PACKED_MESSAGE_SIZE];
+ byte[] buffer = new byte[MAX_PACKET_SIZE];
ArrayList<MidiReceiver> deadReceivers = new ArrayList<MidiReceiver>();
try {
@@ -54,9 +54,6 @@
int count = mInputStream.read(buffer);
if (count < 0) {
break;
- } else if (count < MIN_PACKED_MESSAGE_SIZE || count > MAX_PACKED_MESSAGE_SIZE) {
- Log.e(TAG, "Number of bytes read out of range: " + count);
- continue;
}
int offset = getMessageOffset(buffer, count);
@@ -96,7 +93,6 @@
}
};
-
/* package */ MidiOutputPort(ParcelFileDescriptor pfd, int portNumber) {
super(portNumber);
mInputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
diff --git a/core/java/android/midi/MidiPort.java b/core/java/android/midi/MidiPort.java
index 1fa7946..44d1a88 100644
--- a/core/java/android/midi/MidiPort.java
+++ b/core/java/android/midi/MidiPort.java
@@ -32,16 +32,19 @@
private final int mPortNumber;
/**
- * Minimum size of packed message as sent through our ParcelFileDescriptor
- * 8 bytes for timestamp and 1 to 3 bytes for message
+ * Maximum size of a packet that can pass through our ParcelFileDescriptor
*/
- protected static final int MIN_PACKED_MESSAGE_SIZE = 9;
+ protected static final int MAX_PACKET_SIZE = 1024;
/**
- * Maximum size of packed message as sent through our ParcelFileDescriptor
- * 8 bytes for timestamp and 1 to 3 bytes for message
+ * size of message timestamp in bytes
*/
- protected static final int MAX_PACKED_MESSAGE_SIZE = 11;
+ private static final int TIMESTAMP_SIZE = 8;
+
+ /**
+ * Maximum amount of MIDI data that can be included in a packet
+ */
+ public static final int MAX_PACKET_DATA_SIZE = MAX_PACKET_SIZE - TIMESTAMP_SIZE;
/* package */ MidiPort(int portNumber) {
@@ -76,49 +79,52 @@
*/
protected static int packMessage(byte[] message, int offset, int size, long timestamp,
byte[] dest) {
- // pack variable length message first
+ if (size + TIMESTAMP_SIZE > MAX_PACKET_SIZE) {
+ size = MAX_PACKET_SIZE - TIMESTAMP_SIZE;
+ }
+ // message data goes first
System.arraycopy(message, offset, dest, 0, size);
- int destOffset = size;
- // timestamp takes 8 bytes
- for (int i = 0; i < 8; i++) {
- dest[destOffset++] = (byte)timestamp;
+
+ // followed by timestamp
+ for (int i = 0; i < TIMESTAMP_SIZE; i++) {
+ dest[size++] = (byte)timestamp;
timestamp >>= 8;
}
- return destOffset;
+ return size;
}
/**
- * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
- * returns the offet of of MIDI message in packed buffer
+ * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
+ * returns the offset of the MIDI message in packed buffer
*/
protected static int getMessageOffset(byte[] buffer, int bufferLength) {
- // message is at start of buffer
+ // message is at the beginning
return 0;
}
/**
- * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
- * returns size of MIDI message in packed buffer
+ * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
+ * returns size of MIDI data in packed buffer
*/
protected static int getMessageSize(byte[] buffer, int bufferLength) {
- // message length is total buffer length minus size of the timestamp and port number
- return bufferLength - 8 /* sizeof(timestamp) */;
+ // message length is total buffer length minus size of the timestamp
+ return bufferLength - TIMESTAMP_SIZE;
}
/**
- * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
+ * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
* unpacks timestamp from packed buffer
*/
protected static long getMessageTimeStamp(byte[] buffer, int bufferLength) {
+ // timestamp is at end of the packet
+ int offset = bufferLength;
long timestamp = 0;
- // timestamp follows variable length message data
- int dataLength = getMessageSize(buffer, bufferLength);
- for (int i = dataLength + 7; i >= dataLength; i--) {
- int b = (int)buffer[i] & 0xFF;
+ for (int i = 0; i < TIMESTAMP_SIZE; i++) {
+ int b = (int)buffer[--offset] & 0xFF;
timestamp = (timestamp << 8) | b;
}
return timestamp;
- }
+ }
}
diff --git a/core/java/android/midi/MidiReceiver.java b/core/java/android/midi/MidiReceiver.java
index 0b183cc..a4e1a10 100644
--- a/core/java/android/midi/MidiReceiver.java
+++ b/core/java/android/midi/MidiReceiver.java
@@ -30,6 +30,8 @@
* NOTE: the msg array parameter is only valid within the context of this call.
* The msg bytes should be copied by the receiver rather than retaining a reference
* to this parameter.
+ * Also, modifying the contents of the msg array parameter may result in other receivers
+ * in the same application receiving incorrect values in their onPost() method.
*
* @param msg a byte array containing the MIDI message
* @param offset the offset of the first byte of the message in the byte array
diff --git a/core/java/android/midi/MidiUtils.java b/core/java/android/midi/MidiUtils.java
deleted file mode 100644
index e60e2db..0000000
--- a/core/java/android/midi/MidiUtils.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package android.midi;
-
-import android.util.Log;
-
-/**
- * Class containing miscellaneous MIDI utilities.
- *
- * @hide
- */
-public final class MidiUtils {
- private static final String TAG = "MidiUtils";
-
- private MidiUtils() { }
-
- /**
- * Returns data size of a MIDI message based on the message's command byte
- * @param b the message command byte
- * @return the message's data length
- */
- public static int getMessageDataSize(byte b) {
- switch (b & 0xF0) {
- case 0x80:
- case 0x90:
- case 0xA0:
- case 0xB0:
- case 0xE0:
- return 2;
- case 0xC0:
- case 0xD0:
- return 1;
- case 0xF0:
- switch (b & 0x0F) {
- case 0x00:
- Log.e(TAG, "System Exclusive not supported yet");
- return -1;
- case 0x01:
- case 0x03:
- return 1;
- case 0x02:
- return 2;
- default:
- return 0;
- }
- default:
- Log.e(TAG, "unknown MIDI command " + b);
- return -1;
- }
- }
-}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 87d9a58..151ff83 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1326,6 +1326,11 @@
}
}
+ // Non-visible windows can't hold accessibility focus.
+ if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
+ host.clearAccessibilityFocus();
+ }
+
// Execute enqueued actions on every traversal in case a detached view enqueued an action
getRunQueue().executeActions(mAttachInfo.mHandler);
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index b5afdf7..6096d7d 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -721,7 +721,7 @@
* @return Whether the refresh succeeded.
*/
public boolean refresh() {
- return refresh(false);
+ return refresh(true);
}
/**
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 9996ce1..9ea63aa 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -511,18 +511,15 @@
///////////////////////////////////////////////////////////////////////////////
-static bool computeAllocationSize(const SkImageInfo& info, size_t* size, size_t* rowBytes) {
- int32_t rowBytes32 = SkToS32(info.minRowBytes());
- int64_t bigSize = (int64_t)info.height() * rowBytes32;
- if (rowBytes32 < 0 || !sk_64_isS32(bigSize)) {
- return false; // allocation will be too large
- }
+static bool computeAllocationSize(const SkBitmap& bitmap, size_t* size) {
+ int32_t rowBytes32 = SkToS32(bitmap.rowBytes());
+ int64_t bigSize = (int64_t)bitmap.height() * rowBytes32;
+ if (rowBytes32 < 0 || !sk_64_isS32(bigSize)) {
+ return false; // allocation will be too large
+ }
- *size = sk_64_asS32(bigSize);
- *rowBytes = rowBytes32;
-
- SkASSERT(*size >= info.getSafeSize(*rowBytes));
- return true;
+ *size = sk_64_asS32(bigSize);
+ return true;
}
jbyteArray GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
@@ -533,11 +530,15 @@
return NULL;
}
- size_t size, rowBytes;
- if (!computeAllocationSize(info, &size, &rowBytes)) {
+ size_t size;
+ if (!computeAllocationSize(*bitmap, &size)) {
return NULL;
}
+ // we must respect the rowBytes value already set on the bitmap instead of
+ // attempting to compute our own.
+ const size_t rowBytes = bitmap->rowBytes();
+
jbyteArray arrayObj = (jbyteArray) env->CallObjectMethod(gVMRuntime,
gVMRuntime_newNonMovableArray,
gByte_class, size);
@@ -580,11 +581,15 @@
return NULL;
}
- size_t size, rowBytes;
- if (!computeAllocationSize(info, &size, &rowBytes)) {
+ size_t size;
+ if (!computeAllocationSize(*bitmap, &size)) {
return false;
}
+ // we must respect the rowBytes value already set on the bitmap instead of
+ // attempting to compute our own.
+ const size_t rowBytes = bitmap->rowBytes();
+
void* addr = sk_malloc_flags(size, 0);
if (NULL == addr) {
return false;
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3843d16..f2d9de8 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -424,6 +424,10 @@
<!-- Integer indicating wpa_supplicant scan interval in milliseconds -->
<integer translatable="false" name="config_wifi_supplicant_scan_interval">15000</integer>
+ <!-- Integer indicating amount of time failed networks areblacklisted for the purpose
+ of network switching in milliseconds -->
+ <integer translatable="false" name="config_wifi_network_switching_blacklist_time">172800000</integer>
+
<!-- Integer indicating wpa_supplicant scan interval when p2p is connected in milliseconds -->
<integer translatable="false" name="config_wifi_scan_interval_p2p_connected">60000</integer>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f51e82c9..efdc3c8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5188,4 +5188,9 @@
<string name="stk_cc_ss_to_ussd">SS request is modified to USSD request.</string>
<string name="stk_cc_ss_to_ss">SS request is modified to new SS request.</string>
+ <!-- Manufacturer name for USB MIDI Peripheral port -->
+ <string name="usb_midi_peripheral_manufacturer_name">Android</string>
+ <!-- Model name for USB MIDI Peripheral port -->
+ <string name="usb_midi_peripheral_model_name">USB Peripheral Port</string>
+
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f6d39a7..607744f 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -327,6 +327,7 @@
<java-symbol type="integer" name="config_wifi_framework_scan_result_rssi_level_patchup_value" />
<java-symbol type="integer" name="config_wifi_framework_current_network_boost" />
<java-symbol type="string" name="config_wifi_random_mac_oui" />
+ <java-symbol type="integer" name="config_wifi_network_switching_blacklist_time" />
<java-symbol type="bool" name="editable_voicemailnumber" />
@@ -2155,4 +2156,7 @@
<java-symbol type="bool" name="config_use_sim_language_file" />
<java-symbol type="bool" name="config_LTE_eri_for_network_name" />
<java-symbol type="bool" name="config_defaultInTouchMode" />
+
+ <java-symbol type="string" name="usb_midi_peripheral_manufacturer_name" />
+ <java-symbol type="string" name="usb_midi_peripheral_model_name" />
</resources>
diff --git a/docs/html/google/play-services/ads.jd b/docs/html/google/play-services/ads.jd
index e4f0b2c..2f915f3 100644
--- a/docs/html/google/play-services/ads.jd
+++ b/docs/html/google/play-services/ads.jd
@@ -98,10 +98,8 @@
serve banner and interstitial ads using the Google Mobile Ads APIs.</p>
<h4>3. Read the documentation</h4>
- <p>Read the <a class="external-link" href="https://www.google.com/adsense/localized-terms">AdSense
- Terms of Service</a> and the <a class="external-link"
- href="https://support.google.com/admob/topic/1307235?hl=en&ref_topic=1307209">AdMob
- publisher guidelines and policies</a>.</p>
+ <p>Your use of the Google Mobile Ads SDK is governed by the terms between you and Google that
+ govern your use of the Google product (AdSense/AdMob, AdX or DFP) with which you use the SDK.</p>
<p>For quick access while developing your Android apps, the <a
href="{@docRoot}reference/gms-packages.html">Google Mobile Ads API reference</a> is available here on
developer.android.com.</p>
diff --git a/libs/hwui/Android.common.mk b/libs/hwui/Android.common.mk
index 5079852..7c1a724 100644
--- a/libs/hwui/Android.common.mk
+++ b/libs/hwui/Android.common.mk
@@ -7,8 +7,11 @@
LOCAL_SRC_FILES := \
font/CacheTexture.cpp \
font/Font.cpp \
+ renderstate/MeshState.cpp \
+ renderstate/PixelBufferState.cpp \
renderstate/RenderState.cpp \
renderstate/Scissor.cpp \
+ renderstate/Stencil.cpp \
renderthread/CanvasContext.cpp \
renderthread/DrawFrameTask.cpp \
renderthread/EglManager.cpp \
@@ -63,7 +66,6 @@
SkiaShader.cpp \
Snapshot.cpp \
SpotShadow.cpp \
- Stencil.cpp \
TessellationCache.cpp \
Texture.cpp \
TextureCache.cpp \
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 20dd21c..1fb8092 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -29,12 +29,10 @@
#include <utils/String8.h>
namespace android {
-
-using namespace uirenderer;
-ANDROID_SINGLETON_STATIC_INSTANCE(Caches);
-
namespace uirenderer {
+Caches* Caches::sInstance = nullptr;
+
///////////////////////////////////////////////////////////////////////////////
// Macros
///////////////////////////////////////////////////////////////////////////////
@@ -49,8 +47,12 @@
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-Caches::Caches(): Singleton<Caches>(),
- mExtensions(Extensions::getInstance()), mInitialized(false), mRenderState(nullptr) {
+Caches::Caches(RenderState& renderState)
+ : patchCache(renderState)
+ , mRenderState(&renderState)
+ , mExtensions(Extensions::getInstance())
+ , mInitialized(false) {
+ INIT_LOGD("Creating OpenGL renderer caches");
init();
initFont();
initConstraints();
@@ -60,7 +62,8 @@
initTempProperties();
mDebugLevel = readDebugLevel();
- ALOGD("Enabling debug mode %d", mDebugLevel);
+ ALOGD_IF(mDebugLevel != kDebugDisabled,
+ "Enabling debug mode %d", mDebugLevel);
}
bool Caches::init() {
@@ -68,25 +71,10 @@
ATRACE_NAME("Caches::init");
- glGenBuffers(1, &meshBuffer);
- glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
- glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
-
- mCurrentBuffer = meshBuffer;
- mCurrentIndicesBuffer = 0;
- mCurrentPositionPointer = this;
- mCurrentPositionStride = 0;
- mCurrentTexCoordsPointer = this;
- mCurrentPixelBuffer = 0;
-
- mTexCoordsArrayEnabled = false;
-
glActiveTexture(gTextureUnits[0]);
mTextureUnit = 0;
mRegionMesh = nullptr;
- mMeshIndices = 0;
- mShadowStripsIndices = 0;
blend = false;
lastSrcMode = GL_ZERO;
lastDstMode = GL_ZERO;
@@ -98,11 +86,12 @@
debugOverdraw = false;
debugStencilClip = kStencilHide;
- patchCache.init(*this);
+ patchCache.init();
mInitialized = true;
resetBoundTextures();
+ mPixelBufferState.reset(new PixelBufferState());
return true;
}
@@ -216,17 +205,8 @@
void Caches::terminate() {
if (!mInitialized) return;
-
- glDeleteBuffers(1, &meshBuffer);
- mCurrentBuffer = 0;
-
- glDeleteBuffers(1, &mMeshIndices);
- mMeshIndices = 0;
mRegionMesh.release();
- glDeleteBuffers(1, &mShadowStripsIndices);
- mShadowStripsIndices = 0;
-
fboCache.clear();
programCache.clear();
@@ -236,6 +216,8 @@
clearGarbage();
+ mPixelBufferState.release();
+
mInitialized = false;
}
@@ -268,7 +250,7 @@
layerCache.getSize(), layerCache.getMaxSize(), layerCache.getCount());
if (mRenderState) {
int memused = 0;
- for (std::set<const Layer*>::iterator it = mRenderState->mActiveLayers.begin();
+ for (std::set<Layer*>::iterator it = mRenderState->mActiveLayers.begin();
it != mRenderState->mActiveLayers.end(); it++) {
const Layer* layer = *it;
log.appendFormat(" Layer size %dx%d; isTextureLayer()=%d; texid=%u fbo=%u; refs=%d\n",
@@ -366,155 +348,9 @@
}
///////////////////////////////////////////////////////////////////////////////
-// VBO
+// Textures
///////////////////////////////////////////////////////////////////////////////
-bool Caches::bindMeshBuffer() {
- return bindMeshBuffer(meshBuffer);
-}
-
-bool Caches::bindMeshBuffer(const GLuint buffer) {
- if (mCurrentBuffer != buffer) {
- glBindBuffer(GL_ARRAY_BUFFER, buffer);
- mCurrentBuffer = buffer;
- return true;
- }
- return false;
-}
-
-bool Caches::unbindMeshBuffer() {
- if (mCurrentBuffer) {
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- mCurrentBuffer = 0;
- return true;
- }
- return false;
-}
-
-bool Caches::bindIndicesBufferInternal(const GLuint buffer) {
- if (mCurrentIndicesBuffer != buffer) {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
- mCurrentIndicesBuffer = buffer;
- return true;
- }
- return false;
-}
-
-bool Caches::bindQuadIndicesBuffer() {
- if (!mMeshIndices) {
- std::unique_ptr<uint16_t[]> regionIndices(new uint16_t[gMaxNumberOfQuads * 6]);
- for (uint32_t i = 0; i < gMaxNumberOfQuads; i++) {
- uint16_t quad = i * 4;
- int index = i * 6;
- regionIndices[index ] = quad; // top-left
- regionIndices[index + 1] = quad + 1; // top-right
- regionIndices[index + 2] = quad + 2; // bottom-left
- regionIndices[index + 3] = quad + 2; // bottom-left
- regionIndices[index + 4] = quad + 1; // top-right
- regionIndices[index + 5] = quad + 3; // bottom-right
- }
-
- glGenBuffers(1, &mMeshIndices);
- bool force = bindIndicesBufferInternal(mMeshIndices);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, gMaxNumberOfQuads * 6 * sizeof(uint16_t),
- regionIndices.get(), GL_STATIC_DRAW);
- return force;
- }
-
- return bindIndicesBufferInternal(mMeshIndices);
-}
-
-bool Caches::bindShadowIndicesBuffer() {
- if (!mShadowStripsIndices) {
- std::unique_ptr<uint16_t[]> shadowIndices(new uint16_t[MAX_SHADOW_INDEX_COUNT]);
- ShadowTessellator::generateShadowIndices(shadowIndices.get());
- glGenBuffers(1, &mShadowStripsIndices);
- bool force = bindIndicesBufferInternal(mShadowStripsIndices);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_SHADOW_INDEX_COUNT * sizeof(uint16_t),
- shadowIndices.get(), GL_STATIC_DRAW);
- return force;
- }
-
- return bindIndicesBufferInternal(mShadowStripsIndices);
-}
-
-bool Caches::unbindIndicesBuffer() {
- if (mCurrentIndicesBuffer) {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- mCurrentIndicesBuffer = 0;
- return true;
- }
- return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// PBO
-///////////////////////////////////////////////////////////////////////////////
-
-bool Caches::bindPixelBuffer(const GLuint buffer) {
- if (mCurrentPixelBuffer != buffer) {
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
- mCurrentPixelBuffer = buffer;
- return true;
- }
- return false;
-}
-
-bool Caches::unbindPixelBuffer() {
- if (mCurrentPixelBuffer) {
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
- mCurrentPixelBuffer = 0;
- return true;
- }
- return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Meshes and textures
-///////////////////////////////////////////////////////////////////////////////
-
-void Caches::bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
- if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
- GLuint slot = currentProgram->position;
- glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
- mCurrentPositionPointer = vertices;
- mCurrentPositionStride = stride;
- }
-}
-
-void Caches::bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
- if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
- GLuint slot = currentProgram->texCoords;
- glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
- mCurrentTexCoordsPointer = vertices;
- mCurrentTexCoordsStride = stride;
- }
-}
-
-void Caches::resetVertexPointers() {
- mCurrentPositionPointer = this;
- mCurrentTexCoordsPointer = this;
-}
-
-void Caches::resetTexCoordsVertexPointer() {
- mCurrentTexCoordsPointer = this;
-}
-
-void Caches::enableTexCoordsVertexArray() {
- if (!mTexCoordsArrayEnabled) {
- glEnableVertexAttribArray(Program::kBindingTexCoords);
- mCurrentTexCoordsPointer = this;
- mTexCoordsArrayEnabled = true;
- }
-}
-
-void Caches::disableTexCoordsVertexArray() {
- if (mTexCoordsArrayEnabled) {
- glDisableVertexAttribArray(Program::kBindingTexCoords);
- mTexCoordsArrayEnabled = false;
- }
-}
-
void Caches::activeTexture(GLuint textureUnit) {
if (mTextureUnit != textureUnit) {
glActiveTexture(gTextureUnits[textureUnit]);
@@ -614,7 +450,7 @@
TextureVertex* Caches::getRegionMesh() {
// Create the mesh, 2 triangles and 4 vertices per rectangle in the region
if (!mRegionMesh) {
- mRegionMesh.reset(new TextureVertex[gMaxNumberOfQuads * 4]);
+ mRegionMesh.reset(new TextureVertex[kMaxNumberOfQuads * 4]);
}
return mRegionMesh.get();
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index fb75dd32..8d23833 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -21,7 +21,27 @@
#define LOG_TAG "OpenGLRenderer"
#endif
+
+#include "AssetAtlas.h"
+#include "Dither.h"
+#include "Extensions.h"
+#include "FboCache.h"
+#include "GradientCache.h"
+#include "LayerCache.h"
+#include "PatchCache.h"
+#include "ProgramCache.h"
+#include "PathCache.h"
+#include "RenderBufferCache.h"
+#include "renderstate/PixelBufferState.h"
+#include "ResourceCache.h"
+#include "TessellationCache.h"
+#include "TextDropShadowCache.h"
+#include "TextureCache.h"
+#include "thread/TaskProcessor.h"
+#include "thread/TaskManager.h"
+
#include <vector>
+#include <memory>
#include <GLES3/gl3.h>
@@ -33,25 +53,6 @@
#include <SkPath.h>
-#include "thread/TaskProcessor.h"
-#include "thread/TaskManager.h"
-
-#include "AssetAtlas.h"
-#include "Extensions.h"
-#include "TextureCache.h"
-#include "LayerCache.h"
-#include "RenderBufferCache.h"
-#include "GradientCache.h"
-#include "PatchCache.h"
-#include "ProgramCache.h"
-#include "PathCache.h"
-#include "TessellationCache.h"
-#include "TextDropShadowCache.h"
-#include "FboCache.h"
-#include "ResourceCache.h"
-#include "Stencil.h"
-#include "Dither.h"
-
namespace android {
namespace uirenderer {
@@ -64,29 +65,6 @@
// GL ES 2.0 defines that at least 16 texture units must be supported
#define REQUIRED_TEXTURE_UNITS_COUNT 3
-// Maximum number of quads that pre-allocated meshes can draw
-static const uint32_t gMaxNumberOfQuads = 2048;
-
-// Generates simple and textured vertices
-#define FV(x, y, u, v) { x, y, u, v }
-
-// This array is never used directly but used as a memcpy source in the
-// OpenGLRenderer constructor
-static const TextureVertex gMeshVertices[] = {
- FV(0.0f, 0.0f, 0.0f, 0.0f),
- FV(1.0f, 0.0f, 1.0f, 0.0f),
- FV(0.0f, 1.0f, 0.0f, 1.0f),
- FV(1.0f, 1.0f, 1.0f, 1.0f)
-};
-static const GLsizei gMeshStride = sizeof(TextureVertex);
-static const GLsizei gVertexStride = sizeof(Vertex);
-static const GLsizei gAlphaVertexStride = sizeof(AlphaVertex);
-static const GLsizei gMeshTextureOffset = 2 * sizeof(float);
-static const GLsizei gVertexAlphaOffset = 2 * sizeof(float);
-static const GLsizei gVertexAAWidthOffset = 2 * sizeof(float);
-static const GLsizei gVertexAALengthOffset = 3 * sizeof(float);
-static const GLsizei gMeshCount = 4;
-
// Must define as many texture units as specified by REQUIRED_TEXTURE_UNITS_COUNT
static const GLenum gTextureUnits[] = {
GL_TEXTURE0,
@@ -95,28 +73,31 @@
};
///////////////////////////////////////////////////////////////////////////////
-// Debug
-///////////////////////////////////////////////////////////////////////////////
-
-struct CacheLogger {
- CacheLogger() {
- INIT_LOGD("Creating OpenGL renderer caches");
- }
-}; // struct CacheLogger
-
-///////////////////////////////////////////////////////////////////////////////
// Caches
///////////////////////////////////////////////////////////////////////////////
class RenderNode;
class RenderState;
-class ANDROID_API Caches: public Singleton<Caches> {
- Caches();
+class ANDROID_API Caches {
+public:
+ static Caches& createInstance(RenderState& renderState) {
+ LOG_ALWAYS_FATAL_IF(sInstance, "double create of Caches attempted");
+ sInstance = new Caches(renderState);
+ return *sInstance;
+ }
- friend class Singleton<Caches>;
+ static Caches& getInstance() {
+ LOG_ALWAYS_FATAL_IF(!sInstance, "instance not yet created");
+ return *sInstance;
+ }
- CacheLogger mLogger;
+ static bool hasInstance() {
+ return sInstance != 0;
+ }
+private:
+ Caches(RenderState& renderState);
+ static Caches* sInstance;
public:
enum FlushMode {
@@ -135,8 +116,6 @@
*/
bool initProperties();
- void setRenderState(RenderState* renderState) { mRenderState = renderState; }
-
/**
* Flush the cache.
*
@@ -175,59 +154,6 @@
*/
void deleteLayerDeferred(Layer* layer);
- /**
- * Binds the VBO used to render simple textured quads.
- */
- bool bindMeshBuffer();
-
- /**
- * Binds the specified VBO if needed.
- */
- bool bindMeshBuffer(const GLuint buffer);
-
- /**
- * Unbinds the VBO used to render simple textured quads.
- */
- bool unbindMeshBuffer();
-
- /**
- * Binds a global indices buffer that can draw up to
- * gMaxNumberOfQuads quads.
- */
- bool bindQuadIndicesBuffer();
- bool bindShadowIndicesBuffer();
- bool unbindIndicesBuffer();
-
- /**
- * Binds the specified buffer as the current GL unpack pixel buffer.
- */
- bool bindPixelBuffer(const GLuint buffer);
-
- /**
- * Resets the current unpack pixel buffer to 0 (default value.)
- */
- bool unbindPixelBuffer();
-
- /**
- * Binds an attrib to the specified float vertex pointer.
- * Assumes a stride of gMeshStride and a size of 2.
- */
- void bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride = gMeshStride);
-
- /**
- * Binds an attrib to the specified float vertex pointer.
- * Assumes a stride of gMeshStride and a size of 2.
- */
- void bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride = gMeshStride);
-
- /**
- * Resets the vertex pointers.
- */
- void resetVertexPointers();
- void resetTexCoordsVertexPointer();
-
- void enableTexCoordsVertexArray();
- void disableTexCoordsVertexArray();
/**
* Activate the specified texture unit. The texture unit must
@@ -300,9 +226,6 @@
bool drawDeferDisabled;
bool drawReorderDisabled;
- // VBO to draw with
- GLuint meshBuffer;
-
// Misc
GLint maxTextureSize;
@@ -333,7 +256,6 @@
TaskManager tasks;
Dither dither;
- Stencil stencil;
bool gpuPixelBuffersEnabled;
@@ -356,6 +278,8 @@
int propertyAmbientShadowStrength;
int propertySpotShadowStrength;
+ PixelBufferState& pixelBuffer() { return *mPixelBufferState; }
+
private:
enum OverdrawColorSet {
kColorSet_Default = 0,
@@ -367,8 +291,6 @@
void initConstraints();
void initStaticProperties();
- bool bindIndicesBufferInternal(const GLuint buffer);
-
static void eventMarkNull(GLsizei length, const GLchar* marker) { }
static void startMarkNull(GLsizei length, const GLchar* marker) { }
static void endMarkNull() { }
@@ -381,15 +303,9 @@
if (label) *label = '\0';
}
- GLuint mCurrentBuffer;
- GLuint mCurrentIndicesBuffer;
- GLuint mCurrentPixelBuffer;
- const void* mCurrentPositionPointer;
- GLsizei mCurrentPositionStride;
- const void* mCurrentTexCoordsPointer;
- GLsizei mCurrentTexCoordsStride;
+ RenderState* mRenderState;
- bool mTexCoordsArrayEnabled;
+ std::unique_ptr<PixelBufferState> mPixelBufferState; // TODO: move to RenderState
GLuint mTextureUnit;
@@ -398,10 +314,6 @@
// Used to render layers
std::unique_ptr<TextureVertex[]> mRegionMesh;
- // Global index buffer
- GLuint mMeshIndices;
- GLuint mShadowStripsIndices;
-
mutable Mutex mGarbageLock;
Vector<Layer*> mLayerGarbage;
@@ -414,8 +326,6 @@
GLuint mBoundTextures[REQUIRED_TEXTURE_UNITS_COUNT];
OverdrawColorSet mOverdrawDebugColorSet;
-
- RenderState* mRenderState;
}; // class Caches
}; // namespace uirenderer
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index a0bc7b0..193474f 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -14,7 +14,17 @@
* limitations under the License.
*/
-#define LOG_TAG "OpenGLRenderer"
+#include "FontRenderer.h"
+
+#include "Caches.h"
+#include "Debug.h"
+#include "Extensions.h"
+#include "OpenGLRenderer.h"
+#include "PixelBuffer.h"
+#include "Rect.h"
+#include "renderstate/RenderState.h"
+#include "utils/Blur.h"
+#include "utils/Timing.h"
#include <SkGlyph.h>
#include <SkUtils.h>
@@ -27,17 +37,6 @@
#include <RenderScript.h>
#endif
-#include "utils/Blur.h"
-#include "utils/Timing.h"
-
-#include "Caches.h"
-#include "Debug.h"
-#include "Extensions.h"
-#include "FontRenderer.h"
-#include "OpenGLRenderer.h"
-#include "PixelBuffer.h"
-#include "Rect.h"
-
namespace android {
namespace uirenderer {
@@ -47,9 +46,7 @@
///////////////////////////////////////////////////////////////////////////////
// TextSetupFunctor
///////////////////////////////////////////////////////////////////////////////
-status_t TextSetupFunctor::operator ()(int what, void* data) {
- Data* typedData = reinterpret_cast<Data*>(data);
- GLenum glyphFormat = typedData ? typedData->glyphFormat : GL_ALPHA;
+status_t TextSetupFunctor::setup(GLenum glyphFormat) {
renderer->setupDraw();
renderer->setupDrawTextGamma(paint);
@@ -397,7 +394,7 @@
CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
bool allocate) {
- CacheTexture* cacheTexture = new CacheTexture(width, height, format, gMaxNumberOfQuads);
+ CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
if (allocate) {
Caches::getInstance().activeTexture(0);
@@ -473,7 +470,7 @@
checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
// Unbind any PBO we might have used to update textures
- caches.unbindPixelBuffer();
+ caches.pixelBuffer().unbind();
// Reset to default unpack row length to avoid affecting texture
// uploads in other parts of the renderer
@@ -485,26 +482,29 @@
}
void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
- Caches& caches = Caches::getInstance();
+ if (!mFunctor) return;
+
+ Caches& caches = mFunctor->renderer->getCaches();
+ RenderState& renderState = mFunctor->renderer->renderState();
+
bool first = true;
- bool force = false;
+ bool forceRebind = false;
for (uint32_t i = 0; i < cacheTextures.size(); i++) {
CacheTexture* texture = cacheTextures[i];
if (texture->canDraw()) {
if (first) {
if (mFunctor) {
- TextSetupFunctor::Data functorData(texture->getFormat());
- (*mFunctor)(0, &functorData);
+ mFunctor->setup(texture->getFormat());
}
checkTextureUpdate();
- caches.bindQuadIndicesBuffer();
+ renderState.meshState().bindQuadIndicesBuffer();
if (!mDrawn) {
// If returns true, a VBO was bound and we must
// rebind our vertex attrib pointers even if
// they have the same values as the current pointers
- force = caches.unbindMeshBuffer();
+ forceRebind = renderState.meshState().unbindMeshBuffer();
}
caches.activeTexture(0);
@@ -515,14 +515,16 @@
texture->setLinearFiltering(mLinearFiltering, false);
TextureVertex* mesh = texture->mesh();
- caches.bindPositionVertexPointer(force, &mesh[0].x);
- caches.bindTexCoordsVertexPointer(force, &mesh[0].u);
- force = false;
+ MeshState& meshState = renderState.meshState();
+ Program* program = caches.currentProgram;
+ meshState.bindPositionVertexPointer(program, forceRebind, &mesh[0].x);
+ meshState.bindTexCoordsVertexPointer(program, forceRebind, &mesh[0].u);
glDrawElements(GL_TRIANGLES, texture->meshElementCount(),
GL_UNSIGNED_SHORT, texture->indices());
texture->resetMesh();
+ forceRebind = false;
}
}
}
@@ -647,7 +649,7 @@
Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
// Unbind any PBO we might have used
- Caches::getInstance().unbindPixelBuffer();
+ Caches::getInstance().pixelBuffer().unbind();
blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
}
@@ -661,7 +663,7 @@
return image;
}
-void FontRenderer::initRender(const Rect* clip, Rect* bounds, Functor* functor) {
+void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextSetupFunctor* functor) {
checkInit();
mDrawn = false;
@@ -689,7 +691,7 @@
bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
- const float* positions, Rect* bounds, Functor* functor, bool forceFinish) {
+ const float* positions, Rect* bounds, TextSetupFunctor* functor, bool forceFinish) {
if (!mCurrentFont) {
ALOGE("No font set");
return false;
@@ -707,7 +709,7 @@
bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
- float hOffset, float vOffset, Rect* bounds, Functor* functor) {
+ float hOffset, float vOffset, Rect* bounds, TextSetupFunctor* functor) {
if (!mCurrentFont) {
ALOGE("No font set");
return false;
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 668ee64..cb63684 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -17,7 +17,12 @@
#ifndef ANDROID_HWUI_FONT_RENDERER_H
#define ANDROID_HWUI_FONT_RENDERER_H
-#include <utils/Functor.h>
+#include "font/FontUtil.h"
+#include "font/CacheTexture.h"
+#include "font/CachedGlyphInfo.h"
+#include "font/Font.h"
+#include "utils/SortedList.h"
+
#include <utils/LruCache.h>
#include <utils/Vector.h>
#include <utils/StrongPointer.h>
@@ -26,12 +31,6 @@
#include <GLES2/gl2.h>
-#include "font/FontUtil.h"
-#include "font/CacheTexture.h"
-#include "font/CachedGlyphInfo.h"
-#include "font/Font.h"
-#include "utils/SortedList.h"
-
#ifdef ANDROID_ENABLE_RENDERSCRIPT
#include "RenderScript.h"
namespace RSC {
@@ -47,26 +46,20 @@
class OpenGLRenderer;
-///////////////////////////////////////////////////////////////////////////////
-// TextSetupFunctor
-///////////////////////////////////////////////////////////////////////////////
-class TextSetupFunctor: public Functor {
+class TextSetupFunctor {
public:
- struct Data {
- Data(GLenum glyphFormat) : glyphFormat(glyphFormat) {
- }
-
- GLenum glyphFormat;
- };
-
TextSetupFunctor(OpenGLRenderer* renderer, float x, float y, bool pureTranslate,
- int alpha, SkXfermode::Mode mode, const SkPaint* paint): Functor(),
- renderer(renderer), x(x), y(y), pureTranslate(pureTranslate),
- alpha(alpha), mode(mode), paint(paint) {
+ int alpha, SkXfermode::Mode mode, const SkPaint* paint)
+ : renderer(renderer)
+ , x(x)
+ , y(y)
+ , pureTranslate(pureTranslate)
+ , alpha(alpha)
+ , mode(mode)
+ , paint(paint) {
}
- ~TextSetupFunctor() { }
- status_t operator ()(int what, void* data) override;
+ status_t setup(GLenum glyphFormat);
OpenGLRenderer* renderer;
float x;
@@ -77,10 +70,6 @@
const SkPaint* paint;
};
-///////////////////////////////////////////////////////////////////////////////
-// FontRenderer
-///////////////////////////////////////////////////////////////////////////////
-
class FontRenderer {
public:
FontRenderer();
@@ -101,22 +90,14 @@
// bounds is an out parameter
bool renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, const float* positions,
- Rect* bounds, Functor* functor, bool forceFinish = true);
+ Rect* bounds, TextSetupFunctor* functor, bool forceFinish = true);
// bounds is an out parameter
bool renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
- float hOffset, float vOffset, Rect* bounds, Functor* functor);
+ float hOffset, float vOffset, Rect* bounds, TextSetupFunctor* functor);
struct DropShadow {
- DropShadow() { };
-
- DropShadow(const DropShadow& dropShadow):
- width(dropShadow.width), height(dropShadow.height),
- image(dropShadow.image), penX(dropShadow.penX),
- penY(dropShadow.penY) {
- }
-
uint32_t width;
uint32_t height;
uint8_t* image;
@@ -152,7 +133,7 @@
void flushAllAndInvalidate();
void checkInit();
- void initRender(const Rect* clip, Rect* bounds, Functor* functor);
+ void initRender(const Rect* clip, Rect* bounds, TextSetupFunctor* functor);
void finishRender();
void issueDrawCommand(Vector<CacheTexture*>& cacheTextures);
@@ -193,7 +174,7 @@
bool mUploadTexture;
- Functor* mFunctor;
+ TextSetupFunctor* mFunctor;
const Rect* mClip;
Rect* mBounds;
bool mDrawn;
diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h
index 9176c76..1714e6d 100644
--- a/libs/hwui/GradientCache.h
+++ b/libs/hwui/GradientCache.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_HWUI_GRADIENT_CACHE_H
#define ANDROID_HWUI_GRADIENT_CACHE_H
+#include <memory>
+
#include <GLES3/gl3.h>
#include <SkShader.h>
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index ee6154f..7a4b830 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -68,15 +68,23 @@
}
Layer::~Layer() {
- renderState.requireGLContext();
renderState.unregisterLayer(this);
SkSafeUnref(colorFilter);
- removeFbo();
- deleteTexture();
+
+ if (stencil || fbo || texture.id) {
+ renderState.requireGLContext();
+ removeFbo();
+ deleteTexture();
+ }
delete[] mesh;
}
+void Layer::onGlContextLost() {
+ removeFbo();
+ deleteTexture();
+}
+
uint32_t Layer::computeIdealWidth(uint32_t layerWidth) {
return uint32_t(ceilf(layerWidth / float(LAYER_SIZE)) * LAYER_SIZE);
}
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 3b4f293..84ff021 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -288,6 +288,12 @@
void postDecStrong();
/**
+ * Lost the GL context but the layer is still around, mark it invalid internally
+ * so the dtor knows not to do any GL work
+ */
+ void onGlContextLost();
+
+ /**
* Bounds of the layer.
*/
Rect layer;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 0844cb6..42b246c 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -152,7 +152,7 @@
memset(&mDrawModifiers, 0, sizeof(mDrawModifiers));
mDrawModifiers.mOverrideLayerAlpha = 1.0f;
- memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
+ memcpy(mMeshVertices, kMeshVertices, sizeof(kMeshVertices));
}
OpenGLRenderer::~OpenGLRenderer() {
@@ -436,22 +436,22 @@
clip->bottom - clip->top);
// 1x overdraw
- mCaches.stencil.enableDebugTest(2);
+ mRenderState.stencil().enableDebugTest(2);
drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode);
// 2x overdraw
- mCaches.stencil.enableDebugTest(3);
+ mRenderState.stencil().enableDebugTest(3);
drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode);
// 3x overdraw
- mCaches.stencil.enableDebugTest(4);
+ mRenderState.stencil().enableDebugTest(4);
drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode);
// 4x overdraw and higher
- mCaches.stencil.enableDebugTest(4, true);
+ mRenderState.stencil().enableDebugTest(4, true);
drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode);
- mCaches.stencil.disable();
+ mRenderState.stencil().disable();
}
}
@@ -894,7 +894,7 @@
layer->setAlpha(255);
}
- mCaches.unbindMeshBuffer();
+ mRenderState.meshState().unbindMeshBuffer();
mCaches.activeTexture(0);
@@ -963,7 +963,7 @@
setupDrawTextureTransformUniforms(layer->getTexTransform());
setupDrawMesh(&mMeshVertices[0].x, &mMeshVertices[0].u);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, kMeshCount);
}
void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
@@ -1005,7 +1005,7 @@
drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
layer->getTexture(), &layerPaint, blend,
&mMeshVertices[0].x, &mMeshVertices[0].u,
- GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
+ GL_TRIANGLE_STRIP, kMeshCount, swap, swap || simpleTransform);
resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
}
@@ -1171,7 +1171,7 @@
numQuads++;
- if (numQuads >= gMaxNumberOfQuads) {
+ if (numQuads >= kMaxNumberOfQuads) {
DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
GL_UNSIGNED_SHORT, nullptr));
numQuads = 0;
@@ -1264,7 +1264,7 @@
void OpenGLRenderer::issueIndexedQuadDraw(Vertex* mesh, GLsizei quadsCount) {
GLsizei elementsCount = quadsCount * 6;
while (elementsCount > 0) {
- GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
+ GLsizei drawCount = min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
setupDrawIndexedVertices(&mesh[0].x);
glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr);
@@ -1537,7 +1537,7 @@
incrementThreshold = 0;
}
- mCaches.stencil.enableWrite(incrementThreshold);
+ mRenderState.stencil().enableWrite(incrementThreshold);
// Clean and update the stencil, but first make sure we restrict drawing
// to the region's bounds
@@ -1547,7 +1547,7 @@
setScissorFromClip();
}
- mCaches.stencil.clear();
+ mRenderState.stencil().clear();
// stash and disable the outline clip state, since stencil doesn't account for outline
bool storedSkipOutlineClip = mSkipOutlineClip;
@@ -1571,7 +1571,7 @@
if (resetScissor) mRenderState.scissor().setEnabled(false);
mSkipOutlineClip = storedSkipOutlineClip;
- mCaches.stencil.enableTest(incrementThreshold);
+ mRenderState.stencil().enableTest(incrementThreshold);
// Draw the region used to generate the stencil if the appropriate debug
// mode is enabled
@@ -1584,7 +1584,7 @@
}
} else {
EVENT_LOGD("setStencilFromClip - disabling");
- mCaches.stencil.disable();
+ mRenderState.stencil().disable();
}
}
}
@@ -1661,7 +1661,7 @@
// the stencil buffer and if stencil highlight debugging is on
mDescription.hasDebugHighlight = !mCaches.debugOverdraw &&
mCaches.debugStencilClip == Caches::kStencilShowHighlight &&
- mCaches.stencil.isTestEnabled();
+ mRenderState.stencil().isTestEnabled();
}
void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
@@ -1680,7 +1680,7 @@
}
void OpenGLRenderer::setupDrawNoTexture() {
- mCaches.disableTexCoordsVertexArray();
+ mRenderState.meshState().disableTexCoordsVertexArray();
}
void OpenGLRenderer::setupDrawVertexAlpha(bool useShadowAlphaInterp) {
@@ -1892,21 +1892,21 @@
}
void OpenGLRenderer::setupDrawSimpleMesh() {
- bool force = mCaches.bindMeshBuffer();
- mCaches.bindPositionVertexPointer(force, nullptr);
- mCaches.unbindIndicesBuffer();
+ bool force = mRenderState.meshState().bindMeshBuffer();
+ mRenderState.meshState().bindPositionVertexPointer(mCaches.currentProgram, force, nullptr);
+ mRenderState.meshState().unbindIndicesBuffer();
}
void OpenGLRenderer::setupDrawTexture(GLuint texture) {
if (texture) bindTexture(texture);
mTextureUnit++;
- mCaches.enableTexCoordsVertexArray();
+ mRenderState.meshState().enableTexCoordsVertexArray();
}
void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
bindExternalTexture(texture);
mTextureUnit++;
- mCaches.enableTexCoordsVertexArray();
+ mRenderState.meshState().enableTexCoordsVertexArray();
}
void OpenGLRenderer::setupDrawTextureTransform() {
@@ -1922,27 +1922,29 @@
const GLvoid* texCoords, GLuint vbo) {
bool force = false;
if (!vertices || vbo) {
- force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
+ force = mRenderState.meshState().bindMeshBuffer(vbo);
} else {
- force = mCaches.unbindMeshBuffer();
+ force = mRenderState.meshState().unbindMeshBuffer();
}
- mCaches.bindPositionVertexPointer(force, vertices);
+ mRenderState.meshState().bindPositionVertexPointer(mCaches.currentProgram, force, vertices);
if (mCaches.currentProgram->texCoords >= 0) {
- mCaches.bindTexCoordsVertexPointer(force, texCoords);
+ mRenderState.meshState().bindTexCoordsVertexPointer(mCaches.currentProgram, force, texCoords);
}
- mCaches.unbindIndicesBuffer();
+ mRenderState.meshState().unbindIndicesBuffer();
}
void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
const GLvoid* texCoords, const GLvoid* colors) {
- bool force = mCaches.unbindMeshBuffer();
+ bool force = mRenderState.meshState().unbindMeshBuffer();
GLsizei stride = sizeof(ColorTextureVertex);
- mCaches.bindPositionVertexPointer(force, vertices, stride);
+ mRenderState.meshState().bindPositionVertexPointer(mCaches.currentProgram, force,
+ vertices, stride);
if (mCaches.currentProgram->texCoords >= 0) {
- mCaches.bindTexCoordsVertexPointer(force, texCoords, stride);
+ mRenderState.meshState().bindTexCoordsVertexPointer(mCaches.currentProgram, force,
+ texCoords, stride);
}
int slot = mCaches.currentProgram->getAttrib("colors");
if (slot >= 0) {
@@ -1950,7 +1952,7 @@
glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors);
}
- mCaches.unbindIndicesBuffer();
+ mRenderState.meshState().unbindIndicesBuffer();
}
void OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices,
@@ -1958,24 +1960,26 @@
bool force = false;
// If vbo is != 0 we want to treat the vertices parameter as an offset inside
// a VBO. However, if vertices is set to NULL and vbo == 0 then we want to
- // use the default VBO found in Caches
+ // use the default VBO found in RenderState
if (!vertices || vbo) {
- force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
+ force = mRenderState.meshState().bindMeshBuffer(vbo);
} else {
- force = mCaches.unbindMeshBuffer();
+ force = mRenderState.meshState().unbindMeshBuffer();
}
- mCaches.bindQuadIndicesBuffer();
+ mRenderState.meshState().bindQuadIndicesBuffer();
- mCaches.bindPositionVertexPointer(force, vertices);
+ mRenderState.meshState().bindPositionVertexPointer(mCaches.currentProgram, force, vertices);
if (mCaches.currentProgram->texCoords >= 0) {
- mCaches.bindTexCoordsVertexPointer(force, texCoords);
+ mRenderState.meshState().bindTexCoordsVertexPointer(mCaches.currentProgram,
+ force, texCoords);
}
}
void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
- bool force = mCaches.unbindMeshBuffer();
- mCaches.bindQuadIndicesBuffer();
- mCaches.bindPositionVertexPointer(force, vertices, gVertexStride);
+ bool force = mRenderState.meshState().unbindMeshBuffer();
+ mRenderState.meshState().bindQuadIndicesBuffer();
+ mRenderState.meshState().bindPositionVertexPointer(mCaches.currentProgram, force,
+ vertices, kVertexStride);
}
///////////////////////////////////////////////////////////////////////////////
@@ -2034,8 +2038,8 @@
// No need to check for a UV mapper on the texture object, only ARGB_8888
// bitmaps get packed in the atlas
drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
- paint, (GLvoid*) nullptr, (GLvoid*) gMeshTextureOffset,
- GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
+ paint, (GLvoid*) nullptr, (GLvoid*) kMeshTextureOffset,
+ GL_TRIANGLE_STRIP, kMeshCount, ignoreTransform);
}
/**
@@ -2228,7 +2232,7 @@
getMapper(texture).map(u1, v1, u2, v2);
- mCaches.unbindMeshBuffer();
+ mRenderState.meshState().unbindMeshBuffer();
resetDrawTextureTexCoords(u1, v1, u2, v2);
texture->setWrap(GL_CLAMP_TO_EDGE, true);
@@ -2275,12 +2279,12 @@
drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom,
texture->id, paint,
&mMeshVertices[0].x, &mMeshVertices[0].u,
- GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
+ GL_TRIANGLE_STRIP, kMeshCount, ignoreTransform);
} else {
drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom,
texture->id, paint, texture->blend,
&mMeshVertices[0].x, &mMeshVertices[0].u,
- GL_TRIANGLE_STRIP, gMeshCount, false, ignoreTransform);
+ GL_TRIANGLE_STRIP, kMeshCount, false, ignoreTransform);
}
if (CC_UNLIKELY(useScaleTransform)) {
@@ -2412,33 +2416,34 @@
setupDrawShaderUniforms(getShader(paint));
const void* vertices = vertexBuffer.getBuffer();
- mCaches.unbindMeshBuffer();
- mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride);
- mCaches.resetTexCoordsVertexPointer();
+ mRenderState.meshState().unbindMeshBuffer();
+ mRenderState.meshState().bindPositionVertexPointer(mCaches.currentProgram,
+ true, vertices, isAA ? kAlphaVertexStride : kVertexStride);
+ mRenderState.meshState().resetTexCoordsVertexPointer();
int alphaSlot = -1;
if (isAA) {
- void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset;
+ void* alphaCoords = ((GLbyte*) vertices) + kVertexAlphaOffset;
alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha");
// TODO: avoid enable/disable in back to back uses of the alpha attribute
glEnableVertexAttribArray(alphaSlot);
- glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
+ glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, kAlphaVertexStride, alphaCoords);
}
const VertexBuffer::Mode mode = vertexBuffer.getMode();
if (mode == VertexBuffer::kStandard) {
- mCaches.unbindIndicesBuffer();
+ mRenderState.meshState().unbindIndicesBuffer();
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
} else if (mode == VertexBuffer::kOnePolyRingShadow) {
- mCaches.bindShadowIndicesBuffer();
+ mRenderState.meshState().bindShadowIndicesBuffer();
glDrawElements(GL_TRIANGLE_STRIP, ONE_POLY_RING_SHADOW_INDEX_COUNT,
GL_UNSIGNED_SHORT, nullptr);
} else if (mode == VertexBuffer::kTwoPolyRingShadow) {
- mCaches.bindShadowIndicesBuffer();
+ mRenderState.meshState().bindShadowIndicesBuffer();
glDrawElements(GL_TRIANGLE_STRIP, TWO_POLY_RING_SHADOW_INDEX_COUNT,
GL_UNSIGNED_SHORT, nullptr);
} else if (mode == VertexBuffer::kIndices) {
- mCaches.unbindIndicesBuffer();
+ mRenderState.meshState().unbindIndicesBuffer();
glDrawElements(GL_TRIANGLE_STRIP, vertexBuffer.getIndexCount(),
GL_UNSIGNED_SHORT, vertexBuffer.getIndices());
}
@@ -2720,9 +2725,9 @@
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawShaderUniforms(getShader(paint));
- setupDrawMesh(nullptr, (GLvoid*) gMeshTextureOffset);
+ setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, kMeshCount);
}
bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
@@ -2872,8 +2877,6 @@
mState.setClippingRoundRect(allocator, rect, radius, highPriority);
}
-
-
void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
DrawOpMode drawOpMode) {
@@ -3078,7 +3081,7 @@
GLsizei elementsCount = layer->meshElementCount;
while (elementsCount > 0) {
- GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
+ GLsizei drawCount = min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
@@ -3156,9 +3159,9 @@
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawShaderUniforms(getShader(paint));
- setupDrawMesh(nullptr, (GLvoid*) gMeshTextureOffset);
+ setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, kMeshCount);
}
// Same values used by Skia
@@ -3337,7 +3340,7 @@
setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawSimpleMesh();
- glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, kMeshCount);
}
void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
@@ -3345,7 +3348,7 @@
texture->setWrap(GL_CLAMP_TO_EDGE, true);
GLvoid* vertices = (GLvoid*) nullptr;
- GLvoid* texCoords = (GLvoid*) gMeshTextureOffset;
+ GLvoid* texCoords = (GLvoid*) kMeshTextureOffset;
if (texture->uvMapper) {
vertices = &mMeshVertices[0].x;
@@ -3364,11 +3367,11 @@
texture->setFilter(GL_NEAREST, true);
drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
paint, texture->blend, vertices, texCoords,
- GL_TRIANGLE_STRIP, gMeshCount, false, true);
+ GL_TRIANGLE_STRIP, kMeshCount, false, true);
} else {
texture->setFilter(getFilter(paint), true);
drawTextureMesh(left, top, right, bottom, texture->id, paint,
- texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, gMeshCount);
+ texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, kMeshCount);
}
if (texture->uvMapper) {
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index eb88bc0..af403b4 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -23,6 +23,7 @@
#include "Patch.h"
#include "PatchCache.h"
#include "Properties.h"
+#include "renderstate/RenderState.h"
namespace android {
namespace uirenderer {
@@ -31,9 +32,13 @@
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-PatchCache::PatchCache():
- mSize(0), mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity),
- mMeshBuffer(0), mFreeBlocks(nullptr), mGenerationId(0) {
+PatchCache::PatchCache(RenderState& renderState)
+ : mRenderState(renderState)
+ , mSize(0)
+ , mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity)
+ , mMeshBuffer(0)
+ , mFreeBlocks(nullptr)
+ , mGenerationId(0) {
char property[PROPERTY_VALUE_MAX];
if (property_get(PROPERTY_PATCH_CACHE_SIZE, property, nullptr) > 0) {
INIT_LOGD(" Setting patch cache size to %skB", property);
@@ -48,15 +53,15 @@
clear();
}
-void PatchCache::init(Caches& caches) {
+void PatchCache::init() {
bool created = false;
if (!mMeshBuffer) {
glGenBuffers(1, &mMeshBuffer);
created = true;
}
- caches.bindMeshBuffer(mMeshBuffer);
- caches.resetVertexPointers();
+ mRenderState.meshState().bindMeshBuffer(mMeshBuffer);
+ mRenderState.meshState().resetVertexPointers();
if (created) {
createVertexBuffer();
@@ -85,7 +90,7 @@
clearCache();
if (mMeshBuffer) {
- Caches::getInstance().unbindMeshBuffer();
+ mRenderState.meshState().unbindMeshBuffer();
glDeleteBuffers(1, &mMeshBuffer);
mMeshBuffer = 0;
mSize = 0;
@@ -187,7 +192,7 @@
*/
void PatchCache::setupMesh(Patch* newMesh, TextureVertex* vertices) {
// This call ensures the VBO exists and that it is bound
- init(Caches::getInstance());
+ init();
// If we're running out of space, let's clear the entire cache
uint32_t size = newMesh->getSize();
@@ -219,7 +224,7 @@
// Copy the 9patch mesh in the VBO
newMesh->offset = (GLintptr) (block->offset);
- newMesh->textureOffset = newMesh->offset + gMeshTextureOffset;
+ newMesh->textureOffset = newMesh->offset + kMeshTextureOffset;
glBufferSubData(GL_ARRAY_BUFFER, newMesh->offset, size, vertices);
// Remove the block since we've used it entirely
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index 4cb5338..e038720 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -51,9 +51,9 @@
class PatchCache {
public:
- PatchCache();
+ PatchCache(RenderState& renderState);
~PatchCache();
- void init(Caches& caches);
+ void init();
const Patch* get(const AssetAtlas::Entry* entry,
const uint32_t bitmapWidth, const uint32_t bitmapHeight,
@@ -168,6 +168,7 @@
void dumpFreeBlocks(const char* prefix);
#endif
+ RenderState& mRenderState;
uint32_t mMaxSize;
uint32_t mSize;
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index c564b87..cc7f88d 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -31,7 +31,6 @@
#include "PathCache.h"
#include "thread/Signal.h"
-#include "thread/Task.h"
#include "thread/TaskProcessor.h"
namespace android {
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index ecd3712..7378018 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -17,21 +17,22 @@
#ifndef ANDROID_HWUI_PATH_CACHE_H
#define ANDROID_HWUI_PATH_CACHE_H
-#include <GLES2/gl2.h>
+#include "Debug.h"
+#include "Texture.h"
+#include "thread/Task.h"
+#include "thread/TaskProcessor.h"
+#include "utils/Macros.h"
+#include "utils/Pair.h"
+#include <GLES2/gl2.h>
+#include <SkPath.h>
#include <utils/LruCache.h>
#include <utils/Mutex.h>
#include <utils/Vector.h>
-#include "Debug.h"
-#include "Texture.h"
-#include "utils/Macros.h"
-#include "utils/Pair.h"
-
class SkBitmap;
class SkCanvas;
class SkPaint;
-class SkPath;
struct SkRect;
namespace android {
diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp
index efa271e..62eb68c 100644
--- a/libs/hwui/PixelBuffer.cpp
+++ b/libs/hwui/PixelBuffer.cpp
@@ -16,13 +16,14 @@
#define LOG_TAG "OpenGLRenderer"
-#include <utils/Log.h>
+#include "PixelBuffer.h"
-#include "Caches.h"
#include "Debug.h"
#include "Extensions.h"
-#include "PixelBuffer.h"
#include "Properties.h"
+#include "renderstate/RenderState.h"
+
+#include <utils/Log.h>
namespace android {
namespace uirenderer {
@@ -93,14 +94,16 @@
Caches& mCaches;
};
-GpuPixelBuffer::GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height)
+GpuPixelBuffer::GpuPixelBuffer(GLenum format,
+ uint32_t width, uint32_t height)
: PixelBuffer(format, width, height)
, mMappedPointer(nullptr)
- , mCaches(Caches::getInstance()) {
+ , mCaches(Caches::getInstance()){
glGenBuffers(1, &mBuffer);
- mCaches.bindPixelBuffer(mBuffer);
+
+ mCaches.pixelBuffer().bind(mBuffer);
glBufferData(GL_PIXEL_UNPACK_BUFFER, getSize(), nullptr, GL_DYNAMIC_DRAW);
- mCaches.unbindPixelBuffer();
+ mCaches.pixelBuffer().unbind();
}
GpuPixelBuffer::~GpuPixelBuffer() {
@@ -109,7 +112,7 @@
uint8_t* GpuPixelBuffer::map(AccessMode mode) {
if (mAccessMode == kAccessMode_None) {
- mCaches.bindPixelBuffer(mBuffer);
+ mCaches.pixelBuffer().bind(mBuffer);
mMappedPointer = (uint8_t*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode);
#if DEBUG_OPENGL
if (!mMappedPointer) {
@@ -128,7 +131,7 @@
void GpuPixelBuffer::unmap() {
if (mAccessMode != kAccessMode_None) {
if (mMappedPointer) {
- mCaches.bindPixelBuffer(mBuffer);
+ mCaches.pixelBuffer().bind(mBuffer);
GLboolean status = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
if (status == GL_FALSE) {
ALOGE("Corrupted GPU pixel buffer");
@@ -145,7 +148,7 @@
void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) {
// If the buffer is not mapped, unmap() will not bind it
- mCaches.bindPixelBuffer(mBuffer);
+ mCaches.pixelBuffer().bind(mBuffer);
unmap();
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat,
GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset));
@@ -155,7 +158,8 @@
// Factory
///////////////////////////////////////////////////////////////////////////////
-PixelBuffer* PixelBuffer::create(GLenum format, uint32_t width, uint32_t height, BufferType type) {
+PixelBuffer* PixelBuffer::create(GLenum format,
+ uint32_t width, uint32_t height, BufferType type) {
if (type == kBufferType_Auto && Caches::getInstance().gpuPixelBuffersEnabled) {
return new GpuPixelBuffer(format, width, height);
}
diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h
index 04225a2..aac5ec4 100644
--- a/libs/hwui/PixelBuffer.h
+++ b/libs/hwui/PixelBuffer.h
@@ -18,6 +18,7 @@
#define ANDROID_HWUI_PIXEL_BUFFER_H
#include <GLES3/gl3.h>
+#include <cutils/log.h>
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/Vector.h b/libs/hwui/Vector.h
index aa6acc9..7c3f2fd 100644
--- a/libs/hwui/Vector.h
+++ b/libs/hwui/Vector.h
@@ -17,6 +17,9 @@
#ifndef ANDROID_HWUI_VECTOR_H
#define ANDROID_HWUI_VECTOR_H
+#include <math.h>
+#include <utils/Log.h>
+
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/renderstate/MeshState.cpp b/libs/hwui/renderstate/MeshState.cpp
new file mode 100644
index 0000000..7820a66
--- /dev/null
+++ b/libs/hwui/renderstate/MeshState.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2015 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 "renderstate/MeshState.h"
+
+#include "Program.h"
+
+#include "ShadowTessellator.h"
+
+namespace android {
+namespace uirenderer {
+
+MeshState::MeshState()
+ : mCurrentPositionPointer(this)
+ , mCurrentPositionStride(0)
+ , mCurrentTexCoordsPointer(this)
+ , mCurrentTexCoordsStride(0)
+ , mTexCoordsArrayEnabled(false) {
+
+ glGenBuffers(1, &meshBuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(kMeshVertices), kMeshVertices, GL_STATIC_DRAW);
+
+ mCurrentBuffer = meshBuffer;
+ mCurrentIndicesBuffer = 0;
+ mCurrentPixelBuffer = 0;
+
+ mQuadListIndices = 0;
+ mShadowStripsIndices = 0;
+}
+
+MeshState::~MeshState() {
+ glDeleteBuffers(1, &meshBuffer);
+ mCurrentBuffer = 0;
+
+ glDeleteBuffers(1, &mQuadListIndices);
+ mQuadListIndices = 0;
+
+ glDeleteBuffers(1, &mShadowStripsIndices);
+ mShadowStripsIndices = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Buffer Objects
+///////////////////////////////////////////////////////////////////////////////
+
+bool MeshState::bindMeshBuffer() {
+ return bindMeshBuffer(meshBuffer);
+}
+
+bool MeshState::bindMeshBuffer(GLuint buffer) {
+ if (!buffer) buffer = meshBuffer;
+ if (mCurrentBuffer != buffer) {
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
+ mCurrentBuffer = buffer;
+ return true;
+ }
+ return false;
+}
+
+bool MeshState::unbindMeshBuffer() {
+ if (mCurrentBuffer) {
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ mCurrentBuffer = 0;
+ return true;
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Vertices
+///////////////////////////////////////////////////////////////////////////////
+
+void MeshState::bindPositionVertexPointer(const Program* currentProgram, bool force,
+ const GLvoid* vertices, GLsizei stride) {
+ if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
+ GLuint slot = currentProgram->position;
+ glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
+ mCurrentPositionPointer = vertices;
+ mCurrentPositionStride = stride;
+ }
+}
+
+void MeshState::bindTexCoordsVertexPointer(const Program* currentProgram, bool force,
+ const GLvoid* vertices, GLsizei stride) {
+ if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
+ GLuint slot = currentProgram->texCoords;
+ glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
+ mCurrentTexCoordsPointer = vertices;
+ mCurrentTexCoordsStride = stride;
+ }
+}
+
+void MeshState::resetVertexPointers() {
+ mCurrentPositionPointer = this;
+ mCurrentTexCoordsPointer = this;
+}
+
+void MeshState::resetTexCoordsVertexPointer() {
+ mCurrentTexCoordsPointer = this;
+}
+
+void MeshState::enableTexCoordsVertexArray() {
+ if (!mTexCoordsArrayEnabled) {
+ glEnableVertexAttribArray(Program::kBindingTexCoords);
+ mCurrentTexCoordsPointer = this;
+ mTexCoordsArrayEnabled = true;
+ }
+}
+
+void MeshState::disableTexCoordsVertexArray() {
+ if (mTexCoordsArrayEnabled) {
+ glDisableVertexAttribArray(Program::kBindingTexCoords);
+ mTexCoordsArrayEnabled = false;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Indices
+///////////////////////////////////////////////////////////////////////////////
+
+bool MeshState::bindIndicesBufferInternal(const GLuint buffer) {
+ if (mCurrentIndicesBuffer != buffer) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
+ mCurrentIndicesBuffer = buffer;
+ return true;
+ }
+ return false;
+}
+
+bool MeshState::bindQuadIndicesBuffer() {
+ if (!mQuadListIndices) {
+ std::unique_ptr<uint16_t[]> regionIndices(new uint16_t[kMaxNumberOfQuads * 6]);
+ for (uint32_t i = 0; i < kMaxNumberOfQuads; i++) {
+ uint16_t quad = i * 4;
+ int index = i * 6;
+ regionIndices[index ] = quad; // top-left
+ regionIndices[index + 1] = quad + 1; // top-right
+ regionIndices[index + 2] = quad + 2; // bottom-left
+ regionIndices[index + 3] = quad + 2; // bottom-left
+ regionIndices[index + 4] = quad + 1; // top-right
+ regionIndices[index + 5] = quad + 3; // bottom-right
+ }
+
+ glGenBuffers(1, &mQuadListIndices);
+ bool force = bindIndicesBufferInternal(mQuadListIndices);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, kMaxNumberOfQuads * 6 * sizeof(uint16_t),
+ regionIndices.get(), GL_STATIC_DRAW);
+ return force;
+ }
+
+ return bindIndicesBufferInternal(mQuadListIndices);
+}
+
+bool MeshState::bindShadowIndicesBuffer() {
+ if (!mShadowStripsIndices) {
+ std::unique_ptr<uint16_t[]> shadowIndices(new uint16_t[MAX_SHADOW_INDEX_COUNT]);
+ ShadowTessellator::generateShadowIndices(shadowIndices.get());
+ glGenBuffers(1, &mShadowStripsIndices);
+ bool force = bindIndicesBufferInternal(mShadowStripsIndices);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_SHADOW_INDEX_COUNT * sizeof(uint16_t),
+ shadowIndices.get(), GL_STATIC_DRAW);
+ return force;
+ }
+
+ return bindIndicesBufferInternal(mShadowStripsIndices);
+}
+
+bool MeshState::unbindIndicesBuffer() {
+ if (mCurrentIndicesBuffer) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ mCurrentIndicesBuffer = 0;
+ return true;
+ }
+ return false;
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/MeshState.h b/libs/hwui/renderstate/MeshState.h
new file mode 100644
index 0000000..76f73d4
--- /dev/null
+++ b/libs/hwui/renderstate/MeshState.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2015 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 RENDERSTATE_MESHSTATE_H
+#define RENDERSTATE_MESHSTATE_H
+
+#include "Vertex.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <memory>
+
+namespace android {
+namespace uirenderer {
+
+class Program;
+
+// Maximum number of quads that pre-allocated meshes can draw
+const uint32_t kMaxNumberOfQuads = 2048;
+
+// This array is never used directly but used as a memcpy source in the
+// OpenGLRenderer constructor
+const TextureVertex kMeshVertices[] = {
+ { 0, 0, 0, 0 },
+ { 1, 0, 1, 0 },
+ { 0, 1, 0, 1 },
+ { 1, 1, 1, 1 },
+};
+
+const GLsizei kVertexStride = sizeof(Vertex);
+const GLsizei kAlphaVertexStride = sizeof(AlphaVertex);
+const GLsizei kTextureVertexStride = sizeof(TextureVertex);
+
+const GLsizei kMeshTextureOffset = 2 * sizeof(float);
+const GLsizei kVertexAlphaOffset = 2 * sizeof(float);
+const GLsizei kVertexAAWidthOffset = 2 * sizeof(float);
+const GLsizei kVertexAALengthOffset = 3 * sizeof(float);
+const GLsizei kMeshCount = 4;
+
+class MeshState {
+private:
+ friend class RenderState;
+
+public:
+ ~MeshState();
+ ///////////////////////////////////////////////////////////////////////////////
+ // Buffer objects
+ ///////////////////////////////////////////////////////////////////////////////
+ /**
+ * Binds the VBO used to render simple textured quads.
+ */
+ bool bindMeshBuffer();
+
+ /**
+ * Binds the specified VBO if needed. If buffer == 0, binds default simple textured quad.
+ */
+ bool bindMeshBuffer(GLuint buffer);
+
+ /**
+ * Unbinds the VBO used to render simple textured quads.
+ */
+ bool unbindMeshBuffer();
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // Vertices
+ ///////////////////////////////////////////////////////////////////////////////
+ /**
+ * Binds an attrib to the specified float vertex pointer.
+ * Assumes a stride of gTextureVertexStride and a size of 2.
+ */
+ void bindPositionVertexPointer(const Program* currentProgram, bool force,
+ const GLvoid* vertices, GLsizei stride = kTextureVertexStride);
+
+ /**
+ * Binds an attrib to the specified float vertex pointer.
+ * Assumes a stride of gTextureVertexStride and a size of 2.
+ */
+ void bindTexCoordsVertexPointer(const Program* currentProgram, bool force,
+ const GLvoid* vertices, GLsizei stride = kTextureVertexStride);
+
+ /**
+ * Resets the vertex pointers.
+ */
+ void resetVertexPointers();
+ void resetTexCoordsVertexPointer();
+
+ void enableTexCoordsVertexArray();
+ void disableTexCoordsVertexArray();
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // Indices
+ ///////////////////////////////////////////////////////////////////////////////
+ /**
+ * Binds a global indices buffer that can draw up to
+ * gMaxNumberOfQuads quads.
+ */
+ bool bindQuadIndicesBuffer();
+ bool bindShadowIndicesBuffer();
+ bool unbindIndicesBuffer();
+
+private:
+ MeshState();
+ bool bindIndicesBufferInternal(const GLuint buffer);
+
+ // VBO to draw with
+ GLuint meshBuffer;
+
+ GLuint mCurrentBuffer;
+ GLuint mCurrentIndicesBuffer;
+ GLuint mCurrentPixelBuffer;
+
+ const void* mCurrentPositionPointer;
+ GLsizei mCurrentPositionStride;
+ const void* mCurrentTexCoordsPointer;
+ GLsizei mCurrentTexCoordsStride;
+
+ bool mTexCoordsArrayEnabled;
+
+ // Global index buffer
+ GLuint mQuadListIndices;
+ GLuint mShadowStripsIndices;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_MESHSTATE_H
diff --git a/libs/hwui/renderstate/PixelBufferState.cpp b/libs/hwui/renderstate/PixelBufferState.cpp
new file mode 100644
index 0000000..c23af52
--- /dev/null
+++ b/libs/hwui/renderstate/PixelBufferState.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 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 "renderstate/PixelBufferState.h"
+
+namespace android {
+namespace uirenderer {
+
+PixelBufferState::PixelBufferState()
+ : mCurrentPixelBuffer(0) {
+}
+
+bool PixelBufferState::bind(GLuint buffer) {
+ if (mCurrentPixelBuffer != buffer) {
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
+ mCurrentPixelBuffer = buffer;
+ return true;
+ }
+ return false;
+}
+
+bool PixelBufferState::unbind() {
+ if (mCurrentPixelBuffer) {
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ mCurrentPixelBuffer = 0;
+ return true;
+ }
+ return false;
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/PixelBufferState.h b/libs/hwui/renderstate/PixelBufferState.h
new file mode 100644
index 0000000..8dab21d
--- /dev/null
+++ b/libs/hwui/renderstate/PixelBufferState.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 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 RENDERSTATE_PIXELBUFFERSTATE_H
+#define RENDERSTATE_PIXELBUFFERSTATE_H
+
+#include <GLES3/gl3.h>
+
+namespace android {
+namespace uirenderer {
+
+class PixelBufferState {
+ friend class Caches; // TODO: move to RenderState
+public:
+ bool bind(GLuint buffer);
+ bool unbind();
+private:
+ PixelBufferState();
+ GLuint mCurrentPixelBuffer;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_PIXELBUFFERSTATE_H
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 3a9a92e..e4c8745 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "RenderState.h"
+#include "renderstate/RenderState.h"
#include "renderthread/CanvasContext.h"
#include "renderthread/EglManager.h"
@@ -24,6 +24,9 @@
RenderState::RenderState(renderthread::RenderThread& thread)
: mRenderThread(thread)
, mCaches(nullptr)
+ , mMeshState(nullptr)
+ , mScissor(nullptr)
+ , mStencil(nullptr)
, mViewportWidth(0)
, mViewportHeight(0)
, mFramebuffer(0) {
@@ -31,17 +34,25 @@
}
RenderState::~RenderState() {
+ LOG_ALWAYS_FATAL_IF(mMeshState || mScissor || mStencil,
+ "State object lifecycle not managed correctly");
}
void RenderState::onGLContextCreated() {
- // This is delayed because the first access of Caches makes GL calls
- mCaches = &Caches::getInstance();
- mCaches->init();
- mCaches->setRenderState(this);
- mCaches->textureCache.setAssetAtlas(&mAssetAtlas);
+ LOG_ALWAYS_FATAL_IF(mMeshState || mScissor || mStencil,
+ "State object lifecycle not managed correctly");
+ mMeshState = new MeshState();
+ mScissor = new Scissor();
+ mStencil = new Stencil();
- LOG_ALWAYS_FATAL_IF(scissor().isEnabled(), "scissor used before GL context created");
- glDisable(GL_SCISSOR_TEST);
+ // This is delayed because the first access of Caches makes GL calls
+ mCaches = &Caches::createInstance(*this);
+ mCaches->init();
+ mCaches->textureCache.setAssetAtlas(&mAssetAtlas);
+}
+
+static void layerLostGlContext(Layer* layer) {
+ layer->onGlContextLost();
}
void RenderState::onGLContextDestroyed() {
@@ -76,7 +87,17 @@
LOG_ALWAYS_FATAL("%d layers have survived gl context destruction", size);
}
*/
+
+ // TODO: reset all cached state in state objects
+ std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext);
mAssetAtlas.terminate();
+
+ delete mMeshState;
+ mMeshState = nullptr;
+ delete mScissor;
+ mScissor = nullptr;
+ delete mStencil;
+ mStencil = nullptr;
}
void RenderState::setViewport(GLsizei width, GLsizei height) {
@@ -112,10 +133,10 @@
}
}
mCaches->resetActiveTexture();
- mCaches->unbindMeshBuffer();
- mCaches->unbindIndicesBuffer();
- mCaches->resetVertexPointers();
- mCaches->disableTexCoordsVertexArray();
+ meshState().unbindMeshBuffer();
+ meshState().unbindIndicesBuffer();
+ meshState().resetVertexPointers();
+ meshState().disableTexCoordsVertexArray();
debugOverdraw(false, false);
}
@@ -141,12 +162,12 @@
if (mCaches->debugOverdraw && mFramebuffer == 0) {
if (clear) {
scissor().setEnabled(false);
- mCaches->stencil.clear();
+ stencil().clear();
}
if (enable) {
- mCaches->stencil.enableDebugWrite();
+ stencil().enableDebugWrite();
} else {
- mCaches->stencil.disable();
+ stencil().disable();
}
}
}
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index b2d5cc5..d1ee64a 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -27,7 +27,10 @@
#include "AssetAtlas.h"
#include "Caches.h"
-#include "Scissor.h"
+#include "renderstate/MeshState.h"
+#include "renderstate/PixelBufferState.h"
+#include "renderstate/Scissor.h"
+#include "renderstate/Stencil.h"
#include "utils/Macros.h"
namespace android {
@@ -59,10 +62,10 @@
void debugOverdraw(bool enable, bool clear);
- void registerLayer(const Layer* layer) {
+ void registerLayer(Layer* layer) {
mActiveLayers.insert(layer);
}
- void unregisterLayer(const Layer* layer) {
+ void unregisterLayer(Layer* layer) {
mActiveLayers.erase(layer);
}
@@ -81,8 +84,9 @@
void postDecStrong(VirtualLightRefBase* object);
AssetAtlas& assetAtlas() { return mAssetAtlas; }
-
- Scissor& scissor() { return mScissor; }
+ MeshState& meshState() { return *mMeshState; }
+ Scissor& scissor() { return *mScissor; }
+ Stencil& stencil() { return *mStencil; }
private:
friend class renderthread::RenderThread;
friend class Caches;
@@ -94,12 +98,16 @@
RenderState(renderthread::RenderThread& thread);
~RenderState();
- Scissor mScissor;
renderthread::RenderThread& mRenderThread;
Caches* mCaches;
+
+ MeshState* mMeshState;
+ Scissor* mScissor;
+ Stencil* mStencil;
+
AssetAtlas mAssetAtlas;
- std::set<const Layer*> mActiveLayers;
+ std::set<Layer*> mActiveLayers;
std::set<renderthread::CanvasContext*> mRegisteredContexts;
GLsizei mViewportWidth;
diff --git a/libs/hwui/renderstate/Scissor.cpp b/libs/hwui/renderstate/Scissor.cpp
index ede57be..66c31a2 100644
--- a/libs/hwui/renderstate/Scissor.cpp
+++ b/libs/hwui/renderstate/Scissor.cpp
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "Scissor.h"
+#include "renderstate/Scissor.h"
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/renderstate/Scissor.h b/libs/hwui/renderstate/Scissor.h
index eabf3a77..cc8b3dd 100644
--- a/libs/hwui/renderstate/Scissor.h
+++ b/libs/hwui/renderstate/Scissor.h
@@ -25,12 +25,12 @@
class Scissor {
friend class RenderState;
public:
- Scissor();
bool setEnabled(bool enabled);
bool set(GLint x, GLint y, GLint width, GLint height);
void reset();
bool isEnabled() { return mEnabled; }
private:
+ Scissor();
void invalidate();
bool mEnabled;
GLint mScissorX;
diff --git a/libs/hwui/Stencil.cpp b/libs/hwui/renderstate/Stencil.cpp
similarity index 98%
rename from libs/hwui/Stencil.cpp
rename to libs/hwui/renderstate/Stencil.cpp
index f56a02e..acbed14 100644
--- a/libs/hwui/Stencil.cpp
+++ b/libs/hwui/renderstate/Stencil.cpp
@@ -17,7 +17,7 @@
#include "Debug.h"
#include "Extensions.h"
#include "Properties.h"
-#include "Stencil.h"
+#include "renderstate/Stencil.h"
#include <GLES2/gl2ext.h>
diff --git a/libs/hwui/Stencil.h b/libs/hwui/renderstate/Stencil.h
similarity index 100%
rename from libs/hwui/Stencil.h
rename to libs/hwui/renderstate/Stencil.h
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 4d5d8c8..6346479 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -22,9 +22,9 @@
#include "../Caches.h"
#include "../DeferredLayerUpdater.h"
#include "../renderstate/RenderState.h"
+#include "../renderstate/Stencil.h"
#include "../LayerRenderer.h"
#include "../OpenGLRenderer.h"
-#include "../Stencil.h"
#include <algorithm>
#include <private/hwui/DrawGlInfo.h>
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 0d6b91a..53ab264 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -214,6 +214,11 @@
* the underlying data could be mapped as a pointer in JNI without doing
* any copies with {@code GetDirectBufferAddress}.</p>
*
+ * <p>For raw formats, each plane is only guaranteed to contain data
+ * up to the last pixel in the last row. In other words, the stride
+ * after the last row may not be mapped into the buffer. This is a
+ * necessary requirement for any interleaved format.</p>
+ *
* @return the byte buffer containing the image data for this plane.
*/
public abstract ByteBuffer getBuffer();
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 8c478ed..f29be0d 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -310,7 +310,9 @@
public void run() {
try {
if (DEBUG) Log.d(TAG, "notifySessionEvent(" + eventType + ")");
- mSessionCallback.onSessionEvent(eventType, eventArgs);
+ if (mSessionCallback != null) {
+ mSessionCallback.onSessionEvent(eventType, eventArgs);
+ }
} catch (RemoteException e) {
Log.w(TAG, "error in sending event (event=" + eventType + ")");
}
@@ -329,7 +331,9 @@
public void run() {
try {
if (DEBUG) Log.d(TAG, "notifyChannelRetuned");
- mSessionCallback.onChannelRetuned(channelUri);
+ if (mSessionCallback != null) {
+ mSessionCallback.onChannelRetuned(channelUri);
+ }
} catch (RemoteException e) {
Log.w(TAG, "error in notifyChannelRetuned");
}
@@ -366,7 +370,9 @@
public void run() {
try {
if (DEBUG) Log.d(TAG, "notifyTracksChanged");
- mSessionCallback.onTracksChanged(tracks);
+ if (mSessionCallback != null) {
+ mSessionCallback.onTracksChanged(tracks);
+ }
} catch (RemoteException e) {
Log.w(TAG, "error in notifyTracksChanged");
}
@@ -394,7 +400,9 @@
public void run() {
try {
if (DEBUG) Log.d(TAG, "notifyTrackSelected");
- mSessionCallback.onTrackSelected(type, trackId);
+ if (mSessionCallback != null) {
+ mSessionCallback.onTrackSelected(type, trackId);
+ }
} catch (RemoteException e) {
Log.w(TAG, "error in notifyTrackSelected");
}
@@ -415,7 +423,9 @@
public void run() {
try {
if (DEBUG) Log.d(TAG, "notifyVideoAvailable");
- mSessionCallback.onVideoAvailable();
+ if (mSessionCallback != null) {
+ mSessionCallback.onVideoAvailable();
+ }
} catch (RemoteException e) {
Log.w(TAG, "error in notifyVideoAvailable");
}
@@ -447,7 +457,9 @@
public void run() {
try {
if (DEBUG) Log.d(TAG, "notifyVideoUnavailable");
- mSessionCallback.onVideoUnavailable(reason);
+ if (mSessionCallback != null) {
+ mSessionCallback.onVideoUnavailable(reason);
+ }
} catch (RemoteException e) {
Log.w(TAG, "error in notifyVideoUnavailable");
}
@@ -486,7 +498,9 @@
public void run() {
try {
if (DEBUG) Log.d(TAG, "notifyContentAllowed");
- mSessionCallback.onContentAllowed();
+ if (mSessionCallback != null) {
+ mSessionCallback.onContentAllowed();
+ }
} catch (RemoteException e) {
Log.w(TAG, "error in notifyContentAllowed");
}
@@ -526,7 +540,9 @@
public void run() {
try {
if (DEBUG) Log.d(TAG, "notifyContentBlocked");
- mSessionCallback.onContentBlocked(rating.flattenToString());
+ if (mSessionCallback != null) {
+ mSessionCallback.onContentBlocked(rating.flattenToString());
+ }
} catch (RemoteException e) {
Log.w(TAG, "error in notifyContentBlocked");
}
@@ -557,7 +573,9 @@
try {
if (DEBUG) Log.d(TAG, "layoutSurface (l=" + left + ", t=" + top + ", r="
+ right + ", b=" + bottom + ",)");
- mSessionCallback.onLayoutSurface(left, top, right, bottom);
+ if (mSessionCallback != null) {
+ mSessionCallback.onLayoutSurface(left, top, right, bottom);
+ }
} catch (RemoteException e) {
Log.w(TAG, "error in layoutSurface");
}
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 7e68c78..5406130 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -351,7 +351,7 @@
int bytesPerPixel = 0;
dataSize = ySize = cSize = cStride = 0;
- int32_t fmt = buffer->format;
+ int32_t fmt = buffer->flexFormat;
bool usingRGBAOverride = usingRGBAToJpegOverride(fmt, readerFormat);
fmt = applyFormatOverrides(fmt, readerFormat);
@@ -363,18 +363,21 @@
(idx == 1) ?
buffer->dataCb :
buffer->dataCr;
+ // only map until last pixel
if (idx == 0) {
- dataSize = buffer->stride * buffer->height;
+ dataSize = buffer->stride * (buffer->height - 1) + buffer->width;
} else {
- dataSize = buffer->chromaStride * buffer->height / 2;
+ dataSize = buffer->chromaStride * (buffer->height / 2 - 1) +
+ buffer->chromaStep * (buffer->width / 2 - 1) + 1;
}
break;
// NV21
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
cr = buffer->data + (buffer->stride * buffer->height);
cb = cr + 1;
- ySize = buffer->width * buffer->height;
- cSize = buffer->width * buffer->height / 2;
+ // only map until last pixel
+ ySize = buffer->width * (buffer->height - 1) + buffer->width;
+ cSize = buffer->width * (buffer->height / 2 - 1) + buffer->width - 1;
pData =
(idx == 0) ?
@@ -488,7 +491,7 @@
int pixelStride = 0;
ALOG_ASSERT(buffer != NULL, "buffer is NULL");
- int32_t fmt = buffer->format;
+ int32_t fmt = buffer->flexFormat;
fmt = applyFormatOverrides(fmt, readerFormat);
@@ -548,7 +551,7 @@
int rowStride = 0;
ALOG_ASSERT(buffer != NULL, "buffer is NULL");
- int32_t fmt = buffer->format;
+ int32_t fmt = buffer->flexFormat;
fmt = applyFormatOverrides(fmt, readerFormat);
@@ -796,7 +799,7 @@
return ACQUIRE_NO_BUFFERS;
}
- if (buffer->format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
+ if (buffer->flexFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
jniThrowException(env, "java/lang/UnsupportedOperationException",
"NV21 format is not supported by ImageReader");
return -1;
@@ -825,8 +828,10 @@
}
int bufFmt = buffer->format;
+ if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+ bufFmt = buffer->flexFormat;
+ }
if (imgReaderFmt != bufFmt) {
-
if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && (bufFmt ==
HAL_PIXEL_FORMAT_YCrCb_420_SP || bufFmt == HAL_PIXEL_FORMAT_YV12)) {
// Special casing for when producer switches to a format compatible with flexible YUV
@@ -848,7 +853,7 @@
String8 msg;
msg.appendFormat("The producer output buffer format 0x%x doesn't "
"match the ImageReader's configured buffer format 0x%x.",
- buffer->format, ctx->getBufferFormat());
+ bufFmt, ctx->getBufferFormat());
jniThrowException(env, "java/lang/UnsupportedOperationException",
msg.string());
return -1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index af92423..e8023bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -57,7 +57,6 @@
// Since some pieces of the phone state are interdependent we store it locally,
// this could potentially become part of MobileState for simplification/complication
// of code.
- private IccCardConstants.State mSimState = IccCardConstants.State.READY;
private int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
private int mDataState = TelephonyManager.DATA_DISCONNECTED;
private ServiceState mServiceState;
@@ -146,11 +145,6 @@
return getIcons().mDataContentDescription;
}
- @VisibleForTesting
- protected IccCardConstants.State getSimState() {
- return mSimState;
- }
-
public void setAirplaneMode(boolean airplaneMode) {
mCurrentState.airplaneMode = airplaneMode;
notifyListenersIfNecessary();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 9b95d5c..260dea0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -69,6 +69,8 @@
protected TelephonyManager mMockTm;
protected Config mConfig;
+ protected int mSubId;
+
private NetworkCapabilities mNetCapabilities;
@Override
@@ -100,13 +102,13 @@
protected void setupNetworkController() {
// For now just pretend to be the data sim, so we can test that too.
- final int subId = SubscriptionManager.getDefaultDataSubId();
+ mSubId = SubscriptionManager.getDefaultDataSubId();
SubscriptionInfo subscription = mock(SubscriptionInfo.class);
List<SubscriptionInfo> subs = new ArrayList<SubscriptionInfo>();
- when(subscription.getSubscriptionId()).thenReturn(subId);
+ when(subscription.getSubscriptionId()).thenReturn(mSubId);
subs.add(subscription);
mNetworkController.setCurrentSubscriptions(subs);
- mMobileSignalController = mNetworkController.mMobileSignalControllers.get(subId);
+ mMobileSignalController = mNetworkController.mMobileSignalControllers.get(mSubId);
mPhoneStateListener = mMobileSignalController.mPhoneStateListener;
mSignalCluster = mock(SignalCluster.class);
mNetworkSignalChangedCallback = mock(NetworkSignalChangedCallback.class);
@@ -291,10 +293,6 @@
assertEquals("Visibility in status bar", visible, (boolean) visibleArg.getValue());
}
- protected void assertSimStateEquals(IccCardConstants.State expected) {
- assertEquals("Sim state", expected, mMobileSignalController.getSimState());
- }
-
protected void assertNetworkNameEquals(String expected) {
assertEquals("Network name", expected, mNetworkController.getMobileNetworkName());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 65b0971..7fa3f68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -25,6 +25,7 @@
import android.telephony.TelephonyManager;
import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.systemui.R;
@@ -254,16 +255,6 @@
setCdmaRoaming(false);
}
- public void testOnReceive_updateSimState_noSim() {
- Intent intent = new Intent();
- intent.setAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
- intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, IccCardConstants.INTENT_VALUE_ICC_ABSENT);
-
- mNetworkController.onReceive(mContext, intent);
-
- assertSimStateEquals(IccCardConstants.State.ABSENT);
- }
-
public void testOnReceive_stringsUpdatedAction_spn() {
String expectedMNetworkName = "Test";
Intent intent = createStringsUpdatedIntent(true /* showSpn */,
@@ -344,6 +335,7 @@
intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn);
intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn);
+ intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, mSubId);
return intent;
}
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
index 59d5605..7f48768 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
@@ -62,11 +62,6 @@
void process(ActiveSource newActive, int deviceType) {
// Seq #17
HdmiCecLocalDeviceTv tv = mSource;
- ActiveSource activeSource = tv.getActiveSource();
- if (activeSource.equals(newActive)) {
- invokeCallback(HdmiControlManager.RESULT_SUCCESS);
- return;
- }
HdmiDeviceInfo device = mService.getDeviceInfo(newActive.logicalAddress);
if (device == null) {
tv.startNewDeviceAction(newActive, deviceType);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 43ef457..664f541 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -34,6 +34,7 @@
import android.content.Context;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.hdmi.HdmiRecordSources;
import android.hardware.hdmi.HdmiTimerRecordSources;
import android.hardware.hdmi.IHdmiControlCallback;
@@ -878,6 +879,17 @@
return oldStatus;
}
+ @ServiceThreadOnly
+ private void updateArcFeatureStatus(int portId, boolean isConnected) {
+ assertRunOnServiceThread();
+ // HEAC 2.4, HEACT 5-15
+ // Should not activate ARC if +5V status is false.
+ HdmiPortInfo portInfo = mService.getPortInfo(portId);
+ if (portInfo.isArcSupported()) {
+ changeArcFeatureEnabled(isConnected);
+ }
+ }
+
private void notifyArcStatusToAudioService(boolean enabled) {
// Note that we don't set any name to ARC.
mService.getAudioManager().setWiredDeviceConnectionState(
@@ -1456,6 +1468,25 @@
}
/**
+ * Returns the {@link HdmiDeviceInfo} instance whose physical address matches
+ * the given routing path. This is the version accessible safely from threads
+ * other than service thread.
+ *
+ * @param path routing path or physical address
+ * @return {@link HdmiDeviceInfo} if the matched info is found; otherwise null
+ */
+ HdmiDeviceInfo getSafeDeviceInfoByPath(int path) {
+ synchronized (mLock) {
+ for (HdmiDeviceInfo info : mSafeAllDeviceInfos) {
+ if (info.getPhysicalAddress() == path) {
+ return info;
+ }
+ }
+ return null;
+ }
+ }
+
+ /**
* Whether a device of the specified physical address and logical address exists
* in a device info list. However, both are minimal condition and it could
* be different device from the original one.
@@ -1490,6 +1521,7 @@
// It covers seq #40, #43.
hotplugActions.get(0).pollAllDevicesNow();
}
+ updateArcFeatureStatus(portId, connected);
}
private void removeCecSwitches(int portId) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 9f78c61..49a96d8 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1196,7 +1196,7 @@
}
int activePath = tv.getActivePath();
if (activePath != HdmiDeviceInfo.PATH_INVALID) {
- HdmiDeviceInfo info = tv.getDeviceInfoByPath(activePath);
+ HdmiDeviceInfo info = tv.getSafeDeviceInfoByPath(activePath);
return (info != null) ? info : new HdmiDeviceInfo(activePath, tv.getActivePortId());
}
return null;
diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
index 722be71..1bbd038 100644
--- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
+++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
@@ -38,6 +38,7 @@
private static final int POLLING_INTERVAL_MS = 5000;
private static final int TIMEOUT_COUNT = 3;
+ private static final int AVR_COUNT_MAX = 3;
// State in which waits for next polling
private static final int STATE_WAIT_FOR_NEXT_POLLING = 1;
@@ -48,6 +49,12 @@
private int mTimeoutCount = 0;
+ // Counter used to ensure the connection to AVR is stable. Occasional failure to get
+ // polling response from AVR despite its presence leads to unstable status flipping.
+ // This is a workaround to deal with it, by removing the device only if the removal
+ // is detected {@code AVR_COUNT_MAX} times in a row.
+ private int mAvrStatusCount = 0;
+
/**
* Constructor
*
@@ -148,10 +155,22 @@
BitSet removed = complement(currentInfos, polledResult);
int index = -1;
while ((index = removed.nextSetBit(index + 1)) != -1) {
+ if (index == Constants.ADDR_AUDIO_SYSTEM) {
+ ++mAvrStatusCount;
+ Slog.w(TAG, "Ack not returned from AVR. count: " + mAvrStatusCount);
+ if (mAvrStatusCount < AVR_COUNT_MAX) {
+ continue;
+ }
+ }
Slog.v(TAG, "Remove device by hot-plug detection:" + index);
removeDevice(index);
}
+ // Reset the counter if the ack is returned from AVR.
+ if (!removed.get(Constants.ADDR_AUDIO_SYSTEM)) {
+ mAvrStatusCount = 0;
+ }
+
// Next, check added devices.
BitSet added = complement(polledResult, currentInfos);
index = -1;
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 01a044e..b508c89 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -20,12 +20,15 @@
import android.alsa.AlsaDevicesParser;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbInterface;
import android.media.AudioSystem;
import android.media.IAudioService;
+import android.midi.MidiDeviceInfo;
import android.os.FileObserver;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -73,6 +76,9 @@
private UsbAudioDevice mSelectedAudioDevice = null;
+ // UsbMidiDevice for USB peripheral mode (gadget) device
+ private UsbMidiDevice mPeripheralMidiDevice = null;
+
private final class AlsaDevice {
public static final int TYPE_UNKNOWN = 0;
public static final int TYPE_PLAYBACK = 1;
@@ -391,7 +397,17 @@
int device = mDevicesParser.getDefaultDeviceNum(addedCard);
AlsaDevice alsaDevice = waitForAlsaDevice(addedCard, device, AlsaDevice.TYPE_MIDI);
if (alsaDevice != null) {
- UsbMidiDevice usbMidiDevice = UsbMidiDevice.create(mContext, usbDevice,
+ Bundle properties = new Bundle();
+ properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER,
+ usbDevice.getManufacturerName());
+ properties.putString(MidiDeviceInfo.PROPERTY_MODEL, usbDevice.getProductName());
+ properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER,
+ usbDevice.getSerialNumber());
+ properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, alsaDevice.mCard);
+ properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, alsaDevice.mDevice);
+ properties.putParcelable(MidiDeviceInfo.PROPERTY_USB_DEVICE, usbDevice);
+
+ UsbMidiDevice usbMidiDevice = UsbMidiDevice.create(mContext, properties,
alsaDevice.mCard, alsaDevice.mDevice);
if (usbMidiDevice != null) {
mMidiDevices.put(usbDevice, usbMidiDevice);
@@ -410,17 +426,16 @@
if (audioDevice != null) {
if (audioDevice.mHasPlayback || audioDevice.mHasPlayback) {
notifyDeviceState(audioDevice, false);
+ mSelectedAudioDevice = null;
+
+ // if there any external devices left, select one of them
+ selectDefaultDevice();
}
}
UsbMidiDevice usbMidiDevice = mMidiDevices.remove(usbDevice);
if (usbMidiDevice != null) {
IoUtils.closeQuietly(usbMidiDevice);
}
-
- mSelectedAudioDevice = null;
-
- // if there any external devices left, select one of them
- selectDefaultDevice();
}
/* package */ void setAccessoryAudioState(boolean enabled, int card, int device) {
@@ -437,6 +452,23 @@
}
}
+ /* package */ void setPeripheralMidiState(boolean enabled, int card, int device) {
+ if (enabled) {
+ Bundle properties = new Bundle();
+ Resources r = mContext.getResources();
+ properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, r.getString(
+ com.android.internal.R.string.usb_midi_peripheral_manufacturer_name));
+ properties.putString(MidiDeviceInfo.PROPERTY_MODEL, r.getString(
+ com.android.internal.R.string.usb_midi_peripheral_model_name));
+ properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, card);
+ properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, device);
+ mPeripheralMidiDevice = UsbMidiDevice.create(mContext, properties, card, device);
+ } else if (mPeripheralMidiDevice != null) {
+ IoUtils.closeQuietly(mPeripheralMidiDevice);
+ mPeripheralMidiDevice = null;
+ }
+ }
+
//
// Devices List
//
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 1426551..2fb6dbf 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -31,6 +31,7 @@
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.media.AudioManager;
+import android.midi.MidiDeviceInfo;
import android.os.FileUtils;
import android.os.Handler;
import android.os.Looper;
@@ -85,6 +86,8 @@
"/sys/class/android_usb/android0/f_rndis/ethaddr";
private static final String AUDIO_SOURCE_PCM_PATH =
"/sys/class/android_usb/android0/f_audio_source/pcm";
+ private static final String MIDI_ALSA_PATH =
+ "/sys/class/android_usb/android0/f_midi/alsa";
private static final int MSG_UPDATE_STATE = 0;
private static final int MSG_ENABLE_ADB = 1;
@@ -124,6 +127,7 @@
private boolean mUseUsbNotification;
private boolean mAdbEnabled;
private boolean mAudioSourceEnabled;
+ private boolean mMidiEnabled;
private Map<String, List<Pair<String, String>>> mOemModeMap;
private String[] mAccessoryStrings;
private UsbDebuggingManager mDebuggingManager;
@@ -618,6 +622,31 @@
}
}
+ private void updateMidiFunction() {
+ boolean enabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MIDI);
+ if (enabled != mMidiEnabled) {
+ int card = -1;
+ int device = -1;
+
+ if (enabled) {
+ Scanner scanner = null;
+ try {
+ scanner = new Scanner(new File(MIDI_ALSA_PATH));
+ card = scanner.nextInt();
+ device = scanner.nextInt();
+ } catch (FileNotFoundException e) {
+ Slog.e(TAG, "could not open MIDI PCM file", e);
+ } finally {
+ if (scanner != null) {
+ scanner.close();
+ }
+ }
+ }
+ mUsbAlsaManager.setPeripheralMidiState(enabled, card, device);
+ mMidiEnabled = enabled;
+ }
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -636,6 +665,7 @@
if (mBootCompleted) {
updateUsbState();
updateAudioSourceFunction();
+ updateMidiFunction();
}
break;
case MSG_ENABLE_ADB:
@@ -651,6 +681,7 @@
updateAdbNotification();
updateUsbState();
updateAudioSourceFunction();
+ updateMidiFunction();
break;
case MSG_BOOT_COMPLETED:
mBootCompleted = true;
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index 01b2df9..8d44905 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -17,13 +17,12 @@
package com.android.server.usb;
import android.content.Context;
-import android.hardware.usb.UsbDevice;
import android.midi.MidiDeviceInfo;
import android.midi.MidiDeviceServer;
import android.midi.MidiManager;
+import android.midi.MidiPort;
import android.midi.MidiReceiver;
import android.midi.MidiSender;
-import android.midi.MidiUtils;
import android.os.Bundle;
import android.system.ErrnoException;
import android.system.Os;
@@ -45,10 +44,12 @@
// for polling multiple FileDescriptors for MIDI events
private final StructPollfd[] mPollFDs;
+ // streams for reading from ALSA driver
private final FileInputStream[] mInputStreams;
+ // streams for writing to ALSA driver
private final FileOutputStream[] mOutputStreams;
- public static UsbMidiDevice create(Context context, UsbDevice usbDevice, int card, int device) {
+ public static UsbMidiDevice create(Context context, Bundle properties, int card, int device) {
MidiManager midiManager = (MidiManager)context.getSystemService(Context.MIDI_SERVICE);
if (midiManager == null) {
Log.e(TAG, "No MidiManager in UsbMidiDevice.create()");
@@ -69,13 +70,6 @@
return null;
}
- Bundle properties = new Bundle();
- properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, usbDevice.getManufacturerName());
- properties.putString(MidiDeviceInfo.PROPERTY_MODEL, usbDevice.getProductName());
- properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER, usbDevice.getSerialNumber());
- properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, card);
- properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, device);
- properties.putParcelable(MidiDeviceInfo.PROPERTY_USB_DEVICE, usbDevice);
MidiDeviceServer server = midiManager.createDeviceServer(subDevices, subDevices, properties,
false, MidiDeviceInfo.TYPE_USB);
if (server == null) {
@@ -131,7 +125,7 @@
new Thread() {
@Override
public void run() {
- byte[] buffer = new byte[3];
+ byte[] buffer = new byte[MidiPort.MAX_PACKET_DATA_SIZE];
try {
boolean done = false;
while (!done) {
@@ -141,7 +135,8 @@
if ((pfd.revents & OsConstants.POLLIN) != 0) {
// clear readable flag
pfd.revents = 0;
- int count = readMessage(buffer, index);
+
+ int count = mInputStreams[index].read(buffer);
mOutputPortReceivers[index].onPost(buffer, 0, count,
System.nanoTime());
} else if ((pfd.revents & (OsConstants.POLLERR
@@ -150,7 +145,7 @@
}
}
- // poll if none are readable
+ // wait until we have a readable port
Os.poll(mPollFDs, -1 /* infinite timeout */);
}
} catch (IOException e) {
@@ -174,26 +169,6 @@
}
}
- private int readMessage(byte[] buffer, int index) throws IOException {
- FileInputStream inputStream = mInputStreams[index];
-
- if (inputStream.read(buffer, 0, 1) != 1) {
- Log.e(TAG, "could not read command byte");
- return -1;
- }
- int dataSize = MidiUtils.getMessageDataSize(buffer[0]);
- if (dataSize < 0) {
- return -1;
- }
- if (dataSize > 0) {
- if (inputStream.read(buffer, 1, dataSize) != dataSize) {
- Log.e(TAG, "could not read command data");
- return -1;
- }
- }
- return dataSize + 1;
- }
-
private static native int nativeGetSubdeviceCount(int card, int device);
private static native FileDescriptor[] nativeOpen(int card, int device, int subdeviceCount);
}
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index adbe1d8..ca3c636 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -335,7 +335,7 @@
public String toString() {
return "{id=" + mId + ", iccId=" + mIccId + " simSlotIndex=" + mSimSlotIndex
+ " displayName=" + mDisplayName + " carrierName=" + mCarrierName
- + " nameSource=" + mNameSource + " iconTint=" + mIconTint + " number=" + mNumber
+ + " nameSource=" + mNameSource + " iconTint=" + mIconTint
+ " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc
+ " mnc " + mMnc + "}";
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a07d10c..339fc6d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -640,13 +640,9 @@
*/
/** {@hide} */
public String getDeviceId(int slotId) {
- // FIXME methods taking slot id should not use subscription, instead us Uicc directly
- int[] subId = SubscriptionManager.getSubId(slotId);
- if (subId == null || subId.length == 0) {
- return null;
- }
+ // FIXME this assumes phoneId == slotId
try {
- return getSubscriberInfo().getDeviceIdForSubscriber(subId[0]);
+ return getSubscriberInfo().getDeviceIdForPhone(slotId);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index eec5333..c91a59c 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -33,10 +33,10 @@
String getNaiForSubscriber(int subId);
/**
- * Retrieves the unique device ID of a subId for the device, e.g., IMEI
+ * Retrieves the unique device ID of a phone for the device, e.g., IMEI
* for GSM phones.
*/
- String getDeviceIdForSubscriber(int subId);
+ String getDeviceIdForPhone(int phoneId);
/**
* Retrieves the IMEI.
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 5202cc3..52f2372 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -733,6 +733,31 @@
/**
* @hide
+ * Last time the system tried to roam and failed because of authentication failure or DHCP
+ * RENEW failure.
+ */
+ public long lastRoamingFailure;
+
+ /** @hide */
+ public static int ROAMING_FAILURE_IP_CONFIG = 1;
+ /** @hide */
+ public static int ROAMING_FAILURE_AUTH_FAILURE = 2;
+
+ /**
+ * @hide
+ * Initial amount of time this Wifi configuration gets blacklisted for network switching
+ * because of roaming failure
+ */
+ public long roamingFailureBlackListTimeMilli = 1000;
+
+ /**
+ * @hide
+ * Last roaming failure reason code
+ */
+ public int lastRoamingFailureReason;
+
+ /**
+ * @hide
* Last time the system was disconnected to this configuration.
*/
public long lastDisconnected;
@@ -1209,6 +1234,18 @@
sbuf.append( "sec");
}
}
+ if (this.lastRoamingFailure != 0) {
+ sbuf.append('\n');
+ long diff = now_ms - this.lastRoamingFailure;
+ if (diff <= 0) {
+ sbuf.append("lastRoamingFailure since <incorrect>");
+ } else {
+ sbuf.append("lastRoamingFailure: ").append(Long.toString(diff/1000));
+ sbuf.append( "sec");
+ }
+ }
+ sbuf.append("roamingFailureBlackListTimeMilli: ").
+ append(Long.toString(this.roamingFailureBlackListTimeMilli));
sbuf.append('\n');
if (this.linkedConfigurations != null) {
for(String key : this.linkedConfigurations.keySet()) {
@@ -1595,6 +1632,9 @@
lastConnected = source.lastConnected;
lastDisconnected = source.lastDisconnected;
lastConnectionFailure = source.lastConnectionFailure;
+ lastRoamingFailure = source.lastRoamingFailure;
+ lastRoamingFailureReason = source.lastRoamingFailureReason;
+ roamingFailureBlackListTimeMilli = source.roamingFailureBlackListTimeMilli;
numConnectionFailures = source.numConnectionFailures;
numIpConfigFailures = source.numIpConfigFailures;
numAuthFailures = source.numAuthFailures;
@@ -1667,6 +1707,9 @@
dest.writeString(lastUpdateName);
dest.writeLong(blackListTimestamp);
dest.writeLong(lastConnectionFailure);
+ dest.writeLong(lastRoamingFailure);
+ dest.writeInt(lastRoamingFailureReason);
+ dest.writeLong(roamingFailureBlackListTimeMilli);
dest.writeInt(numConnectionFailures);
dest.writeInt(numIpConfigFailures);
dest.writeInt(numAuthFailures);
@@ -1732,6 +1775,9 @@
config.lastUpdateName = in.readString();
config.blackListTimestamp = in.readLong();
config.lastConnectionFailure = in.readLong();
+ config.lastRoamingFailure = in.readLong();
+ config.lastRoamingFailureReason = in.readInt();
+ config.roamingFailureBlackListTimeMilli = in.readLong();
config.numConnectionFailures = in.readInt();
config.numIpConfigFailures = in.readInt();
config.numAuthFailures = in.readInt();