diff options
74 files changed, 3048 insertions, 1471 deletions
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index 087753b21987..82186dd36d40 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -931,7 +931,7 @@ public class Dialog implements DialogInterface, Window.Callback, // associate search with owner activity final ComponentName appName = getAssociatedActivity(); - if (appName != null) { + if (appName != null && searchManager.getSearchableInfo(appName) != null) { searchManager.startSearch(null, false, appName, null, false); dismiss(); return true; diff --git a/core/java/android/net/DhcpInfoInternal.java b/core/java/android/net/DhcpInfoInternal.java index 73966692d03f..860da0a335a9 100644 --- a/core/java/android/net/DhcpInfoInternal.java +++ b/core/java/android/net/DhcpInfoInternal.java @@ -22,6 +22,8 @@ import android.util.Log; import java.net.InetAddress; import java.net.Inet4Address; import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collection; /** * A simple object for retrieving the results of a DHCP request. @@ -31,7 +33,6 @@ import java.net.UnknownHostException; public class DhcpInfoInternal { private final static String TAG = "DhcpInfoInternal"; public String ipAddress; - public String gateway; public int prefixLength; public String dns1; @@ -40,7 +41,14 @@ public class DhcpInfoInternal { public String serverAddress; public int leaseDuration; + private Collection<RouteInfo> routes; + public DhcpInfoInternal() { + routes = new ArrayList<RouteInfo>(); + } + + public void addRoute(RouteInfo routeInfo) { + routes.add(routeInfo); } private int convertToInt(String addr) { @@ -58,7 +66,12 @@ public class DhcpInfoInternal { public DhcpInfo makeDhcpInfo() { DhcpInfo info = new DhcpInfo(); info.ipAddress = convertToInt(ipAddress); - info.gateway = convertToInt(gateway); + for (RouteInfo route : routes) { + if (route.isDefaultRoute()) { + info.gateway = convertToInt(route.getGateway().getHostAddress()); + break; + } + } try { InetAddress inetAddress = NetworkUtils.numericToInetAddress(ipAddress); info.netmask = NetworkUtils.prefixLengthToNetmaskInt(prefixLength); @@ -81,8 +94,8 @@ public class DhcpInfoInternal { public LinkProperties makeLinkProperties() { LinkProperties p = new LinkProperties(); p.addLinkAddress(makeLinkAddress()); - if (TextUtils.isEmpty(gateway) == false) { - p.addGateway(NetworkUtils.numericToInetAddress(gateway)); + for (RouteInfo route : routes) { + p.addRoute(route); } if (TextUtils.isEmpty(dns1) == false) { p.addDns(NetworkUtils.numericToInetAddress(dns1)); @@ -98,8 +111,10 @@ public class DhcpInfoInternal { } public String toString() { + String routeString = ""; + for (RouteInfo route : routes) routeString += route.toString() + " | "; return "addr: " + ipAddress + "/" + prefixLength + - " gateway: " + gateway + + " routes: " + routeString + " dns: " + dns1 + "," + dns2 + " dhcpServer: " + serverAddress + " leaseDuration: " + leaseDuration; diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java new file mode 100644 index 000000000000..eaf087f43ab8 --- /dev/null +++ b/core/java/android/net/DhcpStateMachine.java @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import com.android.internal.util.Protocol; +import com.android.internal.util.State; +import com.android.internal.util.StateMachine; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.DhcpInfoInternal; +import android.net.NetworkUtils; +import android.os.Message; +import android.os.PowerManager; +import android.os.SystemClock; +import android.util.Log; + +/** + * StateMachine that interacts with the native DHCP client and can talk to + * a controller that also needs to be a StateMachine + * + * The Dhcp state machine provides the following features: + * - Wakeup and renewal using the native DHCP client (which will not renew + * on its own when the device is in suspend state and this can lead to device + * holding IP address beyond expiry) + * - A notification right before DHCP request or renewal is started. This + * can be used for any additional setup before DHCP. For example, wifi sets + * BT-Wifi coex settings right before DHCP is initiated + * + * @hide + */ +public class DhcpStateMachine extends StateMachine { + + private static final String TAG = "DhcpStateMachine"; + private static final boolean DBG = false; + + + /* A StateMachine that controls the DhcpStateMachine */ + private StateMachine mController; + + private Context mContext; + private BroadcastReceiver mBroadcastReceiver; + private AlarmManager mAlarmManager; + private PendingIntent mDhcpRenewalIntent; + private PowerManager.WakeLock mDhcpRenewWakeLock; + private static final String WAKELOCK_TAG = "DHCP"; + + private static final int DHCP_RENEW = 0; + private static final String ACTION_DHCP_RENEW = "android.net.wifi.DHCP_RENEW"; + + private enum DhcpAction { + START, + RENEW + }; + + private String mInterfaceName; + private boolean mRegisteredForPreDhcpNotification = false; + + private static final int BASE = Protocol.BASE_DHCP; + + /* Commands from controller to start/stop DHCP */ + public static final int CMD_START_DHCP = BASE + 1; + public static final int CMD_STOP_DHCP = BASE + 2; + public static final int CMD_RENEW_DHCP = BASE + 3; + + /* Notification from DHCP state machine prior to DHCP discovery/renewal */ + public static final int CMD_PRE_DHCP_ACTION = BASE + 4; + /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates + * success/failure */ + public static final int CMD_POST_DHCP_ACTION = BASE + 5; + + /* Command from controller to indicate DHCP discovery/renewal can continue + * after pre DHCP action is complete */ + public static final int CMD_PRE_DHCP_ACTION_COMPLETE = BASE + 6; + + /* Message.arg1 arguments to CMD_POST_DHCP notification */ + public static final int DHCP_SUCCESS = 1; + public static final int DHCP_FAILURE = 2; + + private State mDefaultState = new DefaultState(); + private State mStoppedState = new StoppedState(); + private State mWaitBeforeStartState = new WaitBeforeStartState(); + private State mRunningState = new RunningState(); + private State mWaitBeforeRenewalState = new WaitBeforeRenewalState(); + + private DhcpStateMachine(Context context, StateMachine controller, String intf) { + super(TAG); + + mContext = context; + mController = controller; + mInterfaceName = intf; + + mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); + Intent dhcpRenewalIntent = new Intent(ACTION_DHCP_RENEW, null); + mDhcpRenewalIntent = PendingIntent.getBroadcast(mContext, DHCP_RENEW, dhcpRenewalIntent, 0); + + PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); + mDhcpRenewWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); + + mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + //DHCP renew + if (DBG) Log.d(TAG, "Sending a DHCP renewal " + this); + //acquire a 40s wakelock to finish DHCP renewal + mDhcpRenewWakeLock.acquire(40000); + sendMessage(CMD_RENEW_DHCP); + } + }; + mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_DHCP_RENEW)); + + addState(mDefaultState); + addState(mStoppedState, mDefaultState); + addState(mWaitBeforeStartState, mDefaultState); + addState(mRunningState, mDefaultState); + addState(mWaitBeforeRenewalState, mDefaultState); + + setInitialState(mStoppedState); + } + + public static DhcpStateMachine makeDhcpStateMachine(Context context, StateMachine controller, + String intf) { + DhcpStateMachine dsm = new DhcpStateMachine(context, controller, intf); + dsm.start(); + return dsm; + } + + /** + * This sends a notification right before DHCP request/renewal so that the + * controller can do certain actions before DHCP packets are sent out. + * When the controller is ready, it sends a CMD_PRE_DHCP_ACTION_COMPLETE message + * to indicate DHCP can continue + * + * This is used by Wifi at this time for the purpose of doing BT-Wifi coex + * handling during Dhcp + */ + public void registerForPreDhcpNotification() { + mRegisteredForPreDhcpNotification = true; + } + + class DefaultState extends State { + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch (message.what) { + case CMD_RENEW_DHCP: + Log.e(TAG, "Error! Failed to handle a DHCP renewal on " + mInterfaceName); + break; + case SM_QUIT_CMD: + mContext.unregisterReceiver(mBroadcastReceiver); + //let parent kill the state machine + return NOT_HANDLED; + default: + Log.e(TAG, "Error! unhandled message " + message); + break; + } + return HANDLED; + } + } + + + class StoppedState extends State { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + } + + @Override + public boolean processMessage(Message message) { + boolean retValue = HANDLED; + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch (message.what) { + case CMD_START_DHCP: + if (mRegisteredForPreDhcpNotification) { + /* Notify controller before starting DHCP */ + mController.sendMessage(CMD_PRE_DHCP_ACTION); + transitionTo(mWaitBeforeStartState); + } else { + if (runDhcp(DhcpAction.START)) { + transitionTo(mRunningState); + } + } + break; + case CMD_STOP_DHCP: + //ignore + break; + default: + retValue = NOT_HANDLED; + break; + } + return retValue; + } + } + + class WaitBeforeStartState extends State { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + } + + @Override + public boolean processMessage(Message message) { + boolean retValue = HANDLED; + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch (message.what) { + case CMD_PRE_DHCP_ACTION_COMPLETE: + if (runDhcp(DhcpAction.START)) { + transitionTo(mRunningState); + } else { + transitionTo(mStoppedState); + } + break; + case CMD_STOP_DHCP: + transitionTo(mStoppedState); + break; + case CMD_START_DHCP: + //ignore + break; + default: + retValue = NOT_HANDLED; + break; + } + return retValue; + } + } + + class RunningState extends State { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + } + + @Override + public boolean processMessage(Message message) { + boolean retValue = HANDLED; + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch (message.what) { + case CMD_STOP_DHCP: + mAlarmManager.cancel(mDhcpRenewalIntent); + if (!NetworkUtils.stopDhcp(mInterfaceName)) { + Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName); + } + transitionTo(mStoppedState); + break; + case CMD_RENEW_DHCP: + if (mRegisteredForPreDhcpNotification) { + /* Notify controller before starting DHCP */ + mController.sendMessage(CMD_PRE_DHCP_ACTION); + transitionTo(mWaitBeforeRenewalState); + } else { + if (!runDhcp(DhcpAction.RENEW)) { + transitionTo(mStoppedState); + } + } + break; + case CMD_START_DHCP: + //ignore + break; + default: + retValue = NOT_HANDLED; + } + return retValue; + } + } + + class WaitBeforeRenewalState extends State { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + } + + @Override + public boolean processMessage(Message message) { + boolean retValue = HANDLED; + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch (message.what) { + case CMD_STOP_DHCP: + mAlarmManager.cancel(mDhcpRenewalIntent); + if (!NetworkUtils.stopDhcp(mInterfaceName)) { + Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName); + } + transitionTo(mStoppedState); + break; + case CMD_PRE_DHCP_ACTION_COMPLETE: + if (runDhcp(DhcpAction.RENEW)) { + transitionTo(mRunningState); + } else { + transitionTo(mStoppedState); + } + break; + case CMD_START_DHCP: + //ignore + break; + default: + retValue = NOT_HANDLED; + break; + } + return retValue; + } + } + + private boolean runDhcp(DhcpAction dhcpAction) { + boolean success = false; + DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal(); + + if (dhcpAction == DhcpAction.START) { + Log.d(TAG, "DHCP request on " + mInterfaceName); + success = NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal); + } else if (dhcpAction == DhcpAction.RENEW) { + Log.d(TAG, "DHCP renewal on " + mInterfaceName); + success = NetworkUtils.runDhcpRenew(mInterfaceName, dhcpInfoInternal); + } + + if (success) { + Log.d(TAG, "DHCP succeeded on " + mInterfaceName); + //Do it a bit earlier than half the lease duration time + //to beat the native DHCP client and avoid extra packets + //48% for one hour lease time = 29 minutes + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + + dhcpInfoInternal.leaseDuration * 480, //in milliseconds + mDhcpRenewalIntent); + + mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpInfoInternal) + .sendToTarget(); + } else { + Log.d(TAG, "DHCP failed on " + mInterfaceName + ": " + + NetworkUtils.getDhcpError()); + NetworkUtils.stopDhcp(mInterfaceName); + mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0) + .sendToTarget(); + } + return success; + } +} diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index e88292f50744..61acf2b841dd 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -54,7 +54,7 @@ public class LinkProperties implements Parcelable { String mIfaceName; private Collection<LinkAddress> mLinkAddresses; private Collection<InetAddress> mDnses; - private Collection<InetAddress> mGateways; + private Collection<RouteInfo> mRoutes; private ProxyProperties mHttpProxy; public LinkProperties() { @@ -67,7 +67,7 @@ public class LinkProperties implements Parcelable { mIfaceName = source.getInterfaceName(); mLinkAddresses = source.getLinkAddresses(); mDnses = source.getDnses(); - mGateways = source.getGateways(); + mRoutes = source.getRoutes(); mHttpProxy = new ProxyProperties(source.getHttpProxy()); } } @@ -104,11 +104,11 @@ public class LinkProperties implements Parcelable { return Collections.unmodifiableCollection(mDnses); } - public void addGateway(InetAddress gateway) { - if (gateway != null) mGateways.add(gateway); + public void addRoute(RouteInfo route) { + if (route != null) mRoutes.add(route); } - public Collection<InetAddress> getGateways() { - return Collections.unmodifiableCollection(mGateways); + public Collection<RouteInfo> getRoutes() { + return Collections.unmodifiableCollection(mRoutes); } public void setHttpProxy(ProxyProperties proxy) { @@ -122,7 +122,7 @@ public class LinkProperties implements Parcelable { mIfaceName = null; mLinkAddresses = new ArrayList<LinkAddress>(); mDnses = new ArrayList<InetAddress>(); - mGateways = new ArrayList<InetAddress>(); + mRoutes = new ArrayList<RouteInfo>(); mHttpProxy = null; } @@ -146,12 +146,12 @@ public class LinkProperties implements Parcelable { for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ","; dns += "] "; - String gateways = "Gateways: ["; - for (InetAddress gw : mGateways) gateways += gw.getHostAddress() + ","; - gateways += "] "; + String routes = "Routes: ["; + for (RouteInfo route : mRoutes) routes += route.toString() + ","; + routes += "] "; String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " "); - return ifaceName + linkAddresses + gateways + dns + proxy; + return ifaceName + linkAddresses + routes + dns + proxy; } @@ -177,7 +177,7 @@ public class LinkProperties implements Parcelable { boolean sameAddresses; boolean sameDnses; - boolean sameGateways; + boolean sameRoutes; LinkProperties target = (LinkProperties) obj; @@ -190,12 +190,12 @@ public class LinkProperties implements Parcelable { sameDnses = (mDnses.size() == targetDnses.size()) ? mDnses.containsAll(targetDnses) : false; - Collection<InetAddress> targetGateways = target.getGateways(); - sameGateways = (mGateways.size() == targetGateways.size()) ? - mGateways.containsAll(targetGateways) : false; + Collection<RouteInfo> targetRoutes = target.getRoutes(); + sameRoutes = (mRoutes.size() == targetRoutes.size()) ? + mRoutes.containsAll(targetRoutes) : false; return - sameAddresses && sameDnses && sameGateways + sameAddresses && sameDnses && sameRoutes && TextUtils.equals(getInterfaceName(), target.getInterfaceName()) && (getHttpProxy() == null ? target.getHttpProxy() == null : getHttpProxy().equals(target.getHttpProxy())); @@ -211,7 +211,7 @@ public class LinkProperties implements Parcelable { return ((null == mIfaceName) ? 0 : mIfaceName.hashCode() + mLinkAddresses.size() * 31 + mDnses.size() * 37 - + mGateways.size() * 41 + + mRoutes.size() * 41 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())); } @@ -231,9 +231,9 @@ public class LinkProperties implements Parcelable { dest.writeByteArray(d.getAddress()); } - dest.writeInt(mGateways.size()); - for(InetAddress gw : mGateways) { - dest.writeByteArray(gw.getAddress()); + dest.writeInt(mRoutes.size()); + for(RouteInfo route : mRoutes) { + dest.writeParcelable(route, flags); } if (mHttpProxy != null) { @@ -272,9 +272,7 @@ public class LinkProperties implements Parcelable { } addressCount = in.readInt(); for (int i=0; i<addressCount; i++) { - try { - netProp.addGateway(InetAddress.getByAddress(in.createByteArray())); - } catch (UnknownHostException e) { } + netProp.addRoute((RouteInfo)in.readParcelable(null)); } if (in.readByte() == 1) { netProp.setHttpProxy((ProxyProperties)in.readParcelable(null)); diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index b3f39885f943..823d10fa6ba6 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -80,6 +80,16 @@ public class NetworkUtils { public native static boolean runDhcp(String interfaceName, DhcpInfoInternal ipInfo); /** + * Initiate renewal on the Dhcp client daemon. This call blocks until it obtains + * a result (either success or failure) from the daemon. + * @param interfaceName the name of the interface to configure + * @param ipInfo if the request succeeds, this object is filled in with + * the IP address information. + * @return {@code true} for success, {@code false} for failure + */ + public native static boolean runDhcpRenew(String interfaceName, DhcpInfoInternal ipInfo); + + /** * Shut down the DHCP client daemon. * @param interfaceName the name of the interface for which the daemon * should be stopped diff --git a/core/java/android/net/RouteInfo.aidl b/core/java/android/net/RouteInfo.aidl new file mode 100644 index 000000000000..2296a576873d --- /dev/null +++ b/core/java/android/net/RouteInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +parcelable RouteInfo; diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java new file mode 100644 index 000000000000..5b1053140f06 --- /dev/null +++ b/core/java/android/net/RouteInfo.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.net.UnknownHostException; +import java.net.InetAddress; +import java.net.Inet4Address; +import java.net.Inet6Address; +/** + * A simple container for route information. + * + * @hide + */ +public class RouteInfo implements Parcelable { + /** + * The IP destination address for this route. + */ + private final LinkAddress mDestination; + + /** + * The gateway address for this route. + */ + private final InetAddress mGateway; + + private final boolean mIsDefault; + + public RouteInfo(LinkAddress destination, InetAddress gateway) { + if (destination == null) { + try { + if ((gateway != null) && (gateway instanceof Inet4Address)) { + destination = new LinkAddress(InetAddress.getByName("0.0.0.0"), 32); + } else { + destination = new LinkAddress(InetAddress.getByName("::0"), 128); + } + } catch (Exception e) {} + } + mDestination = destination; + mGateway = gateway; + mIsDefault = isDefault(); + } + + public RouteInfo(InetAddress gateway) { + LinkAddress destination = null; + try { + if ((gateway != null) && (gateway instanceof Inet4Address)) { + destination = new LinkAddress(InetAddress.getByName("0.0.0.0"), 32); + } else { + destination = new LinkAddress(InetAddress.getByName("::0"), 128); + } + } catch (Exception e) {} + mDestination = destination; + mGateway = gateway; + mIsDefault = isDefault(); + } + + private boolean isDefault() { + boolean val = false; + if (mGateway != null) { + if (mGateway instanceof Inet4Address) { + val = (mDestination == null || mDestination.getNetworkPrefixLength() == 32); + } else { + val = (mDestination == null || mDestination.getNetworkPrefixLength() == 128); + } + } + return val; + } + + public LinkAddress getDestination() { + return mDestination; + } + + public InetAddress getGateway() { + return mGateway; + } + + public boolean isDefaultRoute() { + return mIsDefault; + } + + public String toString() { + String val = ""; + if (mDestination != null) val = mDestination.toString(); + if (mGateway != null) val += " -> " + mGateway.getHostAddress(); + return val; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + if (mDestination == null) { + dest.writeByte((byte) 0); + } else { + dest.writeByte((byte) 1); + dest.writeByteArray(mDestination.getAddress().getAddress()); + dest.writeInt(mDestination.getNetworkPrefixLength()); + } + + if (mGateway == null) { + dest.writeByte((byte) 0); + } else { + dest.writeByte((byte) 1); + dest.writeByteArray(mGateway.getAddress()); + } + } + + public static final Creator<RouteInfo> CREATOR = + new Creator<RouteInfo>() { + public RouteInfo createFromParcel(Parcel in) { + InetAddress destAddr = null; + int prefix = 0; + InetAddress gateway = null; + + if (in.readByte() == 1) { + byte[] addr = in.createByteArray(); + prefix = in.readInt(); + + try { + destAddr = InetAddress.getByAddress(addr); + } catch (UnknownHostException e) {} + } + + if (in.readByte() == 1) { + byte[] addr = in.createByteArray(); + + try { + gateway = InetAddress.getByAddress(addr); + } catch (UnknownHostException e) {} + } + + LinkAddress dest = null; + + if (destAddr != null) { + dest = new LinkAddress(destAddr, prefix); + } + + return new RouteInfo(dest, gateway); + } + + public RouteInfo[] newArray(int size) { + return new RouteInfo[size]; + } + }; +} diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index ac5db625790c..674105938ea0 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -629,10 +629,16 @@ public class TextUtils { public CharSequence createFromParcel(Parcel p) { int kind = p.readInt(); - if (kind == 1) - return p.readString(); + String string = p.readString(); + if (string == null) { + return null; + } + + if (kind == 1) { + return string; + } - SpannableString sp = new SpannableString(p.readString()); + SpannableString sp = new SpannableString(string); while (true) { kind = p.readInt(); diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 5b2983d548a1..9a9b7b75583d 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -289,9 +289,10 @@ public abstract class HardwareRenderer { @SuppressWarnings({"deprecation"}) static abstract class GlRenderer extends HardwareRenderer { // These values are not exposed in our EGL APIs - private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; - private static final int EGL_SURFACE_TYPE = 0x3033; - private static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400; + static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; + static final int EGL_SURFACE_TYPE = 0x3033; + static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400; + static final int EGL_OPENGL_ES2_BIT = 4; private static final int SURFACE_STATE_ERROR = 0; private static final int SURFACE_STATE_SUCCESS = 1; @@ -459,13 +460,12 @@ public abstract class HardwareRenderer { getEGLErrorString(sEgl.eglGetError())); } - sEglConfig = getConfigChooser(mGlVersion).chooseConfig(sEgl, sEglDisplay); + sEglConfig = chooseEglConfig(); if (sEglConfig == null) { // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without if (mDirtyRegions) { mDirtyRegions = false; - - sEglConfig = getConfigChooser(mGlVersion).chooseConfig(sEgl, sEglDisplay); + sEglConfig = chooseEglConfig(); if (sEglConfig == null) { throw new RuntimeException("eglConfig not initialized"); } @@ -481,6 +481,21 @@ public abstract class HardwareRenderer { sEglContext = createContext(sEgl, sEglDisplay, sEglConfig); } + private EGLConfig chooseEglConfig() { + int[] configsCount = new int[1]; + EGLConfig[] configs = new EGLConfig[1]; + int[] configSpec = getConfig(mDirtyRegions); + if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) { + throw new IllegalArgumentException("eglChooseConfig failed " + + getEGLErrorString(sEgl.eglGetError())); + } else if (configsCount[0] > 0) { + return configs[0]; + } + return null; + } + + abstract int[] getConfig(boolean dirtyRegions); + GL createEglSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException { // Check preconditions. if (sEgl == null) { @@ -592,15 +607,6 @@ public abstract class HardwareRenderer { void onPostDraw() { } - - /** - * Defines the EGL configuration for this renderer. - * - * @return An {@link android.view.HardwareRenderer.GlRenderer.EglConfigChooser}. - */ - EglConfigChooser getConfigChooser(int glVersion) { - return new ComponentSizeChooser(glVersion, 8, 8, 8, 8, 0, 0, mDirtyRegions); - } @Override void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks, @@ -713,134 +719,6 @@ public abstract class HardwareRenderer { } return SURFACE_STATE_SUCCESS; } - - static abstract class EglConfigChooser { - final int[] mConfigSpec; - private final int mGlVersion; - - EglConfigChooser(int glVersion, int[] configSpec) { - mGlVersion = glVersion; - mConfigSpec = filterConfigSpec(configSpec); - } - - EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { - int[] index = new int[1]; - if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, index)) { - throw new IllegalArgumentException("eglChooseConfig failed " - + getEGLErrorString(egl.eglGetError())); - } - - int numConfigs = index[0]; - if (numConfigs <= 0) { - throw new IllegalArgumentException("No configs match configSpec"); - } - - EGLConfig[] configs = new EGLConfig[numConfigs]; - if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, index)) { - throw new IllegalArgumentException("eglChooseConfig failed " - + getEGLErrorString(egl.eglGetError())); - } - - EGLConfig config = chooseConfig(egl, display, configs); - if (config == null) { - throw new IllegalArgumentException("No config chosen"); - } - - return config; - } - - abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs); - - private int[] filterConfigSpec(int[] configSpec) { - if (mGlVersion != 2) { - return configSpec; - } - /* We know none of the subclasses define EGL_RENDERABLE_TYPE. - * And we know the configSpec is well formed. - */ - int len = configSpec.length; - int[] newConfigSpec = new int[len + 2]; - System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1); - newConfigSpec[len - 1] = EGL10.EGL_RENDERABLE_TYPE; - newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */ - newConfigSpec[len + 1] = EGL10.EGL_NONE; - return newConfigSpec; - } - } - - /** - * Choose a configuration with exactly the specified r,g,b,a sizes, - * and at least the specified depth and stencil sizes. - */ - static class ComponentSizeChooser extends EglConfigChooser { - private int[] mValue; - - private final int mRedSize; - private final int mGreenSize; - private final int mBlueSize; - private final int mAlphaSize; - private final int mDepthSize; - private final int mStencilSize; - private final boolean mDirtyRegions; - - ComponentSizeChooser(int glVersion, int redSize, int greenSize, int blueSize, - int alphaSize, int depthSize, int stencilSize, boolean dirtyRegions) { - super(glVersion, new int[] { - EGL10.EGL_RED_SIZE, redSize, - EGL10.EGL_GREEN_SIZE, greenSize, - EGL10.EGL_BLUE_SIZE, blueSize, - EGL10.EGL_ALPHA_SIZE, alphaSize, - EGL10.EGL_DEPTH_SIZE, depthSize, - EGL10.EGL_STENCIL_SIZE, stencilSize, - EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT | - (dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0), - EGL10.EGL_NONE }); - mValue = new int[1]; - mRedSize = redSize; - mGreenSize = greenSize; - mBlueSize = blueSize; - mAlphaSize = alphaSize; - mDepthSize = depthSize; - mStencilSize = stencilSize; - mDirtyRegions = dirtyRegions; - } - - @Override - EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) { - for (EGLConfig config : configs) { - int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0); - int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0); - if (d >= mDepthSize && s >= mStencilSize) { - int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0); - int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0); - int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0); - int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0); - boolean backBuffer; - if (mDirtyRegions) { - int surfaceType = findConfigAttrib(egl, display, config, - EGL_SURFACE_TYPE, 0); - backBuffer = (surfaceType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) != 0; - } else { - backBuffer = true; - } - if (r >= mRedSize && g >= mGreenSize && b >= mBlueSize && a >= mAlphaSize - && backBuffer) { - return config; - } - } - } - return null; - } - - private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config, - int attribute, int defaultValue) { - if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { - return mValue[0]; - } - - return defaultValue; - } - } } /** @@ -857,7 +735,23 @@ public abstract class HardwareRenderer { GLES20Canvas createCanvas() { return mGlCanvas = new GLES20Canvas(mTranslucent); } - + + @Override + int[] getConfig(boolean dirtyRegions) { + return new int[] { + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 8, + EGL10.EGL_DEPTH_SIZE, 0, + EGL10.EGL_STENCIL_SIZE, 0, + EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT | + (dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0), + EGL10.EGL_NONE + }; + } + @Override boolean canDraw() { return super.canDraw() && mGlCanvas != null; diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index 4b4f5f2dbfd7..ade3a0aa94b8 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -873,7 +873,7 @@ public class ScrollView extends FrameLayout { int count = getChildCount(); if (count > 0) { View view = getChildAt(count - 1); - mTempRect.bottom = view.getBottom(); + mTempRect.bottom = view.getBottom() + mPaddingBottom; mTempRect.top = mTempRect.bottom - height; } } @@ -949,9 +949,7 @@ public class ScrollView extends FrameLayout { } else if (direction == View.FOCUS_DOWN) { if (getChildCount() > 0) { int daBottom = getChildAt(0).getBottom(); - - int screenBottom = getScrollY() + getHeight(); - + int screenBottom = getScrollY() + getHeight() - mPaddingBottom; if (daBottom - screenBottom < maxJump) { scrollDelta = daBottom - screenBottom; } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 7cf33fcee754..12687a130e3f 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -4904,7 +4904,7 @@ public final class BatteryStatsImpl extends BatteryStats { void readOldHistory(Parcel in) { mHistory = mHistoryEnd = mHistoryCache = null; long time; - while ((time=in.readLong()) >= 0) { + while (in.dataAvail() > 0 && (time=in.readLong()) >= 0) { HistoryItem rec = new HistoryItem(time, in); addHistoryRecordLocked(rec); } diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java index 4d656c0c4569..39733440f0b6 100644 --- a/core/java/com/android/internal/util/AsyncChannel.java +++ b/core/java/com/android/internal/util/AsyncChannel.java @@ -44,16 +44,16 @@ import java.util.Stack; * In this usage model there is no need for the destination to * use the connect methods. The typical sequence of operations is:</p> *<ol> - * <li>Client calls AsyncChannel#connect</li> - * <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li> + * <li>Client calls AsyncChannel#connectSync or Asynchronously:</li> + * <ol>For an asynchronous half connection client calls AsyncChannel#connect.</ol> + * <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li> + * </ol> * <li><code>comm-loop:</code></li> - * <li>Client calls AsyncChannel#sendMessage(msgX)</li> - * <li>Server receives and processes msgX</li> - * <li>Server optionally calls AsyncChannel#replyToMessage(msgY) - * and if sent Client receives and processes msgY</li> + * <li>Client calls AsyncChannel#sendMessage</li> + * <li>Server processes messages and optionally replies using AsyncChannel#replyToMessage * <li>Loop to <code>comm-loop</code> until done</li> - * <li>When done Client calls {@link AsyncChannel#disconnect(int)}</li> - * <li>Client receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li> + * <li>When done Client calls {@link AsyncChannel#disconnect}</li> + * <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li> *</ol> *<br/> * <p>A second usage model is where the server/destination needs to know @@ -62,21 +62,26 @@ import java.util.Stack; * different state for each client. In this model the server will also * use the connect methods. The typical sequence of operation is:</p> *<ol> - * <li>Client calls AsyncChannel#connect</li> - * <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li> - * <li>Client calls AsyncChannel#sendMessage(CMD_CHANNEL_FULL_CONNECTION)</li> + * <li>Client calls AsyncChannel#fullyConnectSync or Asynchronously:<li> + * <ol>For an asynchronous full connection it calls AsyncChannel#connect</li> + * <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li> + * <li>Client calls AsyncChannel#sendMessage(CMD_CHANNEL_FULL_CONNECTION)</li> + * </ol> * <li>Server receives CMD_CHANNEL_FULL_CONNECTION</li> - * <li>Server calls AsyncChannel#connect</li> - * <li>Server receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li> + * <li>Server calls AsyncChannel#connected</li> * <li>Server sends AsyncChannel#sendMessage(CMD_CHANNEL_FULLY_CONNECTED)</li> * <li>Client receives CMD_CHANNEL_FULLY_CONNECTED</li> * <li><code>comm-loop:</code></li> * <li>Client/Server uses AsyncChannel#sendMessage/replyToMessage * to communicate and perform work</li> * <li>Loop to <code>comm-loop</code> until done</li> - * <li>When done Client/Server calls {@link AsyncChannel#disconnect(int)}</li> + * <li>When done Client/Server calls {@link AsyncChannel#disconnect}</li> * <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li> *</ol> + * + * TODO: Consider simplifying where we have connect and fullyConnect with only one response + * message RSP_CHANNEL_CONNECT instead of two, CMD_CHANNEL_HALF_CONNECTED and + * CMD_CHANNEL_FULLY_CONNECTED. We'd also change CMD_CHANNEL_FULL_CONNECTION to REQ_CHANNEL_CONNECT. */ public class AsyncChannel { /** Log tag */ @@ -85,6 +90,8 @@ public class AsyncChannel { /** Enable to turn on debugging */ private static final boolean DBG = false; + private static final int BASE = Protocol.BASE_SYSTEM_ASYNC_CHANNEL; + /** * Command sent when the channel is half connected. Half connected * means that the channel can be used to send commends to the destination @@ -98,7 +105,7 @@ public class AsyncChannel { * msg.obj == the AsyncChannel * msg.replyTo == dstMessenger if successful */ - public static final int CMD_CHANNEL_HALF_CONNECTED = -1; + public static final int CMD_CHANNEL_HALF_CONNECTED = BASE + 0; /** * Command typically sent when after receiving the CMD_CHANNEL_HALF_CONNECTED. @@ -107,7 +114,7 @@ public class AsyncChannel { * * msg.replyTo = srcMessenger. */ - public static final int CMD_CHANNEL_FULL_CONNECTION = -2; + public static final int CMD_CHANNEL_FULL_CONNECTION = BASE + 1; /** * Command typically sent after the destination receives a CMD_CHANNEL_FULL_CONNECTION. @@ -115,20 +122,20 @@ public class AsyncChannel { * * msg.arg1 == 0 : Accept connection * : All other values signify the destination rejected the connection - * and {@link AsyncChannel#disconnect(int)} would typically be called. + * and {@link AsyncChannel#disconnect} would typically be called. */ - public static final int CMD_CHANNEL_FULLY_CONNECTED = -3; + public static final int CMD_CHANNEL_FULLY_CONNECTED = BASE + 2; /** * Command sent when one side or the other wishes to disconnect. The sender * may or may not be able to receive a reply depending upon the protocol and - * the state of the connection. The receiver should call {@link AsyncChannel#disconnect(int)} + * the state of the connection. The receiver should call {@link AsyncChannel#disconnect} * to close its side of the channel and it will receive a CMD_CHANNEL_DISCONNECTED * when the channel is closed. * * msg.replyTo = messenger that is disconnecting */ - public static final int CMD_CHANNEL_DISCONNECT = -4; + public static final int CMD_CHANNEL_DISCONNECT = BASE + 3; /** * Command sent when the channel becomes disconnected. This is sent when the @@ -141,7 +148,7 @@ public class AsyncChannel { * msg.obj == the AsyncChannel * msg.replyTo = messenger disconnecting or null if it was never connected. */ - public static final int CMD_CHANNEL_DISCONNECTED = -5; + public static final int CMD_CHANNEL_DISCONNECTED = BASE + 4; /** Successful status always 0, !0 is an unsuccessful status */ public static final int STATUS_SUCCESSFUL = 0; @@ -152,6 +159,9 @@ public class AsyncChannel { /** Error attempting to send a message */ public static final int STATUS_SEND_UNSUCCESSFUL = 2; + /** CMD_FULLY_CONNECTED refused because a connection already exists*/ + public static final int STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED = 3; + /** Service connection */ private AsyncChannelConnection mConnection; @@ -174,9 +184,7 @@ public class AsyncChannel { } /** - * Connect handler to named package/class. - * - * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete. + * Connect handler to named package/class synchronously. * * @param srcContext is the context of the source * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED @@ -184,8 +192,10 @@ public class AsyncChannel { * @param dstPackageName is the destination package name * @param dstClassName is the fully qualified class name (i.e. contains * package name) + * + * @return STATUS_SUCCESSFUL on success any other value is an error. */ - private void connectSrcHandlerToPackage( + public int connectSrcHandlerToPackageSync( Context srcContext, Handler srcHandler, String dstPackageName, String dstClassName) { if (DBG) log("connect srcHandler to dst Package & class E"); @@ -207,11 +217,61 @@ public class AsyncChannel { Intent intent = new Intent(Intent.ACTION_MAIN); intent.setClassName(dstPackageName, dstClassName); boolean result = srcContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); - if (!result) { - replyHalfConnected(STATUS_BINDING_UNSUCCESSFUL); - } - if (DBG) log("connect srcHandler to dst Package & class X result=" + result); + return result ? STATUS_SUCCESSFUL : STATUS_BINDING_UNSUCCESSFUL; + } + + /** + * Connect a handler to Messenger synchronously. + * + * @param srcContext is the context of the source + * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED + * messages + * @param dstMessenger is the hander to send messages to. + * + * @return STATUS_SUCCESSFUL on success any other value is an error. + */ + public int connectSync(Context srcContext, Handler srcHandler, Messenger dstMessenger) { + if (DBG) log("halfConnectSync srcHandler to the dstMessenger E"); + + // We are connected + connected(srcContext, srcHandler, dstMessenger); + + if (DBG) log("halfConnectSync srcHandler to the dstMessenger X"); + return STATUS_SUCCESSFUL; + } + + /** + * connect two local Handlers synchronously. + * + * @param srcContext is the context of the source + * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED + * messages + * @param dstHandler is the hander to send messages to. + * + * @return STATUS_SUCCESSFUL on success any other value is an error. + */ + public int connectSync(Context srcContext, Handler srcHandler, Handler dstHandler) { + return connectSync(srcContext, srcHandler, new Messenger(dstHandler)); + } + + /** + * Fully connect two local Handlers synchronously. + * + * @param srcContext is the context of the source + * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED + * messages + * @param dstHandler is the hander to send messages to. + * + * @return STATUS_SUCCESSFUL on success any other value is an error. + */ + public int fullyConnectSync(Context srcContext, Handler srcHandler, Handler dstHandler) { + int status = connectSync(srcContext, srcHandler, dstHandler); + if (status == STATUS_SUCCESSFUL) { + Message response = sendMessageSynchronously(CMD_CHANNEL_FULL_CONNECTION); + status = response.arg1; + } + return status; } /** @@ -246,8 +306,11 @@ public class AsyncChannel { mDstClassName = dstClassName; } + @Override public void run() { - connectSrcHandlerToPackage(mSrcCtx, mSrcHdlr, mDstPackageName, mDstClassName); + int result = connectSrcHandlerToPackageSync(mSrcCtx, mSrcHdlr, mDstPackageName, + mDstClassName); + replyHalfConnected(result); } } @@ -286,6 +349,28 @@ public class AsyncChannel { public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) { if (DBG) log("connect srcHandler to the dstMessenger E"); + // We are connected + connected(srcContext, srcHandler, dstMessenger); + + // Tell source we are half connected + replyHalfConnected(STATUS_SUCCESSFUL); + + if (DBG) log("connect srcHandler to the dstMessenger X"); + } + + /** + * Connect handler to messenger. This method is typically called + * when a server receives a CMD_CHANNEL_FULL_CONNECTION request + * and initializes the internal instance variables to allow communication + * with the dstMessenger. + * + * @param srcContext + * @param srcHandler + * @param dstMessenger + */ + public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) { + if (DBG) log("connected srcHandler to the dstMessenger E"); + // Initialize source fields mSrcContext = srcContext; mSrcHandler = srcHandler; @@ -294,21 +379,12 @@ public class AsyncChannel { // Initialize destination fields mDstMessenger = dstMessenger; - if (DBG) log("tell source we are half connected"); - - // Tell source we are half connected - replyHalfConnected(STATUS_SUCCESSFUL); - - if (DBG) log("connect srcHandler to the dstMessenger X"); + if (DBG) log("connected srcHandler to the dstMessenger X"); } /** * Connect two local Handlers. * - * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete. - * msg.arg1 = status - * msg.obj = the AsyncChannel - * * @param srcContext is the context of the source * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED * messages @@ -336,6 +412,7 @@ public class AsyncChannel { * To close the connection call when handler receives CMD_CHANNEL_DISCONNECTED */ public void disconnected() { + mSrcContext = null; mSrcHandler = null; mSrcMessenger = null; mDstMessenger = null; @@ -346,7 +423,7 @@ public class AsyncChannel { * Disconnect */ public void disconnect() { - if (mConnection != null) { + if ((mConnection != null) && (mSrcContext != null)) { mSrcContext.unbindService(mConnection); } if (mSrcHandler != null) { @@ -445,6 +522,7 @@ public class AsyncChannel { */ public void replyToMessage(Message srcMsg, Message dstMsg) { try { + dstMsg.replyTo = mSrcMessenger; srcMsg.replyTo.send(dstMsg); } catch (RemoteException e) { log("TODO: handle replyToMessage RemoteException" + e); @@ -695,10 +773,14 @@ public class AsyncChannel { private static Message sendMessageSynchronously(Messenger dstMessenger, Message msg) { SyncMessenger sm = SyncMessenger.obtain(); try { - msg.replyTo = sm.mMessenger; - dstMessenger.send(msg); - synchronized (sm.mHandler.mLockObject) { - sm.mHandler.mLockObject.wait(); + if (dstMessenger != null && msg != null) { + msg.replyTo = sm.mMessenger; + synchronized (sm.mHandler.mLockObject) { + dstMessenger.send(msg); + sm.mHandler.mLockObject.wait(); + } + } else { + sm.mHandler.mResultMsg = null; } } catch (InterruptedException e) { sm.mHandler.mResultMsg = null; @@ -747,11 +829,13 @@ public class AsyncChannel { AsyncChannelConnection() { } + @Override public void onServiceConnected(ComponentName className, IBinder service) { mDstMessenger = new Messenger(service); replyHalfConnected(STATUS_SUCCESSFUL); } + @Override public void onServiceDisconnected(ComponentName className) { replyDisconnected(STATUS_SUCCESSFUL); } diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java index 2689f09c518e..b35f615b240d 100644 --- a/core/java/com/android/internal/util/Protocol.java +++ b/core/java/com/android/internal/util/Protocol.java @@ -29,9 +29,17 @@ package com.android.internal.util; * {@hide} */ public class Protocol { - public static final int MAX_MESSAGE = 0x0000FFFF; + public static final int MAX_MESSAGE = 0x0000FFFF; + + /** Base reserved for system */ + public static final int BASE_SYSTEM_RESERVED = 0x00010000; + public static final int BASE_SYSTEM_ASYNC_CHANNEL = 0x00011000; + + /** Non system protocols */ + public static final int BASE_WIFI = 0x00020000; + public static final int BASE_DHCP = 0x00030000; + public static final int BASE_DATA_CONNECTION = 0x00040000; + public static final int BASE_DATA_CONNECTION_TRACKER = 0x00050000; - public static final int BASE_WIFI = 0x00010000; - public static final int BASE_DHCP = 0x00020000; //TODO: define all used protocols } diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp index c11242383814..c1acaa3e4683 100644 --- a/core/jni/android/graphics/Movie.cpp +++ b/core/jni/android/graphics/Movie.cpp @@ -112,6 +112,10 @@ static jobject movie_decodeByteArray(JNIEnv* env, jobject clazz, return create_jmovie(env, moov); } +static void movie_destructor(JNIEnv* env, jobject, SkMovie* movie) { + delete movie; +} + ////////////////////////////////////////////////////////////////////////////////////////////// #include <android_runtime/AndroidRuntime.h> @@ -126,6 +130,7 @@ static JNINativeMethod gMethods[] = { (void*)movie_draw }, { "decodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;", (void*)movie_decodeStream }, + { "nativeDestructor","(I)V", (void*)movie_destructor }, { "decodeByteArray", "([BII)Landroid/graphics/Movie;", (void*)movie_decodeByteArray }, }; diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 4a0e68e01a9b..548376df5296 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -40,6 +40,16 @@ int dhcp_do_request(const char *ifname, const char *dns2, const char *server, uint32_t *lease); + +int dhcp_do_request_renew(const char *ifname, + const char *ipaddr, + const char *gateway, + uint32_t *prefixLength, + const char *dns1, + const char *dns2, + const char *server, + uint32_t *lease); + int dhcp_stop(const char *ifname); int dhcp_release_lease(const char *ifname); char *dhcp_get_errmsg(); @@ -57,7 +67,6 @@ namespace android { static struct fieldIds { jmethodID constructorId; jfieldID ipaddress; - jfieldID gateway; jfieldID prefixLength; jfieldID dns1; jfieldID dns2; @@ -145,7 +154,8 @@ static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz, jstri return (jint)result; } -static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info) +static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstring ifname, + jobject info, bool renew) { int result; char ipaddr[PROPERTY_VALUE_MAX]; @@ -159,12 +169,41 @@ static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring if const char *nameStr = env->GetStringUTFChars(ifname, NULL); if (nameStr == NULL) return (jboolean)false; - result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength, - dns1, dns2, server, &lease); + if (renew) { + result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength, + dns1, dns2, server, &lease); + } else { + result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength, + dns1, dns2, server, &lease); + } + env->ReleaseStringUTFChars(ifname, nameStr); if (result == 0) { env->SetObjectField(info, dhcpInfoInternalFieldIds.ipaddress, env->NewStringUTF(ipaddr)); - env->SetObjectField(info, dhcpInfoInternalFieldIds.gateway, env->NewStringUTF(gateway)); + + // set the gateway + jclass cls = env->FindClass("java/net/InetAddress"); + jmethodID method = env->GetStaticMethodID(cls, "getByName", + "(Ljava/lang/String;)Ljava/net/InetAddress;"); + jvalue args[1]; + args[0].l = env->NewStringUTF(gateway); + jobject inetAddressObject = env->CallStaticObjectMethodA(cls, method, args); + + if (!env->ExceptionOccurred()) { + cls = env->FindClass("android/net/RouteInfo"); + method = env->GetMethodID(cls, "<init>", "(Ljava/net/InetAddress;)V"); + args[0].l = inetAddressObject; + jobject routeInfoObject = env->NewObjectA(cls, method, args); + + cls = env->FindClass("android/net/DhcpInfoInternal"); + method = env->GetMethodID(cls, "addRoute", "(Landroid/net/RouteInfo;)V"); + args[0].l = routeInfoObject; + env->CallVoidMethodA(info, method, args); + } else { + // if we have an exception (host not found perhaps), just don't add the route + env->ExceptionClear(); + } + env->SetIntField(info, dhcpInfoInternalFieldIds.prefixLength, prefixLength); env->SetObjectField(info, dhcpInfoInternalFieldIds.dns1, env->NewStringUTF(dns1)); env->SetObjectField(info, dhcpInfoInternalFieldIds.dns2, env->NewStringUTF(dns2)); @@ -175,6 +214,17 @@ static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring if return (jboolean)(result == 0); } +static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info) +{ + return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false); +} + +static jboolean android_net_utils_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname, jobject info) +{ + return android_net_utils_runDhcpCommon(env, clazz, ifname, info, true); +} + + static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname) { int result; @@ -218,6 +268,7 @@ static JNINativeMethod gNetworkUtilMethods[] = { { "removeDefaultRoute", "(Ljava/lang/String;)I", (void *)android_net_utils_removeDefaultRoute }, { "resetConnections", "(Ljava/lang/String;)I", (void *)android_net_utils_resetConnections }, { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcp }, + { "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcpRenew }, { "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp }, { "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease }, { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError }, @@ -229,7 +280,6 @@ int register_android_net_NetworkUtils(JNIEnv* env) LOG_FATAL_IF(dhcpInfoInternalClass == NULL, "Unable to find class android/net/DhcpInfoInternal"); dhcpInfoInternalFieldIds.constructorId = env->GetMethodID(dhcpInfoInternalClass, "<init>", "()V"); dhcpInfoInternalFieldIds.ipaddress = env->GetFieldID(dhcpInfoInternalClass, "ipAddress", "Ljava/lang/String;"); - dhcpInfoInternalFieldIds.gateway = env->GetFieldID(dhcpInfoInternalClass, "gateway", "Ljava/lang/String;"); dhcpInfoInternalFieldIds.prefixLength = env->GetFieldID(dhcpInfoInternalClass, "prefixLength", "I"); dhcpInfoInternalFieldIds.dns1 = env->GetFieldID(dhcpInfoInternalClass, "dns1", "Ljava/lang/String;"); dhcpInfoInternalFieldIds.dns2 = env->GetFieldID(dhcpInfoInternalClass, "dns2", "Ljava/lang/String;"); diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java index d22356dfe230..27363e828e1f 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java @@ -30,6 +30,7 @@ import android.net.wifi.WifiConfiguration.KeyMgmt; import android.net.wifi.WifiConfiguration.ProxySettings; import android.net.LinkAddress; import android.net.LinkProperties; +import android.net.RouteInfo; import android.util.Log; import java.io.InputStream; @@ -301,7 +302,7 @@ public class AccessPointParserHelper { if (!InetAddress.isNumeric(gwAddr)) { throw new SAXException(); } - mLinkProperties.addGateway(InetAddress.getByName(gwAddr)); + mLinkProperties.addRoute(new RouteInfo(InetAddress.getByName(gwAddr))); } catch (UnknownHostException e) { throw new SAXException(); } diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index 010e3c3cf58d..fadf1ec3961f 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -421,6 +421,13 @@ </intent-filter> </activity> + <activity android:name="android.widget.scroll.arrowscroll.MultiPageTextWithPadding" android:label="arrowscrollMultiPageTextWithPadding"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" /> + </intent-filter> + </activity> + <activity android:name="android.view.Include" android:label="IncludeTag"> <intent-filter> <action android:name="android.intent.action.MAIN" /> diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index 50666b4d0dad..e3b6b5f95050 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -17,6 +17,7 @@ package android.net; import android.net.LinkProperties; +import android.net.RouteInfo; import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; @@ -55,8 +56,8 @@ public class LinkPropertiesTest extends TestCase { source.addDns(NetworkUtils.numericToInetAddress(DNS1)); source.addDns(NetworkUtils.numericToInetAddress(DNS2)); // set 2 gateways - source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1)); - source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2)); + source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); + source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); LinkProperties target = new LinkProperties(); @@ -68,8 +69,8 @@ public class LinkPropertiesTest extends TestCase { NetworkUtils.numericToInetAddress(ADDRV6), 128)); target.addDns(NetworkUtils.numericToInetAddress(DNS1)); target.addDns(NetworkUtils.numericToInetAddress(DNS2)); - target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1)); - target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2)); + target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); + target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); assertTrue(source.equals(target)); assertTrue(source.hashCode() == target.hashCode()); @@ -83,8 +84,8 @@ public class LinkPropertiesTest extends TestCase { NetworkUtils.numericToInetAddress(ADDRV6), 128)); target.addDns(NetworkUtils.numericToInetAddress(DNS1)); target.addDns(NetworkUtils.numericToInetAddress(DNS2)); - target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1)); - target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2)); + target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); + target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); assertFalse(source.equals(target)); target.clear(); @@ -96,8 +97,8 @@ public class LinkPropertiesTest extends TestCase { NetworkUtils.numericToInetAddress(ADDRV6), 128)); target.addDns(NetworkUtils.numericToInetAddress(DNS1)); target.addDns(NetworkUtils.numericToInetAddress(DNS2)); - target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1)); - target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2)); + target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); + target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); assertFalse(source.equals(target)); target.clear(); @@ -109,8 +110,8 @@ public class LinkPropertiesTest extends TestCase { // change dnses target.addDns(NetworkUtils.numericToInetAddress("75.208.7.2")); target.addDns(NetworkUtils.numericToInetAddress(DNS2)); - target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1)); - target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2)); + target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); + target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); assertFalse(source.equals(target)); target.clear(); @@ -122,8 +123,8 @@ public class LinkPropertiesTest extends TestCase { target.addDns(NetworkUtils.numericToInetAddress(DNS1)); target.addDns(NetworkUtils.numericToInetAddress(DNS2)); // change gateway - target.addGateway(NetworkUtils.numericToInetAddress("75.208.8.2")); - target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2)); + target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2"))); + target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); assertFalse(source.equals(target)); } catch (Exception e) { @@ -146,8 +147,8 @@ public class LinkPropertiesTest extends TestCase { source.addDns(NetworkUtils.numericToInetAddress(DNS1)); source.addDns(NetworkUtils.numericToInetAddress(DNS2)); // set 2 gateways - source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1)); - source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2)); + source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); + source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); LinkProperties target = new LinkProperties(); // Exchange order @@ -158,8 +159,8 @@ public class LinkPropertiesTest extends TestCase { NetworkUtils.numericToInetAddress(ADDRV4), 32)); target.addDns(NetworkUtils.numericToInetAddress(DNS2)); target.addDns(NetworkUtils.numericToInetAddress(DNS1)); - target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2)); - target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1)); + target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); + target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); assertTrue(source.equals(target)); assertTrue(source.hashCode() == target.hashCode()); diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java index c82962d5f3c3..d494c5d03b63 100644 --- a/core/tests/coretests/src/android/text/TextUtilsTest.java +++ b/core/tests/coretests/src/android/text/TextUtilsTest.java @@ -19,6 +19,7 @@ package android.text; import com.google.android.collect.Lists; import android.test.MoreAsserts; +import android.os.Parcel; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.SmallTest; import android.text.style.StyleSpan; @@ -344,6 +345,51 @@ public class TextUtilsTest extends TestCase { assertFalse(TextUtils.delimitedStringContains("network,mock,gpsx", ',', "gps")); } + @SmallTest + public void testCharSequenceCreator() { + Parcel p = Parcel.obtain(); + TextUtils.writeToParcel(null, p, 0); + CharSequence text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p); + assertNull("null CharSequence should generate null from parcel", text); + p = Parcel.obtain(); + TextUtils.writeToParcel("test", p, 0); + text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p); + assertEquals("conversion to/from parcel failed", "test", text); + } + + @SmallTest + public void testCharSequenceCreatorNull() { + Parcel p; + CharSequence text; + p = Parcel.obtain(); + TextUtils.writeToParcel(null, p, 0); + p.setDataPosition(0); + text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p); + assertNull("null CharSequence should generate null from parcel", text); + } + + @SmallTest + public void testCharSequenceCreatorSpannable() { + Parcel p; + CharSequence text; + p = Parcel.obtain(); + TextUtils.writeToParcel(new SpannableString("test"), p, 0); + p.setDataPosition(0); + text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p); + assertEquals("conversion to/from parcel failed", "test", text.toString()); + } + + @SmallTest + public void testCharSequenceCreatorString() { + Parcel p; + CharSequence text; + p = Parcel.obtain(); + TextUtils.writeToParcel("test", p, 0); + p.setDataPosition(0); + text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p); + assertEquals("conversion to/from parcel failed", "test", text.toString()); + } + /** * CharSequence wrapper for testing the cases where text is copied into * a char array instead of working from a String or a Spanned. diff --git a/core/tests/coretests/src/android/util/ScrollViewScenario.java b/core/tests/coretests/src/android/util/ScrollViewScenario.java index 83afe062e0f2..db3d9d04785a 100644 --- a/core/tests/coretests/src/android/util/ScrollViewScenario.java +++ b/core/tests/coretests/src/android/util/ScrollViewScenario.java @@ -61,6 +61,7 @@ public abstract class ScrollViewScenario extends Activity { /** * Partially implement ViewFactory given a height ratio. + * A negative height ratio means that WRAP_CONTENT will be used as height */ private static abstract class ViewFactoryBase implements ViewFactory { @@ -87,6 +88,9 @@ public abstract class ScrollViewScenario extends Activity { List<ViewFactory> mViewFactories = Lists.newArrayList(); + int mTopPadding = 0; + int mBottomPadding = 0; + /** * Add a text view. * @param text The text of the text view. @@ -186,6 +190,13 @@ public abstract class ScrollViewScenario extends Activity { }); return this; } + + public Params addPaddingToScrollView(int topPadding, int bottomPadding) { + mTopPadding = topPadding; + mBottomPadding = bottomPadding; + + return this; + } } /** @@ -239,13 +250,17 @@ public abstract class ScrollViewScenario extends Activity { // create views specified by params for (ViewFactory viewFactory : params.mViewFactories) { + int height = ViewGroup.LayoutParams.WRAP_CONTENT; + if (viewFactory.getHeightRatio() >= 0) { + height = (int) (viewFactory.getHeightRatio() * screenHeight); + } final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - (int) (viewFactory.getHeightRatio() * screenHeight)); + ViewGroup.LayoutParams.MATCH_PARENT, height); mLinearLayout.addView(viewFactory.create(this), lp); } mScrollView = createScrollView(); + mScrollView.setPadding(0, params.mTopPadding, 0, params.mBottomPadding); mScrollView.addView(mLinearLayout, new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPadding.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPadding.java new file mode 100644 index 000000000000..7d5a8d8441e8 --- /dev/null +++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPadding.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.widget.scroll.arrowscroll; + +import android.util.ScrollViewScenario; + +/** + * One TextView with a text covering several pages. Padding is added + * above and below the ScrollView. + */ +public class MultiPageTextWithPadding extends ScrollViewScenario { + + @Override + protected void init(Params params) { + + String text = "This is a long text."; + String longText = "First text."; + for (int i = 0; i < 300; i++) { + longText = longText + " " + text; + } + longText = longText + " Last text."; + params.addTextView(longText, -1.0f).addPaddingToScrollView(50, 50); + } +} diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java new file mode 100644 index 000000000000..ddde48f43a71 --- /dev/null +++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2011 Sony Ericsson Mobile Communications AB. + * + * 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.widget.scroll.arrowscroll; + +import android.widget.scroll.arrowscroll.MultiPageTextWithPadding; +import android.test.ActivityInstrumentationTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.MediumTest; +import android.view.KeyEvent; +import android.widget.TextView; +import android.widget.ScrollView; + +public class MultiPageTextWithPaddingTest extends + ActivityInstrumentationTestCase<MultiPageTextWithPadding> { + + private ScrollView mScrollView; + + private TextView mTextView; + + public MultiPageTextWithPaddingTest() { + super("com.android.frameworks.coretests", MultiPageTextWithPadding.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mScrollView = getActivity().getScrollView(); + mTextView = getActivity().getContentChildAt(0); + } + + @MediumTest + public void testPreconditions() { + assertTrue("text should not fit on screen", + mTextView.getHeight() > mScrollView.getHeight()); + } + + @LargeTest + public void testScrollDownToBottom() throws Exception { + // Calculate the number of arrow scrolls needed to reach the bottom + int scrollsNeeded = (int)Math.ceil(Math.max(0.0f, + (mTextView.getHeight() - mScrollView.getHeight())) + / mScrollView.getMaxScrollAmount()); + for (int i = 0; i < scrollsNeeded; i++) { + sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); + } + + assertEquals( + "should be fully scrolled to bottom", + getActivity().getLinearLayout().getHeight() + - (mScrollView.getHeight() - mScrollView.getPaddingTop() - mScrollView + .getPaddingBottom()), mScrollView.getScrollY()); + } +} diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java index 95e9946d55a5..4a334531e070 100644 --- a/graphics/java/android/graphics/Movie.java +++ b/graphics/java/android/graphics/Movie.java @@ -46,6 +46,8 @@ public class Movie { public static native Movie decodeByteArray(byte[] data, int offset, int length); + private static native void nativeDestructor(int nativeMovie); + public static Movie decodeFile(String pathName) { InputStream is; try { @@ -57,6 +59,15 @@ public class Movie { return decodeTempStream(is); } + @Override + protected void finalize() throws Throwable { + try { + nativeDestructor(mNativeMovie); + } finally { + super.finalize(); + } + } + private static Movie decodeTempStream(InputStream is) { Movie moov = null; try { diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index faecadde245a..596781e31aa4 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -62,8 +62,10 @@ static const TextureVertex gMeshVertices[] = { static const GLsizei gMeshStride = sizeof(TextureVertex); static const GLsizei gVertexStride = sizeof(Vertex); static const GLsizei gAlphaVertexStride = sizeof(AlphaVertex); +static const GLsizei gAAVertexStride = sizeof(AAVertex); 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; /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 34d8fd31e206..049e9b70bca9 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -915,7 +915,7 @@ void OpenGLRenderer::setupDrawWithExternalTexture() { } void OpenGLRenderer::setupDrawAALine() { - mDescription.hasWidth = true; + mDescription.isAA = true; } void OpenGLRenderer::setupDrawPoint(float pointSize) { @@ -1121,25 +1121,30 @@ void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) { /** * Sets up the shader to draw an AA line. We draw AA lines with quads, where there is an - * outer boundary that fades out to 0. The variables set in the shader define the width of the - * core line primitive ("width") and the width of the fading boundary ("boundaryWidth"). The - * "vtxDistance" attribute (one per vertex) is a value from zero to one that tells the fragment - * shader where the fragment is in relation to the line width overall; this value is then used - * to compute the proper color, based on whether the fragment lies in the fading AA region of - * the line. + * outer boundary that fades out to 0. The variables set in the shader define the proportion of + * the width and length of the primitive occupied by the AA region. The vtxWidth and vtxLength + * attributes (one per vertex) are values from zero to one that tells the fragment + * shader where the fragment is in relation to the line width/length overall; these values are + * then used to compute the proper color, based on whether the fragment lies in the fading AA + * region of the line. + * Note that we only pass down the width values in this setup function. The length coordinates + * are set up for each individual segment. */ -void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth) { +void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* widthCoords, + GLvoid* lengthCoords, float strokeWidth) { mCaches.unbindMeshBuffer(); glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, - gAlphaVertexStride, vertices); - int distanceSlot = mCaches.currentProgram->getAttrib("vtxDistance"); - glEnableVertexAttribArray(distanceSlot); - glVertexAttribPointer(distanceSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, distanceCoords); - int widthSlot = mCaches.currentProgram->getUniform("width"); + gAAVertexStride, vertices); + int widthSlot = mCaches.currentProgram->getAttrib("vtxWidth"); + glEnableVertexAttribArray(widthSlot); + glVertexAttribPointer(widthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, widthCoords); + int lengthSlot = mCaches.currentProgram->getAttrib("vtxLength"); + glEnableVertexAttribArray(lengthSlot); + glVertexAttribPointer(lengthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, lengthCoords); int boundaryWidthSlot = mCaches.currentProgram->getUniform("boundaryWidth"); + // Setting the inverse value saves computations per-fragment in the shader int inverseBoundaryWidthSlot = mCaches.currentProgram->getUniform("inverseBoundaryWidth"); float boundaryWidth = (1 - strokeWidth) / 2; - glUniform1f(widthSlot, strokeWidth); glUniform1f(boundaryWidthSlot, boundaryWidth); glUniform1f(inverseBoundaryWidthSlot, (1 / boundaryWidth)); } @@ -1480,20 +1485,21 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { } Vertex lines[verticesCount]; Vertex* vertices = &lines[0]; - AlphaVertex wLines[verticesCount]; - AlphaVertex* aaVertices = &wLines[0]; + AAVertex wLines[verticesCount]; + AAVertex* aaVertices = &wLines[0]; if (!isAA) { setupDrawVertices(vertices); } else { - void* alphaCoords = ((GLbyte*) aaVertices) + gVertexAlphaOffset; + void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset; + void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset; // innerProportion is the ratio of the inner (non-AA) port of the line to the total // AA stroke width (the base stroke width expanded by a half pixel on either side). // This value is used in the fragment shader to determine how to fill fragments. float innerProportion = fmax(strokeWidth - 1.0f, 0) / (strokeWidth + .5f); - setupDrawAALine((void*) aaVertices, alphaCoords, innerProportion); + setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords, innerProportion); } - AlphaVertex *prevAAVertex = NULL; + AAVertex *prevAAVertex = NULL; Vertex *prevVertex = NULL; float inverseScaleX = 1.0f; float inverseScaleY = 1.0f; @@ -1516,15 +1522,17 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { } } + int boundaryLengthSlot = -1; + int inverseBoundaryLengthSlot = -1; for (int i = 0; i < count; i += 4) { // a = start point, b = end point vec2 a(points[i], points[i + 1]); vec2 b(points[i + 2], points[i + 3]); + float length = 0; // Find the normal to the line vec2 n = (b - a).copyNormalized() * strokeWidth; if (isHairLine) { - n *= inverseScaleX; if (isAA) { float wideningFactor; if (fabs(n.x) >= fabs(n.y)) { @@ -1534,27 +1542,35 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { } n *= wideningFactor; } + n.x *= inverseScaleX; + n.y *= inverseScaleY; } float x = n.x; n.x = -n.y; n.y = x; + // aa lines expand the endpoint vertices to encompass the AA boundary + if (isAA) { + vec2 abVector = (b - a); + length = abVector.length(); + abVector.normalize(); + a -= abVector; + b += abVector; + } + // Four corners of the rectangle defining a thick line vec2 p1 = a - n; vec2 p2 = a + n; vec2 p3 = b + n; vec2 p4 = b - n; + const float left = fmin(p1.x, fmin(p2.x, fmin(p3.x, p4.x))); const float right = fmax(p1.x, fmax(p2.x, fmax(p3.x, p4.x))); const float top = fmin(p1.y, fmin(p2.y, fmin(p3.y, p4.y))); const float bottom = fmax(p1.y, fmax(p2.y, fmax(p3.y, p4.y))); if (!quickReject(left, top, right, bottom)) { - // Draw the line as 2 triangles, could be optimized - // by using only 4 vertices and the correct indices - // Also we should probably used non textured vertices - // when line AA is disabled to save on bandwidth if (!isAA) { if (prevVertex != NULL) { // Issue two repeat vertices to create degenerate triangles to bridge @@ -1572,24 +1588,36 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { prevVertex = vertices - 1; generatedVerticesCount += 4; } else { + if (boundaryLengthSlot < 0) { + boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength"); + inverseBoundaryLengthSlot = + mCaches.currentProgram->getUniform("inverseBoundaryLength"); + } + float innerProportion = (length) / (length + 2); + float boundaryLength = (1 - innerProportion) / 2; + glUniform1f(boundaryLengthSlot, boundaryLength); + glUniform1f(inverseBoundaryLengthSlot, (1 / boundaryLength)); + if (prevAAVertex != NULL) { // Issue two repeat vertices to create degenerate triangles to bridge // between the previous line and the new one. This is necessary because // we are creating a single triangle_strip which will contain // potentially discontinuous line segments. - AlphaVertex::set(aaVertices++,prevAAVertex->position[0], - prevAAVertex->position[1], prevAAVertex->alpha); - AlphaVertex::set(aaVertices++, p4.x, p4.y, 1); + AAVertex::set(aaVertices++,prevAAVertex->position[0], + prevAAVertex->position[1], prevAAVertex->width, prevAAVertex->length); + AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1); generatedVerticesCount += 2; } - AlphaVertex::set(aaVertices++, p4.x, p4.y, 1); - AlphaVertex::set(aaVertices++, p1.x, p1.y, 1); - AlphaVertex::set(aaVertices++, p3.x, p3.y, 0); - AlphaVertex::set(aaVertices++, p2.x, p2.y, 0); + AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1); + AAVertex::set(aaVertices++, p1.x, p1.y, 1, 0); + AAVertex::set(aaVertices++, p3.x, p3.y, 0, 1); + AAVertex::set(aaVertices++, p2.x, p2.y, 0, 0); prevAAVertex = aaVertices - 1; generatedVerticesCount += 4; } - dirtyLayer(left, top, right, bottom, *mSnapshot->transform); + dirtyLayer(a.x == b.x ? left - 1 : left, a.y == b.y ? top - 1 : top, + a.x == b.x ? right: right, a.y == b.y ? bottom: bottom, + *mSnapshot->transform); } } if (generatedVerticesCount > 0) { diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 0ffd70b4ef99..6ffd931e3025 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -468,7 +468,8 @@ private: void setupDrawTextureTransform(mat4& transform); void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0); void setupDrawVertices(GLvoid* vertices); - void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth); + void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, GLvoid* lengthCoords, + float strokeWidth); void finishDrawTexture(); void drawRegionRects(const Region& region); diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 62ac2baaf7b6..5bfe7a35e3ab 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -39,8 +39,9 @@ const char* gVS_Header_Attributes = "attribute vec4 position;\n"; const char* gVS_Header_Attributes_TexCoords = "attribute vec2 texCoords;\n"; -const char* gVS_Header_Attributes_Distance = - "attribute float vtxDistance;\n"; +const char* gVS_Header_Attributes_AAParameters = + "attribute float vtxWidth;\n" + "attribute float vtxLength;\n"; const char* gVS_Header_Uniforms_TextureTransform = "uniform mat4 mainTextureTransform;\n"; const char* gVS_Header_Uniforms = @@ -60,8 +61,9 @@ const char* gVS_Header_Uniforms_HasBitmap = "uniform mediump vec2 textureDimension;\n"; const char* gVS_Header_Varyings_HasTexture = "varying vec2 outTexCoords;\n"; -const char* gVS_Header_Varyings_HasWidth = - "varying float distance;\n"; +const char* gVS_Header_Varyings_IsAA = + "varying float widthProportion;\n" + "varying float lengthProportion;\n"; const char* gVS_Header_Varyings_HasBitmap = "varying vec2 outBitmapTexCoords;\n"; const char* gVS_Header_Varyings_PointHasBitmap = @@ -96,8 +98,9 @@ const char* gVS_Main_Position = " gl_Position = transform * position;\n"; const char* gVS_Main_PointSize = " gl_PointSize = pointSize;\n"; -const char* gVS_Main_Width = - " distance = vtxDistance;\n"; +const char* gVS_Main_AA = + " widthProportion = vtxWidth;\n" + " lengthProportion = vtxLength;\n"; const char* gVS_Footer = "}\n\n"; @@ -113,10 +116,11 @@ const char* gFS_Header = "precision mediump float;\n\n"; const char* gFS_Uniforms_Color = "uniform vec4 color;\n"; -const char* gFS_Uniforms_Width = - "uniform float width;\n" +const char* gFS_Uniforms_AA = "uniform float boundaryWidth;\n" - "uniform float inverseBoundaryWidth;\n"; + "uniform float inverseBoundaryWidth;\n" + "uniform float boundaryLength;\n" + "uniform float inverseBoundaryLength;\n"; const char* gFS_Header_Uniforms_PointHasBitmap = "uniform vec2 textureDimension;\n" "uniform float pointSize;\n"; @@ -189,11 +193,16 @@ const char* gFS_Main_FetchColor = " fragColor = color;\n"; const char* gFS_Main_ModulateColor = " fragColor *= color.a;\n"; -const char* gFS_Main_AccountForWidth = - " if (distance < boundaryWidth) {\n" - " fragColor *= (distance * inverseBoundaryWidth);\n" - " } else if (distance > (1.0 - boundaryWidth)) {\n" - " fragColor *= ((1.0 - distance) * inverseBoundaryWidth);\n" +const char* gFS_Main_AccountForAA = + " if (widthProportion < boundaryWidth) {\n" + " fragColor *= (widthProportion * inverseBoundaryWidth);\n" + " } else if (widthProportion > (1.0 - boundaryWidth)) {\n" + " fragColor *= ((1.0 - widthProportion) * inverseBoundaryWidth);\n" + " }\n" + " if (lengthProportion < boundaryLength) {\n" + " fragColor *= (lengthProportion * inverseBoundaryLength);\n" + " } else if (lengthProportion > (1.0 - boundaryLength)) {\n" + " fragColor *= ((1.0 - lengthProportion) * inverseBoundaryLength);\n" " }\n"; const char* gFS_Main_FetchTexture[2] = { // Don't modulate @@ -380,8 +389,8 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Attributes_TexCoords); } - if (description.hasWidth) { - shader.append(gVS_Header_Attributes_Distance); + if (description.isAA) { + shader.append(gVS_Header_Attributes_AAParameters); } // Uniforms shader.append(gVS_Header_Uniforms); @@ -401,8 +410,8 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Varyings_HasTexture); } - if (description.hasWidth) { - shader.append(gVS_Header_Varyings_HasWidth); + if (description.isAA) { + shader.append(gVS_Header_Varyings_IsAA); } if (description.hasGradient) { shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); @@ -421,8 +430,8 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasExternalTexture) { shader.append(gVS_Main_OutTransformedTexCoords); } - if (description.hasWidth) { - shader.append(gVS_Main_Width); + if (description.isAA) { + shader.append(gVS_Main_AA); } if (description.hasGradient) { shader.append(gVS_Main_OutGradient[description.gradientType]); @@ -464,8 +473,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Varyings_HasTexture); } - if (description.hasWidth) { - shader.append(gVS_Header_Varyings_HasWidth); + if (description.isAA) { + shader.append(gVS_Header_Varyings_IsAA); } if (description.hasGradient) { shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); @@ -491,8 +500,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (description.hasExternalTexture) { shader.append(gFS_Uniforms_ExternalTextureSampler); } - if (description.hasWidth) { - shader.append(gFS_Uniforms_Width); + if (description.isAA) { + shader.append(gFS_Uniforms_AA); } if (description.hasGradient) { shader.append(gFS_Uniforms_GradientSampler[description.gradientType]); @@ -502,7 +511,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti } // Optimization for common cases - if (!description.hasWidth && !blendFramebuffer && + if (!description.isAA && !blendFramebuffer && description.colorOp == ProgramDescription::kColorNone && !description.isPoint) { bool fast = false; @@ -587,8 +596,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gFS_Main_FetchColor); } } - if (description.hasWidth) { - shader.append(gFS_Main_AccountForWidth); + if (description.isAA) { + shader.append(gFS_Main_AccountForAA); } if (description.hasGradient) { shader.append(gFS_Main_FetchGradient[description.gradientType]); diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h index 70909fd622bf..25866360c93f 100644 --- a/libs/hwui/ProgramCache.h +++ b/libs/hwui/ProgramCache.h @@ -75,7 +75,7 @@ namespace uirenderer { #define PROGRAM_IS_POINT_SHIFT 36 -#define PROGRAM_HAS_WIDTH_SHIFT 37 +#define PROGRAM_HAS_AA_SHIFT 37 #define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38 @@ -124,7 +124,7 @@ struct ProgramDescription { bool hasBitmap; bool isBitmapNpot; - bool hasWidth; + bool isAA; bool hasGradient; Gradient gradientType; @@ -156,7 +156,7 @@ struct ProgramDescription { hasAlpha8Texture = false; hasExternalTexture = false; - hasWidth = false; + isAA = false; modulate = false; @@ -243,7 +243,7 @@ struct ProgramDescription { if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST; if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT; if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT; - if (hasWidth) key |= programid(0x1) << PROGRAM_HAS_WIDTH_SHIFT; + if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT; if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT; return key; } diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h index c120428e16d0..38455dc93274 100644 --- a/libs/hwui/Vertex.h +++ b/libs/hwui/Vertex.h @@ -68,6 +68,25 @@ struct AlphaVertex : Vertex { } }; // struct AlphaVertex +/** + * Simple structure to describe a vertex with a position and an alpha value. + */ +struct AAVertex : Vertex { + float width; + float length; + + static inline void set(AAVertex* vertex, float x, float y, float width, float length) { + Vertex::set(vertex, x, y); + vertex[0].width = width; + vertex[0].length = length; + } + + static inline void setColor(AAVertex* vertex, float width, float length) { + vertex[0].width = width; + vertex[0].length = length; + } +}; // struct AlphaVertex + }; // namespace uirenderer }; // namespace android diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk index a99a599e2225..232ab36ceb88 100644 --- a/libs/rs/Android.mk +++ b/libs/rs/Android.mk @@ -110,20 +110,23 @@ LOCAL_SRC_FILES:= \ rsScriptC.cpp \ rsScriptC_Lib.cpp \ rsScriptC_LibGL.cpp \ - rsShaderCache.cpp \ rsSignal.cpp \ rsStream.cpp \ rsThreadIO.cpp \ rsType.cpp \ - rsVertexArray.cpp \ driver/rsdBcc.cpp \ driver/rsdCore.cpp \ driver/rsdGL.cpp \ + driver/rsdMesh.cpp \ + driver/rsdMeshObj.cpp \ + driver/rsdProgram.cpp \ driver/rsdProgramRaster.cpp \ driver/rsdProgramStore.cpp \ driver/rsdRuntimeMath.cpp \ - driver/rsdRuntimeStubs.cpp - + driver/rsdRuntimeStubs.cpp \ + driver/rsdShader.cpp \ + driver/rsdShaderCache.cpp \ + driver/rsdVertexArray.cpp LOCAL_SHARED_LIBRARIES += libz libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp index 5b80439974cb..d5d23c755ab7 100644 --- a/libs/rs/driver/rsdCore.cpp +++ b/libs/rs/driver/rsdCore.cpp @@ -19,6 +19,9 @@ #include "rsdGL.h" #include "rsdProgramStore.h" #include "rsdProgramRaster.h" +#include "rsdProgramVertex.h" +#include "rsdProgramFragment.h" +#include "rsdMesh.h" #include <malloc.h> #include "rsContext.h" @@ -69,6 +72,24 @@ static RsdHalFunctions FunctionTable = { rsdProgramRasterInit, rsdProgramRasterSetActive, rsdProgramRasterDestroy + }, + + { + rsdProgramVertexInit, + rsdProgramVertexSetActive, + rsdProgramVertexDestroy + }, + + { + rsdProgramFragmentInit, + rsdProgramFragmentSetActive, + rsdProgramFragmentDestroy + }, + + { + rsdMeshInit, + rsdMeshDraw, + rsdMeshDestroy } }; diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp index 26e1bdf4fa27..48690d54490c 100644 --- a/libs/rs/driver/rsdGL.cpp +++ b/libs/rs/driver/rsdGL.cpp @@ -40,6 +40,8 @@ #include <malloc.h> #include "rsContext.h" +#include "rsdShaderCache.h" +#include "rsdVertexArray.h" using namespace android; using namespace android::renderscript; @@ -128,6 +130,11 @@ static void DumpDebug(RsdHal *dc) { void rsdGLShutdown(const Context *rsc) { RsdHal *dc = (RsdHal *)rsc->mHal.drv; + dc->gl.shaderCache->cleanupAll(); + delete dc->gl.shaderCache; + + delete dc->gl.vertexArrayState; + LOGV("%p, deinitEGL", rsc); if (dc->gl.egl.context != EGL_NO_CONTEXT) { @@ -287,6 +294,10 @@ bool rsdGLInit(const Context *rsc) { DumpDebug(dc); } + dc->gl.shaderCache = new RsdShaderCache(); + dc->gl.vertexArrayState = new RsdVertexArrayState(); + dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs); + LOGV("initGLThread end %p", rsc); return true; } diff --git a/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h index 246931f8ff7c..351b2d5dd4e2 100644 --- a/libs/rs/driver/rsdGL.h +++ b/libs/rs/driver/rsdGL.h @@ -19,7 +19,8 @@ #include <rs_hal.h> - +class RsdShaderCache; +class RsdVertexArrayState; typedef void (* InvokeFunc_t)(void); typedef void (*WorkerCallback_t)(void *usr, uint32_t idx); @@ -64,6 +65,8 @@ typedef struct RsdGLRec { ANativeWindow *wndSurface; uint32_t width; uint32_t height; + RsdShaderCache *shaderCache; + RsdVertexArrayState *vertexArrayState; } RsdGL; diff --git a/libs/rs/driver/rsdMesh.cpp b/libs/rs/driver/rsdMesh.cpp new file mode 100644 index 000000000000..eb62ddb6a845 --- /dev/null +++ b/libs/rs/driver/rsdMesh.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include <rs_hal.h> +#include <rsContext.h> +#include <rsMesh.h> + +#include "rsdCore.h" +#include "rsdMesh.h" +#include "rsdMeshObj.h" +#include "rsdShaderCache.h" + +using namespace android; +using namespace android::renderscript; + +bool rsdMeshInit(const Context *rsc, const Mesh *m) { + RsdMeshObj *drv = NULL; + if(m->mHal.drv) { + drv = (RsdMeshObj*)m->mHal.drv; + delete drv; + } + drv = new RsdMeshObj(rsc, m); + m->mHal.drv = drv; + return drv->init(); +} + +void rsdMeshDraw(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len) { + if(m->mHal.drv) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + if (!dc->gl.shaderCache->setup(rsc)) { + return; + } + + RsdMeshObj *drv = (RsdMeshObj*)m->mHal.drv; + drv->renderPrimitiveRange(rsc, primIndex, start, len); + } +} + +void rsdMeshDestroy(const Context *rsc, const Mesh *m) { + if(m->mHal.drv) { + RsdMeshObj *drv = (RsdMeshObj*)m->mHal.drv; + delete drv; + } +} + + diff --git a/libs/rs/driver/rsdMesh.h b/libs/rs/driver/rsdMesh.h new file mode 100644 index 000000000000..d2714fd24a29 --- /dev/null +++ b/libs/rs/driver/rsdMesh.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RSD_MESH_H +#define RSD_MESH_H + +#include <rs_hal.h> + + +bool rsdMeshInit(const android::renderscript::Context *rsc, + const android::renderscript::Mesh *m); +void rsdMeshDraw(const android::renderscript::Context *rsc, + const android::renderscript::Mesh *m, + uint32_t primIndex, uint32_t start, uint32_t len); +void rsdMeshDestroy(const android::renderscript::Context *rsc, + const android::renderscript::Mesh *m); + + +#endif diff --git a/libs/rs/driver/rsdMeshObj.cpp b/libs/rs/driver/rsdMeshObj.cpp new file mode 100644 index 000000000000..6bb33f76fe95 --- /dev/null +++ b/libs/rs/driver/rsdMeshObj.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <GLES/gl.h> +#include <GLES2/gl2.h> +#include <GLES/glext.h> + +#include <rs_hal.h> +#include <rsContext.h> +#include <rsMesh.h> + +#include "rsdMeshObj.h" + +using namespace android; +using namespace android::renderscript; + +RsdMeshObj::RsdMeshObj(const Context *rsc, const Mesh *rsMesh) { + mRSMesh = rsMesh; + + mAttribs = NULL; + mAttribAllocationIndex = NULL; + mGLPrimitives = NULL; + + mAttribCount = 0; +} + +RsdMeshObj::~RsdMeshObj() { + if (mAttribs) { + delete[] mAttribs; + delete[] mAttribAllocationIndex; + } + if (mGLPrimitives) { + delete[] mGLPrimitives; + } +} + +bool RsdMeshObj::isValidGLComponent(const Element *elem, uint32_t fieldIdx) { + // Do not create attribs for padding + if (elem->getFieldName(fieldIdx)[0] == '#') { + return false; + } + + // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted. + // Filter rs types accordingly + RsDataType dt = elem->getField(fieldIdx)->getComponent().getType(); + if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 && + dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 && + dt != RS_TYPE_SIGNED_16) { + return false; + } + + // Now make sure they are not arrays + uint32_t arraySize = elem->getFieldArraySize(fieldIdx); + if (arraySize != 1) { + return false; + } + + return true; +} + +bool RsdMeshObj::init() { + + updateGLPrimitives(); + + // Count the number of gl attrs to initialize + mAttribCount = 0; + for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) { + const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement(); + for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) { + if (isValidGLComponent(elem, ct)) { + mAttribCount ++; + } + } + } + + if (mAttribs) { + delete [] mAttribs; + delete [] mAttribAllocationIndex; + mAttribs = NULL; + mAttribAllocationIndex = NULL; + } + if (!mAttribCount) { + return false; + } + + mAttribs = new RsdVertexArray::Attrib[mAttribCount]; + mAttribAllocationIndex = new uint32_t[mAttribCount]; + + uint32_t userNum = 0; + for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) { + const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement(); + uint32_t stride = elem->getSizeBytes(); + for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) { + const Component &c = elem->getField(fieldI)->getComponent(); + + if (!isValidGLComponent(elem, fieldI)) { + continue; + } + + mAttribs[userNum].size = c.getVectorSize(); + mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI); + mAttribs[userNum].type = c.getGLType(); + mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized(); + mAttribs[userNum].stride = stride; + String8 tmp(RS_SHADER_ATTR); + tmp.append(elem->getFieldName(fieldI)); + mAttribs[userNum].name.setTo(tmp.string()); + + // Remember which allocation this attribute came from + mAttribAllocationIndex[userNum] = ct; + userNum ++; + } + } + + return true; +} + +void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const { + if (len < 1 || primIndex >= mRSMesh->mHal.state.primitivesCount || mAttribCount == 0) { + LOGE("Invalid mesh or parameters"); + return; + } + + rsc->checkError("Mesh::renderPrimitiveRange 1"); + // update attributes with either buffer information or data ptr based on their current state + for (uint32_t ct=0; ct < mAttribCount; ct++) { + uint32_t allocIndex = mAttribAllocationIndex[ct]; + Allocation *alloc = mRSMesh->mHal.state.vertexBuffers[allocIndex].get(); + if (alloc->getIsBufferObject() && alloc->getBufferObjectID()) { + mAttribs[ct].buffer = alloc->getBufferObjectID(); + mAttribs[ct].ptr = NULL; + } else { + mAttribs[ct].buffer = 0; + mAttribs[ct].ptr = (const uint8_t*)alloc->getPtr(); + } + } + + RsdVertexArray va(mAttribs, mAttribCount); + va.setupGL2(rsc); + + rsc->checkError("Mesh::renderPrimitiveRange 2"); + Mesh::Primitive_t *prim = mRSMesh->mHal.state.primitives[primIndex]; + if (prim->mIndexBuffer.get()) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prim->mIndexBuffer->getBufferObjectID()); + glDrawElements(mGLPrimitives[primIndex], len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2)); + } else { + glDrawArrays(mGLPrimitives[primIndex], start, len); + } + + rsc->checkError("Mesh::renderPrimitiveRange"); +} + +void RsdMeshObj::updateGLPrimitives() { + mGLPrimitives = new uint32_t[mRSMesh->mHal.state.primitivesCount]; + for (uint32_t i = 0; i < mRSMesh->mHal.state.primitivesCount; i ++) { + switch (mRSMesh->mHal.state.primitives[i]->mPrimitive) { + case RS_PRIMITIVE_POINT: mGLPrimitives[i] = GL_POINTS; break; + case RS_PRIMITIVE_LINE: mGLPrimitives[i] = GL_LINES; break; + case RS_PRIMITIVE_LINE_STRIP: mGLPrimitives[i] = GL_LINE_STRIP; break; + case RS_PRIMITIVE_TRIANGLE: mGLPrimitives[i] = GL_TRIANGLES; break; + case RS_PRIMITIVE_TRIANGLE_STRIP: mGLPrimitives[i] = GL_TRIANGLE_STRIP; break; + case RS_PRIMITIVE_TRIANGLE_FAN: mGLPrimitives[i] = GL_TRIANGLE_FAN; break; + } + } +} diff --git a/libs/rs/driver/rsdMeshObj.h b/libs/rs/driver/rsdMeshObj.h new file mode 100644 index 000000000000..8b1271baeaf7 --- /dev/null +++ b/libs/rs/driver/rsdMeshObj.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_RSD_MESH_OBJ_H +#define ANDROID_RSD_MESH_OBJ_H + +// --------------------------------------------------------------------------- +namespace android { +namespace renderscript { + + class Context; + class Mesh; + class Element; + +} +} + +#include "driver/rsdVertexArray.h" + +// An element is a group of Components that occupies one cell in a structure. +class RsdMeshObj { +public: + RsdMeshObj(const android::renderscript::Context *, + const android::renderscript::Mesh *); + ~RsdMeshObj(); + + void renderPrimitiveRange(const android::renderscript::Context *, uint32_t primIndex, uint32_t start, uint32_t len) const; + + bool init(); + +protected: + const android::renderscript::Mesh *mRSMesh; + + uint32_t *mGLPrimitives; + void updateGLPrimitives(); + + bool isValidGLComponent(const android::renderscript::Element *elem, uint32_t fieldIdx); + // Attribues that allow us to map to GL + RsdVertexArray::Attrib *mAttribs; + // This allows us to figure out which allocation the attribute + // belongs to. In the event the allocation is uploaded to GL + // buffer, it lets us properly map it + uint32_t *mAttribAllocationIndex; + uint32_t mAttribCount; +}; + +#endif //ANDROID_RSD_MESH_OBJ_H + + + diff --git a/libs/rs/driver/rsdProgram.cpp b/libs/rs/driver/rsdProgram.cpp new file mode 100644 index 000000000000..502c5ee5903e --- /dev/null +++ b/libs/rs/driver/rsdProgram.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "rsdCore.h" +#include "rsdProgramVertex.h" +#include "rsdShader.h" +#include "rsdShaderCache.h" + +#include "rsContext.h" +#include "rsProgramVertex.h" +#include "rsProgramFragment.h" + +#include <GLES/gl.h> +#include <GLES/glext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +using namespace android; +using namespace android::renderscript; + +bool rsdProgramVertexInit(const Context *rsc, const ProgramVertex *pv, + const char* shader, uint32_t shaderLen) { + RsdShader *drv = new RsdShader(pv, GL_VERTEX_SHADER, shader, shaderLen); + pv->mHal.drv = drv; + + return drv->createShader(); +} + +void rsdProgramVertexSetActive(const Context *rsc, const ProgramVertex *pv) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + dc->gl.shaderCache->setActiveVertex((RsdShader*)pv->mHal.drv); +} + +void rsdProgramVertexDestroy(const Context *rsc, const ProgramVertex *pv) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + RsdShader *drv = NULL; + if(pv->mHal.drv) { + drv = (RsdShader*)pv->mHal.drv; + if (rsc->props.mLogShaders) { + LOGV("Destroying vertex shader with ID %u", drv->getShaderID()); + } + if (drv->getShaderID()) { + dc->gl.shaderCache->cleanupVertex(drv->getShaderID()); + } + delete drv; + } +} + +bool rsdProgramFragmentInit(const Context *rsc, const ProgramFragment *pf, + const char* shader, uint32_t shaderLen) { + RsdShader *drv = new RsdShader(pf, GL_FRAGMENT_SHADER, shader, shaderLen); + pf->mHal.drv = drv; + + return drv->createShader(); +} + +void rsdProgramFragmentSetActive(const Context *rsc, const ProgramFragment *pf) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + dc->gl.shaderCache->setActiveFragment((RsdShader*)pf->mHal.drv); +} + +void rsdProgramFragmentDestroy(const Context *rsc, const ProgramFragment *pf) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + RsdShader *drv = NULL; + if(pf->mHal.drv) { + drv = (RsdShader*)pf->mHal.drv; + if (rsc->props.mLogShaders) { + LOGV("Destroying fragment shader with ID %u", drv->getShaderID()); + } + if (drv->getShaderID()) { + dc->gl.shaderCache->cleanupFragment(drv->getShaderID()); + } + delete drv; + } +} + + diff --git a/libs/rs/driver/rsdProgramFragment.h b/libs/rs/driver/rsdProgramFragment.h new file mode 100644 index 000000000000..366cb40d2962 --- /dev/null +++ b/libs/rs/driver/rsdProgramFragment.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RSD_PROGRAM_FRAGMENT_H +#define RSD_PROGRAM_FRAGMENT_H + +#include <rs_hal.h> + + +bool rsdProgramFragmentInit(const android::renderscript::Context *rsc, + const android::renderscript::ProgramFragment *, + const char* shader, uint32_t shaderLen); +void rsdProgramFragmentSetActive(const android::renderscript::Context *rsc, + const android::renderscript::ProgramFragment *); +void rsdProgramFragmentDestroy(const android::renderscript::Context *rsc, + const android::renderscript::ProgramFragment *); + + +#endif //RSD_PROGRAM_Fragment_H diff --git a/libs/rs/driver/rsdProgramVertex.h b/libs/rs/driver/rsdProgramVertex.h new file mode 100644 index 000000000000..e99857298165 --- /dev/null +++ b/libs/rs/driver/rsdProgramVertex.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RSD_PROGRAM_VERTEX_H +#define RSD_PROGRAM_VERTEX_H + +#include <rs_hal.h> + +bool rsdProgramVertexInit(const android::renderscript::Context *rsc, + const android::renderscript::ProgramVertex *, + const char* shader, uint32_t shaderLen); +void rsdProgramVertexSetActive(const android::renderscript::Context *rsc, + const android::renderscript::ProgramVertex *); +void rsdProgramVertexDestroy(const android::renderscript::Context *rsc, + const android::renderscript::ProgramVertex *); + + +#endif //RSD_PROGRAM_VERTEX_H diff --git a/libs/rs/driver/rsdRuntimeMath.cpp b/libs/rs/driver/rsdRuntimeMath.cpp index 093e311e5a3d..acb990d8c78b 100644 --- a/libs/rs/driver/rsdRuntimeMath.cpp +++ b/libs/rs/driver/rsdRuntimeMath.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/libs/rs/driver/rsdRuntimeStubs.cpp b/libs/rs/driver/rsdRuntimeStubs.cpp index b70a1232ef3d..9cbff9526b16 100644 --- a/libs/rs/driver/rsdRuntimeStubs.cpp +++ b/libs/rs/driver/rsdRuntimeStubs.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp new file mode 100644 index 000000000000..fc623d689dfd --- /dev/null +++ b/libs/rs/driver/rsdShader.cpp @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <rs_hal.h> +#include <rsContext.h> +#include <rsProgram.h> + +#include "rsdShader.h" +#include "rsdShaderCache.h" + +using namespace android; +using namespace android::renderscript; + +RsdShader::RsdShader(const Program *p, uint32_t type, + const char * shaderText, uint32_t shaderLength) { + + mUserShader.setTo(shaderText, shaderLength); + mRSProgram = p; + mType = type; + initMemberVars(); + initAttribAndUniformArray(); + init(); +} + +RsdShader::~RsdShader() { + if (mShaderID) { + glDeleteShader(mShaderID); + } + + delete[] mAttribNames; + delete[] mUniformNames; + delete[] mUniformArraySizes; +} + +void RsdShader::initMemberVars() { + mDirty = true; + mShaderID = 0; + mAttribCount = 0; + mUniformCount = 0; + + mAttribNames = NULL; + mUniformNames = NULL; + mUniformArraySizes = NULL; + + mIsValid = false; +} + +void RsdShader::init() { + uint32_t attribCount = 0; + uint32_t uniformCount = 0; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { + initAddUserElement(mRSProgram->mHal.state.inputElements[ct].get(), mAttribNames, NULL, &attribCount, RS_SHADER_ATTR); + } + for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { + initAddUserElement(mRSProgram->mHal.state.constantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI); + } + + mTextureUniformIndexStart = uniformCount; + char buf[256]; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) { + snprintf(buf, sizeof(buf), "UNI_Tex%i", ct); + mUniformNames[uniformCount].setTo(buf); + mUniformArraySizes[uniformCount] = 1; + uniformCount++; + } +} + +String8 RsdShader::getGLSLInputString() const { + String8 s; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { + const Element *e = mRSProgram->mHal.state.inputElements[ct].get(); + for (uint32_t field=0; field < e->getFieldCount(); field++) { + const Element *f = e->getField(field); + + // Cannot be complex + rsAssert(!f->getFieldCount()); + switch (f->getComponent().getVectorSize()) { + case 1: s.append("attribute float ATTRIB_"); break; + case 2: s.append("attribute vec2 ATTRIB_"); break; + case 3: s.append("attribute vec3 ATTRIB_"); break; + case 4: s.append("attribute vec4 ATTRIB_"); break; + default: + rsAssert(0); + } + + s.append(e->getFieldName(field)); + s.append(";\n"); + } + } + return s; +} + +void RsdShader::appendAttributes() { + for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { + const Element *e = mRSProgram->mHal.state.inputElements[ct].get(); + for (uint32_t field=0; field < e->getFieldCount(); field++) { + const Element *f = e->getField(field); + const char *fn = e->getFieldName(field); + + if (fn[0] == '#') { + continue; + } + + // Cannot be complex + rsAssert(!f->getFieldCount()); + switch (f->getComponent().getVectorSize()) { + case 1: mShader.append("attribute float ATTRIB_"); break; + case 2: mShader.append("attribute vec2 ATTRIB_"); break; + case 3: mShader.append("attribute vec3 ATTRIB_"); break; + case 4: mShader.append("attribute vec4 ATTRIB_"); break; + default: + rsAssert(0); + } + + mShader.append(fn); + mShader.append(";\n"); + } + } +} + +void RsdShader::appendTextures() { + char buf[256]; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) { + if (mRSProgram->mHal.state.textureTargets[ct] == RS_TEXTURE_2D) { + snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct); + } else { + snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct); + } + mShader.append(buf); + } +} + +bool RsdShader::createShader() { + + if (mType == GL_FRAGMENT_SHADER) { + mShader.append("precision mediump float;\n"); + } + appendUserConstants(); + appendAttributes(); + appendTextures(); + + mShader.append(mUserShader); + + return true; +} + +bool RsdShader::loadShader(const Context *rsc) { + mShaderID = glCreateShader(mType); + rsAssert(mShaderID); + + if (rsc->props.mLogShaders) { + LOGV("Loading shader type %x, ID %i", mType, mShaderID); + LOGV("%s", mShader.string()); + } + + if (mShaderID) { + const char * ss = mShader.string(); + glShaderSource(mShaderID, 1, &ss, NULL); + glCompileShader(mShaderID); + + GLint compiled = 0; + glGetShaderiv(mShaderID, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + GLint infoLen = 0; + glGetShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen) { + char* buf = (char*) malloc(infoLen); + if (buf) { + glGetShaderInfoLog(mShaderID, infoLen, NULL, buf); + LOGE("Could not compile shader \n%s\n", buf); + free(buf); + } + glDeleteShader(mShaderID); + mShaderID = 0; + rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,"); + return false; + } + } + } + + if (rsc->props.mLogShaders) { + LOGV("--Shader load result %x ", glGetError()); + } + mIsValid = true; + return true; +} + +void RsdShader::appendUserConstants() { + for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { + const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement(); + for (uint32_t field=0; field < e->getFieldCount(); field++) { + const Element *f = e->getField(field); + const char *fn = e->getFieldName(field); + + if (fn[0] == '#') { + continue; + } + + // Cannot be complex + rsAssert(!f->getFieldCount()); + if (f->getType() == RS_TYPE_MATRIX_4X4) { + mShader.append("uniform mat4 UNI_"); + } else if (f->getType() == RS_TYPE_MATRIX_3X3) { + mShader.append("uniform mat3 UNI_"); + } else if (f->getType() == RS_TYPE_MATRIX_2X2) { + mShader.append("uniform mat2 UNI_"); + } else { + switch (f->getComponent().getVectorSize()) { + case 1: mShader.append("uniform float UNI_"); break; + case 2: mShader.append("uniform vec2 UNI_"); break; + case 3: mShader.append("uniform vec3 UNI_"); break; + case 4: mShader.append("uniform vec4 UNI_"); break; + default: + rsAssert(0); + } + } + + mShader.append(fn); + if (e->getFieldArraySize(field) > 1) { + mShader.appendFormat("[%d]", e->getFieldArraySize(field)); + } + mShader.append(";\n"); + } + } +} + +void RsdShader::logUniform(const Element *field, const float *fd, uint32_t arraySize ) { + RsDataType dataType = field->getType(); + uint32_t elementSize = field->getSizeBytes() / sizeof(float); + for (uint32_t i = 0; i < arraySize; i ++) { + if (arraySize > 1) { + LOGV("Array Element [%u]", i); + } + if (dataType == RS_TYPE_MATRIX_4X4) { + LOGV("Matrix4x4"); + LOGV("{%f, %f, %f, %f", fd[0], fd[4], fd[8], fd[12]); + LOGV(" %f, %f, %f, %f", fd[1], fd[5], fd[9], fd[13]); + LOGV(" %f, %f, %f, %f", fd[2], fd[6], fd[10], fd[14]); + LOGV(" %f, %f, %f, %f}", fd[3], fd[7], fd[11], fd[15]); + } else if (dataType == RS_TYPE_MATRIX_3X3) { + LOGV("Matrix3x3"); + LOGV("{%f, %f, %f", fd[0], fd[3], fd[6]); + LOGV(" %f, %f, %f", fd[1], fd[4], fd[7]); + LOGV(" %f, %f, %f}", fd[2], fd[5], fd[8]); + } else if (dataType == RS_TYPE_MATRIX_2X2) { + LOGV("Matrix2x2"); + LOGV("{%f, %f", fd[0], fd[2]); + LOGV(" %f, %f}", fd[1], fd[3]); + } else { + switch (field->getComponent().getVectorSize()) { + case 1: + LOGV("Uniform 1 = %f", fd[0]); + break; + case 2: + LOGV("Uniform 2 = %f %f", fd[0], fd[1]); + break; + case 3: + LOGV("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]); + break; + case 4: + LOGV("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]); + break; + default: + rsAssert(0); + } + } + LOGE("Element size %u data=%p", elementSize, fd); + fd += elementSize; + LOGE("New data=%p", fd); + } +} + +void RsdShader::setUniform(const Context *rsc, const Element *field, const float *fd, + int32_t slot, uint32_t arraySize ) { + RsDataType dataType = field->getType(); + if (dataType == RS_TYPE_MATRIX_4X4) { + glUniformMatrix4fv(slot, arraySize, GL_FALSE, fd); + } else if (dataType == RS_TYPE_MATRIX_3X3) { + glUniformMatrix3fv(slot, arraySize, GL_FALSE, fd); + } else if (dataType == RS_TYPE_MATRIX_2X2) { + glUniformMatrix2fv(slot, arraySize, GL_FALSE, fd); + } else { + switch (field->getComponent().getVectorSize()) { + case 1: + glUniform1fv(slot, arraySize, fd); + break; + case 2: + glUniform2fv(slot, arraySize, fd); + break; + case 3: + glUniform3fv(slot, arraySize, fd); + break; + case 4: + glUniform4fv(slot, arraySize, fd); + break; + default: + rsAssert(0); + } + } +} + +void RsdShader::setupTextures(const Context *rsc, RsdShaderCache *sc) { + if (mRSProgram->mHal.state.texturesCount == 0) { + return; + } + + uint32_t numTexturesToBind = mRSProgram->mHal.state.texturesCount; + uint32_t numTexturesAvailable = rsc->getMaxFragmentTextures(); + if (numTexturesToBind >= numTexturesAvailable) { + LOGE("Attempting to bind %u textures on shader id %u, but only %u are available", + mRSProgram->mHal.state.texturesCount, (uint32_t)this, numTexturesAvailable); + rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind more textuers than available"); + numTexturesToBind = numTexturesAvailable; + } + + for (uint32_t ct=0; ct < numTexturesToBind; ct++) { + glActiveTexture(GL_TEXTURE0 + ct); + if (!mRSProgram->mHal.state.textures[ct].get()) { + LOGE("No texture bound for shader id %u, texture unit %u", (uint)this, ct); + rsc->setError(RS_ERROR_BAD_SHADER, "No texture bound"); + continue; + } + + GLenum target = (GLenum)mRSProgram->mHal.state.textures[ct]->getGLTarget(); + if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) { + LOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct); + rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader"); + } + glBindTexture(target, mRSProgram->mHal.state.textures[ct]->getTextureID()); + rsc->checkError("ProgramFragment::setupGL2 tex bind"); + if (mRSProgram->mHal.state.samplers[ct].get()) { + mRSProgram->mHal.state.samplers[ct]->setupGL(rsc, mRSProgram->mHal.state.textures[ct].get()); + } else { + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + rsc->checkError("ProgramFragment::setupGL2 tex env"); + } + + glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct); + rsc->checkError("ProgramFragment::setupGL2 uniforms"); + } + + glActiveTexture(GL_TEXTURE0); + mDirty = false; + rsc->checkError("ProgramFragment::setupGL2"); +} + +void RsdShader::setupUserConstants(const Context *rsc, RsdShaderCache *sc, bool isFragment) { + uint32_t uidx = 0; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { + Allocation *alloc = mRSProgram->mHal.state.constants[ct].get(); + if (!alloc) { + LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set", (uint32_t)this, ct); + rsc->setError(RS_ERROR_BAD_SHADER, "No constant allocation bound"); + continue; + } + + const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr()); + const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement(); + for (uint32_t field=0; field < e->getFieldCount(); field++) { + const Element *f = e->getField(field); + const char *fieldName = e->getFieldName(field); + // If this field is padding, skip it + if (fieldName[0] == '#') { + continue; + } + + uint32_t offset = e->getFieldOffsetBytes(field); + const float *fd = reinterpret_cast<const float *>(&data[offset]); + + int32_t slot = -1; + uint32_t arraySize = 1; + if (!isFragment) { + slot = sc->vtxUniformSlot(uidx); + arraySize = sc->vtxUniformSize(uidx); + } else { + slot = sc->fragUniformSlot(uidx); + arraySize = sc->fragUniformSize(uidx); + } + if (rsc->props.mLogShadersUniforms) { + LOGV("Uniform slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName); + } + uidx ++; + if (slot < 0) { + continue; + } + + if (rsc->props.mLogShadersUniforms) { + logUniform(f, fd, arraySize); + } + setUniform(rsc, f, fd, slot, arraySize); + } + } +} + +void RsdShader::setup(const android::renderscript::Context *rsc, RsdShaderCache *sc) { + + setupUserConstants(rsc, sc, mType == GL_FRAGMENT_SHADER); + setupTextures(rsc, sc); +} + +void RsdShader::initAttribAndUniformArray() { + mAttribCount = 0; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { + const Element *elem = mRSProgram->mHal.state.inputElements[ct].get(); + for (uint32_t field=0; field < elem->getFieldCount(); field++) { + if (elem->getFieldName(field)[0] != '#') { + mAttribCount ++; + } + } + } + + mUniformCount = 0; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { + const Element *elem = mRSProgram->mHal.state.constantTypes[ct]->getElement(); + + for (uint32_t field=0; field < elem->getFieldCount(); field++) { + if (elem->getFieldName(field)[0] != '#') { + mUniformCount ++; + } + } + } + mUniformCount += mRSProgram->mHal.state.texturesCount; + + if (mAttribCount) { + mAttribNames = new String8[mAttribCount]; + } + if (mUniformCount) { + mUniformNames = new String8[mUniformCount]; + mUniformArraySizes = new uint32_t[mUniformCount]; + } +} + +void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) { + rsAssert(e->getFieldCount()); + for (uint32_t ct=0; ct < e->getFieldCount(); ct++) { + const Element *ce = e->getField(ct); + if (ce->getFieldCount()) { + initAddUserElement(ce, names, arrayLengths, count, prefix); + } else if (e->getFieldName(ct)[0] != '#') { + String8 tmp(prefix); + tmp.append(e->getFieldName(ct)); + names[*count].setTo(tmp.string()); + if (arrayLengths) { + arrayLengths[*count] = e->getFieldArraySize(ct); + } + (*count)++; + } + } +} diff --git a/libs/rs/driver/rsdShader.h b/libs/rs/driver/rsdShader.h new file mode 100644 index 000000000000..37b1c3d0b496 --- /dev/null +++ b/libs/rs/driver/rsdShader.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_RSD_SHADER_H +#define ANDROID_RSD_SHADER_H + +#include <utils/String8.h> + +// --------------------------------------------------------------------------- +namespace android { +namespace renderscript { + +class Element; +class Context; +class Program; + +} +} + +class RsdShaderCache; + +#define RS_SHADER_ATTR "ATTRIB_" +#define RS_SHADER_UNI "UNI_" + +class RsdShader { +public: + + RsdShader(const android::renderscript::Program *p, uint32_t type, + const char * shaderText, uint32_t shaderLength); + virtual ~RsdShader(); + + bool createShader(); + + uint32_t getShaderID() const {return mShaderID;} + + uint32_t getAttribCount() const {return mAttribCount;} + uint32_t getUniformCount() const {return mUniformCount;} + const android::String8 & getAttribName(uint32_t i) const {return mAttribNames[i];} + const android::String8 & getUniformName(uint32_t i) const {return mUniformNames[i];} + uint32_t getUniformArraySize(uint32_t i) const {return mUniformArraySizes[i];} + + android::String8 getGLSLInputString() const; + + bool isValid() const {return mIsValid;} + void forceDirty() const {mDirty = true;} + + bool loadShader(const android::renderscript::Context *); + void setup(const android::renderscript::Context *, RsdShaderCache *sc); + +protected: + + const android::renderscript::Program *mRSProgram; + bool mIsValid; + + // Applies to vertex and fragment shaders only + void appendUserConstants(); + void setupUserConstants(const android::renderscript::Context *rsc, RsdShaderCache *sc, bool isFragment); + void initAddUserElement(const android::renderscript::Element *e, android::String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix); + void setupTextures(const android::renderscript::Context *rsc, RsdShaderCache *sc); + + void appendAttributes(); + void appendTextures(); + + void initAttribAndUniformArray(); + + mutable bool mDirty; + android::String8 mShader; + android::String8 mUserShader; + uint32_t mShaderID; + uint32_t mType; + + uint32_t mTextureCount; + uint32_t mAttribCount; + uint32_t mUniformCount; + android::String8 *mAttribNames; + android::String8 *mUniformNames; + uint32_t *mUniformArraySizes; + + int32_t mTextureUniformIndexStart; + + void logUniform(const android::renderscript::Element *field, const float *fd, uint32_t arraySize ); + void setUniform(const android::renderscript::Context *rsc, const android::renderscript::Element *field, const float *fd, int32_t slot, uint32_t arraySize ); + void initMemberVars(); + void init(); +}; + +#endif //ANDROID_RSD_SHADER_H + + + + diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/driver/rsdShaderCache.cpp index e8d89c21cb77..18a8225f0847 100644 --- a/libs/rs/rsShaderCache.cpp +++ b/libs/rs/driver/rsdShaderCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,25 +14,30 @@ * limitations under the License. */ -#include "rsContext.h" -#ifndef ANDROID_RS_SERIALIZE +#include <rs_hal.h> +#include <rsContext.h> + +#include "rsdShader.h" +#include "rsdShaderCache.h" + #include <GLES/gl.h> #include <GLES2/gl2.h> -#endif //ANDROID_RS_SERIALIZE using namespace android; using namespace android::renderscript; -ShaderCache::ShaderCache() { +RsdShaderCache::RsdShaderCache() { mEntries.setCapacity(16); + mVertexDirty = true; + mFragmentDirty = true; } -ShaderCache::~ShaderCache() { +RsdShaderCache::~RsdShaderCache() { cleanupAll(); } -void ShaderCache::updateUniformArrayData(Context *rsc, Program *prog, uint32_t linkedID, +void RsdShaderCache::updateUniformArrayData(const Context *rsc, RsdShader *prog, uint32_t linkedID, UniformData *data, const char* logTag, UniformQueryData **uniformList, uint32_t uniListSize) { @@ -54,14 +59,14 @@ void ShaderCache::updateUniformArrayData(Context *rsc, Program *prog, uint32_t l } } -void ShaderCache::populateUniformData(Program *prog, uint32_t linkedID, UniformData *data) { +void RsdShaderCache::populateUniformData(RsdShader *prog, uint32_t linkedID, UniformData *data) { for (uint32_t ct=0; ct < prog->getUniformCount(); ct++) { data[ct].slot = glGetUniformLocation(linkedID, prog->getUniformName(ct)); data[ct].arraySize = prog->getUniformArraySize(ct); } } -bool ShaderCache::hasArrayUniforms(ProgramVertex *vtx, ProgramFragment *frag) { +bool RsdShaderCache::hasArrayUniforms(RsdShader *vtx, RsdShader *frag) { UniformData *data = mCurrent->vtxUniforms; for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) { if (data[ct].slot >= 0 && data[ct].arraySize > 1) { @@ -77,7 +82,31 @@ bool ShaderCache::hasArrayUniforms(ProgramVertex *vtx, ProgramFragment *frag) { return false; } -bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag) { +bool RsdShaderCache::setup(const Context *rsc) { + if (!mVertexDirty && !mFragmentDirty) { + return true; + } + + if (!link(rsc)) { + return false; + } + + if (mFragmentDirty) { + mFragment->setup(rsc, this); + mFragmentDirty = false; + } + if (mVertexDirty) { + mVertex->setup(rsc, this); + mVertexDirty = false; + } + + return true; +} + +bool RsdShaderCache::link(const Context *rsc) { + + RsdShader *vtx = mVertex; + RsdShader *frag = mFragment; if (!vtx->getShaderID()) { vtx->loadShader(rsc); } @@ -89,7 +118,7 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag if (!vtx->getShaderID() || !frag->getShaderID()) { return false; } - //LOGV("ShaderCache lookup vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID()); + //LOGV("rsdShaderCache lookup vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID()); uint32_t entryCount = mEntries.size(); for (uint32_t ct = 0; ct < entryCount; ct ++) { if ((mEntries[ct]->vtx == vtx->getShaderID()) && @@ -98,13 +127,13 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag //LOGV("SC using program %i", mEntries[ct]->program); glUseProgram(mEntries[ct]->program); mCurrent = mEntries[ct]; - //LOGV("ShaderCache hit, using %i", ct); - rsc->checkError("ShaderCache::lookup (hit)"); + //LOGV("RsdShaderCache hit, using %i", ct); + rsc->checkError("RsdShaderCache::link (hit)"); return true; } } - //LOGV("ShaderCache miss"); + //LOGV("RsdShaderCache miss"); //LOGE("e0 %x", glGetError()); ProgramEntry *e = new ProgramEntry(vtx->getAttribCount(), vtx->getUniformCount(), @@ -120,12 +149,10 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag //LOGE("e1 %x", glGetError()); glAttachShader(pgm, frag->getShaderID()); - if (!vtx->isUserProgram()) { - glBindAttribLocation(pgm, 0, "ATTRIB_position"); - glBindAttribLocation(pgm, 1, "ATTRIB_color"); - glBindAttribLocation(pgm, 2, "ATTRIB_normal"); - glBindAttribLocation(pgm, 3, "ATTRIB_texture0"); - } + glBindAttribLocation(pgm, 0, "ATTRIB_position"); + glBindAttribLocation(pgm, 1, "ATTRIB_color"); + glBindAttribLocation(pgm, 2, "ATTRIB_normal"); + glBindAttribLocation(pgm, 3, "ATTRIB_texture0"); //LOGE("e2 %x", glGetError()); glLinkProgram(pgm); @@ -203,11 +230,12 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag //LOGV("SC made program %i", e->program); glUseProgram(e->program); - rsc->checkError("ShaderCache::lookup (miss)"); + rsc->checkError("RsdShaderCache::link (miss)"); + return true; } -int32_t ShaderCache::vtxAttribSlot(const String8 &attrName) const { +int32_t RsdShaderCache::vtxAttribSlot(const String8 &attrName) const { for (uint32_t ct=0; ct < mCurrent->vtxAttrCount; ct++) { if (attrName == mCurrent->vtxAttrs[ct].name) { return mCurrent->vtxAttrs[ct].slot; @@ -216,7 +244,7 @@ int32_t ShaderCache::vtxAttribSlot(const String8 &attrName) const { return -1; } -void ShaderCache::cleanupVertex(uint32_t id) { +void RsdShaderCache::cleanupVertex(uint32_t id) { int32_t numEntries = (int32_t)mEntries.size(); for (int32_t ct = 0; ct < numEntries; ct ++) { if (mEntries[ct]->vtx == id) { @@ -230,7 +258,7 @@ void ShaderCache::cleanupVertex(uint32_t id) { } } -void ShaderCache::cleanupFragment(uint32_t id) { +void RsdShaderCache::cleanupFragment(uint32_t id) { int32_t numEntries = (int32_t)mEntries.size(); for (int32_t ct = 0; ct < numEntries; ct ++) { if (mEntries[ct]->frag == id) { @@ -244,7 +272,7 @@ void ShaderCache::cleanupFragment(uint32_t id) { } } -void ShaderCache::cleanupAll() { +void RsdShaderCache::cleanupAll() { for (uint32_t ct=0; ct < mEntries.size(); ct++) { glDeleteProgram(mEntries[ct]->program); free(mEntries[ct]); diff --git a/libs/rs/rsShaderCache.h b/libs/rs/driver/rsdShaderCache.h index 354036697e90..17ee3e83769f 100644 --- a/libs/rs/rsShaderCache.h +++ b/libs/rs/driver/rsdShaderCache.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,38 +14,59 @@ * limitations under the License. */ -#ifndef ANDROID_SHADER_CACHE_H -#define ANDROID_SHADER_CACHE_H +#ifndef ANDROID_RSD_SHADER_CACHE_H +#define ANDROID_RSD_SHADER_CACHE_H - -#include "rsObjectBase.h" -#include "rsVertexArray.h" - -// --------------------------------------------------------------------------- namespace android { namespace renderscript { +class Context; + +} +} + +#include <utils/String8.h> +#include <utils/Vector.h> +class RsdShader; + +// --------------------------------------------------------------------------- // An element is a group of Components that occupies one cell in a structure. -class ShaderCache { +class RsdShaderCache { public: - ShaderCache(); - virtual ~ShaderCache(); + RsdShaderCache(); + virtual ~RsdShaderCache(); + + void setActiveVertex(RsdShader *pv) { + mVertexDirty = true; + mVertex = pv; + } - bool lookup(Context *rsc, ProgramVertex *, ProgramFragment *); + void setActiveFragment(RsdShader *pf) { + mFragmentDirty = true; + mFragment = pf; + } + + bool setup(const android::renderscript::Context *rsc); void cleanupVertex(uint32_t id); void cleanupFragment(uint32_t id); void cleanupAll(); - int32_t vtxAttribSlot(const String8 &attrName) const; + int32_t vtxAttribSlot(const android::String8 &attrName) const; int32_t vtxUniformSlot(uint32_t a) const {return mCurrent->vtxUniforms[a].slot;} uint32_t vtxUniformSize(uint32_t a) const {return mCurrent->vtxUniforms[a].arraySize;} int32_t fragUniformSlot(uint32_t a) const {return mCurrent->fragUniforms[a].slot;} uint32_t fragUniformSize(uint32_t a) const {return mCurrent->fragUniforms[a].arraySize;} protected: + bool link(const android::renderscript::Context *rsc); + bool mFragmentDirty; + bool mVertexDirty; + RsdShader *mVertex; + RsdShader *mFragment; + struct UniformQueryData { char *name; uint32_t nameLength; @@ -111,21 +132,19 @@ protected: UniformData *vtxUniforms; UniformData *fragUniforms; }; - Vector<ProgramEntry*> mEntries; + android::Vector<ProgramEntry*> mEntries; ProgramEntry *mCurrent; - bool hasArrayUniforms(ProgramVertex *vtx, ProgramFragment *frag); - void populateUniformData(Program *prog, uint32_t linkedID, UniformData *data); - void updateUniformArrayData(Context *rsc, Program *prog, uint32_t linkedID, + bool hasArrayUniforms(RsdShader *vtx, RsdShader *frag); + void populateUniformData(RsdShader *prog, uint32_t linkedID, UniformData *data); + void updateUniformArrayData(const android::renderscript::Context *rsc, + RsdShader *prog, uint32_t linkedID, UniformData *data, const char* logTag, UniformQueryData **uniformList, uint32_t uniListSize); }; - -} -} -#endif //ANDROID_SHADER_CACHE_H +#endif //ANDROID_RSD_SHADER_CACHE_H diff --git a/libs/rs/rsVertexArray.cpp b/libs/rs/driver/rsdVertexArray.cpp index 354ee89f7c5b..d0a5a54b569f 100644 --- a/libs/rs/rsVertexArray.cpp +++ b/libs/rs/driver/rsdVertexArray.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,28 +14,32 @@ * limitations under the License. */ -#include "rsContext.h" -#ifndef ANDROID_RS_SERIALIZE +#include <rs_hal.h> +#include <rsContext.h> + #include <GLES/gl.h> #include <GLES2/gl2.h> -#endif + +#include "rsdCore.h" +#include "rsdVertexArray.h" +#include "rsdShaderCache.h" using namespace android; using namespace android::renderscript; -VertexArray::VertexArray(const Attrib *attribs, uint32_t numAttribs) { +RsdVertexArray::RsdVertexArray(const Attrib *attribs, uint32_t numAttribs) { mAttribs = attribs; mCount = numAttribs; } -VertexArray::~VertexArray() { +RsdVertexArray::~RsdVertexArray() { } -VertexArray::Attrib::Attrib() { +RsdVertexArray::Attrib::Attrib() { clear(); } -void VertexArray::Attrib::clear() { +void RsdVertexArray::Attrib::clear() { buffer = 0; offset = 0; type = 0; @@ -46,7 +50,7 @@ void VertexArray::Attrib::clear() { name.setTo(""); } -void VertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride, +void RsdVertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride, bool normalized, uint32_t offset, const char *name) { clear(); @@ -58,7 +62,7 @@ void VertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride, this->name.setTo(name); } -void VertexArray::logAttrib(uint32_t idx, uint32_t slot) const { +void RsdVertexArray::logAttrib(uint32_t idx, uint32_t slot) const { if (idx == 0) { LOGV("Starting vertex attribute binding"); } @@ -74,11 +78,15 @@ void VertexArray::logAttrib(uint32_t idx, uint32_t slot) const { mAttribs[idx].offset); } -void VertexArray::setupGL2(const Context *rsc, - class VertexArrayState *state, - ShaderCache *sc) const { - rsc->checkError("VertexArray::setupGL2 start"); +void RsdVertexArray::setupGL2(const Context *rsc) const { + + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + RsdVertexArrayState *state = dc->gl.vertexArrayState; + RsdShaderCache *sc = dc->gl.shaderCache; + + rsc->checkError("RsdVertexArray::setupGL2 start"); uint32_t maxAttrs = state->mAttrsEnabledSize; + for (uint32_t ct=1; ct < maxAttrs; ct++) { if(state->mAttrsEnabled[ct]) { glDisableVertexAttribArray(ct); @@ -86,7 +94,7 @@ void VertexArray::setupGL2(const Context *rsc, } } - rsc->checkError("VertexArray::setupGL2 disabled"); + rsc->checkError("RsdVertexArray::setupGL2 disabled"); for (uint32_t ct=0; ct < mCount; ct++) { int32_t slot = sc->vtxAttribSlot(mAttribs[ct].name); if (rsc->props.mLogShadersAttr) { @@ -105,22 +113,22 @@ void VertexArray::setupGL2(const Context *rsc, mAttribs[ct].stride, mAttribs[ct].ptr + mAttribs[ct].offset); } - rsc->checkError("VertexArray::setupGL2 done"); + rsc->checkError("RsdVertexArray::setupGL2 done"); } //////////////////////////////////////////// -VertexArrayState::VertexArrayState() { +RsdVertexArrayState::RsdVertexArrayState() { mAttrsEnabled = NULL; mAttrsEnabledSize = 0; } -VertexArrayState::~VertexArrayState() { +RsdVertexArrayState::~RsdVertexArrayState() { if (mAttrsEnabled) { delete[] mAttrsEnabled; mAttrsEnabled = NULL; } } -void VertexArrayState::init(Context *rsc) { - mAttrsEnabledSize = rsc->getMaxVertexAttributes(); +void RsdVertexArrayState::init(uint32_t maxAttrs) { + mAttrsEnabledSize = maxAttrs; mAttrsEnabled = new bool[mAttrsEnabledSize]; for (uint32_t ct = 0; ct < mAttrsEnabledSize; ct++) { mAttrsEnabled[ct] = false; diff --git a/libs/rs/rsVertexArray.h b/libs/rs/driver/rsdVertexArray.h index 45d9e82ab108..925a6aebfb76 100644 --- a/libs/rs/rsVertexArray.h +++ b/libs/rs/driver/rsdVertexArray.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,20 +14,21 @@ * limitations under the License. */ -#ifndef ANDROID_VERTEX_ARRAY_H -#define ANDROID_VERTEX_ARRAY_H +#ifndef ANDROID_RSD_VERTEX_ARRAY_H +#define ANDROID_RSD_VERTEX_ARRAY_H - -#include "rsObjectBase.h" - -// --------------------------------------------------------------------------- namespace android { namespace renderscript { -class ShaderCache; +class Context; + +} +} + +#include <utils/String8.h> // An element is a group of Components that occupies one cell in a structure. -class VertexArray { +class RsdVertexArray { public: class Attrib { public: @@ -38,17 +39,17 @@ public: uint32_t size; uint32_t stride; bool normalized; - String8 name; + android::String8 name; Attrib(); void clear(); void set(uint32_t type, uint32_t size, uint32_t stride, bool normalized, uint32_t offset, const char *name); }; - VertexArray(const Attrib *attribs, uint32_t numAttribs); - virtual ~VertexArray(); + RsdVertexArray(const Attrib *attribs, uint32_t numAttribs); + virtual ~RsdVertexArray(); - void setupGL2(const Context *rsc, class VertexArrayState *, ShaderCache *) const; + void setupGL2(const android::renderscript::Context *rsc) const; void logAttrib(uint32_t idx, uint32_t slot) const; protected: @@ -61,20 +62,18 @@ protected: }; -class VertexArrayState { +class RsdVertexArrayState { public: - VertexArrayState(); - ~VertexArrayState(); - void init(Context *); + RsdVertexArrayState(); + ~RsdVertexArrayState(); + void init(uint32_t maxAttrs); bool *mAttrsEnabled; uint32_t mAttrsEnabledSize; }; -} -} -#endif //ANDROID_VERTEX_ARRAY_H +#endif //ANDROID_RSD_VERTEX_ARRAY_H diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp index 4321592ec7ab..6d63f673f5b1 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -215,15 +215,11 @@ void Context::timerPrint() { } bool Context::setupCheck() { - if (!mShaderCache.lookup(this, mVertex.get(), mFragment.get())) { - LOGE("Context::setupCheck() 1 fail"); - return false; - } mFragmentStore->setup(this, &mStateFragmentStore); - mFragment->setupGL2(this, &mStateFragment, &mShaderCache); + mFragment->setupGL2(this, &mStateFragment); mRaster->setup(this, &mStateRaster); - mVertex->setupGL2(this, &mStateVertex, &mShaderCache); + mVertex->setupGL2(this, &mStateVertex); mFBOCache.setupGL2(this); return true; } @@ -295,7 +291,6 @@ void * Context::threadProc(void *vrsc) { rsc->setProgramStore(NULL); rsc->mStateFont.init(rsc); rsc->setFont(NULL); - rsc->mStateVertexArray.init(rsc); } rsc->mRunning = true; @@ -356,7 +351,6 @@ void Context::destroyWorkerThreadResources() { mStateFragment.deinit(this); mStateFragmentStore.deinit(this); mStateFont.deinit(this); - mShaderCache.cleanupAll(); } //LOGV("destroyWorkerThreadResources 2"); mExit = true; diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h index df85a6bc9283..107f63926a56 100644 --- a/libs/rs/rsContext.h +++ b/libs/rs/rsContext.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,9 +37,7 @@ #include "rsProgramStore.h" #include "rsProgramRaster.h" #include "rsProgramVertex.h" -#include "rsShaderCache.h" #include "rsFBOCache.h" -#include "rsVertexArray.h" #include "rsgApiStructs.h" #include "rsLocklessFifo.h" @@ -111,11 +109,9 @@ public: ProgramStoreState mStateFragmentStore; ProgramRasterState mStateRaster; ProgramVertexState mStateVertex; - VertexArrayState mStateVertexArray; FontState mStateFont; ScriptCState mScriptC; - ShaderCache mShaderCache; FBOCache mFBOCache; void swapBuffers(); diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp index b7b85b68372a..5e47ddb17536 100644 --- a/libs/rs/rsFont.cpp +++ b/libs/rs/rsFont.cpp @@ -25,11 +25,6 @@ #include FT_FREETYPE_H #include FT_BITMAP_H -#include <GLES/gl.h> -#include <GLES/glext.h> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> - using namespace android; using namespace android::renderscript; @@ -457,7 +452,7 @@ bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *r // This will dirty the texture and the shader so next time // we draw it will upload the data - mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT); + mTextTexture->deferredUploadToTexture(mRSC); mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get()); // Some debug code @@ -568,7 +563,6 @@ void FontState::initVertexArrayBuffers() { } indexAlloc->deferredUploadToBufferObject(mRSC); - mIndexBuffer.set(indexAlloc); const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3); const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2); @@ -585,7 +579,10 @@ void FontState::initVertexArrayBuffers() { Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX); mTextMeshPtr = (float*)vertexAlloc->getPtr(); - mVertexArray.set(vertexAlloc); + mMesh.set(new Mesh(mRSC, 1, 1)); + mMesh->setVertexBuffer(vertexAlloc, 0); + mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0); + mMesh->init(); } // We don't want to allocate anything unless we actually draw text @@ -625,18 +622,7 @@ void FontState::issueDrawCommand() { return; } - float *vtx = (float*)mVertexArray->getPtr(); - float *tex = vtx + 3; - - VertexArray::Attrib attribs[2]; - attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position"); - attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0"); - VertexArray va(attribs, 2); - va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache); - - mIndexBuffer->uploadCheck(mRSC); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID()); - glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0)); + mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6); } void FontState::appendMeshQuad(float x1, float y1, float z1, @@ -787,8 +773,7 @@ void FontState::deinit(Context *rsc) { mFontShaderFConstant.clear(); - mIndexBuffer.clear(); - mVertexArray.clear(); + mMesh.clear(); mFontShaderF.clear(); mFontSampler.clear(); diff --git a/libs/rs/rsFont.h b/libs/rs/rsFont.h index 91a5da90d067..d18c0d91566d 100644 --- a/libs/rs/rsFont.h +++ b/libs/rs/rsFont.h @@ -230,9 +230,7 @@ protected: uint32_t mMaxNumberOfQuads; void initVertexArrayBuffers(); - ObjectBaseRef<Allocation> mIndexBuffer; - ObjectBaseRef<Allocation> mVertexArray; - + ObjectBaseRef<Mesh> mMesh; bool mInitialized; diff --git a/libs/rs/rsMesh.cpp b/libs/rs/rsMesh.cpp index e29c80028192..ed29063ab2e1 100644 --- a/libs/rs/rsMesh.cpp +++ b/libs/rs/rsMesh.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,46 +15,53 @@ */ #include "rsContext.h" -#ifndef ANDROID_RS_SERIALIZE -#include <GLES/gl.h> -#include <GLES2/gl2.h> -#include <GLES/glext.h> -#endif using namespace android; using namespace android::renderscript; Mesh::Mesh(Context *rsc) : ObjectBase(rsc) { - mPrimitives = NULL; - mPrimitivesCount = 0; - mVertexBuffers = NULL; - mVertexBufferCount = 0; - -#ifndef ANDROID_RS_SERIALIZE - mAttribs = NULL; - mAttribAllocationIndex = NULL; + mHal.drv = NULL; + mHal.state.primitives = NULL; + mHal.state.primitivesCount = 0; + mHal.state.vertexBuffers = NULL; + mHal.state.vertexBuffersCount = 0; + mInitialized = false; +} - mAttribCount = 0; -#endif +Mesh::Mesh(Context *rsc, + uint32_t vertexBuffersCount, + uint32_t primitivesCount) : ObjectBase(rsc) { + mHal.drv = NULL; + mHal.state.primitivesCount = primitivesCount; + mHal.state.primitives = new Primitive_t *[mHal.state.primitivesCount]; + for (uint32_t i = 0; i < mHal.state.primitivesCount; i ++) { + mHal.state.primitives[i] = new Primitive_t; + } + mHal.state.vertexBuffersCount = vertexBuffersCount; + mHal.state.vertexBuffers = new ObjectBaseRef<Allocation>[mHal.state.vertexBuffersCount]; } Mesh::~Mesh() { - if (mVertexBuffers) { - delete[] mVertexBuffers; +#ifndef ANDROID_RS_SERIALIZE + mRSC->mHal.funcs.mesh.destroy(mRSC, this); +#endif + + if (mHal.state.vertexBuffers) { + delete[] mHal.state.vertexBuffers; } - if (mPrimitives) { - for (uint32_t i = 0; i < mPrimitivesCount; i ++) { - delete mPrimitives[i]; + if (mHal.state.primitives) { + for (uint32_t i = 0; i < mHal.state.primitivesCount; i ++) { + mHal.state.primitives[i]->mIndexBuffer.clear(); + delete mHal.state.primitives[i]; } - delete[] mPrimitives; + delete[] mHal.state.primitives; } +} +void Mesh::init() { #ifndef ANDROID_RS_SERIALIZE - if (mAttribs) { - delete[] mAttribs; - delete[] mAttribAllocationIndex; - } + mRSC->mHal.funcs.mesh.init(mRSC, this); #endif } @@ -66,15 +73,15 @@ void Mesh::serialize(OStream *stream) const { stream->addString(&name); // Store number of vertex streams - stream->addU32(mVertexBufferCount); - for (uint32_t vCount = 0; vCount < mVertexBufferCount; vCount ++) { - mVertexBuffers[vCount]->serialize(stream); + stream->addU32(mHal.state.vertexBuffersCount); + for (uint32_t vCount = 0; vCount < mHal.state.vertexBuffersCount; vCount ++) { + mHal.state.vertexBuffers[vCount]->serialize(stream); } - stream->addU32(mPrimitivesCount); + stream->addU32(mHal.state.primitivesCount); // Store the primitives - for (uint32_t pCount = 0; pCount < mPrimitivesCount; pCount ++) { - Primitive_t * prim = mPrimitives[pCount]; + for (uint32_t pCount = 0; pCount < mHal.state.primitivesCount; pCount ++) { + Primitive_t * prim = mHal.state.primitives[pCount]; stream->addU8((uint8_t)prim->mPrimitive); @@ -95,213 +102,119 @@ Mesh *Mesh::createFromStream(Context *rsc, IStream *stream) { return NULL; } - Mesh * mesh = new Mesh(rsc); - String8 name; stream->loadString(&name); - mesh->setName(name.string(), name.size()); - mesh->mVertexBufferCount = stream->loadU32(); - if (mesh->mVertexBufferCount) { - mesh->mVertexBuffers = new ObjectBaseRef<Allocation>[mesh->mVertexBufferCount]; + uint32_t vertexBuffersCount = stream->loadU32(); + ObjectBaseRef<Allocation> *vertexBuffers = NULL; + if (vertexBuffersCount) { + vertexBuffers = new ObjectBaseRef<Allocation>[vertexBuffersCount]; - for (uint32_t vCount = 0; vCount < mesh->mVertexBufferCount; vCount ++) { + for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) { Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream); - mesh->mVertexBuffers[vCount].set(vertexAlloc); + vertexBuffers[vCount].set(vertexAlloc); } } - mesh->mPrimitivesCount = stream->loadU32(); - if (mesh->mPrimitivesCount) { - mesh->mPrimitives = new Primitive_t *[mesh->mPrimitivesCount]; + uint32_t primitivesCount = stream->loadU32(); + ObjectBaseRef<Allocation> *indexBuffers = NULL; + RsPrimitive *primitives = NULL; + if (primitivesCount) { + indexBuffers = new ObjectBaseRef<Allocation>[primitivesCount]; + primitives = new RsPrimitive[primitivesCount]; // load all primitives - for (uint32_t pCount = 0; pCount < mesh->mPrimitivesCount; pCount ++) { - Primitive_t * prim = new Primitive_t; - mesh->mPrimitives[pCount] = prim; - - prim->mPrimitive = (RsPrimitive)stream->loadU8(); + for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) { + primitives[pCount] = (RsPrimitive)stream->loadU8(); // Check to see if the index buffer was stored uint32_t isIndexPresent = stream->loadU32(); if (isIndexPresent) { Allocation *indexAlloc = Allocation::createFromStream(rsc, stream); - prim->mIndexBuffer.set(indexAlloc); + indexBuffers[pCount].set(indexAlloc); } } } -#ifndef ANDROID_RS_SERIALIZE - mesh->updateGLPrimitives(); - mesh->initVertexAttribs(); - mesh->uploadAll(rsc); -#endif - return mesh; -} - -#ifndef ANDROID_RS_SERIALIZE - -bool Mesh::isValidGLComponent(const Element *elem, uint32_t fieldIdx) { - // Do not create attribs for padding - if (elem->getFieldName(fieldIdx)[0] == '#') { - return false; - } - - // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted. - // Filter rs types accordingly - RsDataType dt = elem->getField(fieldIdx)->getComponent().getType(); - if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 && - dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 && - dt != RS_TYPE_SIGNED_16) { - return false; - } - - // Now make sure they are not arrays - uint32_t arraySize = elem->getFieldArraySize(fieldIdx); - if (arraySize != 1) { - return false; + Mesh *mesh = new Mesh(rsc, vertexBuffersCount, primitivesCount); + mesh->setName(name.string(), name.size()); + for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) { + mesh->setVertexBuffer(vertexBuffers[vCount].get(), vCount); } - - return true; -} - -void Mesh::initVertexAttribs() { - // Count the number of gl attrs to initialize - mAttribCount = 0; - for (uint32_t ct=0; ct < mVertexBufferCount; ct++) { - const Element *elem = mVertexBuffers[ct]->getType()->getElement(); - for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) { - if (isValidGLComponent(elem, ct)) { - mAttribCount ++; - } - } + for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) { + mesh->setPrimitive(indexBuffers[pCount].get(), primitives[pCount], pCount); } - if (mAttribs) { - delete [] mAttribs; - delete [] mAttribAllocationIndex; - mAttribs = NULL; - mAttribAllocationIndex = NULL; + // Cleanup + if (vertexBuffersCount) { + delete[] vertexBuffers; } - if (!mAttribCount) { - return; + if (primitivesCount) { + delete[] indexBuffers; + delete[] primitives; } - mAttribs = new VertexArray::Attrib[mAttribCount]; - mAttribAllocationIndex = new uint32_t[mAttribCount]; - - uint32_t userNum = 0; - for (uint32_t ct=0; ct < mVertexBufferCount; ct++) { - const Element *elem = mVertexBuffers[ct]->getType()->getElement(); - uint32_t stride = elem->getSizeBytes(); - for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) { - const Component &c = elem->getField(fieldI)->getComponent(); - - if (!isValidGLComponent(elem, fieldI)) { - continue; - } - - mAttribs[userNum].size = c.getVectorSize(); - mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI); - mAttribs[userNum].type = c.getGLType(); - mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized(); - mAttribs[userNum].stride = stride; - String8 tmp(RS_SHADER_ATTR); - tmp.append(elem->getFieldName(fieldI)); - mAttribs[userNum].name.setTo(tmp.string()); - - // Remember which allocation this attribute came from - mAttribAllocationIndex[userNum] = ct; - userNum ++; - } - } +#ifndef ANDROID_RS_SERIALIZE + mesh->init(); + mesh->uploadAll(rsc); +#endif + return mesh; } +#ifndef ANDROID_RS_SERIALIZE + void Mesh::render(Context *rsc) const { - for (uint32_t ct = 0; ct < mPrimitivesCount; ct ++) { + for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) { renderPrimitive(rsc, ct); } } void Mesh::renderPrimitive(Context *rsc, uint32_t primIndex) const { - if (primIndex >= mPrimitivesCount) { + if (primIndex >= mHal.state.primitivesCount) { LOGE("Invalid primitive index"); return; } - Primitive_t *prim = mPrimitives[primIndex]; + Primitive_t *prim = mHal.state.primitives[primIndex]; if (prim->mIndexBuffer.get()) { renderPrimitiveRange(rsc, primIndex, 0, prim->mIndexBuffer->getType()->getDimX()); return; } - renderPrimitiveRange(rsc, primIndex, 0, mVertexBuffers[0]->getType()->getDimX()); + renderPrimitiveRange(rsc, primIndex, 0, mHal.state.vertexBuffers[0]->getType()->getDimX()); } void Mesh::renderPrimitiveRange(Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const { - if (len < 1 || primIndex >= mPrimitivesCount || mAttribCount == 0) { + if (len < 1 || primIndex >= mHal.state.primitivesCount) { LOGE("Invalid mesh or parameters"); return; } - rsc->checkError("Mesh::renderPrimitiveRange 1"); - for (uint32_t ct=0; ct < mVertexBufferCount; ct++) { - mVertexBuffers[ct]->uploadCheck(rsc); + for (uint32_t ct=0; ct < mHal.state.vertexBuffersCount; ct++) { + mHal.state.vertexBuffers[ct]->uploadCheck(rsc); } - // update attributes with either buffer information or data ptr based on their current state - for (uint32_t ct=0; ct < mAttribCount; ct++) { - uint32_t allocIndex = mAttribAllocationIndex[ct]; - Allocation *alloc = mVertexBuffers[allocIndex].get(); - if (alloc->getIsBufferObject()) { - mAttribs[ct].buffer = alloc->getBufferObjectID(); - mAttribs[ct].ptr = NULL; - } else { - mAttribs[ct].buffer = 0; - mAttribs[ct].ptr = (const uint8_t*)alloc->getPtr(); - } - } - - VertexArray va(mAttribs, mAttribCount); - va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache); - rsc->checkError("Mesh::renderPrimitiveRange 2"); - Primitive_t *prim = mPrimitives[primIndex]; + Primitive_t *prim = mHal.state.primitives[primIndex]; if (prim->mIndexBuffer.get()) { prim->mIndexBuffer->uploadCheck(rsc); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prim->mIndexBuffer->getBufferObjectID()); - glDrawElements(prim->mGLPrimitive, len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2)); - } else { - glDrawArrays(prim->mGLPrimitive, start, len); } + rsc->checkError("Mesh::renderPrimitiveRange upload check"); - rsc->checkError("Mesh::renderPrimitiveRange"); + mRSC->mHal.funcs.mesh.draw(mRSC, this, primIndex, start, len); + rsc->checkError("Mesh::renderPrimitiveRange draw"); } - void Mesh::uploadAll(Context *rsc) { - for (uint32_t ct = 0; ct < mVertexBufferCount; ct ++) { - if (mVertexBuffers[ct].get()) { - mVertexBuffers[ct]->deferredUploadToBufferObject(rsc); + for (uint32_t ct = 0; ct < mHal.state.vertexBuffersCount; ct ++) { + if (mHal.state.vertexBuffers[ct].get()) { + mHal.state.vertexBuffers[ct]->deferredUploadToBufferObject(rsc); } } - for (uint32_t ct = 0; ct < mPrimitivesCount; ct ++) { - if (mPrimitives[ct]->mIndexBuffer.get()) { - mPrimitives[ct]->mIndexBuffer->deferredUploadToBufferObject(rsc); - } - } -} - -void Mesh::updateGLPrimitives() { - for (uint32_t i = 0; i < mPrimitivesCount; i ++) { - switch (mPrimitives[i]->mPrimitive) { - case RS_PRIMITIVE_POINT: mPrimitives[i]->mGLPrimitive = GL_POINTS; break; - case RS_PRIMITIVE_LINE: mPrimitives[i]->mGLPrimitive = GL_LINES; break; - case RS_PRIMITIVE_LINE_STRIP: mPrimitives[i]->mGLPrimitive = GL_LINE_STRIP; break; - case RS_PRIMITIVE_TRIANGLE: mPrimitives[i]->mGLPrimitive = GL_TRIANGLES; break; - case RS_PRIMITIVE_TRIANGLE_STRIP: mPrimitives[i]->mGLPrimitive = GL_TRIANGLE_STRIP; break; - case RS_PRIMITIVE_TRIANGLE_FAN: mPrimitives[i]->mGLPrimitive = GL_TRIANGLE_FAN; break; + for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) { + if (mHal.state.primitives[ct]->mIndexBuffer.get()) { + mHal.state.primitives[ct]->mIndexBuffer->deferredUploadToBufferObject(rsc); } } } @@ -312,8 +225,8 @@ void Mesh::computeBBox() { uint32_t stride = 0; uint32_t numVerts = 0; // First we need to find the position ptr and stride - for (uint32_t ct=0; ct < mVertexBufferCount; ct++) { - const Type *bufferType = mVertexBuffers[ct]->getType(); + for (uint32_t ct=0; ct < mHal.state.vertexBuffersCount; ct++) { + const Type *bufferType = mHal.state.vertexBuffers[ct]->getType(); const Element *bufferElem = bufferType->getElement(); for (uint32_t ct=0; ct < bufferElem->getFieldCount(); ct++) { @@ -321,7 +234,7 @@ void Mesh::computeBBox() { vectorSize = bufferElem->getField(ct)->getComponent().getVectorSize(); stride = bufferElem->getSizeBytes() / sizeof(float); uint32_t offset = bufferElem->getFieldOffsetBytes(ct); - posPtr = (float*)((uint8_t*)mVertexBuffers[ct]->getPtr() + offset); + posPtr = (float*)((uint8_t*)mHal.state.vertexBuffers[ct]->getPtr() + offset); numVerts = bufferType->getDimX(); break; } @@ -353,73 +266,62 @@ namespace android { namespace renderscript { RsMesh rsi_MeshCreate(Context *rsc, uint32_t vtxCount, uint32_t idxCount) { - Mesh *sm = new Mesh(rsc); + Mesh *sm = new Mesh(rsc, vtxCount, idxCount); sm->incUserRef(); - sm->mPrimitivesCount = idxCount; - sm->mPrimitives = new Mesh::Primitive_t *[sm->mPrimitivesCount]; - for (uint32_t ct = 0; ct < idxCount; ct ++) { - sm->mPrimitives[ct] = new Mesh::Primitive_t; - } - - sm->mVertexBufferCount = vtxCount; - sm->mVertexBuffers = new ObjectBaseRef<Allocation>[vtxCount]; - return sm; } void rsi_MeshBindVertex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t slot) { Mesh *sm = static_cast<Mesh *>(mv); - rsAssert(slot < sm->mVertexBufferCount); + rsAssert(slot < sm->mHal.state.vertexBuffersCount); - sm->mVertexBuffers[slot].set((Allocation *)va); + sm->setVertexBuffer((Allocation *)va, slot); } void rsi_MeshBindIndex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t primType, uint32_t slot) { Mesh *sm = static_cast<Mesh *>(mv); - rsAssert(slot < sm->mPrimitivesCount); + rsAssert(slot < sm->mHal.state.primitivesCount); - sm->mPrimitives[slot]->mIndexBuffer.set((Allocation *)va); - sm->mPrimitives[slot]->mPrimitive = (RsPrimitive)primType; - sm->updateGLPrimitives(); + sm->setPrimitive((Allocation *)va, (RsPrimitive)primType, slot); } void rsi_MeshInitVertexAttribs(Context *rsc, RsMesh mv) { Mesh *sm = static_cast<Mesh *>(mv); - sm->initVertexAttribs(); + sm->init(); } }} void rsaMeshGetVertexBufferCount(RsContext con, RsMesh mv, int32_t *numVtx) { Mesh *sm = static_cast<Mesh *>(mv); - *numVtx = sm->mVertexBufferCount; + *numVtx = sm->mHal.state.vertexBuffersCount; } void rsaMeshGetIndexCount(RsContext con, RsMesh mv, int32_t *numIdx) { Mesh *sm = static_cast<Mesh *>(mv); - *numIdx = sm->mPrimitivesCount; + *numIdx = sm->mHal.state.primitivesCount; } void rsaMeshGetVertices(RsContext con, RsMesh mv, RsAllocation *vtxData, uint32_t vtxDataCount) { Mesh *sm = static_cast<Mesh *>(mv); - rsAssert(vtxDataCount == sm->mVertexBufferCount); + rsAssert(vtxDataCount == sm->mHal.state.vertexBuffersCount); for (uint32_t ct = 0; ct < vtxDataCount; ct ++) { - vtxData[ct] = sm->mVertexBuffers[ct].get(); - sm->mVertexBuffers[ct]->incUserRef(); + vtxData[ct] = sm->mHal.state.vertexBuffers[ct].get(); + sm->mHal.state.vertexBuffers[ct]->incUserRef(); } } void rsaMeshGetIndices(RsContext con, RsMesh mv, RsAllocation *va, uint32_t *primType, uint32_t idxDataCount) { Mesh *sm = static_cast<Mesh *>(mv); - rsAssert(idxDataCount == sm->mPrimitivesCount); + rsAssert(idxDataCount == sm->mHal.state.primitivesCount); for (uint32_t ct = 0; ct < idxDataCount; ct ++) { - va[ct] = sm->mPrimitives[ct]->mIndexBuffer.get(); - primType[ct] = sm->mPrimitives[ct]->mPrimitive; - if (sm->mPrimitives[ct]->mIndexBuffer.get()) { - sm->mPrimitives[ct]->mIndexBuffer->incUserRef(); + va[ct] = sm->mHal.state.primitives[ct]->mIndexBuffer.get(); + primType[ct] = sm->mHal.state.primitives[ct]->mPrimitive; + if (sm->mHal.state.primitives[ct]->mIndexBuffer.get()) { + sm->mHal.state.primitives[ct]->mIndexBuffer->incUserRef(); } } } diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h index 3e080e2aabb9..1e279f4d1320 100644 --- a/libs/rs/rsMesh.h +++ b/libs/rs/rsMesh.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,57 +29,65 @@ namespace renderscript { class Mesh : public ObjectBase { public: Mesh(Context *); + Mesh(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount); ~Mesh(); - // Contains vertex data - // Position, normal, texcoord, etc could either be strided in one allocation - // of provided separetely in multiple ones - ObjectBaseRef<Allocation> *mVertexBuffers; - uint32_t mVertexBufferCount; - // Either mIndexBuffer, mPrimitiveBuffer or both could have a NULL reference // If both are null, mPrimitive only would be used to render the mesh - struct Primitive_t - { + struct Primitive_t { ObjectBaseRef<Allocation> mIndexBuffer; - RsPrimitive mPrimitive; - uint32_t mGLPrimitive; }; + // compatibility to not break the build + ObjectBaseRef<Allocation> *mVertexBuffers; + uint32_t mVertexBufferCount; Primitive_t ** mPrimitives; uint32_t mPrimitivesCount; + // end compatibility virtual void serialize(OStream *stream) const; virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; } static Mesh *createFromStream(Context *rsc, IStream *stream); + void init(); + + struct Hal { + mutable void *drv; + + struct State { + // Contains vertex data + // Position, normal, texcoord, etc could either be strided in one allocation + // of provided separetely in multiple ones + ObjectBaseRef<Allocation> *vertexBuffers; + uint32_t vertexBuffersCount; + + Primitive_t ** primitives; + uint32_t primitivesCount; + }; + State state; + }; + Hal mHal; + + void setVertexBuffer(Allocation *vb, uint32_t index) { + mHal.state.vertexBuffers[index].set(vb); + } + + void setPrimitive(Allocation *idx, RsPrimitive prim, uint32_t index) { + mHal.state.primitives[index]->mIndexBuffer.set(idx); + mHal.state.primitives[index]->mPrimitive = prim; + } -#ifndef ANDROID_RS_SERIALIZE void render(Context *) const; void renderPrimitive(Context *, uint32_t primIndex) const; void renderPrimitiveRange(Context *, uint32_t primIndex, uint32_t start, uint32_t len) const; void uploadAll(Context *); - void updateGLPrimitives(); - - // Bounding volumes float mBBoxMin[3]; float mBBoxMax[3]; void computeBBox(); - - void initVertexAttribs(); - protected: - bool isValidGLComponent(const Element *elem, uint32_t fieldIdx); - // Attribues that allow us to map to GL - VertexArray::Attrib *mAttribs; - // This allows us to figure out which allocation the attribute - // belongs to. In the event the allocation is uploaded to GL - // buffer, it lets us properly map it - uint32_t *mAttribAllocationIndex; - uint32_t mAttribCount; -#endif + bool mInitialized; }; class MeshContext { @@ -92,7 +100,7 @@ public: } } -#endif //ANDROID_RS_TRIANGLE_MESH_H +#endif //ANDROID_RS_MESH_H diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp index 4ef05bf4372f..28fa0617b99d 100644 --- a/libs/rs/rsProgram.cpp +++ b/libs/rs/rsProgram.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,11 +15,6 @@ */ #include "rsContext.h" -#ifndef ANDROID_RS_SERIALIZE -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#endif //ANDROID_RS_SERIALIZE - #include "rsProgram.h" using namespace android; @@ -36,26 +31,22 @@ Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength, initMemberVars(); for (uint32_t ct=0; ct < paramLength; ct+=2) { if (params[ct] == RS_PROGRAM_PARAM_INPUT) { - mInputCount++; - } - if (params[ct] == RS_PROGRAM_PARAM_OUTPUT) { - mOutputCount++; + mHal.state.inputElementsCount++; } if (params[ct] == RS_PROGRAM_PARAM_CONSTANT) { - mConstantCount++; + mHal.state.constantsCount++; } if (params[ct] == RS_PROGRAM_PARAM_TEXTURE_TYPE) { - mTextureCount++; + mHal.state.texturesCount++; } } - mTextures = new ObjectBaseRef<Allocation>[mTextureCount]; - mSamplers = new ObjectBaseRef<Sampler>[mTextureCount]; - mTextureTargets = new RsTextureTarget[mTextureCount]; - mInputElements = new ObjectBaseRef<Element>[mInputCount]; - mOutputElements = new ObjectBaseRef<Element>[mOutputCount]; - mConstantTypes = new ObjectBaseRef<Type>[mConstantCount]; - mConstants = new ObjectBaseRef<Allocation>[mConstantCount]; + mHal.state.textures = new ObjectBaseRef<Allocation>[mHal.state.texturesCount]; + mHal.state.samplers = new ObjectBaseRef<Sampler>[mHal.state.texturesCount]; + mHal.state.textureTargets = new RsTextureTarget[mHal.state.texturesCount]; + mHal.state.inputElements = new ObjectBaseRef<Element>[mHal.state.inputElementsCount]; + mHal.state.constantTypes = new ObjectBaseRef<Type>[mHal.state.constantsCount]; + mHal.state.constants = new ObjectBaseRef<Allocation>[mHal.state.constantsCount]; uint32_t input = 0; uint32_t output = 0; @@ -63,16 +54,13 @@ Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength, uint32_t texture = 0; for (uint32_t ct=0; ct < paramLength; ct+=2) { if (params[ct] == RS_PROGRAM_PARAM_INPUT) { - mInputElements[input++].set(reinterpret_cast<Element *>(params[ct+1])); - } - if (params[ct] == RS_PROGRAM_PARAM_OUTPUT) { - mOutputElements[output++].set(reinterpret_cast<Element *>(params[ct+1])); + mHal.state.inputElements[input++].set(reinterpret_cast<Element *>(params[ct+1])); } if (params[ct] == RS_PROGRAM_PARAM_CONSTANT) { - mConstantTypes[constant++].set(reinterpret_cast<Type *>(params[ct+1])); + mHal.state.constantTypes[constant++].set(reinterpret_cast<Type *>(params[ct+1])); } if (params[ct] == RS_PROGRAM_PARAM_TEXTURE_TYPE) { - mTextureTargets[texture++] = (RsTextureTarget)params[ct+1]; + mHal.state.textureTargets[texture++] = (RsTextureTarget)params[ct+1]; } } mIsInternal = false; @@ -84,88 +72,69 @@ Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength, shaderLength -= internalTokenLen; } mUserShader.setTo(shaderText, shaderLength); - - initAttribAndUniformArray(); } Program::~Program() { - if (mRSC->props.mLogShaders) { - LOGV("Program::~Program with shader id %u", mShaderID); - } - if (mShaderID) { - glDeleteShader(mShaderID); - } - - for (uint32_t ct=0; ct < mConstantCount; ct++) { + for (uint32_t ct=0; ct < mHal.state.constantsCount; ct++) { bindAllocation(NULL, NULL, ct); } - for (uint32_t ct=0; ct < mTextureCount; ct++) { + for (uint32_t ct=0; ct < mHal.state.texturesCount; ct++) { bindTexture(NULL, ct, NULL); bindSampler(NULL, ct, NULL); } - delete[] mTextures; - delete[] mSamplers; - delete[] mTextureTargets; - delete[] mInputElements; - delete[] mOutputElements; - delete[] mConstantTypes; - delete[] mConstants; - delete[] mAttribNames; - delete[] mUniformNames; - delete[] mUniformArraySizes; - mInputCount = 0; - mOutputCount = 0; - mConstantCount = 0; + delete[] mHal.state.textures; + delete[] mHal.state.samplers; + delete[] mHal.state.textureTargets; + delete[] mHal.state.inputElements; + delete[] mHal.state.constantTypes; + delete[] mHal.state.constants; + mHal.state.inputElementsCount = 0; + mHal.state.constantsCount = 0; + mHal.state.texturesCount = 0; } void Program::initMemberVars() { mDirty = true; - mShaderID = 0; - mAttribCount = 0; - mUniformCount = 0; - mTextureCount = 0; - mTextures = NULL; - mSamplers = NULL; - mTextureTargets = NULL; - mInputElements = NULL; - mOutputElements = NULL; - mConstantTypes = NULL; - mConstants = NULL; - mAttribNames = NULL; - mUniformNames = NULL; - mUniformArraySizes = NULL; - mInputCount = 0; - mOutputCount = 0; - mConstantCount = 0; - mIsValid = false; + mHal.drv = NULL; + mHal.state.textures = NULL; + mHal.state.samplers = NULL; + mHal.state.textureTargets = NULL; + mHal.state.inputElements = NULL; + mHal.state.constantTypes = NULL; + mHal.state.constants = NULL; + + mHal.state.inputElementsCount = 0; + mHal.state.constantsCount = 0; + mHal.state.texturesCount = 0; + mIsInternal = false; } void Program::bindAllocation(Context *rsc, Allocation *alloc, uint32_t slot) { if (alloc != NULL) { - if (slot >= mConstantCount) { + if (slot >= mHal.state.constantsCount) { LOGE("Attempt to bind alloc at slot %u, on shader id %u, but const count is %u", - slot, (uint32_t)this, mConstantCount); + slot, (uint32_t)this, mHal.state.constantsCount); rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind allocation"); return; } - if (!alloc->getType()->isEqual(mConstantTypes[slot].get())) { + if (!alloc->getType()->isEqual(mHal.state.constantTypes[slot].get())) { LOGE("Attempt to bind alloc at slot %u, on shader id %u, but types mismatch", slot, (uint32_t)this); rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind allocation"); return; } } - if (mConstants[slot].get() == alloc) { + if (mHal.state.constants[slot].get() == alloc) { return; } - if (mConstants[slot].get()) { - mConstants[slot].get()->removeProgramToDirty(this); + if (mHal.state.constants[slot].get()) { + mHal.state.constants[slot].get()->removeProgramToDirty(this); } - mConstants[slot].set(alloc); + mHal.state.constants[slot].set(alloc); if (alloc) { alloc->addProgramToDirty(this); } @@ -173,327 +142,38 @@ void Program::bindAllocation(Context *rsc, Allocation *alloc, uint32_t slot) { } void Program::bindTexture(Context *rsc, uint32_t slot, Allocation *a) { - if (slot >= mTextureCount) { - LOGE("Attempt to bind texture to slot %u but tex count is %u", slot, mTextureCount); + if (slot >= mHal.state.texturesCount) { + LOGE("Attempt to bind texture to slot %u but tex count is %u", slot, mHal.state.texturesCount); rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind texture"); return; } - if (a && a->getType()->getDimFaces() && mTextureTargets[slot] != RS_TEXTURE_CUBE) { + if (a && a->getType()->getDimFaces() && mHal.state.textureTargets[slot] != RS_TEXTURE_CUBE) { LOGE("Attempt to bind cubemap to slot %u but 2d texture needed", slot); rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind cubemap to 2d texture slot"); return; } //LOGE("bindtex %i %p", slot, a); - mTextures[slot].set(a); + mHal.state.textures[slot].set(a); mDirty = true; } void Program::bindSampler(Context *rsc, uint32_t slot, Sampler *s) { - if (slot >= mTextureCount) { - LOGE("Attempt to bind sampler to slot %u but tex count is %u", slot, mTextureCount); + if (slot >= mHal.state.texturesCount) { + LOGE("Attempt to bind sampler to slot %u but tex count is %u", slot, mHal.state.texturesCount); rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind sampler"); return; } - mSamplers[slot].set(s); + mHal.state.samplers[slot].set(s); mDirty = true; } -String8 Program::getGLSLInputString() const { - String8 s; - for (uint32_t ct=0; ct < mInputCount; ct++) { - const Element *e = mInputElements[ct].get(); - for (uint32_t field=0; field < e->getFieldCount(); field++) { - const Element *f = e->getField(field); - - // Cannot be complex - rsAssert(!f->getFieldCount()); - switch (f->getComponent().getVectorSize()) { - case 1: s.append("attribute float ATTRIB_"); break; - case 2: s.append("attribute vec2 ATTRIB_"); break; - case 3: s.append("attribute vec3 ATTRIB_"); break; - case 4: s.append("attribute vec4 ATTRIB_"); break; - default: - rsAssert(0); - } - - s.append(e->getFieldName(field)); - s.append(";\n"); - } - } - return s; -} - -String8 Program::getGLSLOutputString() const { - return String8(); -} - -String8 Program::getGLSLConstantString() const { - return String8(); -} - -void Program::createShader() { -} - -bool Program::loadShader(Context *rsc, uint32_t type) { - mShaderID = glCreateShader(type); - rsAssert(mShaderID); - - if (rsc->props.mLogShaders) { - LOGV("Loading shader type %x, ID %i", type, mShaderID); - LOGV("%s", mShader.string()); - } - - if (mShaderID) { - const char * ss = mShader.string(); - glShaderSource(mShaderID, 1, &ss, NULL); - glCompileShader(mShaderID); - - GLint compiled = 0; - glGetShaderiv(mShaderID, GL_COMPILE_STATUS, &compiled); - if (!compiled) { - GLint infoLen = 0; - glGetShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLen); - if (infoLen) { - char* buf = (char*) malloc(infoLen); - if (buf) { - glGetShaderInfoLog(mShaderID, infoLen, NULL, buf); - LOGE("Could not compile shader \n%s\n", buf); - free(buf); - } - glDeleteShader(mShaderID); - mShaderID = 0; - rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,"); - return false; - } - } - } - - if (rsc->props.mLogShaders) { - LOGV("--Shader load result %x ", glGetError()); - } - mIsValid = true; - return true; -} - void Program::setShader(const char *txt, uint32_t len) { mUserShader.setTo(txt, len); } -void Program::appendUserConstants() { - for (uint32_t ct=0; ct < mConstantCount; ct++) { - const Element *e = mConstantTypes[ct]->getElement(); - for (uint32_t field=0; field < e->getFieldCount(); field++) { - const Element *f = e->getField(field); - const char *fn = e->getFieldName(field); - - if (fn[0] == '#') { - continue; - } - - // Cannot be complex - rsAssert(!f->getFieldCount()); - if (f->getType() == RS_TYPE_MATRIX_4X4) { - mShader.append("uniform mat4 UNI_"); - } else if (f->getType() == RS_TYPE_MATRIX_3X3) { - mShader.append("uniform mat3 UNI_"); - } else if (f->getType() == RS_TYPE_MATRIX_2X2) { - mShader.append("uniform mat2 UNI_"); - } else { - switch (f->getComponent().getVectorSize()) { - case 1: mShader.append("uniform float UNI_"); break; - case 2: mShader.append("uniform vec2 UNI_"); break; - case 3: mShader.append("uniform vec3 UNI_"); break; - case 4: mShader.append("uniform vec4 UNI_"); break; - default: - rsAssert(0); - } - } - - mShader.append(fn); - if (e->getFieldArraySize(field) > 1) { - mShader.appendFormat("[%d]", e->getFieldArraySize(field)); - } - mShader.append(";\n"); - } - } -} - -void Program::logUniform(const Element *field, const float *fd, uint32_t arraySize ) { - RsDataType dataType = field->getType(); - uint32_t elementSize = field->getSizeBytes() / sizeof(float); - for (uint32_t i = 0; i < arraySize; i ++) { - if (arraySize > 1) { - LOGV("Array Element [%u]", i); - } - if (dataType == RS_TYPE_MATRIX_4X4) { - LOGV("Matrix4x4"); - LOGV("{%f, %f, %f, %f", fd[0], fd[4], fd[8], fd[12]); - LOGV(" %f, %f, %f, %f", fd[1], fd[5], fd[9], fd[13]); - LOGV(" %f, %f, %f, %f", fd[2], fd[6], fd[10], fd[14]); - LOGV(" %f, %f, %f, %f}", fd[3], fd[7], fd[11], fd[15]); - } else if (dataType == RS_TYPE_MATRIX_3X3) { - LOGV("Matrix3x3"); - LOGV("{%f, %f, %f", fd[0], fd[3], fd[6]); - LOGV(" %f, %f, %f", fd[1], fd[4], fd[7]); - LOGV(" %f, %f, %f}", fd[2], fd[5], fd[8]); - } else if (dataType == RS_TYPE_MATRIX_2X2) { - LOGV("Matrix2x2"); - LOGV("{%f, %f", fd[0], fd[2]); - LOGV(" %f, %f}", fd[1], fd[3]); - } else { - switch (field->getComponent().getVectorSize()) { - case 1: - LOGV("Uniform 1 = %f", fd[0]); - break; - case 2: - LOGV("Uniform 2 = %f %f", fd[0], fd[1]); - break; - case 3: - LOGV("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]); - break; - case 4: - LOGV("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]); - break; - default: - rsAssert(0); - } - } - LOGE("Element size %u data=%p", elementSize, fd); - fd += elementSize; - LOGE("New data=%p", fd); - } -} - -void Program::setUniform(Context *rsc, const Element *field, const float *fd, - int32_t slot, uint32_t arraySize ) { - RsDataType dataType = field->getType(); - if (dataType == RS_TYPE_MATRIX_4X4) { - glUniformMatrix4fv(slot, arraySize, GL_FALSE, fd); - } else if (dataType == RS_TYPE_MATRIX_3X3) { - glUniformMatrix3fv(slot, arraySize, GL_FALSE, fd); - } else if (dataType == RS_TYPE_MATRIX_2X2) { - glUniformMatrix2fv(slot, arraySize, GL_FALSE, fd); - } else { - switch (field->getComponent().getVectorSize()) { - case 1: - glUniform1fv(slot, arraySize, fd); - break; - case 2: - glUniform2fv(slot, arraySize, fd); - break; - case 3: - glUniform3fv(slot, arraySize, fd); - break; - case 4: - glUniform4fv(slot, arraySize, fd); - break; - default: - rsAssert(0); - } - } -} - -void Program::setupUserConstants(Context *rsc, ShaderCache *sc, bool isFragment) { - uint32_t uidx = 0; - for (uint32_t ct=0; ct < mConstantCount; ct++) { - Allocation *alloc = mConstants[ct].get(); - if (!alloc) { - LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set", (uint32_t)this, ct); - rsc->setError(RS_ERROR_BAD_SHADER, "No constant allocation bound"); - continue; - } - - const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr()); - const Element *e = mConstantTypes[ct]->getElement(); - for (uint32_t field=0; field < e->getFieldCount(); field++) { - const Element *f = e->getField(field); - const char *fieldName = e->getFieldName(field); - // If this field is padding, skip it - if (fieldName[0] == '#') { - continue; - } - - uint32_t offset = e->getFieldOffsetBytes(field); - const float *fd = reinterpret_cast<const float *>(&data[offset]); - - int32_t slot = -1; - uint32_t arraySize = 1; - if (!isFragment) { - slot = sc->vtxUniformSlot(uidx); - arraySize = sc->vtxUniformSize(uidx); - } else { - slot = sc->fragUniformSlot(uidx); - arraySize = sc->fragUniformSize(uidx); - } - if (rsc->props.mLogShadersUniforms) { - LOGV("Uniform slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName); - } - uidx ++; - if (slot < 0) { - continue; - } - - if (rsc->props.mLogShadersUniforms) { - logUniform(f, fd, arraySize); - } - setUniform(rsc, f, fd, slot, arraySize); - } - } -} - -void Program::initAttribAndUniformArray() { - mAttribCount = 0; - for (uint32_t ct=0; ct < mInputCount; ct++) { - const Element *elem = mInputElements[ct].get(); - for (uint32_t field=0; field < elem->getFieldCount(); field++) { - if (elem->getFieldName(field)[0] != '#') { - mAttribCount ++; - } - } - } - - mUniformCount = 0; - for (uint32_t ct=0; ct < mConstantCount; ct++) { - const Element *elem = mConstantTypes[ct]->getElement(); - - for (uint32_t field=0; field < elem->getFieldCount(); field++) { - if (elem->getFieldName(field)[0] != '#') { - mUniformCount ++; - } - } - } - mUniformCount += mTextureCount; - - if (mAttribCount) { - mAttribNames = new String8[mAttribCount]; - } - if (mUniformCount) { - mUniformNames = new String8[mUniformCount]; - mUniformArraySizes = new uint32_t[mUniformCount]; - } -} - -void Program::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) { - rsAssert(e->getFieldCount()); - for (uint32_t ct=0; ct < e->getFieldCount(); ct++) { - const Element *ce = e->getField(ct); - if (ce->getFieldCount()) { - initAddUserElement(ce, names, arrayLengths, count, prefix); - } else if (e->getFieldName(ct)[0] != '#') { - String8 tmp(prefix); - tmp.append(e->getFieldName(ct)); - names[*count].setTo(tmp.string()); - if (arrayLengths) { - arrayLengths[*count] = e->getFieldArraySize(ct); - } - (*count)++; - } - } -} - namespace android { namespace renderscript { diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h index c48464dadecc..bcf55196fbfa 100644 --- a/libs/rs/rsProgram.h +++ b/libs/rs/rsProgram.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,6 @@ // --------------------------------------------------------------------------- namespace android { namespace renderscript { -class ShaderCache; #define RS_SHADER_INTERNAL "//rs_shader_internal\n" #define RS_SHADER_ATTR "ATTRIB_" @@ -38,75 +37,53 @@ public: virtual ~Program(); void bindAllocation(Context *, Allocation *, uint32_t slot); - virtual void createShader(); bool isUserProgram() const {return !mIsInternal;} void bindTexture(Context *, uint32_t slot, Allocation *); void bindSampler(Context *, uint32_t slot, Sampler *); - uint32_t getShaderID() const {return mShaderID;} void setShader(const char *, uint32_t len); - uint32_t getAttribCount() const {return mAttribCount;} - uint32_t getUniformCount() const {return mUniformCount;} - const String8 & getAttribName(uint32_t i) const {return mAttribNames[i];} - const String8 & getUniformName(uint32_t i) const {return mUniformNames[i];} - uint32_t getUniformArraySize(uint32_t i) const {return mUniformArraySizes[i];} - - String8 getGLSLInputString() const; - String8 getGLSLOutputString() const; - String8 getGLSLConstantString() const; - - bool isValid() const {return mIsValid;} void forceDirty() const {mDirty = true;} + struct Hal { + mutable void *drv; + + struct State { + // The difference between Textures and Constants is how they are accessed + // Texture lookups go though a sampler which in effect converts normalized + // coordinates into type specific. Multiple samples may also be taken + // and filtered. + // + // Constants are strictly accessed by the shader code + ObjectBaseRef<Allocation> *textures; + RsTextureTarget *textureTargets; + uint32_t texturesCount; + + ObjectBaseRef<Sampler> *samplers; + uint32_t samplersCount; + + ObjectBaseRef<Allocation> *constants; + ObjectBaseRef<Type> *constantTypes; + uint32_t constantsCount; + + ObjectBaseRef<Element> *inputElements; + uint32_t inputElementsCount; + }; + State state; + }; + Hal mHal; + protected: - // Components not listed in "in" will be passed though - // unless overwritten by components in out. - ObjectBaseRef<Element> *mInputElements; - ObjectBaseRef<Element> *mOutputElements; - ObjectBaseRef<Type> *mConstantTypes; - ObjectBaseRef<Allocation> *mConstants; - uint32_t mInputCount; - uint32_t mOutputCount; - uint32_t mConstantCount; - bool mIsValid; bool mIsInternal; - // Applies to vertex and fragment shaders only - void appendUserConstants(); - void setupUserConstants(Context *rsc, ShaderCache *sc, bool isFragment); - void initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix); - - void initAttribAndUniformArray(); - mutable bool mDirty; - String8 mShader; String8 mUserShader; - uint32_t mShaderID; - - uint32_t mTextureCount; - uint32_t mAttribCount; - uint32_t mUniformCount; - String8 *mAttribNames; - String8 *mUniformNames; - uint32_t *mUniformArraySizes; void logUniform(const Element *field, const float *fd, uint32_t arraySize ); void setUniform(Context *rsc, const Element *field, const float *fd, int32_t slot, uint32_t arraySize ); void initMemberVars(); - - // The difference between Textures and Constants is how they are accessed - // Texture lookups go though a sampler which in effect converts normalized - // coordinates into type specific. Multiple samples may also be taken - // and filtered. - // - // Constants are strictly accessed by programetic loads. - ObjectBaseRef<Allocation> *mTextures; - ObjectBaseRef<Sampler> *mSamplers; - RsTextureTarget *mTextureTargets; - bool loadShader(Context *, uint32_t type); }; } diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp index ff314b7f6429..39887ca3f43b 100644 --- a/libs/rs/rsProgramFragment.cpp +++ b/libs/rs/rsProgramFragment.cpp @@ -15,13 +15,6 @@ */ #include "rsContext.h" -#ifndef ANDROID_RS_SERIALIZE -#include <GLES/gl.h> -#include <GLES/glext.h> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#endif //ANDROID_RS_SERIALIZE - #include "rsProgramFragment.h" using namespace android; @@ -31,19 +24,16 @@ ProgramFragment::ProgramFragment(Context *rsc, const char * shaderText, uint32_t shaderLength, const uint32_t * params, uint32_t paramLength) : Program(rsc, shaderText, shaderLength, params, paramLength) { - mConstantColor[0] = 1.f; mConstantColor[1] = 1.f; mConstantColor[2] = 1.f; mConstantColor[3] = 1.f; - init(rsc); + mRSC->mHal.funcs.fragment.init(mRSC, this, mUserShader.string(), mUserShader.length()); } ProgramFragment::~ProgramFragment() { - if (mShaderID) { - mRSC->mShaderCache.cleanupFragment(mShaderID); - } + mRSC->mHal.funcs.fragment.destroy(mRSC, this); } void ProgramFragment::setConstantColor(Context *rsc, float r, float g, float b, float a) { @@ -52,7 +42,7 @@ void ProgramFragment::setConstantColor(Context *rsc, float r, float g, float b, rsc->setError(RS_ERROR_BAD_SHADER, "Cannot set fixed function emulation color on user program"); return; } - if (mConstants[0].get() == NULL) { + if (mHal.state.constants[0].get() == NULL) { LOGE("Unable to set fixed function emulation color because allocation is missing"); rsc->setError(RS_ERROR_BAD_SHADER, "Unable to set fixed function emulation color because allocation is missing"); return; @@ -61,11 +51,11 @@ void ProgramFragment::setConstantColor(Context *rsc, float r, float g, float b, mConstantColor[1] = g; mConstantColor[2] = b; mConstantColor[3] = a; - memcpy(mConstants[0]->getPtr(), mConstantColor, 4*sizeof(float)); + memcpy(mHal.state.constants[0]->getPtr(), mConstantColor, 4*sizeof(float)); mDirty = true; } -void ProgramFragment::setupGL2(Context *rsc, ProgramFragmentState *state, ShaderCache *sc) { +void ProgramFragment::setupGL2(Context *rsc, ProgramFragmentState *state) { //LOGE("sgl2 frag1 %x", glGetError()); if ((state->mLast.get() == this) && !mDirty) { return; @@ -74,94 +64,16 @@ void ProgramFragment::setupGL2(Context *rsc, ProgramFragmentState *state, Shader rsc->checkError("ProgramFragment::setupGL2 start"); - rsc->checkError("ProgramFragment::setupGL2 begin uniforms"); - setupUserConstants(rsc, sc, true); - - uint32_t numTexturesToBind = mTextureCount; - uint32_t numTexturesAvailable = rsc->getMaxFragmentTextures(); - if (numTexturesToBind >= numTexturesAvailable) { - LOGE("Attempting to bind %u textures on shader id %u, but only %u are available", - mTextureCount, (uint32_t)this, numTexturesAvailable); - rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind more textuers than available"); - numTexturesToBind = numTexturesAvailable; - } - - for (uint32_t ct=0; ct < numTexturesToBind; ct++) { - glActiveTexture(GL_TEXTURE0 + ct); - if (!mTextures[ct].get()) { + for (uint32_t ct=0; ct < mHal.state.texturesCount; ct++) { + if (!mHal.state.textures[ct].get()) { LOGE("No texture bound for shader id %u, texture unit %u", (uint)this, ct); rsc->setError(RS_ERROR_BAD_SHADER, "No texture bound"); continue; } - - mTextures[ct]->uploadCheck(rsc); - GLenum target = (GLenum)mTextures[ct]->getGLTarget(); - if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) { - LOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct); - rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader"); - } - glBindTexture(target, mTextures[ct]->getTextureID()); - rsc->checkError("ProgramFragment::setupGL2 tex bind"); - if (mSamplers[ct].get()) { - mSamplers[ct]->setupGL(rsc, mTextures[ct].get()); - } else { - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - rsc->checkError("ProgramFragment::setupGL2 tex env"); - } - - glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct); - rsc->checkError("ProgramFragment::setupGL2 uniforms"); - } - - glActiveTexture(GL_TEXTURE0); - mDirty = false; - rsc->checkError("ProgramFragment::setupGL2"); -} - -void ProgramFragment::loadShader(Context *rsc) { - Program::loadShader(rsc, GL_FRAGMENT_SHADER); -} - -void ProgramFragment::createShader() { - if (mUserShader.length() > 1) { - mShader.append("precision mediump float;\n"); - appendUserConstants(); - char buf[256]; - for (uint32_t ct=0; ct < mTextureCount; ct++) { - if (mTextureTargets[ct] == RS_TEXTURE_2D) { - snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct); - } else { - snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct); - } - mShader.append(buf); - } - mShader.append(mUserShader); - } else { - LOGE("ProgramFragment::createShader cannot create program, shader code not defined"); - rsAssert(0); - } -} - -void ProgramFragment::init(Context *rsc) { - uint32_t uniformIndex = 0; - if (mUserShader.size() > 0) { - for (uint32_t ct=0; ct < mConstantCount; ct++) { - initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformIndex, RS_SHADER_UNI); - } - } - mTextureUniformIndexStart = uniformIndex; - char buf[256]; - for (uint32_t ct=0; ct < mTextureCount; ct++) { - snprintf(buf, sizeof(buf), "UNI_Tex%i", ct); - mUniformNames[uniformIndex].setTo(buf); - mUniformArraySizes[uniformIndex] = 1; - uniformIndex++; + mHal.state.textures[ct]->uploadCheck(rsc); } - createShader(); + rsc->mHal.funcs.fragment.setActive(rsc, this); } void ProgramFragment::serialize(OStream *stream) const { diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h index 3d2894690cb2..7520af0b6510 100644 --- a/libs/rs/rsProgramFragment.h +++ b/libs/rs/rsProgramFragment.h @@ -32,11 +32,8 @@ public: uint32_t paramLength); virtual ~ProgramFragment(); - virtual void setupGL2(Context *, ProgramFragmentState *, ShaderCache *sc); + virtual void setupGL2(Context *, ProgramFragmentState *); - virtual void createShader(); - virtual void loadShader(Context *rsc); - virtual void init(Context *rsc); virtual void serialize(OStream *stream) const; virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_FRAGMENT; } static ProgramFragment *createFromStream(Context *rsc, IStream *stream); diff --git a/libs/rs/rsProgramStore.h b/libs/rs/rsProgramStore.h index bfe276d95748..88a06a8b0024 100644 --- a/libs/rs/rsProgramStore.h +++ b/libs/rs/rsProgramStore.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -62,8 +62,6 @@ public: RsDepthFunc depthFunc; }; State state; - - }; Hal mHal; diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp index e407d3ac4781..dfd732f39def 100644 --- a/libs/rs/rsProgramVertex.cpp +++ b/libs/rs/rsProgramVertex.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,13 +15,6 @@ */ #include "rsContext.h" -#ifndef ANDROID_RS_SERIALIZE -#include <GLES/gl.h> -#include <GLES/glext.h> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#endif //ANDROID_RS_SERIALIZE - #include "rsProgramVertex.h" using namespace android; @@ -32,57 +25,14 @@ ProgramVertex::ProgramVertex(Context *rsc, const char * shaderText, uint32_t shaderLength, const uint32_t * params, uint32_t paramLength) : Program(rsc, shaderText, shaderLength, params, paramLength) { - init(rsc); + mRSC->mHal.funcs.vertex.init(mRSC, this, mUserShader.string(), mUserShader.length()); } ProgramVertex::~ProgramVertex() { - if (mShaderID) { - mRSC->mShaderCache.cleanupVertex(mShaderID); - } -} - -void ProgramVertex::loadShader(Context *rsc) { - Program::loadShader(rsc, GL_VERTEX_SHADER); -} - -void ProgramVertex::createShader(Context *rsc) { - if (mUserShader.length() > 1) { - - appendUserConstants(); - - for (uint32_t ct=0; ct < mInputCount; ct++) { - const Element *e = mInputElements[ct].get(); - for (uint32_t field=0; field < e->getFieldCount(); field++) { - const Element *f = e->getField(field); - const char *fn = e->getFieldName(field); - - if (fn[0] == '#') { - continue; - } - - // Cannot be complex - rsAssert(!f->getFieldCount()); - switch (f->getComponent().getVectorSize()) { - case 1: mShader.append("attribute float ATTRIB_"); break; - case 2: mShader.append("attribute vec2 ATTRIB_"); break; - case 3: mShader.append("attribute vec3 ATTRIB_"); break; - case 4: mShader.append("attribute vec4 ATTRIB_"); break; - default: - rsAssert(0); - } - - mShader.append(fn); - mShader.append(";\n"); - } - } - mShader.append(mUserShader); - } else { - rsc->setError(RS_ERROR_FATAL_UNKNOWN, - "ProgramFragment::createShader cannot create program, shader code not defined"); - } + mRSC->mHal.funcs.vertex.destroy(mRSC, this); } -void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state, ShaderCache *sc) { +void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state) { if ((state->mLast.get() == this) && !mDirty) { return; } @@ -90,12 +40,12 @@ void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state, ShaderCach rsc->checkError("ProgramVertex::setupGL2 start"); if (!isUserProgram()) { - if (mConstants[0].get() == NULL) { + if (mHal.state.constants[0].get() == NULL) { rsc->setError(RS_ERROR_FATAL_UNKNOWN, "Unable to set fixed function emulation matrices because allocation is missing"); return; } - float *f = static_cast<float *>(mConstants[0]->getPtr()); + float *f = static_cast<float *>(mHal.state.constants[0]->getPtr()); Matrix4x4 mvp; mvp.load(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]); Matrix4x4 t; @@ -106,10 +56,10 @@ void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state, ShaderCach } } - rsc->checkError("ProgramVertex::setupGL2 begin uniforms"); - setupUserConstants(rsc, sc, false); - state->mLast.set(this); + + rsc->mHal.funcs.vertex.setActive(rsc, this); + rsc->checkError("ProgramVertex::setupGL2"); } @@ -119,12 +69,12 @@ void ProgramVertex::setProjectionMatrix(Context *rsc, const rsc_Matrix *m) const "Attempting to set fixed function emulation matrix projection on user program"); return; } - if (mConstants[0].get() == NULL) { + if (mHal.state.constants[0].get() == NULL) { rsc->setError(RS_ERROR_FATAL_UNKNOWN, "Unable to set fixed function emulation matrix projection because allocation is missing"); return; } - float *f = static_cast<float *>(mConstants[0]->getPtr()); + float *f = static_cast<float *>(mHal.state.constants[0]->getPtr()); memcpy(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], m, sizeof(rsc_Matrix)); mDirty = true; } @@ -135,12 +85,12 @@ void ProgramVertex::setModelviewMatrix(Context *rsc, const rsc_Matrix *m) const "Attempting to set fixed function emulation matrix modelview on user program"); return; } - if (mConstants[0].get() == NULL) { + if (mHal.state.constants[0].get() == NULL) { rsc->setError(RS_ERROR_FATAL_UNKNOWN, "Unable to set fixed function emulation matrix modelview because allocation is missing"); return; } - float *f = static_cast<float *>(mConstants[0]->getPtr()); + float *f = static_cast<float *>(mHal.state.constants[0]->getPtr()); memcpy(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], m, sizeof(rsc_Matrix)); mDirty = true; } @@ -151,12 +101,12 @@ void ProgramVertex::setTextureMatrix(Context *rsc, const rsc_Matrix *m) const { "Attempting to set fixed function emulation matrix texture on user program"); return; } - if (mConstants[0].get() == NULL) { + if (mHal.state.constants[0].get() == NULL) { rsc->setError(RS_ERROR_FATAL_UNKNOWN, "Unable to set fixed function emulation matrix texture because allocation is missing"); return; } - float *f = static_cast<float *>(mConstants[0]->getPtr()); + float *f = static_cast<float *>(mHal.state.constants[0]->getPtr()); memcpy(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET], m, sizeof(rsc_Matrix)); mDirty = true; } @@ -167,12 +117,12 @@ void ProgramVertex::getProjectionMatrix(Context *rsc, rsc_Matrix *m) const { "Attempting to get fixed function emulation matrix projection on user program"); return; } - if (mConstants[0].get() == NULL) { + if (mHal.state.constants[0].get() == NULL) { rsc->setError(RS_ERROR_FATAL_UNKNOWN, "Unable to get fixed function emulation matrix projection because allocation is missing"); return; } - float *f = static_cast<float *>(mConstants[0]->getPtr()); + float *f = static_cast<float *>(mHal.state.constants[0]->getPtr()); memcpy(m, &f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], sizeof(rsc_Matrix)); } @@ -180,27 +130,13 @@ void ProgramVertex::transformToScreen(Context *rsc, float *v4out, const float *v if (isUserProgram()) { return; } - float *f = static_cast<float *>(mConstants[0]->getPtr()); + float *f = static_cast<float *>(mHal.state.constants[0]->getPtr()); Matrix4x4 mvp; mvp.loadMultiply((Matrix4x4 *)&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], (Matrix4x4 *)&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]); mvp.vectorMultiply(v4out, v3in); } -void ProgramVertex::init(Context *rsc) { - uint32_t attribCount = 0; - uint32_t uniformCount = 0; - if (mUserShader.size() > 0) { - for (uint32_t ct=0; ct < mInputCount; ct++) { - initAddUserElement(mInputElements[ct].get(), mAttribNames, NULL, &attribCount, RS_SHADER_ATTR); - } - for (uint32_t ct=0; ct < mConstantCount; ct++) { - initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI); - } - } - createShader(rsc); -} - void ProgramVertex::serialize(OStream *stream) const { } diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h index 2a5c863cd2e9..04224a7502f2 100644 --- a/libs/rs/rsProgramVertex.h +++ b/libs/rs/rsProgramVertex.h @@ -31,7 +31,7 @@ public: const uint32_t * params, uint32_t paramLength); virtual ~ProgramVertex(); - virtual void setupGL2(Context *rsc, ProgramVertexState *state, ShaderCache *sc); + virtual void setupGL2(Context *rsc, ProgramVertexState *state); void setProjectionMatrix(Context *, const rsc_Matrix *) const; void getProjectionMatrix(Context *, rsc_Matrix *) const; @@ -40,10 +40,6 @@ public: void transformToScreen(Context *, float *v4out, const float *v3in) const; - virtual void createShader(Context *); - virtual void loadShader(Context *); - virtual void init(Context *); - virtual void serialize(OStream *stream) const; virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_VERTEX; } static ProgramVertex *createFromStream(Context *rsc, IStream *stream); diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp index 71f1312d564a..ecda485442c2 100644 --- a/libs/rs/rsScriptC_LibGL.cpp +++ b/libs/rs/rsScriptC_LibGL.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,9 @@ #include "rsMatrix2x2.h" #include "utils/Timers.h" +#include "driver/rsdVertexArray.h" +#include "driver/rsdShaderCache.h" +#include "driver/rsdCore.h" #define GL_GLEXT_PROTOTYPES @@ -134,6 +137,11 @@ void rsrDrawQuadTexCoords(Context *rsc, Script *sc, return; } + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + if (!dc->gl.shaderCache->setup(rsc)) { + return; + } + //LOGE("Quad"); //LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1); //LOGE("%4.2f, %4.2f, %4.2f", x2, y2, z2); @@ -143,12 +151,12 @@ void rsrDrawQuadTexCoords(Context *rsc, Script *sc, float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4}; const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4}; - VertexArray::Attrib attribs[2]; + RsdVertexArray::Attrib attribs[2]; attribs[0].set(GL_FLOAT, 3, 12, false, (uint32_t)vtx, "ATTRIB_position"); attribs[1].set(GL_FLOAT, 2, 8, false, (uint32_t)tex, "ATTRIB_texture0"); - VertexArray va(attribs, 2); - va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache); + RsdVertexArray va(attribs, 2); + va.setupGL2(rsc); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h index 90ae039da3e3..086db337093b 100644 --- a/libs/rs/rsType.h +++ b/libs/rs/rsType.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,6 @@ #define ANDROID_STRUCTURED_TYPE_H #include "rsElement.h" -#include "rsVertexArray.h" // --------------------------------------------------------------------------- namespace android { diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h index 4283d4a6ae00..d2f273bc3b41 100644 --- a/libs/rs/rs_hal.h +++ b/libs/rs/rs_hal.h @@ -32,6 +32,9 @@ class Script; class ScriptC; class ProgramStore; class ProgramRaster; +class ProgramVertex; +class ProgramFragment; +class Mesh; typedef void *(*RsHalSymbolLookupFunc)(void *usrptr, char const *symbolName); @@ -98,6 +101,25 @@ typedef struct { void (*destroy)(const Context *rsc, const ProgramRaster *ps); } raster; + struct { + bool (*init)(const Context *rsc, const ProgramVertex *pv, + const char* shader, uint32_t shaderLen); + void (*setActive)(const Context *rsc, const ProgramVertex *pv); + void (*destroy)(const Context *rsc, const ProgramVertex *pv); + } vertex; + + struct { + bool (*init)(const Context *rsc, const ProgramFragment *pf, + const char* shader, uint32_t shaderLen); + void (*setActive)(const Context *rsc, const ProgramFragment *pf); + void (*destroy)(const Context *rsc, const ProgramFragment *pf); + } fragment; + + struct { + bool (*init)(const Context *rsc, const Mesh *m); + void (*draw)(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len); + void (*destroy)(const Context *rsc, const Mesh *m); + } mesh; } RsdHalFunctions; diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c index 239795d52055..0e914fc30f44 100644 --- a/libs/rs/rsg_generator.c +++ b/libs/rs/rsg_generator.c @@ -157,7 +157,8 @@ void printPlaybackFuncs(FILE *f, const char *prefix) { static int hasInlineDataPointers(const ApiEntry * api) { int ret = 0; int ct; - if (api->sync || api->ret.typeName[0]) { + // Temporarly disable inbanding while we sort though the bugs. + if (1|| api->sync || api->ret.typeName[0]) { return 0; } for (ct=0; ct < api->paramCount; ct++) { diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 6c3b3d38678e..c225e895cb9d 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -34,6 +34,7 @@ import android.net.NetworkStateTracker; import android.net.NetworkUtils; import android.net.Proxy; import android.net.ProxyProperties; +import android.net.RouteInfo; import android.net.vpn.VpnManager; import android.net.wifi.WifiStateTracker; import android.os.Binder; @@ -1417,14 +1418,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (p == null) return; String interfaceName = p.getInterfaceName(); if (TextUtils.isEmpty(interfaceName)) return; - for (InetAddress gateway : p.getGateways()) { + for (RouteInfo route : p.getRoutes()) { - if (NetworkUtils.addHostRoute(interfaceName, gateway, null) && - NetworkUtils.addDefaultRoute(interfaceName, gateway)) { - if (DBG) { - NetworkInfo networkInfo = nt.getNetworkInfo(); - log("addDefaultRoute for " + networkInfo.getTypeName() + - " (" + interfaceName + "), GatewayAddr=" + gateway.getHostAddress()); + //TODO - handle non-default routes + if (route.isDefaultRoute()) { + InetAddress gateway = route.getGateway(); + if (NetworkUtils.addHostRoute(interfaceName, gateway, null) && + NetworkUtils.addDefaultRoute(interfaceName, gateway)) { + if (DBG) { + NetworkInfo networkInfo = nt.getNetworkInfo(); + log("addDefaultRoute for " + networkInfo.getTypeName() + + " (" + interfaceName + "), GatewayAddr=" + + gateway.getHostAddress()); + } } } } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 31b7f86e0bb8..da34644a3fa0 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -7091,18 +7091,25 @@ public final class ActivityManagerService extends ActivityManagerNative * to append various headers to the dropbox log text. */ private void appendDropBoxProcessHeaders(ProcessRecord process, StringBuilder sb) { + // Watchdog thread ends up invoking this function (with + // a null ProcessRecord) to add the stack file to dropbox. + // Do not acquire a lock on this (am) in such cases, as it + // could cause a potential deadlock, if and when watchdog + // is invoked due to unavailability of lock on am and it + // would prevent watchdog from killing system_server. + if (process == null) { + sb.append("Process: system_server\n"); + return; + } // Note: ProcessRecord 'process' is guarded by the service // instance. (notably process.pkgList, which could otherwise change // concurrently during execution of this method) synchronized (this) { - if (process == null || process.pid == MY_PID) { + if (process.pid == MY_PID) { sb.append("Process: system_server\n"); } else { sb.append("Process: ").append(process.processName).append("\n"); } - if (process == null) { - return; - } int flags = process.info.flags; IPackageManager pm = AppGlobals.getPackageManager(); sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n"); diff --git a/services/surfaceflinger/TextureManager.cpp b/services/surfaceflinger/TextureManager.cpp index c9a15f56ab74..9e24f90d550b 100644 --- a/services/surfaceflinger/TextureManager.cpp +++ b/services/surfaceflinger/TextureManager.cpp @@ -186,7 +186,7 @@ status_t TextureManager::loadTexture(Texture* texture, if (texture->name == -1UL) { status_t err = initTexture(texture); LOGE_IF(err, "loadTexture failed in initTexture (%s)", strerror(err)); - return err; + if (err != NO_ERROR) return err; } if (texture->target != Texture::TEXTURE_2D) diff --git a/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java b/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java index 6390d8e29ec9..f5e53ef1ee5d 100644 --- a/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java +++ b/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java @@ -24,6 +24,7 @@ import android.text.Editable; * * 022-229-1234 0223-23-1234 022-301-9876 015-482-7849 0154-91-3478 * 01547-5-4534 090-1234-1234 080-0123-6789 + * 050-0000-0000 060-0000-0000 * 0800-000-9999 0570-000-000 0276-00-0000 * * As you can see, there is no straight-forward rule here. @@ -31,7 +32,7 @@ import android.text.Editable; */ /* package */ class JapanesePhoneNumberFormatter { private static short FORMAT_MAP[] = { - -100, 10, 220, -15, 410, 530, -15, 670, 780, 1060, + -100, 10, 220, -15, 410, 530, 1200, 670, 780, 1060, -100, -25, 20, 40, 70, 100, 150, 190, 200, 210, -36, -100, -100, -35, -35, -35, 30, -100, -100, -100, -35, -35, -35, -35, -35, -35, -35, -45, -35, -35, @@ -84,7 +85,7 @@ import android.text.Editable; -35, -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, -35, -35, -35, -25, -25, -25, 520, -100, -100, -45, -100, -45, -100, -45, -100, -45, -100, - -25, -100, -25, 540, 580, 590, 600, 610, 630, 640, + -26, -100, -25, 540, 580, 590, 600, 610, 630, 640, -25, -35, -35, -35, -25, -25, -35, -35, -35, 550, -35, -35, -25, -25, -25, -25, 560, 570, -25, -35, -35, -35, -35, -35, -25, -25, -25, -25, -25, -25, @@ -150,7 +151,8 @@ import android.text.Editable; -35, 1170, -25, -35, 1180, -35, 1190, -35, -25, -25, -100, -100, -45, -45, -100, -100, -100, -100, -100, -100, -25, -35, -35, -35, -35, -35, -35, -25, -25, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -45}; + -35, -35, -35, -35, -35, -35, -35, -35, -35, -45, + -26, -15, -15, -15, -15, -15, -15, -15, -15, -15}; public static void format(Editable text) { // Here, "root" means the position of "'": diff --git a/telephony/java/com/android/internal/telephony/DataCallState.java b/telephony/java/com/android/internal/telephony/DataCallState.java index a883e8efc36f..1d67d454b3fb 100644 --- a/telephony/java/com/android/internal/telephony/DataCallState.java +++ b/telephony/java/com/android/internal/telephony/DataCallState.java @@ -20,6 +20,7 @@ package com.android.internal.telephony; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkUtils; +import android.net.RouteInfo; import android.os.SystemProperties; import android.util.Log; @@ -196,7 +197,7 @@ public class DataCallState { } catch (IllegalArgumentException e) { throw new UnknownHostException("Non-numeric gateway addr=" + addr); } - linkProperties.addGateway(ia); + linkProperties.addRoute(new RouteInfo(ia)); } result = SetupResult.SUCCESS; @@ -223,5 +224,3 @@ public class DataCallState { return result; } } - - diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java index c052e5142351..490051d8cb9c 100644 --- a/telephony/java/com/android/internal/telephony/RIL.java +++ b/telephony/java/com/android/internal/telephony/RIL.java @@ -3024,7 +3024,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { dataCall.active = p.readInt(); dataCall.type = p.readString(); String addresses = p.readString(); - if (TextUtils.isEmpty(addresses)) { + if (!TextUtils.isEmpty(addresses)) { dataCall.addresses = addresses.split(" "); } } else { @@ -3033,7 +3033,8 @@ public final class RIL extends BaseCommands implements CommandsInterface { dataCall.active = p.readInt(); dataCall.type = p.readString(); dataCall.ifname = p.readString(); - if (TextUtils.isEmpty(dataCall.ifname)) { + if ((dataCall.status == DataConnection.FailCause.NONE.getErrorCode()) && + TextUtils.isEmpty(dataCall.ifname)) { throw new RuntimeException("getDataCallState, no ifname"); } String addresses = p.readString(); diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java index 55fab3f10ca9..7173a85f73e7 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java @@ -86,6 +86,14 @@ public class Lines2Activity extends Activity { canvas.drawLines(copyPoints, 0, 12, p); } + private void drawVerticalLine(Canvas canvas, Paint p, float length, float x, float y) { + canvas.drawLine(x, y, x, y + length, p); + } + + private void drawDiagonalLine(Canvas canvas, Paint p, float length, float x, float y) { + canvas.drawLine(x, y, x + length, y + length, p); + } + @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); @@ -145,6 +153,99 @@ public class Lines2Activity extends Activity { canvas.translate(60, 0); drawLines(canvas, p, mOffset/2, yOffset/2); canvas.restore(); + + yOffset += 100; + canvas.save(); + p.setStrokeWidth(1); + float x = 10 + mOffset; + for (float length = 1; length <= 10; length +=1 ) { + p.setAntiAlias(false); + drawVerticalLine(canvas, p, length, x, yOffset); + x += 5; + p.setAntiAlias(true); + drawVerticalLine(canvas, p, length, x, yOffset); + x += 5; + } + p.setStrokeWidth(5); + for (float length = 1; length <= 10; length +=1 ) { + p.setAntiAlias(false); + drawVerticalLine(canvas, p, length, x, yOffset); + x += 10; + p.setAntiAlias(true); + drawVerticalLine(canvas, p, length, x, yOffset); + x += 10; + } + canvas.restore(); + + yOffset += 20; + canvas.save(); + p.setStrokeWidth(1); + x = 10 + mOffset; + for (float length = 1; length <= 10; length +=1 ) { + p.setAntiAlias(false); + drawDiagonalLine(canvas, p, length, x, yOffset); + x += 5; + p.setAntiAlias(true); + drawDiagonalLine(canvas, p, length, x, yOffset); + x += 5; + } + p.setStrokeWidth(2); + for (float length = 1; length <= 10; length +=1 ) { + p.setAntiAlias(false); + drawDiagonalLine(canvas, p, length, x, yOffset); + x += 10; + p.setAntiAlias(true); + drawDiagonalLine(canvas, p, length, x, yOffset); + x += 10; + } + canvas.restore(); + + yOffset += 20; + canvas.save(); + p.setStrokeWidth(1); + x = 10 + mOffset; + for (float length = 1; length <= 10; length +=1 ) { + p.setAntiAlias(false); + canvas.drawLine(x, yOffset, x + 1, yOffset + length, p); + x += 5; + p.setAntiAlias(true); + canvas.drawLine(x, yOffset, x + 1, yOffset + length, p); + x += 5; + } + p.setStrokeWidth(2); + for (float length = 1; length <= 10; length +=1 ) { + p.setAntiAlias(false); + canvas.drawLine(x, yOffset, x + 1, yOffset + length, p); + x += 10; + p.setAntiAlias(true); + canvas.drawLine(x, yOffset, x + 1, yOffset + length, p); + x += 10; + } + canvas.restore(); + + yOffset += 20; + canvas.save(); + p.setStrokeWidth(1); + x = 10 + mOffset; + for (float length = 1; length <= 10; length +=1 ) { + p.setAntiAlias(false); + canvas.drawLine(x, yOffset, x + length, yOffset + 1, p); + x += 5; + p.setAntiAlias(true); + canvas.drawLine(x, yOffset, x + length, yOffset + 1, p); + x += 5; + } + p.setStrokeWidth(2); + for (float length = 1; length <= 10; length +=1 ) { + p.setAntiAlias(false); + canvas.drawLine(x, yOffset, x + length, yOffset + 1, p); + x += 10; + p.setAntiAlias(true); + canvas.drawLine(x, yOffset, x + length, yOffset + 1, p); + x += 10; + } + canvas.restore(); + } } } diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java index 6455d8486f51..7f9fc31b5fed 100644 --- a/wifi/java/android/net/wifi/WifiConfigStore.java +++ b/wifi/java/android/net/wifi/WifiConfigStore.java @@ -23,6 +23,7 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkUtils; import android.net.ProxyProperties; +import android.net.RouteInfo; import android.net.wifi.WifiConfiguration.IpAssignment; import android.net.wifi.WifiConfiguration.KeyMgmt; import android.net.wifi.WifiConfiguration.ProxySettings; @@ -120,7 +121,7 @@ class WifiConfigStore { private static final String ipConfigFile = Environment.getDataDirectory() + "/misc/wifi/ipconfig.txt"; - private static final int IPCONFIG_FILE_VERSION = 1; + private static final int IPCONFIG_FILE_VERSION = 2; /* IP and proxy configuration keys */ private static final String ID_KEY = "id"; @@ -445,9 +446,8 @@ class WifiConfigStore { if (iter.hasNext()) { LinkAddress linkAddress = iter.next(); dhcpInfoInternal.ipAddress = linkAddress.getAddress().getHostAddress(); - Iterator<InetAddress>gateways = linkProperties.getGateways().iterator(); - if (gateways.hasNext()) { - dhcpInfoInternal.gateway = gateways.next().getHostAddress(); + for (RouteInfo route : linkProperties.getRoutes()) { + dhcpInfoInternal.addRoute(route); } dhcpInfoInternal.prefixLength = linkAddress.getNetworkPrefixLength(); Iterator<InetAddress> dnsIterator = linkProperties.getDnses().iterator(); @@ -604,9 +604,22 @@ class WifiConfigStore { out.writeUTF(linkAddr.getAddress().getHostAddress()); out.writeInt(linkAddr.getNetworkPrefixLength()); } - for (InetAddress gateway : linkProperties.getGateways()) { + for (RouteInfo route : linkProperties.getRoutes()) { out.writeUTF(GATEWAY_KEY); - out.writeUTF(gateway.getHostAddress()); + LinkAddress dest = route.getDestination(); + if (dest != null) { + out.writeInt(1); + out.writeUTF(dest.getAddress().getHostAddress()); + out.writeInt(dest.getNetworkPrefixLength()); + } else { + out.writeInt(0); + } + if (route.getGateway() != null) { + out.writeInt(1); + out.writeUTF(route.getGateway().getHostAddress()); + } else { + out.writeInt(0); + } } for (InetAddress inetAddr : linkProperties.getDnses()) { out.writeUTF(DNS_KEY); @@ -682,7 +695,8 @@ class WifiConfigStore { in = new DataInputStream(new BufferedInputStream(new FileInputStream( ipConfigFile))); - if (in.readInt() != IPCONFIG_FILE_VERSION) { + int version = in.readInt(); + if (version != 2 && version != 1) { Log.e(TAG, "Bad version on IP configuration file, ignore read"); return; } @@ -709,8 +723,22 @@ class WifiConfigStore { NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt()); linkProperties.addLinkAddress(linkAddr); } else if (key.equals(GATEWAY_KEY)) { - linkProperties.addGateway( - NetworkUtils.numericToInetAddress(in.readUTF())); + LinkAddress dest = null; + InetAddress gateway = null; + if (version == 1) { + // only supported default gateways - leave the dest/prefix empty + gateway = NetworkUtils.numericToInetAddress(in.readUTF()); + } else { + if (in.readInt() == 1) { + dest = new LinkAddress( + NetworkUtils.numericToInetAddress(in.readUTF()), + in.readInt()); + } + if (in.readInt() == 1) { + gateway = NetworkUtils.numericToInetAddress(in.readUTF()); + } + } + linkProperties.addRoute(new RouteInfo(dest, gateway)); } else if (key.equals(DNS_KEY)) { linkProperties.addDns( NetworkUtils.numericToInetAddress(in.readUTF())); @@ -1022,22 +1050,21 @@ class WifiConfigStore { .getLinkAddresses(); Collection<InetAddress> currentDnses = currentConfig.linkProperties.getDnses(); Collection<InetAddress> newDnses = newConfig.linkProperties.getDnses(); - Collection<InetAddress> currentGateways = - currentConfig.linkProperties.getGateways(); - Collection<InetAddress> newGateways = newConfig.linkProperties.getGateways(); + Collection<RouteInfo> currentRoutes = currentConfig.linkProperties.getRoutes(); + Collection<RouteInfo> newRoutes = newConfig.linkProperties.getRoutes(); boolean linkAddressesDiffer = (currentLinkAddresses.size() != newLinkAddresses.size()) || !currentLinkAddresses.containsAll(newLinkAddresses); boolean dnsesDiffer = (currentDnses.size() != newDnses.size()) || !currentDnses.containsAll(newDnses); - boolean gatewaysDiffer = (currentGateways.size() != newGateways.size()) || - !currentGateways.containsAll(newGateways); + boolean routesDiffer = (currentRoutes.size() != newRoutes.size()) || + !currentRoutes.containsAll(newRoutes); if ((currentConfig.ipAssignment != newConfig.ipAssignment) || linkAddressesDiffer || dnsesDiffer || - gatewaysDiffer) { + routesDiffer) { ipChanged = true; } break; @@ -1112,8 +1139,8 @@ class WifiConfigStore { for (LinkAddress linkAddr : config.linkProperties.getLinkAddresses()) { linkProperties.addLinkAddress(linkAddr); } - for (InetAddress gateway : config.linkProperties.getGateways()) { - linkProperties.addGateway(gateway); + for (RouteInfo route : config.linkProperties.getRoutes()) { + linkProperties.addRoute(route); } for (InetAddress dns : config.linkProperties.getDnses()) { linkProperties.addDns(dns); diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index 33d4e1fc489b..91250375f2c9 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -48,6 +48,7 @@ import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.DhcpInfo; import android.net.DhcpInfoInternal; +import android.net.DhcpStateMachine; import android.net.InterfaceConfiguration; import android.net.LinkAddress; import android.net.LinkProperties; @@ -152,6 +153,7 @@ public class WifiStateMachine extends StateMachine { private NetworkInfo mNetworkInfo; private SupplicantStateTracker mSupplicantStateTracker; private WpsStateMachine mWpsStateMachine; + private DhcpStateMachine mDhcpStateMachine; private AlarmManager mAlarmManager; private PendingIntent mScanIntent; @@ -189,10 +191,10 @@ public class WifiStateMachine extends StateMachine { static final int CMD_START_DRIVER = BASE + 13; /* Start the driver */ static final int CMD_STOP_DRIVER = BASE + 14; - /* Indicates DHCP succeded */ - static final int CMD_IP_CONFIG_SUCCESS = BASE + 15; - /* Indicates DHCP failed */ - static final int CMD_IP_CONFIG_FAILURE = BASE + 16; + /* Indicates Static IP succeded */ + static final int CMD_STATIC_IP_SUCCESS = BASE + 15; + /* Indicates Static IP failed */ + static final int CMD_STATIC_IP_FAILURE = BASE + 16; /* Start the soft access point */ static final int CMD_START_AP = BASE + 21; @@ -338,8 +340,11 @@ public class WifiStateMachine extends StateMachine { */ private static final int DEFAULT_MAX_DHCP_RETRIES = 9; - private static final int POWER_MODE_ACTIVE = 1; - private static final int POWER_MODE_AUTO = 0; + static final int POWER_MODE_ACTIVE = 1; + static final int POWER_MODE_AUTO = 0; + + /* Tracks the power mode for restoration after a DHCP request/renewal goes through */ + private int mPowerMode = POWER_MODE_AUTO; /** * Default framework scan interval in milliseconds. This is used in the scenario in which @@ -1408,8 +1413,10 @@ public class WifiStateMachine extends StateMachine { */ NetworkUtils.resetConnections(mInterfaceName); - if (!NetworkUtils.stopDhcp(mInterfaceName)) { - Log.e(TAG, "Could not stop DHCP"); + if (mDhcpStateMachine != null) { + mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); + mDhcpStateMachine.quit(); + mDhcpStateMachine = null; } /* Disable interface */ @@ -1435,6 +1442,100 @@ public class WifiStateMachine extends StateMachine { } + void handlePreDhcpSetup() { + if (!mBluetoothConnectionActive) { + /* + * There are problems setting the Wi-Fi driver's power + * mode to active when bluetooth coexistence mode is + * enabled or sense. + * <p> + * We set Wi-Fi to active mode when + * obtaining an IP address because we've found + * compatibility issues with some routers with low power + * mode. + * <p> + * In order for this active power mode to properly be set, + * we disable coexistence mode until we're done with + * obtaining an IP address. One exception is if we + * are currently connected to a headset, since disabling + * coexistence would interrupt that connection. + */ + // Disable the coexistence mode + WifiNative.setBluetoothCoexistenceModeCommand( + WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); + } + + mPowerMode = WifiNative.getPowerModeCommand(); + if (mPowerMode < 0) { + // Handle the case where supplicant driver does not support + // getPowerModeCommand. + mPowerMode = WifiStateMachine.POWER_MODE_AUTO; + } + if (mPowerMode != WifiStateMachine.POWER_MODE_ACTIVE) { + WifiNative.setPowerModeCommand(WifiStateMachine.POWER_MODE_ACTIVE); + } + } + + + void handlePostDhcpSetup() { + /* restore power mode */ + WifiNative.setPowerModeCommand(mPowerMode); + + // Set the coexistence mode back to its default value + WifiNative.setBluetoothCoexistenceModeCommand( + WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); + } + + private void handleSuccessfulIpConfiguration(DhcpInfoInternal dhcpInfoInternal) { + synchronized (mDhcpInfoInternal) { + mDhcpInfoInternal = dhcpInfoInternal; + } + mLastSignalLevel = -1; // force update of signal strength + WifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal); + InetAddress addr = NetworkUtils.numericToInetAddress(dhcpInfoInternal.ipAddress); + mWifiInfo.setInetAddress(addr); + if (getNetworkDetailedState() == DetailedState.CONNECTED) { + //DHCP renewal in connected state + LinkProperties linkProperties = dhcpInfoInternal.makeLinkProperties(); + linkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId)); + linkProperties.setInterfaceName(mInterfaceName); + if (!linkProperties.equals(mLinkProperties)) { + Log.d(TAG, "Link configuration changed for netId: " + mLastNetworkId + + " old: " + mLinkProperties + "new: " + linkProperties); + NetworkUtils.resetConnections(mInterfaceName); + mLinkProperties = linkProperties; + sendLinkConfigurationChangedBroadcast(); + } + } else { + configureLinkProperties(); + setNetworkDetailedState(DetailedState.CONNECTED); + sendNetworkStateChangeBroadcast(mLastBssid); + } + } + + private void handleFailedIpConfiguration() { + Log.e(TAG, "IP configuration failed"); + + mWifiInfo.setInetAddress(null); + /** + * If we've exceeded the maximum number of retries for DHCP + * to a given network, disable the network + */ + if (++mReconnectCount > getMaxDhcpRetries()) { + Log.e(TAG, "Failed " + + mReconnectCount + " times, Disabling " + mLastNetworkId); + WifiConfigStore.disableNetwork(mLastNetworkId); + mReconnectCount = 0; + } + + /* DHCP times out after about 30 seconds, we do a + * disconnect and an immediate reconnect to try again + */ + WifiNative.disconnectCommand(); + WifiNative.reconnectCommand(); + + } + /********************************************************* * Notifications from WifiMonitor @@ -1606,6 +1707,8 @@ public class WifiStateMachine extends StateMachine { case CMD_FORGET_NETWORK: case CMD_RSSI_POLL: case CMD_ENABLE_ALL_NETWORKS: + case DhcpStateMachine.CMD_PRE_DHCP_ACTION: + case DhcpStateMachine.CMD_POST_DHCP_ACTION: break; case CMD_START_WPS: /* Return failure when the state machine cannot handle WPS initiation*/ @@ -2483,74 +2586,18 @@ public class WifiStateMachine extends StateMachine { } class ConnectingState extends State { - boolean mModifiedBluetoothCoexistenceMode; - int mPowerMode; - boolean mUseStaticIp; - Thread mDhcpThread; @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - mUseStaticIp = WifiConfigStore.isUsingStaticIp(mLastNetworkId); - if (!mUseStaticIp) { - mDhcpThread = null; - mModifiedBluetoothCoexistenceMode = false; - mPowerMode = POWER_MODE_AUTO; - - if (!mBluetoothConnectionActive) { - /* - * There are problems setting the Wi-Fi driver's power - * mode to active when bluetooth coexistence mode is - * enabled or sense. - * <p> - * We set Wi-Fi to active mode when - * obtaining an IP address because we've found - * compatibility issues with some routers with low power - * mode. - * <p> - * In order for this active power mode to properly be set, - * we disable coexistence mode until we're done with - * obtaining an IP address. One exception is if we - * are currently connected to a headset, since disabling - * coexistence would interrupt that connection. - */ - mModifiedBluetoothCoexistenceMode = true; - - // Disable the coexistence mode - WifiNative.setBluetoothCoexistenceModeCommand( - WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); - } - - mPowerMode = WifiNative.getPowerModeCommand(); - if (mPowerMode < 0) { - // Handle the case where supplicant driver does not support - // getPowerModeCommand. - mPowerMode = POWER_MODE_AUTO; - } - if (mPowerMode != POWER_MODE_ACTIVE) { - WifiNative.setPowerModeCommand(POWER_MODE_ACTIVE); - } - Log.d(TAG, "DHCP request started"); - mDhcpThread = new Thread(new Runnable() { - public void run() { - DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal(); - if (NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal)) { - Log.d(TAG, "DHCP request succeeded"); - synchronized (mDhcpInfoInternal) { - mDhcpInfoInternal = dhcpInfoInternal; - } - WifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal); - sendMessage(CMD_IP_CONFIG_SUCCESS); - } else { - Log.d(TAG, "DHCP request failed: " + - NetworkUtils.getDhcpError()); - sendMessage(CMD_IP_CONFIG_FAILURE); - } - } - }); - mDhcpThread.start(); + if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) { + //start DHCP + mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( + mContext, WifiStateMachine.this, mInterfaceName); + mDhcpStateMachine.registerForPreDhcpNotification(); + mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); } else { DhcpInfoInternal dhcpInfoInternal = WifiConfigStore.getIpConfiguration( mLastNetworkId); @@ -2562,16 +2609,13 @@ public class WifiStateMachine extends StateMachine { try { netd.setInterfaceConfig(mInterfaceName, ifcg); Log.v(TAG, "Static IP configuration succeeded"); - synchronized (mDhcpInfoInternal) { - mDhcpInfoInternal = dhcpInfoInternal; - } - sendMessage(CMD_IP_CONFIG_SUCCESS); + sendMessage(CMD_STATIC_IP_SUCCESS, dhcpInfoInternal); } catch (RemoteException re) { Log.v(TAG, "Static IP configuration failed: " + re); - sendMessage(CMD_IP_CONFIG_FAILURE); + sendMessage(CMD_STATIC_IP_FAILURE); } catch (IllegalStateException e) { Log.v(TAG, "Static IP configuration failed: " + e); - sendMessage(CMD_IP_CONFIG_FAILURE); + sendMessage(CMD_STATIC_IP_FAILURE); } } } @@ -2580,44 +2624,26 @@ public class WifiStateMachine extends StateMachine { if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); switch(message.what) { - case CMD_IP_CONFIG_SUCCESS: - mLastSignalLevel = -1; // force update of signal strength - InetAddress addr; - synchronized (mDhcpInfoInternal) { - addr = NetworkUtils.numericToInetAddress(mDhcpInfoInternal.ipAddress); - } - mWifiInfo.setInetAddress(addr); - configureLinkProperties(); - if (getNetworkDetailedState() == DetailedState.CONNECTED) { - sendLinkConfigurationChangedBroadcast(); - } else { - setNetworkDetailedState(DetailedState.CONNECTED); - sendNetworkStateChangeBroadcast(mLastBssid); + case DhcpStateMachine.CMD_PRE_DHCP_ACTION: + handlePreDhcpSetup(); + mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE); + break; + case DhcpStateMachine.CMD_POST_DHCP_ACTION: + handlePostDhcpSetup(); + if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { + handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj); + transitionTo(mConnectedState); + } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { + handleFailedIpConfiguration(); + transitionTo(mDisconnectingState); } - //TODO: The framework is not detecting a DHCP renewal and a possible - //IP change. we should detect this and send out a config change broadcast + break; + case CMD_STATIC_IP_SUCCESS: + handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj); transitionTo(mConnectedState); break; - case CMD_IP_CONFIG_FAILURE: - mWifiInfo.setInetAddress(null); - - Log.e(TAG, "IP configuration failed"); - /** - * If we've exceeded the maximum number of retries for DHCP - * to a given network, disable the network - */ - if (++mReconnectCount > getMaxDhcpRetries()) { - Log.e(TAG, "Failed " + - mReconnectCount + " times, Disabling " + mLastNetworkId); - WifiConfigStore.disableNetwork(mLastNetworkId); - mReconnectCount = 0; - } - - /* DHCP times out after about 30 seconds, we do a - * disconnect and an immediate reconnect to try again - */ - WifiNative.disconnectCommand(); - WifiNative.reconnectCommand(); + case CMD_STATIC_IP_FAILURE: + handleFailedIpConfiguration(); transitionTo(mDisconnectingState); break; case CMD_DISCONNECT: @@ -2661,23 +2687,6 @@ public class WifiStateMachine extends StateMachine { EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); return HANDLED; } - - @Override - public void exit() { - /* reset power state & bluetooth coexistence if on DHCP */ - if (!mUseStaticIp) { - if (mPowerMode != POWER_MODE_ACTIVE) { - WifiNative.setPowerModeCommand(mPowerMode); - } - - if (mModifiedBluetoothCoexistenceMode) { - // Set the coexistence mode back to its default value - WifiNative.setBluetoothCoexistenceModeCommand( - WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); - } - } - - } } class ConnectedState extends State { @@ -2695,6 +2704,19 @@ public class WifiStateMachine extends StateMachine { if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); boolean eventLoggingEnabled = true; switch (message.what) { + case DhcpStateMachine.CMD_PRE_DHCP_ACTION: + handlePreDhcpSetup(); + mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE); + break; + case DhcpStateMachine.CMD_POST_DHCP_ACTION: + handlePostDhcpSetup(); + if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { + handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj); + } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { + handleFailedIpConfiguration(); + transitionTo(mDisconnectingState); + } + break; case CMD_DISCONNECT: WifiNative.disconnectCommand(); transitionTo(mDisconnectingState); |